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