s4:ldb_msg_element_compare - fix typo in comment
[Samba/ekacnet.git] / source4 / lib / ldb / common / ldb_msg.c
blob59bd32090e5a5a6922c85a1b2e7417c271db1aa2
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. If you
587 then use this in a ldb_modify() call it can be used to save edits to a message
589 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
590 struct ldb_message *msg1,
591 struct ldb_message *msg2)
593 struct ldb_message *mod;
594 struct ldb_message_element *el;
595 unsigned int i;
597 mod = ldb_msg_new(ldb);
598 if (mod == NULL) {
599 return NULL;
602 mod->dn = msg1->dn;
603 mod->num_elements = 0;
604 mod->elements = NULL;
606 msg2 = ldb_msg_canonicalize(ldb, msg2);
607 if (msg2 == NULL) {
608 talloc_free(mod);
609 return NULL;
612 /* look in msg2 to find elements that need to be added
613 or modified */
614 for (i=0;i<msg2->num_elements;i++) {
615 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
617 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
618 continue;
621 if (ldb_msg_add(mod,
622 &msg2->elements[i],
623 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
624 talloc_free(mod);
625 return NULL;
629 /* look in msg1 to find elements that need to be deleted */
630 for (i=0;i<msg1->num_elements;i++) {
631 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
632 if (el == NULL) {
633 if (ldb_msg_add_empty(mod,
634 msg1->elements[i].name,
635 LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
636 talloc_free(mod);
637 return NULL;
642 return mod;
645 int ldb_msg_sanity_check(struct ldb_context *ldb,
646 const struct ldb_message *msg)
648 unsigned int i, j;
650 /* basic check on DN */
651 if (msg->dn == NULL) {
652 /* TODO: return also an error string */
653 ldb_set_errstring(ldb, "ldb message lacks a DN!");
654 return LDB_ERR_INVALID_DN_SYNTAX;
657 /* basic syntax checks */
658 for (i = 0; i < msg->num_elements; i++) {
659 for (j = 0; j < msg->elements[i].num_values; j++) {
660 if (msg->elements[i].values[j].length == 0) {
661 TALLOC_CTX *mem_ctx = talloc_new(ldb);
662 /* an attribute cannot be empty */
663 /* TODO: return also an error string */
664 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
665 msg->elements[i].name,
666 ldb_dn_get_linearized(msg->dn));
667 talloc_free(mem_ctx);
668 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
673 return LDB_SUCCESS;
680 copy an attribute list. This only copies the array, not the elements
681 (ie. the elements are left as the same pointers)
683 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
685 const char **ret;
686 unsigned int i;
688 for (i=0;attrs && attrs[i];i++) /* noop */ ;
689 ret = talloc_array(mem_ctx, const char *, i+1);
690 if (ret == NULL) {
691 return NULL;
693 for (i=0;attrs && attrs[i];i++) {
694 ret[i] = attrs[i];
696 ret[i] = attrs[i];
697 return ret;
702 copy an attribute list. This only copies the array, not the elements
703 (ie. the elements are left as the same pointers). The new attribute is added to the list.
705 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
707 const char **ret;
708 unsigned int i;
709 bool found = false;
711 for (i=0;attrs && attrs[i];i++) {
712 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
713 found = true;
716 if (found) {
717 return ldb_attr_list_copy(mem_ctx, attrs);
719 ret = talloc_array(mem_ctx, const char *, i+2);
720 if (ret == NULL) {
721 return NULL;
723 for (i=0;attrs && attrs[i];i++) {
724 ret[i] = attrs[i];
726 ret[i] = new_attr;
727 ret[i+1] = NULL;
728 return ret;
733 return 1 if an attribute is in a list of attributes, or 0 otherwise
735 int ldb_attr_in_list(const char * const *attrs, const char *attr)
737 unsigned int i;
738 for (i=0;attrs && attrs[i];i++) {
739 if (ldb_attr_cmp(attrs[i], attr) == 0) {
740 return 1;
743 return 0;
748 rename the specified attribute in a search result
750 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
752 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
753 if (el == NULL) {
754 return LDB_SUCCESS;
756 el->name = talloc_strdup(msg->elements, replace);
757 if (el->name == NULL) {
758 return LDB_ERR_OPERATIONS_ERROR;
760 return LDB_SUCCESS;
765 copy the specified attribute in a search result to a new attribute
767 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
769 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
770 if (el == NULL) {
771 return LDB_SUCCESS;
773 if (ldb_msg_add(msg, el, 0) != 0) {
774 return LDB_ERR_OPERATIONS_ERROR;
776 return ldb_msg_rename_attr(msg, attr, replace);
780 remove the specified element in a search result
782 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
784 ptrdiff_t n = (el - msg->elements);
785 if (n >= msg->num_elements) {
786 /* should we abort() here? */
787 return;
789 if (n != msg->num_elements-1) {
790 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
792 msg->num_elements--;
797 remove the specified attribute in a search result
799 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
801 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
802 if (el) {
803 ldb_msg_remove_element(msg, el);
808 return a LDAP formatted GeneralizedTime string
810 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
812 struct tm *tm = gmtime(&t);
813 char *ts;
814 int r;
816 if (!tm) {
817 return NULL;
820 /* we now excatly how long this string will be */
821 ts = talloc_array(mem_ctx, char, 18);
823 /* formatted like: 20040408072012.0Z */
824 r = snprintf(ts, 18,
825 "%04u%02u%02u%02u%02u%02u.0Z",
826 tm->tm_year+1900, tm->tm_mon+1,
827 tm->tm_mday, tm->tm_hour, tm->tm_min,
828 tm->tm_sec);
830 if (r != 17) {
831 talloc_free(ts);
832 return NULL;
835 return ts;
839 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
841 time_t ldb_string_to_time(const char *s)
843 struct tm tm;
845 if (s == NULL) return 0;
847 memset(&tm, 0, sizeof(tm));
848 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
849 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
850 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
851 return 0;
853 tm.tm_year -= 1900;
854 tm.tm_mon -= 1;
856 return timegm(&tm);
860 convert a LDAP GeneralizedTime string in ldb_val format to a
861 time_t.
863 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
865 struct tm tm;
867 if (v == NULL || !v->data || v->length < 17) {
868 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
871 memset(&tm, 0, sizeof(tm));
873 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
874 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
875 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
876 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
878 tm.tm_year -= 1900;
879 tm.tm_mon -= 1;
881 *t = timegm(&tm);
883 return LDB_SUCCESS;
887 return a LDAP formatted UTCTime string
889 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
891 struct tm *tm = gmtime(&t);
892 char *ts;
893 int r;
895 if (!tm) {
896 return NULL;
899 /* we now excatly how long this string will be */
900 ts = talloc_array(mem_ctx, char, 14);
902 /* formatted like: 20040408072012.0Z => 040408072012Z */
903 r = snprintf(ts, 14,
904 "%02u%02u%02u%02u%02u%02uZ",
905 (tm->tm_year+1900)%100, tm->tm_mon+1,
906 tm->tm_mday, tm->tm_hour, tm->tm_min,
907 tm->tm_sec);
909 if (r != 13) {
910 talloc_free(ts);
911 return NULL;
914 return ts;
918 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
920 time_t ldb_string_utc_to_time(const char *s)
922 struct tm tm;
924 if (s == NULL) return 0;
926 memset(&tm, 0, sizeof(tm));
927 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
928 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
929 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
930 return 0;
932 if (tm.tm_year < 50) {
933 tm.tm_year += 100;
935 tm.tm_mon -= 1;
937 return timegm(&tm);
942 dump a set of results to a file. Useful from within gdb
944 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
946 unsigned int i;
948 for (i = 0; i < result->count; i++) {
949 struct ldb_ldif ldif;
950 fprintf(f, "# record %d\n", i+1);
951 ldif.changetype = LDB_CHANGETYPE_NONE;
952 ldif.msg = result->msgs[i];
953 ldb_ldif_write_file(ldb, f, &ldif);
958 checks for a string attribute. Returns "1" on match and otherwise "0".
960 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
961 const char *name, const char *value)
963 struct ldb_message_element *el;
964 struct ldb_val val;
966 el = ldb_msg_find_element(msg, name);
967 if (el == NULL) {
968 return 0;
971 val.data = discard_const_p(uint8_t, value);
972 val.length = strlen(value);
974 if (ldb_msg_find_val(el, &val)) {
975 return 1;
978 return 0;