📄 ldb_dn.c
字号:
/* 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 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 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, see <http://www.gnu.org/licenses/>.*//* * 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 "ldb_includes.h"#include <ctype.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_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 (! 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, "<GUID=", 6) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a GUID string to ldb_dn structure */ } else if (strncasecmp(strdn, "<SID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a SID string to ldb_dn structure */ } else if (strncasecmp(strdn, "<WKGUID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->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); 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, "<GUID=", 6) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a GUID string to ldb_dn structure */ } else if (strncasecmp(strdn, "<SID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a SID string to ldb_dn structure */ } else if (strncasecmp(strdn, "<WKGUID=", 8) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; /* FIXME: add a WKGUID string to ldb_dn structure */ } dn->linearized = strdn; 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); dst = talloc_realloc(mem_ctx, dst, char, strlen(dst) + 1); 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->components) { return true; } if ( ! dn->linearized) { return false; } /* Empty DNs */ if (dn->linearized[0] == '\0') { return true; } /* Special DNs case */ if (dn->special) { return true; } /* make sure we free this if alloced previously before replacing */ talloc_free(dn->components); /* 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); if (!data) { return false; } 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 (!isascii(*p)) { /* attr names must be ascii only */ dn->invalid = true; goto failed; } 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 = talloc_strdup(dn->components, dt); if ( ! dn->components[dn->comp_num].name) { /* ouch */ goto failed; } dt = d; p++; 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; 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 *)talloc_strdup(dn->components, dt); dn->components[dn->comp_num].value.length = l; if ( ! dn->components[dn->comp_num].value.data) { /* ouch ! */ goto failed; } 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 *)talloc_strdup(dn->components, dt); dn->components[dn->comp_num].value.length = l; if ( ! dn->components[dn->comp_num].value.data) { /* ouch */ goto failed; } dn->comp_num++; talloc_free(data); return true;failed: dn->comp_num = 0; 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->linearized) return dn->linearized; if ( ! dn->components) { dn->invalid = true; return NULL; } if (dn->comp_num == 0) { dn->linearized = talloc_strdup(dn, ""); if ( ! dn->linearized) return NULL; 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'; /* 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->components) && ( ! ldb_dn_explode(dn))) { return false; } for (i = 0; i < dn->comp_num; i++) { const struct ldb_schema_attribute *a; dn->components[i].cf_name = ldb_attr_casefold(dn->components, dn->components[i].name); if (!dn->components[i].cf_name) { goto failed; } a = ldb_schema_attribute_by_name(dn->ldb, dn->components[i].cf_name); ret = a->syntax->canonicalise_fn(dn->ldb, dn->components, &(dn->components[i].value), &(dn->components[i].cf_value)); if (ret != 0) { goto failed; } } dn->valid_case = true; return true;failed: for (i = 0; i < dn->comp_num; i++) { LDB_FREE(dn->components[i].cf_name); LDB_FREE(dn->components[i].cf_value.data); } return false;}const char *ldb_dn_get_casefold(struct ldb_dn *dn){ int i, len; char *d, *n; if (dn->casefold) return dn->casefold; if (dn->special) { dn->casefold = talloc_strdup(dn, dn->linearized); if (!dn->casefold) return NULL; dn->valid_case = true; return dn->casefold; } if ( ! ldb_dn_casefold_internal(dn)) { return NULL; } if (dn->comp_num == 0) { if (dn->linearized && dn->linearized[0] == '\0') { /* hmm a NULL dn, should we faild casefolding ? */ dn->casefold = talloc_strdup(dn, ""); return dn->casefold; } /* A DN must be NULL, special, or have components */ dn->invalid = true; return NULL; } /* 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'; /* don't waste more memory than necessary */ dn->casefold = talloc_realloc(dn, dn->casefold, char, strlen(dn->casefold) + 1); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -