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_module.h>
31 #include "ldb/ldb_map/ldb_map.h"
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "librpc/ndr/libndr.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "dsdb/common/util.h"
37 #include <ldb_handlers.h>
39 struct entryuuid_private {
40 struct ldb_context *ldb;
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_data_blob(val, &guid);
48 struct ldb_val out = data_blob(NULL, 0);
50 if (!NT_STATUS_IS_OK(status)) {
53 status = GUID_to_ndr_blob(&guid, ctx, &out);
54 if (!NT_STATUS_IS_OK(status)) {
55 return data_blob(NULL, 0);
61 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
63 struct ldb_val out = data_blob(NULL, 0);
65 NTSTATUS status = GUID_from_data_blob(val, &guid);
66 if (!NT_STATUS_IS_OK(status)) {
69 return data_blob_string_const(GUID_string(ctx, &guid));
72 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
75 NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
76 struct ldb_val out = data_blob(NULL, 0);
78 if (!NT_STATUS_IS_OK(status)) {
81 status = GUID_to_ndr_blob(&guid, ctx, &out);
82 if (!NT_STATUS_IS_OK(status)) {
83 return data_blob(NULL, 0);
89 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
91 struct ldb_val out = data_blob(NULL, 0);
93 NTSTATUS status = GUID_from_data_blob(val, &guid);
94 if (!NT_STATUS_IS_OK(status)) {
97 return data_blob_string_const(NS_GUID_string(ctx, &guid));
100 /* The backend holds binary sids, so just copy them back */
101 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
103 struct ldb_val out = data_blob(NULL, 0);
104 out = ldb_val_dup(ctx, val);
109 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
110 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
112 struct ldb_context *ldb = ldb_module_get_ctx(module);
113 struct ldb_val out = data_blob(NULL, 0);
114 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectSid");
116 if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
117 return data_blob(NULL, 0);
123 /* Ensure we always convert sids into string, so the backend doesn't have to know about both forms */
124 static struct ldb_val sid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
126 struct ldb_context *ldb = ldb_module_get_ctx(module);
127 struct ldb_val out = data_blob(NULL, 0);
129 if (ldif_comparision_objectSid_isString(val)) {
130 if (ldb_handler_copy(ldb, ctx, val, &out) != LDB_SUCCESS) {
131 return data_blob(NULL, 0);
135 if (ldif_write_objectSid(ldb, ctx, val, &out) != LDB_SUCCESS) {
136 return data_blob(NULL, 0);
142 /* Ensure we always convert objectCategory into a DN */
143 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
145 struct ldb_context *ldb = ldb_module_get_ctx(module);
147 struct ldb_val out = data_blob(NULL, 0);
148 const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectCategory");
150 dn = ldb_dn_from_ldb_val(ctx, ldb, val);
151 if (ldb_dn_validate(dn)) {
153 return val_copy(module, ctx, val);
157 if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
158 return data_blob(NULL, 0);
164 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
167 /* We've to use "strtoll" here to have the intended overflows.
168 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
169 int32_t i = (int32_t) strtoll((char *)val->data, NULL, 0);
170 out = data_blob_string_const(talloc_asprintf(ctx, "%d", i));
174 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
177 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
178 time_t t = (usn >> 24);
179 out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
183 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val)
185 char *entryCSN = talloc_strndup(ctx, (const char *)val->data, val->length);
188 unsigned long long usn;
193 p = strchr(entryCSN, '#');
208 usn = strtol(mod_per_sec, NULL, 16);
210 t = ldb_string_to_time(entryCSN);
212 usn = usn | ((unsigned long long)t <<24);
216 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
219 unsigned long long usn = entryCSN_to_usn_int(ctx, val);
220 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
224 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
227 unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
228 time_t t = (usn >> 24);
229 out = data_blob_string_const(ldb_timestring(ctx, t));
233 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
237 unsigned long long usn;
239 ldb_val_to_time(val, &t);
241 usn = ((unsigned long long)t <<24);
243 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
248 static const struct ldb_map_attribute entryuuid_attributes[] =
252 .local_name = "objectGUID",
253 .type = LDB_MAP_CONVERT,
256 .remote_name = "entryUUID",
257 .convert_local = guid_always_string,
258 .convert_remote = encode_guid,
264 .local_name = "invocationId",
265 .type = LDB_MAP_CONVERT,
268 .remote_name = "invocationId",
269 .convert_local = guid_always_string,
270 .convert_remote = encode_guid,
276 .local_name = "objectSid",
277 .type = LDB_MAP_CONVERT,
280 .remote_name = "objectSid",
281 .convert_local = sid_always_binary,
282 .convert_remote = val_copy,
286 /* securityIdentifier */
288 .local_name = "securityIdentifier",
289 .type = LDB_MAP_CONVERT,
292 .remote_name = "securityIdentifier",
293 .convert_local = sid_always_binary,
294 .convert_remote = val_copy,
299 .local_name = "name",
300 .type = LDB_MAP_RENAME,
303 .remote_name = "rdnValue"
308 .local_name = "whenCreated",
309 .type = LDB_MAP_RENAME,
312 .remote_name = "createTimestamp"
317 .local_name = "whenChanged",
318 .type = LDB_MAP_RENAME,
321 .remote_name = "modifyTimestamp"
326 .local_name = "objectClasses",
327 .type = LDB_MAP_RENAME,
330 .remote_name = "samba4ObjectClasses"
335 .local_name = "dITContentRules",
336 .type = LDB_MAP_RENAME,
339 .remote_name = "samba4DITContentRules"
344 .local_name = "attributeTypes",
345 .type = LDB_MAP_RENAME,
348 .remote_name = "samba4AttributeTypes"
353 .local_name = "objectCategory",
354 .type = LDB_MAP_CONVERT,
357 .remote_name = "objectCategory",
358 .convert_local = objectCategory_always_dn,
359 .convert_remote = val_copy,
364 .local_name = "distinguishedName",
365 .type = LDB_MAP_RENDROP,
368 .remote_name = "entryDN"
373 .local_name = "primaryGroupID",
374 .type = LDB_MAP_CONVERT,
377 .remote_name = "primaryGroupID",
378 .convert_local = normalise_to_signed32,
379 .convert_remote = val_copy,
384 .local_name = "groupType",
385 .type = LDB_MAP_CONVERT,
388 .remote_name = "groupType",
389 .convert_local = normalise_to_signed32,
390 .convert_remote = val_copy,
395 .local_name = "userAccountControl",
396 .type = LDB_MAP_CONVERT,
399 .remote_name = "userAccountControl",
400 .convert_local = normalise_to_signed32,
401 .convert_remote = val_copy,
406 .local_name = "sAMAccountType",
407 .type = LDB_MAP_CONVERT,
410 .remote_name = "sAMAccountType",
411 .convert_local = normalise_to_signed32,
412 .convert_remote = val_copy,
417 .local_name = "systemFlags",
418 .type = LDB_MAP_CONVERT,
421 .remote_name = "systemFlags",
422 .convert_local = normalise_to_signed32,
423 .convert_remote = val_copy,
428 .local_name = "usnChanged",
429 .type = LDB_MAP_CONVERT,
432 .remote_name = "entryCSN",
433 .convert_local = usn_to_entryCSN,
434 .convert_remote = entryCSN_to_usn
439 .local_name = "usnCreated",
440 .type = LDB_MAP_CONVERT,
443 .remote_name = "createTimestamp",
444 .convert_local = usn_to_timestamp,
445 .convert_remote = timestamp_to_usn,
451 .type = LDB_MAP_KEEP,
458 /* This objectClass conflicts with builtin classes on OpenLDAP */
459 const struct ldb_map_objectclass entryuuid_objectclasses[] =
462 .local_name = "subSchema",
463 .remote_name = "samba4SubSchema"
470 /* These things do not show up in wildcard searches in OpenLDAP, but
471 * we need them to show up in the AD-like view */
472 static const char * const entryuuid_wildcard_attributes[] = {
484 static const struct ldb_map_attribute nsuniqueid_attributes[] =
488 .local_name = "objectGUID",
489 .type = LDB_MAP_CONVERT,
492 .remote_name = "nsuniqueid",
493 .convert_local = guid_ns_string,
494 .convert_remote = encode_ns_guid,
500 .local_name = "objectSid",
501 .type = LDB_MAP_CONVERT,
504 .remote_name = "sambaSID",
505 .convert_local = sid_always_string,
506 .convert_remote = sid_always_binary,
510 /* securityIdentifier */
512 .local_name = "securityIdentifier",
513 .type = LDB_MAP_CONVERT,
516 .remote_name = "securityIdentifier",
517 .convert_local = sid_always_binary,
518 .convert_remote = val_copy,
523 .local_name = "whenCreated",
524 .type = LDB_MAP_RENAME,
527 .remote_name = "createTimestamp"
532 .local_name = "whenChanged",
533 .type = LDB_MAP_RENAME,
536 .remote_name = "modifyTimestamp"
541 .local_name = "objectCategory",
542 .type = LDB_MAP_CONVERT,
545 .remote_name = "objectCategory",
546 .convert_local = objectCategory_always_dn,
547 .convert_remote = val_copy,
552 .local_name = "distinguishedName",
553 .type = LDB_MAP_RENAME,
556 .remote_name = "entryDN"
561 .local_name = "primaryGroupID",
562 .type = LDB_MAP_CONVERT,
565 .remote_name = "primaryGroupID",
566 .convert_local = normalise_to_signed32,
567 .convert_remote = val_copy,
572 .local_name = "groupType",
573 .type = LDB_MAP_CONVERT,
576 .remote_name = "sambaGroupType",
577 .convert_local = normalise_to_signed32,
578 .convert_remote = val_copy,
583 .local_name = "userAccountControl",
584 .type = LDB_MAP_CONVERT,
587 .remote_name = "userAccountControl",
588 .convert_local = normalise_to_signed32,
589 .convert_remote = val_copy,
594 .local_name = "sAMAccountType",
595 .type = LDB_MAP_CONVERT,
598 .remote_name = "sAMAccountType",
599 .convert_local = normalise_to_signed32,
600 .convert_remote = val_copy,
605 .local_name = "systemFlags",
606 .type = LDB_MAP_CONVERT,
609 .remote_name = "systemFlags",
610 .convert_local = normalise_to_signed32,
611 .convert_remote = val_copy,
616 .local_name = "usnChanged",
617 .type = LDB_MAP_CONVERT,
620 .remote_name = "modifyTimestamp",
621 .convert_local = usn_to_timestamp,
622 .convert_remote = timestamp_to_usn,
627 .local_name = "usnCreated",
628 .type = LDB_MAP_CONVERT,
631 .remote_name = "createTimestamp",
632 .convert_local = usn_to_timestamp,
633 .convert_remote = timestamp_to_usn,
638 .local_name = "pwdLastSet",
639 .type = LDB_MAP_RENAME,
642 .remote_name = "sambaPwdLastSet"
647 .local_name = "lastLogon",
648 .type = LDB_MAP_RENAME,
651 .remote_name = "sambaLogonTime"
656 .local_name = "lastLogoff",
657 .type = LDB_MAP_RENAME,
660 .remote_name = "sambaLogoffTime"
665 .local_name = "badPwdCount",
666 .type = LDB_MAP_RENAME,
669 .remote_name = "sambaBadPasswordCount"
674 .local_name = "logonHours",
675 .type = LDB_MAP_RENAME,
678 .remote_name = "sambaLogonHours"
683 .local_name = "homeDrive",
684 .type = LDB_MAP_RENAME,
687 .remote_name = "sambaHomeDrive"
692 .local_name = "scriptPath",
693 .type = LDB_MAP_RENAME,
696 .remote_name = "sambaLogonScript"
701 .local_name = "profilePath",
702 .type = LDB_MAP_RENAME,
705 .remote_name = "sambaProfilePath"
710 .local_name = "userWorkstations",
711 .type = LDB_MAP_RENAME,
714 .remote_name = "sambaUserWorkstations"
719 .local_name = "homeDirectory",
720 .type = LDB_MAP_RENAME,
723 .remote_name = "sambaHomePath"
728 .local_name = "nextRid",
729 .type = LDB_MAP_RENAME,
732 .remote_name = "sambaNextRid"
737 .local_name = "privilegeDisplayName",
738 .type = LDB_MAP_RENAME,
741 .remote_name = "sambaPrivName"
747 .type = LDB_MAP_KEEP,
754 /* This objectClass conflicts with builtin classes on FDS */
755 const struct ldb_map_objectclass nsuniqueid_objectclasses[] =
762 /* These things do not show up in wildcard searches in OpenLDAP, but
763 * we need them to show up in the AD-like view */
764 static const char * const nsuniqueid_wildcard_attributes[] = {
773 /* the context init function */
774 static int entryuuid_init(struct ldb_module *module)
777 ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
778 if (ret != LDB_SUCCESS)
781 return ldb_next_init(module);
784 /* the context init function */
785 static int nsuniqueid_init(struct ldb_module *module)
788 ret = ldb_map_init(module, nsuniqueid_attributes, nsuniqueid_objectclasses, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
789 if (ret != LDB_SUCCESS)
792 return ldb_next_init(module);
795 static int get_seq_callback(struct ldb_request *req,
796 struct ldb_reply *ares)
798 unsigned long long *seq = (unsigned long long *)req->context;
801 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
803 if (ares->error != LDB_SUCCESS) {
804 return ldb_request_done(req, ares->error);
807 if (ares->type == LDB_REPLY_ENTRY) {
808 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
810 *seq = entryCSN_to_usn_int(ares, &el->values[0]);
814 if (ares->type == LDB_REPLY_DONE) {
815 return ldb_request_done(req, LDB_SUCCESS);
822 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
824 struct ldb_context *ldb;
826 struct map_private *map_private;
827 unsigned long long seq_num = 0;
828 struct ldb_request *search_req;
830 const struct ldb_control *partition_ctrl;
831 const struct dsdb_control_current_partition *partition;
833 static const char *contextCSN_attr[] = {
837 struct ldb_seqnum_request *seq;
838 struct ldb_seqnum_result *seqr;
839 struct ldb_extended *ext;
841 ldb = ldb_module_get_ctx(module);
843 seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
845 map_private = talloc_get_type(ldb_module_get_private(module), struct map_private);
847 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
848 "private data is not of type struct map_private");
849 return LDB_ERR_PROTOCOL_ERROR;
852 /* All this to get the DN of the parition, so we can search the right thing */
853 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
854 if (!partition_ctrl) {
855 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
856 "entryuuid_sequence_number: no current partition control found!");
857 return LDB_ERR_PROTOCOL_ERROR;
860 partition = talloc_get_type(partition_ctrl->data,
861 struct dsdb_control_current_partition);
862 if ((partition == NULL) || (partition->version != DSDB_CONTROL_CURRENT_PARTITION_VERSION)) {
863 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
864 "entryuuid_sequence_number: current partition control with wrong data!");
865 return LDB_ERR_PROTOCOL_ERROR;
868 ret = ldb_build_search_req(&search_req, ldb, req,
869 partition->dn, LDB_SCOPE_BASE,
870 NULL, contextCSN_attr, NULL,
871 &seq_num, get_seq_callback,
873 LDB_REQ_SET_LOCATION(search_req);
874 if (ret != LDB_SUCCESS) {
878 ret = ldb_next_request(module, search_req);
880 if (ret == LDB_SUCCESS) {
881 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
884 talloc_free(search_req);
885 if (ret != LDB_SUCCESS) {
889 ext = talloc_zero(req, struct ldb_extended);
893 seqr = talloc_zero(req, struct ldb_seqnum_result);
898 ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
902 case LDB_SEQ_HIGHEST_SEQ:
903 seqr->seq_num = seq_num;
906 seqr->seq_num = seq_num;
909 case LDB_SEQ_HIGHEST_TIMESTAMP:
910 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, "LDB_SEQ_HIGHEST_TIMESTAMP not supported");
914 seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
916 /* send request done */
917 return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
920 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
922 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
923 return entryuuid_sequence_number(module, req);
926 return ldb_next_request(module, req);
929 static const struct ldb_module_ops ldb_entryuuid_module_ops = {
931 .init_context = entryuuid_init,
932 .extended = entryuuid_extended,
936 static const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
937 .name = "nsuniqueid",
938 .init_context = nsuniqueid_init,
939 .extended = entryuuid_extended,
944 initialise the module
946 _PUBLIC_ int ldb_simple_ldap_map_module_init(const char *version)
949 LDB_MODULE_CHECK_VERSION(version);
950 ret = ldb_register_module(&ldb_entryuuid_module_ops);
951 if (ret != LDB_SUCCESS) {
954 ret = ldb_register_module(&ldb_nsuniqueid_module_ops);
955 if (ret != LDB_SUCCESS) {