Merge branch 'abartlet-4-0-local' into v4-0-test
[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      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/ldb/include/ldb_includes.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "libcli/security/security.h"
31 #include "param/param.h"
32
33 /*
34   convert a ldif formatted objectSid to a NDR formatted blob
35 */
36 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
37                                const struct ldb_val *in, struct ldb_val *out)
38 {
39         enum ndr_err_code ndr_err;
40         struct dom_sid *sid;
41         sid = dom_sid_parse_length(mem_ctx, in);
42         if (sid == NULL) {
43                 return -1;
44         }
45         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid,
46                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
47         talloc_free(sid);
48         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
49                 return -1;
50         }
51         return 0;
52 }
53
54 /*
55   convert a NDR formatted blob to a ldif formatted objectSid
56 */
57 static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
58                                 const struct ldb_val *in, struct ldb_val *out)
59 {
60         struct dom_sid *sid;
61         enum ndr_err_code ndr_err;
62
63         sid = talloc(mem_ctx, struct dom_sid);
64         if (sid == NULL) {
65                 return -1;
66         }
67         ndr_err = ndr_pull_struct_blob(in, sid, NULL, sid,
68                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
69         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
70                 talloc_free(sid);
71                 return -1;
72         }
73         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
74         talloc_free(sid);
75         if (out->data == NULL) {
76                 return -1;
77         }
78         return 0;
79 }
80
81 static bool ldb_comparision_objectSid_isString(const struct ldb_val *v)
82 {
83         if (v->length < 3) {
84                 return false;
85         }
86
87         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
88         
89         return true;
90 }
91
92 /*
93   compare two objectSids
94 */
95 static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
96                                     const struct ldb_val *v1, const struct ldb_val *v2)
97 {
98         if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) {
99                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
100         } else if (ldb_comparision_objectSid_isString(v1)
101                    && !ldb_comparision_objectSid_isString(v2)) {
102                 struct ldb_val v;
103                 int ret;
104                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
105                         /* Perhaps not a string after all */
106                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
107                 }
108                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
109                 talloc_free(v.data);
110                 return ret;
111         } else if (!ldb_comparision_objectSid_isString(v1)
112                    && ldb_comparision_objectSid_isString(v2)) {
113                 struct ldb_val v;
114                 int ret;
115                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
116                         /* Perhaps not a string after all */
117                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
118                 }
119                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
120                 talloc_free(v.data);
121                 return ret;
122         }
123         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
124 }
125
126 /*
127   canonicalise a objectSid
128 */
129 static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
130                                       const struct ldb_val *in, struct ldb_val *out)
131 {
132         if (ldb_comparision_objectSid_isString(in)) {
133                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
134                         /* Perhaps not a string after all */
135                         return ldb_handler_copy(ldb, mem_ctx, in, out);
136                 }
137         }
138         return ldb_handler_copy(ldb, mem_ctx, in, out);
139 }
140
141 /*
142   convert a ldif formatted objectGUID to a NDR formatted blob
143 */
144 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
145                                 const struct ldb_val *in, struct ldb_val *out)
146 {
147         struct GUID guid;
148         char *guid_string;
149         NTSTATUS status;
150         enum ndr_err_code ndr_err;
151         guid_string = talloc_strndup(mem_ctx, in->data, in->length);
152         if (!guid_string) {
153                 return -1;
154         }
155
156         status = GUID_from_string(guid_string, &guid);
157         talloc_free(guid_string);
158         if (!NT_STATUS_IS_OK(status)) {
159                 return -1;
160         }
161
162         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
163                                        (ndr_push_flags_fn_t)ndr_push_GUID);
164         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
165                 return -1;
166         }
167         return 0;
168 }
169
170 /*
171   convert a NDR formatted blob to a ldif formatted objectGUID
172 */
173 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
174                                  const struct ldb_val *in, struct ldb_val *out)
175 {
176         struct GUID guid;
177         enum ndr_err_code ndr_err;
178         ndr_err = ndr_pull_struct_blob(in, mem_ctx, NULL, &guid,
179                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
180         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
181                 return -1;
182         }
183         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
184         if (out->data == NULL) {
185                 return -1;
186         }
187         out->length = strlen((const char *)out->data);
188         return 0;
189 }
190
191 static bool ldb_comparision_objectGUID_isString(const struct ldb_val *v)
192 {
193         struct GUID guid;
194         NTSTATUS status;
195
196         if (v->length < 33) return false;
197
198         /* see if the input if null-terninated (safety check for the below) */
199         if (v->data[v->length] != '\0') return false;
200
201         status = GUID_from_string((const char *)v->data, &guid);
202         if (!NT_STATUS_IS_OK(status)) {
203                 return false;
204         }
205
206         return true;
207 }
208
209 /*
210   compare two objectGUIDs
211 */
212 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
213                                      const struct ldb_val *v1, const struct ldb_val *v2)
214 {
215         if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
216                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
217         } else if (ldb_comparision_objectGUID_isString(v1)
218                    && !ldb_comparision_objectGUID_isString(v2)) {
219                 struct ldb_val v;
220                 int ret;
221                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
222                         /* Perhaps it wasn't a valid string after all */
223                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
224                 }
225                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
226                 talloc_free(v.data);
227                 return ret;
228         } else if (!ldb_comparision_objectGUID_isString(v1)
229                    && ldb_comparision_objectGUID_isString(v2)) {
230                 struct ldb_val v;
231                 int ret;
232                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
233                         /* Perhaps it wasn't a valid string after all */
234                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
235                 }
236                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
237                 talloc_free(v.data);
238                 return ret;
239         }
240         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
241 }
242
243 /*
244   canonicalise a objectGUID
245 */
246 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
247                                        const struct ldb_val *in, struct ldb_val *out)
248 {
249         if (ldb_comparision_objectGUID_isString(in)) {
250                 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
251                         /* Perhaps it wasn't a valid string after all */
252                         return ldb_handler_copy(ldb, mem_ctx, in, out);
253                 }
254         }
255         return ldb_handler_copy(ldb, mem_ctx, in, out);
256 }
257
258
259 /*
260   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
261 */
262 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
263                                           const struct ldb_val *in, struct ldb_val *out)
264 {
265         struct security_descriptor *sd;
266         enum ndr_err_code ndr_err;
267
268         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
269         if (sd == NULL) {
270                 return -1;
271         }
272         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
273                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
274         talloc_free(sd);
275         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
276                 return -1;
277         }
278         return 0;
279 }
280
281 /*
282   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
283 */
284 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
285                                            const struct ldb_val *in, struct ldb_val *out)
286 {
287         struct security_descriptor *sd;
288         enum ndr_err_code ndr_err;
289
290         sd = talloc(mem_ctx, struct security_descriptor);
291         if (sd == NULL) {
292                 return -1;
293         }
294         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
295                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
296         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
297                 talloc_free(sd);
298                 return -1;
299         }
300         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
301         talloc_free(sd);
302         if (out->data == NULL) {
303                 return -1;
304         }
305         out->length = strlen((const char *)out->data);
306         return 0;
307 }
308
309 /* 
310    canonicalise an objectCategory.  We use the short form as the cannoical form:
311    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
312 */
313
314 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
315                                             const struct ldb_val *in, struct ldb_val *out)
316 {
317         struct ldb_dn *dn1 = NULL;
318         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
319         const struct dsdb_class *class;
320         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
321         if (!tmp_ctx) {
322                 return LDB_ERR_OPERATIONS_ERROR;
323         }
324
325         if (!schema) {
326                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
327                 if (in->data && !out->data) {
328                         return LDB_ERR_OPERATIONS_ERROR;
329                 }
330                 return LDB_SUCCESS;
331         }
332         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
333         if ( ! ldb_dn_validate(dn1)) {
334                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
335                 class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
336                 if (class) {
337                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
338                                                        class->defaultObjectCategory);
339                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
340                         talloc_free(tmp_ctx);
341
342                         if (!out->data) {
343                                 return LDB_ERR_OPERATIONS_ERROR;
344                         }
345                         return LDB_SUCCESS;
346                 } else {
347                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
348                         talloc_free(tmp_ctx);
349
350                         if (in->data && !out->data) {
351                                 return LDB_ERR_OPERATIONS_ERROR;
352                         }
353                         return LDB_SUCCESS;
354                 }
355         }
356         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
357         talloc_free(tmp_ctx);
358
359         if (!out->data) {
360                 return LDB_ERR_OPERATIONS_ERROR;
361         }
362         return LDB_SUCCESS;
363 }
364
365 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
366                                           const struct ldb_val *v1,
367                                           const struct ldb_val *v2)
368 {
369
370         int ret, ret1, ret2;
371         struct ldb_val v1_canon, v2_canon;
372         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
373
374         /* I could try and bail if tmp_ctx was NULL, but what return
375          * value would I use?
376          *
377          * It seems easier to continue on the NULL context 
378          */
379         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
380         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
381
382         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
383                 ret = data_blob_cmp(&v1_canon, &v2_canon);
384         } else {
385                 ret = data_blob_cmp(v1, v2);
386         }
387         talloc_free(tmp_ctx);
388         return ret;
389 }
390
391 /*
392   convert a ldif formatted prefixMap to a NDR formatted blob
393 */
394 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
395                                const struct ldb_val *in, struct ldb_val *out)
396 {
397         struct prefixMapBlob *blob;
398         enum ndr_err_code ndr_err;
399         char *string, *line, *p, *oid;
400
401         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
402
403         if (tmp_ctx == NULL) {
404                 return -1;
405         }
406
407         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
408         if (blob == NULL) {
409                 talloc_free(blob);
410                 return -1;
411         }
412
413         blob->version = PREFIX_MAP_VERSION_DSDB;
414         
415         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
416         if (string == NULL) {
417                 talloc_free(blob);
418                 return -1;
419         }
420
421         line = string;
422         while (line && line[0]) {
423                 p=strchr(line, ';');
424                 if (p) {
425                         p[0] = '\0';
426                 } else {
427                         p=strchr(line, '\n');
428                         if (p) {
429                                 p[0] = '\0';
430                         }
431                 }
432                 /* allow a traling seperator */
433                 if (line == p) {
434                         break;
435                 }
436                 
437                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
438                                                          blob->ctr.dsdb.mappings, 
439                                                          struct drsuapi_DsReplicaOIDMapping,
440                                                          blob->ctr.dsdb.num_mappings+1);
441                 if (!blob->ctr.dsdb.mappings) {
442                         talloc_free(tmp_ctx);
443                         return -1;
444                 }
445
446                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
447
448                 if (oid[0] != ':') {
449                         talloc_free(tmp_ctx);
450                         return -1;
451                 }
452
453                 /* we know there must be at least ":" */
454                 oid++;
455
456                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
457                         = talloc_strdup(blob->ctr.dsdb.mappings, oid);
458
459                 blob->ctr.dsdb.num_mappings++;
460
461                 /* Now look past the terminator we added above */
462                 if (p) {
463                         line = p + 1;
464                 } else {
465                         line = NULL;
466                 }
467         }
468
469         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
470                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
471                                        blob,
472                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
473         talloc_free(tmp_ctx);
474         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
475                 return -1;
476         }
477         return 0;
478 }
479
480 /*
481   convert a NDR formatted blob to a ldif formatted prefixMap
482 */
483 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
484                                 const struct ldb_val *in, struct ldb_val *out)
485 {
486         struct prefixMapBlob *blob;
487         enum ndr_err_code ndr_err;
488         char *string;
489         uint32_t i;
490
491         blob = talloc(mem_ctx, struct prefixMapBlob);
492         if (blob == NULL) {
493                 return -1;
494         }
495         ndr_err = ndr_pull_struct_blob(in, blob, 
496                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
497                                        blob,
498                                        (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
499         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
500                 talloc_free(blob);
501                 return -1;
502         }
503         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
504                 return -1;
505         }
506         string = talloc_strdup(mem_ctx, "");
507         if (string == NULL) {
508                 return -1;
509         }
510
511         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
512                 if (i > 0) {
513                         string = talloc_asprintf_append(string, ";"); 
514                 }
515                 string = talloc_asprintf_append(string, "%u:%s", 
516                                                    blob->ctr.dsdb.mappings[i].id_prefix,
517                                                    blob->ctr.dsdb.mappings[i].oid.oid);
518                 if (string == NULL) {
519                         return -1;
520                 }
521         }
522
523         talloc_free(blob);
524         *out = data_blob_string_const(string);
525         return 0;
526 }
527
528 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
529 {
530         if (v->length < 4) {
531                 return true;
532         }
533
534         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
535                 return false;
536         }
537         
538         return true;
539 }
540
541 /*
542   canonicalise a prefixMap
543 */
544 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
545                                        const struct ldb_val *in, struct ldb_val *out)
546 {
547         if (ldif_comparision_prefixMap_isString(in)) {
548                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
549         }
550         return ldb_handler_copy(ldb, mem_ctx, in, out);
551 }
552
553 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
554                                      const struct ldb_val *v1,
555                                      const struct ldb_val *v2)
556 {
557
558         int ret, ret1, ret2;
559         struct ldb_val v1_canon, v2_canon;
560         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
561
562         /* I could try and bail if tmp_ctx was NULL, but what return
563          * value would I use?
564          *
565          * It seems easier to continue on the NULL context 
566          */
567         ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
568         ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
569
570         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
571                 ret = data_blob_cmp(&v1_canon, &v2_canon);
572         } else {
573                 ret = data_blob_cmp(v1, v2);
574         }
575         talloc_free(tmp_ctx);
576         return ret;
577 }
578
579 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
580 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
581 #define LDB_SYNTAX_SAMBA_PREFIX_MAP     "LDB_SYNTAX_SAMBA_PREFIX_MAP"
582
583 static const struct ldb_schema_syntax samba_syntaxes[] = {
584         {
585                 .name           = LDB_SYNTAX_SAMBA_SID,
586                 .ldif_read_fn   = ldif_read_objectSid,
587                 .ldif_write_fn  = ldif_write_objectSid,
588                 .canonicalise_fn= ldb_canonicalise_objectSid,
589                 .comparison_fn  = ldb_comparison_objectSid
590         },{
591                 .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
592                 .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
593                 .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
594                 .canonicalise_fn= ldb_handler_copy,
595                 .comparison_fn  = ldb_comparison_binary
596         },{
597                 .name           = LDB_SYNTAX_SAMBA_GUID,
598                 .ldif_read_fn   = ldif_read_objectGUID,
599                 .ldif_write_fn  = ldif_write_objectGUID,
600                 .canonicalise_fn= ldb_canonicalise_objectGUID,
601                 .comparison_fn  = ldb_comparison_objectGUID
602         },{
603                 .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
604                 .ldif_read_fn   = ldb_handler_copy,
605                 .ldif_write_fn  = ldb_handler_copy,
606                 .canonicalise_fn= ldif_canonicalise_objectCategory,
607                 .comparison_fn  = ldif_comparison_objectCategory
608         },{
609                 .name           = LDB_SYNTAX_SAMBA_PREFIX_MAP,
610                 .ldif_read_fn   = ldif_read_prefixMap,
611                 .ldif_write_fn  = ldif_write_prefixMap,
612                 .canonicalise_fn= ldif_canonicalise_prefixMap,
613                 .comparison_fn  = ldif_comparison_prefixMap
614         }
615 };
616
617 static const struct {
618         const char *name;
619         const char *syntax;
620 } samba_attributes[] = {
621         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
622         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
623         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
624         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
625         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
626         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
627         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
628         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
629         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
630         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
631         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
632         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
633         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
634         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
635         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP }
636 };
637
638 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
639 {
640         uint32_t j;
641         const struct ldb_schema_syntax *s = NULL;
642         
643         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
644                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
645                         s = &samba_syntaxes[j];
646                         break;
647                 }
648         }
649         return s;
650 }
651
652
653 /*
654   register the samba ldif handlers
655 */
656 int ldb_register_samba_handlers(struct ldb_context *ldb)
657 {
658         uint32_t i;
659
660         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
661                 int ret;
662                 const struct ldb_schema_syntax *s = NULL;
663
664                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
665
666                 if (!s) {
667                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
668                 }
669
670                 if (!s) {
671                         return -1;
672                 }
673
674                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
675                 if (ret != LDB_SUCCESS) {
676                         return ret;
677                 }
678         }
679
680         return LDB_SUCCESS;
681 }