r26638: libndr: Require explicitly specifying iconv_convenience for ndr_struct_push_b...
[kai/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 "libcli/security/security.h"
30
31 /*
32   convert a ldif formatted objectSid to a NDR formatted blob
33 */
34 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
35                                const struct ldb_val *in, struct ldb_val *out)
36 {
37         enum ndr_err_code ndr_err;
38         struct dom_sid *sid;
39         sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
40         if (sid == NULL) {
41                 return -1;
42         }
43         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid,
44                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
45         talloc_free(sid);
46         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
47                 return -1;
48         }
49         return 0;
50 }
51
52 /*
53   convert a NDR formatted blob to a ldif formatted objectSid
54 */
55 static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
56                                 const struct ldb_val *in, struct ldb_val *out)
57 {
58         struct dom_sid *sid;
59         enum ndr_err_code ndr_err;
60
61         sid = talloc(mem_ctx, struct dom_sid);
62         if (sid == NULL) {
63                 return -1;
64         }
65         ndr_err = ndr_pull_struct_blob(in, sid, sid,
66                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
67         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
68                 talloc_free(sid);
69                 return -1;
70         }
71         out->data = (uint8_t *)dom_sid_string(mem_ctx, sid);
72         talloc_free(sid);
73         if (out->data == NULL) {
74                 return -1;
75         }
76         out->length = strlen((const char *)out->data);
77         return 0;
78 }
79
80 static bool ldb_comparision_objectSid_isString(const struct ldb_val *v)
81 {
82         if (v->length < 3) {
83                 return false;
84         }
85
86         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
87         
88         return true;
89 }
90
91 /*
92   compare two objectSids
93 */
94 static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
95                                     const struct ldb_val *v1, const struct ldb_val *v2)
96 {
97         if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) {
98                 return strcmp((const char *)v1->data, (const char *)v2->data);
99         } else if (ldb_comparision_objectSid_isString(v1)
100                    && !ldb_comparision_objectSid_isString(v2)) {
101                 struct ldb_val v;
102                 int ret;
103                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
104                         return -1;
105                 }
106                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
107                 talloc_free(v.data);
108                 return ret;
109         } else if (!ldb_comparision_objectSid_isString(v1)
110                    && ldb_comparision_objectSid_isString(v2)) {
111                 struct ldb_val v;
112                 int ret;
113                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
114                         return -1;
115                 }
116                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
117                 talloc_free(v.data);
118                 return ret;
119         }
120         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
121 }
122
123 /*
124   canonicalise a objectSid
125 */
126 static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
127                                       const struct ldb_val *in, struct ldb_val *out)
128 {
129         if (ldb_comparision_objectSid_isString(in)) {
130                 return ldif_read_objectSid(ldb, mem_ctx, in, out);
131         }
132         return ldb_handler_copy(ldb, mem_ctx, in, out);
133 }
134
135 /*
136   convert a ldif formatted objectGUID to a NDR formatted blob
137 */
138 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
139                                 const struct ldb_val *in, struct ldb_val *out)
140 {
141         struct GUID guid;
142         NTSTATUS status;
143         enum ndr_err_code ndr_err;
144
145         status = GUID_from_string((const char *)in->data, &guid);
146         if (!NT_STATUS_IS_OK(status)) {
147                 return -1;
148         }
149
150         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
151                                        (ndr_push_flags_fn_t)ndr_push_GUID);
152         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
153                 return -1;
154         }
155         return 0;
156 }
157
158 /*
159   convert a NDR formatted blob to a ldif formatted objectGUID
160 */
161 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
162                                  const struct ldb_val *in, struct ldb_val *out)
163 {
164         struct GUID guid;
165         enum ndr_err_code ndr_err;
166         ndr_err = ndr_pull_struct_blob(in, mem_ctx, &guid,
167                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
168         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169                 return -1;
170         }
171         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
172         if (out->data == NULL) {
173                 return -1;
174         }
175         out->length = strlen((const char *)out->data);
176         return 0;
177 }
178
179 static bool ldb_comparision_objectGUID_isString(const struct ldb_val *v)
180 {
181         struct GUID guid;
182         NTSTATUS status;
183
184         if (v->length < 33) return false;
185
186         /* see if the input if null-terninated (safety check for the below) */
187         if (v->data[v->length] != '\0') return false;
188
189         status = GUID_from_string((const char *)v->data, &guid);
190         if (!NT_STATUS_IS_OK(status)) {
191                 return false;
192         }
193
194         return true;
195 }
196
197 /*
198   compare two objectGUIDs
199 */
200 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
201                                      const struct ldb_val *v1, const struct ldb_val *v2)
202 {
203         if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
204                 return strcmp((const char *)v1->data, (const char *)v2->data);
205         } else if (ldb_comparision_objectGUID_isString(v1)
206                    && !ldb_comparision_objectGUID_isString(v2)) {
207                 struct ldb_val v;
208                 int ret;
209                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
210                         return -1;
211                 }
212                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
213                 talloc_free(v.data);
214                 return ret;
215         } else if (!ldb_comparision_objectGUID_isString(v1)
216                    && ldb_comparision_objectGUID_isString(v2)) {
217                 struct ldb_val v;
218                 int ret;
219                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
220                         return -1;
221                 }
222                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
223                 talloc_free(v.data);
224                 return ret;
225         }
226         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
227 }
228
229 /*
230   canonicalise a objectGUID
231 */
232 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
233                                        const struct ldb_val *in, struct ldb_val *out)
234 {
235         if (ldb_comparision_objectGUID_isString(in)) {
236                 return ldif_read_objectGUID(ldb, mem_ctx, in, out);
237         }
238         return ldb_handler_copy(ldb, mem_ctx, in, out);
239 }
240
241
242 /*
243   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
244 */
245 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
246                                           const struct ldb_val *in, struct ldb_val *out)
247 {
248         struct security_descriptor *sd;
249         enum ndr_err_code ndr_err;
250
251         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
252         if (sd == NULL) {
253                 return -1;
254         }
255         ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
256                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
257         talloc_free(sd);
258         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
259                 return -1;
260         }
261         return 0;
262 }
263
264 /*
265   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
266 */
267 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
268                                            const struct ldb_val *in, struct ldb_val *out)
269 {
270         struct security_descriptor *sd;
271         enum ndr_err_code ndr_err;
272
273         sd = talloc(mem_ctx, struct security_descriptor);
274         if (sd == NULL) {
275                 return -1;
276         }
277         ndr_err = ndr_pull_struct_blob(in, sd, sd,
278                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
279         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
280                 talloc_free(sd);
281                 return -1;
282         }
283         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
284         talloc_free(sd);
285         if (out->data == NULL) {
286                 return -1;
287         }
288         out->length = strlen((const char *)out->data);
289         return 0;
290 }
291
292 /* 
293    canonicalise an objectCategory.  We use the short form as the cannoical form:
294    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
295 */
296
297 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
298                                             const struct ldb_val *in, struct ldb_val *out)
299 {
300         struct ldb_dn *dn1 = NULL;
301         const struct dsdb_schema *schema = dsdb_get_schema(ldb);
302         const struct dsdb_class *class;
303         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
304         if (!tmp_ctx) {
305                 return LDB_ERR_OPERATIONS_ERROR;
306         }
307
308         if (!schema) {
309                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
310                 if (in->data && !out->data) {
311                         return LDB_ERR_OPERATIONS_ERROR;
312                 }
313                 return LDB_SUCCESS;
314         }
315         dn1 = ldb_dn_new(tmp_ctx, ldb, (char *)in->data);
316         if ( ! ldb_dn_validate(dn1)) {
317                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
318                 class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
319                 if (class) {
320                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
321                                                        class->defaultObjectCategory);
322                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
323                         talloc_free(tmp_ctx);
324
325                         if (!out->data) {
326                                 return LDB_ERR_OPERATIONS_ERROR;
327                         }
328                         return LDB_SUCCESS;
329                 } else {
330                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
331                         talloc_free(tmp_ctx);
332
333                         if (in->data && !out->data) {
334                                 return LDB_ERR_OPERATIONS_ERROR;
335                         }
336                         return LDB_SUCCESS;
337                 }
338         }
339         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
340         talloc_free(tmp_ctx);
341
342         if (!out->data) {
343                 return LDB_ERR_OPERATIONS_ERROR;
344         }
345         return LDB_SUCCESS;
346 }
347
348 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
349                                           const struct ldb_val *v1,
350                                           const struct ldb_val *v2)
351 {
352
353         int ret, ret1, ret2;
354         struct ldb_val v1_canon, v2_canon;
355         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
356
357         /* I could try and bail if tmp_ctx was NULL, but what return
358          * value would I use?
359          *
360          * It seems easier to continue on the NULL context 
361          */
362         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
363         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
364
365         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
366                 ret = data_blob_cmp(&v1_canon, &v2_canon);
367         } else {
368                 ret = data_blob_cmp(v1, v2);
369         }
370         talloc_free(tmp_ctx);
371         return ret;
372 }
373
374 #define LDB_SYNTAX_SAMBA_SID                    "LDB_SYNTAX_SAMBA_SID"
375 #define LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR    "LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR"
376 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
377 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
378
379 static const struct ldb_schema_syntax samba_syntaxes[] = {
380         {
381                 .name           = LDB_SYNTAX_SAMBA_SID,
382                 .ldif_read_fn   = ldif_read_objectSid,
383                 .ldif_write_fn  = ldif_write_objectSid,
384                 .canonicalise_fn= ldb_canonicalise_objectSid,
385                 .comparison_fn  = ldb_comparison_objectSid
386         },{
387                 .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
388                 .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
389                 .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
390                 .canonicalise_fn= ldb_handler_copy,
391                 .comparison_fn  = ldb_comparison_binary
392         },{
393                 .name           = LDB_SYNTAX_SAMBA_GUID,
394                 .ldif_read_fn   = ldif_read_objectGUID,
395                 .ldif_write_fn  = ldif_write_objectGUID,
396                 .canonicalise_fn= ldb_canonicalise_objectGUID,
397                 .comparison_fn  = ldb_comparison_objectGUID
398         },{
399                 .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
400                 .ldif_read_fn   = ldb_handler_copy,
401                 .ldif_write_fn  = ldb_handler_copy,
402                 .canonicalise_fn= ldif_canonicalise_objectCategory,
403                 .comparison_fn  = ldif_comparison_objectCategory
404         }
405 };
406
407 static const struct {
408         const char *name;
409         const char *syntax;
410 } samba_attributes[] = {
411         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
412         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
413         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
414         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
415         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
416         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
417         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
418         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
419         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
420         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
421         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
422         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
423         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
424         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
425         { "member",                     LDB_SYNTAX_DN },
426         { "memberOf",                   LDB_SYNTAX_DN },
427         { "nCName",                     LDB_SYNTAX_DN },
428         { "schemaNamingContext",        LDB_SYNTAX_DN },
429         { "configurationNamingContext", LDB_SYNTAX_DN },
430         { "rootDomainNamingContext",    LDB_SYNTAX_DN },
431         { "defaultNamingContext",       LDB_SYNTAX_DN },
432         { "subRefs",                    LDB_SYNTAX_DN },
433         { "dMDLocation",                LDB_SYNTAX_DN },
434         { "serverReference",            LDB_SYNTAX_DN },
435         { "masteredBy",                 LDB_SYNTAX_DN },
436         { "msDs-masteredBy",            LDB_SYNTAX_DN },
437         { "fSMORoleOwner",              LDB_SYNTAX_DN },
438 };
439
440 /*
441   register the samba ldif handlers
442 */
443 int ldb_register_samba_handlers(struct ldb_context *ldb)
444 {
445         uint32_t i;
446
447         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
448                 int ret;
449                 uint32_t j;
450                 const struct ldb_schema_syntax *s = NULL;
451
452                 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
453                         if (strcmp(samba_attributes[i].syntax, samba_syntaxes[j].name) == 0) {
454                                 s = &samba_syntaxes[j];
455                                 break;
456                         }
457                 }
458
459                 if (!s) {
460                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
461                 }
462
463                 if (!s) {
464                         return -1;
465                 }
466
467                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, 0, s);
468                 if (ret != LDB_SUCCESS) {
469                         return ret;
470                 }
471         }
472
473         return LDB_SUCCESS;
474 }