s4/ldb: added ldif handler for repsFrom/repsTo
[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-2007
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
37 /*
38   convert a ldif formatted objectSid to a NDR formatted blob
39 */
40 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
41                                const struct ldb_val *in, struct ldb_val *out)
42 {
43         enum ndr_err_code ndr_err;
44         struct dom_sid *sid;
45         sid = dom_sid_parse_length(mem_ctx, in);
46         if (sid == NULL) {
47                 return -1;
48         }
49         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid,
50                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
51         talloc_free(sid);
52         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
53                 return -1;
54         }
55         return 0;
56 }
57
58 /*
59   convert a NDR formatted blob to a ldif formatted objectSid
60 */
61 static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
62                                 const struct ldb_val *in, struct ldb_val *out)
63 {
64         struct dom_sid *sid;
65         enum ndr_err_code ndr_err;
66
67         sid = talloc(mem_ctx, struct dom_sid);
68         if (sid == NULL) {
69                 return -1;
70         }
71         ndr_err = ndr_pull_struct_blob_all(in, sid, NULL, sid,
72                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
73         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
74                 talloc_free(sid);
75                 return -1;
76         }
77         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
78         talloc_free(sid);
79         if (out->data == NULL) {
80                 return -1;
81         }
82         return 0;
83 }
84
85 static bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
86 {
87         if (v->length < 3) {
88                 return false;
89         }
90
91         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
92         
93         return true;
94 }
95
96 /*
97   compare two objectSids
98 */
99 static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
100                                     const struct ldb_val *v1, const struct ldb_val *v2)
101 {
102         if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
103                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
104         } else if (ldif_comparision_objectSid_isString(v1)
105                    && !ldif_comparision_objectSid_isString(v2)) {
106                 struct ldb_val v;
107                 int ret;
108                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
109                         /* Perhaps not a string after all */
110                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
111                 }
112                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
113                 talloc_free(v.data);
114                 return ret;
115         } else if (!ldif_comparision_objectSid_isString(v1)
116                    && ldif_comparision_objectSid_isString(v2)) {
117                 struct ldb_val v;
118                 int ret;
119                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
120                         /* Perhaps not a string after all */
121                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
122                 }
123                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
124                 talloc_free(v.data);
125                 return ret;
126         }
127         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
128 }
129
130 /*
131   canonicalise a objectSid
132 */
133 static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
134                                       const struct ldb_val *in, struct ldb_val *out)
135 {
136         if (ldif_comparision_objectSid_isString(in)) {
137                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
138                         /* Perhaps not a string after all */
139                         return ldb_handler_copy(ldb, mem_ctx, in, out);
140                 }
141                 return 0;
142         }
143         return ldb_handler_copy(ldb, mem_ctx, in, out);
144 }
145
146 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
147                               const struct ldb_val *in, struct ldb_val *out)
148 {
149         struct dom_sid sid;
150         enum ndr_err_code ndr_err;
151         if (ldif_comparision_objectSid_isString(in)) {
152                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
153                         return 0;
154                 }
155         }
156         
157         /* Perhaps not a string after all */
158         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
159
160         if (!out->data) {
161                 return -1;
162         }
163
164         (*out).length = strhex_to_str((char *)out->data, out->length,
165                                      (const char *)in->data, in->length);
166
167         /* Check it looks like a SID */
168         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid,
169                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
170         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
171                 return -1;
172         }
173         return 0;
174 }
175
176 /*
177   convert a ldif formatted objectGUID to a NDR formatted blob
178 */
179 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
180                                 const struct ldb_val *in, struct ldb_val *out)
181 {
182         struct GUID guid;
183         NTSTATUS status;
184         enum ndr_err_code ndr_err;
185
186         status = GUID_from_data_blob(in, &guid);
187         if (!NT_STATUS_IS_OK(status)) {
188                 return -1;
189         }
190
191         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
192                                        (ndr_push_flags_fn_t)ndr_push_GUID);
193         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
194                 return -1;
195         }
196         return 0;
197 }
198
199 /*
200   convert a NDR formatted blob to a ldif formatted objectGUID
201 */
202 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
203                                  const struct ldb_val *in, struct ldb_val *out)
204 {
205         struct GUID guid;
206         enum ndr_err_code ndr_err;
207         ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid,
208                                            (ndr_pull_flags_fn_t)ndr_pull_GUID);
209         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
210                 return -1;
211         }
212         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
213         if (out->data == NULL) {
214                 return -1;
215         }
216         out->length = strlen((const char *)out->data);
217         return 0;
218 }
219
220 static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
221 {
222         if (v->length != 36 && v->length != 38) return false;
223
224         /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
225         return true;
226 }
227
228 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
229                               const struct ldb_val *in, struct ldb_val *out)
230 {
231         struct GUID guid;
232         enum ndr_err_code ndr_err;
233         if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
234                 return 0;
235         }
236
237         /* Try as 'hex' form */
238         if (in->length != 32) {
239                 return -1;
240         }
241                 
242         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
243         
244         if (!out->data) {
245                 return -1;
246         }
247         
248         (*out).length = strhex_to_str((char *)out->data, out->length,
249                                       (const char *)in->data, in->length);
250         
251         /* Check it looks like a GUID */
252         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid,
253                                            (ndr_pull_flags_fn_t)ndr_pull_GUID);
254         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
255                 return -1;
256         }
257         return 0;
258 }
259
260 /*
261   compare two objectGUIDs
262 */
263 static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
264                                      const struct ldb_val *v1, const struct ldb_val *v2)
265 {
266         if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) {
267                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
268         } else if (ldif_comparision_objectGUID_isString(v1)
269                    && !ldif_comparision_objectGUID_isString(v2)) {
270                 struct ldb_val v;
271                 int ret;
272                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
273                         /* Perhaps it wasn't a valid string after all */
274                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
275                 }
276                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
277                 talloc_free(v.data);
278                 return ret;
279         } else if (!ldif_comparision_objectGUID_isString(v1)
280                    && ldif_comparision_objectGUID_isString(v2)) {
281                 struct ldb_val v;
282                 int ret;
283                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
284                         /* Perhaps it wasn't a valid string after all */
285                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
286                 }
287                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
288                 talloc_free(v.data);
289                 return ret;
290         }
291         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
292 }
293
294 /*
295   canonicalise a objectGUID
296 */
297 static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
298                                        const struct ldb_val *in, struct ldb_val *out)
299 {
300         if (ldif_comparision_objectGUID_isString(in)) {
301                 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
302                         /* Perhaps it wasn't a valid string after all */
303                         return ldb_handler_copy(ldb, mem_ctx, in, out);
304                 }
305                 return 0;
306         }
307         return ldb_handler_copy(ldb, mem_ctx, in, out);
308 }
309
310
311 /*
312   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
313 */
314 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
315                                           const struct ldb_val *in, struct ldb_val *out)
316 {
317         struct security_descriptor *sd;
318
319         enum ndr_err_code ndr_err;
320
321         sd = talloc(mem_ctx, struct security_descriptor);
322         if (sd == NULL) {
323                 return -1;
324         }
325
326         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
327                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
328         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
329                 /* If this does not parse, then it is probably SDDL, and we should try it that way */
330                 
331                 const struct dom_sid *sid = samdb_domain_sid(ldb);
332                 talloc_free(sd);
333                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
334                 if (sd == NULL) {
335                         return -1;
336                 }
337         }
338
339         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
340                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
341         talloc_free(sd);
342         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
343                 return -1;
344         }
345
346         return 0;
347 }
348
349 /*
350   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
351 */
352 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
353                                            const struct ldb_val *in, struct ldb_val *out)
354 {
355         struct security_descriptor *sd;
356         enum ndr_err_code ndr_err;
357
358         sd = talloc(mem_ctx, struct security_descriptor);
359         if (sd == NULL) {
360                 return -1;
361         }
362         /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
363         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
364                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
365         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
366                 talloc_free(sd);
367                 return -1;
368         }
369         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
370         talloc_free(sd);
371         if (out->data == NULL) {
372                 return -1;
373         }
374         out->length = strlen((const char *)out->data);
375         return 0;
376 }
377
378 /* 
379    canonicalise an objectCategory.  We use the short form as the cannoical form:
380    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
381 */
382
383 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
384                                             const struct ldb_val *in, struct ldb_val *out)
385 {
386         struct ldb_dn *dn1 = NULL;
387         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
388         const struct dsdb_class *sclass;
389         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
390         if (!tmp_ctx) {
391                 return LDB_ERR_OPERATIONS_ERROR;
392         }
393
394         if (!schema) {
395                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
396                 if (in->data && !out->data) {
397                         return LDB_ERR_OPERATIONS_ERROR;
398                 }
399                 return LDB_SUCCESS;
400         }
401         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
402         if ( ! ldb_dn_validate(dn1)) {
403                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
404                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
405                 if (sclass) {
406                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
407                                                        sclass->defaultObjectCategory);
408                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
409                         talloc_free(tmp_ctx);
410
411                         if (!out->data) {
412                                 return LDB_ERR_OPERATIONS_ERROR;
413                         }
414                         return LDB_SUCCESS;
415                 } else {
416                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
417                         talloc_free(tmp_ctx);
418
419                         if (in->data && !out->data) {
420                                 return LDB_ERR_OPERATIONS_ERROR;
421                         }
422                         return LDB_SUCCESS;
423                 }
424         }
425         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
426         talloc_free(tmp_ctx);
427
428         if (!out->data) {
429                 return LDB_ERR_OPERATIONS_ERROR;
430         }
431         return LDB_SUCCESS;
432 }
433
434 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
435                                           const struct ldb_val *v1,
436                                           const struct ldb_val *v2)
437 {
438
439         int ret, ret1, ret2;
440         struct ldb_val v1_canon, v2_canon;
441         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
442
443         /* I could try and bail if tmp_ctx was NULL, but what return
444          * value would I use?
445          *
446          * It seems easier to continue on the NULL context 
447          */
448         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
449         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
450
451         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
452                 ret = data_blob_cmp(&v1_canon, &v2_canon);
453         } else {
454                 ret = data_blob_cmp(v1, v2);
455         }
456         talloc_free(tmp_ctx);
457         return ret;
458 }
459
460 /*
461   convert a ldif formatted prefixMap to a NDR formatted blob
462 */
463 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
464                                const struct ldb_val *in, struct ldb_val *out)
465 {
466         struct prefixMapBlob *blob;
467         enum ndr_err_code ndr_err;
468         char *string, *line, *p, *oid;
469
470         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
471
472         if (tmp_ctx == NULL) {
473                 return -1;
474         }
475
476         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
477         if (blob == NULL) {
478                 talloc_free(blob);
479                 return -1;
480         }
481
482         blob->version = PREFIX_MAP_VERSION_DSDB;
483         
484         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
485         if (string == NULL) {
486                 talloc_free(blob);
487                 return -1;
488         }
489
490         line = string;
491         while (line && line[0]) {
492                 p=strchr(line, ';');
493                 if (p) {
494                         p[0] = '\0';
495                 } else {
496                         p=strchr(line, '\n');
497                         if (p) {
498                                 p[0] = '\0';
499                         }
500                 }
501                 /* allow a traling seperator */
502                 if (line == p) {
503                         break;
504                 }
505                 
506                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
507                                                          blob->ctr.dsdb.mappings, 
508                                                          struct drsuapi_DsReplicaOIDMapping,
509                                                          blob->ctr.dsdb.num_mappings+1);
510                 if (!blob->ctr.dsdb.mappings) {
511                         talloc_free(tmp_ctx);
512                         return -1;
513                 }
514
515                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
516
517                 if (oid[0] != ':') {
518                         talloc_free(tmp_ctx);
519                         return -1;
520                 }
521
522                 /* we know there must be at least ":" */
523                 oid++;
524
525                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
526                         = talloc_strdup(blob->ctr.dsdb.mappings, oid);
527
528                 blob->ctr.dsdb.num_mappings++;
529
530                 /* Now look past the terminator we added above */
531                 if (p) {
532                         line = p + 1;
533                 } else {
534                         line = NULL;
535                 }
536         }
537
538         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
539                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
540                                        blob,
541                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
542         talloc_free(tmp_ctx);
543         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544                 return -1;
545         }
546         return 0;
547 }
548
549 /*
550   convert a NDR formatted blob to a ldif formatted prefixMap
551 */
552 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
553                                 const struct ldb_val *in, struct ldb_val *out)
554 {
555         struct prefixMapBlob *blob;
556         enum ndr_err_code ndr_err;
557         char *string;
558         uint32_t i;
559
560         blob = talloc(mem_ctx, struct prefixMapBlob);
561         if (blob == NULL) {
562                 return -1;
563         }
564         ndr_err = ndr_pull_struct_blob_all(in, blob, 
565                                            lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
566                                            blob,
567                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
568         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
569                 talloc_free(blob);
570                 return -1;
571         }
572         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
573                 return -1;
574         }
575         string = talloc_strdup(mem_ctx, "");
576         if (string == NULL) {
577                 return -1;
578         }
579
580         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
581                 if (i > 0) {
582                         string = talloc_asprintf_append(string, ";"); 
583                 }
584                 string = talloc_asprintf_append(string, "%u:%s", 
585                                                    blob->ctr.dsdb.mappings[i].id_prefix,
586                                                    blob->ctr.dsdb.mappings[i].oid.oid);
587                 if (string == NULL) {
588                         return -1;
589                 }
590         }
591
592         talloc_free(blob);
593         *out = data_blob_string_const(string);
594         return 0;
595 }
596
597 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
598 {
599         if (v->length < 4) {
600                 return true;
601         }
602
603         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
604                 return false;
605         }
606         
607         return true;
608 }
609
610 /*
611   canonicalise a prefixMap
612 */
613 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
614                                        const struct ldb_val *in, struct ldb_val *out)
615 {
616         if (ldif_comparision_prefixMap_isString(in)) {
617                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
618         }
619         return ldb_handler_copy(ldb, mem_ctx, in, out);
620 }
621
622 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
623                                      const struct ldb_val *v1,
624                                      const struct ldb_val *v2)
625 {
626
627         int ret, ret1, ret2;
628         struct ldb_val v1_canon, v2_canon;
629         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
630
631         /* I could try and bail if tmp_ctx was NULL, but what return
632          * value would I use?
633          *
634          * It seems easier to continue on the NULL context 
635          */
636         ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
637         ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
638
639         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
640                 ret = data_blob_cmp(&v1_canon, &v2_canon);
641         } else {
642                 ret = data_blob_cmp(v1, v2);
643         }
644         talloc_free(tmp_ctx);
645         return ret;
646 }
647
648 /* Canonicalisation of two 32-bit integers */
649 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
650                         const struct ldb_val *in, struct ldb_val *out)
651 {
652         char *end;
653         /* We've to use "strtoll" here to have the intended overflows.
654          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
655         int32_t i = (int32_t) strtoll((char *)in->data, &end, 0);
656         if (*end != 0) {
657                 return -1;
658         }
659         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
660         if (out->data == NULL) {
661                 return -1;
662         }
663         out->length = strlen((char *)out->data);
664         return 0;
665 }
666
667 /* Comparison of two 32-bit integers */
668 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
669                         const struct ldb_val *v1, const struct ldb_val *v2)
670 {
671         /* We've to use "strtoll" here to have the intended overflows.
672          * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
673         return (int32_t) strtoll((char *)v1->data, NULL, 0)
674          - (int32_t) strtoll((char *)v2->data, NULL, 0);
675 }
676
677 /*
678   use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
679 */
680 static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
681                           const struct ldb_val *in, struct ldb_val *out,
682                           size_t struct_size,
683                           ndr_pull_flags_fn_t pull_fn,
684                           ndr_print_fn_t print_fn)
685 {
686         uint8_t *p;
687         enum ndr_err_code err;
688         if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
689                 return ldb_handler_copy(ldb, mem_ctx, in, out);
690         }
691         p = talloc_size(mem_ctx, struct_size);
692         err = ndr_pull_struct_blob(in, mem_ctx, 
693                                    lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
694                                    p, pull_fn);
695         if (err != NDR_ERR_SUCCESS) {
696                 talloc_free(p);
697                 return ldb_handler_copy(ldb, mem_ctx, in, out);
698         }
699         out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
700         talloc_free(p);
701         if (out->data == NULL) {
702                 return ldb_handler_copy(ldb, mem_ctx, in, out);         
703         }
704         out->length = strlen((char *)out->data);
705         return 0;
706 }
707
708
709 /*
710   convert a NDR formatted blob to a ldif formatted repsFromTo
711 */
712 static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
713                                  const struct ldb_val *in, struct ldb_val *out)
714 {
715         return ldif_write_NDR(ldb, mem_ctx, in, out, 
716                               sizeof(struct repsFromToBlob),
717                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
718                               (ndr_print_fn_t)ndr_print_repsFromToBlob);
719 }
720
721
722 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
723                                  const struct ldb_val *in, struct ldb_val *out)
724 {
725         *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
726         if (!out->data) {
727                 return -1;
728         }
729         return 0;
730 }
731
732 static const struct ldb_schema_syntax samba_syntaxes[] = {
733         {
734                 .name             = LDB_SYNTAX_SAMBA_SID,
735                 .ldif_read_fn     = ldif_read_objectSid,
736                 .ldif_write_fn    = ldif_write_objectSid,
737                 .canonicalise_fn  = ldif_canonicalise_objectSid,
738                 .comparison_fn    = ldif_comparison_objectSid
739         },{
740                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
741                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
742                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
743                 .canonicalise_fn  = ldb_handler_copy,
744                 .comparison_fn    = ldb_comparison_binary
745         },{
746                 .name             = LDB_SYNTAX_SAMBA_GUID,
747                 .ldif_read_fn     = ldif_read_objectGUID,
748                 .ldif_write_fn    = ldif_write_objectGUID,
749                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
750                 .comparison_fn    = ldif_comparison_objectGUID
751         },{
752                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
753                 .ldif_read_fn     = ldb_handler_copy,
754                 .ldif_write_fn    = ldb_handler_copy,
755                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
756                 .comparison_fn    = ldif_comparison_objectCategory
757         },{
758                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
759                 .ldif_read_fn     = ldif_read_prefixMap,
760                 .ldif_write_fn    = ldif_write_prefixMap,
761                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
762                 .comparison_fn    = ldif_comparison_prefixMap
763         },{
764                 .name             = LDB_SYNTAX_SAMBA_INT32,
765                 .ldif_read_fn     = ldb_handler_copy,
766                 .ldif_write_fn    = ldb_handler_copy,
767                 .canonicalise_fn  = ldif_canonicalise_int32,
768                 .comparison_fn    = ldif_comparison_int32
769         },{
770                 .name             = LDB_SYNTAX_SAMBA_REPSFROMTO,
771                 .ldif_read_fn     = ldb_handler_copy,
772                 .ldif_write_fn    = ldif_write_repsFromTo,
773                 .canonicalise_fn  = ldb_handler_copy,
774                 .comparison_fn    = ldb_comparison_binary
775         },
776 };
777
778 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
779         {
780                 .name             = "SID",
781                 .read_fn          = extended_dn_read_SID,
782                 .write_clear_fn   = ldif_write_objectSid,
783                 .write_hex_fn     = extended_dn_write_hex
784         },{
785                 .name             = "GUID",
786                 .read_fn          = extended_dn_read_GUID,
787                 .write_clear_fn   = ldif_write_objectGUID,
788                 .write_hex_fn     = extended_dn_write_hex
789         },{
790                 .name             = "WKGUID",
791                 .read_fn          = ldb_handler_copy,
792                 .write_clear_fn   = ldb_handler_copy,
793                 .write_hex_fn     = ldb_handler_copy
794         }
795 };
796
797 /* TODO: Should be dynamic at some point */
798 static const struct {
799         const char *name;
800         const char *syntax;
801 } samba_attributes[] = {
802         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
803         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
804         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
805         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
806         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
807         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
808         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
809         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
810         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
811         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
812         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
813         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
814         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
815         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
816         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
817         { "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
818         { "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
819 };
820
821 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
822 {
823         uint32_t j;
824         const struct ldb_schema_syntax *s = NULL;
825         
826         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
827                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
828                         s = &samba_syntaxes[j];
829                         break;
830                 }
831         }
832         return s;
833 }
834
835 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
836 {
837         uint32_t j;
838         const struct ldb_schema_syntax *s = NULL;
839
840         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
841                 if (strcmp(samba_attributes[j].name, name) == 0) {
842                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
843                         break;
844                 }
845         }
846         
847         return s;
848 }
849
850 /*
851   register the samba ldif handlers
852 */
853 int ldb_register_samba_handlers(struct ldb_context *ldb)
854 {
855         uint32_t i;
856
857         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
858                 int ret;
859                 const struct ldb_schema_syntax *s = NULL;
860
861                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
862
863                 if (!s) {
864                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
865                 }
866
867                 if (!s) {
868                         return -1;
869                 }
870
871                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
872                 if (ret != LDB_SUCCESS) {
873                         return ret;
874                 }
875         }
876
877         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
878                 int ret;
879                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
880                 if (ret != LDB_SUCCESS) {
881                         return ret;
882                 }
883
884                 
885         }
886
887         return LDB_SUCCESS;
888 }