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