s4:dsdb - Fixed attribute dereferencing for FDS
[samba.git] / source4 / dsdb / samdb / ldb_modules / simple_ldap_map.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_module.h"
31 #include "ldb/ldb_map/ldb_map.h"
32
33 #include "librpc/gen_ndr/ndr_misc.h"
34 #include "librpc/ndr/libndr.h"
35 #include "dsdb/samdb/samdb.h"
36
37 struct entryuuid_private {
38         struct ldb_context *ldb;
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_data_blob(val, &guid);
46         enum ndr_err_code ndr_err;
47         struct ldb_val out = data_blob(NULL, 0);
48
49         if (!NT_STATUS_IS_OK(status)) {
50                 return out;
51         }
52         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
53                                        (ndr_push_flags_fn_t)ndr_push_GUID);
54         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
55                 return out;
56         }
57
58         return out;
59 }
60
61 static struct ldb_val guid_always_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
62 {
63         struct ldb_val out = data_blob(NULL, 0);
64         struct GUID guid;
65         NTSTATUS status = GUID_from_data_blob(val, &guid);
66         if (!NT_STATUS_IS_OK(status)) {
67                 return out;
68         }
69         return data_blob_string_const(GUID_string(ctx, &guid));
70 }
71
72 static struct ldb_val encode_ns_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
73 {
74         struct GUID guid;
75         NTSTATUS status = NS_GUID_from_string((char *)val->data, &guid);
76         enum ndr_err_code ndr_err;
77         struct ldb_val out = data_blob(NULL, 0);
78
79         if (!NT_STATUS_IS_OK(status)) {
80                 return out;
81         }
82         ndr_err = ndr_push_struct_blob(&out, ctx, NULL, &guid,
83                                        (ndr_push_flags_fn_t)ndr_push_GUID);
84         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
85                 return out;
86         }
87
88         return out;
89 }
90
91 static struct ldb_val guid_ns_string(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
92 {
93         struct ldb_val out = data_blob(NULL, 0);
94         struct GUID guid;
95         NTSTATUS status = GUID_from_data_blob(val, &guid);
96         if (!NT_STATUS_IS_OK(status)) {
97                 return out;
98         }
99         return data_blob_string_const(NS_GUID_string(ctx, &guid));
100 }
101
102 /* The backend holds binary sids, so just copy them back */
103 static struct ldb_val val_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
104 {
105         struct ldb_val out = data_blob(NULL, 0);
106         out = ldb_val_dup(ctx, val);
107
108         return out;
109 }
110
111 /* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
112 static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
113 {
114         struct ldb_context *ldb = ldb_module_get_ctx(module);
115         struct ldb_val out = data_blob(NULL, 0);
116         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectSid");
117
118         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
119                 return data_blob(NULL, 0);
120         }
121
122         return out;
123 }
124
125 /* Ensure we always convert objectCategory into a DN */
126 static struct ldb_val objectCategory_always_dn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
127 {
128         struct ldb_context *ldb = ldb_module_get_ctx(module);
129         struct ldb_dn *dn;
130         struct ldb_val out = data_blob(NULL, 0);
131         const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, "objectCategory");
132
133         dn = ldb_dn_from_ldb_val(ctx, ldb, val);
134         if (dn && ldb_dn_validate(dn)) {
135                 talloc_free(dn);
136                 return val_copy(module, ctx, val);
137         }
138         talloc_free(dn);
139
140         if (a->syntax->canonicalise_fn(ldb, ctx, val, &out) != LDB_SUCCESS) {
141                 return data_blob(NULL, 0);
142         }
143
144         return out;
145 }
146
147 static struct ldb_val normalise_to_signed32(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
148 {
149         struct ldb_val out;
150         /* We've to use "strtoll" here to have the intended overflows.
151          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
152         int32_t i = (int32_t) strtoll((char *)val->data, NULL, 0);
153         out = data_blob_string_const(talloc_asprintf(ctx, "%d", i));
154         return out;
155 }
156
157 static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
158 {
159         struct ldb_val out;
160         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
161         time_t t = (usn >> 24);
162         out = data_blob_string_const(talloc_asprintf(ctx, "%s#%06x#00#000000", ldb_timestring(ctx, t), (unsigned int)(usn & 0xFFFFFF)));
163         return out;
164 }
165
166 static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) 
167 {
168         char *entryCSN = talloc_strdup(ctx, (const char *)val->data);
169         char *mod_per_sec;
170         time_t t;
171         unsigned long long usn;
172         char *p;
173         if (!entryCSN) {
174                 return 0;
175         }
176         p = strchr(entryCSN, '#');
177         if (!p) {
178                 return 0;
179         }
180         p[0] = '\0';
181         p++;
182         mod_per_sec = p;
183
184         p = strchr(p, '#');
185         if (!p) {
186                 return 0;
187         }
188         p[0] = '\0';
189         p++;
190
191         usn = strtol(mod_per_sec, NULL, 16);
192
193         t = ldb_string_to_time(entryCSN);
194         
195         usn = usn | ((unsigned long long)t <<24);
196         return usn;
197 }
198
199 static struct ldb_val entryCSN_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
200 {
201         struct ldb_val out;
202         unsigned long long usn = entryCSN_to_usn_int(ctx, val);
203         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
204         return out;
205 }
206
207 static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
208 {
209         struct ldb_val out;
210         unsigned long long usn = strtoull((const char *)val->data, NULL, 10);
211         time_t t = (usn >> 24);
212         out = data_blob_string_const(ldb_timestring(ctx, t));
213         return out;
214 }
215
216 static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
217 {
218         struct ldb_val out;
219         time_t t;
220         unsigned long long usn;
221
222         t = ldb_string_to_time((const char *)val->data);
223         
224         usn = ((unsigned long long)t <<24);
225
226         out = data_blob_string_const(talloc_asprintf(ctx, "%lld", usn));
227         return out;
228 }
229
230
231 static const struct ldb_map_attribute entryuuid_attributes[] = 
232 {
233         /* objectGUID */
234         {
235                 .local_name = "objectGUID",
236                 .type = LDB_MAP_CONVERT,
237                 .u = {
238                         .convert = {
239                                 .remote_name = "entryUUID", 
240                                 .convert_local = guid_always_string,
241                                 .convert_remote = encode_guid,
242                         },
243                 },
244         },
245         /* invocationId */
246         {
247                 .local_name = "invocationId",
248                 .type = LDB_MAP_CONVERT,
249                 .u = {
250                         .convert = {
251                                 .remote_name = "invocationId", 
252                                 .convert_local = guid_always_string,
253                                 .convert_remote = encode_guid,
254                         },
255                 },
256         },
257         /* objectSid */
258         {
259                 .local_name = "objectSid",
260                 .type = LDB_MAP_CONVERT,
261                 .u = {
262                         .convert = {
263                                 .remote_name = "objectSid", 
264                                 .convert_local = sid_always_binary,
265                                 .convert_remote = val_copy,
266                         },
267                 },
268         },
269         {
270                 .local_name = "name",
271                 .type = LDB_MAP_RENAME,
272                 .u = {
273                         .rename = {
274                                  .remote_name = "samba4RDN"
275                          }
276                 }
277         },
278         {
279                 .local_name = "whenCreated",
280                 .type = LDB_MAP_RENAME,
281                 .u = {
282                         .rename = {
283                                  .remote_name = "createTimestamp"
284                          }
285                 }
286         },
287         {
288                 .local_name = "whenChanged",
289                 .type = LDB_MAP_RENAME,
290                 .u = {
291                         .rename = {
292                                  .remote_name = "modifyTimestamp"
293                          }
294                 }
295         },
296         {
297                 .local_name = "objectClasses",
298                 .type = LDB_MAP_RENAME,
299                 .u = {
300                         .rename = {
301                                  .remote_name = "samba4ObjectClasses"
302                          }
303                 }
304         },
305         {
306                 .local_name = "dITContentRules",
307                 .type = LDB_MAP_RENAME,
308                 .u = {
309                         .rename = {
310                                  .remote_name = "samba4DITContentRules"
311                          }
312                 }
313         },
314         {
315                 .local_name = "attributeTypes",
316                 .type = LDB_MAP_RENAME,
317                 .u = {
318                         .rename = {
319                                  .remote_name = "samba4AttributeTypes"
320                          }
321                 }
322         },
323         {
324                 .local_name = "objectCategory",
325                 .type = LDB_MAP_CONVERT,
326                 .u = {
327                         .convert = {
328                                 .remote_name = "objectCategory", 
329                                 .convert_local = objectCategory_always_dn,
330                                 .convert_remote = val_copy,
331                         },
332                 },
333         },
334         {
335                 .local_name = "distinguishedName",
336                 .type = LDB_MAP_RENAME,
337                 .u = {
338                         .rename = {
339                                  .remote_name = "entryDN"
340                          }
341                 }
342         },
343         {
344                 .local_name = "primaryGroupID",
345                 .type = LDB_MAP_CONVERT,
346                 .u = {
347                         .convert = {
348                                  .remote_name = "primaryGroupID",
349                                  .convert_local = normalise_to_signed32,
350                                  .convert_remote = val_copy,
351                         }
352                 }
353         },
354         {
355                 .local_name = "groupType",
356                 .type = LDB_MAP_CONVERT,
357                 .u = {
358                         .convert = {
359                                  .remote_name = "groupType",
360                                  .convert_local = normalise_to_signed32,
361                                  .convert_remote = val_copy,
362                          }
363                 }
364         },
365         {
366                 .local_name = "userAccountControl",
367                 .type = LDB_MAP_CONVERT,
368                 .u = {
369                         .convert = {
370                                  .remote_name = "userAccountControl",
371                                  .convert_local = normalise_to_signed32,
372                                  .convert_remote = val_copy,
373                          }
374                 }
375         },
376         {
377                 .local_name = "sAMAccountType",
378                 .type = LDB_MAP_CONVERT,
379                 .u = {
380                         .convert = {
381                                  .remote_name = "sAMAccountType",
382                                  .convert_local = normalise_to_signed32,
383                                  .convert_remote = val_copy,
384                          }
385                 }
386         },
387         {
388                 .local_name = "systemFlags",
389                 .type = LDB_MAP_CONVERT,
390                 .u = {
391                         .convert = {
392                                  .remote_name = "systemFlags",
393                                  .convert_local = normalise_to_signed32,
394                                  .convert_remote = val_copy,
395                          }
396                 }
397         },
398         {
399                 .local_name = "usnChanged",
400                 .type = LDB_MAP_CONVERT,
401                 .u = {
402                         .convert = {
403                                  .remote_name = "entryCSN",
404                                  .convert_local = usn_to_entryCSN,
405                                  .convert_remote = entryCSN_to_usn
406                          },
407                 },
408         },
409         {
410                 .local_name = "usnCreated",
411                 .type = LDB_MAP_CONVERT,
412                 .u = {
413                         .convert = {
414                                  .remote_name = "createTimestamp",
415                                  .convert_local = usn_to_timestamp,
416                                  .convert_remote = timestamp_to_usn,
417                          },
418                 },
419         },
420         {
421                 .local_name = "*",
422                 .type = LDB_MAP_KEEP,
423         },
424         {
425                 .local_name = NULL,
426         }
427 };
428
429 /* This objectClass conflicts with builtin classes on OpenLDAP */
430 const struct ldb_map_objectclass entryuuid_objectclasses[] =
431 {
432         {
433                 .local_name = "subSchema",
434                 .remote_name = "samba4SubSchema"
435         },
436         {
437                 .local_name = NULL
438         }
439 };
440
441 /* These things do not show up in wildcard searches in OpenLDAP, but
442  * we need them to show up in the AD-like view */
443 static const char * const entryuuid_wildcard_attributes[] = {
444         "objectGUID", 
445         "whenCreated", 
446         "whenChanged",
447         "usnCreated",
448         "usnChanged",
449         "memberOf",
450         NULL
451 };
452
453 static const struct ldb_map_attribute nsuniqueid_attributes[] = 
454 {
455         /* objectGUID */
456         {
457                 .local_name = "objectGUID",
458                 .type = LDB_MAP_CONVERT,
459                 .u = {
460                         .convert = {
461                                 .remote_name = "nsuniqueid", 
462                                 .convert_local = guid_ns_string,
463                                 .convert_remote = encode_ns_guid,
464                         }
465                 }
466         },
467         /* objectSid */ 
468         {
469                 .local_name = "objectSid",
470                 .type = LDB_MAP_CONVERT,
471                 .u = {
472                         .convert = {
473                                 .remote_name = "objectSid", 
474                                 .convert_local = sid_always_binary,
475                                 .convert_remote = val_copy,
476                         }
477                 }
478         },
479         {
480                 .local_name = "whenCreated",
481                 .type = LDB_MAP_RENAME,
482                 .u = {
483                         .rename = {
484                                  .remote_name = "createTimestamp"
485                          }
486                 }
487         },
488         {
489                 .local_name = "whenChanged",
490                 .type = LDB_MAP_RENAME,
491                 .u = {
492                         .rename = {
493                                  .remote_name = "modifyTimestamp"
494                          }
495                 }
496         },
497         {
498                 .local_name = "objectCategory",
499                 .type = LDB_MAP_CONVERT,
500                 .u = {
501                         .convert = {
502                                 .remote_name = "objectCategory", 
503                                 .convert_local = objectCategory_always_dn,
504                                 .convert_remote = val_copy,
505                         }
506                 }
507         },
508         {
509                 .local_name = "distinguishedName",
510                 .type = LDB_MAP_RENAME,
511                 .u = {
512                         .rename = {
513                                  .remote_name = "entryDN"
514                          }
515                 }
516         },
517         {
518                 .local_name = "primaryGroupID",
519                 .type = LDB_MAP_CONVERT,
520                 .u = {
521                         .convert = {
522                                  .remote_name = "primaryGroupID",
523                                  .convert_local = normalise_to_signed32,
524                                  .convert_remote = val_copy,
525                         }
526                 }
527         },
528         {
529                 .local_name = "groupType",
530                 .type = LDB_MAP_CONVERT,
531                 .u = {
532                         .convert = {
533                                  .remote_name = "groupType",
534                                  .convert_local = normalise_to_signed32,
535                                  .convert_remote = val_copy,
536                          }
537                 }
538         },
539         {
540                 .local_name = "userAccountControl",
541                 .type = LDB_MAP_CONVERT,
542                 .u = {
543                         .convert = {
544                                  .remote_name = "userAccountControl",
545                                  .convert_local = normalise_to_signed32,
546                                  .convert_remote = val_copy,
547                          }
548                 }
549         },
550         {
551                 .local_name = "sAMAccountType",
552                 .type = LDB_MAP_CONVERT,
553                 .u = {
554                         .convert = {
555                                  .remote_name = "sAMAccountType",
556                                  .convert_local = normalise_to_signed32,
557                                  .convert_remote = val_copy,
558                          }
559                 }
560         },
561         {
562                 .local_name = "systemFlags",
563                 .type = LDB_MAP_CONVERT,
564                 .u = {
565                         .convert = {
566                                  .remote_name = "systemFlags",
567                                  .convert_local = normalise_to_signed32,
568                                  .convert_remote = val_copy,
569                          }
570                 }
571         },
572         {
573                 .local_name = "usnChanged",
574                 .type = LDB_MAP_CONVERT,
575                 .u = {
576                         .convert = {
577                                  .remote_name = "modifyTimestamp",
578                                  .convert_local = usn_to_timestamp,
579                                  .convert_remote = timestamp_to_usn,
580                          }
581                 }
582         },
583         {
584                 .local_name = "usnCreated",
585                 .type = LDB_MAP_CONVERT,
586                 .u = {
587                         .convert = {
588                                  .remote_name = "createTimestamp",
589                                  .convert_local = usn_to_timestamp,
590                                  .convert_remote = timestamp_to_usn,
591                          }
592                 }
593         },
594         {
595                 .local_name = "*",
596                 .type = LDB_MAP_KEEP,
597         },
598         {
599                 .local_name = NULL,
600         }
601 };
602
603 /* These things do not show up in wildcard searches in OpenLDAP, but
604  * we need them to show up in the AD-like view */
605 static const char * const nsuniqueid_wildcard_attributes[] = {
606         "objectGUID", 
607         "whenCreated", 
608         "whenChanged",
609         "usnCreated",
610         "usnChanged",
611         NULL
612 };
613
614 /* the context init function */
615 static int entryuuid_init(struct ldb_module *module)
616 {
617         int ret;
618         ret = ldb_map_init(module, entryuuid_attributes, entryuuid_objectclasses, entryuuid_wildcard_attributes, "samba4Top", NULL);
619         if (ret != LDB_SUCCESS)
620                 return ret;
621
622         return ldb_next_init(module);
623 }
624
625 /* the context init function */
626 static int nsuniqueid_init(struct ldb_module *module)
627 {
628         int ret;
629         ret = ldb_map_init(module, nsuniqueid_attributes, NULL, nsuniqueid_wildcard_attributes, "extensibleObject", NULL);
630         if (ret != LDB_SUCCESS)
631                 return ret;
632
633         return ldb_next_init(module);
634 }
635
636 static int get_seq_callback(struct ldb_request *req,
637                             struct ldb_reply *ares)
638 {
639         unsigned long long *seq = (unsigned long long *)req->context;
640
641         if (!ares) {
642                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
643         }
644         if (ares->error != LDB_SUCCESS) {
645                 return ldb_request_done(req, ares->error);
646         }
647
648         if (ares->type == LDB_REPLY_ENTRY) {
649                 struct ldb_message_element *el = ldb_msg_find_element(ares->message, "contextCSN");
650                 if (el) {
651                         *seq = entryCSN_to_usn_int(ares, &el->values[0]);
652                 }
653         }
654
655         if (ares->type == LDB_REPLY_DONE) {
656                 return ldb_request_done(req, LDB_SUCCESS);
657         }
658
659         talloc_free(ares);
660         return LDB_SUCCESS;
661 }
662
663 static int entryuuid_sequence_number(struct ldb_module *module, struct ldb_request *req)
664 {
665         struct ldb_context *ldb;
666         int ret;
667         struct map_private *map_private;
668         struct entryuuid_private *entryuuid_private;
669         unsigned long long seq_num = 0;
670         struct ldb_request *search_req;
671
672         const struct ldb_control *partition_ctrl;
673         const struct dsdb_control_current_partition *partition;
674  
675         static const char *contextCSN_attr[] = {
676                 "contextCSN", NULL
677         };
678
679         struct ldb_seqnum_request *seq;
680         struct ldb_seqnum_result *seqr;
681         struct ldb_extended *ext;
682
683         ldb = ldb_module_get_ctx(module);
684
685         seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
686
687         map_private = talloc_get_type(ldb_module_get_private(module), struct map_private);
688
689         entryuuid_private = talloc_get_type(map_private->caller_private, struct entryuuid_private);
690
691         /* All this to get the DN of the parition, so we can search the right thing */
692         partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
693         if (!partition_ctrl) {
694                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
695                               "entryuuid_sequence_number: no current partition control found");
696                 return LDB_ERR_CONSTRAINT_VIOLATION;
697         }
698
699         partition = talloc_get_type(partition_ctrl->data,
700                                     struct dsdb_control_current_partition);
701         SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION);
702
703         ret = ldb_build_search_req(&search_req, ldb, req,
704                                    partition->dn, LDB_SCOPE_BASE,
705                                    NULL, contextCSN_attr, NULL,
706                                    &seq_num, get_seq_callback,
707                                    NULL);
708         if (ret != LDB_SUCCESS) {
709                 return ret;
710         }
711
712         ret = ldb_next_request(module, search_req);
713
714         if (ret == LDB_SUCCESS) {
715                 ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
716         }
717
718         talloc_free(search_req);
719         if (ret != LDB_SUCCESS) {
720                 return ret;
721         }
722
723         ext = talloc_zero(req, struct ldb_extended);
724         if (!ext) {
725                 return LDB_ERR_OPERATIONS_ERROR;
726         }
727         seqr = talloc_zero(req, struct ldb_seqnum_result);
728         if (seqr == NULL) {
729                 talloc_free(ext);
730                 return LDB_ERR_OPERATIONS_ERROR;
731         }
732         ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
733         ext->data = seqr;
734
735         switch (seq->type) {
736         case LDB_SEQ_HIGHEST_SEQ:
737                 seqr->seq_num = seq_num;
738                 break;
739         case LDB_SEQ_NEXT:
740                 seqr->seq_num = seq_num;
741                 seqr->seq_num++;
742                 break;
743         case LDB_SEQ_HIGHEST_TIMESTAMP:
744         {
745                 seqr->seq_num = (seq_num >> 24);
746                 break;
747         }
748         }
749         seqr->flags = 0;
750         seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
751         seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
752
753         /* send request done */
754         return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
755 }
756
757 static int entryuuid_extended(struct ldb_module *module, struct ldb_request *req)
758 {
759         if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
760                 return entryuuid_sequence_number(module, req);
761         }
762
763         return ldb_next_request(module, req);
764 }
765
766 _PUBLIC_ const struct ldb_module_ops ldb_entryuuid_module_ops = {
767         .name              = "entryuuid",
768         .init_context      = entryuuid_init,
769         .extended          = entryuuid_extended,
770         LDB_MAP_OPS
771 };
772
773 _PUBLIC_ const struct ldb_module_ops ldb_nsuniqueid_module_ops = {
774         .name              = "nsuniqueid",
775         .init_context      = nsuniqueid_init,
776         .extended          = entryuuid_extended,
777         LDB_MAP_OPS
778 };