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 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 els = talloc_realloc(msg, msg->elements,
128 struct ldb_message_element, msg->num_elements+1);
131 return LDB_ERR_OPERATIONS_ERROR;
134 els[msg->num_elements].values = NULL;
135 els[msg->num_elements].num_values = 0;
136 els[msg->num_elements].flags = flags;
137 els[msg->num_elements].name = talloc_strdup(els, attr_name);
138 if (!els[msg->num_elements].name) {
140 return LDB_ERR_OPERATIONS_ERROR;
147 *return_el = &els[msg->num_elements-1];
154 add an empty element to a message
156 int ldb_msg_add(struct ldb_message *msg,
157 const struct ldb_message_element *el,
160 /* We have to copy this, just in case *el is a pointer into
161 * what ldb_msg_add_empty() is about to realloc() */
162 struct ldb_message_element el_copy = *el;
163 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
164 return LDB_ERR_OPERATIONS_ERROR;
167 msg->elements[msg->num_elements-1] = el_copy;
168 msg->elements[msg->num_elements-1].flags = flags;
174 add a value to a message
176 int ldb_msg_add_value(struct ldb_message *msg,
177 const char *attr_name,
178 const struct ldb_val *val,
179 struct ldb_message_element **return_el)
181 struct ldb_message_element *el;
182 struct ldb_val *vals;
185 el = ldb_msg_find_element(msg, attr_name);
187 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
188 if (ret != LDB_SUCCESS) {
193 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
196 return LDB_ERR_OPERATIONS_ERROR;
199 el->values[el->num_values] = *val;
211 add a value to a message, stealing it into the 'right' place
213 int ldb_msg_add_steal_value(struct ldb_message *msg,
214 const char *attr_name,
218 struct ldb_message_element *el;
220 ret = ldb_msg_add_value(msg, attr_name, val, &el);
221 if (ret == LDB_SUCCESS) {
222 talloc_steal(el->values, val->data);
229 add a string element to a message
231 int ldb_msg_add_string(struct ldb_message *msg,
232 const char *attr_name, const char *str)
236 val.data = discard_const_p(uint8_t, str);
237 val.length = strlen(str);
239 if (val.length == 0) {
240 /* allow empty strings as non-existant attributes */
244 return ldb_msg_add_value(msg, attr_name, &val, NULL);
248 add a string element to a message, stealing it into the 'right' place
250 int ldb_msg_add_steal_string(struct ldb_message *msg,
251 const char *attr_name, char *str)
255 val.data = (uint8_t *)str;
256 val.length = strlen(str);
258 return ldb_msg_add_steal_value(msg, attr_name, &val);
262 add a DN element to a message
263 WARNING: this uses the linearized string from the dn, and does not
266 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
269 return ldb_msg_add_steal_string(msg, attr_name,
270 ldb_dn_alloc_linearized(msg, dn));
274 add a printf formatted element to a message
276 int ldb_msg_add_fmt(struct ldb_message *msg,
277 const char *attr_name, const char *fmt, ...)
284 str = talloc_vasprintf(msg, fmt, ap);
287 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
289 val.data = (uint8_t *)str;
290 val.length = strlen(str);
292 return ldb_msg_add_steal_value(msg, attr_name, &val);
296 compare two ldb_message_element structures
297 assumes case senistive comparison
299 int ldb_msg_element_compare(struct ldb_message_element *el1,
300 struct ldb_message_element *el2)
304 if (el1->num_values != el2->num_values) {
305 return el1->num_values - el2->num_values;
308 for (i=0;i<el1->num_values;i++) {
309 if (!ldb_msg_find_val(el2, &el1->values[i])) {
318 compare two ldb_message_element structures
319 comparing by element name
321 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
322 struct ldb_message_element *el2)
324 return ldb_attr_cmp(el1->name, el2->name);
328 convenience functions to return common types from a message
329 these return the first value if the attribute is multi-valued
331 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
332 const char *attr_name)
334 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
335 if (!el || el->num_values == 0) {
338 return &el->values[0];
341 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
342 const char *attr_name,
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 strtol((const char *)v->data, NULL, 0);
352 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
353 const char *attr_name,
354 unsigned int 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 strtoul((const char *)v->data, NULL, 0);
363 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
364 const char *attr_name,
365 int64_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 strtoll((const char *)v->data, NULL, 0);
374 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
375 const char *attr_name,
376 uint64_t 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 strtoull((const char *)v->data, NULL, 0);
385 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
386 const char *attr_name,
387 double default_value)
389 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
390 if (!v || !v->data) {
391 return default_value;
393 return strtod((const char *)v->data, NULL);
396 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
397 const char *attr_name,
400 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
401 if (!v || !v->data) {
402 return default_value;
404 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
407 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
410 return default_value;
413 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
414 const char *attr_name,
415 const char *default_value)
417 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
418 if (!v || !v->data) {
419 return default_value;
421 return (const char *)v->data;
424 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
426 const struct ldb_message *msg,
427 const char *attr_name)
429 struct ldb_dn *res_dn;
430 const struct ldb_val *v;
432 v = ldb_msg_find_ldb_val(msg, attr_name);
433 if (!v || !v->data) {
436 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
437 if ( ! ldb_dn_validate(res_dn)) {
445 sort the elements of a message by name
447 void ldb_msg_sort_elements(struct ldb_message *msg)
449 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
450 (comparison_fn_t)ldb_msg_element_compare_name);
454 shallow copy a message - copying only the elements array so that the caller
455 can safely add new elements without changing the message
457 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
458 const struct ldb_message *msg)
460 struct ldb_message *msg2;
463 msg2 = talloc(mem_ctx, struct ldb_message);
464 if (msg2 == NULL) return NULL;
468 msg2->elements = talloc_array(msg2, struct ldb_message_element,
470 if (msg2->elements == NULL) goto failed;
472 for (i=0;i<msg2->num_elements;i++) {
473 msg2->elements[i] = msg->elements[i];
485 copy a message, allocating new memory for all parts
487 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
488 const struct ldb_message *msg)
490 struct ldb_message *msg2;
493 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
494 if (msg2 == NULL) return NULL;
496 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
497 if (msg2->dn == NULL) goto failed;
499 for (i=0;i<msg2->num_elements;i++) {
500 struct ldb_message_element *el = &msg2->elements[i];
501 struct ldb_val *values = el->values;
502 el->name = talloc_strdup(msg2->elements, el->name);
503 if (el->name == NULL) goto failed;
504 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
505 for (j=0;j<el->num_values;j++) {
506 el->values[j] = ldb_val_dup(el->values, &values[j]);
507 if (el->values[j].data == NULL && values[j].length != 0) {
522 canonicalise a message, merging elements of the same name
524 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
525 const struct ldb_message *msg)
528 struct ldb_message *msg2;
530 msg2 = ldb_msg_copy(ldb, msg);
531 if (msg2 == NULL) return NULL;
533 ldb_msg_sort_elements(msg2);
535 for (i=1;i<msg2->num_elements;i++) {
536 struct ldb_message_element *el1 = &msg2->elements[i-1];
537 struct ldb_message_element *el2 = &msg2->elements[i];
538 if (ldb_msg_element_compare_name(el1, el2) == 0) {
539 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
540 el1->num_values + el2->num_values);
541 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
544 memcpy(el1->values + el1->num_values,
546 sizeof(struct ldb_val) * el2->num_values);
547 el1->num_values += el2->num_values;
548 talloc_free(discard_const_p(char, el2->name));
549 if (i+1<msg2->num_elements) {
550 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
551 (msg2->num_elements - (i+1)));
553 msg2->num_elements--;
563 return a ldb_message representing the differences between msg1 and msg2. If you
564 then use this in a ldb_modify() call it can be used to save edits to a message
566 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
567 struct ldb_message *msg1,
568 struct ldb_message *msg2)
570 struct ldb_message *mod;
571 struct ldb_message_element *el;
574 mod = ldb_msg_new(ldb);
580 mod->num_elements = 0;
581 mod->elements = NULL;
583 msg2 = ldb_msg_canonicalize(ldb, msg2);
589 /* look in msg2 to find elements that need to be added
591 for (i=0;i<msg2->num_elements;i++) {
592 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
594 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
600 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
606 /* look in msg1 to find elements that need to be deleted */
607 for (i=0;i<msg1->num_elements;i++) {
608 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
610 if (ldb_msg_add_empty(mod,
611 msg1->elements[i].name,
612 LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
622 int ldb_msg_sanity_check(struct ldb_context *ldb,
623 const struct ldb_message *msg)
627 /* basic check on DN */
628 if (msg->dn == NULL) {
629 /* TODO: return also an error string */
630 ldb_set_errstring(ldb, "ldb message lacks a DN!");
631 return LDB_ERR_INVALID_DN_SYNTAX;
634 /* basic syntax checks */
635 for (i = 0; i < msg->num_elements; i++) {
636 for (j = 0; j < msg->elements[i].num_values; j++) {
637 if (msg->elements[i].values[j].length == 0) {
638 TALLOC_CTX *mem_ctx = talloc_new(ldb);
639 /* an attribute cannot be empty */
640 /* TODO: return also an error string */
641 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
642 msg->elements[i].name,
643 ldb_dn_get_linearized(msg->dn));
644 talloc_free(mem_ctx);
645 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
657 copy an attribute list. This only copies the array, not the elements
658 (ie. the elements are left as the same pointers)
660 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
664 for (i=0;attrs && attrs[i];i++) /* noop */ ;
665 ret = talloc_array(mem_ctx, const char *, i+1);
669 for (i=0;attrs && attrs[i];i++) {
678 copy an attribute list. This only copies the array, not the elements
679 (ie. the elements are left as the same pointers). The new attribute is added to the list.
681 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
686 for (i=0;attrs && attrs[i];i++) {
687 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
692 return ldb_attr_list_copy(mem_ctx, attrs);
694 ret = talloc_array(mem_ctx, const char *, i+2);
698 for (i=0;attrs && attrs[i];i++) {
708 return 1 if an attribute is in a list of attributes, or 0 otherwise
710 int ldb_attr_in_list(const char * const *attrs, const char *attr)
713 for (i=0;attrs && attrs[i];i++) {
714 if (ldb_attr_cmp(attrs[i], attr) == 0) {
723 rename the specified attribute in a search result
725 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
727 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
731 el->name = talloc_strdup(msg->elements, replace);
732 if (el->name == NULL) {
733 return LDB_ERR_OPERATIONS_ERROR;
740 copy the specified attribute in a search result to a new attribute
742 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
744 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
748 if (ldb_msg_add(msg, el, 0) != 0) {
749 return LDB_ERR_OPERATIONS_ERROR;
751 return ldb_msg_rename_attr(msg, attr, replace);
755 remove the specified element in a search result
757 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
759 int n = (el - msg->elements);
760 if (n >= msg->num_elements) {
761 /* should we abort() here? */
764 if (n != msg->num_elements-1) {
765 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
772 remove the specified attribute in a search result
774 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
776 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
778 ldb_msg_remove_element(msg, el);
783 return a LDAP formatted GeneralizedTime string
785 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
787 struct tm *tm = gmtime(&t);
795 /* we now excatly how long this string will be */
796 ts = talloc_array(mem_ctx, char, 18);
798 /* formatted like: 20040408072012.0Z */
800 "%04u%02u%02u%02u%02u%02u.0Z",
801 tm->tm_year+1900, tm->tm_mon+1,
802 tm->tm_mday, tm->tm_hour, tm->tm_min,
814 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
816 time_t ldb_string_to_time(const char *s)
820 if (s == NULL) return 0;
822 memset(&tm, 0, sizeof(tm));
823 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
824 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
825 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
835 convert a LDAP GeneralizedTime string in ldb_val format to a
838 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
842 if (v == NULL || !v->data || v->length < 14) {
843 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
846 memset(&tm, 0, sizeof(tm));
848 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u",
849 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
850 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
851 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
862 return a LDAP formatted UTCTime string
864 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
866 struct tm *tm = gmtime(&t);
874 /* we now excatly how long this string will be */
875 ts = talloc_array(mem_ctx, char, 14);
877 /* formatted like: 20040408072012.0Z => 040408072012Z */
879 "%02u%02u%02u%02u%02u%02uZ",
880 (tm->tm_year+1900)%100, tm->tm_mon+1,
881 tm->tm_mday, tm->tm_hour, tm->tm_min,
893 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
895 time_t ldb_string_utc_to_time(const char *s)
899 if (s == NULL) return 0;
901 memset(&tm, 0, sizeof(tm));
902 if (sscanf(s, "%02u%02u%02u%02u%02u%02u",
903 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
904 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
907 if (tm.tm_year < 50) {
917 dump a set of results to a file. Useful from within gdb
919 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
923 for (i = 0; i < result->count; i++) {
924 struct ldb_ldif ldif;
925 fprintf(f, "# record %d\n", i+1);
926 ldif.changetype = LDB_CHANGETYPE_NONE;
927 ldif.msg = result->msgs[i];
928 ldb_ldif_write_file(ldb, f, &ldif);
933 checks for a string attribute. Returns "1" on match and otherwise "0".
935 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
936 const char *name, const char *value)
938 struct ldb_message_element *el;
941 el = ldb_msg_find_element(msg, name);
946 val.data = discard_const_p(uint8_t, value);
947 val.length = strlen(value);
949 if (ldb_msg_find_val(el, &val)) {