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