r26129: Specify path explicitly in case an external ldb installation is used.
[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
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "libcli/security/security.h"
31
32 /*
33   convert a ldif formatted objectSid to a NDR formatted blob
34 */
35 static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
36                                const struct ldb_val *in, struct ldb_val *out)
37 {
38         enum ndr_err_code ndr_err;
39         struct dom_sid *sid;
40         sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
41         if (sid == NULL) {
42                 return -1;
43         }
44         ndr_err = ndr_push_struct_blob(out, mem_ctx, sid,
45                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
46         talloc_free(sid);
47         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
48                 return -1;
49         }
50         return 0;
51 }
52
53 /*
54   convert a NDR formatted blob to a ldif formatted objectSid
55 */
56 static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
57                                 const struct ldb_val *in, struct ldb_val *out)
58 {
59         struct dom_sid *sid;
60         enum ndr_err_code ndr_err;
61
62         sid = talloc(mem_ctx, struct dom_sid);
63         if (sid == NULL) {
64                 return -1;
65         }
66         ndr_err = ndr_pull_struct_blob(in, sid, sid,
67                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
68         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
69                 talloc_free(sid);
70                 return -1;
71         }
72         out->data = (uint8_t *)dom_sid_string(mem_ctx, sid);
73         talloc_free(sid);
74         if (out->data == NULL) {
75                 return -1;
76         }
77         out->length = strlen((const char *)out->data);
78         return 0;
79 }
80
81 static bool ldb_comparision_objectSid_isString(const struct ldb_val *v)
82 {
83         if (v->length < 3) {
84                 return false;
85         }
86
87         if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
88         
89         return true;
90 }
91
92 /*
93   compare two objectSids
94 */
95 static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
96                                     const struct ldb_val *v1, const struct ldb_val *v2)
97 {
98         if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) {
99                 return strcmp((const char *)v1->data, (const char *)v2->data);
100         } else if (ldb_comparision_objectSid_isString(v1)
101                    && !ldb_comparision_objectSid_isString(v2)) {
102                 struct ldb_val v;
103                 int ret;
104                 if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
105                         return -1;
106                 }
107                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
108                 talloc_free(v.data);
109                 return ret;
110         } else if (!ldb_comparision_objectSid_isString(v1)
111                    && ldb_comparision_objectSid_isString(v2)) {
112                 struct ldb_val v;
113                 int ret;
114                 if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
115                         return -1;
116                 }
117                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
118                 talloc_free(v.data);
119                 return ret;
120         }
121         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
122 }
123
124 /*
125   canonicalise a objectSid
126 */
127 static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
128                                       const struct ldb_val *in, struct ldb_val *out)
129 {
130         if (ldb_comparision_objectSid_isString(in)) {
131                 return ldif_read_objectSid(ldb, mem_ctx, in, out);
132         }
133         return ldb_handler_copy(ldb, mem_ctx, in, out);
134 }
135
136 /*
137   convert a ldif formatted objectGUID to a NDR formatted blob
138 */
139 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
140                                 const struct ldb_val *in, struct ldb_val *out)
141 {
142         struct GUID guid;
143         NTSTATUS status;
144         enum ndr_err_code ndr_err;
145
146         status = GUID_from_string((const char *)in->data, &guid);
147         if (!NT_STATUS_IS_OK(status)) {
148                 return -1;
149         }
150
151         ndr_err = ndr_push_struct_blob(out, mem_ctx, &guid,
152                                        (ndr_push_flags_fn_t)ndr_push_GUID);
153         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
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         enum ndr_err_code ndr_err;
167         ndr_err = ndr_pull_struct_blob(in, mem_ctx, &guid,
168                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
169         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
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         enum ndr_err_code ndr_err;
251
252         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
253         if (sd == NULL) {
254                 return -1;
255         }
256         ndr_err = ndr_push_struct_blob(out, mem_ctx, sd,
257                                        (ndr_push_flags_fn_t)ndr_push_security_descriptor);
258         talloc_free(sd);
259         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
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         enum ndr_err_code ndr_err;
273
274         sd = talloc(mem_ctx, struct security_descriptor);
275         if (sd == NULL) {
276                 return -1;
277         }
278         ndr_err = ndr_pull_struct_blob(in, sd, sd,
279                                        (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
280         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
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         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
305         if (!tmp_ctx) {
306                 return LDB_ERR_OPERATIONS_ERROR;
307         }
308
309         if (!schema) {
310                 *out = data_blob_talloc(mem_ctx, in->data, in->length);
311                 if (in->data && !out->data) {
312                         return LDB_ERR_OPERATIONS_ERROR;
313                 }
314                 return LDB_SUCCESS;
315         }
316         dn1 = ldb_dn_new(tmp_ctx, ldb, (char *)in->data);
317         if ( ! ldb_dn_validate(dn1)) {
318                 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
319                 class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
320                 if (class) {
321                         struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,  
322                                                        class->defaultObjectCategory);
323                         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
324                         talloc_free(tmp_ctx);
325
326                         if (!out->data) {
327                                 return LDB_ERR_OPERATIONS_ERROR;
328                         }
329                         return LDB_SUCCESS;
330                 } else {
331                         *out = data_blob_talloc(mem_ctx, in->data, in->length);
332                         talloc_free(tmp_ctx);
333
334                         if (in->data && !out->data) {
335                                 return LDB_ERR_OPERATIONS_ERROR;
336                         }
337                         return LDB_SUCCESS;
338                 }
339         }
340         *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
341         talloc_free(tmp_ctx);
342
343         if (!out->data) {
344                 return LDB_ERR_OPERATIONS_ERROR;
345         }
346         return LDB_SUCCESS;
347 }
348
349 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
350                                           const struct ldb_val *v1,
351                                           const struct ldb_val *v2)
352 {
353
354         int ret, ret1, ret2;
355         struct ldb_val v1_canon, v2_canon;
356         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
357
358         /* I could try and bail if tmp_ctx was NULL, but what return
359          * value would I use?
360          *
361          * It seems easier to continue on the NULL context 
362          */
363         ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
364         ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
365
366         if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
367                 ret = data_blob_cmp(&v1_canon, &v2_canon);
368         } else {
369                 ret = data_blob_cmp(v1, v2);
370         }
371         talloc_free(tmp_ctx);
372         return ret;
373 }
374
375 #define LDB_SYNTAX_SAMBA_SID                    "LDB_SYNTAX_SAMBA_SID"
376 #define LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR    "LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR"
377 #define LDB_SYNTAX_SAMBA_GUID                   "LDB_SYNTAX_SAMBA_GUID"
378 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY        "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
379
380 static const struct ldb_schema_syntax samba_syntaxes[] = {
381         {
382                 .name           = LDB_SYNTAX_SAMBA_SID,
383                 .ldif_read_fn   = ldif_read_objectSid,
384                 .ldif_write_fn  = ldif_write_objectSid,
385                 .canonicalise_fn= ldb_canonicalise_objectSid,
386                 .comparison_fn  = ldb_comparison_objectSid
387         },{
388                 .name           = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
389                 .ldif_read_fn   = ldif_read_ntSecurityDescriptor,
390                 .ldif_write_fn  = ldif_write_ntSecurityDescriptor,
391                 .canonicalise_fn= ldb_handler_copy,
392                 .comparison_fn  = ldb_comparison_binary
393         },{
394                 .name           = LDB_SYNTAX_SAMBA_GUID,
395                 .ldif_read_fn   = ldif_read_objectGUID,
396                 .ldif_write_fn  = ldif_write_objectGUID,
397                 .canonicalise_fn= ldb_canonicalise_objectGUID,
398                 .comparison_fn  = ldb_comparison_objectGUID
399         },{
400                 .name           = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
401                 .ldif_read_fn   = ldb_handler_copy,
402                 .ldif_write_fn  = ldb_handler_copy,
403                 .canonicalise_fn= ldif_canonicalise_objectCategory,
404                 .comparison_fn  = ldif_comparison_objectCategory
405         }
406 };
407
408 static const struct {
409         const char *name;
410         const char *syntax;
411 } samba_attributes[] = {
412         { "objectSid",                  LDB_SYNTAX_SAMBA_SID },
413         { "securityIdentifier",         LDB_SYNTAX_SAMBA_SID },
414         { "ntSecurityDescriptor",       LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
415         { "objectGUID",                 LDB_SYNTAX_SAMBA_GUID },
416         { "invocationId",               LDB_SYNTAX_SAMBA_GUID },
417         { "schemaIDGUID",               LDB_SYNTAX_SAMBA_GUID },
418         { "attributeSecurityGUID",      LDB_SYNTAX_SAMBA_GUID },
419         { "parentGUID",                 LDB_SYNTAX_SAMBA_GUID },
420         { "siteGUID",                   LDB_SYNTAX_SAMBA_GUID },
421         { "pKTGUID",                    LDB_SYNTAX_SAMBA_GUID },
422         { "fRSVersionGUID",             LDB_SYNTAX_SAMBA_GUID },
423         { "fRSReplicaSetGUID",          LDB_SYNTAX_SAMBA_GUID },
424         { "netbootGUID",                LDB_SYNTAX_SAMBA_GUID },
425         { "objectCategory",             LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
426         { "member",                     LDB_SYNTAX_DN },
427         { "memberOf",                   LDB_SYNTAX_DN },
428         { "nCName",                     LDB_SYNTAX_DN },
429         { "schemaNamingContext",        LDB_SYNTAX_DN },
430         { "configurationNamingContext", LDB_SYNTAX_DN },
431         { "rootDomainNamingContext",    LDB_SYNTAX_DN },
432         { "defaultNamingContext",       LDB_SYNTAX_DN },
433         { "subRefs",                    LDB_SYNTAX_DN },
434         { "dMDLocation",                LDB_SYNTAX_DN },
435         { "serverReference",            LDB_SYNTAX_DN },
436         { "masteredBy",                 LDB_SYNTAX_DN },
437         { "msDs-masteredBy",            LDB_SYNTAX_DN },
438         { "fSMORoleOwner",              LDB_SYNTAX_DN },
439 };
440
441 /*
442   register the samba ldif handlers
443 */
444 int ldb_register_samba_handlers(struct ldb_context *ldb)
445 {
446         uint32_t i;
447
448         for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
449                 int ret;
450                 uint32_t j;
451                 const struct ldb_schema_syntax *s = NULL;
452
453                 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
454                         if (strcmp(samba_attributes[i].syntax, samba_syntaxes[j].name) == 0) {
455                                 s = &samba_syntaxes[j];
456                                 break;
457                         }
458                 }
459
460                 if (!s) {
461                         s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
462                 }
463
464                 if (!s) {
465                         return -1;
466                 }
467
468                 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, 0, s);
469                 if (ret != LDB_SUCCESS) {
470                         return ret;
471                 }
472         }
473
474         return LDB_SUCCESS;
475 }