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