WHATSNEW: Add release notes for Samba 4.4.0rc2.
[Samba.git] / lib / ldb / common / ldb_msg.c
blob3f65351ff293f0d656835038813372e26a9bbc36
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 Different ordering is considered a mismatch
366 bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
367 const struct ldb_message_element *el2)
369 unsigned i;
370 if (el1->num_values != el2->num_values) {
371 return false;
373 for (i=0;i<el1->num_values;i++) {
374 if (ldb_val_equal_exact(&el1->values[i],
375 &el2->values[i]) != 1) {
376 return false;
379 return true;
383 compare two ldb_message_element structures
384 comparing by element name
386 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
387 struct ldb_message_element *el2)
389 return ldb_attr_cmp(el1->name, el2->name);
393 convenience functions to return common types from a message
394 these return the first value if the attribute is multi-valued
396 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
397 const char *attr_name)
399 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
400 if (!el || el->num_values == 0) {
401 return NULL;
403 return &el->values[0];
406 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
407 const char *attr_name,
408 int default_value)
410 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
411 char buf[sizeof("-2147483648")];
412 char *end = NULL;
413 int ret;
415 if (!v || !v->data) {
416 return default_value;
419 ZERO_STRUCT(buf);
420 if (v->length >= sizeof(buf)) {
421 return default_value;
424 memcpy(buf, v->data, v->length);
425 errno = 0;
426 ret = (int) strtoll(buf, &end, 10);
427 if (errno != 0) {
428 return default_value;
430 if (end && end[0] != '\0') {
431 return default_value;
433 return ret;
436 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
437 const char *attr_name,
438 unsigned int default_value)
440 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
441 char buf[sizeof("-2147483648")];
442 char *end = NULL;
443 unsigned int ret;
445 if (!v || !v->data) {
446 return default_value;
449 ZERO_STRUCT(buf);
450 if (v->length >= sizeof(buf)) {
451 return default_value;
454 memcpy(buf, v->data, v->length);
455 errno = 0;
456 ret = (unsigned int) strtoll(buf, &end, 10);
457 if (errno != 0) {
458 errno = 0;
459 ret = (unsigned int) strtoull(buf, &end, 10);
460 if (errno != 0) {
461 return default_value;
464 if (end && end[0] != '\0') {
465 return default_value;
467 return ret;
470 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
471 const char *attr_name,
472 int64_t default_value)
474 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
475 char buf[sizeof("-9223372036854775808")];
476 char *end = NULL;
477 int64_t ret;
479 if (!v || !v->data) {
480 return default_value;
483 ZERO_STRUCT(buf);
484 if (v->length >= sizeof(buf)) {
485 return default_value;
488 memcpy(buf, v->data, v->length);
489 errno = 0;
490 ret = (int64_t) strtoll(buf, &end, 10);
491 if (errno != 0) {
492 return default_value;
494 if (end && end[0] != '\0') {
495 return default_value;
497 return ret;
500 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
501 const char *attr_name,
502 uint64_t default_value)
504 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
505 char buf[sizeof("-9223372036854775808")];
506 char *end = NULL;
507 uint64_t ret;
509 if (!v || !v->data) {
510 return default_value;
513 ZERO_STRUCT(buf);
514 if (v->length >= sizeof(buf)) {
515 return default_value;
518 memcpy(buf, v->data, v->length);
519 errno = 0;
520 ret = (uint64_t) strtoll(buf, &end, 10);
521 if (errno != 0) {
522 errno = 0;
523 ret = (uint64_t) strtoull(buf, &end, 10);
524 if (errno != 0) {
525 return default_value;
528 if (end && end[0] != '\0') {
529 return default_value;
531 return ret;
534 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
535 const char *attr_name,
536 double default_value)
538 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
539 char *buf;
540 char *end = NULL;
541 double ret;
543 if (!v || !v->data) {
544 return default_value;
546 buf = talloc_strndup(msg, (const char *)v->data, v->length);
547 if (buf == NULL) {
548 return default_value;
551 errno = 0;
552 ret = strtod(buf, &end);
553 talloc_free(buf);
554 if (errno != 0) {
555 return default_value;
557 if (end && end[0] != '\0') {
558 return default_value;
560 return ret;
563 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
564 const char *attr_name,
565 int default_value)
567 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
568 if (!v || !v->data) {
569 return default_value;
571 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
572 return 0;
574 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
575 return 1;
577 return default_value;
580 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
581 const char *attr_name,
582 const char *default_value)
584 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
585 if (!v || !v->data) {
586 return default_value;
588 if (v->data[v->length] != '\0') {
589 return default_value;
591 return (const char *)v->data;
594 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
595 TALLOC_CTX *mem_ctx,
596 const struct ldb_message *msg,
597 const char *attr_name)
599 struct ldb_dn *res_dn;
600 const struct ldb_val *v;
602 v = ldb_msg_find_ldb_val(msg, attr_name);
603 if (!v || !v->data) {
604 return NULL;
606 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
607 if ( ! ldb_dn_validate(res_dn)) {
608 talloc_free(res_dn);
609 return NULL;
611 return res_dn;
615 sort the elements of a message by name
617 void ldb_msg_sort_elements(struct ldb_message *msg)
619 TYPESAFE_QSORT(msg->elements, msg->num_elements,
620 ldb_msg_element_compare_name);
624 shallow copy a message - copying only the elements array so that the caller
625 can safely add new elements without changing the message
627 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
628 const struct ldb_message *msg)
630 struct ldb_message *msg2;
631 unsigned int i;
633 msg2 = talloc(mem_ctx, struct ldb_message);
634 if (msg2 == NULL) return NULL;
636 *msg2 = *msg;
638 msg2->elements = talloc_array(msg2, struct ldb_message_element,
639 msg2->num_elements);
640 if (msg2->elements == NULL) goto failed;
642 for (i=0;i<msg2->num_elements;i++) {
643 msg2->elements[i] = msg->elements[i];
646 return msg2;
648 failed:
649 talloc_free(msg2);
650 return NULL;
655 copy a message, allocating new memory for all parts
657 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
658 const struct ldb_message *msg)
660 struct ldb_message *msg2;
661 unsigned int i, j;
663 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
664 if (msg2 == NULL) return NULL;
666 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
667 if (msg2->dn == NULL) goto failed;
669 for (i=0;i<msg2->num_elements;i++) {
670 struct ldb_message_element *el = &msg2->elements[i];
671 struct ldb_val *values = el->values;
672 el->name = talloc_strdup(msg2->elements, el->name);
673 if (el->name == NULL) goto failed;
674 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
675 if (el->values == NULL) goto failed;
676 for (j=0;j<el->num_values;j++) {
677 el->values[j] = ldb_val_dup(el->values, &values[j]);
678 if (el->values[j].data == NULL && values[j].length != 0) {
679 goto failed;
684 return msg2;
686 failed:
687 talloc_free(msg2);
688 return NULL;
693 * Canonicalize a message, merging elements of the same name
695 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
696 const struct ldb_message *msg)
698 int ret;
699 struct ldb_message *msg2;
702 * Preserve previous behavior and allocate
703 * *msg2 into *ldb context
705 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
706 if (ret != LDB_SUCCESS) {
707 return NULL;
710 return msg2;
714 * Canonicalize a message, merging elements of the same name
716 int ldb_msg_normalize(struct ldb_context *ldb,
717 TALLOC_CTX *mem_ctx,
718 const struct ldb_message *msg,
719 struct ldb_message **_msg_out)
721 unsigned int i;
722 struct ldb_message *msg2;
724 msg2 = ldb_msg_copy(mem_ctx, msg);
725 if (msg2 == NULL) {
726 return LDB_ERR_OPERATIONS_ERROR;
729 ldb_msg_sort_elements(msg2);
731 for (i=1; i < msg2->num_elements; i++) {
732 struct ldb_message_element *el1 = &msg2->elements[i-1];
733 struct ldb_message_element *el2 = &msg2->elements[i];
735 if (ldb_msg_element_compare_name(el1, el2) == 0) {
736 el1->values = talloc_realloc(msg2->elements,
737 el1->values, struct ldb_val,
738 el1->num_values + el2->num_values);
739 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
740 talloc_free(msg2);
741 return LDB_ERR_OPERATIONS_ERROR;
743 memcpy(el1->values + el1->num_values,
744 el2->values,
745 sizeof(struct ldb_val) * el2->num_values);
746 el1->num_values += el2->num_values;
747 talloc_free(discard_const_p(char, el2->name));
748 if ((i+1) < msg2->num_elements) {
749 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
750 (msg2->num_elements - (i+1)));
752 msg2->num_elements--;
753 i--;
757 *_msg_out = msg2;
758 return LDB_SUCCESS;
763 * return a ldb_message representing the differences between msg1 and msg2.
764 * If you then use this in a ldb_modify() call,
765 * it can be used to save edits to a message
767 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
768 struct ldb_message *msg1,
769 struct ldb_message *msg2)
771 int ldb_ret;
772 struct ldb_message *mod;
774 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
775 if (ldb_ret != LDB_SUCCESS) {
776 return NULL;
779 return mod;
783 * return a ldb_message representing the differences between msg1 and msg2.
784 * If you then use this in a ldb_modify() call it can be used to save edits to a message
786 * Result message is constructed as follows:
787 * - LDB_FLAG_MOD_ADD - elements found only in msg2
788 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
789 * Value for msg2 element is used
790 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
792 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
794 int ldb_msg_difference(struct ldb_context *ldb,
795 TALLOC_CTX *mem_ctx,
796 struct ldb_message *msg1,
797 struct ldb_message *msg2,
798 struct ldb_message **_msg_out)
800 int ldb_res;
801 unsigned int i;
802 struct ldb_message *mod;
803 struct ldb_message_element *el;
804 TALLOC_CTX *temp_ctx;
806 temp_ctx = talloc_new(mem_ctx);
807 if (!temp_ctx) {
808 return LDB_ERR_OPERATIONS_ERROR;
811 mod = ldb_msg_new(temp_ctx);
812 if (mod == NULL) {
813 goto failed;
816 mod->dn = msg1->dn;
817 mod->num_elements = 0;
818 mod->elements = NULL;
821 * Canonicalize *msg2 so we have no repeated elements
822 * Resulting message is allocated in *mod's mem context,
823 * as we are going to move some elements from *msg2 to
824 * *mod object later
826 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
827 if (ldb_res != LDB_SUCCESS) {
828 goto failed;
831 /* look in msg2 to find elements that need to be added or modified */
832 for (i=0;i<msg2->num_elements;i++) {
833 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
835 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
836 continue;
839 ldb_res = ldb_msg_add(mod,
840 &msg2->elements[i],
841 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
842 if (ldb_res != LDB_SUCCESS) {
843 goto failed;
847 /* look in msg1 to find elements that need to be deleted */
848 for (i=0;i<msg1->num_elements;i++) {
849 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
850 if (el == NULL) {
851 ldb_res = ldb_msg_add_empty(mod,
852 msg1->elements[i].name,
853 LDB_FLAG_MOD_DELETE, NULL);
854 if (ldb_res != LDB_SUCCESS) {
855 goto failed;
860 /* steal resulting message into supplied context */
861 talloc_steal(mem_ctx, mod);
862 *_msg_out = mod;
864 talloc_free(temp_ctx);
865 return LDB_SUCCESS;
867 failed:
868 talloc_free(temp_ctx);
869 return LDB_ERR_OPERATIONS_ERROR;
873 int ldb_msg_sanity_check(struct ldb_context *ldb,
874 const struct ldb_message *msg)
876 unsigned int i, j;
878 /* basic check on DN */
879 if (msg->dn == NULL) {
880 ldb_set_errstring(ldb, "ldb message lacks a DN!");
881 return LDB_ERR_INVALID_DN_SYNTAX;
884 /* basic syntax checks */
885 for (i = 0; i < msg->num_elements; i++) {
886 for (j = 0; j < msg->elements[i].num_values; j++) {
887 if (msg->elements[i].values[j].length == 0) {
888 /* an attribute cannot be empty */
889 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
890 msg->elements[i].name,
891 ldb_dn_get_linearized(msg->dn));
892 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
897 return LDB_SUCCESS;
904 copy an attribute list. This only copies the array, not the elements
905 (ie. the elements are left as the same pointers)
907 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
909 const char **ret;
910 unsigned int i;
912 for (i=0;attrs && attrs[i];i++) /* noop */ ;
913 ret = talloc_array(mem_ctx, const char *, i+1);
914 if (ret == NULL) {
915 return NULL;
917 for (i=0;attrs && attrs[i];i++) {
918 ret[i] = attrs[i];
920 ret[i] = attrs[i];
921 return ret;
926 copy an attribute list. This only copies the array, not the elements
927 (ie. the elements are left as the same pointers). The new attribute is added to the list.
929 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
931 const char **ret;
932 unsigned int i;
933 bool found = false;
935 for (i=0;attrs && attrs[i];i++) {
936 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
937 found = true;
940 if (found) {
941 return ldb_attr_list_copy(mem_ctx, attrs);
943 ret = talloc_array(mem_ctx, const char *, i+2);
944 if (ret == NULL) {
945 return NULL;
947 for (i=0;attrs && attrs[i];i++) {
948 ret[i] = attrs[i];
950 ret[i] = new_attr;
951 ret[i+1] = NULL;
952 return ret;
957 return 1 if an attribute is in a list of attributes, or 0 otherwise
959 int ldb_attr_in_list(const char * const *attrs, const char *attr)
961 unsigned int i;
962 for (i=0;attrs && attrs[i];i++) {
963 if (ldb_attr_cmp(attrs[i], attr) == 0) {
964 return 1;
967 return 0;
972 rename the specified attribute in a search result
974 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
976 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
977 if (el == NULL) {
978 return LDB_SUCCESS;
980 el->name = talloc_strdup(msg->elements, replace);
981 if (el->name == NULL) {
982 return LDB_ERR_OPERATIONS_ERROR;
984 return LDB_SUCCESS;
989 copy the specified attribute in a search result to a new attribute
991 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
993 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
994 int ret;
996 if (el == NULL) {
997 return LDB_SUCCESS;
999 ret = ldb_msg_add(msg, el, 0);
1000 if (ret != LDB_SUCCESS) {
1001 return ret;
1003 return ldb_msg_rename_attr(msg, attr, replace);
1007 remove the specified element in a search result
1009 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
1011 ptrdiff_t n = (el - msg->elements);
1012 if (n >= msg->num_elements) {
1013 /* should we abort() here? */
1014 return;
1016 if (n != msg->num_elements-1) {
1017 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
1019 msg->num_elements--;
1024 remove the specified attribute in a search result
1026 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1028 struct ldb_message_element *el;
1030 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1031 ldb_msg_remove_element(msg, el);
1036 return a LDAP formatted GeneralizedTime string
1038 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1040 struct tm *tm = gmtime(&t);
1041 char *ts;
1042 int r;
1044 if (!tm) {
1045 return NULL;
1048 /* we now excatly how long this string will be */
1049 ts = talloc_array(mem_ctx, char, 18);
1051 /* formatted like: 20040408072012.0Z */
1052 r = snprintf(ts, 18,
1053 "%04u%02u%02u%02u%02u%02u.0Z",
1054 tm->tm_year+1900, tm->tm_mon+1,
1055 tm->tm_mday, tm->tm_hour, tm->tm_min,
1056 tm->tm_sec);
1058 if (r != 17) {
1059 talloc_free(ts);
1060 return NULL;
1063 return ts;
1067 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1069 time_t ldb_string_to_time(const char *s)
1071 struct tm tm;
1073 if (s == NULL) return 0;
1075 memset(&tm, 0, sizeof(tm));
1076 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1077 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1078 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1079 return 0;
1081 tm.tm_year -= 1900;
1082 tm.tm_mon -= 1;
1084 return timegm(&tm);
1088 convert a LDAP GeneralizedTime string in ldb_val format to a
1089 time_t.
1091 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1093 char val[15] = {};
1094 struct tm tm = {};
1096 if (v == NULL) {
1097 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1100 if (v->data == NULL) {
1101 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1104 if (v->length < 16 && v->length != 13) {
1105 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1108 if (v->data[v->length - 1] != 'Z') {
1109 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1112 if (v->length == 13) {
1113 memcpy(val, v->data, 12);
1115 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
1116 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1117 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1118 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1120 if (tm.tm_year < 50) {
1121 tm.tm_year += 100;
1123 } else {
1126 * anything between '.' and 'Z' is silently ignored.
1128 if (v->data[14] != '.') {
1129 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1132 memcpy(val, v->data, 14);
1134 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
1135 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1136 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1137 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1139 tm.tm_year -= 1900;
1141 tm.tm_mon -= 1;
1143 *t = timegm(&tm);
1145 return LDB_SUCCESS;
1149 return a LDAP formatted UTCTime string
1151 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1153 struct tm *tm = gmtime(&t);
1154 char *ts;
1155 int r;
1157 if (!tm) {
1158 return NULL;
1161 /* we now excatly how long this string will be */
1162 ts = talloc_array(mem_ctx, char, 14);
1164 /* formatted like: 20040408072012.0Z => 040408072012Z */
1165 r = snprintf(ts, 14,
1166 "%02u%02u%02u%02u%02u%02uZ",
1167 (tm->tm_year+1900)%100, tm->tm_mon+1,
1168 tm->tm_mday, tm->tm_hour, tm->tm_min,
1169 tm->tm_sec);
1171 if (r != 13) {
1172 talloc_free(ts);
1173 return NULL;
1176 return ts;
1180 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1182 time_t ldb_string_utc_to_time(const char *s)
1184 struct tm tm;
1186 if (s == NULL) return 0;
1188 memset(&tm, 0, sizeof(tm));
1189 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1190 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1191 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1192 return 0;
1194 if (tm.tm_year < 50) {
1195 tm.tm_year += 100;
1197 tm.tm_mon -= 1;
1199 return timegm(&tm);
1204 dump a set of results to a file. Useful from within gdb
1206 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1208 unsigned int i;
1210 for (i = 0; i < result->count; i++) {
1211 struct ldb_ldif ldif;
1212 fprintf(f, "# record %d\n", i+1);
1213 ldif.changetype = LDB_CHANGETYPE_NONE;
1214 ldif.msg = result->msgs[i];
1215 ldb_ldif_write_file(ldb, f, &ldif);
1220 checks for a string attribute. Returns "1" on match and otherwise "0".
1222 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1223 const char *name, const char *value)
1225 struct ldb_message_element *el;
1226 struct ldb_val val;
1228 el = ldb_msg_find_element(msg, name);
1229 if (el == NULL) {
1230 return 0;
1233 val.data = discard_const_p(uint8_t, value);
1234 val.length = strlen(value);
1236 if (ldb_msg_find_val(el, &val)) {
1237 return 1;
1240 return 0;
1245 compare a ldb_val to a string
1247 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1249 size_t len = strlen(str);
1250 if (len != v->length) {
1251 return len - v->length;
1253 return strncmp((const char *)v->data, str, len);