Fix up new OpenLDAP MMR code.
[tprouty/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 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         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
387
388         if (tmp_ctx == NULL) {
389                 return -1;
390         }
391
392         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
393         if (blob == NULL) {
394                 talloc_free(blob);
395                 return -1;
396         }
397
398         blob->version = PREFIX_MAP_VERSION_DSDB;
399         
400         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
401         if (string == NULL) {
402                 talloc_free(blob);
403                 return -1;
404         }
405
406         line = string;
407         while (line && line[0]) {
408                 p=strchr(line, ';');
409                 if (p) {
410                         p[0] = '\0';
411                 } else {
412                         p=strchr(line, '\n');
413                         if (p) {
414                                 p[0] = '\0';
415                         }
416                 }
417                 /* allow a traling seperator */
418                 if (line == p) {
419                         break;
420                 }
421                 
422                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
423                                                          blob->ctr.dsdb.mappings, 
424                                                          struct drsuapi_DsReplicaOIDMapping,
425                                                          blob->ctr.dsdb.num_mappings+1);
426                 if (!blob->ctr.dsdb.mappings) {
427                         talloc_free(tmp_ctx);
428                         return -1;
429                 }
430
431                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
432
433                 if (oid[0] != ':') {
434                         talloc_free(tmp_ctx);
435                         return -1;
436                 }
437
438                 /* we know there must be at least ":" */
439                 oid++;
440
441                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
442                         = talloc_strdup(blob->ctr.dsdb.mappings, oid);
443
444                 blob->ctr.dsdb.num_mappings++;
445
446                 /* Now look past the terminator we added above */
447                 if (p) {
448                         line = p + 1;
449                 } else {
450                         line = NULL;
451                 }
452         }
453
454         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
455                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
456                                        blob,
457                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
458         talloc_free(tmp_ctx);
459         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
460                 return -1;
461         }
462         return 0;
463 }
464
465 /*
466   convert a NDR formatted blob to a ldif formatted prefixMap
467 */
468 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
469                                 const struct ldb_val *in, struct ldb_val *out)
470 {
471         struct prefixMapBlob *blob;
472         enum ndr_err_code ndr_err;
473         char *string;
474         uint32_t i;
475
476         blob = talloc(mem_ctx, struct prefixMapBlob);
477         if (blob == NULL) {
478                 return -1;
479         }
480         ndr_err = ndr_pull_struct_blob(in, blob, 
481                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
482                                        blob,
483                                        (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
484         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
485                 talloc_free(blob);
486                 return -1;
487         }
488         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
489                 return -1;
490         }
491         string = talloc_strdup(mem_ctx, "");
492         if (string == NULL) {
493                 return -1;
494         }
495
496         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
497                 if (i > 0) {
498                         string = talloc_asprintf_append(string, ";"); 
499                 }
500                 string = talloc_asprintf_append(string, "%u:%s", 
501                                                    blob->ctr.dsdb.mappings[i].id_prefix,
502                                                    blob->ctr.dsdb.mappings[i].oid.oid);
503                 if (string == NULL) {
504                         return -1;
505                 }
506         }
507
508         talloc_free(blob);
509         *out = data_blob_string_const(string);
510         return 0;
511 }
512
513 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
514 {
515         if (v->length < 4) {
516                 return true;
517         }
518
519         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
520                 return false;
521         }
522         
523         return true;
524 }
525
526 /*
527   canonicalise a prefixMap
528 */
529 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
530                                        const struct ldb_val *in, struct ldb_val *out)
531 {
532         if (ldif_comparision_prefixMap_isString(in)) {
533                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
534         }
535         return ldb_handler_copy(ldb, mem_ctx, in, out);
536 }
537
538 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
539                                      const struct ldb_val *v1,
540                                      const struct ldb_val *v2)
541 {
542
543         int ret, ret1, ret2;
544         struct ldb_val v1_canon, v2_canon;
545         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
546
547         /* I could try and bail if tmp_ctx was NULL, but what return
548          * value would I use?
549          *
550          * It seems easier to continue on the NULL context 
551          */
552         ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
553         ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
554
555         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
556                 ret = data_blob_cmp(&v1_canon, &v2_canon);
557         } else {
558                 ret = data_blob_cmp(v1, v2);
559         }
560         talloc_free(tmp_ctx);
561         return ret;
562 }
563
564 #define LDB_SYNTAX_SAMBA_SID                    "LDB_SYNTAX_SAMBA_SID"
565 #define LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR    "LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR"
566 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
567 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
568 #define LDB_SYNTAX_SAMBA_PREFIX_MAP     "LDB_SYNTAX_SAMBA_PREFIX_MAP"
569
570 static const struct ldb_schema_syntax samba_syntaxes[] = {
571         {
572                 .name           = LDB_SYNTAX_SAMBA_SID,
573                 .ldif_read_fn   = ldif_read_objectSid,
574                 .ldif_write_fn  = ldif_write_objectSid,
575                 .canonicalise_fn= ldb_canonicalise_objectSid,
576                 .comparison_fn  = ldb_comparison_objectSid
577         },{
578                 .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
579                 .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
580                 .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
581                 .canonicalise_fn= ldb_handler_copy,
582                 .comparison_fn  = ldb_comparison_binary
583         },{
584                 .name           = LDB_SYNTAX_SAMBA_GUID,
585                 .ldif_read_fn   = ldif_read_objectGUID,
586                 .ldif_write_fn  = ldif_write_objectGUID,
587                 .canonicalise_fn= ldb_canonicalise_objectGUID,
588                 .comparison_fn  = ldb_comparison_objectGUID
589         },{
590                 .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
591                 .ldif_read_fn   = ldb_handler_copy,
592                 .ldif_write_fn  = ldb_handler_copy,
593                 .canonicalise_fn= ldif_canonicalise_objectCategory,
594                 .comparison_fn  = ldif_comparison_objectCategory
595         },{
596                 .name           = LDB_SYNTAX_SAMBA_PREFIX_MAP,
597                 .ldif_read_fn   = ldif_read_prefixMap,
598                 .ldif_write_fn  = ldif_write_prefixMap,
599                 .canonicalise_fn= ldif_canonicalise_prefixMap,
600                 .comparison_fn  = ldif_comparison_prefixMap
601         }
602 };
603
604 static const struct {
605         const char *name;
606         const char *syntax;
607 } samba_attributes[] = {
608         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
609         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
610         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
611         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
612         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
613         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
614         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
615         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
616         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
617         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
618         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
619         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
620         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
621         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
622         { "member",                     LDB_SYNTAX_DN },
623         { "memberOf",                   LDB_SYNTAX_DN },
624         { "nCName",                     LDB_SYNTAX_DN },
625         { "schemaNamingContext",        LDB_SYNTAX_DN },
626         { "configurationNamingContext", LDB_SYNTAX_DN },
627         { "rootDomainNamingContext",    LDB_SYNTAX_DN },
628         { "defaultNamingContext",       LDB_SYNTAX_DN },
629         { "subRefs",                    LDB_SYNTAX_DN },
630         { "dMDLocation",                LDB_SYNTAX_DN },
631         { "serverReference",            LDB_SYNTAX_DN },
632         { "masteredBy",                 LDB_SYNTAX_DN },
633         { "msDs-masteredBy",            LDB_SYNTAX_DN },
634         { "fSMORoleOwner",              LDB_SYNTAX_DN },
635         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP }
636 };
637
638 /*
639   register the samba ldif handlers
640 */
641 int ldb_register_samba_handlers(struct ldb_context *ldb)
642 {
643         uint32_t i;
644
645         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
646                 int ret;
647                 uint32_t j;
648                 const struct ldb_schema_syntax *s = NULL;
649
650                 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
651                         if (strcmp(samba_attributes[i].syntax, samba_syntaxes[j].name) == 0) {
652                                 s = &samba_syntaxes[j];
653                                 break;
654                         }
655                 }
656
657                 if (!s) {
658                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
659                 }
660
661                 if (!s) {
662                         return -1;
663                 }
664
665                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, 0, s);
666                 if (ret != LDB_SUCCESS) {
667                         return ret;
668                 }
669         }
670
671         return LDB_SUCCESS;
672 }