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"
35 #include "lib/util/binsearch.h"
38 create a new ldb_message in a given memory context (NULL for top level)
40 struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
42 return talloc_zero(mem_ctx, struct ldb_message);
46 find an element in a message by attribute name
48 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
49 const char *attr_name)
52 if (msg->flags & LDB_FLAG_SORTED_ATTRIBUTES) {
53 struct ldb_message_element *e;
54 if (msg->num_elements == 0) {
57 BINARY_ARRAY_SEARCH(msg->elements, msg->num_elements, name,
58 attr_name, strcasecmp, e);
59 /* distinguishedname if present on sorted message is always at the end */
61 strcasecmp(attr_name, "distinguishedname") == 0 &&
62 strcasecmp(msg->elements[msg->num_elements - 1].name, attr_name) == 0)
64 return &msg->elements[msg->num_elements - 1];
68 for (i=0;i<msg->num_elements;i++) {
69 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
70 return &msg->elements[i];
77 see if two ldb_val structures contain exactly the same data
78 return 1 for a match, 0 for a mis-match
80 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
82 if (v1->length != v2->length) return 0;
83 if (v1->data == v2->data) return 1;
84 if (v1->length == 0) return 1;
86 if (memcmp(v1->data, v2->data, v1->length) == 0) {
94 find a value in an element
95 assumes case sensitive comparison
97 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
101 for (i=0;i<el->num_values;i++) {
102 if (ldb_val_equal_exact(val, &el->values[i])) {
103 return &el->values[i];
110 duplicate a ldb_val structure
112 struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
115 v2.length = v->length;
116 if (v->data == NULL) {
121 /* the +1 is to cope with buggy C library routines like strndup
122 that look one byte beyond */
123 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
129 memcpy(v2.data, v->data, v->length);
130 ((char *)v2.data)[v->length] = 0;
135 * Adds new empty element to msg->elements
137 static int _ldb_msg_add_el(struct ldb_message *msg,
138 struct ldb_message_element **return_el)
140 struct ldb_message_element *els;
142 /* do not concidere attributes to be sorted */
145 * TODO: Find out a way to assert on input parameters.
146 * msg and return_el must be valid
149 els = talloc_realloc(msg, msg->elements,
150 struct ldb_message_element, msg->num_elements + 1);
152 return LDB_ERR_OPERATIONS_ERROR;
155 ZERO_STRUCT(els[msg->num_elements]);
160 *return_el = &els[msg->num_elements-1];
166 * Add an empty element with a given name to a message
168 int ldb_msg_add_empty(struct ldb_message *msg,
169 const char *attr_name,
171 struct ldb_message_element **return_el)
174 struct ldb_message_element *el;
175 int msgflags = msg->flags;
177 ret = _ldb_msg_add_el(msg, &el);
178 if (ret != LDB_SUCCESS) {
182 /* initialize newly added element */
184 el->name = talloc_strdup(msg->elements, attr_name);
186 return LDB_ERR_OPERATIONS_ERROR;
188 /* Restore flags as distinguisedName is always at the end in sorted
190 if (strcasecmp(attr_name, "distinguishedName") == 0) {
191 msg->flags = msgflags;
202 * Adds an element to a message.
204 * NOTE: Ownership of ldb_message_element fields
205 * is NOT transferred. Thus, if *el pointer
206 * is invalidated for some reason, this will
207 * corrupt *msg contents also
209 int ldb_msg_add(struct ldb_message *msg,
210 const struct ldb_message_element *el,
214 struct ldb_message_element *el_new;
215 /* We have to copy this, just in case *el is a pointer into
216 * what ldb_msg_add_empty() is about to realloc() */
217 struct ldb_message_element el_copy = *el;
219 ret = _ldb_msg_add_el(msg, &el_new);
220 if (ret != LDB_SUCCESS) {
224 el_new->flags = flags;
225 el_new->name = el_copy.name;
226 el_new->num_values = el_copy.num_values;
227 el_new->values = el_copy.values;
233 add a value to a message
235 int ldb_msg_add_value(struct ldb_message *msg,
236 const char *attr_name,
237 const struct ldb_val *val,
238 struct ldb_message_element **return_el)
240 struct ldb_message_element *el;
241 struct ldb_val *vals;
244 el = ldb_msg_find_element(msg, attr_name);
246 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
247 if (ret != LDB_SUCCESS) {
252 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
255 return LDB_ERR_OPERATIONS_ERROR;
258 el->values[el->num_values] = *val;
270 add a value to a message, stealing it into the 'right' place
272 int ldb_msg_add_steal_value(struct ldb_message *msg,
273 const char *attr_name,
277 struct ldb_message_element *el;
279 ret = ldb_msg_add_value(msg, attr_name, val, &el);
280 if (ret == LDB_SUCCESS) {
281 talloc_steal(el->values, val->data);
288 add a string element to a message
290 int ldb_msg_add_string(struct ldb_message *msg,
291 const char *attr_name, const char *str)
295 val.data = discard_const_p(uint8_t, str);
296 val.length = strlen(str);
298 if (val.length == 0) {
299 /* allow empty strings as non-existent attributes */
303 return ldb_msg_add_value(msg, attr_name, &val, NULL);
307 add a string element to a message, stealing it into the 'right' place
309 int ldb_msg_add_steal_string(struct ldb_message *msg,
310 const char *attr_name, char *str)
314 val.data = (uint8_t *)str;
315 val.length = strlen(str);
317 if (val.length == 0) {
318 /* allow empty strings as non-existent attributes */
322 return ldb_msg_add_steal_value(msg, attr_name, &val);
326 add a DN element to a message
327 WARNING: this uses the linearized string from the dn, and does not
330 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
333 char *str = ldb_dn_alloc_linearized(msg, dn);
336 /* we don't want to have unknown DNs added */
337 return LDB_ERR_OPERATIONS_ERROR;
340 return ldb_msg_add_steal_string(msg, attr_name, str);
344 add a printf formatted element to a message
346 int ldb_msg_add_fmt(struct ldb_message *msg,
347 const char *attr_name, const char *fmt, ...)
354 str = talloc_vasprintf(msg, fmt, ap);
357 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
359 val.data = (uint8_t *)str;
360 val.length = strlen(str);
362 return ldb_msg_add_steal_value(msg, attr_name, &val);
366 compare two ldb_message_element structures
367 assumes case sensitive comparison
369 int ldb_msg_element_compare(struct ldb_message_element *el1,
370 struct ldb_message_element *el2)
374 if (el1->num_values != el2->num_values) {
375 return el1->num_values - el2->num_values;
378 for (i=0;i<el1->num_values;i++) {
379 if (!ldb_msg_find_val(el2, &el1->values[i])) {
388 compare two ldb_message_element structures.
389 Different ordering is considered a mismatch
391 bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
392 const struct ldb_message_element *el2)
395 if (el1->num_values != el2->num_values) {
398 for (i=0;i<el1->num_values;i++) {
399 if (ldb_val_equal_exact(&el1->values[i],
400 &el2->values[i]) != 1) {
408 compare two ldb_message_element structures
409 comparing by element name
411 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
412 struct ldb_message_element *el2)
414 return ldb_attr_cmp(el1->name, el2->name);
418 convenience functions to return common types from a message
419 these return the first value if the attribute is multi-valued
421 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
422 const char *attr_name)
424 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
425 if (!el || el->num_values == 0) {
428 return &el->values[0];
431 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
432 const char *attr_name,
435 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
436 char buf[sizeof("-2147483648")];
440 if (!v || !v->data) {
441 return default_value;
445 if (v->length >= sizeof(buf)) {
446 return default_value;
449 memcpy(buf, v->data, v->length);
451 ret = (int) strtoll(buf, &end, 10);
453 return default_value;
455 if (end && end[0] != '\0') {
456 return default_value;
461 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
462 const char *attr_name,
463 unsigned int default_value)
465 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
466 char buf[sizeof("-2147483648")];
470 if (!v || !v->data) {
471 return default_value;
475 if (v->length >= sizeof(buf)) {
476 return default_value;
479 memcpy(buf, v->data, v->length);
481 ret = (unsigned int) strtoll(buf, &end, 10);
484 ret = (unsigned int) strtoull(buf, &end, 10);
486 return default_value;
489 if (end && end[0] != '\0') {
490 return default_value;
495 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
496 const char *attr_name,
497 int64_t default_value)
499 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
500 char buf[sizeof("-9223372036854775808")];
504 if (!v || !v->data) {
505 return default_value;
509 if (v->length >= sizeof(buf)) {
510 return default_value;
513 memcpy(buf, v->data, v->length);
515 ret = (int64_t) strtoll(buf, &end, 10);
517 return default_value;
519 if (end && end[0] != '\0') {
520 return default_value;
525 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
526 const char *attr_name,
527 uint64_t default_value)
529 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
530 char buf[sizeof("-9223372036854775808")];
534 if (!v || !v->data) {
535 return default_value;
539 if (v->length >= sizeof(buf)) {
540 return default_value;
543 memcpy(buf, v->data, v->length);
545 ret = (uint64_t) strtoll(buf, &end, 10);
548 ret = (uint64_t) strtoull(buf, &end, 10);
550 return default_value;
553 if (end && end[0] != '\0') {
554 return default_value;
559 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
560 const char *attr_name,
561 double default_value)
563 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
568 if (!v || !v->data) {
569 return default_value;
571 buf = talloc_strndup(msg, (const char *)v->data, v->length);
573 return default_value;
577 ret = strtod(buf, &end);
580 return default_value;
582 if (end && end[0] != '\0') {
583 return default_value;
588 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
589 const char *attr_name,
592 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
593 if (!v || !v->data) {
594 return default_value;
596 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
599 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
602 return default_value;
605 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
606 const char *attr_name,
607 const char *default_value)
609 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
610 if (!v || !v->data) {
611 return default_value;
613 if (v->data[v->length] != '\0') {
614 return default_value;
616 return (const char *)v->data;
619 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
621 const struct ldb_message *msg,
622 const char *attr_name)
624 struct ldb_dn *res_dn;
625 const struct ldb_val *v;
627 v = ldb_msg_find_ldb_val(msg, attr_name);
628 if (!v || !v->data) {
631 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
632 if ( ! ldb_dn_validate(res_dn)) {
640 sort the elements of a message by name
642 void ldb_msg_sort_elements(struct ldb_message *msg)
644 TYPESAFE_QSORT(msg->elements, msg->num_elements,
645 ldb_msg_element_compare_name);
649 shallow copy a message - copying only the elements array so that the caller
650 can safely add new elements without changing the message
652 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
653 const struct ldb_message *msg)
655 struct ldb_message *msg2;
658 msg2 = talloc(mem_ctx, struct ldb_message);
659 if (msg2 == NULL) return NULL;
663 msg2->elements = talloc_array(msg2, struct ldb_message_element,
665 if (msg2->elements == NULL) goto failed;
667 for (i=0;i<msg2->num_elements;i++) {
668 msg2->elements[i] = msg->elements[i];
680 copy a message, allocating new memory for all parts
682 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
683 const struct ldb_message *msg)
685 struct ldb_message *msg2;
688 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
689 if (msg2 == NULL) return NULL;
691 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
692 if (msg2->dn == NULL) goto failed;
694 for (i=0;i<msg2->num_elements;i++) {
695 struct ldb_message_element *el = &msg2->elements[i];
696 struct ldb_val *values = el->values;
697 el->name = talloc_strdup(msg2->elements, el->name);
698 if (el->name == NULL) goto failed;
699 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
700 if (el->values == NULL) goto failed;
701 for (j=0;j<el->num_values;j++) {
702 el->values[j] = ldb_val_dup(el->values, &values[j]);
703 if (el->values[j].data == NULL && values[j].length != 0) {
718 * Canonicalize a message, merging elements of the same name
720 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
721 const struct ldb_message *msg)
724 struct ldb_message *msg2;
727 * Preserve previous behavior and allocate
728 * *msg2 into *ldb context
730 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
731 if (ret != LDB_SUCCESS) {
739 * Canonicalize a message, merging elements of the same name
741 int ldb_msg_normalize(struct ldb_context *ldb,
743 const struct ldb_message *msg,
744 struct ldb_message **_msg_out)
747 struct ldb_message *msg2;
749 msg2 = ldb_msg_copy(mem_ctx, msg);
752 return LDB_ERR_OPERATIONS_ERROR;
755 ldb_msg_sort_elements(msg2);
757 for (i=1; i < msg2->num_elements; i++) {
758 struct ldb_message_element *el1 = &msg2->elements[i-1];
759 struct ldb_message_element *el2 = &msg2->elements[i];
761 if (ldb_msg_element_compare_name(el1, el2) == 0) {
762 el1->values = talloc_realloc(msg2->elements,
763 el1->values, struct ldb_val,
764 el1->num_values + el2->num_values);
765 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
767 return LDB_ERR_OPERATIONS_ERROR;
769 memcpy(el1->values + el1->num_values,
771 sizeof(struct ldb_val) * el2->num_values);
772 el1->num_values += el2->num_values;
773 talloc_free(discard_const_p(char, el2->name));
774 if ((i+1) < msg2->num_elements) {
775 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
776 (msg2->num_elements - (i+1)));
778 msg2->num_elements--;
789 * return a ldb_message representing the differences between msg1 and msg2.
790 * If you then use this in a ldb_modify() call,
791 * it can be used to save edits to a message
793 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
794 struct ldb_message *msg1,
795 struct ldb_message *msg2)
798 struct ldb_message *mod;
800 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
801 if (ldb_ret != LDB_SUCCESS) {
809 * return a ldb_message representing the differences between msg1 and msg2.
810 * If you then use this in a ldb_modify() call it can be used to save edits to a message
812 * Result message is constructed as follows:
813 * - LDB_FLAG_MOD_ADD - elements found only in msg2
814 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
815 * Value for msg2 element is used
816 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
818 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
820 int ldb_msg_difference(struct ldb_context *ldb,
822 struct ldb_message *msg1,
823 struct ldb_message *msg2,
824 struct ldb_message **_msg_out)
828 struct ldb_message *mod;
829 struct ldb_message_element *el;
830 TALLOC_CTX *temp_ctx;
832 temp_ctx = talloc_new(mem_ctx);
834 return LDB_ERR_OPERATIONS_ERROR;
837 mod = ldb_msg_new(temp_ctx);
843 mod->num_elements = 0;
844 mod->elements = NULL;
847 * Canonicalize *msg2 so we have no repeated elements
848 * Resulting message is allocated in *mod's mem context,
849 * as we are going to move some elements from *msg2 to
852 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
853 if (ldb_res != LDB_SUCCESS) {
857 /* look in msg2 to find elements that need to be added or modified */
858 for (i=0;i<msg2->num_elements;i++) {
859 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
861 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
865 ldb_res = ldb_msg_add(mod,
867 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
868 if (ldb_res != LDB_SUCCESS) {
873 /* look in msg1 to find elements that need to be deleted */
874 for (i=0;i<msg1->num_elements;i++) {
875 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
877 ldb_res = ldb_msg_add_empty(mod,
878 msg1->elements[i].name,
879 LDB_FLAG_MOD_DELETE, NULL);
880 if (ldb_res != LDB_SUCCESS) {
886 /* steal resulting message into supplied context */
887 talloc_steal(mem_ctx, mod);
890 talloc_free(temp_ctx);
894 talloc_free(temp_ctx);
895 return LDB_ERR_OPERATIONS_ERROR;
899 int ldb_msg_sanity_check(struct ldb_context *ldb,
900 const struct ldb_message *msg)
904 /* basic check on DN */
905 if (msg->dn == NULL) {
906 ldb_set_errstring(ldb, "ldb message lacks a DN!");
907 return LDB_ERR_INVALID_DN_SYNTAX;
910 /* basic syntax checks */
911 for (i = 0; i < msg->num_elements; i++) {
912 for (j = 0; j < msg->elements[i].num_values; j++) {
913 if (msg->elements[i].values[j].length == 0) {
914 /* an attribute cannot be empty */
915 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
916 msg->elements[i].name,
917 ldb_dn_get_linearized(msg->dn));
918 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
930 copy an attribute list. This only copies the array, not the elements
931 (ie. the elements are left as the same pointers)
933 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
938 for (i=0;attrs && attrs[i];i++) /* noop */ ;
939 ret = talloc_array(mem_ctx, const char *, i+1);
943 for (i=0;attrs && attrs[i];i++) {
952 copy an attribute list. This only copies the array, not the elements
953 (ie. the elements are left as the same pointers). The new attribute is added to the list.
955 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
961 for (i=0;attrs && attrs[i];i++) {
962 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
967 return ldb_attr_list_copy(mem_ctx, attrs);
969 ret = talloc_array(mem_ctx, const char *, i+2);
973 for (i=0;attrs && attrs[i];i++) {
983 return 1 if an attribute is in a list of attributes, or 0 otherwise
985 int ldb_attr_in_list(const char * const *attrs, const char *attr)
988 for (i=0;attrs && attrs[i];i++) {
989 if (ldb_attr_cmp(attrs[i], attr) == 0) {
998 rename the specified attribute in a search result
1000 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
1002 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1007 el->name = talloc_strdup(msg->elements, replace);
1008 if (el->name == NULL) {
1009 return LDB_ERR_OPERATIONS_ERROR;
1016 copy the specified attribute in a search result to a new attribute
1018 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
1020 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1026 ret = ldb_msg_add(msg, el, 0);
1027 if (ret != LDB_SUCCESS) {
1030 return ldb_msg_rename_attr(msg, attr, replace);
1034 remove the specified element in a search result
1036 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
1038 ptrdiff_t n = (el - msg->elements);
1039 if (n >= msg->num_elements) {
1040 /* should we abort() here? */
1043 if (n != msg->num_elements-1) {
1044 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
1046 msg->num_elements--;
1051 remove the specified attribute in a search result
1053 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1055 struct ldb_message_element *el;
1057 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1058 ldb_msg_remove_element(msg, el);
1063 return a LDAP formatted GeneralizedTime string
1065 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1067 struct tm *tm = gmtime(&t);
1075 /* we now excatly how long this string will be */
1076 ts = talloc_array(mem_ctx, char, 18);
1078 /* formatted like: 20040408072012.0Z */
1079 r = snprintf(ts, 18,
1080 "%04u%02u%02u%02u%02u%02u.0Z",
1081 tm->tm_year+1900, tm->tm_mon+1,
1082 tm->tm_mday, tm->tm_hour, tm->tm_min,
1094 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1096 time_t ldb_string_to_time(const char *s)
1100 if (s == NULL) return 0;
1102 memset(&tm, 0, sizeof(tm));
1103 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1104 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1105 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1115 convert a LDAP GeneralizedTime string in ldb_val format to a
1118 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1124 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1127 if (v->data == NULL) {
1128 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1131 if (v->length < 16 && v->length != 13) {
1132 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1135 if (v->data[v->length - 1] != 'Z') {
1136 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1139 if (v->length == 13) {
1140 memcpy(val, v->data, 12);
1142 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
1143 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1144 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1145 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1147 if (tm.tm_year < 50) {
1153 * anything between '.' and 'Z' is silently ignored.
1155 if (v->data[14] != '.') {
1156 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1159 memcpy(val, v->data, 14);
1161 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
1162 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1163 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1164 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1176 return a LDAP formatted UTCTime string
1178 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1180 struct tm *tm = gmtime(&t);
1188 /* we now excatly how long this string will be */
1189 ts = talloc_array(mem_ctx, char, 14);
1191 /* formatted like: 20040408072012.0Z => 040408072012Z */
1192 r = snprintf(ts, 14,
1193 "%02u%02u%02u%02u%02u%02uZ",
1194 (tm->tm_year+1900)%100, tm->tm_mon+1,
1195 tm->tm_mday, tm->tm_hour, tm->tm_min,
1207 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1209 time_t ldb_string_utc_to_time(const char *s)
1213 if (s == NULL) return 0;
1215 memset(&tm, 0, sizeof(tm));
1216 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1217 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1218 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1221 if (tm.tm_year < 50) {
1231 dump a set of results to a file. Useful from within gdb
1233 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1237 for (i = 0; i < result->count; i++) {
1238 struct ldb_ldif ldif;
1239 fprintf(f, "# record %d\n", i+1);
1240 ldif.changetype = LDB_CHANGETYPE_NONE;
1241 ldif.msg = result->msgs[i];
1242 ldb_ldif_write_file(ldb, f, &ldif);
1247 checks for a string attribute. Returns "1" on match and otherwise "0".
1249 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1250 const char *name, const char *value)
1252 struct ldb_message_element *el;
1255 el = ldb_msg_find_element(msg, name);
1260 val.data = discard_const_p(uint8_t, value);
1261 val.length = strlen(value);
1263 if (ldb_msg_find_val(el, &val)) {
1272 compare a ldb_val to a string
1274 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1276 size_t len = strlen(str);
1277 if (len != v->length) {
1278 return len - v->length;
1280 return strncmp((const char *)v->data, str, len);