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