806f0e872d5613b1e2469429103508e849312b1d
[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   canonicalise 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         unsigned int i;
586         struct ldb_message *msg2;
587
588         msg2 = ldb_msg_copy(ldb, msg);
589         if (msg2 == NULL) return NULL;
590
591         ldb_msg_sort_elements(msg2);
592
593         for (i=1;i<msg2->num_elements;i++) {
594                 struct ldb_message_element *el1 = &msg2->elements[i-1];
595                 struct ldb_message_element *el2 = &msg2->elements[i];
596                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
597                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
598                                                        el1->num_values + el2->num_values);
599                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
600                                 return NULL;
601                         }
602                         memcpy(el1->values + el1->num_values,
603                                el2->values,
604                                sizeof(struct ldb_val) * el2->num_values);
605                         el1->num_values += el2->num_values;
606                         talloc_free(discard_const_p(char, el2->name));
607                         if (i+1<msg2->num_elements) {
608                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
609                                         (msg2->num_elements - (i+1)));
610                         }
611                         msg2->num_elements--;
612                         i--;
613                 }
614         }
615
616         return msg2;
617 }
618
619 /**
620  * Canonicalize a message, merging elements of the same name
621  */
622 int ldb_msg_canonicalize_ex(struct ldb_context *ldb,
623                             const struct ldb_message *msg,
624                             TALLOC_CTX *mem_ctx,
625                             struct ldb_message **_msg_out)
626 {
627         unsigned int i;
628         struct ldb_message *msg2;
629
630         msg2 = ldb_msg_copy(mem_ctx, msg);
631         if (msg2 == NULL) {
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         ldb_msg_sort_elements(msg2);
636
637         for (i=1; i < msg2->num_elements; i++) {
638                 struct ldb_message_element *el1 = &msg2->elements[i-1];
639                 struct ldb_message_element *el2 = &msg2->elements[i];
640
641                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
642                         el1->values = talloc_realloc(msg2->elements,
643                                                      el1->values, struct ldb_val,
644                                                      el1->num_values + el2->num_values);
645                         if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
646                                 talloc_free(msg2);
647                                 return LDB_ERR_OPERATIONS_ERROR;
648                         }
649                         memcpy(el1->values + el1->num_values,
650                                el2->values,
651                                sizeof(struct ldb_val) * el2->num_values);
652                         el1->num_values += el2->num_values;
653                         talloc_free(discard_const_p(char, el2->name));
654                         if ((i+1) < msg2->num_elements) {
655                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
656                                         (msg2->num_elements - (i+1)));
657                         }
658                         msg2->num_elements--;
659                         i--;
660                 }
661         }
662
663         *_msg_out = msg2;
664         return LDB_SUCCESS;
665 }
666
667
668 /*
669   return a ldb_message representing the differences between msg1 and msg2. If you
670   then use this in a ldb_modify() call it can be used to save edits to a message
671 */
672 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
673                                  struct ldb_message *msg1,
674                                  struct ldb_message *msg2)
675 {
676         int ldb_ret;
677         struct ldb_message *mod;
678
679         /* allocate mod message in NULL context
680          * so it should appear as 'leaked' in talloc reports */
681         ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2,
682                                   (TALLOC_CTX*)NULL, &mod);
683         if (ldb_ret != LDB_SUCCESS) {
684                 return NULL;
685         }
686
687         return mod;
688 }
689
690 /**
691  * return a ldb_message representing the differences between msg1 and msg2.
692  * If you then use this in a ldb_modify() call it can be used to save edits to a message
693  *
694  * Result message is constructed as follows:
695  * - LDB_FLAG_MOD_ADD     - elements found only in msg2
696  * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
697  *                          Value for msg2 element is used
698  * - LDB_FLAG_MOD_DELETE  - elements found only in msg2
699  *
700  * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
701  */
702 int ldb_msg_diff_ex(struct ldb_context *ldb,
703                     struct ldb_message *msg1,
704                     struct ldb_message *msg2,
705                     TALLOC_CTX *mem_ctx,
706                     struct ldb_message **_msg_out)
707 {
708         int ldb_res;
709         unsigned int i;
710         struct ldb_message *mod;
711         struct ldb_message_element *el;
712         TALLOC_CTX *temp_ctx;
713
714         temp_ctx = talloc_new(mem_ctx);
715         if (!temp_ctx) {
716                 return LDB_ERR_OPERATIONS_ERROR;
717         }
718
719         mod = ldb_msg_new(temp_ctx);
720         if (mod == NULL) {
721                 goto failed;
722         }
723
724         mod->dn = msg1->dn;
725         mod->num_elements = 0;
726         mod->elements = NULL;
727
728         /* Canonicalize msg2 so we have no repeated elements
729          * Resulting message is allocated in mod's mem context,
730          * as we are going to move some elements from msg2 to
731          * mod object later */
732         ldb_res = ldb_msg_canonicalize_ex(ldb, msg2, (TALLOC_CTX*)mod, &msg2);
733         if (ldb_res != LDB_SUCCESS) {
734                 goto failed;
735         }
736
737         /* look in msg2 to find elements that need to be added
738            or modified */
739         for (i=0;i<msg2->num_elements;i++) {
740                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
741
742                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
743                         continue;
744                 }
745
746                 ldb_res = ldb_msg_add(mod,
747                                       &msg2->elements[i],
748                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
749                 if (ldb_res != LDB_SUCCESS) {
750                         goto failed;
751                 }
752         }
753
754         /* look in msg1 to find elements that need to be deleted */
755         for (i=0;i<msg1->num_elements;i++) {
756                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
757                 if (el == NULL) {
758                         ldb_res = ldb_msg_add_empty(mod,
759                                                     msg1->elements[i].name,
760                                                     LDB_FLAG_MOD_DELETE, NULL);
761                         if (ldb_res != LDB_SUCCESS) {
762                                 goto failed;
763                         }
764                 }
765         }
766
767         /* steal resulting message into supplied context */
768         talloc_steal(mem_ctx, mod);
769         *_msg_out = mod;
770
771         talloc_free(temp_ctx);
772         return LDB_SUCCESS;
773
774 failed:
775         talloc_free(temp_ctx);
776         return LDB_ERR_OPERATIONS_ERROR;
777 }
778
779
780 int ldb_msg_sanity_check(struct ldb_context *ldb, 
781                          const struct ldb_message *msg)
782 {
783         unsigned int i, j;
784
785         /* basic check on DN */
786         if (msg->dn == NULL) {
787                 /* TODO: return also an error string */
788                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
789                 return LDB_ERR_INVALID_DN_SYNTAX;
790         }
791
792         /* basic syntax checks */
793         for (i = 0; i < msg->num_elements; i++) {
794                 for (j = 0; j < msg->elements[i].num_values; j++) {
795                         if (msg->elements[i].values[j].length == 0) {
796                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
797                                 /* an attribute cannot be empty */
798                                 /* TODO: return also an error string */
799                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
800                                                             msg->elements[i].name, 
801                                                             ldb_dn_get_linearized(msg->dn));
802                                 talloc_free(mem_ctx);
803                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
804                         }
805                 }
806         }
807
808         return LDB_SUCCESS;
809 }
810
811
812
813
814 /*
815   copy an attribute list. This only copies the array, not the elements
816   (ie. the elements are left as the same pointers)
817 */
818 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
819 {
820         const char **ret;
821         unsigned int i;
822
823         for (i=0;attrs && attrs[i];i++) /* noop */ ;
824         ret = talloc_array(mem_ctx, const char *, i+1);
825         if (ret == NULL) {
826                 return NULL;
827         }
828         for (i=0;attrs && attrs[i];i++) {
829                 ret[i] = attrs[i];
830         }
831         ret[i] = attrs[i];
832         return ret;
833 }
834
835
836 /*
837   copy an attribute list. This only copies the array, not the elements
838   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
839 */
840 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
841 {
842         const char **ret;
843         unsigned int i;
844         bool found = false;
845
846         for (i=0;attrs && attrs[i];i++) {
847                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
848                         found = true;
849                 }
850         }
851         if (found) {
852                 return ldb_attr_list_copy(mem_ctx, attrs);
853         }
854         ret = talloc_array(mem_ctx, const char *, i+2);
855         if (ret == NULL) {
856                 return NULL;
857         }
858         for (i=0;attrs && attrs[i];i++) {
859                 ret[i] = attrs[i];
860         }
861         ret[i] = new_attr;
862         ret[i+1] = NULL;
863         return ret;
864 }
865
866
867 /*
868   return 1 if an attribute is in a list of attributes, or 0 otherwise
869 */
870 int ldb_attr_in_list(const char * const *attrs, const char *attr)
871 {
872         unsigned int i;
873         for (i=0;attrs && attrs[i];i++) {
874                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
875                         return 1;
876                 }
877         }
878         return 0;
879 }
880
881
882 /*
883   rename the specified attribute in a search result
884 */
885 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
886 {
887         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
888         if (el == NULL) {
889                 return LDB_SUCCESS;
890         }
891         el->name = talloc_strdup(msg->elements, replace);
892         if (el->name == NULL) {
893                 return LDB_ERR_OPERATIONS_ERROR;
894         }
895         return LDB_SUCCESS;
896 }
897
898
899 /*
900   copy the specified attribute in a search result to a new attribute
901 */
902 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
903 {
904         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
905         if (el == NULL) {
906                 return LDB_SUCCESS;
907         }
908         if (ldb_msg_add(msg, el, 0) != 0) {
909                 return LDB_ERR_OPERATIONS_ERROR;
910         }
911         return ldb_msg_rename_attr(msg, attr, replace);
912 }
913
914 /*
915   remove the specified element in a search result
916 */
917 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
918 {
919         ptrdiff_t n = (el - msg->elements);
920         if (n >= msg->num_elements) {
921                 /* should we abort() here? */
922                 return;
923         }
924         if (n != msg->num_elements-1) {
925                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
926         }
927         msg->num_elements--;
928 }
929
930
931 /*
932   remove the specified attribute in a search result
933 */
934 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
935 {
936         struct ldb_message_element *el;
937
938         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
939                 ldb_msg_remove_element(msg, el);
940         }
941 }
942
943 /*
944   return a LDAP formatted GeneralizedTime string
945 */
946 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
947 {
948         struct tm *tm = gmtime(&t);
949         char *ts;
950         int r;
951
952         if (!tm) {
953                 return NULL;
954         }
955
956         /* we now excatly how long this string will be */
957         ts = talloc_array(mem_ctx, char, 18);
958
959         /* formatted like: 20040408072012.0Z */
960         r = snprintf(ts, 18,
961                         "%04u%02u%02u%02u%02u%02u.0Z",
962                         tm->tm_year+1900, tm->tm_mon+1,
963                         tm->tm_mday, tm->tm_hour, tm->tm_min,
964                         tm->tm_sec);
965
966         if (r != 17) {
967                 talloc_free(ts);
968                 return NULL;
969         }
970
971         return ts;
972 }
973
974 /*
975   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
976 */
977 time_t ldb_string_to_time(const char *s)
978 {
979         struct tm tm;
980         
981         if (s == NULL) return 0;
982         
983         memset(&tm, 0, sizeof(tm));
984         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
985                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
986                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
987                 return 0;
988         }
989         tm.tm_year -= 1900;
990         tm.tm_mon -= 1;
991         
992         return timegm(&tm);
993 }
994
995 /*
996   convert a LDAP GeneralizedTime string in ldb_val format to a
997   time_t.
998 */
999 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1000 {
1001         struct tm tm;
1002
1003         if (v == NULL || !v->data || v->length < 17) {
1004                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1005         }
1006
1007         memset(&tm, 0, sizeof(tm));
1008
1009         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1010                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1011                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1012                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1013         }
1014         tm.tm_year -= 1900;
1015         tm.tm_mon -= 1;
1016
1017         *t = timegm(&tm);
1018
1019         return LDB_SUCCESS;
1020 }
1021
1022 /*
1023   return a LDAP formatted UTCTime string
1024 */
1025 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1026 {
1027         struct tm *tm = gmtime(&t);
1028         char *ts;
1029         int r;
1030
1031         if (!tm) {
1032                 return NULL;
1033         }
1034
1035         /* we now excatly how long this string will be */
1036         ts = talloc_array(mem_ctx, char, 14);
1037
1038         /* formatted like: 20040408072012.0Z => 040408072012Z */
1039         r = snprintf(ts, 14,
1040                         "%02u%02u%02u%02u%02u%02uZ",
1041                         (tm->tm_year+1900)%100, tm->tm_mon+1,
1042                         tm->tm_mday, tm->tm_hour, tm->tm_min,
1043                         tm->tm_sec);
1044
1045         if (r != 13) {
1046                 talloc_free(ts);
1047                 return NULL;
1048         }
1049
1050         return ts;
1051 }
1052
1053 /*
1054   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1055 */
1056 time_t ldb_string_utc_to_time(const char *s)
1057 {
1058         struct tm tm;
1059         
1060         if (s == NULL) return 0;
1061         
1062         memset(&tm, 0, sizeof(tm));
1063         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1064                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1065                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1066                 return 0;
1067         }
1068         if (tm.tm_year < 50) {
1069                 tm.tm_year += 100;
1070         }
1071         tm.tm_mon -= 1;
1072         
1073         return timegm(&tm);
1074 }
1075
1076
1077 /*
1078   dump a set of results to a file. Useful from within gdb
1079 */
1080 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1081 {
1082         unsigned int i;
1083
1084         for (i = 0; i < result->count; i++) {
1085                 struct ldb_ldif ldif;
1086                 fprintf(f, "# record %d\n", i+1);
1087                 ldif.changetype = LDB_CHANGETYPE_NONE;
1088                 ldif.msg = result->msgs[i];
1089                 ldb_ldif_write_file(ldb, f, &ldif);
1090         }
1091 }
1092
1093 /*
1094   checks for a string attribute. Returns "1" on match and otherwise "0".
1095 */
1096 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1097                                    const char *name, const char *value)
1098 {
1099         struct ldb_message_element *el;
1100         struct ldb_val val;
1101         
1102         el = ldb_msg_find_element(msg, name);
1103         if (el == NULL) {
1104                 return 0;
1105         }
1106
1107         val.data = discard_const_p(uint8_t, value);
1108         val.length = strlen(value);
1109
1110         if (ldb_msg_find_val(el, &val)) {
1111                 return 1;
1112         }
1113
1114         return 0;
1115 }
1116