pyldb: avoid segfault when adding an element with no name
[kai/samba-autobuild/.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                 int error = 0;
600
601                 p=strchr(line, ';');
602                 if (p) {
603                         p[0] = '\0';
604                 } else {
605                         p=strchr(line, '\n');
606                         if (p) {
607                                 p[0] = '\0';
608                         }
609                 }
610                 /* allow a trailing separator */
611                 if (line == p) {
612                         break;
613                 }
614                 
615                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
616                                                          blob->ctr.dsdb.mappings, 
617                                                          struct drsuapi_DsReplicaOIDMapping,
618                                                          blob->ctr.dsdb.num_mappings+1);
619                 if (!blob->ctr.dsdb.mappings) {
620                         talloc_free(tmp_ctx);
621                         return -1;
622                 }
623
624                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix =
625                         strtoul_err(line, &oid, 10, &error);
626
627                 if (oid[0] != ':' || error != 0) {
628                         talloc_free(tmp_ctx);
629                         return -1;
630                 }
631
632                 /* we know there must be at least ":" */
633                 oid++;
634
635                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
636                         talloc_free(tmp_ctx);
637                         return -1;
638                 }
639                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
640                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
641
642                 blob->ctr.dsdb.num_mappings++;
643
644                 /* Now look past the terminator we added above */
645                 if (p) {
646                         line = p + 1;
647                 } else {
648                         line = NULL;
649                 }
650         }
651
652         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
653                                        blob,
654                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
655         talloc_free(tmp_ctx);
656         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
657                 return -1;
658         }
659         return 0;
660 }
661
662 /*
663   convert a NDR formatted blob to a ldif formatted prefixMap
664 */
665 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
666                                 const struct ldb_val *in, struct ldb_val *out)
667 {
668         struct prefixMapBlob *blob;
669         enum ndr_err_code ndr_err;
670         char *string;
671         uint32_t i;
672
673         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
674                 int err;
675                 /* try to decode the blob as S4 prefixMap */
676                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
677                                      sizeof(struct prefixMapBlob),
678                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
679                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
680                                      false);
681                 if (0 == err) {
682                         return err;
683                 }
684                 /* try parsing it as Windows PrefixMap value */
685                 return ldif_write_NDR(ldb, mem_ctx, in, out,
686                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
687                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
688                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
689                                       true);
690         }
691
692         blob = talloc(mem_ctx, struct prefixMapBlob);
693         if (blob == NULL) {
694                 return -1;
695         }
696         ndr_err = ndr_pull_struct_blob_all(in, blob, 
697                                            blob,
698                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
699         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
700                 goto failed;
701         }
702         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
703                 goto failed;
704         }
705         string = talloc_strdup(mem_ctx, "");
706         if (string == NULL) {
707                 goto failed;
708         }
709
710         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
711                 DATA_BLOB oid_blob;
712                 char *partial_oid = NULL;
713
714                 if (i > 0) {
715                         string = talloc_asprintf_append(string, ";"); 
716                 }
717
718                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
719                                            blob->ctr.dsdb.mappings[i].oid.length);
720                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
721                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
722                                   blob->ctr.dsdb.mappings[i].id_prefix));
723                         goto failed;
724                 }
725                 string = talloc_asprintf_append(string, "%u:%s", 
726                                                    blob->ctr.dsdb.mappings[i].id_prefix,
727                                                    partial_oid);
728                 talloc_free(discard_const(partial_oid));
729                 if (string == NULL) {
730                         goto failed;
731                 }
732         }
733
734         talloc_free(blob);
735         *out = data_blob_string_const(string);
736         return 0;
737
738 failed:
739         talloc_free(blob);
740         return -1;
741 }
742
743 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
744 {
745         if (v->length < 4) {
746                 return true;
747         }
748
749         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
750                 return false;
751         }
752         
753         return true;
754 }
755
756 /*
757   canonicalise a prefixMap
758 */
759 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
760                                        const struct ldb_val *in, struct ldb_val *out)
761 {
762         if (ldif_comparision_prefixMap_isString(in)) {
763                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
764         }
765         return ldb_handler_copy(ldb, mem_ctx, in, out);
766 }
767
768 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
769                                      const struct ldb_val *v1,
770                                      const struct ldb_val *v2)
771 {
772         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
773                                   v1, v2);
774 }
775
776 /* length limited conversion of a ldb_val to a int32_t */
777 static int val_to_int32(const struct ldb_val *in, int32_t *v)
778 {
779         char *end;
780         char buf[64];
781
782         /* make sure we don't read past the end of the data */
783         if (in->length > sizeof(buf)-1) {
784                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
785         }
786         strncpy(buf, (char *)in->data, in->length);
787         buf[in->length] = 0;
788
789         /* We've to use "strtoll" here to have the intended overflows.
790          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
791         *v = (int32_t) strtoll(buf, &end, 0);
792         if (*end != 0) {
793                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
794         }
795         return LDB_SUCCESS;
796 }
797
798 /* length limited conversion of a ldb_val to a int64_t */
799 static int val_to_int64(const struct ldb_val *in, int64_t *v)
800 {
801         char *end;
802         char buf[64];
803
804         /* make sure we don't read past the end of the data */
805         if (in->length > sizeof(buf)-1) {
806                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
807         }
808         strncpy(buf, (char *)in->data, in->length);
809         buf[in->length] = 0;
810
811         *v = (int64_t) strtoll(buf, &end, 0);
812         if (*end != 0) {
813                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
814         }
815         return LDB_SUCCESS;
816 }
817
818 /* Canonicalisation of two 32-bit integers */
819 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
820                         const struct ldb_val *in, struct ldb_val *out)
821 {
822         int32_t i;
823         int ret;
824
825         ret = val_to_int32(in, &i);
826         if (ret != LDB_SUCCESS) {
827                 return ret;
828         }
829         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
830         if (out->data == NULL) {
831                 ldb_oom(ldb);
832                 return LDB_ERR_OPERATIONS_ERROR;
833         }
834         out->length = strlen((char *)out->data);
835         return 0;
836 }
837
838 /*
839  * Lexicographically sorted representation for a 32-bit integer
840  *
841  * [ INT32_MIN ... -3, -2, -1 | 0 | +1, +2, +3 ... INT32_MAX ]
842  *             n                o              p
843  *
844  * Refer to the comment in lib/ldb/common/attrib_handlers.c for the
845  * corresponding documentation for 64-bit integers.
846  *
847  * The same rules apply but use INT32_MIN and INT32_MAX.
848  *
849  * String representation padding is done to 10 characters.
850  *
851  * INT32_MAX = 2^31 - 1 = 2147483647 (10 characters long)
852  *
853  */
854 static int ldif_index_format_int32(struct ldb_context *ldb,
855                                     void *mem_ctx,
856                                     const struct ldb_val *in,
857                                     struct ldb_val *out)
858 {
859         int32_t i;
860         int ret;
861         char prefix;
862         size_t len;
863
864         ret = val_to_int32(in, &i);
865         if (ret != LDB_SUCCESS) {
866                 return ret;
867         }
868
869         if (i < 0) {
870                 /*
871                  * i is negative, so this is subtraction rather than
872                  * wrap-around.
873                  */
874                 prefix = 'n';
875                 i = INT32_MAX + i + 1;
876         } else if (i > 0) {
877                 prefix = 'p';
878         } else {
879                 prefix = 'o';
880         }
881
882         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%c%010ld", prefix, (long)i);
883         if (out->data == NULL) {
884                 ldb_oom(ldb);
885                 return LDB_ERR_OPERATIONS_ERROR;
886         }
887
888         len = talloc_array_length(out->data) - 1;
889         if (len != 11) {
890                 ldb_debug(ldb, LDB_DEBUG_ERROR,
891                           __location__ ": expected index format str %s to"
892                           " have length 11 but got %zu",
893                           (char*)out->data, len);
894                 return LDB_ERR_OPERATIONS_ERROR;
895         }
896
897         out->length = 11;
898         return 0;
899 }
900
901 /* Comparison of two 32-bit integers */
902 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
903                                  const struct ldb_val *v1, const struct ldb_val *v2)
904 {
905         int32_t i1=0, i2=0;
906         val_to_int32(v1, &i1);
907         val_to_int32(v2, &i2);
908         if (i1 == i2) return 0;
909         return i1 > i2? 1 : -1;
910 }
911
912 /* Canonicalisation of two 64-bit integers */
913 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
914                                    const struct ldb_val *in, struct ldb_val *out)
915 {
916         int64_t i;
917         int ret;
918
919         ret = val_to_int64(in, &i);
920         if (ret != LDB_SUCCESS) {
921                 return ret;
922         }
923         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
924         if (out->data == NULL) {
925                 ldb_oom(ldb);
926                 return LDB_ERR_OPERATIONS_ERROR;
927         }
928         out->length = strlen((char *)out->data);
929         return 0;
930 }
931
932 /* Comparison of two 64-bit integers */
933 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
934                                  const struct ldb_val *v1, const struct ldb_val *v2)
935 {
936         int64_t i1=0, i2=0;
937         val_to_int64(v1, &i1);
938         val_to_int64(v2, &i2);
939         if (i1 == i2) return 0;
940         return i1 > i2? 1 : -1;
941 }
942
943 /*
944   convert a NDR formatted blob to a ldif formatted repsFromTo
945 */
946 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
947                                  const struct ldb_val *in, struct ldb_val *out)
948 {
949         return ldif_write_NDR(ldb, mem_ctx, in, out, 
950                               sizeof(struct repsFromToBlob),
951                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
952                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
953                               true);
954 }
955
956 /*
957   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
958 */
959 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
960                                            const struct ldb_val *in, struct ldb_val *out)
961 {
962         return ldif_write_NDR(ldb, mem_ctx, in, out, 
963                               sizeof(struct replPropertyMetaDataBlob),
964                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
965                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
966                               true);
967 }
968
969 /*
970   convert a NDR formatted blob to a ldif formatted replUpToDateVector
971 */
972 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
973                                          const struct ldb_val *in, struct ldb_val *out)
974 {
975         return ldif_write_NDR(ldb, mem_ctx, in, out, 
976                               sizeof(struct replUpToDateVectorBlob),
977                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
978                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
979                               true);
980 }
981
982 static int ldif_write_dn_binary_NDR(struct ldb_context *ldb, void *mem_ctx,
983                                     const struct ldb_val *in, struct ldb_val *out,
984                                     size_t struct_size,
985                                     ndr_pull_flags_fn_t pull_fn,
986                                     ndr_print_fn_t print_fn,
987                                     bool mask_errors)
988 {
989         uint8_t *p = NULL;
990         enum ndr_err_code err;
991         struct dsdb_dn *dsdb_dn = NULL;
992         char *dn_str = NULL;
993         char *str = NULL;
994
995         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
996                 return ldb_handler_copy(ldb, mem_ctx, in, out);
997         }
998
999         dsdb_dn = dsdb_dn_parse(mem_ctx, ldb, in, DSDB_SYNTAX_BINARY_DN);
1000         if (dsdb_dn == NULL) {
1001                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1002         }
1003
1004         p = talloc_size(dsdb_dn, struct_size);
1005         if (p == NULL) {
1006                 TALLOC_FREE(dsdb_dn);
1007                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1008         }
1009
1010         err = ndr_pull_struct_blob(&dsdb_dn->extra_part, p, p, pull_fn);
1011         if (err != NDR_ERR_SUCCESS) {
1012                 /* fail in not in mask_error mode */
1013                 if (!mask_errors) {
1014                         return -1;
1015                 }
1016                 TALLOC_FREE(dsdb_dn);
1017                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1018         }
1019
1020         dn_str = ldb_dn_get_extended_linearized(dsdb_dn, dsdb_dn->dn, 1);
1021         if (dn_str == NULL) {
1022                 TALLOC_FREE(dsdb_dn);
1023                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1024         }
1025
1026         str = ndr_print_struct_string(mem_ctx, print_fn, dn_str, p);
1027         TALLOC_FREE(dsdb_dn);
1028         if (str == NULL) {
1029                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1030         }
1031
1032         *out = data_blob_string_const(str);
1033         return 0;
1034 }
1035
1036 static int ldif_write_msDS_RevealedUsers(struct ldb_context *ldb, void *mem_ctx,
1037                                          const struct ldb_val *in, struct ldb_val *out)
1038 {
1039         return ldif_write_dn_binary_NDR(ldb, mem_ctx, in, out,
1040                               sizeof(struct replPropertyMetaData1),
1041                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaData1,
1042                               (ndr_print_fn_t)ndr_print_replPropertyMetaData1,
1043                               true);
1044 }
1045
1046 /*
1047   convert a NDR formatted blob to a ldif formatted dnsRecord
1048 */
1049 static int ldif_write_dnsRecord(struct ldb_context *ldb, void *mem_ctx,
1050                                 const struct ldb_val *in, struct ldb_val *out)
1051 {
1052         return ldif_write_NDR(ldb, mem_ctx, in, out,
1053                               sizeof(struct dnsp_DnssrvRpcRecord),
1054                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord,
1055                               (ndr_print_fn_t)ndr_print_dnsp_DnssrvRpcRecord,
1056                               true);
1057 }
1058
1059 /*
1060   convert a NDR formatted blob to a ldif formatted dnsProperty
1061 */
1062 static int ldif_write_dnsProperty(struct ldb_context *ldb, void *mem_ctx,
1063                                 const struct ldb_val *in, struct ldb_val *out)
1064 {
1065         return ldif_write_NDR(ldb, mem_ctx, in, out,
1066                               sizeof(struct dnsp_DnsProperty),
1067                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty,
1068                               (ndr_print_fn_t)ndr_print_dnsp_DnsProperty,
1069                               true);
1070 }
1071
1072 /*
1073   convert a NDR formatted blob of a supplementalCredentials into text
1074 */
1075 static int ldif_write_supplementalCredentialsBlob(struct ldb_context *ldb, void *mem_ctx,
1076                                                   const struct ldb_val *in, struct ldb_val *out)
1077 {
1078         return ldif_write_NDR(ldb, mem_ctx, in, out,
1079                               sizeof(struct supplementalCredentialsBlob),
1080                               (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob,
1081                               (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob,
1082                               true);
1083 }
1084
1085 /*
1086   convert a NDR formatted blob to a ldif formatted trustAuthInOutBlob
1087 */
1088 static int ldif_write_trustAuthInOutBlob(struct ldb_context *ldb, void *mem_ctx,
1089                                            const struct ldb_val *in, struct ldb_val *out)
1090 {
1091         return ldif_write_NDR(ldb, mem_ctx, in, out,
1092                               sizeof(struct trustAuthInOutBlob),
1093                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob,
1094                               (ndr_print_fn_t)ndr_print_trustAuthInOutBlob,
1095                               true);
1096 }
1097
1098 /*
1099   convert a NDR formatted blob to a ldif formatted msDS-TrustForestTrustInfo
1100 */
1101 static int ldif_write_ForestTrustInfo(struct ldb_context *ldb, void *mem_ctx,
1102                                       const struct ldb_val *in, struct ldb_val *out)
1103 {
1104         return ldif_write_NDR(ldb, mem_ctx, in, out,
1105                               sizeof(struct ForestTrustInfo),
1106                               (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo,
1107                               (ndr_print_fn_t)ndr_print_ForestTrustInfo,
1108                               true);
1109 }
1110 /*
1111   convert a NDR formatted blob of a partialAttributeSet into text
1112 */
1113 static int ldif_write_partialAttributeSet(struct ldb_context *ldb, void *mem_ctx,
1114                                           const struct ldb_val *in, struct ldb_val *out)
1115 {
1116         return ldif_write_NDR(ldb, mem_ctx, in, out,
1117                               sizeof(struct partialAttributeSetBlob),
1118                               (ndr_pull_flags_fn_t)ndr_pull_partialAttributeSetBlob,
1119                               (ndr_print_fn_t)ndr_print_partialAttributeSetBlob,
1120                               true);
1121 }
1122
1123
1124 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
1125                                  const struct ldb_val *in, struct ldb_val *out)
1126 {
1127         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
1128         if (!out->data) {
1129                 return -1;
1130         }
1131         return 0;
1132 }
1133
1134 /*
1135   compare two dns
1136 */
1137 static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
1138                                         const struct ldb_val *v1, const struct ldb_val *v2)
1139 {
1140         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
1141         int ret;
1142
1143         if (dsdb_dn_is_deleted_val(v1)) {
1144                 /* If the DN is deleted, then we can't search for it */
1145                 return -1;
1146         }
1147
1148         if (dsdb_dn_is_deleted_val(v2)) {
1149                 /* If the DN is deleted, then we can't search for it */
1150                 return -1;
1151         }
1152
1153         dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
1154         if ( ! ldb_dn_validate(dn1)) return -1;
1155
1156         dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
1157         if ( ! ldb_dn_validate(dn2)) {
1158                 talloc_free(dn1);
1159                 return -1;
1160         }
1161
1162         ret = ldb_dn_compare(dn1, dn2);
1163
1164         talloc_free(dn1);
1165         talloc_free(dn2);
1166         return ret;
1167 }
1168
1169 static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
1170                                           const struct ldb_val *in, struct ldb_val *out)
1171 {
1172         struct ldb_dn *dn;
1173         int ret = -1;
1174
1175         out->length = 0;
1176         out->data = NULL;
1177
1178         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
1179         if ( ! ldb_dn_validate(dn)) {
1180                 return LDB_ERR_INVALID_DN_SYNTAX;
1181         }
1182
1183         /* By including the RMD_FLAGS of a deleted DN, we ensure it
1184          * does not casually match a not deleted DN */
1185         if (dsdb_dn_is_deleted_val(in)) {
1186                 out->data = (uint8_t *)talloc_asprintf(mem_ctx,
1187                                                        "<RMD_FLAGS=%u>%s",
1188                                                        dsdb_dn_val_rmd_flags(in),
1189                                                        ldb_dn_get_casefold(dn));
1190         } else {
1191                 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
1192         }
1193
1194         if (out->data == NULL) {
1195                 goto done;
1196         }
1197         out->length = strlen((char *)out->data);
1198
1199         ret = 0;
1200
1201 done:
1202         talloc_free(dn);
1203
1204         return ret;
1205 }
1206
1207
1208 /*
1209   write a 64 bit 2-part range
1210 */
1211 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
1212                               const struct ldb_val *in, struct ldb_val *out)
1213 {
1214         int64_t v;
1215         int ret;
1216         ret = val_to_int64(in, &v);
1217         if (ret != LDB_SUCCESS) {
1218                 return ret;
1219         }
1220         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
1221                                                (unsigned long)(v&0xFFFFFFFF),
1222                                                (unsigned long)(v>>32));
1223         if (out->data == NULL) {
1224                 ldb_oom(ldb);
1225                 return LDB_ERR_OPERATIONS_ERROR;
1226         }
1227         out->length = strlen((char *)out->data);
1228         return LDB_SUCCESS;
1229 }
1230
1231 /*
1232   read a 64 bit 2-part range
1233 */
1234 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
1235                               const struct ldb_val *in, struct ldb_val *out)
1236 {
1237         unsigned long high, low;
1238         char buf[64];
1239
1240         if (memchr(in->data, '-', in->length) == NULL) {
1241                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1242         }
1243
1244         if (in->length > sizeof(buf)-1) {
1245                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1246         }
1247         strncpy(buf, (const char *)in->data, in->length);
1248         buf[in->length] = 0;
1249
1250         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
1251                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1252         }
1253
1254         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
1255                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
1256
1257         if (out->data == NULL) {
1258                 ldb_oom(ldb);
1259                 return LDB_ERR_OPERATIONS_ERROR;
1260         }
1261         out->length = strlen((char *)out->data);
1262         return LDB_SUCCESS;
1263 }
1264
1265 /*
1266   when this operator_fn is set for a syntax, the backend calls is in
1267   preference to the comparison function. We are told the exact
1268   comparison operation that is needed, and we can return errors
1269  */
1270 static int samba_syntax_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         switch (operation) {
1275         case LDB_OP_AND:
1276         case LDB_OP_OR:
1277         case LDB_OP_NOT:
1278         case LDB_OP_SUBSTRING:
1279         case LDB_OP_APPROX:
1280         case LDB_OP_EXTENDED:
1281                 /* handled in the backends */
1282                 return LDB_ERR_INAPPROPRIATE_MATCHING;
1283
1284         case LDB_OP_GREATER:
1285         case LDB_OP_LESS:
1286         case LDB_OP_EQUALITY:
1287         {
1288                 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1289                 int ret;
1290                 if (tmp_ctx == NULL) {
1291                         return ldb_oom(ldb);
1292                 }
1293                 ret = a->syntax->comparison_fn(ldb, tmp_ctx, v1, v2);
1294                 talloc_free(tmp_ctx);
1295                 if (operation == LDB_OP_GREATER) {
1296                         *matched = (ret >= 0);
1297                 } else if (operation == LDB_OP_LESS) {
1298                         *matched = (ret <= 0);
1299                 } else {
1300                         *matched = (ret == 0);
1301                 }
1302                 return LDB_SUCCESS;
1303         }
1304
1305         case LDB_OP_PRESENT:
1306                 *matched = true;
1307                 return LDB_SUCCESS;
1308         }
1309
1310         /* we shouldn't get here */
1311         return LDB_ERR_INAPPROPRIATE_MATCHING;
1312 }
1313
1314 /*
1315   compare two binary objects.  This is correct for sorting as the sort order is:
1316   
1317   a
1318   aa
1319   b
1320   bb
1321
1322   rather than ldb_comparison_binary() which is:
1323
1324   a
1325   b
1326   aa
1327   bb
1328   
1329 */
1330 static int samba_ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
1331                                        const struct ldb_val *v1, const struct ldb_val *v2)
1332 {
1333         return data_blob_cmp(v1, v2);
1334 }
1335
1336 /*
1337   when this operator_fn is set for a syntax, the backend calls is in
1338   preference to the comparison function. We are told the exact
1339   comparison operation that is needed, and we can return errors.
1340
1341   This mode optimises for ldb_comparison_binary() if we need equality,
1342   as this should be faster as it can do a length-check first.
1343  */
1344 static int samba_syntax_binary_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
1345                                            const struct ldb_schema_attribute *a,
1346                                            const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1347 {
1348         if (operation == LDB_OP_EQUALITY) {
1349                 *matched = (ldb_comparison_binary(ldb, NULL, v1, v2) == 0);
1350                 return LDB_SUCCESS;
1351         }
1352         return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
1353 }
1354
1355 /*
1356   see if two DNs match, comparing first by GUID, then by SID, and
1357   finally by string components
1358  */
1359 static int samba_dn_extended_match(struct ldb_context *ldb,
1360                                    const struct ldb_val *v1,
1361                                    const struct ldb_val *v2,
1362                                    bool *matched)
1363 {
1364         TALLOC_CTX *tmp_ctx;
1365         struct ldb_dn *dn1, *dn2;
1366         const struct ldb_val *guid1, *guid2, *sid1, *sid2;
1367         uint32_t rmd_flags1, rmd_flags2;
1368
1369         tmp_ctx = talloc_new(ldb);
1370
1371         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v1);
1372         dn2 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v2);
1373         if (!dn1 || !dn2) {
1374                 /* couldn't parse as DN's */
1375                 talloc_free(tmp_ctx);
1376                 (*matched) = false;
1377                 return LDB_SUCCESS;
1378         }
1379
1380         rmd_flags1 = dsdb_dn_rmd_flags(dn1);
1381         rmd_flags2 = dsdb_dn_rmd_flags(dn2);
1382
1383         if ((rmd_flags1 & DSDB_RMD_FLAG_DELETED) !=
1384             (rmd_flags2 & DSDB_RMD_FLAG_DELETED)) {
1385                 /* only match if they have the same deletion status */
1386                 talloc_free(tmp_ctx);
1387                 (*matched) = false;
1388                 return LDB_SUCCESS;
1389         }
1390
1391
1392         guid1 = ldb_dn_get_extended_component(dn1, "GUID");
1393         guid2 = ldb_dn_get_extended_component(dn2, "GUID");
1394         if (guid1 && guid2) {
1395                 (*matched) = (data_blob_cmp(guid1, guid2) == 0);
1396                 talloc_free(tmp_ctx);
1397                 return LDB_SUCCESS;
1398         }
1399
1400         sid1 = ldb_dn_get_extended_component(dn1, "SID");
1401         sid2 = ldb_dn_get_extended_component(dn2, "SID");
1402         if (sid1 && sid2) {
1403                 (*matched) = (data_blob_cmp(sid1, sid2) == 0);
1404                 talloc_free(tmp_ctx);
1405                 return LDB_SUCCESS;
1406         }
1407
1408         (*matched) = (ldb_dn_compare(dn1, dn2) == 0);
1409
1410         talloc_free(tmp_ctx);
1411         return LDB_SUCCESS;
1412 }
1413
1414 /*
1415   special operation for DNs, to take account of the RMD_FLAGS deleted bit
1416  */
1417 static int samba_syntax_operator_dn(struct ldb_context *ldb, enum ldb_parse_op operation,
1418                                     const struct ldb_schema_attribute *a,
1419                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1420 {
1421         if (operation == LDB_OP_PRESENT && dsdb_dn_is_deleted_val(v1)) {
1422                 /* If the DN is deleted, then we can't search for it */
1423
1424                 /* should this be for equality too? */
1425                 *matched = false;
1426                 return LDB_SUCCESS;
1427         }
1428
1429         if (operation == LDB_OP_EQUALITY &&
1430             samba_dn_extended_match(ldb, v1, v2, matched) == LDB_SUCCESS) {
1431                 return LDB_SUCCESS;
1432         }
1433
1434         return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
1435 }
1436
1437
1438 static const struct ldb_schema_syntax samba_syntaxes[] = {
1439         {
1440                 .name             = LDB_SYNTAX_SAMBA_SID,
1441                 .ldif_read_fn     = ldif_read_objectSid,
1442                 .ldif_write_fn    = ldif_write_objectSid,
1443                 .canonicalise_fn  = ldif_canonicalise_objectSid,
1444                 .comparison_fn    = ldif_comparison_objectSid,
1445                 .operator_fn      = samba_syntax_operator_fn
1446         },{
1447                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
1448                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
1449                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
1450                 .canonicalise_fn  = ldb_handler_copy,
1451                 .comparison_fn    = samba_ldb_comparison_binary,
1452                 .operator_fn      = samba_syntax_binary_operator_fn
1453         },{
1454                 .name             = LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR,
1455                 .ldif_read_fn     = ldb_handler_copy,
1456                 .ldif_write_fn    = ldif_write_sddlSecurityDescriptor,
1457                 .canonicalise_fn  = ldb_handler_fold,
1458                 .comparison_fn    = ldb_comparison_fold,
1459                 .operator_fn      = samba_syntax_operator_fn
1460         },{
1461                 .name             = LDB_SYNTAX_SAMBA_GUID,
1462                 .ldif_read_fn     = ldif_read_objectGUID,
1463                 .ldif_write_fn    = ldif_write_objectGUID,
1464                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
1465                 .comparison_fn    = ldif_comparison_objectGUID,
1466                 .operator_fn      = samba_syntax_operator_fn
1467         },{
1468                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
1469                 .ldif_read_fn     = ldb_handler_copy,
1470                 .ldif_write_fn    = ldb_handler_copy,
1471                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
1472                 .comparison_fn    = ldif_comparison_objectCategory,
1473                 .operator_fn      = samba_syntax_operator_fn
1474         },{
1475                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
1476                 .ldif_read_fn     = ldb_handler_copy,
1477                 .ldif_write_fn    = ldif_write_schemaInfo,
1478                 .canonicalise_fn  = ldb_handler_copy,
1479                 .comparison_fn    = samba_ldb_comparison_binary,
1480                 .operator_fn      = samba_syntax_binary_operator_fn
1481         },{
1482                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
1483                 .ldif_read_fn     = ldif_read_prefixMap,
1484                 .ldif_write_fn    = ldif_write_prefixMap,
1485                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
1486                 .comparison_fn    = ldif_comparison_prefixMap,
1487                 .operator_fn      = samba_syntax_operator_fn
1488         },{
1489                 .name             = LDB_SYNTAX_SAMBA_INT32,
1490                 .ldif_read_fn     = ldb_handler_copy,
1491                 .ldif_write_fn    = ldb_handler_copy,
1492                 .canonicalise_fn  = ldif_canonicalise_int32,
1493                 .index_format_fn  = ldif_index_format_int32,
1494                 .comparison_fn    = ldif_comparison_int32,
1495                 .operator_fn      = samba_syntax_operator_fn
1496         },{
1497                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
1498                 .ldif_read_fn     = ldb_handler_copy,
1499                 .ldif_write_fn    = ldif_write_repsFromTo,
1500                 .canonicalise_fn  = ldb_handler_copy,
1501                 .comparison_fn    = samba_ldb_comparison_binary,
1502                 .operator_fn      = samba_syntax_binary_operator_fn
1503         },{
1504                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
1505                 .ldif_read_fn     = ldb_handler_copy,
1506                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
1507                 .canonicalise_fn  = ldb_handler_copy,
1508                 .comparison_fn    = samba_ldb_comparison_binary,
1509                 .operator_fn      = samba_syntax_binary_operator_fn
1510         },{
1511                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
1512                 .ldif_read_fn     = ldb_handler_copy,
1513                 .ldif_write_fn    = ldif_write_replUpToDateVector,
1514                 .canonicalise_fn  = ldb_handler_copy,
1515                 .comparison_fn    = samba_ldb_comparison_binary,
1516                 .operator_fn      = samba_syntax_binary_operator_fn
1517         },{
1518                 .name             = LDB_SYNTAX_SAMBA_REVEALEDUSERS,
1519                 .ldif_read_fn     = ldb_handler_copy,
1520                 .ldif_write_fn    = ldif_write_msDS_RevealedUsers,
1521                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1522                 .comparison_fn    = dsdb_dn_binary_comparison,
1523                 .operator_fn      = samba_syntax_operator_fn
1524         },{
1525                 .name             = LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB,
1526                 .ldif_read_fn     = ldb_handler_copy,
1527                 .ldif_write_fn    = ldif_write_trustAuthInOutBlob,
1528                 .canonicalise_fn  = ldb_handler_copy,
1529                 .comparison_fn    = samba_ldb_comparison_binary,
1530                 .operator_fn      = samba_syntax_binary_operator_fn
1531         },{
1532                 .name             = LDB_SYNTAX_SAMBA_FORESTTRUSTINFO,
1533                 .ldif_read_fn     = ldb_handler_copy,
1534                 .ldif_write_fn    = ldif_write_ForestTrustInfo,
1535                 .canonicalise_fn  = ldb_handler_copy,
1536                 .comparison_fn    = samba_ldb_comparison_binary,
1537                 .operator_fn      = samba_syntax_binary_operator_fn
1538         },{
1539                 .name             = DSDB_SYNTAX_BINARY_DN,
1540                 .ldif_read_fn     = ldb_handler_copy,
1541                 .ldif_write_fn    = ldb_handler_copy,
1542                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1543                 .comparison_fn    = dsdb_dn_binary_comparison,
1544                 .operator_fn      = samba_syntax_operator_fn
1545         },{
1546                 .name             = DSDB_SYNTAX_STRING_DN,
1547                 .ldif_read_fn     = ldb_handler_copy,
1548                 .ldif_write_fn    = ldb_handler_copy,
1549                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
1550                 .comparison_fn    = dsdb_dn_string_comparison,
1551                 .operator_fn      = samba_syntax_operator_fn
1552         },{
1553                 .name             = LDB_SYNTAX_DN,
1554                 .ldif_read_fn     = ldb_handler_copy,
1555                 .ldif_write_fn    = ldb_handler_copy,
1556                 .canonicalise_fn  = samba_ldb_dn_link_canonicalise,
1557                 .comparison_fn    = samba_ldb_dn_link_comparison,
1558                 .operator_fn      = samba_syntax_operator_dn
1559         },{
1560                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1561                 .ldif_read_fn     = ldif_read_range64,
1562                 .ldif_write_fn    = ldif_write_range64,
1563                 .canonicalise_fn  = ldif_canonicalise_int64,
1564                 .comparison_fn    = ldif_comparison_int64,
1565                 .operator_fn      = samba_syntax_operator_fn
1566         },{
1567                 .name             = LDB_SYNTAX_SAMBA_DNSRECORD,
1568                 .ldif_read_fn     = ldb_handler_copy,
1569                 .ldif_write_fn    = ldif_write_dnsRecord,
1570                 .canonicalise_fn  = ldb_handler_copy,
1571                 .comparison_fn    = samba_ldb_comparison_binary,
1572                 .operator_fn      = samba_syntax_binary_operator_fn
1573         },{
1574                 .name             = LDB_SYNTAX_SAMBA_DNSPROPERTY,
1575                 .ldif_read_fn     = ldb_handler_copy,
1576                 .ldif_write_fn    = ldif_write_dnsProperty,
1577                 .canonicalise_fn  = ldb_handler_copy,
1578                 .comparison_fn    = samba_ldb_comparison_binary,
1579                 .operator_fn      = samba_syntax_binary_operator_fn
1580         },{
1581                 .name             = LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS,
1582                 .ldif_read_fn     = ldb_handler_copy,
1583                 .ldif_write_fn    = ldif_write_supplementalCredentialsBlob,
1584                 .canonicalise_fn  = ldb_handler_copy,
1585                 .comparison_fn    = samba_ldb_comparison_binary,
1586                 .operator_fn      = samba_syntax_binary_operator_fn
1587         },{
1588                 .name             = LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET,
1589                 .ldif_read_fn     = ldb_handler_copy,
1590                 .ldif_write_fn    = ldif_write_partialAttributeSet,
1591                 .canonicalise_fn  = ldb_handler_copy,
1592                 .comparison_fn    = samba_ldb_comparison_binary,
1593                 .operator_fn      = samba_syntax_binary_operator_fn
1594         },{
1595                 .name             = LDB_SYNTAX_SAMBA_OCTET_STRING,
1596                 .ldif_read_fn     = ldb_handler_copy,
1597                 .ldif_write_fn    = ldb_handler_copy,
1598                 .canonicalise_fn  = ldb_handler_copy,
1599                 .comparison_fn    = samba_ldb_comparison_binary,
1600                 .operator_fn      = samba_syntax_binary_operator_fn
1601         }
1602 };
1603
1604 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1605         {
1606                 .name             = "SID",
1607                 .read_fn          = extended_dn_read_SID,
1608                 .write_clear_fn   = ldif_write_objectSid,
1609                 .write_hex_fn     = extended_dn_write_hex
1610         },{
1611                 .name             = "GUID",
1612                 .read_fn          = extended_dn_read_GUID,
1613                 .write_clear_fn   = ldif_write_objectGUID,
1614                 .write_hex_fn     = extended_dn_write_hex
1615         },{
1616                 .name             = "WKGUID",
1617                 .read_fn          = ldb_handler_copy,
1618                 .write_clear_fn   = ldb_handler_copy,
1619                 .write_hex_fn     = ldb_handler_copy
1620         },{
1621                 .name             = "RMD_INVOCID",
1622                 .read_fn          = extended_dn_read_GUID,
1623                 .write_clear_fn   = ldif_write_objectGUID,
1624                 .write_hex_fn     = extended_dn_write_hex
1625         },{
1626                 .name             = "RMD_FLAGS",
1627                 .read_fn          = ldb_handler_copy,
1628                 .write_clear_fn   = ldb_handler_copy,
1629                 .write_hex_fn     = ldb_handler_copy
1630         },{
1631                 .name             = "RMD_ADDTIME",
1632                 .read_fn          = ldb_handler_copy,
1633                 .write_clear_fn   = ldb_handler_copy,
1634                 .write_hex_fn     = ldb_handler_copy
1635         },{
1636                 .name             = "RMD_CHANGETIME",
1637                 .read_fn          = ldb_handler_copy,
1638                 .write_clear_fn   = ldb_handler_copy,
1639                 .write_hex_fn     = ldb_handler_copy
1640         },{
1641                 .name             = "RMD_LOCAL_USN",
1642                 .read_fn          = ldb_handler_copy,
1643                 .write_clear_fn   = ldb_handler_copy,
1644                 .write_hex_fn     = ldb_handler_copy
1645         },{
1646                 .name             = "RMD_ORIGINATING_USN",
1647                 .read_fn          = ldb_handler_copy,
1648                 .write_clear_fn   = ldb_handler_copy,
1649                 .write_hex_fn     = ldb_handler_copy
1650         },{
1651                 .name             = "RMD_VERSION",
1652                 .read_fn          = ldb_handler_copy,
1653                 .write_clear_fn   = ldb_handler_copy,
1654                 .write_hex_fn     = ldb_handler_copy
1655         }
1656 };
1657
1658 /* TODO: Should be dynamic at some point */
1659 static const struct {
1660         const char *name;
1661         const char *syntax;
1662 } samba_attributes[] = {
1663         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1664         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1665         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1666         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1667         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1668         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1669         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1670         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1671         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1672         { "msDS-RevealedUsers",         LDB_SYNTAX_SAMBA_REVEALEDUSERS },
1673         { "trustAuthIncoming",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1674         { "trustAuthOutgoing",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1675         { "msDS-TrustForestTrustInfo",  LDB_SYNTAX_SAMBA_FORESTTRUSTINFO },
1676         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1677         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1678         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1679         { "defaultSecurityDescriptor",  LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR },
1680
1681         /*
1682          * these are extracted by searching
1683          * (&(attributeSyntax=2.5.5.17)(omSyntax=4))
1684          *
1685          * Except: msAuthz-CentralAccessPolicyID as it might be a GUID see:
1686          * adminDescription: For a Central Access Policy, this attribute defines a GUID t
1687          * hat can be used to identify the set of policies when applied to a resource.
1688          * Until we see a msAuthz-CentralAccessPolicyID value on a windows
1689          * server, we ignore it here.
1690          */
1691         { "mS-DS-CreatorSID",           LDB_SYNTAX_SAMBA_SID },
1692         { "msDS-QuotaTrustee",          LDB_SYNTAX_SAMBA_SID },
1693         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1694         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1695         { "tokenGroupsGlobalAndUniversal", LDB_SYNTAX_SAMBA_SID },
1696         { "tokenGroupsNoGCAcceptable",  LDB_SYNTAX_SAMBA_SID },
1697         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1698         { "sIDHistory",                 LDB_SYNTAX_SAMBA_SID },
1699         { "syncWithSID",                LDB_SYNTAX_SAMBA_SID },
1700
1701         /*
1702          * these are extracted by searching
1703          * (&(attributeSyntax=2.5.5.10)(rangeLower=16)(rangeUpper=16)(omSyntax=4))
1704          */
1705         { "attributeSecurityGUID",              LDB_SYNTAX_SAMBA_GUID },
1706         { "categoryId",                         LDB_SYNTAX_SAMBA_GUID },
1707         { "controlAccessRights",                LDB_SYNTAX_SAMBA_GUID },
1708         { "currMachineId",                      LDB_SYNTAX_SAMBA_GUID },
1709         { "fRSReplicaSetGUID",                  LDB_SYNTAX_SAMBA_GUID },
1710         { "fRSVersionGUID",                     LDB_SYNTAX_SAMBA_GUID },
1711         { "implementedCategories",              LDB_SYNTAX_SAMBA_GUID },
1712         { "msDS-AzObjectGuid",                  LDB_SYNTAX_SAMBA_GUID },
1713         { "msDS-GenerationId",                  LDB_SYNTAX_SAMBA_GUID },
1714         { "msDS-OptionalFeatureGUID",           LDB_SYNTAX_SAMBA_GUID },
1715         { "msDFSR-ContentSetGuid",              LDB_SYNTAX_SAMBA_GUID },
1716         { "msDFSR-ReplicationGroupGuid",        LDB_SYNTAX_SAMBA_GUID },
1717         { "mSMQDigests",                        LDB_SYNTAX_SAMBA_GUID },
1718         { "mSMQOwnerID",                        LDB_SYNTAX_SAMBA_GUID },
1719         { "mSMQQMID",                           LDB_SYNTAX_SAMBA_GUID },
1720         { "mSMQQueueType",                      LDB_SYNTAX_SAMBA_GUID },
1721         { "mSMQSites",                          LDB_SYNTAX_SAMBA_GUID },
1722         { "netbootGUID",                        LDB_SYNTAX_SAMBA_GUID },
1723         { "objectGUID",                         LDB_SYNTAX_SAMBA_GUID },
1724         { "pKTGuid",                            LDB_SYNTAX_SAMBA_GUID },
1725         { "requiredCategories",                 LDB_SYNTAX_SAMBA_GUID },
1726         { "schemaIDGUID",                       LDB_SYNTAX_SAMBA_GUID },
1727         { "siteGUID",                           LDB_SYNTAX_SAMBA_GUID },
1728         { "msDFS-GenerationGUIDv2",             LDB_SYNTAX_SAMBA_GUID },
1729         { "msDFS-LinkIdentityGUIDv2",           LDB_SYNTAX_SAMBA_GUID },
1730         { "msDFS-NamespaceIdentityGUIDv2",      LDB_SYNTAX_SAMBA_GUID },
1731         { "msSPP-CSVLKSkuId",                   LDB_SYNTAX_SAMBA_GUID },
1732         { "msSPP-KMSIds",                       LDB_SYNTAX_SAMBA_GUID },
1733
1734         /*
1735          * these are known to be GUIDs
1736          */
1737         { "invocationId",                       LDB_SYNTAX_SAMBA_GUID },
1738         { "parentGUID",                         LDB_SYNTAX_SAMBA_GUID },
1739
1740         /* These NDR encoded things we want to be able to read with --show-binary */
1741         { "dnsRecord",                          LDB_SYNTAX_SAMBA_DNSRECORD },
1742         { "dNSProperty",                        LDB_SYNTAX_SAMBA_DNSPROPERTY },
1743         { "supplementalCredentials",            LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS},
1744         { "partialAttributeSet",                LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET}
1745 };
1746
1747 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1748 {
1749         unsigned int j;
1750         const struct ldb_schema_syntax *s = NULL;
1751         
1752         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1753                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1754                         s = &samba_syntaxes[j];
1755                         break;
1756                 }
1757         }
1758         return s;
1759 }
1760
1761 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1762 {
1763         unsigned int j;
1764         const struct ldb_schema_syntax *s = NULL;
1765
1766         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1767                 if (strcmp(samba_attributes[j].name, name) == 0) {
1768                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1769                         break;
1770                 }
1771         }
1772         
1773         return s;
1774 }
1775
1776 static const char *secret_attributes[] = {DSDB_SECRET_ATTRIBUTES, "secret",
1777                                           "priorSecret", NULL};
1778
1779 /*
1780   register the samba ldif handlers
1781 */
1782 int ldb_register_samba_handlers(struct ldb_context *ldb)
1783 {
1784         unsigned int i;
1785         int ret;
1786
1787         if (ldb_get_opaque(ldb, "SAMBA_HANDLERS_REGISTERED") != NULL) {
1788                 return LDB_SUCCESS;
1789         }
1790
1791         ret = ldb_set_opaque(ldb, LDB_SECRET_ATTRIBUTE_LIST_OPAQUE, discard_const_p(char *, secret_attributes));
1792         if (ret != LDB_SUCCESS) {
1793                 return ret;
1794         }
1795
1796         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1797                 const struct ldb_schema_syntax *s = NULL;
1798
1799                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1800
1801                 if (!s) {
1802                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1803                 }
1804
1805                 if (!s) {
1806                         return LDB_ERR_OPERATIONS_ERROR;
1807                 }
1808
1809                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1810                 if (ret != LDB_SUCCESS) {
1811                         return ret;
1812                 }
1813         }
1814
1815         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1816                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1817                 if (ret != LDB_SUCCESS) {
1818                         return ret;
1819                 }
1820
1821         }
1822
1823         ret = ldb_register_samba_matching_rules(ldb);
1824         if (ret != LDB_SUCCESS) {
1825                 talloc_free(ldb);
1826                 return LDB_SUCCESS;
1827         }
1828
1829         ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
1830         if (ret != LDB_SUCCESS) {
1831                 return ret;
1832         }
1833
1834         return LDB_SUCCESS;
1835 }