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