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