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