r19683: Guard GUID_from_string from walking off the end.
[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
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 2 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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include "includes.h"
26 #include "ldb/include/includes.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         char *oc1, *oc2;
302
303         dn1 = ldb_dn_explode(mem_ctx, (char *)in->data);
304         if (dn1 == NULL) {
305                 oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length);
306         } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
307                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
308                 oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
309         } else {
310                 return -1;
311         }
312
313         oc2 = ldb_casefold(ldb, mem_ctx, oc1);
314         out->data = (void *)oc2;
315         out->length = strlen(oc2);
316         talloc_free(oc1);
317         talloc_free(dn1);
318         return 0;
319 }
320
321 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
322                                           const struct ldb_val *v1,
323                                           const struct ldb_val *v2)
324 {
325         struct ldb_dn *dn1 = NULL, *dn2 = NULL;
326         const char *oc1, *oc2;
327
328         dn1 = ldb_dn_explode(mem_ctx, (char *)v1->data);
329         if (dn1 == NULL) {
330                 oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length);
331         } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) {
332                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn1);
333                 oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
334         } else {
335                 oc1 = NULL;
336         }
337
338         dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data);
339         if (dn2 == NULL) {
340                 oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length);
341         } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) {
342                 const struct ldb_val *val = ldb_dn_get_rdn_val(dn2);
343                 oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length);
344         } else {
345                 oc2 = NULL;
346         }
347
348         oc1 = ldb_casefold(ldb, mem_ctx, oc1);
349         oc2 = ldb_casefold(ldb, mem_ctx, oc2);
350         if (!oc1 && oc2) {
351                 return -1;
352         } 
353         if (oc1 && !oc2) {
354                 return 1;
355         }       
356         if (!oc1 && !oc2) {
357                 return -1;
358         }
359
360         return strcmp(oc1, oc2);
361 }
362
363 static const struct ldb_attrib_handler samba_handlers[] = {
364         { 
365                 .attr            = "objectSid",
366                 .flags           = 0,
367                 .ldif_read_fn    = ldif_read_objectSid,
368                 .ldif_write_fn   = ldif_write_objectSid,
369                 .canonicalise_fn = ldb_canonicalise_objectSid,
370                 .comparison_fn   = ldb_comparison_objectSid
371         },
372         { 
373                 .attr            = "securityIdentifier",
374                 .flags           = 0,
375                 .ldif_read_fn    = ldif_read_objectSid,
376                 .ldif_write_fn   = ldif_write_objectSid,
377                 .canonicalise_fn = ldb_canonicalise_objectSid,
378                 .comparison_fn   = ldb_comparison_objectSid
379         },
380         { 
381                 .attr            = "ntSecurityDescriptor",
382                 .flags           = 0,
383                 .ldif_read_fn    = ldif_read_ntSecurityDescriptor,
384                 .ldif_write_fn   = ldif_write_ntSecurityDescriptor,
385                 .canonicalise_fn = ldb_handler_copy,
386                 .comparison_fn   = ldb_comparison_binary
387         },
388         { 
389                 .attr            = "objectGUID",
390                 .flags           = 0,
391                 .ldif_read_fn    = ldif_read_objectGUID,
392                 .ldif_write_fn   = ldif_write_objectGUID,
393                 .canonicalise_fn = ldb_canonicalise_objectGUID,
394                 .comparison_fn   = ldb_comparison_objectGUID
395         },
396         { 
397                 .attr            = "invocationId",
398                 .flags           = 0,
399                 .ldif_read_fn    = ldif_read_objectGUID,
400                 .ldif_write_fn   = ldif_write_objectGUID,
401                 .canonicalise_fn = ldb_canonicalise_objectGUID,
402                 .comparison_fn   = ldb_comparison_objectGUID
403         },
404         { 
405                 .attr            = "schemaIDGUID",
406                 .flags           = 0,
407                 .ldif_read_fn    = ldif_read_objectGUID,
408                 .ldif_write_fn   = ldif_write_objectGUID,
409                 .canonicalise_fn = ldb_canonicalise_objectGUID,
410                 .comparison_fn   = ldb_comparison_objectGUID
411         },
412         { 
413                 .attr            = "attributeSecurityGUID",
414                 .flags           = 0,
415                 .ldif_read_fn    = ldif_read_objectGUID,
416                 .ldif_write_fn   = ldif_write_objectGUID,
417                 .canonicalise_fn = ldb_canonicalise_objectGUID,
418                 .comparison_fn   = ldb_comparison_objectGUID
419         },
420         { 
421                 .attr            = "parentGUID",
422                 .flags           = 0,
423                 .ldif_read_fn    = ldif_read_objectGUID,
424                 .ldif_write_fn   = ldif_write_objectGUID,
425                 .canonicalise_fn = ldb_canonicalise_objectGUID,
426                 .comparison_fn   = ldb_comparison_objectGUID
427         },
428         { 
429                 .attr            = "siteGUID",
430                 .flags           = 0,
431                 .ldif_read_fn    = ldif_read_objectGUID,
432                 .ldif_write_fn   = ldif_write_objectGUID,
433                 .canonicalise_fn = ldb_canonicalise_objectGUID,
434                 .comparison_fn   = ldb_comparison_objectGUID
435         },
436         { 
437                 .attr            = "pKTGUID",
438                 .flags           = 0,
439                 .ldif_read_fn    = ldif_read_objectGUID,
440                 .ldif_write_fn   = ldif_write_objectGUID,
441                 .canonicalise_fn = ldb_canonicalise_objectGUID,
442                 .comparison_fn   = ldb_comparison_objectGUID
443         },
444         { 
445                 .attr            = "fRSVersionGUID",
446                 .flags           = 0,
447                 .ldif_read_fn    = ldif_read_objectGUID,
448                 .ldif_write_fn   = ldif_write_objectGUID,
449                 .canonicalise_fn = ldb_canonicalise_objectGUID,
450                 .comparison_fn   = ldb_comparison_objectGUID
451         },
452         { 
453                 .attr            = "fRSReplicaSetGUID",
454                 .flags           = 0,
455                 .ldif_read_fn    = ldif_read_objectGUID,
456                 .ldif_write_fn   = ldif_write_objectGUID,
457                 .canonicalise_fn = ldb_canonicalise_objectGUID,
458                 .comparison_fn   = ldb_comparison_objectGUID
459         },
460         { 
461                 .attr            = "netbootGUID",
462                 .flags           = 0,
463                 .ldif_read_fn    = ldif_read_objectGUID,
464                 .ldif_write_fn   = ldif_write_objectGUID,
465                 .canonicalise_fn = ldb_canonicalise_objectGUID,
466                 .comparison_fn   = ldb_comparison_objectGUID
467         },
468         { 
469                 .attr            = "objectCategory",
470                 .flags           = 0,
471                 .ldif_read_fn    = ldb_handler_copy,
472                 .ldif_write_fn   = ldb_handler_copy,
473                 .canonicalise_fn = ldif_canonicalise_objectCategory,
474                 .comparison_fn   = ldif_comparison_objectCategory,
475         }
476 };
477
478 /*
479   register the samba ldif handlers
480 */
481 int ldb_register_samba_handlers(struct ldb_context *ldb)
482 {
483         return ldb_set_attrib_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
484 }