s4-ldb: Refactor ldb_msg_canonicalize() to be based on ldb_msg_canonicalize_ex()...
[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  * Adds new empty element to msg->elements
119  */
120 static int _ldb_msg_add_el(struct ldb_message *msg,
121                            struct ldb_message_element **return_el)
122 {
123         struct ldb_message_element *els;
124
125         /* TODO: Find out a way to assert
126          * on input parameters.
127          * msg and return_el must be valid */
128
129         els = talloc_realloc(msg, msg->elements,
130                              struct ldb_message_element, msg->num_elements + 1);
131         if (!els) {
132                 errno = ENOMEM;
133                 return LDB_ERR_OPERATIONS_ERROR;
134         }
135
136         ZERO_STRUCT(els[msg->num_elements]);
137
138         msg->elements = els;
139         msg->num_elements++;
140
141         *return_el = &els[msg->num_elements-1];
142
143         return LDB_SUCCESS;
144 }
145
146 /**
147  * Add an empty element with a given name to a message
148  */
149 int ldb_msg_add_empty(struct ldb_message *msg,
150                       const char *attr_name,
151                       int flags,
152                       struct ldb_message_element **return_el)
153 {
154         int ret;
155         struct ldb_message_element *el;
156
157         ret = _ldb_msg_add_el(msg, &el);
158         if (ret != LDB_SUCCESS) {
159                 return ret;
160         }
161
162         /* initialize newly added element */
163         el->flags = flags;
164         el->name = talloc_strdup(msg->elements, attr_name);
165         if (!el->name) {
166                 errno = ENOMEM;
167                 return LDB_ERR_OPERATIONS_ERROR;
168         }
169
170         if (return_el) {
171                 *return_el = el;
172         }
173
174         return LDB_SUCCESS;
175 }
176
177 /**
178  * Adds an element to a message.
179  *
180  * NOTE: Ownership of ldb_message_element fields
181  *       is NOT transferred. Thus, if el pointer
182  *       is invalidated for some reason, this will
183  *       corrupt msg contents also
184  */
185 int ldb_msg_add(struct ldb_message *msg, 
186                 const struct ldb_message_element *el, 
187                 int flags)
188 {
189         int ret;
190         struct ldb_message_element *el_new;
191         /* We have to copy this, just in case *el is a pointer into
192          * what ldb_msg_add_empty() is about to realloc() */
193         struct ldb_message_element el_copy = *el;
194
195         ret = _ldb_msg_add_el(msg, &el_new);
196         if (ret != LDB_SUCCESS) {
197                 return ret;
198         }
199
200         el_new->flags      = flags;
201         el_new->name       = el_copy.name;
202         el_new->num_values = el_copy.num_values;
203         el_new->values     = el_copy.values;
204
205         return LDB_SUCCESS;
206 }
207
208 /*
209   add a value to a message
210 */
211 int ldb_msg_add_value(struct ldb_message *msg, 
212                       const char *attr_name,
213                       const struct ldb_val *val,
214                       struct ldb_message_element **return_el)
215 {
216         struct ldb_message_element *el;
217         struct ldb_val *vals;
218         int ret;
219
220         el = ldb_msg_find_element(msg, attr_name);
221         if (!el) {
222                 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
223                 if (ret != LDB_SUCCESS) {
224                         return ret;
225                 }
226         }
227
228         vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
229         if (!vals) {
230                 errno = ENOMEM;
231                 return LDB_ERR_OPERATIONS_ERROR;
232         }
233         el->values = vals;
234         el->values[el->num_values] = *val;
235         el->num_values++;
236
237         if (return_el) {
238                 *return_el = el;
239         }
240
241         return LDB_SUCCESS;
242 }
243
244
245 /*
246   add a value to a message, stealing it into the 'right' place
247 */
248 int ldb_msg_add_steal_value(struct ldb_message *msg, 
249                             const char *attr_name,
250                             struct ldb_val *val)
251 {
252         int ret;
253         struct ldb_message_element *el;
254
255         ret = ldb_msg_add_value(msg, attr_name, val, &el);
256         if (ret == LDB_SUCCESS) {
257                 talloc_steal(el->values, val->data);
258         }
259         return ret;
260 }
261
262
263 /*
264   add a string element to a message
265 */
266 int ldb_msg_add_string(struct ldb_message *msg, 
267                        const char *attr_name, const char *str)
268 {
269         struct ldb_val val;
270
271         val.data = discard_const_p(uint8_t, str);
272         val.length = strlen(str);
273
274         if (val.length == 0) {
275                 /* allow empty strings as non-existent attributes */
276                 return LDB_SUCCESS;
277         }
278
279         return ldb_msg_add_value(msg, attr_name, &val, NULL);
280 }
281
282 /*
283   add a string element to a message, stealing it into the 'right' place
284 */
285 int ldb_msg_add_steal_string(struct ldb_message *msg, 
286                              const char *attr_name, char *str)
287 {
288         struct ldb_val val;
289
290         val.data = (uint8_t *)str;
291         val.length = strlen(str);
292
293         if (val.length == 0) {
294                 /* allow empty strings as non-existent attributes */
295                 return LDB_SUCCESS;
296         }
297
298         return ldb_msg_add_steal_value(msg, attr_name, &val);
299 }
300
301 /*
302   add a DN element to a message
303   WARNING: this uses the linearized string from the dn, and does not
304   copy the string.
305 */
306 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
307                               struct ldb_dn *dn)
308 {
309         return ldb_msg_add_steal_string(msg, attr_name,
310                                         ldb_dn_alloc_linearized(msg, dn));
311 }
312
313 /*
314   add a printf formatted element to a message
315 */
316 int ldb_msg_add_fmt(struct ldb_message *msg, 
317                     const char *attr_name, const char *fmt, ...)
318 {
319         struct ldb_val val;
320         va_list ap;
321         char *str;
322
323         va_start(ap, fmt);
324         str = talloc_vasprintf(msg, fmt, ap);
325         va_end(ap);
326
327         if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
328
329         val.data   = (uint8_t *)str;
330         val.length = strlen(str);
331
332         return ldb_msg_add_steal_value(msg, attr_name, &val);
333 }
334
335 /*
336   compare two ldb_message_element structures
337   assumes case sensitive comparison
338 */
339 int ldb_msg_element_compare(struct ldb_message_element *el1, 
340                             struct ldb_message_element *el2)
341 {
342         unsigned int i;
343
344         if (el1->num_values != el2->num_values) {
345                 return el1->num_values - el2->num_values;
346         }
347
348         for (i=0;i<el1->num_values;i++) {
349                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
350                         return -1;
351                 }
352         }
353
354         return 0;
355 }
356
357 /*
358   compare two ldb_message_element structures
359   comparing by element name
360 */
361 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
362                                  struct ldb_message_element *el2)
363 {
364         return ldb_attr_cmp(el1->name, el2->name);
365 }
366
367 /*
368   convenience functions to return common types from a message
369   these return the first value if the attribute is multi-valued
370 */
371 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, 
372                                            const char *attr_name)
373 {
374         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
375         if (!el || el->num_values == 0) {
376                 return NULL;
377         }
378         return &el->values[0];
379 }
380
381 int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
382                              const char *attr_name,
383                              int default_value)
384 {
385         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
386         if (!v || !v->data) {
387                 return default_value;
388         }
389         return strtol((const char *)v->data, NULL, 0);
390 }
391
392 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
393                                        const char *attr_name,
394                                        unsigned int default_value)
395 {
396         unsigned int ret;
397         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
398         if (!v || !v->data) {
399                 return default_value;
400         }
401
402         /* in LDAP there're only int32_t values */
403         errno = 0;
404         ret = strtol((const char *)v->data, NULL, 0);
405         if (errno == 0) {
406                 return ret;
407         }
408
409         return strtoul((const char *)v->data, NULL, 0);
410 }
411
412 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
413                                    const char *attr_name,
414                                    int64_t default_value)
415 {
416         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
417         if (!v || !v->data) {
418                 return default_value;
419         }
420         return strtoll((const char *)v->data, NULL, 0);
421 }
422
423 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
424                                      const char *attr_name,
425                                      uint64_t default_value)
426 {
427         uint64_t ret;
428         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
429         if (!v || !v->data) {
430                 return default_value;
431         }
432
433         /* in LDAP there're only int64_t values */
434         errno = 0;
435         ret = strtoll((const char *)v->data, NULL, 0);
436         if (errno == 0) {
437                 return ret;
438         }
439
440         return strtoull((const char *)v->data, NULL, 0);
441 }
442
443 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
444                                    const char *attr_name,
445                                    double default_value)
446 {
447         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
448         if (!v || !v->data) {
449                 return default_value;
450         }
451         return strtod((const char *)v->data, NULL);
452 }
453
454 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
455                               const char *attr_name,
456                               int default_value)
457 {
458         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
459         if (!v || !v->data) {
460                 return default_value;
461         }
462         if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
463                 return 0;
464         }
465         if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
466                 return 1;
467         }
468         return default_value;
469 }
470
471 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
472                                         const char *attr_name,
473                                         const char *default_value)
474 {
475         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
476         if (!v || !v->data) {
477                 return default_value;
478         }
479         return (const char *)v->data;
480 }
481
482 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
483                                        void *mem_ctx,
484                                        const struct ldb_message *msg,
485                                        const char *attr_name)
486 {
487         struct ldb_dn *res_dn;
488         const struct ldb_val *v;
489
490         v = ldb_msg_find_ldb_val(msg, attr_name);
491         if (!v || !v->data) {
492                 return NULL;
493         }
494         res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
495         if ( ! ldb_dn_validate(res_dn)) {
496                 talloc_free(res_dn);
497                 return NULL;
498         }
499         return res_dn;
500 }
501
502 /*
503   sort the elements of a message by name
504 */
505 void ldb_msg_sort_elements(struct ldb_message *msg)
506 {
507         TYPESAFE_QSORT(msg->elements, msg->num_elements,
508                        ldb_msg_element_compare_name);
509 }
510
511 /*
512   shallow copy a message - copying only the elements array so that the caller
513   can safely add new elements without changing the message
514 */
515 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, 
516                                          const struct ldb_message *msg)
517 {
518         struct ldb_message *msg2;
519         unsigned int i;
520
521         msg2 = talloc(mem_ctx, struct ldb_message);
522         if (msg2 == NULL) return NULL;
523
524         *msg2 = *msg;
525
526         msg2->elements = talloc_array(msg2, struct ldb_message_element, 
527                                       msg2->num_elements);
528         if (msg2->elements == NULL) goto failed;
529
530         for (i=0;i<msg2->num_elements;i++) {
531                 msg2->elements[i] = msg->elements[i];
532         }
533
534         return msg2;
535
536 failed:
537         talloc_free(msg2);
538         return NULL;
539 }
540
541
542 /*
543   copy a message, allocating new memory for all parts
544 */
545 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
546                                  const struct ldb_message *msg)
547 {
548         struct ldb_message *msg2;
549         unsigned int i, j;
550
551         msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
552         if (msg2 == NULL) return NULL;
553
554         msg2->dn = ldb_dn_copy(msg2, msg2->dn);
555         if (msg2->dn == NULL) goto failed;
556
557         for (i=0;i<msg2->num_elements;i++) {
558                 struct ldb_message_element *el = &msg2->elements[i];
559                 struct ldb_val *values = el->values;
560                 el->name = talloc_strdup(msg2->elements, el->name);
561                 if (el->name == NULL) goto failed;
562                 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
563                 for (j=0;j<el->num_values;j++) {
564                         el->values[j] = ldb_val_dup(el->values, &values[j]);
565                         if (el->values[j].data == NULL && values[j].length != 0) {
566                                 goto failed;
567                         }
568                 }
569         }
570
571         return msg2;
572
573 failed:
574         talloc_free(msg2);
575         return NULL;
576 }
577
578
579 /**
580  * Canonicalize a message, merging elements of the same name
581  */
582 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
583                                          const struct ldb_message *msg)
584 {
585         int ret;
586         struct ldb_message *msg2;
587
588         /* allocate msg2 message in NULL context
589          * so it should appear as 'leaked' in talloc reports */
590         ret = ldb_msg_canonicalize_ex(ldb, msg, (TALLOC_CTX*)NULL, &msg2);
591         if (ret != LDB_SUCCESS) {
592                 return NULL;
593         }
594
595         return msg2;
596 }
597
598 /**
599  * Canonicalize a message, merging elements of the same name
600  */
601 int ldb_msg_canonicalize_ex(struct ldb_context *ldb,
602                             const struct ldb_message *msg,
603                             TALLOC_CTX *mem_ctx,
604                             struct ldb_message **_msg_out)
605 {
606         unsigned int i;
607         struct ldb_message *msg2;
608
609         msg2 = ldb_msg_copy(mem_ctx, msg);
610         if (msg2 == NULL) {
611                 return LDB_ERR_OPERATIONS_ERROR;
612         }
613
614         ldb_msg_sort_elements(msg2);
615
616         for (i=1; i < msg2->num_elements; i++) {
617                 struct ldb_message_element *el1 = &msg2->elements[i-1];
618                 struct ldb_message_element *el2 = &msg2->elements[i];
619
620                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
621                         el1->values = talloc_realloc(msg2->elements,
622                                                      el1->values, struct ldb_val,
623                                                      el1->num_values + el2->num_values);
624                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
625                                 talloc_free(msg2);
626                                 return LDB_ERR_OPERATIONS_ERROR;
627                         }
628                         memcpy(el1->values + el1->num_values,
629                                el2->values,
630                                sizeof(struct ldb_val) * el2->num_values);
631                         el1->num_values += el2->num_values;
632                         talloc_free(discard_const_p(char, el2->name));
633                         if ((i+1) < msg2->num_elements) {
634                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
635                                         (msg2->num_elements - (i+1)));
636                         }
637                         msg2->num_elements--;
638                         i--;
639                 }
640         }
641
642         *_msg_out = msg2;
643         return LDB_SUCCESS;
644 }
645
646
647 /*
648   return a ldb_message representing the differences between msg1 and msg2. If you
649   then use this in a ldb_modify() call it can be used to save edits to a message
650 */
651 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
652                                  struct ldb_message *msg1,
653                                  struct ldb_message *msg2)
654 {
655         int ldb_ret;
656         struct ldb_message *mod;
657
658         /* allocate mod message in NULL context
659          * so it should appear as 'leaked' in talloc reports */
660         ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2,
661                                   (TALLOC_CTX*)NULL, &mod);
662         if (ldb_ret != LDB_SUCCESS) {
663                 return NULL;
664         }
665
666         return mod;
667 }
668
669 /**
670  * return a ldb_message representing the differences between msg1 and msg2.
671  * If you then use this in a ldb_modify() call it can be used to save edits to a message
672  *
673  * Result message is constructed as follows:
674  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
675  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
676  *                          Value for msg2 element is used
677  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
678  *
679  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
680  */
681 int ldb_msg_diff_ex(struct ldb_context *ldb,
682                     struct ldb_message *msg1,
683                     struct ldb_message *msg2,
684                     TALLOC_CTX *mem_ctx,
685                     struct ldb_message **_msg_out)
686 {
687         int ldb_res;
688         unsigned int i;
689         struct ldb_message *mod;
690         struct ldb_message_element *el;
691         TALLOC_CTX *temp_ctx;
692
693         temp_ctx = talloc_new(mem_ctx);
694         if (!temp_ctx) {
695                 return LDB_ERR_OPERATIONS_ERROR;
696         }
697
698         mod = ldb_msg_new(temp_ctx);
699         if (mod == NULL) {
700                 goto failed;
701         }
702
703         mod->dn = msg1->dn;
704         mod->num_elements = 0;
705         mod->elements = NULL;
706
707         /* Canonicalize msg2 so we have no repeated elements
708          * Resulting message is allocated in mod's mem context,
709          * as we are going to move some elements from msg2 to
710          * mod object later */
711         ldb_res = ldb_msg_canonicalize_ex(ldb, msg2, (TALLOC_CTX*)mod, &msg2);
712         if (ldb_res != LDB_SUCCESS) {
713                 goto failed;
714         }
715
716         /* look in msg2 to find elements that need to be added
717            or modified */
718         for (i=0;i<msg2->num_elements;i++) {
719                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
720
721                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
722                         continue;
723                 }
724
725                 ldb_res = ldb_msg_add(mod,
726                                       &msg2->elements[i],
727                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
728                 if (ldb_res != LDB_SUCCESS) {
729                         goto failed;
730                 }
731         }
732
733         /* look in msg1 to find elements that need to be deleted */
734         for (i=0;i<msg1->num_elements;i++) {
735                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
736                 if (el == NULL) {
737                         ldb_res = ldb_msg_add_empty(mod,
738                                                     msg1->elements[i].name,
739                                                     LDB_FLAG_MOD_DELETE, NULL);
740                         if (ldb_res != LDB_SUCCESS) {
741                                 goto failed;
742                         }
743                 }
744         }
745
746         /* steal resulting message into supplied context */
747         talloc_steal(mem_ctx, mod);
748         *_msg_out = mod;
749
750         talloc_free(temp_ctx);
751         return LDB_SUCCESS;
752
753 failed:
754         talloc_free(temp_ctx);
755         return LDB_ERR_OPERATIONS_ERROR;
756 }
757
758
759 int ldb_msg_sanity_check(struct ldb_context *ldb, 
760                          const struct ldb_message *msg)
761 {
762         unsigned int i, j;
763
764         /* basic check on DN */
765         if (msg->dn == NULL) {
766                 /* TODO: return also an error string */
767                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
768                 return LDB_ERR_INVALID_DN_SYNTAX;
769         }
770
771         /* basic syntax checks */
772         for (i = 0; i < msg->num_elements; i++) {
773                 for (j = 0; j < msg->elements[i].num_values; j++) {
774                         if (msg->elements[i].values[j].length == 0) {
775                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
776                                 /* an attribute cannot be empty */
777                                 /* TODO: return also an error string */
778                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
779                                                             msg->elements[i].name, 
780                                                             ldb_dn_get_linearized(msg->dn));
781                                 talloc_free(mem_ctx);
782                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
783                         }
784                 }
785         }
786
787         return LDB_SUCCESS;
788 }
789
790
791
792
793 /*
794   copy an attribute list. This only copies the array, not the elements
795   (ie. the elements are left as the same pointers)
796 */
797 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
798 {
799         const char **ret;
800         unsigned int i;
801
802         for (i=0;attrs && attrs[i];i++) /* noop */ ;
803         ret = talloc_array(mem_ctx, const char *, i+1);
804         if (ret == NULL) {
805                 return NULL;
806         }
807         for (i=0;attrs && attrs[i];i++) {
808                 ret[i] = attrs[i];
809         }
810         ret[i] = attrs[i];
811         return ret;
812 }
813
814
815 /*
816   copy an attribute list. This only copies the array, not the elements
817   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
818 */
819 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
820 {
821         const char **ret;
822         unsigned int i;
823         bool found = false;
824
825         for (i=0;attrs && attrs[i];i++) {
826                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
827                         found = true;
828                 }
829         }
830         if (found) {
831                 return ldb_attr_list_copy(mem_ctx, attrs);
832         }
833         ret = talloc_array(mem_ctx, const char *, i+2);
834         if (ret == NULL) {
835                 return NULL;
836         }
837         for (i=0;attrs && attrs[i];i++) {
838                 ret[i] = attrs[i];
839         }
840         ret[i] = new_attr;
841         ret[i+1] = NULL;
842         return ret;
843 }
844
845
846 /*
847   return 1 if an attribute is in a list of attributes, or 0 otherwise
848 */
849 int ldb_attr_in_list(const char * const *attrs, const char *attr)
850 {
851         unsigned int i;
852         for (i=0;attrs && attrs[i];i++) {
853                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
854                         return 1;
855                 }
856         }
857         return 0;
858 }
859
860
861 /*
862   rename the specified attribute in a search result
863 */
864 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
865 {
866         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
867         if (el == NULL) {
868                 return LDB_SUCCESS;
869         }
870         el->name = talloc_strdup(msg->elements, replace);
871         if (el->name == NULL) {
872                 return LDB_ERR_OPERATIONS_ERROR;
873         }
874         return LDB_SUCCESS;
875 }
876
877
878 /*
879   copy the specified attribute in a search result to a new attribute
880 */
881 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
882 {
883         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
884         if (el == NULL) {
885                 return LDB_SUCCESS;
886         }
887         if (ldb_msg_add(msg, el, 0) != 0) {
888                 return LDB_ERR_OPERATIONS_ERROR;
889         }
890         return ldb_msg_rename_attr(msg, attr, replace);
891 }
892
893 /*
894   remove the specified element in a search result
895 */
896 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
897 {
898         ptrdiff_t n = (el - msg->elements);
899         if (n >= msg->num_elements) {
900                 /* should we abort() here? */
901                 return;
902         }
903         if (n != msg->num_elements-1) {
904                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
905         }
906         msg->num_elements--;
907 }
908
909
910 /*
911   remove the specified attribute in a search result
912 */
913 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
914 {
915         struct ldb_message_element *el;
916
917         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
918                 ldb_msg_remove_element(msg, el);
919         }
920 }
921
922 /*
923   return a LDAP formatted GeneralizedTime string
924 */
925 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
926 {
927         struct tm *tm = gmtime(&t);
928         char *ts;
929         int r;
930
931         if (!tm) {
932                 return NULL;
933         }
934
935         /* we now excatly how long this string will be */
936         ts = talloc_array(mem_ctx, char, 18);
937
938         /* formatted like: 20040408072012.0Z */
939         r = snprintf(ts, 18,
940                         "%04u%02u%02u%02u%02u%02u.0Z",
941                         tm->tm_year+1900, tm->tm_mon+1,
942                         tm->tm_mday, tm->tm_hour, tm->tm_min,
943                         tm->tm_sec);
944
945         if (r != 17) {
946                 talloc_free(ts);
947                 return NULL;
948         }
949
950         return ts;
951 }
952
953 /*
954   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
955 */
956 time_t ldb_string_to_time(const char *s)
957 {
958         struct tm tm;
959         
960         if (s == NULL) return 0;
961         
962         memset(&tm, 0, sizeof(tm));
963         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
964                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
965                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
966                 return 0;
967         }
968         tm.tm_year -= 1900;
969         tm.tm_mon -= 1;
970         
971         return timegm(&tm);
972 }
973
974 /*
975   convert a LDAP GeneralizedTime string in ldb_val format to a
976   time_t.
977 */
978 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
979 {
980         struct tm tm;
981
982         if (v == NULL || !v->data || v->length < 17) {
983                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
984         }
985
986         memset(&tm, 0, sizeof(tm));
987
988         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
989                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
990                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
991                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
992         }
993         tm.tm_year -= 1900;
994         tm.tm_mon -= 1;
995
996         *t = timegm(&tm);
997
998         return LDB_SUCCESS;
999 }
1000
1001 /*
1002   return a LDAP formatted UTCTime string
1003 */
1004 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1005 {
1006         struct tm *tm = gmtime(&t);
1007         char *ts;
1008         int r;
1009
1010         if (!tm) {
1011                 return NULL;
1012         }
1013
1014         /* we now excatly how long this string will be */
1015         ts = talloc_array(mem_ctx, char, 14);
1016
1017         /* formatted like: 20040408072012.0Z => 040408072012Z */
1018         r = snprintf(ts, 14,
1019                         "%02u%02u%02u%02u%02u%02uZ",
1020                         (tm->tm_year+1900)%100, tm->tm_mon+1,
1021                         tm->tm_mday, tm->tm_hour, tm->tm_min,
1022                         tm->tm_sec);
1023
1024         if (r != 13) {
1025                 talloc_free(ts);
1026                 return NULL;
1027         }
1028
1029         return ts;
1030 }
1031
1032 /*
1033   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1034 */
1035 time_t ldb_string_utc_to_time(const char *s)
1036 {
1037         struct tm tm;
1038         
1039         if (s == NULL) return 0;
1040         
1041         memset(&tm, 0, sizeof(tm));
1042         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1043                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1044                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1045                 return 0;
1046         }
1047         if (tm.tm_year < 50) {
1048                 tm.tm_year += 100;
1049         }
1050         tm.tm_mon -= 1;
1051         
1052         return timegm(&tm);
1053 }
1054
1055
1056 /*
1057   dump a set of results to a file. Useful from within gdb
1058 */
1059 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1060 {
1061         unsigned int i;
1062
1063         for (i = 0; i < result->count; i++) {
1064                 struct ldb_ldif ldif;
1065                 fprintf(f, "# record %d\n", i+1);
1066                 ldif.changetype = LDB_CHANGETYPE_NONE;
1067                 ldif.msg = result->msgs[i];
1068                 ldb_ldif_write_file(ldb, f, &ldif);
1069         }
1070 }
1071
1072 /*
1073   checks for a string attribute. Returns "1" on match and otherwise "0".
1074 */
1075 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1076                                    const char *name, const char *value)
1077 {
1078         struct ldb_message_element *el;
1079         struct ldb_val val;
1080         
1081         el = ldb_msg_find_element(msg, name);
1082         if (el == NULL) {
1083                 return 0;
1084         }
1085
1086         val.data = discard_const_p(uint8_t, value);
1087         val.length = strlen(value);
1088
1089         if (ldb_msg_find_val(el, &val)) {
1090                 return 1;
1091         }
1092
1093         return 0;
1094 }
1095