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