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_RENAME,
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[] = {
482 static const struct ldb_map_attribute nsuniqueid_attributes[] =
486 .local_name = "objectGUID",
487 .type = LDB_MAP_CONVERT,
490 .remote_name = "nsuniqueid",
491 .convert_local = guid_ns_string,
492 .convert_remote = encode_ns_guid,
498 .local_name = "objectSid",
499 .type = LDB_MAP_CONVERT,
502 .remote_name = "sambaSID",
503 .convert_local = sid_always_string,
504 .convert_remote = sid_always_binary,
508 /* securityIdentifier */
510 .local_name = "securityIdentifier",
511 .type = LDB_MAP_CONVERT,
514 .remote_name = "securityIdentifier",
515 .convert_local = sid_always_binary,
516 .convert_remote = val_copy,
521 .local_name = "whenCreated",
522 .type = LDB_MAP_RENAME,
525 .remote_name = "createTimestamp"
530 .local_name = "whenChanged",
531 .type = LDB_MAP_RENAME,
534 .remote_name = "modifyTimestamp"
539 .local_name = "objectCategory",
540 .type = LDB_MAP_CONVERT,
543 .remote_name = "objectCategory",
544 .convert_local = objectCategory_always_dn,
545 .convert_remote = val_copy,
550 .local_name = "distinguishedName",
551 .type = LDB_MAP_RENAME,
554 .remote_name = "entryDN"
559 .local_name = "primaryGroupID",
560 .type = LDB_MAP_CONVERT,
563 .remote_name = "primaryGroupID",
564 .convert_local = normalise_to_signed32,
565 .convert_remote = val_copy,
570 .local_name = "groupType",
571 .type = LDB_MAP_CONVERT,
574 .remote_name = "sambaGroupType",
575 .convert_local = normalise_to_signed32,
576 .convert_remote = val_copy,
581 .local_name = "userAccountControl",
582 .type = LDB_MAP_CONVERT,
585 .remote_name = "userAccountControl",
586 .convert_local = normalise_to_signed32,
587 .convert_remote = val_copy,
592 .local_name = "sAMAccountType",
593 .type = LDB_MAP_CONVERT,
596 .remote_name = "sAMAccountType",
597 .convert_local = normalise_to_signed32,
598 .convert_remote = val_copy,
603 .local_name = "systemFlags",
604 .type = LDB_MAP_CONVERT,
607 .remote_name = "systemFlags",
608 .convert_local = normalise_to_signed32,
609 .convert_remote = val_copy,
614 .local_name = "usnChanged",
615 .type = LDB_MAP_CONVERT,
618 .remote_name = "modifyTimestamp",
619 .convert_local = usn_to_timestamp,
620 .convert_remote = timestamp_to_usn,
625 .local_name = "usnCreated",
626 .type = LDB_MAP_CONVERT,
629 .remote_name = "createTimestamp",
630 .convert_local = usn_to_timestamp,
631 .convert_remote = timestamp_to_usn,
636 .local_name = "pwdLastSet",
637 .type = LDB_MAP_RENAME,
640 .remote_name = "sambaPwdLastSet"
645 .local_name = "lastLogon",
646 .type = LDB_MAP_RENAME,
649 .remote_name = "sambaLogonTime"
654 .local_name = "lastLogoff",
655 .type = LDB_MAP_RENAME,
658 .remote_name = "sambaLogoffTime"
663 .local_name = "badPwdCount",
664 .type = LDB_MAP_RENAME,
667 .remote_name = "sambaBadPasswordCount"
672 .local_name = "logonHours",
673 .type = LDB_MAP_RENAME,
676 .remote_name = "sambaLogonHours"
681 .local_name = "homeDrive",
682 .type = LDB_MAP_RENAME,
685 .remote_name = "sambaHomeDrive"
690 .local_name = "scriptPath",
691 .type = LDB_MAP_RENAME,
694 .remote_name = "sambaLogonScript"
699 .local_name = "profilePath",
700 .type = LDB_MAP_RENAME,
703 .remote_name = "sambaProfilePath"
708 .local_name = "userWorkstations",
709 .type = LDB_MAP_RENAME,
712 .remote_name = "sambaUserWorkstations"
717 .local_name = "homeDirectory",
718 .type = LDB_MAP_RENAME,
721 .remote_name = "sambaHomePath"
726 .local_name = "nextRid",
727 .type = LDB_MAP_RENAME,
730 .remote_name = "sambaNextRid"
735 .local_name = "privilegeDisplayName",
736 .type = LDB_MAP_RENAME,
739 .remote_name = "sambaPrivName"
745 .type = LDB_MAP_KEEP,
752 /* This objectClass conflicts with builtin classes on FDS */
753 const struct ldb_map_objectclass nsuniqueid_objectclasses[] =
760 /* These things do not show up in wildcard searches in OpenLDAP, but
761 * we need them to show up in the AD-like view */
762 static const char * const nsuniqueid_wildcard_attributes[] = {
771 /* the context init function */
772 static int entryuuid_init(struct ldb_module *module)
775 ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
776 if (ret != LDB_SUCCESS)
779 return ldb_next_init(module);
782 /* the context init function */
783 static int nsuniqueid_init(struct ldb_module *module)
786 ret = ldb_map_init(module, nsuniqueid_attributes, nsuniqueid_objectclasses, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
787 if (ret != LDB_SUCCESS)
790 return ldb_next_init(module);
793 static int get_seq_callback(struct ldb_request *req,
794 struct ldb_reply *ares)
796 unsigned long long *seq = (unsigned long long *)req->context;
799 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
801 if (ares->error != LDB_SUCCESS) {
802 return ldb_request_done(req, ares->error);
805 if (ares->type == LDB_REPLY_ENTRY) {
806 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
808 *seq = entryCSN_to_usn_int(ares, &el->values[0]);
812 if (ares->type == LDB_REPLY_DONE) {
813 return ldb_request_done(req, LDB_SUCCESS);
820 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
822 struct ldb_context *ldb;
824 struct map_private *map_private;
825 unsigned long long seq_num = 0;
826 struct ldb_request *search_req;
828 const struct ldb_control *partition_ctrl;
829 const struct dsdb_control_current_partition *partition;
831 static const char *contextCSN_attr[] = {
835 struct ldb_seqnum_request *seq;
836 struct ldb_seqnum_result *seqr;
837 struct ldb_extended *ext;
839 ldb = ldb_module_get_ctx(module);
841 seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
843 map_private = talloc_get_type(ldb_module_get_private(module), struct map_private);
845 /* All this to get the DN of the parition, so we can search the right thing */
846 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
847 if (!partition_ctrl) {
848 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
849 "entryuuid_sequence_number: no current partition control found!");
850 return LDB_ERR_PROTOCOL_ERROR;
853 partition = talloc_get_type(partition_ctrl->data,
854 struct dsdb_control_current_partition);
855 if ((partition == NULL) || (partition->version != DSDB_CONTROL_CURRENT_PARTITION_VERSION)) {
856 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
857 "entryuuid_sequence_number: current partition control with wrong data!");
858 return LDB_ERR_PROTOCOL_ERROR;
861 ret = ldb_build_search_req(&search_req, ldb, req,
862 partition->dn, LDB_SCOPE_BASE,
863 NULL, contextCSN_attr, NULL,
864 &seq_num, get_seq_callback,
866 LDB_REQ_SET_LOCATION(search_req);
867 if (ret != LDB_SUCCESS) {
871 ret = ldb_next_request(module, search_req);
873 if (ret == LDB_SUCCESS) {
874 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
877 talloc_free(search_req);
878 if (ret != LDB_SUCCESS) {
882 ext = talloc_zero(req, struct ldb_extended);
886 seqr = talloc_zero(req, struct ldb_seqnum_result);
891 ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
895 case LDB_SEQ_HIGHEST_SEQ:
896 seqr->seq_num = seq_num;
899 seqr->seq_num = seq_num;
902 case LDB_SEQ_HIGHEST_TIMESTAMP:
903 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, "LDB_SEQ_HIGHEST_TIMESTAMP not supported");
907 seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
909 /* send request done */
910 return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
913 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
915 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
916 return entryuuid_sequence_number(module, req);
919 return ldb_next_request(module, req);
922 static const struct ldb_module_ops ldb_entryuuid_module_ops = {
924 .init_context = entryuuid_init,
925 .extended = entryuuid_extended,
929 static const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
930 .name = "nsuniqueid",
931 .init_context = nsuniqueid_init,
932 .extended = entryuuid_extended,
937 initialise the module
939 _PUBLIC_ int ldb_simple_ldap_map_module_init(const char *version)
942 LDB_MODULE_CHECK_VERSION(version);
943 ret = ldb_register_module(&ldb_entryuuid_module_ops);
944 if (ret != LDB_SUCCESS) {
947 ret = ldb_register_module(&ldb_nsuniqueid_module_ops);
948 if (ret != LDB_SUCCESS) {