s4-ldb: Implement ldb_msg_difference() function to accept a memory context from client
[Samba.git] / source4 / lib / ldb / common / ldb_msg.c
blob9f96ae6cbfd8509d16d2f71b408a5e418be6735f
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2004
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
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.
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.
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/>.
25 * Name: ldb
27 * Component: ldb message component utility functions
29 * Description: functions for manipulating ldb_message structures
31 * Author: Andrew Tridgell
34 #include "ldb_private.h"
37 create a new ldb_message in a given memory context (NULL for top level)
39 struct ldb_message *ldb_msg_new(void *mem_ctx)
41 return talloc_zero(mem_ctx, struct ldb_message);
45 find an element in a message by attribute name
47 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
48 const char *attr_name)
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];
56 return NULL;
60 see if two ldb_val structures contain exactly the same data
61 return 1 for a match, 0 for a mis-match
63 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
65 if (v1->length != v2->length) return 0;
66 if (v1->data == v2->data) return 1;
67 if (v1->length == 0) return 1;
69 if (memcmp(v1->data, v2->data, v1->length) == 0) {
70 return 1;
73 return 0;
77 find a value in an element
78 assumes case sensitive comparison
80 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
81 struct ldb_val *val)
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];
89 return NULL;
93 duplicate a ldb_val structure
95 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
97 struct ldb_val v2;
98 v2.length = v->length;
99 if (v->data == NULL) {
100 v2.data = NULL;
101 return v2;
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;
112 memcpy(v2.data, v->data, v->length);
113 ((char *)v2.data)[v->length] = 0;
114 return v2;
118 add an empty element to a message
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)
125 struct ldb_message_element *els;
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;
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;
143 msg->elements = els;
144 msg->num_elements++;
146 if (return_el) {
147 *return_el = &els[msg->num_elements-1];
150 return LDB_SUCCESS;
154 add an empty element to a message
156 int ldb_msg_add(struct ldb_message *msg,
157 const struct ldb_message_element *el,
158 int flags)
160 /* We have to copy this, just in case *el is a pointer into
161 * what ldb_msg_add_empty() is about to realloc() */
162 struct ldb_message_element el_copy = *el;
163 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != LDB_SUCCESS) {
164 return LDB_ERR_OPERATIONS_ERROR;
167 msg->elements[msg->num_elements-1] = el_copy;
168 msg->elements[msg->num_elements-1].flags = flags;
170 return LDB_SUCCESS;
174 add a value to a message
176 int ldb_msg_add_value(struct ldb_message *msg,
177 const char *attr_name,
178 const struct ldb_val *val,
179 struct ldb_message_element **return_el)
181 struct ldb_message_element *el;
182 struct ldb_val *vals;
183 int ret;
185 el = ldb_msg_find_element(msg, attr_name);
186 if (!el) {
187 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
188 if (ret != LDB_SUCCESS) {
189 return ret;
193 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
194 if (!vals) {
195 errno = ENOMEM;
196 return LDB_ERR_OPERATIONS_ERROR;
198 el->values = vals;
199 el->values[el->num_values] = *val;
200 el->num_values++;
202 if (return_el) {
203 *return_el = el;
206 return LDB_SUCCESS;
211 add a value to a message, stealing it into the 'right' place
213 int ldb_msg_add_steal_value(struct ldb_message *msg,
214 const char *attr_name,
215 struct ldb_val *val)
217 int ret;
218 struct ldb_message_element *el;
220 ret = ldb_msg_add_value(msg, attr_name, val, &el);
221 if (ret == LDB_SUCCESS) {
222 talloc_steal(el->values, val->data);
224 return ret;
229 add a string element to a message
231 int ldb_msg_add_string(struct ldb_message *msg,
232 const char *attr_name, const char *str)
234 struct ldb_val val;
236 val.data = discard_const_p(uint8_t, str);
237 val.length = strlen(str);
239 if (val.length == 0) {
240 /* allow empty strings as non-existent attributes */
241 return LDB_SUCCESS;
244 return ldb_msg_add_value(msg, attr_name, &val, NULL);
248 add a string element to a message, stealing it into the 'right' place
250 int ldb_msg_add_steal_string(struct ldb_message *msg,
251 const char *attr_name, char *str)
253 struct ldb_val val;
255 val.data = (uint8_t *)str;
256 val.length = strlen(str);
258 if (val.length == 0) {
259 /* allow empty strings as non-existent attributes */
260 return LDB_SUCCESS;
263 return ldb_msg_add_steal_value(msg, attr_name, &val);
267 add a DN element to a message
268 WARNING: this uses the linearized string from the dn, and does not
269 copy the string.
271 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
272 struct ldb_dn *dn)
274 return ldb_msg_add_steal_string(msg, attr_name,
275 ldb_dn_alloc_linearized(msg, dn));
279 add a printf formatted element to a message
281 int ldb_msg_add_fmt(struct ldb_message *msg,
282 const char *attr_name, const char *fmt, ...)
284 struct ldb_val val;
285 va_list ap;
286 char *str;
288 va_start(ap, fmt);
289 str = talloc_vasprintf(msg, fmt, ap);
290 va_end(ap);
292 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
294 val.data = (uint8_t *)str;
295 val.length = strlen(str);
297 return ldb_msg_add_steal_value(msg, attr_name, &val);
301 compare two ldb_message_element structures
302 assumes case sensitive comparison
304 int ldb_msg_element_compare(struct ldb_message_element *el1,
305 struct ldb_message_element *el2)
307 unsigned int i;
309 if (el1->num_values != el2->num_values) {
310 return el1->num_values - el2->num_values;
313 for (i=0;i<el1->num_values;i++) {
314 if (!ldb_msg_find_val(el2, &el1->values[i])) {
315 return -1;
319 return 0;
323 compare two ldb_message_element structures
324 comparing by element name
326 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
327 struct ldb_message_element *el2)
329 return ldb_attr_cmp(el1->name, el2->name);
333 convenience functions to return common types from a message
334 these return the first value if the attribute is multi-valued
336 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
337 const char *attr_name)
339 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
340 if (!el || el->num_values == 0) {
341 return NULL;
343 return &el->values[0];
346 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
347 const char *attr_name,
348 int default_value)
350 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
351 if (!v || !v->data) {
352 return default_value;
354 return strtol((const char *)v->data, NULL, 0);
357 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
358 const char *attr_name,
359 unsigned int default_value)
361 unsigned int ret;
362 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
363 if (!v || !v->data) {
364 return default_value;
367 /* in LDAP there're only int32_t values */
368 errno = 0;
369 ret = strtol((const char *)v->data, NULL, 0);
370 if (errno == 0) {
371 return ret;
374 return strtoul((const char *)v->data, NULL, 0);
377 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
378 const char *attr_name,
379 int64_t default_value)
381 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
382 if (!v || !v->data) {
383 return default_value;
385 return strtoll((const char *)v->data, NULL, 0);
388 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
389 const char *attr_name,
390 uint64_t default_value)
392 uint64_t ret;
393 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
394 if (!v || !v->data) {
395 return default_value;
398 /* in LDAP there're only int64_t values */
399 errno = 0;
400 ret = strtoll((const char *)v->data, NULL, 0);
401 if (errno == 0) {
402 return ret;
405 return strtoull((const char *)v->data, NULL, 0);
408 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
409 const char *attr_name,
410 double default_value)
412 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
413 if (!v || !v->data) {
414 return default_value;
416 return strtod((const char *)v->data, NULL);
419 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
420 const char *attr_name,
421 int default_value)
423 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
424 if (!v || !v->data) {
425 return default_value;
427 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
428 return 0;
430 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
431 return 1;
433 return default_value;
436 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
437 const char *attr_name,
438 const char *default_value)
440 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
441 if (!v || !v->data) {
442 return default_value;
444 return (const char *)v->data;
447 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
448 void *mem_ctx,
449 const struct ldb_message *msg,
450 const char *attr_name)
452 struct ldb_dn *res_dn;
453 const struct ldb_val *v;
455 v = ldb_msg_find_ldb_val(msg, attr_name);
456 if (!v || !v->data) {
457 return NULL;
459 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
460 if ( ! ldb_dn_validate(res_dn)) {
461 talloc_free(res_dn);
462 return NULL;
464 return res_dn;
468 sort the elements of a message by name
470 void ldb_msg_sort_elements(struct ldb_message *msg)
472 TYPESAFE_QSORT(msg->elements, msg->num_elements,
473 ldb_msg_element_compare_name);
477 shallow copy a message - copying only the elements array so that the caller
478 can safely add new elements without changing the message
480 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
481 const struct ldb_message *msg)
483 struct ldb_message *msg2;
484 unsigned int i;
486 msg2 = talloc(mem_ctx, struct ldb_message);
487 if (msg2 == NULL) return NULL;
489 *msg2 = *msg;
491 msg2->elements = talloc_array(msg2, struct ldb_message_element,
492 msg2->num_elements);
493 if (msg2->elements == NULL) goto failed;
495 for (i=0;i<msg2->num_elements;i++) {
496 msg2->elements[i] = msg->elements[i];
499 return msg2;
501 failed:
502 talloc_free(msg2);
503 return NULL;
508 copy a message, allocating new memory for all parts
510 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
511 const struct ldb_message *msg)
513 struct ldb_message *msg2;
514 unsigned int i, j;
516 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
517 if (msg2 == NULL) return NULL;
519 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
520 if (msg2->dn == NULL) goto failed;
522 for (i=0;i<msg2->num_elements;i++) {
523 struct ldb_message_element *el = &msg2->elements[i];
524 struct ldb_val *values = el->values;
525 el->name = talloc_strdup(msg2->elements, el->name);
526 if (el->name == NULL) goto failed;
527 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
528 for (j=0;j<el->num_values;j++) {
529 el->values[j] = ldb_val_dup(el->values, &values[j]);
530 if (el->values[j].data == NULL && values[j].length != 0) {
531 goto failed;
536 return msg2;
538 failed:
539 talloc_free(msg2);
540 return NULL;
545 canonicalise a message, merging elements of the same name
547 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
548 const struct ldb_message *msg)
550 unsigned int i;
551 struct ldb_message *msg2;
553 msg2 = ldb_msg_copy(ldb, msg);
554 if (msg2 == NULL) return NULL;
556 ldb_msg_sort_elements(msg2);
558 for (i=1;i<msg2->num_elements;i++) {
559 struct ldb_message_element *el1 = &msg2->elements[i-1];
560 struct ldb_message_element *el2 = &msg2->elements[i];
561 if (ldb_msg_element_compare_name(el1, el2) == 0) {
562 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
563 el1->num_values + el2->num_values);
564 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
565 return NULL;
567 memcpy(el1->values + el1->num_values,
568 el2->values,
569 sizeof(struct ldb_val) * el2->num_values);
570 el1->num_values += el2->num_values;
571 talloc_free(discard_const_p(char, el2->name));
572 if (i+1<msg2->num_elements) {
573 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
574 (msg2->num_elements - (i+1)));
576 msg2->num_elements--;
577 i--;
581 return msg2;
586 * return a ldb_message representing the differences between msg1 and msg2.
587 * If you then use this in a ldb_modify() call,
588 * it can be used to save edits to a message
590 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
591 struct ldb_message *msg1,
592 struct ldb_message *msg2)
594 int ldb_ret;
595 struct ldb_message *mod;
597 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
598 if (ldb_ret != LDB_SUCCESS) {
599 return NULL;
602 return mod;
606 * return a ldb_message representing the differences between msg1 and msg2.
607 * If you then use this in a ldb_modify() call it can be used to save edits to a message
609 * Result message is constructed as follows:
610 * - LDB_FLAG_MOD_ADD - elements found only in msg2
611 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
612 * Value for msg2 element is used
613 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
615 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
617 int ldb_msg_difference(struct ldb_context *ldb,
618 TALLOC_CTX *mem_ctx,
619 struct ldb_message *msg1,
620 struct ldb_message *msg2,
621 struct ldb_message **_msg_out)
623 int ldb_res;
624 unsigned int i;
625 struct ldb_message *mod;
626 struct ldb_message_element *el;
627 TALLOC_CTX *temp_ctx;
629 temp_ctx = talloc_new(mem_ctx);
630 if (!temp_ctx) {
631 return LDB_ERR_OPERATIONS_ERROR;
634 mod = ldb_msg_new(temp_ctx);
635 if (mod == NULL) {
636 goto failed;
639 mod->dn = msg1->dn;
640 mod->num_elements = 0;
641 mod->elements = NULL;
643 /* canonicalize msg2 so we have no repeated elements */
644 msg2 = ldb_msg_canonicalize(ldb, msg2);
645 if (msg2 == NULL) {
646 goto failed;
649 /* steal msg2 into mod context as it is allocated in ldb's context */
650 talloc_steal(mod, msg2);
652 /* look in msg2 to find elements that need to be added or modified */
653 for (i=0;i<msg2->num_elements;i++) {
654 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
656 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
657 continue;
660 ldb_res = ldb_msg_add(mod,
661 &msg2->elements[i],
662 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
663 if (ldb_res != LDB_SUCCESS) {
664 goto failed;
668 /* look in msg1 to find elements that need to be deleted */
669 for (i=0;i<msg1->num_elements;i++) {
670 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
671 if (el == NULL) {
672 ldb_res = ldb_msg_add_empty(mod,
673 msg1->elements[i].name,
674 LDB_FLAG_MOD_DELETE, NULL);
675 if (ldb_res != LDB_SUCCESS) {
676 goto failed;
681 /* steal resulting message into supplied context */
682 talloc_steal(mem_ctx, mod);
683 *_msg_out = mod;
685 talloc_free(temp_ctx);
686 return LDB_SUCCESS;
688 failed:
689 talloc_free(temp_ctx);
690 return LDB_ERR_OPERATIONS_ERROR;
694 int ldb_msg_sanity_check(struct ldb_context *ldb,
695 const struct ldb_message *msg)
697 unsigned int i, j;
699 /* basic check on DN */
700 if (msg->dn == NULL) {
701 /* TODO: return also an error string */
702 ldb_set_errstring(ldb, "ldb message lacks a DN!");
703 return LDB_ERR_INVALID_DN_SYNTAX;
706 /* basic syntax checks */
707 for (i = 0; i < msg->num_elements; i++) {
708 for (j = 0; j < msg->elements[i].num_values; j++) {
709 if (msg->elements[i].values[j].length == 0) {
710 TALLOC_CTX *mem_ctx = talloc_new(ldb);
711 /* an attribute cannot be empty */
712 /* TODO: return also an error string */
713 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
714 msg->elements[i].name,
715 ldb_dn_get_linearized(msg->dn));
716 talloc_free(mem_ctx);
717 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
722 return LDB_SUCCESS;
729 copy an attribute list. This only copies the array, not the elements
730 (ie. the elements are left as the same pointers)
732 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
734 const char **ret;
735 unsigned int i;
737 for (i=0;attrs && attrs[i];i++) /* noop */ ;
738 ret = talloc_array(mem_ctx, const char *, i+1);
739 if (ret == NULL) {
740 return NULL;
742 for (i=0;attrs && attrs[i];i++) {
743 ret[i] = attrs[i];
745 ret[i] = attrs[i];
746 return ret;
751 copy an attribute list. This only copies the array, not the elements
752 (ie. the elements are left as the same pointers). The new attribute is added to the list.
754 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
756 const char **ret;
757 unsigned int i;
758 bool found = false;
760 for (i=0;attrs && attrs[i];i++) {
761 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
762 found = true;
765 if (found) {
766 return ldb_attr_list_copy(mem_ctx, attrs);
768 ret = talloc_array(mem_ctx, const char *, i+2);
769 if (ret == NULL) {
770 return NULL;
772 for (i=0;attrs && attrs[i];i++) {
773 ret[i] = attrs[i];
775 ret[i] = new_attr;
776 ret[i+1] = NULL;
777 return ret;
782 return 1 if an attribute is in a list of attributes, or 0 otherwise
784 int ldb_attr_in_list(const char * const *attrs, const char *attr)
786 unsigned int i;
787 for (i=0;attrs && attrs[i];i++) {
788 if (ldb_attr_cmp(attrs[i], attr) == 0) {
789 return 1;
792 return 0;
797 rename the specified attribute in a search result
799 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
801 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
802 if (el == NULL) {
803 return LDB_SUCCESS;
805 el->name = talloc_strdup(msg->elements, replace);
806 if (el->name == NULL) {
807 return LDB_ERR_OPERATIONS_ERROR;
809 return LDB_SUCCESS;
814 copy the specified attribute in a search result to a new attribute
816 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
818 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
819 if (el == NULL) {
820 return LDB_SUCCESS;
822 if (ldb_msg_add(msg, el, 0) != 0) {
823 return LDB_ERR_OPERATIONS_ERROR;
825 return ldb_msg_rename_attr(msg, attr, replace);
829 remove the specified element in a search result
831 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
833 ptrdiff_t n = (el - msg->elements);
834 if (n >= msg->num_elements) {
835 /* should we abort() here? */
836 return;
838 if (n != msg->num_elements-1) {
839 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
841 msg->num_elements--;
846 remove the specified attribute in a search result
848 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
850 struct ldb_message_element *el;
852 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
853 ldb_msg_remove_element(msg, el);
858 return a LDAP formatted GeneralizedTime string
860 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
862 struct tm *tm = gmtime(&t);
863 char *ts;
864 int r;
866 if (!tm) {
867 return NULL;
870 /* we now excatly how long this string will be */
871 ts = talloc_array(mem_ctx, char, 18);
873 /* formatted like: 20040408072012.0Z */
874 r = snprintf(ts, 18,
875 "%04u%02u%02u%02u%02u%02u.0Z",
876 tm->tm_year+1900, tm->tm_mon+1,
877 tm->tm_mday, tm->tm_hour, tm->tm_min,
878 tm->tm_sec);
880 if (r != 17) {
881 talloc_free(ts);
882 return NULL;
885 return ts;
889 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
891 time_t ldb_string_to_time(const char *s)
893 struct tm tm;
895 if (s == NULL) return 0;
897 memset(&tm, 0, sizeof(tm));
898 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
899 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
900 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
901 return 0;
903 tm.tm_year -= 1900;
904 tm.tm_mon -= 1;
906 return timegm(&tm);
910 convert a LDAP GeneralizedTime string in ldb_val format to a
911 time_t.
913 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
915 struct tm tm;
917 if (v == NULL || !v->data || v->length < 17) {
918 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
921 memset(&tm, 0, sizeof(tm));
923 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
924 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
925 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
926 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
928 tm.tm_year -= 1900;
929 tm.tm_mon -= 1;
931 *t = timegm(&tm);
933 return LDB_SUCCESS;
937 return a LDAP formatted UTCTime string
939 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
941 struct tm *tm = gmtime(&t);
942 char *ts;
943 int r;
945 if (!tm) {
946 return NULL;
949 /* we now excatly how long this string will be */
950 ts = talloc_array(mem_ctx, char, 14);
952 /* formatted like: 20040408072012.0Z => 040408072012Z */
953 r = snprintf(ts, 14,
954 "%02u%02u%02u%02u%02u%02uZ",
955 (tm->tm_year+1900)%100, tm->tm_mon+1,
956 tm->tm_mday, tm->tm_hour, tm->tm_min,
957 tm->tm_sec);
959 if (r != 13) {
960 talloc_free(ts);
961 return NULL;
964 return ts;
968 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
970 time_t ldb_string_utc_to_time(const char *s)
972 struct tm tm;
974 if (s == NULL) return 0;
976 memset(&tm, 0, sizeof(tm));
977 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
978 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
979 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
980 return 0;
982 if (tm.tm_year < 50) {
983 tm.tm_year += 100;
985 tm.tm_mon -= 1;
987 return timegm(&tm);
992 dump a set of results to a file. Useful from within gdb
994 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
996 unsigned int i;
998 for (i = 0; i < result->count; i++) {
999 struct ldb_ldif ldif;
1000 fprintf(f, "# record %d\n", i+1);
1001 ldif.changetype = LDB_CHANGETYPE_NONE;
1002 ldif.msg = result->msgs[i];
1003 ldb_ldif_write_file(ldb, f, &ldif);
1008 checks for a string attribute. Returns "1" on match and otherwise "0".
1010 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1011 const char *name, const char *value)
1013 struct ldb_message_element *el;
1014 struct ldb_val val;
1016 el = ldb_msg_find_element(msg, name);
1017 if (el == NULL) {
1018 return 0;
1021 val.data = discard_const_p(uint8_t, value);
1022 val.length = strlen(value);
1024 if (ldb_msg_find_val(el, &val)) {
1025 return 1;
1028 return 0;