r19955: I'll leave that to others. I *knew* I should not have touchec this
[Samba.git] / source / lib / ldb / common / ldb_msg.c
blob65d1ecacb7a98ee502a5e94ccd99587371af9bfd
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 2 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Name: ldb
28 * Component: ldb message component utility functions
30 * Description: functions for manipulating ldb_message structures
32 * Author: Andrew Tridgell
35 #include "includes.h"
36 #include "ldb/include/includes.h"
39 create a new ldb_message in a given memory context (NULL for top level)
41 struct ldb_message *ldb_msg_new(void *mem_ctx)
43 return talloc_zero(mem_ctx, struct ldb_message);
47 find an element in a message by attribute name
49 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
50 const char *attr_name)
52 unsigned int i;
53 for (i=0;i<msg->num_elements;i++) {
54 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
55 return &msg->elements[i];
58 return NULL;
62 see if two ldb_val structures contain exactly the same data
63 return 1 for a match, 0 for a mis-match
65 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
67 if (v1->length != v2->length) return 0;
69 if (v1->length == 0) return 1;
71 if (memcmp(v1->data, v2->data, v1->length) == 0) {
72 return 1;
75 return 0;
79 find a value in an element
80 assumes case sensitive comparison
82 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
83 struct ldb_val *val)
85 unsigned int i;
86 for (i=0;i<el->num_values;i++) {
87 if (ldb_val_equal_exact(val, &el->values[i])) {
88 return &el->values[i];
91 return NULL;
95 duplicate a ldb_val structure
97 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
99 struct ldb_val v2;
100 v2.length = v->length;
101 if (v->data == NULL) {
102 v2.data = NULL;
103 return v2;
106 /* the +1 is to cope with buggy C library routines like strndup
107 that look one byte beyond */
108 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
109 if (!v2.data) {
110 v2.length = 0;
111 return v2;
114 memcpy(v2.data, v->data, v->length);
115 ((char *)v2.data)[v->length] = 0;
116 return v2;
120 add an empty element to a message
122 int ldb_msg_add_empty( struct ldb_message *msg,
123 const char *attr_name,
124 int flags,
125 struct ldb_message_element **return_el)
127 struct ldb_message_element *els;
129 if (! ldb_valid_attr_name(attr_name)) {
130 return LDB_ERR_OPERATIONS_ERROR;
133 els = talloc_realloc(msg, msg->elements,
134 struct ldb_message_element, msg->num_elements+1);
135 if (!els) {
136 errno = ENOMEM;
137 return LDB_ERR_OPERATIONS_ERROR;
140 els[msg->num_elements].values = NULL;
141 els[msg->num_elements].num_values = 0;
142 els[msg->num_elements].flags = flags;
143 els[msg->num_elements].name = talloc_strdup(els, attr_name);
144 if (!els[msg->num_elements].name) {
145 errno = ENOMEM;
146 return LDB_ERR_OPERATIONS_ERROR;
149 msg->elements = els;
150 msg->num_elements++;
152 if (return_el) {
153 *return_el = &els[msg->num_elements-1];
156 return LDB_SUCCESS;
160 add an empty element to a message
162 int ldb_msg_add(struct ldb_message *msg,
163 const struct ldb_message_element *el,
164 int flags)
166 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
167 return LDB_ERR_OPERATIONS_ERROR;
170 msg->elements[msg->num_elements-1] = *el;
171 msg->elements[msg->num_elements-1].flags = flags;
173 return LDB_SUCCESS;
177 add a value to a message
179 int ldb_msg_add_value(struct ldb_message *msg,
180 const char *attr_name,
181 const struct ldb_val *val,
182 struct ldb_message_element **return_el)
184 struct ldb_message_element *el;
185 struct ldb_val *vals;
186 int ret;
188 el = ldb_msg_find_element(msg, attr_name);
189 if (!el) {
190 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
191 if (ret != LDB_SUCCESS) {
192 return ret;
196 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
197 if (!vals) {
198 errno = ENOMEM;
199 return LDB_ERR_OPERATIONS_ERROR;
201 el->values = vals;
202 el->values[el->num_values] = *val;
203 el->num_values++;
205 if (return_el) {
206 *return_el = el;
209 return LDB_SUCCESS;
214 add a value to a message, stealing it into the 'right' place
216 int ldb_msg_add_steal_value(struct ldb_message *msg,
217 const char *attr_name,
218 struct ldb_val *val)
220 int ret;
221 struct ldb_message_element *el;
223 ret = ldb_msg_add_value(msg, attr_name, val, &el);
224 if (ret == LDB_SUCCESS) {
225 talloc_steal(el->values, val->data);
227 return ret;
232 add a string element to a message
234 int ldb_msg_add_string(struct ldb_message *msg,
235 const char *attr_name, const char *str)
237 struct ldb_val val;
239 val.data = discard_const_p(uint8_t, str);
240 val.length = strlen(str);
242 if (val.length == 0) {
243 /* allow empty strings as non-existant attributes */
244 return LDB_SUCCESS;
247 return ldb_msg_add_value(msg, attr_name, &val, NULL);
251 add a string element to a message, stealing it into the 'right' place
253 int ldb_msg_add_steal_string(struct ldb_message *msg,
254 const char *attr_name, char *str)
256 struct ldb_val val;
258 val.data = (uint8_t *)str;
259 val.length = strlen(str);
261 return ldb_msg_add_steal_value(msg, attr_name, &val);
265 add a printf formatted element to a message
267 int ldb_msg_add_fmt(struct ldb_message *msg,
268 const char *attr_name, const char *fmt, ...)
270 struct ldb_val val;
271 va_list ap;
272 char *str;
274 va_start(ap, fmt);
275 str = talloc_vasprintf(msg, fmt, ap);
276 va_end(ap);
278 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
280 val.data = (uint8_t *)str;
281 val.length = strlen(str);
283 return ldb_msg_add_steal_value(msg, attr_name, &val);
287 compare two ldb_message_element structures
288 assumes case senistive comparison
290 int ldb_msg_element_compare(struct ldb_message_element *el1,
291 struct ldb_message_element *el2)
293 unsigned int i;
295 if (el1->num_values != el2->num_values) {
296 return el1->num_values - el2->num_values;
299 for (i=0;i<el1->num_values;i++) {
300 if (!ldb_msg_find_val(el2, &el1->values[i])) {
301 return -1;
305 return 0;
309 compare two ldb_message_element structures
310 comparing by element name
312 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
313 struct ldb_message_element *el2)
315 return ldb_attr_cmp(el1->name, el2->name);
319 convenience functions to return common types from a message
320 these return the first value if the attribute is multi-valued
322 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
324 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
325 if (!el || el->num_values == 0) {
326 return NULL;
328 return &el->values[0];
331 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
332 const char *attr_name,
333 int default_value)
335 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
336 if (!v || !v->data) {
337 return default_value;
339 return strtol((const char *)v->data, NULL, 0);
342 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
343 const char *attr_name,
344 unsigned int default_value)
346 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
347 if (!v || !v->data) {
348 return default_value;
350 return strtoul((const char *)v->data, NULL, 0);
353 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
354 const char *attr_name,
355 int64_t default_value)
357 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
358 if (!v || !v->data) {
359 return default_value;
361 return strtoll((const char *)v->data, NULL, 0);
364 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
365 const char *attr_name,
366 uint64_t default_value)
368 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
369 if (!v || !v->data) {
370 return default_value;
372 return strtoull((const char *)v->data, NULL, 0);
375 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
376 const char *attr_name,
377 double default_value)
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 strtod((const char *)v->data, NULL);
386 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
387 const char *attr_name,
388 int default_value)
390 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
391 if (!v || !v->data) {
392 return default_value;
394 if (strcasecmp((const char *)v->data, "FALSE") == 0) {
395 return 0;
397 if (strcasecmp((const char *)v->data, "TRUE") == 0) {
398 return 1;
400 return default_value;
403 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
404 const char *attr_name,
405 const char *default_value)
407 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
408 if (!v || !v->data) {
409 return default_value;
411 return (const char *)v->data;
414 struct ldb_dn *ldb_msg_find_attr_as_dn(void *mem_ctx,
415 const struct ldb_message *msg,
416 const char *attr_name)
418 const struct ldb_val *v;
420 v = ldb_msg_find_ldb_val(msg, attr_name);
421 if (!v || !v->data) {
422 return NULL;
424 return ldb_dn_explode(mem_ctx, (const char *)v->data);
428 sort the elements of a message by name
430 void ldb_msg_sort_elements(struct ldb_message *msg)
432 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
433 (comparison_fn_t)ldb_msg_element_compare_name);
437 shallow copy a message - copying only the elements array so that the caller
438 can safely add new elements without changing the message
440 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
441 const struct ldb_message *msg)
443 struct ldb_message *msg2;
444 int i;
446 msg2 = talloc(mem_ctx, struct ldb_message);
447 if (msg2 == NULL) return NULL;
449 *msg2 = *msg;
450 msg2->private_data = NULL;
452 msg2->elements = talloc_array(msg2, struct ldb_message_element,
453 msg2->num_elements);
454 if (msg2->elements == NULL) goto failed;
456 for (i=0;i<msg2->num_elements;i++) {
457 msg2->elements[i] = msg->elements[i];
460 return msg2;
462 failed:
463 talloc_free(msg2);
464 return NULL;
469 copy a message, allocating new memory for all parts
471 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
472 const struct ldb_message *msg)
474 struct ldb_message *msg2;
475 int i, j;
477 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
478 if (msg2 == NULL) return NULL;
480 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
481 if (msg2->dn == NULL) goto failed;
483 for (i=0;i<msg2->num_elements;i++) {
484 struct ldb_message_element *el = &msg2->elements[i];
485 struct ldb_val *values = el->values;
486 el->name = talloc_strdup(msg2->elements, el->name);
487 if (el->name == NULL) goto failed;
488 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
489 for (j=0;j<el->num_values;j++) {
490 el->values[j] = ldb_val_dup(el->values, &values[j]);
491 if (el->values[j].data == NULL && values[j].length != 0) {
492 goto failed;
497 return msg2;
499 failed:
500 talloc_free(msg2);
501 return NULL;
506 canonicalise a message, merging elements of the same name
508 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
509 const struct ldb_message *msg)
511 int i;
512 struct ldb_message *msg2;
514 msg2 = ldb_msg_copy(ldb, msg);
515 if (msg2 == NULL) return NULL;
517 ldb_msg_sort_elements(msg2);
519 for (i=1;i<msg2->num_elements;i++) {
520 struct ldb_message_element *el1 = &msg2->elements[i-1];
521 struct ldb_message_element *el2 = &msg2->elements[i];
522 if (ldb_msg_element_compare_name(el1, el2) == 0) {
523 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
524 el1->num_values + el2->num_values);
525 if (el1->values == NULL) {
526 return NULL;
528 memcpy(el1->values + el1->num_values,
529 el2->values,
530 sizeof(struct ldb_val) * el2->num_values);
531 el1->num_values += el2->num_values;
532 talloc_free(discard_const_p(char, el2->name));
533 if (i+1<msg2->num_elements) {
534 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
535 (msg2->num_elements - (i+1)));
537 msg2->num_elements--;
538 i--;
542 return msg2;
547 return a ldb_message representing the differences between msg1 and msg2. If you
548 then use this in a ldb_modify() call it can be used to save edits to a message
550 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
551 struct ldb_message *msg1,
552 struct ldb_message *msg2)
554 struct ldb_message *mod;
555 struct ldb_message_element *el;
556 unsigned int i;
558 mod = ldb_msg_new(ldb);
560 mod->dn = msg1->dn;
561 mod->num_elements = 0;
562 mod->elements = NULL;
564 msg2 = ldb_msg_canonicalize(ldb, msg2);
565 if (msg2 == NULL) {
566 return NULL;
569 /* look in msg2 to find elements that need to be added
570 or modified */
571 for (i=0;i<msg2->num_elements;i++) {
572 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
574 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
575 continue;
578 if (ldb_msg_add(mod,
579 &msg2->elements[i],
580 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
581 return NULL;
585 /* look in msg1 to find elements that need to be deleted */
586 for (i=0;i<msg1->num_elements;i++) {
587 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
588 if (!el) {
589 if (ldb_msg_add_empty(mod,
590 msg1->elements[i].name,
591 LDB_FLAG_MOD_DELETE, NULL) != 0) {
592 return NULL;
597 return mod;
600 int ldb_msg_sanity_check(struct ldb_context *ldb,
601 const struct ldb_message *msg)
603 int i, j;
605 /* basic check on DN */
606 if (msg->dn == NULL) {
607 /* TODO: return also an error string */
608 ldb_set_errstring(ldb, "ldb message lacks a DN!");
609 return LDB_ERR_INVALID_DN_SYNTAX;
612 /* basic syntax checks */
613 for (i = 0; i < msg->num_elements; i++) {
614 for (j = 0; j < msg->elements[i].num_values; j++) {
615 if (msg->elements[i].values[j].length == 0) {
616 TALLOC_CTX *mem_ctx = talloc_new(ldb);
617 /* an attribute cannot be empty */
618 /* TODO: return also an error string */
619 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
620 msg->elements[i].name,
621 ldb_dn_linearize(mem_ctx, msg->dn));
622 talloc_free(mem_ctx);
623 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
628 return LDB_SUCCESS;
635 copy an attribute list. This only copies the array, not the elements
636 (ie. the elements are left as the same pointers)
638 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
640 const char **ret;
641 int i;
642 for (i=0;attrs[i];i++) /* noop */ ;
643 ret = talloc_array(mem_ctx, const char *, i+1);
644 if (ret == NULL) {
645 return NULL;
647 for (i=0;attrs[i];i++) {
648 ret[i] = attrs[i];
650 ret[i] = attrs[i];
651 return ret;
656 copy an attribute list. This only copies the array, not the elements
657 (ie. the elements are left as the same pointers). The new attribute is added to the list.
659 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
661 const char **ret;
662 int i;
663 for (i=0;attrs[i];i++) /* noop */ ;
664 ret = talloc_array(mem_ctx, const char *, i+2);
665 if (ret == NULL) {
666 return NULL;
668 for (i=0;attrs[i];i++) {
669 ret[i] = attrs[i];
671 ret[i] = new_attr;
672 ret[i+1] = NULL;
673 return ret;
678 return 1 if an attribute is in a list of attributes, or 0 otherwise
680 int ldb_attr_in_list(const char * const *attrs, const char *attr)
682 int i;
683 for (i=0;attrs[i];i++) {
684 if (ldb_attr_cmp(attrs[i], attr) == 0) {
685 return 1;
688 return 0;
693 rename the specified attribute in a search result
695 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
697 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
698 if (el == NULL) {
699 return LDB_SUCCESS;
701 el->name = talloc_strdup(msg->elements, replace);
702 if (el->name == NULL) {
703 return LDB_ERR_OPERATIONS_ERROR;
705 return LDB_SUCCESS;
710 copy the specified attribute in a search result to a new attribute
712 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
714 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
715 if (el == NULL) {
716 return LDB_SUCCESS;
718 if (ldb_msg_add(msg, el, 0) != 0) {
719 return LDB_ERR_OPERATIONS_ERROR;
721 return ldb_msg_rename_attr(msg, attr, replace);
726 remove the specified attribute in a search result
728 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
730 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
731 if (el) {
732 int n = (el - msg->elements);
733 if (n != msg->num_elements-1) {
734 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
736 msg->num_elements--;
741 remove the specified element in a search result
743 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
745 int n = (el - msg->elements);
746 if (n != msg->num_elements-1) {
747 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
749 msg->num_elements--;
753 return a LDAP formatted time string
755 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
757 struct tm *tm = gmtime(&t);
759 if (!tm) {
760 return NULL;
763 /* formatted like: 20040408072012.0Z */
764 return talloc_asprintf(mem_ctx,
765 "%04u%02u%02u%02u%02u%02u.0Z",
766 tm->tm_year+1900, tm->tm_mon+1,
767 tm->tm_mday, tm->tm_hour, tm->tm_min,
768 tm->tm_sec);
773 convert a LDAP time string to a time_t. Return 0 if unable to convert
775 time_t ldb_string_to_time(const char *s)
777 struct tm tm;
779 if (s == NULL) return 0;
781 memset(&tm, 0, sizeof(tm));
782 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
783 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
784 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
785 return 0;
787 tm.tm_year -= 1900;
788 tm.tm_mon -= 1;
790 return timegm(&tm);
795 dump a set of results to a file. Useful from within gdb
797 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
799 int i;
801 for (i = 0; i < result->count; i++) {
802 struct ldb_ldif ldif;
803 fprintf(f, "# record %d\n", i+1);
804 ldif.changetype = LDB_CHANGETYPE_NONE;
805 ldif.msg = result->msgs[i];
806 ldb_ldif_write_file(ldb, f, &ldif);
810 int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
812 struct ldb_message_element *el;
813 struct ldb_val val;
815 el = ldb_msg_find_element(msg, name);
816 if (el == NULL)
817 return 0;
819 val.data = discard_const_p(uint8_t, value);
820 val.length = strlen(value);
822 if (ldb_msg_find_val(el, &val))
823 return 1;
825 return 0;