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