r23560: - Activate metze's schema modules (from metze's schema-loading-13 patch).
[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         bool found = false;
670         for (i=0;attrs[i];i++) {
671                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
672                         found = true;
673                 }
674         }
675         if (found) {
676                 return ldb_attr_list_copy(mem_ctx, attrs);
677         }
678         ret = talloc_array(mem_ctx, const char *, i+2);
679         if (ret == NULL) {
680                 return NULL;
681         }
682         for (i=0;attrs[i];i++) {
683                 ret[i] = attrs[i];
684         }
685         ret[i] = new_attr;
686         ret[i+1] = NULL;
687         return ret;
688 }
689
690
691 /*
692   return 1 if an attribute is in a list of attributes, or 0 otherwise
693 */
694 int ldb_attr_in_list(const char * const *attrs, const char *attr)
695 {
696         int i;
697         for (i=0;attrs && attrs[i];i++) {
698                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
699                         return 1;
700                 }
701         }
702         return 0;
703 }
704
705
706 /*
707   rename the specified attribute in a search result
708 */
709 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
710 {
711         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
712         if (el == NULL) {
713                 return LDB_SUCCESS;
714         }
715         el->name = talloc_strdup(msg->elements, replace);
716         if (el->name == NULL) {
717                 return LDB_ERR_OPERATIONS_ERROR;
718         }
719         return LDB_SUCCESS;
720 }
721
722
723 /*
724   copy the specified attribute in a search result to a new attribute
725 */
726 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
727 {
728         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
729         if (el == NULL) {
730                 return LDB_SUCCESS;
731         }
732         if (ldb_msg_add(msg, el, 0) != 0) {
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735         return ldb_msg_rename_attr(msg, attr, replace);
736 }
737
738 /*
739   remove the specified element in a search result
740 */
741 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
742 {
743         int n = (el - msg->elements);
744         if (n != msg->num_elements-1) {
745                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
746         }
747         msg->num_elements--;
748 }
749
750
751 /*
752   remove the specified attribute in a search result
753 */
754 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
755 {
756         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
757         if (el) {
758                 ldb_msg_remove_element(msg, el);
759         }
760 }
761
762 /*
763   return a LDAP formatted GeneralizedTime string
764 */
765 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
766 {
767         struct tm *tm = gmtime(&t);
768         char *ts;
769         int r;
770
771         if (!tm) {
772                 return NULL;
773         }
774
775         /* we now excatly how long this string will be */
776         ts = talloc_array(mem_ctx, char, 18);
777
778         /* formatted like: 20040408072012.0Z */
779         r = snprintf(ts, 18,
780                         "%04u%02u%02u%02u%02u%02u.0Z",
781                         tm->tm_year+1900, tm->tm_mon+1,
782                         tm->tm_mday, tm->tm_hour, tm->tm_min,
783                         tm->tm_sec);
784
785         if (r != 17) {
786                 talloc_free(ts);
787                 return NULL;
788         }
789
790         return ts;
791 }
792
793 /*
794   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
795 */
796 time_t ldb_string_to_time(const char *s)
797 {
798         struct tm tm;
799         
800         if (s == NULL) return 0;
801         
802         memset(&tm, 0, sizeof(tm));
803         if (sscanf(s, "%04u%02u%02u%02u%02u%02u", 
804                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
805                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
806                 return 0;
807         }
808         tm.tm_year -= 1900;
809         tm.tm_mon -= 1;
810         
811         return timegm(&tm);
812 }
813
814 /*
815   return a LDAP formatted UTCTime string
816 */
817 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
818 {
819         struct tm *tm = gmtime(&t);
820         char *ts;
821         int r;
822
823         if (!tm) {
824                 return NULL;
825         }
826
827         /* we now excatly how long this string will be */
828         ts = talloc_array(mem_ctx, char, 14);
829
830         /* formatted like: 20040408072012.0Z => 040408072012Z */
831         r = snprintf(ts, 14,
832                         "%02u%02u%02u%02u%02u%02uZ",
833                         (tm->tm_year+1900)%100, tm->tm_mon+1,
834                         tm->tm_mday, tm->tm_hour, tm->tm_min,
835                         tm->tm_sec);
836
837         if (r != 13) {
838                 talloc_free(ts);
839                 return NULL;
840         }
841
842         return ts;
843 }
844
845 /*
846   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
847 */
848 time_t ldb_string_utc_to_time(const char *s)
849 {
850         struct tm tm;
851         
852         if (s == NULL) return 0;
853         
854         memset(&tm, 0, sizeof(tm));
855         if (sscanf(s, "%02u%02u%02u%02u%02u%02u", 
856                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
857                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
858                 return 0;
859         }
860         if (tm.tm_year < 50) {
861                 tm.tm_year += 100;
862         }
863         tm.tm_mon -= 1;
864         
865         return timegm(&tm);
866 }
867
868
869 /*
870   dump a set of results to a file. Useful from within gdb
871 */
872 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
873 {
874         int i;
875
876         for (i = 0; i < result->count; i++) {
877                 struct ldb_ldif ldif;
878                 fprintf(f, "# record %d\n", i+1);
879                 ldif.changetype = LDB_CHANGETYPE_NONE;
880                 ldif.msg = result->msgs[i];
881                 ldb_ldif_write_file(ldb, f, &ldif);
882         }
883 }
884
885 int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
886 {
887         struct ldb_message_element *el;
888         struct ldb_val val;
889         
890         el = ldb_msg_find_element(msg, name);
891         if (el == NULL)
892                 return 0;
893
894         val.data = discard_const_p(uint8_t, value);
895         val.length = strlen(value);
896
897         if (ldb_msg_find_val(el, &val))
898                 return 1;
899
900         return 0;
901 }