ldb:ldb_msg_add_steal_string - prevent also there the addition of strings with length 0
[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) != 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 senistive 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                                        void *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 = ldb_msg_find_element(msg, attr);
802         if (el) {
803                 ldb_msg_remove_element(msg, el);
804         }
805 }
806
807 /*
808   return a LDAP formatted GeneralizedTime string
809 */
810 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
811 {
812         struct tm *tm = gmtime(&t);
813         char *ts;
814         int r;
815
816         if (!tm) {
817                 return NULL;
818         }
819
820         /* we now excatly how long this string will be */
821         ts = talloc_array(mem_ctx, char, 18);
822
823         /* formatted like: 20040408072012.0Z */
824         r = snprintf(ts, 18,
825                         "%04u%02u%02u%02u%02u%02u.0Z",
826                         tm->tm_year+1900, tm->tm_mon+1,
827                         tm->tm_mday, tm->tm_hour, tm->tm_min,
828                         tm->tm_sec);
829
830         if (r != 17) {
831                 talloc_free(ts);
832                 return NULL;
833         }
834
835         return ts;
836 }
837
838 /*
839   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
840 */
841 time_t ldb_string_to_time(const char *s)
842 {
843         struct tm tm;
844         
845         if (s == NULL) return 0;
846         
847         memset(&tm, 0, sizeof(tm));
848         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
849                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
850                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
851                 return 0;
852         }
853         tm.tm_year -= 1900;
854         tm.tm_mon -= 1;
855         
856         return timegm(&tm);
857 }
858
859 /*
860   convert a LDAP GeneralizedTime string in ldb_val format to a
861   time_t.
862 */
863 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
864 {
865         struct tm tm;
866
867         if (v == NULL || !v->data || v->length < 17) {
868                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
869         }
870
871         memset(&tm, 0, sizeof(tm));
872
873         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
874                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
875                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
876                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
877         }
878         tm.tm_year -= 1900;
879         tm.tm_mon -= 1;
880
881         *t = timegm(&tm);
882
883         return LDB_SUCCESS;
884 }
885
886 /*
887   return a LDAP formatted UTCTime string
888 */
889 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
890 {
891         struct tm *tm = gmtime(&t);
892         char *ts;
893         int r;
894
895         if (!tm) {
896                 return NULL;
897         }
898
899         /* we now excatly how long this string will be */
900         ts = talloc_array(mem_ctx, char, 14);
901
902         /* formatted like: 20040408072012.0Z => 040408072012Z */
903         r = snprintf(ts, 14,
904                         "%02u%02u%02u%02u%02u%02uZ",
905                         (tm->tm_year+1900)%100, tm->tm_mon+1,
906                         tm->tm_mday, tm->tm_hour, tm->tm_min,
907                         tm->tm_sec);
908
909         if (r != 13) {
910                 talloc_free(ts);
911                 return NULL;
912         }
913
914         return ts;
915 }
916
917 /*
918   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
919 */
920 time_t ldb_string_utc_to_time(const char *s)
921 {
922         struct tm tm;
923         
924         if (s == NULL) return 0;
925         
926         memset(&tm, 0, sizeof(tm));
927         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
928                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
929                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
930                 return 0;
931         }
932         if (tm.tm_year < 50) {
933                 tm.tm_year += 100;
934         }
935         tm.tm_mon -= 1;
936         
937         return timegm(&tm);
938 }
939
940
941 /*
942   dump a set of results to a file. Useful from within gdb
943 */
944 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
945 {
946         unsigned int i;
947
948         for (i = 0; i < result->count; i++) {
949                 struct ldb_ldif ldif;
950                 fprintf(f, "# record %d\n", i+1);
951                 ldif.changetype = LDB_CHANGETYPE_NONE;
952                 ldif.msg = result->msgs[i];
953                 ldb_ldif_write_file(ldb, f, &ldif);
954         }
955 }
956
957 /*
958   checks for a string attribute. Returns "1" on match and otherwise "0".
959 */
960 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
961                                    const char *name, const char *value)
962 {
963         struct ldb_message_element *el;
964         struct ldb_val val;
965         
966         el = ldb_msg_find_element(msg, name);
967         if (el == NULL) {
968                 return 0;
969         }
970
971         val.data = discard_const_p(uint8_t, value);
972         val.length = strlen(value);
973
974         if (ldb_msg_find_val(el, &val)) {
975                 return 1;
976         }
977
978         return 0;
979 }
980