s4-ldb: Separate function to add empty element into ldb_msg
[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 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(void *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(void *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         /* TODO: Find out a way to assert
126          * on input parameters.
127          * msg and return_el must be valid */
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 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 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         struct ldb_message_element *els;
155
156         els = talloc_realloc(msg, msg->elements, 
157                              struct ldb_message_element, msg->num_elements+1);
158         if (!els) {
159                 errno = ENOMEM;
160                 return LDB_ERR_OPERATIONS_ERROR;
161         }
162
163         els[msg->num_elements].values = NULL;
164         els[msg->num_elements].num_values = 0;
165         els[msg->num_elements].flags = flags;
166         els[msg->num_elements].name = talloc_strdup(els, attr_name);
167         if (!els[msg->num_elements].name) {
168                 errno = ENOMEM;
169                 return LDB_ERR_OPERATIONS_ERROR;
170         }
171
172         msg->elements = els;
173         msg->num_elements++;
174
175         if (return_el) {
176                 *return_el = &els[msg->num_elements-1];
177         }
178
179         return LDB_SUCCESS;
180 }
181
182 /**
183  * Adds an element to a message.
184  *
185  * NOTE: Ownership of ldb_message_element fields
186  *       is NOT transferred. Thus, if el pointer
187  *       is invalidated for some reason, this will
188  *       corrupt msg contents also
189  */
190 int ldb_msg_add(struct ldb_message *msg, 
191                 const struct ldb_message_element *el, 
192                 int flags)
193 {
194         /* We have to copy this, just in case *el is a pointer into
195          * what ldb_msg_add_empty() is about to realloc() */
196         struct ldb_message_element el_copy = *el;
197         if (ldb_msg_add_empty(msg, el->name, flags, NULL) != LDB_SUCCESS) {
198                 return LDB_ERR_OPERATIONS_ERROR;
199         }
200
201         msg->elements[msg->num_elements-1] = el_copy;
202         msg->elements[msg->num_elements-1].flags = flags;
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, el->values, struct ldb_val, el->num_values+1);
228         if (!vals) {
229                 errno = ENOMEM;
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         return ldb_msg_add_steal_string(msg, attr_name,
309                                         ldb_dn_alloc_linearized(msg, dn));
310 }
311
312 /*
313   add a printf formatted element to a message
314 */
315 int ldb_msg_add_fmt(struct ldb_message *msg, 
316                     const char *attr_name, const char *fmt, ...)
317 {
318         struct ldb_val val;
319         va_list ap;
320         char *str;
321
322         va_start(ap, fmt);
323         str = talloc_vasprintf(msg, fmt, ap);
324         va_end(ap);
325
326         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
327
328         val.data   = (uint8_t *)str;
329         val.length = strlen(str);
330
331         return ldb_msg_add_steal_value(msg, attr_name, &val);
332 }
333
334 /*
335   compare two ldb_message_element structures
336   assumes case sensitive comparison
337 */
338 int ldb_msg_element_compare(struct ldb_message_element *el1, 
339                             struct ldb_message_element *el2)
340 {
341         unsigned int i;
342
343         if (el1->num_values != el2->num_values) {
344                 return el1->num_values - el2->num_values;
345         }
346
347         for (i=0;i<el1->num_values;i++) {
348                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
349                         return -1;
350                 }
351         }
352
353         return 0;
354 }
355
356 /*
357   compare two ldb_message_element structures
358   comparing by element name
359 */
360 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
361                                  struct ldb_message_element *el2)
362 {
363         return ldb_attr_cmp(el1->name, el2->name);
364 }
365
366 /*
367   convenience functions to return common types from a message
368   these return the first value if the attribute is multi-valued
369 */
370 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, 
371                                            const char *attr_name)
372 {
373         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
374         if (!el || el->num_values == 0) {
375                 return NULL;
376         }
377         return &el->values[0];
378 }
379
380 int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
381                              const char *attr_name,
382                              int default_value)
383 {
384         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
385         if (!v || !v->data) {
386                 return default_value;
387         }
388         return strtol((const char *)v->data, NULL, 0);
389 }
390
391 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
392                                        const char *attr_name,
393                                        unsigned int default_value)
394 {
395         unsigned int ret;
396         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
397         if (!v || !v->data) {
398                 return default_value;
399         }
400
401         /* in LDAP there're only int32_t values */
402         errno = 0;
403         ret = strtol((const char *)v->data, NULL, 0);
404         if (errno == 0) {
405                 return ret;
406         }
407
408         return strtoul((const char *)v->data, NULL, 0);
409 }
410
411 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
412                                    const char *attr_name,
413                                    int64_t default_value)
414 {
415         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
416         if (!v || !v->data) {
417                 return default_value;
418         }
419         return strtoll((const char *)v->data, NULL, 0);
420 }
421
422 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
423                                      const char *attr_name,
424                                      uint64_t default_value)
425 {
426         uint64_t ret;
427         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
428         if (!v || !v->data) {
429                 return default_value;
430         }
431
432         /* in LDAP there're only int64_t values */
433         errno = 0;
434         ret = strtoll((const char *)v->data, NULL, 0);
435         if (errno == 0) {
436                 return ret;
437         }
438
439         return strtoull((const char *)v->data, NULL, 0);
440 }
441
442 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
443                                    const char *attr_name,
444                                    double default_value)
445 {
446         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
447         if (!v || !v->data) {
448                 return default_value;
449         }
450         return strtod((const char *)v->data, NULL);
451 }
452
453 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
454                               const char *attr_name,
455                               int default_value)
456 {
457         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
458         if (!v || !v->data) {
459                 return default_value;
460         }
461         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
462                 return 0;
463         }
464         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
465                 return 1;
466         }
467         return default_value;
468 }
469
470 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
471                                         const char *attr_name,
472                                         const char *default_value)
473 {
474         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
475         if (!v || !v->data) {
476                 return default_value;
477         }
478         return (const char *)v->data;
479 }
480
481 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
482                                        void *mem_ctx,
483                                        const struct ldb_message *msg,
484                                        const char *attr_name)
485 {
486         struct ldb_dn *res_dn;
487         const struct ldb_val *v;
488
489         v = ldb_msg_find_ldb_val(msg, attr_name);
490         if (!v || !v->data) {
491                 return NULL;
492         }
493         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
494         if ( ! ldb_dn_validate(res_dn)) {
495                 talloc_free(res_dn);
496                 return NULL;
497         }
498         return res_dn;
499 }
500
501 /*
502   sort the elements of a message by name
503 */
504 void ldb_msg_sort_elements(struct ldb_message *msg)
505 {
506         TYPESAFE_QSORT(msg->elements, msg->num_elements,
507                        ldb_msg_element_compare_name);
508 }
509
510 /*
511   shallow copy a message - copying only the elements array so that the caller
512   can safely add new elements without changing the message
513 */
514 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
515                                          const struct ldb_message *msg)
516 {
517         struct ldb_message *msg2;
518         unsigned int i;
519
520         msg2 = talloc(mem_ctx, struct ldb_message);
521         if (msg2 == NULL) return NULL;
522
523         *msg2 = *msg;
524
525         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
526                                       msg2->num_elements);
527         if (msg2->elements == NULL) goto failed;
528
529         for (i=0;i<msg2->num_elements;i++) {
530                 msg2->elements[i] = msg->elements[i];
531         }
532
533         return msg2;
534
535 failed:
536         talloc_free(msg2);
537         return NULL;
538 }
539
540
541 /*
542   copy a message, allocating new memory for all parts
543 */
544 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
545                                  const struct ldb_message *msg)
546 {
547         struct ldb_message *msg2;
548         unsigned int i, j;
549
550         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
551         if (msg2 == NULL) return NULL;
552
553         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
554         if (msg2->dn == NULL) goto failed;
555
556         for (i=0;i<msg2->num_elements;i++) {
557                 struct ldb_message_element *el = &msg2->elements[i];
558                 struct ldb_val *values = el->values;
559                 el->name = talloc_strdup(msg2->elements, el->name);
560                 if (el->name == NULL) goto failed;
561                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
562                 for (j=0;j<el->num_values;j++) {
563                         el->values[j] = ldb_val_dup(el->values, &values[j]);
564                         if (el->values[j].data == NULL && values[j].length != 0) {
565                                 goto failed;
566                         }
567                 }
568         }
569
570         return msg2;
571
572 failed:
573         talloc_free(msg2);
574         return NULL;
575 }
576
577
578 /*
579   canonicalise a message, merging elements of the same name
580 */
581 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
582                                          const struct ldb_message *msg)
583 {
584         unsigned int i;
585         struct ldb_message *msg2;
586
587         msg2 = ldb_msg_copy(ldb, msg);
588         if (msg2 == NULL) return NULL;
589
590         ldb_msg_sort_elements(msg2);
591
592         for (i=1;i<msg2->num_elements;i++) {
593                 struct ldb_message_element *el1 = &msg2->elements[i-1];
594                 struct ldb_message_element *el2 = &msg2->elements[i];
595                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
596                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
597                                                        el1->num_values + el2->num_values);
598                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
599                                 return NULL;
600                         }
601                         memcpy(el1->values + el1->num_values,
602                                el2->values,
603                                sizeof(struct ldb_val) * el2->num_values);
604                         el1->num_values += el2->num_values;
605                         talloc_free(discard_const_p(char, el2->name));
606                         if (i+1<msg2->num_elements) {
607                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
608                                         (msg2->num_elements - (i+1)));
609                         }
610                         msg2->num_elements--;
611                         i--;
612                 }
613         }
614
615         return msg2;
616 }
617
618
619 /*
620   return a ldb_message representing the differences between msg1 and msg2. If you
621   then use this in a ldb_modify() call it can be used to save edits to a message
622 */
623 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
624                                  struct ldb_message *msg1,
625                                  struct ldb_message *msg2)
626 {
627         int ldb_ret;
628         struct ldb_message *mod;
629
630         /* allocate mod message in NULL context
631          * so it should appear as 'leaked' in talloc reports */
632         ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2,
633                                   (TALLOC_CTX*)NULL, &mod);
634         if (ldb_ret != LDB_SUCCESS) {
635                 return NULL;
636         }
637
638         return mod;
639 }
640
641 /**
642  * return a ldb_message representing the differences between msg1 and msg2.
643  * If you then use this in a ldb_modify() call it can be used to save edits to a message
644  *
645  * Result message is constructed as follows:
646  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
647  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
648  *                          Value for msg2 element is used
649  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
650  *
651  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
652  */
653 int ldb_msg_diff_ex(struct ldb_context *ldb,
654                     struct ldb_message *msg1,
655                     struct ldb_message *msg2,
656                     TALLOC_CTX *mem_ctx,
657                     struct ldb_message **_msg_out)
658 {
659         int ldb_res;
660         unsigned int i;
661         struct ldb_message *mod;
662         struct ldb_message_element *el;
663         TALLOC_CTX *temp_ctx;
664
665         temp_ctx = talloc_new(mem_ctx);
666         if (!temp_ctx) {
667                 return LDB_ERR_OPERATIONS_ERROR;
668         }
669
670         mod = ldb_msg_new(temp_ctx);
671         if (mod == NULL) {
672                 goto failed;
673         }
674
675         mod->dn = msg1->dn;
676         mod->num_elements = 0;
677         mod->elements = NULL;
678
679         /* canonicalize msg2 so we have no
680          * repeated elements */
681         msg2 = ldb_msg_canonicalize(ldb, msg2);
682         if (msg2 == NULL) {
683                 goto failed;
684         }
685
686         /* steal msg2 into mod context as it is
687          * allocated in ldb's context */
688         talloc_steal(mod, msg2);
689
690         /* look in msg2 to find elements that need to be added
691            or modified */
692         for (i=0;i<msg2->num_elements;i++) {
693                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
694
695                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
696                         continue;
697                 }
698
699                 ldb_res = ldb_msg_add(mod,
700                                       &msg2->elements[i],
701                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
702                 if (ldb_res != LDB_SUCCESS) {
703                         goto failed;
704                 }
705         }
706
707         /* look in msg1 to find elements that need to be deleted */
708         for (i=0;i<msg1->num_elements;i++) {
709                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
710                 if (el == NULL) {
711                         ldb_res = ldb_msg_add_empty(mod,
712                                                     msg1->elements[i].name,
713                                                     LDB_FLAG_MOD_DELETE, NULL);
714                         if (ldb_res != LDB_SUCCESS) {
715                                 goto failed;
716                         }
717                 }
718         }
719
720         /* steal resulting message into supplied context */
721         talloc_steal(mem_ctx, mod);
722         *_msg_out = mod;
723
724         talloc_free(temp_ctx);
725         return LDB_SUCCESS;
726
727 failed:
728         talloc_free(temp_ctx);
729         return LDB_ERR_OPERATIONS_ERROR;
730 }
731
732
733 int ldb_msg_sanity_check(struct ldb_context *ldb, 
734                          const struct ldb_message *msg)
735 {
736         unsigned int i, j;
737
738         /* basic check on DN */
739         if (msg->dn == NULL) {
740                 /* TODO: return also an error string */
741                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
742                 return LDB_ERR_INVALID_DN_SYNTAX;
743         }
744
745         /* basic syntax checks */
746         for (i = 0; i < msg->num_elements; i++) {
747                 for (j = 0; j < msg->elements[i].num_values; j++) {
748                         if (msg->elements[i].values[j].length == 0) {
749                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
750                                 /* an attribute cannot be empty */
751                                 /* TODO: return also an error string */
752                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
753                                                             msg->elements[i].name, 
754                                                             ldb_dn_get_linearized(msg->dn));
755                                 talloc_free(mem_ctx);
756                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
757                         }
758                 }
759         }
760
761         return LDB_SUCCESS;
762 }
763
764
765
766
767 /*
768   copy an attribute list. This only copies the array, not the elements
769   (ie. the elements are left as the same pointers)
770 */
771 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
772 {
773         const char **ret;
774         unsigned int i;
775
776         for (i=0;attrs && attrs[i];i++) /* noop */ ;
777         ret = talloc_array(mem_ctx, const char *, i+1);
778         if (ret == NULL) {
779                 return NULL;
780         }
781         for (i=0;attrs && attrs[i];i++) {
782                 ret[i] = attrs[i];
783         }
784         ret[i] = attrs[i];
785         return ret;
786 }
787
788
789 /*
790   copy an attribute list. This only copies the array, not the elements
791   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
792 */
793 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
794 {
795         const char **ret;
796         unsigned int i;
797         bool found = false;
798
799         for (i=0;attrs && attrs[i];i++) {
800                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
801                         found = true;
802                 }
803         }
804         if (found) {
805                 return ldb_attr_list_copy(mem_ctx, attrs);
806         }
807         ret = talloc_array(mem_ctx, const char *, i+2);
808         if (ret == NULL) {
809                 return NULL;
810         }
811         for (i=0;attrs && attrs[i];i++) {
812                 ret[i] = attrs[i];
813         }
814         ret[i] = new_attr;
815         ret[i+1] = NULL;
816         return ret;
817 }
818
819
820 /*
821   return 1 if an attribute is in a list of attributes, or 0 otherwise
822 */
823 int ldb_attr_in_list(const char * const *attrs, const char *attr)
824 {
825         unsigned int i;
826         for (i=0;attrs && attrs[i];i++) {
827                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
828                         return 1;
829                 }
830         }
831         return 0;
832 }
833
834
835 /*
836   rename the specified attribute in a search result
837 */
838 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
839 {
840         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
841         if (el == NULL) {
842                 return LDB_SUCCESS;
843         }
844         el->name = talloc_strdup(msg->elements, replace);
845         if (el->name == NULL) {
846                 return LDB_ERR_OPERATIONS_ERROR;
847         }
848         return LDB_SUCCESS;
849 }
850
851
852 /*
853   copy the specified attribute in a search result to a new attribute
854 */
855 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
856 {
857         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
858         if (el == NULL) {
859                 return LDB_SUCCESS;
860         }
861         if (ldb_msg_add(msg, el, 0) != 0) {
862                 return LDB_ERR_OPERATIONS_ERROR;
863         }
864         return ldb_msg_rename_attr(msg, attr, replace);
865 }
866
867 /*
868   remove the specified element in a search result
869 */
870 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
871 {
872         ptrdiff_t n = (el - msg->elements);
873         if (n >= msg->num_elements) {
874                 /* should we abort() here? */
875                 return;
876         }
877         if (n != msg->num_elements-1) {
878                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
879         }
880         msg->num_elements--;
881 }
882
883
884 /*
885   remove the specified attribute in a search result
886 */
887 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
888 {
889         struct ldb_message_element *el;
890
891         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
892                 ldb_msg_remove_element(msg, el);
893         }
894 }
895
896 /*
897   return a LDAP formatted GeneralizedTime string
898 */
899 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
900 {
901         struct tm *tm = gmtime(&t);
902         char *ts;
903         int r;
904
905         if (!tm) {
906                 return NULL;
907         }
908
909         /* we now excatly how long this string will be */
910         ts = talloc_array(mem_ctx, char, 18);
911
912         /* formatted like: 20040408072012.0Z */
913         r = snprintf(ts, 18,
914                         "%04u%02u%02u%02u%02u%02u.0Z",
915                         tm->tm_year+1900, tm->tm_mon+1,
916                         tm->tm_mday, tm->tm_hour, tm->tm_min,
917                         tm->tm_sec);
918
919         if (r != 17) {
920                 talloc_free(ts);
921                 return NULL;
922         }
923
924         return ts;
925 }
926
927 /*
928   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
929 */
930 time_t ldb_string_to_time(const char *s)
931 {
932         struct tm tm;
933         
934         if (s == NULL) return 0;
935         
936         memset(&tm, 0, sizeof(tm));
937         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
938                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
939                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
940                 return 0;
941         }
942         tm.tm_year -= 1900;
943         tm.tm_mon -= 1;
944         
945         return timegm(&tm);
946 }
947
948 /*
949   convert a LDAP GeneralizedTime string in ldb_val format to a
950   time_t.
951 */
952 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
953 {
954         struct tm tm;
955
956         if (v == NULL || !v->data || v->length < 17) {
957                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
958         }
959
960         memset(&tm, 0, sizeof(tm));
961
962         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
963                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
964                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
965                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
966         }
967         tm.tm_year -= 1900;
968         tm.tm_mon -= 1;
969
970         *t = timegm(&tm);
971
972         return LDB_SUCCESS;
973 }
974
975 /*
976   return a LDAP formatted UTCTime string
977 */
978 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
979 {
980         struct tm *tm = gmtime(&t);
981         char *ts;
982         int r;
983
984         if (!tm) {
985                 return NULL;
986         }
987
988         /* we now excatly how long this string will be */
989         ts = talloc_array(mem_ctx, char, 14);
990
991         /* formatted like: 20040408072012.0Z => 040408072012Z */
992         r = snprintf(ts, 14,
993                         "%02u%02u%02u%02u%02u%02uZ",
994                         (tm->tm_year+1900)%100, tm->tm_mon+1,
995                         tm->tm_mday, tm->tm_hour, tm->tm_min,
996                         tm->tm_sec);
997
998         if (r != 13) {
999                 talloc_free(ts);
1000                 return NULL;
1001         }
1002
1003         return ts;
1004 }
1005
1006 /*
1007   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1008 */
1009 time_t ldb_string_utc_to_time(const char *s)
1010 {
1011         struct tm tm;
1012         
1013         if (s == NULL) return 0;
1014         
1015         memset(&tm, 0, sizeof(tm));
1016         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1017                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1018                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1019                 return 0;
1020         }
1021         if (tm.tm_year < 50) {
1022                 tm.tm_year += 100;
1023         }
1024         tm.tm_mon -= 1;
1025         
1026         return timegm(&tm);
1027 }
1028
1029
1030 /*
1031   dump a set of results to a file. Useful from within gdb
1032 */
1033 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1034 {
1035         unsigned int i;
1036
1037         for (i = 0; i < result->count; i++) {
1038                 struct ldb_ldif ldif;
1039                 fprintf(f, "# record %d\n", i+1);
1040                 ldif.changetype = LDB_CHANGETYPE_NONE;
1041                 ldif.msg = result->msgs[i];
1042                 ldb_ldif_write_file(ldb, f, &ldif);
1043         }
1044 }
1045
1046 /*
1047   checks for a string attribute. Returns "1" on match and otherwise "0".
1048 */
1049 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1050                                    const char *name, const char *value)
1051 {
1052         struct ldb_message_element *el;
1053         struct ldb_val val;
1054         
1055         el = ldb_msg_find_element(msg, name);
1056         if (el == NULL) {
1057                 return 0;
1058         }
1059
1060         val.data = discard_const_p(uint8_t, value);
1061         val.length = strlen(value);
1062
1063         if (ldb_msg_find_val(el, &val)) {
1064                 return 1;
1065         }
1066
1067         return 0;
1068 }
1069