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