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"
38 struct entryUUID_private {
39 struct ldb_result *objectclass_res;
40 struct ldb_dn **base_dns;
43 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
46 NTSTATUS status = GUID_from_string((char *)val->data, &guid);
47 struct ldb_val out = data_blob(NULL, 0);
49 if (!NT_STATUS_IS_OK(status)) {
52 status = ndr_push_struct_blob(&out, ctx, &guid,
53 (ndr_push_flags_fn_t)ndr_push_GUID);
54 if (!NT_STATUS_IS_OK(status)) {
61 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
65 struct ldb_val out = data_blob(NULL, 0);
66 if (val->length >= 32 && val->data[val->length] == '\0') {
67 ldb_handler_copy(module->ldb, ctx, val, &out);
69 guid = talloc(ctx, struct GUID);
73 status = ndr_pull_struct_blob(val, guid, guid,
74 (ndr_pull_flags_fn_t)ndr_pull_GUID);
75 if (!NT_STATUS_IS_OK(status)) {
79 out = data_blob_string_const(GUID_string(ctx, guid));
85 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
88 NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
89 struct ldb_val out = data_blob(NULL, 0);
91 if (!NT_STATUS_IS_OK(status)) {
94 status = ndr_push_struct_blob(&out, ctx, &guid,
95 (ndr_push_flags_fn_t)ndr_push_GUID);
96 if (!NT_STATUS_IS_OK(status)) {
103 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
106 struct ldb_val out = data_blob(NULL, 0);
107 if (val->length >= 32 && val->data[val->length] == '\0') {
109 GUID_from_string((char *)val->data, &guid);
110 out = data_blob_string_const(NS_GUID_string(ctx, &guid));
113 guid_p = talloc(ctx, struct GUID);
114 if (guid_p == NULL) {
117 status = ndr_pull_struct_blob(val, guid_p, guid_p,
118 (ndr_pull_flags_fn_t)ndr_pull_GUID);
119 if (!NT_STATUS_IS_OK(status)) {
123 out = data_blob_string_const(NS_GUID_string(ctx, guid_p));
129 /* The backend holds binary sids, so just copy them back */
130 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
132 struct ldb_val out = data_blob(NULL, 0);
133 ldb_handler_copy(module->ldb, ctx, val, &out);
138 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
139 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
141 struct ldb_val out = data_blob(NULL, 0);
142 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectSid");
144 if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
145 return data_blob(NULL, 0);
151 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
154 struct map_private *map_private;
155 struct entryUUID_private *entryUUID_private;
156 struct ldb_result *list;
158 if (ldb_dn_validate(ldb_dn_new(ctx, module->ldb, (const char *)val->data))) {
161 map_private = talloc_get_type(module->private_data, struct map_private);
163 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
164 list = entryUUID_private->objectclass_res;
166 for (i=0; list && (i < list->count); i++) {
167 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL)) == 0) {
168 char *dn = ldb_dn_alloc_linearized(ctx, list->msgs[i]->dn);
169 return data_blob_string_const(dn);
175 static struct ldb_val class_to_oid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
178 struct map_private *map_private;
179 struct entryUUID_private *entryUUID_private;
180 struct ldb_result *list;
182 map_private = talloc_get_type(module->private_data, struct map_private);
184 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
185 list = entryUUID_private->objectclass_res;
187 for (i=0; list && (i < list->count); i++) {
188 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL)) == 0) {
189 const char *oid = ldb_msg_find_attr_as_string(list->msgs[i], "governsID", NULL);
190 return data_blob_string_const(oid);
196 static struct ldb_val class_from_oid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
199 struct map_private *map_private;
200 struct entryUUID_private *entryUUID_private;
201 struct ldb_result *list;
203 map_private = talloc_get_type(module->private_data, struct map_private);
205 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
206 list = entryUUID_private->objectclass_res;
208 for (i=0; list && (i < list->count); i++) {
209 if (ldb_attr_cmp((const char *)val->data, ldb_msg_find_attr_as_string(list->msgs[i], "governsID", NULL)) == 0) {
210 const char *oc = ldb_msg_find_attr_as_string(list->msgs[i], "lDAPDisplayName", NULL);
211 return data_blob_string_const(oc);
218 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
220 long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
221 if (signed_ll >= 0x80000000LL) {
224 uint32_t unsigned_int;
226 .unsigned_int = strtoul((const char *)val->data, NULL, 10)
229 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
232 return val_copy(module, ctx, val);
235 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
238 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
239 time_t t = (usn >> 24);
240 out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
244 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
246 char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
249 unsigned long long usn;
254 p = strchr(entryCSN, '#');
269 usn = strtol(mod_per_sec, NULL, 16);
271 t = ldb_string_to_time(entryCSN);
273 usn = usn | ((unsigned long long)t <<24);
277 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
280 unsigned long long usn = entryCSN_to_usn_int(ctx, val);
281 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
285 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
288 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
289 time_t t = (usn >> 24);
290 out = data_blob_string_const(ldb_timestring(ctx, t));
294 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
298 unsigned long long usn;
300 t = ldb_string_to_time((const char *)val->data);
302 usn = ((unsigned long long)t <<24);
304 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
309 const struct ldb_map_attribute entryUUID_attributes[] =
313 .local_name = "objectGUID",
317 .remote_name = "entryUUID",
318 .convert_local = guid_always_string,
319 .convert_remote = encode_guid,
325 .local_name = "invocationId",
329 .remote_name = "invocationId",
330 .convert_local = guid_always_string,
331 .convert_remote = encode_guid,
337 .local_name = "objectSid",
341 .remote_name = "objectSid",
342 .convert_local = sid_always_binary,
343 .convert_remote = val_copy,
348 .local_name = "whenCreated",
352 .remote_name = "createTimestamp"
357 .local_name = "whenChanged",
361 .remote_name = "modifyTimestamp"
366 .local_name = "objectClasses",
370 .remote_name = "samba4ObjectClasses"
375 .local_name = "dITContentRules",
379 .remote_name = "samba4DITContentRules"
384 .local_name = "attributeTypes",
388 .remote_name = "samba4AttributeTypes"
393 .local_name = "sambaPassword",
397 .remote_name = "userPassword"
403 .local_name = "allowedChildClassesEffective",
407 .remote_name = "allowedChildClassesEffective",
408 .convert_local = class_to_oid,
409 .convert_remote = class_from_oid,
415 .local_name = "objectCategory",
419 .remote_name = "objectCategory",
420 .convert_local = objectCategory_always_dn,
421 .convert_remote = val_copy,
426 .local_name = "distinguishedName",
430 .remote_name = "entryDN"
435 .local_name = "groupType",
439 .remote_name = "groupType",
440 .convert_local = normalise_to_signed32,
441 .convert_remote = val_copy,
446 .local_name = "sAMAccountType",
450 .remote_name = "sAMAccountType",
451 .convert_local = normalise_to_signed32,
452 .convert_remote = val_copy,
457 .local_name = "usnChanged",
461 .remote_name = "entryCSN",
462 .convert_local = usn_to_entryCSN,
463 .convert_remote = entryCSN_to_usn
468 .local_name = "usnCreated",
472 .remote_name = "createTimestamp",
473 .convert_local = usn_to_timestamp,
474 .convert_remote = timestamp_to_usn,
487 /* This objectClass conflicts with builtin classes on OpenLDAP */
488 const struct ldb_map_objectclass entryUUID_objectclasses[] =
491 .local_name = "subSchema",
492 .remote_name = "samba4SubSchema"
499 /* These things do not show up in wildcard searches in OpenLDAP, but
500 * we need them to show up in the AD-like view */
501 const char * const entryUUID_wildcard_attributes[] = {
510 const struct ldb_map_attribute nsuniqueid_attributes[] =
514 .local_name = "objectGUID",
518 .remote_name = "nsuniqueid",
519 .convert_local = guid_ns_string,
520 .convert_remote = encode_ns_guid,
526 .local_name = "objectSid",
530 .remote_name = "objectSid",
531 .convert_local = sid_always_binary,
532 .convert_remote = val_copy,
537 .local_name = "whenCreated",
541 .remote_name = "createTimestamp"
546 .local_name = "whenChanged",
550 .remote_name = "modifyTimestamp"
555 .local_name = "sambaPassword",
559 .remote_name = "userPassword"
565 .local_name = "allowedChildClassesEffective",
569 .remote_name = "allowedChildClassesEffective",
570 .convert_local = class_to_oid,
571 .convert_remote = class_from_oid,
577 .local_name = "objectCategory",
581 .remote_name = "objectCategory",
582 .convert_local = objectCategory_always_dn,
583 .convert_remote = val_copy,
588 .local_name = "distinguishedName",
592 .remote_name = "entryDN"
597 .local_name = "groupType",
601 .remote_name = "groupType",
602 .convert_local = normalise_to_signed32,
603 .convert_remote = val_copy,
608 .local_name = "sAMAccountType",
612 .remote_name = "sAMAccountType",
613 .convert_local = normalise_to_signed32,
614 .convert_remote = val_copy,
619 .local_name = "usnChanged",
623 .remote_name = "modifyTimestamp",
624 .convert_local = usn_to_timestamp,
625 .convert_remote = timestamp_to_usn,
630 .local_name = "usnCreated",
634 .remote_name = "createTimestamp",
635 .convert_local = usn_to_timestamp,
636 .convert_remote = timestamp_to_usn,
649 /* These things do not show up in wildcard searches in OpenLDAP, but
650 * we need them to show up in the AD-like view */
651 const char * const nsuniqueid_wildcard_attributes[] = {
660 static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
662 const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
663 struct ldb_dn *schema_dn;
664 struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
665 struct ldb_result *rootdse_res;
671 /* Search for rootdse */
672 ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res);
673 if (ldb_ret != LDB_SUCCESS) {
677 talloc_steal(mem_ctx, rootdse_res);
679 if (rootdse_res->count != 1) {
680 ldb_asprintf_errstring(ldb, "Failed to find rootDSE: count %d", rootdse_res->count);
685 schema_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
690 talloc_free(rootdse_res);
694 static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
696 struct ldb_result **objectclass_res)
698 TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
700 const char *attrs[] = {
707 return LDB_ERR_OPERATIONS_ERROR;
710 /* Downlaod schema */
711 ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE,
712 "objectClass=classSchema",
713 attrs, objectclass_res);
714 if (ret != LDB_SUCCESS) {
718 talloc_steal(mem_ctx, objectclass_res);
724 static int get_remote_rootdse(struct ldb_context *ldb, void *context,
725 struct ldb_reply *ares)
727 struct entryUUID_private *entryUUID_private;
728 entryUUID_private = talloc_get_type(context,
729 struct entryUUID_private);
730 if (ares->type == LDB_REPLY_ENTRY) {
732 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "namingContexts");
733 entryUUID_private->base_dns = talloc_realloc(entryUUID_private, entryUUID_private->base_dns, struct ldb_dn *,
735 for (i=0; i < el->num_values; i++) {
736 if (!entryUUID_private->base_dns) {
737 return LDB_ERR_OPERATIONS_ERROR;
739 entryUUID_private->base_dns[i] = ldb_dn_new(entryUUID_private->base_dns, ldb, (const char *)el->values[i].data);
740 if ( ! ldb_dn_validate(entryUUID_private->base_dns[i])) {
741 return LDB_ERR_OPERATIONS_ERROR;
744 entryUUID_private->base_dns[i] = NULL;
750 static int find_base_dns(struct ldb_module *module,
751 struct entryUUID_private *entryUUID_private)
754 struct ldb_request *req;
755 const char *naming_context_attr[] = {
759 req = talloc(entryUUID_private, struct ldb_request);
761 ldb_set_errstring(module->ldb, "Out of Memory");
762 return LDB_ERR_OPERATIONS_ERROR;
765 req->operation = LDB_SEARCH;
766 req->op.search.base = ldb_dn_new(req, module->ldb, NULL);
767 req->op.search.scope = LDB_SCOPE_BASE;
769 req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
770 if (req->op.search.tree == NULL) {
771 ldb_set_errstring(module->ldb, "Unable to parse search expression");
773 return LDB_ERR_OPERATIONS_ERROR;
776 req->op.search.attrs = naming_context_attr;
777 req->controls = NULL;
778 req->context = entryUUID_private;
779 req->callback = get_remote_rootdse;
780 ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
782 ret = ldb_next_request(module, req);
784 if (ret == LDB_SUCCESS) {
785 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
789 if (ret != LDB_SUCCESS) {
796 /* the context init function */
797 static int entryUUID_init(struct ldb_module *module)
800 struct map_private *map_private;
801 struct entryUUID_private *entryUUID_private;
802 struct ldb_dn *schema_dn;
804 ret = ldb_map_init(module, entryUUID_attributes, entryUUID_objectclasses, entryUUID_wildcard_attributes, NULL);
805 if (ret != LDB_SUCCESS)
808 map_private = talloc_get_type(module->private_data, struct map_private);
810 entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
811 map_private->caller_private = entryUUID_private;
813 schema_dn = find_schema_dn(module->ldb, map_private);
815 /* Perhaps no schema yet */
819 ret = fetch_objectclass_schema(module->ldb, schema_dn, entryUUID_private,
820 &entryUUID_private->objectclass_res);
821 if (ret != LDB_SUCCESS) {
822 /* Perhaps no schema yet */
826 ret = find_base_dns(module, entryUUID_private);
828 return ldb_next_init(module);
831 /* the context init function */
832 static int nsuniqueid_init(struct ldb_module *module)
835 struct map_private *map_private;
836 struct entryUUID_private *entryUUID_private;
837 struct ldb_dn *schema_dn;
839 ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, NULL);
840 if (ret != LDB_SUCCESS)
843 map_private = talloc_get_type(module->private_data, struct map_private);
845 entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
846 map_private->caller_private = entryUUID_private;
848 schema_dn = find_schema_dn(module->ldb, map_private);
850 /* Perhaps no schema yet */
854 ret = fetch_objectclass_schema(module->ldb, schema_dn, entryUUID_private,
855 &entryUUID_private->objectclass_res);
856 if (ret != LDB_SUCCESS) {
857 /* Perhaps no schema yet */
861 ret = find_base_dns(module, entryUUID_private);
863 return ldb_next_init(module);
866 static int get_seq(struct ldb_context *ldb, void *context,
867 struct ldb_reply *ares)
869 unsigned long long *max_seq = context;
870 unsigned long long seq;
871 if (ares->type == LDB_REPLY_ENTRY) {
872 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
874 seq = entryCSN_to_usn_int(ares, &el->values[0]);
875 *max_seq = MAX(seq, *max_seq);
882 static int entryUUID_sequence_number(struct ldb_module *module, struct ldb_request *req)
885 struct map_private *map_private;
886 struct entryUUID_private *entryUUID_private;
887 unsigned long long max_seq = 0;
888 struct ldb_request *search_req;
889 map_private = talloc_get_type(module->private_data, struct map_private);
891 entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
893 /* Search the baseDNs for a sequence number */
894 for (i=0; entryUUID_private &&
895 entryUUID_private->base_dns &&
896 entryUUID_private->base_dns[i];
898 static const char *contextCSN_attr[] = {
901 search_req = talloc(req, struct ldb_request);
902 if (search_req == NULL) {
903 ldb_set_errstring(module->ldb, "Out of Memory");
904 return LDB_ERR_OPERATIONS_ERROR;
907 search_req->operation = LDB_SEARCH;
908 search_req->op.search.base = entryUUID_private->base_dns[i];
909 search_req->op.search.scope = LDB_SCOPE_BASE;
911 search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
912 if (search_req->op.search.tree == NULL) {
913 ldb_set_errstring(module->ldb, "Unable to parse search expression");
914 talloc_free(search_req);
915 return LDB_ERR_OPERATIONS_ERROR;
918 search_req->op.search.attrs = contextCSN_attr;
919 search_req->controls = NULL;
920 search_req->context = &max_seq;
921 search_req->callback = get_seq;
922 ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
924 ret = ldb_next_request(module, search_req);
926 if (ret == LDB_SUCCESS) {
927 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
930 talloc_free(search_req);
931 if (ret != LDB_SUCCESS) {
936 switch (req->op.seq_num.type) {
937 case LDB_SEQ_HIGHEST_SEQ:
938 req->op.seq_num.seq_num = max_seq;
941 req->op.seq_num.seq_num = max_seq;
942 req->op.seq_num.seq_num++;
944 case LDB_SEQ_HIGHEST_TIMESTAMP:
946 req->op.seq_num.seq_num = (max_seq >> 24);
950 req->op.seq_num.flags = 0;
951 req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
952 req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
956 static struct ldb_module_ops entryUUID_ops = {
958 .init_context = entryUUID_init,
959 .sequence_number = entryUUID_sequence_number
962 static struct ldb_module_ops nsuniqueid_ops = {
963 .name = "nsuniqueid",
964 .init_context = nsuniqueid_init,
965 .sequence_number = entryUUID_sequence_number
968 /* the init function */
969 int ldb_entryUUID_module_init(void)
972 struct ldb_module_ops ops = ldb_map_get_ops();
973 entryUUID_ops.add = ops.add;
974 entryUUID_ops.modify = ops.modify;
975 entryUUID_ops.del = ops.del;
976 entryUUID_ops.rename = ops.rename;
977 entryUUID_ops.search = ops.search;
978 entryUUID_ops.wait = ops.wait;
979 ret = ldb_register_module(&entryUUID_ops);
985 nsuniqueid_ops.add = ops.add;
986 nsuniqueid_ops.modify = ops.modify;
987 nsuniqueid_ops.del = ops.del;
988 nsuniqueid_ops.rename = ops.rename;
989 nsuniqueid_ops.search = ops.search;
990 nsuniqueid_ops.wait = ops.wait;
991 ret = ldb_register_module(&nsuniqueid_ops);