Merge branch 'wspp-schema'
[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 "ldb_private.h"
26 #include "ldb_handlers.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_drsblobs.h"
31 #include "libcli/security/security.h"
32 #include "param/param.h"
33
34 /*
35   convert a ldif formatted objectSid to a NDR formatted blob
36 */
37 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
38                                const struct ldb_val *in, struct ldb_val *out)
39 {
40         enum ndr_err_code ndr_err;
41         struct dom_sid *sid;
42         sid = dom_sid_parse_length(mem_ctx, in);
43         if (sid == NULL) {
44                 return -1;
45         }
46         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid,
47                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
48         talloc_free(sid);
49         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
50                 return -1;
51         }
52         return 0;
53 }
54
55 /*
56   convert a NDR formatted blob to a ldif formatted objectSid
57 */
58 static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
59                                 const struct ldb_val *in, struct ldb_val *out)
60 {
61         struct dom_sid *sid;
62         enum ndr_err_code ndr_err;
63
64         sid = talloc(mem_ctx, struct dom_sid);
65         if (sid == NULL) {
66                 return -1;
67         }
68         ndr_err = ndr_pull_struct_blob_all(in, sid, NULL, sid,
69                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
70         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
71                 talloc_free(sid);
72                 return -1;
73         }
74         *out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
75         talloc_free(sid);
76         if (out->data == NULL) {
77                 return -1;
78         }
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                 return 0;
139         }
140         return ldb_handler_copy(ldb, mem_ctx, in, out);
141 }
142
143 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
144                               const struct ldb_val *in, struct ldb_val *out)
145 {
146         struct dom_sid sid;
147         enum ndr_err_code ndr_err;
148         if (ldb_comparision_objectSid_isString(in)) {
149                 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
150                         return 0;
151                 }
152         }
153         
154         /* Perhaps not a string after all */
155         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
156
157         if (!out->data) {
158                 return -1;
159         }
160
161         (*out).length = strhex_to_str((char *)out->data, out->length,
162                                      (const char *)in->data, in->length);
163
164         /* Check it looks like a SID */
165         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid,
166                                            (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
167         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
168                 return -1;
169         }
170         return 0;
171 }
172
173 /*
174   convert a ldif formatted objectGUID to a NDR formatted blob
175 */
176 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
177                                 const struct ldb_val *in, struct ldb_val *out)
178 {
179         struct GUID guid;
180         NTSTATUS status;
181         enum ndr_err_code ndr_err;
182
183         status = GUID_from_data_blob(in, &guid);
184         if (!NT_STATUS_IS_OK(status)) {
185                 return -1;
186         }
187
188         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
189                                        (ndr_push_flags_fn_t)ndr_push_GUID);
190         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
191                 return -1;
192         }
193         return 0;
194 }
195
196 /*
197   convert a NDR formatted blob to a ldif formatted objectGUID
198 */
199 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
200                                  const struct ldb_val *in, struct ldb_val *out)
201 {
202         struct GUID guid;
203         enum ndr_err_code ndr_err;
204         ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid,
205                                            (ndr_pull_flags_fn_t)ndr_pull_GUID);
206         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
207                 return -1;
208         }
209         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
210         if (out->data == NULL) {
211                 return -1;
212         }
213         out->length = strlen((const char *)out->data);
214         return 0;
215 }
216
217 static bool ldb_comparision_objectGUID_isString(const struct ldb_val *v)
218 {
219         if (v->length != 36 && v->length != 38) return false;
220
221         /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
222         return true;
223 }
224
225 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
226                               const struct ldb_val *in, struct ldb_val *out)
227 {
228         struct GUID guid;
229         enum ndr_err_code ndr_err;
230         if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
231                 return 0;
232         }
233
234         /* Try as 'hex' form */
235         if (in->length != 32) {
236                 return -1;
237         }
238                 
239         *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
240         
241         if (!out->data) {
242                 return -1;
243         }
244         
245         (*out).length = strhex_to_str((char *)out->data, out->length,
246                                       (const char *)in->data, in->length);
247         
248         /* Check it looks like a GUID */
249         ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid,
250                                            (ndr_pull_flags_fn_t)ndr_pull_GUID);
251         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
252                 return -1;
253         }
254         return 0;
255 }
256
257 /*
258   compare two objectGUIDs
259 */
260 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
261                                      const struct ldb_val *v1, const struct ldb_val *v2)
262 {
263         if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
264                 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
265         } else if (ldb_comparision_objectGUID_isString(v1)
266                    && !ldb_comparision_objectGUID_isString(v2)) {
267                 struct ldb_val v;
268                 int ret;
269                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
270                         /* Perhaps it wasn't a valid string after all */
271                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
272                 }
273                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
274                 talloc_free(v.data);
275                 return ret;
276         } else if (!ldb_comparision_objectGUID_isString(v1)
277                    && ldb_comparision_objectGUID_isString(v2)) {
278                 struct ldb_val v;
279                 int ret;
280                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
281                         /* Perhaps it wasn't a valid string after all */
282                         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
283                 }
284                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
285                 talloc_free(v.data);
286                 return ret;
287         }
288         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
289 }
290
291 /*
292   canonicalise a objectGUID
293 */
294 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
295                                        const struct ldb_val *in, struct ldb_val *out)
296 {
297         if (ldb_comparision_objectGUID_isString(in)) {
298                 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
299                         /* Perhaps it wasn't a valid string after all */
300                         return ldb_handler_copy(ldb, mem_ctx, in, out);
301                 }
302                 return 0;
303         }
304         return ldb_handler_copy(ldb, mem_ctx, in, out);
305 }
306
307
308 /*
309   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
310 */
311 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
312                                           const struct ldb_val *in, struct ldb_val *out)
313 {
314         struct security_descriptor *sd;
315         enum ndr_err_code ndr_err;
316
317         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
318         if (sd == NULL) {
319                 return -1;
320         }
321         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
322                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
323         talloc_free(sd);
324         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
325                 return -1;
326         }
327         return 0;
328 }
329
330 /*
331   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
332 */
333 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
334                                            const struct ldb_val *in, struct ldb_val *out)
335 {
336         struct security_descriptor *sd;
337         enum ndr_err_code ndr_err;
338
339         sd = talloc(mem_ctx, struct security_descriptor);
340         if (sd == NULL) {
341                 return -1;
342         }
343         /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
344         ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
345                                            (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
346         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
347                 talloc_free(sd);
348                 return -1;
349         }
350         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
351         talloc_free(sd);
352         if (out->data == NULL) {
353                 return -1;
354         }
355         out->length = strlen((const char *)out->data);
356         return 0;
357 }
358
359 /* 
360    canonicalise an objectCategory.  We use the short form as the cannoical form:
361    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
362 */
363
364 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
365                                             const struct ldb_val *in, struct ldb_val *out)
366 {
367         struct ldb_dn *dn1 = NULL;
368         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
369         const struct dsdb_class *sclass;
370         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
371         if (!tmp_ctx) {
372                 return LDB_ERR_OPERATIONS_ERROR;
373         }
374
375         if (!schema) {
376                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
377                 if (in->data && !out->data) {
378                         return LDB_ERR_OPERATIONS_ERROR;
379                 }
380                 return LDB_SUCCESS;
381         }
382         dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
383         if ( ! ldb_dn_validate(dn1)) {
384                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
385                 sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
386                 if (sclass) {
387                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
388                                                        sclass->defaultObjectCategory);
389                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
390                         talloc_free(tmp_ctx);
391
392                         if (!out->data) {
393                                 return LDB_ERR_OPERATIONS_ERROR;
394                         }
395                         return LDB_SUCCESS;
396                 } else {
397                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
398                         talloc_free(tmp_ctx);
399
400                         if (in->data && !out->data) {
401                                 return LDB_ERR_OPERATIONS_ERROR;
402                         }
403                         return LDB_SUCCESS;
404                 }
405         }
406         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
407         talloc_free(tmp_ctx);
408
409         if (!out->data) {
410                 return LDB_ERR_OPERATIONS_ERROR;
411         }
412         return LDB_SUCCESS;
413 }
414
415 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
416                                           const struct ldb_val *v1,
417                                           const struct ldb_val *v2)
418 {
419
420         int ret, ret1, ret2;
421         struct ldb_val v1_canon, v2_canon;
422         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
423
424         /* I could try and bail if tmp_ctx was NULL, but what return
425          * value would I use?
426          *
427          * It seems easier to continue on the NULL context 
428          */
429         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
430         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
431
432         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
433                 ret = data_blob_cmp(&v1_canon, &v2_canon);
434         } else {
435                 ret = data_blob_cmp(v1, v2);
436         }
437         talloc_free(tmp_ctx);
438         return ret;
439 }
440
441 /*
442   convert a ldif formatted prefixMap to a NDR formatted blob
443 */
444 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
445                                const struct ldb_val *in, struct ldb_val *out)
446 {
447         struct prefixMapBlob *blob;
448         enum ndr_err_code ndr_err;
449         char *string, *line, *p, *oid;
450
451         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
452
453         if (tmp_ctx == NULL) {
454                 return -1;
455         }
456
457         blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
458         if (blob == NULL) {
459                 talloc_free(blob);
460                 return -1;
461         }
462
463         blob->version = PREFIX_MAP_VERSION_DSDB;
464         
465         string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
466         if (string == NULL) {
467                 talloc_free(blob);
468                 return -1;
469         }
470
471         line = string;
472         while (line && line[0]) {
473                 p=strchr(line, ';');
474                 if (p) {
475                         p[0] = '\0';
476                 } else {
477                         p=strchr(line, '\n');
478                         if (p) {
479                                 p[0] = '\0';
480                         }
481                 }
482                 /* allow a traling seperator */
483                 if (line == p) {
484                         break;
485                 }
486                 
487                 blob->ctr.dsdb.mappings = talloc_realloc(blob, 
488                                                          blob->ctr.dsdb.mappings, 
489                                                          struct drsuapi_DsReplicaOIDMapping,
490                                                          blob->ctr.dsdb.num_mappings+1);
491                 if (!blob->ctr.dsdb.mappings) {
492                         talloc_free(tmp_ctx);
493                         return -1;
494                 }
495
496                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
497
498                 if (oid[0] != ':') {
499                         talloc_free(tmp_ctx);
500                         return -1;
501                 }
502
503                 /* we know there must be at least ":" */
504                 oid++;
505
506                 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
507                         = talloc_strdup(blob->ctr.dsdb.mappings, oid);
508
509                 blob->ctr.dsdb.num_mappings++;
510
511                 /* Now look past the terminator we added above */
512                 if (p) {
513                         line = p + 1;
514                 } else {
515                         line = NULL;
516                 }
517         }
518
519         ndr_err = ndr_push_struct_blob(out, mem_ctx, 
520                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
521                                        blob,
522                                        (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
523         talloc_free(tmp_ctx);
524         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
525                 return -1;
526         }
527         return 0;
528 }
529
530 /*
531   convert a NDR formatted blob to a ldif formatted prefixMap
532 */
533 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
534                                 const struct ldb_val *in, struct ldb_val *out)
535 {
536         struct prefixMapBlob *blob;
537         enum ndr_err_code ndr_err;
538         char *string;
539         uint32_t i;
540
541         blob = talloc(mem_ctx, struct prefixMapBlob);
542         if (blob == NULL) {
543                 return -1;
544         }
545         ndr_err = ndr_pull_struct_blob_all(in, blob, 
546                                            lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
547                                            blob,
548                                            (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
549         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
550                 talloc_free(blob);
551                 return -1;
552         }
553         if (blob->version != PREFIX_MAP_VERSION_DSDB) {
554                 return -1;
555         }
556         string = talloc_strdup(mem_ctx, "");
557         if (string == NULL) {
558                 return -1;
559         }
560
561         for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
562                 if (i > 0) {
563                         string = talloc_asprintf_append(string, ";"); 
564                 }
565                 string = talloc_asprintf_append(string, "%u:%s", 
566                                                    blob->ctr.dsdb.mappings[i].id_prefix,
567                                                    blob->ctr.dsdb.mappings[i].oid.oid);
568                 if (string == NULL) {
569                         return -1;
570                 }
571         }
572
573         talloc_free(blob);
574         *out = data_blob_string_const(string);
575         return 0;
576 }
577
578 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
579 {
580         if (v->length < 4) {
581                 return true;
582         }
583
584         if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
585                 return false;
586         }
587         
588         return true;
589 }
590
591 /*
592   canonicalise a prefixMap
593 */
594 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
595                                        const struct ldb_val *in, struct ldb_val *out)
596 {
597         if (ldif_comparision_prefixMap_isString(in)) {
598                 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
599         }
600         return ldb_handler_copy(ldb, mem_ctx, in, out);
601 }
602
603 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
604                                      const struct ldb_val *v1,
605                                      const struct ldb_val *v2)
606 {
607
608         int ret, ret1, ret2;
609         struct ldb_val v1_canon, v2_canon;
610         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
611
612         /* I could try and bail if tmp_ctx was NULL, but what return
613          * value would I use?
614          *
615          * It seems easier to continue on the NULL context 
616          */
617         ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
618         ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
619
620         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
621                 ret = data_blob_cmp(&v1_canon, &v2_canon);
622         } else {
623                 ret = data_blob_cmp(v1, v2);
624         }
625         talloc_free(tmp_ctx);
626         return ret;
627 }
628
629 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
630                                  const struct ldb_val *in, struct ldb_val *out)
631 {
632         *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
633         if (!out->data) {
634                 return -1;
635         }
636         return 0;
637 }
638
639
640 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
641 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
642 #define LDB_SYNTAX_SAMBA_PREFIX_MAP     "LDB_SYNTAX_SAMBA_PREFIX_MAP"
643
644 static const struct ldb_schema_syntax samba_syntaxes[] = {
645         {
646                 .name             = LDB_SYNTAX_SAMBA_SID,
647                 .ldif_read_fn     = ldif_read_objectSid,
648                 .ldif_write_fn    = ldif_write_objectSid,
649                 .canonicalise_fn  = ldb_canonicalise_objectSid,
650                 .comparison_fn    = ldb_comparison_objectSid
651         },{
652                 .name             = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
653                 .ldif_read_fn     = ldif_read_ntSecurityDescriptor,
654                 .ldif_write_fn    = ldif_write_ntSecurityDescriptor,
655                 .canonicalise_fn  = ldb_handler_copy,
656                 .comparison_fn    = ldb_comparison_binary
657         },{
658                 .name             = LDB_SYNTAX_SAMBA_GUID,
659                 .ldif_read_fn     = ldif_read_objectGUID,
660                 .ldif_write_fn    = ldif_write_objectGUID,
661                 .canonicalise_fn  = ldb_canonicalise_objectGUID,
662                 .comparison_fn    = ldb_comparison_objectGUID
663         },{
664                 .name             = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
665                 .ldif_read_fn     = ldb_handler_copy,
666                 .ldif_write_fn    = ldb_handler_copy,
667                 .canonicalise_fn  = ldif_canonicalise_objectCategory,
668                 .comparison_fn    = ldif_comparison_objectCategory
669         },{
670                 .name             = LDB_SYNTAX_SAMBA_PREFIX_MAP,
671                 .ldif_read_fn     = ldif_read_prefixMap,
672                 .ldif_write_fn    = ldif_write_prefixMap,
673                 .canonicalise_fn  = ldif_canonicalise_prefixMap,
674                 .comparison_fn    = ldif_comparison_prefixMap
675         }
676 };
677
678 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
679         {
680                 .name             = "SID",
681                 .read_fn          = extended_dn_read_SID,
682                 .write_clear_fn   = ldif_write_objectSid,
683                 .write_hex_fn     = extended_dn_write_hex
684         },{
685                 .name             = "GUID",
686                 .read_fn          = extended_dn_read_GUID,
687                 .write_clear_fn   = ldif_write_objectGUID,
688                 .write_hex_fn     = extended_dn_write_hex
689         },{
690                 .name             = "WKGUID",
691                 .read_fn          = ldb_handler_copy,
692                 .write_clear_fn   = ldb_handler_copy,
693                 .write_hex_fn     = ldb_handler_copy
694         }
695 };
696
697 static const struct {
698         const char *name;
699         const char *syntax;
700 } samba_attributes[] = {
701         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
702         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
703         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
704         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
705         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
706         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
707         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
708         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
709         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
710         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
711         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
712         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
713         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
714         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
715         { "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP }
716 };
717
718 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
719 {
720         uint32_t j;
721         const struct ldb_schema_syntax *s = NULL;
722         
723         for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
724                 if (strcmp(name, samba_syntaxes[j].name) == 0) {
725                         s = &samba_syntaxes[j];
726                         break;
727                 }
728         }
729         return s;
730 }
731
732 const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
733 {
734         uint32_t j;
735         const struct ldb_schema_syntax *s = NULL;
736
737         for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
738                 if (strcmp(samba_attributes[j].name, name) == 0) {
739                         s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
740                         break;
741                 }
742         }
743         
744         return s;
745 }
746
747 /*
748   register the samba ldif handlers
749 */
750 int ldb_register_samba_handlers(struct ldb_context *ldb)
751 {
752         uint32_t i;
753
754         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
755                 int ret;
756                 const struct ldb_schema_syntax *s = NULL;
757
758                 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
759
760                 if (!s) {
761                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
762                 }
763
764                 if (!s) {
765                         return -1;
766                 }
767
768                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
769                 if (ret != LDB_SUCCESS) {
770                         return ret;
771                 }
772         }
773
774         for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
775                 int ret;
776                 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
777                 if (ret != LDB_SUCCESS) {
778                         return ret;
779                 }
780
781                 
782         }
783
784         return LDB_SUCCESS;
785 }