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