s4-ldb: Add ldb_msg_canonicalize_ex() to accept a memory context from client
[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
729          * repeated elements */
730         msg2 = ldb_msg_canonicalize(ldb, msg2);
731         if (msg2 == NULL) {
732                 goto failed;
733         }
734
735         /* steal msg2 into mod context as it is
736          * allocated in ldb's context */
737         talloc_steal(mod, msg2);
738
739         /* look in msg2 to find elements that need to be added
740            or modified */
741         for (i=0;i<msg2->num_elements;i++) {
742                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
743
744                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
745                         continue;
746                 }
747
748                 ldb_res = ldb_msg_add(mod,
749                                       &msg2->elements[i],
750                                       el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
751                 if (ldb_res != LDB_SUCCESS) {
752                         goto failed;
753                 }
754         }
755
756         /* look in msg1 to find elements that need to be deleted */
757         for (i=0;i<msg1->num_elements;i++) {
758                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
759                 if (el == NULL) {
760                         ldb_res = ldb_msg_add_empty(mod,
761                                                     msg1->elements[i].name,
762                                                     LDB_FLAG_MOD_DELETE, NULL);
763                         if (ldb_res != LDB_SUCCESS) {
764                                 goto failed;
765                         }
766                 }
767         }
768
769         /* steal resulting message into supplied context */
770         talloc_steal(mem_ctx, mod);
771         *_msg_out = mod;
772
773         talloc_free(temp_ctx);
774         return LDB_SUCCESS;
775
776 failed:
777         talloc_free(temp_ctx);
778         return LDB_ERR_OPERATIONS_ERROR;
779 }
780
781
782 int ldb_msg_sanity_check(struct ldb_context *ldb, 
783                          const struct ldb_message *msg)
784 {
785         unsigned int i, j;
786
787         /* basic check on DN */
788         if (msg->dn == NULL) {
789                 /* TODO: return also an error string */
790                 ldb_set_errstring(ldb, "ldb message lacks a DN!");
791                 return LDB_ERR_INVALID_DN_SYNTAX;
792         }
793
794         /* basic syntax checks */
795         for (i = 0; i < msg->num_elements; i++) {
796                 for (j = 0; j < msg->elements[i].num_values; j++) {
797                         if (msg->elements[i].values[j].length == 0) {
798                                 TALLOC_CTX *mem_ctx = talloc_new(ldb);
799                                 /* an attribute cannot be empty */
800                                 /* TODO: return also an error string */
801                                 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
802                                                             msg->elements[i].name, 
803                                                             ldb_dn_get_linearized(msg->dn));
804                                 talloc_free(mem_ctx);
805                                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
806                         }
807                 }
808         }
809
810         return LDB_SUCCESS;
811 }
812
813
814
815
816 /*
817   copy an attribute list. This only copies the array, not the elements
818   (ie. the elements are left as the same pointers)
819 */
820 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
821 {
822         const char **ret;
823         unsigned int i;
824
825         for (i=0;attrs && attrs[i];i++) /* noop */ ;
826         ret = talloc_array(mem_ctx, const char *, i+1);
827         if (ret == NULL) {
828                 return NULL;
829         }
830         for (i=0;attrs && attrs[i];i++) {
831                 ret[i] = attrs[i];
832         }
833         ret[i] = attrs[i];
834         return ret;
835 }
836
837
838 /*
839   copy an attribute list. This only copies the array, not the elements
840   (ie. the elements are left as the same pointers).  The new attribute is added to the list.
841 */
842 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
843 {
844         const char **ret;
845         unsigned int i;
846         bool found = false;
847
848         for (i=0;attrs && attrs[i];i++) {
849                 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
850                         found = true;
851                 }
852         }
853         if (found) {
854                 return ldb_attr_list_copy(mem_ctx, attrs);
855         }
856         ret = talloc_array(mem_ctx, const char *, i+2);
857         if (ret == NULL) {
858                 return NULL;
859         }
860         for (i=0;attrs && attrs[i];i++) {
861                 ret[i] = attrs[i];
862         }
863         ret[i] = new_attr;
864         ret[i+1] = NULL;
865         return ret;
866 }
867
868
869 /*
870   return 1 if an attribute is in a list of attributes, or 0 otherwise
871 */
872 int ldb_attr_in_list(const char * const *attrs, const char *attr)
873 {
874         unsigned int i;
875         for (i=0;attrs && attrs[i];i++) {
876                 if (ldb_attr_cmp(attrs[i], attr) == 0) {
877                         return 1;
878                 }
879         }
880         return 0;
881 }
882
883
884 /*
885   rename the specified attribute in a search result
886 */
887 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
888 {
889         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
890         if (el == NULL) {
891                 return LDB_SUCCESS;
892         }
893         el->name = talloc_strdup(msg->elements, replace);
894         if (el->name == NULL) {
895                 return LDB_ERR_OPERATIONS_ERROR;
896         }
897         return LDB_SUCCESS;
898 }
899
900
901 /*
902   copy the specified attribute in a search result to a new attribute
903 */
904 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
905 {
906         struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
907         if (el == NULL) {
908                 return LDB_SUCCESS;
909         }
910         if (ldb_msg_add(msg, el, 0) != 0) {
911                 return LDB_ERR_OPERATIONS_ERROR;
912         }
913         return ldb_msg_rename_attr(msg, attr, replace);
914 }
915
916 /*
917   remove the specified element in a search result
918 */
919 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
920 {
921         ptrdiff_t n = (el - msg->elements);
922         if (n >= msg->num_elements) {
923                 /* should we abort() here? */
924                 return;
925         }
926         if (n != msg->num_elements-1) {
927                 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
928         }
929         msg->num_elements--;
930 }
931
932
933 /*
934   remove the specified attribute in a search result
935 */
936 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
937 {
938         struct ldb_message_element *el;
939
940         while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
941                 ldb_msg_remove_element(msg, el);
942         }
943 }
944
945 /*
946   return a LDAP formatted GeneralizedTime string
947 */
948 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
949 {
950         struct tm *tm = gmtime(&t);
951         char *ts;
952         int r;
953
954         if (!tm) {
955                 return NULL;
956         }
957
958         /* we now excatly how long this string will be */
959         ts = talloc_array(mem_ctx, char, 18);
960
961         /* formatted like: 20040408072012.0Z */
962         r = snprintf(ts, 18,
963                         "%04u%02u%02u%02u%02u%02u.0Z",
964                         tm->tm_year+1900, tm->tm_mon+1,
965                         tm->tm_mday, tm->tm_hour, tm->tm_min,
966                         tm->tm_sec);
967
968         if (r != 17) {
969                 talloc_free(ts);
970                 return NULL;
971         }
972
973         return ts;
974 }
975
976 /*
977   convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
978 */
979 time_t ldb_string_to_time(const char *s)
980 {
981         struct tm tm;
982         
983         if (s == NULL) return 0;
984         
985         memset(&tm, 0, sizeof(tm));
986         if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
987                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
988                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
989                 return 0;
990         }
991         tm.tm_year -= 1900;
992         tm.tm_mon -= 1;
993         
994         return timegm(&tm);
995 }
996
997 /*
998   convert a LDAP GeneralizedTime string in ldb_val format to a
999   time_t.
1000 */
1001 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1002 {
1003         struct tm tm;
1004
1005         if (v == NULL || !v->data || v->length < 17) {
1006                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1007         }
1008
1009         memset(&tm, 0, sizeof(tm));
1010
1011         if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1012                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1013                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1014                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1015         }
1016         tm.tm_year -= 1900;
1017         tm.tm_mon -= 1;
1018
1019         *t = timegm(&tm);
1020
1021         return LDB_SUCCESS;
1022 }
1023
1024 /*
1025   return a LDAP formatted UTCTime string
1026 */
1027 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1028 {
1029         struct tm *tm = gmtime(&t);
1030         char *ts;
1031         int r;
1032
1033         if (!tm) {
1034                 return NULL;
1035         }
1036
1037         /* we now excatly how long this string will be */
1038         ts = talloc_array(mem_ctx, char, 14);
1039
1040         /* formatted like: 20040408072012.0Z => 040408072012Z */
1041         r = snprintf(ts, 14,
1042                         "%02u%02u%02u%02u%02u%02uZ",
1043                         (tm->tm_year+1900)%100, tm->tm_mon+1,
1044                         tm->tm_mday, tm->tm_hour, tm->tm_min,
1045                         tm->tm_sec);
1046
1047         if (r != 13) {
1048                 talloc_free(ts);
1049                 return NULL;
1050         }
1051
1052         return ts;
1053 }
1054
1055 /*
1056   convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1057 */
1058 time_t ldb_string_utc_to_time(const char *s)
1059 {
1060         struct tm tm;
1061         
1062         if (s == NULL) return 0;
1063         
1064         memset(&tm, 0, sizeof(tm));
1065         if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1066                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
1067                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1068                 return 0;
1069         }
1070         if (tm.tm_year < 50) {
1071                 tm.tm_year += 100;
1072         }
1073         tm.tm_mon -= 1;
1074         
1075         return timegm(&tm);
1076 }
1077
1078
1079 /*
1080   dump a set of results to a file. Useful from within gdb
1081 */
1082 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1083 {
1084         unsigned int i;
1085
1086         for (i = 0; i < result->count; i++) {
1087                 struct ldb_ldif ldif;
1088                 fprintf(f, "# record %d\n", i+1);
1089                 ldif.changetype = LDB_CHANGETYPE_NONE;
1090                 ldif.msg = result->msgs[i];
1091                 ldb_ldif_write_file(ldb, f, &ldif);
1092         }
1093 }
1094
1095 /*
1096   checks for a string attribute. Returns "1" on match and otherwise "0".
1097 */
1098 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1099                                    const char *name, const char *value)
1100 {
1101         struct ldb_message_element *el;
1102         struct ldb_val val;
1103         
1104         el = ldb_msg_find_element(msg, name);
1105         if (el == NULL) {
1106                 return 0;
1107         }
1108
1109         val.data = discard_const_p(uint8_t, value);
1110         val.length = strlen(value);
1111
1112         if (ldb_msg_find_val(el, &val)) {
1113                 return 1;
1114         }
1115
1116         return 0;
1117 }
1118