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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This module relies on ldb_map to do all the real work, but performs
26 some of the trivial mappings between AD semantics and that provided
27 by OpenLDAP and similar servers.
31 #include "ldb/include/ldb.h"
32 #include "ldb/include/ldb_private.h"
33 #include "ldb/include/ldb_errors.h"
34 #include "ldb/ldb_map/ldb_map.h"
36 #include "librpc/gen_ndr/ndr_misc.h"
37 #include "librpc/ndr/libndr.h"
39 struct entryUUID_private {
40 struct ldb_result *objectclass_res;
41 struct ldb_dn **base_dns;
44 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
47 NTSTATUS status = GUID_from_string((char *)val->data, &guid);
48 struct ldb_val out = data_blob(NULL, 0);
50 if (!NT_STATUS_IS_OK(status)) {
53 status = ndr_push_struct_blob(&out, ctx, &guid,
54 (ndr_push_flags_fn_t)ndr_push_GUID);
55 if (!NT_STATUS_IS_OK(status)) {
62 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
66 struct ldb_val out = data_blob(NULL, 0);
67 if (val->length >= 32 && val->data[val->length] == '\0') {
68 ldb_handler_copy(module->ldb, ctx, val, &out);
70 guid = talloc(ctx, struct GUID);
74 status = ndr_pull_struct_blob(val, guid, guid,
75 (ndr_pull_flags_fn_t)ndr_pull_GUID);
76 if (!NT_STATUS_IS_OK(status)) {
80 out = data_blob_string_const(GUID_string(ctx, guid));
86 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
89 NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
90 struct ldb_val out = data_blob(NULL, 0);
92 if (!NT_STATUS_IS_OK(status)) {
95 status = ndr_push_struct_blob(&out, ctx, &guid,
96 (ndr_push_flags_fn_t)ndr_push_GUID);
97 if (!NT_STATUS_IS_OK(status)) {
104 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
107 struct ldb_val out = data_blob(NULL, 0);
108 if (val->length >= 32 && val->data[val->length] == '\0') {
110 GUID_from_string((char *)val->data, &guid);
111 out = data_blob_string_const(NS_GUID_string(ctx, &guid));
114 guid_p = talloc(ctx, struct GUID);
115 if (guid_p == NULL) {
118 status = ndr_pull_struct_blob(val, guid_p, guid_p,
119 (ndr_pull_flags_fn_t)ndr_pull_GUID);
120 if (!NT_STATUS_IS_OK(status)) {
124 out = data_blob_string_const(NS_GUID_string(ctx, guid_p));
130 /* The backend holds binary sids, so just copy them back */
131 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
133 struct ldb_val out = data_blob(NULL, 0);
134 ldb_handler_copy(module->ldb, ctx, val, &out);
139 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
140 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
142 struct ldb_val out = data_blob(NULL, 0);
143 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectSid");
145 if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
146 return data_blob(NULL, 0);
152 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
155 struct map_private *map_private;
156 struct entryUUID_private *entryUUID_private;
157 struct ldb_result *list;
159 if (ldb_dn_validate(ldb_dn_new(ctx, module->ldb, (const char *)val->data))) {
162 map_private = talloc_get_type(module->private_data, struct map_private);
164 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
165 list = entryUUID_private->objectclass_res;
167 for (i=0; list && (i < list->count); i++) {
168 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL)) == 0) {
169 char *dn = ldb_dn_alloc_linearized(ctx, list->msgs[i]->dn);
170 return data_blob_string_const(dn);
176 static struct ldb_val class_to_oid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
179 struct map_private *map_private;
180 struct entryUUID_private *entryUUID_private;
181 struct ldb_result *list;
183 map_private = talloc_get_type(module->private_data, struct map_private);
185 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
186 list = entryUUID_private->objectclass_res;
188 for (i=0; list && (i < list->count); i++) {
189 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL)) == 0) {
190 const char *oid = ldb_msg_find_attr_as_string(list->msgs[i], "governsID", NULL);
191 return data_blob_string_const(oid);
197 static struct ldb_val class_from_oid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
200 struct map_private *map_private;
201 struct entryUUID_private *entryUUID_private;
202 struct ldb_result *list;
204 map_private = talloc_get_type(module->private_data, struct map_private);
206 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
207 list = entryUUID_private->objectclass_res;
209 for (i=0; list && (i < list->count); i++) {
210 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "governsID", NULL)) == 0) {
211 const char *oc = ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL);
212 return data_blob_string_const(oc);
219 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
221 long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
222 if (signed_ll >= 0x80000000LL) {
225 uint32_t unsigned_int;
227 .unsigned_int = strtoul((const char *)val->data, NULL, 10)
230 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
233 return val_copy(module, ctx, val);
236 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
239 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
240 time_t t = (usn >> 24);
241 out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
245 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
247 char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
250 unsigned long long usn;
255 p = strchr(entryCSN, '#');
270 usn = strtol(mod_per_sec, NULL, 16);
272 t = ldb_string_to_time(entryCSN);
274 usn = usn | ((unsigned long long)t <<24);
278 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
281 unsigned long long usn = entryCSN_to_usn_int(ctx, val);
282 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
286 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
289 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
290 time_t t = (usn >> 24);
291 out = data_blob_string_const(ldb_timestring(ctx, t));
295 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
299 unsigned long long usn;
301 t = ldb_string_to_time((const char *)val->data);
303 usn = ((unsigned long long)t <<24);
305 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
310 const struct ldb_map_attribute entryUUID_attributes[] =
314 .local_name = "objectGUID",
318 .remote_name = "entryUUID",
319 .convert_local = guid_always_string,
320 .convert_remote = encode_guid,
326 .local_name = "invocationId",
330 .remote_name = "invocationId",
331 .convert_local = guid_always_string,
332 .convert_remote = encode_guid,
338 .local_name = "objectSid",
342 .remote_name = "objectSid",
343 .convert_local = sid_always_binary,
344 .convert_remote = val_copy,
349 .local_name = "whenCreated",
353 .remote_name = "createTimestamp"
358 .local_name = "whenChanged",
362 .remote_name = "modifyTimestamp"
367 .local_name = "objectClasses",
371 .remote_name = "samba4ObjectClasses"
376 .local_name = "dITContentRules",
380 .remote_name = "samba4DITContentRules"
385 .local_name = "attributeTypes",
389 .remote_name = "samba4AttributeTypes"
394 .local_name = "sambaPassword",
398 .remote_name = "userPassword"
404 .local_name = "allowedChildClassesEffective",
408 .remote_name = "allowedChildClassesEffective",
409 .convert_local = class_to_oid,
410 .convert_remote = class_from_oid,
416 .local_name = "objectCategory",
420 .remote_name = "objectCategory",
421 .convert_local = objectCategory_always_dn,
422 .convert_remote = val_copy,
427 .local_name = "distinguishedName",
431 .remote_name = "entryDN"
436 .local_name = "groupType",
440 .remote_name = "groupType",
441 .convert_local = normalise_to_signed32,
442 .convert_remote = val_copy,
447 .local_name = "sAMAccountType",
451 .remote_name = "sAMAccountType",
452 .convert_local = normalise_to_signed32,
453 .convert_remote = val_copy,
458 .local_name = "usnChanged",
462 .remote_name = "entryCSN",
463 .convert_local = usn_to_entryCSN,
464 .convert_remote = entryCSN_to_usn
469 .local_name = "usnCreated",
473 .remote_name = "createTimestamp",
474 .convert_local = usn_to_timestamp,
475 .convert_remote = timestamp_to_usn,
488 /* This objectClass conflicts with builtin classes on OpenLDAP */
489 const struct ldb_map_objectclass entryUUID_objectclasses[] =
492 .local_name = "subSchema",
493 .remote_name = "samba4SubSchema"
500 /* These things do not show up in wildcard searches in OpenLDAP, but
501 * we need them to show up in the AD-like view */
502 const char * const entryUUID_wildcard_attributes[] = {
511 const struct ldb_map_attribute nsuniqueid_attributes[] =
515 .local_name = "objectGUID",
519 .remote_name = "nsuniqueid",
520 .convert_local = guid_ns_string,
521 .convert_remote = encode_ns_guid,
527 .local_name = "objectSid",
531 .remote_name = "objectSid",
532 .convert_local = sid_always_binary,
533 .convert_remote = val_copy,
538 .local_name = "whenCreated",
542 .remote_name = "createTimestamp"
547 .local_name = "whenChanged",
551 .remote_name = "modifyTimestamp"
556 .local_name = "sambaPassword",
560 .remote_name = "userPassword"
566 .local_name = "allowedChildClassesEffective",
570 .remote_name = "allowedChildClassesEffective",
571 .convert_local = class_to_oid,
572 .convert_remote = class_from_oid,
578 .local_name = "objectCategory",
582 .remote_name = "objectCategory",
583 .convert_local = objectCategory_always_dn,
584 .convert_remote = val_copy,
589 .local_name = "distinguishedName",
593 .remote_name = "entryDN"
598 .local_name = "groupType",
602 .remote_name = "groupType",
603 .convert_local = normalise_to_signed32,
604 .convert_remote = val_copy,
609 .local_name = "sAMAccountType",
613 .remote_name = "sAMAccountType",
614 .convert_local = normalise_to_signed32,
615 .convert_remote = val_copy,
620 .local_name = "usnChanged",
624 .remote_name = "modifyTimestamp",
625 .convert_local = usn_to_timestamp,
626 .convert_remote = timestamp_to_usn,
631 .local_name = "usnCreated",
635 .remote_name = "createTimestamp",
636 .convert_local = usn_to_timestamp,
637 .convert_remote = timestamp_to_usn,
650 /* These things do not show up in wildcard searches in OpenLDAP, but
651 * we need them to show up in the AD-like view */
652 const char * const nsuniqueid_wildcard_attributes[] = {
661 static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
663 const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
664 struct ldb_dn *schema_dn;
665 struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
666 struct ldb_result *rootdse_res;
672 /* Search for rootdse */
673 ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res);
674 if (ldb_ret != LDB_SUCCESS) {
678 talloc_steal(mem_ctx, rootdse_res);
680 if (rootdse_res->count != 1) {
681 ldb_asprintf_errstring(ldb, "Failed to find rootDSE: count %d", rootdse_res->count);
686 schema_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
691 talloc_free(rootdse_res);
695 static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
697 struct ldb_result **objectclass_res)
699 TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
701 const char *attrs[] = {
708 return LDB_ERR_OPERATIONS_ERROR;
711 /* Downlaod schema */
712 ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
713 "objectClass=classSchema",
714 attrs, objectclass_res);
715 if (ret != LDB_SUCCESS) {
719 talloc_steal(mem_ctx, objectclass_res);
725 static int get_remote_rootdse(struct ldb_context *ldb, void *context,
726 struct ldb_reply *ares)
728 struct entryUUID_private *entryUUID_private;
729 entryUUID_private = talloc_get_type(context,
730 struct entryUUID_private);
731 if (ares->type == LDB_REPLY_ENTRY) {
733 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "namingContexts");
734 entryUUID_private->base_dns = talloc_realloc(entryUUID_private, entryUUID_private->base_dns, struct ldb_dn *,
736 for (i=0; i < el->num_values; i++) {
737 if (!entryUUID_private->base_dns) {
738 return LDB_ERR_OPERATIONS_ERROR;
740 entryUUID_private->base_dns[i] = ldb_dn_new(entryUUID_private->base_dns, ldb, (const char *)el->values[i].data);
741 if ( ! ldb_dn_validate(entryUUID_private->base_dns[i])) {
742 return LDB_ERR_OPERATIONS_ERROR;
745 entryUUID_private->base_dns[i] = NULL;
751 static int find_base_dns(struct ldb_module *module,
752 struct entryUUID_private *entryUUID_private)
755 struct ldb_request *req;
756 const char *naming_context_attr[] = {
760 req = talloc(entryUUID_private, struct ldb_request);
762 ldb_set_errstring(module->ldb, "Out of Memory");
763 return LDB_ERR_OPERATIONS_ERROR;
766 req->operation = LDB_SEARCH;
767 req->op.search.base = ldb_dn_new(req, module->ldb, NULL);
768 req->op.search.scope = LDB_SCOPE_BASE;
770 req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
771 if (req->op.search.tree == NULL) {
772 ldb_set_errstring(module->ldb, "Unable to parse search expression");
774 return LDB_ERR_OPERATIONS_ERROR;
777 req->op.search.attrs = naming_context_attr;
778 req->controls = NULL;
779 req->context = entryUUID_private;
780 req->callback = get_remote_rootdse;
781 ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
783 ret = ldb_next_request(module, req);
785 if (ret == LDB_SUCCESS) {
786 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
790 if (ret != LDB_SUCCESS) {
797 /* the context init function */
798 static int entryUUID_init(struct ldb_module *module)
801 struct map_private *map_private;
802 struct entryUUID_private *entryUUID_private;
803 struct ldb_dn *schema_dn;
805 ret = ldb_map_init(module, entryUUID_attributes, entryUUID_objectclasses, entryUUID_wildcard_attributes, NULL);
806 if (ret != LDB_SUCCESS)
809 map_private = talloc_get_type(module->private_data, struct map_private);
811 entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
812 map_private->caller_private = entryUUID_private;
814 schema_dn = find_schema_dn(module->ldb, map_private);
816 /* Perhaps no schema yet */
820 ret = fetch_objectclass_schema(module->ldb, schema_dn, entryUUID_private,
821 &entryUUID_private->objectclass_res);
822 if (ret != LDB_SUCCESS) {
823 /* Perhaps no schema yet */
827 ret = find_base_dns(module, entryUUID_private);
829 return ldb_next_init(module);
832 /* the context init function */
833 static int nsuniqueid_init(struct ldb_module *module)
836 struct map_private *map_private;
837 struct entryUUID_private *entryUUID_private;
838 struct ldb_dn *schema_dn;
840 ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, NULL);
841 if (ret != LDB_SUCCESS)
844 map_private = talloc_get_type(module->private_data, struct map_private);
846 entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
847 map_private->caller_private = entryUUID_private;
849 schema_dn = find_schema_dn(module->ldb, map_private);
851 /* Perhaps no schema yet */
855 ret = fetch_objectclass_schema(module->ldb, schema_dn, entryUUID_private,
856 &entryUUID_private->objectclass_res);
857 if (ret != LDB_SUCCESS) {
858 /* Perhaps no schema yet */
862 ret = find_base_dns(module, entryUUID_private);
864 return ldb_next_init(module);
867 static int get_seq(struct ldb_context *ldb, void *context,
868 struct ldb_reply *ares)
870 unsigned long long *max_seq = context;
871 unsigned long long seq;
872 if (ares->type == LDB_REPLY_ENTRY) {
873 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
875 seq = entryCSN_to_usn_int(ares, &el->values[0]);
876 *max_seq = MAX(seq, *max_seq);
883 static int entryUUID_sequence_number(struct ldb_module *module, struct ldb_request *req)
886 struct map_private *map_private;
887 struct entryUUID_private *entryUUID_private;
888 unsigned long long max_seq = 0;
889 struct ldb_request *search_req;
890 map_private = talloc_get_type(module->private_data, struct map_private);
892 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
894 /* Search the baseDNs for a sequence number */
895 for (i=0; entryUUID_private &&
896 entryUUID_private->base_dns &&
897 entryUUID_private->base_dns[i];
899 static const char *contextCSN_attr[] = {
902 search_req = talloc(req, struct ldb_request);
903 if (search_req == NULL) {
904 ldb_set_errstring(module->ldb, "Out of Memory");
905 return LDB_ERR_OPERATIONS_ERROR;
908 search_req->operation = LDB_SEARCH;
909 search_req->op.search.base = entryUUID_private->base_dns[i];
910 search_req->op.search.scope = LDB_SCOPE_BASE;
912 search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
913 if (search_req->op.search.tree == NULL) {
914 ldb_set_errstring(module->ldb, "Unable to parse search expression");
915 talloc_free(search_req);
916 return LDB_ERR_OPERATIONS_ERROR;
919 search_req->op.search.attrs = contextCSN_attr;
920 search_req->controls = NULL;
921 search_req->context = &max_seq;
922 search_req->callback = get_seq;
923 ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
925 ret = ldb_next_request(module, search_req);
927 if (ret == LDB_SUCCESS) {
928 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
931 talloc_free(search_req);
932 if (ret != LDB_SUCCESS) {
937 switch (req->op.seq_num.type) {
938 case LDB_SEQ_HIGHEST_SEQ:
939 req->op.seq_num.seq_num = max_seq;
942 req->op.seq_num.seq_num = max_seq;
943 req->op.seq_num.seq_num++;
945 case LDB_SEQ_HIGHEST_TIMESTAMP:
947 req->op.seq_num.seq_num = (max_seq >> 24);
951 req->op.seq_num.flags = 0;
952 req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
953 req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
957 static struct ldb_module_ops entryUUID_ops = {
959 .init_context = entryUUID_init,
960 .sequence_number = entryUUID_sequence_number
963 static struct ldb_module_ops nsuniqueid_ops = {
964 .name = "nsuniqueid",
965 .init_context = nsuniqueid_init,
966 .sequence_number = entryUUID_sequence_number
969 /* the init function */
970 int ldb_entryUUID_module_init(void)
973 struct ldb_module_ops ops = ldb_map_get_ops();
974 entryUUID_ops.add = ops.add;
975 entryUUID_ops.modify = ops.modify;
976 entryUUID_ops.del = ops.del;
977 entryUUID_ops.rename = ops.rename;
978 entryUUID_ops.search = ops.search;
979 entryUUID_ops.wait = ops.wait;
980 ret = ldb_register_module(&entryUUID_ops);
986 nsuniqueid_ops.add = ops.add;
987 nsuniqueid_ops.modify = ops.modify;
988 nsuniqueid_ops.del = ops.del;
989 nsuniqueid_ops.rename = ops.rename;
990 nsuniqueid_ops.search = ops.search;
991 nsuniqueid_ops.wait = ops.wait;
992 ret = ldb_register_module(&nsuniqueid_ops);