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_includes.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;
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 add an empty element to a message
120 int ldb_msg_add_empty( struct ldb_message *msg,
121 const char *attr_name,
123 struct ldb_message_element **return_el)
125 struct ldb_message_element *els;
127 /* FIXME: we should probably leave this to the schema module to check */
128 if (! ldb_valid_attr_name(attr_name)) {
129 return LDB_ERR_OPERATIONS_ERROR;
132 els = talloc_realloc(msg, msg->elements,
133 struct ldb_message_element, msg->num_elements+1);
136 return LDB_ERR_OPERATIONS_ERROR;
139 els[msg->num_elements].values = NULL;
140 els[msg->num_elements].num_values = 0;
141 els[msg->num_elements].flags = flags;
142 els[msg->num_elements].name = talloc_strdup(els, attr_name);
143 if (!els[msg->num_elements].name) {
145 return LDB_ERR_OPERATIONS_ERROR;
152 *return_el = &els[msg->num_elements-1];
159 add an empty element to a message
161 int ldb_msg_add(struct ldb_message *msg,
162 const struct ldb_message_element *el,
165 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
166 return LDB_ERR_OPERATIONS_ERROR;
169 msg->elements[msg->num_elements-1] = *el;
170 msg->elements[msg->num_elements-1].flags = flags;
176 add a value to a message
178 int ldb_msg_add_value(struct ldb_message *msg,
179 const char *attr_name,
180 const struct ldb_val *val,
181 struct ldb_message_element **return_el)
183 struct ldb_message_element *el;
184 struct ldb_val *vals;
187 el = ldb_msg_find_element(msg, attr_name);
189 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
190 if (ret != LDB_SUCCESS) {
195 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
198 return LDB_ERR_OPERATIONS_ERROR;
201 el->values[el->num_values] = *val;
213 add a value to a message, stealing it into the 'right' place
215 int ldb_msg_add_steal_value(struct ldb_message *msg,
216 const char *attr_name,
220 struct ldb_message_element *el;
222 ret = ldb_msg_add_value(msg, attr_name, val, &el);
223 if (ret == LDB_SUCCESS) {
224 talloc_steal(el->values, val->data);
231 add a string element to a message
233 int ldb_msg_add_string(struct ldb_message *msg,
234 const char *attr_name, const char *str)
238 val.data = discard_const_p(uint8_t, str);
239 val.length = strlen(str);
241 if (val.length == 0) {
242 /* allow empty strings as non-existant attributes */
246 return ldb_msg_add_value(msg, attr_name, &val, NULL);
250 add a string element to a message, stealing it into the 'right' place
252 int ldb_msg_add_steal_string(struct ldb_message *msg,
253 const char *attr_name, char *str)
257 val.data = (uint8_t *)str;
258 val.length = strlen(str);
260 return ldb_msg_add_steal_value(msg, attr_name, &val);
264 add a printf formatted element to a message
266 int ldb_msg_add_fmt(struct ldb_message *msg,
267 const char *attr_name, const char *fmt, ...)
274 str = talloc_vasprintf(msg, fmt, ap);
277 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
279 val.data = (uint8_t *)str;
280 val.length = strlen(str);
282 return ldb_msg_add_steal_value(msg, attr_name, &val);
286 compare two ldb_message_element structures
287 assumes case senistive comparison
289 int ldb_msg_element_compare(struct ldb_message_element *el1,
290 struct ldb_message_element *el2)
294 if (el1->num_values != el2->num_values) {
295 return el1->num_values - el2->num_values;
298 for (i=0;i<el1->num_values;i++) {
299 if (!ldb_msg_find_val(el2, &el1->values[i])) {
308 compare two ldb_message_element structures
309 comparing by element name
311 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
312 struct ldb_message_element *el2)
314 return ldb_attr_cmp(el1->name, el2->name);
318 convenience functions to return common types from a message
319 these return the first value if the attribute is multi-valued
321 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
323 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
324 if (!el || el->num_values == 0) {
327 return &el->values[0];
330 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
331 const char *attr_name,
334 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
335 if (!v || !v->data) {
336 return default_value;
338 return strtol((const char *)v->data, NULL, 0);
341 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
342 const char *attr_name,
343 unsigned int default_value)
345 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
346 if (!v || !v->data) {
347 return default_value;
349 return strtoul((const char *)v->data, NULL, 0);
352 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
353 const char *attr_name,
354 int64_t default_value)
356 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
357 if (!v || !v->data) {
358 return default_value;
360 return strtoll((const char *)v->data, NULL, 0);
363 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
364 const char *attr_name,
365 uint64_t default_value)
367 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
368 if (!v || !v->data) {
369 return default_value;
371 return strtoull((const char *)v->data, NULL, 0);
374 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
375 const char *attr_name,
376 double default_value)
378 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
379 if (!v || !v->data) {
380 return default_value;
382 return strtod((const char *)v->data, NULL);
385 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
386 const char *attr_name,
389 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
390 if (!v || !v->data) {
391 return default_value;
393 if (strcasecmp((const char *)v->data, "FALSE") == 0) {
396 if (strcasecmp((const char *)v->data, "TRUE") == 0) {
399 return default_value;
402 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
403 const char *attr_name,
404 const char *default_value)
406 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
407 if (!v || !v->data) {
408 return default_value;
410 return (const char *)v->data;
413 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
415 const struct ldb_message *msg,
416 const char *attr_name)
418 struct ldb_dn *res_dn;
419 const struct ldb_val *v;
421 v = ldb_msg_find_ldb_val(msg, attr_name);
422 if (!v || !v->data) {
425 res_dn = ldb_dn_new(mem_ctx, ldb, (const char *)v->data);
426 if ( ! ldb_dn_validate(res_dn)) {
434 sort the elements of a message by name
436 void ldb_msg_sort_elements(struct ldb_message *msg)
438 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
439 (comparison_fn_t)ldb_msg_element_compare_name);
443 shallow copy a message - copying only the elements array so that the caller
444 can safely add new elements without changing the message
446 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
447 const struct ldb_message *msg)
449 struct ldb_message *msg2;
452 msg2 = talloc(mem_ctx, struct ldb_message);
453 if (msg2 == NULL) return NULL;
457 msg2->elements = talloc_array(msg2, struct ldb_message_element,
459 if (msg2->elements == NULL) goto failed;
461 for (i=0;i<msg2->num_elements;i++) {
462 msg2->elements[i] = msg->elements[i];
474 copy a message, allocating new memory for all parts
476 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
477 const struct ldb_message *msg)
479 struct ldb_message *msg2;
482 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
483 if (msg2 == NULL) return NULL;
485 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
486 if (msg2->dn == NULL) goto failed;
488 for (i=0;i<msg2->num_elements;i++) {
489 struct ldb_message_element *el = &msg2->elements[i];
490 struct ldb_val *values = el->values;
491 el->name = talloc_strdup(msg2->elements, el->name);
492 if (el->name == NULL) goto failed;
493 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
494 for (j=0;j<el->num_values;j++) {
495 el->values[j] = ldb_val_dup(el->values, &values[j]);
496 if (el->values[j].data == NULL && values[j].length != 0) {
511 canonicalise a message, merging elements of the same name
513 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
514 const struct ldb_message *msg)
517 struct ldb_message *msg2;
519 msg2 = ldb_msg_copy(ldb, msg);
520 if (msg2 == NULL) return NULL;
522 ldb_msg_sort_elements(msg2);
524 for (i=1;i<msg2->num_elements;i++) {
525 struct ldb_message_element *el1 = &msg2->elements[i-1];
526 struct ldb_message_element *el2 = &msg2->elements[i];
527 if (ldb_msg_element_compare_name(el1, el2) == 0) {
528 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
529 el1->num_values + el2->num_values);
530 if (el1->values == NULL) {
533 memcpy(el1->values + el1->num_values,
535 sizeof(struct ldb_val) * el2->num_values);
536 el1->num_values += el2->num_values;
537 talloc_free(discard_const_p(char, el2->name));
538 if (i+1<msg2->num_elements) {
539 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
540 (msg2->num_elements - (i+1)));
542 msg2->num_elements--;
552 return a ldb_message representing the differences between msg1 and msg2. If you
553 then use this in a ldb_modify() call it can be used to save edits to a message
555 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
556 struct ldb_message *msg1,
557 struct ldb_message *msg2)
559 struct ldb_message *mod;
560 struct ldb_message_element *el;
563 mod = ldb_msg_new(ldb);
566 mod->num_elements = 0;
567 mod->elements = NULL;
569 msg2 = ldb_msg_canonicalize(ldb, msg2);
574 /* look in msg2 to find elements that need to be added
576 for (i=0;i<msg2->num_elements;i++) {
577 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
579 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
585 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
590 /* look in msg1 to find elements that need to be deleted */
591 for (i=0;i<msg1->num_elements;i++) {
592 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
594 if (ldb_msg_add_empty(mod,
595 msg1->elements[i].name,
596 LDB_FLAG_MOD_DELETE, NULL) != 0) {
605 int ldb_msg_sanity_check(struct ldb_context *ldb,
606 const struct ldb_message *msg)
610 /* basic check on DN */
611 if (msg->dn == NULL) {
612 /* TODO: return also an error string */
613 ldb_set_errstring(ldb, "ldb message lacks a DN!");
614 return LDB_ERR_INVALID_DN_SYNTAX;
617 /* basic syntax checks */
618 for (i = 0; i < msg->num_elements; i++) {
619 for (j = 0; j < msg->elements[i].num_values; j++) {
620 if (msg->elements[i].values[j].length == 0) {
621 TALLOC_CTX *mem_ctx = talloc_new(ldb);
622 /* an attribute cannot be empty */
623 /* TODO: return also an error string */
624 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
625 msg->elements[i].name,
626 ldb_dn_get_linearized(msg->dn));
627 talloc_free(mem_ctx);
628 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
640 copy an attribute list. This only copies the array, not the elements
641 (ie. the elements are left as the same pointers)
643 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
647 for (i=0;attrs[i];i++) /* noop */ ;
648 ret = talloc_array(mem_ctx, const char *, i+1);
652 for (i=0;attrs[i];i++) {
661 copy an attribute list. This only copies the array, not the elements
662 (ie. the elements are left as the same pointers). The new attribute is added to the list.
664 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
669 for (i=0;attrs[i];i++) {
670 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
675 return ldb_attr_list_copy(mem_ctx, attrs);
677 ret = talloc_array(mem_ctx, const char *, i+2);
681 for (i=0;attrs[i];i++) {
691 return 1 if an attribute is in a list of attributes, or 0 otherwise
693 int ldb_attr_in_list(const char * const *attrs, const char *attr)
696 for (i=0;attrs && attrs[i];i++) {
697 if (ldb_attr_cmp(attrs[i], attr) == 0) {
706 rename the specified attribute in a search result
708 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
710 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
714 el->name = talloc_strdup(msg->elements, replace);
715 if (el->name == NULL) {
716 return LDB_ERR_OPERATIONS_ERROR;
723 copy the specified attribute in a search result to a new attribute
725 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
727 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
731 if (ldb_msg_add(msg, el, 0) != 0) {
732 return LDB_ERR_OPERATIONS_ERROR;
734 return ldb_msg_rename_attr(msg, attr, replace);
738 remove the specified element in a search result
740 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
742 int n = (el - msg->elements);
743 if (n != msg->num_elements-1) {
744 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
751 remove the specified attribute in a search result
753 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
755 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
757 ldb_msg_remove_element(msg, el);
762 return a LDAP formatted GeneralizedTime string
764 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
766 struct tm *tm = gmtime(&t);
774 /* we now excatly how long this string will be */
775 ts = talloc_array(mem_ctx, char, 18);
777 /* formatted like: 20040408072012.0Z */
779 "%04u%02u%02u%02u%02u%02u.0Z",
780 tm->tm_year+1900, tm->tm_mon+1,
781 tm->tm_mday, tm->tm_hour, tm->tm_min,
793 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
795 time_t ldb_string_to_time(const char *s)
799 if (s == NULL) return 0;
801 memset(&tm, 0, sizeof(tm));
802 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
803 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
804 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
814 return a LDAP formatted UTCTime string
816 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
818 struct tm *tm = gmtime(&t);
826 /* we now excatly how long this string will be */
827 ts = talloc_array(mem_ctx, char, 14);
829 /* formatted like: 20040408072012.0Z => 040408072012Z */
831 "%02u%02u%02u%02u%02u%02uZ",
832 (tm->tm_year+1900)%100, tm->tm_mon+1,
833 tm->tm_mday, tm->tm_hour, tm->tm_min,
845 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
847 time_t ldb_string_utc_to_time(const char *s)
851 if (s == NULL) return 0;
853 memset(&tm, 0, sizeof(tm));
854 if (sscanf(s, "%02u%02u%02u%02u%02u%02u",
855 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
856 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
859 if (tm.tm_year < 50) {
869 dump a set of results to a file. Useful from within gdb
871 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
875 for (i = 0; i < result->count; i++) {
876 struct ldb_ldif ldif;
877 fprintf(f, "# record %d\n", i+1);
878 ldif.changetype = LDB_CHANGETYPE_NONE;
879 ldif.msg = result->msgs[i];
880 ldb_ldif_write_file(ldb, f, &ldif);
884 int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
886 struct ldb_message_element *el;
889 el = ldb_msg_find_element(msg, name);
893 val.data = discard_const_p(uint8_t, value);
894 val.length = strlen(value);
896 if (ldb_msg_find_val(el, &val))