513a4de1f81a183864c3d91a110fac2d4d054beb
[samba.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/includes.h"
37
38 /*
39   create a new ldb_message in a given memory context (NULL for top level)
40 */
41 struct ldb_message *ldb_msg_new(void *mem_ctx)
42 {
43         return talloc_zero(mem_ctx, struct ldb_message);
44 }
45
46 /*
47   find an element in a message by attribute name
48 */
49 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
50                                                  const char *attr_name)
51 {
52         unsigned int i;
53         for (i=0;i<msg->num_elements;i++) {
54                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
55                         return &msg->elements[i];
56                 }
57         }
58         return NULL;
59 }
60
61 /*
62   see if two ldb_val structures contain exactly the same data
63   return 1 for a match, 0 for a mis-match
64 */
65 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
66 {
67         if (v1->length != v2->length) return 0;
68
69         if (v1->length == 0) return 1;
70
71         if (memcmp(v1->data, v2->data, v1->length) == 0) {
72                 return 1;
73         }
74
75         return 0;
76 }
77
78 /*
79   find a value in an element
80   assumes case sensitive comparison
81 */
82 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
83                                  struct ldb_val *val)
84 {
85         unsigned int i;
86         for (i=0;i<el->num_values;i++) {
87                 if (ldb_val_equal_exact(val, &el->values[i])) {
88                         return &el->values[i];
89                 }
90         }
91         return NULL;
92 }
93
94 /*
95   duplicate a ldb_val structure
96 */
97 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
98 {
99         struct ldb_val v2;
100         v2.length = v->length;
101         if (v->data == NULL) {
102                 v2.data = NULL;
103                 return v2;
104         }
105
106         /* the +1 is to cope with buggy C library routines like strndup
107            that look one byte beyond */
108         v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
109         if (!v2.data) {
110                 v2.length = 0;
111                 return v2;
112         }
113
114         memcpy(v2.data, v->data, v->length);
115         ((char *)v2.data)[v->length] = 0;
116         return v2;
117 }
118
119 /*
120   add an empty element to a message
121 */
122 int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags)
123 {
124         struct ldb_message_element *els;
125
126         els = talloc_realloc(msg, msg->elements, 
127                              struct ldb_message_element, msg->num_elements+1);
128         if (!els) {
129                 errno = ENOMEM;
130                 return -1;
131         }
132
133         els[msg->num_elements].values = NULL;
134         els[msg->num_elements].num_values = 0;
135         els[msg->num_elements].flags = flags;
136         els[msg->num_elements].name = talloc_strdup(els, attr_name);
137         if (!els[msg->num_elements].name) {
138                 return -1;
139         }
140
141         msg->elements = els;
142         msg->num_elements++;
143
144         return 0;
145 }
146
147 /*
148   add an empty element to a message
149 */
150 int ldb_msg_add(struct ldb_message *msg, 
151                 const struct ldb_message_element *el, 
152                 int flags)
153 {
154         if (ldb_msg_add_empty(msg, el->name, flags) != 0) {
155                 return -1;
156         }
157
158         msg->elements[msg->num_elements-1] = *el;
159         msg->elements[msg->num_elements-1].flags = flags;
160
161         return 0;
162 }
163
164 /*
165   add a value to a message
166 */
167 int ldb_msg_add_value(struct ldb_message *msg, 
168                       const char *attr_name,
169                       const struct ldb_val *val)
170 {
171         struct ldb_message_element *el;
172         struct ldb_val *vals;
173
174         el = ldb_msg_find_element(msg, attr_name);
175         if (!el) {
176                 ldb_msg_add_empty(msg, attr_name, 0);
177                 el = ldb_msg_find_element(msg, attr_name);
178         }
179         if (!el) {
180                 return -1;
181         }
182
183         vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
184         if (!vals) {
185                 errno = ENOMEM;
186                 return -1;
187         }
188         el->values = vals;
189         el->values[el->num_values] = *val;
190         el->num_values++;
191
192         return 0;
193 }
194
195
196 /*
197   add a string element to a message
198 */
199 int ldb_msg_add_string(struct ldb_message *msg, 
200                        const char *attr_name, const char *str)
201 {
202         struct ldb_val val;
203
204         val.data = discard_const_p(uint8_t, str);
205         val.length = strlen(str);
206
207         return ldb_msg_add_value(msg, attr_name, &val);
208 }
209
210 /*
211   add a printf formatted element to a message
212 */
213 int ldb_msg_add_fmt(struct ldb_message *msg, 
214                     const char *attr_name, const char *fmt, ...)
215 {
216         struct ldb_val val;
217         va_list ap;
218         char *str;
219
220         va_start(ap, fmt);
221         str = talloc_vasprintf(msg, fmt, ap);
222         va_end(ap);
223
224         if (str == NULL) return -1;
225
226         val.data   = (uint8_t *)str;
227         val.length = strlen(str);
228
229         return ldb_msg_add_value(msg, attr_name, &val);
230 }
231
232 /*
233   compare two ldb_message_element structures
234   assumes case senistive comparison
235 */
236 int ldb_msg_element_compare(struct ldb_message_element *el1, 
237                             struct ldb_message_element *el2)
238 {
239         unsigned int i;
240
241         if (el1->num_values != el2->num_values) {
242                 return el1->num_values - el2->num_values;
243         }
244
245         for (i=0;i<el1->num_values;i++) {
246                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
247                         return -1;
248                 }
249         }
250
251         return 0;
252 }
253
254 /*
255   compare two ldb_message_element structures
256   comparing by element name
257 */
258 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
259                                  struct ldb_message_element *el2)
260 {
261         return ldb_attr_cmp(el1->name, el2->name);
262 }
263
264 /*
265   convenience functions to return common types from a message
266   these return the first value if the attribute is multi-valued
267 */
268 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
269 {
270         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
271         if (!el || el->num_values == 0) {
272                 return NULL;
273         }
274         return &el->values[0];
275 }
276
277 int ldb_msg_find_int(const struct ldb_message *msg, 
278                      const char *attr_name,
279                      int default_value)
280 {
281         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
282         if (!v || !v->data) {
283                 return default_value;
284         }
285         return strtol((const char *)v->data, NULL, 0);
286 }
287
288 unsigned int ldb_msg_find_uint(const struct ldb_message *msg, 
289                                const char *attr_name,
290                                unsigned int default_value)
291 {
292         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
293         if (!v || !v->data) {
294                 return default_value;
295         }
296         return strtoul((const char *)v->data, NULL, 0);
297 }
298
299 int64_t ldb_msg_find_int64(const struct ldb_message *msg, 
300                            const char *attr_name,
301                            int64_t default_value)
302 {
303         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
304         if (!v || !v->data) {
305                 return default_value;
306         }
307         return strtoll((const char *)v->data, NULL, 0);
308 }
309
310 uint64_t ldb_msg_find_uint64(const struct ldb_message *msg, 
311                              const char *attr_name,
312                              uint64_t default_value)
313 {
314         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
315         if (!v || !v->data) {
316                 return default_value;
317         }
318         return strtoull((const char *)v->data, NULL, 0);
319 }
320
321 double ldb_msg_find_double(const struct ldb_message *msg, 
322                            const char *attr_name,
323                            double default_value)
324 {
325         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
326         if (!v || !v->data) {
327                 return default_value;
328         }
329         return strtod((const char *)v->data, NULL);
330 }
331
332 const char *ldb_msg_find_string(const struct ldb_message *msg, 
333                                 const char *attr_name,
334                                 const char *default_value)
335 {
336         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
337         if (!v || !v->data) {
338                 return default_value;
339         }
340         return (const char *)v->data;
341 }
342
343 /*
344   sort the elements of a message by name
345 */
346 void ldb_msg_sort_elements(struct ldb_message *msg)
347 {
348         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
349               (comparison_fn_t)ldb_msg_element_compare_name);
350 }
351
352 /*
353   shallow copy a message - copying only the elements array so that the caller
354   can safely add new elements without changing the message
355 */
356 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
357                                          const struct ldb_message *msg)
358 {
359         struct ldb_message *msg2;
360         int i;
361
362         msg2 = talloc(mem_ctx, struct ldb_message);
363         if (msg2 == NULL) return NULL;
364
365         *msg2 = *msg;
366         msg2->private_data = NULL;
367
368         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
369                                       msg2->num_elements);
370         if (msg2->elements == NULL) goto failed;
371
372         for (i=0;i<msg2->num_elements;i++) {
373                 msg2->elements[i] = msg->elements[i];
374         }
375
376         return msg2;
377
378 failed:
379         talloc_free(msg2);
380         return NULL;
381 }
382
383
384 /*
385   copy a message, allocating new memory for all parts
386 */
387 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
388                                  const struct ldb_message *msg)
389 {
390         struct ldb_message *msg2;
391         int i, j;
392
393         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
394         if (msg2 == NULL) return NULL;
395
396         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
397         if (msg2->dn == NULL) goto failed;
398
399         for (i=0;i<msg2->num_elements;i++) {
400                 struct ldb_message_element *el = &msg2->elements[i];
401                 struct ldb_val *values = el->values;
402                 el->name = talloc_strdup(msg2->elements, el->name);
403                 if (el->name == NULL) goto failed;
404                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
405                 for (j=0;j<el->num_values;j++) {
406                         el->values[j] = ldb_val_dup(el->values, &values[j]);
407                         if (el->values[j].data == NULL && values[j].length != 0) {
408                                 goto failed;
409                         }
410                 }
411         }
412
413         return msg2;
414
415 failed:
416         talloc_free(msg2);
417         return NULL;
418 }
419
420
421 /*
422   canonicalise a message, merging elements of the same name
423 */
424 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
425                                          const struct ldb_message *msg)
426 {
427         int i;
428         struct ldb_message *msg2;
429
430         msg2 = ldb_msg_copy(ldb, msg);
431         if (msg2 == NULL) return NULL;
432
433         ldb_msg_sort_elements(msg2);
434
435         for (i=1;i<msg2->num_elements;i++) {
436                 struct ldb_message_element *el1 = &msg2->elements[i-1];
437                 struct ldb_message_element *el2 = &msg2->elements[i];
438                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
439                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
440                                                        el1->num_values + el2->num_values);
441                         if (el1->values == NULL) {
442                                 return NULL;
443                         }
444                         memcpy(el1->values + el1->num_values,
445                                el2->values,
446                                sizeof(struct ldb_val) * el2->num_values);
447                         el1->num_values += el2->num_values;
448                         talloc_free(discard_const_p(char, el2->name));
449                         if (i+1<msg2->num_elements) {
450                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
451                                         (msg2->num_elements - (i+1)));
452                         }
453                         msg2->num_elements--;
454                         i--;
455                 }
456         }
457
458         return msg2;
459 }
460
461
462 /*
463   return a ldb_message representing the differences between msg1 and msg2. If you
464   then use this in a ldb_modify() call it can be used to save edits to a message
465 */
466 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
467                                  struct ldb_message *msg1,
468                                  struct ldb_message *msg2)
469 {
470         struct ldb_message *mod;
471         struct ldb_message_element *el;
472         unsigned int i;
473
474         mod = ldb_msg_new(ldb);
475
476         mod->dn = msg1->dn;
477         mod->num_elements = 0;
478         mod->elements = NULL;
479
480         msg2 = ldb_msg_canonicalize(ldb, msg2);
481         if (msg2 == NULL) {
482                 return NULL;
483         }
484         
485         /* look in msg2 to find elements that need to be added
486            or modified */
487         for (i=0;i<msg2->num_elements;i++) {
488                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
489
490                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
491                         continue;
492                 }
493
494                 if (ldb_msg_add(mod, 
495                                 &msg2->elements[i],
496                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
497                         return NULL;
498                 }
499         }
500
501         /* look in msg1 to find elements that need to be deleted */
502         for (i=0;i<msg1->num_elements;i++) {
503                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
504                 if (!el) {
505                         if (ldb_msg_add_empty(mod, 
506                                               msg1->elements[i].name,
507                                               LDB_FLAG_MOD_DELETE) != 0) {
508                                 return NULL;
509                         }
510                 }
511         }
512
513         return mod;
514 }
515
516 int ldb_msg_sanity_check(const struct ldb_message *msg)
517 {
518         int i, j;
519
520         /* basic check on DN */
521         if (msg->dn == NULL) {
522                 /* TODO: return also an error string */
523                 return LDB_ERR_INVALID_DN_SYNTAX;
524         }
525         if (msg->dn->comp_num == 0) {
526                 /* root dse has empty dn */
527                 /* TODO: return also an error string */
528                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
529         }
530
531         /* basic syntax checks */
532         for (i = 0; i < msg->num_elements; i++) {
533                 for (j = 0; j < msg->elements[i].num_values; j++) {
534                         if (msg->elements[i].values[j].length == 0) {
535                                 /* an attribute cannot be empty */
536                                 /* TODO: return also an error string */
537                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
538                         }
539                 }
540         }
541
542         return LDB_SUCCESS;
543 }
544
545
546
547
548 /*
549   copy an attribute list. This only copies the array, not the elements
550   (ie. the elements are left as the same pointers)
551 */
552 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
553 {
554         const char **ret;
555         int i;
556         for (i=0;attrs[i];i++) /* noop */ ;
557         ret = talloc_array(mem_ctx, const char *, i+1);
558         if (ret == NULL) {
559                 return NULL;
560         }
561         for (i=0;attrs[i];i++) {
562                 ret[i] = attrs[i];
563         }
564         ret[i] = attrs[i];
565         return ret;
566 }
567
568
569 /*
570   return 1 if an attribute is in a list of attributes, or 0 otherwise
571 */
572 int ldb_attr_in_list(const char * const *attrs, const char *attr)
573 {
574         int i;
575         for (i=0;attrs[i];i++) {
576                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
577                         return 1;
578                 }
579         }
580         return 0;
581 }
582
583
584 /*
585   rename the specified attribute in a search result
586 */
587 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
588 {
589         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
590         if (el == NULL) {
591                 return 0;
592         }
593         el->name = talloc_strdup(msg->elements, replace);
594         if (el->name == NULL) {
595                 return -1;
596         }
597         return 0;
598 }
599
600
601 /*
602   copy the specified attribute in a search result to a new attribute
603 */
604 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
605 {
606         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
607         if (el == NULL) {
608                 return 0;
609         }
610         if (ldb_msg_add(msg, el, 0) != 0) {
611                 return -1;
612         }
613         return ldb_msg_rename_attr(msg, attr, replace);
614 }
615
616
617 /*
618   remove the specified attribute in a search result
619 */
620 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
621 {
622         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
623         if (el) {
624                 int n = (el - msg->elements);
625                 if (n != msg->num_elements-1) {
626                         memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
627                 }
628                 msg->num_elements--;
629         }
630 }
631
632 /*
633   return a LDAP formatted time string
634 */
635 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
636 {
637         struct tm *tm = gmtime(&t);
638
639         if (!tm) {
640                 return NULL;
641         }
642
643         /* formatted like: 20040408072012.0Z */
644         return talloc_asprintf(mem_ctx, 
645                                "%04u%02u%02u%02u%02u%02u.0Z",
646                                tm->tm_year+1900, tm->tm_mon+1,
647                                tm->tm_mday, tm->tm_hour, tm->tm_min,
648                                tm->tm_sec);
649 }
650
651
652 /*
653   convert a LDAP time string to a time_t. Return 0 if unable to convert
654 */
655 time_t ldb_string_to_time(const char *s)
656 {
657         struct tm tm;
658         
659         if (s == NULL) return 0;
660         
661         memset(&tm, 0, sizeof(tm));
662         if (sscanf(s, "%04u%02u%02u%02u%02u%02u", 
663                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
664                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
665                 return 0;
666         }
667         tm.tm_year -= 1900;
668         tm.tm_mon -= 1;
669         
670         return timegm(&tm);
671 }
672
673
674 /*
675   dump a set of results to a file. Useful from within gdb
676 */
677 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
678 {
679         int i;
680
681         for (i = 0; i < result->count; i++) {
682                 struct ldb_ldif ldif;
683                 fprintf(f, "# record %d\n", i+1);
684                 ldif.changetype = LDB_CHANGETYPE_NONE;
685                 ldif.msg = result->msgs[i];
686                 ldb_ldif_write_file(ldb, f, &ldif);
687         }
688 }
689