4 LDAP semantics mapping module
6 Copyright (C) Jelmer Vernooij 2005
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 This module relies on ldb_map to do all the real work, but performs
25 some of the trivial mappings between AD semantics and that provided
26 by OpenLDAP and similar servers.
30 #include "ldb/include/ldb.h"
31 #include "ldb/include/ldb_private.h"
32 #include "ldb/include/ldb_errors.h"
33 #include "ldb/ldb_map/ldb_map.h"
35 #include "librpc/gen_ndr/ndr_misc.h"
36 #include "librpc/ndr/libndr.h"
37 #include "dsdb/samdb/samdb.h"
39 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
42 NTSTATUS status = GUID_from_string((char *)val->data, &guid);
43 enum ndr_err_code ndr_err;
44 struct ldb_val out = data_blob(NULL, 0);
46 if (!NT_STATUS_IS_OK(status)) {
49 ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
50 (ndr_push_flags_fn_t)ndr_push_GUID);
51 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
58 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
61 struct ldb_val out = data_blob(NULL, 0);
62 if (val->length >= 32 && val->data[val->length] == '\0') {
63 ldb_handler_copy(module->ldb, ctx, val, &out);
65 enum ndr_err_code ndr_err;
67 guid = talloc(ctx, struct GUID);
71 ndr_err = ndr_pull_struct_blob(val, guid, NULL, guid,
72 (ndr_pull_flags_fn_t)ndr_pull_GUID);
73 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
77 out = data_blob_string_const(GUID_string(ctx, guid));
83 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
86 NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
87 enum ndr_err_code ndr_err;
88 struct ldb_val out = data_blob(NULL, 0);
90 if (!NT_STATUS_IS_OK(status)) {
93 ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
94 (ndr_push_flags_fn_t)ndr_push_GUID);
95 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
104 struct ldb_val out = data_blob(NULL, 0);
105 if (val->length >= 32 && val->data[val->length] == '\0') {
107 GUID_from_string((char *)val->data, &guid);
108 out = data_blob_string_const(NS_GUID_string(ctx, &guid));
110 enum ndr_err_code ndr_err;
112 guid_p = talloc(ctx, struct GUID);
113 if (guid_p == NULL) {
116 ndr_err = ndr_pull_struct_blob(val, guid_p, NULL, guid_p,
117 (ndr_pull_flags_fn_t)ndr_pull_GUID);
118 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
122 out = data_blob_string_const(NS_GUID_string(ctx, guid_p));
128 /* The backend holds binary sids, so just copy them back */
129 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
131 struct ldb_val out = data_blob(NULL, 0);
132 ldb_handler_copy(module->ldb, ctx, val, &out);
137 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
138 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
140 struct ldb_val out = data_blob(NULL, 0);
141 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectSid");
143 if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
144 return data_blob(NULL, 0);
150 /* Ensure we always convert objectCategory into a DN */
151 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
154 struct ldb_val out = data_blob(NULL, 0);
155 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectCategory");
157 dn = ldb_dn_from_ldb_val(ctx, module->ldb, val);
158 if (dn && ldb_dn_validate(dn)) {
160 return val_copy(module, ctx, val);
164 if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
165 return data_blob(NULL, 0);
171 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
173 long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
174 if (signed_ll >= 0x80000000LL) {
177 uint32_t unsigned_int;
179 .unsigned_int = strtoul((const char *)val->data, NULL, 10)
182 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
185 return val_copy(module, ctx, val);
188 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
191 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
192 time_t t = (usn >> 24);
193 out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
197 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
199 char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
202 unsigned long long usn;
207 p = strchr(entryCSN, '#');
222 usn = strtol(mod_per_sec, NULL, 16);
224 t = ldb_string_to_time(entryCSN);
226 usn = usn | ((unsigned long long)t <<24);
230 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
233 unsigned long long usn = entryCSN_to_usn_int(ctx, val);
234 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
238 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
241 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
242 time_t t = (usn >> 24);
243 out = data_blob_string_const(ldb_timestring(ctx, t));
247 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
251 unsigned long long usn;
253 t = ldb_string_to_time((const char *)val->data);
255 usn = ((unsigned long long)t <<24);
257 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
262 static const struct ldb_map_attribute entryuuid_attributes[] =
266 .local_name = "objectGUID",
270 .remote_name = "entryUUID",
271 .convert_local = guid_always_string,
272 .convert_remote = encode_guid,
278 .local_name = "invocationId",
282 .remote_name = "invocationId",
283 .convert_local = guid_always_string,
284 .convert_remote = encode_guid,
290 .local_name = "objectSid",
294 .remote_name = "objectSid",
295 .convert_local = sid_always_binary,
296 .convert_remote = val_copy,
301 .local_name = "name",
305 .remote_name = "samba4RDN"
310 .local_name = "whenCreated",
314 .remote_name = "createTimestamp"
319 .local_name = "whenChanged",
323 .remote_name = "modifyTimestamp"
328 .local_name = "objectClasses",
332 .remote_name = "samba4ObjectClasses"
337 .local_name = "dITContentRules",
341 .remote_name = "samba4DITContentRules"
346 .local_name = "attributeTypes",
350 .remote_name = "samba4AttributeTypes"
355 .local_name = "objectCategory",
359 .remote_name = "objectCategory",
360 .convert_local = objectCategory_always_dn,
361 .convert_remote = val_copy,
366 .local_name = "distinguishedName",
370 .remote_name = "entryDN"
375 .local_name = "groupType",
379 .remote_name = "groupType",
380 .convert_local = normalise_to_signed32,
381 .convert_remote = val_copy,
386 .local_name = "sAMAccountType",
390 .remote_name = "sAMAccountType",
391 .convert_local = normalise_to_signed32,
392 .convert_remote = val_copy,
397 .local_name = "usnChanged",
401 .remote_name = "entryCSN",
402 .convert_local = usn_to_entryCSN,
403 .convert_remote = entryCSN_to_usn
408 .local_name = "usnCreated",
412 .remote_name = "createTimestamp",
413 .convert_local = usn_to_timestamp,
414 .convert_remote = timestamp_to_usn,
427 /* This objectClass conflicts with builtin classes on OpenLDAP */
428 const struct ldb_map_objectclass entryuuid_objectclasses[] =
431 .local_name = "subSchema",
432 .remote_name = "samba4SubSchema"
439 /* These things do not show up in wildcard searches in OpenLDAP, but
440 * we need them to show up in the AD-like view */
441 static const char * const entryuuid_wildcard_attributes[] = {
451 static const struct ldb_map_attribute nsuniqueid_attributes[] =
455 .local_name = "objectGUID",
459 .remote_name = "nsuniqueid",
460 .convert_local = guid_ns_string,
461 .convert_remote = encode_ns_guid,
467 .local_name = "objectSid",
471 .remote_name = "objectSid",
472 .convert_local = sid_always_binary,
473 .convert_remote = val_copy,
478 .local_name = "whenCreated",
482 .remote_name = "createTimestamp"
487 .local_name = "whenChanged",
491 .remote_name = "modifyTimestamp"
496 .local_name = "objectCategory",
500 .remote_name = "objectCategory",
501 .convert_local = objectCategory_always_dn,
502 .convert_remote = val_copy,
507 .local_name = "distinguishedName",
511 .remote_name = "entryDN"
516 .local_name = "groupType",
520 .remote_name = "groupType",
521 .convert_local = normalise_to_signed32,
522 .convert_remote = val_copy,
527 .local_name = "sAMAccountType",
531 .remote_name = "sAMAccountType",
532 .convert_local = normalise_to_signed32,
533 .convert_remote = val_copy,
538 .local_name = "usnChanged",
542 .remote_name = "modifyTimestamp",
543 .convert_local = usn_to_timestamp,
544 .convert_remote = timestamp_to_usn,
549 .local_name = "usnCreated",
553 .remote_name = "createTimestamp",
554 .convert_local = usn_to_timestamp,
555 .convert_remote = timestamp_to_usn,
568 /* These things do not show up in wildcard searches in OpenLDAP, but
569 * we need them to show up in the AD-like view */
570 static const char * const nsuniqueid_wildcard_attributes[] = {
579 /* the context init function */
580 static int entryuuid_init(struct ldb_module *module)
583 ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
584 if (ret != LDB_SUCCESS)
587 return ldb_next_init(module);
590 /* the context init function */
591 static int nsuniqueid_init(struct ldb_module *module)
594 ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
595 if (ret != LDB_SUCCESS)
598 return ldb_next_init(module);
601 static int get_seq(struct ldb_context *ldb, void *context,
602 struct ldb_reply *ares)
604 unsigned long long *seq = (unsigned long long *)context;
605 if (ares->type == LDB_REPLY_ENTRY) {
606 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
608 *seq = entryCSN_to_usn_int(ares, &el->values[0]);
615 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
618 struct map_private *map_private;
619 struct entryuuid_private *entryuuid_private;
620 unsigned long long seq = 0;
621 struct ldb_request *search_req;
623 const struct ldb_control *partition_ctrl;
624 const struct dsdb_control_current_partition *partition;
626 static const char *contextCSN_attr[] = {
630 map_private = talloc_get_type(module->private_data, struct map_private);
632 entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
634 /* All this to get the DN of the parition, so we can search the right thing */
635 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
636 if (!partition_ctrl) {
637 ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
638 "instancetype_add: no current partition control found");
639 return LDB_ERR_CONSTRAINT_VIOLATION;
642 partition = talloc_get_type(partition_ctrl->data,
643 struct dsdb_control_current_partition);
644 SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
646 search_req = talloc(req, struct ldb_request);
647 if (search_req == NULL) {
648 ldb_set_errstring(module->ldb, "Out of Memory");
649 return LDB_ERR_OPERATIONS_ERROR;
652 /* Finally, we have it. This saves searching over more
653 * partitions than we expose to the client, such as a cn=samba
654 * configuration partition */
656 search_req->operation = LDB_SEARCH;
657 search_req->op.search.base = partition->dn;
658 search_req->op.search.scope = LDB_SCOPE_BASE;
660 search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
661 if (search_req->op.search.tree == NULL) {
662 ldb_set_errstring(module->ldb, "Unable to parse search expression");
663 talloc_free(search_req);
664 return LDB_ERR_OPERATIONS_ERROR;
667 search_req->op.search.attrs = contextCSN_attr;
668 search_req->controls = NULL;
669 search_req->context = &seq;
670 search_req->callback = get_seq;
671 ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
673 ret = ldb_next_request(module, search_req);
675 if (ret == LDB_SUCCESS) {
676 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
679 talloc_free(search_req);
680 if (ret != LDB_SUCCESS) {
684 switch (req->op.seq_num.type) {
685 case LDB_SEQ_HIGHEST_SEQ:
686 req->op.seq_num.seq_num = seq;
689 req->op.seq_num.seq_num = seq;
690 req->op.seq_num.seq_num++;
692 case LDB_SEQ_HIGHEST_TIMESTAMP:
694 req->op.seq_num.seq_num = (seq >> 24);
698 req->op.seq_num.flags = 0;
699 req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
700 req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
704 _PUBLIC_ const struct ldb_module_ops ldb_entryuuid_module_ops = {
706 .init_context = entryuuid_init,
707 .sequence_number = entryuuid_sequence_number,
711 _PUBLIC_ const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
712 .name = "nsuniqueid",
713 .init_context = nsuniqueid_init,
714 .sequence_number = entryuuid_sequence_number,