r25084: Move samba-specific code out of lib/ldb directory.
[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 "ldb_includes.h"
26 #include "ldb_handlers.h"
27
28 #include "librpc/gen_ndr/ndr_security.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "dsdb/samdb/samdb.h"
31 #include "libcli/security/security.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         struct dom_sid *sid;
40         NTSTATUS status;
41         sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
42         if (sid == NULL) {
43                 return -1;
44         }
45         status = ndr_push_struct_blob(out, mem_ctx, sid, 
46                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
47         talloc_free(sid);
48         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
62         sid = talloc(mem_ctx, struct dom_sid);
63         if (sid == NULL) {
64                 return -1;
65         }
66         status = ndr_pull_struct_blob(in, sid, sid, 
67                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
68         if (!NT_STATUS_IS_OK(status)) {
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
145         status = GUID_from_string((const char *)in->data, &guid);
146         if (!NT_STATUS_IS_OK(status)) {
147                 return -1;
148         }
149
150         status = ndr_push_struct_blob(out, mem_ctx, &guid,
151                                       (ndr_push_flags_fn_t)ndr_push_GUID);
152         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
166         status = ndr_pull_struct_blob(in, mem_ctx, &guid,
167                                       (ndr_pull_flags_fn_t)ndr_pull_GUID);
168         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
250
251         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
252         if (sd == NULL) {
253                 return -1;
254         }
255         status = ndr_push_struct_blob(out, mem_ctx, sd, 
256                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
257         talloc_free(sd);
258         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
272
273         sd = talloc(mem_ctx, struct security_descriptor);
274         if (sd == NULL) {
275                 return -1;
276         }
277         status = ndr_pull_struct_blob(in, sd, sd, 
278                                       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
279         if (!NT_STATUS_IS_OK(status)) {
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    canonicolise 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 }