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