65f1d885759e74992e5d0b84a612c744f6b84909
[obnox/samba/samba-obnox.git] / lib / ldb-samba / ldif_handlers.c
1 /* 
2    ldb database library - ldif handlers for Samba
3
4    Copyright (C) Andrew Tridgell 2005
5    Copyright (C) Andrew Bartlett 2006-2009
6    Copyright (C) Matthias Dieter Wallnöfer 2009
7      ** NOTE! The following LGPL license applies to the ldb
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10    
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include <ldb.h>
27 #include <ldb_module.h>
28 #include "ldb_handlers.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/common/util.h"
31 #include "librpc/gen_ndr/ndr_security.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "librpc/gen_ndr/ndr_dnsp.h"
35 #include "librpc/ndr/libndr.h"
36 #include "libcli/security/security.h"
37 #include "param/param.h"
38 #include "../lib/util/asn1.h"
39
40 /*
41   use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
42
43   If mask_errors is true, then function succeeds but out data
44   is set to "<Unable to decode binary data>" message
45
46   \return 0 on success; -1 on error
47 */
48 static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
49                           const struct ldb_val *in, struct ldb_val *out,
50                           size_t struct_size,
51                           ndr_pull_flags_fn_t pull_fn,
52                           ndr_print_fn_t print_fn,
53                           bool mask_errors)
54 {
55         uint8_t *p;
56         enum ndr_err_code err;
57         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
58                 return ldb_handler_copy(ldb, mem_ctx, in, out);
59         }
60         p = talloc_size(mem_ctx, struct_size);
61         err = ndr_pull_struct_blob(in, mem_ctx, 
62                                    p, pull_fn);
63         if (err != NDR_ERR_SUCCESS) {
64                 /* fail in not in mask_error mode */
65                 if (!mask_errors) {
66                         return -1;
67                 }
68                 talloc_free(p);
69                 out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
70                 out->length = strlen((const char *)out->data);
71                 return 0;
72         }
73         out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
74         talloc_free(p);
75         if (out->data == NULL) {
76                 return ldb_handler_copy(ldb, mem_ctx, in, out);         
77         }
78         out->length = strlen((char *)out->data);
79         return 0;
80 }
81
82 /*
83   convert a ldif formatted objectSid to a NDR formatted blob
84 */
85 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
86                                const struct ldb_val *in, struct ldb_val *out)
87 {
88         enum ndr_err_code ndr_err;
89         struct dom_sid *sid;
90         sid = dom_sid_parse_length(mem_ctx, in);
91         if (sid == NULL) {
92                 return -1;
93         }
94         ndr_err = ndr_push_struct_blob(out, mem_ctx, sid,
95                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
96         talloc_free(sid);
97         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
98                 return -1;
99         }
100         return 0;
101 }
102
103 /*
104   convert a NDR formatted blob to a ldif formatted objectSid
105 */
106 int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
107                                 const struct ldb_val *in, struct ldb_val *out)
108 {
109         struct dom_sid *sid;
110         enum ndr_err_code ndr_err;
111
112         sid = talloc(mem_ctx, struct dom_sid);
113         if (sid == NULL) {
114                 return -1;
115         }
116         ndr_err = ndr_pull_struct_blob_all(in, sid, sid,
117                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
118         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
119                 talloc_free(sid);
120                 return -1;
121         }
122         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
123         talloc_free(sid);
124         if (out->data == NULL) {
125                 return -1;
126         }
127         return 0;
128 }
129
130 bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
131 {
132         if (v->length < 3) {
133                 return false;
134         }
135
136         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
137         
138         return true;
139 }
140
141 /*
142   compare two objectSids
143 */
144 static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
145                                     const struct ldb_val *v1, const struct ldb_val *v2)
146 {
147         if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
148                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
149         } else if (ldif_comparision_objectSid_isString(v1)
150                    && !ldif_comparision_objectSid_isString(v2)) {
151                 struct ldb_val v;
152                 int ret;
153                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
154                         /* Perhaps not a string after all */
155                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
156                 }
157                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
158                 talloc_free(v.data);
159                 return ret;
160         } else if (!ldif_comparision_objectSid_isString(v1)
161                    && ldif_comparision_objectSid_isString(v2)) {
162                 struct ldb_val v;
163                 int ret;
164                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
165                         /* Perhaps not a string after all */
166                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
167                 }
168                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
169                 talloc_free(v.data);
170                 return ret;
171         }
172         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
173 }
174
175 /*
176   canonicalise a objectSid
177 */
178 static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
179                                       const struct ldb_val *in, struct ldb_val *out)
180 {
181         if (ldif_comparision_objectSid_isString(in)) {
182                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
183                         /* Perhaps not a string after all */
184                         return ldb_handler_copy(ldb, mem_ctx, in, out);
185                 }
186                 return 0;
187         }
188         return ldb_handler_copy(ldb, mem_ctx, in, out);
189 }
190
191 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
192                               const struct ldb_val *in, struct ldb_val *out)
193 {
194         struct dom_sid sid;
195         enum ndr_err_code ndr_err;
196         if (ldif_comparision_objectSid_isString(in)) {
197                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
198                         return 0;
199                 }
200         }
201         
202         /* Perhaps not a string after all */
203         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
204
205         if (!out->data) {
206                 return -1;
207         }
208
209         (*out).length = strhex_to_str((char *)out->data, out->length,
210                                      (const char *)in->data, in->length);
211
212         /* Check it looks like a SID */
213         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, &sid,
214                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
215         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
216                 return -1;
217         }
218         return 0;
219 }
220
221 /*
222   convert a ldif formatted objectGUID to a NDR formatted blob
223 */
224 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
225                                 const struct ldb_val *in, struct ldb_val *out)
226 {
227         struct GUID guid;
228         NTSTATUS status;
229
230         status = GUID_from_data_blob(in, &guid);
231         if (!NT_STATUS_IS_OK(status)) {
232                 return -1;
233         }
234
235         status = GUID_to_ndr_blob(&guid, mem_ctx, out);
236         if (!NT_STATUS_IS_OK(status)) {
237                 return -1;
238         }
239         return 0;
240 }
241
242 /*
243   convert a NDR formatted blob to a ldif formatted objectGUID
244 */
245 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
246                                  const struct ldb_val *in, struct ldb_val *out)
247 {
248         struct GUID guid;
249         NTSTATUS status;
250
251         status = GUID_from_ndr_blob(in, &guid);
252         if (!NT_STATUS_IS_OK(status)) {
253                 return -1;
254         }
255         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
256         if (out->data == NULL) {
257                 return -1;
258         }
259         out->length = strlen((const char *)out->data);
260         return 0;
261 }
262
263 static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
264 {
265         if (v->length != 36 && v->length != 38) return false;
266
267         /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
268         return true;
269 }
270
271 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
272                               const struct ldb_val *in, struct ldb_val *out)
273 {
274         struct GUID guid;
275         NTSTATUS status;
276
277         if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
278                 return 0;
279         }
280
281         /* Try as 'hex' form */
282         if (in->length != 32) {
283                 return -1;
284         }
285                 
286         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
287         
288         if (!out->data) {
289                 return -1;
290         }
291         
292         (*out).length = strhex_to_str((char *)out->data, out->length,
293                                       (const char *)in->data, in->length);
294         
295         /* Check it looks like a GUID */
296         status = GUID_from_ndr_blob(out, &guid);
297         if (!NT_STATUS_IS_OK(status)) {
298                 data_blob_free(out);
299                 return -1;
300         }
301         return 0;
302 }
303
304 /*
305   compare two objectGUIDs
306 */
307 static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
308                                      const struct ldb_val *v1, const struct ldb_val *v2)
309 {
310         if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) {
311                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
312         } else if (ldif_comparision_objectGUID_isString(v1)
313                    && !ldif_comparision_objectGUID_isString(v2)) {
314                 struct ldb_val v;
315                 int ret;
316                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
317                         /* Perhaps it wasn't a valid string after all */
318                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
319                 }
320                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
321                 talloc_free(v.data);
322                 return ret;
323         } else if (!ldif_comparision_objectGUID_isString(v1)
324                    && ldif_comparision_objectGUID_isString(v2)) {
325                 struct ldb_val v;
326                 int ret;
327                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
328                         /* Perhaps it wasn't a valid string after all */
329                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
330                 }
331                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
332                 talloc_free(v.data);
333                 return ret;
334         }
335         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
336 }
337
338 /*
339   canonicalise a objectGUID
340 */
341 static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
342                                        const struct ldb_val *in, struct ldb_val *out)
343 {
344         if (ldif_comparision_objectGUID_isString(in)) {
345                 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
346                         /* Perhaps it wasn't a valid string after all */
347                         return ldb_handler_copy(ldb, mem_ctx, in, out);
348                 }
349                 return 0;
350         }
351         return ldb_handler_copy(ldb, mem_ctx, in, out);
352 }
353
354
355 /*
356   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
357 */
358 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
359                                           const struct ldb_val *in, struct ldb_val *out)
360 {
361         struct security_descriptor *sd;
362         enum ndr_err_code ndr_err;
363
364         sd = talloc(mem_ctx, struct security_descriptor);
365         if (sd == NULL) {
366                 return -1;
367         }
368
369         ndr_err = ndr_pull_struct_blob(in, sd, sd,
370                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
371         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
372                 /* If this does not parse, then it is probably SDDL, and we should try it that way */
373
374                 const struct dom_sid *sid = samdb_domain_sid(ldb);
375                 talloc_free(sd);
376                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
377                 if (sd == NULL) {
378                         return -1;
379                 }
380         }
381
382         ndr_err = ndr_push_struct_blob(out, mem_ctx, sd,
383                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
384         talloc_free(sd);
385         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
386                 return -1;
387         }
388
389         return 0;
390 }
391
392 /*
393   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
394 */
395 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
396                                            const struct ldb_val *in, struct ldb_val *out)
397 {
398         struct security_descriptor *sd;
399         enum ndr_err_code ndr_err;
400
401         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
402                 return ldif_write_NDR(ldb, mem_ctx, in, out, 
403                                       sizeof(struct security_descriptor),
404                                       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor,
405                                       (ndr_print_fn_t)ndr_print_security_descriptor,
406                                       true);
407                                       
408         }
409
410         sd = talloc(mem_ctx, struct security_descriptor);
411         if (sd == NULL) {
412                 return -1;
413         }
414         /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
415         ndr_err = ndr_pull_struct_blob(in, sd, sd,
416                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
417         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418                 talloc_free(sd);
419                 return -1;
420         }
421         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, samdb_domain_sid_cache_only(ldb));
422         talloc_free(sd);
423         if (out->data == NULL) {
424                 return -1;
425         }
426         out->length = strlen((const char *)out->data);
427         return 0;
428 }
429
430 /*
431   convert a string formatted SDDL to a ldif formatted ntSecurityDescriptor (SDDL format)
432 */
433 static int ldif_write_sddlSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
434                                            const struct ldb_val *in, struct ldb_val *out)
435 {
436         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
437                 struct security_descriptor *sd;
438                 const struct dom_sid *sid = samdb_domain_sid(ldb);
439
440                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
441                 out->data = (uint8_t *)ndr_print_struct_string(mem_ctx,
442                                         (ndr_print_fn_t)ndr_print_security_descriptor,
443                                         "SDDL", sd);
444                 out->length = strlen((const char *)out->data);
445                 talloc_free(sd);
446                 return 0;
447         }
448
449         return ldb_handler_copy(ldb, mem_ctx, in, out);
450 }
451
452 /* 
453    canonicalise an objectCategory.  We use the long form as the canonical form:
454    'person' becomes cn=Person,cn=Schema,cn=Configuration,<basedn>
455
456    Also any short name of an objectClass that points to a different
457    class (such as user) has the canonical form of the class it's
458    defaultObjectCategory points to (eg
459    cn=Person,cn=Schema,cn=Configuration,<basedn>)
460 */
461
462 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
463                                             const struct ldb_val *in, struct ldb_val *out)
464 {
465         struct ldb_dn *dn1 = NULL;
466         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
467         const struct dsdb_class *sclass;
468         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
469         if (!tmp_ctx) {
470                 return LDB_ERR_OPERATIONS_ERROR;
471         }
472
473         if (!schema) {
474                 talloc_free(tmp_ctx);
475                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
476                 if (in->data && !out->data) {
477                         return LDB_ERR_OPERATIONS_ERROR;
478                 }
479                 return LDB_SUCCESS;
480         }
481         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
482         if ( ! ldb_dn_validate(dn1)) {
483                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
484                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
485                 if (sclass) {
486                         struct ldb_dn *dn = ldb_dn_new(tmp_ctx, ldb,
487                                                        sclass->defaultObjectCategory);
488                         if (dn == NULL) {
489                                 talloc_free(tmp_ctx);
490                                 return LDB_ERR_OPERATIONS_ERROR;
491                         }
492
493                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
494                         talloc_free(tmp_ctx);
495
496                         if (!out->data) {
497                                 return LDB_ERR_OPERATIONS_ERROR;
498                         }
499                         return LDB_SUCCESS;
500                 } else {
501                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
502                         talloc_free(tmp_ctx);
503
504                         if (in->data && !out->data) {
505                                 return LDB_ERR_OPERATIONS_ERROR;
506                         }
507                         return LDB_SUCCESS;
508                 }
509         }
510         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
511         talloc_free(tmp_ctx);
512
513         if (!out->data) {
514                 return LDB_ERR_OPERATIONS_ERROR;
515         }
516         return LDB_SUCCESS;
517 }
518
519 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
520                                           const struct ldb_val *v1,
521                                           const struct ldb_val *v2)
522 {
523         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
524                                   v1, v2);
525 }
526
527 /*
528   convert a NDR formatted blob to a ldif formatted schemaInfo
529 */
530 static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
531                                  const struct ldb_val *in, struct ldb_val *out)
532 {
533         return ldif_write_NDR(ldb, mem_ctx, in, out,
534                               sizeof(struct repsFromToBlob),
535                               (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
536                               (ndr_print_fn_t)ndr_print_schemaInfoBlob,
537                               true);
538 }
539
540 /*
541   convert a ldif formatted prefixMap to a NDR formatted blob
542 */
543 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
544                                const struct ldb_val *in, struct ldb_val *out)
545 {
546         struct prefixMapBlob *blob;
547         enum ndr_err_code ndr_err;
548         char *string, *line, *p, *oid;
549         DATA_BLOB oid_blob;
550
551         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
552
553         if (tmp_ctx == NULL) {
554                 return -1;
555         }
556
557         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
558         if (blob == NULL) {
559                 talloc_free(tmp_ctx);
560                 return -1;
561         }
562
563         /* use the switch value to detect if this is in the binary
564          * format
565          */
566         if (in->length >= 4 && IVAL(in->data, 0) == PREFIX_MAP_VERSION_DSDB) {
567                 ndr_err = ndr_pull_struct_blob(in, tmp_ctx, blob,
568                                                (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
569                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
570                         ndr_err = ndr_push_struct_blob(out, mem_ctx,
571                                                        blob,
572                                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
573                         talloc_free(tmp_ctx);
574                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
575                                 return -1;
576                         }
577                         return 0;
578                 }
579         }
580
581         /* If this does not parse, then it is probably the text version, and we should try it that way */
582         blob->version = PREFIX_MAP_VERSION_DSDB;
583         
584         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
585         if (string == NULL) {
586                 talloc_free(blob);
587                 return -1;
588         }
589
590         line = string;
591         while (line && line[0]) {
592                 p=strchr(line, ';');
593                 if (p) {
594                         p[0] = '\0';
595                 } else {
596                         p=strchr(line, '\n');
597                         if (p) {
598                                 p[0] = '\0';
599                         }
600                 }
601                 /* allow a trailing separator */
602                 if (line == p) {
603                         break;
604                 }
605                 
606                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
607                                                          blob->ctr.dsdb.mappings, 
608                                                          struct drsuapi_DsReplicaOIDMapping,
609                                                          blob->ctr.dsdb.num_mappings+1);
610                 if (!blob->ctr.dsdb.mappings) {
611                         talloc_free(tmp_ctx);
612                         return -1;
613                 }
614
615                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
616
617                 if (oid[0] != ':') {
618                         talloc_free(tmp_ctx);
619                         return -1;
620                 }
621
622                 /* we know there must be at least ":" */
623                 oid++;
624
625                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
626                         talloc_free(tmp_ctx);
627                         return -1;
628                 }
629                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
630                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
631
632                 blob->ctr.dsdb.num_mappings++;
633
634                 /* Now look past the terminator we added above */
635                 if (p) {
636                         line = p + 1;
637                 } else {
638                         line = NULL;
639                 }
640         }
641
642         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
643                                        blob,
644                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
645         talloc_free(tmp_ctx);
646         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
647                 return -1;
648         }
649         return 0;
650 }
651
652 /*
653   convert a NDR formatted blob to a ldif formatted prefixMap
654 */
655 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
656                                 const struct ldb_val *in, struct ldb_val *out)
657 {
658         struct prefixMapBlob *blob;
659         enum ndr_err_code ndr_err;
660         char *string;
661         uint32_t i;
662
663         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
664                 int err;
665                 /* try to decode the blob as S4 prefixMap */
666                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
667                                      sizeof(struct prefixMapBlob),
668                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
669                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
670                                      false);
671                 if (0 == err) {
672                         return err;
673                 }
674                 /* try parsing it as Windows PrefixMap value */
675                 return ldif_write_NDR(ldb, mem_ctx, in, out,
676                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
677                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
678                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
679                                       true);
680         }
681
682         blob = talloc(mem_ctx, struct prefixMapBlob);
683         if (blob == NULL) {
684                 return -1;
685         }
686         ndr_err = ndr_pull_struct_blob_all(in, blob, 
687                                            blob,
688                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
689         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
690                 goto failed;
691         }
692         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
693                 goto failed;
694         }
695         string = talloc_strdup(mem_ctx, "");
696         if (string == NULL) {
697                 goto failed;
698         }
699
700         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
701                 DATA_BLOB oid_blob;
702                 char *partial_oid = NULL;
703
704                 if (i > 0) {
705                         string = talloc_asprintf_append(string, ";"); 
706                 }
707
708                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
709                                            blob->ctr.dsdb.mappings[i].oid.length);
710                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
711                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
712                                   blob->ctr.dsdb.mappings[i].id_prefix));
713                         goto failed;
714                 }
715                 string = talloc_asprintf_append(string, "%u:%s", 
716                                                    blob->ctr.dsdb.mappings[i].id_prefix,
717                                                    partial_oid);
718                 talloc_free(discard_const(partial_oid));
719                 if (string == NULL) {
720                         goto failed;
721                 }
722         }
723
724         talloc_free(blob);
725         *out = data_blob_string_const(string);
726         return 0;
727
728 failed:
729         talloc_free(blob);
730         return -1;
731 }
732
733 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
734 {
735         if (v->length < 4) {
736                 return true;
737         }
738
739         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
740                 return false;
741         }
742         
743         return true;
744 }
745
746 /*
747   canonicalise a prefixMap
748 */
749 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
750                                        const struct ldb_val *in, struct ldb_val *out)
751 {
752         if (ldif_comparision_prefixMap_isString(in)) {
753                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
754         }
755         return ldb_handler_copy(ldb, mem_ctx, in, out);
756 }
757
758 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
759                                      const struct ldb_val *v1,
760                                      const struct ldb_val *v2)
761 {
762         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
763                                   v1, v2);
764 }
765
766 /* length limited conversion of a ldb_val to a int32_t */
767 static int val_to_int32(const struct ldb_val *in, int32_t *v)
768 {
769         char *end;
770         char buf[64];
771
772         /* make sure we don't read past the end of the data */
773         if (in->length > sizeof(buf)-1) {
774                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
775         }
776         strncpy(buf, (char *)in->data, in->length);
777         buf[in->length] = 0;
778
779         /* We've to use "strtoll" here to have the intended overflows.
780          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
781         *v = (int32_t) strtoll(buf, &end, 0);
782         if (*end != 0) {
783                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
784         }
785         return LDB_SUCCESS;
786 }
787
788 /* length limited conversion of a ldb_val to a int64_t */
789 static int val_to_int64(const struct ldb_val *in, int64_t *v)
790 {
791         char *end;
792         char buf[64];
793
794         /* make sure we don't read past the end of the data */
795         if (in->length > sizeof(buf)-1) {
796                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
797         }
798         strncpy(buf, (char *)in->data, in->length);
799         buf[in->length] = 0;
800
801         *v = (int64_t) strtoll(buf, &end, 0);
802         if (*end != 0) {
803                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
804         }
805         return LDB_SUCCESS;
806 }
807
808 /* Canonicalisation of two 32-bit integers */
809 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
810                         const struct ldb_val *in, struct ldb_val *out)
811 {
812         int32_t i;
813         int ret;
814
815         ret = val_to_int32(in, &i);
816         if (ret != LDB_SUCCESS) {
817                 return ret;
818         }
819         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
820         if (out->data == NULL) {
821                 ldb_oom(ldb);
822                 return LDB_ERR_OPERATIONS_ERROR;
823         }
824         out->length = strlen((char *)out->data);
825         return 0;
826 }
827
828 /* Comparison of two 32-bit integers */
829 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
830                                  const struct ldb_val *v1, const struct ldb_val *v2)
831 {
832         int32_t i1=0, i2=0;
833         val_to_int32(v1, &i1);
834         val_to_int32(v2, &i2);
835         if (i1 == i2) return 0;
836         return i1 > i2? 1 : -1;
837 }
838
839 /* Canonicalisation of two 64-bit integers */
840 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
841                                    const struct ldb_val *in, struct ldb_val *out)
842 {
843         int64_t i;
844         int ret;
845
846         ret = val_to_int64(in, &i);
847         if (ret != LDB_SUCCESS) {
848                 return ret;
849         }
850         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
851         if (out->data == NULL) {
852                 ldb_oom(ldb);
853                 return LDB_ERR_OPERATIONS_ERROR;
854         }
855         out->length = strlen((char *)out->data);
856         return 0;
857 }
858
859 /* Comparison of two 64-bit integers */
860 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
861                                  const struct ldb_val *v1, const struct ldb_val *v2)
862 {
863         int64_t i1=0, i2=0;
864         val_to_int64(v1, &i1);
865         val_to_int64(v2, &i2);
866         if (i1 == i2) return 0;
867         return i1 > i2? 1 : -1;
868 }
869
870 /*
871   convert a NDR formatted blob to a ldif formatted repsFromTo
872 */
873 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
874                                  const struct ldb_val *in, struct ldb_val *out)
875 {
876         return ldif_write_NDR(ldb, mem_ctx, in, out, 
877                               sizeof(struct repsFromToBlob),
878                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
879                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
880                               true);
881 }
882
883 /*
884   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
885 */
886 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
887                                            const struct ldb_val *in, struct ldb_val *out)
888 {
889         return ldif_write_NDR(ldb, mem_ctx, in, out, 
890                               sizeof(struct replPropertyMetaDataBlob),
891                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
892                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
893                               true);
894 }
895
896 /*
897   convert a NDR formatted blob to a ldif formatted replUpToDateVector
898 */
899 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
900                                          const struct ldb_val *in, struct ldb_val *out)
901 {
902         return ldif_write_NDR(ldb, mem_ctx, in, out, 
903                               sizeof(struct replUpToDateVectorBlob),
904                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
905                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
906                               true);
907 }
908
909 static int ldif_write_dn_binary_NDR(struct ldb_context *ldb, void *mem_ctx,
910                                     const struct ldb_val *in, struct ldb_val *out,
911                                     size_t struct_size,
912                                     ndr_pull_flags_fn_t pull_fn,
913                                     ndr_print_fn_t print_fn,
914                                     bool mask_errors)
915 {
916         uint8_t *p = NULL;
917         enum ndr_err_code err;
918         struct dsdb_dn *dsdb_dn = NULL;
919         char *dn_str = NULL;
920         char *str = NULL;
921
922         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
923                 return ldb_handler_copy(ldb, mem_ctx, in, out);
924         }
925
926         dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
927         if (dsdb_dn == NULL) {
928                 return ldb_handler_copy(ldb, mem_ctx, in, out);
929         }
930
931         p = talloc_size(dsdb_dn, struct_size);
932         if (p == NULL) {
933                 TALLOC_FREE(dsdb_dn);
934                 return ldb_handler_copy(ldb, mem_ctx, in, out);
935         }
936
937         err = ndr_pull_struct_blob(&dsdb_dn->extra_part, p, p, pull_fn);
938         if (err != NDR_ERR_SUCCESS) {
939                 /* fail in not in mask_error mode */
940                 if (!mask_errors) {
941                         return -1;
942                 }
943                 TALLOC_FREE(dsdb_dn);
944                 return ldb_handler_copy(ldb, mem_ctx, in, out);
945         }
946
947         dn_str = ldb_dn_get_extended_linearized(dsdb_dn, dsdb_dn->dn, 1);
948         if (dn_str == NULL) {
949                 TALLOC_FREE(dsdb_dn);
950                 return ldb_handler_copy(ldb, mem_ctx, in, out);
951         }
952
953         str = ndr_print_struct_string(mem_ctx, print_fn, dn_str, p);
954         TALLOC_FREE(dsdb_dn);
955         if (str == NULL) {
956                 return ldb_handler_copy(ldb, mem_ctx, in, out);
957         }
958
959         *out = data_blob_string_const(str);
960         return 0;
961 }
962
963 static int ldif_write_msDS_RevealedUsers(struct ldb_context *ldb, void *mem_ctx,
964                                          const struct ldb_val *in, struct ldb_val *out)
965 {
966         return ldif_write_dn_binary_NDR(ldb, mem_ctx, in, out,
967                               sizeof(struct replPropertyMetaData1),
968                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1,
969                               (ndr_print_fn_t)ndr_print_replPropertyMetaData1,
970                               true);
971 }
972
973 /*
974   convert a NDR formatted blob to a ldif formatted dnsRecord
975 */
976 static int ldif_write_dnsRecord(struct ldb_context *ldb, void *mem_ctx,
977                                 const struct ldb_val *in, struct ldb_val *out)
978 {
979         return ldif_write_NDR(ldb, mem_ctx, in, out,
980                               sizeof(struct dnsp_DnssrvRpcRecord),
981                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord,
982                               (ndr_print_fn_t)ndr_print_dnsp_DnssrvRpcRecord,
983                               true);
984 }
985
986 /*
987   convert a NDR formatted blob to a ldif formatted dnsProperty
988 */
989 static int ldif_write_dnsProperty(struct ldb_context *ldb, void *mem_ctx,
990                                 const struct ldb_val *in, struct ldb_val *out)
991 {
992         return ldif_write_NDR(ldb, mem_ctx, in, out,
993                               sizeof(struct dnsp_DnsProperty),
994                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty,
995                               (ndr_print_fn_t)ndr_print_dnsp_DnsProperty,
996                               true);
997 }
998
999 /*
1000   convert a NDR formatted blob of a supplementalCredentials into text
1001 */
1002 static int ldif_write_supplementalCredentialsBlob(struct ldb_context *ldb, void *mem_ctx,
1003                                                   const struct ldb_val *in, struct ldb_val *out)
1004 {
1005         return ldif_write_NDR(ldb, mem_ctx, in, out,
1006                               sizeof(struct supplementalCredentialsBlob),
1007                               (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob,
1008                               (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob,
1009                               true);
1010 }
1011
1012 /*
1013   convert a NDR formatted blob to a ldif formatted trustAuthInOutBlob
1014 */
1015 static int ldif_write_trustAuthInOutBlob(struct ldb_context *ldb, void *mem_ctx,
1016                                            const struct ldb_val *in, struct ldb_val *out)
1017 {
1018         return ldif_write_NDR(ldb, mem_ctx, in, out,
1019                               sizeof(struct trustAuthInOutBlob),
1020                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob,
1021                               (ndr_print_fn_t)ndr_print_trustAuthInOutBlob,
1022                               true);
1023 }
1024
1025 /*
1026   convert a NDR formatted blob to a ldif formatted msDS-TrustForestTrustInfo
1027 */
1028 static int ldif_write_ForestTrustInfo(struct ldb_context *ldb, void *mem_ctx,
1029                                       const struct ldb_val *in, struct ldb_val *out)
1030 {
1031         return ldif_write_NDR(ldb, mem_ctx, in, out,
1032                               sizeof(struct ForestTrustInfo),
1033                               (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo,
1034                               (ndr_print_fn_t)ndr_print_ForestTrustInfo,
1035                               true);
1036 }
1037 /*
1038   convert a NDR formatted blob of a partialAttributeSet into text
1039 */
1040 static int ldif_write_partialAttributeSet(struct ldb_context *ldb, void *mem_ctx,
1041                                           const struct ldb_val *in, struct ldb_val *out)
1042 {
1043         return ldif_write_NDR(ldb, mem_ctx, in, out,
1044                               sizeof(struct partialAttributeSetBlob),
1045                               (ndr_pull_flags_fn_t)ndr_pull_partialAttributeSetBlob,
1046                               (ndr_print_fn_t)ndr_print_partialAttributeSetBlob,
1047                               true);
1048 }
1049
1050
1051 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
1052                                  const struct ldb_val *in, struct ldb_val *out)
1053 {
1054         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
1055         if (!out->data) {
1056                 return -1;
1057         }
1058         return 0;
1059 }
1060
1061 /*
1062   compare two dns
1063 */
1064 static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
1065                                         const struct ldb_val *v1, const struct ldb_val *v2)
1066 {
1067         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
1068         int ret;
1069
1070         if (dsdb_dn_is_deleted_val(v1)) {
1071                 /* If the DN is deleted, then we can't search for it */
1072                 return -1;
1073         }
1074
1075         if (dsdb_dn_is_deleted_val(v2)) {
1076                 /* If the DN is deleted, then we can't search for it */
1077                 return -1;
1078         }
1079
1080         dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
1081         if ( ! ldb_dn_validate(dn1)) return -1;
1082
1083         dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
1084         if ( ! ldb_dn_validate(dn2)) {
1085                 talloc_free(dn1);
1086                 return -1;
1087         }
1088
1089         ret = ldb_dn_compare(dn1, dn2);
1090
1091         talloc_free(dn1);
1092         talloc_free(dn2);
1093         return ret;
1094 }
1095
1096 static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
1097                                           const struct ldb_val *in, struct ldb_val *out)
1098 {
1099         struct ldb_dn *dn;
1100         int ret = -1;
1101
1102         out->length = 0;
1103         out->data = NULL;
1104
1105         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
1106         if ( ! ldb_dn_validate(dn)) {
1107                 return LDB_ERR_INVALID_DN_SYNTAX;
1108         }
1109
1110         /* By including the RMD_FLAGS of a deleted DN, we ensure it
1111          * does not casually match a not deleted DN */
1112         if (dsdb_dn_is_deleted_val(in)) {
1113                 out->data = (uint8_t *)talloc_asprintf(mem_ctx,
1114                                                        "<RMD_FLAGS=%u>%s",
1115                                                        dsdb_dn_val_rmd_flags(in),
1116                                                        ldb_dn_get_casefold(dn));
1117         } else {
1118                 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
1119         }
1120
1121         if (out->data == NULL) {
1122                 goto done;
1123         }
1124         out->length = strlen((char *)out->data);
1125
1126         ret = 0;
1127
1128 done:
1129         talloc_free(dn);
1130
1131         return ret;
1132 }
1133
1134
1135 /*
1136   write a 64 bit 2-part range
1137 */
1138 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
1139                               const struct ldb_val *in, struct ldb_val *out)
1140 {
1141         int64_t v;
1142         int ret;
1143         ret = val_to_int64(in, &v);
1144         if (ret != LDB_SUCCESS) {
1145                 return ret;
1146         }
1147         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
1148                                                (unsigned long)(v&0xFFFFFFFF),
1149                                                (unsigned long)(v>>32));
1150         if (out->data == NULL) {
1151                 ldb_oom(ldb);
1152                 return LDB_ERR_OPERATIONS_ERROR;
1153         }
1154         out->length = strlen((char *)out->data);
1155         return LDB_SUCCESS;
1156 }
1157
1158 /*
1159   read a 64 bit 2-part range
1160 */
1161 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
1162                               const struct ldb_val *in, struct ldb_val *out)
1163 {
1164         unsigned long high, low;
1165         char buf[64];
1166
1167         if (memchr(in->data, '-', in->length) == NULL) {
1168                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1169         }
1170
1171         if (in->length > sizeof(buf)-1) {
1172                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1173         }
1174         strncpy(buf, (const char *)in->data, in->length);
1175         buf[in->length] = 0;
1176
1177         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
1178                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1179         }
1180
1181         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
1182                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
1183
1184         if (out->data == NULL) {
1185                 ldb_oom(ldb);
1186                 return LDB_ERR_OPERATIONS_ERROR;
1187         }
1188         out->length = strlen((char *)out->data);
1189         return LDB_SUCCESS;
1190 }
1191
1192 /*
1193   when this operator_fn is set for a syntax, the backend calls is in
1194   preference to the comparison function. We are told the exact
1195   comparison operation that is needed, and we can return errors
1196  */
1197 static int samba_syntax_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
1198                                     const struct ldb_schema_attribute *a,
1199                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1200 {
1201         switch (operation) {
1202         case LDB_OP_AND:
1203         case LDB_OP_OR:
1204         case LDB_OP_NOT:
1205         case LDB_OP_SUBSTRING:
1206         case LDB_OP_APPROX:
1207         case LDB_OP_EXTENDED:
1208                 /* handled in the backends */
1209                 return LDB_ERR_INAPPROPRIATE_MATCHING;
1210
1211         case LDB_OP_GREATER:
1212         case LDB_OP_LESS:
1213         case LDB_OP_EQUALITY:
1214         {
1215                 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1216                 int ret;
1217                 if (tmp_ctx == NULL) {
1218                         return ldb_oom(ldb);
1219                 }
1220                 ret = a->syntax->comparison_fn(ldb, tmp_ctx, v1, v2);
1221                 talloc_free(tmp_ctx);
1222                 if (operation == LDB_OP_GREATER) {
1223                         *matched = (ret >= 0);
1224                 } else if (operation == LDB_OP_LESS) {
1225                         *matched = (ret <= 0);
1226                 } else {
1227                         *matched = (ret == 0);
1228                 }
1229                 return LDB_SUCCESS;
1230         }
1231
1232         case LDB_OP_PRESENT:
1233                 *matched = true;
1234                 return LDB_SUCCESS;
1235         }
1236
1237         /* we shouldn't get here */
1238         return LDB_ERR_INAPPROPRIATE_MATCHING;
1239 }
1240
1241 /*
1242   see if two DNs match, comparing first by GUID, then by SID, and
1243   finally by string components
1244  */
1245 static int samba_dn_extended_match(struct ldb_context *ldb,
1246                                    const struct ldb_val *v1,
1247                                    const struct ldb_val *v2,
1248                                    bool *matched)
1249 {
1250         TALLOC_CTX *tmp_ctx;
1251         struct ldb_dn *dn1, *dn2;
1252         const struct ldb_val *guid1, *guid2, *sid1, *sid2;
1253         uint32_t rmd_flags1, rmd_flags2;
1254
1255         tmp_ctx = talloc_new(ldb);
1256
1257         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v1);
1258         dn2 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v2);
1259         if (!dn1 || !dn2) {
1260                 /* couldn't parse as DN's */
1261                 talloc_free(tmp_ctx);
1262                 (*matched) = false;
1263                 return LDB_SUCCESS;
1264         }
1265
1266         rmd_flags1 = dsdb_dn_rmd_flags(dn1);
1267         rmd_flags2 = dsdb_dn_rmd_flags(dn2);
1268
1269         if ((rmd_flags1 & DSDB_RMD_FLAG_DELETED) !=
1270             (rmd_flags2 & DSDB_RMD_FLAG_DELETED)) {
1271                 /* only match if they have the same deletion status */
1272                 talloc_free(tmp_ctx);
1273                 (*matched) = false;
1274                 return LDB_SUCCESS;
1275         }
1276
1277
1278         guid1 = ldb_dn_get_extended_component(dn1, "GUID");
1279         guid2 = ldb_dn_get_extended_component(dn2, "GUID");
1280         if (guid1 && guid2) {
1281                 (*matched) = (data_blob_cmp(guid1, guid2) == 0);
1282                 talloc_free(tmp_ctx);
1283                 return LDB_SUCCESS;
1284         }
1285
1286         sid1 = ldb_dn_get_extended_component(dn1, "SID");
1287         sid2 = ldb_dn_get_extended_component(dn2, "SID");
1288         if (sid1 && sid2) {
1289                 (*matched) = (data_blob_cmp(sid1, sid2) == 0);
1290                 talloc_free(tmp_ctx);
1291                 return LDB_SUCCESS;
1292         }
1293
1294         (*matched) = (ldb_dn_compare(dn1, dn2) == 0);
1295
1296         talloc_free(tmp_ctx);
1297         return LDB_SUCCESS;
1298 }
1299
1300 /*
1301   special operation for DNs, to take account of the RMD_FLAGS deleted bit
1302  */
1303 static int samba_syntax_operator_dn(struct ldb_context *ldb, enum ldb_parse_op operation,
1304                                     const struct ldb_schema_attribute *a,
1305                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1306 {
1307         if (operation == LDB_OP_PRESENT && dsdb_dn_is_deleted_val(v1)) {
1308                 /* If the DN is deleted, then we can't search for it */
1309
1310                 /* should this be for equality too? */
1311                 *matched = false;
1312                 return LDB_SUCCESS;
1313         }
1314
1315         if (operation == LDB_OP_EQUALITY &&
1316             samba_dn_extended_match(ldb, v1, v2, matched) == LDB_SUCCESS) {
1317                 return LDB_SUCCESS;
1318         }
1319
1320         return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
1321 }
1322
1323
1324 static const struct ldb_schema_syntax samba_syntaxes[] = {
1325         {
1326                 .name             = LDB_SYNTAX_SAMBA_SID,
1327                 .ldif_read_fn     = ldif_read_objectSid,
1328                 .ldif_write_fn    = ldif_write_objectSid,
1329                 .canonicalise_fn  = ldif_canonicalise_objectSid,
1330                 .comparison_fn    = ldif_comparison_objectSid,
1331                 .operator_fn      = samba_syntax_operator_fn
1332         },{
1333                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
1334                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
1335                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
1336                 .canonicalise_fn  = ldb_handler_copy,
1337                 .comparison_fn    = ldb_comparison_binary,
1338                 .operator_fn      = samba_syntax_operator_fn
1339         },{
1340                 .name             = LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR,
1341                 .ldif_read_fn     = ldb_handler_copy,
1342                 .ldif_write_fn    = ldif_write_sddlSecurityDescriptor,
1343                 .canonicalise_fn  = ldb_handler_fold,
1344                 .comparison_fn    = ldb_comparison_fold,
1345                 .operator_fn      = samba_syntax_operator_fn
1346         },{
1347                 .name             = LDB_SYNTAX_SAMBA_GUID,
1348                 .ldif_read_fn     = ldif_read_objectGUID,
1349                 .ldif_write_fn    = ldif_write_objectGUID,
1350                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
1351                 .comparison_fn    = ldif_comparison_objectGUID,
1352                 .operator_fn      = samba_syntax_operator_fn
1353         },{
1354                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
1355                 .ldif_read_fn     = ldb_handler_copy,
1356                 .ldif_write_fn    = ldb_handler_copy,
1357                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
1358                 .comparison_fn    = ldif_comparison_objectCategory,
1359                 .operator_fn      = samba_syntax_operator_fn
1360         },{
1361                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
1362                 .ldif_read_fn     = ldb_handler_copy,
1363                 .ldif_write_fn    = ldif_write_schemaInfo,
1364                 .canonicalise_fn  = ldb_handler_copy,
1365                 .comparison_fn    = ldb_comparison_binary,
1366                 .operator_fn      = samba_syntax_operator_fn
1367         },{
1368                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
1369                 .ldif_read_fn     = ldif_read_prefixMap,
1370                 .ldif_write_fn    = ldif_write_prefixMap,
1371                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
1372                 .comparison_fn    = ldif_comparison_prefixMap,
1373                 .operator_fn      = samba_syntax_operator_fn
1374         },{
1375                 .name             = LDB_SYNTAX_SAMBA_INT32,
1376                 .ldif_read_fn     = ldb_handler_copy,
1377                 .ldif_write_fn    = ldb_handler_copy,
1378                 .canonicalise_fn  = ldif_canonicalise_int32,
1379                 .comparison_fn    = ldif_comparison_int32,
1380                 .operator_fn      = samba_syntax_operator_fn
1381         },{
1382                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
1383                 .ldif_read_fn     = ldb_handler_copy,
1384                 .ldif_write_fn    = ldif_write_repsFromTo,
1385                 .canonicalise_fn  = ldb_handler_copy,
1386                 .comparison_fn    = ldb_comparison_binary,
1387                 .operator_fn      = samba_syntax_operator_fn
1388         },{
1389                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
1390                 .ldif_read_fn     = ldb_handler_copy,
1391                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
1392                 .canonicalise_fn  = ldb_handler_copy,
1393                 .comparison_fn    = ldb_comparison_binary,
1394                 .operator_fn      = samba_syntax_operator_fn
1395         },{
1396                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
1397                 .ldif_read_fn     = ldb_handler_copy,
1398                 .ldif_write_fn    = ldif_write_replUpToDateVector,
1399                 .canonicalise_fn  = ldb_handler_copy,
1400                 .comparison_fn    = ldb_comparison_binary,
1401                 .operator_fn      = samba_syntax_operator_fn
1402         },{
1403                 .name             = LDB_SYNTAX_SAMBA_REVEALEDUSERS,
1404                 .ldif_read_fn     = ldb_handler_copy,
1405                 .ldif_write_fn    = ldif_write_msDS_RevealedUsers,
1406                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1407                 .comparison_fn    = dsdb_dn_binary_comparison,
1408                 .operator_fn      = samba_syntax_operator_fn
1409         },{
1410                 .name             = LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB,
1411                 .ldif_read_fn     = ldb_handler_copy,
1412                 .ldif_write_fn    = ldif_write_trustAuthInOutBlob,
1413                 .canonicalise_fn  = ldb_handler_copy,
1414                 .comparison_fn    = ldb_comparison_binary,
1415                 .operator_fn      = samba_syntax_operator_fn
1416         },{
1417                 .name             = LDB_SYNTAX_SAMBA_FORESTTRUSTINFO,
1418                 .ldif_read_fn     = ldb_handler_copy,
1419                 .ldif_write_fn    = ldif_write_ForestTrustInfo,
1420                 .canonicalise_fn  = ldb_handler_copy,
1421                 .comparison_fn    = ldb_comparison_binary,
1422                 .operator_fn      = samba_syntax_operator_fn
1423         },{
1424                 .name             = DSDB_SYNTAX_BINARY_DN,
1425                 .ldif_read_fn     = ldb_handler_copy,
1426                 .ldif_write_fn    = ldb_handler_copy,
1427                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1428                 .comparison_fn    = dsdb_dn_binary_comparison,
1429                 .operator_fn      = samba_syntax_operator_fn
1430         },{
1431                 .name             = DSDB_SYNTAX_STRING_DN,
1432                 .ldif_read_fn     = ldb_handler_copy,
1433                 .ldif_write_fn    = ldb_handler_copy,
1434                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
1435                 .comparison_fn    = dsdb_dn_string_comparison,
1436                 .operator_fn      = samba_syntax_operator_fn
1437         },{
1438                 .name             = LDB_SYNTAX_DN,
1439                 .ldif_read_fn     = ldb_handler_copy,
1440                 .ldif_write_fn    = ldb_handler_copy,
1441                 .canonicalise_fn  = samba_ldb_dn_link_canonicalise,
1442                 .comparison_fn    = samba_ldb_dn_link_comparison,
1443                 .operator_fn      = samba_syntax_operator_dn
1444         },{
1445                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1446                 .ldif_read_fn     = ldif_read_range64,
1447                 .ldif_write_fn    = ldif_write_range64,
1448                 .canonicalise_fn  = ldif_canonicalise_int64,
1449                 .comparison_fn    = ldif_comparison_int64,
1450                 .operator_fn      = samba_syntax_operator_fn
1451         },{
1452                 .name             = LDB_SYNTAX_SAMBA_DNSRECORD,
1453                 .ldif_read_fn     = ldb_handler_copy,
1454                 .ldif_write_fn    = ldif_write_dnsRecord,
1455                 .canonicalise_fn  = ldb_handler_copy,
1456                 .comparison_fn    = ldb_comparison_binary,
1457                 .operator_fn      = samba_syntax_operator_fn
1458         },{
1459                 .name             = LDB_SYNTAX_SAMBA_DNSPROPERTY,
1460                 .ldif_read_fn     = ldb_handler_copy,
1461                 .ldif_write_fn    = ldif_write_dnsProperty,
1462                 .canonicalise_fn  = ldb_handler_copy,
1463                 .comparison_fn    = ldb_comparison_binary,
1464                 .operator_fn      = samba_syntax_operator_fn
1465         },{
1466                 .name             = LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS,
1467                 .ldif_read_fn     = ldb_handler_copy,
1468                 .ldif_write_fn    = ldif_write_supplementalCredentialsBlob,
1469                 .canonicalise_fn  = ldb_handler_copy,
1470                 .comparison_fn    = ldb_comparison_binary,
1471                 .operator_fn      = samba_syntax_operator_fn
1472         },{
1473                 .name             = LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET,
1474                 .ldif_read_fn     = ldb_handler_copy,
1475                 .ldif_write_fn    = ldif_write_partialAttributeSet,
1476                 .canonicalise_fn  = ldb_handler_copy,
1477                 .comparison_fn    = ldb_comparison_binary,
1478                 .operator_fn      = samba_syntax_operator_fn
1479         }
1480 };
1481
1482 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1483         {
1484                 .name             = "SID",
1485                 .read_fn          = extended_dn_read_SID,
1486                 .write_clear_fn   = ldif_write_objectSid,
1487                 .write_hex_fn     = extended_dn_write_hex
1488         },{
1489                 .name             = "GUID",
1490                 .read_fn          = extended_dn_read_GUID,
1491                 .write_clear_fn   = ldif_write_objectGUID,
1492                 .write_hex_fn     = extended_dn_write_hex
1493         },{
1494                 .name             = "WKGUID",
1495                 .read_fn          = ldb_handler_copy,
1496                 .write_clear_fn   = ldb_handler_copy,
1497                 .write_hex_fn     = ldb_handler_copy
1498         },{
1499                 .name             = "RMD_INVOCID",
1500                 .read_fn          = extended_dn_read_GUID,
1501                 .write_clear_fn   = ldif_write_objectGUID,
1502                 .write_hex_fn     = extended_dn_write_hex
1503         },{
1504                 .name             = "RMD_FLAGS",
1505                 .read_fn          = ldb_handler_copy,
1506                 .write_clear_fn   = ldb_handler_copy,
1507                 .write_hex_fn     = ldb_handler_copy
1508         },{
1509                 .name             = "RMD_ADDTIME",
1510                 .read_fn          = ldb_handler_copy,
1511                 .write_clear_fn   = ldb_handler_copy,
1512                 .write_hex_fn     = ldb_handler_copy
1513         },{
1514                 .name             = "RMD_CHANGETIME",
1515                 .read_fn          = ldb_handler_copy,
1516                 .write_clear_fn   = ldb_handler_copy,
1517                 .write_hex_fn     = ldb_handler_copy
1518         },{
1519                 .name             = "RMD_LOCAL_USN",
1520                 .read_fn          = ldb_handler_copy,
1521                 .write_clear_fn   = ldb_handler_copy,
1522                 .write_hex_fn     = ldb_handler_copy
1523         },{
1524                 .name             = "RMD_ORIGINATING_USN",
1525                 .read_fn          = ldb_handler_copy,
1526                 .write_clear_fn   = ldb_handler_copy,
1527                 .write_hex_fn     = ldb_handler_copy
1528         },{
1529                 .name             = "RMD_VERSION",
1530                 .read_fn          = ldb_handler_copy,
1531                 .write_clear_fn   = ldb_handler_copy,
1532                 .write_hex_fn     = ldb_handler_copy
1533         }
1534 };
1535
1536 /* TODO: Should be dynamic at some point */
1537 static const struct {
1538         const char *name;
1539         const char *syntax;
1540 } samba_attributes[] = {
1541         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1542         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1543         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1544         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1545         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1546         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1547         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1548         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1549         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1550         { "msDS-RevealedUsers",         LDB_SYNTAX_SAMBA_REVEALEDUSERS },
1551         { "trustAuthIncoming",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1552         { "trustAuthOutgoing",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1553         { "msDS-TrustForestTrustInfo",  LDB_SYNTAX_SAMBA_FORESTTRUSTINFO },
1554         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1555         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1556         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1557         { "defaultSecurityDescriptor",  LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR },
1558
1559         /*
1560          * these are extracted by searching
1561          * (&(attributeSyntax=2.5.5.17)(omSyntax=4))
1562          *
1563          * Except: msAuthz-CentralAccessPolicyID as it might be a GUID see:
1564          * adminDescription: For a Central Access Policy, this attribute defines a GUID t
1565          * hat can be used to identify the set of policies when applied to a resource.
1566          * Until we see a msAuthz-CentralAccessPolicyID value on a windows
1567          * server, we ignore it here.
1568          */
1569         { "mS-DS-CreatorSID",           LDB_SYNTAX_SAMBA_SID },
1570         { "msDS-QuotaTrustee",          LDB_SYNTAX_SAMBA_SID },
1571         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1572         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1573         { "tokenGroupsGlobalAndUniversal", LDB_SYNTAX_SAMBA_SID },
1574         { "tokenGroupsNoGCAcceptable",  LDB_SYNTAX_SAMBA_SID },
1575         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1576         { "sIDHistory",                 LDB_SYNTAX_SAMBA_SID },
1577         { "syncWithSID",                LDB_SYNTAX_SAMBA_SID },
1578
1579         /*
1580          * these are extracted by searching
1581          * (&(attributeSyntax=2.5.5.10)(rangeLower=16)(rangeUpper=16)(omSyntax=4))
1582          */
1583         { "attributeSecurityGUID",              LDB_SYNTAX_SAMBA_GUID },
1584         { "categoryId",                         LDB_SYNTAX_SAMBA_GUID },
1585         { "controlAccessRights",                LDB_SYNTAX_SAMBA_GUID },
1586         { "currMachineId",                      LDB_SYNTAX_SAMBA_GUID },
1587         { "fRSReplicaSetGUID",                  LDB_SYNTAX_SAMBA_GUID },
1588         { "fRSVersionGUID",                     LDB_SYNTAX_SAMBA_GUID },
1589         { "implementedCategories",              LDB_SYNTAX_SAMBA_GUID },
1590         { "msDS-AzObjectGuid",                  LDB_SYNTAX_SAMBA_GUID },
1591         { "msDS-GenerationId",                  LDB_SYNTAX_SAMBA_GUID },
1592         { "msDS-OptionalFeatureGUID",           LDB_SYNTAX_SAMBA_GUID },
1593         { "msDFSR-ContentSetGuid",              LDB_SYNTAX_SAMBA_GUID },
1594         { "msDFSR-ReplicationGroupGuid",        LDB_SYNTAX_SAMBA_GUID },
1595         { "mSMQDigests",                        LDB_SYNTAX_SAMBA_GUID },
1596         { "mSMQOwnerID",                        LDB_SYNTAX_SAMBA_GUID },
1597         { "mSMQQMID",                           LDB_SYNTAX_SAMBA_GUID },
1598         { "mSMQQueueType",                      LDB_SYNTAX_SAMBA_GUID },
1599         { "mSMQSites",                          LDB_SYNTAX_SAMBA_GUID },
1600         { "netbootGUID",                        LDB_SYNTAX_SAMBA_GUID },
1601         { "objectGUID",                         LDB_SYNTAX_SAMBA_GUID },
1602         { "pKTGuid",                            LDB_SYNTAX_SAMBA_GUID },
1603         { "requiredCategories",                 LDB_SYNTAX_SAMBA_GUID },
1604         { "schemaIDGUID",                       LDB_SYNTAX_SAMBA_GUID },
1605         { "siteGUID",                           LDB_SYNTAX_SAMBA_GUID },
1606         { "msDFS-GenerationGUIDv2",             LDB_SYNTAX_SAMBA_GUID },
1607         { "msDFS-LinkIdentityGUIDv2",           LDB_SYNTAX_SAMBA_GUID },
1608         { "msDFS-NamespaceIdentityGUIDv2",      LDB_SYNTAX_SAMBA_GUID },
1609         { "msSPP-CSVLKSkuId",                   LDB_SYNTAX_SAMBA_GUID },
1610         { "msSPP-KMSIds",                       LDB_SYNTAX_SAMBA_GUID },
1611
1612         /*
1613          * these are known to be GUIDs
1614          */
1615         { "invocationId",                       LDB_SYNTAX_SAMBA_GUID },
1616         { "parentGUID",                         LDB_SYNTAX_SAMBA_GUID },
1617
1618         /* These NDR encoded things we want to be able to read with --show-binary */
1619         { "dnsRecord",                          LDB_SYNTAX_SAMBA_DNSRECORD },
1620         { "dNSProperty",                        LDB_SYNTAX_SAMBA_DNSPROPERTY },
1621         { "supplementalCredentials",            LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS},
1622         { "partialAttributeSet",                LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET}
1623 };
1624
1625 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1626 {
1627         unsigned int j;
1628         const struct ldb_schema_syntax *s = NULL;
1629         
1630         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1631                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1632                         s = &samba_syntaxes[j];
1633                         break;
1634                 }
1635         }
1636         return s;
1637 }
1638
1639 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1640 {
1641         unsigned int j;
1642         const struct ldb_schema_syntax *s = NULL;
1643
1644         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1645                 if (strcmp(samba_attributes[j].name, name) == 0) {
1646                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1647                         break;
1648                 }
1649         }
1650         
1651         return s;
1652 }
1653
1654 static const char *secret_attributes[] = {DSDB_SECRET_ATTRIBUTES, NULL};
1655
1656 /*
1657   register the samba ldif handlers
1658 */
1659 int ldb_register_samba_handlers(struct ldb_context *ldb)
1660 {
1661         unsigned int i;
1662         int ret;
1663
1664         if (ldb_get_opaque(ldb, "SAMBA_HANDLERS_REGISTERED") != NULL) {
1665                 return LDB_SUCCESS;
1666         }
1667
1668         ret = ldb_set_opaque(ldb, LDB_SECRET_ATTRIBUTE_LIST_OPAQUE, discard_const_p(char *, secret_attributes));
1669         if (ret != LDB_SUCCESS) {
1670                 return ret;
1671         }
1672
1673         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1674                 const struct ldb_schema_syntax *s = NULL;
1675
1676                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1677
1678                 if (!s) {
1679                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1680                 }
1681
1682                 if (!s) {
1683                         return LDB_ERR_OPERATIONS_ERROR;
1684                 }
1685
1686                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1687                 if (ret != LDB_SUCCESS) {
1688                         return ret;
1689                 }
1690         }
1691
1692         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1693                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1694                 if (ret != LDB_SUCCESS) {
1695                         return ret;
1696                 }
1697
1698         }
1699
1700         ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
1701         if (ret != LDB_SUCCESS) {
1702                 return ret;
1703         }
1704
1705         return LDB_SUCCESS;
1706 }