1 /*
2 ldb database library
3
4 Copyright (C) Andrew Tridgell 2004
5
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
9
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.
14
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.
19
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/>.
22 */
23
24 /*
25 * Name: ldb
26 *
27 * Component: ldb message component utility functions
28 *
29 * Description: functions for manipulating ldb_message structures
30 *
31 * Author: Andrew Tridgell
32 */
33
34 #include "ldb_private.h"
35
36 /*
37 create a new ldb_message in a given memory context (NULL for top level)
38 */
ldb_msg_new(TALLOC_CTX * mem_ctx)39 struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
40 {
41 return talloc_zero(mem_ctx, struct ldb_message);
42 }
43
44 /*
45 find an element in a message by attribute name
46 */
ldb_msg_find_element(const struct ldb_message * msg,const char * attr_name)47 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
48 const char *attr_name)
49 {
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];
54 }
55 }
56 return NULL;
57 }
58
59 /*
60 see if two ldb_val structures contain exactly the same data
61 return 1 for a match, 0 for a mis-match
62 */
ldb_val_equal_exact(const struct ldb_val * v1,const struct ldb_val * v2)63 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
64 {
65 if (v1->length != v2->length) return 0;
66 if (v1->data == v2->data) return 1;
67 if (v1->length == 0) return 1;
68
69 if (memcmp(v1->data, v2->data, v1->length) == 0) {
70 return 1;
71 }
72
73 return 0;
74 }
75
76 /*
77 find a value in an element
78 assumes case sensitive comparison
79 */
ldb_msg_find_val(const struct ldb_message_element * el,struct ldb_val * val)80 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
81 struct ldb_val *val)
82 {
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];
87 }
88 }
89 return NULL;
90 }
91
92
ldb_val_cmp(const struct ldb_val * v1,const struct ldb_val * v2)93 static int ldb_val_cmp(const struct ldb_val *v1, const struct ldb_val *v2)
94 {
95 if (v1->length != v2->length) {
96 return v1->length - v2->length;
97 }
98 return memcmp(v1->data, v2->data, v1->length);
99 }
100
101
102 /*
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).
105
106 LDB_ERR_OPERATIONS_ERROR indicates an allocation failure or an unknown
107 options flag, otherwise LDB_SUCCESS.
108 */
109 #define LDB_DUP_QUADRATIC_THRESHOLD 10
110
ldb_msg_find_duplicate_val(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,const struct ldb_message_element * el,struct ldb_val ** duplicate,uint32_t options)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)
116 {
117 unsigned int i, j;
118 struct ldb_val *val;
119
120 if (options != 0) {
121 return LDB_ERR_OPERATIONS_ERROR;
122 }
123
124 *duplicate = NULL;
125
126 /*
127 If there are not many values, it is best to avoid the talloc
128 overhead and just do a brute force search.
129 */
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;
137 }
138 }
139 }
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;
145 }
146
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])
157 ) {
158 *duplicate = &el->values[j];
159 break;
160 }
161 }
162 talloc_free(values);
163 if (*duplicate == NULL) {
164 /* how we got here, I don't know */
165 return LDB_ERR_OPERATIONS_ERROR;
166 }
167 return LDB_SUCCESS;
168 }
169 }
170 talloc_free(values);
171 }
172 return LDB_SUCCESS;
173 }
174
175
176 /*
177 Determine whether the values in an element are also in another element.
178
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.
183
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.
186
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.
189 */
190
ldb_msg_find_common_values(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,struct ldb_message_element * el,struct ldb_message_element * el2,uint32_t options)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)
196 {
197 struct ldb_val *values;
198 struct ldb_val *values2;
199 unsigned int i, j, k, n_values;
200
201 bool remove_duplicates = options & LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES;
202
203 if ((options & ~LDB_MSG_FIND_COMMON_REMOVE_DUPLICATES) != 0) {
204 return LDB_ERR_OPERATIONS_ERROR;
205 }
206
207 if (strcmp(el->name, el2->name) != 0) {
208 return LDB_ERR_INAPPROPRIATE_MATCHING;
209 }
210 if (el->num_values == 0 || el2->num_values == 0) {
211 return LDB_SUCCESS;
212 }
213 /*
214 With few values, it is better to do the brute-force search than the
215 clever search involving tallocs, memcpys, sorts, etc.
216 */
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;
226 }
227 /*
228 With the remove_duplicates flag, we
229 resolve the intersection by removing
230 the offending one from el.
231 */
232 el->num_values--;
233 for (k = j; k < el->num_values; k++) {
234 el->values[k] = \
235 el->values[k + 1];
236 }
237 j--; /* rewind */
238 }
239 }
240 }
241 return LDB_SUCCESS;
242 }
243
244 values = talloc_array(mem_ctx, struct ldb_val, el->num_values);
245 if (values == NULL) {
246 return LDB_ERR_OPERATIONS_ERROR;
247 }
248 values2 = talloc_array(mem_ctx, struct ldb_val,
249 el2->num_values);
250 if (values2 == NULL) {
251 return LDB_ERR_OPERATIONS_ERROR;
252 }
253
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);
260
261 /*
262 el->n_values may diverge from the number of values in the sorted
263 list when the remove_duplicates flag is used.
264 */
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;
280 }
281 /*
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.
285 */
286 for (k = 0; k < el->num_values; k++) {
287 if (ldb_val_equal_exact(&el->values[k],
288 &values[i])) {
289 break;
290 }
291 }
292 el->num_values--;
293 for (; k < el->num_values; k++) {
294 el->values[k] = el->values[k + 1];
295 }
296 i++;
297 }
298 }
299 TALLOC_FREE(values);
300 TALLOC_FREE(values2);
301
302 return LDB_SUCCESS;
303 }
304
305 /*
306 duplicate a ldb_val structure
307 */
ldb_val_dup(TALLOC_CTX * mem_ctx,const struct ldb_val * v)308 struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
309 {
310 struct ldb_val v2;
311 v2.length = v->length;
312 if (v->data == NULL) {
313 v2.data = NULL;
314 return v2;
315 }
316
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;
323 }
324
325 memcpy(v2.data, v->data, v->length);
326 ((char *)v2.data)[v->length] = 0;
327 return v2;
328 }
329
330 /**
331 * Adds new empty element to msg->elements
332 */
_ldb_msg_add_el(struct ldb_message * msg,struct ldb_message_element ** return_el)333 static int _ldb_msg_add_el(struct ldb_message *msg,
334 struct ldb_message_element **return_el)
335 {
336 struct ldb_message_element *els;
337
338 /*
339 * TODO: Find out a way to assert on input parameters.
340 * msg and return_el must be valid
341 */
342
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;
347 }
348
349 ZERO_STRUCT(els[msg->num_elements]);
350
351 msg->elements = els;
352 msg->num_elements++;
353
354 *return_el = &els[msg->num_elements-1];
355
356 return LDB_SUCCESS;
357 }
358
359 /**
360 * Add an empty element with a given name to a message
361 */
ldb_msg_add_empty(struct ldb_message * msg,const char * attr_name,int flags,struct ldb_message_element ** return_el)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)
366 {
367 int ret;
368 struct ldb_message_element *el;
369
370 ret = _ldb_msg_add_el(msg, &el);
371 if (ret != LDB_SUCCESS) {
372 return ret;
373 }
374
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;
380 }
381
382 if (return_el) {
383 *return_el = el;
384 }
385
386 return LDB_SUCCESS;
387 }
388
389 /**
390 * Adds an element to a message.
391 *
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
396 */
ldb_msg_add(struct ldb_message * msg,const struct ldb_message_element * el,int flags)397 int ldb_msg_add(struct ldb_message *msg,
398 const struct ldb_message_element *el,
399 int flags)
400 {
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;
406
407 ret = _ldb_msg_add_el(msg, &el_new);
408 if (ret != LDB_SUCCESS) {
409 return ret;
410 }
411
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;
416
417 return LDB_SUCCESS;
418 }
419
420 /*
421 add a value to a message
422 */
ldb_msg_add_value(struct ldb_message * msg,const char * attr_name,const struct ldb_val * val,struct ldb_message_element ** return_el)423 int ldb_msg_add_value(struct ldb_message *msg,
424 const char *attr_name,
425 const struct ldb_val *val,
426 struct ldb_message_element **return_el)
427 {
428 struct ldb_message_element *el;
429 struct ldb_val *vals;
430 int ret;
431
432 el = ldb_msg_find_element(msg, attr_name);
433 if (!el) {
434 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
435 if (ret != LDB_SUCCESS) {
436 return ret;
437 }
438 }
439
440 vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
441 el->num_values+1);
442 if (!vals) {
443 return LDB_ERR_OPERATIONS_ERROR;
444 }
445 el->values = vals;
446 el->values[el->num_values] = *val;
447 el->num_values++;
448
449 if (return_el) {
450 *return_el = el;
451 }
452
453 return LDB_SUCCESS;
454 }
455
456
457 /*
458 add a value to a message, stealing it into the 'right' place
459 */
ldb_msg_add_steal_value(struct ldb_message * msg,const char * attr_name,struct ldb_val * val)460 int ldb_msg_add_steal_value(struct ldb_message *msg,
461 const char *attr_name,
462 struct ldb_val *val)
463 {
464 int ret;
465 struct ldb_message_element *el;
466
467 ret = ldb_msg_add_value(msg, attr_name, val, &el);
468 if (ret == LDB_SUCCESS) {
469 talloc_steal(el->values, val->data);
470 }
471 return ret;
472 }
473
474
475 /*
476 add a string element to a message
477 */
ldb_msg_add_string(struct ldb_message * msg,const char * attr_name,const char * str)478 int ldb_msg_add_string(struct ldb_message *msg,
479 const char *attr_name, const char *str)
480 {
481 struct ldb_val val;
482
483 val.data = discard_const_p(uint8_t, str);
484 val.length = strlen(str);
485
486 if (val.length == 0) {
487 /* allow empty strings as non-existent attributes */
488 return LDB_SUCCESS;
489 }
490
491 return ldb_msg_add_value(msg, attr_name, &val, NULL);
492 }
493
494 /*
495 add a string element to a message, stealing it into the 'right' place
496 */
ldb_msg_add_steal_string(struct ldb_message * msg,const char * attr_name,char * str)497 int ldb_msg_add_steal_string(struct ldb_message *msg,
498 const char *attr_name, char *str)
499 {
500 struct ldb_val val;
501
502 val.data = (uint8_t *)str;
503 val.length = strlen(str);
504
505 if (val.length == 0) {
506 /* allow empty strings as non-existent attributes */
507 return LDB_SUCCESS;
508 }
509
510 return ldb_msg_add_steal_value(msg, attr_name, &val);
511 }
512
513 /*
514 add a DN element to a message
515 WARNING: this uses the linearized string from the dn, and does not
516 copy the string.
517 */
ldb_msg_add_linearized_dn(struct ldb_message * msg,const char * attr_name,struct ldb_dn * dn)518 int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name,
519 struct ldb_dn *dn)
520 {
521 char *str = ldb_dn_alloc_linearized(msg, dn);
522
523 if (str == NULL) {
524 /* we don't want to have unknown DNs added */
525 return LDB_ERR_OPERATIONS_ERROR;
526 }
527
528 return ldb_msg_add_steal_string(msg, attr_name, str);
529 }
530
531 /*
532 add a printf formatted element to a message
533 */
ldb_msg_add_fmt(struct ldb_message * msg,const char * attr_name,const char * fmt,...)534 int ldb_msg_add_fmt(struct ldb_message *msg,
535 const char *attr_name, const char *fmt, ...)
536 {
537 struct ldb_val val;
538 va_list ap;
539 char *str;
540
541 va_start(ap, fmt);
542 str = talloc_vasprintf(msg, fmt, ap);
543 va_end(ap);
544
545 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
546
547 val.data = (uint8_t *)str;
548 val.length = strlen(str);
549
550 return ldb_msg_add_steal_value(msg, attr_name, &val);
551 }
552
553 /*
554 compare two ldb_message_element structures
555 assumes case sensitive comparison
556 */
ldb_msg_element_compare(struct ldb_message_element * el1,struct ldb_message_element * el2)557 int ldb_msg_element_compare(struct ldb_message_element *el1,
558 struct ldb_message_element *el2)
559 {
560 unsigned int i;
561
562 if (el1->num_values != el2->num_values) {
563 return el1->num_values - el2->num_values;
564 }
565
566 for (i=0;i<el1->num_values;i++) {
567 if (!ldb_msg_find_val(el2, &el1->values[i])) {
568 return -1;
569 }
570 }
571
572 return 0;
573 }
574
575 /*
576 compare two ldb_message_element structures.
577 Different ordering is considered a mismatch
578 */
ldb_msg_element_equal_ordered(const struct ldb_message_element * el1,const struct ldb_message_element * el2)579 bool ldb_msg_element_equal_ordered(const struct ldb_message_element *el1,
580 const struct ldb_message_element *el2)
581 {
582 unsigned i;
583 if (el1->num_values != el2->num_values) {
584 return false;
585 }
586 for (i=0;i<el1->num_values;i++) {
587 if (ldb_val_equal_exact(&el1->values[i],
588 &el2->values[i]) != 1) {
589 return false;
590 }
591 }
592 return true;
593 }
594
595 /*
596 compare two ldb_message_element structures
597 comparing by element name
598 */
ldb_msg_element_compare_name(struct ldb_message_element * el1,struct ldb_message_element * el2)599 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
600 struct ldb_message_element *el2)
601 {
602 return ldb_attr_cmp(el1->name, el2->name);
603 }
604
605 /*
606 convenience functions to return common types from a message
607 these return the first value if the attribute is multi-valued
608 */
ldb_msg_find_ldb_val(const struct ldb_message * msg,const char * attr_name)609 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
610 const char *attr_name)
611 {
612 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
613 if (!el || el->num_values == 0) {
614 return NULL;
615 }
616 return &el->values[0];
617 }
618
ldb_msg_find_attr_as_int(const struct ldb_message * msg,const char * attr_name,int default_value)619 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
620 const char *attr_name,
621 int default_value)
622 {
623 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
624 char buf[sizeof("-2147483648")];
625 char *end = NULL;
626 int ret;
627
628 if (!v || !v->data) {
629 return default_value;
630 }
631
632 ZERO_STRUCT(buf);
633 if (v->length >= sizeof(buf)) {
634 return default_value;
635 }
636
637 memcpy(buf, v->data, v->length);
638 errno = 0;
639 ret = (int) strtoll(buf, &end, 10);
640 if (errno != 0) {
641 return default_value;
642 }
643 if (end && end[0] != '\0') {
644 return default_value;
645 }
646 return ret;
647 }
648
ldb_msg_find_attr_as_uint(const struct ldb_message * msg,const char * attr_name,unsigned int default_value)649 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
650 const char *attr_name,
651 unsigned int default_value)
652 {
653 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
654 char buf[sizeof("-2147483648")];
655 char *end = NULL;
656 unsigned int ret;
657
658 if (!v || !v->data) {
659 return default_value;
660 }
661
662 ZERO_STRUCT(buf);
663 if (v->length >= sizeof(buf)) {
664 return default_value;
665 }
666
667 memcpy(buf, v->data, v->length);
668 errno = 0;
669 ret = (unsigned int) strtoll(buf, &end, 10);
670 if (errno != 0) {
671 errno = 0;
672 ret = (unsigned int) strtoull(buf, &end, 10);
673 if (errno != 0) {
674 return default_value;
675 }
676 }
677 if (end && end[0] != '\0') {
678 return default_value;
679 }
680 return ret;
681 }
682
ldb_msg_find_attr_as_int64(const struct ldb_message * msg,const char * attr_name,int64_t default_value)683 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
684 const char *attr_name,
685 int64_t default_value)
686 {
687 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
688 char buf[sizeof("-9223372036854775808")];
689 char *end = NULL;
690 int64_t ret;
691
692 if (!v || !v->data) {
693 return default_value;
694 }
695
696 ZERO_STRUCT(buf);
697 if (v->length >= sizeof(buf)) {
698 return default_value;
699 }
700
701 memcpy(buf, v->data, v->length);
702 errno = 0;
703 ret = (int64_t) strtoll(buf, &end, 10);
704 if (errno != 0) {
705 return default_value;
706 }
707 if (end && end[0] != '\0') {
708 return default_value;
709 }
710 return ret;
711 }
712
ldb_msg_find_attr_as_uint64(const struct ldb_message * msg,const char * attr_name,uint64_t default_value)713 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
714 const char *attr_name,
715 uint64_t default_value)
716 {
717 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
718 char buf[sizeof("-9223372036854775808")];
719 char *end = NULL;
720 uint64_t ret;
721
722 if (!v || !v->data) {
723 return default_value;
724 }
725
726 ZERO_STRUCT(buf);
727 if (v->length >= sizeof(buf)) {
728 return default_value;
729 }
730
731 memcpy(buf, v->data, v->length);
732 errno = 0;
733 ret = (uint64_t) strtoll(buf, &end, 10);
734 if (errno != 0) {
735 errno = 0;
736 ret = (uint64_t) strtoull(buf, &end, 10);
737 if (errno != 0) {
738 return default_value;
739 }
740 }
741 if (end && end[0] != '\0') {
742 return default_value;
743 }
744 return ret;
745 }
746
ldb_msg_find_attr_as_double(const struct ldb_message * msg,const char * attr_name,double default_value)747 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
748 const char *attr_name,
749 double default_value)
750 {
751 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
752 char *buf;
753 char *end = NULL;
754 double ret;
755
756 if (!v || !v->data) {
757 return default_value;
758 }
759 buf = talloc_strndup(msg, (const char *)v->data, v->length);
760 if (buf == NULL) {
761 return default_value;
762 }
763
764 errno = 0;
765 ret = strtod(buf, &end);
766 talloc_free(buf);
767 if (errno != 0) {
768 return default_value;
769 }
770 if (end && end[0] != '\0') {
771 return default_value;
772 }
773 return ret;
774 }
775
ldb_msg_find_attr_as_bool(const struct ldb_message * msg,const char * attr_name,int default_value)776 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
777 const char *attr_name,
778 int default_value)
779 {
780 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
781 if (!v || !v->data) {
782 return default_value;
783 }
784 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
785 return 0;
786 }
787 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
788 return 1;
789 }
790 return default_value;
791 }
792
ldb_msg_find_attr_as_string(const struct ldb_message * msg,const char * attr_name,const char * default_value)793 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
794 const char *attr_name,
795 const char *default_value)
796 {
797 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
798 if (!v || !v->data) {
799 return default_value;
800 }
801 if (v->data[v->length] != '\0') {
802 return default_value;
803 }
804 return (const char *)v->data;
805 }
806
ldb_msg_find_attr_as_dn(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,const struct ldb_message * msg,const char * attr_name)807 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
808 TALLOC_CTX *mem_ctx,
809 const struct ldb_message *msg,
810 const char *attr_name)
811 {
812 struct ldb_dn *res_dn;
813 const struct ldb_val *v;
814
815 v = ldb_msg_find_ldb_val(msg, attr_name);
816 if (!v || !v->data) {
817 return NULL;
818 }
819 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
820 if ( ! ldb_dn_validate(res_dn)) {
821 talloc_free(res_dn);
822 return NULL;
823 }
824 return res_dn;
825 }
826
827 /*
828 sort the elements of a message by name
829 */
ldb_msg_sort_elements(struct ldb_message * msg)830 void ldb_msg_sort_elements(struct ldb_message *msg)
831 {
832 TYPESAFE_QSORT(msg->elements, msg->num_elements,
833 ldb_msg_element_compare_name);
834 }
835
836 /*
837 shallow copy a message - copying only the elements array so that the caller
838 can safely add new elements without changing the message
839 */
ldb_msg_copy_shallow(TALLOC_CTX * mem_ctx,const struct ldb_message * msg)840 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
841 const struct ldb_message *msg)
842 {
843 struct ldb_message *msg2;
844 unsigned int i;
845
846 msg2 = talloc(mem_ctx, struct ldb_message);
847 if (msg2 == NULL) return NULL;
848
849 *msg2 = *msg;
850
851 msg2->elements = talloc_array(msg2, struct ldb_message_element,
852 msg2->num_elements);
853 if (msg2->elements == NULL) goto failed;
854
855 for (i=0;i<msg2->num_elements;i++) {
856 msg2->elements[i] = msg->elements[i];
857 }
858
859 return msg2;
860
861 failed:
862 talloc_free(msg2);
863 return NULL;
864 }
865
866
867 /*
868 copy a message, allocating new memory for all parts
869 */
ldb_msg_copy(TALLOC_CTX * mem_ctx,const struct ldb_message * msg)870 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
871 const struct ldb_message *msg)
872 {
873 struct ldb_message *msg2;
874 unsigned int i, j;
875
876 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
877 if (msg2 == NULL) return NULL;
878
879 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
880 if (msg2->dn == NULL) goto failed;
881
882 for (i=0;i<msg2->num_elements;i++) {
883 struct ldb_message_element *el = &msg2->elements[i];
884 struct ldb_val *values = el->values;
885 el->name = talloc_strdup(msg2->elements, el->name);
886 if (el->name == NULL) goto failed;
887 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
888 if (el->values == NULL) goto failed;
889 for (j=0;j<el->num_values;j++) {
890 el->values[j] = ldb_val_dup(el->values, &values[j]);
891 if (el->values[j].data == NULL && values[j].length != 0) {
892 goto failed;
893 }
894 }
895 }
896
897 return msg2;
898
899 failed:
900 talloc_free(msg2);
901 return NULL;
902 }
903
904
905 /**
906 * Canonicalize a message, merging elements of the same name
907 */
ldb_msg_canonicalize(struct ldb_context * ldb,const struct ldb_message * msg)908 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
909 const struct ldb_message *msg)
910 {
911 int ret;
912 struct ldb_message *msg2;
913
914 /*
915 * Preserve previous behavior and allocate
916 * *msg2 into *ldb context
917 */
918 ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
919 if (ret != LDB_SUCCESS) {
920 return NULL;
921 }
922
923 return msg2;
924 }
925
926 /**
927 * Canonicalize a message, merging elements of the same name
928 */
ldb_msg_normalize(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,const struct ldb_message * msg,struct ldb_message ** _msg_out)929 int ldb_msg_normalize(struct ldb_context *ldb,
930 TALLOC_CTX *mem_ctx,
931 const struct ldb_message *msg,
932 struct ldb_message **_msg_out)
933 {
934 unsigned int i;
935 struct ldb_message *msg2;
936
937 msg2 = ldb_msg_copy(mem_ctx, msg);
938 if (msg2 == NULL) {
939 return LDB_ERR_OPERATIONS_ERROR;
940 }
941
942 ldb_msg_sort_elements(msg2);
943
944 for (i=1; i < msg2->num_elements; i++) {
945 struct ldb_message_element *el1 = &msg2->elements[i-1];
946 struct ldb_message_element *el2 = &msg2->elements[i];
947
948 if (ldb_msg_element_compare_name(el1, el2) == 0) {
949 el1->values = talloc_realloc(msg2->elements,
950 el1->values, struct ldb_val,
951 el1->num_values + el2->num_values);
952 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
953 talloc_free(msg2);
954 return LDB_ERR_OPERATIONS_ERROR;
955 }
956 memcpy(el1->values + el1->num_values,
957 el2->values,
958 sizeof(struct ldb_val) * el2->num_values);
959 el1->num_values += el2->num_values;
960 talloc_free(discard_const_p(char, el2->name));
961 if ((i+1) < msg2->num_elements) {
962 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
963 (msg2->num_elements - (i+1)));
964 }
965 msg2->num_elements--;
966 i--;
967 }
968 }
969
970 *_msg_out = msg2;
971 return LDB_SUCCESS;
972 }
973
974
975 /**
976 * return a ldb_message representing the differences between msg1 and msg2.
977 * If you then use this in a ldb_modify() call,
978 * it can be used to save edits to a message
979 */
ldb_msg_diff(struct ldb_context * ldb,struct ldb_message * msg1,struct ldb_message * msg2)980 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
981 struct ldb_message *msg1,
982 struct ldb_message *msg2)
983 {
984 int ldb_ret;
985 struct ldb_message *mod;
986
987 ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &mod);
988 if (ldb_ret != LDB_SUCCESS) {
989 return NULL;
990 }
991
992 return mod;
993 }
994
995 /**
996 * return a ldb_message representing the differences between msg1 and msg2.
997 * If you then use this in a ldb_modify() call it can be used to save edits to a message
998 *
999 * Result message is constructed as follows:
1000 * - LDB_FLAG_MOD_ADD - elements found only in msg2
1001 * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1
1002 * Value for msg2 element is used
1003 * - LDB_FLAG_MOD_DELETE - elements found only in msg2
1004 *
1005 * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR
1006 */
ldb_msg_difference(struct ldb_context * ldb,TALLOC_CTX * mem_ctx,struct ldb_message * msg1,struct ldb_message * msg2,struct ldb_message ** _msg_out)1007 int ldb_msg_difference(struct ldb_context *ldb,
1008 TALLOC_CTX *mem_ctx,
1009 struct ldb_message *msg1,
1010 struct ldb_message *msg2,
1011 struct ldb_message **_msg_out)
1012 {
1013 int ldb_res;
1014 unsigned int i;
1015 struct ldb_message *mod;
1016 struct ldb_message_element *el;
1017 TALLOC_CTX *temp_ctx;
1018
1019 temp_ctx = talloc_new(mem_ctx);
1020 if (!temp_ctx) {
1021 return LDB_ERR_OPERATIONS_ERROR;
1022 }
1023
1024 mod = ldb_msg_new(temp_ctx);
1025 if (mod == NULL) {
1026 goto failed;
1027 }
1028
1029 mod->dn = msg1->dn;
1030 mod->num_elements = 0;
1031 mod->elements = NULL;
1032
1033 /*
1034 * Canonicalize *msg2 so we have no repeated elements
1035 * Resulting message is allocated in *mod's mem context,
1036 * as we are going to move some elements from *msg2 to
1037 * *mod object later
1038 */
1039 ldb_res = ldb_msg_normalize(ldb, mod, msg2, &msg2);
1040 if (ldb_res != LDB_SUCCESS) {
1041 goto failed;
1042 }
1043
1044 /* look in msg2 to find elements that need to be added or modified */
1045 for (i=0;i<msg2->num_elements;i++) {
1046 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
1047
1048 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
1049 continue;
1050 }
1051
1052 ldb_res = ldb_msg_add(mod,
1053 &msg2->elements[i],
1054 el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD);
1055 if (ldb_res != LDB_SUCCESS) {
1056 goto failed;
1057 }
1058 }
1059
1060 /* look in msg1 to find elements that need to be deleted */
1061 for (i=0;i<msg1->num_elements;i++) {
1062 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
1063 if (el == NULL) {
1064 ldb_res = ldb_msg_add_empty(mod,
1065 msg1->elements[i].name,
1066 LDB_FLAG_MOD_DELETE, NULL);
1067 if (ldb_res != LDB_SUCCESS) {
1068 goto failed;
1069 }
1070 }
1071 }
1072
1073 /* steal resulting message into supplied context */
1074 talloc_steal(mem_ctx, mod);
1075 *_msg_out = mod;
1076
1077 talloc_free(temp_ctx);
1078 return LDB_SUCCESS;
1079
1080 failed:
1081 talloc_free(temp_ctx);
1082 return LDB_ERR_OPERATIONS_ERROR;
1083 }
1084
1085
ldb_msg_sanity_check(struct ldb_context * ldb,const struct ldb_message * msg)1086 int ldb_msg_sanity_check(struct ldb_context *ldb,
1087 const struct ldb_message *msg)
1088 {
1089 unsigned int i, j;
1090
1091 /* basic check on DN */
1092 if (msg->dn == NULL) {
1093 ldb_set_errstring(ldb, "ldb message lacks a DN!");
1094 return LDB_ERR_INVALID_DN_SYNTAX;
1095 }
1096
1097 /* basic syntax checks */
1098 for (i = 0; i < msg->num_elements; i++) {
1099 for (j = 0; j < msg->elements[i].num_values; j++) {
1100 if (msg->elements[i].values[j].length == 0) {
1101 /* an attribute cannot be empty */
1102 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
1103 msg->elements[i].name,
1104 ldb_dn_get_linearized(msg->dn));
1105 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1106 }
1107 }
1108 }
1109
1110 return LDB_SUCCESS;
1111 }
1112
1113
1114
1115
1116 /*
1117 copy an attribute list. This only copies the array, not the elements
1118 (ie. the elements are left as the same pointers)
1119 */
ldb_attr_list_copy(TALLOC_CTX * mem_ctx,const char * const * attrs)1120 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
1121 {
1122 const char **ret;
1123 unsigned int i;
1124
1125 for (i=0;attrs && attrs[i];i++) /* noop */ ;
1126 ret = talloc_array(mem_ctx, const char *, i+1);
1127 if (ret == NULL) {
1128 return NULL;
1129 }
1130 for (i=0;attrs && attrs[i];i++) {
1131 ret[i] = attrs[i];
1132 }
1133 ret[i] = attrs[i];
1134 return ret;
1135 }
1136
1137
1138 /*
1139 copy an attribute list. This only copies the array, not the elements
1140 (ie. the elements are left as the same pointers). The new attribute is added to the list.
1141 */
ldb_attr_list_copy_add(TALLOC_CTX * mem_ctx,const char * const * attrs,const char * new_attr)1142 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
1143 {
1144 const char **ret;
1145 unsigned int i;
1146 bool found = false;
1147
1148 for (i=0;attrs && attrs[i];i++) {
1149 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
1150 found = true;
1151 }
1152 }
1153 if (found) {
1154 return ldb_attr_list_copy(mem_ctx, attrs);
1155 }
1156 ret = talloc_array(mem_ctx, const char *, i+2);
1157 if (ret == NULL) {
1158 return NULL;
1159 }
1160 for (i=0;attrs && attrs[i];i++) {
1161 ret[i] = attrs[i];
1162 }
1163 ret[i] = new_attr;
1164 ret[i+1] = NULL;
1165 return ret;
1166 }
1167
1168
1169 /*
1170 return 1 if an attribute is in a list of attributes, or 0 otherwise
1171 */
ldb_attr_in_list(const char * const * attrs,const char * attr)1172 int ldb_attr_in_list(const char * const *attrs, const char *attr)
1173 {
1174 unsigned int i;
1175 for (i=0;attrs && attrs[i];i++) {
1176 if (ldb_attr_cmp(attrs[i], attr) == 0) {
1177 return 1;
1178 }
1179 }
1180 return 0;
1181 }
1182
1183
1184 /*
1185 rename the specified attribute in a search result
1186 */
ldb_msg_rename_attr(struct ldb_message * msg,const char * attr,const char * replace)1187 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
1188 {
1189 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1190 if (el == NULL) {
1191 return LDB_SUCCESS;
1192 }
1193 el->name = talloc_strdup(msg->elements, replace);
1194 if (el->name == NULL) {
1195 return LDB_ERR_OPERATIONS_ERROR;
1196 }
1197 return LDB_SUCCESS;
1198 }
1199
1200
1201 /*
1202 copy the specified attribute in a search result to a new attribute
1203 */
ldb_msg_copy_attr(struct ldb_message * msg,const char * attr,const char * replace)1204 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
1205 {
1206 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
1207 int ret;
1208
1209 if (el == NULL) {
1210 return LDB_SUCCESS;
1211 }
1212 ret = ldb_msg_add(msg, el, 0);
1213 if (ret != LDB_SUCCESS) {
1214 return ret;
1215 }
1216 return ldb_msg_rename_attr(msg, attr, replace);
1217 }
1218
1219 /*
1220 remove the specified element in a search result
1221 */
ldb_msg_remove_element(struct ldb_message * msg,struct ldb_message_element * el)1222 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
1223 {
1224 ptrdiff_t n = (el - msg->elements);
1225 if (n >= msg->num_elements || n < 0) {
1226 /* the element is not in the list. the caller is crazy. */
1227 return;
1228 }
1229 msg->num_elements--;
1230 if (n != msg->num_elements) {
1231 memmove(el, el+1, (msg->num_elements - n)*sizeof(*el));
1232 }
1233 }
1234
1235
1236 /*
1237 remove the specified attribute in a search result
1238 */
ldb_msg_remove_attr(struct ldb_message * msg,const char * attr)1239 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
1240 {
1241 struct ldb_message_element *el;
1242
1243 while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
1244 ldb_msg_remove_element(msg, el);
1245 }
1246 }
1247
1248 /*
1249 return a LDAP formatted GeneralizedTime string
1250 */
ldb_timestring(TALLOC_CTX * mem_ctx,time_t t)1251 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
1252 {
1253 struct tm *tm = gmtime(&t);
1254 char *ts;
1255 int r;
1256
1257 if (!tm) {
1258 return NULL;
1259 }
1260
1261 /* we now excatly how long this string will be */
1262 ts = talloc_array(mem_ctx, char, 18);
1263
1264 /* formatted like: 20040408072012.0Z */
1265 r = snprintf(ts, 18,
1266 "%04u%02u%02u%02u%02u%02u.0Z",
1267 tm->tm_year+1900, tm->tm_mon+1,
1268 tm->tm_mday, tm->tm_hour, tm->tm_min,
1269 tm->tm_sec);
1270
1271 if (r != 17) {
1272 talloc_free(ts);
1273 return NULL;
1274 }
1275
1276 return ts;
1277 }
1278
1279 /*
1280 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
1281 */
ldb_string_to_time(const char * s)1282 time_t ldb_string_to_time(const char *s)
1283 {
1284 struct tm tm;
1285
1286 if (s == NULL) return 0;
1287
1288 memset(&tm, 0, sizeof(tm));
1289 if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z",
1290 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1291 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1292 return 0;
1293 }
1294 tm.tm_year -= 1900;
1295 tm.tm_mon -= 1;
1296
1297 return timegm(&tm);
1298 }
1299
1300 /*
1301 convert a LDAP GeneralizedTime string in ldb_val format to a
1302 time_t.
1303 */
ldb_val_to_time(const struct ldb_val * v,time_t * t)1304 int ldb_val_to_time(const struct ldb_val *v, time_t *t)
1305 {
1306 char val[15] = {0};
1307 struct tm tm = {
1308 .tm_year = 0,
1309 };
1310
1311 if (v == NULL) {
1312 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1313 }
1314
1315 if (v->data == NULL) {
1316 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1317 }
1318
1319 if (v->length < 16 && v->length != 13) {
1320 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1321 }
1322
1323 if (v->data[v->length - 1] != 'Z') {
1324 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1325 }
1326
1327 if (v->length == 13) {
1328 memcpy(val, v->data, 12);
1329
1330 if (sscanf(val, "%02u%02u%02u%02u%02u%02u",
1331 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1332 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1333 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1334 }
1335 if (tm.tm_year < 50) {
1336 tm.tm_year += 100;
1337 }
1338 } else {
1339
1340 /*
1341 * anything between '.' and 'Z' is silently ignored.
1342 */
1343 if (v->data[14] != '.') {
1344 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1345 }
1346
1347 memcpy(val, v->data, 14);
1348
1349 if (sscanf(val, "%04u%02u%02u%02u%02u%02u",
1350 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1351 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1352 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
1353 }
1354 tm.tm_year -= 1900;
1355 }
1356 tm.tm_mon -= 1;
1357
1358 *t = timegm(&tm);
1359
1360 return LDB_SUCCESS;
1361 }
1362
1363 /*
1364 return a LDAP formatted UTCTime string
1365 */
ldb_timestring_utc(TALLOC_CTX * mem_ctx,time_t t)1366 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
1367 {
1368 struct tm *tm = gmtime(&t);
1369 char *ts;
1370 int r;
1371
1372 if (!tm) {
1373 return NULL;
1374 }
1375
1376 /* we now excatly how long this string will be */
1377 ts = talloc_array(mem_ctx, char, 14);
1378
1379 /* formatted like: 20040408072012.0Z => 040408072012Z */
1380 r = snprintf(ts, 14,
1381 "%02u%02u%02u%02u%02u%02uZ",
1382 (tm->tm_year+1900)%100, tm->tm_mon+1,
1383 tm->tm_mday, tm->tm_hour, tm->tm_min,
1384 tm->tm_sec);
1385
1386 if (r != 13) {
1387 talloc_free(ts);
1388 return NULL;
1389 }
1390
1391 return ts;
1392 }
1393
1394 /*
1395 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
1396 */
ldb_string_utc_to_time(const char * s)1397 time_t ldb_string_utc_to_time(const char *s)
1398 {
1399 struct tm tm;
1400
1401 if (s == NULL) return 0;
1402
1403 memset(&tm, 0, sizeof(tm));
1404 if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ",
1405 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
1406 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
1407 return 0;
1408 }
1409 if (tm.tm_year < 50) {
1410 tm.tm_year += 100;
1411 }
1412 tm.tm_mon -= 1;
1413
1414 return timegm(&tm);
1415 }
1416
1417
1418 /*
1419 dump a set of results to a file. Useful from within gdb
1420 */
ldb_dump_results(struct ldb_context * ldb,struct ldb_result * result,FILE * f)1421 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
1422 {
1423 unsigned int i;
1424
1425 for (i = 0; i < result->count; i++) {
1426 struct ldb_ldif ldif;
1427 fprintf(f, "# record %d\n", i+1);
1428 ldif.changetype = LDB_CHANGETYPE_NONE;
1429 ldif.msg = result->msgs[i];
1430 ldb_ldif_write_file(ldb, f, &ldif);
1431 }
1432 }
1433
1434 /*
1435 checks for a string attribute. Returns "1" on match and otherwise "0".
1436 */
ldb_msg_check_string_attribute(const struct ldb_message * msg,const char * name,const char * value)1437 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
1438 const char *name, const char *value)
1439 {
1440 struct ldb_message_element *el;
1441 struct ldb_val val;
1442
1443 el = ldb_msg_find_element(msg, name);
1444 if (el == NULL) {
1445 return 0;
1446 }
1447
1448 val.data = discard_const_p(uint8_t, value);
1449 val.length = strlen(value);
1450
1451 if (ldb_msg_find_val(el, &val)) {
1452 return 1;
1453 }
1454
1455 return 0;
1456 }
1457
1458
1459 /*
1460 compare a ldb_val to a string
1461 */
ldb_val_string_cmp(const struct ldb_val * v,const char * str)1462 int ldb_val_string_cmp(const struct ldb_val *v, const char *str)
1463 {
1464 size_t len = strlen(str);
1465 if (len != v->length) {
1466 return len - v->length;
1467 }
1468 return strncmp((const char *)v->data, str, len);
1469 }
1470