1a16cb8321e6da6a14702ff056b8f565f86b66cc
[bbaumbach/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / entryUUID.c
1 /* 
2    ldb database module
3
4    LDAP semantics mapping module
5
6    Copyright (C) Jelmer Vernooij 2005
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
8
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.
13    
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.
18    
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/>.
21 */
22
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.
27 */
28
29 #include "includes.h"
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"
34
35 #include "librpc/gen_ndr/ndr_misc.h"
36 #include "librpc/ndr/libndr.h"
37
38 struct entryUUID_private {
39         struct ldb_dn **base_dns;
40 };
41
42 static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
43 {
44         struct GUID guid;
45         NTSTATUS status = GUID_from_string((char *)val->data, &guid);
46         struct ldb_val out = data_blob(NULL, 0);
47
48         if (!NT_STATUS_IS_OK(status)) {
49                 return out;
50         }
51         status = ndr_push_struct_blob(&out, ctx, &guid, 
52                                       (ndr_push_flags_fn_t)ndr_push_GUID);
53         if (!NT_STATUS_IS_OK(status)) {
54                 return out;
55         }
56
57         return out;
58 }
59
60 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
61 {
62         struct GUID *guid;
63         NTSTATUS status;
64         struct ldb_val out = data_blob(NULL, 0);
65         if (val->length >= 32 && val->data[val->length] == '\0') {
66                 ldb_handler_copy(module->ldb, ctx, val, &out);
67         } else {
68                 guid = talloc(ctx, struct GUID);
69                 if (guid == NULL) {
70                         return out;
71                 }
72                 status = ndr_pull_struct_blob(val, guid, guid, 
73                                               (ndr_pull_flags_fn_t)ndr_pull_GUID);
74                 if (!NT_STATUS_IS_OK(status)) {
75                         talloc_free(guid);
76                         return out;
77                 }
78                 out = data_blob_string_const(GUID_string(ctx, guid));
79                 talloc_free(guid);
80         }
81         return out;
82 }
83
84 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
85 {
86         struct GUID guid;
87         NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
88         struct ldb_val out = data_blob(NULL, 0);
89
90         if (!NT_STATUS_IS_OK(status)) {
91                 return out;
92         }
93         status = ndr_push_struct_blob(&out, ctx, &guid, 
94                                       (ndr_push_flags_fn_t)ndr_push_GUID);
95         if (!NT_STATUS_IS_OK(status)) {
96                 return out;
97         }
98
99         return out;
100 }
101
102 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
103 {
104         NTSTATUS status;
105         struct ldb_val out = data_blob(NULL, 0);
106         if (val->length >= 32 && val->data[val->length] == '\0') {
107                 struct GUID guid;
108                 GUID_from_string((char *)val->data, &guid);
109                 out = data_blob_string_const(NS_GUID_string(ctx, &guid));
110         } else {
111                 struct GUID *guid_p;
112                 guid_p = talloc(ctx, struct GUID);
113                 if (guid_p == NULL) {
114                         return out;
115                 }
116                 status = ndr_pull_struct_blob(val, guid_p, guid_p, 
117                                               (ndr_pull_flags_fn_t)ndr_pull_GUID);
118                 if (!NT_STATUS_IS_OK(status)) {
119                         talloc_free(guid_p);
120                         return out;
121                 }
122                 out = data_blob_string_const(NS_GUID_string(ctx, guid_p));
123                 talloc_free(guid_p);
124         }
125         return out;
126 }
127
128 /* The backend holds binary sids, so just copy them back */
129 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
130 {
131         struct ldb_val out = data_blob(NULL, 0);
132         ldb_handler_copy(module->ldb, ctx, val, &out);
133
134         return out;
135 }
136
137 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
138 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
139 {
140         struct ldb_val out = data_blob(NULL, 0);
141         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectSid");
142
143         if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
144                 return data_blob(NULL, 0);
145         }
146
147         return out;
148 }
149
150 /* Ensure we always convert objectCategory into a DN */
151 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
152 {
153         struct ldb_val out = data_blob(NULL, 0);
154         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, "objectCategory");
155
156         if (a->syntax->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
157                 return data_blob(NULL, 0);
158         }
159
160         return out;
161 }
162
163 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
164 {
165         long long int signed_ll = strtoll((const char *)val->data, NULL, 10);
166         if (signed_ll >= 0x80000000LL) {
167                 union {
168                         int32_t signed_int;
169                         uint32_t unsigned_int;
170                 } u = {
171                         .unsigned_int = strtoul((const char *)val->data, NULL, 10)
172                 };
173
174                 struct ldb_val out = data_blob_string_const(talloc_asprintf(ctx, "%d", u.signed_int));
175                 return out;
176         }
177         return val_copy(module, ctx, val);
178 }
179
180 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
181 {
182         struct ldb_val out;
183         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
184         time_t t = (usn >> 24);
185         out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
186         return out;
187 }
188
189 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) 
190 {
191         char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
192         char *mod_per_sec;
193         time_t t;
194         unsigned long long usn;
195         char *p;
196         if (!entryCSN) {
197                 return 0;
198         }
199         p = strchr(entryCSN, '#');
200         if (!p) {
201                 return 0;
202         }
203         p[0] = '\0';
204         p++;
205         mod_per_sec = p;
206
207         p = strchr(p, '#');
208         if (!p) {
209                 return 0;
210         }
211         p[0] = '\0';
212         p++;
213
214         usn = strtol(mod_per_sec, NULL, 16);
215
216         t = ldb_string_to_time(entryCSN);
217         
218         usn = usn | ((unsigned long long)t <<24);
219         return usn;
220 }
221
222 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
223 {
224         struct ldb_val out;
225         unsigned long long usn = entryCSN_to_usn_int(ctx, val);
226         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
227         return out;
228 }
229
230 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
231 {
232         struct ldb_val out;
233         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
234         time_t t = (usn >> 24);
235         out = data_blob_string_const(ldb_timestring(ctx, t));
236         return out;
237 }
238
239 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
240 {
241         struct ldb_val out;
242         time_t t;
243         unsigned long long usn;
244
245         t = ldb_string_to_time((const char *)val->data);
246         
247         usn = ((unsigned long long)t <<24);
248
249         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
250         return out;
251 }
252
253
254 static const struct ldb_map_attribute entryUUID_attributes[] = 
255 {
256         /* objectGUID */
257         {
258                 .local_name = "objectGUID",
259                 .type = MAP_CONVERT,
260                 .u = {
261                         .convert = {
262                                 .remote_name = "entryUUID", 
263                                 .convert_local = guid_always_string,
264                                 .convert_remote = encode_guid,
265                         },
266                 },
267         },
268         /* invocationId */
269         {
270                 .local_name = "invocationId",
271                 .type = MAP_CONVERT,
272                 .u = {
273                         .convert = {
274                                 .remote_name = "invocationId", 
275                                 .convert_local = guid_always_string,
276                                 .convert_remote = encode_guid,
277                         },
278                 },
279         },
280         /* objectSid */
281         {
282                 .local_name = "objectSid",
283                 .type = MAP_CONVERT,
284                 .u = {
285                         .convert = {
286                                 .remote_name = "objectSid", 
287                                 .convert_local = sid_always_binary,
288                                 .convert_remote = val_copy,
289                         },
290                 },
291         },
292         {
293                 .local_name = "whenCreated",
294                 .type = MAP_RENAME,
295                 .u = {
296                         .rename = {
297                                  .remote_name = "createTimestamp"
298                          }
299                 }
300         },
301         {
302                 .local_name = "whenChanged",
303                 .type = MAP_RENAME,
304                 .u = {
305                         .rename = {
306                                  .remote_name = "modifyTimestamp"
307                          }
308                 }
309         },
310         {
311                 .local_name = "objectClasses",
312                 .type = MAP_RENAME,
313                 .u = {
314                         .rename = {
315                                  .remote_name = "samba4ObjectClasses"
316                          }
317                 }
318         },
319         {
320                 .local_name = "dITContentRules",
321                 .type = MAP_RENAME,
322                 .u = {
323                         .rename = {
324                                  .remote_name = "samba4DITContentRules"
325                          }
326                 }
327         },
328         {
329                 .local_name = "attributeTypes",
330                 .type = MAP_RENAME,
331                 .u = {
332                         .rename = {
333                                  .remote_name = "samba4AttributeTypes"
334                          }
335                 }
336         },
337         {
338                 .local_name = "sambaPassword",
339                 .type = MAP_RENAME,
340                 .u = {
341                         .rename = {
342                                  .remote_name = "userPassword"
343                          }
344                 }
345         },
346         {
347                 .local_name = "objectCategory",
348                 .type = MAP_CONVERT,
349                 .u = {
350                         .convert = {
351                                 .remote_name = "objectCategory", 
352                                 .convert_local = objectCategory_always_dn,
353                                 .convert_remote = val_copy,
354                         },
355                 },
356         },
357         {
358                 .local_name = "distinguishedName",
359                 .type = MAP_RENAME,
360                 .u = {
361                         .rename = {
362                                  .remote_name = "entryDN"
363                          }
364                 }
365         },
366         {
367                 .local_name = "groupType",
368                 .type = MAP_CONVERT,
369                 .u = {
370                         .convert = {
371                                  .remote_name = "groupType",
372                                  .convert_local = normalise_to_signed32,
373                                  .convert_remote = val_copy,
374                          },
375                 }
376         },
377         {
378                 .local_name = "sAMAccountType",
379                 .type = MAP_CONVERT,
380                 .u = {
381                         .convert = {
382                                  .remote_name = "sAMAccountType",
383                                  .convert_local = normalise_to_signed32,
384                                  .convert_remote = val_copy,
385                          },
386                 }
387         },
388         {
389                 .local_name = "usnChanged",
390                 .type = MAP_CONVERT,
391                 .u = {
392                         .convert = {
393                                  .remote_name = "entryCSN",
394                                  .convert_local = usn_to_entryCSN,
395                                  .convert_remote = entryCSN_to_usn
396                          },
397                 },
398         },
399         {
400                 .local_name = "usnCreated",
401                 .type = MAP_CONVERT,
402                 .u = {
403                         .convert = {
404                                  .remote_name = "createTimestamp",
405                                  .convert_local = usn_to_timestamp,
406                                  .convert_remote = timestamp_to_usn,
407                          },
408                 },
409         },
410         {
411                 .local_name = "*",
412                 .type = MAP_KEEP,
413         },
414         {
415                 .local_name = NULL,
416         }
417 };
418
419 /* This objectClass conflicts with builtin classes on OpenLDAP */
420 const struct ldb_map_objectclass entryUUID_objectclasses[] =
421 {
422         {
423                 .local_name = "subSchema",
424                 .remote_name = "samba4SubSchema"
425         },
426         {
427                 .local_name = NULL
428         }
429 };
430
431 /* These things do not show up in wildcard searches in OpenLDAP, but
432  * we need them to show up in the AD-like view */
433 static const char * const entryUUID_wildcard_attributes[] = {
434         "objectGUID", 
435         "whenCreated", 
436         "whenChanged",
437         "usnCreated",
438         "usnChanged",
439         NULL
440 };
441
442 static const struct ldb_map_attribute nsuniqueid_attributes[] = 
443 {
444         /* objectGUID */
445         {
446                 .local_name = "objectGUID",
447                 .type = MAP_CONVERT,
448                 .u = {
449                         .convert = {
450                                 .remote_name = "nsuniqueid", 
451                                 .convert_local = guid_ns_string,
452                                 .convert_remote = encode_ns_guid,
453                         },
454                 },
455         },
456         /* objectSid */ 
457         {
458                 .local_name = "objectSid",
459                 .type = MAP_CONVERT,
460                 .u = {
461                         .convert = {
462                                 .remote_name = "objectSid", 
463                                 .convert_local = sid_always_binary,
464                                 .convert_remote = val_copy,
465                         },
466                 },
467         },
468         {
469                 .local_name = "whenCreated",
470                 .type = MAP_RENAME,
471                 .u = {
472                         .rename = {
473                                  .remote_name = "createTimestamp"
474                          }
475                 }
476         },
477         {
478                 .local_name = "whenChanged",
479                 .type = MAP_RENAME,
480                 .u = {
481                         .rename = {
482                                  .remote_name = "modifyTimestamp"
483                          }
484                 }
485         },
486         {
487                 .local_name = "sambaPassword",
488                 .type = MAP_RENAME,
489                 .u = {
490                         .rename = {
491                                  .remote_name = "userPassword"
492                          }
493                 }
494         },
495         {
496                 .local_name = "objectCategory",
497                 .type = MAP_CONVERT,
498                 .u = {
499                         .convert = {
500                                 .remote_name = "objectCategory", 
501                                 .convert_local = objectCategory_always_dn,
502                                 .convert_remote = val_copy,
503                         },
504                 },
505         },
506         {
507                 .local_name = "distinguishedName",
508                 .type = MAP_RENAME,
509                 .u = {
510                         .rename = {
511                                  .remote_name = "entryDN"
512                          }
513                 }
514         },
515         {
516                 .local_name = "groupType",
517                 .type = MAP_CONVERT,
518                 .u = {
519                         .convert = {
520                                  .remote_name = "groupType",
521                                  .convert_local = normalise_to_signed32,
522                                  .convert_remote = val_copy,
523                          },
524                 }
525         },
526         {
527                 .local_name = "sAMAccountType",
528                 .type = MAP_CONVERT,
529                 .u = {
530                         .convert = {
531                                  .remote_name = "sAMAccountType",
532                                  .convert_local = normalise_to_signed32,
533                                  .convert_remote = val_copy,
534                          },
535                 }
536         },
537         {
538                 .local_name = "usnChanged",
539                 .type = MAP_CONVERT,
540                 .u = {
541                         .convert = {
542                                  .remote_name = "modifyTimestamp",
543                                  .convert_local = usn_to_timestamp,
544                                  .convert_remote = timestamp_to_usn,
545                          },
546                 },
547         },
548         {
549                 .local_name = "usnCreated",
550                 .type = MAP_CONVERT,
551                 .u = {
552                         .convert = {
553                                  .remote_name = "createTimestamp",
554                                  .convert_local = usn_to_timestamp,
555                                  .convert_remote = timestamp_to_usn,
556                          },
557                 },
558         },
559         {
560                 .local_name = "*",
561                 .type = MAP_KEEP,
562         },
563         {
564                 .local_name = NULL,
565         }
566 };
567
568 /* These things do not show up in wildcard searches in OpenLDAP, but
569  * we need them to show up in the AD-like view */
570 static const char * const nsuniqueid_wildcard_attributes[] = {
571         "objectGUID", 
572         "whenCreated", 
573         "whenChanged",
574         "usnCreated",
575         "usnChanged",
576         NULL
577 };
578
579 static int get_remote_rootdse(struct ldb_context *ldb, void *context, 
580                        struct ldb_reply *ares) 
581 {
582         struct entryUUID_private *entryUUID_private;
583         entryUUID_private = talloc_get_type(context,
584                                             struct entryUUID_private);
585         if (ares->type == LDB_REPLY_ENTRY) {
586                 int i;
587                 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "namingContexts");
588                 entryUUID_private->base_dns = talloc_realloc(entryUUID_private, entryUUID_private->base_dns, struct ldb_dn *, 
589                                                              el->num_values + 1);
590                 for (i=0; i < el->num_values; i++) {
591                         if (!entryUUID_private->base_dns) {
592                                 return LDB_ERR_OPERATIONS_ERROR;
593                         }
594                         entryUUID_private->base_dns[i] = ldb_dn_new(entryUUID_private->base_dns, ldb, (const char *)el->values[i].data);
595                         if ( ! ldb_dn_validate(entryUUID_private->base_dns[i])) {
596                                 return LDB_ERR_OPERATIONS_ERROR;
597                         }
598                 }
599                 entryUUID_private->base_dns[i] = NULL;
600         }
601
602         return LDB_SUCCESS;
603 }
604
605 static int find_base_dns(struct ldb_module *module, 
606                           struct entryUUID_private *entryUUID_private) 
607 {
608         int ret;
609         struct ldb_request *req;
610         const char *naming_context_attr[] = {
611                 "namingContexts",
612                 NULL
613         };
614         req = talloc(entryUUID_private, struct ldb_request);
615         if (req == NULL) {
616                 ldb_set_errstring(module->ldb, "Out of Memory");
617                 return LDB_ERR_OPERATIONS_ERROR;
618         }
619
620         req->operation = LDB_SEARCH;
621         req->op.search.base = ldb_dn_new(req, module->ldb, NULL);
622         req->op.search.scope = LDB_SCOPE_BASE;
623
624         req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
625         if (req->op.search.tree == NULL) {
626                 ldb_set_errstring(module->ldb, "Unable to parse search expression");
627                 talloc_free(req);
628                 return LDB_ERR_OPERATIONS_ERROR;
629         }
630
631         req->op.search.attrs = naming_context_attr;
632         req->controls = NULL;
633         req->context = entryUUID_private;
634         req->callback = get_remote_rootdse;
635         ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
636
637         ret = ldb_next_request(module, req);
638         
639         if (ret == LDB_SUCCESS) {
640                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
641         }
642         
643         talloc_free(req);
644         if (ret != LDB_SUCCESS) {
645                 return ret;
646         }
647
648         return LDB_SUCCESS;
649 }
650
651 /* the context init function */
652 static int entryUUID_init(struct ldb_module *module)
653 {
654         int ret;
655         struct map_private *map_private;
656         struct entryUUID_private *entryUUID_private;
657
658         ret = ldb_map_init(module, entryUUID_attributes, entryUUID_objectclasses, entryUUID_wildcard_attributes, NULL);
659         if (ret != LDB_SUCCESS)
660                 return ret;
661
662         map_private = talloc_get_type(module->private_data, struct map_private);
663
664         entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
665         map_private->caller_private = entryUUID_private;
666
667         ret = find_base_dns(module, entryUUID_private);
668
669         return ldb_next_init(module);
670 }
671
672 /* the context init function */
673 static int nsuniqueid_init(struct ldb_module *module)
674 {
675         int ret;
676         struct map_private *map_private;
677         struct entryUUID_private *entryUUID_private;
678
679         ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, NULL);
680         if (ret != LDB_SUCCESS)
681                 return ret;
682
683         map_private = talloc_get_type(module->private_data, struct map_private);
684
685         entryUUID_private = talloc_zero(map_private, struct entryUUID_private);
686         map_private->caller_private = entryUUID_private;
687
688         ret = find_base_dns(module, entryUUID_private);
689
690         return ldb_next_init(module);
691 }
692
693 static int get_seq(struct ldb_context *ldb, void *context, 
694                    struct ldb_reply *ares) 
695 {
696         unsigned long long *max_seq = (unsigned long long *)context;
697         unsigned long long seq;
698         if (ares->type == LDB_REPLY_ENTRY) {
699                 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
700                 if (el) {
701                         seq = entryCSN_to_usn_int(ares, &el->values[0]);
702                         *max_seq = MAX(seq, *max_seq);
703                 }
704         }
705
706         return LDB_SUCCESS;
707 }
708
709 static int entryUUID_sequence_number(struct ldb_module *module, struct ldb_request *req)
710 {
711         int i, ret;
712         struct map_private *map_private;
713         struct entryUUID_private *entryUUID_private;
714         unsigned long long max_seq = 0;
715         struct ldb_request *search_req;
716         map_private = talloc_get_type(module->private_data, struct map_private);
717
718         entryUUID_private = talloc_get_type(map_private->caller_private, struct entryUUID_private);
719
720         /* Search the baseDNs for a sequence number */
721         for (i=0; entryUUID_private && 
722                      entryUUID_private->base_dns && 
723                      entryUUID_private->base_dns[i];
724                 i++) {
725                 static const char *contextCSN_attr[] = {
726                         "contextCSN", NULL
727                 };
728                 search_req = talloc(req, struct ldb_request);
729                 if (search_req == NULL) {
730                         ldb_set_errstring(module->ldb, "Out of Memory");
731                         return LDB_ERR_OPERATIONS_ERROR;
732                 }
733                 
734                 search_req->operation = LDB_SEARCH;
735                 search_req->op.search.base = entryUUID_private->base_dns[i];
736                 search_req->op.search.scope = LDB_SCOPE_BASE;
737                 
738                 search_req->op.search.tree = ldb_parse_tree(search_req, "objectClass=*");
739                 if (search_req->op.search.tree == NULL) {
740                         ldb_set_errstring(module->ldb, "Unable to parse search expression");
741                         talloc_free(search_req);
742                         return LDB_ERR_OPERATIONS_ERROR;
743                 }
744                 
745                 search_req->op.search.attrs = contextCSN_attr;
746                 search_req->controls = NULL;
747                 search_req->context = &max_seq;
748                 search_req->callback = get_seq;
749                 ldb_set_timeout(module->ldb, search_req, 0); /* use default timeout */
750                 
751                 ret = ldb_next_request(module, search_req);
752                 
753                 if (ret == LDB_SUCCESS) {
754                         ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
755                 }
756                 
757                 talloc_free(search_req);
758                 if (ret != LDB_SUCCESS) {
759                         return ret;
760                 }
761         }
762
763         switch (req->op.seq_num.type) {
764         case LDB_SEQ_HIGHEST_SEQ:
765                 req->op.seq_num.seq_num = max_seq;
766                 break;
767         case LDB_SEQ_NEXT:
768                 req->op.seq_num.seq_num = max_seq;
769                 req->op.seq_num.seq_num++;
770                 break;
771         case LDB_SEQ_HIGHEST_TIMESTAMP:
772         {
773                 req->op.seq_num.seq_num = (max_seq >> 24);
774                 break;
775         }
776         }
777         req->op.seq_num.flags = 0;
778         req->op.seq_num.flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
779         req->op.seq_num.flags |= LDB_SEQ_GLOBAL_SEQUENCE;
780         return LDB_SUCCESS;
781 }
782
783 static struct ldb_module_ops entryUUID_ops = {
784         .name              = "entryUUID",
785         .init_context      = entryUUID_init,
786         .sequence_number   = entryUUID_sequence_number
787 };
788
789 static struct ldb_module_ops nsuniqueid_ops = {
790         .name              = "nsuniqueid",
791         .init_context      = nsuniqueid_init,
792         .sequence_number   = entryUUID_sequence_number
793 };
794
795 /* the init function */
796 int ldb_entryUUID_module_init(void)
797 {
798         int ret;
799         struct ldb_module_ops ops = ldb_map_get_ops();
800         entryUUID_ops.add       = ops.add;
801         entryUUID_ops.modify    = ops.modify;
802         entryUUID_ops.del       = ops.del;
803         entryUUID_ops.rename    = ops.rename;
804         entryUUID_ops.search    = ops.search;
805         entryUUID_ops.wait      = ops.wait;
806         ret = ldb_register_module(&entryUUID_ops);
807
808         if (ret) {
809                 return ret;
810         }
811
812         nsuniqueid_ops.add      = ops.add;
813         nsuniqueid_ops.modify   = ops.modify;
814         nsuniqueid_ops.del      = ops.del;
815         nsuniqueid_ops.rename   = ops.rename;
816         nsuniqueid_ops.search   = ops.search;
817         nsuniqueid_ops.wait     = ops.wait;
818         ret = ldb_register_module(&nsuniqueid_ops);
819
820         return ret;
821 }