r10913: This patch isn't as big as it looks ...
[kamenim/samba.git] / source4 / 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, uint8_t, 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_message *msg, const char *attr_name, int flags)
125 {
126         struct ldb_message_element *els;
127
128         els = talloc_realloc(msg, msg->elements, 
129                              struct ldb_message_element, msg->num_elements+1);
130         if (!els) {
131                 errno = ENOMEM;
132                 return -1;
133         }
134
135         els[msg->num_elements].values = NULL;
136         els[msg->num_elements].num_values = 0;
137         els[msg->num_elements].flags = flags;
138         els[msg->num_elements].name = talloc_strdup(els, attr_name);
139         if (!els[msg->num_elements].name) {
140                 return -1;
141         }
142
143         msg->elements = els;
144         msg->num_elements++;
145
146         return 0;
147 }
148
149 /*
150   add an empty element to a message
151 */
152 int ldb_msg_add(struct ldb_message *msg, 
153                 const struct ldb_message_element *el, 
154                 int flags)
155 {
156         if (ldb_msg_add_empty(msg, el->name, flags) != 0) {
157                 return -1;
158         }
159
160         msg->elements[msg->num_elements-1] = *el;
161         msg->elements[msg->num_elements-1].flags = flags;
162
163         return 0;
164 }
165
166 /*
167   add a value to a message
168 */
169 int ldb_msg_add_value(struct ldb_message *msg, 
170                       const char *attr_name,
171                       const struct ldb_val *val)
172 {
173         struct ldb_message_element *el;
174         struct ldb_val *vals;
175
176         el = ldb_msg_find_element(msg, attr_name);
177         if (!el) {
178                 ldb_msg_add_empty(msg, attr_name, 0);
179                 el = ldb_msg_find_element(msg, attr_name);
180         }
181         if (!el) {
182                 return -1;
183         }
184
185         vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
186         if (!vals) {
187                 errno = ENOMEM;
188                 return -1;
189         }
190         el->values = vals;
191         el->values[el->num_values] = *val;
192         el->num_values++;
193
194         return 0;
195 }
196
197
198 /*
199   add a string element to a message
200 */
201 int ldb_msg_add_string(struct ldb_message *msg, 
202                        const char *attr_name, const char *str)
203 {
204         struct ldb_val val;
205
206         val.data = discard_const_p(uint8_t, str);
207         val.length = strlen(str);
208
209         return ldb_msg_add_value(msg, attr_name, &val);
210 }
211
212 /*
213   add a printf formatted element to a message
214 */
215 int ldb_msg_add_fmt(struct ldb_message *msg, 
216                     const char *attr_name, const char *fmt, ...)
217 {
218         struct ldb_val val;
219         va_list ap;
220         char *str;
221
222         va_start(ap, fmt);
223         str = talloc_vasprintf(msg, fmt, ap);
224         va_end(ap);
225
226         if (str == NULL) return -1;
227
228         val.data   = (uint8_t *)str;
229         val.length = strlen(str);
230
231         return ldb_msg_add_value(msg, attr_name, &val);
232 }
233
234 /*
235   compare two ldb_message_element structures
236   assumes case senistive comparison
237 */
238 int ldb_msg_element_compare(struct ldb_message_element *el1, 
239                             struct ldb_message_element *el2)
240 {
241         unsigned int i;
242
243         if (el1->num_values != el2->num_values) {
244                 return el1->num_values - el2->num_values;
245         }
246
247         for (i=0;i<el1->num_values;i++) {
248                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
249                         return -1;
250                 }
251         }
252
253         return 0;
254 }
255
256 /*
257   compare two ldb_message_element structures
258   comparing by element name
259 */
260 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
261                                  struct ldb_message_element *el2)
262 {
263         return ldb_attr_cmp(el1->name, el2->name);
264 }
265
266 /*
267   convenience functions to return common types from a message
268   these return the first value if the attribute is multi-valued
269 */
270 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
271 {
272         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
273         if (!el || el->num_values == 0) {
274                 return NULL;
275         }
276         return &el->values[0];
277 }
278
279 int ldb_msg_find_int(const struct ldb_message *msg, 
280                      const char *attr_name,
281                      int default_value)
282 {
283         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
284         if (!v || !v->data) {
285                 return default_value;
286         }
287         return strtol((const char *)v->data, NULL, 0);
288 }
289
290 unsigned int ldb_msg_find_uint(const struct ldb_message *msg, 
291                                const char *attr_name,
292                                unsigned int default_value)
293 {
294         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
295         if (!v || !v->data) {
296                 return default_value;
297         }
298         return strtoul((const char *)v->data, NULL, 0);
299 }
300
301 int64_t ldb_msg_find_int64(const struct ldb_message *msg, 
302                            const char *attr_name,
303                            int64_t default_value)
304 {
305         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
306         if (!v || !v->data) {
307                 return default_value;
308         }
309         return strtoll((const char *)v->data, NULL, 0);
310 }
311
312 uint64_t ldb_msg_find_uint64(const struct ldb_message *msg, 
313                              const char *attr_name,
314                              uint64_t default_value)
315 {
316         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
317         if (!v || !v->data) {
318                 return default_value;
319         }
320         return strtoull((const char *)v->data, NULL, 0);
321 }
322
323 double ldb_msg_find_double(const struct ldb_message *msg, 
324                            const char *attr_name,
325                            double default_value)
326 {
327         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
328         if (!v || !v->data) {
329                 return default_value;
330         }
331         return strtod((const char *)v->data, NULL);
332 }
333
334 const char *ldb_msg_find_string(const struct ldb_message *msg, 
335                                 const char *attr_name,
336                                 const char *default_value)
337 {
338         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
339         if (!v || !v->data) {
340                 return default_value;
341         }
342         return (const char *)v->data;
343 }
344
345 /*
346   sort the elements of a message by name
347 */
348 void ldb_msg_sort_elements(struct ldb_message *msg)
349 {
350         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
351               (comparison_fn_t)ldb_msg_element_compare_name);
352 }
353
354 /*
355   copy a message, allocating new memory for all parts
356 */
357 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
358                                  const struct ldb_message *msg)
359 {
360         struct ldb_message *msg2;
361         int i, j;
362
363         msg2 = talloc(mem_ctx, struct ldb_message);
364         if (msg2 == NULL) return NULL;
365
366         msg2->elements = NULL;
367         msg2->num_elements = 0;
368         msg2->private_data = NULL;
369
370         msg2->dn = ldb_dn_copy(msg2, msg->dn);
371         if (msg2->dn == NULL) goto failed;
372
373         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg->num_elements);
374         if (msg2->elements == NULL) goto failed;
375
376         for (i=0;i<msg->num_elements;i++) {
377                 struct ldb_message_element *el1 = &msg->elements[i];
378                 struct ldb_message_element *el2 = &msg2->elements[i];
379
380                 el2->flags = el1->flags;
381                 el2->num_values = 0;
382                 el2->values = NULL;
383                 el2->name = talloc_strdup(msg2->elements, el1->name);
384                 if (el2->name == NULL) goto failed;
385                 el2->values = talloc_array(msg2->elements, struct ldb_val, el1->num_values);
386                 for (j=0;j<el1->num_values;j++) {
387                         el2->values[j] = ldb_val_dup(el2->values, &el1->values[j]);
388                         if (el2->values[j].data == NULL &&
389                             el1->values[j].length != 0) {
390                                 goto failed;
391                         }
392                         el2->num_values++;
393                 }
394
395                 msg2->num_elements++;
396         }
397
398         return msg2;
399
400 failed:
401         talloc_free(msg2);
402         return NULL;
403 }
404
405
406 /*
407   canonicalise a message, merging elements of the same name
408 */
409 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
410                                          const struct ldb_message *msg)
411 {
412         int i;
413         struct ldb_message *msg2;
414
415         msg2 = ldb_msg_copy(ldb, msg);
416         if (msg2 == NULL) return NULL;
417
418         ldb_msg_sort_elements(msg2);
419
420         for (i=1;i<msg2->num_elements;i++) {
421                 struct ldb_message_element *el1 = &msg2->elements[i-1];
422                 struct ldb_message_element *el2 = &msg2->elements[i];
423                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
424                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
425                                                        el1->num_values + el2->num_values);
426                         if (el1->values == NULL) {
427                                 return NULL;
428                         }
429                         memcpy(el1->values + el1->num_values,
430                                el2->values,
431                                sizeof(struct ldb_val) * el2->num_values);
432                         el1->num_values += el2->num_values;
433                         talloc_free(discard_const_p(char, el2->name));
434                         if (i+1<msg2->num_elements) {
435                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
436                                         (msg2->num_elements - (i+1)));
437                         }
438                         msg2->num_elements--;
439                         i--;
440                 }
441         }
442
443         return msg2;
444 }
445
446
447 /*
448   return a ldb_message representing the differences between msg1 and msg2. If you
449   then use this in a ldb_modify() call it can be used to save edits to a message
450 */
451 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
452                                  struct ldb_message *msg1,
453                                  struct ldb_message *msg2)
454 {
455         struct ldb_message *mod;
456         struct ldb_message_element *el;
457         unsigned int i;
458
459         mod = ldb_msg_new(ldb);
460
461         mod->dn = msg1->dn;
462         mod->num_elements = 0;
463         mod->elements = NULL;
464
465         msg2 = ldb_msg_canonicalize(ldb, msg2);
466         if (msg2 == NULL) {
467                 return NULL;
468         }
469         
470         /* look in msg2 to find elements that need to be added
471            or modified */
472         for (i=0;i<msg2->num_elements;i++) {
473                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
474
475                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
476                         continue;
477                 }
478
479                 if (ldb_msg_add(mod, 
480                                 &msg2->elements[i],
481                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
482                         return NULL;
483                 }
484         }
485
486         /* look in msg1 to find elements that need to be deleted */
487         for (i=0;i<msg1->num_elements;i++) {
488                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
489                 if (!el) {
490                         if (ldb_msg_add_empty(mod, 
491                                               msg1->elements[i].name,
492                                               LDB_FLAG_MOD_DELETE) != 0) {
493                                 return NULL;
494                         }
495                 }
496         }
497
498         return mod;
499 }
500
501 int ldb_msg_sanity_check(const struct ldb_message *msg)
502 {
503         int i, j;
504
505         /* basic check on DN */
506         if (msg->dn == NULL) {
507                 /* TODO: return also an error string */
508                 return LDB_ERR_INVALID_DN_SYNTAX;
509         }
510         if (msg->dn->comp_num == 0) {
511                 /* root dse has empty dn */
512                 /* TODO: return also an error string */
513                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
514         }
515
516         /* basic syntax checks */
517         for (i = 0; i < msg->num_elements; i++) {
518                 for (j = 0; j < msg->elements[i].num_values; j++) {
519                         if (msg->elements[i].values[j].length == 0) {
520                                 /* an attribute cannot be empty */
521                                 /* TODO: return also an error string */
522                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
523                         }
524                 }
525         }
526
527         return LDB_SUCCESS;
528 }
529
530
531
532
533 /*
534   copy an attribute list. This only copies the array, not the elements
535   (ie. the elements are left as the same pointers)
536 */
537 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
538 {
539         const char **ret;
540         int i;
541         for (i=0;attrs[i];i++) /* noop */ ;
542         ret = talloc_array(mem_ctx, const char *, i+1);
543         if (ret == NULL) {
544                 return NULL;
545         }
546         for (i=0;attrs[i];i++) {
547                 ret[i] = attrs[i];
548         }
549         ret[i] = attrs[i];
550         return ret;
551 }
552
553
554 /*
555   return 1 if an attribute is in a list of attributes, or 0 otherwise
556 */
557 int ldb_attr_in_list(const char * const *attrs, const char *attr)
558 {
559         int i;
560         for (i=0;attrs[i];i++) {
561                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
562                         return 1;
563                 }
564         }
565         return 0;
566 }
567
568
569 /*
570   rename the specified attribute in a search result
571 */
572 void ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
573 {
574         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
575         if (el != NULL) {
576                 el->name = replace;
577         }
578 }
579
580
581 /*
582   copy the specified attribute in a search result to a new attribute
583 */
584 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
585 {
586         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
587         if (el == NULL) {
588                 return 0;
589         }
590         if (ldb_msg_add(msg, el, 0) != 0) {
591                 return -1;
592         }
593         ldb_msg_rename_attr(msg, attr, replace);
594         return 0;
595 }
596