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