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"
37 #include "dsdb/samdb/samdb.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_string((char *)val
->data
, &guid
);
48 enum ndr_err_code ndr_err
;
49 struct ldb_val out
= data_blob(NULL
, 0);
51 if (!NT_STATUS_IS_OK(status
)) {
54 ndr_err
= ndr_push_struct_blob(&out
, ctx
, NULL
, &guid
,
55 (ndr_push_flags_fn_t
)ndr_push_GUID
);
56 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
63 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 enum ndr_err_code ndr_err
;
72 guid
= talloc(ctx
, struct GUID
);
76 ndr_err
= ndr_pull_struct_blob(val
, guid
, NULL
, guid
,
77 (ndr_pull_flags_fn_t
)ndr_pull_GUID
);
78 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
82 out
= data_blob_string_const(GUID_string(ctx
, guid
));
88 static struct ldb_val
encode_ns_guid(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
91 NTSTATUS status
= NS_GUID_from_string((char *)val
->data
, &guid
);
92 enum ndr_err_code ndr_err
;
93 struct ldb_val out
= data_blob(NULL
, 0);
95 if (!NT_STATUS_IS_OK(status
)) {
98 ndr_err
= ndr_push_struct_blob(&out
, ctx
, NULL
, &guid
,
99 (ndr_push_flags_fn_t
)ndr_push_GUID
);
100 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
107 static struct ldb_val
guid_ns_string(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
109 struct ldb_val out
= data_blob(NULL
, 0);
110 if (val
->length
>= 32 && val
->data
[val
->length
] == '\0') {
112 GUID_from_string((char *)val
->data
, &guid
);
113 out
= data_blob_string_const(NS_GUID_string(ctx
, &guid
));
115 enum ndr_err_code ndr_err
;
117 guid_p
= talloc(ctx
, struct GUID
);
118 if (guid_p
== NULL
) {
121 ndr_err
= ndr_pull_struct_blob(val
, guid_p
, NULL
, guid_p
,
122 (ndr_pull_flags_fn_t
)ndr_pull_GUID
);
123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
127 out
= data_blob_string_const(NS_GUID_string(ctx
, guid_p
));
133 /* The backend holds binary sids, so just copy them back */
134 static struct ldb_val
val_copy(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
136 struct ldb_val out
= data_blob(NULL
, 0);
137 ldb_handler_copy(module
->ldb
, ctx
, val
, &out
);
142 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
143 static struct ldb_val
sid_always_binary(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
145 struct ldb_val out
= data_blob(NULL
, 0);
146 const struct ldb_schema_attribute
*a
= ldb_schema_attribute_by_name(module
->ldb
, "objectSid");
148 if (a
->syntax
->canonicalise_fn(module
->ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
149 return data_blob(NULL
, 0);
155 /* Ensure we always convert objectCategory into a DN */
156 static struct ldb_val
objectCategory_always_dn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
159 struct ldb_val out
= data_blob(NULL
, 0);
160 const struct ldb_schema_attribute
*a
= ldb_schema_attribute_by_name(module
->ldb
, "objectCategory");
162 dn
= ldb_dn_from_ldb_val(ctx
, module
->ldb
, val
);
163 if (dn
&& ldb_dn_validate(dn
)) {
165 return val_copy(module
, ctx
, val
);
169 if (a
->syntax
->canonicalise_fn(module
->ldb
, ctx
, val
, &out
) != LDB_SUCCESS
) {
170 return data_blob(NULL
, 0);
176 static struct ldb_val
normalise_to_signed32(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
178 long long int signed_ll
= strtoll((const char *)val
->data
, NULL
, 10);
179 if (signed_ll
>= 0x80000000LL
) {
182 uint32_t unsigned_int
;
184 .unsigned_int
= strtoul((const char *)val
->data
, NULL
, 10)
187 struct ldb_val out
= data_blob_string_const(talloc_asprintf(ctx
, "%d", u
.signed_int
));
190 return val_copy(module
, ctx
, val
);
193 static struct ldb_val
usn_to_entryCSN(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
196 unsigned long long usn
= strtoull((const char *)val
->data
, NULL
, 10);
197 time_t t
= (usn
>> 24);
198 out
= data_blob_string_const(talloc_asprintf(ctx
, "%s#%06x#00#000000", ldb_timestring(ctx
, t
), (unsigned int)(usn
& 0xFFFFFF)));
202 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
204 char *entryCSN
= talloc_strdup(ctx
, (const char *)val
->data
);
207 unsigned long long usn
;
212 p
= strchr(entryCSN
, '#');
227 usn
= strtol(mod_per_sec
, NULL
, 16);
229 t
= ldb_string_to_time(entryCSN
);
231 usn
= usn
| ((unsigned long long)t
<<24);
235 static struct ldb_val
entryCSN_to_usn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
238 unsigned long long usn
= entryCSN_to_usn_int(ctx
, val
);
239 out
= data_blob_string_const(talloc_asprintf(ctx
, "%lld", usn
));
243 static struct ldb_val
usn_to_timestamp(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
246 unsigned long long usn
= strtoull((const char *)val
->data
, NULL
, 10);
247 time_t t
= (usn
>> 24);
248 out
= data_blob_string_const(ldb_timestring(ctx
, t
));
252 static struct ldb_val
timestamp_to_usn(struct ldb_module
*module
, TALLOC_CTX
*ctx
, const struct ldb_val
*val
)
256 unsigned long long usn
;
258 t
= ldb_string_to_time((const char *)val
->data
);
260 usn
= ((unsigned long long)t
<<24);
262 out
= data_blob_string_const(talloc_asprintf(ctx
, "%lld", usn
));
267 static const struct ldb_map_attribute entryuuid_attributes
[] =
271 .local_name
= "objectGUID",
275 .remote_name
= "entryUUID",
276 .convert_local
= guid_always_string
,
277 .convert_remote
= encode_guid
,
283 .local_name
= "invocationId",
287 .remote_name
= "invocationId",
288 .convert_local
= guid_always_string
,
289 .convert_remote
= encode_guid
,
295 .local_name
= "objectSid",
299 .remote_name
= "objectSid",
300 .convert_local
= sid_always_binary
,
301 .convert_remote
= val_copy
,
306 .local_name
= "name",
310 .remote_name
= "samba4RDN"
315 .local_name
= "whenCreated",
319 .remote_name
= "createTimestamp"
324 .local_name
= "whenChanged",
328 .remote_name
= "modifyTimestamp"
333 .local_name
= "objectClasses",
337 .remote_name
= "samba4ObjectClasses"
342 .local_name
= "dITContentRules",
346 .remote_name
= "samba4DITContentRules"
351 .local_name
= "attributeTypes",
355 .remote_name
= "samba4AttributeTypes"
360 .local_name
= "objectCategory",
364 .remote_name
= "objectCategory",
365 .convert_local
= objectCategory_always_dn
,
366 .convert_remote
= val_copy
,
371 .local_name
= "distinguishedName",
375 .remote_name
= "entryDN"
380 .local_name
= "groupType",
384 .remote_name
= "groupType",
385 .convert_local
= normalise_to_signed32
,
386 .convert_remote
= val_copy
,
391 .local_name
= "sAMAccountType",
395 .remote_name
= "sAMAccountType",
396 .convert_local
= normalise_to_signed32
,
397 .convert_remote
= val_copy
,
402 .local_name
= "usnChanged",
406 .remote_name
= "entryCSN",
407 .convert_local
= usn_to_entryCSN
,
408 .convert_remote
= entryCSN_to_usn
413 .local_name
= "usnCreated",
417 .remote_name
= "createTimestamp",
418 .convert_local
= usn_to_timestamp
,
419 .convert_remote
= timestamp_to_usn
,
432 /* This objectClass conflicts with builtin classes on OpenLDAP */
433 const struct ldb_map_objectclass entryuuid_objectclasses
[] =
436 .local_name
= "subSchema",
437 .remote_name
= "samba4SubSchema"
444 /* These things do not show up in wildcard searches in OpenLDAP, but
445 * we need them to show up in the AD-like view */
446 static const char * const entryuuid_wildcard_attributes
[] = {
456 static const struct ldb_map_attribute nsuniqueid_attributes
[] =
460 .local_name
= "objectGUID",
464 .remote_name
= "nsuniqueid",
465 .convert_local
= guid_ns_string
,
466 .convert_remote
= encode_ns_guid
,
472 .local_name
= "objectSid",
476 .remote_name
= "objectSid",
477 .convert_local
= sid_always_binary
,
478 .convert_remote
= val_copy
,
483 .local_name
= "whenCreated",
487 .remote_name
= "createTimestamp"
492 .local_name
= "whenChanged",
496 .remote_name
= "modifyTimestamp"
501 .local_name
= "objectCategory",
505 .remote_name
= "objectCategory",
506 .convert_local
= objectCategory_always_dn
,
507 .convert_remote
= val_copy
,
512 .local_name
= "distinguishedName",
516 .remote_name
= "entryDN"
521 .local_name
= "groupType",
525 .remote_name
= "groupType",
526 .convert_local
= normalise_to_signed32
,
527 .convert_remote
= val_copy
,
532 .local_name
= "sAMAccountType",
536 .remote_name
= "sAMAccountType",
537 .convert_local
= normalise_to_signed32
,
538 .convert_remote
= val_copy
,
543 .local_name
= "usnChanged",
547 .remote_name
= "modifyTimestamp",
548 .convert_local
= usn_to_timestamp
,
549 .convert_remote
= timestamp_to_usn
,
554 .local_name
= "usnCreated",
558 .remote_name
= "createTimestamp",
559 .convert_local
= usn_to_timestamp
,
560 .convert_remote
= timestamp_to_usn
,
573 /* These things do not show up in wildcard searches in OpenLDAP, but
574 * we need them to show up in the AD-like view */
575 static const char * const nsuniqueid_wildcard_attributes
[] = {
584 /* the context init function */
585 static int entryuuid_init(struct ldb_module
*module
)
588 ret
= ldb_map_init(module
, entryuuid_attributes
, entryuuid_objectclasses
, entryuuid_wildcard_attributes
, "samba4Top", NULL
);
589 if (ret
!= LDB_SUCCESS
)
592 return ldb_next_init(module
);
595 /* the context init function */
596 static int nsuniqueid_init(struct ldb_module
*module
)
599 ret
= ldb_map_init(module
, nsuniqueid_attributes
, NULL
, nsuniqueid_wildcard_attributes
, "extensibleObject", NULL
);
600 if (ret
!= LDB_SUCCESS
)
603 return ldb_next_init(module
);
606 static int get_seq(struct ldb_request
*req
,
607 struct ldb_reply
*ares
)
609 unsigned long long *seq
= (unsigned long long *)req
->context
;
610 if (ares
->type
== LDB_REPLY_ENTRY
) {
611 struct ldb_message_element
*el
= ldb_msg_find_element(ares
->message
, "contextCSN");
613 *seq
= entryCSN_to_usn_int(ares
, &el
->values
[0]);
617 if (ares
->type
== LDB_REPLY_DONE
) {
618 return ldb_request_done(req
, LDB_SUCCESS
);
624 static int entryuuid_sequence_number(struct ldb_module
*module
, struct ldb_request
*req
)
627 struct map_private
*map_private
;
628 struct entryuuid_private
*entryuuid_private
;
629 unsigned long long seq
= 0;
630 struct ldb_request
*search_req
;
632 const struct ldb_control
*partition_ctrl
;
633 const struct dsdb_control_current_partition
*partition
;
635 static const char *contextCSN_attr
[] = {
639 map_private
= talloc_get_type(module
->private_data
, struct map_private
);
641 entryuuid_private
= talloc_get_type(map_private
->caller_private
, struct entryuuid_private
);
643 /* All this to get the DN of the parition, so we can search the right thing */
644 partition_ctrl
= ldb_request_get_control(req
, DSDB_CONTROL_CURRENT_PARTITION_OID
);
645 if (!partition_ctrl
) {
646 ldb_debug_set(module
->ldb
, LDB_DEBUG_FATAL
,
647 "entryuuid_sequence_number: no current partition control found");
648 return LDB_ERR_CONSTRAINT_VIOLATION
;
651 partition
= talloc_get_type(partition_ctrl
->data
,
652 struct dsdb_control_current_partition
);
653 SMB_ASSERT(partition
&& partition
->version
== DSDB_CONTROL_CURRENT_PARTITION_VERSION
);
655 ret
= ldb_build_search_req(&search_req
, module
->ldb
, req
,
656 partition
->dn
, LDB_SCOPE_BASE
,
657 NULL
, contextCSN_attr
, NULL
,
660 if (ret
!= LDB_SUCCESS
) {
664 ret
= ldb_next_request(module
, search_req
);
666 if (ret
== LDB_SUCCESS
) {
667 ret
= ldb_wait(search_req
->handle
, LDB_WAIT_ALL
);
670 talloc_free(search_req
);
671 if (ret
!= LDB_SUCCESS
) {
675 switch (req
->op
.seq_num
.type
) {
676 case LDB_SEQ_HIGHEST_SEQ
:
677 req
->op
.seq_num
.seq_num
= seq
;
680 req
->op
.seq_num
.seq_num
= seq
;
681 req
->op
.seq_num
.seq_num
++;
683 case LDB_SEQ_HIGHEST_TIMESTAMP
:
685 req
->op
.seq_num
.seq_num
= (seq
>> 24);
689 req
->op
.seq_num
.flags
= 0;
690 req
->op
.seq_num
.flags
|= LDB_SEQ_TIMESTAMP_SEQUENCE
;
691 req
->op
.seq_num
.flags
|= LDB_SEQ_GLOBAL_SEQUENCE
;
695 _PUBLIC_
const struct ldb_module_ops ldb_entryuuid_module_ops
= {
697 .init_context
= entryuuid_init
,
698 .sequence_number
= entryuuid_sequence_number
,
702 _PUBLIC_
const struct ldb_module_ops ldb_nsuniqueid_module_ops
= {
703 .name
= "nsuniqueid",
704 .init_context
= nsuniqueid_init
,
705 .sequence_number
= entryuuid_sequence_number
,