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