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