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