LDB:common - Change counters to "unsigned" where appropriate
[Samba/ita.git] / source4 / lib / ldb / common / ldb_msg.c
blob2d2b34dd33ae5154ccd8aeaa957b93e123a2f167
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) != 0) {
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 return ldb_msg_add_steal_value(msg, attr_name, &val);
262 add a DN element to a message
263 WARNING: this uses the linearized string from the dn, and does not
264 copy the string.
266 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
267 struct ldb_dn *dn)
269 return ldb_msg_add_steal_string(msg, attr_name,
270 ldb_dn_alloc_linearized(msg, dn));
274 add a printf formatted element to a message
276 int ldb_msg_add_fmt(struct ldb_message *msg,
277 const char *attr_name, const char *fmt, ...)
279 struct ldb_val val;
280 va_list ap;
281 char *str;
283 va_start(ap, fmt);
284 str = talloc_vasprintf(msg, fmt, ap);
285 va_end(ap);
287 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
289 val.data = (uint8_t *)str;
290 val.length = strlen(str);
292 return ldb_msg_add_steal_value(msg, attr_name, &val);
296 compare two ldb_message_element structures
297 assumes case senistive comparison
299 int ldb_msg_element_compare(struct ldb_message_element *el1,
300 struct ldb_message_element *el2)
302 unsigned int i;
304 if (el1->num_values != el2->num_values) {
305 return el1->num_values - el2->num_values;
308 for (i=0;i<el1->num_values;i++) {
309 if (!ldb_msg_find_val(el2, &el1->values[i])) {
310 return -1;
314 return 0;
318 compare two ldb_message_element structures
319 comparing by element name
321 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
322 struct ldb_message_element *el2)
324 return ldb_attr_cmp(el1->name, el2->name);
328 convenience functions to return common types from a message
329 these return the first value if the attribute is multi-valued
331 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
332 const char *attr_name)
334 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
335 if (!el || el->num_values == 0) {
336 return NULL;
338 return &el->values[0];
341 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
342 const char *attr_name,
343 int default_value)
345 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
346 if (!v || !v->data) {
347 return default_value;
349 return strtol((const char *)v->data, NULL, 0);
352 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
353 const char *attr_name,
354 unsigned int default_value)
356 unsigned int ret;
357 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
358 if (!v || !v->data) {
359 return default_value;
362 /* in LDAP there're only int32_t values */
363 errno = 0;
364 ret = strtol((const char *)v->data, NULL, 0);
365 if (errno == 0) {
366 return ret;
369 return strtoul((const char *)v->data, NULL, 0);
372 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
373 const char *attr_name,
374 int64_t default_value)
376 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
377 if (!v || !v->data) {
378 return default_value;
380 return strtoll((const char *)v->data, NULL, 0);
383 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
384 const char *attr_name,
385 uint64_t default_value)
387 uint64_t ret;
388 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
389 if (!v || !v->data) {
390 return default_value;
393 /* in LDAP there're only int64_t values */
394 errno = 0;
395 ret = strtoll((const char *)v->data, NULL, 0);
396 if (errno == 0) {
397 return ret;
400 return strtoull((const char *)v->data, NULL, 0);
403 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
404 const char *attr_name,
405 double default_value)
407 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
408 if (!v || !v->data) {
409 return default_value;
411 return strtod((const char *)v->data, NULL);
414 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
415 const char *attr_name,
416 int default_value)
418 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
419 if (!v || !v->data) {
420 return default_value;
422 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
423 return 0;
425 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
426 return 1;
428 return default_value;
431 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
432 const char *attr_name,
433 const char *default_value)
435 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
436 if (!v || !v->data) {
437 return default_value;
439 return (const char *)v->data;
442 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
443 void *mem_ctx,
444 const struct ldb_message *msg,
445 const char *attr_name)
447 struct ldb_dn *res_dn;
448 const struct ldb_val *v;
450 v = ldb_msg_find_ldb_val(msg, attr_name);
451 if (!v || !v->data) {
452 return NULL;
454 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
455 if ( ! ldb_dn_validate(res_dn)) {
456 talloc_free(res_dn);
457 return NULL;
459 return res_dn;
463 sort the elements of a message by name
465 void ldb_msg_sort_elements(struct ldb_message *msg)
467 TYPESAFE_QSORT(msg->elements, msg->num_elements,
468 ldb_msg_element_compare_name);
472 shallow copy a message - copying only the elements array so that the caller
473 can safely add new elements without changing the message
475 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
476 const struct ldb_message *msg)
478 struct ldb_message *msg2;
479 unsigned int i;
481 msg2 = talloc(mem_ctx, struct ldb_message);
482 if (msg2 == NULL) return NULL;
484 *msg2 = *msg;
486 msg2->elements = talloc_array(msg2, struct ldb_message_element,
487 msg2->num_elements);
488 if (msg2->elements == NULL) goto failed;
490 for (i=0;i<msg2->num_elements;i++) {
491 msg2->elements[i] = msg->elements[i];
494 return msg2;
496 failed:
497 talloc_free(msg2);
498 return NULL;
503 copy a message, allocating new memory for all parts
505 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
506 const struct ldb_message *msg)
508 struct ldb_message *msg2;
509 unsigned int i, j;
511 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
512 if (msg2 == NULL) return NULL;
514 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
515 if (msg2->dn == NULL) goto failed;
517 for (i=0;i<msg2->num_elements;i++) {
518 struct ldb_message_element *el = &msg2->elements[i];
519 struct ldb_val *values = el->values;
520 el->name = talloc_strdup(msg2->elements, el->name);
521 if (el->name == NULL) goto failed;
522 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
523 for (j=0;j<el->num_values;j++) {
524 el->values[j] = ldb_val_dup(el->values, &values[j]);
525 if (el->values[j].data == NULL && values[j].length != 0) {
526 goto failed;
531 return msg2;
533 failed:
534 talloc_free(msg2);
535 return NULL;
540 canonicalise a message, merging elements of the same name
542 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
543 const struct ldb_message *msg)
545 unsigned int i;
546 struct ldb_message *msg2;
548 msg2 = ldb_msg_copy(ldb, msg);
549 if (msg2 == NULL) return NULL;
551 ldb_msg_sort_elements(msg2);
553 for (i=1;i<msg2->num_elements;i++) {
554 struct ldb_message_element *el1 = &msg2->elements[i-1];
555 struct ldb_message_element *el2 = &msg2->elements[i];
556 if (ldb_msg_element_compare_name(el1, el2) == 0) {
557 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
558 el1->num_values + el2->num_values);
559 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
560 return NULL;
562 memcpy(el1->values + el1->num_values,
563 el2->values,
564 sizeof(struct ldb_val) * el2->num_values);
565 el1->num_values += el2->num_values;
566 talloc_free(discard_const_p(char, el2->name));
567 if (i+1<msg2->num_elements) {
568 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
569 (msg2->num_elements - (i+1)));
571 msg2->num_elements--;
572 i--;
576 return msg2;
581 return a ldb_message representing the differences between msg1 and msg2. If you
582 then use this in a ldb_modify() call it can be used to save edits to a message
584 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
585 struct ldb_message *msg1,
586 struct ldb_message *msg2)
588 struct ldb_message *mod;
589 struct ldb_message_element *el;
590 unsigned int i;
592 mod = ldb_msg_new(ldb);
593 if (mod == NULL) {
594 return NULL;
597 mod->dn = msg1->dn;
598 mod->num_elements = 0;
599 mod->elements = NULL;
601 msg2 = ldb_msg_canonicalize(ldb, msg2);
602 if (msg2 == NULL) {
603 talloc_free(mod);
604 return NULL;
607 /* look in msg2 to find elements that need to be added
608 or modified */
609 for (i=0;i<msg2->num_elements;i++) {
610 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
612 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
613 continue;
616 if (ldb_msg_add(mod,
617 &msg2->elements[i],
618 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
619 talloc_free(mod);
620 return NULL;
624 /* look in msg1 to find elements that need to be deleted */
625 for (i=0;i<msg1->num_elements;i++) {
626 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
627 if (el == NULL) {
628 if (ldb_msg_add_empty(mod,
629 msg1->elements[i].name,
630 LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
631 talloc_free(mod);
632 return NULL;
637 return mod;
640 int ldb_msg_sanity_check(struct ldb_context *ldb,
641 const struct ldb_message *msg)
643 unsigned int i, j;
645 /* basic check on DN */
646 if (msg->dn == NULL) {
647 /* TODO: return also an error string */
648 ldb_set_errstring(ldb, "ldb message lacks a DN!");
649 return LDB_ERR_INVALID_DN_SYNTAX;
652 /* basic syntax checks */
653 for (i = 0; i < msg->num_elements; i++) {
654 for (j = 0; j < msg->elements[i].num_values; j++) {
655 if (msg->elements[i].values[j].length == 0) {
656 TALLOC_CTX *mem_ctx = talloc_new(ldb);
657 /* an attribute cannot be empty */
658 /* TODO: return also an error string */
659 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
660 msg->elements[i].name,
661 ldb_dn_get_linearized(msg->dn));
662 talloc_free(mem_ctx);
663 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
668 return LDB_SUCCESS;
675 copy an attribute list. This only copies the array, not the elements
676 (ie. the elements are left as the same pointers)
678 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
680 const char **ret;
681 unsigned int i;
683 for (i=0;attrs && attrs[i];i++) /* noop */ ;
684 ret = talloc_array(mem_ctx, const char *, i+1);
685 if (ret == NULL) {
686 return NULL;
688 for (i=0;attrs && attrs[i];i++) {
689 ret[i] = attrs[i];
691 ret[i] = attrs[i];
692 return ret;
697 copy an attribute list. This only copies the array, not the elements
698 (ie. the elements are left as the same pointers). The new attribute is added to the list.
700 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
702 const char **ret;
703 unsigned int i;
704 bool found = false;
706 for (i=0;attrs && attrs[i];i++) {
707 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
708 found = true;
711 if (found) {
712 return ldb_attr_list_copy(mem_ctx, attrs);
714 ret = talloc_array(mem_ctx, const char *, i+2);
715 if (ret == NULL) {
716 return NULL;
718 for (i=0;attrs && attrs[i];i++) {
719 ret[i] = attrs[i];
721 ret[i] = new_attr;
722 ret[i+1] = NULL;
723 return ret;
728 return 1 if an attribute is in a list of attributes, or 0 otherwise
730 int ldb_attr_in_list(const char * const *attrs, const char *attr)
732 unsigned int i;
733 for (i=0;attrs && attrs[i];i++) {
734 if (ldb_attr_cmp(attrs[i], attr) == 0) {
735 return 1;
738 return 0;
743 rename the specified attribute in a search result
745 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
747 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
748 if (el == NULL) {
749 return LDB_SUCCESS;
751 el->name = talloc_strdup(msg->elements, replace);
752 if (el->name == NULL) {
753 return LDB_ERR_OPERATIONS_ERROR;
755 return LDB_SUCCESS;
760 copy the specified attribute in a search result to a new attribute
762 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
764 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
765 if (el == NULL) {
766 return LDB_SUCCESS;
768 if (ldb_msg_add(msg, el, 0) != 0) {
769 return LDB_ERR_OPERATIONS_ERROR;
771 return ldb_msg_rename_attr(msg, attr, replace);
775 remove the specified element in a search result
777 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
779 ptrdiff_t n = (el - msg->elements);
780 if (n >= msg->num_elements) {
781 /* should we abort() here? */
782 return;
784 if (n != msg->num_elements-1) {
785 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
787 msg->num_elements--;
792 remove the specified attribute in a search result
794 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
796 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
797 if (el) {
798 ldb_msg_remove_element(msg, el);
803 return a LDAP formatted GeneralizedTime string
805 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
807 struct tm *tm = gmtime(&t);
808 char *ts;
809 int r;
811 if (!tm) {
812 return NULL;
815 /* we now excatly how long this string will be */
816 ts = talloc_array(mem_ctx, char, 18);
818 /* formatted like: 20040408072012.0Z */
819 r = snprintf(ts, 18,
820 "%04u%02u%02u%02u%02u%02u.0Z",
821 tm->tm_year+1900, tm->tm_mon+1,
822 tm->tm_mday, tm->tm_hour, tm->tm_min,
823 tm->tm_sec);
825 if (r != 17) {
826 talloc_free(ts);
827 return NULL;
830 return ts;
834 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
836 time_t ldb_string_to_time(const char *s)
838 struct tm tm;
840 if (s == NULL) return 0;
842 memset(&tm, 0, sizeof(tm));
843 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
844 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
845 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
846 return 0;
848 tm.tm_year -= 1900;
849 tm.tm_mon -= 1;
851 return timegm(&tm);
855 convert a LDAP GeneralizedTime string in ldb_val format to a
856 time_t.
858 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
860 struct tm tm;
862 if (v == NULL || !v->data || v->length < 17) {
863 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
866 memset(&tm, 0, sizeof(tm));
868 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
869 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
870 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
871 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
873 tm.tm_year -= 1900;
874 tm.tm_mon -= 1;
876 *t = timegm(&tm);
878 return LDB_SUCCESS;
882 return a LDAP formatted UTCTime string
884 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
886 struct tm *tm = gmtime(&t);
887 char *ts;
888 int r;
890 if (!tm) {
891 return NULL;
894 /* we now excatly how long this string will be */
895 ts = talloc_array(mem_ctx, char, 14);
897 /* formatted like: 20040408072012.0Z => 040408072012Z */
898 r = snprintf(ts, 14,
899 "%02u%02u%02u%02u%02u%02uZ",
900 (tm->tm_year+1900)%100, tm->tm_mon+1,
901 tm->tm_mday, tm->tm_hour, tm->tm_min,
902 tm->tm_sec);
904 if (r != 13) {
905 talloc_free(ts);
906 return NULL;
909 return ts;
913 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
915 time_t ldb_string_utc_to_time(const char *s)
917 struct tm tm;
919 if (s == NULL) return 0;
921 memset(&tm, 0, sizeof(tm));
922 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
923 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
924 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
925 return 0;
927 if (tm.tm_year < 50) {
928 tm.tm_year += 100;
930 tm.tm_mon -= 1;
932 return timegm(&tm);
937 dump a set of results to a file. Useful from within gdb
939 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
941 unsigned int i;
943 for (i = 0; i < result->count; i++) {
944 struct ldb_ldif ldif;
945 fprintf(f, "# record %d\n", i+1);
946 ldif.changetype = LDB_CHANGETYPE_NONE;
947 ldif.msg = result->msgs[i];
948 ldb_ldif_write_file(ldb, f, &ldif);
953 checks for a string attribute. Returns "1" on match and otherwise "0".
955 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
956 const char *name, const char *value)
958 struct ldb_message_element *el;
959 struct ldb_val val;
961 el = ldb_msg_find_element(msg, name);
962 if (el == NULL) {
963 return 0;
966 val.data = discard_const_p(uint8_t, value);
967 val.length = strlen(value);
969 if (ldb_msg_find_val(el, &val)) {
970 return 1;
973 return 0;