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_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 "../../../lib/ldb/include/ldb_handlers.h"
38 struct entryuuid_private
{
39 struct ldb_context
*ldb
;
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_data_blob(val
, &guid
);
47 struct ldb_val out
= data_blob(NULL
, 0);
49 if (!NT_STATUS_IS_OK(status
)) {
52 status
= GUID_to_ndr_blob(&guid
, ctx
, &out
);
53 if (!NT_STATUS_IS_OK(status
)) {
54 return data_blob(NULL
, 0);
60 static struct ldb_val
guid_always_string(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
62 struct ldb_val out
= data_blob(NULL
, 0);
64 NTSTATUS status
= GUID_from_data_blob(val
, &guid
);
65 if (!NT_STATUS_IS_OK(status
)) {
68 return data_blob_string_const(GUID_string(ctx
, &guid
));
71 static struct ldb_val
encode_ns_guid(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
74 NTSTATUS status
= NS_GUID_from_string((char *)val
->data
, &guid
);
75 struct ldb_val out
= data_blob(NULL
, 0);
77 if (!NT_STATUS_IS_OK(status
)) {
80 status
= GUID_to_ndr_blob(&guid
, ctx
, &out
);
81 if (!NT_STATUS_IS_OK(status
)) {
82 return data_blob(NULL
, 0);
88 static struct ldb_val
guid_ns_string(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
90 struct ldb_val out
= data_blob(NULL
, 0);
92 NTSTATUS status
= GUID_from_data_blob(val
, &guid
);
93 if (!NT_STATUS_IS_OK(status
)) {
96 return data_blob_string_const(NS_GUID_string(ctx
, &guid
));
99 /* The backend holds binary sids, so just copy them back */
100 static struct ldb_val
val_copy(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
102 struct ldb_val out
= data_blob(NULL
, 0);
103 out
= ldb_val_dup(ctx
, val
);
108 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
109 static struct ldb_val
sid_always_binary(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
111 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
112 struct ldb_val out
= data_blob(NULL
, 0);
113 const struct ldb_schema_attribute
*a
= ldb_schema_attribute_by_name(ldb
, "objectSid");
115 if (a
->syntax
->canonicalise_fn(ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
116 return data_blob(NULL
, 0);
122 /* Ensure we always convert sids into string, so the backend doesn't have to know about both forms */
123 static struct ldb_val
sid_always_string(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
125 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
126 struct ldb_val out
= data_blob(NULL
, 0);
128 if (ldif_comparision_objectSid_isString(val
)) {
129 if (ldb_handler_copy(ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
130 return data_blob(NULL
, 0);
134 if (ldif_write_objectSid(ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
135 return data_blob(NULL
, 0);
141 /* Ensure we always convert objectCategory into a DN */
142 static struct ldb_val
objectCategory_always_dn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
144 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
146 struct ldb_val out
= data_blob(NULL
, 0);
147 const struct ldb_schema_attribute
*a
= ldb_schema_attribute_by_name(ldb
, "objectCategory");
149 dn
= ldb_dn_from_ldb_val(ctx
, ldb
, val
);
150 if (dn
&& ldb_dn_validate(dn
)) {
152 return val_copy(module
, ctx
, val
);
156 if (a
->syntax
->canonicalise_fn(ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
157 return data_blob(NULL
, 0);
163 static struct ldb_val
normalise_to_signed32(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
166 /* We've to use "strtoll" here to have the intended overflows.
167 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
168 int32_t i
= (int32_t) strtoll((char *)val
->data
, NULL
, 0);
169 out
= data_blob_string_const(talloc_asprintf(ctx
, "%d", i
));
173 static struct ldb_val
usn_to_entryCSN(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
176 unsigned long long usn
= strtoull((const char *)val
->data
, NULL
, 10);
177 time_t t
= (usn
>> 24);
178 out
= data_blob_string_const(talloc_asprintf(ctx
, "%s#%06x#00#000000", ldb_timestring(ctx
, t
), (unsigned int)(usn
& 0xFFFFFF)));
182 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
184 char *entryCSN
= talloc_strndup(ctx
, (const char *)val
->data
, val
->length
);
187 unsigned long long usn
;
192 p
= strchr(entryCSN
, '#');
207 usn
= strtol(mod_per_sec
, NULL
, 16);
209 t
= ldb_string_to_time(entryCSN
);
211 usn
= usn
| ((unsigned long long)t
<<24);
215 static struct ldb_val
entryCSN_to_usn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
218 unsigned long long usn
= entryCSN_to_usn_int(ctx
, val
);
219 out
= data_blob_string_const(talloc_asprintf(ctx
, "%lld", usn
));
223 static struct ldb_val
usn_to_timestamp(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
226 unsigned long long usn
= strtoull((const char *)val
->data
, NULL
, 10);
227 time_t t
= (usn
>> 24);
228 out
= data_blob_string_const(ldb_timestring(ctx
, t
));
232 static struct ldb_val
timestamp_to_usn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
236 unsigned long long usn
;
238 ldb_val_to_time(val
, &t
);
240 usn
= ((unsigned long long)t
<<24);
242 out
= data_blob_string_const(talloc_asprintf(ctx
, "%lld", usn
));
247 static const struct ldb_map_attribute entryuuid_attributes
[] =
251 .local_name
= "objectGUID",
252 .type
= LDB_MAP_CONVERT
,
255 .remote_name
= "entryUUID",
256 .convert_local
= guid_always_string
,
257 .convert_remote
= encode_guid
,
263 .local_name
= "invocationId",
264 .type
= LDB_MAP_CONVERT
,
267 .remote_name
= "invocationId",
268 .convert_local
= guid_always_string
,
269 .convert_remote
= encode_guid
,
275 .local_name
= "objectSid",
276 .type
= LDB_MAP_CONVERT
,
279 .remote_name
= "objectSid",
280 .convert_local
= sid_always_binary
,
281 .convert_remote
= val_copy
,
286 .local_name
= "name",
287 .type
= LDB_MAP_RENAME
,
290 .remote_name
= "samba4RDN"
295 .local_name
= "whenCreated",
296 .type
= LDB_MAP_RENAME
,
299 .remote_name
= "createTimestamp"
304 .local_name
= "whenChanged",
305 .type
= LDB_MAP_RENAME
,
308 .remote_name
= "modifyTimestamp"
313 .local_name
= "objectClasses",
314 .type
= LDB_MAP_RENAME
,
317 .remote_name
= "samba4ObjectClasses"
322 .local_name
= "dITContentRules",
323 .type
= LDB_MAP_RENAME
,
326 .remote_name
= "samba4DITContentRules"
331 .local_name
= "attributeTypes",
332 .type
= LDB_MAP_RENAME
,
335 .remote_name
= "samba4AttributeTypes"
340 .local_name
= "objectCategory",
341 .type
= LDB_MAP_CONVERT
,
344 .remote_name
= "objectCategory",
345 .convert_local
= objectCategory_always_dn
,
346 .convert_remote
= val_copy
,
351 .local_name
= "distinguishedName",
352 .type
= LDB_MAP_RENAME
,
355 .remote_name
= "entryDN"
360 .local_name
= "primaryGroupID",
361 .type
= LDB_MAP_CONVERT
,
364 .remote_name
= "primaryGroupID",
365 .convert_local
= normalise_to_signed32
,
366 .convert_remote
= val_copy
,
371 .local_name
= "groupType",
372 .type
= LDB_MAP_CONVERT
,
375 .remote_name
= "groupType",
376 .convert_local
= normalise_to_signed32
,
377 .convert_remote
= val_copy
,
382 .local_name
= "userAccountControl",
383 .type
= LDB_MAP_CONVERT
,
386 .remote_name
= "userAccountControl",
387 .convert_local
= normalise_to_signed32
,
388 .convert_remote
= val_copy
,
393 .local_name
= "sAMAccountType",
394 .type
= LDB_MAP_CONVERT
,
397 .remote_name
= "sAMAccountType",
398 .convert_local
= normalise_to_signed32
,
399 .convert_remote
= val_copy
,
404 .local_name
= "systemFlags",
405 .type
= LDB_MAP_CONVERT
,
408 .remote_name
= "systemFlags",
409 .convert_local
= normalise_to_signed32
,
410 .convert_remote
= val_copy
,
415 .local_name
= "usnChanged",
416 .type
= LDB_MAP_CONVERT
,
419 .remote_name
= "entryCSN",
420 .convert_local
= usn_to_entryCSN
,
421 .convert_remote
= entryCSN_to_usn
426 .local_name
= "usnCreated",
427 .type
= LDB_MAP_CONVERT
,
430 .remote_name
= "createTimestamp",
431 .convert_local
= usn_to_timestamp
,
432 .convert_remote
= timestamp_to_usn
,
438 .type
= LDB_MAP_KEEP
,
445 /* This objectClass conflicts with builtin classes on OpenLDAP */
446 const struct ldb_map_objectclass entryuuid_objectclasses
[] =
449 .local_name
= "subSchema",
450 .remote_name
= "samba4SubSchema"
457 /* These things do not show up in wildcard searches in OpenLDAP, but
458 * we need them to show up in the AD-like view */
459 static const char * const entryuuid_wildcard_attributes
[] = {
469 static const struct ldb_map_attribute nsuniqueid_attributes
[] =
473 .local_name
= "objectGUID",
474 .type
= LDB_MAP_CONVERT
,
477 .remote_name
= "nsuniqueid",
478 .convert_local
= guid_ns_string
,
479 .convert_remote
= encode_ns_guid
,
485 .local_name
= "objectSid",
486 .type
= LDB_MAP_CONVERT
,
489 .remote_name
= "sambaSID",
490 .convert_local
= sid_always_string
,
491 .convert_remote
= sid_always_binary
,
496 .local_name
= "whenCreated",
497 .type
= LDB_MAP_RENAME
,
500 .remote_name
= "createTimestamp"
505 .local_name
= "whenChanged",
506 .type
= LDB_MAP_RENAME
,
509 .remote_name
= "modifyTimestamp"
514 .local_name
= "objectCategory",
515 .type
= LDB_MAP_CONVERT
,
518 .remote_name
= "objectCategory",
519 .convert_local
= objectCategory_always_dn
,
520 .convert_remote
= val_copy
,
525 .local_name
= "distinguishedName",
526 .type
= LDB_MAP_RENAME
,
529 .remote_name
= "entryDN"
534 .local_name
= "primaryGroupID",
535 .type
= LDB_MAP_CONVERT
,
538 .remote_name
= "primaryGroupID",
539 .convert_local
= normalise_to_signed32
,
540 .convert_remote
= val_copy
,
545 .local_name
= "groupType",
546 .type
= LDB_MAP_CONVERT
,
549 .remote_name
= "sambaGroupType",
550 .convert_local
= normalise_to_signed32
,
551 .convert_remote
= val_copy
,
556 .local_name
= "userAccountControl",
557 .type
= LDB_MAP_CONVERT
,
560 .remote_name
= "userAccountControl",
561 .convert_local
= normalise_to_signed32
,
562 .convert_remote
= val_copy
,
567 .local_name
= "sAMAccountType",
568 .type
= LDB_MAP_CONVERT
,
571 .remote_name
= "sAMAccountType",
572 .convert_local
= normalise_to_signed32
,
573 .convert_remote
= val_copy
,
578 .local_name
= "systemFlags",
579 .type
= LDB_MAP_CONVERT
,
582 .remote_name
= "systemFlags",
583 .convert_local
= normalise_to_signed32
,
584 .convert_remote
= val_copy
,
589 .local_name
= "usnChanged",
590 .type
= LDB_MAP_CONVERT
,
593 .remote_name
= "modifyTimestamp",
594 .convert_local
= usn_to_timestamp
,
595 .convert_remote
= timestamp_to_usn
,
600 .local_name
= "usnCreated",
601 .type
= LDB_MAP_CONVERT
,
604 .remote_name
= "createTimestamp",
605 .convert_local
= usn_to_timestamp
,
606 .convert_remote
= timestamp_to_usn
,
611 .local_name
= "pwdLastSet",
612 .type
= LDB_MAP_RENAME
,
615 .remote_name
= "sambaPwdLastSet"
620 .local_name
= "lastLogon",
621 .type
= LDB_MAP_RENAME
,
624 .remote_name
= "sambaLogonTime"
629 .local_name
= "lastLogoff",
630 .type
= LDB_MAP_RENAME
,
633 .remote_name
= "sambaLogoffTime"
638 .local_name
= "badPwdCount",
639 .type
= LDB_MAP_RENAME
,
642 .remote_name
= "sambaBadPasswordCount"
647 .local_name
= "logonHours",
648 .type
= LDB_MAP_RENAME
,
651 .remote_name
= "sambaLogonHours"
656 .local_name
= "homeDrive",
657 .type
= LDB_MAP_RENAME
,
660 .remote_name
= "sambaHomeDrive"
665 .local_name
= "scriptPath",
666 .type
= LDB_MAP_RENAME
,
669 .remote_name
= "sambaLogonScript"
674 .local_name
= "profilePath",
675 .type
= LDB_MAP_RENAME
,
678 .remote_name
= "sambaProfilePath"
683 .local_name
= "userWorkstations",
684 .type
= LDB_MAP_RENAME
,
687 .remote_name
= "sambaUserWorkstations"
692 .local_name
= "homeDirectory",
693 .type
= LDB_MAP_RENAME
,
696 .remote_name
= "sambaHomePath"
701 .local_name
= "nextRid",
702 .type
= LDB_MAP_RENAME
,
705 .remote_name
= "sambaNextRid"
710 .local_name
= "privilegeDisplayName",
711 .type
= LDB_MAP_RENAME
,
714 .remote_name
= "sambaPrivName"
720 .type
= LDB_MAP_KEEP
,
727 /* This objectClass conflicts with builtin classes on FDS */
728 const struct ldb_map_objectclass nsuniqueid_objectclasses
[] =
735 /* These things do not show up in wildcard searches in OpenLDAP, but
736 * we need them to show up in the AD-like view */
737 static const char * const nsuniqueid_wildcard_attributes
[] = {
746 /* the context init function */
747 static int entryuuid_init(struct ldb_module
*module
)
750 ret
= ldb_map_init(module
, entryuuid_attributes
, entryuuid_objectclasses
, entryuuid_wildcard_attributes
, "samba4Top", NULL
);
751 if (ret
!= LDB_SUCCESS
)
754 return ldb_next_init(module
);
757 /* the context init function */
758 static int nsuniqueid_init(struct ldb_module
*module
)
761 ret
= ldb_map_init(module
, nsuniqueid_attributes
, nsuniqueid_objectclasses
, nsuniqueid_wildcard_attributes
, "extensibleObject", NULL
);
762 if (ret
!= LDB_SUCCESS
)
765 return ldb_next_init(module
);
768 static int get_seq_callback(struct ldb_request
*req
,
769 struct ldb_reply
*ares
)
771 unsigned long long *seq
= (unsigned long long *)req
->context
;
774 return ldb_request_done(req
, LDB_ERR_OPERATIONS_ERROR
);
776 if (ares
->error
!= LDB_SUCCESS
) {
777 return ldb_request_done(req
, ares
->error
);
780 if (ares
->type
== LDB_REPLY_ENTRY
) {
781 struct ldb_message_element
*el
= ldb_msg_find_element(ares
->message
, "contextCSN");
783 *seq
= entryCSN_to_usn_int(ares
, &el
->values
[0]);
787 if (ares
->type
== LDB_REPLY_DONE
) {
788 return ldb_request_done(req
, LDB_SUCCESS
);
795 static int entryuuid_sequence_number(struct ldb_module
*module
, struct ldb_request
*req
)
797 struct ldb_context
*ldb
;
799 struct map_private
*map_private
;
800 struct entryuuid_private
*entryuuid_private
;
801 unsigned long long seq_num
= 0;
802 struct ldb_request
*search_req
;
804 const struct ldb_control
*partition_ctrl
;
805 const struct dsdb_control_current_partition
*partition
;
807 static const char *contextCSN_attr
[] = {
811 struct ldb_seqnum_request
*seq
;
812 struct ldb_seqnum_result
*seqr
;
813 struct ldb_extended
*ext
;
815 ldb
= ldb_module_get_ctx(module
);
817 seq
= talloc_get_type(req
->op
.extended
.data
, struct ldb_seqnum_request
);
819 map_private
= talloc_get_type(ldb_module_get_private(module
), struct map_private
);
821 entryuuid_private
= talloc_get_type(map_private
->caller_private
, struct entryuuid_private
);
823 /* All this to get the DN of the parition, so we can search the right thing */
824 partition_ctrl
= ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
);
825 if (!partition_ctrl
) {
826 ldb_debug_set(ldb
, LDB_DEBUG_FATAL
,
827 "entryuuid_sequence_number: no current partition control found");
828 return LDB_ERR_CONSTRAINT_VIOLATION
;
831 partition
= talloc_get_type(partition_ctrl
->data
,
832 struct dsdb_control_current_partition
);
833 SMB_ASSERT(partition
&& partition
->version
== DSDB_CONTROL_CURRENT_PARTITION_VERSION
);
835 ret
= ldb_build_search_req(&search_req
, ldb
, req
,
836 partition
->dn
, LDB_SCOPE_BASE
,
837 NULL
, contextCSN_attr
, NULL
,
838 &seq_num
, get_seq_callback
,
840 if (ret
!= LDB_SUCCESS
) {
844 ret
= ldb_next_request(module
, search_req
);
846 if (ret
== LDB_SUCCESS
) {
847 ret
= ldb_wait(search_req
->handle
, LDB_WAIT_ALL
);
850 talloc_free(search_req
);
851 if (ret
!= LDB_SUCCESS
) {
855 ext
= talloc_zero(req
, struct ldb_extended
);
857 return LDB_ERR_OPERATIONS_ERROR
;
859 seqr
= talloc_zero(req
, struct ldb_seqnum_result
);
862 return LDB_ERR_OPERATIONS_ERROR
;
864 ext
->oid
= LDB_EXTENDED_SEQUENCE_NUMBER
;
868 case LDB_SEQ_HIGHEST_SEQ
:
869 seqr
->seq_num
= seq_num
;
872 seqr
->seq_num
= seq_num
;
875 case LDB_SEQ_HIGHEST_TIMESTAMP
:
877 seqr
->seq_num
= (seq_num
>> 24);
882 seqr
->flags
|= LDB_SEQ_TIMESTAMP_SEQUENCE
;
883 seqr
->flags
|= LDB_SEQ_GLOBAL_SEQUENCE
;
885 /* send request done */
886 return ldb_module_done(req
, NULL
, ext
, LDB_SUCCESS
);
889 static int entryuuid_extended(struct ldb_module
*module
, struct ldb_request
*req
)
891 if (strcmp(req
->op
.extended
.oid
, LDB_EXTENDED_SEQUENCE_NUMBER
) == 0) {
892 return entryuuid_sequence_number(module
, req
);
895 return ldb_next_request(module
, req
);
898 _PUBLIC_
const struct ldb_module_ops ldb_entryuuid_module_ops
= {
900 .init_context
= entryuuid_init
,
901 .extended
= entryuuid_extended
,
905 _PUBLIC_
const struct ldb_module_ops ldb_nsuniqueid_module_ops
= {
906 .name
= "nsuniqueid",
907 .init_context
= nsuniqueid_init
,
908 .extended
= entryuuid_extended
,