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