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