ldb: added ldb_val_string_cmp()
[amitay/samba.git] / 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 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 /*
25  *  Name: ldb
26  *
27  *  Component: ldb message component utility functions
28  *
29  *  Description: functions for manipulating ldb_message structures
30  *
31  *  Author: Andrew Tridgell
32  */
33
34 #include "ldb_private.h"
35
36 /*
37   create a new ldb_message in a given memory context (NULL for top level)
38 */
39 struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
40 {
41         return talloc_zero(mem_ctx, struct ldb_message);
42 }
43
44 /*
45   find an element in a message by attribute name
46 */
47 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
48                                                  const char *attr_name)
49 {
50         unsigned int i;
51         for (i=0;i<msg->num_elements;i++) {
52                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
53                         return &msg->elements[i];
54                 }
55         }
56         return NULL;
57 }
58
59 /*
60   see if two ldb_val structures contain exactly the same data
61   return 1 for a match, 0 for a mis-match
62 */
63 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
64 {
65         if (v1->length != v2->length) return 0;
66         if (v1->data == v2->data) return 1;
67         if (v1->length == 0) return 1;
68
69         if (memcmp(v1->data, v2->data, v1->length) == 0) {
70                 return 1;
71         }
72
73         return 0;
74 }
75
76 /*
77   find a value in an element
78   assumes case sensitive comparison
79 */
80 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
81                                  struct ldb_val *val)
82 {
83         unsigned int i;
84         for (i=0;i<el->num_values;i++) {
85                 if (ldb_val_equal_exact(val, &el->values[i])) {
86                         return &el->values[i];
87                 }
88         }
89         return NULL;
90 }
91
92 /*
93   duplicate a ldb_val structure
94 */
95 struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
96 {
97         struct ldb_val v2;
98         v2.length = v->length;
99         if (v->data == NULL) {
100                 v2.data = NULL;
101                 return v2;
102         }
103
104         /* the +1 is to cope with buggy C library routines like strndup
105            that look one byte beyond */
106         v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
107         if (!v2.data) {
108                 v2.length = 0;
109                 return v2;
110         }
111
112         memcpy(v2.data, v->data, v->length);
113         ((char *)v2.data)[v->length] = 0;
114         return v2;
115 }
116
117 /**
118  * Adds new empty element to msg->elements
119  */
120 static int _ldb_msg_add_el(struct ldb_message *msg,
121                            struct ldb_message_element **return_el)
122 {
123         struct ldb_message_element *els;
124
125         /*
126          * TODO: Find out a way to assert on input parameters.
127          * msg and return_el must be valid
128          */
129
130         els = talloc_realloc(msg, msg->elements,
131                              struct ldb_message_element, msg->num_elements + 1);
132         if (!els) {
133                 return LDB_ERR_OPERATIONS_ERROR;
134         }
135
136         ZERO_STRUCT(els[msg->num_elements]);
137
138         msg->elements = els;
139         msg->num_elements++;
140
141         *return_el = &els[msg->num_elements-1];
142
143         return LDB_SUCCESS;
144 }
145
146 /**
147  * Add an empty element with a given name to a message
148  */
149 int ldb_msg_add_empty(struct ldb_message *msg,
150                       const char *attr_name,
151                       int flags,
152                       struct ldb_message_element **return_el)
153 {
154         int ret;
155         struct ldb_message_element *el;
156
157         ret = _ldb_msg_add_el(msg, &el);
158         if (ret != LDB_SUCCESS) {
159                 return ret;
160         }
161
162         /* initialize newly added element */
163         el->flags = flags;
164         el->name = talloc_strdup(msg->elements, attr_name);
165         if (!el->name) {
166                 return LDB_ERR_OPERATIONS_ERROR;
167         }
168
169         if (return_el) {
170                 *return_el = el;
171         }
172
173         return LDB_SUCCESS;
174 }
175
176 /**
177  * Adds an element to a message.
178  *
179  * NOTE: Ownership of ldb_message_element fields
180  *       is NOT transferred. Thus, if *el pointer
181  *       is invalidated for some reason, this will
182  *       corrupt *msg contents also
183  */
184 int ldb_msg_add(struct ldb_message *msg, 
185                 const struct ldb_message_element *el, 
186                 int flags)
187 {
188         int ret;
189         struct ldb_message_element *el_new;
190         /* We have to copy this, just in case *el is a pointer into
191          * what ldb_msg_add_empty() is about to realloc() */
192         struct ldb_message_element el_copy = *el;
193
194         ret = _ldb_msg_add_el(msg, &el_new);
195         if (ret != LDB_SUCCESS) {
196                 return ret;
197         }
198
199         el_new->flags      = flags;
200         el_new->name       = el_copy.name;
201         el_new->num_values = el_copy.num_values;
202         el_new->values     = el_copy.values;
203
204         return LDB_SUCCESS;
205 }
206
207 /*
208   add a value to a message
209 */
210 int ldb_msg_add_value(struct ldb_message *msg, 
211                       const char *attr_name,
212                       const struct ldb_val *val,
213                       struct ldb_message_element **return_el)
214 {
215         struct ldb_message_element *el;
216         struct ldb_val *vals;
217         int ret;
218
219         el = ldb_msg_find_element(msg, attr_name);
220         if (!el) {
221                 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
222                 if (ret != LDB_SUCCESS) {
223                         return ret;
224                 }
225         }
226
227         vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
228                               el->num_values+1);
229         if (!vals) {
230                 return LDB_ERR_OPERATIONS_ERROR;
231         }
232         el->values = vals;
233         el->values[el->num_values] = *val;
234         el->num_values++;
235
236         if (return_el) {
237                 *return_el = el;
238         }
239
240         return LDB_SUCCESS;
241 }
242
243
244 /*
245   add a value to a message, stealing it into the 'right' place
246 */
247 int ldb_msg_add_steal_value(struct ldb_message *msg, 
248                             const char *attr_name,
249                             struct ldb_val *val)
250 {
251         int ret;
252         struct ldb_message_element *el;
253
254         ret = ldb_msg_add_value(msg, attr_name, val, &el);
255         if (ret == LDB_SUCCESS) {
256                 talloc_steal(el->values, val->data);
257         }
258         return ret;
259 }
260
261
262 /*
263   add a string element to a message
264 */
265 int ldb_msg_add_string(struct ldb_message *msg, 
266                        const char *attr_name, const char *str)
267 {
268         struct ldb_val val;
269
270         val.data = discard_const_p(uint8_t, str);
271         val.length = strlen(str);
272
273         if (val.length == 0) {
274                 /* allow empty strings as non-existent attributes */
275                 return LDB_SUCCESS;
276         }
277
278         return ldb_msg_add_value(msg, attr_name, &val, NULL);
279 }
280
281 /*
282   add a string element to a message, stealing it into the 'right' place
283 */
284 int ldb_msg_add_steal_string(struct ldb_message *msg, 
285                              const char *attr_name, char *str)
286 {
287         struct ldb_val val;
288
289         val.data = (uint8_t *)str;
290         val.length = strlen(str);
291
292         if (val.length == 0) {
293                 /* allow empty strings as non-existent attributes */
294                 return LDB_SUCCESS;
295         }
296
297         return ldb_msg_add_steal_value(msg, attr_name, &val);
298 }
299
300 /*
301   add a DN element to a message
302   WARNING: this uses the linearized string from the dn, and does not
303   copy the string.
304 */
305 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
306                               struct ldb_dn *dn)
307 {
308         char *str = ldb_dn_alloc_linearized(msg, dn);
309
310         if (str == NULL) {
311                 /* we don't want to have unknown DNs added */
312                 return LDB_ERR_OPERATIONS_ERROR;
313         }
314
315         return ldb_msg_add_steal_string(msg, attr_name, str);
316 }
317
318 /*
319   add a printf formatted element to a message
320 */
321 int ldb_msg_add_fmt(struct ldb_message *msg, 
322                     const char *attr_name, const char *fmt, ...)
323 {
324         struct ldb_val val;
325         va_list ap;
326         char *str;
327
328         va_start(ap, fmt);
329         str = talloc_vasprintf(msg, fmt, ap);
330         va_end(ap);
331
332         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
333
334         val.data   = (uint8_t *)str;
335         val.length = strlen(str);
336
337         return ldb_msg_add_steal_value(msg, attr_name, &val);
338 }
339
340 /*
341   compare two ldb_message_element structures
342   assumes case sensitive comparison
343 */
344 int ldb_msg_element_compare(struct ldb_message_element *el1, 
345                             struct ldb_message_element *el2)
346 {
347         unsigned int i;
348
349         if (el1->num_values != el2->num_values) {
350                 return el1->num_values - el2->num_values;
351         }
352
353         for (i=0;i<el1->num_values;i++) {
354                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
355                         return -1;
356                 }
357         }
358
359         return 0;
360 }
361
362 /*
363   compare two ldb_message_element structures
364   comparing by element name
365 */
366 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
367                                  struct ldb_message_element *el2)
368 {
369         return ldb_attr_cmp(el1->name, el2->name);
370 }
371
372 /*
373   convenience functions to return common types from a message
374   these return the first value if the attribute is multi-valued
375 */
376 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, 
377                                            const char *attr_name)
378 {
379         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
380         if (!el || el->num_values == 0) {
381                 return NULL;
382         }
383         return &el->values[0];
384 }
385
386 int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
387                              const char *attr_name,
388                              int default_value)
389 {
390         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
391         char buf[sizeof("-2147483648")];
392         char *end = NULL;
393         int ret;
394
395         if (!v || !v->data) {
396                 return default_value;
397         }
398
399         ZERO_STRUCT(buf);
400         if (v->length >= sizeof(buf)) {
401                 return default_value;
402         }
403
404         memcpy(buf, v->data, v->length);
405         errno = 0;
406         ret = (int) strtoll(buf, &end, 10);
407         if (errno != 0) {
408                 return default_value;
409         }
410         if (end && end[0] != '\0') {
411                 return default_value;
412         }
413         return ret;
414 }
415
416 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
417                                        const char *attr_name,
418                                        unsigned int default_value)
419 {
420         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
421         char buf[sizeof("-2147483648")];
422         char *end = NULL;
423         unsigned int ret;
424
425         if (!v || !v->data) {
426                 return default_value;
427         }
428
429         ZERO_STRUCT(buf);
430         if (v->length >= sizeof(buf)) {
431                 return default_value;
432         }
433
434         memcpy(buf, v->data, v->length);
435         errno = 0;
436         ret = (unsigned int) strtoll(buf, &end, 10);
437         if (errno != 0) {
438                 errno = 0;
439                 ret = (unsigned int) strtoull(buf, &end, 10);
440                 if (errno != 0) {
441                         return default_value;
442                 }
443         }
444         if (end && end[0] != '\0') {
445                 return default_value;
446         }
447         return ret;
448 }
449
450 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
451                                    const char *attr_name,
452                                    int64_t default_value)
453 {
454         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
455         char buf[sizeof("-9223372036854775808")];
456         char *end = NULL;
457         int64_t ret;
458
459         if (!v || !v->data) {
460                 return default_value;
461         }
462
463         ZERO_STRUCT(buf);
464         if (v->length >= sizeof(buf)) {
465                 return default_value;
466         }
467
468         memcpy(buf, v->data, v->length);
469         errno = 0;
470         ret = (int64_t) strtoll(buf, &end, 10);
471         if (errno != 0) {
472                 return default_value;
473         }
474         if (end && end[0] != '\0') {
475                 return default_value;
476         }
477         return ret;
478 }
479
480 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
481                                      const char *attr_name,
482                                      uint64_t default_value)
483 {
484         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
485         char buf[sizeof("-9223372036854775808")];
486         char *end = NULL;
487         uint64_t ret;
488
489         if (!v || !v->data) {
490                 return default_value;
491         }
492
493         ZERO_STRUCT(buf);
494         if (v->length >= sizeof(buf)) {
495                 return default_value;
496         }
497
498         memcpy(buf, v->data, v->length);
499         errno = 0;
500         ret = (uint64_t) strtoll(buf, &end, 10);
501         if (errno != 0) {
502                 errno = 0;
503                 ret = (uint64_t) strtoull(buf, &end, 10);
504                 if (errno != 0) {
505                         return default_value;
506                 }
507         }
508         if (end && end[0] != '\0') {
509                 return default_value;
510         }
511         return ret;
512 }
513
514 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
515                                    const char *attr_name,
516                                    double default_value)
517 {
518         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
519         char *buf;
520         char *end = NULL;
521         double ret;
522
523         if (!v || !v->data) {
524                 return default_value;
525         }
526         buf = talloc_strndup(msg, (const char *)v->data, v->length);
527         if (buf == NULL) {
528                 return default_value;
529         }
530
531         errno = 0;
532         ret = strtod(buf, &end);
533         talloc_free(buf);
534         if (errno != 0) {
535                 return default_value;
536         }
537         if (end && end[0] != '\0') {
538                 return default_value;
539         }
540         return ret;
541 }
542
543 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
544                               const char *attr_name,
545                               int default_value)
546 {
547         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
548         if (!v || !v->data) {
549                 return default_value;
550         }
551         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
552                 return 0;
553         }
554         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
555                 return 1;
556         }
557         return default_value;
558 }
559
560 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
561                                         const char *attr_name,
562                                         const char *default_value)
563 {
564         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
565         if (!v || !v->data) {
566                 return default_value;
567         }
568         if (v->data[v->length] != '\0') {
569                 return default_value;
570         }
571         return (const char *)v->data;
572 }
573
574 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
575                                        TALLOC_CTX *mem_ctx,
576                                        const struct ldb_message *msg,
577                                        const char *attr_name)
578 {
579         struct ldb_dn *res_dn;
580         const struct ldb_val *v;
581
582         v = ldb_msg_find_ldb_val(msg, attr_name);
583         if (!v || !v->data) {
584                 return NULL;
585         }
586         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
587         if ( ! ldb_dn_validate(res_dn)) {
588                 talloc_free(res_dn);
589                 return NULL;
590         }
591         return res_dn;
592 }
593
594 /*
595   sort the elements of a message by name
596 */
597 void ldb_msg_sort_elements(struct ldb_message *msg)
598 {
599         TYPESAFE_QSORT(msg->elements, msg->num_elements,
600                        ldb_msg_element_compare_name);
601 }
602
603 /*
604   shallow copy a message - copying only the elements array so that the caller
605   can safely add new elements without changing the message
606 */
607 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
608                                          const struct ldb_message *msg)
609 {
610         struct ldb_message *msg2;
611         unsigned int i;
612
613         msg2 = talloc(mem_ctx, struct ldb_message);
614         if (msg2 == NULL) return NULL;
615
616         *msg2 = *msg;
617
618         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
619                                       msg2->num_elements);
620         if (msg2->elements == NULL) goto failed;
621
622         for (i=0;i<msg2->num_elements;i++) {
623                 msg2->elements[i] = msg->elements[i];
624         }
625
626         return msg2;
627
628 failed:
629         talloc_free(msg2);
630         return NULL;
631 }
632
633
634 /*
635   copy a message, allocating new memory for all parts
636 */
637 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
638                                  const struct ldb_message *msg)
639 {
640         struct ldb_message *msg2;
641         unsigned int i, j;
642
643         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
644         if (msg2 == NULL) return NULL;
645
646         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
647         if (msg2->dn == NULL) goto failed;
648
649         for (i=0;i<msg2->num_elements;i++) {
650                 struct ldb_message_element *el = &msg2->elements[i];
651                 struct ldb_val *values = el->values;
652                 el->name = talloc_strdup(msg2->elements, el->name);
653                 if (el->name == NULL) goto failed;
654                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
655                 for (j=0;j<el->num_values;j++) {
656                         el->values[j] = ldb_val_dup(el->values, &values[j]);
657                         if (el->values[j].data == NULL && values[j].length != 0) {
658                                 goto failed;
659                         }
660                 }
661         }
662
663         return msg2;
664
665 failed:
666         talloc_free(msg2);
667         return NULL;
668 }
669
670
671 /**
672  * Canonicalize a message, merging elements of the same name
673  */
674 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
675                                          const struct ldb_message *msg)
676 {
677         int ret;
678         struct ldb_message *msg2;
679
680         /*
681          * Preserve previous behavior and allocate
682          * *msg2 into *ldb context
683          */
684         ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
685         if (ret != LDB_SUCCESS) {
686                 return NULL;
687         }
688
689         return msg2;
690 }
691
692 /**
693  * Canonicalize a message, merging elements of the same name
694  */
695 int ldb_msg_normalize(struct ldb_context *ldb,
696                       TALLOC_CTX *mem_ctx,
697                       const struct ldb_message *msg,
698                       struct ldb_message **_msg_out)
699 {
700         unsigned int i;
701         struct ldb_message *msg2;
702
703         msg2 = ldb_msg_copy(mem_ctx, msg);
704         if (msg2 == NULL) {
705                 return LDB_ERR_OPERATIONS_ERROR;
706         }
707
708         ldb_msg_sort_elements(msg2);
709
710         for (i=1; i < msg2->num_elements; i++) {
711                 struct ldb_message_element *el1 = &msg2->elements[i-1];
712                 struct ldb_message_element *el2 = &msg2->elements[i];
713
714                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
715                         el1->values = talloc_realloc(msg2->elements,
716                                                      el1->values, struct ldb_val,
717                                                      el1->num_values + el2->num_values);
718                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
719                                 talloc_free(msg2);
720                                 return LDB_ERR_OPERATIONS_ERROR;
721                         }
722                         memcpy(el1->values + el1->num_values,
723                                el2->values,
724                                sizeof(struct ldb_val) * el2->num_values);
725                         el1->num_values += el2->num_values;
726                         talloc_free(discard_const_p(char, el2->name));
727                         if ((i+1) < msg2->num_elements) {
728                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
729                                         (msg2->num_elements - (i+1)));
730                         }
731                         msg2->num_elements--;
732                         i--;
733                 }
734         }
735
736         *_msg_out = msg2;
737         return LDB_SUCCESS;
738 }
739
740
741 /**
742  * return a ldb_message representing the differences between msg1 and msg2.
743  * If you then use this in a ldb_modify() call,
744  * it can be used to save edits to a message
745  */
746 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
747                                  struct ldb_message *msg1,
748                                  struct ldb_message *msg2)
749 {
750         int ldb_ret;
751         struct ldb_message *mod;
752
753         ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
754         if (ldb_ret != LDB_SUCCESS) {
755                 return NULL;
756         }
757
758         return mod;
759 }
760
761 /**
762  * return a ldb_message representing the differences between msg1 and msg2.
763  * If you then use this in a ldb_modify() call it can be used to save edits to a message
764  *
765  * Result message is constructed as follows:
766  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
767  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
768  *                          Value for msg2 element is used
769  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
770  *
771  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
772  */
773 int ldb_msg_difference(struct ldb_context *ldb,
774                        TALLOC_CTX *mem_ctx,
775                        struct ldb_message *msg1,
776                        struct ldb_message *msg2,
777                        struct ldb_message **_msg_out)
778 {
779         int ldb_res;
780         unsigned int i;
781         struct ldb_message *mod;
782         struct ldb_message_element *el;
783         TALLOC_CTX *temp_ctx;
784
785         temp_ctx = talloc_new(mem_ctx);
786         if (!temp_ctx) {
787                 return LDB_ERR_OPERATIONS_ERROR;
788         }
789
790         mod = ldb_msg_new(temp_ctx);
791         if (mod == NULL) {
792                 goto failed;
793         }
794
795         mod->dn = msg1->dn;
796         mod->num_elements = 0;
797         mod->elements = NULL;
798
799         /*
800          * Canonicalize *msg2 so we have no repeated elements
801          * Resulting message is allocated in *mod's mem context,
802          * as we are going to move some elements from *msg2 to
803          * *mod object later
804          */
805         ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
806         if (ldb_res != LDB_SUCCESS) {
807                 goto failed;
808         }
809
810         /* look in msg2 to find elements that need to be added or modified */
811         for (i=0;i<msg2->num_elements;i++) {
812                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
813
814                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
815                         continue;
816                 }
817
818                 ldb_res = ldb_msg_add(mod,
819                                       &msg2->elements[i],
820                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
821                 if (ldb_res != LDB_SUCCESS) {
822                         goto failed;
823                 }
824         }
825
826         /* look in msg1 to find elements that need to be deleted */
827         for (i=0;i<msg1->num_elements;i++) {
828                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
829                 if (el == NULL) {
830                         ldb_res = ldb_msg_add_empty(mod,
831                                                     msg1->elements[i].name,
832                                                     LDB_FLAG_MOD_DELETE, NULL);
833                         if (ldb_res != LDB_SUCCESS) {
834                                 goto failed;
835                         }
836                 }
837         }
838
839         /* steal resulting message into supplied context */
840         talloc_steal(mem_ctx, mod);
841         *_msg_out = mod;
842
843         talloc_free(temp_ctx);
844         return LDB_SUCCESS;
845
846 failed:
847         talloc_free(temp_ctx);
848         return LDB_ERR_OPERATIONS_ERROR;
849 }
850
851
852 int ldb_msg_sanity_check(struct ldb_context *ldb, 
853                          const struct ldb_message *msg)
854 {
855         unsigned int i, j;
856
857         /* basic check on DN */
858         if (msg->dn == NULL) {
859                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
860                 return LDB_ERR_INVALID_DN_SYNTAX;
861         }
862
863         /* basic syntax checks */
864         for (i = 0; i < msg->num_elements; i++) {
865                 for (j = 0; j < msg->elements[i].num_values; j++) {
866                         if (msg->elements[i].values[j].length == 0) {
867                                 /* an attribute cannot be empty */
868                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
869                                                             msg->elements[i].name, 
870                                                             ldb_dn_get_linearized(msg->dn));
871                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
872                         }
873                 }
874         }
875
876         return LDB_SUCCESS;
877 }
878
879
880
881
882 /*
883   copy an attribute list. This only copies the array, not the elements
884   (ie. the elements are left as the same pointers)
885 */
886 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
887 {
888         const char **ret;
889         unsigned int i;
890
891         for (i=0;attrs && attrs[i];i++) /* noop */ ;
892         ret = talloc_array(mem_ctx, const char *, i+1);
893         if (ret == NULL) {
894                 return NULL;
895         }
896         for (i=0;attrs && attrs[i];i++) {
897                 ret[i] = attrs[i];
898         }
899         ret[i] = attrs[i];
900         return ret;
901 }
902
903
904 /*
905   copy an attribute list. This only copies the array, not the elements
906   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
907 */
908 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
909 {
910         const char **ret;
911         unsigned int i;
912         bool found = false;
913
914         for (i=0;attrs && attrs[i];i++) {
915                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
916                         found = true;
917                 }
918         }
919         if (found) {
920                 return ldb_attr_list_copy(mem_ctx, attrs);
921         }
922         ret = talloc_array(mem_ctx, const char *, i+2);
923         if (ret == NULL) {
924                 return NULL;
925         }
926         for (i=0;attrs && attrs[i];i++) {
927                 ret[i] = attrs[i];
928         }
929         ret[i] = new_attr;
930         ret[i+1] = NULL;
931         return ret;
932 }
933
934
935 /*
936   return 1 if an attribute is in a list of attributes, or 0 otherwise
937 */
938 int ldb_attr_in_list(const char * const *attrs, const char *attr)
939 {
940         unsigned int i;
941         for (i=0;attrs && attrs[i];i++) {
942                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
943                         return 1;
944                 }
945         }
946         return 0;
947 }
948
949
950 /*
951   rename the specified attribute in a search result
952 */
953 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
954 {
955         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
956         if (el == NULL) {
957                 return LDB_SUCCESS;
958         }
959         el->name = talloc_strdup(msg->elements, replace);
960         if (el->name == NULL) {
961                 return LDB_ERR_OPERATIONS_ERROR;
962         }
963         return LDB_SUCCESS;
964 }
965
966
967 /*
968   copy the specified attribute in a search result to a new attribute
969 */
970 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
971 {
972         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
973         int ret;
974
975         if (el == NULL) {
976                 return LDB_SUCCESS;
977         }
978         ret = ldb_msg_add(msg, el, 0);
979         if (ret != LDB_SUCCESS) {
980                 return ret;
981         }
982         return ldb_msg_rename_attr(msg, attr, replace);
983 }
984
985 /*
986   remove the specified element in a search result
987 */
988 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
989 {
990         ptrdiff_t n = (el - msg->elements);
991         if (n >= msg->num_elements) {
992                 /* should we abort() here? */
993                 return;
994         }
995         if (n != msg->num_elements-1) {
996                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
997         }
998         msg->num_elements--;
999 }
1000
1001
1002 /*
1003   remove the specified attribute in a search result
1004 */
1005 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1006 {
1007         struct ldb_message_element *el;
1008
1009         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1010                 ldb_msg_remove_element(msg, el);
1011         }
1012 }
1013
1014 /*
1015   return a LDAP formatted GeneralizedTime string
1016 */
1017 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1018 {
1019         struct tm *tm = gmtime(&t);
1020         char *ts;
1021         int r;
1022
1023         if (!tm) {
1024                 return NULL;
1025         }
1026
1027         /* we now excatly how long this string will be */
1028         ts = talloc_array(mem_ctx, char, 18);
1029
1030         /* formatted like: 20040408072012.0Z */
1031         r = snprintf(ts, 18,
1032                         "%04u%02u%02u%02u%02u%02u.0Z",
1033                         tm->tm_year+1900, tm->tm_mon+1,
1034                         tm->tm_mday, tm->tm_hour, tm->tm_min,
1035                         tm->tm_sec);
1036
1037         if (r != 17) {
1038                 talloc_free(ts);
1039                 return NULL;
1040         }
1041
1042         return ts;
1043 }
1044
1045 /*
1046   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1047 */
1048 time_t ldb_string_to_time(const char *s)
1049 {
1050         struct tm tm;
1051         
1052         if (s == NULL) return 0;
1053         
1054         memset(&tm, 0, sizeof(tm));
1055         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1056                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1057                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1058                 return 0;
1059         }
1060         tm.tm_year -= 1900;
1061         tm.tm_mon -= 1;
1062         
1063         return timegm(&tm);
1064 }
1065
1066 /*
1067   convert a LDAP GeneralizedTime string in ldb_val format to a
1068   time_t.
1069 */
1070 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1071 {
1072         struct tm tm;
1073
1074         if (v == NULL || !v->data || v->length < 17) {
1075                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1076         }
1077
1078         memset(&tm, 0, sizeof(tm));
1079
1080         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1081                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1082                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1083                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1084         }
1085         tm.tm_year -= 1900;
1086         tm.tm_mon -= 1;
1087
1088         *t = timegm(&tm);
1089
1090         return LDB_SUCCESS;
1091 }
1092
1093 /*
1094   return a LDAP formatted UTCTime string
1095 */
1096 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1097 {
1098         struct tm *tm = gmtime(&t);
1099         char *ts;
1100         int r;
1101
1102         if (!tm) {
1103                 return NULL;
1104         }
1105
1106         /* we now excatly how long this string will be */
1107         ts = talloc_array(mem_ctx, char, 14);
1108
1109         /* formatted like: 20040408072012.0Z => 040408072012Z */
1110         r = snprintf(ts, 14,
1111                         "%02u%02u%02u%02u%02u%02uZ",
1112                         (tm->tm_year+1900)%100, tm->tm_mon+1,
1113                         tm->tm_mday, tm->tm_hour, tm->tm_min,
1114                         tm->tm_sec);
1115
1116         if (r != 13) {
1117                 talloc_free(ts);
1118                 return NULL;
1119         }
1120
1121         return ts;
1122 }
1123
1124 /*
1125   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1126 */
1127 time_t ldb_string_utc_to_time(const char *s)
1128 {
1129         struct tm tm;
1130         
1131         if (s == NULL) return 0;
1132         
1133         memset(&tm, 0, sizeof(tm));
1134         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1135                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1136                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1137                 return 0;
1138         }
1139         if (tm.tm_year < 50) {
1140                 tm.tm_year += 100;
1141         }
1142         tm.tm_mon -= 1;
1143         
1144         return timegm(&tm);
1145 }
1146
1147
1148 /*
1149   dump a set of results to a file. Useful from within gdb
1150 */
1151 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1152 {
1153         unsigned int i;
1154
1155         for (i = 0; i < result->count; i++) {
1156                 struct ldb_ldif ldif;
1157                 fprintf(f, "# record %d\n", i+1);
1158                 ldif.changetype = LDB_CHANGETYPE_NONE;
1159                 ldif.msg = result->msgs[i];
1160                 ldb_ldif_write_file(ldb, f, &ldif);
1161         }
1162 }
1163
1164 /*
1165   checks for a string attribute. Returns "1" on match and otherwise "0".
1166 */
1167 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1168                                    const char *name, const char *value)
1169 {
1170         struct ldb_message_element *el;
1171         struct ldb_val val;
1172         
1173         el = ldb_msg_find_element(msg, name);
1174         if (el == NULL) {
1175                 return 0;
1176         }
1177
1178         val.data = discard_const_p(uint8_t, value);
1179         val.length = strlen(value);
1180
1181         if (ldb_msg_find_val(el, &val)) {
1182                 return 1;
1183         }
1184
1185         return 0;
1186 }
1187
1188
1189 /*
1190   compare a ldb_val to a string
1191 */
1192 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1193 {
1194         size_t len = strlen(str);
1195         if (len != v->length) {
1196                 return len - v->length;
1197         }
1198         return strncmp((const char *)v->data, str, len);
1199 }