summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/common
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/ldb/common')
-rw-r--r--source4/lib/ldb/common/attrib_handlers.c496
-rw-r--r--source4/lib/ldb/common/ldb.c1923
-rw-r--r--source4/lib/ldb/common/ldb_attributes.c306
-rw-r--r--source4/lib/ldb/common/ldb_controls.c1043
-rw-r--r--source4/lib/ldb/common/ldb_debug.c142
-rw-r--r--source4/lib/ldb/common/ldb_dn.c2101
-rw-r--r--source4/lib/ldb/common/ldb_ldif.c1026
-rw-r--r--source4/lib/ldb/common/ldb_match.c570
-rw-r--r--source4/lib/ldb/common/ldb_modules.c1146
-rw-r--r--source4/lib/ldb/common/ldb_msg.c1187
-rw-r--r--source4/lib/ldb/common/ldb_options.c72
-rw-r--r--source4/lib/ldb/common/ldb_parse.c903
-rw-r--r--source4/lib/ldb/common/ldb_utf8.c136
-rw-r--r--source4/lib/ldb/common/qsort.c251
14 files changed, 0 insertions, 11302 deletions
diff --git a/source4/lib/ldb/common/attrib_handlers.c b/source4/lib/ldb/common/attrib_handlers.c
deleted file mode 100644
index 2f4454c7b4..0000000000
--- a/source4/lib/ldb/common/attrib_handlers.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2005
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
-
- ** 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/>.
-*/
-/*
- attribute handlers for well known attribute types, selected by syntax OID
- see rfc2252
-*/
-
-#include "ldb_private.h"
-#include "system/locale.h"
-#include "ldb_handlers.h"
-
-/*
- default handler that just copies a ldb_val.
-*/
-int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- *out = ldb_val_dup(mem_ctx, in);
- if (in->length > 0 && out->data == NULL) {
- ldb_oom(ldb);
- return -1;
- }
- return 0;
-}
-
-/*
- a case folding copy handler, removing leading and trailing spaces and
- multiple internal spaces
-
- We exploit the fact that utf8 never uses the space octet except for
- the space itself
-*/
-int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- char *s, *t;
- size_t l;
-
- if (!in || !out || !(in->data)) {
- return -1;
- }
-
- out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data), in->length);
- if (out->data == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%.*s]", (int)in->length, (const char *)in->data);
- return -1;
- }
-
- s = (char *)(out->data);
-
- /* remove trailing spaces if any */
- l = strlen(s);
- while (l > 0 && s[l - 1] == ' ') l--;
- s[l] = '\0';
-
- /* remove leading spaces if any */
- if (*s == ' ') {
- for (t = s; *s == ' '; s++) ;
-
- /* remove leading spaces by moving down the string */
- memmove(t, s, l);
-
- s = t;
- }
-
- /* check middle spaces */
- while ((t = strchr(s, ' ')) != NULL) {
- for (s = t; *s == ' '; s++) ;
-
- if ((s - t) > 1) {
- l = strlen(s);
-
- /* remove all spaces but one by moving down the string */
- memmove(t + 1, s, l);
- }
- }
-
- out->length = strlen((char *)out->data);
- return 0;
-}
-
-/* length limited conversion of a ldb_val to a int32_t */
-static int val_to_int64(const struct ldb_val *in, int64_t *v)
-{
- char *end;
- char buf[64];
-
- /* make sure we don't read past the end of the data */
- if (in->length > sizeof(buf)-1) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- strncpy(buf, (char *)in->data, in->length);
- buf[in->length] = 0;
-
- /* We've to use "strtoll" here to have the intended overflows.
- * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
- *v = (int64_t) strtoll(buf, &end, 0);
- if (*end != 0) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- return LDB_SUCCESS;
-}
-
-
-/*
- canonicalise a ldap Integer
- rfc2252 specifies it should be in decimal form
-*/
-static int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- int64_t i;
- int ret;
-
- ret = val_to_int64(in, &i);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%lld", (long long)i);
- if (out->data == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- out->length = strlen((char *)out->data);
- return 0;
-}
-
-/*
- compare two Integers
-*/
-static int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- int64_t i1=0, i2=0;
- val_to_int64(v1, &i1);
- val_to_int64(v2, &i2);
- if (i1 == i2) return 0;
- return i1 > i2? 1 : -1;
-}
-
-/*
- canonicalise a ldap Boolean
- rfc2252 specifies it should be either "TRUE" or "FALSE"
-*/
-static int ldb_canonicalise_Boolean(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- if (strncasecmp((char *)in->data, "TRUE", in->length) == 0) {
- out->data = (uint8_t *)talloc_strdup(mem_ctx, "TRUE");
- out->length = 4;
- } else if (strncasecmp((char *)in->data, "FALSE", in->length) == 0) {
- out->data = (uint8_t *)talloc_strdup(mem_ctx, "FALSE");
- out->length = 4;
- } else {
- return -1;
- }
- return 0;
-}
-
-/*
- compare two Booleans
-*/
-static int ldb_comparison_Boolean(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- if (v1->length != v2->length) {
- return v1->length - v2->length;
- }
- return strncasecmp((char *)v1->data, (char *)v2->data, v1->length);
-}
-
-
-/*
- compare two binary blobs
-*/
-int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- if (v1->length != v2->length) {
- return v1->length - v2->length;
- }
- return memcmp(v1->data, v2->data, v1->length);
-}
-
-/*
- compare two case insensitive strings, ignoring multiple whitespaces
- and leading and trailing whitespaces
- see rfc2252 section 8.1
-
- try to optimize for the ascii case,
- but if we find out an utf8 codepoint revert to slower but correct function
-*/
-int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
- size_t n1 = v1->length, n2 = v2->length;
- char *b1, *b2;
- const char *u1, *u2;
- int ret;
- while (n1 && *s1 == ' ') { s1++; n1--; };
- while (n2 && *s2 == ' ') { s2++; n2--; };
-
- while (n1 && n2 && *s1 && *s2) {
- /* the first 127 (0x7F) chars are ascii and utf8 guarantes they
- * never appear in multibyte sequences */
- if (((unsigned char)s1[0]) & 0x80) goto utf8str;
- if (((unsigned char)s2[0]) & 0x80) goto utf8str;
- if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
- break;
- if (*s1 == ' ') {
- while (n1 && s1[0] == s1[1]) { s1++; n1--; }
- while (n2 && s2[0] == s2[1]) { s2++; n2--; }
- }
- s1++; s2++;
- n1--; n2--;
- }
-
- /* check for trailing spaces only if the other pointers has
- * reached the end of the strings otherwise we can
- * mistakenly match. ex. "domain users" <->
- * "domainUpdates"
- */
- if (n1 && *s1 == ' ' && (!n2 || !*s2)) {
- while (n1 && *s1 == ' ') { s1++; n1--; }
- }
- if (n2 && *s2 == ' ' && (!n1 || !*s1)) {
- while (n2 && *s2 == ' ') { s2++; n2--; }
- }
- if (n1 == 0 && n2 != 0) {
- return -(int)toupper(*s2);
- }
- if (n2 == 0 && n1 != 0) {
- return (int)toupper(*s1);
- }
- if (n2 == 0 && n2 == 0) {
- return 0;
- }
- return (int)toupper(*s1) - (int)toupper(*s2);
-
-utf8str:
- /* no need to recheck from the start, just from the first utf8 char found */
- b1 = ldb_casefold(ldb, mem_ctx, s1, n1);
- b2 = ldb_casefold(ldb, mem_ctx, s2, n2);
-
- if (!b1 || !b2) {
- /* One of the strings was not UTF8, so we have no
- * options but to do a binary compare */
- talloc_free(b1);
- talloc_free(b2);
- ret = memcmp(s1, s2, MIN(n1, n2));
- if (ret == 0) {
- if (n1 == n2) return 0;
- if (n1 > n2) {
- return (int)toupper(s1[n2]);
- } else {
- return -(int)toupper(s2[n1]);
- }
- }
- return ret;
- }
-
- u1 = b1;
- u2 = b2;
-
- while (*u1 & *u2) {
- if (*u1 != *u2)
- break;
- if (*u1 == ' ') {
- while (u1[0] == u1[1]) u1++;
- while (u2[0] == u2[1]) u2++;
- }
- u1++; u2++;
- }
- if (! (*u1 && *u2)) {
- while (*u1 == ' ') u1++;
- while (*u2 == ' ') u2++;
- }
- ret = (int)(*u1 - *u2);
-
- talloc_free(b1);
- talloc_free(b2);
-
- return ret;
-}
-
-
-/*
- canonicalise a attribute in DN format
-*/
-static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- struct ldb_dn *dn;
- int ret = -1;
-
- out->length = 0;
- out->data = NULL;
-
- dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in);
- if ( ! ldb_dn_validate(dn)) {
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
-
- out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
- if (out->data == NULL) {
- goto done;
- }
- out->length = strlen((char *)out->data);
-
- ret = 0;
-
-done:
- talloc_free(dn);
-
- return ret;
-}
-
-/*
- compare two dns
-*/
-static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- struct ldb_dn *dn1 = NULL, *dn2 = NULL;
- int ret;
-
- dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1);
- if ( ! ldb_dn_validate(dn1)) return -1;
-
- dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2);
- if ( ! ldb_dn_validate(dn2)) {
- talloc_free(dn1);
- return -1;
- }
-
- ret = ldb_dn_compare(dn1, dn2);
-
- talloc_free(dn1);
- talloc_free(dn2);
- return ret;
-}
-
-/*
- compare two utc time values. 1 second resolution
-*/
-static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *v1, const struct ldb_val *v2)
-{
- time_t t1=0, t2=0;
- ldb_val_to_time(v1, &t1);
- ldb_val_to_time(v2, &t2);
- if (t1 == t2) return 0;
- return t1 > t2? 1 : -1;
-}
-
-/*
- canonicalise a utc time
-*/
-static int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
- const struct ldb_val *in, struct ldb_val *out)
-{
- time_t t;
- int ret;
- ret = ldb_val_to_time(in, &t);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
- if (out->data == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- out->length = strlen((char *)out->data);
- return 0;
-}
-
-/*
- table of standard attribute handlers
-*/
-static const struct ldb_schema_syntax ldb_standard_syntaxes[] = {
- {
- .name = LDB_SYNTAX_INTEGER,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_canonicalise_Integer,
- .comparison_fn = ldb_comparison_Integer
- },
- {
- .name = LDB_SYNTAX_OCTET_STRING,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_handler_copy,
- .comparison_fn = ldb_comparison_binary
- },
- {
- .name = LDB_SYNTAX_DIRECTORY_STRING,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_handler_fold,
- .comparison_fn = ldb_comparison_fold
- },
- {
- .name = LDB_SYNTAX_DN,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_canonicalise_dn,
- .comparison_fn = ldb_comparison_dn
- },
- {
- .name = LDB_SYNTAX_OBJECTCLASS,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_handler_fold,
- .comparison_fn = ldb_comparison_fold
- },
- {
- .name = LDB_SYNTAX_UTC_TIME,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_canonicalise_utctime,
- .comparison_fn = ldb_comparison_utctime
- },
- {
- .name = LDB_SYNTAX_BOOLEAN,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_canonicalise_Boolean,
- .comparison_fn = ldb_comparison_Boolean
- },
-};
-
-
-/*
- return the attribute handlers for a given syntax name
-*/
-const struct ldb_schema_syntax *ldb_standard_syntax_by_name(struct ldb_context *ldb,
- const char *syntax)
-{
- unsigned int i;
- unsigned num_handlers = sizeof(ldb_standard_syntaxes)/sizeof(ldb_standard_syntaxes[0]);
- /* TODO: should be replaced with a binary search */
- for (i=0;i<num_handlers;i++) {
- if (strcmp(ldb_standard_syntaxes[i].name, syntax) == 0) {
- return &ldb_standard_syntaxes[i];
- }
- }
- return NULL;
-}
-
-int ldb_any_comparison(struct ldb_context *ldb, void *mem_ctx,
- ldb_attr_handler_t canonicalise_fn,
- const struct ldb_val *v1,
- const struct ldb_val *v2)
-{
- int ret, ret1, ret2;
- struct ldb_val v1_canon, v2_canon;
- TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-
- /* I could try and bail if tmp_ctx was NULL, but what return
- * value would I use?
- *
- * It seems easier to continue on the NULL context
- */
- ret1 = canonicalise_fn(ldb, tmp_ctx, v1, &v1_canon);
- ret2 = canonicalise_fn(ldb, tmp_ctx, v2, &v2_canon);
-
- if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
- ret = ldb_comparison_binary(ldb, mem_ctx, &v1_canon, &v2_canon);
- } else {
- ret = ldb_comparison_binary(ldb, mem_ctx, v1, v2);
- }
- talloc_free(tmp_ctx);
- return ret;
-}
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
deleted file mode 100644
index 433f30b7c1..0000000000
--- a/source4/lib/ldb/common/ldb.c
+++ /dev/null
@@ -1,1923 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Simo Sorce 2005-2008
-
- ** 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 core API
- *
- * Description: core API routines interfacing to ldb backends
- *
- * Author: Andrew Tridgell
- */
-
-#define TEVENT_DEPRECATED 1
-#include "ldb_private.h"
-#include "ldb.h"
-
-static int ldb_context_destructor(void *ptr)
-{
- struct ldb_context *ldb = talloc_get_type(ptr, struct ldb_context);
-
- if (ldb->transaction_active) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "A transaction is still active in ldb context [%p] on %s",
- ldb, (const char *)ldb_get_opaque(ldb, "ldb_url"));
- }
-
- return 0;
-}
-
-/*
- this is used to catch debug messages from events
-*/
-static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
- const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
-
-static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
- const char *fmt, va_list ap)
-{
- struct ldb_context *ldb = talloc_get_type(context, struct ldb_context);
- enum ldb_debug_level ldb_level = LDB_DEBUG_FATAL;
- char *s = NULL;
-
- switch (level) {
- case TEVENT_DEBUG_FATAL:
- ldb_level = LDB_DEBUG_FATAL;
- break;
- case TEVENT_DEBUG_ERROR:
- ldb_level = LDB_DEBUG_ERROR;
- break;
- case TEVENT_DEBUG_WARNING:
- ldb_level = LDB_DEBUG_WARNING;
- break;
- case TEVENT_DEBUG_TRACE:
- ldb_level = LDB_DEBUG_TRACE;
- break;
- };
-
- vasprintf(&s, fmt, ap);
- if (!s) return;
- ldb_debug(ldb, ldb_level, "tevent: %s", s);
- free(s);
-}
-
-/*
- initialise a ldb context
- The mem_ctx is required
- The event_ctx is required
-*/
-struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx)
-{
- struct ldb_context *ldb;
- int ret;
- const char *modules_path = getenv("LDB_MODULES_PATH");
-
- if (modules_path == NULL) {
- modules_path = LDB_MODULESDIR;
- }
-
- ret = ldb_modules_load(modules_path, LDB_VERSION);
- if (ret != LDB_SUCCESS) {
- return NULL;
- }
-
- ldb = talloc_zero(mem_ctx, struct ldb_context);
- if (ldb == NULL) {
- return NULL;
- }
-
- /* A new event context so that callers who don't want ldb
- * operating on thier global event context can work without
- * having to provide their own private one explicitly */
- if (ev_ctx == NULL) {
- ev_ctx = tevent_context_init(ldb);
- tevent_set_debug(ev_ctx, ldb_tevent_debug, ldb);
- tevent_loop_allow_nesting(ev_ctx);
- }
-
- ret = ldb_setup_wellknown_attributes(ldb);
- if (ret != LDB_SUCCESS) {
- talloc_free(ldb);
- return NULL;
- }
-
- ldb_set_utf8_default(ldb);
- ldb_set_create_perms(ldb, 0666);
- ldb_set_modules_dir(ldb, LDB_MODULESDIR);
- ldb_set_event_context(ldb, ev_ctx);
-
- /* TODO: get timeout from options if available there */
- ldb->default_timeout = 300; /* set default to 5 minutes */
-
- talloc_set_destructor((TALLOC_CTX *)ldb, ldb_context_destructor);
-
- return ldb;
-}
-
-/*
- try to autodetect a basedn if none specified. This fixes one of my
- pet hates about ldapsearch, which is that you have to get a long,
- complex basedn right to make any use of it.
-*/
-void ldb_set_default_dns(struct ldb_context *ldb)
-{
- TALLOC_CTX *tmp_ctx;
- int ret;
- struct ldb_result *res;
- struct ldb_dn *tmp_dn=NULL;
- static const char *attrs[] = {
- "rootDomainNamingContext",
- "configurationNamingContext",
- "schemaNamingContext",
- "defaultNamingContext",
- NULL
- };
-
- tmp_ctx = talloc_new(ldb);
- ret = ldb_search(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, NULL),
- LDB_SCOPE_BASE, attrs, "(objectClass=*)");
- if (ret != LDB_SUCCESS) {
- talloc_free(tmp_ctx);
- return;
- }
-
- if (res->count != 1) {
- talloc_free(tmp_ctx);
- return;
- }
-
- if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
- "rootDomainNamingContext");
- ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "configurationNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
- "configurationNamingContext");
- ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "schemaNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
- "schemaNamingContext");
- ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "defaultNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
- "defaultNamingContext");
- ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn);
- }
-
- talloc_free(tmp_ctx);
-}
-
-struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb)
-{
- void *opaque = ldb_get_opaque(ldb, "rootDomainNamingContext");
- return talloc_get_type(opaque, struct ldb_dn);
-}
-
-struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb)
-{
- void *opaque = ldb_get_opaque(ldb, "configurationNamingContext");
- return talloc_get_type(opaque, struct ldb_dn);
-}
-
-struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb)
-{
- void *opaque = ldb_get_opaque(ldb, "schemaNamingContext");
- return talloc_get_type(opaque, struct ldb_dn);
-}
-
-struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb)
-{
- void *opaque = ldb_get_opaque(ldb, "defaultNamingContext");
- return talloc_get_type(opaque, struct ldb_dn);
-}
-
-/*
- connect to a database. The URL can either be one of the following forms
- ldb://path
- ldapi://path
-
- flags is made up of LDB_FLG_*
-
- the options are passed uninterpreted to the backend, and are
- backend specific
-*/
-int ldb_connect(struct ldb_context *ldb, const char *url,
- unsigned int flags, const char *options[])
-{
- int ret;
- char *url2;
- /* We seem to need to do this here, or else some utilities don't
- * get ldb backends */
-
- ldb->flags = flags;
-
- url2 = talloc_strdup(ldb, url);
- if (!url2) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ret = ldb_set_opaque(ldb, "ldb_url", url2);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_module_connect_backend(ldb, url, options, &ldb->modules);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- if (ldb_load_modules(ldb, options) != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "Unable to load modules for %s: %s",
- url, ldb_errstring(ldb));
- return LDB_ERR_OTHER;
- }
-
- /* set the default base dn */
- ldb_set_default_dns(ldb);
-
- return LDB_SUCCESS;
-}
-
-void ldb_set_errstring(struct ldb_context *ldb, const char *err_string)
-{
- if (ldb->err_string) {
- talloc_free(ldb->err_string);
- }
- ldb->err_string = talloc_strdup(ldb, err_string);
- if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_set_errstring: %s", ldb->err_string);
- }
-}
-
-void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...)
-{
- va_list ap;
- char *old_string = NULL;
-
- if (ldb->err_string) {
- old_string = ldb->err_string;
- }
-
- va_start(ap, format);
- ldb->err_string = talloc_vasprintf(ldb, format, ap);
- va_end(ap);
- talloc_free(old_string);
-}
-
-void ldb_reset_err_string(struct ldb_context *ldb)
-{
- if (ldb->err_string) {
- talloc_free(ldb->err_string);
- ldb->err_string = NULL;
- }
-}
-
-
-
-/*
- set an ldb error based on file:line
-*/
-int ldb_error_at(struct ldb_context *ldb, int ecode,
- const char *reason, const char *file, int line)
-{
- if (reason == NULL) {
- reason = ldb_strerror(ecode);
- }
- ldb_asprintf_errstring(ldb, "%s at %s:%d", reason, file, line);
- return ecode;
-}
-
-
-#define FIRST_OP_NOERR(ldb, op) do { \
- module = ldb->modules; \
- while (module && module->ops->op == NULL) module = module->next; \
- if ((ldb->flags & LDB_FLG_ENABLE_TRACING) && module) { \
- ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_trace_request: (%s)->" #op, \
- module->ops->name); \
- } \
-} while (0)
-
-#define FIRST_OP(ldb, op) do { \
- FIRST_OP_NOERR(ldb, op); \
- if (module == NULL) { \
- ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
- return LDB_ERR_OPERATIONS_ERROR; \
- } \
-} while (0)
-
-
-/*
- start a transaction
-*/
-int ldb_transaction_start(struct ldb_context *ldb)
-{
- struct ldb_module *module;
- int status;
-
- ldb_debug(ldb, LDB_DEBUG_TRACE,
- "start ldb transaction (nesting: %d)",
- ldb->transaction_active);
-
- /* explicit transaction active, count nested requests */
- if (ldb->transaction_active) {
- ldb->transaction_active++;
- return LDB_SUCCESS;
- }
-
- /* start a new transaction */
- ldb->transaction_active++;
- ldb->prepare_commit_done = false;
-
- FIRST_OP(ldb, start_transaction);
-
- ldb_reset_err_string(ldb);
-
- status = module->ops->start_transaction(module);
- if (status != LDB_SUCCESS) {
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction start: %s (%d)",
- ldb_strerror(status),
- status);
- }
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "start ldb transaction error: %s",
- ldb_errstring(module->ldb));
- }
- return status;
-}
-
-/*
- prepare for transaction commit (first phase of two phase commit)
-*/
-int ldb_transaction_prepare_commit(struct ldb_context *ldb)
-{
- struct ldb_module *module;
- int status;
-
- if (ldb->prepare_commit_done) {
- return LDB_SUCCESS;
- }
-
- /* commit only when all nested transactions are complete */
- if (ldb->transaction_active > 1) {
- return LDB_SUCCESS;
- }
-
- ldb->prepare_commit_done = true;
-
- if (ldb->transaction_active < 0) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "prepare commit called but no ldb transactions are active!");
- ldb->transaction_active = 0;
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* call prepare transaction if available */
- FIRST_OP_NOERR(ldb, prepare_commit);
- if (module == NULL) {
- return LDB_SUCCESS;
- }
-
- status = module->ops->prepare_commit(module);
- if (status != LDB_SUCCESS) {
- /* if a module fails the prepare then we need
- to call the end transaction for everyone */
- FIRST_OP(ldb, del_transaction);
- module->ops->del_transaction(module);
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction prepare commit: %s (%d)",
- ldb_strerror(status),
- status);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "prepare commit transaction error: %s",
- ldb_errstring(module->ldb));
- }
- }
-
- return status;
-}
-
-
-/*
- commit a transaction
-*/
-int ldb_transaction_commit(struct ldb_context *ldb)
-{
- struct ldb_module *module;
- int status;
-
- status = ldb_transaction_prepare_commit(ldb);
- if (status != LDB_SUCCESS) {
- return status;
- }
-
- ldb->transaction_active--;
-
- ldb_debug(ldb, LDB_DEBUG_TRACE,
- "commit ldb transaction (nesting: %d)",
- ldb->transaction_active);
-
- /* commit only when all nested transactions are complete */
- if (ldb->transaction_active > 0) {
- return LDB_SUCCESS;
- }
-
- if (ldb->transaction_active < 0) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "commit called but no ldb transactions are active!");
- ldb->transaction_active = 0;
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ldb_reset_err_string(ldb);
-
- FIRST_OP(ldb, end_transaction);
- status = module->ops->end_transaction(module);
- if (status != LDB_SUCCESS) {
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction commit: %s (%d)",
- ldb_strerror(status),
- status);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "commit ldb transaction error: %s",
- ldb_errstring(module->ldb));
- }
- /* cancel the transaction */
- FIRST_OP(ldb, del_transaction);
- module->ops->del_transaction(module);
- }
- return status;
-}
-
-
-/*
- cancel a transaction
-*/
-int ldb_transaction_cancel(struct ldb_context *ldb)
-{
- struct ldb_module *module;
- int status;
-
- ldb->transaction_active--;
-
- ldb_debug(ldb, LDB_DEBUG_TRACE,
- "cancel ldb transaction (nesting: %d)",
- ldb->transaction_active);
-
- /* really cancel only if all nested transactions are complete */
- if (ldb->transaction_active > 0) {
- return LDB_SUCCESS;
- }
-
- if (ldb->transaction_active < 0) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "cancel called but no ldb transactions are active!");
- ldb->transaction_active = 0;
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- FIRST_OP(ldb, del_transaction);
-
- status = module->ops->del_transaction(module);
- if (status != LDB_SUCCESS) {
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction cancel: %s (%d)",
- ldb_strerror(status),
- status);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "cancel ldb transaction error: %s",
- ldb_errstring(module->ldb));
- }
- }
- return status;
-}
-
-/*
- cancel a transaction with no error if no transaction is pending
- used when we fork() to clear any parent transactions
-*/
-int ldb_transaction_cancel_noerr(struct ldb_context *ldb)
-{
- if (ldb->transaction_active > 0) {
- return ldb_transaction_cancel(ldb);
- }
- return LDB_SUCCESS;
-}
-
-
-/* autostarts a transacion if none active */
-static int ldb_autotransaction_request(struct ldb_context *ldb,
- struct ldb_request *req)
-{
- int ret;
-
- ret = ldb_transaction_start(ldb);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_request(ldb, req);
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
-
- if (ret == LDB_SUCCESS) {
- return ldb_transaction_commit(ldb);
- }
- ldb_transaction_cancel(ldb);
-
- if (ldb->err_string == NULL) {
- /* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret);
- }
-
- return ret;
-}
-
-int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
- struct tevent_context *ev;
- int ret;
-
- if (!handle) {
- return LDB_ERR_UNAVAILABLE;
- }
-
- if (handle->state == LDB_ASYNC_DONE) {
- return handle->status;
- }
-
- ev = ldb_get_event_context(handle->ldb);
- if (NULL == ev) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- switch (type) {
- case LDB_WAIT_NONE:
- ret = tevent_loop_once(ev);
- if (ret != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- if (handle->state == LDB_ASYNC_DONE ||
- handle->status != LDB_SUCCESS) {
- return handle->status;
- }
- break;
-
- case LDB_WAIT_ALL:
- while (handle->state != LDB_ASYNC_DONE) {
- ret = tevent_loop_once(ev);
- if (ret != 0) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- if (handle->status != LDB_SUCCESS) {
- return handle->status;
- }
- }
- return handle->status;
- }
-
- return LDB_SUCCESS;
-}
-
-/* set the specified timeout or, if timeout is 0 set the default timeout */
-int ldb_set_timeout(struct ldb_context *ldb,
- struct ldb_request *req,
- int timeout)
-{
- if (req == NULL) return LDB_ERR_OPERATIONS_ERROR;
-
- if (timeout != 0) {
- req->timeout = timeout;
- } else {
- req->timeout = ldb->default_timeout;
- }
- req->starttime = time(NULL);
-
- return LDB_SUCCESS;
-}
-
-/* calculates the new timeout based on the previous starttime and timeout */
-int ldb_set_timeout_from_prev_req(struct ldb_context *ldb,
- struct ldb_request *oldreq,
- struct ldb_request *newreq)
-{
- if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR;
-
- if (oldreq == NULL) {
- return ldb_set_timeout(ldb, newreq, 0);
- }
-
- newreq->starttime = oldreq->starttime;
- newreq->timeout = oldreq->timeout;
-
- return LDB_SUCCESS;
-}
-
-
-/*
- set the permissions for new files to be passed to open() in
- backends that use local files
- */
-void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms)
-{
- ldb->create_perms = perms;
-}
-
-unsigned int ldb_get_create_perms(struct ldb_context *ldb)
-{
- return ldb->create_perms;
-}
-
-void ldb_set_event_context(struct ldb_context *ldb, struct tevent_context *ev)
-{
- ldb->ev_ctx = ev;
-}
-
-struct tevent_context * ldb_get_event_context(struct ldb_context *ldb)
-{
- return ldb->ev_ctx;
-}
-
-void ldb_request_set_state(struct ldb_request *req, int state)
-{
- req->handle->state = state;
-}
-
-int ldb_request_get_status(struct ldb_request *req)
-{
- return req->handle->status;
-}
-
-
-/*
- trace a ldb request
-*/
-static void ldb_trace_request(struct ldb_context *ldb, struct ldb_request *req)
-{
- TALLOC_CTX *tmp_ctx = talloc_new(req);
- unsigned int i;
-
- switch (req->operation) {
- case LDB_SEARCH:
- ldb_debug_add(ldb, "ldb_trace_request: SEARCH\n");
- ldb_debug_add(ldb, " dn: %s\n",
- ldb_dn_is_null(req->op.search.base)?"<rootDSE>":
- ldb_dn_get_linearized(req->op.search.base));
- ldb_debug_add(ldb, " scope: %s\n",
- req->op.search.scope==LDB_SCOPE_BASE?"base":
- req->op.search.scope==LDB_SCOPE_ONELEVEL?"one":
- req->op.search.scope==LDB_SCOPE_SUBTREE?"sub":"UNKNOWN");
- ldb_debug_add(ldb, " expr: %s\n",
- ldb_filter_from_tree(tmp_ctx, req->op.search.tree));
- if (req->op.search.attrs == NULL) {
- ldb_debug_add(ldb, " attr: <ALL>\n");
- } else {
- for (i=0; req->op.search.attrs[i]; i++) {
- ldb_debug_add(ldb, " attr: %s\n", req->op.search.attrs[i]);
- }
- }
- break;
- case LDB_DELETE:
- ldb_debug_add(ldb, "ldb_trace_request: DELETE\n");
- ldb_debug_add(ldb, " dn: %s\n",
- ldb_dn_get_linearized(req->op.del.dn));
- break;
- case LDB_RENAME:
- ldb_debug_add(ldb, "ldb_trace_request: RENAME\n");
- ldb_debug_add(ldb, " olddn: %s\n",
- ldb_dn_get_linearized(req->op.rename.olddn));
- ldb_debug_add(ldb, " newdn: %s\n",
- ldb_dn_get_linearized(req->op.rename.newdn));
- break;
- case LDB_EXTENDED:
- ldb_debug_add(ldb, "ldb_trace_request: EXTENDED\n");
- ldb_debug_add(ldb, " oid: %s\n", req->op.extended.oid);
- ldb_debug_add(ldb, " data: %s\n", req->op.extended.data?"yes":"no");
- break;
- case LDB_ADD:
- ldb_debug_add(ldb, "ldb_trace_request: ADD\n");
- ldb_debug_add(req->handle->ldb, "%s\n",
- ldb_ldif_message_string(req->handle->ldb, tmp_ctx,
- LDB_CHANGETYPE_ADD,
- req->op.add.message));
- break;
- case LDB_MODIFY:
- ldb_debug_add(ldb, "ldb_trace_request: MODIFY\n");
- ldb_debug_add(req->handle->ldb, "%s\n",
- ldb_ldif_message_string(req->handle->ldb, tmp_ctx,
- LDB_CHANGETYPE_ADD,
- req->op.mod.message));
- break;
- case LDB_REQ_REGISTER_CONTROL:
- ldb_debug_add(ldb, "ldb_trace_request: REGISTER_CONTROL\n");
- ldb_debug_add(req->handle->ldb, "%s\n",
- req->op.reg_control.oid);
- break;
- case LDB_REQ_REGISTER_PARTITION:
- ldb_debug_add(ldb, "ldb_trace_request: REGISTER_PARTITION\n");
- ldb_debug_add(req->handle->ldb, "%s\n",
- ldb_dn_get_linearized(req->op.reg_partition.dn));
- break;
- default:
- ldb_debug_add(ldb, "ldb_trace_request: UNKNOWN(%u)\n",
- req->operation);
- break;
- }
-
- if (req->controls == NULL) {
- ldb_debug_add(ldb, " control: <NONE>\n");
- } else {
- for (i=0; req->controls && req->controls[i]; i++) {
- if (req->controls[i]->oid) {
- ldb_debug_add(ldb, " control: %s crit:%u data:%s\n",
- req->controls[i]->oid,
- req->controls[i]->critical,
- req->controls[i]->data?"yes":"no");
- }
- }
- }
-
- ldb_debug_end(ldb, LDB_DEBUG_TRACE);
-
- talloc_free(tmp_ctx);
-}
-
-/*
- check that the element flags don't have any internal bits set
- */
-static int ldb_msg_check_element_flags(struct ldb_context *ldb,
- const struct ldb_message *message)
-{
- unsigned i;
- for (i=0; i<message->num_elements; i++) {
- if (message->elements[i].flags & LDB_FLAG_INTERNAL_MASK) {
- ldb_asprintf_errstring(ldb, "Invalid element flags 0x%08x on element %s in %s\n",
- message->elements[i].flags, message->elements[i].name,
- ldb_dn_get_linearized(message->dn));
- return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
- }
- }
- return LDB_SUCCESS;
-}
-
-
-/*
- start an ldb request
- NOTE: the request must be a talloc context.
- returns LDB_ERR_* on errors.
-*/
-int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
-{
- struct ldb_module *module;
- int ret;
-
- if (req->callback == NULL) {
- ldb_set_errstring(ldb, "Requests MUST define callbacks");
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
- ldb_reset_err_string(ldb);
-
- if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
- ldb_trace_request(ldb, req);
- }
-
- /* call the first module in the chain */
- switch (req->operation) {
- case LDB_SEARCH:
- /* due to "ldb_build_search_req" base DN always != NULL */
- if (!ldb_dn_validate(req->op.search.base)) {
- ldb_asprintf_errstring(ldb, "ldb_search: invalid basedn '%s'",
- ldb_dn_get_linearized(req->op.search.base));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- FIRST_OP(ldb, search);
- ret = module->ops->search(module, req);
- break;
- case LDB_ADD:
- if (!ldb_dn_validate(req->op.add.message->dn)) {
- ldb_asprintf_errstring(ldb, "ldb_add: invalid dn '%s'",
- ldb_dn_get_linearized(req->op.add.message->dn));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- /*
- * we have to normalize here, as so many places
- * in modules and backends assume we don't have two
- * elements with the same name
- */
- ret = ldb_msg_normalize(ldb, req, req->op.add.message,
- discard_const(&req->op.add.message));
- if (ret != LDB_SUCCESS) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- FIRST_OP(ldb, add);
- ret = ldb_msg_check_element_flags(ldb, req->op.add.message);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- ret = module->ops->add(module, req);
- break;
- case LDB_MODIFY:
- if (!ldb_dn_validate(req->op.mod.message->dn)) {
- ldb_asprintf_errstring(ldb, "ldb_modify: invalid dn '%s'",
- ldb_dn_get_linearized(req->op.mod.message->dn));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- FIRST_OP(ldb, modify);
- ret = ldb_msg_check_element_flags(ldb, req->op.mod.message);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- ret = module->ops->modify(module, req);
- break;
- case LDB_DELETE:
- if (!ldb_dn_validate(req->op.del.dn)) {
- ldb_asprintf_errstring(ldb, "ldb_delete: invalid dn '%s'",
- ldb_dn_get_linearized(req->op.del.dn));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- FIRST_OP(ldb, del);
- ret = module->ops->del(module, req);
- break;
- case LDB_RENAME:
- if (!ldb_dn_validate(req->op.rename.olddn)) {
- ldb_asprintf_errstring(ldb, "ldb_rename: invalid olddn '%s'",
- ldb_dn_get_linearized(req->op.rename.olddn));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- if (!ldb_dn_validate(req->op.rename.newdn)) {
- ldb_asprintf_errstring(ldb, "ldb_rename: invalid newdn '%s'",
- ldb_dn_get_linearized(req->op.rename.newdn));
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
- FIRST_OP(ldb, rename);
- ret = module->ops->rename(module, req);
- break;
- case LDB_EXTENDED:
- FIRST_OP(ldb, extended);
- ret = module->ops->extended(module, req);
- break;
- default:
- FIRST_OP(ldb, request);
- ret = module->ops->request(module, req);
- break;
- }
-
- return ret;
-}
-
-int ldb_request_done(struct ldb_request *req, int status)
-{
- req->handle->state = LDB_ASYNC_DONE;
- req->handle->status = status;
- return status;
-}
-
-/*
- search the database given a LDAP-like search expression
-
- returns an LDB error code
-
- Use talloc_free to free the ldb_message returned in 'res', if successful
-
-*/
-int ldb_search_default_callback(struct ldb_request *req,
- struct ldb_reply *ares)
-{
- struct ldb_result *res;
- unsigned int n;
-
- res = talloc_get_type(req->context, struct ldb_result);
-
- if (!ares) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_request_done(req, ares->error);
- }
-
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- res->msgs = talloc_realloc(res, res->msgs,
- struct ldb_message *, res->count + 2);
- if (! res->msgs) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- res->msgs[res->count + 1] = NULL;
-
- res->msgs[res->count] = talloc_move(res->msgs, &ares->message);
- res->count++;
- break;
-
- case LDB_REPLY_REFERRAL:
- if (res->refs) {
- for (n = 0; res->refs[n]; n++) /*noop*/ ;
- } else {
- n = 0;
- }
-
- res->refs = talloc_realloc(res, res->refs, char *, n + 2);
- if (! res->refs) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- res->refs[n] = talloc_move(res->refs, &ares->referral);
- res->refs[n + 1] = NULL;
- break;
-
- case LDB_REPLY_DONE:
- /* TODO: we should really support controls on entries
- * and referrals too! */
- res->controls = talloc_move(res, &ares->controls);
-
- /* this is the last message, and means the request is done */
- /* we have to signal and eventual ldb_wait() waiting that the
- * async request operation was completed */
- talloc_free(ares);
- return ldb_request_done(req, LDB_SUCCESS);
- }
-
- talloc_free(ares);
-
- return LDB_SUCCESS;
-}
-
-int ldb_modify_default_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- struct ldb_result *res;
- unsigned int n;
- int ret;
-
- res = talloc_get_type(req->context, struct ldb_result);
-
- if (!ares) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- if (ares->error != LDB_SUCCESS) {
- ret = ares->error;
- talloc_free(ares);
- return ldb_request_done(req, ret);
- }
-
- switch (ares->type) {
- case LDB_REPLY_REFERRAL:
- if (res->refs) {
- for (n = 0; res->refs[n]; n++) /*noop*/ ;
- } else {
- n = 0;
- }
-
- res->refs = talloc_realloc(res, res->refs, char *, n + 2);
- if (! res->refs) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- res->refs[n] = talloc_move(res->refs, &ares->referral);
- res->refs[n + 1] = NULL;
- break;
-
- case LDB_REPLY_DONE:
- talloc_free(ares);
- return ldb_request_done(req, LDB_SUCCESS);
- default:
- talloc_free(ares);
- ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- talloc_free(ares);
- return ldb_request_done(req, LDB_SUCCESS);
-}
-
-int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- int ret;
-
- if (!ares) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- if (ares->error != LDB_SUCCESS) {
- ret = ares->error;
- talloc_free(ares);
- return ldb_request_done(req, ret);
- }
-
- if (ares->type != LDB_REPLY_DONE) {
- talloc_free(ares);
- ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
-
- talloc_free(ares);
- return ldb_request_done(req, LDB_SUCCESS);
-}
-
-int ldb_build_search_req_ex(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- struct ldb_dn *base,
- enum ldb_scope scope,
- struct ldb_parse_tree *tree,
- const char * const *attrs,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_SEARCH;
- if (base == NULL) {
- req->op.search.base = ldb_dn_new(req, ldb, NULL);
- } else {
- req->op.search.base = base;
- }
- req->op.search.scope = scope;
-
- req->op.search.tree = tree;
- if (req->op.search.tree == NULL) {
- ldb_set_errstring(ldb, "'tree' can't be NULL");
- talloc_free(req);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->op.search.attrs = attrs;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
- return LDB_SUCCESS;
-}
-
-int ldb_build_search_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- struct ldb_dn *base,
- enum ldb_scope scope,
- const char *expression,
- const char * const *attrs,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_parse_tree *tree;
- int ret;
-
- tree = ldb_parse_tree(mem_ctx, expression);
- if (tree == NULL) {
- ldb_set_errstring(ldb, "Unable to parse search expression");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_search_req_ex(ret_req, ldb, mem_ctx, base,
- scope, tree, attrs, controls,
- context, callback, parent);
- if (ret == LDB_SUCCESS) {
- talloc_steal(*ret_req, tree);
- }
- return ret;
-}
-
-int ldb_build_add_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- const struct ldb_message *message,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_ADD;
- req->op.add.message = message;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
-
- return LDB_SUCCESS;
-}
-
-int ldb_build_mod_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- const struct ldb_message *message,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_MODIFY;
- req->op.mod.message = message;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
-
- return LDB_SUCCESS;
-}
-
-int ldb_build_del_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- struct ldb_dn *dn,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_DELETE;
- req->op.del.dn = dn;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
-
- return LDB_SUCCESS;
-}
-
-int ldb_build_rename_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- struct ldb_dn *olddn,
- struct ldb_dn *newdn,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_RENAME;
- req->op.rename.olddn = olddn;
- req->op.rename.newdn = newdn;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
-
- return LDB_SUCCESS;
-}
-
-int ldb_extended_default_callback(struct ldb_request *req,
- struct ldb_reply *ares)
-{
- struct ldb_result *res;
-
- res = talloc_get_type(req->context, struct ldb_result);
-
- if (!ares) {
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_request_done(req, ares->error);
- }
-
- if (ares->type == LDB_REPLY_DONE) {
-
- /* TODO: we should really support controls on entries and referrals too! */
- res->extended = talloc_move(res, &ares->response);
- res->controls = talloc_move(res, &ares->controls);
-
- talloc_free(ares);
- return ldb_request_done(req, LDB_SUCCESS);
- }
-
- talloc_free(ares);
- ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
- return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
-}
-
-int ldb_build_extended_req(struct ldb_request **ret_req,
- struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- const char *oid,
- void *data,
- struct ldb_control **controls,
- void *context,
- ldb_request_callback_t callback,
- struct ldb_request *parent)
-{
- struct ldb_request *req;
-
- *ret_req = NULL;
-
- req = talloc(mem_ctx, struct ldb_request);
- if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_EXTENDED;
- req->op.extended.oid = oid;
- req->op.extended.data = data;
- req->controls = controls;
- req->context = context;
- req->callback = callback;
-
- ldb_set_timeout_from_prev_req(ldb, parent, req);
-
- req->handle = ldb_handle_new(req, ldb);
- if (req->handle == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (parent) {
- req->handle->nesting++;
- req->handle->parent = parent;
- req->handle->flags = parent->handle->flags;
- req->handle->custom_flags = parent->handle->custom_flags;
- }
-
- *ret_req = req;
-
- return LDB_SUCCESS;
-}
-
-int ldb_extended(struct ldb_context *ldb,
- const char *oid,
- void *data,
- struct ldb_result **_res)
-{
- struct ldb_request *req;
- int ret;
- struct ldb_result *res;
-
- *_res = NULL;
-
- res = talloc_zero(ldb, struct ldb_result);
- if (!res) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_build_extended_req(&req, ldb, ldb,
- oid, data, NULL,
- res, ldb_extended_default_callback,
- NULL);
- if (ret != LDB_SUCCESS) goto done;
-
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
-
- ret = ldb_request(ldb, req);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
-
- talloc_free(req);
-
-done:
- if (ret != LDB_SUCCESS) {
- talloc_free(res);
- }
-
- *_res = res;
- return ret;
-}
-
-/*
- note that ldb_search() will automatically replace a NULL 'base' value
- with the defaultNamingContext from the rootDSE if available.
-*/
-int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
- struct ldb_result **result, struct ldb_dn *base,
- enum ldb_scope scope, const char * const *attrs,
- const char *exp_fmt, ...)
-{
- struct ldb_request *req;
- struct ldb_result *res;
- char *expression;
- va_list ap;
- int ret;
-
- expression = NULL;
- *result = NULL;
- req = NULL;
-
- res = talloc_zero(mem_ctx, struct ldb_result);
- if (!res) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (exp_fmt) {
- va_start(ap, exp_fmt);
- expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
- va_end(ap);
-
- if (!expression) {
- talloc_free(res);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- }
-
- ret = ldb_build_search_req(&req, ldb, mem_ctx,
- base?base:ldb_get_default_basedn(ldb),
- scope,
- expression,
- attrs,
- NULL,
- res,
- ldb_search_default_callback,
- NULL);
- ldb_req_set_location(req, "ldb_search");
-
- if (ret != LDB_SUCCESS) goto done;
-
- ret = ldb_request(ldb, req);
-
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
-
-done:
- if (ret != LDB_SUCCESS) {
- talloc_free(res);
- res = NULL;
- }
-
- talloc_free(expression);
- talloc_free(req);
-
- *result = res;
- return ret;
-}
-
-/*
- add a record to the database. Will fail if a record with the given class
- and key already exists
-*/
-int ldb_add(struct ldb_context *ldb,
- const struct ldb_message *message)
-{
- struct ldb_request *req;
- int ret;
-
- ret = ldb_msg_sanity_check(ldb, message);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_build_add_req(&req, ldb, ldb,
- message,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
- ldb_req_set_location(req, "ldb_add");
-
- if (ret != LDB_SUCCESS) return ret;
-
- /* do request and autostart a transaction */
- ret = ldb_autotransaction_request(ldb, req);
-
- talloc_free(req);
- return ret;
-}
-
-/*
- modify the specified attributes of a record
-*/
-int ldb_modify(struct ldb_context *ldb,
- const struct ldb_message *message)
-{
- struct ldb_request *req;
- int ret;
-
- ret = ldb_msg_sanity_check(ldb, message);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- ret = ldb_build_mod_req(&req, ldb, ldb,
- message,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
- ldb_req_set_location(req, "ldb_modify");
-
- if (ret != LDB_SUCCESS) return ret;
-
- /* do request and autostart a transaction */
- ret = ldb_autotransaction_request(ldb, req);
-
- talloc_free(req);
- return ret;
-}
-
-
-/*
- delete a record from the database
-*/
-int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn)
-{
- struct ldb_request *req;
- int ret;
-
- ret = ldb_build_del_req(&req, ldb, ldb,
- dn,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
- ldb_req_set_location(req, "ldb_delete");
-
- if (ret != LDB_SUCCESS) return ret;
-
- /* do request and autostart a transaction */
- ret = ldb_autotransaction_request(ldb, req);
-
- talloc_free(req);
- return ret;
-}
-
-/*
- rename a record in the database
-*/
-int ldb_rename(struct ldb_context *ldb,
- struct ldb_dn *olddn, struct ldb_dn *newdn)
-{
- struct ldb_request *req;
- int ret;
-
- ret = ldb_build_rename_req(&req, ldb, ldb,
- olddn,
- newdn,
- NULL,
- NULL,
- ldb_op_default_callback,
- NULL);
- ldb_req_set_location(req, "ldb_rename");
-
- if (ret != LDB_SUCCESS) return ret;
-
- /* do request and autostart a transaction */
- ret = ldb_autotransaction_request(ldb, req);
-
- talloc_free(req);
- return ret;
-}
-
-
-/*
- return the global sequence number
-*/
-int ldb_sequence_number(struct ldb_context *ldb,
- enum ldb_sequence_type type, uint64_t *seq_num)
-{
- struct ldb_seqnum_request *seq;
- struct ldb_seqnum_result *seqr;
- struct ldb_result *res;
- TALLOC_CTX *tmp_ctx;
- int ret;
-
- *seq_num = 0;
-
- tmp_ctx = talloc_zero(ldb, struct ldb_request);
- if (tmp_ctx == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return LDB_ERR_OPERATIONS_ERROR;
- }
- seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
- if (seq == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto done;
- }
- seq->type = type;
-
- ret = ldb_extended(ldb, LDB_EXTENDED_SEQUENCE_NUMBER, seq, &res);
- if (ret != LDB_SUCCESS) {
- goto done;
- }
- talloc_steal(tmp_ctx, res);
-
- if (strcmp(LDB_EXTENDED_SEQUENCE_NUMBER, res->extended->oid) != 0) {
- ldb_set_errstring(ldb, "Invalid OID in reply");
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto done;
- }
- seqr = talloc_get_type(res->extended->data,
- struct ldb_seqnum_result);
- *seq_num = seqr->seq_num;
-
-done:
- talloc_free(tmp_ctx);
- return ret;
-}
-
-/*
- return extended error information
-*/
-const char *ldb_errstring(struct ldb_context *ldb)
-{
- if (ldb->err_string) {
- return ldb->err_string;
- }
-
- return NULL;
-}
-
-/*
- return a string explaining what a ldb error constant meancs
-*/
-const char *ldb_strerror(int ldb_err)
-{
- switch (ldb_err) {
- case LDB_SUCCESS:
- return "Success";
- case LDB_ERR_OPERATIONS_ERROR:
- return "Operations error";
- case LDB_ERR_PROTOCOL_ERROR:
- return "Protocol error";
- case LDB_ERR_TIME_LIMIT_EXCEEDED:
- return "Time limit exceeded";
- case LDB_ERR_SIZE_LIMIT_EXCEEDED:
- return "Size limit exceeded";
- case LDB_ERR_COMPARE_FALSE:
- return "Compare false";
- case LDB_ERR_COMPARE_TRUE:
- return "Compare true";
- case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
- return "Auth method not supported";
- case LDB_ERR_STRONG_AUTH_REQUIRED:
- return "Strong auth required";
-/* 9 RESERVED */
- case LDB_ERR_REFERRAL:
- return "Referral error";
- case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
- return "Admin limit exceeded";
- case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
- return "Unsupported critical extension";
- case LDB_ERR_CONFIDENTIALITY_REQUIRED:
- return "Confidentiality required";
- case LDB_ERR_SASL_BIND_IN_PROGRESS:
- return "SASL bind in progress";
- case LDB_ERR_NO_SUCH_ATTRIBUTE:
- return "No such attribute";
- case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
- return "Undefined attribute type";
- case LDB_ERR_INAPPROPRIATE_MATCHING:
- return "Inappropriate matching";
- case LDB_ERR_CONSTRAINT_VIOLATION:
- return "Constraint violation";
- case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
- return "Attribute or value exists";
- case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
- return "Invalid attribute syntax";
-/* 22-31 unused */
- case LDB_ERR_NO_SUCH_OBJECT:
- return "No such object";
- case LDB_ERR_ALIAS_PROBLEM:
- return "Alias problem";
- case LDB_ERR_INVALID_DN_SYNTAX:
- return "Invalid DN syntax";
-/* 35 RESERVED */
- case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
- return "Alias dereferencing problem";
-/* 37-47 unused */
- case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
- return "Inappropriate authentication";
- case LDB_ERR_INVALID_CREDENTIALS:
- return "Invalid credentials";
- case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
- return "insufficient access rights";
- case LDB_ERR_BUSY:
- return "Busy";
- case LDB_ERR_UNAVAILABLE:
- return "Unavailable";
- case LDB_ERR_UNWILLING_TO_PERFORM:
- return "Unwilling to perform";
- case LDB_ERR_LOOP_DETECT:
- return "Loop detect";
-/* 55-63 unused */
- case LDB_ERR_NAMING_VIOLATION:
- return "Naming violation";
- case LDB_ERR_OBJECT_CLASS_VIOLATION:
- return "Object class violation";
- case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
- return "Not allowed on non-leaf";
- case LDB_ERR_NOT_ALLOWED_ON_RDN:
- return "Not allowed on RDN";
- case LDB_ERR_ENTRY_ALREADY_EXISTS:
- return "Entry already exists";
- case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
- return "Object class mods prohibited";
-/* 70 RESERVED FOR CLDAP */
- case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
- return "Affects multiple DSAs";
-/* 72-79 unused */
- case LDB_ERR_OTHER:
- return "Other";
- }
-
- return "Unknown error";
-}
-
-/*
- set backend specific opaque parameters
-*/
-int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value)
-{
- struct ldb_opaque *o;
-
- /* allow updating an existing value */
- for (o=ldb->opaque;o;o=o->next) {
- if (strcmp(o->name, name) == 0) {
- o->value = value;
- return LDB_SUCCESS;
- }
- }
-
- o = talloc(ldb, struct ldb_opaque);
- if (o == NULL) {
- ldb_oom(ldb);
- return LDB_ERR_OTHER;
- }
- o->next = ldb->opaque;
- o->name = name;
- o->value = value;
- ldb->opaque = o;
- return LDB_SUCCESS;
-}
-
-/*
- get a previously set opaque value
-*/
-void *ldb_get_opaque(struct ldb_context *ldb, const char *name)
-{
- struct ldb_opaque *o;
- for (o=ldb->opaque;o;o=o->next) {
- if (strcmp(o->name, name) == 0) {
- return o->value;
- }
- }
- return NULL;
-}
-
-int ldb_global_init(void)
-{
- /* Provided for compatibility with some older versions of ldb */
- return 0;
-}
-
-/* return the ldb flags */
-unsigned int ldb_get_flags(struct ldb_context *ldb)
-{
- return ldb->flags;
-}
-
-/* set the ldb flags */
-void ldb_set_flags(struct ldb_context *ldb, unsigned flags)
-{
- ldb->flags = flags;
-}
-
-
-/*
- set the location in a ldb request. Used for debugging
- */
-void ldb_req_set_location(struct ldb_request *req, const char *location)
-{
- if (req && req->handle) {
- req->handle->location = location;
- }
-}
-
-/*
- return the location set with dsdb_req_set_location
- */
-const char *ldb_req_location(struct ldb_request *req)
-{
- return req->handle->location;
-}
-
-/**
- mark a request as untrusted. This tells the rootdse module to remove
- unregistered controls
- */
-void ldb_req_mark_untrusted(struct ldb_request *req)
-{
- req->handle->flags |= LDB_HANDLE_FLAG_UNTRUSTED;
-}
-
-/**
- mark a request as trusted.
- */
-void ldb_req_mark_trusted(struct ldb_request *req)
-{
- req->handle->flags &= ~LDB_HANDLE_FLAG_UNTRUSTED;
-}
-
-/**
- set custom flags. Those flags are set by applications using ldb,
- they are application dependent and the same bit can have different
- meaning in different application.
- */
-void ldb_req_set_custom_flags(struct ldb_request *req, uint32_t flags)
-{
- if (req != NULL && req->handle != NULL) {
- req->handle->custom_flags = flags;
- }
-}
-
-
-/**
- get custom flags. Those flags are set by applications using ldb,
- they are application dependent and the same bit can have different
- meaning in different application.
- */
-uint32_t ldb_req_get_custom_flags(struct ldb_request *req)
-{
- if (req != NULL && req->handle != NULL) {
- return req->handle->custom_flags;
- }
-
- /*
- * 0 is not something any better or worse than
- * anything else as req or the handle is NULL
- */
- return 0;
-}
-
-
-/**
- return true is a request is untrusted
- */
-bool ldb_req_is_untrusted(struct ldb_request *req)
-{
- return (req->handle->flags & LDB_HANDLE_FLAG_UNTRUSTED) != 0;
-}
diff --git a/source4/lib/ldb/common/ldb_attributes.c b/source4/lib/ldb/common/ldb_attributes.c
deleted file mode 100644
index 21a3e6eb93..0000000000
--- a/source4/lib/ldb/common/ldb_attributes.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 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/>.
-*/
-/*
- register handlers for specific attributes and objectclass relationships
-
- this allows a backend to store its schema information in any format
- it likes (or to not have any schema information at all) while keeping the
- message matching logic generic
-*/
-
-#include "ldb_private.h"
-#include "ldb_handlers.h"
-
-/*
- add a attribute to the ldb_schema
-
- if flags contains LDB_ATTR_FLAG_ALLOCATED
- the attribute name string will be copied using
- talloc_strdup(), otherwise it needs to be a static const
- string at least with a lifetime longer than the ldb struct!
-
- the ldb_schema_syntax structure should be a pointer
- to a static const struct or at least it needs to be
- a struct with a longer lifetime than the ldb context!
-
-*/
-int ldb_schema_attribute_add_with_syntax(struct ldb_context *ldb,
- const char *attribute,
- unsigned flags,
- const struct ldb_schema_syntax *syntax)
-{
- unsigned int i, n;
- struct ldb_schema_attribute *a;
-
- if (!syntax) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- n = ldb->schema.num_attributes + 1;
-
- a = talloc_realloc(ldb, ldb->schema.attributes,
- struct ldb_schema_attribute, n);
- if (a == NULL) {
- ldb_oom(ldb);
- return -1;
- }
- ldb->schema.attributes = a;
-
- for (i = 0; i < ldb->schema.num_attributes; i++) {
- int cmp = ldb_attr_cmp(attribute, a[i].name);
- if (cmp == 0) {
- /* silently ignore attempts to overwrite fixed attributes */
- if (a[i].flags & LDB_ATTR_FLAG_FIXED) {
- return 0;
- }
- if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) {
- talloc_free(discard_const_p(char, a[i].name));
- }
- /* To cancel out increment below */
- ldb->schema.num_attributes--;
- break;
- } else if (cmp < 0) {
- memmove(a+i+1, a+i, sizeof(*a) * (ldb->schema.num_attributes-i));
- break;
- }
- }
- ldb->schema.num_attributes++;
-
- a[i].name = attribute;
- a[i].flags = flags;
- a[i].syntax = syntax;
-
- if (a[i].flags & LDB_ATTR_FLAG_ALLOCATED) {
- a[i].name = talloc_strdup(a, a[i].name);
- if (a[i].name == NULL) {
- ldb_oom(ldb);
- return -1;
- }
- }
-
- return 0;
-}
-
-static const struct ldb_schema_syntax ldb_syntax_default = {
- .name = LDB_SYNTAX_OCTET_STRING,
- .ldif_read_fn = ldb_handler_copy,
- .ldif_write_fn = ldb_handler_copy,
- .canonicalise_fn = ldb_handler_copy,
- .comparison_fn = ldb_comparison_binary
-};
-
-static const struct ldb_schema_attribute ldb_attribute_default = {
- .name = NULL,
- .flags = 0,
- .syntax = &ldb_syntax_default
-};
-
-/*
- return the attribute handlers for a given attribute
-*/
-static const struct ldb_schema_attribute *ldb_schema_attribute_by_name_internal(
- struct ldb_context *ldb,
- const char *name)
-{
- /* for binary search we need signed variables */
- unsigned int i, e, b = 0;
- int r;
- const struct ldb_schema_attribute *def = &ldb_attribute_default;
-
- /* as handlers are sorted, '*' must be the first if present */
- if (strcmp(ldb->schema.attributes[0].name, "*") == 0) {
- def = &ldb->schema.attributes[0];
- b = 1;
- }
-
- /* do a binary search on the array */
- e = ldb->schema.num_attributes - 1;
-
- while ((b <= e) && (e != (unsigned int) -1)) {
- i = (b + e) / 2;
-
- r = ldb_attr_cmp(name, ldb->schema.attributes[i].name);
- if (r == 0) {
- return &ldb->schema.attributes[i];
- }
- if (r < 0) {
- e = i - 1;
- } else {
- b = i + 1;
- }
- }
-
- return def;
-}
-
-/*
- return the attribute handlers for a given attribute
-*/
-const struct ldb_schema_attribute *ldb_schema_attribute_by_name(struct ldb_context *ldb,
- const char *name)
-{
- if (ldb->schema.attribute_handler_override) {
- const struct ldb_schema_attribute *ret =
- ldb->schema.attribute_handler_override(ldb,
- ldb->schema.attribute_handler_override_private,
- name);
- if (ret) {
- return ret;
- }
- }
-
- return ldb_schema_attribute_by_name_internal(ldb, name);
-}
-
-
-/*
- add to the list of ldif handlers for this ldb context
-*/
-void ldb_schema_attribute_remove(struct ldb_context *ldb, const char *name)
-{
- const struct ldb_schema_attribute *a;
- ptrdiff_t i;
-
- a = ldb_schema_attribute_by_name_internal(ldb, name);
- if (a == NULL || a->name == NULL) {
- return;
- }
-
- /* FIXED attributes are never removed */
- if (a->flags & LDB_ATTR_FLAG_FIXED) {
- return;
- }
-
- if (a->flags & LDB_ATTR_FLAG_ALLOCATED) {
- talloc_free(discard_const_p(char, a->name));
- }
-
- i = a - ldb->schema.attributes;
- if (i < ldb->schema.num_attributes - 1) {
- memmove(&ldb->schema.attributes[i],
- a+1, sizeof(*a) * (ldb->schema.num_attributes-(i+1)));
- }
-
- ldb->schema.num_attributes--;
-}
-
-/*
- setup a attribute handler using a standard syntax
-*/
-int ldb_schema_attribute_add(struct ldb_context *ldb,
- const char *attribute,
- unsigned flags,
- const char *syntax)
-{
- const struct ldb_schema_syntax *s = ldb_standard_syntax_by_name(ldb, syntax);
- return ldb_schema_attribute_add_with_syntax(ldb, attribute, flags, s);
-}
-
-/*
- setup the attribute handles for well known attributes
-*/
-int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
-{
- const struct {
- const char *attr;
- const char *syntax;
- } wellknown[] = {
- { "dn", LDB_SYNTAX_DN },
- { "distinguishedName", LDB_SYNTAX_DN },
- { "cn", LDB_SYNTAX_DIRECTORY_STRING },
- { "dc", LDB_SYNTAX_DIRECTORY_STRING },
- { "ou", LDB_SYNTAX_DIRECTORY_STRING },
- { "objectClass", LDB_SYNTAX_OBJECTCLASS }
- };
- unsigned int i;
- int ret;
-
- for (i=0;i<ARRAY_SIZE(wellknown);i++) {
- ret = ldb_schema_attribute_add(ldb, wellknown[i].attr, 0,
- wellknown[i].syntax);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- return LDB_SUCCESS;
-}
-
-
-/*
- add a extended dn syntax to the ldb_schema
-*/
-int ldb_dn_extended_add_syntax(struct ldb_context *ldb,
- unsigned flags,
- const struct ldb_dn_extended_syntax *syntax)
-{
- unsigned int n;
- struct ldb_dn_extended_syntax *a;
-
- if (!syntax) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- n = ldb->schema.num_dn_extended_syntax + 1;
-
- a = talloc_realloc(ldb, ldb->schema.dn_extended_syntax,
- struct ldb_dn_extended_syntax, n);
-
- if (!a) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- a[ldb->schema.num_dn_extended_syntax] = *syntax;
- ldb->schema.dn_extended_syntax = a;
-
- ldb->schema.num_dn_extended_syntax = n;
-
- return LDB_SUCCESS;
-}
-
-/*
- return the extended dn syntax for a given name
-*/
-const struct ldb_dn_extended_syntax *ldb_dn_extended_syntax_by_name(struct ldb_context *ldb,
- const char *name)
-{
- unsigned int i;
- for (i=0; i < ldb->schema.num_dn_extended_syntax; i++) {
- if (ldb_attr_cmp(ldb->schema.dn_extended_syntax[i].name, name) == 0) {
- return &ldb->schema.dn_extended_syntax[i];
- }
- }
- return NULL;
-}
-
-/*
- set an attribute handler override function - used to delegate schema handling
- to external code
- */
-void ldb_schema_attribute_set_override_handler(struct ldb_context *ldb,
- ldb_attribute_handler_override_fn_t override,
- void *private_data)
-{
- ldb->schema.attribute_handler_override_private = private_data;
- ldb->schema.attribute_handler_override = override;
-}
diff --git a/source4/lib/ldb/common/ldb_controls.c b/source4/lib/ldb/common/ldb_controls.c
deleted file mode 100644
index b3ef243493..0000000000
--- a/source4/lib/ldb/common/ldb_controls.c
+++ /dev/null
@@ -1,1043 +0,0 @@
-/*
- 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_controls.c
- *
- * Component: ldb controls utility functions
- *
- * Description: helper functions for control modules
- *
- * Author: Simo Sorce
- */
-
-#include "ldb_private.h"
-
-/* check if a control with the specified "oid" exist and return it */
-/* returns NULL if not found */
-struct ldb_control *ldb_request_get_control(struct ldb_request *req, const char *oid)
-{
- unsigned int i;
-
- if (req->controls != NULL) {
- for (i = 0; req->controls[i]; i++) {
- if (req->controls[i]->oid && strcmp(oid, req->controls[i]->oid) == 0) {
- break;
- }
- }
-
- return req->controls[i];
- }
-
- return NULL;
-}
-
-/* check if a control with the specified "oid" exist and return it */
-/* returns NULL if not found */
-struct ldb_control *ldb_reply_get_control(struct ldb_reply *rep, const char *oid)
-{
- unsigned int i;
-
- if (rep->controls != NULL) {
- for (i = 0; rep->controls[i]; i++) {
- if (rep->controls[i]->oid && strcmp(oid, rep->controls[i]->oid) == 0) {
- break;
- }
- }
-
- return rep->controls[i];
- }
-
- return NULL;
-}
-
-/*
- * Saves the current controls list into the "saver" (can also be NULL) and
- * replace the one in "req" with a new one excluding the "exclude" control
- * (if it is NULL then the list remains the same)
- *
- * Returns 0 on error.
- */
-int ldb_save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
-{
- struct ldb_control **lcs, **lcs_old;
- unsigned int i, j;
-
- lcs_old = req->controls;
- if (saver != NULL) {
- *saver = lcs_old;
- }
-
- for (i = 0; req->controls && req->controls[i]; i++);
- if (i == 0) {
- req->controls = NULL;
- return 1;
- }
-
- lcs = talloc_array(req, struct ldb_control *, i + 1);
- if (!lcs) {
- return 0;
- }
-
- for (i = 0, j = 0; lcs_old[i]; i++) {
- if (exclude == lcs_old[i]) continue;
- lcs[j] = lcs_old[i];
- j++;
- }
- lcs[j] = NULL;
-
- req->controls = talloc_realloc(req, lcs, struct ldb_control *, j + 1);
- if (req->controls == NULL) {
- return 0;
- }
- return 1;
-}
-
-/*
- * Returns a list of controls, except the one specified with "exclude" (can
- * also be NULL). Included controls become a child of returned list if they
- * were children of "controls_in".
- *
- * Returns NULL on error (OOM) or an empty control list.
- */
-struct ldb_control **ldb_controls_except_specified(struct ldb_control **controls_in,
- TALLOC_CTX *mem_ctx,
- struct ldb_control *exclude)
-{
- struct ldb_control **lcs = NULL;
- unsigned int i, j, n;
-
- for (i = 0; controls_in && controls_in[i]; i++);
- if (i == 0) {
- return NULL;
- }
- n = i;
-
- for (i = 0, j = 0; controls_in && controls_in[i]; i++) {
- if (exclude == controls_in[i]) continue;
-
- if (!lcs) {
- /* Allocate here so if we remove the only
- * control, or there were no controls, we
- * don't allocate at all, and just return
- * NULL */
- lcs = talloc_array(mem_ctx, struct ldb_control *,
- n + 1);
- if (!lcs) {
- return NULL;
- }
- }
-
- lcs[j] = controls_in[i];
- talloc_reparent(controls_in, lcs, lcs[j]);
- j++;
- }
- if (lcs) {
- lcs[j] = NULL;
-
- lcs = talloc_realloc(mem_ctx, lcs, struct ldb_control *, j + 1);
- }
-
- return lcs;
-}
-
-/* check if there's any control marked as critical in the list */
-/* return True if any, False if none */
-int ldb_check_critical_controls(struct ldb_control **controls)
-{
- unsigned int i;
-
- if (controls == NULL) {
- return 0;
- }
-
- for (i = 0; controls[i]; i++) {
- if (controls[i]->critical) {
- return 1;
- }
- }
-
- return 0;
-}
-
-int ldb_request_add_control(struct ldb_request *req, const char *oid, bool critical, void *data)
-{
- unsigned int i, n;
- struct ldb_control **ctrls;
- struct ldb_control *ctrl;
-
- for (n=0; req->controls && req->controls[n];n++) {
- /* having two controls of the same OID makes no sense */
- if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) {
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- }
- }
-
- ctrls = talloc_array(req,
- struct ldb_control *,
- n + 2);
- if (!ctrls) return LDB_ERR_OPERATIONS_ERROR;
-
- for (i=0; i<n; i++) {
- ctrls[i] = req->controls[i];
- }
-
- req->controls = ctrls;
- ctrls[n] = NULL;
- ctrls[n+1] = NULL;
-
- ctrl = talloc(ctrls, struct ldb_control);
- if (!ctrl) return LDB_ERR_OPERATIONS_ERROR;
-
- ctrl->oid = talloc_strdup(ctrl, oid);
- if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR;
- ctrl->critical = critical;
- ctrl->data = data;
-
- ctrls[n] = ctrl;
- return LDB_SUCCESS;
-}
-
-int ldb_reply_add_control(struct ldb_reply *ares, const char *oid, bool critical, void *data)
-{
- unsigned n;
- struct ldb_control **ctrls;
- struct ldb_control *ctrl;
-
- for (n=0; ares->controls && ares->controls[n];) {
- /* having two controls of the same OID makes no sense */
- if (ares->controls[n]->oid && strcmp(oid, ares->controls[n]->oid) == 0) {
- return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
- }
- n++;
- }
-
- ctrls = talloc_realloc(ares, ares->controls,
- struct ldb_control *,
- n + 2);
- if (!ctrls) return LDB_ERR_OPERATIONS_ERROR;
- ares->controls = ctrls;
- ctrls[n] = NULL;
- ctrls[n+1] = NULL;
-
- ctrl = talloc(ctrls, struct ldb_control);
- if (!ctrl) return LDB_ERR_OPERATIONS_ERROR;
-
- ctrl->oid = talloc_strdup(ctrl, oid);
- if (!ctrl->oid) return LDB_ERR_OPERATIONS_ERROR;
- ctrl->critical = critical;
- ctrl->data = data;
-
- ctrls[n] = ctrl;
- return LDB_SUCCESS;
-}
-
-/* Add a control to the request, replacing the old one if it is already in the request */
-int ldb_request_replace_control(struct ldb_request *req, const char *oid, bool critical, void *data)
-{
- unsigned int n;
- int ret;
-
- ret = ldb_request_add_control(req, oid, critical, data);
- if (ret != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
- return ret;
- }
-
- for (n=0; req->controls[n];n++) {
- if (req->controls[n]->oid && strcmp(oid, req->controls[n]->oid) == 0) {
- req->controls[n]->critical = critical;
- req->controls[n]->data = data;
- return LDB_SUCCESS;
- }
- }
-
- return LDB_ERR_OPERATIONS_ERROR;
-}
-
-/*
- * Return a control as string
- * the project (ie. name:value1:value2:...:valuen
- * The string didn't include the criticity of the critical flag
- */
-char *ldb_control_to_string(TALLOC_CTX *mem_ctx, const struct ldb_control *control)
-{
- char *res = NULL;
-
- if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) {
- struct ldb_paged_control *rep_control = talloc_get_type(control->data, struct ldb_paged_control);
- char *cookie;
-
- cookie = ldb_base64_encode(mem_ctx, rep_control->cookie, rep_control->cookie_len);
- if (cookie == NULL) {
- return NULL;
- }
- if (cookie[0] != '\0') {
- res = talloc_asprintf(mem_ctx, "%s:%d:%s",
- LDB_CONTROL_PAGED_RESULTS_NAME,
- control->critical,
- cookie);
-
- talloc_free(cookie);
- } else {
- res = talloc_asprintf(mem_ctx, "%s:%d",
- LDB_CONTROL_PAGED_RESULTS_NAME,
- control->critical);
- }
- return res;
- }
-
- if (strcmp(control->oid, LDB_CONTROL_VLV_RESP_OID) == 0) {
- struct ldb_vlv_resp_control *rep_control = talloc_get_type(control->data,
- struct ldb_vlv_resp_control);
-
- res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%d:%d:%s",
- LDB_CONTROL_VLV_RESP_NAME,
- control->critical,
- rep_control->targetPosition,
- rep_control->contentCount,
- rep_control->vlv_result,
- rep_control->ctxid_len,
- rep_control->contextId);
-
- return res;
- }
-
- if (strcmp(control->oid, LDB_CONTROL_SORT_RESP_OID) == 0) {
- struct ldb_sort_resp_control *rep_control = talloc_get_type(control->data,
- struct ldb_sort_resp_control);
-
- res = talloc_asprintf(mem_ctx, "%s:%d:%d:%s",
- LDB_CONTROL_SORT_RESP_NAME,
- control->critical,
- rep_control->result,
- rep_control->attr_desc);
-
- return res;
- }
-
- if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
- struct ldb_asq_control *rep_control = talloc_get_type(control->data,
- struct ldb_asq_control);
-
- res = talloc_asprintf(mem_ctx, "%s:%d:%d",
- LDB_CONTROL_SORT_RESP_NAME,
- control->critical,
- rep_control->result);
-
- return res;
- }
-
- if (strcmp(control->oid, LDB_CONTROL_DIRSYNC_OID) == 0) {
- char *cookie;
- struct ldb_dirsync_control *rep_control = talloc_get_type(control->data,
- struct ldb_dirsync_control);
-
- cookie = ldb_base64_encode(mem_ctx, rep_control->cookie,
- rep_control->cookie_len);
- if (cookie == NULL) {
- return NULL;
- }
- res = talloc_asprintf(mem_ctx, "%s:%d:%d:%d:%s",
- LDB_CONTROL_DIRSYNC_NAME,
- control->critical,
- rep_control->flags,
- rep_control->max_attributes,
- cookie);
-
- talloc_free(cookie);
- return res;
- }
-
- /*
- * From here we don't know the control
- */
- if (control->data == NULL) {
- /*
- * We don't know the control but there is no real data attached to it
- * so we can represent it with local_oid:oid:criticity
- */
- res = talloc_asprintf(mem_ctx, "local_oid:%s:%d",
- control->oid,
- control->critical);
- return res;
- }
-
- res = talloc_asprintf(mem_ctx, "unknown oid:%s",
- control->oid);
- return res;
-}
-
-
-/*
- * A little trick to allow to use constants defined in headers rather than
- * hardwritten in the file hardwritten in the file
- * sizeof will return the \0 char as well so it will take the place of ":" in the
- * length of the string
- */
-#define LDB_CONTROL_CMP(control, NAME) strncmp(control, NAME ":", sizeof(NAME))
-
-/* Parse one string and return associated control if parsing is successful*/
-struct ldb_control *ldb_parse_control_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *control_strings)
-{
- struct ldb_control *ctrl;
- char *error_string = NULL;
-
- if (!(ctrl = talloc(mem_ctx, struct ldb_control))) {
- ldb_oom(ldb);
- return NULL;
- }
-
- if (LDB_CONTROL_CMP(control_strings,
- LDB_CONTROL_VLV_REQ_NAME) == 0) {
- struct ldb_vlv_req_control *control;
- const char *p;
- char attr[1024];
- char ctxid[1024];
- int crit, bc, ac, os, cc, ret;
-
- attr[0] = '\0';
- ctxid[0] = '\0';
- p = &(control_strings[sizeof(LDB_CONTROL_VLV_REQ_NAME)]);
- ret = sscanf(p, "%d:%d:%d:%d:%d:%1023[^$]", &crit, &bc, &ac, &os, &cc, ctxid);
- if (ret < 5) {
- ret = sscanf(p, "%d:%d:%d:%1023[^:]:%1023[^$]", &crit, &bc, &ac, attr, ctxid);
- }
-
- if ((ret < 4) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):bc(n):ac(n):<os(n):cc(n)|attr(s)>[:ctxid(o)]\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number, s = string, o = b64 binary blob");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
- ctrl->oid = LDB_CONTROL_VLV_REQ_OID;
- ctrl->critical = crit;
- if (!(control = talloc(ctrl,
- struct ldb_vlv_req_control))) {
- ldb_oom(ldb);
- return NULL;
- }
- control->beforeCount = bc;
- control->afterCount = ac;
- if (attr[0]) {
- control->type = 1;
- control->match.gtOrEq.value = talloc_strdup(control, attr);
- control->match.gtOrEq.value_len = strlen(attr);
- } else {
- control->type = 0;
- control->match.byOffset.offset = os;
- control->match.byOffset.contentCount = cc;
- }
- if (ctxid[0]) {
- control->ctxid_len = ldb_base64_decode(ctxid);
- control->contextId = (char *)talloc_memdup(control, ctxid, control->ctxid_len);
- } else {
- control->ctxid_len = 0;
- control->contextId = NULL;
- }
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DIRSYNC_NAME) == 0) {
- struct ldb_dirsync_control *control;
- const char *p;
- char cookie[1024];
- int crit, max_attrs, ret;
- uint32_t flags;
-
- cookie[0] = '\0';
- p = &(control_strings[sizeof(LDB_CONTROL_DIRSYNC_NAME)]);
- ret = sscanf(p, "%d:%u:%d:%1023[^$]", &crit, &flags, &max_attrs, cookie);
-
- if ((ret < 3) || (crit < 0) || (crit > 1) || (flags < 0) || (max_attrs < 0)) {
- error_string = talloc_asprintf(mem_ctx, "invalid dirsync control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):flags(n):max_attrs(n)[:cookie(o)]\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number, o = b64 binary blob");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- /* w2k3 seems to ignore the parameter,
- * but w2k sends a wrong cookie when this value is to small
- * this would cause looping forever, while getting
- * the same data and same cookie forever
- */
- if (max_attrs == 0) max_attrs = 0x0FFFFFFF;
-
- ctrl->oid = LDB_CONTROL_DIRSYNC_OID;
- ctrl->critical = crit;
- control = talloc(ctrl, struct ldb_dirsync_control);
- control->flags = flags;
- control->max_attributes = max_attrs;
- if (*cookie) {
- control->cookie_len = ldb_base64_decode(cookie);
- control->cookie = (char *)talloc_memdup(control, cookie, control->cookie_len);
- } else {
- control->cookie = NULL;
- control->cookie_len = 0;
- }
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_ASQ_NAME) == 0) {
- struct ldb_asq_control *control;
- const char *p;
- char attr[256];
- int crit, ret;
-
- attr[0] = '\0';
- p = &(control_strings[sizeof(LDB_CONTROL_ASQ_NAME)]);
- ret = sscanf(p, "%d:%255[^$]", &crit, attr);
- if ((ret != 2) || (crit < 0) || (crit > 1) || (attr[0] == '\0')) {
- error_string = talloc_asprintf(mem_ctx, "invalid asq control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):attr(s)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, s = string");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_ASQ_OID;
- ctrl->critical = crit;
- control = talloc(ctrl, struct ldb_asq_control);
- control->request = 1;
- control->source_attribute = talloc_strdup(control, attr);
- control->src_attr_len = strlen(attr);
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_EXTENDED_DN_NAME) == 0) {
- struct ldb_extended_dn_control *control;
- const char *p;
- int crit, type, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_EXTENDED_DN_NAME)]);
- ret = sscanf(p, "%d:%d", &crit, &type);
- if ((ret != 2) || (crit < 0) || (crit > 1) || (type < 0) || (type > 1)) {
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid extended_dn control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)[:type(i)]\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean\n");
- error_string = talloc_asprintf_append(error_string, " i = integer\n");
- error_string = talloc_asprintf_append(error_string, " valid values are: 0 - hexadecimal representation\n");
- error_string = talloc_asprintf_append(error_string, " 1 - normal string representation");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
- control = NULL;
- } else {
- control = talloc(ctrl, struct ldb_extended_dn_control);
- control->type = type;
- }
-
- ctrl->oid = LDB_CONTROL_EXTENDED_DN_OID;
- ctrl->critical = crit;
- ctrl->data = talloc_steal(ctrl, control);
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SD_FLAGS_NAME) == 0) {
- struct ldb_sd_flags_control *control;
- const char *p;
- int crit, ret;
- unsigned secinfo_flags;
-
- p = &(control_strings[sizeof(LDB_CONTROL_SD_FLAGS_NAME)]);
- ret = sscanf(p, "%d:%u", &crit, &secinfo_flags);
- if ((ret != 2) || (crit < 0) || (crit > 1) || (secinfo_flags < 0) || (secinfo_flags > 0xF)) {
- error_string = talloc_asprintf(mem_ctx, "invalid sd_flags control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):secinfo_flags(n)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_SD_FLAGS_OID;
- ctrl->critical = crit;
- control = talloc(ctrl, struct ldb_sd_flags_control);
- control->secinfo_flags = secinfo_flags;
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SEARCH_OPTIONS_NAME) == 0) {
- struct ldb_search_options_control *control;
- const char *p;
- int crit, ret;
- unsigned search_options;
-
- p = &(control_strings[sizeof(LDB_CONTROL_SEARCH_OPTIONS_NAME)]);
- ret = sscanf(p, "%d:%u", &crit, &search_options);
- if ((ret != 2) || (crit < 0) || (crit > 1) || (search_options < 0) || (search_options > 0xF)) {
- error_string = talloc_asprintf(mem_ctx, "invalid search_options control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):search_options(n)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_SEARCH_OPTIONS_OID;
- ctrl->critical = crit;
- control = talloc(ctrl, struct ldb_search_options_control);
- control->search_options = search_options;
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_BYPASS_OPERATIONAL_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_BYPASS_OPERATIONAL_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid bypassopreational control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_BYPASS_OPERATIONAL_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RELAX_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_RELAX_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid relax control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_RELAX_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RECALCULATE_SD_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_RECALCULATE_SD_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid recalculate_sd control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_RECALCULATE_SD_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_DOMAIN_SCOPE_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_DOMAIN_SCOPE_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid domain_scope control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_DOMAIN_SCOPE_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PAGED_RESULTS_NAME) == 0) {
- struct ldb_paged_control *control;
- const char *p;
- int crit, size, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_PAGED_RESULTS_NAME)]);
- ret = sscanf(p, "%d:%d", &crit, &size);
- if ((ret != 2) || (crit < 0) || (crit > 1) || (size < 0)) {
- error_string = talloc_asprintf(mem_ctx, "invalid paged_results control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):size(n)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, n = number");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_PAGED_RESULTS_OID;
- ctrl->critical = crit;
- control = talloc(ctrl, struct ldb_paged_control);
- control->size = size;
- control->cookie = NULL;
- control->cookie_len = 0;
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SERVER_SORT_NAME) == 0) {
- struct ldb_server_sort_control **control;
- const char *p;
- char attr[256];
- char rule[128];
- int crit, rev, ret;
-
- attr[0] = '\0';
- rule[0] = '\0';
- p = &(control_strings[sizeof(LDB_CONTROL_SERVER_SORT_NAME)]);
- ret = sscanf(p, "%d:%d:%255[^:]:%127[^:]", &crit, &rev, attr, rule);
- if ((ret < 3) || (crit < 0) || (crit > 1) || (rev < 0 ) || (rev > 1) ||attr[0] == '\0') {
- error_string = talloc_asprintf(mem_ctx, "invalid server_sort control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b):rev(b):attr(s)[:rule(s)]\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, s = string");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
- ctrl->oid = LDB_CONTROL_SERVER_SORT_OID;
- ctrl->critical = crit;
- control = talloc_array(ctrl, struct ldb_server_sort_control *, 2);
- control[0] = talloc(control, struct ldb_server_sort_control);
- control[0]->attributeName = talloc_strdup(control, attr);
- if (rule[0])
- control[0]->orderingRule = talloc_strdup(control, rule);
- else
- control[0]->orderingRule = NULL;
- control[0]->reverse = rev;
- control[1] = NULL;
- ctrl->data = control;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_NOTIFICATION_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_NOTIFICATION_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid notification control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_NOTIFICATION_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_TREE_DELETE_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_TREE_DELETE_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid tree_delete control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_TREE_DELETE_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DELETED_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DELETED_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid show_deleted control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_SHOW_DELETED_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_SHOW_DEACTIVATED_LINK_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid show_deactivated_link control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_SHOW_DEACTIVATED_LINK_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_SHOW_RECYCLED_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_SHOW_RECYCLED_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid show_recycled control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_SHOW_RECYCLED_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PERMISSIVE_MODIFY_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_PERMISSIVE_MODIFY_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid permissive_modify control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_PERMISSIVE_MODIFY_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_REVEAL_INTERNALS_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_REVEAL_INTERNALS_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid reveal_internals control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_REVEAL_INTERNALS;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (strncmp(control_strings, "local_oid:", 10) == 0) {
- const char *p;
- int crit = 0, ret = 0;
- char oid[256];
-
- oid[0] = '\0';
- p = &(control_strings[10]);
- ret = sscanf(p, "%64[^:]:%d", oid, &crit);
-
- if ((ret != 2) || strlen(oid) == 0 || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid local_oid control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: oid(s):crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean, s = string");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = talloc_strdup(ctrl, oid);
- if (!ctrl->oid) {
- ldb_oom(ldb);
- return NULL;
- }
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_RODC_DCPROMO_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_RODC_DCPROMO_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid rodc_join control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_RODC_DCPROMO_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
-
- if (LDB_CONTROL_CMP(control_strings, LDB_CONTROL_PROVISION_NAME) == 0) {
- const char *p;
- int crit, ret;
-
- p = &(control_strings[sizeof(LDB_CONTROL_PROVISION_NAME)]);
- ret = sscanf(p, "%d", &crit);
- if ((ret != 1) || (crit < 0) || (crit > 1)) {
- error_string = talloc_asprintf(mem_ctx, "invalid provision control syntax\n");
- error_string = talloc_asprintf_append(error_string, " syntax: crit(b)\n");
- error_string = talloc_asprintf_append(error_string, " note: b = boolean");
- ldb_set_errstring(ldb, error_string);
- talloc_free(error_string);
- return NULL;
- }
-
- ctrl->oid = LDB_CONTROL_PROVISION_OID;
- ctrl->critical = crit;
- ctrl->data = NULL;
-
- return ctrl;
- }
- /*
- * When no matching control has been found.
- */
- return NULL;
-}
-
-/*
- * A little trick to allow to use constants defined in headers rather than
- * hardwritten in the file hardwritten in the file
- * sizeof will return the \0 char as well so it will take the place of ":" in the
- * length of the string
- */
-#define LDB_CONTROL_CMP(control, NAME) strncmp(control, NAME ":", sizeof(NAME))
-
-/* Parse controls from the format used on the command line and in ejs */
-struct ldb_control **ldb_parse_control_strings(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char **control_strings)
-{
- unsigned int i;
- struct ldb_control **ctrl;
-
- if (control_strings == NULL || control_strings[0] == NULL)
- return NULL;
-
- for (i = 0; control_strings[i]; i++);
-
- ctrl = talloc_array(mem_ctx, struct ldb_control *, i + 1);
-
- ldb_reset_err_string(ldb);
- for (i = 0; control_strings[i]; i++) {
- ctrl[i] = ldb_parse_control_from_string(ldb, ctrl, control_strings[i]);
- if (ctrl[i] == NULL) {
- if( ldb_errstring == NULL ) {
- /* no controls matched, throw an error */
- ldb_asprintf_errstring(ldb, "Invalid control name: '%s'", control_strings[i]);
- }
- talloc_free(ctrl);
- return NULL;
- }
- }
-
- ctrl[i] = NULL;
-
- return ctrl;
-}
-
-
diff --git a/source4/lib/ldb/common/ldb_debug.c b/source4/lib/ldb/common/ldb_debug.c
deleted file mode 100644
index 6aa58ccf71..0000000000
--- a/source4/lib/ldb/common/ldb_debug.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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 debug
- *
- * Description: functions for printing debug messages
- *
- * Author: Andrew Tridgell
- */
-
-#include "ldb_private.h"
-
-/*
- this allows the user to choose their own debug function
-*/
-int ldb_set_debug(struct ldb_context *ldb,
- void (*debug)(void *context, enum ldb_debug_level level,
- const char *fmt, va_list ap),
- void *context)
-{
- ldb->debug_ops.debug = debug;
- ldb->debug_ops.context = context;
- return 0;
-}
-
-/*
- debug function for ldb_set_debug_stderr
-*/
-static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
- const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
-static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
- const char *fmt, va_list ap)
-{
- if (level <= LDB_DEBUG_WARNING) {
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- }
-}
-
-static void ldb_debug_stderr_all(void *context, enum ldb_debug_level level,
- const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
-static void ldb_debug_stderr_all(void *context, enum ldb_debug_level level,
- const char *fmt, va_list ap)
-{
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
-}
-
-/*
- convenience function to setup debug messages on stderr
- messages of level LDB_DEBUG_WARNING and higher are printed
-*/
-int ldb_set_debug_stderr(struct ldb_context *ldb)
-{
- return ldb_set_debug(ldb, ldb_debug_stderr, ldb);
-}
-
-/*
- log a message
-*/
-void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...)
-{
- va_list ap;
- if (ldb->debug_ops.debug == NULL) {
- if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
- ldb_set_debug(ldb, ldb_debug_stderr_all, ldb);
- } else {
- ldb_set_debug_stderr(ldb);
- }
- }
- va_start(ap, fmt);
- ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap);
- va_end(ap);
-}
-
-/*
- add to an accumulated log message
- */
-void ldb_debug_add(struct ldb_context *ldb, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- if (ldb->partial_debug == NULL) {
- ldb->partial_debug = talloc_vasprintf(ldb, fmt, ap);
- } else {
- ldb->partial_debug = talloc_vasprintf_append(ldb->partial_debug,
- fmt, ap);
- }
- va_end(ap);
-}
-
-/*
- send the accumulated log message, and free it
- */
-void ldb_debug_end(struct ldb_context *ldb, enum ldb_debug_level level)
-{
- ldb_debug(ldb, level, "%s", ldb->partial_debug);
- talloc_free(ldb->partial_debug);
- ldb->partial_debug = NULL;
-}
-
-/*
- log a message, and set the ldb error string to the same message
-*/
-void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
- const char *fmt, ...)
-{
- va_list ap;
- char *msg;
- va_start(ap, fmt);
- msg = talloc_vasprintf(ldb, fmt, ap);
- va_end(ap);
- if (msg != NULL) {
- ldb_set_errstring(ldb, msg);
- ldb_debug(ldb, level, "%s", msg);
- }
- talloc_free(msg);
-}
-
diff --git a/source4/lib/ldb/common/ldb_dn.c b/source4/lib/ldb/common/ldb_dn.c
deleted file mode 100644
index cd9055da92..0000000000
--- a/source4/lib/ldb/common/ldb_dn.c
+++ /dev/null
@@ -1,2101 +0,0 @@
-/*
- 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_private.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_ext_component {
-
- char *name;
- struct ldb_val value;
-};
-
-struct ldb_dn {
-
- struct ldb_context *ldb;
-
- /* Special DNs are always linearized */
- bool special;
- bool invalid;
-
- bool valid_case;
-
- char *linearized;
- char *ext_linearized;
- char *casefold;
-
- unsigned int comp_num;
- struct ldb_dn_component *components;
-
- unsigned int ext_comp_num;
- struct ldb_dn_ext_component *ext_components;
-};
-
-/* it is helpful to be able to break on this in gdb */
-static void ldb_dn_mark_invalid(struct ldb_dn *dn)
-{
- dn->invalid = true;
-}
-
-/* strdn may be NULL */
-struct ldb_dn *ldb_dn_from_ldb_val(TALLOC_CTX *mem_ctx,
- struct ldb_context *ldb,
- const struct ldb_val *strdn)
-{
- struct ldb_dn *dn;
-
- if (! ldb) return NULL;
-
- if (strdn && strdn->data
- && (strnlen((const char*)strdn->data, strdn->length) != strdn->length)) {
- /* The RDN must not contain a character with value 0x0 */
- return NULL;
- }
-
- dn = talloc_zero(mem_ctx, struct ldb_dn);
- LDB_DN_NULL_FAILED(dn);
-
- dn->ldb = talloc_get_type(ldb, struct ldb_context);
- if (dn->ldb == NULL) {
- /* the caller probably got the arguments to
- ldb_dn_new() mixed up */
- talloc_free(dn);
- return NULL;
- }
-
- if (strdn->data && strdn->length) {
- const char *data = (const char *)strdn->data;
- size_t length = strdn->length;
-
- if (data[0] == '@') {
- dn->special = true;
- }
- dn->ext_linearized = talloc_strndup(dn, data, length);
- LDB_DN_NULL_FAILED(dn->ext_linearized);
-
- if (data[0] == '<') {
- const char *p_save, *p = dn->ext_linearized;
- do {
- p_save = p;
- p = strstr(p, ">;");
- if (p) {
- p = p + 2;
- }
- } while (p);
-
- if (p_save == dn->ext_linearized) {
- dn->linearized = talloc_strdup(dn, "");
- } else {
- dn->linearized = talloc_strdup(dn, p_save);
- }
- LDB_DN_NULL_FAILED(dn->linearized);
- } else {
- dn->linearized = dn->ext_linearized;
- dn->ext_linearized = NULL;
- }
- } else {
- dn->linearized = talloc_strdup(dn, "");
- LDB_DN_NULL_FAILED(dn->linearized);
- }
-
- return dn;
-
-failed:
- talloc_free(dn);
- return NULL;
-}
-
-/* strdn may be NULL */
-struct ldb_dn *ldb_dn_new(TALLOC_CTX *mem_ctx,
- struct ldb_context *ldb,
- const char *strdn)
-{
- struct ldb_val blob;
- blob.data = discard_const_p(uint8_t, strdn);
- blob.length = strdn ? strlen(strdn) : 0;
- return ldb_dn_from_ldb_val(mem_ctx, ldb, &blob);
-}
-
-struct ldb_dn *ldb_dn_new_fmt(TALLOC_CTX *mem_ctx,
- struct ldb_context *ldb,
- const char *new_fmt, ...)
-{
- char *strdn;
- va_list ap;
-
- if ( (! mem_ctx) || (! ldb)) return NULL;
-
- va_start(ap, new_fmt);
- strdn = talloc_vasprintf(mem_ctx, new_fmt, ap);
- va_end(ap);
-
- if (strdn) {
- struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb, strdn);
- talloc_free(strdn);
- return dn;
- }
-
- return NULL;
-}
-
-/* see RFC2253 section 2.4 */
-static int ldb_dn_escape_internal(char *dst, const char *src, int len)
-{
- const char *p, *s;
- char *d;
- size_t l;
-
- p = s = src;
- d = dst;
-
- while (p - src < len) {
- p += strcspn(p, ",=\n\r+<>#;\\\" ");
-
- if (p - src == len) /* found no escapable chars */
- break;
-
- /* copy the part of the string before the stop */
- memcpy(d, s, p - s);
- d += (p - s); /* move to current position */
-
- switch (*p) {
- case ' ':
- if (p == src || (p-src)==(len-1)) {
- /* if at the beginning or end
- * of the string then escape */
- *d++ = '\\';
- *d++ = *p++;
- } else {
- /* otherwise don't escape */
- *d++ = *p++;
- }
- break;
-
- case '#':
- /* despite the RFC, windows escapes a #
- anywhere in the string */
- case ',':
- case '+':
- case '"':
- case '\\':
- case '<':
- case '>':
- case '?':
- /* these must be escaped using \c form */
- *d++ = '\\';
- *d++ = *p++;
- break;
-
- default: {
- /* any others get \XX form */
- unsigned char v;
- const char *hexbytes = "0123456789ABCDEF";
- v = *(const unsigned char *)p;
- *d++ = '\\';
- *d++ = hexbytes[v>>4];
- *d++ = hexbytes[v&0xF];
- p++;
- break;
- }
- }
- 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(TALLOC_CTX *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
-
- TODO: according to MS-ADTS:3.1.1.5.2 Naming Constraints
- DN must be compliant with RFC2253
-*/
-static bool ldb_dn_explode(struct ldb_dn *dn)
-{
- char *p, *ex_name, *ex_value, *data, *d, *dt, *t;
- bool trim = true;
- bool in_extended = true;
- 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 int x;
- size_t l;
- int ret;
- char *parse_dn;
- bool is_index;
-
- if ( ! dn || dn->invalid) return false;
-
- if (dn->components) {
- return true;
- }
-
- if (dn->ext_linearized) {
- parse_dn = dn->ext_linearized;
- } else {
- parse_dn = dn->linearized;
- }
-
- if ( ! parse_dn ) {
- return false;
- }
-
- is_index = (strncmp(parse_dn, "DN=@INDEX:", 10) == 0);
-
- /* Empty DNs */
- if (parse_dn[0] == '\0') {
- return true;
- }
-
- /* Special DNs case */
- if (dn->special) {
- return true;
- }
-
- /* make sure we free this if allocated previously before replacing */
- LDB_FREE(dn->components);
- dn->comp_num = 0;
-
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- /* in the common case we have 3 or more components */
- /* make sure all components are zeroed, other functions depend on it */
- dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3);
- if ( ! dn->components) {
- return false;
- }
-
- /* Components data space is allocated here once */
- data = talloc_array(dn->components, char, strlen(parse_dn) + 1);
- if (!data) {
- return false;
- }
-
- p = parse_dn;
- 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 *ext_syntax;
- struct ldb_val ex_val = {
- .data = (uint8_t *)ex_value,
- .length = d - ex_value
- };
-
- *d++ = '\0';
- p++;
- in_ex_value = false;
-
- /* Process name and ex_value */
-
- dn->ext_components = talloc_realloc(dn,
- dn->ext_components,
- struct ldb_dn_ext_component,
- dn->ext_comp_num + 1);
- if ( ! dn->ext_components) {
- /* ouch ! */
- goto failed;
- }
-
- ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name);
- if (!ext_syntax) {
- /* We don't know about this type of extended DN */
- goto failed;
- }
-
- dn->ext_components[dn->ext_comp_num].name = talloc_strdup(dn->ext_components, ex_name);
- if (!dn->ext_components[dn->ext_comp_num].name) {
- /* ouch */
- goto failed;
- }
- ret = ext_syntax->read_fn(dn->ldb, dn->ext_components,
- &ex_val, &dn->ext_components[dn->ext_comp_num].value);
- if (ret != LDB_SUCCESS) {
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- dn->ext_comp_num++;
-
- if (*p == '\0') {
- /* We have reached the end (extended component only)! */
- talloc_free(data);
- return true;
-
- } else if (*p == ';') {
- p++;
- continue;
- } else {
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
- }
-
- *d++ = *p++;
- continue;
- }
- if (in_attr) {
- if (trim) {
- if (*p == ' ') {
- p++;
- continue;
- }
-
- /* first char */
- trim = false;
-
- if (!isascii(*p)) {
- /* attr names must be ascii only */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- if (isdigit(*p)) {
- is_oid = true;
- } else
- if ( ! isalpha(*p)) {
- /* not a digit nor an alpha,
- * invalid attribute name */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- /* Copy this character across from parse_dn,
- * now we have trimmed out spaces */
- *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 */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- if (*p == '=') {
- /* attribute terminated */
- in_attr = false;
- in_value = true;
- 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) {
- /* ouch */
- goto failed;
- }
-
- dt = d;
-
- p++;
- continue;
- }
-
- if (!isascii(*p)) {
- /* attr names must be ascii only */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) {
- /* not a digit nor a dot,
- * invalid attribute oid */
- ldb_dn_mark_invalid(dn);
- goto failed;
- } else
- if ( ! (isalpha(*p) || isdigit(*p) || (*p == '-'))) {
- /* not ALPHA, DIGIT or HYPHEN */
- ldb_dn_mark_invalid(dn);
- 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 '=':
- /* to main compatibility with earlier
- versions of ldb indexing, we have to
- accept the base64 encoded binary index
- values, which contain a '+' or '='
- which should normally be escaped */
- if (is_index) {
- if ( t ) t = NULL;
- *d++ = *p++;
- l++;
- break;
- }
- /* fall through */
- case '\"':
- case '<':
- case '>':
- case ';':
- /* a string with not escaped specials is invalid (tested) */
- if ( ! escape) {
- ldb_dn_mark_invalid(dn);
- 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 (isxdigit(p[0]) && isxdigit(p[1])) {
- if (sscanf(p, "%02x", &x) != 1) {
- /* invalid escaping sequence */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
- p += 2;
- *d++ = (unsigned char)x;
- } else {
- *d++ = *p++;
- }
-
- escape = false;
- 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 */
- ldb_dn_mark_invalid(dn);
- goto failed;
- }
-
- /* save last element */
- if ( t ) {
- /* trim back */
- d -= (p - t);
- l -= (p - t);
- }
-
- *d++ = '\0';
- dn->components[dn->comp_num].value.length = l;
- dn->components[dn->comp_num].value.data =
- (uint8_t *)talloc_strdup(dn->components, dt);
- if ( ! dn->components[dn->comp_num].value.data) {
- /* ouch */
- goto failed;
- }
-
- dn->comp_num++;
-
- talloc_free(data);
- return true;
-
-failed:
- LDB_FREE(dn->components); /* "data" is implicitly free'd */
- dn->comp_num = 0;
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- 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)
-{
- unsigned int i;
- size_t len;
- char *d, *n;
-
- if ( ! dn || ( dn->invalid)) return NULL;
-
- if (dn->linearized) return dn->linearized;
-
- if ( ! dn->components) {
- ldb_dn_mark_invalid(dn);
- 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++) {
- /* name len */
- len += strlen(dn->components[i].name);
- /* max escaped data len */
- len += (dn->components[i].value.length * 3);
- 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;
-}
-
-static int ldb_dn_extended_component_compare(const void *p1, const void *p2)
-{
- const struct ldb_dn_ext_component *ec1 = (const struct ldb_dn_ext_component *)p1;
- const struct ldb_dn_ext_component *ec2 = (const struct ldb_dn_ext_component *)p2;
- return strcmp(ec1->name, ec2->name);
-}
-
-char *ldb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int mode)
-{
- const char *linearized = ldb_dn_get_linearized(dn);
- char *p = NULL;
- unsigned 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;
- }
-
- /* sort the extended components by name. The idea is to make
- * the resulting DNs consistent, plus to ensure that we put
- * 'DELETED' first, so it can be very quickly recognised
- */
- TYPESAFE_QSORT(dn->ext_components, dn->ext_comp_num,
- ldb_dn_extended_component_compare);
-
- for (i = 0; i < dn->ext_comp_num; i++) {
- const struct ldb_dn_extended_syntax *ext_syntax;
- const char *name = dn->ext_components[i].name;
- struct ldb_val ec_val = dn->ext_components[i].value;
- struct ldb_val val;
- int ret;
-
- ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, name);
- if (!ext_syntax) {
- return NULL;
- }
-
- if (mode == 1) {
- ret = ext_syntax->write_clear_fn(dn->ldb, mem_ctx,
- &ec_val, &val);
- } else if (mode == 0) {
- ret = ext_syntax->write_hex_fn(dn->ldb, mem_ctx,
- &ec_val, &val);
- } else {
- ret = -1;
- }
-
- if (ret != LDB_SUCCESS) {
- return NULL;
- }
-
- if (i == 0) {
- p = talloc_asprintf(mem_ctx, "<%s=%s>",
- name, val.data);
- } else {
- p = talloc_asprintf_append_buffer(p, ";<%s=%s>",
- name, val.data);
- }
-
- talloc_free(val.data);
-
- if (!p) {
- return NULL;
- }
- }
-
- if (dn->ext_comp_num && *linearized) {
- p = talloc_asprintf_append_buffer(p, ";%s", linearized);
- }
-
- if (!p) {
- return NULL;
- }
-
- return p;
-}
-
-/*
- filter out all but an acceptable list of extended DN components
- */
-void ldb_dn_extended_filter(struct ldb_dn *dn, const char * const *accept_list)
-{
- unsigned int i;
- for (i=0; i<dn->ext_comp_num; i++) {
- if (!ldb_attr_in_list(accept_list, dn->ext_components[i].name)) {
- memmove(&dn->ext_components[i],
- &dn->ext_components[i+1],
- (dn->ext_comp_num-(i+1))*sizeof(dn->ext_components[0]));
- dn->ext_comp_num--;
- i--;
- }
- }
- LDB_FREE(dn->ext_linearized);
-}
-
-
-char *ldb_dn_alloc_linearized(TALLOC_CTX *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)
-{
- unsigned int i;
- int 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)
-{
- unsigned int i;
- size_t 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) {
- dn->casefold = talloc_strdup(dn, "");
- return dn->casefold;
- }
-
- /* calculate maximum possible length of DN */
- for (len = 0, i = 0; i < dn->comp_num; i++) {
- /* name len */
- len += strlen(dn->components[i].cf_name);
- /* max escaped data len */
- len += (dn->components[i].cf_value.length * 3);
- 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(TALLOC_CTX *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;
- unsigned 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->linearized && dn->linearized) {
- /* 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) || (base->comp_num == 0)) {
- if (dn->special && base->special) {
- return strcmp(base->linearized, dn->linearized);
- } else if (dn->special) {
- return -1;
- } else if (base->special) {
- return 1;
- } else {
- return 0;
- }
- }
-
- n_base = base->comp_num - 1;
- n_dn = dn->comp_num - 1;
-
- while (n_base != (unsigned int) -1) {
- char *b_name = base->components[n_base].cf_name;
- char *dn_name = dn->components[n_dn].cf_name;
-
- char *b_vdata = (char *)base->components[n_base].cf_value.data;
- char *dn_vdata = (char *)dn->components[n_dn].cf_value.data;
-
- size_t b_vlen = base->components[n_base].cf_value.length;
- size_t dn_vlen = dn->components[n_dn].cf_value.length;
-
- /* compare attr names */
- ret = strcmp(b_name, dn_name);
- if (ret != 0) return ret;
-
- /* compare attr.cf_value. */
- if (b_vlen != dn_vlen) {
- return b_vlen - dn_vlen;
- }
- ret = strcmp(b_vdata, dn_vdata);
- 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)
-{
- unsigned int i;
- int ret;
-
- if (( ! dn0) || dn0->invalid || ! dn1 || dn1->invalid) {
- return -1;
- }
-
- if (( ! dn0->valid_case) || ( ! dn1->valid_case)) {
- if (dn0->linearized && dn1->linearized) {
- /* 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 if (dn0->special) {
- return 1;
- } else if (dn1->special) {
- return -1;
- } else {
- return 0;
- }
- }
-
- for (i = 0; i < dn0->comp_num; i++) {
- char *dn0_name = dn0->components[i].cf_name;
- char *dn1_name = dn1->components[i].cf_name;
-
- char *dn0_vdata = (char *)dn0->components[i].cf_value.data;
- char *dn1_vdata = (char *)dn1->components[i].cf_value.data;
-
- size_t dn0_vlen = dn0->components[i].cf_value.length;
- size_t dn1_vlen = dn1->components[i].cf_value.length;
-
- /* compare attr names */
- ret = strcmp(dn0_name, dn1_name);
- if (ret != 0) {
- return ret;
- }
-
- /* compare attr.cf_value. */
- if (dn0_vlen != dn1_vlen) {
- return dn0_vlen - dn1_vlen;
- }
- ret = strcmp(dn0_vdata, dn1_vdata);
- if (ret != 0) {
- return ret;
- }
- }
-
- return 0;
-}
-
-static struct ldb_dn_component ldb_dn_copy_component(
- TALLOC_CTX *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);
- return dst;
- }
-
- 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;
-}
-
-static struct ldb_dn_ext_component ldb_dn_ext_copy_component(
- TALLOC_CTX *mem_ctx,
- struct ldb_dn_ext_component *src)
-{
- struct ldb_dn_ext_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(TALLOC_CTX *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->components) {
- unsigned 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->ext_components) {
- unsigned int i;
-
- new_dn->ext_components =
- talloc_zero_array(new_dn,
- struct ldb_dn_ext_component,
- dn->ext_comp_num);
- if ( ! new_dn->ext_components) {
- talloc_free(new_dn);
- return NULL;
- }
-
- for (i = 0; i < dn->ext_comp_num; i++) {
- new_dn->ext_components[i] =
- ldb_dn_ext_copy_component(
- new_dn->ext_components,
- &dn->ext_components[i]);
- if ( ! new_dn->ext_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->linearized) {
- new_dn->linearized = talloc_strdup(new_dn, dn->linearized);
- if ( ! new_dn->linearized) {
- talloc_free(new_dn);
- return NULL;
- }
- }
-
- if (dn->ext_linearized) {
- new_dn->ext_linearized = talloc_strdup(new_dn,
- dn->ext_linearized);
- if ( ! new_dn->ext_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->components) {
- unsigned 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) {
- ldb_dn_mark_invalid(dn);
- 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) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
- }
-
- if (dn->casefold && s) {
- if (*dn->casefold) {
- t = talloc_asprintf(dn, "%s,%s",
- dn->casefold, s);
- } else {
- t = talloc_strdup(dn, s);
- }
- LDB_FREE(dn->casefold);
- dn->casefold = t;
- }
- }
-
- if (dn->linearized) {
-
- s = ldb_dn_get_linearized(base);
- if ( ! s) {
- return false;
- }
-
- if (*dn->linearized) {
- t = talloc_asprintf(dn, "%s,%s",
- dn->linearized, s);
- } else {
- t = talloc_strdup(dn, s);
- }
- if ( ! t) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
- LDB_FREE(dn->linearized);
- dn->linearized = t;
- }
-
- /* Wipe the ext_linearized DN,
- * the GUID and SID are almost certainly no longer valid */
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- 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->components) {
- unsigned int n;
- unsigned int i, j;
-
- if (dn->comp_num == 0) {
- return false;
- }
-
- 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) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
-
- for (i = dn->comp_num - 1, j = n - 1; i != (unsigned int) -1;
- 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) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
- }
-
- dn->comp_num = n;
-
- if (dn->casefold && s) {
- t = talloc_asprintf(dn, "%s,%s", s, dn->casefold);
- LDB_FREE(dn->casefold);
- dn->casefold = t;
- }
- }
-
- if (dn->linearized) {
- if (dn->linearized[0] == '\0') {
- return false;
- }
-
- s = ldb_dn_get_linearized(child);
- if ( ! s) {
- return false;
- }
-
- t = talloc_asprintf(dn, "%s,%s", s, dn->linearized);
- if ( ! t) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
- LDB_FREE(dn->linearized);
- dn->linearized = t;
- }
-
- /* Wipe the ext_linearized DN,
- * the GUID and SID are almost certainly no longer valid */
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- 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)
-{
- unsigned int i;
-
- if ( ! ldb_dn_validate(dn)) {
- return false;
- }
-
- if (dn->comp_num < num) {
- return false;
- }
-
- /* free components */
- for (i = dn->comp_num - num; i < dn->comp_num; i++) {
- LDB_FREE(dn->components[i].name);
- LDB_FREE(dn->components[i].value.data);
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
-
- dn->comp_num -= num;
-
- if (dn->valid_case) {
- for (i = 0; i < dn->comp_num; i++) {
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
- dn->valid_case = false;
- }
-
- LDB_FREE(dn->casefold);
- LDB_FREE(dn->linearized);
-
- /* Wipe the ext_linearized DN,
- * the GUID and SID are almost certainly no longer valid */
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- return true;
-}
-
-bool ldb_dn_remove_child_components(struct ldb_dn *dn, unsigned int num)
-{
- unsigned 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++) {
- if (i < num) {
- LDB_FREE(dn->components[i].name);
- LDB_FREE(dn->components[i].value.data);
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
- dn->components[i] = dn->components[j];
- }
-
- dn->comp_num -= num;
-
- if (dn->valid_case) {
- for (i = 0; i < dn->comp_num; i++) {
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
- dn->valid_case = false;
- }
-
- LDB_FREE(dn->casefold);
- LDB_FREE(dn->linearized);
-
- /* Wipe the ext_linearized DN,
- * the GUID and SID are almost certainly no longer valid */
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- return true;
-}
-
-struct ldb_dn *ldb_dn_get_parent(TALLOC_CTX *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(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int ex_format) {
- unsigned int i;
- TALLOC_CTX *tmpctx;
- char *cracked = NULL;
- const char *format = (ex_format ? "\n" : "/" );
-
- if ( ! ldb_dn_validate(dn)) {
- return NULL;
- }
-
- tmpctx = talloc_new(mem_ctx);
-
- /* Walk backwards down the DN, grabbing 'dc' components at first */
- for (i = dn->comp_num - 1; i != (unsigned int) -1; i--) {
- if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) {
- break;
- }
- if (cracked) {
- cracked = talloc_asprintf(tmpctx, "%s.%s",
- ldb_dn_escape_value(tmpctx,
- dn->components[i].value),
- cracked);
- } else {
- cracked = ldb_dn_escape_value(tmpctx,
- dn->components[i].value);
- }
- if (!cracked) {
- goto done;
- }
- }
-
- /* Only domain components? Finish here */
- if (i == (unsigned int) -1) {
- 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_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 */
- cracked = talloc_asprintf_append_buffer(cracked, "%s%s", format,
- ldb_dn_escape_value(tmpctx,
- dn->components[i].value));
-
- talloc_steal(mem_ctx, cracked);
-done:
- talloc_free(tmpctx);
- return cracked;
-}
-
-/* Wrapper functions for the above, for the two different string formats */
-char *ldb_dn_canonical_string(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) {
- return ldb_dn_canonical(mem_ctx, dn, 0);
-
-}
-
-char *ldb_dn_canonical_ex_string(TALLOC_CTX *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;
-}
-
-int ldb_dn_get_extended_comp_num(struct ldb_dn *dn)
-{
- if ( ! ldb_dn_validate(dn)) {
- return -1;
- }
- return dn->ext_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) {
- talloc_free(n);
- 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) {
- unsigned int i;
- for (i = 0; i < dn->comp_num; i++) {
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
- dn->valid_case = false;
- }
- LDB_FREE(dn->casefold);
- LDB_FREE(dn->linearized);
-
- /* Wipe the ext_linearized DN,
- * the GUID and SID are almost certainly no longer valid */
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-
- return LDB_SUCCESS;
-}
-
-const struct ldb_val *ldb_dn_get_extended_component(struct ldb_dn *dn,
- const char *name)
-{
- unsigned int i;
- if ( ! ldb_dn_validate(dn)) {
- return NULL;
- }
- for (i=0; i < dn->ext_comp_num; i++) {
- if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
- return &dn->ext_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_ext_component *p;
- unsigned int i;
- struct ldb_val v2;
-
- if ( ! ldb_dn_validate(dn)) {
- return LDB_ERR_OTHER;
- }
-
- if (!ldb_dn_extended_syntax_by_name(dn->ldb, name)) {
- /* We don't know how to handle this type of thing */
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
-
- for (i=0; i < dn->ext_comp_num; i++) {
- if (ldb_attr_cmp(dn->ext_components[i].name, name) == 0) {
- if (val) {
- dn->ext_components[i].value =
- ldb_val_dup(dn->ext_components, val);
-
- dn->ext_components[i].name =
- talloc_strdup(dn->ext_components, name);
- if (!dn->ext_components[i].name ||
- !dn->ext_components[i].value.data) {
- ldb_dn_mark_invalid(dn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- } else {
- if (i != (dn->ext_comp_num - 1)) {
- memmove(&dn->ext_components[i],
- &dn->ext_components[i+1],
- ((dn->ext_comp_num-1) - i) *
- sizeof(*dn->ext_components));
- }
- dn->ext_comp_num--;
-
- dn->ext_components = talloc_realloc(dn,
- dn->ext_components,
- struct ldb_dn_ext_component,
- dn->ext_comp_num);
- if (!dn->ext_components) {
- ldb_dn_mark_invalid(dn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- }
- LDB_FREE(dn->ext_linearized);
-
- return LDB_SUCCESS;
- }
- }
-
- if (val == NULL) {
- /* removing a value that doesn't exist is not an error */
- return LDB_SUCCESS;
- }
-
- v2 = *val;
-
- p = dn->ext_components
- = talloc_realloc(dn,
- dn->ext_components,
- struct ldb_dn_ext_component,
- dn->ext_comp_num + 1);
- if (!dn->ext_components) {
- ldb_dn_mark_invalid(dn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- p[dn->ext_comp_num].value = ldb_val_dup(dn->ext_components, &v2);
- p[dn->ext_comp_num].name = talloc_strdup(p, name);
-
- if (!dn->ext_components[i].name || !dn->ext_components[i].value.data) {
- ldb_dn_mark_invalid(dn);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- dn->ext_components = p;
- dn->ext_comp_num++;
-
- LDB_FREE(dn->ext_linearized);
-
- return LDB_SUCCESS;
-}
-
-void ldb_dn_remove_extended_components(struct ldb_dn *dn)
-{
- LDB_FREE(dn->ext_linearized);
- LDB_FREE(dn->ext_components);
- dn->ext_comp_num = 0;
-}
-
-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_has_extended(struct ldb_dn *dn)
-{
- if ( ! dn || dn->invalid) return false;
- if (dn->ext_linearized && (dn->ext_linearized[0] == '<')) return true;
- return dn->ext_comp_num != 0;
-}
-
-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 (ldb_dn_has_extended(dn)) return false;
- if (dn->linearized && (dn->linearized[0] == '\0')) return true;
- return false;
-}
-
-/*
- this updates dn->components, taking the components from ref_dn.
- This is used by code that wants to update the DN path of a DN
- while not impacting on the extended DN components
- */
-int ldb_dn_update_components(struct ldb_dn *dn, const struct ldb_dn *ref_dn)
-{
- dn->components = talloc_realloc(dn, dn->components,
- struct ldb_dn_component, ref_dn->comp_num);
- if (!dn->components) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- memcpy(dn->components, ref_dn->components,
- sizeof(struct ldb_dn_component)*ref_dn->comp_num);
- dn->comp_num = ref_dn->comp_num;
-
- LDB_FREE(dn->casefold);
- LDB_FREE(dn->linearized);
- LDB_FREE(dn->ext_linearized);
-
- return LDB_SUCCESS;
-}
-
-/*
- minimise a DN. The caller must pass in a validated DN.
-
- If the DN has an extended component then only the first extended
- component is kept, the DN string is stripped.
-
- The existing dn is modified
- */
-bool ldb_dn_minimise(struct ldb_dn *dn)
-{
- unsigned int i;
-
- if (!ldb_dn_validate(dn)) {
- return false;
- }
- if (dn->ext_comp_num == 0) {
- return true;
- }
-
- /* free components */
- for (i = 0; i < dn->comp_num; i++) {
- LDB_FREE(dn->components[i].name);
- LDB_FREE(dn->components[i].value.data);
- LDB_FREE(dn->components[i].cf_name);
- LDB_FREE(dn->components[i].cf_value.data);
- }
- dn->comp_num = 0;
- dn->valid_case = false;
-
- LDB_FREE(dn->casefold);
- LDB_FREE(dn->linearized);
-
- /* note that we don't free dn->components as this there are
- * several places in ldb_dn.c that rely on it being non-NULL
- * for an exploded DN
- */
-
- for (i = 1; i < dn->ext_comp_num; i++) {
- LDB_FREE(dn->ext_components[i].name);
- LDB_FREE(dn->ext_components[i].value.data);
- }
- dn->ext_comp_num = 1;
-
- dn->ext_components = talloc_realloc(dn, dn->ext_components, struct ldb_dn_ext_component, 1);
- if (dn->ext_components == NULL) {
- ldb_dn_mark_invalid(dn);
- return false;
- }
-
- LDB_FREE(dn->ext_linearized);
-
- return true;
-}
diff --git a/source4/lib/ldb/common/ldb_ldif.c b/source4/lib/ldb/common/ldb_ldif.c
deleted file mode 100644
index 63b797c4f3..0000000000
--- a/source4/lib/ldb/common/ldb_ldif.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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: ldif routines
- *
- * Description: ldif pack/unpack routines
- *
- * Author: Andrew Tridgell
- */
-
-/*
- see RFC2849 for the LDIF format definition
-*/
-
-#include "ldb_private.h"
-#include "system/locale.h"
-
-/*
-
-*/
-static int ldb_read_data_file(TALLOC_CTX *mem_ctx, struct ldb_val *value)
-{
- struct stat statbuf;
- char *buf;
- int count, size, bytes;
- int ret;
- int f;
- const char *fname = (const char *)value->data;
-
- if (strncmp(fname, "file://", 7) != 0) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- fname += 7;
-
- f = open(fname, O_RDONLY);
- if (f == -1) {
- return -1;
- }
-
- if (fstat(f, &statbuf) != 0) {
- ret = -1;
- goto done;
- }
-
- if (statbuf.st_size == 0) {
- ret = -1;
- goto done;
- }
-
- value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
- if (value->data == NULL) {
- ret = -1;
- goto done;
- }
- value->data[statbuf.st_size] = 0;
-
- count = 0;
- size = statbuf.st_size;
- buf = (char *)value->data;
- while (count < statbuf.st_size) {
- bytes = read(f, buf, size);
- if (bytes == -1) {
- talloc_free(value->data);
- ret = -1;
- goto done;
- }
- count += bytes;
- buf += bytes;
- size -= bytes;
- }
-
- value->length = statbuf.st_size;
- ret = statbuf.st_size;
-
-done:
- close(f);
- return ret;
-}
-
-/*
- this base64 decoder was taken from jitterbug (written by tridge).
- we might need to replace it with a new version
-*/
-int ldb_base64_decode(char *s)
-{
- const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- int bit_offset=0, byte_offset, idx, i, n;
- uint8_t *d = (uint8_t *)s;
- char *p=NULL;
-
- n=i=0;
-
- while (*s && (p=strchr(b64,*s))) {
- idx = (int)(p - b64);
- byte_offset = (i*6)/8;
- bit_offset = (i*6)%8;
- d[byte_offset] &= ~((1<<(8-bit_offset))-1);
- if (bit_offset < 3) {
- d[byte_offset] |= (idx << (2-bit_offset));
- n = byte_offset+1;
- } else {
- d[byte_offset] |= (idx >> (bit_offset-2));
- d[byte_offset+1] = 0;
- d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
- n = byte_offset+2;
- }
- s++; i++;
- }
- if (bit_offset >= 3) {
- n--;
- }
-
- if (*s && !p) {
- /* the only termination allowed */
- if (*s != '=') {
- return -1;
- }
- }
-
- /* null terminate */
- d[n] = 0;
- return n;
-}
-
-
-/*
- encode as base64
- caller frees
-*/
-char *ldb_base64_encode(TALLOC_CTX *mem_ctx, const char *buf, int len)
-{
- const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- int bit_offset, byte_offset, idx, i;
- const uint8_t *d = (const uint8_t *)buf;
- int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
- char *out;
-
- out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
- if (!out) return NULL;
-
- for (i=0;i<bytes;i++) {
- byte_offset = (i*6)/8;
- bit_offset = (i*6)%8;
- if (bit_offset < 3) {
- idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
- } else {
- idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
- if (byte_offset+1 < len) {
- idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
- }
- }
- out[i] = b64[idx];
- }
-
- for (;i<bytes+pad_bytes;i++)
- out[i] = '=';
- out[i] = 0;
-
- return out;
-}
-
-/*
- see if a buffer should be base64 encoded
-*/
-int ldb_should_b64_encode(struct ldb_context *ldb, const struct ldb_val *val)
-{
- unsigned int i;
- uint8_t *p = val->data;
-
- if (val->length == 0) {
- return 0;
- }
-
- if (p[0] == ' ' || p[0] == ':') {
- return 1;
- }
-
- for (i=0; i<val->length; i++) {
- if (!isprint(p[i]) || p[i] == '\n') {
- return 1;
- }
- }
- return 0;
-}
-
-/* this macro is used to handle the return checking on fprintf_fn() */
-#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
-
-/*
- write a line folded string onto a file
-*/
-static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
- const char *buf, size_t length, int start_pos)
-{
- size_t i;
- int total=0, ret;
-
- for (i=0;i<length;i++) {
- ret = fprintf_fn(private_data, "%c", buf[i]);
- CHECK_RET;
- if (i != (length-1) && (i + start_pos) % 77 == 0) {
- ret = fprintf_fn(private_data, "\n ");
- CHECK_RET;
- }
- }
-
- return total;
-}
-
-#undef CHECK_RET
-
-/*
- encode as base64 to a file
-*/
-static int base64_encode_f(struct ldb_context *ldb,
- int (*fprintf_fn)(void *, const char *, ...),
- void *private_data,
- const char *buf, int len, int start_pos)
-{
- char *b = ldb_base64_encode(ldb, buf, len);
- int ret;
-
- if (!b) {
- return -1;
- }
-
- ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
-
- talloc_free(b);
- return ret;
-}
-
-
-static const struct {
- const char *name;
- enum ldb_changetype changetype;
-} ldb_changetypes[] = {
- {"add", LDB_CHANGETYPE_ADD},
- {"delete", LDB_CHANGETYPE_DELETE},
- {"modify", LDB_CHANGETYPE_MODIFY},
- {"modrdn", LDB_CHANGETYPE_MODRDN},
- {"moddn", LDB_CHANGETYPE_MODRDN},
- {NULL, 0}
-};
-
-/* this macro is used to handle the return checking on fprintf_fn() */
-#define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
-
-/*
- write to ldif, using a caller supplied write method
-*/
-int ldb_ldif_write(struct ldb_context *ldb,
- int (*fprintf_fn)(void *, const char *, ...),
- void *private_data,
- const struct ldb_ldif *ldif)
-{
- TALLOC_CTX *mem_ctx;
- unsigned int i, j;
- int total=0, ret;
- char *p;
- const struct ldb_message *msg;
-
- mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
-
- msg = ldif->msg;
- p = ldb_dn_get_extended_linearized(mem_ctx, msg->dn, 1);
- ret = fprintf_fn(private_data, "dn: %s\n", p);
- talloc_free(p);
- CHECK_RET;
-
- if (ldif->changetype != LDB_CHANGETYPE_NONE) {
- for (i=0;ldb_changetypes[i].name;i++) {
- if (ldb_changetypes[i].changetype == ldif->changetype) {
- break;
- }
- }
- if (!ldb_changetypes[i].name) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d",
- ldif->changetype);
- talloc_free(mem_ctx);
- return -1;
- }
- ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
- CHECK_RET;
- }
-
- for (i=0;i<msg->num_elements;i++) {
- const struct ldb_schema_attribute *a;
-
- a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
-
- if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
- switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
- case LDB_FLAG_MOD_ADD:
- fprintf_fn(private_data, "add: %s\n",
- msg->elements[i].name);
- break;
- case LDB_FLAG_MOD_DELETE:
- fprintf_fn(private_data, "delete: %s\n",
- msg->elements[i].name);
- break;
- case LDB_FLAG_MOD_REPLACE:
- fprintf_fn(private_data, "replace: %s\n",
- msg->elements[i].name);
- break;
- }
- }
-
- for (j=0;j<msg->elements[i].num_values;j++) {
- struct ldb_val v;
- bool use_b64_encode;
- ret = a->syntax->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
- if (ret != LDB_SUCCESS) {
- v = msg->elements[i].values[j];
- }
- use_b64_encode = !(ldb->flags & LDB_FLG_SHOW_BINARY)
- && ldb_should_b64_encode(ldb, &v);
- if (ret != LDB_SUCCESS || use_b64_encode) {
- ret = fprintf_fn(private_data, "%s:: ",
- msg->elements[i].name);
- CHECK_RET;
- ret = base64_encode_f(ldb, fprintf_fn, private_data,
- (char *)v.data, v.length,
- strlen(msg->elements[i].name)+3);
- CHECK_RET;
- ret = fprintf_fn(private_data, "\n");
- CHECK_RET;
- } else {
- ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
- CHECK_RET;
- if (ldb->flags & LDB_FLG_SHOW_BINARY) {
- ret = fprintf_fn(private_data, "%*.*s",
- v.length, v.length, (char *)v.data);
- } else {
- ret = fold_string(fprintf_fn, private_data,
- (char *)v.data, v.length,
- strlen(msg->elements[i].name)+2);
- }
- CHECK_RET;
- ret = fprintf_fn(private_data, "\n");
- CHECK_RET;
- }
- if (v.data != msg->elements[i].values[j].data) {
- talloc_free(v.data);
- }
- }
- if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
- fprintf_fn(private_data, "-\n");
- }
- }
- ret = fprintf_fn(private_data,"\n");
- CHECK_RET;
-
- talloc_free(mem_ctx);
-
- return total;
-}
-
-#undef CHECK_RET
-
-
-/*
- pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
- this routine removes any RFC2849 continuations and comments
-
- caller frees
-*/
-static char *next_chunk(struct ldb_context *ldb,
- int (*fgetc_fn)(void *), void *private_data)
-{
- size_t alloc_size=0, chunk_size = 0;
- char *chunk = NULL;
- int c;
- int in_comment = 0;
-
- while ((c = fgetc_fn(private_data)) != EOF) {
- if (chunk_size+1 >= alloc_size) {
- char *c2;
- alloc_size += 1024;
- c2 = talloc_realloc(ldb, chunk, char, alloc_size);
- if (!c2) {
- talloc_free(chunk);
- errno = ENOMEM;
- return NULL;
- }
- chunk = c2;
- }
-
- if (in_comment) {
- if (c == '\n') {
- in_comment = 0;
- }
- continue;
- }
-
- /* handle continuation lines - see RFC2849 */
- if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
- chunk_size--;
- continue;
- }
-
- /* chunks are terminated by a double line-feed */
- if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
- chunk[chunk_size-1] = 0;
- return chunk;
- }
-
- if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
- in_comment = 1;
- continue;
- }
-
- /* ignore leading blank lines */
- if (chunk_size == 0 && c == '\n') {
- continue;
- }
-
- chunk[chunk_size++] = c;
- }
-
- if (chunk) {
- chunk[chunk_size] = 0;
- }
-
- return chunk;
-}
-
-
-/* simple ldif attribute parser */
-static int next_attr(TALLOC_CTX *mem_ctx, char **s, const char **attr, struct ldb_val *value)
-{
- char *p;
- int base64_encoded = 0;
- int binary_file = 0;
-
- if (strncmp(*s, "-\n", 2) == 0) {
- value->length = 0;
- *attr = "-";
- *s += 2;
- return 0;
- }
-
- p = strchr(*s, ':');
- if (!p) {
- return -1;
- }
-
- *p++ = 0;
-
- if (*p == ':') {
- base64_encoded = 1;
- p++;
- }
-
- if (*p == '<') {
- binary_file = 1;
- p++;
- }
-
- *attr = *s;
-
- while (*p == ' ' || *p == '\t') {
- p++;
- }
-
- value->data = (uint8_t *)p;
-
- p = strchr(p, '\n');
-
- if (!p) {
- value->length = strlen((char *)value->data);
- *s = ((char *)value->data) + value->length;
- } else {
- value->length = p - (char *)value->data;
- *s = p+1;
- *p = 0;
- }
-
- if (base64_encoded) {
- int len = ldb_base64_decode((char *)value->data);
- if (len == -1) {
- /* it wasn't valid base64 data */
- return -1;
- }
- value->length = len;
- }
-
- if (binary_file) {
- int len = ldb_read_data_file(mem_ctx, value);
- if (len == -1) {
- /* an error occurred while trying to retrieve the file */
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/*
- free a message from a ldif_read
-*/
-void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
-{
- talloc_free(ldif);
-}
-
-int ldb_ldif_parse_modrdn(struct ldb_context *ldb,
- const struct ldb_ldif *ldif,
- TALLOC_CTX *mem_ctx,
- struct ldb_dn **_olddn,
- struct ldb_dn **_newrdn,
- bool *_deleteoldrdn,
- struct ldb_dn **_newsuperior,
- struct ldb_dn **_newdn)
-{
- struct ldb_message *msg = ldif->msg;
- struct ldb_val *newrdn_val = NULL;
- struct ldb_val *deleteoldrdn_val = NULL;
- struct ldb_val *newsuperior_val = NULL;
- struct ldb_dn *olddn = NULL;
- struct ldb_dn *newrdn = NULL;
- bool deleteoldrdn = true;
- struct ldb_dn *newsuperior = NULL;
- struct ldb_dn *newdn = NULL;
- struct ldb_val tmp_false;
- struct ldb_val tmp_true;
- bool ok;
- TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-
- if (tmp_ctx == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "Error: talloc_new() failed");
- goto err_op;
- }
-
- if (ldif->changetype != LDB_CHANGETYPE_MODRDN) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: invalid changetype '%d'",
- ldif->changetype);
- goto err_other;
- }
-
- if (msg->num_elements < 2) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: num_elements[%u] < 2",
- msg->num_elements);
- goto err_other;
- }
-
- if (msg->num_elements > 3) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: num_elements[%u] > 3",
- msg->num_elements);
- goto err_other;
- }
-
-#define CHECK_ELEMENT(i, _name, v, needed) do { \
- v = NULL; \
- if (msg->num_elements < (i + 1)) { \
- if (needed) { \
- ldb_debug(ldb, LDB_DEBUG_ERROR, \
- "Error: num_elements[%u] < (%u + 1)", \
- msg->num_elements, i); \
- goto err_other; \
- } \
- } else if (ldb_attr_cmp(msg->elements[i].name, _name) != 0) { \
- ldb_debug(ldb, LDB_DEBUG_ERROR, \
- "Error: elements[%u].name[%s] != [%s]", \
- i, msg->elements[i].name, _name); \
- goto err_other; \
- } else if (msg->elements[i].flags != 0) { \
- ldb_debug(ldb, LDB_DEBUG_ERROR, \
- "Error: elements[%u].flags[0x%X} != [0x0]", \
- i, msg->elements[i].flags); \
- goto err_other; \
- } else if (msg->elements[i].num_values != 1) { \
- ldb_debug(ldb, LDB_DEBUG_ERROR, \
- "Error: elements[%u].num_values[%u] != 1", \
- i, msg->elements[i].num_values); \
- goto err_other; \
- } else { \
- v = &msg->elements[i].values[0]; \
- } \
-} while (0)
-
- CHECK_ELEMENT(0, "newrdn", newrdn_val, true);
- CHECK_ELEMENT(1, "deleteoldrdn", deleteoldrdn_val, true);
- CHECK_ELEMENT(2, "newsuperior", newsuperior_val, false);
-
-#undef CHECK_ELEMENT
-
- olddn = ldb_dn_copy(tmp_ctx, msg->dn);
- if (olddn == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: failed to copy olddn '%s'",
- ldb_dn_get_linearized(msg->dn));
- goto err_op;
- }
-
- newrdn = ldb_dn_from_ldb_val(tmp_ctx, ldb, newrdn_val);
- if (!ldb_dn_validate(newrdn)) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: Unable to parse dn '%s'",
- (char *)newrdn_val->data);
- goto err_dn;
- }
-
- tmp_false.length = 1;
- tmp_false.data = discard_const_p(uint8_t, "0");
- tmp_true.length = 1;
- tmp_true.data = discard_const_p(uint8_t, "1");
- if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_false) == 1) {
- deleteoldrdn = false;
- } else if (ldb_val_equal_exact(deleteoldrdn_val, &tmp_true) == 1) {
- deleteoldrdn = true;
- } else {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: deleteoldrdn value invalid '%s' not '0'/'1'",
- (char *)deleteoldrdn_val->data);
- goto err_attr;
- }
-
- if (newsuperior_val) {
- newsuperior = ldb_dn_from_ldb_val(tmp_ctx, ldb, newsuperior_val);
- if (!ldb_dn_validate(newsuperior)) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: Unable to parse dn '%s'",
- (char *)newsuperior_val->data);
- goto err_dn;
- }
- } else {
- newsuperior = ldb_dn_get_parent(tmp_ctx, msg->dn);
- if (newsuperior == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: Unable to get parent dn '%s'",
- ldb_dn_get_linearized(msg->dn));
- goto err_dn;
- }
- }
-
- newdn = ldb_dn_copy(tmp_ctx, newrdn);
- if (newdn == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: failed to copy newrdn '%s'",
- ldb_dn_get_linearized(newrdn));
- goto err_op;
- }
-
- ok = ldb_dn_add_base(newdn, newsuperior);
- if (!ok) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: failed to base '%s' to newdn '%s'",
- ldb_dn_get_linearized(newsuperior),
- ldb_dn_get_linearized(newdn));
- goto err_op;
- }
-
- if (_olddn) {
- *_olddn = talloc_move(mem_ctx, &olddn);
- }
- if (_newrdn) {
- *_newrdn = talloc_move(mem_ctx, &newrdn);
- }
- if (_deleteoldrdn) {
- *_deleteoldrdn = deleteoldrdn;
- }
- if (_newsuperior) {
- if (newsuperior_val) {
- *_newrdn = talloc_move(mem_ctx, &newrdn);
- } else {
- *_newrdn = NULL;
- }
- }
- if (_newdn) {
- *_newdn = talloc_move(mem_ctx, &newdn);
- }
-
- talloc_free(tmp_ctx);
- return LDB_SUCCESS;
-err_other:
- talloc_free(tmp_ctx);
- return LDB_ERR_OTHER;
-err_op:
- talloc_free(tmp_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
-err_attr:
- talloc_free(tmp_ctx);
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
-err_dn:
- talloc_free(tmp_ctx);
- return LDB_ERR_INVALID_DN_SYNTAX;
-}
-
-/*
- read from a LDIF source, creating a ldb_message
-*/
-struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
- int (*fgetc_fn)(void *), void *private_data)
-{
- struct ldb_ldif *ldif;
- struct ldb_message *msg;
- const char *attr=NULL;
- char *chunk=NULL, *s;
- struct ldb_val value;
- unsigned flags = 0;
-
- value.data = NULL;
-
- ldif = talloc(ldb, struct ldb_ldif);
- if (!ldif) return NULL;
-
- ldif->msg = talloc(ldif, struct ldb_message);
- if (ldif->msg == NULL) {
- talloc_free(ldif);
- return NULL;
- }
-
- ldif->changetype = LDB_CHANGETYPE_NONE;
- msg = ldif->msg;
-
- msg->dn = NULL;
- msg->elements = NULL;
- msg->num_elements = 0;
-
- chunk = next_chunk(ldb, fgetc_fn, private_data);
- if (!chunk) {
- goto failed;
- }
- talloc_steal(ldif, chunk);
-
- s = chunk;
-
- if (next_attr(ldif, &s, &attr, &value) != 0) {
- goto failed;
- }
-
- /* first line must be a dn */
- if (ldb_attr_cmp(attr, "dn") != 0) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'",
- attr);
- goto failed;
- }
-
- msg->dn = ldb_dn_from_ldb_val(msg, ldb, &value);
-
- if ( ! ldb_dn_validate(msg->dn)) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'",
- (char *)value.data);
- goto failed;
- }
-
- while (next_attr(ldif, &s, &attr, &value) == 0) {
- const struct ldb_schema_attribute *a;
- struct ldb_message_element *el;
- int ret, empty = 0;
-
- if (ldb_attr_cmp(attr, "changetype") == 0) {
- int i;
- for (i=0;ldb_changetypes[i].name;i++) {
- if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
- ldif->changetype = ldb_changetypes[i].changetype;
- break;
- }
- }
- if (!ldb_changetypes[i].name) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: Bad ldif changetype '%s'",(char *)value.data);
- }
- flags = 0;
- continue;
- }
-
- if (ldb_attr_cmp(attr, "add") == 0) {
- flags = LDB_FLAG_MOD_ADD;
- empty = 1;
- }
- if (ldb_attr_cmp(attr, "delete") == 0) {
- flags = LDB_FLAG_MOD_DELETE;
- empty = 1;
- }
- if (ldb_attr_cmp(attr, "replace") == 0) {
- flags = LDB_FLAG_MOD_REPLACE;
- empty = 1;
- }
- if (ldb_attr_cmp(attr, "-") == 0) {
- flags = 0;
- continue;
- }
-
- if (empty) {
- if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
- goto failed;
- }
- continue;
- }
-
- el = &msg->elements[msg->num_elements-1];
-
- a = ldb_schema_attribute_by_name(ldb, attr);
-
- if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
- flags == el->flags) {
- /* its a continuation */
- el->values =
- talloc_realloc(msg->elements, el->values,
- struct ldb_val, el->num_values+1);
- if (!el->values) {
- goto failed;
- }
- ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[el->num_values]);
- if (ret != 0) {
- goto failed;
- }
- if (value.length == 0) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Error: Attribute value cannot be empty for attribute '%s'", el->name);
- goto failed;
- }
- if (value.data != el->values[el->num_values].data) {
- talloc_steal(el->values, el->values[el->num_values].data);
- }
- el->num_values++;
- } else {
- /* its a new attribute */
- msg->elements = talloc_realloc(msg, msg->elements,
- struct ldb_message_element,
- msg->num_elements+1);
- if (!msg->elements) {
- goto failed;
- }
- el = &msg->elements[msg->num_elements];
- el->flags = flags;
- el->name = talloc_strdup(msg->elements, attr);
- el->values = talloc(msg->elements, struct ldb_val);
- if (!el->values || !el->name) {
- goto failed;
- }
- el->num_values = 1;
- ret = a->syntax->ldif_read_fn(ldb, el->values, &value, &el->values[0]);
- if (ret != 0) {
- goto failed;
- }
- if (value.data != el->values[0].data) {
- talloc_steal(el->values, el->values[0].data);
- }
- msg->num_elements++;
- }
- }
-
- if (ldif->changetype == LDB_CHANGETYPE_MODRDN) {
- int ret;
-
- ret = ldb_ldif_parse_modrdn(ldb, ldif, ldif,
- NULL, NULL, NULL, NULL, NULL);
- if (ret != LDB_SUCCESS) {
- goto failed;
- }
- }
-
- return ldif;
-
-failed:
- talloc_free(ldif);
- return NULL;
-}
-
-
-
-/*
- a wrapper around ldif_read() for reading from FILE*
-*/
-struct ldif_read_file_state {
- FILE *f;
-};
-
-static int fgetc_file(void *private_data)
-{
- struct ldif_read_file_state *state =
- (struct ldif_read_file_state *)private_data;
- return fgetc(state->f);
-}
-
-struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
-{
- struct ldif_read_file_state state;
- state.f = f;
- return ldb_ldif_read(ldb, fgetc_file, &state);
-}
-
-
-/*
- a wrapper around ldif_read() for reading from const char*
-*/
-struct ldif_read_string_state {
- const char *s;
-};
-
-static int fgetc_string(void *private_data)
-{
- struct ldif_read_string_state *state =
- (struct ldif_read_string_state *)private_data;
- if (state->s[0] != 0) {
- return *state->s++;
- }
- return EOF;
-}
-
-struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
-{
- struct ldif_read_string_state state;
- struct ldb_ldif *ldif;
- state.s = *s;
- ldif = ldb_ldif_read(ldb, fgetc_string, &state);
- *s = state.s;
- return ldif;
-}
-
-
-/*
- wrapper around ldif_write() for a file
-*/
-struct ldif_write_file_state {
- FILE *f;
-};
-
-static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
-
-static int fprintf_file(void *private_data, const char *fmt, ...)
-{
- struct ldif_write_file_state *state =
- (struct ldif_write_file_state *)private_data;
- int ret;
- va_list ap;
-
- va_start(ap, fmt);
- ret = vfprintf(state->f, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
-{
- struct ldif_write_file_state state;
- state.f = f;
- return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
-}
-
-/*
- wrapper around ldif_write() for a string
-*/
-struct ldif_write_string_state {
- char *string;
-};
-
-static int ldif_printf_string(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
-
-static int ldif_printf_string(void *private_data, const char *fmt, ...)
-{
- struct ldif_write_string_state *state =
- (struct ldif_write_string_state *)private_data;
- va_list ap;
- size_t oldlen = talloc_get_size(state->string);
- va_start(ap, fmt);
-
- state->string = talloc_vasprintf_append(state->string, fmt, ap);
- va_end(ap);
- if (!state->string) {
- return -1;
- }
-
- return talloc_get_size(state->string) - oldlen;
-}
-
-char *ldb_ldif_write_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
- const struct ldb_ldif *ldif)
-{
- struct ldif_write_string_state state;
- state.string = talloc_strdup(mem_ctx, "");
- if (!state.string) {
- return NULL;
- }
- if (ldb_ldif_write(ldb, ldif_printf_string, &state, ldif) == -1) {
- return NULL;
- }
- return state.string;
-}
-
-/*
- convenient function to turn a ldb_message into a string. Useful for
- debugging
- */
-char *ldb_ldif_message_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
- enum ldb_changetype changetype,
- const struct ldb_message *msg)
-{
- struct ldb_ldif ldif;
-
- ldif.changetype = changetype;
- ldif.msg = discard_const_p(struct ldb_message, msg);
-
- return ldb_ldif_write_string(ldb, mem_ctx, &ldif);
-}
diff --git a/source4/lib/ldb/common/ldb_match.c b/source4/lib/ldb/common/ldb_match.c
deleted file mode 100644
index a42cf9449d..0000000000
--- a/source4/lib/ldb/common/ldb_match.c
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004-2005
- 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 expression matching
- *
- * Description: ldb expression matching
- *
- * Author: Andrew Tridgell
- */
-
-#include "ldb_private.h"
-
-/*
- check if the scope matches in a search result
-*/
-static int ldb_match_scope(struct ldb_context *ldb,
- struct ldb_dn *base,
- struct ldb_dn *dn,
- enum ldb_scope scope)
-{
- int ret = 0;
-
- if (base == NULL || dn == NULL) {
- return 1;
- }
-
- switch (scope) {
- case LDB_SCOPE_BASE:
- if (ldb_dn_compare(base, dn) == 0) {
- ret = 1;
- }
- break;
-
- case LDB_SCOPE_ONELEVEL:
- if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
- if (ldb_dn_compare_base(base, dn) == 0) {
- ret = 1;
- }
- }
- break;
-
- case LDB_SCOPE_SUBTREE:
- default:
- if (ldb_dn_compare_base(base, dn) == 0) {
- ret = 1;
- }
- break;
- }
-
- return ret;
-}
-
-
-/*
- match if node is present
-*/
-static int ldb_match_present(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope, bool *matched)
-{
- const struct ldb_schema_attribute *a;
- struct ldb_message_element *el;
-
- if (ldb_attr_dn(tree->u.present.attr) == 0) {
- *matched = true;
- return LDB_SUCCESS;
- }
-
- el = ldb_msg_find_element(msg, tree->u.present.attr);
- if (el == NULL) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- a = ldb_schema_attribute_by_name(ldb, el->name);
- if (!a) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- if (a->syntax->operator_fn) {
- unsigned int i;
- for (i = 0; i < el->num_values; i++) {
- int ret = a->syntax->operator_fn(ldb, LDB_OP_PRESENT, a, &el->values[i], NULL, matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- }
- *matched = false;
- return LDB_SUCCESS;
- }
-
- *matched = true;
- return LDB_SUCCESS;
-}
-
-static int ldb_match_comparison(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope,
- enum ldb_parse_op comp_op, bool *matched)
-{
- unsigned int i;
- struct ldb_message_element *el;
- const struct ldb_schema_attribute *a;
-
- /* FIXME: APPROX comparison not handled yet */
- if (comp_op == LDB_OP_APPROX) {
- return LDB_ERR_INAPPROPRIATE_MATCHING;
- }
-
- el = ldb_msg_find_element(msg, tree->u.comparison.attr);
- if (el == NULL) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- a = ldb_schema_attribute_by_name(ldb, el->name);
- if (!a) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- for (i = 0; i < el->num_values; i++) {
- if (a->syntax->operator_fn) {
- int ret;
- ret = a->syntax->operator_fn(ldb, comp_op, a, &el->values[i], &tree->u.comparison.value, matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- } else {
- int ret = a->syntax->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
-
- if (ret == 0) {
- *matched = true;
- return LDB_SUCCESS;
- }
- if (ret > 0 && comp_op == LDB_OP_GREATER) {
- *matched = true;
- return LDB_SUCCESS;
- }
- if (ret < 0 && comp_op == LDB_OP_LESS) {
- *matched = true;
- return LDB_SUCCESS;
- }
- }
- }
-
- *matched = false;
- return LDB_SUCCESS;
-}
-
-/*
- match a simple leaf node
-*/
-static int ldb_match_equality(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope,
- bool *matched)
-{
- unsigned int i;
- struct ldb_message_element *el;
- const struct ldb_schema_attribute *a;
- struct ldb_dn *valuedn;
- int ret;
-
- if (ldb_attr_dn(tree->u.equality.attr) == 0) {
- valuedn = ldb_dn_from_ldb_val(ldb, ldb, &tree->u.equality.value);
- if (valuedn == NULL) {
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
-
- ret = ldb_dn_compare(msg->dn, valuedn);
-
- talloc_free(valuedn);
-
- *matched = (ret == 0);
- return LDB_SUCCESS;
- }
-
- /* TODO: handle the "*" case derived from an extended search
- operation without the attibute type defined */
- el = ldb_msg_find_element(msg, tree->u.equality.attr);
- if (el == NULL) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- a = ldb_schema_attribute_by_name(ldb, el->name);
- if (a == NULL) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- for (i=0;i<el->num_values;i++) {
- if (a->syntax->operator_fn) {
- ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
- &tree->u.equality.value, &el->values[i], matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- } else {
- if (a->syntax->comparison_fn(ldb, ldb, &tree->u.equality.value,
- &el->values[i]) == 0) {
- *matched = true;
- return LDB_SUCCESS;
- }
- }
- }
-
- *matched = false;
- return LDB_SUCCESS;
-}
-
-static int ldb_wildcard_compare(struct ldb_context *ldb,
- const struct ldb_parse_tree *tree,
- const struct ldb_val value, bool *matched)
-{
- const struct ldb_schema_attribute *a;
- struct ldb_val val;
- struct ldb_val cnk;
- struct ldb_val *chunk;
- char *p, *g;
- uint8_t *save_p = NULL;
- unsigned int c = 0;
-
- a = ldb_schema_attribute_by_name(ldb, tree->u.substring.attr);
- if (!a) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- if (a->syntax->canonicalise_fn(ldb, ldb, &value, &val) != 0) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
-
- save_p = val.data;
- cnk.data = NULL;
-
- if ( ! tree->u.substring.start_with_wildcard ) {
-
- chunk = tree->u.substring.chunks[c];
- if (a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
-
- /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
- if (cnk.length > val.length) {
- goto mismatch;
- }
- if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto mismatch;
- val.length -= cnk.length;
- val.data += cnk.length;
- c++;
- talloc_free(cnk.data);
- cnk.data = NULL;
- }
-
- while (tree->u.substring.chunks[c]) {
-
- chunk = tree->u.substring.chunks[c];
- if(a->syntax->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto mismatch;
-
- /* FIXME: case of embedded nulls */
- p = strstr((char *)val.data, (char *)cnk.data);
- if (p == NULL) goto mismatch;
- if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
- do { /* greedy */
- g = strstr((char *)p + cnk.length, (char *)cnk.data);
- if (g) p = g;
- } while(g);
- }
- val.length = val.length - (p - (char *)(val.data)) - cnk.length;
- val.data = (uint8_t *)(p + cnk.length);
- c++;
- talloc_free(cnk.data);
- cnk.data = NULL;
- }
-
- /* last chunk may not have reached end of string */
- if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto mismatch;
- talloc_free(save_p);
- *matched = true;
- return LDB_SUCCESS;
-
-mismatch:
- *matched = false;
- talloc_free(save_p);
- talloc_free(cnk.data);
- return LDB_SUCCESS;
-}
-
-/*
- match a simple leaf node
-*/
-static int ldb_match_substring(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope, bool *matched)
-{
- unsigned int i;
- struct ldb_message_element *el;
-
- el = ldb_msg_find_element(msg, tree->u.substring.attr);
- if (el == NULL) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- for (i = 0; i < el->num_values; i++) {
- int ret;
- ret = ldb_wildcard_compare(ldb, tree, el->values[i], matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- }
-
- *matched = false;
- return LDB_SUCCESS;
-}
-
-
-/*
- bitwise-and comparator
-*/
-static int ldb_comparator_bitmask(const char *oid, const struct ldb_val *v1, const struct ldb_val *v2,
- bool *matched)
-{
- uint64_t i1, i2;
- char ibuf[100];
- char *endptr = NULL;
-
- if (v1->length >= sizeof(ibuf)-1) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- memcpy(ibuf, (char *)v1->data, v1->length);
- ibuf[v1->length] = 0;
- i1 = strtoull(ibuf, &endptr, 0);
- if (endptr != NULL) {
- if (endptr == ibuf || *endptr != 0) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- }
-
- if (v2->length >= sizeof(ibuf)-1) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- endptr = NULL;
- memcpy(ibuf, (char *)v2->data, v2->length);
- ibuf[v2->length] = 0;
- i2 = strtoull(ibuf, &endptr, 0);
- if (endptr != NULL) {
- if (endptr == ibuf || *endptr != 0) {
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- }
- if (strcmp(LDB_OID_COMPARATOR_AND, oid) == 0) {
- *matched = ((i1 & i2) == i2);
- } else if (strcmp(LDB_OID_COMPARATOR_OR, oid) == 0) {
- *matched = ((i1 & i2) != 0);
- } else {
- return LDB_ERR_INAPPROPRIATE_MATCHING;
- }
- return LDB_SUCCESS;
-}
-
-
-/*
- extended match, handles things like bitops
-*/
-static int ldb_match_extended(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope, bool *matched)
-{
- unsigned int i;
- const struct {
- const char *oid;
- int (*comparator)(const char *, const struct ldb_val *, const struct ldb_val *, bool *);
- } rules[] = {
- { LDB_OID_COMPARATOR_AND, ldb_comparator_bitmask},
- { LDB_OID_COMPARATOR_OR, ldb_comparator_bitmask}
- };
- int (*comp)(const char *,const struct ldb_val *, const struct ldb_val *, bool *) = NULL;
- struct ldb_message_element *el;
-
- if (tree->u.extended.dnAttributes) {
- /* FIXME: We really need to find out what this ":dn" part in
- * an extended match means and how to handle it. For now print
- * only a warning to have s3 winbind and other tools working
- * against us. - Matthias */
- ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb: dnAttributes extended match not supported yet");
- }
- if (tree->u.extended.rule_id == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
- return LDB_ERR_INAPPROPRIATE_MATCHING;
- }
- if (tree->u.extended.attr == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
- return LDB_ERR_INAPPROPRIATE_MATCHING;
- }
-
- for (i=0;i<ARRAY_SIZE(rules);i++) {
- if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
- comp = rules[i].comparator;
- break;
- }
- }
- if (comp == NULL) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s",
- tree->u.extended.rule_id);
- return LDB_ERR_INAPPROPRIATE_MATCHING;
- }
-
- /* find the message element */
- el = ldb_msg_find_element(msg, tree->u.extended.attr);
- if (el == NULL) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- for (i=0;i<el->num_values;i++) {
- int ret = comp(tree->u.extended.rule_id, &el->values[i], &tree->u.extended.value, matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- }
-
- *matched = false;
- return LDB_SUCCESS;
-}
-
-/*
- return 0 if the given parse tree matches the given message. Assumes
- the message is in sorted order
-
- return 1 if it matches, and 0 if it doesn't match
-
- this is a recursive function, and does short-circuit evaluation
- */
-static int ldb_match_message(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- enum ldb_scope scope, bool *matched)
-{
- unsigned int i;
- int ret;
-
- *matched = false;
-
- switch (tree->operation) {
- case LDB_OP_AND:
- for (i=0;i<tree->u.list.num_elements;i++) {
- ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
- if (ret != LDB_SUCCESS) return ret;
- if (!*matched) return LDB_SUCCESS;
- }
- *matched = true;
- return LDB_SUCCESS;
-
- case LDB_OP_OR:
- for (i=0;i<tree->u.list.num_elements;i++) {
- ret = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope, matched);
- if (ret != LDB_SUCCESS) return ret;
- if (*matched) return LDB_SUCCESS;
- }
- *matched = false;
- return LDB_SUCCESS;
-
- case LDB_OP_NOT:
- ret = ldb_match_message(ldb, msg, tree->u.isnot.child, scope, matched);
- if (ret != LDB_SUCCESS) return ret;
- *matched = ! *matched;
- return LDB_SUCCESS;
-
- case LDB_OP_EQUALITY:
- return ldb_match_equality(ldb, msg, tree, scope, matched);
-
- case LDB_OP_SUBSTRING:
- return ldb_match_substring(ldb, msg, tree, scope, matched);
-
- case LDB_OP_GREATER:
- return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER, matched);
-
- case LDB_OP_LESS:
- return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS, matched);
-
- case LDB_OP_PRESENT:
- return ldb_match_present(ldb, msg, tree, scope, matched);
-
- case LDB_OP_APPROX:
- return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX, matched);
-
- case LDB_OP_EXTENDED:
- return ldb_match_extended(ldb, msg, tree, scope, matched);
- }
-
- return LDB_ERR_INAPPROPRIATE_MATCHING;
-}
-
-int ldb_match_msg(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- struct ldb_dn *base,
- enum ldb_scope scope)
-{
- bool matched;
- int ret;
-
- if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
- return 0;
- }
-
- ret = ldb_match_message(ldb, msg, tree, scope, &matched);
- if (ret != LDB_SUCCESS) {
- /* to match the old API, we need to consider this a
- failure to match */
- return 0;
- }
- return matched?1:0;
-}
-
-int ldb_match_msg_error(struct ldb_context *ldb,
- const struct ldb_message *msg,
- const struct ldb_parse_tree *tree,
- struct ldb_dn *base,
- enum ldb_scope scope,
- bool *matched)
-{
- if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
- *matched = false;
- return LDB_SUCCESS;
- }
-
- return ldb_match_message(ldb, msg, tree, scope, matched);
-}
-
-int ldb_match_msg_objectclass(const struct ldb_message *msg,
- const char *objectclass)
-{
- unsigned int i;
- struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass");
- if (!el) {
- return 0;
- }
- for (i=0; i < el->num_values; i++) {
- if (ldb_attr_cmp((const char *)el->values[i].data, objectclass) == 0) {
- return 1;
- }
- }
- return 0;
-}
-
-
-
diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c
deleted file mode 100644
index 61d1901513..0000000000
--- a/source4/lib/ldb/common/ldb_modules.c
+++ /dev/null
@@ -1,1146 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Simo Sorce 2004-2008
-
- ** 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 modules core
- *
- * Description: core modules routines
- *
- * Author: Simo Sorce
- */
-
-#include "ldb_private.h"
-#include "dlinklist.h"
-#include "system/dir.h"
-
-static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
-{
- size_t i, len;
- char *trimmed;
-
- trimmed = talloc_strdup(mem_ctx, string);
- if (!trimmed) {
- return NULL;
- }
-
- len = strlen(trimmed);
- for (i = 0; trimmed[i] != '\0'; i++) {
- switch (trimmed[i]) {
- case ' ':
- case '\t':
- case '\n':
- memmove(&trimmed[i], &trimmed[i + 1], len -i -1);
- break;
- }
- }
-
- return trimmed;
-}
-
-
-/* modules are called in inverse order on the stack.
- Lets place them as an admin would think the right order is.
- Modules order is important */
-const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string)
-{
- char **modules = NULL;
- const char **m;
- char *modstr, *p;
- unsigned int i;
-
- /* spaces not admitted */
- modstr = ldb_modules_strdup_no_spaces(mem_ctx, string);
- if ( ! modstr) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()");
- return NULL;
- }
-
- modules = talloc_realloc(mem_ctx, modules, char *, 2);
- if ( ! modules ) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()");
- talloc_free(modstr);
- return NULL;
- }
- talloc_steal(modules, modstr);
-
- if (modstr[0] == '\0') {
- modules[0] = NULL;
- m = (const char **)modules;
- return m;
- }
-
- i = 0;
- /* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */
- while ((p = strrchr(modstr, ',')) != NULL) {
- *p = '\0';
- p++;
- modules[i] = p;
-
- i++;
- modules = talloc_realloc(mem_ctx, modules, char *, i + 2);
- if ( ! modules ) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()");
- return NULL;
- }
-
- }
- modules[i] = modstr;
-
- modules[i + 1] = NULL;
-
- m = (const char **)modules;
-
- return m;
-}
-
-static struct backends_list_entry {
- struct ldb_backend_ops *ops;
- struct backends_list_entry *prev, *next;
-} *ldb_backends = NULL;
-
-static struct ops_list_entry {
- const struct ldb_module_ops *ops;
- struct ops_list_entry *next;
-} *registered_modules = NULL;
-
-static struct backends_list_entry *ldb_find_backend(const char *url_prefix)
-{
- struct backends_list_entry *backend;
-
- for (backend = ldb_backends; backend; backend = backend->next) {
- if (strcmp(backend->ops->name, url_prefix) == 0) {
- return backend;
- }
- }
-
- return NULL;
-}
-
-/*
- register a new ldb backend
-
- if override is true, then override any existing backend for this prefix
-*/
-int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn, bool override)
-{
- struct backends_list_entry *be;
-
- be = ldb_find_backend(url_prefix);
- if (be) {
- if (!override) {
- return LDB_SUCCESS;
- }
- } else {
- be = talloc_zero(ldb_backends, struct backends_list_entry);
- if (!be) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- be->ops = talloc_zero(be, struct ldb_backend_ops);
- if (!be->ops) {
- talloc_free(be);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- DLIST_ADD_END(ldb_backends, be, struct backends_list_entry);
- }
-
- be->ops->name = url_prefix;
- be->ops->connect_fn = connectfn;
-
- return LDB_SUCCESS;
-}
-
-/*
- Return the ldb module form of a database.
- The URL can either be one of the following forms
- ldb://path
- ldapi://path
-
- flags is made up of LDB_FLG_*
-
- the options are passed uninterpreted to the backend, and are
- backend specific.
-
- This allows modules to get at only the backend module, for example where a
- module may wish to direct certain requests at a particular backend.
-*/
-int ldb_module_connect_backend(struct ldb_context *ldb,
- const char *url,
- const char *options[],
- struct ldb_module **backend_module)
-{
- int ret;
- char *backend;
- struct backends_list_entry *be;
-
- if (strchr(url, ':') != NULL) {
- backend = talloc_strndup(ldb, url, strchr(url, ':')-url);
- } else {
- /* Default to tdb */
- backend = talloc_strdup(ldb, "tdb");
- }
- if (backend == NULL) {
- return ldb_oom(ldb);
- }
-
- be = ldb_find_backend(backend);
-
- talloc_free(backend);
-
- if (be == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL,
- "Unable to find backend for '%s' - do you need to set LDB_MODULES_PATH?", url);
- return LDB_ERR_OTHER;
- }
-
- ret = be->ops->connect_fn(ldb, url, ldb->flags, options, backend_module);
-
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_ERROR,
- "Failed to connect to '%s' with backend '%s'", url, be->ops->name);
- return ret;
- }
- return ret;
-}
-
-static struct ldb_hooks {
- struct ldb_hooks *next, *prev;
- ldb_hook_fn hook_fn;
-} *ldb_hooks;
-
-/*
- register a ldb hook function
- */
-int ldb_register_hook(ldb_hook_fn hook_fn)
-{
- struct ldb_hooks *lc;
- lc = talloc_zero(ldb_hooks, struct ldb_hooks);
- if (lc == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- lc->hook_fn = hook_fn;
- DLIST_ADD_END(ldb_hooks, lc, struct ldb_hooks);
- return LDB_SUCCESS;
-}
-
-/*
- call ldb hooks of a given type
- */
-int ldb_modules_hook(struct ldb_context *ldb, enum ldb_module_hook_type t)
-{
- struct ldb_hooks *lc;
- for (lc = ldb_hooks; lc; lc=lc->next) {
- int ret = lc->hook_fn(ldb, t);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
- return LDB_SUCCESS;
-}
-
-
-static const struct ldb_module_ops *ldb_find_module_ops(const char *name)
-{
- struct ops_list_entry *e;
-
- for (e = registered_modules; e; e = e->next) {
- if (strcmp(e->ops->name, name) == 0)
- return e->ops;
- }
-
- return NULL;
-}
-
-
-int ldb_register_module(const struct ldb_module_ops *ops)
-{
- struct ops_list_entry *entry;
-
- if (ldb_find_module_ops(ops->name) != NULL)
- return LDB_ERR_ENTRY_ALREADY_EXISTS;
-
- entry = talloc(talloc_autofree_context(), struct ops_list_entry);
- if (entry == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- entry->ops = ops;
- entry->next = registered_modules;
- registered_modules = entry;
-
- return LDB_SUCCESS;
-}
-
-/*
- load a list of modules
- */
-int ldb_module_load_list(struct ldb_context *ldb, const char **module_list,
- struct ldb_module *backend, struct ldb_module **out)
-{
- struct ldb_module *module;
- unsigned int i;
-
- module = backend;
-
- for (i = 0; module_list && module_list[i] != NULL; i++) {
- struct ldb_module *current;
- const struct ldb_module_ops *ops;
-
- if (strcmp(module_list[i], "") == 0) {
- continue;
- }
-
- ops = ldb_find_module_ops(module_list[i]);
-
- if (ops == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "WARNING: Module [%s] not found - do you need to set LDB_MODULES_PATH?",
- module_list[i]);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- current = talloc_zero(ldb, struct ldb_module);
- if (current == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- talloc_set_name(current, "ldb_module: %s", module_list[i]);
-
- current->ldb = ldb;
- current->ops = ops;
-
- DLIST_ADD(module, current);
- }
- *out = module;
- return LDB_SUCCESS;
-}
-
-/*
- initialise a chain of modules
- */
-int ldb_module_init_chain(struct ldb_context *ldb, struct ldb_module *module)
-{
- while (module && module->ops->init_context == NULL)
- module = module->next;
-
- /* init is different in that it is not an error if modules
- * do not require initialization */
-
- if (module) {
- int ret = module->ops->init_context(module);
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "module %s initialization failed : %s",
- module->ops->name, ldb_strerror(ret));
- return ret;
- }
- }
-
- return LDB_SUCCESS;
-}
-
-int ldb_load_modules(struct ldb_context *ldb, const char *options[])
-{
- const char *modules_string;
- const char **modules = NULL;
- int ret;
- TALLOC_CTX *mem_ctx = talloc_new(ldb);
- if (!mem_ctx) {
- return ldb_oom(ldb);
- }
-
- /* find out which modules we are requested to activate */
-
- /* check if we have a custom module list passd as ldb option */
- if (options) {
- modules_string = ldb_options_find(ldb, options, "modules");
- if (modules_string) {
- modules = ldb_modules_list_from_string(ldb, mem_ctx, modules_string);
- }
- }
-
- /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */
- if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) {
- const char * const attrs[] = { "@LIST" , NULL};
- struct ldb_result *res = NULL;
- struct ldb_dn *mods_dn;
-
- mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES");
- if (mods_dn == NULL) {
- talloc_free(mem_ctx);
- return ldb_oom(ldb);
- }
-
- ret = ldb_search(ldb, mods_dn, &res, mods_dn, LDB_SCOPE_BASE, attrs, "@LIST=*");
-
- if (ret == LDB_ERR_NO_SUCH_OBJECT) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
- } else if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out", ldb_errstring(ldb));
- talloc_free(mem_ctx);
- return ret;
- } else {
- const char *module_list;
- if (res->count == 0) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
- } else if (res->count > 1) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%u), bailing out", res->count);
- talloc_free(mem_ctx);
- return LDB_ERR_OPERATIONS_ERROR;
- } else {
- module_list = ldb_msg_find_attr_as_string(res->msgs[0], "@LIST", NULL);
- if (!module_list) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db");
- }
- modules = ldb_modules_list_from_string(ldb, mem_ctx,
- module_list);
- }
- }
-
- talloc_free(mods_dn);
- }
-
- if (modules != NULL) {
- ret = ldb_module_load_list(ldb, modules, ldb->modules, &ldb->modules);
- if (ret != LDB_SUCCESS) {
- talloc_free(mem_ctx);
- return ret;
- }
- } else {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database");
- }
-
- ret = ldb_module_init_chain(ldb, ldb->modules);
- talloc_free(mem_ctx);
- return ret;
-}
-
-/*
- by using this we allow ldb modules to only implement the functions they care about,
- which makes writing a module simpler, and makes it more likely to keep working
- when ldb is extended
-*/
-#define FIND_OP_NOERR(module, op) do { \
- module = module->next; \
- while (module && module->ops->op == NULL) module = module->next; \
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { \
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_trace_next_request: (%s)->" #op, \
- module->ops->name); \
- } \
-} while (0)
-
-#define FIND_OP(module, op) do { \
- struct ldb_context *ldb = module->ldb; \
- FIND_OP_NOERR(module, op); \
- if (module == NULL) { \
- ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
- return LDB_ERR_OPERATIONS_ERROR; \
- } \
-} while (0)
-
-
-struct ldb_module *ldb_module_new(TALLOC_CTX *memctx,
- struct ldb_context *ldb,
- const char *module_name,
- const struct ldb_module_ops *ops)
-{
- struct ldb_module *module;
-
- module = talloc(memctx, struct ldb_module);
- if (!module) {
- ldb_oom(ldb);
- return NULL;
- }
- talloc_set_name_const(module, module_name);
- module->ldb = ldb;
- module->prev = module->next = NULL;
- module->ops = ops;
-
- return module;
-}
-
-const char * ldb_module_get_name(struct ldb_module *module)
-{
- return module->ops->name;
-}
-
-struct ldb_context *ldb_module_get_ctx(struct ldb_module *module)
-{
- return module->ldb;
-}
-
-const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module)
-{
- return module->ops;
-}
-
-void *ldb_module_get_private(struct ldb_module *module)
-{
- return module->private_data;
-}
-
-void ldb_module_set_private(struct ldb_module *module, void *private_data)
-{
- module->private_data = private_data;
-}
-
-/*
- helper functions to call the next module in chain
-*/
-
-int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
-{
- int ret;
-
- if (request->callback == NULL) {
- ldb_set_errstring(module->ldb, "Requests MUST define callbacks");
- return LDB_ERR_UNWILLING_TO_PERFORM;
- }
-
- request->handle->nesting++;
-
- switch (request->operation) {
- case LDB_SEARCH:
- FIND_OP(module, search);
- ret = module->ops->search(module, request);
- break;
- case LDB_ADD:
- FIND_OP(module, add);
- ret = module->ops->add(module, request);
- break;
- case LDB_MODIFY:
- FIND_OP(module, modify);
- ret = module->ops->modify(module, request);
- break;
- case LDB_DELETE:
- FIND_OP(module, del);
- ret = module->ops->del(module, request);
- break;
- case LDB_RENAME:
- FIND_OP(module, rename);
- ret = module->ops->rename(module, request);
- break;
- case LDB_EXTENDED:
- FIND_OP(module, extended);
- ret = module->ops->extended(module, request);
- break;
- default:
- FIND_OP(module, request);
- ret = module->ops->request(module, request);
- break;
- }
-
- request->handle->nesting--;
-
- if (ret == LDB_SUCCESS) {
- return ret;
- }
- if (!ldb_errstring(module->ldb)) {
- /* Set a default error string, to place the blame somewhere */
- ldb_asprintf_errstring(module->ldb, "error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
- }
-
- if (!(request->handle->flags & LDB_HANDLE_FLAG_DONE_CALLED)) {
- /* It is _extremely_ common that a module returns a
- * failure without calling ldb_module_done(), but that
- * guarantees we will end up hanging in
- * ldb_wait(). This fixes it without having to rewrite
- * all our modules, and leaves us one less sharp
- * corner for module developers to cut themselves on
- */
- ret = ldb_module_done(request, NULL, NULL, ret);
- }
- return ret;
-}
-
-int ldb_next_init(struct ldb_module *module)
-{
- module = module->next;
-
- return ldb_module_init_chain(module->ldb, module);
-}
-
-int ldb_next_start_trans(struct ldb_module *module)
-{
- int ret;
- FIND_OP(module, start_transaction);
- ret = module->ops->start_transaction(module);
- if (ret == LDB_SUCCESS) {
- return ret;
- }
- if (!ldb_errstring(module->ldb)) {
- /* Set a default error string, to place the blame somewhere */
- ldb_asprintf_errstring(module->ldb, "start_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_start_trans error: %s",
- ldb_errstring(module->ldb));
- }
- return ret;
-}
-
-int ldb_next_end_trans(struct ldb_module *module)
-{
- int ret;
- FIND_OP(module, end_transaction);
- ret = module->ops->end_transaction(module);
- if (ret == LDB_SUCCESS) {
- return ret;
- }
- if (!ldb_errstring(module->ldb)) {
- /* Set a default error string, to place the blame somewhere */
- ldb_asprintf_errstring(module->ldb, "end_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_end_trans error: %s",
- ldb_errstring(module->ldb));
- }
- return ret;
-}
-
-int ldb_next_prepare_commit(struct ldb_module *module)
-{
- int ret;
- FIND_OP_NOERR(module, prepare_commit);
- if (module == NULL) {
- /* we are allowed to have no prepare commit in
- backends */
- return LDB_SUCCESS;
- }
- ret = module->ops->prepare_commit(module);
- if (ret == LDB_SUCCESS) {
- return ret;
- }
- if (!ldb_errstring(module->ldb)) {
- /* Set a default error string, to place the blame somewhere */
- ldb_asprintf_errstring(module->ldb, "prepare_commit error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_prepare_commit error: %s",
- ldb_errstring(module->ldb));
- }
- return ret;
-}
-
-int ldb_next_del_trans(struct ldb_module *module)
-{
- int ret;
- FIND_OP(module, del_transaction);
- ret = module->ops->del_transaction(module);
- if (ret == LDB_SUCCESS) {
- return ret;
- }
- if (!ldb_errstring(module->ldb)) {
- /* Set a default error string, to place the blame somewhere */
- ldb_asprintf_errstring(module->ldb, "del_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret);
- }
- if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
- ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_del_trans error: %s",
- ldb_errstring(module->ldb));
- }
- return ret;
-}
-
-struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb)
-{
- struct ldb_handle *h;
-
- h = talloc_zero(mem_ctx, struct ldb_handle);
- if (h == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
- return NULL;
- }
-
- h->status = LDB_SUCCESS;
- h->state = LDB_ASYNC_INIT;
- h->ldb = ldb;
- h->flags = 0;
- h->location = NULL;
- h->parent = NULL;
-
- return h;
-}
-
-/* calls the request callback to send an entry
- *
- * params:
- * req: the original request passed to your module
- * msg: reply message (must be a talloc pointer, and it will be stolen
- * on the ldb_reply that is sent to the callback)
- * ctrls: controls to send in the reply (must be a talloc pointer, and it will be stolen
- * on the ldb_reply that is sent to the callback)
- */
-
-int ldb_module_send_entry(struct ldb_request *req,
- struct ldb_message *msg,
- struct ldb_control **ctrls)
-{
- struct ldb_reply *ares;
-
- ares = talloc_zero(req, struct ldb_reply);
- if (!ares) {
- ldb_oom(req->handle->ldb);
- req->callback(req, NULL);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ares->type = LDB_REPLY_ENTRY;
- ares->message = talloc_steal(ares, msg);
- ares->controls = talloc_steal(ares, ctrls);
- ares->error = LDB_SUCCESS;
-
- if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
- req->handle->nesting == 0) {
- char *s;
- ldb_debug_add(req->handle->ldb, "ldb_trace_response: ENTRY\n");
- s = ldb_ldif_message_string(req->handle->ldb, msg, LDB_CHANGETYPE_NONE, msg);
- ldb_debug_add(req->handle->ldb, "%s\n", s);
- talloc_free(s);
- ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
- }
-
- return req->callback(req, ares);
-}
-
-/* calls the request callback to send an referrals
- *
- * params:
- * req: the original request passed to your module
- * ref: referral string (must be a talloc pointeri, steal)
- */
-
-int ldb_module_send_referral(struct ldb_request *req,
- char *ref)
-{
- struct ldb_reply *ares;
-
- ares = talloc_zero(req, struct ldb_reply);
- if (!ares) {
- ldb_oom(req->handle->ldb);
- req->callback(req, NULL);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ares->type = LDB_REPLY_REFERRAL;
- ares->referral = talloc_steal(ares, ref);
- ares->error = LDB_SUCCESS;
-
- if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
- req->handle->nesting == 0) {
- ldb_debug_add(req->handle->ldb, "ldb_trace_response: REFERRAL\n");
- ldb_debug_add(req->handle->ldb, "ref: %s\n", ref);
- ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
- }
-
- return req->callback(req, ares);
-}
-
-/* calls the original request callback
- *
- * params:
- * req: the original request passed to your module
- * ctrls: controls to send in the reply (must be a talloc pointer, steal)
- * response: results for extended request (steal)
- * error: LDB_SUCCESS for a successful return
- * any other ldb error otherwise
- */
-int ldb_module_done(struct ldb_request *req,
- struct ldb_control **ctrls,
- struct ldb_extended *response,
- int error)
-{
- struct ldb_reply *ares;
-
- ares = talloc_zero(req, struct ldb_reply);
- if (!ares) {
- ldb_oom(req->handle->ldb);
- req->callback(req, NULL);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- ares->type = LDB_REPLY_DONE;
- ares->controls = talloc_steal(ares, ctrls);
- ares->response = talloc_steal(ares, response);
- ares->error = error;
-
- req->handle->flags |= LDB_HANDLE_FLAG_DONE_CALLED;
-
- if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) &&
- req->handle->nesting == 0) {
- ldb_debug_add(req->handle->ldb, "ldb_trace_response: DONE\n");
- ldb_debug_add(req->handle->ldb, "error: %d\n", error);
- if (ldb_errstring(req->handle->ldb)) {
- ldb_debug_add(req->handle->ldb, "msg: %s\n",
- ldb_errstring(req->handle->ldb));
- }
- ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE);
- }
-
- return req->callback(req, ares);
-}
-
-/* to be used *only* in modules init functions.
- * this function is synchronous and will register
- * the requested OID in the rootdse module if present
- * otherwise it will return an error */
-int ldb_mod_register_control(struct ldb_module *module, const char *oid)
-{
- struct ldb_request *req;
- int ret;
-
- req = talloc_zero(module, struct ldb_request);
- if (req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- req->operation = LDB_REQ_REGISTER_CONTROL;
- req->op.reg_control.oid = oid;
- req->callback = ldb_op_default_callback;
-
- ldb_set_timeout(module->ldb, req, 0);
-
- req->handle = ldb_handle_new(req, module->ldb);
- if (req->handle == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_request(module->ldb, req);
- if (ret == LDB_SUCCESS) {
- ret = ldb_wait(req->handle, LDB_WAIT_ALL);
- }
- talloc_free(req);
-
- return ret;
-}
-
-static int ldb_modules_load_dir(const char *modules_dir, const char *version);
-
-
-/*
- load one module. A static list of loaded module inode numbers is
- used to prevent a module being loaded twice
-
- dlopen() is used on the module, and dlsym() is then used to look for
- a ldb_init_module() function. If present, that function is called
- with the ldb version number as an argument.
-
- The ldb_init_module() function will typically call
- ldb_register_module() and ldb_register_backend() to register a
- module or backend, but it may also be used to register command line
- handling functions, ldif handlers or any other local
- modififications.
-
- The ldb_init_module() function does not get a ldb_context passed in,
- as modules will be used for multiple ldb context handles. The call
- from the first ldb_init() is just a convenient way to ensure it is
- called early enough.
- */
-static int ldb_modules_load_path(const char *path, const char *version)
-{
- void *handle;
- int (*init_fn)(const char *);
- int ret;
- struct stat st;
- static struct loaded {
- struct loaded *next, *prev;
- ino_t st_ino;
- dev_t st_dev;
- } *loaded;
- struct loaded *le;
- int dlopen_flags;
-
- ret = stat(path, &st);
- if (ret != 0) {
- fprintf(stderr, "ldb: unable to stat module %s : %s\n", path, strerror(errno));
- return LDB_ERR_UNAVAILABLE;
- }
-
- for (le=loaded; le; le=le->next) {
- if (le->st_ino == st.st_ino &&
- le->st_dev == st.st_dev) {
- /* its already loaded */
- return LDB_SUCCESS;
- }
- }
-
- le = talloc(loaded, struct loaded);
- if (le == NULL) {
- fprintf(stderr, "ldb: unable to allocated loaded entry\n");
- return LDB_ERR_UNAVAILABLE;
- }
-
- le->st_ino = st.st_ino;
- le->st_dev = st.st_dev;
-
- DLIST_ADD_END(loaded, le, struct loaded);
-
- /* if it is a directory, recurse */
- if (S_ISDIR(st.st_mode)) {
- return ldb_modules_load_dir(path, version);
- }
-
- dlopen_flags = RTLD_NOW;
-#ifdef RTLD_DEEPBIND
- /* use deepbind if possible, to avoid issues with different
- system library varients, for example ldb modules may be linked
- against Heimdal while the application may use MIT kerberos
-
- See the dlopen manpage for details
- */
- dlopen_flags |= RTLD_DEEPBIND;
-#endif
-
- handle = dlopen(path, dlopen_flags);
- if (handle == NULL) {
- fprintf(stderr, "ldb: unable to dlopen %s : %s\n", path, dlerror());
- return LDB_SUCCESS;
- }
-
- init_fn = dlsym(handle, "ldb_init_module");
- if (init_fn == NULL) {
- /* ignore it, it could be an old-style
- * module. Once we've converted all modules we
- * could consider this an error */
- dlclose(handle);
- return LDB_SUCCESS;
- }
-
- ret = init_fn(version);
- if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
- /* the module is already registered - ignore this, as
- * it can happen if LDB_MODULES_PATH points at both
- * the build and install directory
- */
- ret = LDB_SUCCESS;
- }
- return ret;
-}
-
-static int qsort_string(const char **s1, const char **s2)
-{
- return strcmp(*s1, *s2);
-}
-
-
-/*
- load all modules from the given ldb modules directory. This is run once
- during the first ldb_init() call.
-
- Modules are loaded in alphabetical order to ensure that any module
- load ordering dependencies are reproducible. Modules should avoid
- relying on load order
- */
-static int ldb_modules_load_dir(const char *modules_dir, const char *version)
-{
- DIR *dir;
- struct dirent *de;
- const char **modlist = NULL;
- TALLOC_CTX *tmp_ctx = talloc_new(NULL);
- unsigned i, num_modules = 0;
-
- dir = opendir(modules_dir);
- if (dir == NULL) {
- if (errno == ENOENT) {
- talloc_free(tmp_ctx);
- /* we don't have any modules */
- return LDB_SUCCESS;
- }
- talloc_free(tmp_ctx);
- fprintf(stderr, "ldb: unable to open modules directory '%s' - %s\n",
- modules_dir, strerror(errno));
- return LDB_ERR_UNAVAILABLE;
- }
-
-
- while ((de = readdir(dir))) {
- if (ISDOT(de->d_name) || ISDOTDOT(de->d_name))
- continue;
-
- modlist = talloc_realloc(tmp_ctx, modlist, const char *, num_modules+1);
- if (modlist == NULL) {
- talloc_free(tmp_ctx);
- closedir(dir);
- fprintf(stderr, "ldb: unable to allocate modules list\n");
- return LDB_ERR_UNAVAILABLE;
- }
- modlist[num_modules] = talloc_asprintf(modlist, "%s/%s", modules_dir, de->d_name);
- if (modlist[num_modules] == NULL) {
- talloc_free(tmp_ctx);
- closedir(dir);
- fprintf(stderr, "ldb: unable to allocate module list entry\n");
- return LDB_ERR_UNAVAILABLE;
- }
- num_modules++;
- }
-
- closedir(dir);
-
- /* sort the directory, so we get consistent load ordering */
- TYPESAFE_QSORT(modlist, num_modules, qsort_string);
-
- for (i=0; i<num_modules; i++) {
- int ret = ldb_modules_load_path(modlist[i], version);
- if (ret != LDB_SUCCESS) {
- fprintf(stderr, "ldb: failed to initialise module %s : %s\n",
- modlist[i], ldb_strerror(ret));
- talloc_free(tmp_ctx);
- return ret;
- }
- }
-
- talloc_free(tmp_ctx);
-
- return LDB_SUCCESS;
-}
-
-/*
- load any additional modules from the given directory
-*/
-void ldb_set_modules_dir(struct ldb_context *ldb, const char *path)
-{
- int ret = ldb_modules_load_path(path, LDB_VERSION);
- if (ret != LDB_SUCCESS) {
- ldb_asprintf_errstring(ldb, "Failed to load modules from: %s\n", path);
- }
-}
-
-
-/*
- load all modules static (builtin) modules
- */
-static int ldb_modules_load_static(const char *version)
-{
- static bool initialised;
-#define _MODULE_PROTO(init) extern int init(const char *);
- STATIC_ldb_MODULES_PROTO;
- const ldb_module_init_fn static_init_functions[] = { STATIC_ldb_MODULES };
- unsigned i;
-
- if (initialised) {
- return LDB_SUCCESS;
- }
- initialised = true;
-
- for (i=0; static_init_functions[i]; i++) {
- int ret = static_init_functions[i](version);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
- return LDB_SUCCESS;
-}
-
-/*
- load all modules from the given ldb modules path, colon
- separated.
-
- modules are loaded recursively for all subdirectories in the paths
- */
-int ldb_modules_load(const char *modules_path, const char *version)
-{
- char *tok, *path, *tok_ptr=NULL;
- int ret;
-
- ret = ldb_modules_load_static(version);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
-
- path = talloc_strdup(NULL, modules_path);
- if (path == NULL) {
- fprintf(stderr, "ldb: failed to allocate modules_path\n");
- return LDB_ERR_UNAVAILABLE;
- }
-
- for (tok=strtok_r(path, ":", &tok_ptr);
- tok;
- tok=strtok_r(NULL, ":", &tok_ptr)) {
- ret = ldb_modules_load_path(tok, version);
- if (ret != LDB_SUCCESS) {
- talloc_free(path);
- return ret;
- }
- }
- talloc_free(path);
-
- return LDB_SUCCESS;
-}
-
-
-/*
- return a string representation of the calling chain for the given
- ldb request
- */
-char *ldb_module_call_chain(struct ldb_request *req, TALLOC_CTX *mem_ctx)
-{
- char *ret;
- unsigned int i = 0;
-
- ret = talloc_strdup(mem_ctx, "");
- if (ret == NULL) {
- return NULL;
- }
-
- while (req && req->handle) {
- char *s = talloc_asprintf_append_buffer(ret, "req[%u] %p : %s\n",
- i++, req, ldb_req_location(req));
- if (s == NULL) {
- talloc_free(ret);
- return NULL;
- }
- ret = s;
- req = req->handle->parent;
- }
- return ret;
-}
-
-
-/*
- return the next module in the chain
- */
-struct ldb_module *ldb_module_next(struct ldb_module *module)
-{
- return module->next;
-}
-
-/*
- set the next module in the module chain
- */
-void ldb_module_set_next(struct ldb_module *module, struct ldb_module *next)
-{
- module->next = next;
-}
-
-
-/*
- get the popt_options pointer in the ldb structure. This allows a ldb
- module to change the command line parsing
- */
-struct poptOption **ldb_module_popt_options(struct ldb_context *ldb)
-{
- return &ldb->popt_options;
-}
-
-
-/*
- return the current ldb flags LDB_FLG_*
- */
-uint32_t ldb_module_flags(struct ldb_context *ldb)
-{
- return ldb->flags;
-}
diff --git a/source4/lib/ldb/common/ldb_msg.c b/source4/lib/ldb/common/ldb_msg.c
deleted file mode 100644
index 28c414e6b2..0000000000
--- a/source4/lib/ldb/common/ldb_msg.c
+++ /dev/null
@@ -1,1187 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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 message component utility functions
- *
- * Description: functions for manipulating ldb_message structures
- *
- * Author: Andrew Tridgell
- */
-
-#include "ldb_private.h"
-
-/*
- create a new ldb_message in a given memory context (NULL for top level)
-*/
-struct ldb_message *ldb_msg_new(TALLOC_CTX *mem_ctx)
-{
- return talloc_zero(mem_ctx, struct ldb_message);
-}
-
-/*
- find an element in a message by attribute name
-*/
-struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
- const char *attr_name)
-{
- unsigned int i;
- for (i=0;i<msg->num_elements;i++) {
- if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
- return &msg->elements[i];
- }
- }
- return NULL;
-}
-
-/*
- see if two ldb_val structures contain exactly the same data
- return 1 for a match, 0 for a mis-match
-*/
-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) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- find a value in an element
- assumes case sensitive comparison
-*/
-struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
- struct ldb_val *val)
-{
- unsigned int i;
- for (i=0;i<el->num_values;i++) {
- if (ldb_val_equal_exact(val, &el->values[i])) {
- return &el->values[i];
- }
- }
- return NULL;
-}
-
-/*
- duplicate a ldb_val structure
-*/
-struct ldb_val ldb_val_dup(TALLOC_CTX *mem_ctx, const struct ldb_val *v)
-{
- struct ldb_val v2;
- v2.length = v->length;
- if (v->data == NULL) {
- v2.data = NULL;
- return v2;
- }
-
- /* the +1 is to cope with buggy C library routines like strndup
- that look one byte beyond */
- v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
- if (!v2.data) {
- v2.length = 0;
- return v2;
- }
-
- memcpy(v2.data, v->data, v->length);
- ((char *)v2.data)[v->length] = 0;
- return v2;
-}
-
-/**
- * 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;
-
- /*
- * 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);
- if (!els) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ZERO_STRUCT(els[msg->num_elements]);
-
- msg->elements = els;
- msg->num_elements++;
-
- *return_el = &els[msg->num_elements-1];
-
- return LDB_SUCCESS;
-}
-
-/**
- * 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) {
- 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)
-{
- 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;
- }
-
- 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 LDB_SUCCESS;
-}
-
-/*
- add a value to a message
-*/
-int ldb_msg_add_value(struct ldb_message *msg,
- const char *attr_name,
- 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) {
- ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- }
-
- vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
- el->num_values+1);
- if (!vals) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- el->values = vals;
- el->values[el->num_values] = *val;
- el->num_values++;
-
- if (return_el) {
- *return_el = el;
- }
-
- return LDB_SUCCESS;
-}
-
-
-/*
- add a value to a message, stealing it into the 'right' place
-*/
-int ldb_msg_add_steal_value(struct ldb_message *msg,
- const char *attr_name,
- struct ldb_val *val)
-{
- int ret;
- struct ldb_message_element *el;
-
- ret = ldb_msg_add_value(msg, attr_name, val, &el);
- if (ret == LDB_SUCCESS) {
- talloc_steal(el->values, val->data);
- }
- return ret;
-}
-
-
-/*
- add a string element to a message
-*/
-int ldb_msg_add_string(struct ldb_message *msg,
- const char *attr_name, const char *str)
-{
- struct ldb_val val;
-
- val.data = discard_const_p(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_value(msg, attr_name, &val, NULL);
-}
-
-/*
- add a string element to a message, stealing it into the 'right' place
-*/
-int ldb_msg_add_steal_string(struct ldb_message *msg,
- const char *attr_name, char *str)
-{
- struct ldb_val val;
-
- 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)
-{
- char *str = ldb_dn_alloc_linearized(msg, dn);
-
- if (str == NULL) {
- /* we don't want to have unknown DNs added */
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- return ldb_msg_add_steal_string(msg, attr_name, str);
-}
-
-/*
- add a printf formatted element to a message
-*/
-int ldb_msg_add_fmt(struct ldb_message *msg,
- const char *attr_name, const char *fmt, ...)
-{
- struct ldb_val val;
- va_list ap;
- char *str;
-
- va_start(ap, fmt);
- str = talloc_vasprintf(msg, fmt, ap);
- va_end(ap);
-
- if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
-
- val.data = (uint8_t *)str;
- val.length = strlen(str);
-
- return ldb_msg_add_steal_value(msg, attr_name, &val);
-}
-
-/*
- compare two ldb_message_element structures
- assumes case sensitive comparison
-*/
-int ldb_msg_element_compare(struct ldb_message_element *el1,
- struct ldb_message_element *el2)
-{
- unsigned int i;
-
- if (el1->num_values != el2->num_values) {
- return el1->num_values - el2->num_values;
- }
-
- for (i=0;i<el1->num_values;i++) {
- if (!ldb_msg_find_val(el2, &el1->values[i])) {
- return -1;
- }
- }
-
- return 0;
-}
-
-/*
- compare two ldb_message_element structures
- comparing by element name
-*/
-int ldb_msg_element_compare_name(struct ldb_message_element *el1,
- struct ldb_message_element *el2)
-{
- return ldb_attr_cmp(el1->name, el2->name);
-}
-
-/*
- 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)
-{
- struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
- if (!el || el->num_values == 0) {
- return NULL;
- }
- return &el->values[0];
-}
-
-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);
- char buf[sizeof("-2147483648")];
- char *end = NULL;
- int ret;
-
- if (!v || !v->data) {
- return default_value;
- }
-
- ZERO_STRUCT(buf);
- if (v->length >= sizeof(buf)) {
- return default_value;
- }
-
- memcpy(buf, v->data, v->length);
- errno = 0;
- ret = (int) strtoll(buf, &end, 10);
- if (errno != 0) {
- return default_value;
- }
- if (end && end[0] != '\0') {
- return default_value;
- }
- return ret;
-}
-
-unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
- const char *attr_name,
- unsigned int default_value)
-{
- const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
- char buf[sizeof("-2147483648")];
- char *end = NULL;
- unsigned int ret;
-
- if (!v || !v->data) {
- return default_value;
- }
-
- ZERO_STRUCT(buf);
- if (v->length >= sizeof(buf)) {
- return default_value;
- }
-
- memcpy(buf, v->data, v->length);
- errno = 0;
- ret = (unsigned int) strtoll(buf, &end, 10);
- if (errno != 0) {
- errno = 0;
- ret = (unsigned int) strtoull(buf, &end, 10);
- if (errno != 0) {
- return default_value;
- }
- }
- if (end && end[0] != '\0') {
- return default_value;
- }
- return ret;
-}
-
-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);
- char buf[sizeof("-9223372036854775808")];
- char *end = NULL;
- int64_t ret;
-
- if (!v || !v->data) {
- return default_value;
- }
-
- ZERO_STRUCT(buf);
- if (v->length >= sizeof(buf)) {
- return default_value;
- }
-
- memcpy(buf, v->data, v->length);
- errno = 0;
- ret = (int64_t) strtoll(buf, &end, 10);
- if (errno != 0) {
- return default_value;
- }
- if (end && end[0] != '\0') {
- return default_value;
- }
- return ret;
-}
-
-uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
- const char *attr_name,
- uint64_t default_value)
-{
- const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
- char buf[sizeof("-9223372036854775808")];
- char *end = NULL;
- uint64_t ret;
-
- if (!v || !v->data) {
- return default_value;
- }
-
- ZERO_STRUCT(buf);
- if (v->length >= sizeof(buf)) {
- return default_value;
- }
-
- memcpy(buf, v->data, v->length);
- errno = 0;
- ret = (uint64_t) strtoll(buf, &end, 10);
- if (errno != 0) {
- errno = 0;
- ret = (uint64_t) strtoull(buf, &end, 10);
- if (errno != 0) {
- return default_value;
- }
- }
- if (end && end[0] != '\0') {
- return default_value;
- }
- return ret;
-}
-
-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);
- char *buf;
- char *end = NULL;
- double ret;
-
- if (!v || !v->data) {
- return default_value;
- }
- buf = talloc_strndup(msg, (const char *)v->data, v->length);
- if (buf == NULL) {
- return default_value;
- }
-
- errno = 0;
- ret = strtod(buf, &end);
- talloc_free(buf);
- if (errno != 0) {
- return default_value;
- }
- if (end && end[0] != '\0') {
- return default_value;
- }
- return ret;
-}
-
-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) {
- return default_value;
- }
- if (v->data[v->length] != '\0') {
- return default_value;
- }
- return (const char *)v->data;
-}
-
-struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
- TALLOC_CTX *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)
-{
- TYPESAFE_QSORT(msg->elements, msg->num_elements,
- ldb_msg_element_compare_name);
-}
-
-/*
- shallow copy a message - copying only the elements array so that the caller
- can safely add new elements without changing the message
-*/
-struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
- const struct ldb_message *msg)
-{
- struct ldb_message *msg2;
- unsigned int i;
-
- msg2 = talloc(mem_ctx, struct ldb_message);
- if (msg2 == NULL) return NULL;
-
- *msg2 = *msg;
-
- msg2->elements = talloc_array(msg2, struct ldb_message_element,
- msg2->num_elements);
- if (msg2->elements == NULL) goto failed;
-
- for (i=0;i<msg2->num_elements;i++) {
- msg2->elements[i] = msg->elements[i];
- }
-
- return msg2;
-
-failed:
- talloc_free(msg2);
- return NULL;
-}
-
-
-/*
- copy a message, allocating new memory for all parts
-*/
-struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
- const struct ldb_message *msg)
-{
- struct ldb_message *msg2;
- unsigned int i, j;
-
- msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
- if (msg2 == NULL) return NULL;
-
- msg2->dn = ldb_dn_copy(msg2, msg2->dn);
- if (msg2->dn == NULL) goto failed;
-
- for (i=0;i<msg2->num_elements;i++) {
- struct ldb_message_element *el = &msg2->elements[i];
- struct ldb_val *values = el->values;
- el->name = talloc_strdup(msg2->elements, el->name);
- if (el->name == NULL) goto failed;
- el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
- for (j=0;j<el->num_values;j++) {
- el->values[j] = ldb_val_dup(el->values, &values[j]);
- if (el->values[j].data == NULL && values[j].length != 0) {
- goto failed;
- }
- }
- }
-
- return msg2;
-
-failed:
- talloc_free(msg2);
- return NULL;
-}
-
-
-/**
- * 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 ret;
- struct ldb_message *msg2;
-
- /*
- * Preserve previous behavior and allocate
- * *msg2 into *ldb context
- */
- ret = ldb_msg_normalize(ldb, ldb, msg, &msg2);
- if (ret != LDB_SUCCESS) {
- return NULL;
- }
-
- return msg2;
-}
-
-/**
- * Canonicalize a message, merging elements of the same name
- */
-int ldb_msg_normalize(struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- const struct ldb_message *msg,
- 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; 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->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+1) < msg2->num_elements) {
- memmove(el2, el2+1, sizeof(struct ldb_message_element) *
- (msg2->num_elements - (i+1)));
- }
- msg2->num_elements--;
- i--;
- }
- }
-
- *_msg_out = msg2;
- return LDB_SUCCESS;
-}
-
-
-/**
- * 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
- */
-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;
-
- ldb_ret = ldb_msg_difference(ldb, ldb, msg1, msg2, &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_difference(struct ldb_context *ldb,
- TALLOC_CTX *mem_ctx,
- struct ldb_message *msg1,
- struct ldb_message *msg2,
- 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(temp_ctx);
- if (mod == NULL) {
- goto failed;
- }
-
- mod->dn = msg1->dn;
- mod->num_elements = 0;
- mod->elements = 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_normalize(ldb, mod, msg2, &msg2);
- if (ldb_res != LDB_SUCCESS) {
- goto failed;
- }
-
- /* look in msg2 to find elements that need to be added or modified */
- for (i=0;i<msg2->num_elements;i++) {
- el = ldb_msg_find_element(msg1, msg2->elements[i].name);
-
- if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
- continue;
- }
-
- 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;i<msg1->num_elements;i++) {
- el = ldb_msg_find_element(msg2, msg1->elements[i].name);
- 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;
- }
- }
- }
-
- /* 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(struct ldb_context *ldb,
- const struct ldb_message *msg)
-{
- unsigned int i, j;
-
- /* basic check on DN */
- if (msg->dn == NULL) {
- ldb_set_errstring(ldb, "ldb message lacks a DN!");
- return LDB_ERR_INVALID_DN_SYNTAX;
- }
-
- /* 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) {
- /* an attribute cannot be empty */
- ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
- msg->elements[i].name,
- ldb_dn_get_linearized(msg->dn));
- return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
- }
- }
- }
-
- return LDB_SUCCESS;
-}
-
-
-
-
-/*
- copy an attribute list. This only copies the array, not the elements
- (ie. the elements are left as the same pointers)
-*/
-const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
-{
- const char **ret;
- 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 && attrs[i];i++) {
- ret[i] = attrs[i];
- }
- ret[i] = attrs[i];
- return ret;
-}
-
-
-/*
- 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)
-{
- unsigned int i;
- for (i=0;attrs && attrs[i];i++) {
- if (ldb_attr_cmp(attrs[i], attr) == 0) {
- return 1;
- }
- }
- return 0;
-}
-
-
-/*
- rename the specified attribute in a search result
-*/
-int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
-{
- struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
- if (el == NULL) {
- return LDB_SUCCESS;
- }
- el->name = talloc_strdup(msg->elements, replace);
- if (el->name == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- return LDB_SUCCESS;
-}
-
-
-/*
- copy the specified attribute in a search result to a new attribute
-*/
-int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
-{
- struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
- int ret;
-
- if (el == NULL) {
- return LDB_SUCCESS;
- }
- ret = ldb_msg_add(msg, el, 0);
- if (ret != LDB_SUCCESS) {
- return ret;
- }
- 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;
-
- while ((el = ldb_msg_find_element(msg, attr)) != NULL) {
- ldb_msg_remove_element(msg, el);
- }
-}
-
-/*
- 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 */
- 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 GeneralizedTime string to a time_t. Return 0 if unable to convert
-*/
-time_t ldb_string_to_time(const char *s)
-{
- struct tm tm;
-
- if (s == NULL) return 0;
-
- memset(&tm, 0, sizeof(tm));
- 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;
- }
- tm.tm_year -= 1900;
- tm.tm_mon -= 1;
-
- 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)
-{
- unsigned int i;
-
- for (i = 0; i < result->count; i++) {
- struct ldb_ldif ldif;
- fprintf(f, "# record %d\n", i+1);
- ldif.changetype = LDB_CHANGETYPE_NONE;
- ldif.msg = result->msgs[i];
- ldb_ldif_write_file(ldb, f, &ldif);
- }
-}
-
-/*
- 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;
-}
-
diff --git a/source4/lib/ldb/common/ldb_options.c b/source4/lib/ldb/common/ldb_options.c
deleted file mode 100644
index f07f393562..0000000000
--- a/source4/lib/ldb/common/ldb_options.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2010
-
- ** 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 options[] handling
- *
- * Author: Andrew Tridgell
- */
-
-#include "ldb_private.h"
-
-/*
- find an option within an options array
-
- accepts the following forms:
-
- NAME
- NAME:value
- NAME=value
-
- returns a pointer into an element of the options[] array, or NULL is
- not found.
-
- For the NAME form, returns a pointer to an empty string (thus
- allowing for boolean options).
- */
-const char *ldb_options_find(struct ldb_context *ldb, const char *options[],
- const char *option_name)
-{
- size_t len = strlen(option_name);
- int i;
-
- if (options == NULL) {
- return NULL;
- }
-
- for (i=0; options[i]; i++) {
- if (strncmp(option_name, options[i], len) != 0) {
- continue;
- }
- if (options[i][len] == ':' || options[i][len] == '=') {
- return &options[i][len+1];
- }
- if (options[i][len] == 0) {
- return &options[i][len];
- }
- }
-
- return NULL;
-}
diff --git a/source4/lib/ldb/common/ldb_parse.c b/source4/lib/ldb/common/ldb_parse.c
deleted file mode 100644
index b4eabf8375..0000000000
--- a/source4/lib/ldb/common/ldb_parse.c
+++ /dev/null
@@ -1,903 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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 expression parsing
- *
- * Description: parse LDAP-like search expressions
- *
- * Author: Andrew Tridgell
- */
-
-/*
- TODO:
- - add RFC2254 binary string handling
- - possibly add ~=, <= and >= handling
- - expand the test suite
- - add better parse error handling
-
-*/
-
-#include "ldb_private.h"
-#include "system/locale.h"
-
-static int ldb_parse_hex2char(const char *x)
-{
- if (isxdigit(x[0]) && isxdigit(x[1])) {
- const char h1 = x[0], h2 = x[1];
- int c = 0;
-
- if (h1 >= 'a') c = h1 - (int)'a' + 10;
- else if (h1 >= 'A') c = h1 - (int)'A' + 10;
- else if (h1 >= '0') c = h1 - (int)'0';
- c = c << 4;
- if (h2 >= 'a') c += h2 - (int)'a' + 10;
- else if (h2 >= 'A') c += h2 - (int)'A' + 10;
- else if (h2 >= '0') c += h2 - (int)'0';
-
- return c;
- }
-
- return -1;
-}
-
-/*
-a filter is defined by:
- <filter> ::= '(' <filtercomp> ')'
- <filtercomp> ::= <and> | <or> | <not> | <simple>
- <and> ::= '&' <filterlist>
- <or> ::= '|' <filterlist>
- <not> ::= '!' <filter>
- <filterlist> ::= <filter> | <filter> <filterlist>
- <simple> ::= <attributetype> <filtertype> <attributevalue>
- <filtertype> ::= '=' | '~=' | '<=' | '>='
-*/
-
-/*
- decode a RFC2254 binary string representation of a buffer.
- Used in LDAP filters.
-*/
-struct ldb_val ldb_binary_decode(TALLOC_CTX *mem_ctx, const char *str)
-{
- size_t i, j;
- struct ldb_val ret;
- size_t slen = str?strlen(str):0;
-
- ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
- ret.length = 0;
- if (ret.data == NULL) return ret;
-
- for (i=j=0;i<slen;i++) {
- if (str[i] == '\\') {
- int c;
-
- c = ldb_parse_hex2char(&str[i+1]);
- if (c == -1) {
- talloc_free(ret.data);
- memset(&ret, 0, sizeof(ret));
- return ret;
- }
- ((uint8_t *)ret.data)[j++] = c;
- i += 2;
- } else {
- ((uint8_t *)ret.data)[j++] = str[i];
- }
- }
- ret.length = j;
- ((uint8_t *)ret.data)[j] = 0;
-
- return ret;
-}
-
-
-/*
- encode a blob as a RFC2254 binary string, escaping any
- non-printable or '\' characters
-*/
-char *ldb_binary_encode(TALLOC_CTX *mem_ctx, struct ldb_val val)
-{
- size_t i;
- char *ret;
- size_t len = val.length;
- unsigned char *buf = val.data;
-
- for (i=0;i<val.length;i++) {
- if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
- len += 2;
- }
- }
- ret = talloc_array(mem_ctx, char, len+1);
- if (ret == NULL) return NULL;
-
- len = 0;
- for (i=0;i<val.length;i++) {
- if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
- snprintf(ret+len, 4, "\\%02X", buf[i]);
- len += 3;
- } else {
- ret[len++] = buf[i];
- }
- }
-
- ret[len] = 0;
-
- return ret;
-}
-
-/*
- encode a string as a RFC2254 binary string, escaping any
- non-printable or '\' characters. This routine is suitable for use
- in escaping user data in ldap filters.
-*/
-char *ldb_binary_encode_string(TALLOC_CTX *mem_ctx, const char *string)
-{
- struct ldb_val val;
- if (string == NULL) {
- return NULL;
- }
- val.data = discard_const_p(uint8_t, string);
- val.length = strlen(string);
- return ldb_binary_encode(mem_ctx, val);
-}
-
-/* find the first matching wildcard */
-static char *ldb_parse_find_wildcard(char *value)
-{
- while (*value) {
- value = strpbrk(value, "\\*");
- if (value == NULL) return NULL;
-
- if (value[0] == '\\') {
- if (value[1] == '\0') return NULL;
- value += 2;
- continue;
- }
-
- if (value[0] == '*') return value;
- }
-
- return NULL;
-}
-
-/* return a NULL terminated list of binary strings representing the value
- chunks separated by wildcards that makes the value portion of the filter
-*/
-static struct ldb_val **ldb_wildcard_decode(TALLOC_CTX *mem_ctx, const char *string)
-{
- struct ldb_val **ret = NULL;
- unsigned int val = 0;
- char *wc, *str;
-
- wc = talloc_strdup(mem_ctx, string);
- if (wc == NULL) return NULL;
-
- while (wc && *wc) {
- str = wc;
- wc = ldb_parse_find_wildcard(str);
- if (wc && *wc) {
- if (wc == str) {
- wc++;
- continue;
- }
- *wc = 0;
- wc++;
- }
-
- ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
- if (ret == NULL) return NULL;
-
- ret[val] = talloc(mem_ctx, struct ldb_val);
- if (ret[val] == NULL) return NULL;
-
- *(ret[val]) = ldb_binary_decode(mem_ctx, str);
- if ((ret[val])->data == NULL) return NULL;
-
- val++;
- }
-
- if (ret != NULL) {
- ret[val] = NULL;
- }
-
- return ret;
-}
-
-static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s);
-
-
-/*
- parse an extended match
-
- possible forms:
- (attr:oid:=value)
- (attr:dn:oid:=value)
- (attr:dn:=value)
- (:dn:oid:=value)
-
- the ':dn' part sets the dnAttributes boolean if present
- the oid sets the rule_id string
-
-*/
-static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
- char *attr, char *value)
-{
- char *p1, *p2;
-
- ret->operation = LDB_OP_EXTENDED;
- ret->u.extended.value = ldb_binary_decode(ret, value);
- if (ret->u.extended.value.data == NULL) goto failed;
-
- p1 = strchr(attr, ':');
- if (p1 == NULL) goto failed;
- p2 = strchr(p1+1, ':');
-
- *p1 = 0;
- if (p2) *p2 = 0;
-
- ret->u.extended.attr = attr;
- if (strcmp(p1+1, "dn") == 0) {
- ret->u.extended.dnAttributes = 1;
- if (p2) {
- ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
- if (ret->u.extended.rule_id == NULL) goto failed;
- } else {
- ret->u.extended.rule_id = NULL;
- }
- } else {
- ret->u.extended.dnAttributes = 0;
- ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
- if (ret->u.extended.rule_id == NULL) goto failed;
- }
-
- return ret;
-
-failed:
- talloc_free(ret);
- return NULL;
-}
-
-static enum ldb_parse_op ldb_parse_filtertype(TALLOC_CTX *mem_ctx, char **type, char **value, const char **s)
-{
- enum ldb_parse_op filter = 0;
- char *name, *val, *k;
- const char *p = *s;
- const char *t, *t1;
-
- /* retrieve attributetype name */
- t = p;
-
- if (*p == '@') { /* for internal attributes the first char can be @ */
- p++;
- }
-
- while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-') || (*p == '.')) {
- /* attribute names can only be alphanums */
- p++;
- }
-
- if (*p == ':') { /* but extended searches have : and . chars too */
- p = strstr(p, ":=");
- if (p == NULL) { /* malformed attribute name */
- return 0;
- }
- }
-
- t1 = p;
-
- while (isspace((unsigned char)*p)) p++;
-
- if (!strchr("=<>~:", *p)) {
- return 0;
- }
-
- /* save name */
- name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
- if (name == NULL) return 0;
- name[t1 - t] = '\0';
-
- /* retrieve filtertype */
-
- if (*p == '=') {
- filter = LDB_OP_EQUALITY;
- } else if (*(p + 1) == '=') {
- switch (*p) {
- case '<':
- filter = LDB_OP_LESS;
- p++;
- break;
- case '>':
- filter = LDB_OP_GREATER;
- p++;
- break;
- case '~':
- filter = LDB_OP_APPROX;
- p++;
- break;
- case ':':
- filter = LDB_OP_EXTENDED;
- p++;
- break;
- }
- }
- if (!filter) {
- talloc_free(name);
- return filter;
- }
- p++;
-
- while (isspace((unsigned char)*p)) p++;
-
- /* retrieve value */
- t = p;
-
- while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
-
- val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
- if (val == NULL) {
- talloc_free(name);
- return 0;
- }
- val[p - t] = '\0';
-
- k = &(val[p - t]);
-
- /* remove trailing spaces from value */
- while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
- *k = '\0';
-
- *type = name;
- *value = val;
- *s = p;
- return filter;
-}
-
-/*
- <simple> ::= <attributetype> <filtertype> <attributevalue>
-*/
-static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char **s)
-{
- char *attr, *value;
- struct ldb_parse_tree *ret;
- enum ldb_parse_op filtertype;
-
- ret = talloc(mem_ctx, struct ldb_parse_tree);
- if (!ret) {
- errno = ENOMEM;
- return NULL;
- }
-
- filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
- if (!filtertype) {
- talloc_free(ret);
- return NULL;
- }
-
- switch (filtertype) {
-
- case LDB_OP_PRESENT:
- ret->operation = LDB_OP_PRESENT;
- ret->u.present.attr = attr;
- break;
-
- case LDB_OP_EQUALITY:
-
- if (strcmp(value, "*") == 0) {
- ret->operation = LDB_OP_PRESENT;
- ret->u.present.attr = attr;
- break;
- }
-
- if (ldb_parse_find_wildcard(value) != NULL) {
- ret->operation = LDB_OP_SUBSTRING;
- ret->u.substring.attr = attr;
- ret->u.substring.start_with_wildcard = 0;
- ret->u.substring.end_with_wildcard = 0;
- ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
- if (ret->u.substring.chunks == NULL){
- talloc_free(ret);
- return NULL;
- }
- if (value[0] == '*')
- ret->u.substring.start_with_wildcard = 1;
- if (value[strlen(value) - 1] == '*')
- ret->u.substring.end_with_wildcard = 1;
- talloc_free(value);
-
- break;
- }
-
- ret->operation = LDB_OP_EQUALITY;
- ret->u.equality.attr = attr;
- ret->u.equality.value = ldb_binary_decode(ret, value);
- if (ret->u.equality.value.data == NULL) {
- talloc_free(ret);
- return NULL;
- }
- talloc_free(value);
- break;
-
- case LDB_OP_GREATER:
- ret->operation = LDB_OP_GREATER;
- ret->u.comparison.attr = attr;
- ret->u.comparison.value = ldb_binary_decode(ret, value);
- if (ret->u.comparison.value.data == NULL) {
- talloc_free(ret);
- return NULL;
- }
- talloc_free(value);
- break;
-
- case LDB_OP_LESS:
- ret->operation = LDB_OP_LESS;
- ret->u.comparison.attr = attr;
- ret->u.comparison.value = ldb_binary_decode(ret, value);
- if (ret->u.comparison.value.data == NULL) {
- talloc_free(ret);
- return NULL;
- }
- talloc_free(value);
- break;
-
- case LDB_OP_APPROX:
- ret->operation = LDB_OP_APPROX;
- ret->u.comparison.attr = attr;
- ret->u.comparison.value = ldb_binary_decode(ret, value);
- if (ret->u.comparison.value.data == NULL) {
- talloc_free(ret);
- return NULL;
- }
- talloc_free(value);
- break;
-
- case LDB_OP_EXTENDED:
-
- ret = ldb_parse_extended(ret, attr, value);
- break;
-
- default:
- talloc_free(ret);
- return NULL;
- }
-
- return ret;
-}
-
-
-/*
- parse a filterlist
- <and> ::= '&' <filterlist>
- <or> ::= '|' <filterlist>
- <filterlist> ::= <filter> | <filter> <filterlist>
-*/
-static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const char **s)
-{
- struct ldb_parse_tree *ret, *next;
- enum ldb_parse_op op;
- const char *p = *s;
-
- switch (*p) {
- case '&':
- op = LDB_OP_AND;
- break;
- case '|':
- op = LDB_OP_OR;
- break;
- default:
- return NULL;
- }
- p++;
-
- while (isspace((unsigned char)*p)) p++;
-
- ret = talloc(mem_ctx, struct ldb_parse_tree);
- if (!ret) {
- errno = ENOMEM;
- return NULL;
- }
-
- ret->operation = op;
- ret->u.list.num_elements = 1;
- ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
- if (!ret->u.list.elements) {
- errno = ENOMEM;
- talloc_free(ret);
- return NULL;
- }
-
- ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
- if (!ret->u.list.elements[0]) {
- talloc_free(ret);
- return NULL;
- }
-
- while (isspace((unsigned char)*p)) p++;
-
- while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) {
- struct ldb_parse_tree **e;
- e = talloc_realloc(ret, ret->u.list.elements,
- struct ldb_parse_tree *,
- ret->u.list.num_elements + 1);
- if (!e) {
- errno = ENOMEM;
- talloc_free(ret);
- return NULL;
- }
- ret->u.list.elements = e;
- ret->u.list.elements[ret->u.list.num_elements] = next;
- ret->u.list.num_elements++;
- while (isspace((unsigned char)*p)) p++;
- }
-
- *s = p;
-
- return ret;
-}
-
-
-/*
- <not> ::= '!' <filter>
-*/
-static struct ldb_parse_tree *ldb_parse_not(TALLOC_CTX *mem_ctx, const char **s)
-{
- struct ldb_parse_tree *ret;
- const char *p = *s;
-
- if (*p != '!') {
- return NULL;
- }
- p++;
-
- ret = talloc(mem_ctx, struct ldb_parse_tree);
- if (!ret) {
- errno = ENOMEM;
- return NULL;
- }
-
- ret->operation = LDB_OP_NOT;
- ret->u.isnot.child = ldb_parse_filter(ret, &p);
- if (!ret->u.isnot.child) {
- talloc_free(ret);
- return NULL;
- }
-
- *s = p;
-
- return ret;
-}
-
-/*
- parse a filtercomp
- <filtercomp> ::= <and> | <or> | <not> | <simple>
-*/
-static struct ldb_parse_tree *ldb_parse_filtercomp(TALLOC_CTX *mem_ctx, const char **s)
-{
- struct ldb_parse_tree *ret;
- const char *p = *s;
-
- while (isspace((unsigned char)*p)) p++;
-
- switch (*p) {
- case '&':
- ret = ldb_parse_filterlist(mem_ctx, &p);
- break;
-
- case '|':
- ret = ldb_parse_filterlist(mem_ctx, &p);
- break;
-
- case '!':
- ret = ldb_parse_not(mem_ctx, &p);
- break;
-
- case '(':
- case ')':
- return NULL;
-
- default:
- ret = ldb_parse_simple(mem_ctx, &p);
-
- }
-
- *s = p;
- return ret;
-}
-
-
-/*
- <filter> ::= '(' <filtercomp> ')'
-*/
-static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s)
-{
- struct ldb_parse_tree *ret;
- const char *p = *s;
-
- if (*p != '(') {
- return NULL;
- }
- p++;
-
- ret = ldb_parse_filtercomp(mem_ctx, &p);
-
- if (*p != ')') {
- return NULL;
- }
- p++;
-
- while (isspace((unsigned char)*p)) {
- p++;
- }
-
- *s = p;
-
- return ret;
-}
-
-
-/*
- main parser entry point. Takes a search string and returns a parse tree
-
- expression ::= <simple> | <filter>
-*/
-struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s)
-{
- if (s == NULL || *s == 0) {
- s = "(|(objectClass=*)(distinguishedName=*))";
- }
-
- while (isspace((unsigned char)*s)) s++;
-
- if (*s == '(') {
- return ldb_parse_filter(mem_ctx, &s);
- }
-
- return ldb_parse_simple(mem_ctx, &s);
-}
-
-
-/*
- construct a ldap parse filter given a parse tree
-*/
-char *ldb_filter_from_tree(TALLOC_CTX *mem_ctx, const struct ldb_parse_tree *tree)
-{
- char *s, *s2, *ret;
- unsigned int i;
-
- if (tree == NULL) {
- return NULL;
- }
-
- switch (tree->operation) {
- case LDB_OP_AND:
- case LDB_OP_OR:
- ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
- if (ret == NULL) return NULL;
- for (i=0;i<tree->u.list.num_elements;i++) {
- s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
- if (s == NULL) {
- talloc_free(ret);
- return NULL;
- }
- s2 = talloc_asprintf_append(ret, "%s", s);
- talloc_free(s);
- if (s2 == NULL) {
- talloc_free(ret);
- return NULL;
- }
- ret = s2;
- }
- s = talloc_asprintf_append(ret, ")");
- if (s == NULL) {
- talloc_free(ret);
- return NULL;
- }
- return s;
- case LDB_OP_NOT:
- s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
- if (s == NULL) return NULL;
-
- ret = talloc_asprintf(mem_ctx, "(!%s)", s);
- talloc_free(s);
- return ret;
- case LDB_OP_EQUALITY:
- s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
- if (s == NULL) return NULL;
- ret = talloc_asprintf(mem_ctx, "(%s=%s)",
- tree->u.equality.attr, s);
- talloc_free(s);
- return ret;
- case LDB_OP_SUBSTRING:
- ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
- tree->u.substring.start_with_wildcard?"*":"");
- if (ret == NULL) return NULL;
- for (i = 0; tree->u.substring.chunks[i]; i++) {
- s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
- if (s2 == NULL) {
- talloc_free(ret);
- return NULL;
- }
- if (tree->u.substring.chunks[i+1] ||
- tree->u.substring.end_with_wildcard) {
- s = talloc_asprintf_append(ret, "%s*", s2);
- } else {
- s = talloc_asprintf_append(ret, "%s", s2);
- }
- if (s == NULL) {
- talloc_free(ret);
- return NULL;
- }
- ret = s;
- }
- s = talloc_asprintf_append(ret, ")");
- if (s == NULL) {
- talloc_free(ret);
- return NULL;
- }
- ret = s;
- return ret;
- case LDB_OP_GREATER:
- s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
- if (s == NULL) return NULL;
- ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
- tree->u.equality.attr, s);
- talloc_free(s);
- return ret;
- case LDB_OP_LESS:
- s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
- if (s == NULL) return NULL;
- ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
- tree->u.equality.attr, s);
- talloc_free(s);
- return ret;
- case LDB_OP_PRESENT:
- ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
- return ret;
- case LDB_OP_APPROX:
- s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
- if (s == NULL) return NULL;
- ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
- tree->u.equality.attr, s);
- talloc_free(s);
- return ret;
- case LDB_OP_EXTENDED:
- s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
- if (s == NULL) return NULL;
- ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
- tree->u.extended.attr?tree->u.extended.attr:"",
- tree->u.extended.dnAttributes?":dn":"",
- tree->u.extended.rule_id?":":"",
- tree->u.extended.rule_id?tree->u.extended.rule_id:"",
- s);
- talloc_free(s);
- return ret;
- }
-
- return NULL;
-}
-
-
-/*
- replace any occurrences of an attribute name in the parse tree with a
- new name
-*/
-void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
- const char *attr,
- const char *replace)
-{
- unsigned int i;
- switch (tree->operation) {
- case LDB_OP_AND:
- case LDB_OP_OR:
- for (i=0;i<tree->u.list.num_elements;i++) {
- ldb_parse_tree_attr_replace(tree->u.list.elements[i],
- attr, replace);
- }
- break;
- case LDB_OP_NOT:
- ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace);
- break;
- case LDB_OP_EQUALITY:
- case LDB_OP_GREATER:
- case LDB_OP_LESS:
- case LDB_OP_APPROX:
- if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
- tree->u.equality.attr = replace;
- }
- break;
- case LDB_OP_SUBSTRING:
- if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
- tree->u.substring.attr = replace;
- }
- break;
- case LDB_OP_PRESENT:
- if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) {
- tree->u.present.attr = replace;
- }
- break;
- case LDB_OP_EXTENDED:
- if (tree->u.extended.attr &&
- ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
- tree->u.extended.attr = replace;
- }
- break;
- }
-}
-
-/*
- shallow copy a tree - copying only the elements array so that the caller
- can safely add new elements without changing the message
-*/
-struct ldb_parse_tree *ldb_parse_tree_copy_shallow(TALLOC_CTX *mem_ctx,
- const struct ldb_parse_tree *ot)
-{
- unsigned int i;
- struct ldb_parse_tree *nt;
-
- nt = talloc(mem_ctx, struct ldb_parse_tree);
- if (!nt) {
- return NULL;
- }
-
- *nt = *ot;
-
- switch (ot->operation) {
- case LDB_OP_AND:
- case LDB_OP_OR:
- nt->u.list.elements = talloc_array(nt, struct ldb_parse_tree *,
- ot->u.list.num_elements);
- if (!nt->u.list.elements) {
- talloc_free(nt);
- return NULL;
- }
-
- for (i=0;i<ot->u.list.num_elements;i++) {
- nt->u.list.elements[i] =
- ldb_parse_tree_copy_shallow(nt->u.list.elements,
- ot->u.list.elements[i]);
- if (!nt->u.list.elements[i]) {
- talloc_free(nt);
- return NULL;
- }
- }
- break;
- case LDB_OP_NOT:
- nt->u.isnot.child = ldb_parse_tree_copy_shallow(nt,
- ot->u.isnot.child);
- if (!nt->u.isnot.child) {
- talloc_free(nt);
- return NULL;
- }
- break;
- case LDB_OP_EQUALITY:
- case LDB_OP_GREATER:
- case LDB_OP_LESS:
- case LDB_OP_APPROX:
- case LDB_OP_SUBSTRING:
- case LDB_OP_PRESENT:
- case LDB_OP_EXTENDED:
- break;
- }
-
- return nt;
-}
diff --git a/source4/lib/ldb/common/ldb_utf8.c b/source4/lib/ldb/common/ldb_utf8.c
deleted file mode 100644
index 55d8f905d3..0000000000
--- a/source4/lib/ldb/common/ldb_utf8.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- ldb database library
-
- Copyright (C) Andrew Tridgell 2004
-
- ** 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 utf8 handling
- *
- * Description: case folding and case comparison for UTF8 strings
- *
- * Author: Andrew Tridgell
- */
-
-#include "ldb_private.h"
-#include "system/locale.h"
-
-
-/*
- this allow the user to pass in a caseless comparison
- function to handle utf8 caseless comparisons
- */
-void ldb_set_utf8_fns(struct ldb_context *ldb,
- void *context,
- char *(*casefold)(void *, void *, const char *, size_t))
-{
- if (context)
- ldb->utf8_fns.context = context;
- if (casefold)
- ldb->utf8_fns.casefold = casefold;
-}
-
-/*
- a simple case folding function
- NOTE: does not handle UTF8
-*/
-char *ldb_casefold_default(void *context, TALLOC_CTX *mem_ctx, const char *s, size_t n)
-{
- size_t i;
- char *ret = talloc_strndup(mem_ctx, s, n);
- if (!s) {
- errno = ENOMEM;
- return NULL;
- }
- for (i=0;ret[i];i++) {
- ret[i] = toupper((unsigned char)ret[i]);
- }
- return ret;
-}
-
-void ldb_set_utf8_default(struct ldb_context *ldb)
-{
- ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default);
-}
-
-char *ldb_casefold(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *s, size_t n)
-{
- return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s, n);
-}
-
-/*
- check the attribute name is valid according to rfc2251
- returns 1 if the name is ok
- */
-
-int ldb_valid_attr_name(const char *s)
-{
- size_t i;
-
- if (!s || !s[0])
- return 0;
-
- /* handle special ldb_tdb wildcard */
- if (strcmp(s, "*") == 0) return 1;
-
- for (i = 0; s[i]; i++) {
- if (! isascii(s[i])) {
- return 0;
- }
- if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */
- if (! (isalpha(s[i]) || (s[i] == '@'))) {
- return 0;
- }
- } else {
- if (! (isalnum(s[i]) || (s[i] == '-'))) {
- return 0;
- }
- }
- }
- return 1;
-}
-
-char *ldb_attr_casefold(TALLOC_CTX *mem_ctx, const char *s)
-{
- size_t i;
- char *ret = talloc_strdup(mem_ctx, s);
- if (!ret) {
- errno = ENOMEM;
- return NULL;
- }
- for (i = 0; ret[i]; i++) {
- ret[i] = toupper((unsigned char)ret[i]);
- }
- return ret;
-}
-
-/*
- we accept either 'dn' or 'distinguishedName' for a distinguishedName
-*/
-int ldb_attr_dn(const char *attr)
-{
- if (ldb_attr_cmp(attr, "dn") == 0 ||
- ldb_attr_cmp(attr, "distinguishedName") == 0) {
- return 0;
- }
- return -1;
-}
diff --git a/source4/lib/ldb/common/qsort.c b/source4/lib/ldb/common/qsort.c
deleted file mode 100644
index 1a0b886b8c..0000000000
--- a/source4/lib/ldb/common/qsort.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
-
- The GNU C 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.1 of the License, or (at your option) any later version.
-
- The GNU C 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 the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */
-
-/* If you consider tuning this algorithm, you should consult first:
- Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
- Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
-
-/* Modified to be used in samba4 by
- * Simo Sorce <idra@samba.org> 2005
- */
-
-#include "ldb_private.h"
-
-/* Byte-wise swap two items of size SIZE. */
-#define SWAP(a, b, size) \
- do \
- { \
- register size_t __size = (size); \
- register char *__a = (a), *__b = (b); \
- do \
- { \
- char __tmp = *__a; \
- *__a++ = *__b; \
- *__b++ = __tmp; \
- } while (--__size > 0); \
- } while (0)
-
-/* Discontinue quicksort algorithm when partition gets below this size.
- This particular magic number was chosen to work best on a Sun 4/260. */
-#define MAX_THRESH 4
-
-/* Stack node declarations used to store unfulfilled partition obligations. */
-typedef struct
- {
- char *lo;
- char *hi;
- } stack_node;
-
-/* The next 4 #defines implement a very fast in-line stack abstraction. */
-/* The stack needs log (total_elements) entries (we could even subtract
- log(MAX_THRESH)). Since total_elements has type size_t, we get as
- upper bound for log (total_elements):
- bits per byte (CHAR_BIT) * sizeof(size_t). */
-#ifndef CHAR_BIT
-#define CHAR_BIT 8
-#endif
-#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
-#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
-#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
-#define STACK_NOT_EMPTY (stack < top)
-
-
-/* Order size using quicksort. This implementation incorporates
- four optimizations discussed in Sedgewick:
-
- 1. Non-recursive, using an explicit stack of pointer that store the
- next array partition to sort. To save time, this maximum amount
- of space required to store an array of SIZE_MAX is allocated on the
- stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
- only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
- Pretty cheap, actually.
-
- 2. Chose the pivot element using a median-of-three decision tree.
- This reduces the probability of selecting a bad pivot value and
- eliminates certain extraneous comparisons.
-
- 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
- insertion sort to order the MAX_THRESH items within each partition.
- This is a big win, since insertion sort is faster for small, mostly
- sorted array segments.
-
- 4. The larger of the two sub-partitions is always pushed onto the
- stack first, with the algorithm then concentrating on the
- smaller partition. This *guarantees* no more than log (total_elems)
- stack size is needed (actually O(1) in this case)! */
-
-void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
- void *opaque, ldb_qsort_cmp_fn_t cmp)
-{
- register char *base_ptr = (char *) pbase;
-
- const size_t max_thresh = MAX_THRESH * size;
-
- if (total_elems == 0)
- /* Avoid lossage with unsigned arithmetic below. */
- return;
-
- if (total_elems > MAX_THRESH)
- {
- char *lo = base_ptr;
- char *hi = &lo[size * (total_elems - 1)];
- stack_node stack[STACK_SIZE];
- stack_node *top = stack;
-
- PUSH (NULL, NULL);
-
- while (STACK_NOT_EMPTY)
- {
- char *left_ptr;
- char *right_ptr;
-
- /* Select median value from among LO, MID, and HI. Rearrange
- LO and HI so the three values are sorted. This lowers the
- probability of picking a pathological pivot value and
- skips a comparison for both the LEFT_PTR and RIGHT_PTR in
- the while loops. */
-
- char *mid = lo + size * ((hi - lo) / size >> 1);
-
- if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
- SWAP (mid, lo, size);
- if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
- SWAP (mid, hi, size);
- else
- goto jump_over;
- if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
- SWAP (mid, lo, size);
- jump_over:;
-
- left_ptr = lo + size;
- right_ptr = hi - size;
-
- /* Here's the famous ``collapse the walls'' section of quicksort.
- Gotta like those tight inner loops! They are the main reason
- that this algorithm runs much faster than others. */
- do
- {
- while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
- left_ptr += size;
-
- while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
- right_ptr -= size;
-
- if (left_ptr < right_ptr)
- {
- SWAP (left_ptr, right_ptr, size);
- if (mid == left_ptr)
- mid = right_ptr;
- else if (mid == right_ptr)
- mid = left_ptr;
- left_ptr += size;
- right_ptr -= size;
- }
- else if (left_ptr == right_ptr)
- {
- left_ptr += size;
- right_ptr -= size;
- break;
- }
- }
- while (left_ptr <= right_ptr);
-
- /* Set up pointers for next iteration. First determine whether
- left and right partitions are below the threshold size. If so,
- ignore one or both. Otherwise, push the larger partition's
- bounds on the stack and continue sorting the smaller one. */
-
- if ((size_t) (right_ptr - lo) <= max_thresh)
- {
- if ((size_t) (hi - left_ptr) <= max_thresh)
- /* Ignore both small partitions. */
- POP (lo, hi);
- else
- /* Ignore small left partition. */
- lo = left_ptr;
- }
- else if ((size_t) (hi - left_ptr) <= max_thresh)
- /* Ignore small right partition. */
- hi = right_ptr;
- else if ((right_ptr - lo) > (hi - left_ptr))
- {
- /* Push larger left partition indices. */
- PUSH (lo, right_ptr);
- lo = left_ptr;
- }
- else
- {
- /* Push larger right partition indices. */
- PUSH (left_ptr, hi);
- hi = right_ptr;
- }
- }
- }
-
- /* Once the BASE_PTR array is partially sorted by quicksort the rest
- is completely sorted using insertion sort, since this is efficient
- for partitions below MAX_THRESH size. BASE_PTR points to the beginning
- of the array to sort, and END_PTR points at the very last element in
- the array (*not* one beyond it!). */
-
-#define min(x, y) ((x) < (y) ? (x) : (y))
-
- {
- char *const end_ptr = &base_ptr[size * (total_elems - 1)];
- char *tmp_ptr = base_ptr;
- char *thresh = min(end_ptr, base_ptr + max_thresh);
- register char *run_ptr;
-
- /* Find smallest element in first threshold and place it at the
- array's beginning. This is the smallest array element,
- and the operation speeds up insertion sort's inner loop. */
-
- for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
- if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
- tmp_ptr = run_ptr;
-
- if (tmp_ptr != base_ptr)
- SWAP (tmp_ptr, base_ptr, size);
-
- /* Insertion sort, running from left-hand-side up to right-hand-side. */
-
- run_ptr = base_ptr + size;
- while ((run_ptr += size) <= end_ptr)
- {
- tmp_ptr = run_ptr - size;
- while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
- tmp_ptr -= size;
-
- tmp_ptr += size;
- if (tmp_ptr != run_ptr)
- {
- char *trav;
-
- trav = run_ptr + size;
- while (--trav >= run_ptr)
- {
- char c = *trav;
- char *hi, *lo;
-
- for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
- *hi = *lo;
- *hi = c;
- }
- }
- }
- }
-}