Finish removal of iconv_convenience in public API's.
[mat/samba.git] / source4 / 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 "lib/ldb/include/ldb.h"
27 #include "lib/ldb/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/ndr/libndr.h"
34 #include "libcli/security/security.h"
35 #include "param/param.h"
36 #include "../lib/util/asn1.h"
37
38 /*
39   use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
40
41   If mask_errors is true, then function succeeds but out data
42   is set to "<Unable to decode binary data>" message
43
44   \return 0 on success; -1 on error
45 */
46 static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
47                           const struct ldb_val *in, struct ldb_val *out,
48                           size_t struct_size,
49                           ndr_pull_flags_fn_t pull_fn,
50                           ndr_print_fn_t print_fn,
51                           bool mask_errors)
52 {
53         uint8_t *p;
54         enum ndr_err_code err;
55         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
56                 return ldb_handler_copy(ldb, mem_ctx, in, out);
57         }
58         p = talloc_size(mem_ctx, struct_size);
59         err = ndr_pull_struct_blob(in, mem_ctx, 
60                                    p, pull_fn);
61         if (err != NDR_ERR_SUCCESS) {
62                 /* fail in not in mask_error mode */
63                 if (!mask_errors) {
64                         return -1;
65                 }
66                 talloc_free(p);
67                 out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
68                 out->length = strlen((const char *)out->data);
69                 return 0;
70         }
71         out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
72         talloc_free(p);
73         if (out->data == NULL) {
74                 return ldb_handler_copy(ldb, mem_ctx, in, out);         
75         }
76         out->length = strlen((char *)out->data);
77         return 0;
78 }
79
80 /*
81   convert a ldif formatted objectSid to a NDR formatted blob
82 */
83 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
84                                const struct ldb_val *in, struct ldb_val *out)
85 {
86         enum ndr_err_code ndr_err;
87         struct dom_sid *sid;
88         sid = dom_sid_parse_length(mem_ctx, in);
89         if (sid == NULL) {
90                 return -1;
91         }
92         ndr_err = ndr_push_struct_blob(out, mem_ctx, sid,
93                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
94         talloc_free(sid);
95         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
96                 return -1;
97         }
98         return 0;
99 }
100
101 /*
102   convert a NDR formatted blob to a ldif formatted objectSid
103 */
104 int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
105                                 const struct ldb_val *in, struct ldb_val *out)
106 {
107         struct dom_sid *sid;
108         enum ndr_err_code ndr_err;
109
110         sid = talloc(mem_ctx, struct dom_sid);
111         if (sid == NULL) {
112                 return -1;
113         }
114         ndr_err = ndr_pull_struct_blob_all(in, sid, sid,
115                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
116         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
117                 talloc_free(sid);
118                 return -1;
119         }
120         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
121         talloc_free(sid);
122         if (out->data == NULL) {
123                 return -1;
124         }
125         return 0;
126 }
127
128 bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
129 {
130         if (v->length < 3) {
131                 return false;
132         }
133
134         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
135         
136         return true;
137 }
138
139 /*
140   compare two objectSids
141 */
142 static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
143                                     const struct ldb_val *v1, const struct ldb_val *v2)
144 {
145         if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
146                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
147         } else if (ldif_comparision_objectSid_isString(v1)
148                    && !ldif_comparision_objectSid_isString(v2)) {
149                 struct ldb_val v;
150                 int ret;
151                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
152                         /* Perhaps not a string after all */
153                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
154                 }
155                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
156                 talloc_free(v.data);
157                 return ret;
158         } else if (!ldif_comparision_objectSid_isString(v1)
159                    && ldif_comparision_objectSid_isString(v2)) {
160                 struct ldb_val v;
161                 int ret;
162                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
163                         /* Perhaps not a string after all */
164                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
165                 }
166                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
167                 talloc_free(v.data);
168                 return ret;
169         }
170         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
171 }
172
173 /*
174   canonicalise a objectSid
175 */
176 static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
177                                       const struct ldb_val *in, struct ldb_val *out)
178 {
179         if (ldif_comparision_objectSid_isString(in)) {
180                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
181                         /* Perhaps not a string after all */
182                         return ldb_handler_copy(ldb, mem_ctx, in, out);
183                 }
184                 return 0;
185         }
186         return ldb_handler_copy(ldb, mem_ctx, in, out);
187 }
188
189 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
190                               const struct ldb_val *in, struct ldb_val *out)
191 {
192         struct dom_sid sid;
193         enum ndr_err_code ndr_err;
194         if (ldif_comparision_objectSid_isString(in)) {
195                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
196                         return 0;
197                 }
198         }
199         
200         /* Perhaps not a string after all */
201         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
202
203         if (!out->data) {
204                 return -1;
205         }
206
207         (*out).length = strhex_to_str((char *)out->data, out->length,
208                                      (const char *)in->data, in->length);
209
210         /* Check it looks like a SID */
211         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, &sid,
212                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
213         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
214                 return -1;
215         }
216         return 0;
217 }
218
219 /*
220   convert a ldif formatted objectGUID to a NDR formatted blob
221 */
222 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
223                                 const struct ldb_val *in, struct ldb_val *out)
224 {
225         struct GUID guid;
226         NTSTATUS status;
227
228         status = GUID_from_data_blob(in, &guid);
229         if (!NT_STATUS_IS_OK(status)) {
230                 return -1;
231         }
232
233         status = GUID_to_ndr_blob(&guid, mem_ctx, out);
234         if (!NT_STATUS_IS_OK(status)) {
235                 return -1;
236         }
237         return 0;
238 }
239
240 /*
241   convert a NDR formatted blob to a ldif formatted objectGUID
242 */
243 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
244                                  const struct ldb_val *in, struct ldb_val *out)
245 {
246         struct GUID guid;
247         NTSTATUS status;
248
249         status = GUID_from_ndr_blob(in, &guid);
250         if (!NT_STATUS_IS_OK(status)) {
251                 return -1;
252         }
253         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
254         if (out->data == NULL) {
255                 return -1;
256         }
257         out->length = strlen((const char *)out->data);
258         return 0;
259 }
260
261 static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
262 {
263         if (v->length != 36 && v->length != 38) return false;
264
265         /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
266         return true;
267 }
268
269 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
270                               const struct ldb_val *in, struct ldb_val *out)
271 {
272         struct GUID guid;
273         NTSTATUS status;
274
275         if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
276                 return 0;
277         }
278
279         /* Try as 'hex' form */
280         if (in->length != 32) {
281                 return -1;
282         }
283                 
284         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
285         
286         if (!out->data) {
287                 return -1;
288         }
289         
290         (*out).length = strhex_to_str((char *)out->data, out->length,
291                                       (const char *)in->data, in->length);
292         
293         /* Check it looks like a GUID */
294         status = GUID_from_ndr_blob(out, &guid);
295         if (!NT_STATUS_IS_OK(status)) {
296                 data_blob_free(out);
297                 return -1;
298         }
299         return 0;
300 }
301
302 /*
303   compare two objectGUIDs
304 */
305 static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
306                                      const struct ldb_val *v1, const struct ldb_val *v2)
307 {
308         if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) {
309                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
310         } else if (ldif_comparision_objectGUID_isString(v1)
311                    && !ldif_comparision_objectGUID_isString(v2)) {
312                 struct ldb_val v;
313                 int ret;
314                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
315                         /* Perhaps it wasn't a valid string after all */
316                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
317                 }
318                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
319                 talloc_free(v.data);
320                 return ret;
321         } else if (!ldif_comparision_objectGUID_isString(v1)
322                    && ldif_comparision_objectGUID_isString(v2)) {
323                 struct ldb_val v;
324                 int ret;
325                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
326                         /* Perhaps it wasn't a valid string after all */
327                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
328                 }
329                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
330                 talloc_free(v.data);
331                 return ret;
332         }
333         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
334 }
335
336 /*
337   canonicalise a objectGUID
338 */
339 static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
340                                        const struct ldb_val *in, struct ldb_val *out)
341 {
342         if (ldif_comparision_objectGUID_isString(in)) {
343                 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
344                         /* Perhaps it wasn't a valid string after all */
345                         return ldb_handler_copy(ldb, mem_ctx, in, out);
346                 }
347                 return 0;
348         }
349         return ldb_handler_copy(ldb, mem_ctx, in, out);
350 }
351
352
353 /*
354   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
355 */
356 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
357                                           const struct ldb_val *in, struct ldb_val *out)
358 {
359         struct security_descriptor *sd;
360         enum ndr_err_code ndr_err;
361
362         sd = talloc(mem_ctx, struct security_descriptor);
363         if (sd == NULL) {
364                 return -1;
365         }
366
367         ndr_err = ndr_pull_struct_blob(in, sd, sd,
368                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
369         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
370                 /* If this does not parse, then it is probably SDDL, and we should try it that way */
371                 
372                 const struct dom_sid *sid = samdb_domain_sid(ldb);
373                 talloc_free(sd);
374                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
375                 if (sd == NULL) {
376                         return -1;
377                 }
378         }
379
380         ndr_err = ndr_push_struct_blob(out, mem_ctx, sd,
381                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
382         talloc_free(sd);
383         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384                 return -1;
385         }
386
387         return 0;
388 }
389
390 /*
391   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
392 */
393 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
394                                            const struct ldb_val *in, struct ldb_val *out)
395 {
396         struct security_descriptor *sd;
397         enum ndr_err_code ndr_err;
398
399         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
400                 return ldif_write_NDR(ldb, mem_ctx, in, out, 
401                                       sizeof(struct security_descriptor),
402                                       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor,
403                                       (ndr_print_fn_t)ndr_print_security_descriptor,
404                                       true);
405                                       
406         }
407
408         sd = talloc(mem_ctx, struct security_descriptor);
409         if (sd == NULL) {
410                 return -1;
411         }
412         /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
413         ndr_err = ndr_pull_struct_blob(in, sd, sd,
414                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
415         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
416                 talloc_free(sd);
417                 return -1;
418         }
419         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, samdb_domain_sid_cache_only(ldb));
420         talloc_free(sd);
421         if (out->data == NULL) {
422                 return -1;
423         }
424         out->length = strlen((const char *)out->data);
425         return 0;
426 }
427
428 /* 
429    canonicalise an objectCategory.  We use the short form as the cannoical form:
430    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
431 */
432
433 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
434                                             const struct ldb_val *in, struct ldb_val *out)
435 {
436         struct ldb_dn *dn1 = NULL;
437         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
438         const struct dsdb_class *sclass;
439         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
440         if (!tmp_ctx) {
441                 return LDB_ERR_OPERATIONS_ERROR;
442         }
443
444         if (!schema) {
445                 talloc_free(tmp_ctx);
446                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
447                 if (in->data && !out->data) {
448                         return LDB_ERR_OPERATIONS_ERROR;
449                 }
450                 return LDB_SUCCESS;
451         }
452         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
453         if ( ! ldb_dn_validate(dn1)) {
454                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
455                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
456                 if (sclass) {
457                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
458                                                        sclass->defaultObjectCategory);
459                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
460                         talloc_free(tmp_ctx);
461
462                         if (!out->data) {
463                                 return LDB_ERR_OPERATIONS_ERROR;
464                         }
465                         return LDB_SUCCESS;
466                 } else {
467                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
468                         talloc_free(tmp_ctx);
469
470                         if (in->data && !out->data) {
471                                 return LDB_ERR_OPERATIONS_ERROR;
472                         }
473                         return LDB_SUCCESS;
474                 }
475         }
476         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
477         talloc_free(tmp_ctx);
478
479         if (!out->data) {
480                 return LDB_ERR_OPERATIONS_ERROR;
481         }
482         return LDB_SUCCESS;
483 }
484
485 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
486                                           const struct ldb_val *v1,
487                                           const struct ldb_val *v2)
488 {
489         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
490                                   v1, v2);
491 }
492
493 /*
494   convert a NDR formatted blob to a ldif formatted schemaInfo
495 */
496 static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
497                                  const struct ldb_val *in, struct ldb_val *out)
498 {
499         return ldif_write_NDR(ldb, mem_ctx, in, out,
500                               sizeof(struct repsFromToBlob),
501                               (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
502                               (ndr_print_fn_t)ndr_print_schemaInfoBlob,
503                               true);
504 }
505
506 /*
507   convert a ldif formatted prefixMap to a NDR formatted blob
508 */
509 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
510                                const struct ldb_val *in, struct ldb_val *out)
511 {
512         struct prefixMapBlob *blob;
513         enum ndr_err_code ndr_err;
514         char *string, *line, *p, *oid;
515         DATA_BLOB oid_blob;
516
517         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
518
519         if (tmp_ctx == NULL) {
520                 return -1;
521         }
522
523         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
524         if (blob == NULL) {
525                 talloc_free(blob);
526                 return -1;
527         }
528
529         blob->version = PREFIX_MAP_VERSION_DSDB;
530         
531         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
532         if (string == NULL) {
533                 talloc_free(blob);
534                 return -1;
535         }
536
537         line = string;
538         while (line && line[0]) {
539                 p=strchr(line, ';');
540                 if (p) {
541                         p[0] = '\0';
542                 } else {
543                         p=strchr(line, '\n');
544                         if (p) {
545                                 p[0] = '\0';
546                         }
547                 }
548                 /* allow a trailing separator */
549                 if (line == p) {
550                         break;
551                 }
552                 
553                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
554                                                          blob->ctr.dsdb.mappings, 
555                                                          struct drsuapi_DsReplicaOIDMapping,
556                                                          blob->ctr.dsdb.num_mappings+1);
557                 if (!blob->ctr.dsdb.mappings) {
558                         talloc_free(tmp_ctx);
559                         return -1;
560                 }
561
562                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
563
564                 if (oid[0] != ':') {
565                         talloc_free(tmp_ctx);
566                         return -1;
567                 }
568
569                 /* we know there must be at least ":" */
570                 oid++;
571
572                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
573                         talloc_free(tmp_ctx);
574                         return -1;
575                 }
576                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
577                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
578
579                 blob->ctr.dsdb.num_mappings++;
580
581                 /* Now look past the terminator we added above */
582                 if (p) {
583                         line = p + 1;
584                 } else {
585                         line = NULL;
586                 }
587         }
588
589         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
590                                        blob,
591                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
592         talloc_free(tmp_ctx);
593         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
594                 return -1;
595         }
596         return 0;
597 }
598
599 /*
600   convert a NDR formatted blob to a ldif formatted prefixMap
601 */
602 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
603                                 const struct ldb_val *in, struct ldb_val *out)
604 {
605         struct prefixMapBlob *blob;
606         enum ndr_err_code ndr_err;
607         char *string;
608         uint32_t i;
609
610         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
611                 int err;
612                 /* try to decode the blob as S4 prefixMap */
613                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
614                                      sizeof(struct prefixMapBlob),
615                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
616                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
617                                      false);
618                 if (0 == err) {
619                         return err;
620                 }
621                 /* try parsing it as Windows PrefixMap value */
622                 return ldif_write_NDR(ldb, mem_ctx, in, out,
623                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
624                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
625                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
626                                       true);
627         }
628
629         blob = talloc(mem_ctx, struct prefixMapBlob);
630         if (blob == NULL) {
631                 return -1;
632         }
633         ndr_err = ndr_pull_struct_blob_all(in, blob, 
634                                            blob,
635                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
636         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
637                 goto failed;
638         }
639         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
640                 goto failed;
641         }
642         string = talloc_strdup(mem_ctx, "");
643         if (string == NULL) {
644                 goto failed;
645         }
646
647         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
648                 DATA_BLOB oid_blob;
649                 const char *partial_oid = NULL;
650
651                 if (i > 0) {
652                         string = talloc_asprintf_append(string, ";"); 
653                 }
654
655                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
656                                            blob->ctr.dsdb.mappings[i].oid.length);
657                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
658                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
659                                   blob->ctr.dsdb.mappings[i].id_prefix));
660                         goto failed;
661                 }
662                 string = talloc_asprintf_append(string, "%u:%s", 
663                                                    blob->ctr.dsdb.mappings[i].id_prefix,
664                                                    partial_oid);
665                 talloc_free(discard_const(partial_oid));
666                 if (string == NULL) {
667                         goto failed;
668                 }
669         }
670
671         talloc_free(blob);
672         *out = data_blob_string_const(string);
673         return 0;
674
675 failed:
676         talloc_free(blob);
677         return -1;
678 }
679
680 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
681 {
682         if (v->length < 4) {
683                 return true;
684         }
685
686         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
687                 return false;
688         }
689         
690         return true;
691 }
692
693 /*
694   canonicalise a prefixMap
695 */
696 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
697                                        const struct ldb_val *in, struct ldb_val *out)
698 {
699         if (ldif_comparision_prefixMap_isString(in)) {
700                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
701         }
702         return ldb_handler_copy(ldb, mem_ctx, in, out);
703 }
704
705 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
706                                      const struct ldb_val *v1,
707                                      const struct ldb_val *v2)
708 {
709         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
710                                   v1, v2);
711 }
712
713 /* length limited conversion of a ldb_val to a int32_t */
714 static int val_to_int32(const struct ldb_val *in, int32_t *v)
715 {
716         char *end;
717         char buf[64];
718
719         /* make sure we don't read past the end of the data */
720         if (in->length > sizeof(buf)-1) {
721                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
722         }
723         strncpy(buf, (char *)in->data, in->length);
724         buf[in->length] = 0;
725
726         /* We've to use "strtoll" here to have the intended overflows.
727          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
728         *v = (int32_t) strtoll(buf, &end, 0);
729         if (*end != 0) {
730                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
731         }
732         return LDB_SUCCESS;
733 }
734
735 /* length limited conversion of a ldb_val to a int64_t */
736 static int val_to_int64(const struct ldb_val *in, int64_t *v)
737 {
738         char *end;
739         char buf[64];
740
741         /* make sure we don't read past the end of the data */
742         if (in->length > sizeof(buf)-1) {
743                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
744         }
745         strncpy(buf, (char *)in->data, in->length);
746         buf[in->length] = 0;
747
748         *v = (int64_t) strtoll(buf, &end, 0);
749         if (*end != 0) {
750                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
751         }
752         return LDB_SUCCESS;
753 }
754
755 /* Canonicalisation of two 32-bit integers */
756 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
757                         const struct ldb_val *in, struct ldb_val *out)
758 {
759         int32_t i;
760         int ret;
761
762         ret = val_to_int32(in, &i);
763         if (ret != LDB_SUCCESS) {
764                 return ret;
765         }
766         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
767         if (out->data == NULL) {
768                 ldb_oom(ldb);
769                 return LDB_ERR_OPERATIONS_ERROR;
770         }
771         out->length = strlen((char *)out->data);
772         return 0;
773 }
774
775 /* Comparison of two 32-bit integers */
776 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
777                                  const struct ldb_val *v1, const struct ldb_val *v2)
778 {
779         int32_t i1=0, i2=0;
780         val_to_int32(v1, &i1);
781         val_to_int32(v2, &i2);
782         if (i1 == i2) return 0;
783         return i1 > i2? 1 : -1;
784 }
785
786 /* Canonicalisation of two 64-bit integers */
787 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
788                                    const struct ldb_val *in, struct ldb_val *out)
789 {
790         int64_t i;
791         int ret;
792
793         ret = val_to_int64(in, &i);
794         if (ret != LDB_SUCCESS) {
795                 return ret;
796         }
797         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
798         if (out->data == NULL) {
799                 ldb_oom(ldb);
800                 return LDB_ERR_OPERATIONS_ERROR;
801         }
802         out->length = strlen((char *)out->data);
803         return 0;
804 }
805
806 /* Comparison of two 64-bit integers */
807 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
808                                  const struct ldb_val *v1, const struct ldb_val *v2)
809 {
810         int64_t i1=0, i2=0;
811         val_to_int64(v1, &i1);
812         val_to_int64(v2, &i2);
813         if (i1 == i2) return 0;
814         return i1 > i2? 1 : -1;
815 }
816
817 /*
818   convert a NDR formatted blob to a ldif formatted repsFromTo
819 */
820 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
821                                  const struct ldb_val *in, struct ldb_val *out)
822 {
823         return ldif_write_NDR(ldb, mem_ctx, in, out, 
824                               sizeof(struct repsFromToBlob),
825                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
826                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
827                               true);
828 }
829
830 /*
831   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
832 */
833 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
834                                            const struct ldb_val *in, struct ldb_val *out)
835 {
836         return ldif_write_NDR(ldb, mem_ctx, in, out, 
837                               sizeof(struct replPropertyMetaDataBlob),
838                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
839                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
840                               true);
841 }
842
843 /*
844   convert a NDR formatted blob to a ldif formatted replUpToDateVector
845 */
846 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
847                                          const struct ldb_val *in, struct ldb_val *out)
848 {
849         return ldif_write_NDR(ldb, mem_ctx, in, out, 
850                               sizeof(struct replUpToDateVectorBlob),
851                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
852                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
853                               true);
854 }
855
856
857 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
858                                  const struct ldb_val *in, struct ldb_val *out)
859 {
860         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
861         if (!out->data) {
862                 return -1;
863         }
864         return 0;
865 }
866
867
868 /*
869   write a 64 bit 2-part range
870 */
871 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
872                               const struct ldb_val *in, struct ldb_val *out)
873 {
874         int64_t v;
875         int ret;
876         ret = val_to_int64(in, &v);
877         if (ret != LDB_SUCCESS) {
878                 return ret;
879         }
880         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
881                                                (unsigned long)(v&0xFFFFFFFF),
882                                                (unsigned long)(v>>32));
883         if (out->data == NULL) {
884                 ldb_oom(ldb);
885                 return LDB_ERR_OPERATIONS_ERROR;
886         }
887         out->length = strlen((char *)out->data);
888         return LDB_SUCCESS;
889 }
890
891 /*
892   read a 64 bit 2-part range
893 */
894 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
895                               const struct ldb_val *in, struct ldb_val *out)
896 {
897         unsigned long high, low;
898         char buf[64];
899
900         if (memchr(in->data, '-', in->length) == NULL) {
901                 return ldb_handler_copy(ldb, mem_ctx, in, out);
902         }
903
904         if (in->length > sizeof(buf)-1) {
905                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
906         }
907         strncpy(buf, (const char *)in->data, in->length);
908         buf[in->length] = 0;
909
910         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
911                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
912         }
913
914         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
915                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
916
917         if (out->data == NULL) {
918                 ldb_oom(ldb);
919                 return LDB_ERR_OPERATIONS_ERROR;
920         }
921         out->length = strlen((char *)out->data);
922         return LDB_SUCCESS;
923 }
924
925 static const struct ldb_schema_syntax samba_syntaxes[] = {
926         {
927                 .name             = LDB_SYNTAX_SAMBA_SID,
928                 .ldif_read_fn     = ldif_read_objectSid,
929                 .ldif_write_fn    = ldif_write_objectSid,
930                 .canonicalise_fn  = ldif_canonicalise_objectSid,
931                 .comparison_fn    = ldif_comparison_objectSid
932         },{
933                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
934                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
935                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
936                 .canonicalise_fn  = ldb_handler_copy,
937                 .comparison_fn    = ldb_comparison_binary
938         },{
939                 .name             = LDB_SYNTAX_SAMBA_GUID,
940                 .ldif_read_fn     = ldif_read_objectGUID,
941                 .ldif_write_fn    = ldif_write_objectGUID,
942                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
943                 .comparison_fn    = ldif_comparison_objectGUID
944         },{
945                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
946                 .ldif_read_fn     = ldb_handler_copy,
947                 .ldif_write_fn    = ldb_handler_copy,
948                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
949                 .comparison_fn    = ldif_comparison_objectCategory
950         },{
951                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
952                 .ldif_read_fn     = ldb_handler_copy,
953                 .ldif_write_fn    = ldif_write_schemaInfo,
954                 .canonicalise_fn  = ldb_handler_copy,
955                 .comparison_fn    = ldb_comparison_binary
956         },{
957                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
958                 .ldif_read_fn     = ldif_read_prefixMap,
959                 .ldif_write_fn    = ldif_write_prefixMap,
960                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
961                 .comparison_fn    = ldif_comparison_prefixMap
962         },{
963                 .name             = LDB_SYNTAX_SAMBA_INT32,
964                 .ldif_read_fn     = ldb_handler_copy,
965                 .ldif_write_fn    = ldb_handler_copy,
966                 .canonicalise_fn  = ldif_canonicalise_int32,
967                 .comparison_fn    = ldif_comparison_int32
968         },{
969                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
970                 .ldif_read_fn     = ldb_handler_copy,
971                 .ldif_write_fn    = ldif_write_repsFromTo,
972                 .canonicalise_fn  = ldb_handler_copy,
973                 .comparison_fn    = ldb_comparison_binary
974         },{
975                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
976                 .ldif_read_fn     = ldb_handler_copy,
977                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
978                 .canonicalise_fn  = ldb_handler_copy,
979                 .comparison_fn    = ldb_comparison_binary
980         },{
981                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
982                 .ldif_read_fn     = ldb_handler_copy,
983                 .ldif_write_fn    = ldif_write_replUpToDateVector,
984                 .canonicalise_fn  = ldb_handler_copy,
985                 .comparison_fn    = ldb_comparison_binary
986         },{
987                 .name             = DSDB_SYNTAX_BINARY_DN,
988                 .ldif_read_fn     = ldb_handler_copy,
989                 .ldif_write_fn    = ldb_handler_copy,
990                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
991                 .comparison_fn    = dsdb_dn_binary_comparison
992         },{
993                 .name             = DSDB_SYNTAX_STRING_DN,
994                 .ldif_read_fn     = ldb_handler_copy,
995                 .ldif_write_fn    = ldb_handler_copy,
996                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
997                 .comparison_fn    = dsdb_dn_string_comparison
998         },{
999                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1000                 .ldif_read_fn     = ldif_read_range64,
1001                 .ldif_write_fn    = ldif_write_range64,
1002                 .canonicalise_fn  = ldif_canonicalise_int64,
1003                 .comparison_fn    = ldif_comparison_int64
1004         },
1005 };
1006
1007 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1008         {
1009                 .name             = "SID",
1010                 .read_fn          = extended_dn_read_SID,
1011                 .write_clear_fn   = ldif_write_objectSid,
1012                 .write_hex_fn     = extended_dn_write_hex
1013         },{
1014                 .name             = "GUID",
1015                 .read_fn          = extended_dn_read_GUID,
1016                 .write_clear_fn   = ldif_write_objectGUID,
1017                 .write_hex_fn     = extended_dn_write_hex
1018         },{
1019                 .name             = "WKGUID",
1020                 .read_fn          = ldb_handler_copy,
1021                 .write_clear_fn   = ldb_handler_copy,
1022                 .write_hex_fn     = ldb_handler_copy
1023         },{
1024                 .name             = "RMD_INVOCID",
1025                 .read_fn          = extended_dn_read_GUID,
1026                 .write_clear_fn   = ldif_write_objectGUID,
1027                 .write_hex_fn     = extended_dn_write_hex
1028         },{
1029                 .name             = "RMD_FLAGS",
1030                 .read_fn          = ldb_handler_copy,
1031                 .write_clear_fn   = ldb_handler_copy,
1032                 .write_hex_fn     = ldb_handler_copy
1033         },{
1034                 .name             = "RMD_ADDTIME",
1035                 .read_fn          = ldb_handler_copy,
1036                 .write_clear_fn   = ldb_handler_copy,
1037                 .write_hex_fn     = ldb_handler_copy
1038         },{
1039                 .name             = "RMD_CHANGETIME",
1040                 .read_fn          = ldb_handler_copy,
1041                 .write_clear_fn   = ldb_handler_copy,
1042                 .write_hex_fn     = ldb_handler_copy
1043         },{
1044                 .name             = "RMD_LOCAL_USN",
1045                 .read_fn          = ldb_handler_copy,
1046                 .write_clear_fn   = ldb_handler_copy,
1047                 .write_hex_fn     = ldb_handler_copy
1048         },{
1049                 .name             = "RMD_ORIGINATING_USN",
1050                 .read_fn          = ldb_handler_copy,
1051                 .write_clear_fn   = ldb_handler_copy,
1052                 .write_hex_fn     = ldb_handler_copy
1053         },{
1054                 .name             = "RMD_VERSION",
1055                 .read_fn          = ldb_handler_copy,
1056                 .write_clear_fn   = ldb_handler_copy,
1057                 .write_hex_fn     = ldb_handler_copy
1058         }
1059 };
1060
1061 /* TODO: Should be dynamic at some point */
1062 static const struct {
1063         const char *name;
1064         const char *syntax;
1065 } samba_attributes[] = {
1066         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1067         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1068         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1069         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1070         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
1071         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
1072         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
1073         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1074         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
1075         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
1076         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
1077         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
1078         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
1079         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
1080         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
1081         { "msDS-OptionalFeatureGUID",   LDB_SYNTAX_SAMBA_GUID },
1082         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1083         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1084         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1085         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1086         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1087         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1088         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1089         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1090         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1091         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1092 };
1093
1094 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1095 {
1096         unsigned int j;
1097         const struct ldb_schema_syntax *s = NULL;
1098         
1099         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1100                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1101                         s = &samba_syntaxes[j];
1102                         break;
1103                 }
1104         }
1105         return s;
1106 }
1107
1108 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1109 {
1110         unsigned int j;
1111         const struct ldb_schema_syntax *s = NULL;
1112
1113         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1114                 if (strcmp(samba_attributes[j].name, name) == 0) {
1115                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1116                         break;
1117                 }
1118         }
1119         
1120         return s;
1121 }
1122
1123 /*
1124   register the samba ldif handlers
1125 */
1126 int ldb_register_samba_handlers(struct ldb_context *ldb)
1127 {
1128         unsigned int i;
1129
1130         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1131                 int ret;
1132                 const struct ldb_schema_syntax *s = NULL;
1133
1134                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1135
1136                 if (!s) {
1137                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1138                 }
1139
1140                 if (!s) {
1141                         return -1;
1142                 }
1143
1144                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1145                 if (ret != LDB_SUCCESS) {
1146                         return ret;
1147                 }
1148         }
1149
1150         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1151                 int ret;
1152                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1153                 if (ret != LDB_SUCCESS) {
1154                         return ret;
1155                 }
1156
1157                 
1158         }
1159
1160         return LDB_SUCCESS;
1161 }