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