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