r23798: updated old Temple Place FSF addresses to new URL
[Samba.git] / source / lib / ldb / common / ldb_msg.c
bloba8a6e93f12635b1832dc0341f3c1427fd17ddc1e
1 /*
2 ldb database library
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
8 ** under the LGPL
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/>.
25 * Name: ldb
27 * Component: ldb message component utility functions
29 * Description: functions for manipulating ldb_message structures
31 * Author: Andrew Tridgell
34 #include "includes.h"
35 #include "ldb/include/includes.h"
37 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f);
38 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
39 struct ldb_message_element *el2);
42 create a new ldb_message in a given memory context (NULL for top level)
44 struct ldb_message *ldb_msg_new(void *mem_ctx)
46 return talloc_zero(mem_ctx, struct ldb_message);
50 find an element in a message by attribute name
52 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
53 const char *attr_name)
55 unsigned int i;
56 for (i=0;i<msg->num_elements;i++) {
57 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
58 return &msg->elements[i];
61 return NULL;
65 see if two ldb_val structures contain exactly the same data
66 return 1 for a match, 0 for a mis-match
68 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
70 if (v1->length != v2->length) return 0;
72 if (v1->length == 0) return 1;
74 if (memcmp(v1->data, v2->data, v1->length) == 0) {
75 return 1;
78 return 0;
82 find a value in an element
83 assumes case sensitive comparison
85 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
86 struct ldb_val *val)
88 unsigned int i;
89 for (i=0;i<el->num_values;i++) {
90 if (ldb_val_equal_exact(val, &el->values[i])) {
91 return &el->values[i];
94 return NULL;
98 duplicate a ldb_val structure
100 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
102 struct ldb_val v2;
103 v2.length = v->length;
104 if (v->data == NULL) {
105 v2.data = NULL;
106 return v2;
109 /* the +1 is to cope with buggy C library routines like strndup
110 that look one byte beyond */
111 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
112 if (!v2.data) {
113 v2.length = 0;
114 return v2;
117 memcpy(v2.data, v->data, v->length);
118 ((char *)v2.data)[v->length] = 0;
119 return v2;
123 add an empty element to a message
125 int ldb_msg_add_empty( struct ldb_message *msg,
126 const char *attr_name,
127 int flags,
128 struct ldb_message_element **return_el)
130 struct ldb_message_element *els;
132 if (! ldb_valid_attr_name(attr_name)) {
133 return LDB_ERR_OPERATIONS_ERROR;
136 els = talloc_realloc(msg, msg->elements,
137 struct ldb_message_element, msg->num_elements+1);
138 if (!els) {
139 errno = ENOMEM;
140 return LDB_ERR_OPERATIONS_ERROR;
143 els[msg->num_elements].values = NULL;
144 els[msg->num_elements].num_values = 0;
145 els[msg->num_elements].flags = flags;
146 els[msg->num_elements].name = talloc_strdup(els, attr_name);
147 if (!els[msg->num_elements].name) {
148 errno = ENOMEM;
149 return LDB_ERR_OPERATIONS_ERROR;
152 msg->elements = els;
153 msg->num_elements++;
155 if (return_el) {
156 *return_el = &els[msg->num_elements-1];
159 return LDB_SUCCESS;
163 add an empty element to a message
165 int ldb_msg_add(struct ldb_message *msg,
166 const struct ldb_message_element *el,
167 int flags)
169 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
170 return LDB_ERR_OPERATIONS_ERROR;
173 msg->elements[msg->num_elements-1] = *el;
174 msg->elements[msg->num_elements-1].flags = flags;
176 return LDB_SUCCESS;
180 add a value to a message
182 int ldb_msg_add_value(struct ldb_message *msg,
183 const char *attr_name,
184 const struct ldb_val *val,
185 struct ldb_message_element **return_el)
187 struct ldb_message_element *el;
188 struct ldb_val *vals;
189 int ret;
191 el = ldb_msg_find_element(msg, attr_name);
192 if (!el) {
193 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
194 if (ret != LDB_SUCCESS) {
195 return ret;
199 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
200 if (!vals) {
201 errno = ENOMEM;
202 return LDB_ERR_OPERATIONS_ERROR;
204 el->values = vals;
205 el->values[el->num_values] = *val;
206 el->num_values++;
208 if (return_el) {
209 *return_el = el;
212 return LDB_SUCCESS;
217 add a value to a message, stealing it into the 'right' place
219 int ldb_msg_add_steal_value(struct ldb_message *msg,
220 const char *attr_name,
221 struct ldb_val *val)
223 int ret;
224 struct ldb_message_element *el;
226 ret = ldb_msg_add_value(msg, attr_name, val, &el);
227 if (ret == LDB_SUCCESS) {
228 talloc_steal(el->values, val->data);
230 return ret;
235 add a string element to a message
237 int ldb_msg_add_string(struct ldb_message *msg,
238 const char *attr_name, const char *str)
240 struct ldb_val val;
242 val.data = discard_const_p(uint8_t, str);
243 val.length = strlen(str);
245 if (val.length == 0) {
246 /* allow empty strings as non-existant attributes */
247 return LDB_SUCCESS;
250 return ldb_msg_add_value(msg, attr_name, &val, NULL);
254 add a string element to a message, stealing it into the 'right' place
256 int ldb_msg_add_steal_string(struct ldb_message *msg,
257 const char *attr_name, char *str)
259 struct ldb_val val;
261 val.data = (uint8_t *)str;
262 val.length = strlen(str);
264 return ldb_msg_add_steal_value(msg, attr_name, &val);
268 add a printf formatted element to a message
270 int ldb_msg_add_fmt(struct ldb_message *msg,
271 const char *attr_name, const char *fmt, ...)
273 struct ldb_val val;
274 va_list ap;
275 char *str;
277 va_start(ap, fmt);
278 str = talloc_vasprintf(msg, fmt, ap);
279 va_end(ap);
281 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
283 val.data = (uint8_t *)str;
284 val.length = strlen(str);
286 return ldb_msg_add_steal_value(msg, attr_name, &val);
290 compare two ldb_message_element structures
291 assumes case senistive comparison
293 int ldb_msg_element_compare(struct ldb_message_element *el1,
294 struct ldb_message_element *el2)
296 unsigned int i;
298 if (el1->num_values != el2->num_values) {
299 return el1->num_values - el2->num_values;
302 for (i=0;i<el1->num_values;i++) {
303 if (!ldb_msg_find_val(el2, &el1->values[i])) {
304 return -1;
308 return 0;
312 compare two ldb_message_element structures
313 comparing by element name
315 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
316 struct ldb_message_element *el2)
318 return ldb_attr_cmp(el1->name, el2->name);
322 convenience functions to return common types from a message
323 these return the first value if the attribute is multi-valued
325 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
327 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
328 if (!el || el->num_values == 0) {
329 return NULL;
331 return &el->values[0];
334 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
335 const char *attr_name,
336 int default_value)
338 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
339 if (!v || !v->data) {
340 return default_value;
342 return strtol((const char *)v->data, NULL, 0);
345 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
346 const char *attr_name,
347 unsigned int default_value)
349 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
350 if (!v || !v->data) {
351 return default_value;
353 return strtoul((const char *)v->data, NULL, 0);
356 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
357 const char *attr_name,
358 int64_t default_value)
360 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
361 if (!v || !v->data) {
362 return default_value;
364 return strtoll((const char *)v->data, NULL, 0);
367 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
368 const char *attr_name,
369 uint64_t default_value)
371 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
372 if (!v || !v->data) {
373 return default_value;
375 return strtoull((const char *)v->data, NULL, 0);
378 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
379 const char *attr_name,
380 double default_value)
382 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
383 if (!v || !v->data) {
384 return default_value;
386 return strtod((const char *)v->data, NULL);
389 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
390 const char *attr_name,
391 int default_value)
393 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
394 if (!v || !v->data) {
395 return default_value;
397 if (strcasecmp((const char *)v->data, "FALSE") == 0) {
398 return 0;
400 if (strcasecmp((const char *)v->data, "TRUE") == 0) {
401 return 1;
403 return default_value;
406 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
407 const char *attr_name,
408 const char *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 (const char *)v->data;
417 struct ldb_dn *ldb_msg_find_attr_as_dn(void *mem_ctx,
418 const struct ldb_message *msg,
419 const char *attr_name)
421 const struct ldb_val *v;
423 v = ldb_msg_find_ldb_val(msg, attr_name);
424 if (!v || !v->data) {
425 return NULL;
427 return ldb_dn_explode(mem_ctx, (const char *)v->data);
431 sort the elements of a message by name
433 void ldb_msg_sort_elements(struct ldb_message *msg)
435 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
436 (comparison_fn_t)ldb_msg_element_compare_name);
440 shallow copy a message - copying only the elements array so that the caller
441 can safely add new elements without changing the message
443 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
444 const struct ldb_message *msg)
446 struct ldb_message *msg2;
447 int i;
449 msg2 = talloc(mem_ctx, struct ldb_message);
450 if (msg2 == NULL) return NULL;
452 *msg2 = *msg;
453 msg2->private_data = NULL;
455 msg2->elements = talloc_array(msg2, struct ldb_message_element,
456 msg2->num_elements);
457 if (msg2->elements == NULL) goto failed;
459 for (i=0;i<msg2->num_elements;i++) {
460 msg2->elements[i] = msg->elements[i];
463 return msg2;
465 failed:
466 talloc_free(msg2);
467 return NULL;
472 copy a message, allocating new memory for all parts
474 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
475 const struct ldb_message *msg)
477 struct ldb_message *msg2;
478 int i, j;
480 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
481 if (msg2 == NULL) return NULL;
483 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
484 if (msg2->dn == NULL) goto failed;
486 for (i=0;i<msg2->num_elements;i++) {
487 struct ldb_message_element *el = &msg2->elements[i];
488 struct ldb_val *values = el->values;
489 el->name = talloc_strdup(msg2->elements, el->name);
490 if (el->name == NULL) goto failed;
491 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
492 for (j=0;j<el->num_values;j++) {
493 el->values[j] = ldb_val_dup(el->values, &values[j]);
494 if (el->values[j].data == NULL && values[j].length != 0) {
495 goto failed;
500 return msg2;
502 failed:
503 talloc_free(msg2);
504 return NULL;
509 canonicalise a message, merging elements of the same name
511 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
512 const struct ldb_message *msg)
514 int i;
515 struct ldb_message *msg2;
517 msg2 = ldb_msg_copy(ldb, msg);
518 if (msg2 == NULL) return NULL;
520 ldb_msg_sort_elements(msg2);
522 for (i=1;i<msg2->num_elements;i++) {
523 struct ldb_message_element *el1 = &msg2->elements[i-1];
524 struct ldb_message_element *el2 = &msg2->elements[i];
525 if (ldb_msg_element_compare_name(el1, el2) == 0) {
526 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
527 el1->num_values + el2->num_values);
528 if (el1->values == NULL) {
529 return NULL;
531 memcpy(el1->values + el1->num_values,
532 el2->values,
533 sizeof(struct ldb_val) * el2->num_values);
534 el1->num_values += el2->num_values;
535 talloc_free(discard_const_p(char, el2->name));
536 if (i+1<msg2->num_elements) {
537 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
538 (msg2->num_elements - (i+1)));
540 msg2->num_elements--;
541 i--;
545 return msg2;
550 return a ldb_message representing the differences between msg1 and msg2. If you
551 then use this in a ldb_modify() call it can be used to save edits to a message
553 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
554 struct ldb_message *msg1,
555 struct ldb_message *msg2)
557 struct ldb_message *mod;
558 struct ldb_message_element *el;
559 unsigned int i;
561 mod = ldb_msg_new(ldb);
563 mod->dn = msg1->dn;
564 mod->num_elements = 0;
565 mod->elements = NULL;
567 msg2 = ldb_msg_canonicalize(ldb, msg2);
568 if (msg2 == NULL) {
569 return NULL;
572 /* look in msg2 to find elements that need to be added
573 or modified */
574 for (i=0;i<msg2->num_elements;i++) {
575 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
577 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
578 continue;
581 if (ldb_msg_add(mod,
582 &msg2->elements[i],
583 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
584 return NULL;
588 /* look in msg1 to find elements that need to be deleted */
589 for (i=0;i<msg1->num_elements;i++) {
590 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
591 if (!el) {
592 if (ldb_msg_add_empty(mod,
593 msg1->elements[i].name,
594 LDB_FLAG_MOD_DELETE, NULL) != 0) {
595 return NULL;
600 return mod;
603 int ldb_msg_sanity_check(struct ldb_context *ldb,
604 const struct ldb_message *msg)
606 int i, j;
608 /* basic check on DN */
609 if (msg->dn == NULL) {
610 /* TODO: return also an error string */
611 ldb_set_errstring(ldb, "ldb message lacks a DN!");
612 return LDB_ERR_INVALID_DN_SYNTAX;
615 /* basic syntax checks */
616 for (i = 0; i < msg->num_elements; i++) {
617 for (j = 0; j < msg->elements[i].num_values; j++) {
618 if (msg->elements[i].values[j].length == 0) {
619 TALLOC_CTX *mem_ctx = talloc_new(ldb);
620 /* an attribute cannot be empty */
621 /* TODO: return also an error string */
622 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
623 msg->elements[i].name,
624 ldb_dn_linearize(mem_ctx, msg->dn));
625 talloc_free(mem_ctx);
626 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
631 return LDB_SUCCESS;
638 copy an attribute list. This only copies the array, not the elements
639 (ie. the elements are left as the same pointers)
641 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
643 const char **ret;
644 int i;
645 for (i=0;attrs[i];i++) /* noop */ ;
646 ret = talloc_array(mem_ctx, const char *, i+1);
647 if (ret == NULL) {
648 return NULL;
650 for (i=0;attrs[i];i++) {
651 ret[i] = attrs[i];
653 ret[i] = attrs[i];
654 return ret;
659 copy an attribute list. This only copies the array, not the elements
660 (ie. the elements are left as the same pointers). The new attribute is added to the list.
662 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
664 const char **ret;
665 int i;
666 for (i=0;attrs[i];i++) /* noop */ ;
667 ret = talloc_array(mem_ctx, const char *, i+2);
668 if (ret == NULL) {
669 return NULL;
671 for (i=0;attrs[i];i++) {
672 ret[i] = attrs[i];
674 ret[i] = new_attr;
675 ret[i+1] = NULL;
676 return ret;
681 return 1 if an attribute is in a list of attributes, or 0 otherwise
683 int ldb_attr_in_list(const char * const *attrs, const char *attr)
685 int i;
686 for (i=0;attrs[i];i++) {
687 if (ldb_attr_cmp(attrs[i], attr) == 0) {
688 return 1;
691 return 0;
696 rename the specified attribute in a search result
698 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
700 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
701 if (el == NULL) {
702 return LDB_SUCCESS;
704 el->name = talloc_strdup(msg->elements, replace);
705 if (el->name == NULL) {
706 return LDB_ERR_OPERATIONS_ERROR;
708 return LDB_SUCCESS;
713 copy the specified attribute in a search result to a new attribute
715 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
717 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
718 if (el == NULL) {
719 return LDB_SUCCESS;
721 if (ldb_msg_add(msg, el, 0) != 0) {
722 return LDB_ERR_OPERATIONS_ERROR;
724 return ldb_msg_rename_attr(msg, attr, replace);
729 remove the specified attribute in a search result
731 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
733 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
734 if (el) {
735 int n = (el - msg->elements);
736 if (n != msg->num_elements-1) {
737 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
739 msg->num_elements--;
744 remove the specified element in a search result
746 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
748 int n = (el - msg->elements);
749 if (n != msg->num_elements-1) {
750 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
752 msg->num_elements--;
756 return a LDAP formatted time string
758 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
760 struct tm *tm = gmtime(&t);
762 if (!tm) {
763 return NULL;
766 /* formatted like: 20040408072012.0Z */
767 return talloc_asprintf(mem_ctx,
768 "%04u%02u%02u%02u%02u%02u.0Z",
769 tm->tm_year+1900, tm->tm_mon+1,
770 tm->tm_mday, tm->tm_hour, tm->tm_min,
771 tm->tm_sec);
776 convert a LDAP time string to a time_t. Return 0 if unable to convert
778 time_t ldb_string_to_time(const char *s)
780 struct tm tm;
782 if (s == NULL) return 0;
784 memset(&tm, 0, sizeof(tm));
785 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
786 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
787 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
788 return 0;
790 tm.tm_year -= 1900;
791 tm.tm_mon -= 1;
793 return timegm(&tm);
798 dump a set of results to a file. Useful from within gdb
800 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
802 int i;
804 for (i = 0; i < result->count; i++) {
805 struct ldb_ldif ldif;
806 fprintf(f, "# record %d\n", i+1);
807 ldif.changetype = LDB_CHANGETYPE_NONE;
808 ldif.msg = result->msgs[i];
809 ldb_ldif_write_file(ldb, f, &ldif);
813 int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
815 struct ldb_message_element *el;
816 struct ldb_val val;
818 el = ldb_msg_find_element(msg, name);
819 if (el == NULL)
820 return 0;
822 val.data = discard_const_p(uint8_t, value);
823 val.length = strlen(value);
825 if (ldb_msg_find_val(el, &val))
826 return 1;
828 return 0;