r10304: check for basic ldb_message sanity and return appropriate
[jelmer/samba4-debian.git] / source / lib / ldb / common / ldb_msg.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
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 /*
26  *  Name: ldb
27  *
28  *  Component: ldb message component utility functions
29  *
30  *  Description: functions for manipulating ldb_message structures
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_errors.h"
38 #include "ldb/include/ldb_private.h"
39
40 /*
41   create a new ldb_message in a given memory context (NULL for top level)
42 */
43 struct ldb_message *ldb_msg_new(void *mem_ctx)
44 {
45         return talloc_zero(mem_ctx, struct ldb_message);
46 }
47
48 /*
49   find an element in a message by attribute name
50 */
51 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
52                                                  const char *attr_name)
53 {
54         unsigned int i;
55         for (i=0;i<msg->num_elements;i++) {
56                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
57                         return &msg->elements[i];
58                 }
59         }
60         return NULL;
61 }
62
63 /*
64   see if two ldb_val structures contain exactly the same data
65   return 1 for a match, 0 for a mis-match
66 */
67 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
68 {
69         if (v1->length != v2->length) return 0;
70
71         if (v1->length == 0) return 1;
72
73         if (memcmp(v1->data, v2->data, v1->length) == 0) {
74                 return 1;
75         }
76
77         return 0;
78 }
79
80 /*
81   find a value in an element
82   assumes case sensitive comparison
83 */
84 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
85                                  struct ldb_val *val)
86 {
87         unsigned int i;
88         for (i=0;i<el->num_values;i++) {
89                 if (ldb_val_equal_exact(val, &el->values[i])) {
90                         return &el->values[i];
91                 }
92         }
93         return NULL;
94 }
95
96 /*
97   duplicate a ldb_val structure
98 */
99 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
100 {
101         struct ldb_val v2;
102         v2.length = v->length;
103         if (v->data == NULL) {
104                 v2.data = NULL;
105                 return v2;
106         }
107
108         /* the +1 is to cope with buggy C library routines like strndup
109            that look one byte beyond */
110         v2.data = talloc_array(mem_ctx, char, v->length+1);
111         if (!v2.data) {
112                 v2.length = 0;
113                 return v2;
114         }
115
116         memcpy(v2.data, v->data, v->length);
117         ((char *)v2.data)[v->length] = 0;
118         return v2;
119 }
120
121 /*
122   add an empty element to a message
123 */
124 int ldb_msg_add_empty(struct ldb_context *ldb,
125                       struct ldb_message *msg, const char *attr_name, int flags)
126 {
127         struct ldb_message_element *els;
128
129         els = talloc_realloc(msg, msg->elements, 
130                                struct ldb_message_element, msg->num_elements+1);
131         if (!els) {
132                 errno = ENOMEM;
133                 return -1;
134         }
135
136         els[msg->num_elements].values = NULL;
137         els[msg->num_elements].num_values = 0;
138         els[msg->num_elements].flags = flags;
139         els[msg->num_elements].name = talloc_strdup(els, attr_name);
140         if (!els[msg->num_elements].name) {
141                 return -1;
142         }
143
144         msg->elements = els;
145         msg->num_elements++;
146
147         return 0;
148 }
149
150 /*
151   add an empty element to a message
152 */
153 int ldb_msg_add(struct ldb_context *ldb,
154                 struct ldb_message *msg, 
155                 const struct ldb_message_element *el, 
156                 int flags)
157 {
158         if (ldb_msg_add_empty(ldb, msg, el->name, flags) != 0) {
159                 return -1;
160         }
161
162         msg->elements[msg->num_elements-1] = *el;
163         msg->elements[msg->num_elements-1].flags = flags;
164
165         return 0;
166 }
167
168 /*
169   add a value to a message
170 */
171 int ldb_msg_add_value(struct ldb_context *ldb,
172                       struct ldb_message *msg, 
173                       const char *attr_name,
174                       const struct ldb_val *val)
175 {
176         struct ldb_message_element *el;
177         struct ldb_val *vals;
178
179         el = ldb_msg_find_element(msg, attr_name);
180         if (!el) {
181                 ldb_msg_add_empty(ldb, msg, attr_name, 0);
182                 el = ldb_msg_find_element(msg, attr_name);
183         }
184         if (!el) {
185                 return -1;
186         }
187
188         vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
189         if (!vals) {
190                 errno = ENOMEM;
191                 return -1;
192         }
193         el->values = vals;
194         el->values[el->num_values] = *val;
195         el->num_values++;
196
197         return 0;
198 }
199
200
201 /*
202   add a string element to a message
203 */
204 int ldb_msg_add_string(struct ldb_context *ldb, struct ldb_message *msg, 
205                        const char *attr_name, const char *str)
206 {
207         struct ldb_val val;
208
209         val.data = discard_const_p(char, str);
210         val.length = strlen(str);
211
212         return ldb_msg_add_value(ldb, msg, attr_name, &val);
213 }
214
215 /*
216   add a printf formatted element to a message
217 */
218 int ldb_msg_add_fmt(struct ldb_context *ldb, struct ldb_message *msg, 
219                     const char *attr_name, const char *fmt, ...)
220 {
221         struct ldb_val val;
222         va_list ap;
223         char *str;
224
225         va_start(ap, fmt);
226         str = talloc_vasprintf(msg, fmt, ap);
227         va_end(ap);
228
229         if (str == NULL) return -1;
230
231         val.data   = str;
232         val.length = strlen(str);
233
234         return ldb_msg_add_value(ldb, msg, attr_name, &val);
235 }
236
237 /*
238   compare two ldb_message_element structures
239   assumes case senistive comparison
240 */
241 int ldb_msg_element_compare(struct ldb_message_element *el1, 
242                             struct ldb_message_element *el2)
243 {
244         unsigned int i;
245
246         if (el1->num_values != el2->num_values) {
247                 return el1->num_values - el2->num_values;
248         }
249
250         for (i=0;i<el1->num_values;i++) {
251                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
252                         return -1;
253                 }
254         }
255
256         return 0;
257 }
258
259 /*
260   compare two ldb_message_element structures
261   comparing by element name
262 */
263 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
264                                  struct ldb_message_element *el2)
265 {
266         return ldb_attr_cmp(el1->name, el2->name);
267 }
268
269 /*
270   convenience functions to return common types from a message
271   these return the first value if the attribute is multi-valued
272 */
273 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
274 {
275         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
276         if (!el || el->num_values == 0) {
277                 return NULL;
278         }
279         return &el->values[0];
280 }
281
282 int ldb_msg_find_int(const struct ldb_message *msg, 
283                      const char *attr_name,
284                      int default_value)
285 {
286         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
287         if (!v || !v->data) {
288                 return default_value;
289         }
290         return strtol(v->data, NULL, 0);
291 }
292
293 unsigned int ldb_msg_find_uint(const struct ldb_message *msg, 
294                                const char *attr_name,
295                                unsigned int default_value)
296 {
297         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
298         if (!v || !v->data) {
299                 return default_value;
300         }
301         return strtoul(v->data, NULL, 0);
302 }
303
304 int64_t ldb_msg_find_int64(const struct ldb_message *msg, 
305                            const char *attr_name,
306                            int64_t default_value)
307 {
308         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
309         if (!v || !v->data) {
310                 return default_value;
311         }
312         return strtoll(v->data, NULL, 0);
313 }
314
315 uint64_t ldb_msg_find_uint64(const struct ldb_message *msg, 
316                              const char *attr_name,
317                              uint64_t default_value)
318 {
319         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
320         if (!v || !v->data) {
321                 return default_value;
322         }
323         return strtoull(v->data, NULL, 0);
324 }
325
326 double ldb_msg_find_double(const struct ldb_message *msg, 
327                            const char *attr_name,
328                            double default_value)
329 {
330         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
331         if (!v || !v->data) {
332                 return default_value;
333         }
334         return strtod(v->data, NULL);
335 }
336
337 const char *ldb_msg_find_string(const struct ldb_message *msg, 
338                                 const char *attr_name,
339                                 const char *default_value)
340 {
341         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
342         if (!v || !v->data) {
343                 return default_value;
344         }
345         return v->data;
346 }
347
348 /*
349   sort the elements of a message by name
350 */
351 void ldb_msg_sort_elements(struct ldb_message *msg)
352 {
353         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
354               (comparison_fn_t)ldb_msg_element_compare_name);
355 }
356
357 /*
358   copy a message, allocating new memory for all parts
359 */
360 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
361                                  const struct ldb_message *msg)
362 {
363         struct ldb_message *msg2;
364         int i, j;
365
366         msg2 = talloc(mem_ctx, struct ldb_message);
367         if (msg2 == NULL) return NULL;
368
369         msg2->elements = NULL;
370         msg2->num_elements = 0;
371         msg2->private_data = NULL;
372
373         msg2->dn = ldb_dn_copy(msg2, msg->dn);
374         if (msg2->dn == NULL) goto failed;
375
376         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg->num_elements);
377         if (msg2->elements == NULL) goto failed;
378
379         for (i=0;i<msg->num_elements;i++) {
380                 struct ldb_message_element *el1 = &msg->elements[i];
381                 struct ldb_message_element *el2 = &msg2->elements[i];
382
383                 el2->flags = el1->flags;
384                 el2->num_values = 0;
385                 el2->values = NULL;
386                 el2->name = talloc_strdup(msg2->elements, el1->name);
387                 if (el2->name == NULL) goto failed;
388                 el2->values = talloc_array(msg2->elements, struct ldb_val, el1->num_values);
389                 for (j=0;j<el1->num_values;j++) {
390                         el2->values[j] = ldb_val_dup(el2->values, &el1->values[j]);
391                         if (el2->values[j].data == NULL &&
392                             el1->values[j].length != 0) {
393                                 goto failed;
394                         }
395                         el2->num_values++;
396                 }
397
398                 msg2->num_elements++;
399         }
400
401         return msg2;
402
403 failed:
404         talloc_free(msg2);
405         return NULL;
406 }
407
408
409 /*
410   canonicalise a message, merging elements of the same name
411 */
412 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
413                                          const struct ldb_message *msg)
414 {
415         int i;
416         struct ldb_message *msg2;
417
418         msg2 = ldb_msg_copy(ldb, msg);
419         if (msg2 == NULL) return NULL;
420
421         ldb_msg_sort_elements(msg2);
422
423         for (i=1;i<msg2->num_elements;i++) {
424                 struct ldb_message_element *el1 = &msg2->elements[i-1];
425                 struct ldb_message_element *el2 = &msg2->elements[i];
426                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
427                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
428                                                        el1->num_values + el2->num_values);
429                         if (el1->values == NULL) {
430                                 return NULL;
431                         }
432                         memcpy(el1->values + el1->num_values,
433                                el2->values,
434                                sizeof(struct ldb_val) * el2->num_values);
435                         el1->num_values += el2->num_values;
436                         talloc_free(discard_const_p(char, el2->name));
437                         if (i+1<msg2->num_elements) {
438                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
439                                         (msg2->num_elements - (i+1)));
440                         }
441                         msg2->num_elements--;
442                         i--;
443                 }
444         }
445
446         return msg2;
447 }
448
449
450 /*
451   return a ldb_message representing the differences between msg1 and msg2. If you
452   then use this in a ldb_modify() call it can be used to save edits to a message
453 */
454 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
455                                  struct ldb_message *msg1,
456                                  struct ldb_message *msg2)
457 {
458         struct ldb_message *mod;
459         struct ldb_message_element *el;
460         unsigned int i;
461
462         mod = ldb_msg_new(ldb);
463
464         mod->dn = msg1->dn;
465         mod->num_elements = 0;
466         mod->elements = NULL;
467
468         msg2 = ldb_msg_canonicalize(ldb, msg2);
469         if (msg2 == NULL) {
470                 return NULL;
471         }
472         
473         /* look in msg2 to find elements that need to be added
474            or modified */
475         for (i=0;i<msg2->num_elements;i++) {
476                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
477
478                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
479                         continue;
480                 }
481
482                 if (ldb_msg_add(ldb, mod, 
483                                 &msg2->elements[i],
484                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
485                         return NULL;
486                 }
487         }
488
489         /* look in msg1 to find elements that need to be deleted */
490         for (i=0;i<msg1->num_elements;i++) {
491                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
492                 if (!el) {
493                         if (ldb_msg_add_empty(ldb, mod, 
494                                               msg1->elements[i].name,
495                                               LDB_FLAG_MOD_DELETE) != 0) {
496                                 return NULL;
497                         }
498                 }
499         }
500
501         return mod;
502 }
503
504 int ldb_msg_sanity_check(const struct ldb_message *msg)
505 {
506         int i, j;
507
508         /* basic check on DN */
509         if (msg->dn == NULL) {
510                 /* TODO: return also an error string */
511                 return LDB_ERR_INVALID_DN_SYNTAX;
512         }
513         if (msg->dn->comp_num == 0) {
514                 /* root dse has empty dn */
515                 /* TODO: return also an error string */
516                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
517         }
518
519         /* basic syntax checks */
520         for (i = 0; i < msg->num_elements; i++) {
521                 for (j = 0; j < msg->elements[i].num_values; j++) {
522                         if (msg->elements[i].values[j].length == 0) {
523                                 /* an attribute cannot be empty */
524                                 /* TODO: return also an error string */
525                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
526                         }
527                 }
528         }
529
530         return LDB_ERR_SUCCESS;
531 }