LDB:ldif_handlers.c - LDB_OP_GREATER/LDB_OP_LESS are thought as ">=" or "<="
[mdw/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   convert a string formatted SDDL to a ldif formatted ntSecurityDescriptor (SDDL format)
431 */
432 static int ldif_write_sddlSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
433                                            const struct ldb_val *in, struct ldb_val *out)
434 {
435         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
436                 struct security_descriptor *sd;
437                 const struct dom_sid *sid = samdb_domain_sid(ldb);
438
439                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
440                 out->data = (uint8_t *)ndr_print_struct_string(mem_ctx,
441                                         (ndr_print_fn_t)ndr_print_security_descriptor,
442                                         "SDDL", sd);
443                 out->length = strlen((const char *)out->data);
444                 talloc_free(sd);
445                 return 0;
446         }
447
448         return ldb_handler_copy(ldb, mem_ctx, in, out);
449 }
450
451 /* 
452    canonicalise an objectCategory.  We use the long form as the canonical form:
453    'person' becomes cn=Person,cn=Schema,cn=Configuration,<basedn>
454
455    Also any short name of an objectClass that points to a different
456    class (such as user) has the canonical form of the class it's
457    defaultObjectCategory points to (eg
458    cn=Person,cn=Schema,cn=Configuration,<basedn>)
459 */
460
461 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
462                                             const struct ldb_val *in, struct ldb_val *out)
463 {
464         struct ldb_dn *dn1 = NULL;
465         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
466         const struct dsdb_class *sclass;
467         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
468         if (!tmp_ctx) {
469                 return LDB_ERR_OPERATIONS_ERROR;
470         }
471
472         if (!schema) {
473                 talloc_free(tmp_ctx);
474                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
475                 if (in->data && !out->data) {
476                         return LDB_ERR_OPERATIONS_ERROR;
477                 }
478                 return LDB_SUCCESS;
479         }
480         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
481         if ( ! ldb_dn_validate(dn1)) {
482                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
483                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
484                 if (sclass) {
485                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
486                                                        sclass->defaultObjectCategory);
487                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
488                         talloc_free(tmp_ctx);
489
490                         if (!out->data) {
491                                 return LDB_ERR_OPERATIONS_ERROR;
492                         }
493                         return LDB_SUCCESS;
494                 } else {
495                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
496                         talloc_free(tmp_ctx);
497
498                         if (in->data && !out->data) {
499                                 return LDB_ERR_OPERATIONS_ERROR;
500                         }
501                         return LDB_SUCCESS;
502                 }
503         }
504         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
505         talloc_free(tmp_ctx);
506
507         if (!out->data) {
508                 return LDB_ERR_OPERATIONS_ERROR;
509         }
510         return LDB_SUCCESS;
511 }
512
513 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
514                                           const struct ldb_val *v1,
515                                           const struct ldb_val *v2)
516 {
517         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
518                                   v1, v2);
519 }
520
521 /*
522   convert a NDR formatted blob to a ldif formatted schemaInfo
523 */
524 static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
525                                  const struct ldb_val *in, struct ldb_val *out)
526 {
527         return ldif_write_NDR(ldb, mem_ctx, in, out,
528                               sizeof(struct repsFromToBlob),
529                               (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
530                               (ndr_print_fn_t)ndr_print_schemaInfoBlob,
531                               true);
532 }
533
534 /*
535   convert a ldif formatted prefixMap to a NDR formatted blob
536 */
537 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
538                                const struct ldb_val *in, struct ldb_val *out)
539 {
540         struct prefixMapBlob *blob;
541         enum ndr_err_code ndr_err;
542         char *string, *line, *p, *oid;
543         DATA_BLOB oid_blob;
544
545         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
546
547         if (tmp_ctx == NULL) {
548                 return -1;
549         }
550
551         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
552         if (blob == NULL) {
553                 talloc_free(tmp_ctx);
554                 return -1;
555         }
556
557         /* use the switch value to detect if this is in the binary
558          * format
559          */
560         if (in->length >= 4 && IVAL(in->data, 0) == PREFIX_MAP_VERSION_DSDB) {
561                 ndr_err = ndr_pull_struct_blob(in, tmp_ctx, blob,
562                                                (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
563                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
564                         ndr_err = ndr_push_struct_blob(out, mem_ctx,
565                                                        blob,
566                                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
567                         talloc_free(tmp_ctx);
568                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
569                                 return -1;
570                         }
571                         return 0;
572                 }
573         }
574
575         /* If this does not parse, then it is probably the text version, and we should try it that way */
576         blob->version = PREFIX_MAP_VERSION_DSDB;
577         
578         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
579         if (string == NULL) {
580                 talloc_free(blob);
581                 return -1;
582         }
583
584         line = string;
585         while (line && line[0]) {
586                 p=strchr(line, ';');
587                 if (p) {
588                         p[0] = '\0';
589                 } else {
590                         p=strchr(line, '\n');
591                         if (p) {
592                                 p[0] = '\0';
593                         }
594                 }
595                 /* allow a trailing separator */
596                 if (line == p) {
597                         break;
598                 }
599                 
600                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
601                                                          blob->ctr.dsdb.mappings, 
602                                                          struct drsuapi_DsReplicaOIDMapping,
603                                                          blob->ctr.dsdb.num_mappings+1);
604                 if (!blob->ctr.dsdb.mappings) {
605                         talloc_free(tmp_ctx);
606                         return -1;
607                 }
608
609                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
610
611                 if (oid[0] != ':') {
612                         talloc_free(tmp_ctx);
613                         return -1;
614                 }
615
616                 /* we know there must be at least ":" */
617                 oid++;
618
619                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
620                         talloc_free(tmp_ctx);
621                         return -1;
622                 }
623                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
624                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
625
626                 blob->ctr.dsdb.num_mappings++;
627
628                 /* Now look past the terminator we added above */
629                 if (p) {
630                         line = p + 1;
631                 } else {
632                         line = NULL;
633                 }
634         }
635
636         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
637                                        blob,
638                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
639         talloc_free(tmp_ctx);
640         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
641                 return -1;
642         }
643         return 0;
644 }
645
646 /*
647   convert a NDR formatted blob to a ldif formatted prefixMap
648 */
649 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
650                                 const struct ldb_val *in, struct ldb_val *out)
651 {
652         struct prefixMapBlob *blob;
653         enum ndr_err_code ndr_err;
654         char *string;
655         uint32_t i;
656
657         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
658                 int err;
659                 /* try to decode the blob as S4 prefixMap */
660                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
661                                      sizeof(struct prefixMapBlob),
662                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
663                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
664                                      false);
665                 if (0 == err) {
666                         return err;
667                 }
668                 /* try parsing it as Windows PrefixMap value */
669                 return ldif_write_NDR(ldb, mem_ctx, in, out,
670                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
671                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
672                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
673                                       true);
674         }
675
676         blob = talloc(mem_ctx, struct prefixMapBlob);
677         if (blob == NULL) {
678                 return -1;
679         }
680         ndr_err = ndr_pull_struct_blob_all(in, blob, 
681                                            blob,
682                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
683         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
684                 goto failed;
685         }
686         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
687                 goto failed;
688         }
689         string = talloc_strdup(mem_ctx, "");
690         if (string == NULL) {
691                 goto failed;
692         }
693
694         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
695                 DATA_BLOB oid_blob;
696                 char *partial_oid = NULL;
697
698                 if (i > 0) {
699                         string = talloc_asprintf_append(string, ";"); 
700                 }
701
702                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
703                                            blob->ctr.dsdb.mappings[i].oid.length);
704                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
705                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
706                                   blob->ctr.dsdb.mappings[i].id_prefix));
707                         goto failed;
708                 }
709                 string = talloc_asprintf_append(string, "%u:%s", 
710                                                    blob->ctr.dsdb.mappings[i].id_prefix,
711                                                    partial_oid);
712                 talloc_free(discard_const(partial_oid));
713                 if (string == NULL) {
714                         goto failed;
715                 }
716         }
717
718         talloc_free(blob);
719         *out = data_blob_string_const(string);
720         return 0;
721
722 failed:
723         talloc_free(blob);
724         return -1;
725 }
726
727 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
728 {
729         if (v->length < 4) {
730                 return true;
731         }
732
733         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
734                 return false;
735         }
736         
737         return true;
738 }
739
740 /*
741   canonicalise a prefixMap
742 */
743 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
744                                        const struct ldb_val *in, struct ldb_val *out)
745 {
746         if (ldif_comparision_prefixMap_isString(in)) {
747                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
748         }
749         return ldb_handler_copy(ldb, mem_ctx, in, out);
750 }
751
752 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
753                                      const struct ldb_val *v1,
754                                      const struct ldb_val *v2)
755 {
756         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
757                                   v1, v2);
758 }
759
760 /* length limited conversion of a ldb_val to a int32_t */
761 static int val_to_int32(const struct ldb_val *in, int32_t *v)
762 {
763         char *end;
764         char buf[64];
765
766         /* make sure we don't read past the end of the data */
767         if (in->length > sizeof(buf)-1) {
768                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
769         }
770         strncpy(buf, (char *)in->data, in->length);
771         buf[in->length] = 0;
772
773         /* We've to use "strtoll" here to have the intended overflows.
774          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
775         *v = (int32_t) strtoll(buf, &end, 0);
776         if (*end != 0) {
777                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
778         }
779         return LDB_SUCCESS;
780 }
781
782 /* length limited conversion of a ldb_val to a int64_t */
783 static int val_to_int64(const struct ldb_val *in, int64_t *v)
784 {
785         char *end;
786         char buf[64];
787
788         /* make sure we don't read past the end of the data */
789         if (in->length > sizeof(buf)-1) {
790                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
791         }
792         strncpy(buf, (char *)in->data, in->length);
793         buf[in->length] = 0;
794
795         *v = (int64_t) strtoll(buf, &end, 0);
796         if (*end != 0) {
797                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
798         }
799         return LDB_SUCCESS;
800 }
801
802 /* Canonicalisation of two 32-bit integers */
803 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
804                         const struct ldb_val *in, struct ldb_val *out)
805 {
806         int32_t i;
807         int ret;
808
809         ret = val_to_int32(in, &i);
810         if (ret != LDB_SUCCESS) {
811                 return ret;
812         }
813         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
814         if (out->data == NULL) {
815                 ldb_oom(ldb);
816                 return LDB_ERR_OPERATIONS_ERROR;
817         }
818         out->length = strlen((char *)out->data);
819         return 0;
820 }
821
822 /* Comparison of two 32-bit integers */
823 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
824                                  const struct ldb_val *v1, const struct ldb_val *v2)
825 {
826         int32_t i1=0, i2=0;
827         val_to_int32(v1, &i1);
828         val_to_int32(v2, &i2);
829         if (i1 == i2) return 0;
830         return i1 > i2? 1 : -1;
831 }
832
833 /* Canonicalisation of two 64-bit integers */
834 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
835                                    const struct ldb_val *in, struct ldb_val *out)
836 {
837         int64_t i;
838         int ret;
839
840         ret = val_to_int64(in, &i);
841         if (ret != LDB_SUCCESS) {
842                 return ret;
843         }
844         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
845         if (out->data == NULL) {
846                 ldb_oom(ldb);
847                 return LDB_ERR_OPERATIONS_ERROR;
848         }
849         out->length = strlen((char *)out->data);
850         return 0;
851 }
852
853 /* Comparison of two 64-bit integers */
854 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
855                                  const struct ldb_val *v1, const struct ldb_val *v2)
856 {
857         int64_t i1=0, i2=0;
858         val_to_int64(v1, &i1);
859         val_to_int64(v2, &i2);
860         if (i1 == i2) return 0;
861         return i1 > i2? 1 : -1;
862 }
863
864 /*
865   convert a NDR formatted blob to a ldif formatted repsFromTo
866 */
867 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
868                                  const struct ldb_val *in, struct ldb_val *out)
869 {
870         return ldif_write_NDR(ldb, mem_ctx, in, out, 
871                               sizeof(struct repsFromToBlob),
872                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
873                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
874                               true);
875 }
876
877 /*
878   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
879 */
880 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
881                                            const struct ldb_val *in, struct ldb_val *out)
882 {
883         return ldif_write_NDR(ldb, mem_ctx, in, out, 
884                               sizeof(struct replPropertyMetaDataBlob),
885                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
886                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
887                               true);
888 }
889
890 /*
891   convert a NDR formatted blob to a ldif formatted replUpToDateVector
892 */
893 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
894                                          const struct ldb_val *in, struct ldb_val *out)
895 {
896         return ldif_write_NDR(ldb, mem_ctx, in, out, 
897                               sizeof(struct replUpToDateVectorBlob),
898                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
899                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
900                               true);
901 }
902
903
904 /*
905   convert a NDR formatted blob to a ldif formatted dnsRecord
906 */
907 static int ldif_write_dnsRecord(struct ldb_context *ldb, void *mem_ctx,
908                                 const struct ldb_val *in, struct ldb_val *out)
909 {
910         return ldif_write_NDR(ldb, mem_ctx, in, out,
911                               sizeof(struct dnsp_DnssrvRpcRecord),
912                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord,
913                               (ndr_print_fn_t)ndr_print_dnsp_DnssrvRpcRecord,
914                               true);
915 }
916
917 /*
918   convert a NDR formatted blob to a ldif formatted dnsProperty
919 */
920 static int ldif_write_dnsProperty(struct ldb_context *ldb, void *mem_ctx,
921                                 const struct ldb_val *in, struct ldb_val *out)
922 {
923         return ldif_write_NDR(ldb, mem_ctx, in, out,
924                               sizeof(struct dnsp_DnsProperty),
925                               (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty,
926                               (ndr_print_fn_t)ndr_print_dnsp_DnsProperty,
927                               true);
928 }
929
930 /*
931   convert a NDR formatted blob of a supplementalCredentials into text
932 */
933 static int ldif_write_supplementalCredentialsBlob(struct ldb_context *ldb, void *mem_ctx,
934                                                   const struct ldb_val *in, struct ldb_val *out)
935 {
936         return ldif_write_NDR(ldb, mem_ctx, in, out,
937                               sizeof(struct supplementalCredentialsBlob),
938                               (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob,
939                               (ndr_print_fn_t)ndr_print_supplementalCredentialsBlob,
940                               true);
941 }
942
943 /*
944   convert a NDR formatted blob to a ldif formatted trustAuthInOutBlob
945 */
946 static int ldif_write_trustAuthInOutBlob(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 trustAuthInOutBlob),
951                               (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob,
952                               (ndr_print_fn_t)ndr_print_trustAuthInOutBlob,
953                               true);
954 }
955
956 /*
957   convert a NDR formatted blob of a partialAttributeSet into text
958 */
959 static int ldif_write_partialAttributeSet(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 partialAttributeSetBlob),
964                               (ndr_pull_flags_fn_t)ndr_pull_partialAttributeSetBlob,
965                               (ndr_print_fn_t)ndr_print_partialAttributeSetBlob,
966                               true);
967 }
968
969
970 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
971                                  const struct ldb_val *in, struct ldb_val *out)
972 {
973         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
974         if (!out->data) {
975                 return -1;
976         }
977         return 0;
978 }
979
980 /*
981   compare two dns
982 */
983 static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx,
984                                         const struct ldb_val *v1, const struct ldb_val *v2)
985 {
986         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
987         int ret;
988
989         if (dsdb_dn_is_deleted_val(v1)) {
990                 /* If the DN is deleted, then we can't search for it */
991                 return -1;
992         }
993
994         if (dsdb_dn_is_deleted_val(v2)) {
995                 /* If the DN is deleted, then we can't search for it */
996                 return -1;
997         }
998
999         dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
1000         if ( ! ldb_dn_validate(dn1)) return -1;
1001
1002         dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
1003         if ( ! ldb_dn_validate(dn2)) {
1004                 talloc_free(dn1);
1005                 return -1;
1006         }
1007
1008         ret = ldb_dn_compare(dn1, dn2);
1009
1010         talloc_free(dn1);
1011         talloc_free(dn2);
1012         return ret;
1013 }
1014
1015 static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx,
1016                                           const struct ldb_val *in, struct ldb_val *out)
1017 {
1018         struct ldb_dn *dn;
1019         int ret = -1;
1020
1021         out->length = 0;
1022         out->data = NULL;
1023
1024         dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
1025         if ( ! ldb_dn_validate(dn)) {
1026                 return LDB_ERR_INVALID_DN_SYNTAX;
1027         }
1028
1029         /* By including the RMD_FLAGS of a deleted DN, we ensure it
1030          * does not casually match a not deleted DN */
1031         if (dsdb_dn_is_deleted_val(in)) {
1032                 out->data = (uint8_t *)talloc_asprintf(mem_ctx,
1033                                                        "<RMD_FLAGS=%u>%s",
1034                                                        dsdb_dn_val_rmd_flags(in),
1035                                                        ldb_dn_get_casefold(dn));
1036         } else {
1037                 out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
1038         }
1039
1040         if (out->data == NULL) {
1041                 goto done;
1042         }
1043         out->length = strlen((char *)out->data);
1044
1045         ret = 0;
1046
1047 done:
1048         talloc_free(dn);
1049
1050         return ret;
1051 }
1052
1053
1054 /*
1055   write a 64 bit 2-part range
1056 */
1057 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
1058                               const struct ldb_val *in, struct ldb_val *out)
1059 {
1060         int64_t v;
1061         int ret;
1062         ret = val_to_int64(in, &v);
1063         if (ret != LDB_SUCCESS) {
1064                 return ret;
1065         }
1066         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
1067                                                (unsigned long)(v&0xFFFFFFFF),
1068                                                (unsigned long)(v>>32));
1069         if (out->data == NULL) {
1070                 ldb_oom(ldb);
1071                 return LDB_ERR_OPERATIONS_ERROR;
1072         }
1073         out->length = strlen((char *)out->data);
1074         return LDB_SUCCESS;
1075 }
1076
1077 /*
1078   read a 64 bit 2-part range
1079 */
1080 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
1081                               const struct ldb_val *in, struct ldb_val *out)
1082 {
1083         unsigned long high, low;
1084         char buf[64];
1085
1086         if (memchr(in->data, '-', in->length) == NULL) {
1087                 return ldb_handler_copy(ldb, mem_ctx, in, out);
1088         }
1089
1090         if (in->length > sizeof(buf)-1) {
1091                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1092         }
1093         strncpy(buf, (const char *)in->data, in->length);
1094         buf[in->length] = 0;
1095
1096         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
1097                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1098         }
1099
1100         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
1101                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
1102
1103         if (out->data == NULL) {
1104                 ldb_oom(ldb);
1105                 return LDB_ERR_OPERATIONS_ERROR;
1106         }
1107         out->length = strlen((char *)out->data);
1108         return LDB_SUCCESS;
1109 }
1110
1111 /*
1112   when this operator_fn is set for a syntax, the backend calls is in
1113   preference to the comparison function. We are told the exact
1114   comparison operation that is needed, and we can return errors
1115  */
1116 static int samba_syntax_operator_fn(struct ldb_context *ldb, enum ldb_parse_op operation,
1117                                     const struct ldb_schema_attribute *a,
1118                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1119 {
1120         switch (operation) {
1121         case LDB_OP_AND:
1122         case LDB_OP_OR:
1123         case LDB_OP_NOT:
1124         case LDB_OP_SUBSTRING:
1125         case LDB_OP_APPROX:
1126         case LDB_OP_EXTENDED:
1127                 /* handled in the backends */
1128                 return LDB_ERR_INAPPROPRIATE_MATCHING;
1129
1130         case LDB_OP_GREATER:
1131         case LDB_OP_LESS:
1132         case LDB_OP_EQUALITY:
1133         {
1134                 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1135                 int ret;
1136                 if (tmp_ctx == NULL) {
1137                         return ldb_oom(ldb);
1138                 }
1139                 ret = a->syntax->comparison_fn(ldb, tmp_ctx, v1, v2);
1140                 talloc_free(tmp_ctx);
1141                 if (operation == LDB_OP_GREATER) {
1142                         *matched = (ret >= 0);
1143                 } else if (operation == LDB_OP_LESS) {
1144                         *matched = (ret <= 0);
1145                 } else {
1146                         *matched = (ret == 0);
1147                 }
1148                 return LDB_SUCCESS;
1149         }
1150
1151         case LDB_OP_PRESENT:
1152                 *matched = true;
1153                 return LDB_SUCCESS;
1154         }
1155
1156         /* we shouldn't get here */
1157         return LDB_ERR_INAPPROPRIATE_MATCHING;
1158 }
1159
1160 /*
1161   see if two DNs match, comparing first by GUID, then by SID, and
1162   finally by string components
1163  */
1164 static int samba_dn_extended_match(struct ldb_context *ldb,
1165                                    const struct ldb_val *v1,
1166                                    const struct ldb_val *v2,
1167                                    bool *matched)
1168 {
1169         TALLOC_CTX *tmp_ctx;
1170         struct ldb_dn *dn1, *dn2;
1171         const struct ldb_val *guid1, *guid2, *sid1, *sid2;
1172         uint32_t rmd_flags1, rmd_flags2;
1173
1174         tmp_ctx = talloc_new(ldb);
1175
1176         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v1);
1177         dn2 = ldb_dn_from_ldb_val(tmp_ctx, ldb, v2);
1178         if (!dn1 || !dn2) {
1179                 /* couldn't parse as DN's */
1180                 talloc_free(tmp_ctx);
1181                 (*matched) = false;
1182                 return LDB_SUCCESS;
1183         }
1184
1185         rmd_flags1 = dsdb_dn_rmd_flags(dn1);
1186         rmd_flags2 = dsdb_dn_rmd_flags(dn2);
1187
1188         if ((rmd_flags1 & DSDB_RMD_FLAG_DELETED) !=
1189             (rmd_flags2 & DSDB_RMD_FLAG_DELETED)) {
1190                 /* only match if they have the same deletion status */
1191                 talloc_free(tmp_ctx);
1192                 (*matched) = false;
1193                 return LDB_SUCCESS;
1194         }
1195
1196
1197         guid1 = ldb_dn_get_extended_component(dn1, "GUID");
1198         guid2 = ldb_dn_get_extended_component(dn2, "GUID");
1199         if (guid1 && guid2) {
1200                 (*matched) = (data_blob_cmp(guid1, guid2) == 0);
1201                 talloc_free(tmp_ctx);
1202                 return LDB_SUCCESS;
1203         }
1204
1205         sid1 = ldb_dn_get_extended_component(dn1, "SID");
1206         sid2 = ldb_dn_get_extended_component(dn2, "SID");
1207         if (sid1 && sid2) {
1208                 (*matched) = (data_blob_cmp(sid1, sid2) == 0);
1209                 talloc_free(tmp_ctx);
1210                 return LDB_SUCCESS;
1211         }
1212
1213         (*matched) = (ldb_dn_compare(dn1, dn2) == 0);
1214
1215         talloc_free(tmp_ctx);
1216         return LDB_SUCCESS;
1217 }
1218
1219 /*
1220   special operation for DNs, to take account of the RMD_FLAGS deleted bit
1221  */
1222 static int samba_syntax_operator_dn(struct ldb_context *ldb, enum ldb_parse_op operation,
1223                                     const struct ldb_schema_attribute *a,
1224                                     const struct ldb_val *v1, const struct ldb_val *v2, bool *matched)
1225 {
1226         if (operation == LDB_OP_PRESENT && dsdb_dn_is_deleted_val(v1)) {
1227                 /* If the DN is deleted, then we can't search for it */
1228
1229                 /* should this be for equality too? */
1230                 *matched = false;
1231                 return LDB_SUCCESS;
1232         }
1233
1234         if (operation == LDB_OP_EQUALITY &&
1235             samba_dn_extended_match(ldb, v1, v2, matched) == LDB_SUCCESS) {
1236                 return LDB_SUCCESS;
1237         }
1238
1239         return samba_syntax_operator_fn(ldb, operation, a, v1, v2, matched);
1240 }
1241
1242
1243 static const struct ldb_schema_syntax samba_syntaxes[] = {
1244         {
1245                 .name             = LDB_SYNTAX_SAMBA_SID,
1246                 .ldif_read_fn     = ldif_read_objectSid,
1247                 .ldif_write_fn    = ldif_write_objectSid,
1248                 .canonicalise_fn  = ldif_canonicalise_objectSid,
1249                 .comparison_fn    = ldif_comparison_objectSid,
1250                 .operator_fn      = samba_syntax_operator_fn
1251         },{
1252                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
1253                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
1254                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
1255                 .canonicalise_fn  = ldb_handler_copy,
1256                 .comparison_fn    = ldb_comparison_binary,
1257                 .operator_fn      = samba_syntax_operator_fn
1258         },{
1259                 .name             = LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR,
1260                 .ldif_read_fn     = ldb_handler_copy,
1261                 .ldif_write_fn    = ldif_write_sddlSecurityDescriptor,
1262                 .canonicalise_fn  = ldb_handler_fold,
1263                 .comparison_fn    = ldb_comparison_fold,
1264                 .operator_fn      = samba_syntax_operator_fn
1265         },{
1266                 .name             = LDB_SYNTAX_SAMBA_GUID,
1267                 .ldif_read_fn     = ldif_read_objectGUID,
1268                 .ldif_write_fn    = ldif_write_objectGUID,
1269                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
1270                 .comparison_fn    = ldif_comparison_objectGUID,
1271                 .operator_fn      = samba_syntax_operator_fn
1272         },{
1273                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
1274                 .ldif_read_fn     = ldb_handler_copy,
1275                 .ldif_write_fn    = ldb_handler_copy,
1276                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
1277                 .comparison_fn    = ldif_comparison_objectCategory,
1278                 .operator_fn      = samba_syntax_operator_fn
1279         },{
1280                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
1281                 .ldif_read_fn     = ldb_handler_copy,
1282                 .ldif_write_fn    = ldif_write_schemaInfo,
1283                 .canonicalise_fn  = ldb_handler_copy,
1284                 .comparison_fn    = ldb_comparison_binary,
1285                 .operator_fn      = samba_syntax_operator_fn
1286         },{
1287                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
1288                 .ldif_read_fn     = ldif_read_prefixMap,
1289                 .ldif_write_fn    = ldif_write_prefixMap,
1290                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
1291                 .comparison_fn    = ldif_comparison_prefixMap,
1292                 .operator_fn      = samba_syntax_operator_fn
1293         },{
1294                 .name             = LDB_SYNTAX_SAMBA_INT32,
1295                 .ldif_read_fn     = ldb_handler_copy,
1296                 .ldif_write_fn    = ldb_handler_copy,
1297                 .canonicalise_fn  = ldif_canonicalise_int32,
1298                 .comparison_fn    = ldif_comparison_int32,
1299                 .operator_fn      = samba_syntax_operator_fn
1300         },{
1301                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
1302                 .ldif_read_fn     = ldb_handler_copy,
1303                 .ldif_write_fn    = ldif_write_repsFromTo,
1304                 .canonicalise_fn  = ldb_handler_copy,
1305                 .comparison_fn    = ldb_comparison_binary,
1306                 .operator_fn      = samba_syntax_operator_fn
1307         },{
1308                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
1309                 .ldif_read_fn     = ldb_handler_copy,
1310                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
1311                 .canonicalise_fn  = ldb_handler_copy,
1312                 .comparison_fn    = ldb_comparison_binary,
1313                 .operator_fn      = samba_syntax_operator_fn
1314         },{
1315                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
1316                 .ldif_read_fn     = ldb_handler_copy,
1317                 .ldif_write_fn    = ldif_write_replUpToDateVector,
1318                 .canonicalise_fn  = ldb_handler_copy,
1319                 .comparison_fn    = ldb_comparison_binary,
1320                 .operator_fn      = samba_syntax_operator_fn
1321         },{
1322                 .name             = LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB,
1323                 .ldif_read_fn     = ldb_handler_copy,
1324                 .ldif_write_fn    = ldif_write_trustAuthInOutBlob,
1325                 .canonicalise_fn  = ldb_handler_copy,
1326                 .comparison_fn    = ldb_comparison_binary,
1327                 .operator_fn      = samba_syntax_operator_fn
1328         },{
1329                 .name             = DSDB_SYNTAX_BINARY_DN,
1330                 .ldif_read_fn     = ldb_handler_copy,
1331                 .ldif_write_fn    = ldb_handler_copy,
1332                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
1333                 .comparison_fn    = dsdb_dn_binary_comparison,
1334                 .operator_fn      = samba_syntax_operator_fn
1335         },{
1336                 .name             = DSDB_SYNTAX_STRING_DN,
1337                 .ldif_read_fn     = ldb_handler_copy,
1338                 .ldif_write_fn    = ldb_handler_copy,
1339                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
1340                 .comparison_fn    = dsdb_dn_string_comparison,
1341                 .operator_fn      = samba_syntax_operator_fn
1342         },{
1343                 .name             = LDB_SYNTAX_DN,
1344                 .ldif_read_fn     = ldb_handler_copy,
1345                 .ldif_write_fn    = ldb_handler_copy,
1346                 .canonicalise_fn  = samba_ldb_dn_link_canonicalise,
1347                 .comparison_fn    = samba_ldb_dn_link_comparison,
1348                 .operator_fn      = samba_syntax_operator_dn
1349         },{
1350                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1351                 .ldif_read_fn     = ldif_read_range64,
1352                 .ldif_write_fn    = ldif_write_range64,
1353                 .canonicalise_fn  = ldif_canonicalise_int64,
1354                 .comparison_fn    = ldif_comparison_int64,
1355                 .operator_fn      = samba_syntax_operator_fn
1356         },{
1357                 .name             = LDB_SYNTAX_SAMBA_DNSRECORD,
1358                 .ldif_read_fn     = ldb_handler_copy,
1359                 .ldif_write_fn    = ldif_write_dnsRecord,
1360                 .canonicalise_fn  = ldb_handler_copy,
1361                 .comparison_fn    = ldb_comparison_binary,
1362                 .operator_fn      = samba_syntax_operator_fn
1363         },{
1364                 .name             = LDB_SYNTAX_SAMBA_DNSPROPERTY,
1365                 .ldif_read_fn     = ldb_handler_copy,
1366                 .ldif_write_fn    = ldif_write_dnsProperty,
1367                 .canonicalise_fn  = ldb_handler_copy,
1368                 .comparison_fn    = ldb_comparison_binary,
1369                 .operator_fn      = samba_syntax_operator_fn
1370         },{
1371                 .name             = LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS,
1372                 .ldif_read_fn     = ldb_handler_copy,
1373                 .ldif_write_fn    = ldif_write_supplementalCredentialsBlob,
1374                 .canonicalise_fn  = ldb_handler_copy,
1375                 .comparison_fn    = ldb_comparison_binary,
1376                 .operator_fn      = samba_syntax_operator_fn
1377         },{
1378                 .name             = LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET,
1379                 .ldif_read_fn     = ldb_handler_copy,
1380                 .ldif_write_fn    = ldif_write_partialAttributeSet,
1381                 .canonicalise_fn  = ldb_handler_copy,
1382                 .comparison_fn    = ldb_comparison_binary,
1383                 .operator_fn      = samba_syntax_operator_fn
1384         }
1385 };
1386
1387 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1388         {
1389                 .name             = "SID",
1390                 .read_fn          = extended_dn_read_SID,
1391                 .write_clear_fn   = ldif_write_objectSid,
1392                 .write_hex_fn     = extended_dn_write_hex
1393         },{
1394                 .name             = "GUID",
1395                 .read_fn          = extended_dn_read_GUID,
1396                 .write_clear_fn   = ldif_write_objectGUID,
1397                 .write_hex_fn     = extended_dn_write_hex
1398         },{
1399                 .name             = "WKGUID",
1400                 .read_fn          = ldb_handler_copy,
1401                 .write_clear_fn   = ldb_handler_copy,
1402                 .write_hex_fn     = ldb_handler_copy
1403         },{
1404                 .name             = "RMD_INVOCID",
1405                 .read_fn          = extended_dn_read_GUID,
1406                 .write_clear_fn   = ldif_write_objectGUID,
1407                 .write_hex_fn     = extended_dn_write_hex
1408         },{
1409                 .name             = "RMD_FLAGS",
1410                 .read_fn          = ldb_handler_copy,
1411                 .write_clear_fn   = ldb_handler_copy,
1412                 .write_hex_fn     = ldb_handler_copy
1413         },{
1414                 .name             = "RMD_ADDTIME",
1415                 .read_fn          = ldb_handler_copy,
1416                 .write_clear_fn   = ldb_handler_copy,
1417                 .write_hex_fn     = ldb_handler_copy
1418         },{
1419                 .name             = "RMD_CHANGETIME",
1420                 .read_fn          = ldb_handler_copy,
1421                 .write_clear_fn   = ldb_handler_copy,
1422                 .write_hex_fn     = ldb_handler_copy
1423         },{
1424                 .name             = "RMD_LOCAL_USN",
1425                 .read_fn          = ldb_handler_copy,
1426                 .write_clear_fn   = ldb_handler_copy,
1427                 .write_hex_fn     = ldb_handler_copy
1428         },{
1429                 .name             = "RMD_ORIGINATING_USN",
1430                 .read_fn          = ldb_handler_copy,
1431                 .write_clear_fn   = ldb_handler_copy,
1432                 .write_hex_fn     = ldb_handler_copy
1433         },{
1434                 .name             = "RMD_VERSION",
1435                 .read_fn          = ldb_handler_copy,
1436                 .write_clear_fn   = ldb_handler_copy,
1437                 .write_hex_fn     = ldb_handler_copy
1438         }
1439 };
1440
1441 /* TODO: Should be dynamic at some point */
1442 static const struct {
1443         const char *name;
1444         const char *syntax;
1445 } samba_attributes[] = {
1446         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1447         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1448         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1449         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1450         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1451         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1452         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1453         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1454         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1455         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1456         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1457         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1458         { "trustAuthIncoming",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1459         { "trustAuthOutgoing",          LDB_SYNTAX_SAMBA_TRUSTAUTHINOUTBLOB },
1460         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1461         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1462         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1463         { "defaultSecurityDescriptor",  LDB_SYNTAX_SAMBA_SDDL_SECURITY_DESCRIPTOR },
1464
1465         /*
1466          * these are extracted by searching
1467          * (&(attributeSyntax=2.5.5.10)(rangeLower=16)(rangeUpper=16)(omSyntax=4))
1468          */
1469         { "attributeSecurityGUID",              LDB_SYNTAX_SAMBA_GUID },
1470         { "categoryId",                         LDB_SYNTAX_SAMBA_GUID },
1471         { "controlAccessRights",                LDB_SYNTAX_SAMBA_GUID },
1472         { "currMachineId",                      LDB_SYNTAX_SAMBA_GUID },
1473         { "fRSReplicaSetGUID",                  LDB_SYNTAX_SAMBA_GUID },
1474         { "fRSVersionGUID",                     LDB_SYNTAX_SAMBA_GUID },
1475         { "implementedCategories",              LDB_SYNTAX_SAMBA_GUID },
1476         { "msDS-AzObjectGuid",                  LDB_SYNTAX_SAMBA_GUID },
1477         { "msDFSR-ContentSetGuid",              LDB_SYNTAX_SAMBA_GUID },
1478         { "msDFSR-ReplicationGroupGuid",        LDB_SYNTAX_SAMBA_GUID },
1479         { "mSMQDigests",                        LDB_SYNTAX_SAMBA_GUID },
1480         { "mSMQOwnerID",                        LDB_SYNTAX_SAMBA_GUID },
1481         { "mSMQQMID",                           LDB_SYNTAX_SAMBA_GUID },
1482         { "mSMQQueueType",                      LDB_SYNTAX_SAMBA_GUID },
1483         { "mSMQSites",                          LDB_SYNTAX_SAMBA_GUID },
1484         { "netbootGUID",                        LDB_SYNTAX_SAMBA_GUID },
1485         { "objectGUID",                         LDB_SYNTAX_SAMBA_GUID },
1486         { "pKTGuid",                            LDB_SYNTAX_SAMBA_GUID },
1487         { "requiredCategories",                 LDB_SYNTAX_SAMBA_GUID },
1488         { "schemaIDGUID",                       LDB_SYNTAX_SAMBA_GUID },
1489         { "siteGUID",                           LDB_SYNTAX_SAMBA_GUID },
1490         { "msDFS-GenerationGUIDv2",             LDB_SYNTAX_SAMBA_GUID },
1491         { "msDFS-LinkIdentityGUIDv2",           LDB_SYNTAX_SAMBA_GUID },
1492         { "msDFS-NamespaceIdentityGUIDv2",      LDB_SYNTAX_SAMBA_GUID },
1493
1494         /*
1495          * these are known to be GUIDs
1496          */
1497         { "invocationId",                       LDB_SYNTAX_SAMBA_GUID },
1498         { "parentGUID",                         LDB_SYNTAX_SAMBA_GUID },
1499         { "msDS-OptionalFeatureGUID",           LDB_SYNTAX_SAMBA_GUID },
1500
1501         /* These NDR encoded things we want to be able to read with --show-binary */
1502         { "dnsRecord",                          LDB_SYNTAX_SAMBA_DNSRECORD },
1503         { "dNSProperty",                        LDB_SYNTAX_SAMBA_DNSPROPERTY },
1504         { "supplementalCredentials",            LDB_SYNTAX_SAMBA_SUPPLEMENTALCREDENTIALS},
1505         { "partialAttributeSet",                LDB_SYNTAX_SAMBA_PARTIALATTRIBUTESET}
1506 };
1507
1508 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1509 {
1510         unsigned int j;
1511         const struct ldb_schema_syntax *s = NULL;
1512         
1513         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1514                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1515                         s = &samba_syntaxes[j];
1516                         break;
1517                 }
1518         }
1519         return s;
1520 }
1521
1522 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1523 {
1524         unsigned int j;
1525         const struct ldb_schema_syntax *s = NULL;
1526
1527         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1528                 if (strcmp(samba_attributes[j].name, name) == 0) {
1529                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1530                         break;
1531                 }
1532         }
1533         
1534         return s;
1535 }
1536
1537 /*
1538   register the samba ldif handlers
1539 */
1540 int ldb_register_samba_handlers(struct ldb_context *ldb)
1541 {
1542         unsigned int i;
1543         int ret;
1544
1545         if (ldb_get_opaque(ldb, "SAMBA_HANDLERS_REGISTERED") != NULL) {
1546                 return LDB_SUCCESS;
1547         }
1548
1549         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1550                 const struct ldb_schema_syntax *s = NULL;
1551
1552                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1553
1554                 if (!s) {
1555                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1556                 }
1557
1558                 if (!s) {
1559                         return LDB_ERR_OPERATIONS_ERROR;
1560                 }
1561
1562                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1563                 if (ret != LDB_SUCCESS) {
1564                         return ret;
1565                 }
1566         }
1567
1568         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1569                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1570                 if (ret != LDB_SUCCESS) {
1571                         return ret;
1572                 }
1573
1574         }
1575
1576         ret = ldb_set_opaque(ldb, "SAMBA_HANDLERS_REGISTERED", (void*)1);
1577         if (ret != LDB_SUCCESS) {
1578                 return ret;
1579         }
1580
1581         return LDB_SUCCESS;
1582 }