s4-dbcheck: support the 'none' option for prompts
[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 "librpc/gen_ndr/ndr_security.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_drsblobs.h"
33 #include "librpc/gen_ndr/ndr_dnsp.h"
34 #include "librpc/ndr/libndr.h"
35 #include "libcli/security/security.h"
36 #include "param/param.h"
37 #include "../lib/util/asn1.h"
38
39 /*
40   use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
41
42   If mask_errors is true, then function succeeds but out data
43   is set to "<Unable to decode binary data>" message
44
45   \return 0 on success; -1 on error
46 */
47 static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
48                           const struct ldb_val *in, struct ldb_val *out,
49                           size_t struct_size,
50                           ndr_pull_flags_fn_t pull_fn,
51                           ndr_print_fn_t print_fn,
52                           bool mask_errors)
53 {
54         uint8_t *p;
55         enum ndr_err_code err;
56         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
57                 return ldb_handler_copy(ldb, mem_ctx, in, out);
58         }
59         p = talloc_size(mem_ctx, struct_size);
60         err = ndr_pull_struct_blob(in, mem_ctx, 
61                                    p, pull_fn);
62         if (err != NDR_ERR_SUCCESS) {
63                 /* fail in not in mask_error mode */
64                 if (!mask_errors) {
65                         return -1;
66                 }
67                 talloc_free(p);
68                 out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
69                 out->length = strlen((const char *)out->data);
70                 return 0;
71         }
72         out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
73         talloc_free(p);
74         if (out->data == NULL) {
75                 return ldb_handler_copy(ldb, mem_ctx, in, out);         
76         }
77         out->length = strlen((char *)out->data);
78         return 0;
79 }
80
81 /*
82   convert a ldif formatted objectSid to a NDR formatted blob
83 */
84 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
85                                const struct ldb_val *in, struct ldb_val *out)
86 {
87         enum ndr_err_code ndr_err;
88         struct dom_sid *sid;
89         sid = dom_sid_parse_length(mem_ctx, in);
90         if (sid == NULL) {
91                 return -1;
92         }
93         ndr_err = ndr_push_struct_blob(out, mem_ctx, sid,
94                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
95         talloc_free(sid);
96         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
97                 return -1;
98         }
99         return 0;
100 }
101
102 /*
103   convert a NDR formatted blob to a ldif formatted objectSid
104 */
105 int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
106                                 const struct ldb_val *in, struct ldb_val *out)
107 {
108         struct dom_sid *sid;
109         enum ndr_err_code ndr_err;
110
111         sid = talloc(mem_ctx, struct dom_sid);
112         if (sid == NULL) {
113                 return -1;
114         }
115         ndr_err = ndr_pull_struct_blob_all(in, sid, sid,
116                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
117         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
118                 talloc_free(sid);
119                 return -1;
120         }
121         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
122         talloc_free(sid);
123         if (out->data == NULL) {
124                 return -1;
125         }
126         return 0;
127 }
128
129 bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
130 {
131         if (v->length < 3) {
132                 return false;
133         }
134
135         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
136         
137         return true;
138 }
139
140 /*
141   compare two objectSids
142 */
143 static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
144                                     const struct ldb_val *v1, const struct ldb_val *v2)
145 {
146         if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
147                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
148         } else if (ldif_comparision_objectSid_isString(v1)
149                    && !ldif_comparision_objectSid_isString(v2)) {
150                 struct ldb_val v;
151                 int ret;
152                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
153                         /* Perhaps not a string after all */
154                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
155                 }
156                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
157                 talloc_free(v.data);
158                 return ret;
159         } else if (!ldif_comparision_objectSid_isString(v1)
160                    && ldif_comparision_objectSid_isString(v2)) {
161                 struct ldb_val v;
162                 int ret;
163                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
164                         /* Perhaps not a string after all */
165                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
166                 }
167                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
168                 talloc_free(v.data);
169                 return ret;
170         }
171         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
172 }
173
174 /*
175   canonicalise a objectSid
176 */
177 static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
178                                       const struct ldb_val *in, struct ldb_val *out)
179 {
180         if (ldif_comparision_objectSid_isString(in)) {
181                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
182                         /* Perhaps not a string after all */
183                         return ldb_handler_copy(ldb, mem_ctx, in, out);
184                 }
185                 return 0;
186         }
187         return ldb_handler_copy(ldb, mem_ctx, in, out);
188 }
189
190 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
191                               const struct ldb_val *in, struct ldb_val *out)
192 {
193         struct dom_sid sid;
194         enum ndr_err_code ndr_err;
195         if (ldif_comparision_objectSid_isString(in)) {
196                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
197                         return 0;
198                 }
199         }
200         
201         /* Perhaps not a string after all */
202         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
203
204         if (!out->data) {
205                 return -1;
206         }
207
208         (*out).length = strhex_to_str((char *)out->data, out->length,
209                                      (const char *)in->data, in->length);
210
211         /* Check it looks like a SID */
212         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, &sid,
213                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
214         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
215                 return -1;
216         }
217         return 0;
218 }
219
220 /*
221   convert a ldif formatted objectGUID to a NDR formatted blob
222 */
223 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
224                                 const struct ldb_val *in, struct ldb_val *out)
225 {
226         struct GUID guid;
227         NTSTATUS status;
228
229         status = GUID_from_data_blob(in, &guid);
230         if (!NT_STATUS_IS_OK(status)) {
231                 return -1;
232         }
233
234         status = GUID_to_ndr_blob(&guid, mem_ctx, out);
235         if (!NT_STATUS_IS_OK(status)) {
236                 return -1;
237         }
238         return 0;
239 }
240
241 /*
242   convert a NDR formatted blob to a ldif formatted objectGUID
243 */
244 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
245                                  const struct ldb_val *in, struct ldb_val *out)
246 {
247         struct GUID guid;
248         NTSTATUS status;
249
250         status = GUID_from_ndr_blob(in, &guid);
251         if (!NT_STATUS_IS_OK(status)) {
252                 return -1;
253         }
254         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
255         if (out->data == NULL) {
256                 return -1;
257         }
258         out->length = strlen((const char *)out->data);
259         return 0;
260 }
261
262 static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
263 {
264         if (v->length != 36 && v->length != 38) return false;
265
266         /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
267         return true;
268 }
269
270 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
271                               const struct ldb_val *in, struct ldb_val *out)
272 {
273         struct GUID guid;
274         NTSTATUS status;
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         status = GUID_from_ndr_blob(out, &guid);
296         if (!NT_STATUS_IS_OK(status)) {
297                 data_blob_free(out);
298                 return -1;
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    canonicalise an objectCategory.  We use the short form as the canonical form:
431    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
432 */
433
434 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
435                                             const struct ldb_val *in, struct ldb_val *out)
436 {
437         struct ldb_dn *dn1 = NULL;
438         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
439         const struct dsdb_class *sclass;
440         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
441         if (!tmp_ctx) {
442                 return LDB_ERR_OPERATIONS_ERROR;
443         }
444
445         if (!schema) {
446                 talloc_free(tmp_ctx);
447                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
448                 if (in->data && !out->data) {
449                         return LDB_ERR_OPERATIONS_ERROR;
450                 }
451                 return LDB_SUCCESS;
452         }
453         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
454         if ( ! ldb_dn_validate(dn1)) {
455                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
456                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
457                 if (sclass) {
458                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
459                                                        sclass->defaultObjectCategory);
460                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
461                         talloc_free(tmp_ctx);
462
463                         if (!out->data) {
464                                 return LDB_ERR_OPERATIONS_ERROR;
465                         }
466                         return LDB_SUCCESS;
467                 } else {
468                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
469                         talloc_free(tmp_ctx);
470
471                         if (in->data && !out->data) {
472                                 return LDB_ERR_OPERATIONS_ERROR;
473                         }
474                         return LDB_SUCCESS;
475                 }
476         }
477         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
478         talloc_free(tmp_ctx);
479
480         if (!out->data) {
481                 return LDB_ERR_OPERATIONS_ERROR;
482         }
483         return LDB_SUCCESS;
484 }
485
486 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
487                                           const struct ldb_val *v1,
488                                           const struct ldb_val *v2)
489 {
490         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
491                                   v1, v2);
492 }
493
494 /*
495   convert a NDR formatted blob to a ldif formatted schemaInfo
496 */
497 static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
498                                  const struct ldb_val *in, struct ldb_val *out)
499 {
500         return ldif_write_NDR(ldb, mem_ctx, in, out,
501                               sizeof(struct repsFromToBlob),
502                               (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
503                               (ndr_print_fn_t)ndr_print_schemaInfoBlob,
504                               true);
505 }
506
507 /*
508   convert a ldif formatted prefixMap to a NDR formatted blob
509 */
510 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
511                                const struct ldb_val *in, struct ldb_val *out)
512 {
513         struct prefixMapBlob *blob;
514         enum ndr_err_code ndr_err;
515         char *string, *line, *p, *oid;
516         DATA_BLOB oid_blob;
517
518         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
519
520         if (tmp_ctx == NULL) {
521                 return -1;
522         }
523
524         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
525         if (blob == NULL) {
526                 talloc_free(tmp_ctx);
527                 return -1;
528         }
529
530         /* use the switch value to detect if this is in the binary
531          * format
532          */
533         if (in->length >= 4 && IVAL(in->data, 0) == PREFIX_MAP_VERSION_DSDB) {
534                 ndr_err = ndr_pull_struct_blob(in, tmp_ctx, blob,
535                                                (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
536                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
537                         ndr_err = ndr_push_struct_blob(out, mem_ctx,
538                                                        blob,
539                                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
540                         talloc_free(tmp_ctx);
541                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
542                                 return -1;
543                         }
544                         return 0;
545                 }
546         }
547
548         /* If this does not parse, then it is probably the text version, and we should try it that way */
549         blob->version = PREFIX_MAP_VERSION_DSDB;
550         
551         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
552         if (string == NULL) {
553                 talloc_free(blob);
554                 return -1;
555         }
556
557         line = string;
558         while (line && line[0]) {
559                 p=strchr(line, ';');
560                 if (p) {
561                         p[0] = '\0';
562                 } else {
563                         p=strchr(line, '\n');
564                         if (p) {
565                                 p[0] = '\0';
566                         }
567                 }
568                 /* allow a trailing separator */
569                 if (line == p) {
570                         break;
571                 }
572                 
573                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
574                                                          blob->ctr.dsdb.mappings, 
575                                                          struct drsuapi_DsReplicaOIDMapping,
576                                                          blob->ctr.dsdb.num_mappings+1);
577                 if (!blob->ctr.dsdb.mappings) {
578                         talloc_free(tmp_ctx);
579                         return -1;
580                 }
581
582                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
583
584                 if (oid[0] != ':') {
585                         talloc_free(tmp_ctx);
586                         return -1;
587                 }
588
589                 /* we know there must be at least ":" */
590                 oid++;
591
592                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
593                         talloc_free(tmp_ctx);
594                         return -1;
595                 }
596                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
597                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
598
599                 blob->ctr.dsdb.num_mappings++;
600
601                 /* Now look past the terminator we added above */
602                 if (p) {
603                         line = p + 1;
604                 } else {
605                         line = NULL;
606                 }
607         }
608
609         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
610                                        blob,
611                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
612         talloc_free(tmp_ctx);
613         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
614                 return -1;
615         }
616         return 0;
617 }
618
619 /*
620   convert a NDR formatted blob to a ldif formatted prefixMap
621 */
622 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
623                                 const struct ldb_val *in, struct ldb_val *out)
624 {
625         struct prefixMapBlob *blob;
626         enum ndr_err_code ndr_err;
627         char *string;
628         uint32_t i;
629
630         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
631                 int err;
632                 /* try to decode the blob as S4 prefixMap */
633                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
634                                      sizeof(struct prefixMapBlob),
635                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
636                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
637                                      false);
638                 if (0 == err) {
639                         return err;
640                 }
641                 /* try parsing it as Windows PrefixMap value */
642                 return ldif_write_NDR(ldb, mem_ctx, in, out,
643                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
644                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
645                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
646                                       true);
647         }
648
649         blob = talloc(mem_ctx, struct prefixMapBlob);
650         if (blob == NULL) {
651                 return -1;
652         }
653         ndr_err = ndr_pull_struct_blob_all(in, blob, 
654                                            blob,
655                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
656         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
657                 goto failed;
658         }
659         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
660                 goto failed;
661         }
662         string = talloc_strdup(mem_ctx, "");
663         if (string == NULL) {
664                 goto failed;
665         }
666
667         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
668                 DATA_BLOB oid_blob;
669                 char *partial_oid = NULL;
670
671                 if (i > 0) {
672                         string = talloc_asprintf_append(string, ";"); 
673                 }
674
675                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
676                                            blob->ctr.dsdb.mappings[i].oid.length);
677                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
678                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
679                                   blob->ctr.dsdb.mappings[i].id_prefix));
680                         goto failed;
681                 }
682                 string = talloc_asprintf_append(string, "%u:%s", 
683                                                    blob->ctr.dsdb.mappings[i].id_prefix,
684                                                    partial_oid);
685                 talloc_free(discard_const(partial_oid));
686                 if (string == NULL) {
687                         goto failed;
688                 }
689         }
690
691         talloc_free(blob);
692         *out = data_blob_string_const(string);
693         return 0;
694
695 failed:
696         talloc_free(blob);
697         return -1;
698 }
699
700 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
701 {
702         if (v->length < 4) {
703                 return true;
704         }
705
706         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
707                 return false;
708         }
709         
710         return true;
711 }
712
713 /*
714   canonicalise a prefixMap
715 */
716 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
717                                        const struct ldb_val *in, struct ldb_val *out)
718 {
719         if (ldif_comparision_prefixMap_isString(in)) {
720                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
721         }
722         return ldb_handler_copy(ldb, mem_ctx, in, out);
723 }
724
725 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
726                                      const struct ldb_val *v1,
727                                      const struct ldb_val *v2)
728 {
729         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
730                                   v1, v2);
731 }
732
733 /* length limited conversion of a ldb_val to a int32_t */
734 static int val_to_int32(const struct ldb_val *in, int32_t *v)
735 {
736         char *end;
737         char buf[64];
738
739         /* make sure we don't read past the end of the data */
740         if (in->length > sizeof(buf)-1) {
741                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
742         }
743         strncpy(buf, (char *)in->data, in->length);
744         buf[in->length] = 0;
745
746         /* We've to use "strtoll" here to have the intended overflows.
747          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
748         *v = (int32_t) strtoll(buf, &end, 0);
749         if (*end != 0) {
750                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
751         }
752         return LDB_SUCCESS;
753 }
754
755 /* length limited conversion of a ldb_val to a int64_t */
756 static int val_to_int64(const struct ldb_val *in, int64_t *v)
757 {
758         char *end;
759         char buf[64];
760
761         /* make sure we don't read past the end of the data */
762         if (in->length > sizeof(buf)-1) {
763                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
764         }
765         strncpy(buf, (char *)in->data, in->length);
766         buf[in->length] = 0;
767
768         *v = (int64_t) strtoll(buf, &end, 0);
769         if (*end != 0) {
770                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
771         }
772         return LDB_SUCCESS;
773 }
774
775 /* Canonicalisation of two 32-bit integers */
776 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
777                         const struct ldb_val *in, struct ldb_val *out)
778 {
779         int32_t i;
780         int ret;
781
782         ret = val_to_int32(in, &i);
783         if (ret != LDB_SUCCESS) {
784                 return ret;
785         }
786         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
787         if (out->data == NULL) {
788                 ldb_oom(ldb);
789                 return LDB_ERR_OPERATIONS_ERROR;
790         }
791         out->length = strlen((char *)out->data);
792         return 0;
793 }
794
795 /* Comparison of two 32-bit integers */
796 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
797                                  const struct ldb_val *v1, const struct ldb_val *v2)
798 {
799         int32_t i1=0, i2=0;
800         val_to_int32(v1, &i1);
801         val_to_int32(v2, &i2);
802         if (i1 == i2) return 0;
803         return i1 > i2? 1 : -1;
804 }
805
806 /* Canonicalisation of two 64-bit integers */
807 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
808                                    const struct ldb_val *in, struct ldb_val *out)
809 {
810         int64_t i;
811         int ret;
812
813         ret = val_to_int64(in, &i);
814         if (ret != LDB_SUCCESS) {
815                 return ret;
816         }
817         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
818         if (out->data == NULL) {
819                 ldb_oom(ldb);
820                 return LDB_ERR_OPERATIONS_ERROR;
821         }
822         out->length = strlen((char *)out->data);
823         return 0;
824 }
825
826 /* Comparison of two 64-bit integers */
827 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
828                                  const struct ldb_val *v1, const struct ldb_val *v2)
829 {
830         int64_t i1=0, i2=0;
831         val_to_int64(v1, &i1);
832         val_to_int64(v2, &i2);
833         if (i1 == i2) return 0;
834         return i1 > i2? 1 : -1;
835 }
836
837 /*
838   convert a NDR formatted blob to a ldif formatted repsFromTo
839 */
840 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
841                                  const struct ldb_val *in, struct ldb_val *out)
842 {
843         return ldif_write_NDR(ldb, mem_ctx, in, out, 
844                               sizeof(struct repsFromToBlob),
845                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
846                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
847                               true);
848 }
849
850 /*
851   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
852 */
853 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
854                                            const struct ldb_val *in, struct ldb_val *out)
855 {
856         return ldif_write_NDR(ldb, mem_ctx, in, out, 
857                               sizeof(struct replPropertyMetaDataBlob),
858                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
859                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
860                               true);
861 }
862
863 /*
864   convert a NDR formatted blob to a ldif formatted replUpToDateVector
865 */
866 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
867                                          const struct ldb_val *in, struct ldb_val *out)
868 {
869         return ldif_write_NDR(ldb, mem_ctx, in, out, 
870                               sizeof(struct replUpToDateVectorBlob),
871                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
872                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
873                               true);
874 }
875
876
877 /*
878   convert a NDR formatted blob to a ldif formatted dnsRecord
879 */
880 static int ldif_write_dnsRecord(struct ldb_context *ldb, void *mem_ctx,
881                                 const struct ldb_val *in, struct ldb_val *out)
882 {
883         return ldif_write_NDR(ldb, mem_ctx, in, out,
884                               sizeof(struct dnsp_DnssrvRpcRecord),
885                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord,
886                               (ndr_print_fn_t)ndr_print_dnsp_DnssrvRpcRecord,
887                               true);
888 }
889
890 /*
891   convert a NDR formatted blob of a supplementalCredentials into text
892 */
893 static int ldif_write_supplementalCredentialsBlob(struct ldb_context *ldb, void *mem_ctx,
894                                                   const struct ldb_val *in, struct ldb_val *out)
895 {
896         return ldif_write_NDR(ldb, mem_ctx, in, out,
897                               sizeof(struct supplementalCredentialsBlob),
898                               (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob,
899                               (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob,
900                               true);
901 }
902
903
904 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
905                                  const struct ldb_val *in, struct ldb_val *out)
906 {
907         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
908         if (!out->data) {
909                 return -1;
910         }
911         return 0;
912 }
913
914 /*
915   compare two dns
916 */
917 static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
918                                         const struct ldb_val *v1, const struct ldb_val *v2)
919 {
920         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
921         int ret;
922
923         if (dsdb_dn_is_deleted_val(v1)) {
924                 /* If the DN is deleted, then we can't search for it */
925                 return -1;
926         }
927
928         if (dsdb_dn_is_deleted_val(v2)) {
929                 /* If the DN is deleted, then we can't search for it */
930                 return -1;
931         }
932
933         dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
934         if ( ! ldb_dn_validate(dn1)) return -1;
935
936         dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
937         if ( ! ldb_dn_validate(dn2)) {
938                 talloc_free(dn1);
939                 return -1;
940         }
941
942         ret = ldb_dn_compare(dn1, dn2);
943
944         talloc_free(dn1);
945         talloc_free(dn2);
946         return ret;
947 }
948
949 static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
950                                           const struct ldb_val *in, struct ldb_val *out)
951 {
952         struct ldb_dn *dn;
953         int ret = -1;
954
955         out->length = 0;
956         out->data = NULL;
957
958         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
959         if ( ! ldb_dn_validate(dn)) {
960                 return LDB_ERR_INVALID_DN_SYNTAX;
961         }
962
963         /* By including the RMD_FLAGS of a deleted DN, we ensure it
964          * does not casually match a not deleted DN */
965         if (dsdb_dn_is_deleted_val(in)) {
966                 out->data = (uint8_t *)talloc_asprintf(mem_ctx,
967                                                        "<RMD_FLAGS=%u>%s",
968                                                        dsdb_dn_val_rmd_flags(in),
969                                                        ldb_dn_get_casefold(dn));
970         } else {
971                 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
972         }
973
974         if (out->data == NULL) {
975                 goto done;
976         }
977         out->length = strlen((char *)out->data);
978
979         ret = 0;
980
981 done:
982         talloc_free(dn);
983
984         return ret;
985 }
986
987
988 /*
989   write a 64 bit 2-part range
990 */
991 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
992                               const struct ldb_val *in, struct ldb_val *out)
993 {
994         int64_t v;
995         int ret;
996         ret = val_to_int64(in, &v);
997         if (ret != LDB_SUCCESS) {
998                 return ret;
999         }
1000         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
1001                                                (unsigned long)(v&0xFFFFFFFF),
1002                                                (unsigned long)(v>>32));
1003         if (out->data == NULL) {
1004                 ldb_oom(ldb);
1005                 return LDB_ERR_OPERATIONS_ERROR;
1006         }
1007         out->length = strlen((char *)out->data);
1008         return LDB_SUCCESS;
1009 }
1010
1011 /*
1012   read a 64 bit 2-part range
1013 */
1014 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
1015                               const struct ldb_val *in, struct ldb_val *out)
1016 {
1017         unsigned long high, low;
1018         char buf[64];
1019
1020         if (memchr(in->data, '-', in->length) == NULL) {
1021                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1022         }
1023
1024         if (in->length > sizeof(buf)-1) {
1025                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1026         }
1027         strncpy(buf, (const char *)in->data, in->length);
1028         buf[in->length] = 0;
1029
1030         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
1031                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1032         }
1033
1034         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
1035                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
1036
1037         if (out->data == NULL) {
1038                 ldb_oom(ldb);
1039                 return LDB_ERR_OPERATIONS_ERROR;
1040         }
1041         out->length = strlen((char *)out->data);
1042         return LDB_SUCCESS;
1043 }
1044
1045 /*
1046   when this operator_fn is set for a syntax, the backend calls is in
1047   preference to the comparison function. We are told the exact
1048   comparison operation that is needed, and we can return errors
1049  */
1050 static int samba_syntax_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
1051                                     const struct ldb_schema_attribute *a,
1052                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1053 {
1054         switch (operation) {
1055         case LDB_OP_AND:
1056         case LDB_OP_OR:
1057         case LDB_OP_NOT:
1058         case LDB_OP_SUBSTRING:
1059         case LDB_OP_APPROX:
1060         case LDB_OP_EXTENDED:
1061                 /* handled in the backends */
1062                 return LDB_ERR_INAPPROPRIATE_MATCHING;
1063
1064         case LDB_OP_GREATER:
1065         case LDB_OP_LESS:
1066         case LDB_OP_EQUALITY:
1067         {
1068                 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1069                 int ret;
1070                 if (tmp_ctx == NULL) {
1071                         return ldb_oom(ldb);
1072                 }
1073                 ret = a->syntax->comparison_fn(ldb, tmp_ctx, v1, v2);
1074                 talloc_free(tmp_ctx);
1075                 if (operation == LDB_OP_GREATER) {
1076                         *matched = (ret > 0);
1077                 } else if (operation == LDB_OP_LESS) {
1078                         *matched = (ret < 0);
1079                 } else {
1080                         *matched = (ret == 0);
1081                 }
1082                 return LDB_SUCCESS;
1083         }
1084
1085         case LDB_OP_PRESENT:
1086                 *matched = true;
1087                 return LDB_SUCCESS;
1088         }
1089
1090         /* we shouldn't get here */
1091         return LDB_ERR_INAPPROPRIATE_MATCHING;
1092 }
1093
1094 /*
1095   special operation for DNs, to take account of the RMD_FLAGS deleted bit
1096  */
1097 static int samba_syntax_operator_dn(struct ldb_context *ldb, enum ldb_parse_op operation,
1098                                     const struct ldb_schema_attribute *a,
1099                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1100 {
1101         if (operation == LDB_OP_PRESENT && dsdb_dn_is_deleted_val(v1)) {
1102                 /* If the DN is deleted, then we can't search for it */
1103                 *matched = false;
1104                 return LDB_SUCCESS;
1105         }
1106         return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
1107 }
1108
1109
1110 static const struct ldb_schema_syntax samba_syntaxes[] = {
1111         {
1112                 .name             = LDB_SYNTAX_SAMBA_SID,
1113                 .ldif_read_fn     = ldif_read_objectSid,
1114                 .ldif_write_fn    = ldif_write_objectSid,
1115                 .canonicalise_fn  = ldif_canonicalise_objectSid,
1116                 .comparison_fn    = ldif_comparison_objectSid,
1117                 .operator_fn      = samba_syntax_operator_fn
1118         },{
1119                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
1120                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
1121                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
1122                 .canonicalise_fn  = ldb_handler_copy,
1123                 .comparison_fn    = ldb_comparison_binary,
1124                 .operator_fn      = samba_syntax_operator_fn
1125         },{
1126                 .name             = LDB_SYNTAX_SAMBA_GUID,
1127                 .ldif_read_fn     = ldif_read_objectGUID,
1128                 .ldif_write_fn    = ldif_write_objectGUID,
1129                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
1130                 .comparison_fn    = ldif_comparison_objectGUID,
1131                 .operator_fn      = samba_syntax_operator_fn
1132         },{
1133                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
1134                 .ldif_read_fn     = ldb_handler_copy,
1135                 .ldif_write_fn    = ldb_handler_copy,
1136                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
1137                 .comparison_fn    = ldif_comparison_objectCategory,
1138                 .operator_fn      = samba_syntax_operator_fn
1139         },{
1140                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
1141                 .ldif_read_fn     = ldb_handler_copy,
1142                 .ldif_write_fn    = ldif_write_schemaInfo,
1143                 .canonicalise_fn  = ldb_handler_copy,
1144                 .comparison_fn    = ldb_comparison_binary,
1145                 .operator_fn      = samba_syntax_operator_fn
1146         },{
1147                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
1148                 .ldif_read_fn     = ldif_read_prefixMap,
1149                 .ldif_write_fn    = ldif_write_prefixMap,
1150                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
1151                 .comparison_fn    = ldif_comparison_prefixMap,
1152                 .operator_fn      = samba_syntax_operator_fn
1153         },{
1154                 .name             = LDB_SYNTAX_SAMBA_INT32,
1155                 .ldif_read_fn     = ldb_handler_copy,
1156                 .ldif_write_fn    = ldb_handler_copy,
1157                 .canonicalise_fn  = ldif_canonicalise_int32,
1158                 .comparison_fn    = ldif_comparison_int32,
1159                 .operator_fn      = samba_syntax_operator_fn
1160         },{
1161                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
1162                 .ldif_read_fn     = ldb_handler_copy,
1163                 .ldif_write_fn    = ldif_write_repsFromTo,
1164                 .canonicalise_fn  = ldb_handler_copy,
1165                 .comparison_fn    = ldb_comparison_binary,
1166                 .operator_fn      = samba_syntax_operator_fn
1167         },{
1168                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
1169                 .ldif_read_fn     = ldb_handler_copy,
1170                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
1171                 .canonicalise_fn  = ldb_handler_copy,
1172                 .comparison_fn    = ldb_comparison_binary,
1173                 .operator_fn      = samba_syntax_operator_fn
1174         },{
1175                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
1176                 .ldif_read_fn     = ldb_handler_copy,
1177                 .ldif_write_fn    = ldif_write_replUpToDateVector,
1178                 .canonicalise_fn  = ldb_handler_copy,
1179                 .comparison_fn    = ldb_comparison_binary,
1180                 .operator_fn      = samba_syntax_operator_fn
1181         },{
1182                 .name             = DSDB_SYNTAX_BINARY_DN,
1183                 .ldif_read_fn     = ldb_handler_copy,
1184                 .ldif_write_fn    = ldb_handler_copy,
1185                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1186                 .comparison_fn    = dsdb_dn_binary_comparison,
1187                 .operator_fn      = samba_syntax_operator_fn
1188         },{
1189                 .name             = DSDB_SYNTAX_STRING_DN,
1190                 .ldif_read_fn     = ldb_handler_copy,
1191                 .ldif_write_fn    = ldb_handler_copy,
1192                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
1193                 .comparison_fn    = dsdb_dn_string_comparison,
1194                 .operator_fn      = samba_syntax_operator_fn
1195         },{
1196                 .name             = LDB_SYNTAX_DN,
1197                 .ldif_read_fn     = ldb_handler_copy,
1198                 .ldif_write_fn    = ldb_handler_copy,
1199                 .canonicalise_fn  = samba_ldb_dn_link_canonicalise,
1200                 .comparison_fn    = samba_ldb_dn_link_comparison,
1201                 .operator_fn      = samba_syntax_operator_dn
1202         },{
1203                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1204                 .ldif_read_fn     = ldif_read_range64,
1205                 .ldif_write_fn    = ldif_write_range64,
1206                 .canonicalise_fn  = ldif_canonicalise_int64,
1207                 .comparison_fn    = ldif_comparison_int64,
1208                 .operator_fn      = samba_syntax_operator_fn
1209         },{
1210                 .name             = LDB_SYNTAX_SAMBA_DNSRECORD,
1211                 .ldif_read_fn     = ldb_handler_copy,
1212                 .ldif_write_fn    = ldif_write_dnsRecord,
1213                 .canonicalise_fn  = ldb_handler_copy,
1214                 .comparison_fn    = ldb_comparison_binary,
1215                 .operator_fn      = samba_syntax_operator_fn
1216         },{
1217                 .name             = LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS,
1218                 .ldif_read_fn     = ldb_handler_copy,
1219                 .ldif_write_fn    = ldif_write_supplementalCredentialsBlob,
1220                 .canonicalise_fn  = ldb_handler_copy,
1221                 .comparison_fn    = ldb_comparison_binary,
1222                 .operator_fn      = samba_syntax_operator_fn
1223         }
1224 };
1225
1226 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1227         {
1228                 .name             = "SID",
1229                 .read_fn          = extended_dn_read_SID,
1230                 .write_clear_fn   = ldif_write_objectSid,
1231                 .write_hex_fn     = extended_dn_write_hex
1232         },{
1233                 .name             = "GUID",
1234                 .read_fn          = extended_dn_read_GUID,
1235                 .write_clear_fn   = ldif_write_objectGUID,
1236                 .write_hex_fn     = extended_dn_write_hex
1237         },{
1238                 .name             = "WKGUID",
1239                 .read_fn          = ldb_handler_copy,
1240                 .write_clear_fn   = ldb_handler_copy,
1241                 .write_hex_fn     = ldb_handler_copy
1242         },{
1243                 .name             = "RMD_INVOCID",
1244                 .read_fn          = extended_dn_read_GUID,
1245                 .write_clear_fn   = ldif_write_objectGUID,
1246                 .write_hex_fn     = extended_dn_write_hex
1247         },{
1248                 .name             = "RMD_FLAGS",
1249                 .read_fn          = ldb_handler_copy,
1250                 .write_clear_fn   = ldb_handler_copy,
1251                 .write_hex_fn     = ldb_handler_copy
1252         },{
1253                 .name             = "RMD_ADDTIME",
1254                 .read_fn          = ldb_handler_copy,
1255                 .write_clear_fn   = ldb_handler_copy,
1256                 .write_hex_fn     = ldb_handler_copy
1257         },{
1258                 .name             = "RMD_CHANGETIME",
1259                 .read_fn          = ldb_handler_copy,
1260                 .write_clear_fn   = ldb_handler_copy,
1261                 .write_hex_fn     = ldb_handler_copy
1262         },{
1263                 .name             = "RMD_LOCAL_USN",
1264                 .read_fn          = ldb_handler_copy,
1265                 .write_clear_fn   = ldb_handler_copy,
1266                 .write_hex_fn     = ldb_handler_copy
1267         },{
1268                 .name             = "RMD_ORIGINATING_USN",
1269                 .read_fn          = ldb_handler_copy,
1270                 .write_clear_fn   = ldb_handler_copy,
1271                 .write_hex_fn     = ldb_handler_copy
1272         },{
1273                 .name             = "RMD_VERSION",
1274                 .read_fn          = ldb_handler_copy,
1275                 .write_clear_fn   = ldb_handler_copy,
1276                 .write_hex_fn     = ldb_handler_copy
1277         }
1278 };
1279
1280 /* TODO: Should be dynamic at some point */
1281 static const struct {
1282         const char *name;
1283         const char *syntax;
1284 } samba_attributes[] = {
1285         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1286         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1287         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1288         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1289         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1290         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1291         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1292         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1293         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1294         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1295         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1296         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1297         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1298         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1299         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1300
1301         /*
1302          * these are extracted by searching
1303          * (&(attributeSyntax=2.5.5.10)(rangeLower=16)(rangeUpper=16)(omSyntax=4))
1304          */
1305         { "attributeSecurityGUID",              LDB_SYNTAX_SAMBA_GUID },
1306         { "categoryId",                         LDB_SYNTAX_SAMBA_GUID },
1307         { "controlAccessRights",                LDB_SYNTAX_SAMBA_GUID },
1308         { "currMachineId",                      LDB_SYNTAX_SAMBA_GUID },
1309         { "fRSReplicaSetGUID",                  LDB_SYNTAX_SAMBA_GUID },
1310         { "fRSVersionGUID",                     LDB_SYNTAX_SAMBA_GUID },
1311         { "implementedCategories",              LDB_SYNTAX_SAMBA_GUID },
1312         { "msDS-AzObjectGuid",                  LDB_SYNTAX_SAMBA_GUID },
1313         { "msDFSR-ContentSetGuid",              LDB_SYNTAX_SAMBA_GUID },
1314         { "msDFSR-ReplicationGroupGuid",        LDB_SYNTAX_SAMBA_GUID },
1315         { "mSMQDigests",                        LDB_SYNTAX_SAMBA_GUID },
1316         { "mSMQOwnerID",                        LDB_SYNTAX_SAMBA_GUID },
1317         { "mSMQQMID",                           LDB_SYNTAX_SAMBA_GUID },
1318         { "mSMQQueueType",                      LDB_SYNTAX_SAMBA_GUID },
1319         { "mSMQSites",                          LDB_SYNTAX_SAMBA_GUID },
1320         { "netbootGUID",                        LDB_SYNTAX_SAMBA_GUID },
1321         { "objectGUID",                         LDB_SYNTAX_SAMBA_GUID },
1322         { "pKTGuid",                            LDB_SYNTAX_SAMBA_GUID },
1323         { "requiredCategories",                 LDB_SYNTAX_SAMBA_GUID },
1324         { "schemaIDGUID",                       LDB_SYNTAX_SAMBA_GUID },
1325         { "siteGUID",                           LDB_SYNTAX_SAMBA_GUID },
1326         { "msDFS-GenerationGUIDv2",             LDB_SYNTAX_SAMBA_GUID },
1327         { "msDFS-LinkIdentityGUIDv2",           LDB_SYNTAX_SAMBA_GUID },
1328         { "msDFS-NamespaceIdentityGUIDv2",      LDB_SYNTAX_SAMBA_GUID },
1329
1330         /*
1331          * these are known to be GUIDs
1332          */
1333         { "invocationId",                       LDB_SYNTAX_SAMBA_GUID },
1334         { "parentGUID",                         LDB_SYNTAX_SAMBA_GUID },
1335         { "msDS-OptionalFeatureGUID",           LDB_SYNTAX_SAMBA_GUID },
1336
1337         /* These NDR encoded things we want to be able to read with --show-binary */
1338         { "dnsRecord",                          LDB_SYNTAX_SAMBA_DNSRECORD },
1339         { "supplementalCredentials",            LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS}
1340 };
1341
1342 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1343 {
1344         unsigned int j;
1345         const struct ldb_schema_syntax *s = NULL;
1346         
1347         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1348                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1349                         s = &samba_syntaxes[j];
1350                         break;
1351                 }
1352         }
1353         return s;
1354 }
1355
1356 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1357 {
1358         unsigned int j;
1359         const struct ldb_schema_syntax *s = NULL;
1360
1361         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1362                 if (strcmp(samba_attributes[j].name, name) == 0) {
1363                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1364                         break;
1365                 }
1366         }
1367         
1368         return s;
1369 }
1370
1371 /*
1372   register the samba ldif handlers
1373 */
1374 int ldb_register_samba_handlers(struct ldb_context *ldb)
1375 {
1376         unsigned int i;
1377         int ret;
1378
1379         if (ldb_get_opaque(ldb, "SAMBA_HANDLERS_REGISTERED") != NULL) {
1380                 return LDB_SUCCESS;
1381         }
1382
1383         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1384                 const struct ldb_schema_syntax *s = NULL;
1385
1386                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1387
1388                 if (!s) {
1389                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1390                 }
1391
1392                 if (!s) {
1393                         return LDB_ERR_OPERATIONS_ERROR;
1394                 }
1395
1396                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1397                 if (ret != LDB_SUCCESS) {
1398                         return ret;
1399                 }
1400         }
1401
1402         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1403                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1404                 if (ret != LDB_SUCCESS) {
1405                         return ret;
1406                 }
1407
1408         }
1409
1410         ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
1411         if (ret != LDB_SUCCESS) {
1412                 return ret;
1413         }
1414
1415         return LDB_SUCCESS;
1416 }