s4-dsdb: Remove LDB_SEQ_HIGHEST_TIMESTAMP sequence number support
[Samba.git] / source4 / dsdb / samdb / ldb_modules / simple_ldap_map.c
blob9c7599acf588b6d004bbcbceb4cc56806d5c4982
1 /*
2 ldb database module
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/>.
23 /*
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.
29 #include "includes.h"
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 <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)
45 struct GUID guid;
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)) {
50 return out;
52 status = GUID_to_ndr_blob(&guid, ctx, &out);
53 if (!NT_STATUS_IS_OK(status)) {
54 return data_blob(NULL, 0);
57 return out;
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);
63 struct GUID guid;
64 NTSTATUS status = GUID_from_data_blob(val, &guid);
65 if (!NT_STATUS_IS_OK(status)) {
66 return out;
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)
73 struct GUID guid;
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)) {
78 return out;
80 status = GUID_to_ndr_blob(&guid, ctx, &out);
81 if (!NT_STATUS_IS_OK(status)) {
82 return data_blob(NULL, 0);
85 return out;
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);
91 struct GUID guid;
92 NTSTATUS status = GUID_from_data_blob(val, &guid);
93 if (!NT_STATUS_IS_OK(status)) {
94 return out;
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);
105 return out;
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);
119 return out;
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);
133 } else {
134 if (ldif_write_objectSid(ldb, ctx, val, &out) != LDB_SUCCESS) {
135 return data_blob(NULL, 0);
138 return out;
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);
145 struct ldb_dn *dn;
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 (ldb_dn_validate(dn)) {
151 talloc_free(dn);
152 return val_copy(module, ctx, val);
154 talloc_free(dn);
156 if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
157 return data_blob(NULL, 0);
160 return out;
163 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
165 struct ldb_val out;
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));
170 return out;
173 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
175 struct ldb_val out;
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)));
179 return out;
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);
185 char *mod_per_sec;
186 time_t t;
187 unsigned long long usn;
188 char *p;
189 if (!entryCSN) {
190 return 0;
192 p = strchr(entryCSN, '#');
193 if (!p) {
194 return 0;
196 p[0] = '\0';
197 p++;
198 mod_per_sec = p;
200 p = strchr(p, '#');
201 if (!p) {
202 return 0;
204 p[0] = '\0';
205 p++;
207 usn = strtol(mod_per_sec, NULL, 16);
209 t = ldb_string_to_time(entryCSN);
211 usn = usn | ((unsigned long long)t <<24);
212 return usn;
215 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
217 struct ldb_val out;
218 unsigned long long usn = entryCSN_to_usn_int(ctx, val);
219 out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
220 return out;
223 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
225 struct ldb_val out;
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));
229 return out;
232 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
234 struct ldb_val out;
235 time_t t=0;
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));
243 return out;
247 static const struct ldb_map_attribute entryuuid_attributes[] =
249 /* objectGUID */
251 .local_name = "objectGUID",
252 .type = LDB_MAP_CONVERT,
253 .u = {
254 .convert = {
255 .remote_name = "entryUUID",
256 .convert_local = guid_always_string,
257 .convert_remote = encode_guid,
261 /* invocationId */
263 .local_name = "invocationId",
264 .type = LDB_MAP_CONVERT,
265 .u = {
266 .convert = {
267 .remote_name = "invocationId",
268 .convert_local = guid_always_string,
269 .convert_remote = encode_guid,
273 /* objectSid */
275 .local_name = "objectSid",
276 .type = LDB_MAP_CONVERT,
277 .u = {
278 .convert = {
279 .remote_name = "objectSid",
280 .convert_local = sid_always_binary,
281 .convert_remote = val_copy,
285 /* securityIdentifier */
287 .local_name = "securityIdentifier",
288 .type = LDB_MAP_CONVERT,
289 .u = {
290 .convert = {
291 .remote_name = "securityIdentifier",
292 .convert_local = sid_always_binary,
293 .convert_remote = val_copy,
298 .local_name = "name",
299 .type = LDB_MAP_RENAME,
300 .u = {
301 .rename = {
302 .remote_name = "rdnValue"
307 .local_name = "whenCreated",
308 .type = LDB_MAP_RENAME,
309 .u = {
310 .rename = {
311 .remote_name = "createTimestamp"
316 .local_name = "whenChanged",
317 .type = LDB_MAP_RENAME,
318 .u = {
319 .rename = {
320 .remote_name = "modifyTimestamp"
325 .local_name = "objectClasses",
326 .type = LDB_MAP_RENAME,
327 .u = {
328 .rename = {
329 .remote_name = "samba4ObjectClasses"
334 .local_name = "dITContentRules",
335 .type = LDB_MAP_RENAME,
336 .u = {
337 .rename = {
338 .remote_name = "samba4DITContentRules"
343 .local_name = "attributeTypes",
344 .type = LDB_MAP_RENAME,
345 .u = {
346 .rename = {
347 .remote_name = "samba4AttributeTypes"
352 .local_name = "objectCategory",
353 .type = LDB_MAP_CONVERT,
354 .u = {
355 .convert = {
356 .remote_name = "objectCategory",
357 .convert_local = objectCategory_always_dn,
358 .convert_remote = val_copy,
363 .local_name = "distinguishedName",
364 .type = LDB_MAP_RENAME,
365 .u = {
366 .rename = {
367 .remote_name = "entryDN"
372 .local_name = "primaryGroupID",
373 .type = LDB_MAP_CONVERT,
374 .u = {
375 .convert = {
376 .remote_name = "primaryGroupID",
377 .convert_local = normalise_to_signed32,
378 .convert_remote = val_copy,
383 .local_name = "groupType",
384 .type = LDB_MAP_CONVERT,
385 .u = {
386 .convert = {
387 .remote_name = "groupType",
388 .convert_local = normalise_to_signed32,
389 .convert_remote = val_copy,
394 .local_name = "userAccountControl",
395 .type = LDB_MAP_CONVERT,
396 .u = {
397 .convert = {
398 .remote_name = "userAccountControl",
399 .convert_local = normalise_to_signed32,
400 .convert_remote = val_copy,
405 .local_name = "sAMAccountType",
406 .type = LDB_MAP_CONVERT,
407 .u = {
408 .convert = {
409 .remote_name = "sAMAccountType",
410 .convert_local = normalise_to_signed32,
411 .convert_remote = val_copy,
416 .local_name = "systemFlags",
417 .type = LDB_MAP_CONVERT,
418 .u = {
419 .convert = {
420 .remote_name = "systemFlags",
421 .convert_local = normalise_to_signed32,
422 .convert_remote = val_copy,
427 .local_name = "usnChanged",
428 .type = LDB_MAP_CONVERT,
429 .u = {
430 .convert = {
431 .remote_name = "entryCSN",
432 .convert_local = usn_to_entryCSN,
433 .convert_remote = entryCSN_to_usn
438 .local_name = "usnCreated",
439 .type = LDB_MAP_CONVERT,
440 .u = {
441 .convert = {
442 .remote_name = "createTimestamp",
443 .convert_local = usn_to_timestamp,
444 .convert_remote = timestamp_to_usn,
449 .local_name = "*",
450 .type = LDB_MAP_KEEP,
453 .local_name = NULL,
457 /* This objectClass conflicts with builtin classes on OpenLDAP */
458 const struct ldb_map_objectclass entryuuid_objectclasses[] =
461 .local_name = "subSchema",
462 .remote_name = "samba4SubSchema"
465 .local_name = NULL
469 /* These things do not show up in wildcard searches in OpenLDAP, but
470 * we need them to show up in the AD-like view */
471 static const char * const entryuuid_wildcard_attributes[] = {
472 "objectGUID",
473 "whenCreated",
474 "whenChanged",
475 "usnCreated",
476 "usnChanged",
477 "memberOf",
478 NULL
481 static const struct ldb_map_attribute nsuniqueid_attributes[] =
483 /* objectGUID */
485 .local_name = "objectGUID",
486 .type = LDB_MAP_CONVERT,
487 .u = {
488 .convert = {
489 .remote_name = "nsuniqueid",
490 .convert_local = guid_ns_string,
491 .convert_remote = encode_ns_guid,
495 /* objectSid */
497 .local_name = "objectSid",
498 .type = LDB_MAP_CONVERT,
499 .u = {
500 .convert = {
501 .remote_name = "sambaSID",
502 .convert_local = sid_always_string,
503 .convert_remote = sid_always_binary,
507 /* securityIdentifier */
509 .local_name = "securityIdentifier",
510 .type = LDB_MAP_CONVERT,
511 .u = {
512 .convert = {
513 .remote_name = "securityIdentifier",
514 .convert_local = sid_always_binary,
515 .convert_remote = val_copy,
520 .local_name = "whenCreated",
521 .type = LDB_MAP_RENAME,
522 .u = {
523 .rename = {
524 .remote_name = "createTimestamp"
529 .local_name = "whenChanged",
530 .type = LDB_MAP_RENAME,
531 .u = {
532 .rename = {
533 .remote_name = "modifyTimestamp"
538 .local_name = "objectCategory",
539 .type = LDB_MAP_CONVERT,
540 .u = {
541 .convert = {
542 .remote_name = "objectCategory",
543 .convert_local = objectCategory_always_dn,
544 .convert_remote = val_copy,
549 .local_name = "distinguishedName",
550 .type = LDB_MAP_RENAME,
551 .u = {
552 .rename = {
553 .remote_name = "entryDN"
558 .local_name = "primaryGroupID",
559 .type = LDB_MAP_CONVERT,
560 .u = {
561 .convert = {
562 .remote_name = "primaryGroupID",
563 .convert_local = normalise_to_signed32,
564 .convert_remote = val_copy,
569 .local_name = "groupType",
570 .type = LDB_MAP_CONVERT,
571 .u = {
572 .convert = {
573 .remote_name = "sambaGroupType",
574 .convert_local = normalise_to_signed32,
575 .convert_remote = val_copy,
580 .local_name = "userAccountControl",
581 .type = LDB_MAP_CONVERT,
582 .u = {
583 .convert = {
584 .remote_name = "userAccountControl",
585 .convert_local = normalise_to_signed32,
586 .convert_remote = val_copy,
591 .local_name = "sAMAccountType",
592 .type = LDB_MAP_CONVERT,
593 .u = {
594 .convert = {
595 .remote_name = "sAMAccountType",
596 .convert_local = normalise_to_signed32,
597 .convert_remote = val_copy,
602 .local_name = "systemFlags",
603 .type = LDB_MAP_CONVERT,
604 .u = {
605 .convert = {
606 .remote_name = "systemFlags",
607 .convert_local = normalise_to_signed32,
608 .convert_remote = val_copy,
613 .local_name = "usnChanged",
614 .type = LDB_MAP_CONVERT,
615 .u = {
616 .convert = {
617 .remote_name = "modifyTimestamp",
618 .convert_local = usn_to_timestamp,
619 .convert_remote = timestamp_to_usn,
624 .local_name = "usnCreated",
625 .type = LDB_MAP_CONVERT,
626 .u = {
627 .convert = {
628 .remote_name = "createTimestamp",
629 .convert_local = usn_to_timestamp,
630 .convert_remote = timestamp_to_usn,
635 .local_name = "pwdLastSet",
636 .type = LDB_MAP_RENAME,
637 .u = {
638 .rename = {
639 .remote_name = "sambaPwdLastSet"
644 .local_name = "lastLogon",
645 .type = LDB_MAP_RENAME,
646 .u = {
647 .rename = {
648 .remote_name = "sambaLogonTime"
653 .local_name = "lastLogoff",
654 .type = LDB_MAP_RENAME,
655 .u = {
656 .rename = {
657 .remote_name = "sambaLogoffTime"
662 .local_name = "badPwdCount",
663 .type = LDB_MAP_RENAME,
664 .u = {
665 .rename = {
666 .remote_name = "sambaBadPasswordCount"
671 .local_name = "logonHours",
672 .type = LDB_MAP_RENAME,
673 .u = {
674 .rename = {
675 .remote_name = "sambaLogonHours"
680 .local_name = "homeDrive",
681 .type = LDB_MAP_RENAME,
682 .u = {
683 .rename = {
684 .remote_name = "sambaHomeDrive"
689 .local_name = "scriptPath",
690 .type = LDB_MAP_RENAME,
691 .u = {
692 .rename = {
693 .remote_name = "sambaLogonScript"
698 .local_name = "profilePath",
699 .type = LDB_MAP_RENAME,
700 .u = {
701 .rename = {
702 .remote_name = "sambaProfilePath"
707 .local_name = "userWorkstations",
708 .type = LDB_MAP_RENAME,
709 .u = {
710 .rename = {
711 .remote_name = "sambaUserWorkstations"
716 .local_name = "homeDirectory",
717 .type = LDB_MAP_RENAME,
718 .u = {
719 .rename = {
720 .remote_name = "sambaHomePath"
725 .local_name = "nextRid",
726 .type = LDB_MAP_RENAME,
727 .u = {
728 .rename = {
729 .remote_name = "sambaNextRid"
734 .local_name = "privilegeDisplayName",
735 .type = LDB_MAP_RENAME,
736 .u = {
737 .rename = {
738 .remote_name = "sambaPrivName"
743 .local_name = "*",
744 .type = LDB_MAP_KEEP,
747 .local_name = NULL,
751 /* This objectClass conflicts with builtin classes on FDS */
752 const struct ldb_map_objectclass nsuniqueid_objectclasses[] =
755 .local_name = NULL
759 /* These things do not show up in wildcard searches in OpenLDAP, but
760 * we need them to show up in the AD-like view */
761 static const char * const nsuniqueid_wildcard_attributes[] = {
762 "objectGUID",
763 "whenCreated",
764 "whenChanged",
765 "usnCreated",
766 "usnChanged",
767 NULL
770 /* the context init function */
771 static int entryuuid_init(struct ldb_module *module)
773 int ret;
774 ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
775 if (ret != LDB_SUCCESS)
776 return ret;
778 return ldb_next_init(module);
781 /* the context init function */
782 static int nsuniqueid_init(struct ldb_module *module)
784 int ret;
785 ret = ldb_map_init(module, nsuniqueid_attributes, nsuniqueid_objectclasses, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
786 if (ret != LDB_SUCCESS)
787 return ret;
789 return ldb_next_init(module);
792 static int get_seq_callback(struct ldb_request *req,
793 struct ldb_reply *ares)
795 unsigned long long *seq = (unsigned long long *)req->context;
797 if (!ares) {
798 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
800 if (ares->error != LDB_SUCCESS) {
801 return ldb_request_done(req, ares->error);
804 if (ares->type == LDB_REPLY_ENTRY) {
805 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
806 if (el) {
807 *seq = entryCSN_to_usn_int(ares, &el->values[0]);
811 if (ares->type == LDB_REPLY_DONE) {
812 return ldb_request_done(req, LDB_SUCCESS);
815 talloc_free(ares);
816 return LDB_SUCCESS;
819 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
821 struct ldb_context *ldb;
822 int ret;
823 struct map_private *map_private;
824 struct entryuuid_private *entryuuid_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[] = {
832 "contextCSN", NULL
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 entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
847 /* All this to get the DN of the parition, so we can search the right thing */
848 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
849 if (!partition_ctrl) {
850 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
851 "entryuuid_sequence_number: no current partition control found!");
852 return LDB_ERR_PROTOCOL_ERROR;
855 partition = talloc_get_type(partition_ctrl->data,
856 struct dsdb_control_current_partition);
857 if ((partition == NULL) || (partition->version != DSDB_CONTROL_CURRENT_PARTITION_VERSION)) {
858 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
859 "entryuuid_sequence_number: current partition control with wrong data!");
860 return LDB_ERR_PROTOCOL_ERROR;
863 ret = ldb_build_search_req(&search_req, ldb, req,
864 partition->dn, LDB_SCOPE_BASE,
865 NULL, contextCSN_attr, NULL,
866 &seq_num, get_seq_callback,
867 NULL);
868 LDB_REQ_SET_LOCATION(search_req);
869 if (ret != LDB_SUCCESS) {
870 return ret;
873 ret = ldb_next_request(module, search_req);
875 if (ret == LDB_SUCCESS) {
876 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
879 talloc_free(search_req);
880 if (ret != LDB_SUCCESS) {
881 return ret;
884 ext = talloc_zero(req, struct ldb_extended);
885 if (!ext) {
886 return ldb_oom(ldb);
888 seqr = talloc_zero(req, struct ldb_seqnum_result);
889 if (seqr == NULL) {
890 talloc_free(ext);
891 return ldb_oom(ldb);
893 ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
894 ext->data = seqr;
896 switch (seq->type) {
897 case LDB_SEQ_HIGHEST_SEQ:
898 seqr->seq_num = seq_num;
899 break;
900 case LDB_SEQ_NEXT:
901 seqr->seq_num = seq_num;
902 seqr->seq_num++;
903 break;
904 case LDB_SEQ_HIGHEST_TIMESTAMP:
905 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, "LDB_SEQ_HIGHEST_TIMESTAMP not supported");
908 seqr->flags = 0;
909 seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
911 /* send request done */
912 return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
915 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
917 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
918 return entryuuid_sequence_number(module, req);
921 return ldb_next_request(module, req);
924 static const struct ldb_module_ops ldb_entryuuid_module_ops = {
925 .name = "entryuuid",
926 .init_context = entryuuid_init,
927 .extended = entryuuid_extended,
928 LDB_MAP_OPS
931 static const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
932 .name = "nsuniqueid",
933 .init_context = nsuniqueid_init,
934 .extended = entryuuid_extended,
935 LDB_MAP_OPS
939 initialise the module
941 _PUBLIC_ int ldb_simple_ldap_map_module_init(const char *version)
943 int ret;
944 LDB_MODULE_CHECK_VERSION(version);
945 ret = ldb_register_module(&ldb_entryuuid_module_ops);
946 if (ret != LDB_SUCCESS) {
947 return ret;
949 ret = ldb_register_module(&ldb_nsuniqueid_module_ops);
950 if (ret != LDB_SUCCESS) {
951 return ret;
953 return LDB_SUCCESS;