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
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 2 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, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * Component: ldb message component utility functions
30 * Description: functions for manipulating ldb_message structures
32 * Author: Andrew Tridgell
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_errors.h"
38 #include "ldb/include/ldb_private.h"
41 create a new ldb_message in a given memory context (NULL for top level)
43 struct ldb_message *ldb_msg_new(void *mem_ctx)
45 return talloc_zero(mem_ctx, struct ldb_message);
49 find an element in a message by attribute name
51 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
52 const char *attr_name)
55 for (i=0;i<msg->num_elements;i++) {
56 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
57 return &msg->elements[i];
64 see if two ldb_val structures contain exactly the same data
65 return 1 for a match, 0 for a mis-match
67 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
69 if (v1->length != v2->length) return 0;
71 if (v1->length == 0) return 1;
73 if (memcmp(v1->data, v2->data, v1->length) == 0) {
81 find a value in an element
82 assumes case sensitive comparison
84 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
88 for (i=0;i<el->num_values;i++) {
89 if (ldb_val_equal_exact(val, &el->values[i])) {
90 return &el->values[i];
97 duplicate a ldb_val structure
99 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
102 v2.length = v->length;
103 if (v->data == NULL) {
108 /* the +1 is to cope with buggy C library routines like strndup
109 that look one byte beyond */
110 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
116 memcpy(v2.data, v->data, v->length);
117 ((char *)v2.data)[v->length] = 0;
122 add an empty element to a message
124 int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags)
126 struct ldb_message_element *els;
128 els = talloc_realloc(msg, msg->elements,
129 struct ldb_message_element, msg->num_elements+1);
135 els[msg->num_elements].values = NULL;
136 els[msg->num_elements].num_values = 0;
137 els[msg->num_elements].flags = flags;
138 els[msg->num_elements].name = talloc_strdup(els, attr_name);
139 if (!els[msg->num_elements].name) {
150 add an empty element to a message
152 int ldb_msg_add(struct ldb_message *msg,
153 const struct ldb_message_element *el,
156 if (ldb_msg_add_empty(msg, el->name, flags) != 0) {
160 msg->elements[msg->num_elements-1] = *el;
161 msg->elements[msg->num_elements-1].flags = flags;
167 add a value to a message
169 int ldb_msg_add_value(struct ldb_message *msg,
170 const char *attr_name,
171 const struct ldb_val *val)
173 struct ldb_message_element *el;
174 struct ldb_val *vals;
176 el = ldb_msg_find_element(msg, attr_name);
178 ldb_msg_add_empty(msg, attr_name, 0);
179 el = ldb_msg_find_element(msg, attr_name);
185 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
191 el->values[el->num_values] = *val;
199 add a string element to a message
201 int ldb_msg_add_string(struct ldb_message *msg,
202 const char *attr_name, const char *str)
206 val.data = discard_const_p(uint8_t, str);
207 val.length = strlen(str);
209 return ldb_msg_add_value(msg, attr_name, &val);
213 add a printf formatted element to a message
215 int ldb_msg_add_fmt(struct ldb_message *msg,
216 const char *attr_name, const char *fmt, ...)
223 str = talloc_vasprintf(msg, fmt, ap);
226 if (str == NULL) return -1;
228 val.data = (uint8_t *)str;
229 val.length = strlen(str);
231 return ldb_msg_add_value(msg, attr_name, &val);
235 compare two ldb_message_element structures
236 assumes case senistive comparison
238 int ldb_msg_element_compare(struct ldb_message_element *el1,
239 struct ldb_message_element *el2)
243 if (el1->num_values != el2->num_values) {
244 return el1->num_values - el2->num_values;
247 for (i=0;i<el1->num_values;i++) {
248 if (!ldb_msg_find_val(el2, &el1->values[i])) {
257 compare two ldb_message_element structures
258 comparing by element name
260 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
261 struct ldb_message_element *el2)
263 return ldb_attr_cmp(el1->name, el2->name);
267 convenience functions to return common types from a message
268 these return the first value if the attribute is multi-valued
270 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
272 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
273 if (!el || el->num_values == 0) {
276 return &el->values[0];
279 int ldb_msg_find_int(const struct ldb_message *msg,
280 const char *attr_name,
283 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
284 if (!v || !v->data) {
285 return default_value;
287 return strtol((const char *)v->data, NULL, 0);
290 unsigned int ldb_msg_find_uint(const struct ldb_message *msg,
291 const char *attr_name,
292 unsigned int default_value)
294 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
295 if (!v || !v->data) {
296 return default_value;
298 return strtoul((const char *)v->data, NULL, 0);
301 int64_t ldb_msg_find_int64(const struct ldb_message *msg,
302 const char *attr_name,
303 int64_t default_value)
305 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
306 if (!v || !v->data) {
307 return default_value;
309 return strtoll((const char *)v->data, NULL, 0);
312 uint64_t ldb_msg_find_uint64(const struct ldb_message *msg,
313 const char *attr_name,
314 uint64_t default_value)
316 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
317 if (!v || !v->data) {
318 return default_value;
320 return strtoull((const char *)v->data, NULL, 0);
323 double ldb_msg_find_double(const struct ldb_message *msg,
324 const char *attr_name,
325 double default_value)
327 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
328 if (!v || !v->data) {
329 return default_value;
331 return strtod((const char *)v->data, NULL);
334 const char *ldb_msg_find_string(const struct ldb_message *msg,
335 const char *attr_name,
336 const char *default_value)
338 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
339 if (!v || !v->data) {
340 return default_value;
342 return (const char *)v->data;
346 sort the elements of a message by name
348 void ldb_msg_sort_elements(struct ldb_message *msg)
350 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
351 (comparison_fn_t)ldb_msg_element_compare_name);
355 copy a message, allocating new memory for all parts
357 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
358 const struct ldb_message *msg)
360 struct ldb_message *msg2;
363 msg2 = talloc(mem_ctx, struct ldb_message);
364 if (msg2 == NULL) return NULL;
366 msg2->elements = NULL;
367 msg2->num_elements = 0;
368 msg2->private_data = NULL;
370 msg2->dn = ldb_dn_copy(msg2, msg->dn);
371 if (msg2->dn == NULL) goto failed;
373 msg2->elements = talloc_array(msg2, struct ldb_message_element, msg->num_elements);
374 if (msg2->elements == NULL) goto failed;
376 for (i=0;i<msg->num_elements;i++) {
377 struct ldb_message_element *el1 = &msg->elements[i];
378 struct ldb_message_element *el2 = &msg2->elements[i];
380 el2->flags = el1->flags;
383 el2->name = talloc_strdup(msg2->elements, el1->name);
384 if (el2->name == NULL) goto failed;
385 el2->values = talloc_array(msg2->elements, struct ldb_val, el1->num_values);
386 for (j=0;j<el1->num_values;j++) {
387 el2->values[j] = ldb_val_dup(el2->values, &el1->values[j]);
388 if (el2->values[j].data == NULL &&
389 el1->values[j].length != 0) {
395 msg2->num_elements++;
407 canonicalise a message, merging elements of the same name
409 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
410 const struct ldb_message *msg)
413 struct ldb_message *msg2;
415 msg2 = ldb_msg_copy(ldb, msg);
416 if (msg2 == NULL) return NULL;
418 ldb_msg_sort_elements(msg2);
420 for (i=1;i<msg2->num_elements;i++) {
421 struct ldb_message_element *el1 = &msg2->elements[i-1];
422 struct ldb_message_element *el2 = &msg2->elements[i];
423 if (ldb_msg_element_compare_name(el1, el2) == 0) {
424 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
425 el1->num_values + el2->num_values);
426 if (el1->values == NULL) {
429 memcpy(el1->values + el1->num_values,
431 sizeof(struct ldb_val) * el2->num_values);
432 el1->num_values += el2->num_values;
433 talloc_free(discard_const_p(char, el2->name));
434 if (i+1<msg2->num_elements) {
435 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
436 (msg2->num_elements - (i+1)));
438 msg2->num_elements--;
448 return a ldb_message representing the differences between msg1 and msg2. If you
449 then use this in a ldb_modify() call it can be used to save edits to a message
451 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
452 struct ldb_message *msg1,
453 struct ldb_message *msg2)
455 struct ldb_message *mod;
456 struct ldb_message_element *el;
459 mod = ldb_msg_new(ldb);
462 mod->num_elements = 0;
463 mod->elements = NULL;
465 msg2 = ldb_msg_canonicalize(ldb, msg2);
470 /* look in msg2 to find elements that need to be added
472 for (i=0;i<msg2->num_elements;i++) {
473 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
475 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
481 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
486 /* look in msg1 to find elements that need to be deleted */
487 for (i=0;i<msg1->num_elements;i++) {
488 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
490 if (ldb_msg_add_empty(mod,
491 msg1->elements[i].name,
492 LDB_FLAG_MOD_DELETE) != 0) {
501 int ldb_msg_sanity_check(const struct ldb_message *msg)
505 /* basic check on DN */
506 if (msg->dn == NULL) {
507 /* TODO: return also an error string */
508 return LDB_ERR_INVALID_DN_SYNTAX;
510 if (msg->dn->comp_num == 0) {
511 /* root dse has empty dn */
512 /* TODO: return also an error string */
513 return LDB_ERR_ENTRY_ALREADY_EXISTS;
516 /* basic syntax checks */
517 for (i = 0; i < msg->num_elements; i++) {
518 for (j = 0; j < msg->elements[i].num_values; j++) {
519 if (msg->elements[i].values[j].length == 0) {
520 /* an attribute cannot be empty */
521 /* TODO: return also an error string */
522 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
534 copy an attribute list. This only copies the array, not the elements
535 (ie. the elements are left as the same pointers)
537 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
541 for (i=0;attrs[i];i++) /* noop */ ;
542 ret = talloc_array(mem_ctx, const char *, i+1);
546 for (i=0;attrs[i];i++) {
555 return 1 if an attribute is in a list of attributes, or 0 otherwise
557 int ldb_attr_in_list(const char * const *attrs, const char *attr)
560 for (i=0;attrs[i];i++) {
561 if (ldb_attr_cmp(attrs[i], attr) == 0) {
570 rename the specified attribute in a search result
572 void ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
574 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
582 copy the specified attribute in a search result to a new attribute
584 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
586 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
590 if (ldb_msg_add(msg, el, 0) != 0) {
593 ldb_msg_rename_attr(msg, attr, replace);