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
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/>.
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)
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];
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) {
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,
84 for (i=0;i<el->num_values;i++) {
85 if (ldb_val_equal_exact(val, &el->values[i])) {
86 return &el->values[i];
93 duplicate a ldb_val structure
95 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
98 v2.length = v->length;
99 if (v->data == NULL) {
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);
112 memcpy(v2.data, v->data, v->length);
113 ((char *)v2.data)[v->length] = 0;
118 * Adds new empty element to msg->elements
120 static int _ldb_msg_add_el(struct ldb_message *msg,
121 struct ldb_message_element **return_el)
123 struct ldb_message_element *els;
125 /* TODO: Find out a way to assert
126 * on input parameters.
127 * msg and return_el must be valid */
129 els = talloc_realloc(msg, msg->elements,
130 struct ldb_message_element, msg->num_elements + 1);
133 return LDB_ERR_OPERATIONS_ERROR;
136 ZERO_STRUCT(els[msg->num_elements]);
141 *return_el = &els[msg->num_elements-1];
147 * Add an empty element with a given name to a message
149 int ldb_msg_add_empty(struct ldb_message *msg,
150 const char *attr_name,
152 struct ldb_message_element **return_el)
155 struct ldb_message_element *el;
157 ret = _ldb_msg_add_el(msg, &el);
158 if (ret != LDB_SUCCESS) {
162 /* initialize newly added element */
164 el->name = talloc_strdup(msg->elements, attr_name);
167 return LDB_ERR_OPERATIONS_ERROR;
178 * Adds an element to a message.
180 * NOTE: Ownership of ldb_message_element fields
181 * is NOT transferred. Thus, if el pointer
182 * is invalidated for some reason, this will
183 * corrupt msg contents also
185 int ldb_msg_add(struct ldb_message *msg,
186 const struct ldb_message_element *el,
190 struct ldb_message_element *el_new;
191 /* We have to copy this, just in case *el is a pointer into
192 * what ldb_msg_add_empty() is about to realloc() */
193 struct ldb_message_element el_copy = *el;
195 ret = _ldb_msg_add_el(msg, &el_new);
196 if (ret != LDB_SUCCESS) {
200 el_new->flags = flags;
201 el_new->name = el_copy.name;
202 el_new->num_values = el_copy.num_values;
203 el_new->values = el_copy.values;
209 add a value to a message
211 int ldb_msg_add_value(struct ldb_message *msg,
212 const char *attr_name,
213 const struct ldb_val *val,
214 struct ldb_message_element **return_el)
216 struct ldb_message_element *el;
217 struct ldb_val *vals;
220 el = ldb_msg_find_element(msg, attr_name);
222 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
223 if (ret != LDB_SUCCESS) {
228 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
231 return LDB_ERR_OPERATIONS_ERROR;
234 el->values[el->num_values] = *val;
246 add a value to a message, stealing it into the 'right' place
248 int ldb_msg_add_steal_value(struct ldb_message *msg,
249 const char *attr_name,
253 struct ldb_message_element *el;
255 ret = ldb_msg_add_value(msg, attr_name, val, &el);
256 if (ret == LDB_SUCCESS) {
257 talloc_steal(el->values, val->data);
264 add a string element to a message
266 int ldb_msg_add_string(struct ldb_message *msg,
267 const char *attr_name, const char *str)
271 val.data = discard_const_p(uint8_t, str);
272 val.length = strlen(str);
274 if (val.length == 0) {
275 /* allow empty strings as non-existent attributes */
279 return ldb_msg_add_value(msg, attr_name, &val, NULL);
283 add a string element to a message, stealing it into the 'right' place
285 int ldb_msg_add_steal_string(struct ldb_message *msg,
286 const char *attr_name, char *str)
290 val.data = (uint8_t *)str;
291 val.length = strlen(str);
293 if (val.length == 0) {
294 /* allow empty strings as non-existent attributes */
298 return ldb_msg_add_steal_value(msg, attr_name, &val);
302 add a DN element to a message
303 WARNING: this uses the linearized string from the dn, and does not
306 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
309 return ldb_msg_add_steal_string(msg, attr_name,
310 ldb_dn_alloc_linearized(msg, dn));
314 add a printf formatted element to a message
316 int ldb_msg_add_fmt(struct ldb_message *msg,
317 const char *attr_name, const char *fmt, ...)
324 str = talloc_vasprintf(msg, fmt, ap);
327 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
329 val.data = (uint8_t *)str;
330 val.length = strlen(str);
332 return ldb_msg_add_steal_value(msg, attr_name, &val);
336 compare two ldb_message_element structures
337 assumes case sensitive comparison
339 int ldb_msg_element_compare(struct ldb_message_element *el1,
340 struct ldb_message_element *el2)
344 if (el1->num_values != el2->num_values) {
345 return el1->num_values - el2->num_values;
348 for (i=0;i<el1->num_values;i++) {
349 if (!ldb_msg_find_val(el2, &el1->values[i])) {
358 compare two ldb_message_element structures
359 comparing by element name
361 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
362 struct ldb_message_element *el2)
364 return ldb_attr_cmp(el1->name, el2->name);
368 convenience functions to return common types from a message
369 these return the first value if the attribute is multi-valued
371 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
372 const char *attr_name)
374 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
375 if (!el || el->num_values == 0) {
378 return &el->values[0];
381 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
382 const char *attr_name,
385 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
386 if (!v || !v->data) {
387 return default_value;
389 return strtol((const char *)v->data, NULL, 0);
392 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
393 const char *attr_name,
394 unsigned int default_value)
397 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
398 if (!v || !v->data) {
399 return default_value;
402 /* in LDAP there're only int32_t values */
404 ret = strtol((const char *)v->data, NULL, 0);
409 return strtoul((const char *)v->data, NULL, 0);
412 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
413 const char *attr_name,
414 int64_t default_value)
416 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
417 if (!v || !v->data) {
418 return default_value;
420 return strtoll((const char *)v->data, NULL, 0);
423 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
424 const char *attr_name,
425 uint64_t default_value)
428 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
429 if (!v || !v->data) {
430 return default_value;
433 /* in LDAP there're only int64_t values */
435 ret = strtoll((const char *)v->data, NULL, 0);
440 return strtoull((const char *)v->data, NULL, 0);
443 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
444 const char *attr_name,
445 double default_value)
447 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
448 if (!v || !v->data) {
449 return default_value;
451 return strtod((const char *)v->data, NULL);
454 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
455 const char *attr_name,
458 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
459 if (!v || !v->data) {
460 return default_value;
462 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
465 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
468 return default_value;
471 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
472 const char *attr_name,
473 const char *default_value)
475 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
476 if (!v || !v->data) {
477 return default_value;
479 return (const char *)v->data;
482 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
484 const struct ldb_message *msg,
485 const char *attr_name)
487 struct ldb_dn *res_dn;
488 const struct ldb_val *v;
490 v = ldb_msg_find_ldb_val(msg, attr_name);
491 if (!v || !v->data) {
494 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
495 if ( ! ldb_dn_validate(res_dn)) {
503 sort the elements of a message by name
505 void ldb_msg_sort_elements(struct ldb_message *msg)
507 TYPESAFE_QSORT(msg->elements, msg->num_elements,
508 ldb_msg_element_compare_name);
512 shallow copy a message - copying only the elements array so that the caller
513 can safely add new elements without changing the message
515 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
516 const struct ldb_message *msg)
518 struct ldb_message *msg2;
521 msg2 = talloc(mem_ctx, struct ldb_message);
522 if (msg2 == NULL) return NULL;
526 msg2->elements = talloc_array(msg2, struct ldb_message_element,
528 if (msg2->elements == NULL) goto failed;
530 for (i=0;i<msg2->num_elements;i++) {
531 msg2->elements[i] = msg->elements[i];
543 copy a message, allocating new memory for all parts
545 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
546 const struct ldb_message *msg)
548 struct ldb_message *msg2;
551 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
552 if (msg2 == NULL) return NULL;
554 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
555 if (msg2->dn == NULL) goto failed;
557 for (i=0;i<msg2->num_elements;i++) {
558 struct ldb_message_element *el = &msg2->elements[i];
559 struct ldb_val *values = el->values;
560 el->name = talloc_strdup(msg2->elements, el->name);
561 if (el->name == NULL) goto failed;
562 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
563 for (j=0;j<el->num_values;j++) {
564 el->values[j] = ldb_val_dup(el->values, &values[j]);
565 if (el->values[j].data == NULL && values[j].length != 0) {
580 canonicalise a message, merging elements of the same name
582 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
583 const struct ldb_message *msg)
586 struct ldb_message *msg2;
588 msg2 = ldb_msg_copy(ldb, msg);
589 if (msg2 == NULL) return NULL;
591 ldb_msg_sort_elements(msg2);
593 for (i=1;i<msg2->num_elements;i++) {
594 struct ldb_message_element *el1 = &msg2->elements[i-1];
595 struct ldb_message_element *el2 = &msg2->elements[i];
596 if (ldb_msg_element_compare_name(el1, el2) == 0) {
597 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
598 el1->num_values + el2->num_values);
599 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
602 memcpy(el1->values + el1->num_values,
604 sizeof(struct ldb_val) * el2->num_values);
605 el1->num_values += el2->num_values;
606 talloc_free(discard_const_p(char, el2->name));
607 if (i+1<msg2->num_elements) {
608 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
609 (msg2->num_elements - (i+1)));
611 msg2->num_elements--;
620 * Canonicalize a message, merging elements of the same name
622 int ldb_msg_canonicalize_ex(struct ldb_context *ldb,
623 const struct ldb_message *msg,
625 struct ldb_message **_msg_out)
628 struct ldb_message *msg2;
630 msg2 = ldb_msg_copy(mem_ctx, msg);
632 return LDB_ERR_OPERATIONS_ERROR;
635 ldb_msg_sort_elements(msg2);
637 for (i=1; i < msg2->num_elements; i++) {
638 struct ldb_message_element *el1 = &msg2->elements[i-1];
639 struct ldb_message_element *el2 = &msg2->elements[i];
641 if (ldb_msg_element_compare_name(el1, el2) == 0) {
642 el1->values = talloc_realloc(msg2->elements,
643 el1->values, struct ldb_val,
644 el1->num_values + el2->num_values);
645 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
647 return LDB_ERR_OPERATIONS_ERROR;
649 memcpy(el1->values + el1->num_values,
651 sizeof(struct ldb_val) * el2->num_values);
652 el1->num_values += el2->num_values;
653 talloc_free(discard_const_p(char, el2->name));
654 if ((i+1) < msg2->num_elements) {
655 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
656 (msg2->num_elements - (i+1)));
658 msg2->num_elements--;
669 return a ldb_message representing the differences between msg1 and msg2. If you
670 then use this in a ldb_modify() call it can be used to save edits to a message
672 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
673 struct ldb_message *msg1,
674 struct ldb_message *msg2)
677 struct ldb_message *mod;
679 /* allocate mod message in NULL context
680 * so it should appear as 'leaked' in talloc reports */
681 ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2,
682 (TALLOC_CTX*)NULL, &mod);
683 if (ldb_ret != LDB_SUCCESS) {
691 * return a ldb_message representing the differences between msg1 and msg2.
692 * If you then use this in a ldb_modify() call it can be used to save edits to a message
694 * Result message is constructed as follows:
695 * - LDB_FLAG_MOD_ADD - elements found only in msg2
696 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
697 * Value for msg2 element is used
698 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
700 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
702 int ldb_msg_diff_ex(struct ldb_context *ldb,
703 struct ldb_message *msg1,
704 struct ldb_message *msg2,
706 struct ldb_message **_msg_out)
710 struct ldb_message *mod;
711 struct ldb_message_element *el;
712 TALLOC_CTX *temp_ctx;
714 temp_ctx = talloc_new(mem_ctx);
716 return LDB_ERR_OPERATIONS_ERROR;
719 mod = ldb_msg_new(temp_ctx);
725 mod->num_elements = 0;
726 mod->elements = NULL;
728 /* Canonicalize msg2 so we have no repeated elements
729 * Resulting message is allocated in mod's mem context,
730 * as we are going to move some elements from msg2 to
731 * mod object later */
732 ldb_res = ldb_msg_canonicalize_ex(ldb, msg2, (TALLOC_CTX*)mod, &msg2);
733 if (ldb_res != LDB_SUCCESS) {
737 /* look in msg2 to find elements that need to be added
739 for (i=0;i<msg2->num_elements;i++) {
740 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
742 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
746 ldb_res = ldb_msg_add(mod,
748 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
749 if (ldb_res != LDB_SUCCESS) {
754 /* look in msg1 to find elements that need to be deleted */
755 for (i=0;i<msg1->num_elements;i++) {
756 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
758 ldb_res = ldb_msg_add_empty(mod,
759 msg1->elements[i].name,
760 LDB_FLAG_MOD_DELETE, NULL);
761 if (ldb_res != LDB_SUCCESS) {
767 /* steal resulting message into supplied context */
768 talloc_steal(mem_ctx, mod);
771 talloc_free(temp_ctx);
775 talloc_free(temp_ctx);
776 return LDB_ERR_OPERATIONS_ERROR;
780 int ldb_msg_sanity_check(struct ldb_context *ldb,
781 const struct ldb_message *msg)
785 /* basic check on DN */
786 if (msg->dn == NULL) {
787 /* TODO: return also an error string */
788 ldb_set_errstring(ldb, "ldb message lacks a DN!");
789 return LDB_ERR_INVALID_DN_SYNTAX;
792 /* basic syntax checks */
793 for (i = 0; i < msg->num_elements; i++) {
794 for (j = 0; j < msg->elements[i].num_values; j++) {
795 if (msg->elements[i].values[j].length == 0) {
796 TALLOC_CTX *mem_ctx = talloc_new(ldb);
797 /* an attribute cannot be empty */
798 /* TODO: return also an error string */
799 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
800 msg->elements[i].name,
801 ldb_dn_get_linearized(msg->dn));
802 talloc_free(mem_ctx);
803 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
815 copy an attribute list. This only copies the array, not the elements
816 (ie. the elements are left as the same pointers)
818 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
823 for (i=0;attrs && attrs[i];i++) /* noop */ ;
824 ret = talloc_array(mem_ctx, const char *, i+1);
828 for (i=0;attrs && attrs[i];i++) {
837 copy an attribute list. This only copies the array, not the elements
838 (ie. the elements are left as the same pointers). The new attribute is added to the list.
840 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
846 for (i=0;attrs && attrs[i];i++) {
847 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
852 return ldb_attr_list_copy(mem_ctx, attrs);
854 ret = talloc_array(mem_ctx, const char *, i+2);
858 for (i=0;attrs && attrs[i];i++) {
868 return 1 if an attribute is in a list of attributes, or 0 otherwise
870 int ldb_attr_in_list(const char * const *attrs, const char *attr)
873 for (i=0;attrs && attrs[i];i++) {
874 if (ldb_attr_cmp(attrs[i], attr) == 0) {
883 rename the specified attribute in a search result
885 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
887 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
891 el->name = talloc_strdup(msg->elements, replace);
892 if (el->name == NULL) {
893 return LDB_ERR_OPERATIONS_ERROR;
900 copy the specified attribute in a search result to a new attribute
902 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
904 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
908 if (ldb_msg_add(msg, el, 0) != 0) {
909 return LDB_ERR_OPERATIONS_ERROR;
911 return ldb_msg_rename_attr(msg, attr, replace);
915 remove the specified element in a search result
917 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
919 ptrdiff_t n = (el - msg->elements);
920 if (n >= msg->num_elements) {
921 /* should we abort() here? */
924 if (n != msg->num_elements-1) {
925 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
932 remove the specified attribute in a search result
934 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
936 struct ldb_message_element *el;
938 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
939 ldb_msg_remove_element(msg, el);
944 return a LDAP formatted GeneralizedTime string
946 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
948 struct tm *tm = gmtime(&t);
956 /* we now excatly how long this string will be */
957 ts = talloc_array(mem_ctx, char, 18);
959 /* formatted like: 20040408072012.0Z */
961 "%04u%02u%02u%02u%02u%02u.0Z",
962 tm->tm_year+1900, tm->tm_mon+1,
963 tm->tm_mday, tm->tm_hour, tm->tm_min,
975 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
977 time_t ldb_string_to_time(const char *s)
981 if (s == NULL) return 0;
983 memset(&tm, 0, sizeof(tm));
984 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
985 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
986 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
996 convert a LDAP GeneralizedTime string in ldb_val format to a
999 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1003 if (v == NULL || !v->data || v->length < 17) {
1004 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1007 memset(&tm, 0, sizeof(tm));
1009 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1010 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1011 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1012 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1023 return a LDAP formatted UTCTime string
1025 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1027 struct tm *tm = gmtime(&t);
1035 /* we now excatly how long this string will be */
1036 ts = talloc_array(mem_ctx, char, 14);
1038 /* formatted like: 20040408072012.0Z => 040408072012Z */
1039 r = snprintf(ts, 14,
1040 "%02u%02u%02u%02u%02u%02uZ",
1041 (tm->tm_year+1900)%100, tm->tm_mon+1,
1042 tm->tm_mday, tm->tm_hour, tm->tm_min,
1054 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1056 time_t ldb_string_utc_to_time(const char *s)
1060 if (s == NULL) return 0;
1062 memset(&tm, 0, sizeof(tm));
1063 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1064 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1065 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1068 if (tm.tm_year < 50) {
1078 dump a set of results to a file. Useful from within gdb
1080 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1084 for (i = 0; i < result->count; i++) {
1085 struct ldb_ldif ldif;
1086 fprintf(f, "# record %d\n", i+1);
1087 ldif.changetype = LDB_CHANGETYPE_NONE;
1088 ldif.msg = result->msgs[i];
1089 ldb_ldif_write_file(ldb, f, &ldif);
1094 checks for a string attribute. Returns "1" on match and otherwise "0".
1096 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1097 const char *name, const char *value)
1099 struct ldb_message_element *el;
1102 el = ldb_msg_find_element(msg, name);
1107 val.data = discard_const_p(uint8_t, value);
1108 val.length = strlen(value);
1110 if (ldb_msg_find_val(el, &val)) {