e9c04df55a8538ef012dab33d5d0389a3f74f498
[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_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, const char *attr_name)
325 {
326         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
327         if (!el || el->num_values == 0) {
328                 return NULL;
329         }
330         return &el->values[0];
331 }
332
333 int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
334                              const char *attr_name,
335                              int default_value)
336 {
337         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
338         if (!v || !v->data) {
339                 return default_value;
340         }
341         return strtol((const char *)v->data, NULL, 0);
342 }
343
344 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
345                                        const char *attr_name,
346                                        unsigned int default_value)
347 {
348         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
349         if (!v || !v->data) {
350                 return default_value;
351         }
352         return strtoul((const char *)v->data, NULL, 0);
353 }
354
355 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
356                                    const char *attr_name,
357                                    int64_t default_value)
358 {
359         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
360         if (!v || !v->data) {
361                 return default_value;
362         }
363         return strtoll((const char *)v->data, NULL, 0);
364 }
365
366 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
367                                      const char *attr_name,
368                                      uint64_t default_value)
369 {
370         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
371         if (!v || !v->data) {
372                 return default_value;
373         }
374         return strtoull((const char *)v->data, NULL, 0);
375 }
376
377 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
378                                    const char *attr_name,
379                                    double default_value)
380 {
381         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
382         if (!v || !v->data) {
383                 return default_value;
384         }
385         return strtod((const char *)v->data, NULL);
386 }
387
388 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
389                               const char *attr_name,
390                               int default_value)
391 {
392         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
393         if (!v || !v->data) {
394                 return default_value;
395         }
396         if (strcasecmp((const char *)v->data, "FALSE") == 0) {
397                 return 0;
398         }
399         if (strcasecmp((const char *)v->data, "TRUE") == 0) {
400                 return 1;
401         }
402         return default_value;
403 }
404
405 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
406                                         const char *attr_name,
407                                         const char *default_value)
408 {
409         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
410         if (!v || !v->data) {
411                 return default_value;
412         }
413         return (const char *)v->data;
414 }
415
416 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
417                                        void *mem_ctx,
418                                        const struct ldb_message *msg,
419                                        const char *attr_name)
420 {
421         struct ldb_dn *res_dn;
422         const struct ldb_val *v;
423
424         v = ldb_msg_find_ldb_val(msg, attr_name);
425         if (!v || !v->data) {
426                 return NULL;
427         }
428         res_dn = ldb_dn_new(mem_ctx, ldb, (const char *)v->data);
429         if ( ! ldb_dn_validate(res_dn)) {
430                 talloc_free(res_dn);
431                 return NULL;
432         }
433         return res_dn;
434 }
435
436 /*
437   sort the elements of a message by name
438 */
439 void ldb_msg_sort_elements(struct ldb_message *msg)
440 {
441         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
442               (comparison_fn_t)ldb_msg_element_compare_name);
443 }
444
445 /*
446   shallow copy a message - copying only the elements array so that the caller
447   can safely add new elements without changing the message
448 */
449 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
450                                          const struct ldb_message *msg)
451 {
452         struct ldb_message *msg2;
453         int i;
454
455         msg2 = talloc(mem_ctx, struct ldb_message);
456         if (msg2 == NULL) return NULL;
457
458         *msg2 = *msg;
459
460         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
461                                       msg2->num_elements);
462         if (msg2->elements == NULL) goto failed;
463
464         for (i=0;i<msg2->num_elements;i++) {
465                 msg2->elements[i] = msg->elements[i];
466         }
467
468         return msg2;
469
470 failed:
471         talloc_free(msg2);
472         return NULL;
473 }
474
475
476 /*
477   copy a message, allocating new memory for all parts
478 */
479 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
480                                  const struct ldb_message *msg)
481 {
482         struct ldb_message *msg2;
483         int i, j;
484
485         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
486         if (msg2 == NULL) return NULL;
487
488         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
489         if (msg2->dn == NULL) goto failed;
490
491         for (i=0;i<msg2->num_elements;i++) {
492                 struct ldb_message_element *el = &msg2->elements[i];
493                 struct ldb_val *values = el->values;
494                 el->name = talloc_strdup(msg2->elements, el->name);
495                 if (el->name == NULL) goto failed;
496                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
497                 for (j=0;j<el->num_values;j++) {
498                         el->values[j] = ldb_val_dup(el->values, &values[j]);
499                         if (el->values[j].data == NULL && values[j].length != 0) {
500                                 goto failed;
501                         }
502                 }
503         }
504
505         return msg2;
506
507 failed:
508         talloc_free(msg2);
509         return NULL;
510 }
511
512
513 /*
514   canonicalise a message, merging elements of the same name
515 */
516 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
517                                          const struct ldb_message *msg)
518 {
519         int i;
520         struct ldb_message *msg2;
521
522         msg2 = ldb_msg_copy(ldb, msg);
523         if (msg2 == NULL) return NULL;
524
525         ldb_msg_sort_elements(msg2);
526
527         for (i=1;i<msg2->num_elements;i++) {
528                 struct ldb_message_element *el1 = &msg2->elements[i-1];
529                 struct ldb_message_element *el2 = &msg2->elements[i];
530                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
531                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
532                                                        el1->num_values + el2->num_values);
533                         if (el1->values == NULL) {
534                                 return NULL;
535                         }
536                         memcpy(el1->values + el1->num_values,
537                                el2->values,
538                                sizeof(struct ldb_val) * el2->num_values);
539                         el1->num_values += el2->num_values;
540                         talloc_free(discard_const_p(char, el2->name));
541                         if (i+1<msg2->num_elements) {
542                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
543                                         (msg2->num_elements - (i+1)));
544                         }
545                         msg2->num_elements--;
546                         i--;
547                 }
548         }
549
550         return msg2;
551 }
552
553
554 /*
555   return a ldb_message representing the differences between msg1 and msg2. If you
556   then use this in a ldb_modify() call it can be used to save edits to a message
557 */
558 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
559                                  struct ldb_message *msg1,
560                                  struct ldb_message *msg2)
561 {
562         struct ldb_message *mod;
563         struct ldb_message_element *el;
564         unsigned int i;
565
566         mod = ldb_msg_new(ldb);
567
568         mod->dn = msg1->dn;
569         mod->num_elements = 0;
570         mod->elements = NULL;
571
572         msg2 = ldb_msg_canonicalize(ldb, msg2);
573         if (msg2 == NULL) {
574                 return NULL;
575         }
576         
577         /* look in msg2 to find elements that need to be added
578            or modified */
579         for (i=0;i<msg2->num_elements;i++) {
580                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
581
582                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
583                         continue;
584                 }
585
586                 if (ldb_msg_add(mod, 
587                                 &msg2->elements[i],
588                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
589                         return NULL;
590                 }
591         }
592
593         /* look in msg1 to find elements that need to be deleted */
594         for (i=0;i<msg1->num_elements;i++) {
595                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
596                 if (!el) {
597                         if (ldb_msg_add_empty(mod, 
598                                               msg1->elements[i].name,
599                                               LDB_FLAG_MOD_DELETE, NULL) != 0) {
600                                 return NULL;
601                         }
602                 }
603         }
604
605         return mod;
606 }
607
608 int ldb_msg_sanity_check(struct ldb_context *ldb, 
609                          const struct ldb_message *msg)
610 {
611         int i, j;
612
613         /* basic check on DN */
614         if (msg->dn == NULL) {
615                 /* TODO: return also an error string */
616                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
617                 return LDB_ERR_INVALID_DN_SYNTAX;
618         }
619
620         /* basic syntax checks */
621         for (i = 0; i < msg->num_elements; i++) {
622                 for (j = 0; j < msg->elements[i].num_values; j++) {
623                         if (msg->elements[i].values[j].length == 0) {
624                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
625                                 /* an attribute cannot be empty */
626                                 /* TODO: return also an error string */
627                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
628                                                             msg->elements[i].name, 
629                                                             ldb_dn_get_linearized(msg->dn));
630                                 talloc_free(mem_ctx);
631                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
632                         }
633                 }
634         }
635
636         return LDB_SUCCESS;
637 }
638
639
640
641
642 /*
643   copy an attribute list. This only copies the array, not the elements
644   (ie. the elements are left as the same pointers)
645 */
646 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
647 {
648         const char **ret;
649         int i;
650         for (i=0;attrs[i];i++) /* noop */ ;
651         ret = talloc_array(mem_ctx, const char *, i+1);
652         if (ret == NULL) {
653                 return NULL;
654         }
655         for (i=0;attrs[i];i++) {
656                 ret[i] = attrs[i];
657         }
658         ret[i] = attrs[i];
659         return ret;
660 }
661
662
663 /*
664   copy an attribute list. This only copies the array, not the elements
665   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
666 */
667 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
668 {
669         const char **ret;
670         int i;
671         bool found = false;
672         for (i=0;attrs[i];i++) {
673                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
674                         found = true;
675                 }
676         }
677         if (found) {
678                 return ldb_attr_list_copy(mem_ctx, attrs);
679         }
680         ret = talloc_array(mem_ctx, const char *, i+2);
681         if (ret == NULL) {
682                 return NULL;
683         }
684         for (i=0;attrs[i];i++) {
685                 ret[i] = attrs[i];
686         }
687         ret[i] = new_attr;
688         ret[i+1] = NULL;
689         return ret;
690 }
691
692
693 /*
694   return 1 if an attribute is in a list of attributes, or 0 otherwise
695 */
696 int ldb_attr_in_list(const char * const *attrs, const char *attr)
697 {
698         int i;
699         for (i=0;attrs && attrs[i];i++) {
700                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
701                         return 1;
702                 }
703         }
704         return 0;
705 }
706
707
708 /*
709   rename the specified attribute in a search result
710 */
711 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
712 {
713         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
714         if (el == NULL) {
715                 return LDB_SUCCESS;
716         }
717         el->name = talloc_strdup(msg->elements, replace);
718         if (el->name == NULL) {
719                 return LDB_ERR_OPERATIONS_ERROR;
720         }
721         return LDB_SUCCESS;
722 }
723
724
725 /*
726   copy the specified attribute in a search result to a new attribute
727 */
728 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
729 {
730         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
731         if (el == NULL) {
732                 return LDB_SUCCESS;
733         }
734         if (ldb_msg_add(msg, el, 0) != 0) {
735                 return LDB_ERR_OPERATIONS_ERROR;
736         }
737         return ldb_msg_rename_attr(msg, attr, replace);
738 }
739
740 /*
741   remove the specified element in a search result
742 */
743 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
744 {
745         int n = (el - msg->elements);
746         if (n != msg->num_elements-1) {
747                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
748         }
749         msg->num_elements--;
750 }
751
752
753 /*
754   remove the specified attribute in a search result
755 */
756 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
757 {
758         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
759         if (el) {
760                 ldb_msg_remove_element(msg, el);
761         }
762 }
763
764 /*
765   return a LDAP formatted GeneralizedTime string
766 */
767 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
768 {
769         struct tm *tm = gmtime(&t);
770         char *ts;
771         int r;
772
773         if (!tm) {
774                 return NULL;
775         }
776
777         /* we now excatly how long this string will be */
778         ts = talloc_array(mem_ctx, char, 18);
779
780         /* formatted like: 20040408072012.0Z */
781         r = snprintf(ts, 18,
782                         "%04u%02u%02u%02u%02u%02u.0Z",
783                         tm->tm_year+1900, tm->tm_mon+1,
784                         tm->tm_mday, tm->tm_hour, tm->tm_min,
785                         tm->tm_sec);
786
787         if (r != 17) {
788                 talloc_free(ts);
789                 return NULL;
790         }
791
792         return ts;
793 }
794
795 /*
796   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
797 */
798 time_t ldb_string_to_time(const char *s)
799 {
800         struct tm tm;
801         
802         if (s == NULL) return 0;
803         
804         memset(&tm, 0, sizeof(tm));
805         if (sscanf(s, "%04u%02u%02u%02u%02u%02u", 
806                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
807                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
808                 return 0;
809         }
810         tm.tm_year -= 1900;
811         tm.tm_mon -= 1;
812         
813         return timegm(&tm);
814 }
815
816 /*
817   return a LDAP formatted UTCTime string
818 */
819 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
820 {
821         struct tm *tm = gmtime(&t);
822         char *ts;
823         int r;
824
825         if (!tm) {
826                 return NULL;
827         }
828
829         /* we now excatly how long this string will be */
830         ts = talloc_array(mem_ctx, char, 14);
831
832         /* formatted like: 20040408072012.0Z => 040408072012Z */
833         r = snprintf(ts, 14,
834                         "%02u%02u%02u%02u%02u%02uZ",
835                         (tm->tm_year+1900)%100, tm->tm_mon+1,
836                         tm->tm_mday, tm->tm_hour, tm->tm_min,
837                         tm->tm_sec);
838
839         if (r != 13) {
840                 talloc_free(ts);
841                 return NULL;
842         }
843
844         return ts;
845 }
846
847 /*
848   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
849 */
850 time_t ldb_string_utc_to_time(const char *s)
851 {
852         struct tm tm;
853         
854         if (s == NULL) return 0;
855         
856         memset(&tm, 0, sizeof(tm));
857         if (sscanf(s, "%02u%02u%02u%02u%02u%02u", 
858                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
859                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
860                 return 0;
861         }
862         if (tm.tm_year < 50) {
863                 tm.tm_year += 100;
864         }
865         tm.tm_mon -= 1;
866         
867         return timegm(&tm);
868 }
869
870
871 /*
872   dump a set of results to a file. Useful from within gdb
873 */
874 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
875 {
876         int i;
877
878         for (i = 0; i < result->count; i++) {
879                 struct ldb_ldif ldif;
880                 fprintf(f, "# record %d\n", i+1);
881                 ldif.changetype = LDB_CHANGETYPE_NONE;
882                 ldif.msg = result->msgs[i];
883                 ldb_ldif_write_file(ldb, f, &ldif);
884         }
885 }
886
887 int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
888 {
889         struct ldb_message_element *el;
890         struct ldb_val val;
891         
892         el = ldb_msg_find_element(msg, name);
893         if (el == NULL)
894                 return 0;
895
896         val.data = discard_const_p(uint8_t, value);
897         val.length = strlen(value);
898
899         if (ldb_msg_find_val(el, &val))
900                 return 1;
901
902         return 0;
903 }