584d99979db045e56274fa0d49beaa34b2ed666f
[ira/wip.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
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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include "includes.h"
26 #include "ldb_includes.h"
27 #include "ldb_handlers.h"
28
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "libcli/security/security.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         struct dom_sid *sid;
41         NTSTATUS status;
42         sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
43         if (sid == NULL) {
44                 return -1;
45         }
46         status = ndr_push_struct_blob(out, mem_ctx, sid, 
47                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
48         talloc_free(sid);
49         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
63         sid = talloc(mem_ctx, struct dom_sid);
64         if (sid == NULL) {
65                 return -1;
66         }
67         status = ndr_pull_struct_blob(in, sid, sid, 
68                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
69         if (!NT_STATUS_IS_OK(status)) {
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
146         status = GUID_from_string((const char *)in->data, &guid);
147         if (!NT_STATUS_IS_OK(status)) {
148                 return -1;
149         }
150
151         status = ndr_push_struct_blob(out, mem_ctx, &guid,
152                                       (ndr_push_flags_fn_t)ndr_push_GUID);
153         if (!NT_STATUS_IS_OK(status)) {
154                 return -1;
155         }
156         return 0;
157 }
158
159 /*
160   convert a NDR formatted blob to a ldif formatted objectGUID
161 */
162 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
163                                  const struct ldb_val *in, struct ldb_val *out)
164 {
165         struct GUID guid;
166         NTSTATUS status;
167         status = ndr_pull_struct_blob(in, mem_ctx, &guid,
168                                       (ndr_pull_flags_fn_t)ndr_pull_GUID);
169         if (!NT_STATUS_IS_OK(status)) {
170                 return -1;
171         }
172         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
173         if (out->data == NULL) {
174                 return -1;
175         }
176         out->length = strlen((const char *)out->data);
177         return 0;
178 }
179
180 static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v)
181 {
182         struct GUID guid;
183         NTSTATUS status;
184
185         if (v->length < 33) return False;
186
187         /* see if the input if null-terninated (safety check for the below) */
188         if (v->data[v->length] != '\0') return False;
189
190         status = GUID_from_string((const char *)v->data, &guid);
191         if (!NT_STATUS_IS_OK(status)) {
192                 return False;
193         }
194
195         return True;
196 }
197
198 /*
199   compare two objectGUIDs
200 */
201 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
202                                      const struct ldb_val *v1, const struct ldb_val *v2)
203 {
204         if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
205                 return strcmp((const char *)v1->data, (const char *)v2->data);
206         } else if (ldb_comparision_objectGUID_isString(v1)
207                    && !ldb_comparision_objectGUID_isString(v2)) {
208                 struct ldb_val v;
209                 int ret;
210                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
211                         return -1;
212                 }
213                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
214                 talloc_free(v.data);
215                 return ret;
216         } else if (!ldb_comparision_objectGUID_isString(v1)
217                    && ldb_comparision_objectGUID_isString(v2)) {
218                 struct ldb_val v;
219                 int ret;
220                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
221                         return -1;
222                 }
223                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
224                 talloc_free(v.data);
225                 return ret;
226         }
227         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
228 }
229
230 /*
231   canonicalise a objectGUID
232 */
233 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
234                                        const struct ldb_val *in, struct ldb_val *out)
235 {
236         if (ldb_comparision_objectGUID_isString(in)) {
237                 return ldif_read_objectGUID(ldb, mem_ctx, in, out);
238         }
239         return ldb_handler_copy(ldb, mem_ctx, in, out);
240 }
241
242
243 /*
244   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
245 */
246 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
247                                           const struct ldb_val *in, struct ldb_val *out)
248 {
249         struct security_descriptor *sd;
250         NTSTATUS status;
251
252         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
253         if (sd == NULL) {
254                 return -1;
255         }
256         status = ndr_push_struct_blob(out, mem_ctx, sd, 
257                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
258         talloc_free(sd);
259         if (!NT_STATUS_IS_OK(status)) {
260                 return -1;
261         }
262         return 0;
263 }
264
265 /*
266   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
267 */
268 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
269                                            const struct ldb_val *in, struct ldb_val *out)
270 {
271         struct security_descriptor *sd;
272         NTSTATUS status;
273
274         sd = talloc(mem_ctx, struct security_descriptor);
275         if (sd == NULL) {
276                 return -1;
277         }
278         status = ndr_pull_struct_blob(in, sd, sd, 
279                                       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
280         if (!NT_STATUS_IS_OK(status)) {
281                 talloc_free(sd);
282                 return -1;
283         }
284         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
285         talloc_free(sd);
286         if (out->data == NULL) {
287                 return -1;
288         }
289         out->length = strlen((const char *)out->data);
290         return 0;
291 }
292
293 /* 
294    canonicolise an objectCategory.  We use the short form as the cannoical form:
295    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
296 */
297
298 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
299                                             const struct ldb_val *in, struct ldb_val *out)
300 {
301         struct ldb_dn *dn1 = NULL;
302         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
303         const struct dsdb_class *class;
304
305         if (!schema) {
306                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
307                 return LDB_SUCCESS;
308         }
309         dn1 = ldb_dn_new(mem_ctx, ldb, (char *)in->data);
310         if ( ! ldb_dn_validate(dn1)) {
311                 const char *lDAPDisplayName = talloc_strndup(mem_ctx, (char *)in->data, in->length);
312                 class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
313                 talloc_free(lDAPDisplayName);
314         } else if (ldb_dn_get_comp_num(dn1) >= 1 && ldb_attr_cmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
315                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
316                 const char *cn = talloc_strndup(mem_ctx, (char *)val->data, val->length);
317                 class = dsdb_class_by_cn(schema, cn);
318                 talloc_free(cn);
319         } else {
320                 talloc_free(dn1);
321                 return -1;
322         }
323         talloc_free(dn1);
324
325         if (!class) {
326                 return -1;
327         }
328         
329         *out = data_blob_string_const(talloc_strdup(mem_ctx, class->lDAPDisplayName));
330
331         return LDB_SUCCESS;
332 }
333
334 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
335                                           const struct ldb_val *v1,
336                                           const struct ldb_val *v2)
337 {
338
339         int ret1, ret2;
340         struct ldb_val v1_canon, v2_canon;
341         ret1 = ldif_canonicalise_objectCategory(ldb, mem_ctx, v1, &v1_canon);
342         ret2 = ldif_canonicalise_objectCategory(ldb, mem_ctx, v2, &v2_canon);
343
344         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
345                 return ldb_attr_cmp(v1_canon.data, v2_canon.data);
346         } else {
347                 return strcasecmp(v1->data, v2->data);
348         }
349 }
350
351 #define LDB_SYNTAX_SAMBA_SID                    "LDB_SYNTAX_SAMBA_SID"
352 #define LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR    "LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR"
353 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
354 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
355
356 static const struct ldb_schema_syntax samba_syntaxes[] = {
357         {
358                 .name           = LDB_SYNTAX_SAMBA_SID,
359                 .ldif_read_fn   = ldif_read_objectSid,
360                 .ldif_write_fn  = ldif_write_objectSid,
361                 .canonicalise_fn= ldb_canonicalise_objectSid,
362                 .comparison_fn  = ldb_comparison_objectSid
363         },{
364                 .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
365                 .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
366                 .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
367                 .canonicalise_fn= ldb_handler_copy,
368                 .comparison_fn  = ldb_comparison_binary
369         },{
370                 .name           = LDB_SYNTAX_SAMBA_GUID,
371                 .ldif_read_fn   = ldif_read_objectGUID,
372                 .ldif_write_fn  = ldif_write_objectGUID,
373                 .canonicalise_fn= ldb_canonicalise_objectGUID,
374                 .comparison_fn  = ldb_comparison_objectGUID
375         },{
376                 .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
377                 .ldif_read_fn   = ldb_handler_copy,
378                 .ldif_write_fn  = ldb_handler_copy,
379                 .canonicalise_fn= ldif_canonicalise_objectCategory,
380                 .comparison_fn  = ldif_comparison_objectCategory
381         }
382 };
383
384 static const struct {
385         const char *name;
386         const char *syntax;
387 } samba_attributes[] = {
388         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
389         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
390         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
391         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
392         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
393         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
394         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
395         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
396         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
397         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
398         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
399         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
400         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
401         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
402         { "member",                     LDB_SYNTAX_DN },
403         { "memberOf",                   LDB_SYNTAX_DN },
404         { "nCName",                     LDB_SYNTAX_DN },
405         { "schemaNamingContext",        LDB_SYNTAX_DN },
406         { "configurationNamingContext", LDB_SYNTAX_DN },
407         { "rootDomainNamingContext",    LDB_SYNTAX_DN },
408         { "defaultNamingContext",       LDB_SYNTAX_DN },
409         { "subRefs",                    LDB_SYNTAX_DN },
410         { "dMDLocation",                LDB_SYNTAX_DN },
411         { "serverReference",            LDB_SYNTAX_DN },
412         { "masteredBy",                 LDB_SYNTAX_DN },
413         { "msDs-masteredBy",            LDB_SYNTAX_DN },
414         { "fSMORoleOwner",              LDB_SYNTAX_DN },
415 };
416
417 /*
418   register the samba ldif handlers
419 */
420 int ldb_register_samba_handlers(struct ldb_context *ldb)
421 {
422         uint32_t i;
423
424         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
425                 int ret;
426                 uint32_t j;
427                 const struct ldb_schema_syntax *s = NULL;
428
429                 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
430                         if (strcmp(samba_attributes[i].syntax, samba_syntaxes[j].name) == 0) {
431                                 s = &samba_syntaxes[j];
432                                 break;
433                         }
434                 }
435
436                 if (!s) {
437                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
438                 }
439
440                 if (!s) {
441                         return -1;
442                 }
443
444                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, 0, s);
445                 if (ret != LDB_SUCCESS) {
446                         return ret;
447                 }
448         }
449
450         return LDB_SUCCESS;
451 }