X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source4%2Flib%2Fldb%2Fcommon%2Fldb_dn.c;h=402d6295015d141de84211692b1131f7a0a6ff70;hb=380874ef863866c94c999ef53252b9d30df65e88;hp=ea7c6b5f690666c0aa17d4aa836c4c596c297caa;hpb=d6121458b0b3cfecb857877e0740560f282cbe48;p=metze%2Fsamba%2Fwip.git diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c index ea7c6b5f6906..402d6295015d 100644 --- a/source4/lib/ldb/common/ldb_dn.c +++ b/source4/lib/ldb/common/ldb_dn.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 . */ /* @@ -34,7 +33,7 @@ * Author: Simo Sorce */ -#include "ldb_includes.h" +#include "ldb_private.h" #include #define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed @@ -53,6 +52,12 @@ struct ldb_dn_component { struct ldb_val cf_value; }; +struct ldb_dn_extended_component { + + char *name; + struct ldb_val value; +}; + struct ldb_dn { struct ldb_context *ldb; @@ -64,50 +69,59 @@ struct ldb_dn { bool valid_case; char *linearized; + char *extended_linearized; char *casefold; unsigned int comp_num; struct ldb_dn_component *components; + unsigned int extended_comp_num; + struct ldb_dn_extended_component *extended_components; }; /* strdn may be NULL */ -struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) +struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const struct ldb_val *strdn) { struct ldb_dn *dn; - if ( (! mem_ctx) || (! ldb)) return NULL; + if (! ldb) return NULL; dn = talloc_zero(mem_ctx, struct ldb_dn); LDB_DN_NULL_FAILED(dn); dn->ldb = ldb; - if (strdn) { - if (strdn[0] == '@') { + if (strdn->data && strdn->length) { + if (strdn->data[0] == '@') { dn->special = true; + } + dn->extended_linearized = talloc_strndup(dn, (const char *)strdn->data, strdn->length); + LDB_DN_NULL_FAILED(dn->extended_linearized); + + if (strdn->data[0] == '<') { + const char *p_save, *p = dn->extended_linearized; + do { + p_save = p; + p = strstr(p, ">;"); + if (p) { + p = p + 2; + } + } while (p); + + if (p_save == dn->extended_linearized) { + dn->linearized = talloc_strdup(dn, ""); + } else { + dn->linearized = talloc_strdup(dn, p_save); + } + LDB_DN_NULL_FAILED(dn->linearized); + } else { + dn->linearized = dn->extended_linearized; + dn->extended_linearized = NULL; } - if (strncasecmp(strdn, "special = true; - /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "special = true; - /* FIXME: add a SID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "special = true; - /* FIXME: add a WKGUID string to ldb_dn structure */ - } - dn->linearized = talloc_strdup(dn, strdn); } else { dn->linearized = talloc_strdup(dn, ""); + LDB_DN_NULL_FAILED(dn->linearized); } - LDB_DN_NULL_FAILED(dn->linearized); return dn; @@ -116,49 +130,32 @@ failed: return NULL; } +/* strdn may be NULL */ +struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) +{ + struct ldb_val blob; + blob.data = strdn; + blob.length = strdn ? strlen(strdn) : 0; + return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob); +} + struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx, struct ldb_context *ldb, const char *new_fmt, ...) { - struct ldb_dn *dn; char *strdn; va_list ap; if ( (! mem_ctx) || (! ldb)) return NULL; - dn = talloc_zero(mem_ctx, struct ldb_dn); - LDB_DN_NULL_FAILED(dn); - - dn->ldb = ldb; - va_start(ap, new_fmt); - strdn = talloc_vasprintf(dn, new_fmt, ap); + strdn = talloc_vasprintf(mem_ctx, new_fmt, ap); va_end(ap); - LDB_DN_NULL_FAILED(strdn); - - if (strdn[0] == '@') { - dn->special = true; - } - if (strncasecmp(strdn, "special = true; - /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "special = true; - /* FIXME: add a SID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "special = true; - /* FIXME: add a WKGUID string to ldb_dn structure */ - } - dn->linearized = strdn; - return dn; - -failed: - talloc_free(dn); + if (strdn) { + struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, strdn); + talloc_free(strdn); + return dn; + } + return NULL; } @@ -227,15 +224,19 @@ char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) */ static bool ldb_dn_explode(struct ldb_dn *dn) { - char *p, *data, *d, *dt, *t; + char *p, *ex_name, *ex_value, *data, *d, *dt, *t; bool trim = false; + bool in_extended = false; + bool in_ex_name = false; + bool in_ex_value = false; bool in_attr = false; bool in_value = false; bool in_quote = false; bool is_oid = false; bool escape = false; unsigned x; - int l; + int l, ret; + char *parse_dn; if ( ! dn || dn->invalid) return false; @@ -243,12 +244,18 @@ static bool ldb_dn_explode(struct ldb_dn *dn) return true; } - if ( ! dn->linearized) { + if (dn->extended_linearized) { + parse_dn = dn->extended_linearized; + } else { + parse_dn = dn->linearized; + } + + if ( ! parse_dn ) { return false; } /* Empty DNs */ - if (dn->linearized[0] == '\0') { + if (parse_dn[0] == '\0') { return true; } @@ -260,6 +267,9 @@ static bool ldb_dn_explode(struct ldb_dn *dn) /* make sure we free this if alloced previously before replacing */ talloc_free(dn->components); + talloc_free(dn->extended_components); + dn->extended_components = NULL; + /* in the common case we have 3 or more components */ /* make sure all components are zeroed, other functions depend on this */ dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3); @@ -269,19 +279,109 @@ static bool ldb_dn_explode(struct ldb_dn *dn) dn->comp_num = 0; /* Components data space is allocated here once */ - data = talloc_array(dn->components, char, strlen(dn->linearized) + 1); + data = talloc_array(dn->components, char, strlen(parse_dn) + 1); if (!data) { return false; } - p = dn->linearized; - in_attr = true; + p = parse_dn; + in_extended = true; + in_ex_name = false; + in_ex_value = false; trim = true; t = NULL; d = dt = data; while (*p) { + if (in_extended) { + + if (!in_ex_name && !in_ex_value) { + + if (p[0] == '<') { + p++; + ex_name = d; + in_ex_name = true; + continue; + } else if (p[0] == '\0') { + p++; + continue; + } else { + in_extended = false; + in_attr = true; + dt = d; + + continue; + } + } + + if (in_ex_name && *p == '=') { + *d++ = '\0'; + p++; + ex_value = d; + in_ex_name = false; + in_ex_value = true; + continue; + } + + if (in_ex_value && *p == '>') { + const struct ldb_dn_extended_syntax *extended_syntax; + struct ldb_val ex_val = { + .data = ex_value, + .length = d - ex_value + }; + + *d++ = '\0'; + p++; + in_ex_value = false; + + /* Process name and ex_value */ + + dn->extended_components = talloc_realloc(dn, + dn->extended_components, + struct ldb_dn_extended_component, + dn->extended_comp_num + 1); + if ( ! dn->extended_components) { + /* ouch ! */ + goto failed; + } + extended_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name); + if (!extended_syntax) { + /* We don't know about this type of extended DN */ + goto failed; + } + + dn->extended_components[dn->extended_comp_num].name = talloc_strdup(dn->extended_components, ex_name); + if (!dn->extended_components[dn->extended_comp_num].name) { + /* ouch */ + goto failed; + } + ret = extended_syntax->read_fn(dn->ldb, dn->extended_components, + &ex_val, &dn->extended_components[dn->extended_comp_num].value); + if (ret != LDB_SUCCESS) { + dn->invalid = true; + goto failed; + } + + dn->extended_comp_num++; + + if (*p == '\0') { + /* We have reached the end (extended component only)! */ + talloc_free(data); + return true; + + } else if (*p == ';') { + p++; + continue; + } else { + dn->invalid = true; + goto failed; + } + } + + *d++ = *p++; + continue; + } if (in_attr) { if (trim) { if (*p == ' ') { @@ -292,6 +392,12 @@ static bool ldb_dn_explode(struct ldb_dn *dn) /* first char */ trim = false; + if (!isascii(*p)) { + /* attr names must be ascii only */ + dn->invalid = true; + goto failed; + } + if (isdigit(*p)) { is_oid = true; } else @@ -301,6 +407,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) goto failed; } + /* Copy this character across from parse_dn, now we have trimmed out spaces */ *d++ = *p++; continue; } @@ -325,6 +432,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) trim = true; l = 0; + /* Terminate this string in d (which is a copy of parse_dn with spaces trimmed) */ *d++ = '\0'; dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt); if ( ! dn->components[dn->comp_num].name) { @@ -338,6 +446,12 @@ static bool ldb_dn_explode(struct ldb_dn *dn) continue; } + if (!isascii(*p)) { + /* attr names must be ascii only */ + dn->invalid = true; + goto failed; + } + if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) { /* not a digit nor a dot, invalid attribute oid */ dn->invalid = true; @@ -594,6 +708,74 @@ const char *ldb_dn_get_linearized(struct ldb_dn *dn) return dn->linearized; } +char *ldb_dn_get_extended_linearized(void *mem_ctx, struct ldb_dn *dn, int mode) +{ + const char *linearized = ldb_dn_get_linearized(dn); + char *p; + int i; + + if (!linearized) { + return NULL; + } + + if (!ldb_dn_has_extended(dn)) { + return talloc_strdup(mem_ctx, linearized); + } + + if (!ldb_dn_validate(dn)) { + return NULL; + } + + for (i=0; i < dn->extended_comp_num; i++) { + struct ldb_val val; + int ret; + const struct ldb_dn_extended_syntax *extended_syntax; + const char *name = dn->extended_components[i].name; + + extended_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name); + + if (mode == 1) { + ret = extended_syntax->write_clear_fn(dn->ldb, mem_ctx, + &dn->extended_components[i].value, + &val); + } else if (mode == 0) { + ret = extended_syntax->write_hex_fn(dn->ldb, mem_ctx, + &dn->extended_components[i].value, + &val); + } else { + ret = -1; + } + + if (ret != LDB_SUCCESS) { + return NULL; + } + + if (i == 0) { + p = talloc_asprintf(mem_ctx, "<%s=%s>", dn->extended_components[i].name, val.data); + } else { + p = talloc_asprintf_append(p, ";<%s=%s>", dn->extended_components[i].name, val.data); + } + + talloc_free(val.data); + + if (!p) { + return NULL; + } + } + + if (dn->extended_comp_num && *linearized) { + p = talloc_asprintf_append(p, ";%s", linearized); + } + + if (!p) { + return NULL; + } + + return p; +} + + + char *ldb_dn_alloc_linearized(void *mem_ctx, struct ldb_dn *dn) { return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn)); @@ -889,6 +1071,30 @@ static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_d return dst; } +static struct ldb_dn_extended_component ldb_dn_extended_copy_component(void *mem_ctx, struct ldb_dn_extended_component *src) +{ + struct ldb_dn_extended_component dst; + + memset(&dst, 0, sizeof(dst)); + + if (src == NULL) { + return dst; + } + + dst.value = ldb_val_dup(mem_ctx, &(src->value)); + if (dst.value.data == NULL) { + return dst; + } + + dst.name = talloc_strdup(mem_ctx, src->name); + if (dst.name == NULL) { + LDB_FREE(dst.value.data); + return dst; + } + + return dst; +} + struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn) { struct ldb_dn *new_dn; @@ -922,6 +1128,24 @@ struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn) } } + if (dn->extended_components) { + int i; + + new_dn->extended_components = talloc_zero_array(new_dn, struct ldb_dn_extended_component, dn->extended_comp_num); + if ( ! new_dn->extended_components) { + talloc_free(new_dn); + return NULL; + } + + for (i = 0; i < dn->extended_comp_num; i++) { + new_dn->extended_components[i] = ldb_dn_extended_copy_component(new_dn->extended_components, &dn->extended_components[i]); + if ( ! new_dn->extended_components[i].value.data) { + talloc_free(new_dn); + return NULL; + } + } + } + if (dn->casefold) { new_dn->casefold = talloc_strdup(new_dn, dn->casefold); if ( ! new_dn->casefold) { @@ -938,6 +1162,14 @@ struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn) } } + if (dn->extended_linearized) { + new_dn->extended_linearized = talloc_strdup(new_dn, dn->extended_linearized); + if ( ! new_dn->extended_linearized) { + talloc_free(new_dn); + return NULL; + } + } + return new_dn; } @@ -1017,6 +1249,13 @@ bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base) dn->linearized = t; } + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + if (dn->extended_linearized) { + LDB_FREE(dn->extended_linearized); + } + + LDB_FREE(dn->extended_components); + dn->extended_comp_num = 0; return true; } @@ -1129,6 +1368,12 @@ bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child) dn->linearized = t; } + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + LDB_FREE(dn->extended_linearized); + + LDB_FREE(dn->extended_components); + dn->extended_comp_num = 0; + return true; } @@ -1198,6 +1443,12 @@ bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num) LDB_FREE(dn->casefold); LDB_FREE(dn->linearized); + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + LDB_FREE(dn->extended_linearized); + + LDB_FREE(dn->extended_components); + dn->extended_comp_num = 0; + return true; } @@ -1236,6 +1487,11 @@ bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num) LDB_FREE(dn->casefold); LDB_FREE(dn->linearized); + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + LDB_FREE(dn->extended_linearized); + + LDB_FREE(dn->extended_components); + dn->extended_comp_num = 0; return true; } @@ -1253,6 +1509,11 @@ struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, struct ldb_dn *dn) return NULL; } + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + LDB_FREE(dn->extended_linearized); + + LDB_FREE(dn->extended_components); + dn->extended_comp_num = 0; return new_dn; } @@ -1268,6 +1529,7 @@ static char *ldb_dn_canonical(void *mem_ctx, struct ldb_dn *dn, int ex_format) { int i; TALLOC_CTX *tmpctx; char *cracked = NULL; + const char *format = (ex_format ? "\n" : "/" ); if ( ! ldb_dn_validate(dn)) { return NULL; @@ -1294,32 +1556,23 @@ static char *ldb_dn_canonical(void *mem_ctx, struct ldb_dn *dn, int ex_format) { /* Only domain components? Finish here */ if (i < 0) { - if (ex_format) { - cracked = talloc_append_string(tmpctx, cracked, "\n"); - } else { - cracked = talloc_append_string(tmpctx, cracked, "/"); - } + cracked = talloc_strdup_append_buffer(cracked, format); talloc_steal(mem_ctx, cracked); goto done; } /* Now walk backwards appending remaining components */ for (; i > 0; i--) { - cracked = talloc_asprintf_append(cracked, "/%s", - ldb_dn_escape_value(tmpctx, dn->components[i].value)); + cracked = talloc_asprintf_append_buffer(cracked, "/%s", + ldb_dn_escape_value(tmpctx, dn->components[i].value)); if (!cracked) { goto done; } } /* Last one, possibly a newline for the 'ex' format */ - if (ex_format) { - cracked = talloc_asprintf_append(cracked, "\n%s", - ldb_dn_escape_value(tmpctx, dn->components[i].value)); - } else { - cracked = talloc_asprintf_append(cracked, "/%s", - ldb_dn_escape_value(tmpctx, dn->components[i].value)); - } + cracked = talloc_asprintf_append_buffer(cracked, "%s%s", format, + ldb_dn_escape_value(tmpctx, dn->components[i].value)); talloc_steal(mem_ctx, cracked); done: @@ -1422,9 +1675,97 @@ int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const str LDB_FREE(dn->casefold); LDB_FREE(dn->linearized); + /* Wipe the extended_linearized DN, as the GUID and SID are almost certainly no longer valid */ + LDB_FREE(dn->extended_linearized); + + dn->extended_comp_num = 0; + LDB_FREE(dn->extended_components); return LDB_SUCCESS; } +const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn, const char *name) +{ + int i; + if ( ! ldb_dn_validate(dn)) { + return NULL; + } + for (i=0; i < dn->extended_comp_num; i++) { + if (ldb_attr_cmp(dn->extended_components[i].name, name) == 0) { + return &dn->extended_components[i].value; + } + } + return NULL; +} + +int ldb_dn_set_extended_component(struct ldb_dn *dn, const char *name, const struct ldb_val *val) +{ + struct ldb_dn_extended_component *p; + int i; + + if ( ! ldb_dn_validate(dn)) { + return LDB_ERR_OTHER; + } + + for (i=0; i < dn->extended_comp_num; i++) { + if (ldb_attr_cmp(dn->extended_components[i].name, name) == 0) { + if (val) { + dn->extended_components[i].value = ldb_val_dup(dn->extended_components, val); + + dn->extended_components[i].name = talloc_strdup(dn->extended_components, name); + if (!dn->extended_components[i].name || !dn->extended_components[i].value.data) { + dn->invalid = true; + return LDB_ERR_OPERATIONS_ERROR; + } + + } else { + if (i != (dn->extended_comp_num - 1)) { + memmove(&dn->extended_components[i], &dn->extended_components[i+1], + ((dn->extended_comp_num-1) - i)*sizeof(*dn->extended_components)); + } + dn->extended_comp_num--; + + dn->extended_components = talloc_realloc(dn, + dn->extended_components, + struct ldb_dn_extended_component, + dn->extended_comp_num); + if (!dn->extended_components) { + dn->invalid = true; + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; + } + } + } + + p = dn->extended_components + = talloc_realloc(dn, + dn->extended_components, + struct ldb_dn_extended_component, + dn->extended_comp_num + 1); + if (!dn->extended_components) { + dn->invalid = true; + return LDB_ERR_OPERATIONS_ERROR; + } + + p[dn->extended_comp_num].value = ldb_val_dup(dn->extended_components, val); + p[dn->extended_comp_num].name = talloc_strdup(p, name); + + if (!dn->extended_components[i].name || !dn->extended_components[i].value.data) { + dn->invalid = true; + return LDB_ERR_OPERATIONS_ERROR; + } + dn->extended_components = p; + dn->extended_comp_num++; + + return LDB_SUCCESS; +} + +void ldb_dn_remove_extended_components(struct ldb_dn *dn) +{ + dn->extended_comp_num = 0; + LDB_FREE(dn->extended_components); +} + bool ldb_dn_is_valid(struct ldb_dn *dn) { if ( ! dn) return false; @@ -1437,6 +1778,13 @@ bool ldb_dn_is_special(struct ldb_dn *dn) return dn->special; } +bool ldb_dn_has_extended(struct ldb_dn *dn) +{ + if ( ! dn || dn->invalid) return false; + if (dn->extended_linearized && (dn->extended_linearized[0] == '<')) return true; + return dn->extended_comp_num != 0; +} + bool ldb_dn_check_special(struct ldb_dn *dn, const char *check) { if ( ! dn || dn->invalid) return false; @@ -1446,6 +1794,7 @@ bool ldb_dn_check_special(struct ldb_dn *dn, const char *check) bool ldb_dn_is_null(struct ldb_dn *dn) { if ( ! dn || dn->invalid) return false; + if (ldb_dn_has_extended(dn)) return false; if (dn->linearized && (dn->linearized[0] == '\0')) return true; return false; }