s4-ldb: changed ldb_msg_add_dn() to ldb_msg_add_linearized_dn()
[kamenim/samba.git] / source4 / lib / ldb / common / ldb_msg.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb message component utility functions
28  *
29  *  Description: functions for manipulating ldb_message structures
30  *
31  *  Author: Andrew Tridgell
32  */
33
34 #include "ldb_private.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         if (v1->data == v2->data) return 1;
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 DN element to a message
263   WARNING: this uses the linearized string from the dn, and does not
264   copy the string.
265 */
266 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
267                               struct ldb_dn *dn)
268 {
269         return ldb_msg_add_steal_string(msg, attr_name,
270                                         ldb_dn_alloc_linearized(msg, dn));
271 }
272
273 /*
274   add a printf formatted element to a message
275 */
276 int ldb_msg_add_fmt(struct ldb_message *msg, 
277                     const char *attr_name, const char *fmt, ...)
278 {
279         struct ldb_val val;
280         va_list ap;
281         char *str;
282
283         va_start(ap, fmt);
284         str = talloc_vasprintf(msg, fmt, ap);
285         va_end(ap);
286
287         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
288
289         val.data   = (uint8_t *)str;
290         val.length = strlen(str);
291
292         return ldb_msg_add_steal_value(msg, attr_name, &val);
293 }
294
295 /*
296   compare two ldb_message_element structures
297   assumes case senistive comparison
298 */
299 int ldb_msg_element_compare(struct ldb_message_element *el1, 
300                             struct ldb_message_element *el2)
301 {
302         unsigned int i;
303
304         if (el1->num_values != el2->num_values) {
305                 return el1->num_values - el2->num_values;
306         }
307
308         for (i=0;i<el1->num_values;i++) {
309                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
310                         return -1;
311                 }
312         }
313
314         return 0;
315 }
316
317 /*
318   compare two ldb_message_element structures
319   comparing by element name
320 */
321 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
322                                  struct ldb_message_element *el2)
323 {
324         return ldb_attr_cmp(el1->name, el2->name);
325 }
326
327 /*
328   convenience functions to return common types from a message
329   these return the first value if the attribute is multi-valued
330 */
331 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, 
332                                            const char *attr_name)
333 {
334         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
335         if (!el || el->num_values == 0) {
336                 return NULL;
337         }
338         return &el->values[0];
339 }
340
341 int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
342                              const char *attr_name,
343                              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 strtol((const char *)v->data, NULL, 0);
350 }
351
352 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
353                                        const char *attr_name,
354                                        unsigned int 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 strtoul((const char *)v->data, NULL, 0);
361 }
362
363 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
364                                    const char *attr_name,
365                                    int64_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 strtoll((const char *)v->data, NULL, 0);
372 }
373
374 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
375                                      const char *attr_name,
376                                      uint64_t 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 strtoull((const char *)v->data, NULL, 0);
383 }
384
385 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
386                                    const char *attr_name,
387                                    double 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         return strtod((const char *)v->data, NULL);
394 }
395
396 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
397                               const char *attr_name,
398                               int default_value)
399 {
400         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
401         if (!v || !v->data) {
402                 return default_value;
403         }
404         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
405                 return 0;
406         }
407         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
408                 return 1;
409         }
410         return default_value;
411 }
412
413 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
414                                         const char *attr_name,
415                                         const char *default_value)
416 {
417         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
418         if (!v || !v->data) {
419                 return default_value;
420         }
421         return (const char *)v->data;
422 }
423
424 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
425                                        void *mem_ctx,
426                                        const struct ldb_message *msg,
427                                        const char *attr_name)
428 {
429         struct ldb_dn *res_dn;
430         const struct ldb_val *v;
431
432         v = ldb_msg_find_ldb_val(msg, attr_name);
433         if (!v || !v->data) {
434                 return NULL;
435         }
436         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
437         if ( ! ldb_dn_validate(res_dn)) {
438                 talloc_free(res_dn);
439                 return NULL;
440         }
441         return res_dn;
442 }
443
444 /*
445   sort the elements of a message by name
446 */
447 void ldb_msg_sort_elements(struct ldb_message *msg)
448 {
449         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
450               (comparison_fn_t)ldb_msg_element_compare_name);
451 }
452
453 /*
454   shallow copy a message - copying only the elements array so that the caller
455   can safely add new elements without changing the message
456 */
457 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
458                                          const struct ldb_message *msg)
459 {
460         struct ldb_message *msg2;
461         int i;
462
463         msg2 = talloc(mem_ctx, struct ldb_message);
464         if (msg2 == NULL) return NULL;
465
466         *msg2 = *msg;
467
468         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
469                                       msg2->num_elements);
470         if (msg2->elements == NULL) goto failed;
471
472         for (i=0;i<msg2->num_elements;i++) {
473                 msg2->elements[i] = msg->elements[i];
474         }
475
476         return msg2;
477
478 failed:
479         talloc_free(msg2);
480         return NULL;
481 }
482
483
484 /*
485   copy a message, allocating new memory for all parts
486 */
487 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
488                                  const struct ldb_message *msg)
489 {
490         struct ldb_message *msg2;
491         int i, j;
492
493         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
494         if (msg2 == NULL) return NULL;
495
496         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
497         if (msg2->dn == NULL) goto failed;
498
499         for (i=0;i<msg2->num_elements;i++) {
500                 struct ldb_message_element *el = &msg2->elements[i];
501                 struct ldb_val *values = el->values;
502                 el->name = talloc_strdup(msg2->elements, el->name);
503                 if (el->name == NULL) goto failed;
504                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
505                 for (j=0;j<el->num_values;j++) {
506                         el->values[j] = ldb_val_dup(el->values, &values[j]);
507                         if (el->values[j].data == NULL && values[j].length != 0) {
508                                 goto failed;
509                         }
510                 }
511         }
512
513         return msg2;
514
515 failed:
516         talloc_free(msg2);
517         return NULL;
518 }
519
520
521 /*
522   canonicalise a message, merging elements of the same name
523 */
524 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
525                                          const struct ldb_message *msg)
526 {
527         int i;
528         struct ldb_message *msg2;
529
530         msg2 = ldb_msg_copy(ldb, msg);
531         if (msg2 == NULL) return NULL;
532
533         ldb_msg_sort_elements(msg2);
534
535         for (i=1;i<msg2->num_elements;i++) {
536                 struct ldb_message_element *el1 = &msg2->elements[i-1];
537                 struct ldb_message_element *el2 = &msg2->elements[i];
538                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
539                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
540                                                        el1->num_values + el2->num_values);
541                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
542                                 return NULL;
543                         }
544                         memcpy(el1->values + el1->num_values,
545                                el2->values,
546                                sizeof(struct ldb_val) * el2->num_values);
547                         el1->num_values += el2->num_values;
548                         talloc_free(discard_const_p(char, el2->name));
549                         if (i+1<msg2->num_elements) {
550                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
551                                         (msg2->num_elements - (i+1)));
552                         }
553                         msg2->num_elements--;
554                         i--;
555                 }
556         }
557
558         return msg2;
559 }
560
561
562 /*
563   return a ldb_message representing the differences between msg1 and msg2. If you
564   then use this in a ldb_modify() call it can be used to save edits to a message
565 */
566 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
567                                  struct ldb_message *msg1,
568                                  struct ldb_message *msg2)
569 {
570         struct ldb_message *mod;
571         struct ldb_message_element *el;
572         unsigned int i;
573
574         mod = ldb_msg_new(ldb);
575         if (mod == NULL) {
576                 return NULL;
577         }
578
579         mod->dn = msg1->dn;
580         mod->num_elements = 0;
581         mod->elements = NULL;
582
583         msg2 = ldb_msg_canonicalize(ldb, msg2);
584         if (msg2 == NULL) {
585                 talloc_free(mod);
586                 return NULL;
587         }
588         
589         /* look in msg2 to find elements that need to be added
590            or modified */
591         for (i=0;i<msg2->num_elements;i++) {
592                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
593
594                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
595                         continue;
596                 }
597
598                 if (ldb_msg_add(mod, 
599                                 &msg2->elements[i],
600                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
601                         talloc_free(mod);
602                         return NULL;
603                 }
604         }
605
606         /* look in msg1 to find elements that need to be deleted */
607         for (i=0;i<msg1->num_elements;i++) {
608                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
609                 if (el == NULL) {
610                         if (ldb_msg_add_empty(mod, 
611                                               msg1->elements[i].name,
612                                               LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
613                                 talloc_free(mod);
614                                 return NULL;
615                         }
616                 }
617         }
618
619         return mod;
620 }
621
622 int ldb_msg_sanity_check(struct ldb_context *ldb, 
623                          const struct ldb_message *msg)
624 {
625         int i, j;
626
627         /* basic check on DN */
628         if (msg->dn == NULL) {
629                 /* TODO: return also an error string */
630                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
631                 return LDB_ERR_INVALID_DN_SYNTAX;
632         }
633
634         /* basic syntax checks */
635         for (i = 0; i < msg->num_elements; i++) {
636                 for (j = 0; j < msg->elements[i].num_values; j++) {
637                         if (msg->elements[i].values[j].length == 0) {
638                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
639                                 /* an attribute cannot be empty */
640                                 /* TODO: return also an error string */
641                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
642                                                             msg->elements[i].name, 
643                                                             ldb_dn_get_linearized(msg->dn));
644                                 talloc_free(mem_ctx);
645                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
646                         }
647                 }
648         }
649
650         return LDB_SUCCESS;
651 }
652
653
654
655
656 /*
657   copy an attribute list. This only copies the array, not the elements
658   (ie. the elements are left as the same pointers)
659 */
660 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
661 {
662         const char **ret;
663         int i;
664         for (i=0;attrs && attrs[i];i++) /* noop */ ;
665         ret = talloc_array(mem_ctx, const char *, i+1);
666         if (ret == NULL) {
667                 return NULL;
668         }
669         for (i=0;attrs && attrs[i];i++) {
670                 ret[i] = attrs[i];
671         }
672         ret[i] = attrs[i];
673         return ret;
674 }
675
676
677 /*
678   copy an attribute list. This only copies the array, not the elements
679   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
680 */
681 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
682 {
683         const char **ret;
684         int i;
685         bool found = false;
686         for (i=0;attrs && attrs[i];i++) {
687                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
688                         found = true;
689                 }
690         }
691         if (found) {
692                 return ldb_attr_list_copy(mem_ctx, attrs);
693         }
694         ret = talloc_array(mem_ctx, const char *, i+2);
695         if (ret == NULL) {
696                 return NULL;
697         }
698         for (i=0;attrs && attrs[i];i++) {
699                 ret[i] = attrs[i];
700         }
701         ret[i] = new_attr;
702         ret[i+1] = NULL;
703         return ret;
704 }
705
706
707 /*
708   return 1 if an attribute is in a list of attributes, or 0 otherwise
709 */
710 int ldb_attr_in_list(const char * const *attrs, const char *attr)
711 {
712         int i;
713         for (i=0;attrs && attrs[i];i++) {
714                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
715                         return 1;
716                 }
717         }
718         return 0;
719 }
720
721
722 /*
723   rename the specified attribute in a search result
724 */
725 int ldb_msg_rename_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         el->name = talloc_strdup(msg->elements, replace);
732         if (el->name == NULL) {
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735         return LDB_SUCCESS;
736 }
737
738
739 /*
740   copy the specified attribute in a search result to a new attribute
741 */
742 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
743 {
744         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
745         if (el == NULL) {
746                 return LDB_SUCCESS;
747         }
748         if (ldb_msg_add(msg, el, 0) != 0) {
749                 return LDB_ERR_OPERATIONS_ERROR;
750         }
751         return ldb_msg_rename_attr(msg, attr, replace);
752 }
753
754 /*
755   remove the specified element in a search result
756 */
757 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
758 {
759         int n = (el - msg->elements);
760         if (n >= msg->num_elements) {
761                 /* should we abort() here? */
762                 return;
763         }
764         if (n != msg->num_elements-1) {
765                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
766         }
767         msg->num_elements--;
768 }
769
770
771 /*
772   remove the specified attribute in a search result
773 */
774 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
775 {
776         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
777         if (el) {
778                 ldb_msg_remove_element(msg, el);
779         }
780 }
781
782 /*
783   return a LDAP formatted GeneralizedTime string
784 */
785 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
786 {
787         struct tm *tm = gmtime(&t);
788         char *ts;
789         int r;
790
791         if (!tm) {
792                 return NULL;
793         }
794
795         /* we now excatly how long this string will be */
796         ts = talloc_array(mem_ctx, char, 18);
797
798         /* formatted like: 20040408072012.0Z */
799         r = snprintf(ts, 18,
800                         "%04u%02u%02u%02u%02u%02u.0Z",
801                         tm->tm_year+1900, tm->tm_mon+1,
802                         tm->tm_mday, tm->tm_hour, tm->tm_min,
803                         tm->tm_sec);
804
805         if (r != 17) {
806                 talloc_free(ts);
807                 return NULL;
808         }
809
810         return ts;
811 }
812
813 /*
814   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
815 */
816 time_t ldb_string_to_time(const char *s)
817 {
818         struct tm tm;
819         
820         if (s == NULL) return 0;
821         
822         memset(&tm, 0, sizeof(tm));
823         if (sscanf(s, "%04u%02u%02u%02u%02u%02u", 
824                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
825                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
826                 return 0;
827         }
828         tm.tm_year -= 1900;
829         tm.tm_mon -= 1;
830         
831         return timegm(&tm);
832 }
833
834 /*
835   return a LDAP formatted UTCTime string
836 */
837 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
838 {
839         struct tm *tm = gmtime(&t);
840         char *ts;
841         int r;
842
843         if (!tm) {
844                 return NULL;
845         }
846
847         /* we now excatly how long this string will be */
848         ts = talloc_array(mem_ctx, char, 14);
849
850         /* formatted like: 20040408072012.0Z => 040408072012Z */
851         r = snprintf(ts, 14,
852                         "%02u%02u%02u%02u%02u%02uZ",
853                         (tm->tm_year+1900)%100, tm->tm_mon+1,
854                         tm->tm_mday, tm->tm_hour, tm->tm_min,
855                         tm->tm_sec);
856
857         if (r != 13) {
858                 talloc_free(ts);
859                 return NULL;
860         }
861
862         return ts;
863 }
864
865 /*
866   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
867 */
868 time_t ldb_string_utc_to_time(const char *s)
869 {
870         struct tm tm;
871         
872         if (s == NULL) return 0;
873         
874         memset(&tm, 0, sizeof(tm));
875         if (sscanf(s, "%02u%02u%02u%02u%02u%02u", 
876                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
877                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
878                 return 0;
879         }
880         if (tm.tm_year < 50) {
881                 tm.tm_year += 100;
882         }
883         tm.tm_mon -= 1;
884         
885         return timegm(&tm);
886 }
887
888
889 /*
890   dump a set of results to a file. Useful from within gdb
891 */
892 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
893 {
894         int i;
895
896         for (i = 0; i < result->count; i++) {
897                 struct ldb_ldif ldif;
898                 fprintf(f, "# record %d\n", i+1);
899                 ldif.changetype = LDB_CHANGETYPE_NONE;
900                 ldif.msg = result->msgs[i];
901                 ldb_ldif_write_file(ldb, f, &ldif);
902         }
903 }
904
905 /*
906   checks for a string attribute. Returns "1" on match and otherwise "0".
907 */
908 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
909                                    const char *name, const char *value)
910 {
911         struct ldb_message_element *el;
912         struct ldb_val val;
913         
914         el = ldb_msg_find_element(msg, name);
915         if (el == NULL) {
916                 return 0;
917         }
918
919         val.data = discard_const_p(uint8_t, value);
920         val.length = strlen(value);
921
922         if (ldb_msg_find_val(el, &val)) {
923                 return 1;
924         }
925
926         return 0;
927 }
928