r23798: updated old Temple Place FSF addresses to new URL
[kai/samba.git] / source3 / 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, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "ldb/include/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         struct dom_sid *sid;
39         NTSTATUS status;
40         sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
41         if (sid == NULL) {
42                 return -1;
43         }
44         status = ndr_push_struct_blob(out, mem_ctx, sid, 
45                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
46         talloc_free(sid);
47         if (!NT_STATUS_IS_OK(status)) {
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         NTSTATUS status;
61         sid = talloc(mem_ctx, struct dom_sid);
62         if (sid == NULL) {
63                 return -1;
64         }
65         status = ndr_pull_struct_blob(in, sid, sid, 
66                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
67         if (!NT_STATUS_IS_OK(status)) {
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
144         status = GUID_from_string((const char *)in->data, &guid);
145         if (!NT_STATUS_IS_OK(status)) {
146                 return -1;
147         }
148
149         status = ndr_push_struct_blob(out, mem_ctx, &guid,
150                                       (ndr_push_flags_fn_t)ndr_push_GUID);
151         if (!NT_STATUS_IS_OK(status)) {
152                 return -1;
153         }
154         return 0;
155 }
156
157 /*
158   convert a NDR formatted blob to a ldif formatted objectGUID
159 */
160 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
161                                  const struct ldb_val *in, struct ldb_val *out)
162 {
163         struct GUID guid;
164         NTSTATUS status;
165         status = ndr_pull_struct_blob(in, mem_ctx, &guid,
166                                       (ndr_pull_flags_fn_t)ndr_pull_GUID);
167         if (!NT_STATUS_IS_OK(status)) {
168                 return -1;
169         }
170         out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
171         if (out->data == NULL) {
172                 return -1;
173         }
174         out->length = strlen((const char *)out->data);
175         return 0;
176 }
177
178 static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v)
179 {
180         struct GUID guid;
181         NTSTATUS status;
182
183         if (v->length < 33) return False;
184
185         /* see if the input if null-terninated (safety check for the below) */
186         if (v->data[v->length] != '\0') return False;
187
188         status = GUID_from_string((const char *)v->data, &guid);
189         if (!NT_STATUS_IS_OK(status)) {
190                 return False;
191         }
192
193         return True;
194 }
195
196 /*
197   compare two objectGUIDs
198 */
199 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
200                                      const struct ldb_val *v1, const struct ldb_val *v2)
201 {
202         if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
203                 return strcmp((const char *)v1->data, (const char *)v2->data);
204         } else if (ldb_comparision_objectGUID_isString(v1)
205                    && !ldb_comparision_objectGUID_isString(v2)) {
206                 struct ldb_val v;
207                 int ret;
208                 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
209                         return -1;
210                 }
211                 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
212                 talloc_free(v.data);
213                 return ret;
214         } else if (!ldb_comparision_objectGUID_isString(v1)
215                    && ldb_comparision_objectGUID_isString(v2)) {
216                 struct ldb_val v;
217                 int ret;
218                 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
219                         return -1;
220                 }
221                 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
222                 talloc_free(v.data);
223                 return ret;
224         }
225         return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
226 }
227
228 /*
229   canonicalise a objectGUID
230 */
231 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
232                                        const struct ldb_val *in, struct ldb_val *out)
233 {
234         if (ldb_comparision_objectGUID_isString(in)) {
235                 return ldif_read_objectGUID(ldb, mem_ctx, in, out);
236         }
237         return ldb_handler_copy(ldb, mem_ctx, in, out);
238 }
239
240
241 /*
242   convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
243 */
244 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
245                                           const struct ldb_val *in, struct ldb_val *out)
246 {
247         struct security_descriptor *sd;
248         NTSTATUS status;
249
250         sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
251         if (sd == NULL) {
252                 return -1;
253         }
254         status = ndr_push_struct_blob(out, mem_ctx, sd, 
255                                       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
256         talloc_free(sd);
257         if (!NT_STATUS_IS_OK(status)) {
258                 return -1;
259         }
260         return 0;
261 }
262
263 /*
264   convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
265 */
266 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
267                                            const struct ldb_val *in, struct ldb_val *out)
268 {
269         struct security_descriptor *sd;
270         NTSTATUS status;
271
272         sd = talloc(mem_ctx, struct security_descriptor);
273         if (sd == NULL) {
274                 return -1;
275         }
276         status = ndr_pull_struct_blob(in, sd, sd, 
277                                       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
278         if (!NT_STATUS_IS_OK(status)) {
279                 talloc_free(sd);
280                 return -1;
281         }
282         out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
283         talloc_free(sd);
284         if (out->data == NULL) {
285                 return -1;
286         }
287         out->length = strlen((const char *)out->data);
288         return 0;
289 }
290
291 /* 
292    canonicolise an objectCategory.  We use the short form as the cannoical form:
293    cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
294 */
295
296 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
297                                             const struct ldb_val *in, struct ldb_val *out)
298 {
299         struct ldb_dn *dn1 = NULL;
300         char *oc1, *oc2;
301
302         dn1 = ldb_dn_explode(mem_ctx, (char *)in->data);
303         if (dn1 == NULL) {
304                 oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length);
305         } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
306                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
307                 oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
308         } else {
309                 return -1;
310         }
311
312         oc2 = ldb_casefold(ldb, mem_ctx, oc1);
313         out->data = (void *)oc2;
314         out->length = strlen(oc2);
315         talloc_free(oc1);
316         talloc_free(dn1);
317         return 0;
318 }
319
320 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
321                                           const struct ldb_val *v1,
322                                           const struct ldb_val *v2)
323 {
324         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
325         const char *oc1, *oc2;
326
327         dn1 = ldb_dn_explode(mem_ctx, (char *)v1->data);
328         if (dn1 == NULL) {
329                 oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length);
330         } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
331                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
332                 oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
333         } else {
334                 oc1 = NULL;
335         }
336
337         dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data);
338         if (dn2 == NULL) {
339                 oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length);
340         } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) {
341                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn2);
342                 oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
343         } else {
344                 oc2 = NULL;
345         }
346
347         oc1 = ldb_casefold(ldb, mem_ctx, oc1);
348         oc2 = ldb_casefold(ldb, mem_ctx, oc2);
349         if (!oc1 && oc2) {
350                 return -1;
351         } 
352         if (oc1 && !oc2) {
353                 return 1;
354         }       
355         if (!oc1 && !oc2) {
356                 return -1;
357         }
358
359         return strcmp(oc1, oc2);
360 }
361
362 static const struct ldb_attrib_handler samba_handlers[] = {
363         { 
364                 .attr            = "objectSid",
365                 .flags           = 0,
366                 .ldif_read_fn    = ldif_read_objectSid,
367                 .ldif_write_fn   = ldif_write_objectSid,
368                 .canonicalise_fn = ldb_canonicalise_objectSid,
369                 .comparison_fn   = ldb_comparison_objectSid
370         },
371         { 
372                 .attr            = "securityIdentifier",
373                 .flags           = 0,
374                 .ldif_read_fn    = ldif_read_objectSid,
375                 .ldif_write_fn   = ldif_write_objectSid,
376                 .canonicalise_fn = ldb_canonicalise_objectSid,
377                 .comparison_fn   = ldb_comparison_objectSid
378         },
379         { 
380                 .attr            = "ntSecurityDescriptor",
381                 .flags           = 0,
382                 .ldif_read_fn    = ldif_read_ntSecurityDescriptor,
383                 .ldif_write_fn   = ldif_write_ntSecurityDescriptor,
384                 .canonicalise_fn = ldb_handler_copy,
385                 .comparison_fn   = ldb_comparison_binary
386         },
387         { 
388                 .attr            = "objectGUID",
389                 .flags           = 0,
390                 .ldif_read_fn    = ldif_read_objectGUID,
391                 .ldif_write_fn   = ldif_write_objectGUID,
392                 .canonicalise_fn = ldb_canonicalise_objectGUID,
393                 .comparison_fn   = ldb_comparison_objectGUID
394         },
395         { 
396                 .attr            = "invocationId",
397                 .flags           = 0,
398                 .ldif_read_fn    = ldif_read_objectGUID,
399                 .ldif_write_fn   = ldif_write_objectGUID,
400                 .canonicalise_fn = ldb_canonicalise_objectGUID,
401                 .comparison_fn   = ldb_comparison_objectGUID
402         },
403         { 
404                 .attr            = "schemaIDGUID",
405                 .flags           = 0,
406                 .ldif_read_fn    = ldif_read_objectGUID,
407                 .ldif_write_fn   = ldif_write_objectGUID,
408                 .canonicalise_fn = ldb_canonicalise_objectGUID,
409                 .comparison_fn   = ldb_comparison_objectGUID
410         },
411         { 
412                 .attr            = "attributeSecurityGUID",
413                 .flags           = 0,
414                 .ldif_read_fn    = ldif_read_objectGUID,
415                 .ldif_write_fn   = ldif_write_objectGUID,
416                 .canonicalise_fn = ldb_canonicalise_objectGUID,
417                 .comparison_fn   = ldb_comparison_objectGUID
418         },
419         { 
420                 .attr            = "parentGUID",
421                 .flags           = 0,
422                 .ldif_read_fn    = ldif_read_objectGUID,
423                 .ldif_write_fn   = ldif_write_objectGUID,
424                 .canonicalise_fn = ldb_canonicalise_objectGUID,
425                 .comparison_fn   = ldb_comparison_objectGUID
426         },
427         { 
428                 .attr            = "siteGUID",
429                 .flags           = 0,
430                 .ldif_read_fn    = ldif_read_objectGUID,
431                 .ldif_write_fn   = ldif_write_objectGUID,
432                 .canonicalise_fn = ldb_canonicalise_objectGUID,
433                 .comparison_fn   = ldb_comparison_objectGUID
434         },
435         { 
436                 .attr            = "pKTGUID",
437                 .flags           = 0,
438                 .ldif_read_fn    = ldif_read_objectGUID,
439                 .ldif_write_fn   = ldif_write_objectGUID,
440                 .canonicalise_fn = ldb_canonicalise_objectGUID,
441                 .comparison_fn   = ldb_comparison_objectGUID
442         },
443         { 
444                 .attr            = "fRSVersionGUID",
445                 .flags           = 0,
446                 .ldif_read_fn    = ldif_read_objectGUID,
447                 .ldif_write_fn   = ldif_write_objectGUID,
448                 .canonicalise_fn = ldb_canonicalise_objectGUID,
449                 .comparison_fn   = ldb_comparison_objectGUID
450         },
451         { 
452                 .attr            = "fRSReplicaSetGUID",
453                 .flags           = 0,
454                 .ldif_read_fn    = ldif_read_objectGUID,
455                 .ldif_write_fn   = ldif_write_objectGUID,
456                 .canonicalise_fn = ldb_canonicalise_objectGUID,
457                 .comparison_fn   = ldb_comparison_objectGUID
458         },
459         { 
460                 .attr            = "netbootGUID",
461                 .flags           = 0,
462                 .ldif_read_fn    = ldif_read_objectGUID,
463                 .ldif_write_fn   = ldif_write_objectGUID,
464                 .canonicalise_fn = ldb_canonicalise_objectGUID,
465                 .comparison_fn   = ldb_comparison_objectGUID
466         },
467         { 
468                 .attr            = "objectCategory",
469                 .flags           = 0,
470                 .ldif_read_fn    = ldb_handler_copy,
471                 .ldif_write_fn   = ldb_handler_copy,
472                 .canonicalise_fn = ldif_canonicalise_objectCategory,
473                 .comparison_fn   = ldif_comparison_objectCategory,
474         }
475 };
476
477 /*
478   register the samba ldif handlers
479 */
480 int ldb_register_samba_handlers(struct ldb_context *ldb)
481 {
482         return ldb_set_attrib_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
483 }