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