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,
189 /* We have to copy this, just in case *el is a pointer into
190 * what ldb_msg_add_empty() is about to realloc() */
191 struct ldb_message_element el_copy = *el;
192 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != LDB_SUCCESS) {
193 return LDB_ERR_OPERATIONS_ERROR;
196 msg->elements[msg->num_elements-1] = el_copy;
197 msg->elements[msg->num_elements-1].flags = flags;
203 add a value to a message
205 int ldb_msg_add_value(struct ldb_message *msg,
206 const char *attr_name,
207 const struct ldb_val *val,
208 struct ldb_message_element **return_el)
210 struct ldb_message_element *el;
211 struct ldb_val *vals;
214 el = ldb_msg_find_element(msg, attr_name);
216 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
217 if (ret != LDB_SUCCESS) {
222 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
225 return LDB_ERR_OPERATIONS_ERROR;
228 el->values[el->num_values] = *val;
240 add a value to a message, stealing it into the 'right' place
242 int ldb_msg_add_steal_value(struct ldb_message *msg,
243 const char *attr_name,
247 struct ldb_message_element *el;
249 ret = ldb_msg_add_value(msg, attr_name, val, &el);
250 if (ret == LDB_SUCCESS) {
251 talloc_steal(el->values, val->data);
258 add a string element to a message
260 int ldb_msg_add_string(struct ldb_message *msg,
261 const char *attr_name, const char *str)
265 val.data = discard_const_p(uint8_t, str);
266 val.length = strlen(str);
268 if (val.length == 0) {
269 /* allow empty strings as non-existent attributes */
273 return ldb_msg_add_value(msg, attr_name, &val, NULL);
277 add a string element to a message, stealing it into the 'right' place
279 int ldb_msg_add_steal_string(struct ldb_message *msg,
280 const char *attr_name, char *str)
284 val.data = (uint8_t *)str;
285 val.length = strlen(str);
287 if (val.length == 0) {
288 /* allow empty strings as non-existent attributes */
292 return ldb_msg_add_steal_value(msg, attr_name, &val);
296 add a DN element to a message
297 WARNING: this uses the linearized string from the dn, and does not
300 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
303 return ldb_msg_add_steal_string(msg, attr_name,
304 ldb_dn_alloc_linearized(msg, dn));
308 add a printf formatted element to a message
310 int ldb_msg_add_fmt(struct ldb_message *msg,
311 const char *attr_name, const char *fmt, ...)
318 str = talloc_vasprintf(msg, fmt, ap);
321 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
323 val.data = (uint8_t *)str;
324 val.length = strlen(str);
326 return ldb_msg_add_steal_value(msg, attr_name, &val);
330 compare two ldb_message_element structures
331 assumes case sensitive comparison
333 int ldb_msg_element_compare(struct ldb_message_element *el1,
334 struct ldb_message_element *el2)
338 if (el1->num_values != el2->num_values) {
339 return el1->num_values - el2->num_values;
342 for (i=0;i<el1->num_values;i++) {
343 if (!ldb_msg_find_val(el2, &el1->values[i])) {
352 compare two ldb_message_element structures
353 comparing by element name
355 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
356 struct ldb_message_element *el2)
358 return ldb_attr_cmp(el1->name, el2->name);
362 convenience functions to return common types from a message
363 these return the first value if the attribute is multi-valued
365 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
366 const char *attr_name)
368 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
369 if (!el || el->num_values == 0) {
372 return &el->values[0];
375 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
376 const char *attr_name,
379 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
380 if (!v || !v->data) {
381 return default_value;
383 return strtol((const char *)v->data, NULL, 0);
386 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
387 const char *attr_name,
388 unsigned int default_value)
391 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
392 if (!v || !v->data) {
393 return default_value;
396 /* in LDAP there're only int32_t values */
398 ret = strtol((const char *)v->data, NULL, 0);
403 return strtoul((const char *)v->data, NULL, 0);
406 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
407 const char *attr_name,
408 int64_t default_value)
410 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
411 if (!v || !v->data) {
412 return default_value;
414 return strtoll((const char *)v->data, NULL, 0);
417 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
418 const char *attr_name,
419 uint64_t default_value)
422 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
423 if (!v || !v->data) {
424 return default_value;
427 /* in LDAP there're only int64_t values */
429 ret = strtoll((const char *)v->data, NULL, 0);
434 return strtoull((const char *)v->data, NULL, 0);
437 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
438 const char *attr_name,
439 double default_value)
441 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
442 if (!v || !v->data) {
443 return default_value;
445 return strtod((const char *)v->data, NULL);
448 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
449 const char *attr_name,
452 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
453 if (!v || !v->data) {
454 return default_value;
456 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
459 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
462 return default_value;
465 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
466 const char *attr_name,
467 const char *default_value)
469 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
470 if (!v || !v->data) {
471 return default_value;
473 return (const char *)v->data;
476 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
478 const struct ldb_message *msg,
479 const char *attr_name)
481 struct ldb_dn *res_dn;
482 const struct ldb_val *v;
484 v = ldb_msg_find_ldb_val(msg, attr_name);
485 if (!v || !v->data) {
488 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
489 if ( ! ldb_dn_validate(res_dn)) {
497 sort the elements of a message by name
499 void ldb_msg_sort_elements(struct ldb_message *msg)
501 TYPESAFE_QSORT(msg->elements, msg->num_elements,
502 ldb_msg_element_compare_name);
506 shallow copy a message - copying only the elements array so that the caller
507 can safely add new elements without changing the message
509 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
510 const struct ldb_message *msg)
512 struct ldb_message *msg2;
515 msg2 = talloc(mem_ctx, struct ldb_message);
516 if (msg2 == NULL) return NULL;
520 msg2->elements = talloc_array(msg2, struct ldb_message_element,
522 if (msg2->elements == NULL) goto failed;
524 for (i=0;i<msg2->num_elements;i++) {
525 msg2->elements[i] = msg->elements[i];
537 copy a message, allocating new memory for all parts
539 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
540 const struct ldb_message *msg)
542 struct ldb_message *msg2;
545 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
546 if (msg2 == NULL) return NULL;
548 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
549 if (msg2->dn == NULL) goto failed;
551 for (i=0;i<msg2->num_elements;i++) {
552 struct ldb_message_element *el = &msg2->elements[i];
553 struct ldb_val *values = el->values;
554 el->name = talloc_strdup(msg2->elements, el->name);
555 if (el->name == NULL) goto failed;
556 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
557 for (j=0;j<el->num_values;j++) {
558 el->values[j] = ldb_val_dup(el->values, &values[j]);
559 if (el->values[j].data == NULL && values[j].length != 0) {
574 canonicalise a message, merging elements of the same name
576 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
577 const struct ldb_message *msg)
580 struct ldb_message *msg2;
582 msg2 = ldb_msg_copy(ldb, msg);
583 if (msg2 == NULL) return NULL;
585 ldb_msg_sort_elements(msg2);
587 for (i=1;i<msg2->num_elements;i++) {
588 struct ldb_message_element *el1 = &msg2->elements[i-1];
589 struct ldb_message_element *el2 = &msg2->elements[i];
590 if (ldb_msg_element_compare_name(el1, el2) == 0) {
591 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
592 el1->num_values + el2->num_values);
593 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
596 memcpy(el1->values + el1->num_values,
598 sizeof(struct ldb_val) * el2->num_values);
599 el1->num_values += el2->num_values;
600 talloc_free(discard_const_p(char, el2->name));
601 if (i+1<msg2->num_elements) {
602 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
603 (msg2->num_elements - (i+1)));
605 msg2->num_elements--;
615 return a ldb_message representing the differences between msg1 and msg2. If you
616 then use this in a ldb_modify() call it can be used to save edits to a message
618 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
619 struct ldb_message *msg1,
620 struct ldb_message *msg2)
623 struct ldb_message *mod;
625 /* allocate mod message in NULL context
626 * so it should appear as 'leaked' in talloc reports */
627 ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2,
628 (TALLOC_CTX*)NULL, &mod);
629 if (ldb_ret != LDB_SUCCESS) {
637 * return a ldb_message representing the differences between msg1 and msg2.
638 * If you then use this in a ldb_modify() call it can be used to save edits to a message
640 * Result message is constructed as follows:
641 * - LDB_FLAG_MOD_ADD - elements found only in msg2
642 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
643 * Value for msg2 element is used
644 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
646 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
648 int ldb_msg_diff_ex(struct ldb_context *ldb,
649 struct ldb_message *msg1,
650 struct ldb_message *msg2,
652 struct ldb_message **_msg_out)
656 struct ldb_message *mod;
657 struct ldb_message_element *el;
658 TALLOC_CTX *temp_ctx;
660 temp_ctx = talloc_new(mem_ctx);
662 return LDB_ERR_OPERATIONS_ERROR;
665 mod = ldb_msg_new(temp_ctx);
671 mod->num_elements = 0;
672 mod->elements = NULL;
674 /* canonicalize msg2 so we have no
675 * repeated elements */
676 msg2 = ldb_msg_canonicalize(ldb, msg2);
681 /* steal msg2 into mod context as it is
682 * allocated in ldb's context */
683 talloc_steal(mod, msg2);
685 /* look in msg2 to find elements that need to be added
687 for (i=0;i<msg2->num_elements;i++) {
688 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
690 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
694 ldb_res = ldb_msg_add(mod,
696 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
697 if (ldb_res != LDB_SUCCESS) {
702 /* look in msg1 to find elements that need to be deleted */
703 for (i=0;i<msg1->num_elements;i++) {
704 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
706 ldb_res = ldb_msg_add_empty(mod,
707 msg1->elements[i].name,
708 LDB_FLAG_MOD_DELETE, NULL);
709 if (ldb_res != LDB_SUCCESS) {
715 /* steal resulting message into supplied context */
716 talloc_steal(mem_ctx, mod);
719 talloc_free(temp_ctx);
723 talloc_free(temp_ctx);
724 return LDB_ERR_OPERATIONS_ERROR;
728 int ldb_msg_sanity_check(struct ldb_context *ldb,
729 const struct ldb_message *msg)
733 /* basic check on DN */
734 if (msg->dn == NULL) {
735 /* TODO: return also an error string */
736 ldb_set_errstring(ldb, "ldb message lacks a DN!");
737 return LDB_ERR_INVALID_DN_SYNTAX;
740 /* basic syntax checks */
741 for (i = 0; i < msg->num_elements; i++) {
742 for (j = 0; j < msg->elements[i].num_values; j++) {
743 if (msg->elements[i].values[j].length == 0) {
744 TALLOC_CTX *mem_ctx = talloc_new(ldb);
745 /* an attribute cannot be empty */
746 /* TODO: return also an error string */
747 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
748 msg->elements[i].name,
749 ldb_dn_get_linearized(msg->dn));
750 talloc_free(mem_ctx);
751 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
763 copy an attribute list. This only copies the array, not the elements
764 (ie. the elements are left as the same pointers)
766 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
771 for (i=0;attrs && attrs[i];i++) /* noop */ ;
772 ret = talloc_array(mem_ctx, const char *, i+1);
776 for (i=0;attrs && attrs[i];i++) {
785 copy an attribute list. This only copies the array, not the elements
786 (ie. the elements are left as the same pointers). The new attribute is added to the list.
788 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
794 for (i=0;attrs && attrs[i];i++) {
795 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
800 return ldb_attr_list_copy(mem_ctx, attrs);
802 ret = talloc_array(mem_ctx, const char *, i+2);
806 for (i=0;attrs && attrs[i];i++) {
816 return 1 if an attribute is in a list of attributes, or 0 otherwise
818 int ldb_attr_in_list(const char * const *attrs, const char *attr)
821 for (i=0;attrs && attrs[i];i++) {
822 if (ldb_attr_cmp(attrs[i], attr) == 0) {
831 rename the specified attribute in a search result
833 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
835 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
839 el->name = talloc_strdup(msg->elements, replace);
840 if (el->name == NULL) {
841 return LDB_ERR_OPERATIONS_ERROR;
848 copy the specified attribute in a search result to a new attribute
850 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
852 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
856 if (ldb_msg_add(msg, el, 0) != 0) {
857 return LDB_ERR_OPERATIONS_ERROR;
859 return ldb_msg_rename_attr(msg, attr, replace);
863 remove the specified element in a search result
865 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
867 ptrdiff_t n = (el - msg->elements);
868 if (n >= msg->num_elements) {
869 /* should we abort() here? */
872 if (n != msg->num_elements-1) {
873 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
880 remove the specified attribute in a search result
882 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
884 struct ldb_message_element *el;
886 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
887 ldb_msg_remove_element(msg, el);
892 return a LDAP formatted GeneralizedTime string
894 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
896 struct tm *tm = gmtime(&t);
904 /* we now excatly how long this string will be */
905 ts = talloc_array(mem_ctx, char, 18);
907 /* formatted like: 20040408072012.0Z */
909 "%04u%02u%02u%02u%02u%02u.0Z",
910 tm->tm_year+1900, tm->tm_mon+1,
911 tm->tm_mday, tm->tm_hour, tm->tm_min,
923 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
925 time_t ldb_string_to_time(const char *s)
929 if (s == NULL) return 0;
931 memset(&tm, 0, sizeof(tm));
932 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
933 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
934 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
944 convert a LDAP GeneralizedTime string in ldb_val format to a
947 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
951 if (v == NULL || !v->data || v->length < 17) {
952 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
955 memset(&tm, 0, sizeof(tm));
957 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
958 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
959 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
960 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
971 return a LDAP formatted UTCTime string
973 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
975 struct tm *tm = gmtime(&t);
983 /* we now excatly how long this string will be */
984 ts = talloc_array(mem_ctx, char, 14);
986 /* formatted like: 20040408072012.0Z => 040408072012Z */
988 "%02u%02u%02u%02u%02u%02uZ",
989 (tm->tm_year+1900)%100, tm->tm_mon+1,
990 tm->tm_mday, tm->tm_hour, tm->tm_min,
1002 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1004 time_t ldb_string_utc_to_time(const char *s)
1008 if (s == NULL) return 0;
1010 memset(&tm, 0, sizeof(tm));
1011 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1012 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1013 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1016 if (tm.tm_year < 50) {
1026 dump a set of results to a file. Useful from within gdb
1028 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1032 for (i = 0; i < result->count; i++) {
1033 struct ldb_ldif ldif;
1034 fprintf(f, "# record %d\n", i+1);
1035 ldif.changetype = LDB_CHANGETYPE_NONE;
1036 ldif.msg = result->msgs[i];
1037 ldb_ldif_write_file(ldb, f, &ldif);
1042 checks for a string attribute. Returns "1" on match and otherwise "0".
1044 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1045 const char *name, const char *value)
1047 struct ldb_message_element *el;
1050 el = ldb_msg_find_element(msg, name);
1055 val.data = discard_const_p(uint8_t, value);
1056 val.length = strlen(value);
1058 if (ldb_msg_find_val(el, &val)) {