added new function "ldb_msg_add_dn"
[Samba/cd1.git] / source4 / lib / ldb / common / ldb_msg.c
blob375751262f56e31fa4f9521ba146720473d4dbc3
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(void *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(void *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 add an empty element to a message
120 int ldb_msg_add_empty( struct ldb_message *msg,
121 const char *attr_name,
122 int flags,
123 struct ldb_message_element **return_el)
125 struct ldb_message_element *els;
127 els = talloc_realloc(msg, msg->elements,
128 struct ldb_message_element, msg->num_elements+1);
129 if (!els) {
130 errno = ENOMEM;
131 return LDB_ERR_OPERATIONS_ERROR;
134 els[msg->num_elements].values = NULL;
135 els[msg->num_elements].num_values = 0;
136 els[msg->num_elements].flags = flags;
137 els[msg->num_elements].name = talloc_strdup(els, attr_name);
138 if (!els[msg->num_elements].name) {
139 errno = ENOMEM;
140 return LDB_ERR_OPERATIONS_ERROR;
143 msg->elements = els;
144 msg->num_elements++;
146 if (return_el) {
147 *return_el = &els[msg->num_elements-1];
150 return LDB_SUCCESS;
154 add an empty element to a message
156 int ldb_msg_add(struct ldb_message *msg,
157 const struct ldb_message_element *el,
158 int flags)
160 /* We have to copy this, just in case *el is a pointer into
161 * what ldb_msg_add_empty() is about to realloc() */
162 struct ldb_message_element el_copy = *el;
163 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
164 return LDB_ERR_OPERATIONS_ERROR;
167 msg->elements[msg->num_elements-1] = el_copy;
168 msg->elements[msg->num_elements-1].flags = flags;
170 return LDB_SUCCESS;
174 add a value to a message
176 int ldb_msg_add_value(struct ldb_message *msg,
177 const char *attr_name,
178 const struct ldb_val *val,
179 struct ldb_message_element **return_el)
181 struct ldb_message_element *el;
182 struct ldb_val *vals;
183 int ret;
185 el = ldb_msg_find_element(msg, attr_name);
186 if (!el) {
187 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
188 if (ret != LDB_SUCCESS) {
189 return ret;
193 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
194 if (!vals) {
195 errno = ENOMEM;
196 return LDB_ERR_OPERATIONS_ERROR;
198 el->values = vals;
199 el->values[el->num_values] = *val;
200 el->num_values++;
202 if (return_el) {
203 *return_el = el;
206 return LDB_SUCCESS;
211 add a value to a message, stealing it into the 'right' place
213 int ldb_msg_add_steal_value(struct ldb_message *msg,
214 const char *attr_name,
215 struct ldb_val *val)
217 int ret;
218 struct ldb_message_element *el;
220 ret = ldb_msg_add_value(msg, attr_name, val, &el);
221 if (ret == LDB_SUCCESS) {
222 talloc_steal(el->values, val->data);
224 return ret;
229 add a string element to a message
231 int ldb_msg_add_string(struct ldb_message *msg,
232 const char *attr_name, const char *str)
234 struct ldb_val val;
236 val.data = discard_const_p(uint8_t, str);
237 val.length = strlen(str);
239 if (val.length == 0) {
240 /* allow empty strings as non-existant attributes */
241 return LDB_SUCCESS;
244 return ldb_msg_add_value(msg, attr_name, &val, NULL);
248 add a string element to a message, stealing it into the 'right' place
250 int ldb_msg_add_steal_string(struct ldb_message *msg,
251 const char *attr_name, char *str)
253 struct ldb_val val;
255 val.data = (uint8_t *)str;
256 val.length = strlen(str);
258 return ldb_msg_add_steal_value(msg, attr_name, &val);
262 add a DN element to a message
264 int ldb_msg_add_dn(struct ldb_message *msg, const char *attr_name,
265 struct ldb_dn *dn)
267 return ldb_msg_add_string(msg, attr_name, ldb_dn_get_linearized(dn));
271 add a printf formatted element to a message
273 int ldb_msg_add_fmt(struct ldb_message *msg,
274 const char *attr_name, const char *fmt, ...)
276 struct ldb_val val;
277 va_list ap;
278 char *str;
280 va_start(ap, fmt);
281 str = talloc_vasprintf(msg, fmt, ap);
282 va_end(ap);
284 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
286 val.data = (uint8_t *)str;
287 val.length = strlen(str);
289 return ldb_msg_add_steal_value(msg, attr_name, &val);
293 compare two ldb_message_element structures
294 assumes case senistive comparison
296 int ldb_msg_element_compare(struct ldb_message_element *el1,
297 struct ldb_message_element *el2)
299 unsigned int i;
301 if (el1->num_values != el2->num_values) {
302 return el1->num_values - el2->num_values;
305 for (i=0;i<el1->num_values;i++) {
306 if (!ldb_msg_find_val(el2, &el1->values[i])) {
307 return -1;
311 return 0;
315 compare two ldb_message_element structures
316 comparing by element name
318 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
319 struct ldb_message_element *el2)
321 return ldb_attr_cmp(el1->name, el2->name);
325 convenience functions to return common types from a message
326 these return the first value if the attribute is multi-valued
328 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
329 const char *attr_name)
331 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
332 if (!el || el->num_values == 0) {
333 return NULL;
335 return &el->values[0];
338 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
339 const char *attr_name,
340 int default_value)
342 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
343 if (!v || !v->data) {
344 return default_value;
346 return strtol((const char *)v->data, NULL, 0);
349 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
350 const char *attr_name,
351 unsigned int default_value)
353 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
354 if (!v || !v->data) {
355 return default_value;
357 return strtoul((const char *)v->data, NULL, 0);
360 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
361 const char *attr_name,
362 int64_t default_value)
364 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
365 if (!v || !v->data) {
366 return default_value;
368 return strtoll((const char *)v->data, NULL, 0);
371 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
372 const char *attr_name,
373 uint64_t default_value)
375 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
376 if (!v || !v->data) {
377 return default_value;
379 return strtoull((const char *)v->data, NULL, 0);
382 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
383 const char *attr_name,
384 double default_value)
386 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
387 if (!v || !v->data) {
388 return default_value;
390 return strtod((const char *)v->data, NULL);
393 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
394 const char *attr_name,
395 int default_value)
397 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
398 if (!v || !v->data) {
399 return default_value;
401 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
402 return 0;
404 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
405 return 1;
407 return default_value;
410 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
411 const char *attr_name,
412 const char *default_value)
414 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
415 if (!v || !v->data) {
416 return default_value;
418 return (const char *)v->data;
421 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
422 void *mem_ctx,
423 const struct ldb_message *msg,
424 const char *attr_name)
426 struct ldb_dn *res_dn;
427 const struct ldb_val *v;
429 v = ldb_msg_find_ldb_val(msg, attr_name);
430 if (!v || !v->data) {
431 return NULL;
433 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
434 if ( ! ldb_dn_validate(res_dn)) {
435 talloc_free(res_dn);
436 return NULL;
438 return res_dn;
442 sort the elements of a message by name
444 void ldb_msg_sort_elements(struct ldb_message *msg)
446 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
447 (comparison_fn_t)ldb_msg_element_compare_name);
451 shallow copy a message - copying only the elements array so that the caller
452 can safely add new elements without changing the message
454 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
455 const struct ldb_message *msg)
457 struct ldb_message *msg2;
458 int i;
460 msg2 = talloc(mem_ctx, struct ldb_message);
461 if (msg2 == NULL) return NULL;
463 *msg2 = *msg;
465 msg2->elements = talloc_array(msg2, struct ldb_message_element,
466 msg2->num_elements);
467 if (msg2->elements == NULL) goto failed;
469 for (i=0;i<msg2->num_elements;i++) {
470 msg2->elements[i] = msg->elements[i];
473 return msg2;
475 failed:
476 talloc_free(msg2);
477 return NULL;
482 copy a message, allocating new memory for all parts
484 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
485 const struct ldb_message *msg)
487 struct ldb_message *msg2;
488 int i, j;
490 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
491 if (msg2 == NULL) return NULL;
493 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
494 if (msg2->dn == NULL) goto failed;
496 for (i=0;i<msg2->num_elements;i++) {
497 struct ldb_message_element *el = &msg2->elements[i];
498 struct ldb_val *values = el->values;
499 el->name = talloc_strdup(msg2->elements, el->name);
500 if (el->name == NULL) goto failed;
501 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
502 for (j=0;j<el->num_values;j++) {
503 el->values[j] = ldb_val_dup(el->values, &values[j]);
504 if (el->values[j].data == NULL && values[j].length != 0) {
505 goto failed;
510 return msg2;
512 failed:
513 talloc_free(msg2);
514 return NULL;
519 canonicalise a message, merging elements of the same name
521 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
522 const struct ldb_message *msg)
524 int i;
525 struct ldb_message *msg2;
527 msg2 = ldb_msg_copy(ldb, msg);
528 if (msg2 == NULL) return NULL;
530 ldb_msg_sort_elements(msg2);
532 for (i=1;i<msg2->num_elements;i++) {
533 struct ldb_message_element *el1 = &msg2->elements[i-1];
534 struct ldb_message_element *el2 = &msg2->elements[i];
535 if (ldb_msg_element_compare_name(el1, el2) == 0) {
536 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
537 el1->num_values + el2->num_values);
538 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
539 return NULL;
541 memcpy(el1->values + el1->num_values,
542 el2->values,
543 sizeof(struct ldb_val) * el2->num_values);
544 el1->num_values += el2->num_values;
545 talloc_free(discard_const_p(char, el2->name));
546 if (i+1<msg2->num_elements) {
547 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
548 (msg2->num_elements - (i+1)));
550 msg2->num_elements--;
551 i--;
555 return msg2;
560 return a ldb_message representing the differences between msg1 and msg2. If you
561 then use this in a ldb_modify() call it can be used to save edits to a message
563 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
564 struct ldb_message *msg1,
565 struct ldb_message *msg2)
567 struct ldb_message *mod;
568 struct ldb_message_element *el;
569 unsigned int i;
571 mod = ldb_msg_new(ldb);
572 if (mod == NULL) {
573 return NULL;
576 mod->dn = msg1->dn;
577 mod->num_elements = 0;
578 mod->elements = NULL;
580 msg2 = ldb_msg_canonicalize(ldb, msg2);
581 if (msg2 == NULL) {
582 talloc_free(mod);
583 return NULL;
586 /* look in msg2 to find elements that need to be added
587 or modified */
588 for (i=0;i<msg2->num_elements;i++) {
589 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
591 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
592 continue;
595 if (ldb_msg_add(mod,
596 &msg2->elements[i],
597 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
598 talloc_free(mod);
599 return NULL;
603 /* look in msg1 to find elements that need to be deleted */
604 for (i=0;i<msg1->num_elements;i++) {
605 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
606 if (el == NULL) {
607 if (ldb_msg_add_empty(mod,
608 msg1->elements[i].name,
609 LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
610 talloc_free(mod);
611 return NULL;
616 return mod;
619 int ldb_msg_sanity_check(struct ldb_context *ldb,
620 const struct ldb_message *msg)
622 int i, j;
624 /* basic check on DN */
625 if (msg->dn == NULL) {
626 /* TODO: return also an error string */
627 ldb_set_errstring(ldb, "ldb message lacks a DN!");
628 return LDB_ERR_INVALID_DN_SYNTAX;
631 /* basic syntax checks */
632 for (i = 0; i < msg->num_elements; i++) {
633 for (j = 0; j < msg->elements[i].num_values; j++) {
634 if (msg->elements[i].values[j].length == 0) {
635 TALLOC_CTX *mem_ctx = talloc_new(ldb);
636 /* an attribute cannot be empty */
637 /* TODO: return also an error string */
638 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
639 msg->elements[i].name,
640 ldb_dn_get_linearized(msg->dn));
641 talloc_free(mem_ctx);
642 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
647 return LDB_SUCCESS;
654 copy an attribute list. This only copies the array, not the elements
655 (ie. the elements are left as the same pointers)
657 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
659 const char **ret;
660 int i;
661 for (i=0;attrs && attrs[i];i++) /* noop */ ;
662 ret = talloc_array(mem_ctx, const char *, i+1);
663 if (ret == NULL) {
664 return NULL;
666 for (i=0;attrs && attrs[i];i++) {
667 ret[i] = attrs[i];
669 ret[i] = attrs[i];
670 return ret;
675 copy an attribute list. This only copies the array, not the elements
676 (ie. the elements are left as the same pointers). The new attribute is added to the list.
678 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
680 const char **ret;
681 int i;
682 bool found = false;
683 for (i=0;attrs && attrs[i];i++) {
684 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
685 found = true;
688 if (found) {
689 return ldb_attr_list_copy(mem_ctx, attrs);
691 ret = talloc_array(mem_ctx, const char *, i+2);
692 if (ret == NULL) {
693 return NULL;
695 for (i=0;attrs && attrs[i];i++) {
696 ret[i] = attrs[i];
698 ret[i] = new_attr;
699 ret[i+1] = NULL;
700 return ret;
705 return 1 if an attribute is in a list of attributes, or 0 otherwise
707 int ldb_attr_in_list(const char * const *attrs, const char *attr)
709 int i;
710 for (i=0;attrs && attrs[i];i++) {
711 if (ldb_attr_cmp(attrs[i], attr) == 0) {
712 return 1;
715 return 0;
720 rename the specified attribute in a search result
722 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
724 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
725 if (el == NULL) {
726 return LDB_SUCCESS;
728 el->name = talloc_strdup(msg->elements, replace);
729 if (el->name == NULL) {
730 return LDB_ERR_OPERATIONS_ERROR;
732 return LDB_SUCCESS;
737 copy the specified attribute in a search result to a new attribute
739 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
741 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
742 if (el == NULL) {
743 return LDB_SUCCESS;
745 if (ldb_msg_add(msg, el, 0) != 0) {
746 return LDB_ERR_OPERATIONS_ERROR;
748 return ldb_msg_rename_attr(msg, attr, replace);
752 remove the specified element in a search result
754 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
756 int n = (el - msg->elements);
757 if (n >= msg->num_elements) {
758 /* should we abort() here? */
759 return;
761 if (n != msg->num_elements-1) {
762 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
764 msg->num_elements--;
769 remove the specified attribute in a search result
771 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
773 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
774 if (el) {
775 ldb_msg_remove_element(msg, el);
780 return a LDAP formatted GeneralizedTime string
782 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
784 struct tm *tm = gmtime(&t);
785 char *ts;
786 int r;
788 if (!tm) {
789 return NULL;
792 /* we now excatly how long this string will be */
793 ts = talloc_array(mem_ctx, char, 18);
795 /* formatted like: 20040408072012.0Z */
796 r = snprintf(ts, 18,
797 "%04u%02u%02u%02u%02u%02u.0Z",
798 tm->tm_year+1900, tm->tm_mon+1,
799 tm->tm_mday, tm->tm_hour, tm->tm_min,
800 tm->tm_sec);
802 if (r != 17) {
803 talloc_free(ts);
804 return NULL;
807 return ts;
811 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
813 time_t ldb_string_to_time(const char *s)
815 struct tm tm;
817 if (s == NULL) return 0;
819 memset(&tm, 0, sizeof(tm));
820 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
821 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
822 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
823 return 0;
825 tm.tm_year -= 1900;
826 tm.tm_mon -= 1;
828 return timegm(&tm);
832 return a LDAP formatted UTCTime string
834 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
836 struct tm *tm = gmtime(&t);
837 char *ts;
838 int r;
840 if (!tm) {
841 return NULL;
844 /* we now excatly how long this string will be */
845 ts = talloc_array(mem_ctx, char, 14);
847 /* formatted like: 20040408072012.0Z => 040408072012Z */
848 r = snprintf(ts, 14,
849 "%02u%02u%02u%02u%02u%02uZ",
850 (tm->tm_year+1900)%100, tm->tm_mon+1,
851 tm->tm_mday, tm->tm_hour, tm->tm_min,
852 tm->tm_sec);
854 if (r != 13) {
855 talloc_free(ts);
856 return NULL;
859 return ts;
863 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
865 time_t ldb_string_utc_to_time(const char *s)
867 struct tm tm;
869 if (s == NULL) return 0;
871 memset(&tm, 0, sizeof(tm));
872 if (sscanf(s, "%02u%02u%02u%02u%02u%02u",
873 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
874 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
875 return 0;
877 if (tm.tm_year < 50) {
878 tm.tm_year += 100;
880 tm.tm_mon -= 1;
882 return timegm(&tm);
887 dump a set of results to a file. Useful from within gdb
889 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
891 int i;
893 for (i = 0; i < result->count; i++) {
894 struct ldb_ldif ldif;
895 fprintf(f, "# record %d\n", i+1);
896 ldif.changetype = LDB_CHANGETYPE_NONE;
897 ldif.msg = result->msgs[i];
898 ldb_ldif_write_file(ldb, f, &ldif);
903 checks for a string attribute. Returns "1" on match and otherwise "0".
905 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
906 const char *name, const char *value)
908 struct ldb_message_element *el;
909 struct ldb_val val;
911 el = ldb_msg_find_element(msg, name);
912 if (el == NULL) {
913 return 0;
916 val.data = discard_const_p(uint8_t, value);
917 val.length = strlen(value);
919 if (ldb_msg_find_val(el, &val)) {
920 return 1;
923 return 0;