9ebb4bb5c3d8c18dd3e4773ed846dec97605cfe7
[kai/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                                    lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
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, NULL, 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, NULL, 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, NULL, &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, NULL, 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, NULL, 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, NULL, sd,
415                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
416         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
417                 talloc_free(sd);
418                 return -1;
419         }
420         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, samdb_domain_sid_cache_only(ldb));
421         talloc_free(sd);
422         if (out->data == NULL) {
423                 return -1;
424         }
425         out->length = strlen((const char *)out->data);
426         return 0;
427 }
428
429 /* 
430    canonicalise an objectCategory.  We use the short form as the cannoical form:
431    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
432 */
433
434 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
435                                             const struct ldb_val *in, struct ldb_val *out)
436 {
437         struct ldb_dn *dn1 = NULL;
438         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
439         const struct dsdb_class *sclass;
440         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
441         if (!tmp_ctx) {
442                 return LDB_ERR_OPERATIONS_ERROR;
443         }
444
445         if (!schema) {
446                 talloc_free(tmp_ctx);
447                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
448                 if (in->data && !out->data) {
449                         return LDB_ERR_OPERATIONS_ERROR;
450                 }
451                 return LDB_SUCCESS;
452         }
453         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
454         if ( ! ldb_dn_validate(dn1)) {
455                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
456                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
457                 if (sclass) {
458                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
459                                                        sclass->defaultObjectCategory);
460                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
461                         talloc_free(tmp_ctx);
462
463                         if (!out->data) {
464                                 return LDB_ERR_OPERATIONS_ERROR;
465                         }
466                         return LDB_SUCCESS;
467                 } else {
468                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
469                         talloc_free(tmp_ctx);
470
471                         if (in->data && !out->data) {
472                                 return LDB_ERR_OPERATIONS_ERROR;
473                         }
474                         return LDB_SUCCESS;
475                 }
476         }
477         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
478         talloc_free(tmp_ctx);
479
480         if (!out->data) {
481                 return LDB_ERR_OPERATIONS_ERROR;
482         }
483         return LDB_SUCCESS;
484 }
485
486 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
487                                           const struct ldb_val *v1,
488                                           const struct ldb_val *v2)
489 {
490         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_objectCategory,
491                                   v1, v2);
492 }
493
494 /*
495   convert a NDR formatted blob to a ldif formatted schemaInfo
496 */
497 static int ldif_write_schemaInfo(struct ldb_context *ldb, void *mem_ctx,
498                                  const struct ldb_val *in, struct ldb_val *out)
499 {
500         return ldif_write_NDR(ldb, mem_ctx, in, out,
501                               sizeof(struct repsFromToBlob),
502                               (ndr_pull_flags_fn_t)ndr_pull_schemaInfoBlob,
503                               (ndr_print_fn_t)ndr_print_schemaInfoBlob,
504                               true);
505 }
506
507 /*
508   convert a ldif formatted prefixMap to a NDR formatted blob
509 */
510 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
511                                const struct ldb_val *in, struct ldb_val *out)
512 {
513         struct prefixMapBlob *blob;
514         enum ndr_err_code ndr_err;
515         char *string, *line, *p, *oid;
516         DATA_BLOB oid_blob;
517
518         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
519
520         if (tmp_ctx == NULL) {
521                 return -1;
522         }
523
524         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
525         if (blob == NULL) {
526                 talloc_free(blob);
527                 return -1;
528         }
529
530         blob->version = PREFIX_MAP_VERSION_DSDB;
531         
532         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
533         if (string == NULL) {
534                 talloc_free(blob);
535                 return -1;
536         }
537
538         line = string;
539         while (line && line[0]) {
540                 p=strchr(line, ';');
541                 if (p) {
542                         p[0] = '\0';
543                 } else {
544                         p=strchr(line, '\n');
545                         if (p) {
546                                 p[0] = '\0';
547                         }
548                 }
549                 /* allow a trailing separator */
550                 if (line == p) {
551                         break;
552                 }
553                 
554                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
555                                                          blob->ctr.dsdb.mappings, 
556                                                          struct drsuapi_DsReplicaOIDMapping,
557                                                          blob->ctr.dsdb.num_mappings+1);
558                 if (!blob->ctr.dsdb.mappings) {
559                         talloc_free(tmp_ctx);
560                         return -1;
561                 }
562
563                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
564
565                 if (oid[0] != ':') {
566                         talloc_free(tmp_ctx);
567                         return -1;
568                 }
569
570                 /* we know there must be at least ":" */
571                 oid++;
572
573                 if (!ber_write_partial_OID_String(blob->ctr.dsdb.mappings, &oid_blob, oid)) {
574                         talloc_free(tmp_ctx);
575                         return -1;
576                 }
577                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.length = oid_blob.length;
578                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.binary_oid = oid_blob.data;
579
580                 blob->ctr.dsdb.num_mappings++;
581
582                 /* Now look past the terminator we added above */
583                 if (p) {
584                         line = p + 1;
585                 } else {
586                         line = NULL;
587                 }
588         }
589
590         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
591                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
592                                        blob,
593                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
594         talloc_free(tmp_ctx);
595         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
596                 return -1;
597         }
598         return 0;
599 }
600
601 /*
602   convert a NDR formatted blob to a ldif formatted prefixMap
603 */
604 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
605                                 const struct ldb_val *in, struct ldb_val *out)
606 {
607         struct prefixMapBlob *blob;
608         enum ndr_err_code ndr_err;
609         char *string;
610         uint32_t i;
611
612         if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
613                 int err;
614                 /* try to decode the blob as S4 prefixMap */
615                 err = ldif_write_NDR(ldb, mem_ctx, in, out,
616                                      sizeof(struct prefixMapBlob),
617                                      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
618                                      (ndr_print_fn_t)ndr_print_prefixMapBlob,
619                                      false);
620                 if (0 == err) {
621                         return err;
622                 }
623                 /* try parsing it as Windows PrefixMap value */
624                 return ldif_write_NDR(ldb, mem_ctx, in, out,
625                                       sizeof(struct drsuapi_MSPrefixMap_Ctr),
626                                       (ndr_pull_flags_fn_t)ndr_pull_drsuapi_MSPrefixMap_Ctr,
627                                       (ndr_print_fn_t)ndr_print_drsuapi_MSPrefixMap_Ctr,
628                                       true);
629         }
630
631         blob = talloc(mem_ctx, struct prefixMapBlob);
632         if (blob == NULL) {
633                 return -1;
634         }
635         ndr_err = ndr_pull_struct_blob_all(in, blob, 
636                                            lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
637                                            blob,
638                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
639         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
640                 goto failed;
641         }
642         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
643                 goto failed;
644         }
645         string = talloc_strdup(mem_ctx, "");
646         if (string == NULL) {
647                 goto failed;
648         }
649
650         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
651                 DATA_BLOB oid_blob;
652                 const char *partial_oid = NULL;
653
654                 if (i > 0) {
655                         string = talloc_asprintf_append(string, ";"); 
656                 }
657
658                 oid_blob = data_blob_const(blob->ctr.dsdb.mappings[i].oid.binary_oid,
659                                            blob->ctr.dsdb.mappings[i].oid.length);
660                 if (!ber_read_partial_OID_String(blob, oid_blob, &partial_oid)) {
661                         DEBUG(0, ("ber_read_partial_OID failed on prefixMap item with id: 0x%X",
662                                   blob->ctr.dsdb.mappings[i].id_prefix));
663                         goto failed;
664                 }
665                 string = talloc_asprintf_append(string, "%u:%s", 
666                                                    blob->ctr.dsdb.mappings[i].id_prefix,
667                                                    partial_oid);
668                 talloc_free(discard_const(partial_oid));
669                 if (string == NULL) {
670                         goto failed;
671                 }
672         }
673
674         talloc_free(blob);
675         *out = data_blob_string_const(string);
676         return 0;
677
678 failed:
679         talloc_free(blob);
680         return -1;
681 }
682
683 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
684 {
685         if (v->length < 4) {
686                 return true;
687         }
688
689         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
690                 return false;
691         }
692         
693         return true;
694 }
695
696 /*
697   canonicalise a prefixMap
698 */
699 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
700                                        const struct ldb_val *in, struct ldb_val *out)
701 {
702         if (ldif_comparision_prefixMap_isString(in)) {
703                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
704         }
705         return ldb_handler_copy(ldb, mem_ctx, in, out);
706 }
707
708 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
709                                      const struct ldb_val *v1,
710                                      const struct ldb_val *v2)
711 {
712         return ldb_any_comparison(ldb, mem_ctx, ldif_canonicalise_prefixMap,
713                                   v1, v2);
714 }
715
716 /* length limited conversion of a ldb_val to a int32_t */
717 static int val_to_int32(const struct ldb_val *in, int32_t *v)
718 {
719         char *end;
720         char buf[64];
721
722         /* make sure we don't read past the end of the data */
723         if (in->length > sizeof(buf)-1) {
724                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
725         }
726         strncpy(buf, (char *)in->data, in->length);
727         buf[in->length] = 0;
728
729         /* We've to use "strtoll" here to have the intended overflows.
730          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
731         *v = (int32_t) strtoll(buf, &end, 0);
732         if (*end != 0) {
733                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
734         }
735         return LDB_SUCCESS;
736 }
737
738 /* length limited conversion of a ldb_val to a int64_t */
739 static int val_to_int64(const struct ldb_val *in, int64_t *v)
740 {
741         char *end;
742         char buf[64];
743
744         /* make sure we don't read past the end of the data */
745         if (in->length > sizeof(buf)-1) {
746                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
747         }
748         strncpy(buf, (char *)in->data, in->length);
749         buf[in->length] = 0;
750
751         *v = (int64_t) strtoll(buf, &end, 0);
752         if (*end != 0) {
753                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
754         }
755         return LDB_SUCCESS;
756 }
757
758 /* Canonicalisation of two 32-bit integers */
759 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
760                         const struct ldb_val *in, struct ldb_val *out)
761 {
762         int32_t i;
763         int ret;
764
765         ret = val_to_int32(in, &i);
766         if (ret != LDB_SUCCESS) {
767                 return ret;
768         }
769         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
770         if (out->data == NULL) {
771                 ldb_oom(ldb);
772                 return LDB_ERR_OPERATIONS_ERROR;
773         }
774         out->length = strlen((char *)out->data);
775         return 0;
776 }
777
778 /* Comparison of two 32-bit integers */
779 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
780                                  const struct ldb_val *v1, const struct ldb_val *v2)
781 {
782         int32_t i1=0, i2=0;
783         val_to_int32(v1, &i1);
784         val_to_int32(v2, &i2);
785         if (i1 == i2) return 0;
786         return i1 > i2? 1 : -1;
787 }
788
789 /* Canonicalisation of two 64-bit integers */
790 static int ldif_canonicalise_int64(struct ldb_context *ldb, void *mem_ctx,
791                                    const struct ldb_val *in, struct ldb_val *out)
792 {
793         int64_t i;
794         int ret;
795
796         ret = val_to_int64(in, &i);
797         if (ret != LDB_SUCCESS) {
798                 return ret;
799         }
800         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
801         if (out->data == NULL) {
802                 ldb_oom(ldb);
803                 return LDB_ERR_OPERATIONS_ERROR;
804         }
805         out->length = strlen((char *)out->data);
806         return 0;
807 }
808
809 /* Comparison of two 64-bit integers */
810 static int ldif_comparison_int64(struct ldb_context *ldb, void *mem_ctx,
811                                  const struct ldb_val *v1, const struct ldb_val *v2)
812 {
813         int64_t i1=0, i2=0;
814         val_to_int64(v1, &i1);
815         val_to_int64(v2, &i2);
816         if (i1 == i2) return 0;
817         return i1 > i2? 1 : -1;
818 }
819
820 /*
821   convert a NDR formatted blob to a ldif formatted repsFromTo
822 */
823 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
824                                  const struct ldb_val *in, struct ldb_val *out)
825 {
826         return ldif_write_NDR(ldb, mem_ctx, in, out, 
827                               sizeof(struct repsFromToBlob),
828                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
829                               (ndr_print_fn_t)ndr_print_repsFromToBlob,
830                               true);
831 }
832
833 /*
834   convert a NDR formatted blob to a ldif formatted replPropertyMetaData
835 */
836 static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
837                                            const struct ldb_val *in, struct ldb_val *out)
838 {
839         return ldif_write_NDR(ldb, mem_ctx, in, out, 
840                               sizeof(struct replPropertyMetaDataBlob),
841                               (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
842                               (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
843                               true);
844 }
845
846 /*
847   convert a NDR formatted blob to a ldif formatted replUpToDateVector
848 */
849 static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
850                                          const struct ldb_val *in, struct ldb_val *out)
851 {
852         return ldif_write_NDR(ldb, mem_ctx, in, out, 
853                               sizeof(struct replUpToDateVectorBlob),
854                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
855                               (ndr_print_fn_t)ndr_print_replUpToDateVectorBlob,
856                               true);
857 }
858
859
860 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
861                                  const struct ldb_val *in, struct ldb_val *out)
862 {
863         *out = data_blob_string_const(data_blob_hex_string_lower(mem_ctx, in));
864         if (!out->data) {
865                 return -1;
866         }
867         return 0;
868 }
869
870
871 /*
872   write a 64 bit 2-part range
873 */
874 static int ldif_write_range64(struct ldb_context *ldb, void *mem_ctx,
875                               const struct ldb_val *in, struct ldb_val *out)
876 {
877         int64_t v;
878         int ret;
879         ret = val_to_int64(in, &v);
880         if (ret != LDB_SUCCESS) {
881                 return ret;
882         }
883         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lu-%lu",
884                                                (unsigned long)(v&0xFFFFFFFF),
885                                                (unsigned long)(v>>32));
886         if (out->data == NULL) {
887                 ldb_oom(ldb);
888                 return LDB_ERR_OPERATIONS_ERROR;
889         }
890         out->length = strlen((char *)out->data);
891         return LDB_SUCCESS;
892 }
893
894 /*
895   read a 64 bit 2-part range
896 */
897 static int ldif_read_range64(struct ldb_context *ldb, void *mem_ctx,
898                               const struct ldb_val *in, struct ldb_val *out)
899 {
900         unsigned long high, low;
901         char buf[64];
902
903         if (memchr(in->data, '-', in->length) == NULL) {
904                 return ldb_handler_copy(ldb, mem_ctx, in, out);
905         }
906
907         if (in->length > sizeof(buf)-1) {
908                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
909         }
910         strncpy(buf, (const char *)in->data, in->length);
911         buf[in->length] = 0;
912
913         if (sscanf(buf, "%lu-%lu", &low, &high) != 2) {
914                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
915         }
916
917         out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%llu",
918                                                (unsigned long long)(((uint64_t)high)<<32) | (low));
919
920         if (out->data == NULL) {
921                 ldb_oom(ldb);
922                 return LDB_ERR_OPERATIONS_ERROR;
923         }
924         out->length = strlen((char *)out->data);
925         return LDB_SUCCESS;
926 }
927
928 static const struct ldb_schema_syntax samba_syntaxes[] = {
929         {
930                 .name             = LDB_SYNTAX_SAMBA_SID,
931                 .ldif_read_fn     = ldif_read_objectSid,
932                 .ldif_write_fn    = ldif_write_objectSid,
933                 .canonicalise_fn  = ldif_canonicalise_objectSid,
934                 .comparison_fn    = ldif_comparison_objectSid
935         },{
936                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
937                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
938                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
939                 .canonicalise_fn  = ldb_handler_copy,
940                 .comparison_fn    = ldb_comparison_binary
941         },{
942                 .name             = LDB_SYNTAX_SAMBA_GUID,
943                 .ldif_read_fn     = ldif_read_objectGUID,
944                 .ldif_write_fn    = ldif_write_objectGUID,
945                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
946                 .comparison_fn    = ldif_comparison_objectGUID
947         },{
948                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
949                 .ldif_read_fn     = ldb_handler_copy,
950                 .ldif_write_fn    = ldb_handler_copy,
951                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
952                 .comparison_fn    = ldif_comparison_objectCategory
953         },{
954                 .name             = LDB_SYNTAX_SAMBA_SCHEMAINFO,
955                 .ldif_read_fn     = ldb_handler_copy,
956                 .ldif_write_fn    = ldif_write_schemaInfo,
957                 .canonicalise_fn  = ldb_handler_copy,
958                 .comparison_fn    = ldb_comparison_binary
959         },{
960                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
961                 .ldif_read_fn     = ldif_read_prefixMap,
962                 .ldif_write_fn    = ldif_write_prefixMap,
963                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
964                 .comparison_fn    = ldif_comparison_prefixMap
965         },{
966                 .name             = LDB_SYNTAX_SAMBA_INT32,
967                 .ldif_read_fn     = ldb_handler_copy,
968                 .ldif_write_fn    = ldb_handler_copy,
969                 .canonicalise_fn  = ldif_canonicalise_int32,
970                 .comparison_fn    = ldif_comparison_int32
971         },{
972                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
973                 .ldif_read_fn     = ldb_handler_copy,
974                 .ldif_write_fn    = ldif_write_repsFromTo,
975                 .canonicalise_fn  = ldb_handler_copy,
976                 .comparison_fn    = ldb_comparison_binary
977         },{
978                 .name             = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
979                 .ldif_read_fn     = ldb_handler_copy,
980                 .ldif_write_fn    = ldif_write_replPropertyMetaData,
981                 .canonicalise_fn  = ldb_handler_copy,
982                 .comparison_fn    = ldb_comparison_binary
983         },{
984                 .name             = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
985                 .ldif_read_fn     = ldb_handler_copy,
986                 .ldif_write_fn    = ldif_write_replUpToDateVector,
987                 .canonicalise_fn  = ldb_handler_copy,
988                 .comparison_fn    = ldb_comparison_binary
989         },{
990                 .name             = DSDB_SYNTAX_BINARY_DN,
991                 .ldif_read_fn     = ldb_handler_copy,
992                 .ldif_write_fn    = ldb_handler_copy,
993                 .canonicalise_fn  = dsdb_dn_binary_canonicalise,
994                 .comparison_fn    = dsdb_dn_binary_comparison
995         },{
996                 .name             = DSDB_SYNTAX_STRING_DN,
997                 .ldif_read_fn     = ldb_handler_copy,
998                 .ldif_write_fn    = ldb_handler_copy,
999                 .canonicalise_fn  = dsdb_dn_string_canonicalise,
1000                 .comparison_fn    = dsdb_dn_string_comparison
1001         },{
1002                 .name             = LDB_SYNTAX_SAMBA_RANGE64,
1003                 .ldif_read_fn     = ldif_read_range64,
1004                 .ldif_write_fn    = ldif_write_range64,
1005                 .canonicalise_fn  = ldif_canonicalise_int64,
1006                 .comparison_fn    = ldif_comparison_int64
1007         },
1008 };
1009
1010 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
1011         {
1012                 .name             = "SID",
1013                 .read_fn          = extended_dn_read_SID,
1014                 .write_clear_fn   = ldif_write_objectSid,
1015                 .write_hex_fn     = extended_dn_write_hex
1016         },{
1017                 .name             = "GUID",
1018                 .read_fn          = extended_dn_read_GUID,
1019                 .write_clear_fn   = ldif_write_objectGUID,
1020                 .write_hex_fn     = extended_dn_write_hex
1021         },{
1022                 .name             = "WKGUID",
1023                 .read_fn          = ldb_handler_copy,
1024                 .write_clear_fn   = ldb_handler_copy,
1025                 .write_hex_fn     = ldb_handler_copy
1026         },{
1027                 .name             = "RMD_INVOCID",
1028                 .read_fn          = extended_dn_read_GUID,
1029                 .write_clear_fn   = ldif_write_objectGUID,
1030                 .write_hex_fn     = extended_dn_write_hex
1031         },{
1032                 .name             = "RMD_FLAGS",
1033                 .read_fn          = ldb_handler_copy,
1034                 .write_clear_fn   = ldb_handler_copy,
1035                 .write_hex_fn     = ldb_handler_copy
1036         },{
1037                 .name             = "RMD_ADDTIME",
1038                 .read_fn          = ldb_handler_copy,
1039                 .write_clear_fn   = ldb_handler_copy,
1040                 .write_hex_fn     = ldb_handler_copy
1041         },{
1042                 .name             = "RMD_CHANGETIME",
1043                 .read_fn          = ldb_handler_copy,
1044                 .write_clear_fn   = ldb_handler_copy,
1045                 .write_hex_fn     = ldb_handler_copy
1046         },{
1047                 .name             = "RMD_LOCAL_USN",
1048                 .read_fn          = ldb_handler_copy,
1049                 .write_clear_fn   = ldb_handler_copy,
1050                 .write_hex_fn     = ldb_handler_copy
1051         },{
1052                 .name             = "RMD_ORIGINATING_USN",
1053                 .read_fn          = ldb_handler_copy,
1054                 .write_clear_fn   = ldb_handler_copy,
1055                 .write_hex_fn     = ldb_handler_copy
1056         },{
1057                 .name             = "RMD_VERSION",
1058                 .read_fn          = ldb_handler_copy,
1059                 .write_clear_fn   = ldb_handler_copy,
1060                 .write_hex_fn     = ldb_handler_copy
1061         }
1062 };
1063
1064 /* TODO: Should be dynamic at some point */
1065 static const struct {
1066         const char *name;
1067         const char *syntax;
1068 } samba_attributes[] = {
1069         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
1070         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
1071         { "tokenGroups",                LDB_SYNTAX_SAMBA_SID },
1072         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
1073         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
1074         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
1075         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
1076         { "oMSyntax",                   LDB_SYNTAX_SAMBA_INT32 },
1077         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
1078         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
1079         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
1080         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
1081         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
1082         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
1083         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
1084         { "msDS-OptionalFeatureGUID",   LDB_SYNTAX_SAMBA_GUID },
1085         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
1086         { "schemaInfo",                 LDB_SYNTAX_SAMBA_SCHEMAINFO },
1087         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
1088         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
1089         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
1090         { "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
1091         { "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
1092         { "rIDAllocationPool",          LDB_SYNTAX_SAMBA_RANGE64 },
1093         { "rIDPreviousAllocationPool",  LDB_SYNTAX_SAMBA_RANGE64 },
1094         { "rIDAvailablePool",           LDB_SYNTAX_SAMBA_RANGE64 },
1095 };
1096
1097 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
1098 {
1099         unsigned int j;
1100         const struct ldb_schema_syntax *s = NULL;
1101         
1102         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
1103                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
1104                         s = &samba_syntaxes[j];
1105                         break;
1106                 }
1107         }
1108         return s;
1109 }
1110
1111 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
1112 {
1113         unsigned int j;
1114         const struct ldb_schema_syntax *s = NULL;
1115
1116         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
1117                 if (strcmp(samba_attributes[j].name, name) == 0) {
1118                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
1119                         break;
1120                 }
1121         }
1122         
1123         return s;
1124 }
1125
1126 /*
1127   register the samba ldif handlers
1128 */
1129 int ldb_register_samba_handlers(struct ldb_context *ldb)
1130 {
1131         unsigned int i;
1132
1133         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
1134                 int ret;
1135                 const struct ldb_schema_syntax *s = NULL;
1136
1137                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
1138
1139                 if (!s) {
1140                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
1141                 }
1142
1143                 if (!s) {
1144                         return -1;
1145                 }
1146
1147                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
1148                 if (ret != LDB_SUCCESS) {
1149                         return ret;
1150                 }
1151         }
1152
1153         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
1154                 int ret;
1155                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
1156                 if (ret != LDB_SUCCESS) {
1157                         return ret;
1158                 }
1159
1160                 
1161         }
1162
1163         return LDB_SUCCESS;
1164 }