drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / lib / ldb / common / ldb_msg.c
blob8477ab2b00be68d1e5972f5c65541bf75ab53939
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 mismatch
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 static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
95 if (v1->length != v2->length) {
96 return NUMERIC_CMP(v1->length, v2->length);
98 return memcmp(v1->data, v2->data, v1->length);
103 ldb_msg_find_duplicate_val() will set the **duplicate pointer to the first
104 duplicate value it finds. It does a case sensitive comparison (memcmp).
106 LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown
107 options flag, otherwise LDB_SUCCESS.
109 #define LDB_DUP_QUADRATIC_THRESHOLD 10
111 int ldb_msg_find_duplicate_val(struct ldb_context *ldb,
112 TALLOC_CTX *mem_ctx,
113 const struct ldb_message_element *el,
114 struct ldb_val **duplicate,
115 uint32_t options)
117 unsigned int i, j;
118 struct ldb_val *val;
120 if (options != 0) {
121 return LDB_ERR_OPERATIONS_ERROR;
124 *duplicate = NULL;
127 If there are not many values, it is best to avoid the talloc
128 overhead and just do a brute force search.
130 if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) {
131 for (j = 0; j < el->num_values; j++) {
132 val = &el->values[j];
133 for ( i = j + 1; i < el->num_values; i++) {
134 if (ldb_val_equal_exact(val, &el->values[i])) {
135 *duplicate = val;
136 return LDB_SUCCESS;
140 } else {
141 struct ldb_val *values;
142 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
143 if (values == NULL) {
144 return LDB_ERR_OPERATIONS_ERROR;
147 memcpy(values, el->values,
148 el->num_values * sizeof(struct ldb_val));
149 TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
150 for (i = 1; i < el->num_values; i++) {
151 if (ldb_val_equal_exact(&values[i],
152 &values[i - 1])) {
153 /* find the original location */
154 for (j = 0; j < el->num_values; j++) {
155 if (ldb_val_equal_exact(&values[i],
156 &el->values[j])
158 *duplicate = &el->values[j];
159 break;
162 talloc_free(values);
163 if (*duplicate == NULL) {
164 /* how we got here, I don't know */
165 return LDB_ERR_OPERATIONS_ERROR;
167 return LDB_SUCCESS;
170 talloc_free(values);
172 return LDB_SUCCESS;
177 Determine whether the values in an element are also in another element.
179 Without any flags, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS if the elements
180 share values, or LDB_SUCCESS if they don't. In this case, the function
181 simply determines the set intersection and it doesn't matter in which order
182 the elements are provided.
184 With the LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES flag, any values in common are
185 removed from the first element and LDB_SUCCESS is returned.
187 LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown option.
188 LDB_ERR_INAPPROPRIATE_MATCHING is returned if the elements differ in name.
191 int ldb_msg_find_common_values(struct ldb_context *ldb,
192 TALLOC_CTX *mem_ctx,
193 struct ldb_message_element *el,
194 struct ldb_message_element *el2,
195 uint32_t options)
197 struct ldb_val *values;
198 struct ldb_val *values2;
199 unsigned int i, j, k, n_values;
201 bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
203 if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
204 return LDB_ERR_OPERATIONS_ERROR;
207 if (strcmp(el->name, el2->name) != 0) {
208 return LDB_ERR_INAPPROPRIATE_MATCHING;
210 if (el->num_values == 0 || el2->num_values == 0) {
211 return LDB_SUCCESS;
214 With few values, it is better to do the brute-force search than the
215 clever search involving tallocs, memcpys, sorts, etc.
217 if (MIN(el->num_values, el2->num_values) == 1 ||
218 MAX(el->num_values, el2->num_values) < LDB_DUP_QUADRATIC_THRESHOLD) {
219 for (i = 0; i < el2->num_values; i++) {
220 for (j = 0; j < el->num_values; j++) {
221 if (ldb_val_equal_exact(&el->values[j],
222 &el2->values[i])) {
223 if (! remove_duplicates) {
224 return \
225 LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
228 With the remove_duplicates flag, we
229 resolve the intersection by removing
230 the offending one from el.
232 el->num_values--;
233 for (k = j; k < el->num_values; k++) {
234 el->values[k] = \
235 el->values[k + 1];
237 j--; /* rewind */
241 return LDB_SUCCESS;
244 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
245 if (values == NULL) {
246 return LDB_ERR_OPERATIONS_ERROR;
248 values2 = talloc_array(mem_ctx, struct ldb_val,
249 el2->num_values);
250 if (values2 == NULL) {
251 return LDB_ERR_OPERATIONS_ERROR;
254 memcpy(values, el->values,
255 el->num_values * sizeof(struct ldb_val));
256 memcpy(values2, el2->values,
257 el2->num_values * sizeof(struct ldb_val));
258 TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp);
259 TYPESAFE_QSORT(values2, el2->num_values, ldb_val_cmp);
262 el->n_values may diverge from the number of values in the sorted
263 list when the remove_duplicates flag is used.
265 n_values = el->num_values;
266 i = 0;
267 j = 0;
268 while (i != n_values && j < el2->num_values) {
269 int ret = ldb_val_cmp(&values[i], &values2[j]);
270 if (ret < 0) {
271 i++;
272 } else if (ret > 0) {
273 j++;
274 } else {
275 /* we have a collision */
276 if (! remove_duplicates) {
277 TALLOC_FREE(values);
278 TALLOC_FREE(values2);
279 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
282 With the remove_duplicates flag we need to find
283 this in the original list and remove it, which is
284 inefficient but hopefully rare.
286 for (k = 0; k < el->num_values; k++) {
287 if (ldb_val_equal_exact(&el->values[k],
288 &values[i])) {
289 break;
292 el->num_values--;
293 for (; k < el->num_values; k++) {
294 el->values[k] = el->values[k + 1];
296 i++;
299 TALLOC_FREE(values);
300 TALLOC_FREE(values2);
302 return LDB_SUCCESS;
306 duplicate a ldb_val structure
308 struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
310 struct ldb_val v2;
311 v2.length = v->length;
312 if (v->data == NULL) {
313 v2.data = NULL;
314 return v2;
317 /* the +1 is to cope with buggy C library routines like strndup
318 that look one byte beyond */
319 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
320 if (!v2.data) {
321 v2.length = 0;
322 return v2;
325 memcpy(v2.data, v->data, v->length);
326 ((char *)v2.data)[v->length] = 0;
327 return v2;
331 * Adds new empty element to msg->elements
333 static int _ldb_msg_add_el(struct ldb_message *msg,
334 struct ldb_message_element **return_el)
336 struct ldb_message_element *els;
339 * TODO: Find out a way to assert on input parameters.
340 * msg and return_el must be valid
343 els = talloc_realloc(msg, msg->elements,
344 struct ldb_message_element, msg->num_elements + 1);
345 if (!els) {
346 return LDB_ERR_OPERATIONS_ERROR;
349 els[msg->num_elements] = (struct ldb_message_element) {};
351 msg->elements = els;
352 msg->num_elements++;
354 *return_el = &els[msg->num_elements-1];
356 return LDB_SUCCESS;
360 * Add an empty element with a given name to a message
362 int ldb_msg_add_empty(struct ldb_message *msg,
363 const char *attr_name,
364 int flags,
365 struct ldb_message_element **return_el)
367 int ret;
368 struct ldb_message_element *el;
370 ret = _ldb_msg_add_el(msg, &el);
371 if (ret != LDB_SUCCESS) {
372 return ret;
375 /* initialize newly added element */
376 el->flags = flags;
377 el->name = talloc_strdup(msg->elements, attr_name);
378 if (!el->name) {
379 return LDB_ERR_OPERATIONS_ERROR;
382 if (return_el) {
383 *return_el = el;
386 return LDB_SUCCESS;
390 * Adds an element to a message.
392 * NOTE: Ownership of ldb_message_element fields
393 * is NOT transferred. Thus, if *el pointer
394 * is invalidated for some reason, this will
395 * corrupt *msg contents also
397 int ldb_msg_add(struct ldb_message *msg,
398 const struct ldb_message_element *el,
399 int flags)
401 int ret;
402 struct ldb_message_element *el_new;
403 /* We have to copy this, just in case *el is a pointer into
404 * what ldb_msg_add_empty() is about to realloc() */
405 struct ldb_message_element el_copy = *el;
407 ret = _ldb_msg_add_el(msg, &el_new);
408 if (ret != LDB_SUCCESS) {
409 return ret;
412 el_new->flags = flags;
413 el_new->name = el_copy.name;
414 el_new->num_values = el_copy.num_values;
415 el_new->values = el_copy.values;
417 return LDB_SUCCESS;
421 * add a value to a message element
423 int ldb_msg_element_add_value(TALLOC_CTX *mem_ctx,
424 struct ldb_message_element *el,
425 const struct ldb_val *val)
427 struct ldb_val *vals;
429 if (el->flags & LDB_FLAG_INTERNAL_SHARED_VALUES) {
431 * Another message is using this message element's values array,
432 * so we don't want to make any modifications to the original
433 * message, or potentially invalidate its own values by calling
434 * talloc_realloc(). Make a copy instead.
436 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
438 vals = talloc_array(mem_ctx, struct ldb_val,
439 el->num_values + 1);
440 if (vals == NULL) {
441 return LDB_ERR_OPERATIONS_ERROR;
444 if (el->values != NULL) {
445 memcpy(vals, el->values, el->num_values * sizeof(struct ldb_val));
447 } else {
448 vals = talloc_realloc(mem_ctx, el->values, struct ldb_val,
449 el->num_values + 1);
450 if (vals == NULL) {
451 return LDB_ERR_OPERATIONS_ERROR;
454 el->values = vals;
455 el->values[el->num_values] = *val;
456 el->num_values++;
458 return LDB_SUCCESS;
462 add a value to a message
464 int ldb_msg_add_value(struct ldb_message *msg,
465 const char *attr_name,
466 const struct ldb_val *val,
467 struct ldb_message_element **return_el)
469 struct ldb_message_element *el;
470 int ret;
472 el = ldb_msg_find_element(msg, attr_name);
473 if (!el) {
474 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
475 if (ret != LDB_SUCCESS) {
476 return ret;
480 ret = ldb_msg_element_add_value(msg->elements, el, val);
481 if (ret != LDB_SUCCESS) {
482 return ret;
485 if (return_el) {
486 *return_el = el;
489 return LDB_SUCCESS;
494 add a value to a message, stealing it into the 'right' place
496 int ldb_msg_add_steal_value(struct ldb_message *msg,
497 const char *attr_name,
498 struct ldb_val *val)
500 int ret;
501 struct ldb_message_element *el;
503 ret = ldb_msg_add_value(msg, attr_name, val, &el);
504 if (ret == LDB_SUCCESS) {
505 talloc_steal(el->values, val->data);
507 return ret;
512 add a string element to a message, specifying flags
514 int ldb_msg_add_string_flags(struct ldb_message *msg,
515 const char *attr_name, const char *str,
516 int flags)
518 struct ldb_val val;
519 int ret;
520 struct ldb_message_element *el = NULL;
522 val.data = discard_const_p(uint8_t, str);
523 val.length = strlen(str);
525 if (val.length == 0) {
526 /* allow empty strings as non-existent attributes */
527 return LDB_SUCCESS;
530 ret = ldb_msg_add_value(msg, attr_name, &val, &el);
531 if (ret != LDB_SUCCESS) {
532 return ret;
535 if (flags != 0) {
536 el->flags = flags;
539 return LDB_SUCCESS;
543 add a string element to a message
545 int ldb_msg_add_string(struct ldb_message *msg,
546 const char *attr_name, const char *str)
548 return ldb_msg_add_string_flags(msg, attr_name, str, 0);
552 add a string element to a message, stealing it into the 'right' place
554 int ldb_msg_add_steal_string(struct ldb_message *msg,
555 const char *attr_name, char *str)
557 struct ldb_val val;
559 val.data = (uint8_t *)str;
560 val.length = strlen(str);
562 if (val.length == 0) {
563 /* allow empty strings as non-existent attributes */
564 return LDB_SUCCESS;
567 return ldb_msg_add_steal_value(msg, attr_name, &val);
571 add a DN element to a message
573 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
574 struct ldb_dn *dn)
576 char *str = ldb_dn_alloc_linearized(msg, dn);
578 if (str == NULL) {
579 /* we don't want to have unknown DNs added */
580 return LDB_ERR_OPERATIONS_ERROR;
583 return ldb_msg_add_steal_string(msg, attr_name, str);
587 add a printf formatted element to a message
589 int ldb_msg_add_fmt(struct ldb_message *msg,
590 const char *attr_name, const char *fmt, ...)
592 struct ldb_val val;
593 va_list ap;
594 char *str;
596 va_start(ap, fmt);
597 str = talloc_vasprintf(msg, fmt, ap);
598 va_end(ap);
600 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
602 val.data = (uint8_t *)str;
603 val.length = strlen(str);
605 return ldb_msg_add_steal_value(msg, attr_name, &val);
608 static int ldb_msg_append_value_impl(struct ldb_message *msg,
609 const char *attr_name,
610 const struct ldb_val *val,
611 int flags,
612 struct ldb_message_element **return_el)
614 struct ldb_message_element *el = NULL;
615 int ret;
617 ret = ldb_msg_add_empty(msg, attr_name, flags, &el);
618 if (ret != LDB_SUCCESS) {
619 return ret;
622 ret = ldb_msg_element_add_value(msg->elements, el, val);
623 if (ret != LDB_SUCCESS) {
624 return ret;
627 if (return_el != NULL) {
628 *return_el = el;
631 return LDB_SUCCESS;
635 append a value to a message
637 int ldb_msg_append_value(struct ldb_message *msg,
638 const char *attr_name,
639 const struct ldb_val *val,
640 int flags)
642 return ldb_msg_append_value_impl(msg, attr_name, val, flags, NULL);
646 append a value to a message, stealing it into the 'right' place
648 int ldb_msg_append_steal_value(struct ldb_message *msg,
649 const char *attr_name,
650 struct ldb_val *val,
651 int flags)
653 int ret;
654 struct ldb_message_element *el = NULL;
656 ret = ldb_msg_append_value_impl(msg, attr_name, val, flags, &el);
657 if (ret == LDB_SUCCESS) {
658 talloc_steal(el->values, val->data);
660 return ret;
664 append a string element to a message, stealing it into the 'right' place
666 int ldb_msg_append_steal_string(struct ldb_message *msg,
667 const char *attr_name, char *str,
668 int flags)
670 struct ldb_val val;
672 val.data = (uint8_t *)str;
673 val.length = strlen(str);
675 if (val.length == 0) {
676 /* allow empty strings as non-existent attributes */
677 return LDB_SUCCESS;
680 return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
684 append a string element to a message
686 int ldb_msg_append_string(struct ldb_message *msg,
687 const char *attr_name, const char *str, int flags)
689 struct ldb_val val;
691 val.data = discard_const_p(uint8_t, str);
692 val.length = strlen(str);
694 if (val.length == 0) {
695 /* allow empty strings as non-existent attributes */
696 return LDB_SUCCESS;
699 return ldb_msg_append_value(msg, attr_name, &val, flags);
703 append a DN element to a message
705 int ldb_msg_append_linearized_dn(struct ldb_message *msg, const char *attr_name,
706 struct ldb_dn *dn, int flags)
708 char *str = ldb_dn_alloc_linearized(msg, dn);
710 if (str == NULL) {
711 /* we don't want to have unknown DNs added */
712 return LDB_ERR_OPERATIONS_ERROR;
715 return ldb_msg_append_steal_string(msg, attr_name, str, flags);
719 append a printf formatted element to a message
721 int ldb_msg_append_fmt(struct ldb_message *msg, int flags,
722 const char *attr_name, const char *fmt, ...)
724 struct ldb_val val;
725 va_list ap;
726 char *str = NULL;
728 va_start(ap, fmt);
729 str = talloc_vasprintf(msg, fmt, ap);
730 va_end(ap);
732 if (str == NULL) {
733 return LDB_ERR_OPERATIONS_ERROR;
736 val.data = (uint8_t *)str;
737 val.length = strlen(str);
739 return ldb_msg_append_steal_value(msg, attr_name, &val, flags);
743 compare two ldb_message_element structures
744 assumes case sensitive comparison
746 int ldb_msg_element_compare(struct ldb_message_element *el1,
747 struct ldb_message_element *el2)
749 unsigned int i;
751 if (el1->num_values != el2->num_values) {
752 return NUMERIC_CMP(el1->num_values, el2->num_values);
755 * Note this is an inconsistent comparison, unsuitable for
756 * sorting. If A has values {a, b} and B has values {b, c},
757 * then
759 * ldb_msg_element_compare(A, B) returns -1, meaning A < B
760 * ldb_msg_element_compare(B, A) returns -1, meaning B < A
762 for (i=0;i<el1->num_values;i++) {
763 if (!ldb_msg_find_val(el2, &el1->values[i])) {
764 return -1;
768 return 0;
772 compare two ldb_message_element structures.
773 Different ordering is considered a mismatch
775 bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
776 const struct ldb_message_element *el2)
778 unsigned i;
779 if (el1->num_values != el2->num_values) {
780 return false;
782 for (i=0;i<el1->num_values;i++) {
783 if (ldb_val_equal_exact(&el1->values[i],
784 &el2->values[i]) != 1) {
785 return false;
788 return true;
792 compare two ldb_message_element structures
793 comparing by element name
795 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
796 struct ldb_message_element *el2)
798 if (el1->name == el2->name) {
799 return 0;
802 if (el1->name == NULL) {
803 return -1;
806 if (el2->name == NULL) {
807 return 1;
810 return ldb_attr_cmp(el1->name, el2->name);
813 void ldb_msg_element_mark_inaccessible(struct ldb_message_element *el)
815 el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
818 bool ldb_msg_element_is_inaccessible(const struct ldb_message_element *el)
820 return (el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE) != 0;
823 void ldb_msg_remove_inaccessible(struct ldb_message *msg)
825 unsigned i;
826 unsigned num_del = 0;
828 for (i = 0; i < msg->num_elements; ++i) {
829 if (ldb_msg_element_is_inaccessible(&msg->elements[i])) {
830 ++num_del;
831 } else if (num_del) {
832 msg->elements[i - num_del] = msg->elements[i];
836 msg->num_elements -= num_del;
840 convenience functions to return common types from a message
841 these return the first value if the attribute is multi-valued
843 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
844 const char *attr_name)
846 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
847 if (!el || el->num_values == 0) {
848 return NULL;
850 return &el->values[0];
853 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
854 const char *attr_name,
855 int default_value)
857 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
858 char buf[sizeof("-2147483648")] = {};
859 char *end = NULL;
860 int ret;
862 if (!v || !v->data) {
863 return default_value;
866 if (v->length >= sizeof(buf)) {
867 return default_value;
870 memcpy(buf, v->data, v->length);
871 errno = 0;
872 ret = (int) strtoll(buf, &end, 10);
873 if (errno != 0) {
874 return default_value;
876 if (end && end[0] != '\0') {
877 return default_value;
879 return ret;
882 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
883 const char *attr_name,
884 unsigned int default_value)
886 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
887 char buf[sizeof("-2147483648")] = {};
888 char *end = NULL;
889 unsigned int ret;
891 if (!v || !v->data) {
892 return default_value;
895 if (v->length >= sizeof(buf)) {
896 return default_value;
899 memcpy(buf, v->data, v->length);
900 errno = 0;
901 ret = (unsigned int) strtoll(buf, &end, 10);
902 if (errno != 0) {
903 errno = 0;
904 ret = (unsigned int) strtoull(buf, &end, 10);
905 if (errno != 0) {
906 return default_value;
909 if (end && end[0] != '\0') {
910 return default_value;
912 return ret;
915 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
916 const char *attr_name,
917 int64_t default_value)
919 int64_t val = 0;
920 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
921 int ret = ldb_val_as_int64(v, &val);
922 return ret ? default_value : val;
925 int ldb_val_as_int64(const struct ldb_val *v, int64_t *val)
927 char buf[sizeof("-9223372036854775808")] = {};
928 char *end = NULL;
929 int64_t result;
931 if (!v || !v->data) {
932 return LDB_ERR_OPERATIONS_ERROR;
935 if (v->length >= sizeof(buf)) {
936 return LDB_ERR_OPERATIONS_ERROR;
939 memcpy(buf, v->data, v->length);
940 errno = 0;
941 result = (int64_t) strtoll(buf, &end, 10);
942 if (errno != 0) {
943 return LDB_ERR_OPERATIONS_ERROR;
945 if (end && end[0] != '\0') {
946 return LDB_ERR_OPERATIONS_ERROR;
949 *val = result;
950 return LDB_SUCCESS;
953 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
954 const char *attr_name,
955 uint64_t default_value)
957 uint64_t val = 0;
958 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
959 int ret = ldb_val_as_uint64(v, &val);
960 return ret ? default_value : val;
963 int ldb_val_as_uint64(const struct ldb_val *v, uint64_t *val)
965 char buf[sizeof("-9223372036854775808")] = {};
966 char *end = NULL;
967 uint64_t result;
969 if (!v || !v->data) {
970 return LDB_ERR_OPERATIONS_ERROR;
973 if (v->length >= sizeof(buf)) {
974 return LDB_ERR_OPERATIONS_ERROR;
977 memcpy(buf, v->data, v->length);
978 errno = 0;
979 result = (uint64_t) strtoll(buf, &end, 10);
980 if (errno != 0) {
981 errno = 0;
982 result = (uint64_t) strtoull(buf, &end, 10);
983 if (errno != 0) {
984 return LDB_ERR_OPERATIONS_ERROR;
987 if (end && end[0] != '\0') {
988 return LDB_ERR_OPERATIONS_ERROR;
991 *val = result;
992 return LDB_SUCCESS;
995 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
996 const char *attr_name,
997 double default_value)
999 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
1000 char *buf;
1001 char *end = NULL;
1002 double ret;
1004 if (!v || !v->data) {
1005 return default_value;
1007 buf = talloc_strndup(msg, (const char *)v->data, v->length);
1008 if (buf == NULL) {
1009 return default_value;
1012 errno = 0;
1013 ret = strtod(buf, &end);
1014 talloc_free(buf);
1015 if (errno != 0) {
1016 return default_value;
1018 if (end && end[0] != '\0') {
1019 return default_value;
1021 return ret;
1024 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
1025 const char *attr_name,
1026 int default_value)
1028 bool val = false;
1029 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
1030 int ret = ldb_val_as_bool(v, &val);
1031 return ret ? default_value : val;
1034 int ldb_val_as_bool(const struct ldb_val *v, bool *val)
1036 if (!v || !v->data) {
1037 return LDB_ERR_OPERATIONS_ERROR;
1039 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
1040 *val = false;
1041 return LDB_SUCCESS;
1043 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
1044 *val = true;
1045 return LDB_SUCCESS;
1047 return LDB_ERR_OPERATIONS_ERROR;
1050 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
1051 const char *attr_name,
1052 const char *default_value)
1054 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
1055 if (!v || !v->data) {
1056 return default_value;
1058 if (v->data[v->length] != '\0') {
1059 return default_value;
1061 return (const char *)v->data;
1064 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
1065 TALLOC_CTX *mem_ctx,
1066 const struct ldb_message *msg,
1067 const char *attr_name)
1069 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
1070 return ldb_val_as_dn(ldb, mem_ctx, v);
1073 struct ldb_dn *ldb_val_as_dn(struct ldb_context *ldb,
1074 TALLOC_CTX *mem_ctx,
1075 const struct ldb_val *v)
1077 struct ldb_dn *res_dn;
1079 if (!v || !v->data) {
1080 return NULL;
1082 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
1083 if ( ! ldb_dn_validate(res_dn)) {
1084 talloc_free(res_dn);
1085 return NULL;
1087 return res_dn;
1091 sort the elements of a message by name
1093 void ldb_msg_sort_elements(struct ldb_message *msg)
1095 TYPESAFE_QSORT(msg->elements, msg->num_elements,
1096 ldb_msg_element_compare_name);
1099 static struct ldb_message *ldb_msg_copy_shallow_impl(TALLOC_CTX *mem_ctx,
1100 const struct ldb_message *msg)
1102 struct ldb_message *msg2;
1103 unsigned int i;
1105 msg2 = talloc(mem_ctx, struct ldb_message);
1106 if (msg2 == NULL) return NULL;
1108 *msg2 = *msg;
1110 msg2->elements = talloc_array(msg2, struct ldb_message_element,
1111 msg2->num_elements);
1112 if (msg2->elements == NULL) goto failed;
1114 for (i=0;i<msg2->num_elements;i++) {
1115 msg2->elements[i] = msg->elements[i];
1118 return msg2;
1120 failed:
1121 talloc_free(msg2);
1122 return NULL;
1126 shallow copy a message - copying only the elements array so that the caller
1127 can safely add new elements without changing the message
1129 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
1130 const struct ldb_message *msg)
1132 struct ldb_message *msg2;
1133 unsigned int i;
1135 msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
1136 if (msg2 == NULL) {
1137 return NULL;
1140 for (i = 0; i < msg2->num_elements; ++i) {
1142 * Mark this message's elements as sharing their values with the
1143 * original message, so that we don't inadvertently modify or
1144 * free them. We don't mark the original message element as
1145 * shared, so the original message element should not be
1146 * modified or freed while the shallow copy lives.
1148 struct ldb_message_element *el = &msg2->elements[i];
1149 el->flags |= LDB_FLAG_INTERNAL_SHARED_VALUES;
1152 return msg2;
1156 copy a message, allocating new memory for all parts
1158 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
1159 const struct ldb_message *msg)
1161 struct ldb_message *msg2;
1162 unsigned int i, j;
1164 msg2 = ldb_msg_copy_shallow_impl(mem_ctx, msg);
1165 if (msg2 == NULL) return NULL;
1167 if (msg2->dn != NULL) {
1168 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
1169 if (msg2->dn == NULL) goto failed;
1172 for (i=0;i<msg2->num_elements;i++) {
1173 struct ldb_message_element *el = &msg2->elements[i];
1174 struct ldb_val *values = el->values;
1175 if (el->name != NULL) {
1176 el->name = talloc_strdup(msg2->elements, el->name);
1177 if (el->name == NULL) goto failed;
1179 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
1180 if (el->values == NULL) goto failed;
1181 for (j=0;j<el->num_values;j++) {
1182 el->values[j] = ldb_val_dup(el->values, &values[j]);
1183 if (el->values[j].data == NULL && values[j].length != 0) {
1184 goto failed;
1189 * Since we copied this element's values, we can mark them as
1190 * not shared.
1192 el->flags &= ~LDB_FLAG_INTERNAL_SHARED_VALUES;
1195 return msg2;
1197 failed:
1198 talloc_free(msg2);
1199 return NULL;
1204 * Canonicalize a message, merging elements of the same name
1206 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
1207 const struct ldb_message *msg)
1209 int ret;
1210 struct ldb_message *msg2;
1213 * Preserve previous behavior and allocate
1214 * *msg2 into *ldb context
1216 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
1217 if (ret != LDB_SUCCESS) {
1218 return NULL;
1221 return msg2;
1225 * Canonicalize a message, merging elements of the same name
1227 int ldb_msg_normalize(struct ldb_context *ldb,
1228 TALLOC_CTX *mem_ctx,
1229 const struct ldb_message *msg,
1230 struct ldb_message **_msg_out)
1232 unsigned int i;
1233 struct ldb_message *msg2;
1235 msg2 = ldb_msg_copy(mem_ctx, msg);
1236 if (msg2 == NULL) {
1237 return LDB_ERR_OPERATIONS_ERROR;
1240 ldb_msg_sort_elements(msg2);
1242 for (i=1; i < msg2->num_elements; i++) {
1243 struct ldb_message_element *el1 = &msg2->elements[i-1];
1244 struct ldb_message_element *el2 = &msg2->elements[i];
1246 if (ldb_msg_element_compare_name(el1, el2) == 0) {
1247 el1->values = talloc_realloc(msg2->elements,
1248 el1->values, struct ldb_val,
1249 el1->num_values + el2->num_values);
1250 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
1251 talloc_free(msg2);
1252 return LDB_ERR_OPERATIONS_ERROR;
1254 memcpy(el1->values + el1->num_values,
1255 el2->values,
1256 sizeof(struct ldb_val) * el2->num_values);
1257 el1->num_values += el2->num_values;
1258 talloc_free(discard_const_p(char, el2->name));
1259 if ((i + 1 > i) && ((i + 1) < msg2->num_elements)) {
1260 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
1261 (msg2->num_elements - (i+1)));
1263 msg2->num_elements--;
1264 i--;
1268 *_msg_out = msg2;
1269 return LDB_SUCCESS;
1274 * return a ldb_message representing the differences between msg1 and msg2.
1275 * If you then use this in a ldb_modify() call,
1276 * it can be used to save edits to a message
1278 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
1279 struct ldb_message *msg1,
1280 struct ldb_message *msg2)
1282 int ldb_ret;
1283 struct ldb_message *mod;
1285 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
1286 if (ldb_ret != LDB_SUCCESS) {
1287 return NULL;
1290 return mod;
1294 * return a ldb_message representing the differences between msg1 and msg2.
1295 * If you then use this in a ldb_modify() call it can be used to save edits to a message
1297 * Result message is constructed as follows:
1298 * - LDB_FLAG_MOD_ADD - elements found only in msg2
1299 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
1300 * Value for msg2 element is used
1301 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
1303 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
1305 int ldb_msg_difference(struct ldb_context *ldb,
1306 TALLOC_CTX *mem_ctx,
1307 struct ldb_message *msg1,
1308 struct ldb_message *msg2,
1309 struct ldb_message **_msg_out)
1311 int ldb_res;
1312 unsigned int i;
1313 struct ldb_message *mod;
1314 struct ldb_message_element *el;
1315 TALLOC_CTX *temp_ctx;
1317 temp_ctx = talloc_new(mem_ctx);
1318 if (!temp_ctx) {
1319 return LDB_ERR_OPERATIONS_ERROR;
1322 mod = ldb_msg_new(temp_ctx);
1323 if (mod == NULL) {
1324 goto failed;
1327 mod->dn = msg1->dn;
1328 mod->num_elements = 0;
1329 mod->elements = NULL;
1332 * Canonicalize *msg2 so we have no repeated elements
1333 * Resulting message is allocated in *mod's mem context,
1334 * as we are going to move some elements from *msg2 to
1335 * *mod object later
1337 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
1338 if (ldb_res != LDB_SUCCESS) {
1339 goto failed;
1342 /* look in msg2 to find elements that need to be added or modified */
1343 for (i=0;i<msg2->num_elements;i++) {
1344 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
1346 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
1347 continue;
1350 ldb_res = ldb_msg_add(mod,
1351 &msg2->elements[i],
1352 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
1353 if (ldb_res != LDB_SUCCESS) {
1354 goto failed;
1358 /* look in msg1 to find elements that need to be deleted */
1359 for (i=0;i<msg1->num_elements;i++) {
1360 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
1361 if (el == NULL) {
1362 ldb_res = ldb_msg_add_empty(mod,
1363 msg1->elements[i].name,
1364 LDB_FLAG_MOD_DELETE, NULL);
1365 if (ldb_res != LDB_SUCCESS) {
1366 goto failed;
1371 /* steal resulting message into supplied context */
1372 talloc_steal(mem_ctx, mod);
1373 *_msg_out = mod;
1375 talloc_free(temp_ctx);
1376 return LDB_SUCCESS;
1378 failed:
1379 talloc_free(temp_ctx);
1380 return LDB_ERR_OPERATIONS_ERROR;
1384 int ldb_msg_sanity_check(struct ldb_context *ldb,
1385 const struct ldb_message *msg)
1387 unsigned int i, j;
1389 /* basic check on DN */
1390 if (msg->dn == NULL) {
1391 ldb_set_errstring(ldb, "ldb message lacks a DN!");
1392 return LDB_ERR_INVALID_DN_SYNTAX;
1395 /* basic syntax checks */
1396 for (i = 0; i < msg->num_elements; i++) {
1397 for (j = 0; j < msg->elements[i].num_values; j++) {
1398 if (msg->elements[i].values[j].length == 0) {
1399 /* an attribute cannot be empty */
1400 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
1401 msg->elements[i].name,
1402 ldb_dn_get_linearized(msg->dn));
1403 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1408 return LDB_SUCCESS;
1415 copy an attribute list. This only copies the array, not the elements
1416 (ie. the elements are left as the same pointers)
1418 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
1420 const char **ret;
1421 unsigned int i;
1423 for (i=0;attrs && attrs[i];i++) /* noop */ ;
1424 ret = talloc_array(mem_ctx, const char *, i+1);
1425 if (ret == NULL) {
1426 return NULL;
1428 for (i=0;attrs && attrs[i];i++) {
1429 ret[i] = attrs[i];
1431 ret[i] = attrs[i];
1432 return ret;
1437 copy an attribute list. This only copies the array, not the elements
1438 (ie. the elements are left as the same pointers). The new attribute is added to the list.
1440 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
1442 const char **ret;
1443 unsigned int i;
1444 bool found = false;
1446 for (i=0;attrs && attrs[i];i++) {
1447 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
1448 found = true;
1451 if (found) {
1452 return ldb_attr_list_copy(mem_ctx, attrs);
1454 ret = talloc_array(mem_ctx, const char *, i+2);
1455 if (ret == NULL) {
1456 return NULL;
1458 for (i=0;attrs && attrs[i];i++) {
1459 ret[i] = attrs[i];
1461 ret[i] = new_attr;
1462 ret[i+1] = NULL;
1463 return ret;
1468 return 1 if an attribute is in a list of attributes, or 0 otherwise
1470 int ldb_attr_in_list(const char * const *attrs, const char *attr)
1472 unsigned int i;
1473 for (i=0;attrs && attrs[i];i++) {
1474 if (ldb_attr_cmp(attrs[i], attr) == 0) {
1475 return 1;
1478 return 0;
1483 rename the specified attribute in a search result
1485 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
1487 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1488 if (el == NULL) {
1489 return LDB_SUCCESS;
1491 el->name = talloc_strdup(msg->elements, replace);
1492 if (el->name == NULL) {
1493 return LDB_ERR_OPERATIONS_ERROR;
1495 return LDB_SUCCESS;
1500 copy the specified attribute in a search result to a new attribute
1502 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
1504 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1505 int ret;
1507 if (el == NULL) {
1508 return LDB_SUCCESS;
1510 ret = ldb_msg_add(msg, el, 0);
1511 if (ret != LDB_SUCCESS) {
1512 return ret;
1514 return ldb_msg_rename_attr(msg, attr, replace);
1518 remove the specified element in a search result
1520 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
1522 ptrdiff_t n = (el - msg->elements);
1523 if (n >= msg->num_elements || n < 0) {
1524 /* the element is not in the list. the caller is crazy. */
1525 return;
1527 msg->num_elements--;
1528 if (n != msg->num_elements) {
1529 memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
1535 remove the specified attribute in a search result
1537 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1539 unsigned int i;
1540 unsigned int num_del = 0;
1542 for (i = 0; i < msg->num_elements; ++i) {
1543 if (ldb_attr_cmp(msg->elements[i].name, attr) == 0) {
1544 ++num_del;
1545 } else if (num_del) {
1546 msg->elements[i - num_del] = msg->elements[i];
1550 msg->num_elements -= num_del;
1553 /* Reallocate elements to drop any excess capacity. */
1554 void ldb_msg_shrink_to_fit(struct ldb_message *msg)
1556 if (msg->num_elements > 0) {
1557 struct ldb_message_element *elements = talloc_realloc(msg,
1558 msg->elements,
1559 struct ldb_message_element,
1560 msg->num_elements);
1561 if (elements != NULL) {
1562 msg->elements = elements;
1564 } else {
1565 TALLOC_FREE(msg->elements);
1570 return a LDAP formatted GeneralizedTime string
1572 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1574 struct tm *tm = gmtime(&t);
1575 char *ts;
1576 int r;
1578 if (!tm) {
1579 return NULL;
1582 /* we know exactly how long this string will be */
1583 ts = talloc_array(mem_ctx, char, 18);
1585 /* formatted like: 20040408072012.0Z */
1586 r = snprintf(ts, 18,
1587 "%04u%02u%02u%02u%02u%02u.0Z",
1588 tm->tm_year+1900, tm->tm_mon+1,
1589 tm->tm_mday, tm->tm_hour, tm->tm_min,
1590 tm->tm_sec);
1592 if (r != 17) {
1593 talloc_free(ts);
1594 errno = EOVERFLOW;
1595 return NULL;
1598 return ts;
1602 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1604 time_t ldb_string_to_time(const char *s)
1606 struct tm tm;
1607 time_t t;
1609 if (s == NULL) return 0;
1611 memset(&tm, 0, sizeof(tm));
1612 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1613 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1614 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1615 return 0;
1617 tm.tm_year -= 1900;
1618 tm.tm_mon -= 1;
1620 t = timegm(&tm);
1622 if (t == (time_t)-1 && errno != 0) {
1624 * timegm() returns -1 on error, but also for '19691231235959.0Z'.
1626 return 0;
1628 return t;
1632 convert a LDAP GeneralizedTime string in ldb_val format to a
1633 time_t.
1635 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1637 char val[15] = {0};
1638 struct tm tm = {
1639 .tm_year = 0,
1642 if (v == NULL) {
1643 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1646 if (v->data == NULL) {
1647 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1650 if (v->length < 16 && v->length != 13) {
1651 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1654 if (v->data[v->length - 1] != 'Z') {
1655 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1658 if (v->length == 13) {
1659 memcpy(val, v->data, 12);
1661 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
1662 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1663 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1664 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1666 if (tm.tm_year < 50) {
1667 tm.tm_year += 100;
1669 } else {
1672 * anything between '.' and 'Z' is silently ignored.
1674 if (v->data[14] != '.') {
1675 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1678 memcpy(val, v->data, 14);
1680 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
1681 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1682 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1683 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1685 tm.tm_year -= 1900;
1687 tm.tm_mon -= 1;
1689 *t = timegm(&tm);
1691 return LDB_SUCCESS;
1695 return a LDAP formatted UTCTime string
1697 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1699 struct tm *tm = gmtime(&t);
1700 char *ts;
1701 int r;
1703 if (!tm) {
1704 return NULL;
1707 /* we know exactly how long this string will be */
1708 ts = talloc_array(mem_ctx, char, 14);
1710 /* formatted like: 20040408072012.0Z => 040408072012Z */
1711 r = snprintf(ts, 14,
1712 "%02u%02u%02u%02u%02u%02uZ",
1713 (tm->tm_year+1900)%100, tm->tm_mon+1,
1714 tm->tm_mday, tm->tm_hour, tm->tm_min,
1715 tm->tm_sec);
1717 if (r != 13) {
1718 talloc_free(ts);
1719 return NULL;
1722 return ts;
1726 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1728 time_t ldb_string_utc_to_time(const char *s)
1730 struct tm tm;
1732 if (s == NULL) return 0;
1734 memset(&tm, 0, sizeof(tm));
1735 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1736 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1737 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1738 return 0;
1740 if (tm.tm_year < 50) {
1741 tm.tm_year += 100;
1743 tm.tm_mon -= 1;
1745 return timegm(&tm);
1750 dump a set of results to a file. Useful from within gdb
1752 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1754 unsigned int i;
1756 for (i = 0; i < result->count; i++) {
1757 struct ldb_ldif ldif;
1758 fprintf(f, "# record %d\n", i+1);
1759 ldif.changetype = LDB_CHANGETYPE_NONE;
1760 ldif.msg = result->msgs[i];
1761 ldb_ldif_write_file(ldb, f, &ldif);
1766 checks for a string attribute. Returns "1" on match and otherwise "0".
1768 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1769 const char *name, const char *value)
1771 struct ldb_message_element *el;
1772 struct ldb_val val;
1774 el = ldb_msg_find_element(msg, name);
1775 if (el == NULL) {
1776 return 0;
1779 val.data = discard_const_p(uint8_t, value);
1780 val.length = strlen(value);
1782 if (ldb_msg_find_val(el, &val)) {
1783 return 1;
1786 return 0;
1791 compare a ldb_val to a string
1793 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1795 size_t len = strlen(str);
1796 if (len != v->length) {
1797 return len - v->length;
1799 return strncmp((const char *)v->data, str, len);