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(TALLOC_CTX *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(TALLOC_CTX *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;
126 * TODO: Find out a way to assert on input parameters.
127 * msg and return_el must be valid
130 els = talloc_realloc(msg, msg->elements,
131 struct ldb_message_element, msg->num_elements + 1);
134 return LDB_ERR_OPERATIONS_ERROR;
137 ZERO_STRUCT(els[msg->num_elements]);
142 *return_el = &els[msg->num_elements-1];
148 * Add an empty element with a given name to a message
150 int ldb_msg_add_empty(struct ldb_message *msg,
151 const char *attr_name,
153 struct ldb_message_element **return_el)
156 struct ldb_message_element *el;
158 ret = _ldb_msg_add_el(msg, &el);
159 if (ret != LDB_SUCCESS) {
163 /* initialize newly added element */
165 el->name = talloc_strdup(msg->elements, attr_name);
168 return LDB_ERR_OPERATIONS_ERROR;
179 * Adds an element to a message.
181 * NOTE: Ownership of ldb_message_element fields
182 * is NOT transferred. Thus, if *el pointer
183 * is invalidated for some reason, this will
184 * corrupt *msg contents also
186 int ldb_msg_add(struct ldb_message *msg,
187 const struct ldb_message_element *el,
191 struct ldb_message_element *el_new;
192 /* We have to copy this, just in case *el is a pointer into
193 * what ldb_msg_add_empty() is about to realloc() */
194 struct ldb_message_element el_copy = *el;
196 ret = _ldb_msg_add_el(msg, &el_new);
197 if (ret != LDB_SUCCESS) {
201 el_new->flags = flags;
202 el_new->name = el_copy.name;
203 el_new->num_values = el_copy.num_values;
204 el_new->values = el_copy.values;
210 add a value to a message
212 int ldb_msg_add_value(struct ldb_message *msg,
213 const char *attr_name,
214 const struct ldb_val *val,
215 struct ldb_message_element **return_el)
217 struct ldb_message_element *el;
218 struct ldb_val *vals;
221 el = ldb_msg_find_element(msg, attr_name);
223 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
224 if (ret != LDB_SUCCESS) {
229 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
233 return LDB_ERR_OPERATIONS_ERROR;
236 el->values[el->num_values] = *val;
248 add a value to a message, stealing it into the 'right' place
250 int ldb_msg_add_steal_value(struct ldb_message *msg,
251 const char *attr_name,
255 struct ldb_message_element *el;
257 ret = ldb_msg_add_value(msg, attr_name, val, &el);
258 if (ret == LDB_SUCCESS) {
259 talloc_steal(el->values, val->data);
266 add a string element to a message
268 int ldb_msg_add_string(struct ldb_message *msg,
269 const char *attr_name, const char *str)
273 val.data = discard_const_p(uint8_t, str);
274 val.length = strlen(str);
276 if (val.length == 0) {
277 /* allow empty strings as non-existent attributes */
281 return ldb_msg_add_value(msg, attr_name, &val, NULL);
285 add a string element to a message, stealing it into the 'right' place
287 int ldb_msg_add_steal_string(struct ldb_message *msg,
288 const char *attr_name, char *str)
292 val.data = (uint8_t *)str;
293 val.length = strlen(str);
295 if (val.length == 0) {
296 /* allow empty strings as non-existent attributes */
300 return ldb_msg_add_steal_value(msg, attr_name, &val);
304 add a DN element to a message
305 WARNING: this uses the linearized string from the dn, and does not
308 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
311 char *str = ldb_dn_alloc_linearized(msg, dn);
314 /* we don't want to have unknown DNs added */
315 return LDB_ERR_OPERATIONS_ERROR;
318 return ldb_msg_add_steal_string(msg, attr_name, str);
322 add a printf formatted element to a message
324 int ldb_msg_add_fmt(struct ldb_message *msg,
325 const char *attr_name, const char *fmt, ...)
332 str = talloc_vasprintf(msg, fmt, ap);
335 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
337 val.data = (uint8_t *)str;
338 val.length = strlen(str);
340 return ldb_msg_add_steal_value(msg, attr_name, &val);
344 compare two ldb_message_element structures
345 assumes case sensitive comparison
347 int ldb_msg_element_compare(struct ldb_message_element *el1,
348 struct ldb_message_element *el2)
352 if (el1->num_values != el2->num_values) {
353 return el1->num_values - el2->num_values;
356 for (i=0;i<el1->num_values;i++) {
357 if (!ldb_msg_find_val(el2, &el1->values[i])) {
366 compare two ldb_message_element structures
367 comparing by element name
369 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
370 struct ldb_message_element *el2)
372 return ldb_attr_cmp(el1->name, el2->name);
376 convenience functions to return common types from a message
377 these return the first value if the attribute is multi-valued
379 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
380 const char *attr_name)
382 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
383 if (!el || el->num_values == 0) {
386 return &el->values[0];
389 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
390 const char *attr_name,
393 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
394 char buf[sizeof("-2147483648")];
398 if (!v || !v->data) {
399 return default_value;
403 if (v->length >= sizeof(buf)) {
404 return default_value;
407 memcpy(buf, v->data, v->length);
409 ret = (int) strtoll(buf, &end, 10);
411 return default_value;
413 if (end && end[0] != '\0') {
414 return default_value;
419 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
420 const char *attr_name,
421 unsigned int default_value)
423 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
424 char buf[sizeof("-2147483648")];
428 if (!v || !v->data) {
429 return default_value;
433 if (v->length >= sizeof(buf)) {
434 return default_value;
437 memcpy(buf, v->data, v->length);
439 ret = (unsigned int) strtoll(buf, &end, 10);
442 ret = (unsigned int) strtoull(buf, &end, 10);
444 return default_value;
447 if (end && end[0] != '\0') {
448 return default_value;
453 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
454 const char *attr_name,
455 int64_t default_value)
457 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
458 char buf[sizeof("-9223372036854775808")];
462 if (!v || !v->data) {
463 return default_value;
467 if (v->length >= sizeof(buf)) {
468 return default_value;
471 memcpy(buf, v->data, v->length);
473 ret = (int64_t) strtoll(buf, &end, 10);
475 return default_value;
477 if (end && end[0] != '\0') {
478 return default_value;
483 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
484 const char *attr_name,
485 uint64_t default_value)
487 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
488 char buf[sizeof("-9223372036854775808")];
492 if (!v || !v->data) {
493 return default_value;
497 if (v->length >= sizeof(buf)) {
498 return default_value;
501 memcpy(buf, v->data, v->length);
503 ret = (uint64_t) strtoll(buf, &end, 10);
506 ret = (uint64_t) strtoull(buf, &end, 10);
508 return default_value;
511 if (end && end[0] != '\0') {
512 return default_value;
517 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
518 const char *attr_name,
519 double default_value)
521 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
526 if (!v || !v->data) {
527 return default_value;
529 buf = talloc_strndup(msg, (const char *)v->data, v->length);
531 return default_value;
535 ret = strtod(buf, &end);
538 return default_value;
540 if (end && end[0] != '\0') {
541 return default_value;
546 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
547 const char *attr_name,
550 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
551 if (!v || !v->data) {
552 return default_value;
554 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
557 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
560 return default_value;
563 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
564 const char *attr_name,
565 const char *default_value)
567 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
568 if (!v || !v->data) {
569 return default_value;
571 if (v->data[v->length] != '\0') {
572 return default_value;
574 return (const char *)v->data;
577 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
579 const struct ldb_message *msg,
580 const char *attr_name)
582 struct ldb_dn *res_dn;
583 const struct ldb_val *v;
585 v = ldb_msg_find_ldb_val(msg, attr_name);
586 if (!v || !v->data) {
589 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
590 if ( ! ldb_dn_validate(res_dn)) {
598 sort the elements of a message by name
600 void ldb_msg_sort_elements(struct ldb_message *msg)
602 TYPESAFE_QSORT(msg->elements, msg->num_elements,
603 ldb_msg_element_compare_name);
607 shallow copy a message - copying only the elements array so that the caller
608 can safely add new elements without changing the message
610 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
611 const struct ldb_message *msg)
613 struct ldb_message *msg2;
616 msg2 = talloc(mem_ctx, struct ldb_message);
617 if (msg2 == NULL) return NULL;
621 msg2->elements = talloc_array(msg2, struct ldb_message_element,
623 if (msg2->elements == NULL) goto failed;
625 for (i=0;i<msg2->num_elements;i++) {
626 msg2->elements[i] = msg->elements[i];
638 copy a message, allocating new memory for all parts
640 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
641 const struct ldb_message *msg)
643 struct ldb_message *msg2;
646 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
647 if (msg2 == NULL) return NULL;
649 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
650 if (msg2->dn == NULL) goto failed;
652 for (i=0;i<msg2->num_elements;i++) {
653 struct ldb_message_element *el = &msg2->elements[i];
654 struct ldb_val *values = el->values;
655 el->name = talloc_strdup(msg2->elements, el->name);
656 if (el->name == NULL) goto failed;
657 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
658 for (j=0;j<el->num_values;j++) {
659 el->values[j] = ldb_val_dup(el->values, &values[j]);
660 if (el->values[j].data == NULL && values[j].length != 0) {
675 * Canonicalize a message, merging elements of the same name
677 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
678 const struct ldb_message *msg)
681 struct ldb_message *msg2;
684 * Preserve previous behavior and allocate
685 * *msg2 into *ldb context
687 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
688 if (ret != LDB_SUCCESS) {
696 * Canonicalize a message, merging elements of the same name
698 int ldb_msg_normalize(struct ldb_context *ldb,
700 const struct ldb_message *msg,
701 struct ldb_message **_msg_out)
704 struct ldb_message *msg2;
706 msg2 = ldb_msg_copy(mem_ctx, msg);
708 return LDB_ERR_OPERATIONS_ERROR;
711 ldb_msg_sort_elements(msg2);
713 for (i=1; i < msg2->num_elements; i++) {
714 struct ldb_message_element *el1 = &msg2->elements[i-1];
715 struct ldb_message_element *el2 = &msg2->elements[i];
717 if (ldb_msg_element_compare_name(el1, el2) == 0) {
718 el1->values = talloc_realloc(msg2->elements,
719 el1->values, struct ldb_val,
720 el1->num_values + el2->num_values);
721 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
723 return LDB_ERR_OPERATIONS_ERROR;
725 memcpy(el1->values + el1->num_values,
727 sizeof(struct ldb_val) * el2->num_values);
728 el1->num_values += el2->num_values;
729 talloc_free(discard_const_p(char, el2->name));
730 if ((i+1) < msg2->num_elements) {
731 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
732 (msg2->num_elements - (i+1)));
734 msg2->num_elements--;
745 * return a ldb_message representing the differences between msg1 and msg2.
746 * If you then use this in a ldb_modify() call,
747 * it can be used to save edits to a message
749 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
750 struct ldb_message *msg1,
751 struct ldb_message *msg2)
754 struct ldb_message *mod;
756 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
757 if (ldb_ret != LDB_SUCCESS) {
765 * return a ldb_message representing the differences between msg1 and msg2.
766 * If you then use this in a ldb_modify() call it can be used to save edits to a message
768 * Result message is constructed as follows:
769 * - LDB_FLAG_MOD_ADD - elements found only in msg2
770 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
771 * Value for msg2 element is used
772 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
774 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
776 int ldb_msg_difference(struct ldb_context *ldb,
778 struct ldb_message *msg1,
779 struct ldb_message *msg2,
780 struct ldb_message **_msg_out)
784 struct ldb_message *mod;
785 struct ldb_message_element *el;
786 TALLOC_CTX *temp_ctx;
788 temp_ctx = talloc_new(mem_ctx);
790 return LDB_ERR_OPERATIONS_ERROR;
793 mod = ldb_msg_new(temp_ctx);
799 mod->num_elements = 0;
800 mod->elements = NULL;
803 * Canonicalize *msg2 so we have no repeated elements
804 * Resulting message is allocated in *mod's mem context,
805 * as we are going to move some elements from *msg2 to
808 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
809 if (ldb_res != LDB_SUCCESS) {
813 /* look in msg2 to find elements that need to be added or modified */
814 for (i=0;i<msg2->num_elements;i++) {
815 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
817 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
821 ldb_res = ldb_msg_add(mod,
823 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
824 if (ldb_res != LDB_SUCCESS) {
829 /* look in msg1 to find elements that need to be deleted */
830 for (i=0;i<msg1->num_elements;i++) {
831 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
833 ldb_res = ldb_msg_add_empty(mod,
834 msg1->elements[i].name,
835 LDB_FLAG_MOD_DELETE, NULL);
836 if (ldb_res != LDB_SUCCESS) {
842 /* steal resulting message into supplied context */
843 talloc_steal(mem_ctx, mod);
846 talloc_free(temp_ctx);
850 talloc_free(temp_ctx);
851 return LDB_ERR_OPERATIONS_ERROR;
855 int ldb_msg_sanity_check(struct ldb_context *ldb,
856 const struct ldb_message *msg)
860 /* basic check on DN */
861 if (msg->dn == NULL) {
862 ldb_set_errstring(ldb, "ldb message lacks a DN!");
863 return LDB_ERR_INVALID_DN_SYNTAX;
866 /* basic syntax checks */
867 for (i = 0; i < msg->num_elements; i++) {
868 for (j = 0; j < msg->elements[i].num_values; j++) {
869 if (msg->elements[i].values[j].length == 0) {
870 /* an attribute cannot be empty */
871 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
872 msg->elements[i].name,
873 ldb_dn_get_linearized(msg->dn));
874 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
886 copy an attribute list. This only copies the array, not the elements
887 (ie. the elements are left as the same pointers)
889 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
894 for (i=0;attrs && attrs[i];i++) /* noop */ ;
895 ret = talloc_array(mem_ctx, const char *, i+1);
899 for (i=0;attrs && attrs[i];i++) {
908 copy an attribute list. This only copies the array, not the elements
909 (ie. the elements are left as the same pointers). The new attribute is added to the list.
911 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
917 for (i=0;attrs && attrs[i];i++) {
918 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
923 return ldb_attr_list_copy(mem_ctx, attrs);
925 ret = talloc_array(mem_ctx, const char *, i+2);
929 for (i=0;attrs && attrs[i];i++) {
939 return 1 if an attribute is in a list of attributes, or 0 otherwise
941 int ldb_attr_in_list(const char * const *attrs, const char *attr)
944 for (i=0;attrs && attrs[i];i++) {
945 if (ldb_attr_cmp(attrs[i], attr) == 0) {
954 rename the specified attribute in a search result
956 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
958 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
962 el->name = talloc_strdup(msg->elements, replace);
963 if (el->name == NULL) {
964 return LDB_ERR_OPERATIONS_ERROR;
971 copy the specified attribute in a search result to a new attribute
973 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
975 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
981 ret = ldb_msg_add(msg, el, 0);
982 if (ret != LDB_SUCCESS) {
985 return ldb_msg_rename_attr(msg, attr, replace);
989 remove the specified element in a search result
991 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
993 ptrdiff_t n = (el - msg->elements);
994 if (n >= msg->num_elements) {
995 /* should we abort() here? */
998 if (n != msg->num_elements-1) {
999 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
1001 msg->num_elements--;
1006 remove the specified attribute in a search result
1008 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1010 struct ldb_message_element *el;
1012 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1013 ldb_msg_remove_element(msg, el);
1018 return a LDAP formatted GeneralizedTime string
1020 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1022 struct tm *tm = gmtime(&t);
1030 /* we now excatly how long this string will be */
1031 ts = talloc_array(mem_ctx, char, 18);
1033 /* formatted like: 20040408072012.0Z */
1034 r = snprintf(ts, 18,
1035 "%04u%02u%02u%02u%02u%02u.0Z",
1036 tm->tm_year+1900, tm->tm_mon+1,
1037 tm->tm_mday, tm->tm_hour, tm->tm_min,
1049 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1051 time_t ldb_string_to_time(const char *s)
1055 if (s == NULL) return 0;
1057 memset(&tm, 0, sizeof(tm));
1058 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1059 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1060 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1070 convert a LDAP GeneralizedTime string in ldb_val format to a
1073 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1077 if (v == NULL || !v->data || v->length < 17) {
1078 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1081 memset(&tm, 0, sizeof(tm));
1083 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1084 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1085 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1086 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1097 return a LDAP formatted UTCTime string
1099 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1101 struct tm *tm = gmtime(&t);
1109 /* we now excatly how long this string will be */
1110 ts = talloc_array(mem_ctx, char, 14);
1112 /* formatted like: 20040408072012.0Z => 040408072012Z */
1113 r = snprintf(ts, 14,
1114 "%02u%02u%02u%02u%02u%02uZ",
1115 (tm->tm_year+1900)%100, tm->tm_mon+1,
1116 tm->tm_mday, tm->tm_hour, tm->tm_min,
1128 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1130 time_t ldb_string_utc_to_time(const char *s)
1134 if (s == NULL) return 0;
1136 memset(&tm, 0, sizeof(tm));
1137 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1138 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1139 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1142 if (tm.tm_year < 50) {
1152 dump a set of results to a file. Useful from within gdb
1154 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1158 for (i = 0; i < result->count; i++) {
1159 struct ldb_ldif ldif;
1160 fprintf(f, "# record %d\n", i+1);
1161 ldif.changetype = LDB_CHANGETYPE_NONE;
1162 ldif.msg = result->msgs[i];
1163 ldb_ldif_write_file(ldb, f, &ldif);
1168 checks for a string attribute. Returns "1" on match and otherwise "0".
1170 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1171 const char *name, const char *value)
1173 struct ldb_message_element *el;
1176 el = ldb_msg_find_element(msg, name);
1181 val.data = discard_const_p(uint8_t, value);
1182 val.length = strlen(value);
1184 if (ldb_msg_find_val(el, &val)) {