X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Flib%2Fldb%2Fcommon%2Fldb_msg.c;h=4b3271166c462e1ceb33df479f57151ce65fde31;hb=694fef30d8e5f4f9a0122bb24f8a339938e50a57;hp=f76d7e8dd9a64814cb36237b91cdea816002cbfe;hpb=af03a9b8fbe32d9c7a2bcd1d4cb377b44894d666;p=kamenim%2Fsamba.git diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c index f76d7e8dd9..4b3271166c 100644 --- a/source4/lib/ldb/common/ldb_msg.c +++ b/source4/lib/ldb/common/ldb_msg.c @@ -10,7 +10,7 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,8 +18,7 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + License along with this library; if not, see . */ /* @@ -32,8 +31,7 @@ * Author: Andrew Tridgell */ -#include "includes.h" -#include "ldb/include/includes.h" +#include "ldb_private.h" /* create a new ldb_message in a given memory context (NULL for top level) @@ -65,7 +63,7 @@ struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2) { if (v1->length != v2->length) return 0; - + if (v1->data == v2->data) return 1; if (v1->length == 0) return 1; if (memcmp(v1->data, v2->data, v1->length) == 0) { @@ -116,54 +114,95 @@ struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v) return v2; } -/* - add an empty element to a message -*/ -int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) +/** + * Adds new empty element to msg->elements + */ +static int _ldb_msg_add_el(struct ldb_message *msg, + struct ldb_message_element **return_el) { struct ldb_message_element *els; - if (! ldb_valid_attr_name(attr_name)) { - return -1; - } + /* TODO: Find out a way to assert + * on input parameters. + * msg and return_el must be valid */ - els = talloc_realloc(msg, msg->elements, - struct ldb_message_element, msg->num_elements+1); + els = talloc_realloc(msg, msg->elements, + struct ldb_message_element, msg->num_elements + 1); if (!els) { errno = ENOMEM; - return -1; + return LDB_ERR_OPERATIONS_ERROR; } - els[msg->num_elements].values = NULL; - els[msg->num_elements].num_values = 0; - els[msg->num_elements].flags = flags; - els[msg->num_elements].name = talloc_strdup(els, attr_name); - if (!els[msg->num_elements].name) { - errno = ENOMEM; - return -1; - } + ZERO_STRUCT(els[msg->num_elements]); msg->elements = els; msg->num_elements++; - return 0; + *return_el = &els[msg->num_elements-1]; + + return LDB_SUCCESS; } -/* - add an empty element to a message -*/ +/** + * Add an empty element with a given name to a message + */ +int ldb_msg_add_empty(struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el) +{ + int ret; + struct ldb_message_element *el; + + ret = _ldb_msg_add_el(msg, &el); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* initialize newly added element */ + el->flags = flags; + el->name = talloc_strdup(msg->elements, attr_name); + if (!el->name) { + errno = ENOMEM; + return LDB_ERR_OPERATIONS_ERROR; + } + + if (return_el) { + *return_el = el; + } + + return LDB_SUCCESS; +} + +/** + * Adds an element to a message. + * + * NOTE: Ownership of ldb_message_element fields + * is NOT transferred. Thus, if el pointer + * is invalidated for some reason, this will + * corrupt msg contents also + */ int ldb_msg_add(struct ldb_message *msg, const struct ldb_message_element *el, int flags) { - if (ldb_msg_add_empty(msg, el->name, flags) != 0) { - return -1; + int ret; + struct ldb_message_element *el_new; + /* We have to copy this, just in case *el is a pointer into + * what ldb_msg_add_empty() is about to realloc() */ + struct ldb_message_element el_copy = *el; + + ret = _ldb_msg_add_el(msg, &el_new); + if (ret != LDB_SUCCESS) { + return ret; } - msg->elements[msg->num_elements-1] = *el; - msg->elements[msg->num_elements-1].flags = flags; + el_new->flags = flags; + el_new->name = el_copy.name; + el_new->num_values = el_copy.num_values; + el_new->values = el_copy.values; - return 0; + return LDB_SUCCESS; } /* @@ -171,30 +210,35 @@ int ldb_msg_add(struct ldb_message *msg, */ int ldb_msg_add_value(struct ldb_message *msg, const char *attr_name, - const struct ldb_val *val) + const struct ldb_val *val, + struct ldb_message_element **return_el) { struct ldb_message_element *el; struct ldb_val *vals; + int ret; el = ldb_msg_find_element(msg, attr_name); if (!el) { - ldb_msg_add_empty(msg, attr_name, 0); - el = ldb_msg_find_element(msg, attr_name); - } - if (!el) { - return -1; + ret = ldb_msg_add_empty(msg, attr_name, 0, &el); + if (ret != LDB_SUCCESS) { + return ret; + } } vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1); if (!vals) { errno = ENOMEM; - return -1; + return LDB_ERR_OPERATIONS_ERROR; } el->values = vals; el->values[el->num_values] = *val; el->num_values++; - return 0; + if (return_el) { + *return_el = el; + } + + return LDB_SUCCESS; } @@ -206,10 +250,10 @@ int ldb_msg_add_steal_value(struct ldb_message *msg, struct ldb_val *val) { int ret; - ret = ldb_msg_add_value(msg, attr_name, val); + struct ldb_message_element *el; + + ret = ldb_msg_add_value(msg, attr_name, val, &el); if (ret == LDB_SUCCESS) { - struct ldb_message_element *el; - el = ldb_msg_find_element(msg, attr_name); talloc_steal(el->values, val->data); } return ret; @@ -227,7 +271,12 @@ int ldb_msg_add_string(struct ldb_message *msg, val.data = discard_const_p(uint8_t, str); val.length = strlen(str); - return ldb_msg_add_value(msg, attr_name, &val); + if (val.length == 0) { + /* allow empty strings as non-existent attributes */ + return LDB_SUCCESS; + } + + return ldb_msg_add_value(msg, attr_name, &val, NULL); } /* @@ -241,9 +290,26 @@ int ldb_msg_add_steal_string(struct ldb_message *msg, val.data = (uint8_t *)str; val.length = strlen(str); + if (val.length == 0) { + /* allow empty strings as non-existent attributes */ + return LDB_SUCCESS; + } + return ldb_msg_add_steal_value(msg, attr_name, &val); } +/* + add a DN element to a message + WARNING: this uses the linearized string from the dn, and does not + copy the string. +*/ +int ldb_msg_add_linearized_dn(struct ldb_message *msg, const char *attr_name, + struct ldb_dn *dn) +{ + return ldb_msg_add_steal_string(msg, attr_name, + ldb_dn_alloc_linearized(msg, dn)); +} + /* add a printf formatted element to a message */ @@ -258,7 +324,7 @@ int ldb_msg_add_fmt(struct ldb_message *msg, str = talloc_vasprintf(msg, fmt, ap); va_end(ap); - if (str == NULL) return -1; + if (str == NULL) return LDB_ERR_OPERATIONS_ERROR; val.data = (uint8_t *)str; val.length = strlen(str); @@ -268,7 +334,7 @@ int ldb_msg_add_fmt(struct ldb_message *msg, /* compare two ldb_message_element structures - assumes case senistive comparison + assumes case sensitive comparison */ int ldb_msg_element_compare(struct ldb_message_element *el1, struct ldb_message_element *el2) @@ -302,7 +368,8 @@ int ldb_msg_element_compare_name(struct ldb_message_element *el1, convenience functions to return common types from a message these return the first value if the attribute is multi-valued */ -const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name) +const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, + const char *attr_name) { struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name); if (!el || el->num_values == 0) { @@ -311,9 +378,9 @@ const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const return &el->values[0]; } -int ldb_msg_find_int(const struct ldb_message *msg, - const char *attr_name, - int default_value) +int ldb_msg_find_attr_as_int(const struct ldb_message *msg, + const char *attr_name, + int default_value) { const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { @@ -322,20 +389,29 @@ int ldb_msg_find_int(const struct ldb_message *msg, return strtol((const char *)v->data, NULL, 0); } -unsigned int ldb_msg_find_uint(const struct ldb_message *msg, - const char *attr_name, - unsigned int default_value) +unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, + const char *attr_name, + unsigned int default_value) { + unsigned int ret; const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { return default_value; } + + /* in LDAP there're only int32_t values */ + errno = 0; + ret = strtol((const char *)v->data, NULL, 0); + if (errno == 0) { + return ret; + } + return strtoul((const char *)v->data, NULL, 0); } -int64_t ldb_msg_find_int64(const struct ldb_message *msg, - const char *attr_name, - int64_t default_value) +int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, + const char *attr_name, + int64_t default_value) { const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { @@ -344,20 +420,29 @@ int64_t ldb_msg_find_int64(const struct ldb_message *msg, return strtoll((const char *)v->data, NULL, 0); } -uint64_t ldb_msg_find_uint64(const struct ldb_message *msg, - const char *attr_name, - uint64_t default_value) +uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, + const char *attr_name, + uint64_t default_value) { + uint64_t ret; const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { return default_value; } + + /* in LDAP there're only int64_t values */ + errno = 0; + ret = strtoll((const char *)v->data, NULL, 0); + if (errno == 0) { + return ret; + } + return strtoull((const char *)v->data, NULL, 0); } -double ldb_msg_find_double(const struct ldb_message *msg, - const char *attr_name, - double default_value) +double ldb_msg_find_attr_as_double(const struct ldb_message *msg, + const char *attr_name, + double default_value) { const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { @@ -366,9 +451,26 @@ double ldb_msg_find_double(const struct ldb_message *msg, return strtod((const char *)v->data, NULL); } -const char *ldb_msg_find_string(const struct ldb_message *msg, - const char *attr_name, - const char *default_value) +int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, + const char *attr_name, + int default_value) +{ + const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return default_value; + } + if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) { + return 0; + } + if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) { + return 1; + } + return default_value; +} + +const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, + const char *attr_name, + const char *default_value) { const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { @@ -377,13 +479,33 @@ const char *ldb_msg_find_string(const struct ldb_message *msg, return (const char *)v->data; } +struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *msg, + const char *attr_name) +{ + struct ldb_dn *res_dn; + const struct ldb_val *v; + + v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return NULL; + } + res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v); + if ( ! ldb_dn_validate(res_dn)) { + talloc_free(res_dn); + return NULL; + } + return res_dn; +} + /* sort the elements of a message by name */ void ldb_msg_sort_elements(struct ldb_message *msg) { - qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), - (comparison_fn_t)ldb_msg_element_compare_name); + TYPESAFE_QSORT(msg->elements, msg->num_elements, + ldb_msg_element_compare_name); } /* @@ -394,13 +516,12 @@ struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx, const struct ldb_message *msg) { struct ldb_message *msg2; - int i; + unsigned int i; msg2 = talloc(mem_ctx, struct ldb_message); if (msg2 == NULL) return NULL; *msg2 = *msg; - msg2->private_data = NULL; msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements); @@ -425,7 +546,7 @@ struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, const struct ldb_message *msg) { struct ldb_message *msg2; - int i, j; + unsigned int i, j; msg2 = ldb_msg_copy_shallow(mem_ctx, msg); if (msg2 == NULL) return NULL; @@ -455,36 +576,62 @@ failed: } -/* - canonicalise a message, merging elements of the same name -*/ +/** + * Canonicalize a message, merging elements of the same name + */ struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, const struct ldb_message *msg) { - int i; + int ret; struct ldb_message *msg2; - msg2 = ldb_msg_copy(ldb, msg); - if (msg2 == NULL) return NULL; + /* allocate msg2 message in NULL context + * so it should appear as 'leaked' in talloc reports */ + ret = ldb_msg_canonicalize_ex(ldb, msg, (TALLOC_CTX*)NULL, &msg2); + if (ret != LDB_SUCCESS) { + return NULL; + } + + return msg2; +} + +/** + * Canonicalize a message, merging elements of the same name + */ +int ldb_msg_canonicalize_ex(struct ldb_context *ldb, + const struct ldb_message *msg, + TALLOC_CTX *mem_ctx, + struct ldb_message **_msg_out) +{ + unsigned int i; + struct ldb_message *msg2; + + msg2 = ldb_msg_copy(mem_ctx, msg); + if (msg2 == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } ldb_msg_sort_elements(msg2); - for (i=1;inum_elements;i++) { + for (i=1; i < msg2->num_elements; i++) { struct ldb_message_element *el1 = &msg2->elements[i-1]; struct ldb_message_element *el2 = &msg2->elements[i]; + if (ldb_msg_element_compare_name(el1, el2) == 0) { - el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, - el1->num_values + el2->num_values); - if (el1->values == NULL) { - return NULL; + el1->values = talloc_realloc(msg2->elements, + el1->values, struct ldb_val, + el1->num_values + el2->num_values); + if (el1->num_values + el2->num_values > 0 && el1->values == NULL) { + talloc_free(msg2); + return LDB_ERR_OPERATIONS_ERROR; } memcpy(el1->values + el1->num_values, el2->values, sizeof(struct ldb_val) * el2->num_values); el1->num_values += el2->num_values; talloc_free(discard_const_p(char, el2->name)); - if (i+1num_elements) { - memmove(el2, el2+1, sizeof(struct ldb_message_element) * + if ((i+1) < msg2->num_elements) { + memmove(el2, el2+1, sizeof(struct ldb_message_element) * (msg2->num_elements - (i+1))); } msg2->num_elements--; @@ -492,7 +639,8 @@ struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, } } - return msg2; + *_msg_out = msg2; + return LDB_SUCCESS; } @@ -504,21 +652,67 @@ struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, struct ldb_message *msg1, struct ldb_message *msg2) { + int ldb_ret; struct ldb_message *mod; - struct ldb_message_element *el; + + /* allocate mod message in NULL context + * so it should appear as 'leaked' in talloc reports */ + ldb_ret = ldb_msg_diff_ex(ldb, msg1, msg2, + (TALLOC_CTX*)NULL, &mod); + if (ldb_ret != LDB_SUCCESS) { + return NULL; + } + + return mod; +} + +/** + * return a ldb_message representing the differences between msg1 and msg2. + * If you then use this in a ldb_modify() call it can be used to save edits to a message + * + * Result message is constructed as follows: + * - LDB_FLAG_MOD_ADD - elements found only in msg2 + * - LDB_FLAG_MOD_REPLACE - elements in msg2 that have different value in msg1 + * Value for msg2 element is used + * - LDB_FLAG_MOD_DELETE - elements found only in msg2 + * + * @return LDB_SUCCESS or LDB_ERR_OPERATIONS_ERROR + */ +int ldb_msg_diff_ex(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2, + TALLOC_CTX *mem_ctx, + struct ldb_message **_msg_out) +{ + int ldb_res; unsigned int i; + struct ldb_message *mod; + struct ldb_message_element *el; + TALLOC_CTX *temp_ctx; + + temp_ctx = talloc_new(mem_ctx); + if (!temp_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } - mod = ldb_msg_new(ldb); + mod = ldb_msg_new(temp_ctx); + if (mod == NULL) { + goto failed; + } mod->dn = msg1->dn; mod->num_elements = 0; mod->elements = NULL; - msg2 = ldb_msg_canonicalize(ldb, msg2); - if (msg2 == NULL) { - return NULL; + /* Canonicalize msg2 so we have no repeated elements + * Resulting message is allocated in mod's mem context, + * as we are going to move some elements from msg2 to + * mod object later */ + ldb_res = ldb_msg_canonicalize_ex(ldb, msg2, (TALLOC_CTX*)mod, &msg2); + if (ldb_res != LDB_SUCCESS) { + goto failed; } - + /* look in msg2 to find elements that need to be added or modified */ for (i=0;inum_elements;i++) { @@ -528,49 +722,63 @@ struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, continue; } - if (ldb_msg_add(mod, - &msg2->elements[i], - el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) { - return NULL; + ldb_res = ldb_msg_add(mod, + &msg2->elements[i], + el ? LDB_FLAG_MOD_REPLACE : LDB_FLAG_MOD_ADD); + if (ldb_res != LDB_SUCCESS) { + goto failed; } } /* look in msg1 to find elements that need to be deleted */ for (i=0;inum_elements;i++) { el = ldb_msg_find_element(msg2, msg1->elements[i].name); - if (!el) { - if (ldb_msg_add_empty(mod, - msg1->elements[i].name, - LDB_FLAG_MOD_DELETE) != 0) { - return NULL; + if (el == NULL) { + ldb_res = ldb_msg_add_empty(mod, + msg1->elements[i].name, + LDB_FLAG_MOD_DELETE, NULL); + if (ldb_res != LDB_SUCCESS) { + goto failed; } } } - return mod; + /* steal resulting message into supplied context */ + talloc_steal(mem_ctx, mod); + *_msg_out = mod; + + talloc_free(temp_ctx); + return LDB_SUCCESS; + +failed: + talloc_free(temp_ctx); + return LDB_ERR_OPERATIONS_ERROR; } -int ldb_msg_sanity_check(const struct ldb_message *msg) + +int ldb_msg_sanity_check(struct ldb_context *ldb, + const struct ldb_message *msg) { - int i, j; + unsigned int i, j; /* basic check on DN */ if (msg->dn == NULL) { /* TODO: return also an error string */ + ldb_set_errstring(ldb, "ldb message lacks a DN!"); return LDB_ERR_INVALID_DN_SYNTAX; } - if (msg->dn->comp_num == 0) { - /* root dse has empty dn */ - /* TODO: return also an error string */ - return LDB_ERR_ENTRY_ALREADY_EXISTS; - } /* basic syntax checks */ for (i = 0; i < msg->num_elements; i++) { for (j = 0; j < msg->elements[i].num_values; j++) { if (msg->elements[i].values[j].length == 0) { + TALLOC_CTX *mem_ctx = talloc_new(ldb); /* an attribute cannot be empty */ /* TODO: return also an error string */ + ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!", + msg->elements[i].name, + ldb_dn_get_linearized(msg->dn)); + talloc_free(mem_ctx); return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; } } @@ -589,13 +797,14 @@ int ldb_msg_sanity_check(const struct ldb_message *msg) const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs) { const char **ret; - int i; - for (i=0;attrs[i];i++) /* noop */ ; + unsigned int i; + + for (i=0;attrs && attrs[i];i++) /* noop */ ; ret = talloc_array(mem_ctx, const char *, i+1); if (ret == NULL) { return NULL; } - for (i=0;attrs[i];i++) { + for (i=0;attrs && attrs[i];i++) { ret[i] = attrs[i]; } ret[i] = attrs[i]; @@ -603,13 +812,44 @@ const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs) } +/* + copy an attribute list. This only copies the array, not the elements + (ie. the elements are left as the same pointers). The new attribute is added to the list. +*/ +const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr) +{ + const char **ret; + unsigned int i; + bool found = false; + + for (i=0;attrs && attrs[i];i++) { + if (ldb_attr_cmp(attrs[i], new_attr) == 0) { + found = true; + } + } + if (found) { + return ldb_attr_list_copy(mem_ctx, attrs); + } + ret = talloc_array(mem_ctx, const char *, i+2); + if (ret == NULL) { + return NULL; + } + for (i=0;attrs && attrs[i];i++) { + ret[i] = attrs[i]; + } + ret[i] = new_attr; + ret[i+1] = NULL; + return ret; +} + + /* return 1 if an attribute is in a list of attributes, or 0 otherwise */ int ldb_attr_in_list(const char * const *attrs, const char *attr) { - int i; - for (i=0;attrs[i];i++) { + unsigned int i; + for (i=0;attrs && attrs[i];i++) { if (ldb_attr_cmp(attrs[i], attr) == 0) { return 1; } @@ -625,13 +865,13 @@ int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *r { struct ldb_message_element *el = ldb_msg_find_element(msg, attr); if (el == NULL) { - return 0; + return LDB_SUCCESS; } el->name = talloc_strdup(msg->elements, replace); if (el->name == NULL) { - return -1; + return LDB_ERR_OPERATIONS_ERROR; } - return 0; + return LDB_SUCCESS; } @@ -642,52 +882,76 @@ int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *rep { struct ldb_message_element *el = ldb_msg_find_element(msg, attr); if (el == NULL) { - return 0; + return LDB_SUCCESS; } if (ldb_msg_add(msg, el, 0) != 0) { - return -1; + return LDB_ERR_OPERATIONS_ERROR; } return ldb_msg_rename_attr(msg, attr, replace); } +/* + remove the specified element in a search result +*/ +void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el) +{ + ptrdiff_t n = (el - msg->elements); + if (n >= msg->num_elements) { + /* should we abort() here? */ + return; + } + if (n != msg->num_elements-1) { + memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el)); + } + msg->num_elements--; +} + /* remove the specified attribute in a search result */ void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr) { - struct ldb_message_element *el = ldb_msg_find_element(msg, attr); - if (el) { - int n = (el - msg->elements); - if (n != msg->num_elements-1) { - memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el)); - } - msg->num_elements--; + struct ldb_message_element *el; + + while ((el = ldb_msg_find_element(msg, attr)) != NULL) { + ldb_msg_remove_element(msg, el); } } /* - return a LDAP formatted time string + return a LDAP formatted GeneralizedTime string */ char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t) { struct tm *tm = gmtime(&t); + char *ts; + int r; if (!tm) { return NULL; } + /* we now excatly how long this string will be */ + ts = talloc_array(mem_ctx, char, 18); + /* formatted like: 20040408072012.0Z */ - return talloc_asprintf(mem_ctx, - "%04u%02u%02u%02u%02u%02u.0Z", - tm->tm_year+1900, tm->tm_mon+1, - tm->tm_mday, tm->tm_hour, tm->tm_min, - tm->tm_sec); -} + r = snprintf(ts, 18, + "%04u%02u%02u%02u%02u%02u.0Z", + tm->tm_year+1900, tm->tm_mon+1, + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + if (r != 17) { + talloc_free(ts); + return NULL; + } + return ts; +} /* - convert a LDAP time string to a time_t. Return 0 if unable to convert + convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert */ time_t ldb_string_to_time(const char *s) { @@ -696,7 +960,7 @@ time_t ldb_string_to_time(const char *s) if (s == NULL) return 0; memset(&tm, 0, sizeof(tm)); - if (sscanf(s, "%04u%02u%02u%02u%02u%02u", + if (sscanf(s, "%04u%02u%02u%02u%02u%02u.0Z", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { return 0; @@ -707,13 +971,94 @@ time_t ldb_string_to_time(const char *s) return timegm(&tm); } +/* + convert a LDAP GeneralizedTime string in ldb_val format to a + time_t. +*/ +int ldb_val_to_time(const struct ldb_val *v, time_t *t) +{ + struct tm tm; + + if (v == NULL || !v->data || v->length < 17) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + memset(&tm, 0, sizeof(tm)); + + if (sscanf((char *)v->data, "%04u%02u%02u%02u%02u%02u.0Z", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + *t = timegm(&tm); + + return LDB_SUCCESS; +} + +/* + return a LDAP formatted UTCTime string +*/ +char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t) +{ + struct tm *tm = gmtime(&t); + char *ts; + int r; + + if (!tm) { + return NULL; + } + + /* we now excatly how long this string will be */ + ts = talloc_array(mem_ctx, char, 14); + + /* formatted like: 20040408072012.0Z => 040408072012Z */ + r = snprintf(ts, 14, + "%02u%02u%02u%02u%02u%02uZ", + (tm->tm_year+1900)%100, tm->tm_mon+1, + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + if (r != 13) { + talloc_free(ts); + return NULL; + } + + return ts; +} + +/* + convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert +*/ +time_t ldb_string_utc_to_time(const char *s) +{ + struct tm tm; + + if (s == NULL) return 0; + + memset(&tm, 0, sizeof(tm)); + if (sscanf(s, "%02u%02u%02u%02u%02u%02uZ", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return 0; + } + if (tm.tm_year < 50) { + tm.tm_year += 100; + } + tm.tm_mon -= 1; + + return timegm(&tm); +} + /* dump a set of results to a file. Useful from within gdb */ void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f) { - int i; + unsigned int i; for (i = 0; i < result->count; i++) { struct ldb_ldif ldif; @@ -724,3 +1069,27 @@ void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE * } } +/* + checks for a string attribute. Returns "1" on match and otherwise "0". +*/ +int ldb_msg_check_string_attribute(const struct ldb_message *msg, + const char *name, const char *value) +{ + struct ldb_message_element *el; + struct ldb_val val; + + el = ldb_msg_find_element(msg, name); + if (el == NULL) { + return 0; + } + + val.data = discard_const_p(uint8_t, value); + val.length = strlen(value); + + if (ldb_msg_find_val(el, &val)) { + return 1; + } + + return 0; +} +