s4-dsdb: initialize correctly the value of originating_change_time for the Deleted...
[Samba/gebeck_regimport.git] / lib / ldb / common / ldb_msg.c
blob1a2bebc983fad4e56fce73ead5d42b6924a676a4
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 "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(TALLOC_CTX *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)
50 unsigned int i;
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];
56 return NULL;
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) {
70 return 1;
73 return 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,
81 struct ldb_val *val)
83 unsigned int i;
84 for (i=0;i<el->num_values;i++) {
85 if (ldb_val_equal_exact(val, &el->values[i])) {
86 return &el->values[i];
89 return NULL;
93 duplicate a ldb_val structure
95 struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
97 struct ldb_val v2;
98 v2.length = v->length;
99 if (v->data == NULL) {
100 v2.data = NULL;
101 return v2;
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);
107 if (!v2.data) {
108 v2.length = 0;
109 return v2;
112 memcpy(v2.data, v->data, v->length);
113 ((char *)v2.data)[v->length] = 0;
114 return v2;
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;
126 * TODO: Find out a way to assert on input parameters.
127 * msg and return_el must be valid
130 els = talloc_realloc(msg, msg->elements,
131 struct ldb_message_element, msg->num_elements + 1);
132 if (!els) {
133 return LDB_ERR_OPERATIONS_ERROR;
136 ZERO_STRUCT(els[msg->num_elements]);
138 msg->elements = els;
139 msg->num_elements++;
141 *return_el = &els[msg->num_elements-1];
143 return LDB_SUCCESS;
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,
151 int flags,
152 struct ldb_message_element **return_el)
154 int ret;
155 struct ldb_message_element *el;
157 ret = _ldb_msg_add_el(msg, &el);
158 if (ret != LDB_SUCCESS) {
159 return ret;
162 /* initialize newly added element */
163 el->flags = flags;
164 el->name = talloc_strdup(msg->elements, attr_name);
165 if (!el->name) {
166 return LDB_ERR_OPERATIONS_ERROR;
169 if (return_el) {
170 *return_el = el;
173 return LDB_SUCCESS;
177 * Adds an element to a message.
179 * NOTE: Ownership of ldb_message_element fields
180 * is NOT transferred. Thus, if *el pointer
181 * is invalidated for some reason, this will
182 * corrupt *msg contents also
184 int ldb_msg_add(struct ldb_message *msg,
185 const struct ldb_message_element *el,
186 int flags)
188 int ret;
189 struct ldb_message_element *el_new;
190 /* We have to copy this, just in case *el is a pointer into
191 * what ldb_msg_add_empty() is about to realloc() */
192 struct ldb_message_element el_copy = *el;
194 ret = _ldb_msg_add_el(msg, &el_new);
195 if (ret != LDB_SUCCESS) {
196 return ret;
199 el_new->flags = flags;
200 el_new->name = el_copy.name;
201 el_new->num_values = el_copy.num_values;
202 el_new->values = el_copy.values;
204 return LDB_SUCCESS;
208 add a value to a message
210 int ldb_msg_add_value(struct ldb_message *msg,
211 const char *attr_name,
212 const struct ldb_val *val,
213 struct ldb_message_element **return_el)
215 struct ldb_message_element *el;
216 struct ldb_val *vals;
217 int ret;
219 el = ldb_msg_find_element(msg, attr_name);
220 if (!el) {
221 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
222 if (ret != LDB_SUCCESS) {
223 return ret;
227 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
228 el->num_values+1);
229 if (!vals) {
230 return LDB_ERR_OPERATIONS_ERROR;
232 el->values = vals;
233 el->values[el->num_values] = *val;
234 el->num_values++;
236 if (return_el) {
237 *return_el = el;
240 return LDB_SUCCESS;
245 add a value to a message, stealing it into the 'right' place
247 int ldb_msg_add_steal_value(struct ldb_message *msg,
248 const char *attr_name,
249 struct ldb_val *val)
251 int ret;
252 struct ldb_message_element *el;
254 ret = ldb_msg_add_value(msg, attr_name, val, &el);
255 if (ret == LDB_SUCCESS) {
256 talloc_steal(el->values, val->data);
258 return ret;
263 add a string element to a message
265 int ldb_msg_add_string(struct ldb_message *msg,
266 const char *attr_name, const char *str)
268 struct ldb_val val;
270 val.data = discard_const_p(uint8_t, str);
271 val.length = strlen(str);
273 if (val.length == 0) {
274 /* allow empty strings as non-existent attributes */
275 return LDB_SUCCESS;
278 return ldb_msg_add_value(msg, attr_name, &val, NULL);
282 add a string element to a message, stealing it into the 'right' place
284 int ldb_msg_add_steal_string(struct ldb_message *msg,
285 const char *attr_name, char *str)
287 struct ldb_val val;
289 val.data = (uint8_t *)str;
290 val.length = strlen(str);
292 if (val.length == 0) {
293 /* allow empty strings as non-existent attributes */
294 return LDB_SUCCESS;
297 return ldb_msg_add_steal_value(msg, attr_name, &val);
301 add a DN element to a message
302 WARNING: this uses the linearized string from the dn, and does not
303 copy the string.
305 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
306 struct ldb_dn *dn)
308 char *str = ldb_dn_alloc_linearized(msg, dn);
310 if (str == NULL) {
311 /* we don't want to have unknown DNs added */
312 return LDB_ERR_OPERATIONS_ERROR;
315 return ldb_msg_add_steal_string(msg, attr_name, str);
319 add a printf formatted element to a message
321 int ldb_msg_add_fmt(struct ldb_message *msg,
322 const char *attr_name, const char *fmt, ...)
324 struct ldb_val val;
325 va_list ap;
326 char *str;
328 va_start(ap, fmt);
329 str = talloc_vasprintf(msg, fmt, ap);
330 va_end(ap);
332 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
334 val.data = (uint8_t *)str;
335 val.length = strlen(str);
337 return ldb_msg_add_steal_value(msg, attr_name, &val);
341 compare two ldb_message_element structures
342 assumes case sensitive comparison
344 int ldb_msg_element_compare(struct ldb_message_element *el1,
345 struct ldb_message_element *el2)
347 unsigned int i;
349 if (el1->num_values != el2->num_values) {
350 return el1->num_values - el2->num_values;
353 for (i=0;i<el1->num_values;i++) {
354 if (!ldb_msg_find_val(el2, &el1->values[i])) {
355 return -1;
359 return 0;
363 compare two ldb_message_element structures
364 comparing by element name
366 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
367 struct ldb_message_element *el2)
369 return ldb_attr_cmp(el1->name, el2->name);
373 convenience functions to return common types from a message
374 these return the first value if the attribute is multi-valued
376 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
377 const char *attr_name)
379 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
380 if (!el || el->num_values == 0) {
381 return NULL;
383 return &el->values[0];
386 int ldb_msg_find_attr_as_int(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 char buf[sizeof("-2147483648")];
392 char *end = NULL;
393 int ret;
395 if (!v || !v->data) {
396 return default_value;
399 ZERO_STRUCT(buf);
400 if (v->length >= sizeof(buf)) {
401 return default_value;
404 memcpy(buf, v->data, v->length);
405 errno = 0;
406 ret = (int) strtoll(buf, &end, 10);
407 if (errno != 0) {
408 return default_value;
410 if (end && end[0] != '\0') {
411 return default_value;
413 return ret;
416 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
417 const char *attr_name,
418 unsigned int default_value)
420 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
421 char buf[sizeof("-2147483648")];
422 char *end = NULL;
423 unsigned int ret;
425 if (!v || !v->data) {
426 return default_value;
429 ZERO_STRUCT(buf);
430 if (v->length >= sizeof(buf)) {
431 return default_value;
434 memcpy(buf, v->data, v->length);
435 errno = 0;
436 ret = (unsigned int) strtoll(buf, &end, 10);
437 if (errno != 0) {
438 errno = 0;
439 ret = (unsigned int) strtoull(buf, &end, 10);
440 if (errno != 0) {
441 return default_value;
444 if (end && end[0] != '\0') {
445 return default_value;
447 return ret;
450 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
451 const char *attr_name,
452 int64_t default_value)
454 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
455 char buf[sizeof("-9223372036854775808")];
456 char *end = NULL;
457 int64_t ret;
459 if (!v || !v->data) {
460 return default_value;
463 ZERO_STRUCT(buf);
464 if (v->length >= sizeof(buf)) {
465 return default_value;
468 memcpy(buf, v->data, v->length);
469 errno = 0;
470 ret = (int64_t) strtoll(buf, &end, 10);
471 if (errno != 0) {
472 return default_value;
474 if (end && end[0] != '\0') {
475 return default_value;
477 return ret;
480 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
481 const char *attr_name,
482 uint64_t default_value)
484 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
485 char buf[sizeof("-9223372036854775808")];
486 char *end = NULL;
487 uint64_t ret;
489 if (!v || !v->data) {
490 return default_value;
493 ZERO_STRUCT(buf);
494 if (v->length >= sizeof(buf)) {
495 return default_value;
498 memcpy(buf, v->data, v->length);
499 errno = 0;
500 ret = (uint64_t) strtoll(buf, &end, 10);
501 if (errno != 0) {
502 errno = 0;
503 ret = (uint64_t) strtoull(buf, &end, 10);
504 if (errno != 0) {
505 return default_value;
508 if (end && end[0] != '\0') {
509 return default_value;
511 return ret;
514 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
515 const char *attr_name,
516 double default_value)
518 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
519 char *buf;
520 char *end = NULL;
521 double ret;
523 if (!v || !v->data) {
524 return default_value;
526 buf = talloc_strndup(msg, (const char *)v->data, v->length);
527 if (buf == NULL) {
528 return default_value;
531 errno = 0;
532 ret = strtod(buf, &end);
533 talloc_free(buf);
534 if (errno != 0) {
535 return default_value;
537 if (end && end[0] != '\0') {
538 return default_value;
540 return ret;
543 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
544 const char *attr_name,
545 int default_value)
547 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
548 if (!v || !v->data) {
549 return default_value;
551 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
552 return 0;
554 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
555 return 1;
557 return default_value;
560 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
561 const char *attr_name,
562 const char *default_value)
564 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
565 if (!v || !v->data) {
566 return default_value;
568 if (v->data[v->length] != '\0') {
569 return default_value;
571 return (const char *)v->data;
574 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
575 TALLOC_CTX *mem_ctx,
576 const struct ldb_message *msg,
577 const char *attr_name)
579 struct ldb_dn *res_dn;
580 const struct ldb_val *v;
582 v = ldb_msg_find_ldb_val(msg, attr_name);
583 if (!v || !v->data) {
584 return NULL;
586 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
587 if ( ! ldb_dn_validate(res_dn)) {
588 talloc_free(res_dn);
589 return NULL;
591 return res_dn;
595 sort the elements of a message by name
597 void ldb_msg_sort_elements(struct ldb_message *msg)
599 TYPESAFE_QSORT(msg->elements, msg->num_elements,
600 ldb_msg_element_compare_name);
604 shallow copy a message - copying only the elements array so that the caller
605 can safely add new elements without changing the message
607 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
608 const struct ldb_message *msg)
610 struct ldb_message *msg2;
611 unsigned int i;
613 msg2 = talloc(mem_ctx, struct ldb_message);
614 if (msg2 == NULL) return NULL;
616 *msg2 = *msg;
618 msg2->elements = talloc_array(msg2, struct ldb_message_element,
619 msg2->num_elements);
620 if (msg2->elements == NULL) goto failed;
622 for (i=0;i<msg2->num_elements;i++) {
623 msg2->elements[i] = msg->elements[i];
626 return msg2;
628 failed:
629 talloc_free(msg2);
630 return NULL;
635 copy a message, allocating new memory for all parts
637 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
638 const struct ldb_message *msg)
640 struct ldb_message *msg2;
641 unsigned int i, j;
643 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
644 if (msg2 == NULL) return NULL;
646 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
647 if (msg2->dn == NULL) goto failed;
649 for (i=0;i<msg2->num_elements;i++) {
650 struct ldb_message_element *el = &msg2->elements[i];
651 struct ldb_val *values = el->values;
652 el->name = talloc_strdup(msg2->elements, el->name);
653 if (el->name == NULL) goto failed;
654 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
655 for (j=0;j<el->num_values;j++) {
656 el->values[j] = ldb_val_dup(el->values, &values[j]);
657 if (el->values[j].data == NULL && values[j].length != 0) {
658 goto failed;
663 return msg2;
665 failed:
666 talloc_free(msg2);
667 return NULL;
672 * Canonicalize a message, merging elements of the same name
674 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
675 const struct ldb_message *msg)
677 int ret;
678 struct ldb_message *msg2;
681 * Preserve previous behavior and allocate
682 * *msg2 into *ldb context
684 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
685 if (ret != LDB_SUCCESS) {
686 return NULL;
689 return msg2;
693 * Canonicalize a message, merging elements of the same name
695 int ldb_msg_normalize(struct ldb_context *ldb,
696 TALLOC_CTX *mem_ctx,
697 const struct ldb_message *msg,
698 struct ldb_message **_msg_out)
700 unsigned int i;
701 struct ldb_message *msg2;
703 msg2 = ldb_msg_copy(mem_ctx, msg);
704 if (msg2 == NULL) {
705 return LDB_ERR_OPERATIONS_ERROR;
708 ldb_msg_sort_elements(msg2);
710 for (i=1; i < msg2->num_elements; i++) {
711 struct ldb_message_element *el1 = &msg2->elements[i-1];
712 struct ldb_message_element *el2 = &msg2->elements[i];
714 if (ldb_msg_element_compare_name(el1, el2) == 0) {
715 el1->values = talloc_realloc(msg2->elements,
716 el1->values, struct ldb_val,
717 el1->num_values + el2->num_values);
718 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
719 talloc_free(msg2);
720 return LDB_ERR_OPERATIONS_ERROR;
722 memcpy(el1->values + el1->num_values,
723 el2->values,
724 sizeof(struct ldb_val) * el2->num_values);
725 el1->num_values += el2->num_values;
726 talloc_free(discard_const_p(char, el2->name));
727 if ((i+1) < msg2->num_elements) {
728 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
729 (msg2->num_elements - (i+1)));
731 msg2->num_elements--;
732 i--;
736 *_msg_out = msg2;
737 return LDB_SUCCESS;
742 * return a ldb_message representing the differences between msg1 and msg2.
743 * If you then use this in a ldb_modify() call,
744 * it can be used to save edits to a message
746 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
747 struct ldb_message *msg1,
748 struct ldb_message *msg2)
750 int ldb_ret;
751 struct ldb_message *mod;
753 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
754 if (ldb_ret != LDB_SUCCESS) {
755 return NULL;
758 return mod;
762 * return a ldb_message representing the differences between msg1 and msg2.
763 * If you then use this in a ldb_modify() call it can be used to save edits to a message
765 * Result message is constructed as follows:
766 * - LDB_FLAG_MOD_ADD - elements found only in msg2
767 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
768 * Value for msg2 element is used
769 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
771 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
773 int ldb_msg_difference(struct ldb_context *ldb,
774 TALLOC_CTX *mem_ctx,
775 struct ldb_message *msg1,
776 struct ldb_message *msg2,
777 struct ldb_message **_msg_out)
779 int ldb_res;
780 unsigned int i;
781 struct ldb_message *mod;
782 struct ldb_message_element *el;
783 TALLOC_CTX *temp_ctx;
785 temp_ctx = talloc_new(mem_ctx);
786 if (!temp_ctx) {
787 return LDB_ERR_OPERATIONS_ERROR;
790 mod = ldb_msg_new(temp_ctx);
791 if (mod == NULL) {
792 goto failed;
795 mod->dn = msg1->dn;
796 mod->num_elements = 0;
797 mod->elements = NULL;
800 * Canonicalize *msg2 so we have no repeated elements
801 * Resulting message is allocated in *mod's mem context,
802 * as we are going to move some elements from *msg2 to
803 * *mod object later
805 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
806 if (ldb_res != LDB_SUCCESS) {
807 goto failed;
810 /* look in msg2 to find elements that need to be added or modified */
811 for (i=0;i<msg2->num_elements;i++) {
812 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
814 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
815 continue;
818 ldb_res = ldb_msg_add(mod,
819 &msg2->elements[i],
820 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
821 if (ldb_res != LDB_SUCCESS) {
822 goto failed;
826 /* look in msg1 to find elements that need to be deleted */
827 for (i=0;i<msg1->num_elements;i++) {
828 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
829 if (el == NULL) {
830 ldb_res = ldb_msg_add_empty(mod,
831 msg1->elements[i].name,
832 LDB_FLAG_MOD_DELETE, NULL);
833 if (ldb_res != LDB_SUCCESS) {
834 goto failed;
839 /* steal resulting message into supplied context */
840 talloc_steal(mem_ctx, mod);
841 *_msg_out = mod;
843 talloc_free(temp_ctx);
844 return LDB_SUCCESS;
846 failed:
847 talloc_free(temp_ctx);
848 return LDB_ERR_OPERATIONS_ERROR;
852 int ldb_msg_sanity_check(struct ldb_context *ldb,
853 const struct ldb_message *msg)
855 unsigned int i, j;
857 /* basic check on DN */
858 if (msg->dn == NULL) {
859 ldb_set_errstring(ldb, "ldb message lacks a DN!");
860 return LDB_ERR_INVALID_DN_SYNTAX;
863 /* basic syntax checks */
864 for (i = 0; i < msg->num_elements; i++) {
865 for (j = 0; j < msg->elements[i].num_values; j++) {
866 if (msg->elements[i].values[j].length == 0) {
867 /* an attribute cannot be empty */
868 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
869 msg->elements[i].name,
870 ldb_dn_get_linearized(msg->dn));
871 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
876 return LDB_SUCCESS;
883 copy an attribute list. This only copies the array, not the elements
884 (ie. the elements are left as the same pointers)
886 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
888 const char **ret;
889 unsigned int i;
891 for (i=0;attrs && attrs[i];i++) /* noop */ ;
892 ret = talloc_array(mem_ctx, const char *, i+1);
893 if (ret == NULL) {
894 return NULL;
896 for (i=0;attrs && attrs[i];i++) {
897 ret[i] = attrs[i];
899 ret[i] = attrs[i];
900 return ret;
905 copy an attribute list. This only copies the array, not the elements
906 (ie. the elements are left as the same pointers). The new attribute is added to the list.
908 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
910 const char **ret;
911 unsigned int i;
912 bool found = false;
914 for (i=0;attrs && attrs[i];i++) {
915 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
916 found = true;
919 if (found) {
920 return ldb_attr_list_copy(mem_ctx, attrs);
922 ret = talloc_array(mem_ctx, const char *, i+2);
923 if (ret == NULL) {
924 return NULL;
926 for (i=0;attrs && attrs[i];i++) {
927 ret[i] = attrs[i];
929 ret[i] = new_attr;
930 ret[i+1] = NULL;
931 return ret;
936 return 1 if an attribute is in a list of attributes, or 0 otherwise
938 int ldb_attr_in_list(const char * const *attrs, const char *attr)
940 unsigned int i;
941 for (i=0;attrs && attrs[i];i++) {
942 if (ldb_attr_cmp(attrs[i], attr) == 0) {
943 return 1;
946 return 0;
951 rename the specified attribute in a search result
953 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
955 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
956 if (el == NULL) {
957 return LDB_SUCCESS;
959 el->name = talloc_strdup(msg->elements, replace);
960 if (el->name == NULL) {
961 return LDB_ERR_OPERATIONS_ERROR;
963 return LDB_SUCCESS;
968 copy the specified attribute in a search result to a new attribute
970 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
972 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
973 int ret;
975 if (el == NULL) {
976 return LDB_SUCCESS;
978 ret = ldb_msg_add(msg, el, 0);
979 if (ret != LDB_SUCCESS) {
980 return ret;
982 return ldb_msg_rename_attr(msg, attr, replace);
986 remove the specified element in a search result
988 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
990 ptrdiff_t n = (el - msg->elements);
991 if (n >= msg->num_elements) {
992 /* should we abort() here? */
993 return;
995 if (n != msg->num_elements-1) {
996 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
998 msg->num_elements--;
1003 remove the specified attribute in a search result
1005 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1007 struct ldb_message_element *el;
1009 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1010 ldb_msg_remove_element(msg, el);
1015 return a LDAP formatted GeneralizedTime string
1017 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1019 struct tm *tm = gmtime(&t);
1020 char *ts;
1021 int r;
1023 if (!tm) {
1024 return NULL;
1027 /* we now excatly how long this string will be */
1028 ts = talloc_array(mem_ctx, char, 18);
1030 /* formatted like: 20040408072012.0Z */
1031 r = snprintf(ts, 18,
1032 "%04u%02u%02u%02u%02u%02u.0Z",
1033 tm->tm_year+1900, tm->tm_mon+1,
1034 tm->tm_mday, tm->tm_hour, tm->tm_min,
1035 tm->tm_sec);
1037 if (r != 17) {
1038 talloc_free(ts);
1039 return NULL;
1042 return ts;
1046 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1048 time_t ldb_string_to_time(const char *s)
1050 struct tm tm;
1052 if (s == NULL) return 0;
1054 memset(&tm, 0, sizeof(tm));
1055 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1056 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1057 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1058 return 0;
1060 tm.tm_year -= 1900;
1061 tm.tm_mon -= 1;
1063 return timegm(&tm);
1067 convert a LDAP GeneralizedTime string in ldb_val format to a
1068 time_t.
1070 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1072 struct tm tm;
1074 if (v == NULL || !v->data || v->length < 17) {
1075 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1078 memset(&tm, 0, sizeof(tm));
1080 if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z",
1081 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1082 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1083 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1085 tm.tm_year -= 1900;
1086 tm.tm_mon -= 1;
1088 *t = timegm(&tm);
1090 return LDB_SUCCESS;
1094 return a LDAP formatted UTCTime string
1096 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1098 struct tm *tm = gmtime(&t);
1099 char *ts;
1100 int r;
1102 if (!tm) {
1103 return NULL;
1106 /* we now excatly how long this string will be */
1107 ts = talloc_array(mem_ctx, char, 14);
1109 /* formatted like: 20040408072012.0Z => 040408072012Z */
1110 r = snprintf(ts, 14,
1111 "%02u%02u%02u%02u%02u%02uZ",
1112 (tm->tm_year+1900)%100, tm->tm_mon+1,
1113 tm->tm_mday, tm->tm_hour, tm->tm_min,
1114 tm->tm_sec);
1116 if (r != 13) {
1117 talloc_free(ts);
1118 return NULL;
1121 return ts;
1125 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1127 time_t ldb_string_utc_to_time(const char *s)
1129 struct tm tm;
1131 if (s == NULL) return 0;
1133 memset(&tm, 0, sizeof(tm));
1134 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1135 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1136 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1137 return 0;
1139 if (tm.tm_year < 50) {
1140 tm.tm_year += 100;
1142 tm.tm_mon -= 1;
1144 return timegm(&tm);
1149 dump a set of results to a file. Useful from within gdb
1151 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1153 unsigned int i;
1155 for (i = 0; i < result->count; i++) {
1156 struct ldb_ldif ldif;
1157 fprintf(f, "# record %d\n", i+1);
1158 ldif.changetype = LDB_CHANGETYPE_NONE;
1159 ldif.msg = result->msgs[i];
1160 ldb_ldif_write_file(ldb, f, &ldif);
1165 checks for a string attribute. Returns "1" on match and otherwise "0".
1167 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1168 const char *name, const char *value)
1170 struct ldb_message_element *el;
1171 struct ldb_val val;
1173 el = ldb_msg_find_element(msg, name);
1174 if (el == NULL) {
1175 return 0;
1178 val.data = discard_const_p(uint8_t, value);
1179 val.length = strlen(value);
1181 if (ldb_msg_find_val(el, &val)) {
1182 return 1;
1185 return 0;
1190 compare a ldb_val to a string
1192 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1194 size_t len = strlen(str);
1195 if (len != v->length) {
1196 return len - v->length;
1198 return strncmp((const char *)v->data, str, len);