/* ldb database library Copyright (C) Simo Sorce 2005 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released ** under the LGPL 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. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 */ /* * Name: ldb * * Component: ldb dn creation and manipulation utility functions * * Description: - explode a dn into it's own basic elements * and put them in a structure (only if necessary) * - manipulate ldb_dn structures * * Author: Simo Sorce */ #include "includes.h" #include #include "ldb/include/includes.h" #define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed #define LDB_FREE(x) do { talloc_free(x); x = NULL; } while(0) /** internal ldb exploded dn structures */ struct ldb_dn_component { char *name; struct ldb_val value; char *cf_name; struct ldb_val cf_value; }; struct ldb_dn { struct ldb_context *ldb; /* Special DNs are always linearized */ bool special; bool invalid; bool valid_lin; bool valid_comp; bool valid_case; char *linearized; char *casefold; unsigned int comp_num; struct ldb_dn_component *components; }; /* strdn may be NULL */ struct ldb_dn *ldb_dn_new(void *mem_ctx, struct ldb_context *ldb, const char *strdn) { struct ldb_dn *dn; if ( (! mem_ctx) || (! ldb)) return NULL; dn = talloc_zero(mem_ctx, struct ldb_dn); LDB_DN_NULL_FAILED(dn); dn->ldb = ldb; if (strdn) { if (strdn[0] == '@') { dn->special = true; } if (strncasecmp(strdn, "special = true; /* FIXME: add a GUID string to ldb_dn structure */ } dn->linearized = talloc_strdup(dn, strdn); } else { dn->linearized = talloc_strdup(dn, ""); } LDB_DN_NULL_FAILED(dn->linearized); dn->valid_lin = true; return dn; failed: talloc_free(dn); return NULL; } 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); 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 */ } dn->linearized = strdn; dn->valid_lin = true; return dn; failed: talloc_free(dn); return NULL; } static int ldb_dn_escape_internal(char *dst, const char *src, int len) { const char *p, *s; char *d; int l; p = s = src; d = dst; while (p - src < len) { p += strcspn(p, ",=\n+<>#;\\\""); if (p - src == len) /* found no escapable chars */ break; memcpy(d, s, p - s); /* copy the part of the string before the stop */ d += (p - s); /* move to current position */ if (*p) { /* it is a normal escapable character */ *d++ = '\\'; *d++ = *p++; } else { /* we have a zero byte in the string */ strncpy(d, "\00", 3); /* escape the zero */ d += 3; p++; /* skip the zero */ } s = p; /* move forward */ } /* copy the last part (with zero) and return */ l = len - (s - src); memcpy(d, s, l + 1); /* return the length of the resulting string */ return (l + (d - dst)); } char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) { char *dst; if (!value.length) return NULL; /* allocate destination string, it will be at most 3 times the source */ dst = talloc_array(mem_ctx, char, value.length * 3 + 1); if ( ! dst) { talloc_free(dst); return NULL; } ldb_dn_escape_internal(dst, (const char *)value.data, value.length); return dst; } /* explode a DN string into a ldb_dn structure based on RFC4514 except that we don't support multiple valued RDNs */ static bool ldb_dn_explode(struct ldb_dn *dn) { char *p, *data, *d, *dt, *t; bool trim = false; bool in_attr = false; bool in_value = false; bool in_quote = false; bool is_oid = false; bool escape = false; unsigned x; int l; if ( ! dn || dn->invalid) return false; if (dn->valid_comp) { return true; } if ( ! dn->valid_lin) { return false; } /* Empty DNs */ if (dn->linearized[0] == '\0') { dn->valid_comp = true; return true; } /* Special DNs case */ if (dn->special) { return true; } /* 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); if ( ! dn->components) { return false; } dn->comp_num = 0; /* Components data space is allocated here once */ data = talloc_array(dn->components, char, strlen(dn->linearized) + 1); p = dn->linearized; in_attr = true; trim = true; t = NULL; d = dt = data; while (*p) { if (in_attr) { if (trim) { if (*p == ' ') { p++; continue; } /* first char */ trim = false; if (isdigit(*p)) { is_oid = true; } else if ( ! isalpha(*p)) { /* not a digit nor an alpha, invalid attribute name */ dn->invalid = true; goto failed; } *d++ = *p++; continue; } if (*p == ' ') { p++; /* valid only if we are at the end */ trim = true; continue; } if (trim && (*p != '=')) { /* spaces/tabs are not allowed in attribute names */ dn->invalid = true; goto failed; } if (*p == '=') { /* attribute terminated */ in_attr = false; in_value = true; trim = true; l = 0; *d++ = '\0'; dn->components[dn->comp_num].name = dt; dt = d; p++; continue; } if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) { /* not a digit nor a dot, invalid attribute oid */ dn->invalid = true; goto failed; } else if ( ! (isalpha(*p) || isdigit(*p) || (*p == '-'))) { /* not ALPHA, DIGIT or HYPHEN */ dn->invalid = true; goto failed; } *d++ = *p++; continue; } if (in_value) { if (in_quote) { if (*p == '\"') { if (p[-1] != '\\') { p++; in_quote = false; continue; } } *d++ = *p++; l++; continue; } if (trim) { if (*p == ' ') { p++; continue; } /* first char */ trim = false; if (*p == '\"') { in_quote = true; p++; continue; } } switch (*p) { /* TODO: support ber encoded values case '#': */ case ',': if (escape) { *d++ = *p++; l++; escape = false; continue; } /* ok found value terminator */ if ( t ) { /* trim back */ d -= (p - t); l -= (p - t); } in_attr = true; in_value = false; trim = true; p++; *d++ = '\0'; dn->components[dn->comp_num].value.data = (uint8_t *)dt; dn->components[dn->comp_num].value.length = l; dt = d; dn->comp_num++; if (dn->comp_num > 2) { dn->components = talloc_realloc(dn, dn->components, struct ldb_dn_component, dn->comp_num + 1); if ( ! dn->components) { /* ouch ! */ goto failed; } /* make sure all components are zeroed, other functions depend on this */ memset(&dn->components[dn->comp_num], '\0', sizeof(struct ldb_dn_component)); } continue; case '=': case '\n': case '+': case '<': case '>': case '#': case ';': case '\"': /* a string with not escaped specials is invalid (tested) */ if ( ! escape) { dn->invalid = true; goto failed; } escape = false; *d++ = *p++; l++; if ( t ) t = NULL; break; case '\\': if ( ! escape) { escape = true; p++; continue; } escape = false; *d++ = *p++; l++; if ( t ) t = NULL; break; default: if (escape) { if (sscanf(p, "%02x", &x) != 1) { /* invalid escaping sequence */ dn->invalid = true; goto failed; } escape = false; p += 2; *d++ = (unsigned char)x; l++; if ( t ) t = NULL; break; } if (*p == ' ') { if ( ! t) t = p; } else { if ( t ) t = NULL; } *d++ = *p++; l++; break; } } } if (in_attr || in_quote) { /* invalid dn */ dn->invalid = true; goto failed; } /* save last element */ if ( t ) { /* trim back */ d -= (p - t); l -= (p - t); } *d++ = '\0'; dn->components[dn->comp_num].value.data = (uint8_t *)dt; dn->components[dn->comp_num].value.length = l; dn->comp_num++; dn->valid_comp = true; return true; failed: talloc_free(dn->components); return false; } bool ldb_dn_validate(struct ldb_dn *dn) { return ldb_dn_explode(dn); } const char *ldb_dn_get_linearized(struct ldb_dn *dn) { int i, len; char *d, *n; if ( ! dn || ( dn->invalid)) return NULL; if (dn->valid_lin) return dn->linearized; if ( ! dn->valid_comp) { dn->invalid = true; return NULL; } if (dn->comp_num == 0) { dn->linearized = talloc_strdup(dn, ""); if ( ! dn->linearized) return NULL; dn->valid_lin = true; return dn->linearized; } /* calculate maximum possible length of DN */ for (len = 0, i = 0; i < dn->comp_num; i++) { len += strlen(dn->components[i].name); /* name len */ len += (dn->components[i].value.length * 3); /* max escaped data len */ len += 2; /* '=' and ',' */ } dn->linearized = talloc_array(dn, char, len); if ( ! dn->linearized) return NULL; d = dn->linearized; for (i = 0; i < dn->comp_num; i++) { /* copy the name */ n = dn->components[i].name; while (*n) *d++ = *n++; *d++ = '='; /* and the value */ d += ldb_dn_escape_internal( d, (char *)dn->components[i].value.data, dn->components[i].value.length); *d++ = ','; } *(--d) = '\0'; dn->valid_lin = true; /* don't waste more memory than necessary */ dn->linearized = talloc_realloc(dn, dn->linearized, char, (d - dn->linearized + 1)); return dn->linearized; } char *ldb_dn_alloc_linearized(void *mem_ctx, struct ldb_dn *dn) { return talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn)); } /* casefold a dn. We need to casefold the attribute names, and canonicalize attribute values of case insensitive attributes. */ static bool ldb_dn_casefold_internal(struct ldb_dn *dn) { int i, ret; if ( ! dn || dn->invalid) return false; if (dn->valid_case) return true; if (( ! dn->valid_comp) && ( ! ldb_dn_explode(dn))) { return false; } for (i = 0; i < dn->comp_num; i++) { struct ldb_dn_component dc; const struct ldb_attrib_handler *h; memset(&dc, 0, sizeof(dc)); dn->components[i].cf_name = ldb_attr_casefold(dn->components, dn->components[i].name); if (!dn->components[i].cf_name) { return false; } h = ldb_attrib_handler(dn->ldb, dn->components[i].cf_name); ret = h->canonicalise_fn(dn->ldb, dn->components, &(dn->components[i].value), &(dn->components[i].cf_value)); if (ret != 0) { return false; } } return true; } const char *ldb_dn_get_casefold(struct ldb_dn *dn) { int i, len; char *d, *n; if ( ! ldb_dn_casefold_internal(dn)) { return NULL; } if (dn->casefold) return dn->casefold; if (dn->comp_num == 0) { if (dn->special) { len = strlen(dn->linearized); dn->casefold = talloc_array(dn, char, len * 3 + 1); if ( ! dn->casefold) return NULL; ldb_dn_escape_internal(dn->casefold, dn->linearized, len); /* don't waste more memory than necessary */ dn->casefold = talloc_realloc(dn, dn->casefold, char, strlen(dn->casefold) + 1); } else { dn->casefold = talloc_strdup(dn, ""); if ( ! dn->casefold) return NULL; } dn->valid_case = true; return dn->casefold; } /* calculate maximum possible length of DN */ for (len = 0, i = 0; i < dn->comp_num; i++) { len += strlen(dn->components[i].cf_name); /* name len */ len += (dn->components[i].cf_value.length * 3); /* max escaped data len */ len += 2; /* '=' and ',' */ } dn->casefold = talloc_array(dn, char, len); if ( ! dn->casefold) return NULL; d = dn->casefold; for (i = 0; i < dn->comp_num; i++) { /* copy the name */ n = dn->components[i].cf_name; while (*n) *d++ = *n++; *d++ = '='; /* and the value */ d += ldb_dn_escape_internal( d, (char *)dn->components[i].cf_value.data, dn->components[i].cf_value.length); *d++ = ','; } *(--d) = '\0'; dn->valid_case = true; return dn->casefold; } char *ldb_dn_alloc_casefold(void *mem_ctx, struct ldb_dn *dn) { return talloc_strdup(mem_ctx, ldb_dn_get_casefold(dn)); } /* Determine if dn is below base, in the ldap tree. Used for * evaluating a subtree search. * 0 if they match, otherwise non-zero */ int ldb_dn_compare_base(struct ldb_dn *base, struct ldb_dn *dn) { int ret; int n_base, n_dn; if ( ! base || base->invalid) return 1; if ( ! dn || dn->invalid) return -1; if (( ! base->valid_case) || ( ! dn->valid_case)) { if (base->valid_lin && dn->valid_lin) { /* try with a normal compare first, if we are lucky * we will avoid exploding and casfolding */ int dif; dif = strlen(dn->linearized) - strlen(base->linearized); if (dif < 0) return dif; if (strcmp(base->linearized, &dn->linearized[dif]) == 0) return 0; } if ( ! ldb_dn_casefold_internal(base)) { return 1; } if ( ! ldb_dn_casefold_internal(dn)) { return -1; } } /* if base has more components, * they don't have the same base */ if (base->comp_num > dn->comp_num) { return (dn->comp_num - base->comp_num); } if (dn->comp_num == 0) { if (dn->special && base->special) { return strcmp(base->linearized, dn->linearized); } else { return 0; } } n_base = base->comp_num - 1; n_dn = dn->comp_num - 1; while (n_base >= 0) { /* compare attr names */ ret = strcmp(base->components[n_base].cf_name, dn->components[n_dn].cf_name); if (ret != 0) return ret; /* compare attr.cf_value. */ if (base->components[n_base].cf_value.length != dn->components[n_dn].cf_value.length) { return base->components[n_base].cf_value.length - dn->components[n_dn].cf_value.length; } ret = strcmp((char *)base->components[n_base].cf_value.data, (char *)dn->components[n_dn].cf_value.data); if (ret != 0) return ret; n_base--; n_dn--; } return 0; } /* compare DNs using casefolding compare functions. If they match, then return 0 */ int ldb_dn_compare(struct ldb_dn *dn0, struct ldb_dn *dn1) { int i, ret; if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) return -1; if (( ! dn0->valid_case) || ( ! dn1->valid_case)) { if (dn0->valid_lin && dn1->valid_lin) { /* try with a normal compare first, if we are lucky * we will avoid exploding and casfolding */ if (strcmp(dn0->linearized, dn1->linearized) == 0) return 0; } if ( ! ldb_dn_casefold_internal(dn0)) { return 1; } if ( ! ldb_dn_casefold_internal(dn1)) { return -1; } } if (dn0->comp_num != dn1->comp_num) { return (dn1->comp_num - dn0->comp_num); } if (dn0->comp_num == 0) { if (dn0->special && dn1->special) { return strcmp(dn0->linearized, dn1->linearized); } else { return 0; } } for (i = 0; i < dn0->comp_num; i++) { /* compare attr names */ ret = strcmp(dn0->components[i].cf_name, dn1->components[i].cf_name); if (ret != 0) return ret; /* compare attr.cf_value. */ if (dn0->components[i].cf_value.length != dn1->components[i].cf_value.length) { return dn0->components[i].cf_value.length - dn1->components[i].cf_value.length; } ret = strcmp((char *)dn0->components[i].cf_value.data, (char *)dn1->components[i].cf_value.data); if (ret != 0) return ret; } return 0; } static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) { struct ldb_dn_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); } if (src->cf_value.data) { dst.cf_value = ldb_val_dup(mem_ctx, &(src->cf_value)); if (dst.cf_value.data == NULL) { LDB_FREE(dst.value.data); LDB_FREE(dst.name); return dst; } dst.cf_name = talloc_strdup(mem_ctx, src->cf_name); if (dst.cf_name == NULL) { LDB_FREE(dst.cf_name); LDB_FREE(dst.value.data); LDB_FREE(dst.name); return dst; } } else { dst.cf_value.data = NULL; dst.cf_name = NULL; } return dst; } struct ldb_dn *ldb_dn_copy(void *mem_ctx, struct ldb_dn *dn) { struct ldb_dn *new_dn; if (!dn || dn->invalid) { return NULL; } new_dn = talloc_zero(mem_ctx, struct ldb_dn); if ( !new_dn) { return NULL; } *new_dn = *dn; if (dn->valid_comp) { int i; new_dn->components = talloc_zero_array(new_dn, struct ldb_dn_component, dn->comp_num); if ( ! new_dn->components) { talloc_free(new_dn); return NULL; } for (i = 0; i < dn->comp_num; i++) { new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &dn->components[i]); if ( ! new_dn->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) { talloc_free(new_dn); return NULL; } } } if (dn->valid_lin) { new_dn->linearized = talloc_strdup(new_dn, dn->linearized); if ( ! new_dn->linearized) { talloc_free(new_dn); return NULL; } } return new_dn; } /* modify the given dn by adding a base. * * return true if successful and false if not * if false is returned the dn may be marked invalid */ bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base) { const char *s; char *t; if ( !base || base->invalid || !dn || dn->invalid) { return false; } if (dn->valid_comp) { int i; if ( ! ldb_dn_validate(base)) { return false; } s = NULL; if (dn->valid_case) { if ( ! (s = ldb_dn_get_casefold(base))) { return false; } } dn->components = talloc_realloc(dn, dn->components, struct ldb_dn_component, dn->comp_num + base->comp_num); if ( ! dn->components) { dn->invalid = true; return false; } for (i = 0; i < base->comp_num; dn->comp_num++, i++) { dn->components[dn->comp_num] = ldb_dn_copy_component(dn->components, &base->components[i]); if (dn->components[dn->comp_num].value.data == NULL) { dn->invalid = true; return false; } } if (s) { t = talloc_asprintf(dn, "%s,%s", dn->casefold, s); LDB_FREE(dn->casefold); dn->casefold = t; } } if (dn->valid_lin) { s = ldb_dn_get_linearized(base); if ( ! s) { return false; } t = talloc_asprintf(dn, "%s,%s", dn->linearized, s); if ( ! t) { dn->invalid = true; return false; } LDB_FREE(dn->linearized); dn->linearized = t; } return true; } /* modify the given dn by adding a base. * * return true if successful and false if not * if false is returned the dn may be marked invalid */ bool ldb_dn_add_base_fmt(struct ldb_dn *dn, const char *base_fmt, ...) { struct ldb_dn *base; char *base_str; va_list ap; bool ret; if ( !dn || dn->invalid) { return false; } va_start(ap, base_fmt); base_str = talloc_vasprintf(dn, base_fmt, ap); va_end(ap); if (base_str == NULL) { return false; } base = ldb_dn_new(base_str, dn->ldb, base_str); ret = ldb_dn_add_base(dn, base); talloc_free(base_str); return ret; } /* modify the given dn by adding children elements. * * return true if successful and false if not * if false is returned the dn may be marked invalid */ bool ldb_dn_add_child(struct ldb_dn *dn, struct ldb_dn *child) { const char *s; char *t; if ( !child || child->invalid || !dn || dn->invalid) { return false; } if (dn->valid_comp) { int n, i, j; if ( ! ldb_dn_validate(child)) { return false; } s = NULL; if (dn->valid_case) { if ( ! (s = ldb_dn_get_casefold(child))) { return false; } } n = dn->comp_num + child->comp_num; dn->components = talloc_realloc(dn, dn->components, struct ldb_dn_component, n); if ( ! dn->components) { dn->invalid = true; return false; } for (i = dn->comp_num - 1, j = n - 1; i >= 0; i--, j--) { dn->components[j] = dn->components[i]; } for (i = 0; i < child->comp_num; i++) { dn->components[i] = ldb_dn_copy_component(dn->components, &child->components[i]); if (dn->components[i].value.data == NULL) { dn->invalid = true; return false; } } dn->comp_num = n; if (s) { t = talloc_asprintf(dn, "%s,%s", s, dn->casefold); LDB_FREE(dn->casefold); dn->casefold = t; } } if (dn->valid_lin) { s = ldb_dn_get_linearized(child); if ( ! s) { return false; } t = talloc_asprintf(dn, "%s,%s", s, dn->linearized); if ( ! t) { dn->invalid = true; return false; } LDB_FREE(dn->linearized); dn->linearized = t; } return true; } /* modify the given dn by adding children elements. * * return true if successful and false if not * if false is returned the dn may be marked invalid */ bool ldb_dn_add_child_fmt(struct ldb_dn *dn, const char *child_fmt, ...) { struct ldb_dn *child; char *child_str; va_list ap; bool ret; if ( !dn || dn->invalid) { return false; } va_start(ap, child_fmt); child_str = talloc_vasprintf(dn, child_fmt, ap); va_end(ap); if (child_str == NULL) { return false; } child = ldb_dn_new(child_str, dn->ldb, child_str); ret = ldb_dn_add_child(dn, child); talloc_free(child_str); return ret; } bool ldb_dn_remove_base_components(struct ldb_dn *dn, unsigned int num) { if ( ! ldb_dn_validate(dn)) { return false; } if (dn->comp_num < num) { return false; } dn->comp_num -= num; dn->valid_case = false; if (dn->valid_lin) { dn->valid_lin = false; LDB_FREE(dn->linearized); } return true; } bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num) { int i, j; if ( ! ldb_dn_validate(dn)) { return false; } if (dn->comp_num < num) { return false; } for (i = 0, j = num; j < dn->comp_num; i++, j++) { dn->components[i] = dn->components[j]; } dn->comp_num -= num; dn->valid_case = false; if (dn->valid_lin) { dn->valid_lin = false; LDB_FREE(dn->linearized); } return true; } struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, struct ldb_dn *dn) { struct ldb_dn *new_dn; new_dn = ldb_dn_copy(mem_ctx, dn); if ( !new_dn ) { return NULL; } if ( ! ldb_dn_remove_child_components(new_dn, 1)) { talloc_free(new_dn); return NULL; } return new_dn; } /* Create a 'canonical name' string from a DN: ie dc=samba,dc=org -> samba.org/ uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator There are two formats, the EX format has the last / replaced with a newline (\n). */ static char *ldb_dn_canonical(void *mem_ctx, struct ldb_dn *dn, int ex_format) { int i; char *cracked = NULL; if ( ! ldb_dn_validate(dn)) { return NULL; } /* Walk backwards down the DN, grabbing 'dc' components at first */ for (i = dn->comp_num - 1 ; i >= 0; i--) { if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) { break; } if (cracked) { cracked = talloc_asprintf(mem_ctx, "%s.%s", ldb_dn_escape_value(mem_ctx, dn->components[i].value), cracked); } else { cracked = ldb_dn_escape_value(mem_ctx, dn->components[i].value); } if (!cracked) { return NULL; } } /* Only domain components? Finish here */ if (i < 0) { if (ex_format) { cracked = talloc_asprintf(mem_ctx, "%s\n", cracked); } else { cracked = talloc_asprintf(mem_ctx, "%s/", cracked); } return cracked; } /* Now walk backwards appending remaining components */ for (; i > 0; i--) { cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, ldb_dn_escape_value(mem_ctx, dn->components[i].value)); if (!cracked) { return NULL; } } /* Last one, possibly a newline for the 'ex' format */ if (ex_format) { cracked = talloc_asprintf(mem_ctx, "%s\n%s", cracked, ldb_dn_escape_value(mem_ctx, dn->components[i].value)); } else { cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, ldb_dn_escape_value(mem_ctx, dn->components[i].value)); } return cracked; } /* Wrapper functions for the above, for the two different string formats */ char *ldb_dn_canonical_string(void *mem_ctx, struct ldb_dn *dn) { return ldb_dn_canonical(mem_ctx, dn, 0); } char *ldb_dn_canonical_ex_string(void *mem_ctx, struct ldb_dn *dn) { return ldb_dn_canonical(mem_ctx, dn, 1); } int ldb_dn_get_comp_num(struct ldb_dn *dn) { if ( ! ldb_dn_validate(dn)) { return -1; } return dn->comp_num; } const char *ldb_dn_get_component_name(struct ldb_dn *dn, unsigned int num) { if ( ! ldb_dn_validate(dn)) { return NULL; } if (num >= dn->comp_num) return NULL; return dn->components[num].name; } const struct ldb_val *ldb_dn_get_component_val(struct ldb_dn *dn, unsigned int num) { if ( ! ldb_dn_validate(dn)) { return NULL; } if (num >= dn->comp_num) return NULL; return &dn->components[num].value; } const char *ldb_dn_get_rdn_name(struct ldb_dn *dn) { if ( ! ldb_dn_validate(dn)) { return NULL; } if (dn->comp_num == 0) return NULL; return dn->components[0].name; } const struct ldb_val *ldb_dn_get_rdn_val(struct ldb_dn *dn) { if ( ! ldb_dn_validate(dn)) { return NULL; } if (dn->comp_num == 0) return NULL; return &dn->components[0].value; } int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val) { char *n; struct ldb_val v; if ( ! ldb_dn_validate(dn)) { return LDB_ERR_OTHER; } if (num >= dn->comp_num) { return LDB_ERR_OTHER; } n = talloc_strdup(dn, name); if ( ! n) { return LDB_ERR_OTHER; } v.length = val.length; v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1); if ( ! v.data) { return LDB_ERR_OTHER; } talloc_free(dn->components[num].name); talloc_free(dn->components[num].value.data); dn->components[num].name = n; dn->components[num].value = v; if (dn->valid_case) dn->valid_case = false; if (dn->casefold) LDB_FREE(dn->casefold); return LDB_SUCCESS; } bool ldb_dn_is_valid(struct ldb_dn *dn) { if ( ! dn) return false; return ! dn->invalid; } bool ldb_dn_is_special(struct ldb_dn *dn) { if ( ! dn || dn->invalid) return false; return dn->special; } bool ldb_dn_check_special(struct ldb_dn *dn, const char *check) { if ( ! dn || dn->invalid) return false; return ! strcmp(dn->linearized, check); } bool ldb_dn_is_null(struct ldb_dn *dn) { if ( ! dn || dn->invalid) return false; if (dn->special) return false; if (dn->valid_comp) { if (dn->comp_num == 0) return true; return false; } else { if (dn->linearized[0] == '\0') return true; } return false; }