s4:librpc/rpc: fix DEBUG() message
[ira/wip.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
318         enum ndr_err_code ndr_err;
319
320         sd = talloc(mem_ctx, struct security_descriptor);
321         if (sd == NULL) {
322                 return -1;
323         }
324
325         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
326                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
327         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
328                 /* If this does not parse, then it is probably SDDL, and we should try it that way */
329                 
330                 const struct dom_sid *sid = samdb_domain_sid(ldb);
331                 talloc_free(sd);
332                 sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
333                 if (sd == NULL) {
334                         return -1;
335                 }
336         }
337
338         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
339                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
340         talloc_free(sd);
341         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
342                 return -1;
343         }
344
345         return 0;
346 }
347
348 /*
349   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
350 */
351 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
352                                            const struct ldb_val *in, struct ldb_val *out)
353 {
354         struct security_descriptor *sd;
355         enum ndr_err_code ndr_err;
356
357         sd = talloc(mem_ctx, struct security_descriptor);
358         if (sd == NULL) {
359                 return -1;
360         }
361         /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
362         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
363                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
364         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
365                 talloc_free(sd);
366                 return -1;
367         }
368         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
369         talloc_free(sd);
370         if (out->data == NULL) {
371                 return -1;
372         }
373         out->length = strlen((const char *)out->data);
374         return 0;
375 }
376
377 /* 
378    canonicalise an objectCategory.  We use the short form as the cannoical form:
379    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
380 */
381
382 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
383                                             const struct ldb_val *in, struct ldb_val *out)
384 {
385         struct ldb_dn *dn1 = NULL;
386         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
387         const struct dsdb_class *sclass;
388         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
389         if (!tmp_ctx) {
390                 return LDB_ERR_OPERATIONS_ERROR;
391         }
392
393         if (!schema) {
394                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
395                 if (in->data && !out->data) {
396                         return LDB_ERR_OPERATIONS_ERROR;
397                 }
398                 return LDB_SUCCESS;
399         }
400         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
401         if ( ! ldb_dn_validate(dn1)) {
402                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
403                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
404                 if (sclass) {
405                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
406                                                        sclass->defaultObjectCategory);
407                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
408                         talloc_free(tmp_ctx);
409
410                         if (!out->data) {
411                                 return LDB_ERR_OPERATIONS_ERROR;
412                         }
413                         return LDB_SUCCESS;
414                 } else {
415                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
416                         talloc_free(tmp_ctx);
417
418                         if (in->data && !out->data) {
419                                 return LDB_ERR_OPERATIONS_ERROR;
420                         }
421                         return LDB_SUCCESS;
422                 }
423         }
424         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
425         talloc_free(tmp_ctx);
426
427         if (!out->data) {
428                 return LDB_ERR_OPERATIONS_ERROR;
429         }
430         return LDB_SUCCESS;
431 }
432
433 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
434                                           const struct ldb_val *v1,
435                                           const struct ldb_val *v2)
436 {
437
438         int ret, ret1, ret2;
439         struct ldb_val v1_canon, v2_canon;
440         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
441
442         /* I could try and bail if tmp_ctx was NULL, but what return
443          * value would I use?
444          *
445          * It seems easier to continue on the NULL context 
446          */
447         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
448         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
449
450         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
451                 ret = data_blob_cmp(&v1_canon, &v2_canon);
452         } else {
453                 ret = data_blob_cmp(v1, v2);
454         }
455         talloc_free(tmp_ctx);
456         return ret;
457 }
458
459 /*
460   convert a ldif formatted prefixMap to a NDR formatted blob
461 */
462 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
463                                const struct ldb_val *in, struct ldb_val *out)
464 {
465         struct prefixMapBlob *blob;
466         enum ndr_err_code ndr_err;
467         char *string, *line, *p, *oid;
468
469         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
470
471         if (tmp_ctx == NULL) {
472                 return -1;
473         }
474
475         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
476         if (blob == NULL) {
477                 talloc_free(blob);
478                 return -1;
479         }
480
481         blob->version = PREFIX_MAP_VERSION_DSDB;
482         
483         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
484         if (string == NULL) {
485                 talloc_free(blob);
486                 return -1;
487         }
488
489         line = string;
490         while (line && line[0]) {
491                 p=strchr(line, ';');
492                 if (p) {
493                         p[0] = '\0';
494                 } else {
495                         p=strchr(line, '\n');
496                         if (p) {
497                                 p[0] = '\0';
498                         }
499                 }
500                 /* allow a traling seperator */
501                 if (line == p) {
502                         break;
503                 }
504                 
505                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
506                                                          blob->ctr.dsdb.mappings, 
507                                                          struct drsuapi_DsReplicaOIDMapping,
508                                                          blob->ctr.dsdb.num_mappings+1);
509                 if (!blob->ctr.dsdb.mappings) {
510                         talloc_free(tmp_ctx);
511                         return -1;
512                 }
513
514                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
515
516                 if (oid[0] != ':') {
517                         talloc_free(tmp_ctx);
518                         return -1;
519                 }
520
521                 /* we know there must be at least ":" */
522                 oid++;
523
524                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
525                         = talloc_strdup(blob->ctr.dsdb.mappings, oid);
526
527                 blob->ctr.dsdb.num_mappings++;
528
529                 /* Now look past the terminator we added above */
530                 if (p) {
531                         line = p + 1;
532                 } else {
533                         line = NULL;
534                 }
535         }
536
537         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
538                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
539                                        blob,
540                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
541         talloc_free(tmp_ctx);
542         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
543                 return -1;
544         }
545         return 0;
546 }
547
548 /*
549   convert a NDR formatted blob to a ldif formatted prefixMap
550 */
551 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
552                                 const struct ldb_val *in, struct ldb_val *out)
553 {
554         struct prefixMapBlob *blob;
555         enum ndr_err_code ndr_err;
556         char *string;
557         uint32_t i;
558
559         blob = talloc(mem_ctx, struct prefixMapBlob);
560         if (blob == NULL) {
561                 return -1;
562         }
563         ndr_err = ndr_pull_struct_blob_all(in, blob, 
564                                            lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
565                                            blob,
566                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
567         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
568                 talloc_free(blob);
569                 return -1;
570         }
571         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
572                 return -1;
573         }
574         string = talloc_strdup(mem_ctx, "");
575         if (string == NULL) {
576                 return -1;
577         }
578
579         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
580                 if (i > 0) {
581                         string = talloc_asprintf_append(string, ";"); 
582                 }
583                 string = talloc_asprintf_append(string, "%u:%s", 
584                                                    blob->ctr.dsdb.mappings[i].id_prefix,
585                                                    blob->ctr.dsdb.mappings[i].oid.oid);
586                 if (string == NULL) {
587                         return -1;
588                 }
589         }
590
591         talloc_free(blob);
592         *out = data_blob_string_const(string);
593         return 0;
594 }
595
596 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
597 {
598         if (v->length < 4) {
599                 return true;
600         }
601
602         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
603                 return false;
604         }
605         
606         return true;
607 }
608
609 /*
610   canonicalise a prefixMap
611 */
612 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
613                                        const struct ldb_val *in, struct ldb_val *out)
614 {
615         if (ldif_comparision_prefixMap_isString(in)) {
616                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
617         }
618         return ldb_handler_copy(ldb, mem_ctx, in, out);
619 }
620
621 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
622                                      const struct ldb_val *v1,
623                                      const struct ldb_val *v2)
624 {
625
626         int ret, ret1, ret2;
627         struct ldb_val v1_canon, v2_canon;
628         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
629
630         /* I could try and bail if tmp_ctx was NULL, but what return
631          * value would I use?
632          *
633          * It seems easier to continue on the NULL context 
634          */
635         ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
636         ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
637
638         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
639                 ret = data_blob_cmp(&v1_canon, &v2_canon);
640         } else {
641                 ret = data_blob_cmp(v1, v2);
642         }
643         talloc_free(tmp_ctx);
644         return ret;
645 }
646
647 /* Canonicalisation of two 32-bit integers */
648 static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
649                         const struct ldb_val *in, struct ldb_val *out)
650 {
651         char *end;
652         int32_t i = (int32_t) strtoll((char *)in->data, &end, 0);
653         if (*end != 0) {
654                 return -1;
655         }
656         out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
657         if (out->data == NULL) {
658                 return -1;
659         }
660         out->length = strlen((char *)out->data);
661         return 0;
662 }
663
664 /* Comparison of two 32-bit integers */
665 static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
666                         const struct ldb_val *v1, const struct ldb_val *v2)
667 {
668         return (int32_t) strtoll((char *)v1->data, NULL, 0)
669          - (int32_t) strtoll((char *)v2->data, NULL, 0);
670 }
671
672 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
673                                  const struct ldb_val *in, struct ldb_val *out)
674 {
675         *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
676         if (!out->data) {
677                 return -1;
678         }
679         return 0;
680 }
681
682 static const struct ldb_schema_syntax samba_syntaxes[] = {
683         {
684                 .name             = LDB_SYNTAX_SAMBA_SID,
685                 .ldif_read_fn     = ldif_read_objectSid,
686                 .ldif_write_fn    = ldif_write_objectSid,
687                 .canonicalise_fn  = ldif_canonicalise_objectSid,
688                 .comparison_fn    = ldif_comparison_objectSid
689         },{
690                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
691                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
692                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
693                 .canonicalise_fn  = ldb_handler_copy,
694                 .comparison_fn    = ldb_comparison_binary
695         },{
696                 .name             = LDB_SYNTAX_SAMBA_GUID,
697                 .ldif_read_fn     = ldif_read_objectGUID,
698                 .ldif_write_fn    = ldif_write_objectGUID,
699                 .canonicalise_fn  = ldif_canonicalise_objectGUID,
700                 .comparison_fn    = ldif_comparison_objectGUID
701         },{
702                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
703                 .ldif_read_fn     = ldb_handler_copy,
704                 .ldif_write_fn    = ldb_handler_copy,
705                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
706                 .comparison_fn    = ldif_comparison_objectCategory
707         },{
708                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
709                 .ldif_read_fn     = ldif_read_prefixMap,
710                 .ldif_write_fn    = ldif_write_prefixMap,
711                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
712                 .comparison_fn    = ldif_comparison_prefixMap
713         },{
714                 .name             = LDB_SYNTAX_SAMBA_INT32,
715                 .ldif_read_fn     = ldb_handler_copy,
716                 .ldif_write_fn    = ldb_handler_copy,
717                 .canonicalise_fn  = ldif_canonicalise_int32,
718                 .comparison_fn    = ldif_comparison_int32
719         }
720 };
721
722 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
723         {
724                 .name             = "SID",
725                 .read_fn          = extended_dn_read_SID,
726                 .write_clear_fn   = ldif_write_objectSid,
727                 .write_hex_fn     = extended_dn_write_hex
728         },{
729                 .name             = "GUID",
730                 .read_fn          = extended_dn_read_GUID,
731                 .write_clear_fn   = ldif_write_objectGUID,
732                 .write_hex_fn     = extended_dn_write_hex
733         },{
734                 .name             = "WKGUID",
735                 .read_fn          = ldb_handler_copy,
736                 .write_clear_fn   = ldb_handler_copy,
737                 .write_hex_fn     = ldb_handler_copy
738         }
739 };
740
741 /* TODO: Should be dynamic at some point */
742 static const struct {
743         const char *name;
744         const char *syntax;
745 } samba_attributes[] = {
746         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
747         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
748         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
749         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
750         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
751         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
752         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
753         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
754         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
755         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
756         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
757         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
758         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
759         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
760         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP }
761 };
762
763 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
764 {
765         uint32_t j;
766         const struct ldb_schema_syntax *s = NULL;
767         
768         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
769                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
770                         s = &samba_syntaxes[j];
771                         break;
772                 }
773         }
774         return s;
775 }
776
777 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
778 {
779         uint32_t j;
780         const struct ldb_schema_syntax *s = NULL;
781
782         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
783                 if (strcmp(samba_attributes[j].name, name) == 0) {
784                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
785                         break;
786                 }
787         }
788         
789         return s;
790 }
791
792 /*
793   register the samba ldif handlers
794 */
795 int ldb_register_samba_handlers(struct ldb_context *ldb)
796 {
797         uint32_t i;
798
799         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
800                 int ret;
801                 const struct ldb_schema_syntax *s = NULL;
802
803                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
804
805                 if (!s) {
806                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
807                 }
808
809                 if (!s) {
810                         return -1;
811                 }
812
813                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
814                 if (ret != LDB_SUCCESS) {
815                         return ret;
816                 }
817         }
818
819         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
820                 int ret;
821                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
822                 if (ret != LDB_SUCCESS) {
823                         return ret;
824                 }
825
826                 
827         }
828
829         return LDB_SUCCESS;
830 }