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 3 of the License, or (at your option) any later version.
15
This library is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
Lesser General Public License for more details.
20
You should have received a copy of the GNU Lesser General Public
21
License along with this library; if not, see <http://www.gnu.org/licenses/>.
27
* Component: ldb message component utility functions
29
* Description: functions for manipulating ldb_message structures
31
* Author: Andrew Tridgell
34
#include "ldb_private.h"
37
create a new ldb_message in a given memory context (NULL for top level)
39
struct ldb_message *ldb_msg_new(void *mem_ctx)
41
return talloc_zero(mem_ctx, struct ldb_message);
45
find an element in a message by attribute name
47
struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
48
const char *attr_name)
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];
60
see if two ldb_val structures contain exactly the same data
61
return 1 for a match, 0 for a mis-match
63
int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
65
if (v1->length != v2->length) return 0;
67
if (v1->length == 0) return 1;
69
if (memcmp(v1->data, v2->data, v1->length) == 0) {
77
find a value in an element
78
assumes case sensitive comparison
80
struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
84
for (i=0;i<el->num_values;i++) {
85
if (ldb_val_equal_exact(val, &el->values[i])) {
86
return &el->values[i];
93
duplicate a ldb_val structure
95
struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
98
v2.length = v->length;
99
if (v->data == NULL) {
104
/* the +1 is to cope with buggy C library routines like strndup
105
that look one byte beyond */
106
v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
112
memcpy(v2.data, v->data, v->length);
113
((char *)v2.data)[v->length] = 0;
118
add an empty element to a message
120
int ldb_msg_add_empty( struct ldb_message *msg,
121
const char *attr_name,
123
struct ldb_message_element **return_el)
125
struct ldb_message_element *els;
127
els = talloc_realloc(msg, msg->elements,
128
struct ldb_message_element, msg->num_elements+1);
131
return LDB_ERR_OPERATIONS_ERROR;
134
els[msg->num_elements].values = NULL;
135
els[msg->num_elements].num_values = 0;
136
els[msg->num_elements].flags = flags;
137
els[msg->num_elements].name = talloc_strdup(els, attr_name);
138
if (!els[msg->num_elements].name) {
140
return LDB_ERR_OPERATIONS_ERROR;
147
*return_el = &els[msg->num_elements-1];
154
add an empty element to a message
156
int ldb_msg_add(struct ldb_message *msg,
157
const struct ldb_message_element *el,
160
/* We have to copy this, just in case *el is a pointer into
161
* what ldb_msg_add_empty() is about to realloc() */
162
struct ldb_message_element el_copy = *el;
163
if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
164
return LDB_ERR_OPERATIONS_ERROR;
167
msg->elements[msg->num_elements-1] = el_copy;
168
msg->elements[msg->num_elements-1].flags = flags;
174
add a value to a message
176
int ldb_msg_add_value(struct ldb_message *msg,
177
const char *attr_name,
178
const struct ldb_val *val,
179
struct ldb_message_element **return_el)
181
struct ldb_message_element *el;
182
struct ldb_val *vals;
185
el = ldb_msg_find_element(msg, attr_name);
187
ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
188
if (ret != LDB_SUCCESS) {
193
vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
196
return LDB_ERR_OPERATIONS_ERROR;
199
el->values[el->num_values] = *val;
211
add a value to a message, stealing it into the 'right' place
213
int ldb_msg_add_steal_value(struct ldb_message *msg,
214
const char *attr_name,
218
struct ldb_message_element *el;
220
ret = ldb_msg_add_value(msg, attr_name, val, &el);
221
if (ret == LDB_SUCCESS) {
222
talloc_steal(el->values, val->data);
229
add a string element to a message
231
int ldb_msg_add_string(struct ldb_message *msg,
232
const char *attr_name, const char *str)
236
val.data = discard_const_p(uint8_t, str);
237
val.length = strlen(str);
239
if (val.length == 0) {
240
/* allow empty strings as non-existant attributes */
244
return ldb_msg_add_value(msg, attr_name, &val, NULL);
248
add a string element to a message, stealing it into the 'right' place
250
int ldb_msg_add_steal_string(struct ldb_message *msg,
251
const char *attr_name, char *str)
255
val.data = (uint8_t *)str;
256
val.length = strlen(str);
258
return ldb_msg_add_steal_value(msg, attr_name, &val);
262
add a printf formatted element to a message
264
int ldb_msg_add_fmt(struct ldb_message *msg,
265
const char *attr_name, const char *fmt, ...)
272
str = talloc_vasprintf(msg, fmt, ap);
275
if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
277
val.data = (uint8_t *)str;
278
val.length = strlen(str);
280
return ldb_msg_add_steal_value(msg, attr_name, &val);
284
compare two ldb_message_element structures
285
assumes case senistive comparison
287
int ldb_msg_element_compare(struct ldb_message_element *el1,
288
struct ldb_message_element *el2)
292
if (el1->num_values != el2->num_values) {
293
return el1->num_values - el2->num_values;
296
for (i=0;i<el1->num_values;i++) {
297
if (!ldb_msg_find_val(el2, &el1->values[i])) {
306
compare two ldb_message_element structures
307
comparing by element name
309
int ldb_msg_element_compare_name(struct ldb_message_element *el1,
310
struct ldb_message_element *el2)
312
return ldb_attr_cmp(el1->name, el2->name);
316
convenience functions to return common types from a message
317
these return the first value if the attribute is multi-valued
319
const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
320
const char *attr_name)
322
struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
323
if (!el || el->num_values == 0) {
326
return &el->values[0];
329
int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
330
const char *attr_name,
333
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
334
if (!v || !v->data) {
335
return default_value;
337
return strtol((const char *)v->data, NULL, 0);
340
unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
341
const char *attr_name,
342
unsigned int default_value)
344
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
345
if (!v || !v->data) {
346
return default_value;
348
return strtoul((const char *)v->data, NULL, 0);
351
int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
352
const char *attr_name,
353
int64_t default_value)
355
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
356
if (!v || !v->data) {
357
return default_value;
359
return strtoll((const char *)v->data, NULL, 0);
362
uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
363
const char *attr_name,
364
uint64_t default_value)
366
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
367
if (!v || !v->data) {
368
return default_value;
370
return strtoull((const char *)v->data, NULL, 0);
373
double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
374
const char *attr_name,
375
double default_value)
377
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
378
if (!v || !v->data) {
379
return default_value;
381
return strtod((const char *)v->data, NULL);
384
int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
385
const char *attr_name,
388
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
389
if (!v || !v->data) {
390
return default_value;
392
if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
395
if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
398
return default_value;
401
const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
402
const char *attr_name,
403
const char *default_value)
405
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
406
if (!v || !v->data) {
407
return default_value;
409
return (const char *)v->data;
412
struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
414
const struct ldb_message *msg,
415
const char *attr_name)
417
struct ldb_dn *res_dn;
418
const struct ldb_val *v;
420
v = ldb_msg_find_ldb_val(msg, attr_name);
421
if (!v || !v->data) {
424
res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
425
if ( ! ldb_dn_validate(res_dn)) {
433
sort the elements of a message by name
435
void ldb_msg_sort_elements(struct ldb_message *msg)
437
qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
438
(comparison_fn_t)ldb_msg_element_compare_name);
442
shallow copy a message - copying only the elements array so that the caller
443
can safely add new elements without changing the message
445
struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
446
const struct ldb_message *msg)
448
struct ldb_message *msg2;
451
msg2 = talloc(mem_ctx, struct ldb_message);
452
if (msg2 == NULL) return NULL;
456
msg2->elements = talloc_array(msg2, struct ldb_message_element,
458
if (msg2->elements == NULL) goto failed;
460
for (i=0;i<msg2->num_elements;i++) {
461
msg2->elements[i] = msg->elements[i];
473
copy a message, allocating new memory for all parts
475
struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
476
const struct ldb_message *msg)
478
struct ldb_message *msg2;
481
msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
482
if (msg2 == NULL) return NULL;
484
msg2->dn = ldb_dn_copy(msg2, msg2->dn);
485
if (msg2->dn == NULL) goto failed;
487
for (i=0;i<msg2->num_elements;i++) {
488
struct ldb_message_element *el = &msg2->elements[i];
489
struct ldb_val *values = el->values;
490
el->name = talloc_strdup(msg2->elements, el->name);
491
if (el->name == NULL) goto failed;
492
el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
493
for (j=0;j<el->num_values;j++) {
494
el->values[j] = ldb_val_dup(el->values, &values[j]);
495
if (el->values[j].data == NULL && values[j].length != 0) {
510
canonicalise a message, merging elements of the same name
512
struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
513
const struct ldb_message *msg)
516
struct ldb_message *msg2;
518
msg2 = ldb_msg_copy(ldb, msg);
519
if (msg2 == NULL) return NULL;
521
ldb_msg_sort_elements(msg2);
523
for (i=1;i<msg2->num_elements;i++) {
524
struct ldb_message_element *el1 = &msg2->elements[i-1];
525
struct ldb_message_element *el2 = &msg2->elements[i];
526
if (ldb_msg_element_compare_name(el1, el2) == 0) {
527
el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
528
el1->num_values + el2->num_values);
529
if (el1->values == NULL) {
532
memcpy(el1->values + el1->num_values,
534
sizeof(struct ldb_val) * el2->num_values);
535
el1->num_values += el2->num_values;
536
talloc_free(discard_const_p(char, el2->name));
537
if (i+1<msg2->num_elements) {
538
memmove(el2, el2+1, sizeof(struct ldb_message_element) *
539
(msg2->num_elements - (i+1)));
541
msg2->num_elements--;
551
return a ldb_message representing the differences between msg1 and msg2. If you
552
then use this in a ldb_modify() call it can be used to save edits to a message
554
struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
555
struct ldb_message *msg1,
556
struct ldb_message *msg2)
558
struct ldb_message *mod;
559
struct ldb_message_element *el;
562
mod = ldb_msg_new(ldb);
565
mod->num_elements = 0;
566
mod->elements = NULL;
568
msg2 = ldb_msg_canonicalize(ldb, msg2);
573
/* look in msg2 to find elements that need to be added
575
for (i=0;i<msg2->num_elements;i++) {
576
el = ldb_msg_find_element(msg1, msg2->elements[i].name);
578
if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
584
el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
589
/* look in msg1 to find elements that need to be deleted */
590
for (i=0;i<msg1->num_elements;i++) {
591
el = ldb_msg_find_element(msg2, msg1->elements[i].name);
593
if (ldb_msg_add_empty(mod,
594
msg1->elements[i].name,
595
LDB_FLAG_MOD_DELETE, NULL) != 0) {
604
int ldb_msg_sanity_check(struct ldb_context *ldb,
605
const struct ldb_message *msg)
609
/* basic check on DN */
610
if (msg->dn == NULL) {
611
/* TODO: return also an error string */
612
ldb_set_errstring(ldb, "ldb message lacks a DN!");
613
return LDB_ERR_INVALID_DN_SYNTAX;
616
/* basic syntax checks */
617
for (i = 0; i < msg->num_elements; i++) {
618
for (j = 0; j < msg->elements[i].num_values; j++) {
619
if (msg->elements[i].values[j].length == 0) {
620
TALLOC_CTX *mem_ctx = talloc_new(ldb);
621
/* an attribute cannot be empty */
622
/* TODO: return also an error string */
623
ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
624
msg->elements[i].name,
625
ldb_dn_get_linearized(msg->dn));
626
talloc_free(mem_ctx);
627
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
639
copy an attribute list. This only copies the array, not the elements
640
(ie. the elements are left as the same pointers)
642
const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
646
for (i=0;attrs[i];i++) /* noop */ ;
647
ret = talloc_array(mem_ctx, const char *, i+1);
651
for (i=0;attrs[i];i++) {
660
copy an attribute list. This only copies the array, not the elements
661
(ie. the elements are left as the same pointers). The new attribute is added to the list.
663
const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
668
for (i=0;attrs[i];i++) {
669
if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
674
return ldb_attr_list_copy(mem_ctx, attrs);
676
ret = talloc_array(mem_ctx, const char *, i+2);
680
for (i=0;attrs[i];i++) {
690
return 1 if an attribute is in a list of attributes, or 0 otherwise
692
int ldb_attr_in_list(const char * const *attrs, const char *attr)
695
for (i=0;attrs && attrs[i];i++) {
696
if (ldb_attr_cmp(attrs[i], attr) == 0) {
705
rename the specified attribute in a search result
707
int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
709
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
713
el->name = talloc_strdup(msg->elements, replace);
714
if (el->name == NULL) {
715
return LDB_ERR_OPERATIONS_ERROR;
722
copy the specified attribute in a search result to a new attribute
724
int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
726
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
730
if (ldb_msg_add(msg, el, 0) != 0) {
731
return LDB_ERR_OPERATIONS_ERROR;
733
return ldb_msg_rename_attr(msg, attr, replace);
737
remove the specified element in a search result
739
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
741
int n = (el - msg->elements);
742
if (n != msg->num_elements-1) {
743
memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
750
remove the specified attribute in a search result
752
void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
754
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
756
ldb_msg_remove_element(msg, el);
761
return a LDAP formatted GeneralizedTime string
763
char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
765
struct tm *tm = gmtime(&t);
773
/* we now excatly how long this string will be */
774
ts = talloc_array(mem_ctx, char, 18);
776
/* formatted like: 20040408072012.0Z */
778
"%04u%02u%02u%02u%02u%02u.0Z",
779
tm->tm_year+1900, tm->tm_mon+1,
780
tm->tm_mday, tm->tm_hour, tm->tm_min,
792
convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
794
time_t ldb_string_to_time(const char *s)
798
if (s == NULL) return 0;
800
memset(&tm, 0, sizeof(tm));
801
if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
802
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
803
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
813
return a LDAP formatted UTCTime string
815
char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
817
struct tm *tm = gmtime(&t);
825
/* we now excatly how long this string will be */
826
ts = talloc_array(mem_ctx, char, 14);
828
/* formatted like: 20040408072012.0Z => 040408072012Z */
830
"%02u%02u%02u%02u%02u%02uZ",
831
(tm->tm_year+1900)%100, tm->tm_mon+1,
832
tm->tm_mday, tm->tm_hour, tm->tm_min,
844
convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
846
time_t ldb_string_utc_to_time(const char *s)
850
if (s == NULL) return 0;
852
memset(&tm, 0, sizeof(tm));
853
if (sscanf(s, "%02u%02u%02u%02u%02u%02u",
854
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
855
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
858
if (tm.tm_year < 50) {
868
dump a set of results to a file. Useful from within gdb
870
void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
874
for (i = 0; i < result->count; i++) {
875
struct ldb_ldif ldif;
876
fprintf(f, "# record %d\n", i+1);
877
ldif.changetype = LDB_CHANGETYPE_NONE;
878
ldif.msg = result->msgs[i];
879
ldb_ldif_write_file(ldb, f, &ldif);
883
int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
885
struct ldb_message_element *el;
888
el = ldb_msg_find_element(msg, name);
892
val.data = discard_const_p(uint8_t, value);
893
val.length = strlen(value);
895
if (ldb_msg_find_val(el, &val))