diff options
31 files changed, 1810 insertions, 628 deletions
diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in index c27ecf68c8..a091b4832e 100644 --- a/source3/lib/ldb/Makefile.in +++ b/source3/lib/ldb/Makefile.in @@ -18,7 +18,7 @@ SLAPD = @SLAPD@ EXTRA_OBJ=@EXTRA_OBJ@ TESTS=test-tdb.sh @TESTS@ -CFLAGS=-I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ +CFLAGS=-g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ @POPT_CFLAGS@ -I@tallocdir@ -I@tdbdir@/include -I@libreplacedir@ \ -DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"@SHLIBEXT@\" -DUSE_MMAP=1 @CFLAGS@ @@ -41,6 +41,10 @@ MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/rdn_name.o \ $(MODDIR)/objectclass.o \ $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o +NSSDIR=nssldb +NSS_OBJ= $(NSSDIR)/ldb-nss.o $(NSSDIR)/ldb-pwd.o $(NSSDIR)/ldb-grp.o +NSS_LIB = lib/libnss_ldb.so.2 + OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) @TDBOBJ@ @TALLOCOBJ@ @POPTOBJ@ @LIBREPLACEOBJ@ $(EXTRA_OBJ) LDB_LIB = lib/libldb.a @@ -53,6 +57,13 @@ EXAMPLES = examples/ldbreader examples/ldifreader DIRS = lib bin common ldb_tdb ldb_ldap ldb_sqlite3 modules tools examples +default: all + +nss: nssdir all $(NSS_LIB) + +nssdir: + @mkdir -p $(NSSDIR) + all: showflags dirs $(OBJS) $(LDB_LIB) $(BINS) $(EXAMPLES) manpages showflags: @@ -72,6 +83,9 @@ lib/libldb.a: $(OBJS) ar -rv $@ $(OBJS) @-ranlib $@ +lib/libnss_ldb.so.2: $(NSS_OBJ) $(LIBS) + $(CC) -shared -Wl,-soname,libnss_ldb.so.2 -o lib/libnss_ldb.so.2 $(NSS_OBJ) $(OBJS) $(LIB_FLAGS) + bin/ldbadd: tools/ldbadd.o tools/cmdline.o $(LIBS) $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS) @@ -112,7 +126,7 @@ doxygen: clean: rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb* - rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) + rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) $(NSS_LIB) rm -f man/*.1 man/*.3 man/*.html rm -f $(EXAMPLES) rm -rf apidocs/ diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 7648abf795..9e0ee6ebca 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -522,7 +522,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req) Use talloc_free to free the ldb_message returned in 'res', if successful */ -static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct ldb_result *res; int n; @@ -532,12 +532,13 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld return LDB_ERR_OPERATIONS_ERROR; } - res = *((struct ldb_result **)context); + res = talloc_get_type(context, struct ldb_result); if (!res || !ares) { + ldb_set_errstring(ldb, "NULL res or ares in callback"); goto error; } - + switch (ares->type) { case LDB_REPLY_ENTRY: res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); @@ -564,19 +565,17 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld res->refs[n] = talloc_move(res->refs, &ares->referral); res->refs[n + 1] = NULL; + case LDB_REPLY_EXTENDED: case LDB_REPLY_DONE: - /* Should do something here to detect if this never - * happens */ + /* TODO: we should really support controls on entries and referrals too! */ + res->controls = talloc_move(res, &ares->controls); break; } - talloc_steal(res, ares->controls); talloc_free(ares); return LDB_SUCCESS; error: talloc_free(ares); - talloc_free(res); - *((struct ldb_result **)context) = NULL; return LDB_ERR_OPERATIONS_ERROR; } @@ -752,16 +751,19 @@ int ldb_search(struct ldb_context *ldb, enum ldb_scope scope, const char *expression, const char * const *attrs, - struct ldb_result **res) + 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) { + res = talloc_zero(ldb, struct ldb_result); + if (!res) { return LDB_ERR_OPERATIONS_ERROR; } - + ret = ldb_build_search_req(&req, ldb, ldb, base?base:ldb_get_default_basedn(ldb), scope, @@ -769,7 +771,7 @@ int ldb_search(struct ldb_context *ldb, attrs, NULL, res, - ldb_search_callback); + ldb_search_default_callback); if (ret != LDB_SUCCESS) goto done; @@ -785,10 +787,10 @@ int ldb_search(struct ldb_context *ldb, done: if (ret != LDB_SUCCESS) { - talloc_free(*res); - *res = NULL; + talloc_free(res); } + *_res = res; return ret; } diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index e937a2b7fc..48f471bf6f 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -41,6 +41,19 @@ #define LDB_SPECIAL "@SPECIAL" +/** + internal ldb exploded dn structures +*/ +struct ldb_dn_component { + char *name; + struct ldb_val value; +}; + +struct ldb_dn { + int comp_num; + struct ldb_dn_component *components; +}; + int ldb_dn_is_special(const struct ldb_dn *dn) { if (dn == NULL || dn->comp_num != 1) return 0; @@ -688,6 +701,26 @@ static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_d return dst; } +/* Copy a DN but replace the old with the new base DN. */ +struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base) +{ + struct ldb_dn *new_dn; + int i, offset; + + /* Perhaps we don't need to rebase at all? */ + if (!old_base || !new_base) { + return ldb_dn_copy(mem_ctx, old); + } + + offset = old->comp_num - old_base->comp_num; + new_dn = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); + for (i = 0; i < offset; i++) { + new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &(old->components[i])); + } + + return new_dn; +} + /* copy specified number of elements of a dn into a new one element are copied from top level up to the unique rdn num_el may be greater than dn->comp_num (see ldb_dn_make_child) @@ -799,15 +832,6 @@ failed: } -struct ldb_dn *ldb_dn_make_child(void *mem_ctx, const struct ldb_dn_component *component, - const struct ldb_dn *base) -{ - if (component == NULL) return NULL; - - return ldb_dn_build_child(mem_ctx, component->name, - (char *)component->value.data, base); -} - struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2) { int i; @@ -872,28 +896,6 @@ struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, c return dn; } -struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn) -{ - struct ldb_dn_component *rdn; - - if (dn == NULL) return NULL; - - if (dn->comp_num < 1) { - return NULL; - } - - rdn = talloc(mem_ctx, struct ldb_dn_component); - if (rdn == NULL) return NULL; - - *rdn = ldb_dn_copy_component(mem_ctx, &dn->components[0]); - if (rdn->name == NULL) { - talloc_free(rdn); - return NULL; - } - - return rdn; -} - /* Create a 'canonical name' string from a DN: ie dc=samba,dc=org -> samba.org/ @@ -962,3 +964,58 @@ char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn) { char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn) { return ldb_dn_canonical(mem_ctx, dn, 1); } + +int ldb_dn_get_comp_num(const struct ldb_dn *dn) +{ + return dn->comp_num; +} + +const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num) +{ + if (num >= dn->comp_num) return NULL; + return dn->components[num].name; +} + +const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num) +{ + if (num >= dn->comp_num) return NULL; + return &dn->components[num].value; +} + +const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn) { + if (dn->comp_num == 0) return NULL; + return dn->components[0].name; +} + +const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn) { + 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 (num >= dn->comp_num) { + return LDB_ERR_OTHER; + } + + n = talloc_strdup(dn, name); + if ( ! n) { + return LDB_ERR_OTHER; + } + + v.length = val.length; + v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1); + if ( ! v.data) { + return LDB_ERR_OTHER; + } + + talloc_free(dn->components[num].name); + talloc_free(dn->components[num].value.data); + dn->components[num].name = n; + dn->components[num].value = v; + + return LDB_SUCCESS; +} diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c index 1fd12da7f3..0cd220ad60 100644 --- a/source3/lib/ldb/common/ldb_match.c +++ b/source3/lib/ldb/common/ldb_match.c @@ -58,7 +58,7 @@ static int ldb_match_scope(struct ldb_context *ldb, break; case LDB_SCOPE_ONELEVEL: - if (dn->comp_num == (base->comp_num + 1)) { + if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) { if (ldb_dn_compare_base(ldb, base, dn) == 0) { ret = 1; } diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 8bcafa36a8..a6997b324a 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -159,6 +159,7 @@ static const struct ldb_module_ops *ldb_find_module_ops(const char *name) ldb_objectclass_init, \ ldb_paged_results_init, \ ldb_sort_init, \ + ldb_asq_init, \ NULL \ } #endif @@ -205,17 +206,26 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) char *path; void *handle; int (*init_fn) (void); + char *modulesdir; #ifdef HAVE_DLOPEN + if (getenv("LD_LDB_MODULE_PATH") != NULL) { + modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH")); + } else { #ifdef _SAMBA_BUILD_ - path = talloc_asprintf(ldb, "%s/ldb/%s.%s", dyn_MODULESDIR, name, dyn_SHLIBEXT); + modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR); #else - path = talloc_asprintf(ldb, "%s/%s.%s", MODULESDIR, name, SHLIBEXT); + modulesdir = talloc_strdup(ldb, MODULESDIR); #endif + } + + path = talloc_asprintf(ldb, "%s/%s.%s", modulesdir, name, SHLIBEXT); + + talloc_free(modulesdir); ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path); - handle = dlopen(path, 0); + handle = dlopen(path, RTLD_NOW); if (handle == NULL) { ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror()); return -1; diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 46ab721e2e..9cb4cf5ed0 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -119,10 +119,10 @@ struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v) /* add an empty element 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 ldb_msg_add_empty( struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el) { struct ldb_message_element *els; diff --git a/source3/lib/ldb/config.mk b/source3/lib/ldb/config.mk index 4e3ba273d6..cd80adf721 100644 --- a/source3/lib/ldb/config.mk +++ b/source3/lib/ldb/config.mk @@ -167,7 +167,9 @@ OBJ_FILES = \ common/ldb_controls.o \ common/qsort.o PUBLIC_DEPENDENCIES = \ - LIBTALLOC + LIBTALLOC \ + DYNCONFIG \ + SOCKET_WRAPPER MANPAGE = man/ldb.3 PUBLIC_HEADERS = include/ldb.h include/ldb_errors.h # diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 2c332b2f9d..17a2ec7556 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -3,7 +3,7 @@ Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2004 - Copyright (C) Simo Sorce 2005 + Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -86,18 +86,9 @@ struct ldb_val { #endif /*! \endcond */ -/** - internal ldb exploded dn structures -*/ -struct ldb_dn_component { - char *name; - struct ldb_val value; -}; - -struct ldb_dn { - int comp_num; - struct ldb_dn_component *components; -}; +/* opaque ldb_dn structures, see ldb_dn.c for internals */ +struct ldb_dn_component; +struct ldb_dn; /** There are a number of flags that are used with ldap_modify() in @@ -193,12 +184,6 @@ enum ldb_scope {LDB_SCOPE_DEFAULT=-1, struct ldb_context; -/* - the fuction type for the callback used in traversing the database -*/ -typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *); - - /* debugging uses one of the following levels */ enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, LDB_DEBUG_WARNING, LDB_DEBUG_TRACE}; @@ -333,22 +318,25 @@ char *ldb_binary_encode_string(void *mem_ctx, const char *string); typedef int (*ldb_attr_handler_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, struct ldb_val *); typedef int (*ldb_attr_comparison_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, const struct ldb_val *); +/* + attribute handler structure + + attr -> The attribute name + flags -> LDB_ATTR_FLAG_* + ldif_read_fn -> convert from ldif to binary format + ldif_write_fn -> convert from binary to ldif format + canonicalise_fn -> canonicalise a value, for use by indexing and dn construction + comparison_fn -> compare two values +*/ + struct ldb_attrib_handler { - const char *attr; - /* LDB_ATTR_FLAG_* */ + const char *attr; unsigned flags; - /* convert from ldif to binary format */ ldb_attr_handler_t ldif_read_fn; - - /* convert from binary to ldif format */ ldb_attr_handler_t ldif_write_fn; - - /* canonicalise a value, for use by indexing and dn construction */ ldb_attr_handler_t canonicalise_fn; - - /* compare two values */ ldb_attr_comparison_t comparison_fn; }; @@ -839,6 +827,145 @@ int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, co */ const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); + +/** + The Default iasync search callback function + + \param ldb the context associated with the database (from ldb_init()) + \param context the callback context + \param ares a single reply from the async core + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note this function expects the context to always be an struct ldb_result pointer + AND a talloc context, this function will steal on the context each message + from the ares reply passed on by the async core so that in the end all the + messages will be in the context (ldb_result) memory tree. + Freeing the passed context (ldb_result tree) will free all the resources + (the request need to be freed separately and the result doe not depend on the + request that can be freed as sson as the search request is finished) +*/ + +int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares); + +/** + Helper function to build a search request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) + \param scope the search scope for the query + \param expression the search expression to use for this query + \param attrs the search attributes for the query (pass NULL if none required) + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_search_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const 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); + +/** + Helper function to build an add request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param message contains the entry to be added + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_add_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a modify request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param message contains the entry to be modified + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_mod_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a delete request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param dn the DN to be deleted + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_del_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *dn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a rename request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param olddn the old DN + \param newdn the new DN + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_rename_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *olddn, + const struct ldb_dn *newdn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + /** Search the database @@ -846,7 +973,7 @@ const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); records that match an LDAP-like search expression \param ldb the context associated with the database (from ldb_init()) - \param base the Base Distinguished Name for the query (pass NULL for root DN) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) \param scope the search scope for the query \param expression the search expression to use for this query \param attrs the search attributes for the query (pass NULL if none required) @@ -1156,18 +1283,25 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const str struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn); struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el); struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base); struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn); struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr, const char *val); struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, const char * value, const struct ldb_dn *base); -struct ldb_dn *ldb_dn_make_child(void *mem_ctx, - const struct ldb_dn_component *component, - const struct ldb_dn *base); struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2); struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) PRINTF_ATTRIBUTE(3,4); -struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn); +char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn); +char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn); +int ldb_dn_get_comp_num(const struct ldb_dn *dn); +const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num); +const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num); +const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn); +const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn); +int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val); + + /* useful functions for ldb_message structure manipulation */ int ldb_dn_cmp(struct ldb_context *ldb, const char *dn1, const char *dn2); @@ -1228,9 +1362,9 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, add a new empty element to a ldb_message */ int ldb_msg_add_empty(struct ldb_message *msg, - const char *attr_name, - int flags, - struct ldb_message_element **return_el); + const char *attr_name, + int flags, + struct ldb_message_element **return_el); /** add a element to a ldb_message @@ -1239,9 +1373,9 @@ int ldb_msg_add(struct ldb_message *msg, const struct ldb_message_element *el, int flags); int ldb_msg_add_value(struct ldb_message *msg, - const char *attr_name, - const struct ldb_val *val, - struct ldb_message_element **return_el); + const char *attr_name, + const struct ldb_val *val, + struct ldb_message_element **return_el); int ldb_msg_add_steal_value(struct ldb_message *msg, const char *attr_name, struct ldb_val *val); @@ -1407,9 +1541,6 @@ char *ldb_timestring(void *mem_ctx, time_t t); */ time_t ldb_string_to_time(const char *s); -char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn); -char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn); - void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp); #endif diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index 3cacd5e292..3902bb2fc2 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -170,6 +170,7 @@ int ldb_operational_init(void); int ldb_paged_results_init(void); int ldb_rdn_name_init(void); int ldb_schema_init(void); +int ldb_asq_init(void); int ldb_sort_init(void); int ldb_ldap_init(void); int ldb_ildap_init(void); diff --git a/source3/lib/ldb/ldb.pc.in b/source3/lib/ldb/ldb.pc.in index 8b0536e21e..815d663a7c 100644 --- a/source3/lib/ldb/ldb.pc.in +++ b/source3/lib/ldb/ldb.pc.in @@ -7,6 +7,9 @@ modulesdir=@modulesdir@ Name: ldb Description: An LDAP-like embedded database Version: 4.0 -Libs: @LIBS@ -L${libdir} -lldb +Requires.private: tdb +Requires: talloc +Libs: -L${libdir} -lldb Cflags: -I${includedir} @CFLAGS@ Modulesdir: ${modulesdir} +URL: http://ldb.samba.org/ diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 3843d2b825..51ae031cf9 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -49,6 +49,7 @@ #include "libcli/ldap/ldap.h" #include "libcli/ldap/ldap_client.h" #include "auth/auth.h" +#include "auth/credentials/credentials.h" struct ildb_private { struct ldap_connection *ldap; @@ -639,8 +640,8 @@ static int ildb_rename(struct ldb_module *module, struct ldb_request *req) msg->r.ModifyDNRequest.newrdn = talloc_asprintf(msg, "%s=%s", - req->op.rename.newdn->components[0].name, - ldb_dn_escape_value(msg, req->op.rename.newdn->components[0].value)); + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn))); if (msg->r.ModifyDNRequest.newrdn == NULL) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index a17e80cde0..cdc1a500f8 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -463,8 +463,8 @@ static int lldb_rename(struct ldb_module *module, struct ldb_request *req) } newrdn = talloc_asprintf(lldb_ac, "%s=%s", - req->op.rename.newdn->components[0].name, - ldb_dn_escape_value(lldb, req->op.rename.newdn->components[0].value)); + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(lldb, *(ldb_dn_get_rdn_val(req->op.rename.newdn)))); if (!newrdn) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8dd25db1d6..4f9b0f6370 100644 --- a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Derrell Lipman 2005 - Copyright (C) Simo Sorce 2005 + Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -57,9 +57,9 @@ struct lsql_context { int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; -static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, + struct ldb_module *module, + struct ldb_request *req) { struct lsql_context *ac; struct ldb_handle *h; @@ -85,8 +85,8 @@ static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct h->status = LDB_SUCCESS; ac->module = module; - ac->context = context; - ac->callback = callback; + ac->context = req->context; + ac->callback = req->callback; return h; } @@ -370,6 +370,7 @@ static char *parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ char *cdn = ldb_dn_linearize_casefold(module->ldb, + mem_ctx, ldb_dn_explode(module->ldb, (const char *)value.data)); @@ -828,7 +829,7 @@ static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn return -1; } - cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, dn)); + cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, local_ctx, dn)); if (!cdn) goto done; eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); @@ -842,53 +843,8 @@ done: * Interface functions referenced by lsqlite3_ops */ -static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct ldb_result *res = NULL; - - if (!context) { - ldb_set_errstring(ldb, "NULL Context in callback"); - goto error; - } - - res = *((struct ldb_result **)context); - - if (!res || !ares) { - goto error; - } - - if (ares->type == LDB_REPLY_ENTRY) { - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); - if (! res->msgs) { - goto error; - } - - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_move(res->msgs, &ares->message); - res->count++; - } else { - ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); - goto error; - } - - talloc_free(ares); - return LDB_SUCCESS; - -error: - if (ares) talloc_free(ares); - if (res) talloc_free(res); - if (context) *((struct ldb_result **)context) = NULL; - return LDB_ERR_OPERATIONS_ERROR; -} - /* search for matching records, by tree */ -int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +int lsql_search(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; @@ -898,32 +854,29 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, char *query = NULL; int ret; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - talloc_free(*handle); + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); - if (base) { - norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); + if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; + + if (req->op.search.base) { + norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.search.base)); if (norm_basedn == NULL) { ret = LDB_ERR_INVALID_DN_SYNTAX; goto failed; } } else norm_basedn = talloc_strdup(lsql_ac, ""); - if (*norm_basedn == '\0' && - (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { - ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; - } - /* Convert filter into a series of SQL conditions (constraints) */ - sqlfilter = parsetree_to_sql(module, lsql_ac, tree); + sqlfilter = parsetree_to_sql(module, lsql_ac, req->op.search.tree); - switch(scope) { + switch(req->op.search.scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: if (*norm_basedn != '\0') { @@ -1033,12 +986,12 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, / * */ lsql_ac->current_eid = 0; - lsql_ac->attrs = attrs; + lsql_ac->attrs = req->op.search.attrs; lsql_ac->ares = NULL; - (*handle)->state = LDB_ASYNC_PENDING; + req->handle->state = LDB_ASYNC_PENDING; - ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, req->handle, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { ldb_set_errstring(module->ldb, errmsg); @@ -1053,70 +1006,39 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, if (lsql_ac->ares->message == NULL) goto failed; - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); - if ((*handle)->status != LDB_SUCCESS) + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if (req->handle->status != LDB_SUCCESS) goto failed; } - (*handle)->state = LDB_ASYNC_DONE; + req->handle->state = LDB_ASYNC_DONE; return LDB_SUCCESS; failed: - talloc_free(*handle); return LDB_ERR_OPERATIONS_ERROR; } -static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* base, - enum ldb_scope scope, struct ldb_parse_tree * tree, - const char * const * attrs, struct ldb_result ** res) -{ - struct ldb_handle *handle; - int ret; - - *res = talloc_zero(module, struct ldb_result); - if (! *res) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = lsql_search_async(module, base, scope, tree, attrs, - res, &lsql_search_sync_callback, - &handle); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(handle, LDB_WAIT_ALL); - talloc_free(handle); - } - - if (ret != LDB_SUCCESS) { - talloc_free(*res); - } - - return ret; -} - /* add a record */ -static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_add(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.add.message; long long eid; char *dn, *ndn; char *errmsg; char *query; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1126,26 +1048,28 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } /* c = ldb_dn_explode(local_ctx, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" - goto failed; + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } */ - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } /* create linearized and normalized dns */ dn = ldb_dn_linearize(lsql_ac, msg->dn); - ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, msg->dn)); + ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, msg->dn)); if (dn == NULL || ndn == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1156,7 +1080,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, dn, ndn); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1166,13 +1090,13 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1185,7 +1109,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1199,7 +1123,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } insert = lsqlite3_tprintf(lsql_ac, @@ -1211,7 +1135,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, el->values[j].data, value.data); if (insert == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); @@ -1221,58 +1145,38 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_add_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } - /* modify a record */ -static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_modify(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.mod.message; long long eid; char *errmsg; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1282,17 +1186,18 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } eid = lsqlite3_get_eid(module, msg->dn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1307,7 +1212,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1324,7 +1229,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1334,7 +1239,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } /* MISSING break is INTENTIONAL */ @@ -1349,7 +1254,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1362,7 +1267,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1372,7 +1277,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1388,7 +1293,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1398,7 +1303,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1410,7 +1315,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1422,7 +1327,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1432,7 +1337,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1440,57 +1345,37 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_modify_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* delete a record */ -static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_delete(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; long long eid; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; - eid = lsqlite3_get_eid(module, dn); + eid = lsqlite3_get_eid(module, req->op.del.dn); if (eid == -1) { - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1501,7 +1386,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, eid, eid); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1510,68 +1395,43 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, ldb_set_errstring(module->ldb, errmsg); free(errmsg); } - ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + req->handle->status = LDB_ERR_OPERATIONS_ERROR; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(dn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_delete_async(module, dn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); + +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* rename a record */ -static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_rename(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; char *new_dn, *new_cdn, *old_cdn; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* create linearized and normalized dns */ - old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, olddn)); - new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, newdn)); - new_dn = ldb_dn_linearize(lsql_ac, newdn); + old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.olddn)); + new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.newdn)); + new_dn = ldb_dn_linearize(lsql_ac, req->op.rename.newdn); if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { - goto failed; + goto done; } /* build the SQL query */ @@ -1580,7 +1440,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old "WHERE norm_dn = '%q';", new_dn, new_cdn, old_cdn); if (query == NULL) { - goto failed; + goto done; } /* execute */ @@ -1591,38 +1451,15 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old free(errmsg); } ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_rename_async(module, olddn, newdn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } @@ -1687,6 +1524,41 @@ static int lsql_del_trans(struct ldb_module *module) return -1; } +static int destructor(struct lsqlite3_private *lsqlite3) +{ + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} + +static int lsql_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .search = lsql_search, + .add = lsql_add, + .modify = lsql_modify, + .del = lsql_delete, + .rename = lsql_rename, + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .wait = lsql_wait, +}; + /* * Static functions */ @@ -1796,12 +1668,12 @@ static int initialize(struct lsqlite3_private *lsqlite3, " ('TOP', '0001');"); /* Skip protocol indicator of url */ - if (strncmp(url, "sqlite://", 9) != 0) { + if (strncmp(url, "sqlite3://", 10) != 0) { return SQLITE_MISUSE; } /* Update pointer to just after the protocol indicator */ - url += 9; + url += 10; /* Try to open the (possibly empty/non-existent) database */ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { @@ -1959,112 +1831,6 @@ failed: return -1; } -static int destructor(struct lsqlite3_private *lsqlite3) -{ - if (lsqlite3->sqlite) { - sqlite3_close(lsqlite3->sqlite); - } - return 0; -} - -static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - return handle->status; -} - -static int lsql_request(struct ldb_module *module, struct ldb_request *req) -{ - /* check for oustanding critical controls and return an error if found */ - - if (req->controls != NULL) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_sqlite3 backend!\n"); - } - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - switch (req->operation) { - - case LDB_SEARCH: - return lsql_search_bytree(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - &req->op.search.res); - - case LDB_ADD: - return lsql_add(module, req->op.add.message); - - case LDB_MODIFY: - return lsql_modify(module, req->op.mod.message); - - case LDB_DELETE: - return lsql_delete(module, req->op.del.dn); - - case LDB_RENAME: - return lsql_rename(module, - req->op.rename.olddn, - req->op.rename.newdn); - - case LDB_SEARCH: - return lsql_search_async(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - req->context, - req->callback, - &req->handle); -/* - case LDB_ADD: - return lsql_add_async(module, - req->op.add.message, - req->context, - req->callback, - &req->handle); - - case LDB_MODIFY: - return lsql_modify_async(module, - req->op.mod.message, - req->context, - req->callback, - &req->handle); -*/ - case LDB_DELETE: - return lsql_delete_async(module, - req->op.del.dn, - req->context, - req->callback, - &req->handle); - - case LDB_RENAME: - return lsql_rename_async(module, - req->op.rename.olddn, - req->op.rename.newdn, - req->context, - req->callback, - &req->handle); - - default: - return LDB_ERR_OPERATIONS_ERROR; - - } -} - -/* - * Table of operations for the sqlite3 backend - */ -static const struct ldb_module_ops lsqlite3_ops = { - .name = "sqlite", - .request = lsql_request, - .start_transaction = lsql_start_trans, - .end_transaction = lsql_end_trans, - .del_transaction = lsql_del_trans, - .wait = lsql_wait, -}; - /* * connect to the database */ diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index 4b76c437b6..884eccd362 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -464,7 +464,7 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) struct ldb_reply *ares; int ret; - if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) && (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) return LDB_ERR_OPERATIONS_ERROR; diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 354bbf2bc8..2fed6aac50 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -454,8 +454,7 @@ static int asq_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Unable to register control with rootdse!\n"); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n"); } return ldb_next_init(module); diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index 1cdeeeb293..32e64f3eb2 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -181,60 +181,16 @@ BOOL map_check_local_db(struct ldb_module *module) return True; } -/* WARK: verbatim copy from ldb_dn.c */ -static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) -{ - struct ldb_dn_component dst; - - memset(&dst, 0, sizeof(dst)); - - if (src == NULL) { - return dst; - } - - dst.value = ldb_val_dup(mem_ctx, &(src->value)); - if (dst.value.data == NULL) { - return dst; - } - - dst.name = talloc_strdup(mem_ctx, src->name); - if (dst.name == NULL) { - talloc_free(dst.value.data); - } - - return dst; -} - -/* Copy a DN but replace the old with the new base DN. */ -static struct ldb_dn *ldb_dn_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base) -{ - struct ldb_dn *new; - int i, offset; - - /* Perhaps we don't need to rebase at all? */ - if (!old_base || !new_base) { - return ldb_dn_copy(mem_ctx, old); - } - - offset = old->comp_num - old_base->comp_num; - new = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); - for (i = 0; i < offset; i++) { - new->components[i] = ldb_dn_copy_component(new->components, &(old->components[i])); - } - - return new; -} - /* Copy a DN with the base DN of the local partition. */ static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) { - return ldb_dn_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn); + return ldb_dn_copy_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn); } /* Copy a DN with the base DN of the remote partition. */ static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) { - return ldb_dn_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn); + return ldb_dn_copy_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn); } /* Run a request and make sure it targets the remote partition. */ @@ -460,23 +416,23 @@ int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attr * ================== */ /* Map an ldb value into the remote partition. */ -struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) { - return map->u.convert.convert_local(module, mem_ctx, &val); + return map->u.convert.convert_local(module, mem_ctx, val); } - return ldb_val_dup(mem_ctx, &val); + return ldb_val_dup(mem_ctx, val); } /* Map an ldb value back into the local partition. */ -struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) { - return map->u.convert.convert_remote(module, mem_ctx, &val); + return map->u.convert.convert_remote(module, mem_ctx, val); } - return ldb_val_dup(mem_ctx, &val); + return ldb_val_dup(mem_ctx, val); } @@ -500,10 +456,11 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const { const struct ldb_map_context *data = map_get_context(module); struct ldb_dn *newdn; - struct ldb_dn_component *old, *new; const struct ldb_map_attribute *map; enum ldb_map_attr_type map_type; - int i; + const char *name; + struct ldb_val value; + int i, ret; if (dn == NULL) { return NULL; @@ -516,10 +473,8 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const } /* For each RDN, map the component name and possibly the value */ - for (i = 0; i < newdn->comp_num; i++) { - old = &dn->components[i]; - new = &newdn->components[i]; - map = map_attr_find_local(data, old->name); + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i)); /* Unknown attribute - leave this RDN as is and hope the best... */ if (map == NULL) { @@ -533,21 +488,30 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const case MAP_GENERATE: ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "MAP_IGNORE/MAP_GENERATE attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; case MAP_CONVERT: if (map->u.convert.convert_local == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "'convert_local' not set for attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; } /* fall through */ case MAP_KEEP: case MAP_RENAME: - new->name = discard_const_p(char, map_attr_map_local(newdn->components, map, old->name)); - new->value = ldb_val_map_local(module, newdn->components, map, old->value); + name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + break; } } @@ -564,10 +528,11 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const { const struct ldb_map_context *data = map_get_context(module); struct ldb_dn *newdn; - struct ldb_dn_component *old, *new; const struct ldb_map_attribute *map; enum ldb_map_attr_type map_type; - int i; + const char *name; + struct ldb_val value; + int i, ret; if (dn == NULL) { return NULL; @@ -580,10 +545,8 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const } /* For each RDN, map the component name and possibly the value */ - for (i = 0; i < newdn->comp_num; i++) { - old = &dn->components[i]; - new = &newdn->components[i]; - map = map_attr_find_remote(data, old->name); + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i)); /* Unknown attribute - leave this RDN as is and hope the best... */ if (map == NULL) { @@ -597,21 +560,30 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const case MAP_GENERATE: ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "MAP_IGNORE/MAP_GENERATE attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; case MAP_CONVERT: if (map->u.convert.convert_remote == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "'convert_remote' not set for attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; } /* fall through */ case MAP_KEEP: case MAP_RENAME: - new->name = discard_const_p(char, map_attr_map_remote(newdn->components, map, old->name)); - new->value = ldb_val_map_remote(module, newdn->components, map, old->value); + name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + break; } } @@ -1296,13 +1268,13 @@ static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data } /* Copy the list of provided module operations. */ -struct ldb_module_ops ldb_map_get_ops(void) +_PUBLIC_ struct ldb_module_ops ldb_map_get_ops(void) { return map_ops; } /* Initialize global private data. */ -int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, +_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char * const *wildcard_attributes, const char *name) diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c index b83a17e502..38454b2b11 100644 --- a/source3/lib/ldb/modules/ldb_map_inbound.c +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -56,7 +56,7 @@ static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *modul el->name = map_attr_map_local(el, map, old->name); for (i = 0; i < el->num_values; i++) { - el->values[i] = ldb_val_map_local(module, el->values, map, old->values[i]); + el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]); } return el; diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index ff3b5c3aa2..dc213f36d1 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -195,6 +195,7 @@ static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_ele if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) { return -1; } + talloc_free(old->name); } /* copy new element */ @@ -234,7 +235,7 @@ static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *modu el->name = map_attr_map_remote(el, map, old->name); for (i = 0; i < el->num_values; i++) { - el->values[i] = ldb_val_map_remote(module, el->values, map, old->values[i]); + el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]); } return el; @@ -728,21 +729,21 @@ int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, *new = NULL; return 0; } - *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, *tree->u.substring.chunks[i]); + *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]); (*new)->u.substring.chunks[i+1] = NULL; } break; } case LDB_OP_EQUALITY: - (*new)->u.equality.value = ldb_val_map_local(module, *new, map, tree->u.equality.value); + (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value); break; case LDB_OP_LESS: case LDB_OP_GREATER: case LDB_OP_APPROX: - (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, tree->u.comparison.value); + (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value); break; case LDB_OP_EXTENDED: - (*new)->u.extended.value = ldb_val_map_local(module, *new, map, tree->u.extended.value); + (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value); (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id); break; default: /* unknown kind of simple subtree */ diff --git a/source3/lib/ldb/modules/ldb_map_private.h b/source3/lib/ldb/modules/ldb_map_private.h index 7fb2745179..ae53ebbdd4 100644 --- a/source3/lib/ldb/modules/ldb_map_private.h +++ b/source3/lib/ldb/modules/ldb_map_private.h @@ -77,8 +77,8 @@ const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *ma const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr); int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs); -struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val); -struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val); +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c index 3ab575ef6b..c4b1ecf26b 100644 --- a/source3/lib/ldb/modules/paged_results.c +++ b/source3/lib/ldb/modules/paged_results.c @@ -544,9 +544,7 @@ static int paged_request_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "paged_request: Unable to register control with rootdse!\n"); - talloc_free(req); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n"); } talloc_free(req); diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c index 510a43dbc9..bab5f6a014 100644 --- a/source3/lib/ldb/modules/rdn_name.c +++ b/source3/lib/ldb/modules/rdn_name.c @@ -58,7 +58,8 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) struct ldb_request *down_req; struct ldb_message *msg; struct ldb_message_element *attribute; - struct ldb_dn_component *rdn; + const char *rdn_name; + struct ldb_val rdn_val; int i, ret; ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n"); @@ -80,43 +81,45 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - rdn = ldb_dn_get_rdn(msg, msg->dn); - if (rdn == NULL) { + rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (rdn_name == NULL) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn)); + /* Perhaps someone above us tried to set this? */ if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { attribute->num_values = 0; } - if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } - attribute = rdn_name_find_attribute(msg, rdn->name); + attribute = rdn_name_find_attribute(msg, rdn_name); if (!attribute) { - if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } } else { - const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn->name); + const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn_name); for (i = 0; i < attribute->num_values; i++) { - if (handler->comparison_fn(module->ldb, msg, &rdn->value, &attribute->values[i]) == 0) { + if (handler->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) { /* overwrite so it matches in case */ - attribute->values[i] = rdn->value; + attribute->values[i] = rdn_val; break; } } if (i == attribute->num_values) { ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, - "RDN mismatch on %s: %s", - ldb_dn_linearize(msg, msg->dn), rdn->name); + "RDN mismatch on %s: %s (%s)", + ldb_dn_linearize(msg, msg->dn), rdn_name, rdn_val.data); talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } @@ -190,16 +193,12 @@ static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) static int rdn_name_rename_do_mod(struct ldb_handle *h) { struct rename_context *ac; - struct ldb_dn_component *rdn; + const char *rdn_name; + struct ldb_val rdn_val; struct ldb_message *msg; ac = talloc_get_type(h->private_data, struct rename_context); - rdn = ldb_dn_get_rdn(ac, ac->orig_req->op.rename.newdn); - if (rdn == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ac->mod_req = talloc_zero(ac, struct ldb_request); ac->mod_req->operation = LDB_MODIFY; @@ -213,16 +212,23 @@ static int rdn_name_rename_do_mod(struct ldb_handle *h) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { + rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn); + if (rdn_name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn)); + + if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c index 3a0598c528..4fa03f8bfa 100644 --- a/source3/lib/ldb/modules/sort.c +++ b/source3/lib/ldb/modules/sort.c @@ -423,9 +423,7 @@ static int server_sort_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "server_sort: Unable to register control with rootdse!\n"); - talloc_free(req); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n"); } talloc_free(req); diff --git a/source3/lib/ldb/nssldb/README.txt b/source3/lib/ldb/nssldb/README.txt new file mode 100644 index 0000000000..ddba62b380 --- /dev/null +++ b/source3/lib/ldb/nssldb/README.txt @@ -0,0 +1,34 @@ + +This test code requires a tdb that is configured for to use the asq module. +You can do that adding the following record to a tdb: + +dn: @MODULES +@LIST: asq + +Other modules can be used as well (like rdn_name for example) + +The uidNumber 0 and the gidNumber 0 are considered invalid. + +The user records should contain the followin attributes: +uid (required) the user name +userPassword (optional) the user password (if not present "LDB" is + returned in the password field) +uidNumber (required) the user uid +gidNumber (required) the user primary gid +gecos (optional) the GECOS +homeDirectory (required) the home directory +loginShell (required) the login shell +memberOf (required) all the groups the user is member of should + be reported here using their DNs. The + primary group as well. + +The group accounts should contain the following attributes: +cn (required) the group name +uesrPassword (optional) the group password (if not present "LDB" is + returned in the password field) +gidNumber (required) the group gid +member (optional) the DNs of the member users, also the ones + that have this group as primary + + +SSS diff --git a/source3/lib/ldb/nssldb/ldb-grp.c b/source3/lib/ldb/nssldb/ldb-grp.c new file mode 100644 index 0000000000..f33ec65c55 --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-grp.c @@ -0,0 +1,427 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_gr_attrs[] = { + "cn", + "userPassword", + "gidNumber", + NULL +}; + +const char *_ldb_nss_mem_attrs[] = { + "uid", + NULL +}; + +#define _NSS_LDB_ENOMEM(amem) \ + do { \ + if ( ! amem) { \ + errno = ENOMEM; \ + talloc_free(memctx); \ + return NSS_STATUS_UNAVAIL; \ + } \ + } while(0) + +/* This setgrent, getgrent, endgrent is not very efficient */ + +NSS_STATUS _nss_ldb_setgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res != NULL) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_GRENT_FILTER, + _ldb_nss_gr_attrs, + &_ldb_nss_ctx->gr_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result); + if ( ! res) { + errno = *errnop = ENOMEM; + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return NSS_STATUS_UNAVAIL; + } + + ret = _ldb_nss_group_request(&res, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + talloc_free(res); + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return ret; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur], + res); + + talloc_free(res); + + if (ret != NSS_STATUS_SUCCESS) { + if (ret != NSS_STATUS_TRYAGAIN) { + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + } + return ret; + } + + /* this entry is ok, increment counter to nex entry */ + _ldb_nss_ctx->gr_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + if (gid == 0) { /* we don't serve root gid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop) +{ + int ret; + char *filter; + const char * attrs[] = { "uidNumber", "gidNumber", NULL }; + struct ldb_result *uid_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this name */ + filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + attrs, + &uid_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(mem_res, uid_res); + + /* if none found return */ + if (uid_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (uid_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + uid_res->msgs[0]->dn, + attrs, + "memberOf"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_initgr(group, + limit, + start, + size, + groups, + errnop, + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; + +done: + talloc_free(mem_res); + return ret; +} diff --git a/source3/lib/ldb/nssldb/ldb-nss.c b/source3/lib/ldb/nssldb/ldb-nss.c new file mode 100644 index 0000000000..614f6e170f --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-nss.c @@ -0,0 +1,402 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +struct _ldb_nss_context *_ldb_nss_ctx = NULL; + +NSS_STATUS _ldb_nss_init(void) +{ + int ret; + + pid_t mypid = getpid(); + + if (_ldb_nss_ctx != NULL) { + if (_ldb_nss_ctx->pid == mypid) { + /* already initialized */ + return NSS_STATUS_SUCCESS; + } else { + /* we are in a forked child now, reinitialize */ + talloc_free(_ldb_nss_ctx); + _ldb_nss_ctx = NULL; + } + } + + _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid); + if (_ldb_nss_ctx == NULL) { + return NSS_STATUS_UNAVAIL; + } + + _ldb_nss_ctx->pid = mypid; + + ret = ldb_global_init(); + if (ret != 0) { + goto failed; + } + + _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx); + if (_ldb_nss_ctx->ldb == NULL) { + goto failed; + } + + ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL); + if (ret != LDB_SUCCESS) { + goto failed; + } + + _ldb_nss_ctx->base = ldb_dn_explode(_ldb_nss_ctx, _LDB_NSS_BASEDN); + if (_ldb_nss_ctx->base == NULL) { + goto failed; + } + + _ldb_nss_ctx->pw_cur = 0; + _ldb_nss_ctx->pw_res = NULL; + _ldb_nss_ctx->gr_cur = 0; + _ldb_nss_ctx->gr_res = NULL; + + return NSS_STATUS_SUCCESS; + +failed: + /* talloc_free(_ldb_nss_ctx); */ + _ldb_nss_ctx = NULL; + return NSS_STATUS_UNAVAIL; +} + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg) +{ + int len; + int bufpos; + const char *tmp; + + bufpos = 0; + + /* get username */ + tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_passwd = &buffer[bufpos]; + bufpos += len; + + /* this backend never serves an uid 0 user */ + result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0); + if (result->pw_uid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0); + if (result->pw_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* get gecos */ + tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_gecos = &buffer[bufpos]; + bufpos += len; + + /* get homeDirectory */ + tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_dir = &buffer[bufpos]; + bufpos += len; + + /* get shell */ + tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_shell = &buffer[bufpos]; + bufpos += len; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members) +{ + const char *tmp; + size_t len; + size_t bufpos; + size_t lsize; + int i; + + bufpos = 0; + + /* get group name */ + tmp = ldb_msg_find_attr_as_string(group, "cn", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_passwd = &buffer[bufpos]; + bufpos += len; + + result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0); + if (result->gr_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* check if there is enough memory for the list of pointers */ + lsize = (members->count + 1) * sizeof(char *); + + /* align buffer on pointer boundary */ + bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*))); + if ((buflen - bufpos) < lsize) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + + result->gr_mem = (char **)&buffer[bufpos]; + bufpos += lsize; + + for (i = 0; i < members->count; i++) { + tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_mem[i] = &buffer[bufpos]; + bufpos += len; + } + + result->gr_mem[i] = NULL; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist) +{ + NSS_STATUS ret; + int i; + + for (i = 0; i < grlist->count; i++) { + + if (limit && (*start > limit)) { + /* TODO: warn no all groups were reported */ + *errnop = 0; + ret = NSS_STATUS_SUCCESS; + goto done; + } + + if (*start == *size) { + /* buffer full, enlarge it */ + long int gs; + gid_t *gm; + + gs = (*size) + 32; + if (limit && (gs > limit)) { + gs = limit; + } + + gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t)); + if ( ! gm) { + *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + *groups = gm; + *size = gs; + } + + (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0); + if ((*groups)[*start] == 0 || (*groups)[*start] == group) { + /* skip root group or primary group */ + continue; + } + (*start)++; + + } + + *errnop = 0; + ret = NSS_STATUS_SUCCESS; +done: + return ret; +} + +#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0) + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr) +{ + struct ldb_control **ctrls; + struct ldb_control *ctrl; + struct ldb_asq_control *asqc; + struct ldb_request *req; + int ret; + struct ldb_result *res = *_res; + + ctrls = talloc_array(res, struct ldb_control *, 2); + _LDB_NSS_ALLOC_CHECK(ctrls); + + ctrl = talloc(ctrls, struct ldb_control); + _LDB_NSS_ALLOC_CHECK(ctrl); + + asqc = talloc(ctrl, struct ldb_asq_control); + _LDB_NSS_ALLOC_CHECK(asqc); + + asqc->source_attribute = talloc_strdup(asqc, mattr); + _LDB_NSS_ALLOC_CHECK(asqc->source_attribute); + + asqc->request = 1; + asqc->src_attr_len = strlen(asqc->source_attribute); + ctrl->oid = LDB_CONTROL_ASQ_OID; + ctrl->critical = 1; + ctrl->data = asqc; + ctrls[0] = ctrl; + ctrls[1] = NULL; + + ret = ldb_build_search_req( + &req, + _ldb_nss_ctx->ldb, + res, + group_dn, + LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, + ctrls, + res, + ldb_search_default_callback); + + if (ret != LDB_SUCCESS) { + errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0); + + ret = ldb_request(_ldb_nss_ctx->ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } else { + talloc_free(req); + return NSS_STATUS_UNAVAIL; + } + + talloc_free(req); + return NSS_STATUS_SUCCESS; +} + diff --git a/source3/lib/ldb/nssldb/ldb-nss.h b/source3/lib/ldb/nssldb/ldb-nss.h new file mode 100644 index 0000000000..c780a21e81 --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-nss.h @@ -0,0 +1,86 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _LDB_NSS +#define _LDB_NSS + +#include "includes.h" +#include "ldb/include/includes.h" + +#include <nss.h> +#include <pwd.h> +#include <grp.h> + +#define _LDB_NSS_URL "etc/users.ldb" +#define _LDB_NSS_BASEDN "CN=Users,CN=System" +#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))" +#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))" +#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))" + +#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))" +#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))" +#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))" + +typedef enum nss_status NSS_STATUS; + +struct _ldb_nss_context { + + pid_t pid; + + struct ldb_context *ldb; + const struct ldb_dn *base; + + int pw_cur; + struct ldb_result *pw_res; + + int gr_cur; + struct ldb_result *gr_res; +}; + +NSS_STATUS _ldb_nss_init(void); + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg); + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members); + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist); + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr); + +#endif /* _LDB_NSS */ diff --git a/source3/lib/ldb/nssldb/ldb-pwd.c b/source3/lib/ldb/nssldb/ldb-pwd.c new file mode 100644 index 0000000000..e4bafdcf7c --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-pwd.c @@ -0,0 +1,241 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_pw_attrs[] = { + "uid", + "userPassword", + "uidNumber", + "gidNumber", + "gecos", + "homeDirectory", + "loginShell", + NULL +}; + +NSS_STATUS _nss_ldb_setpwent(void) +{ + int ret; + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res != NULL) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_PWENT_FILTER, + _ldb_nss_pw_attrs, + &_ldb_nss_ctx->pw_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endpwent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf, + char *buffer, + int buflen, + int *errnop) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + if (uid == 0) { /* we don't serve root uid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + +NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this name */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c index 46eac2295d..8abfb87238 100644 --- a/source3/lib/ldb/samba/ldif_handlers.c +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -80,10 +80,12 @@ static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx, static BOOL ldb_comparision_objectSid_isString(const struct ldb_val *v) { - /* see if the input if null-terninated */ - if (v->data[v->length] != '\0') return False; - + if (v->length < 3) { + return False; + } + if (strncmp("S-", (const char *)v->data, 2) != 0) return False; + return True; } @@ -179,11 +181,11 @@ static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v) struct GUID guid; NTSTATUS status; - /* see if the input if null-terninated */ - if (v->data[v->length] != '\0') return False; - if (v->length < 33) return False; + /* see if the input if null-terninated (safety check for the below) */ + if (v->data[v->length] != '\0') return False; + status = GUID_from_string((const char *)v->data, &guid); if (!NT_STATUS_IS_OK(status)) { return False; @@ -301,9 +303,9 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c dn1 = ldb_dn_explode(mem_ctx, (char *)in->data); if (dn1 == NULL) { oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length); - } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { - oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, - dn1->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn1); + oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { return -1; } @@ -326,9 +328,9 @@ static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx dn1 = ldb_dn_explode(mem_ctx, (char *)v1->data); if (dn1 == NULL) { oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length); - } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { - oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, - dn1->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn1); + oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { oc1 = NULL; } @@ -336,9 +338,9 @@ static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data); if (dn2 == NULL) { oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length); - } else if (dn2->comp_num >= 2 && strcasecmp(dn2->components[0].name, "cn") == 0) { - oc2 = talloc_strndup(mem_ctx, (char *)dn2->components[0].value.data, - dn2->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn2); + oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { oc2 = NULL; } diff --git a/source3/lib/ldb/standalone.sh b/source3/lib/ldb/standalone.sh new file mode 100755 index 0000000000..fa1b9bafe3 --- /dev/null +++ b/source3/lib/ldb/standalone.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +cd ../replace +make clean + +cd ../talloc +make clean + +cd ../tdb +make clean + +cd ../ldb +make clean + +./autogen.sh + +rm -fr build +mkdir build +cd build + +../configure $* +make dirs +make all + +cd .. diff --git a/source3/lib/ldb/tests/test-sqlite3.sh b/source3/lib/ldb/tests/test-sqlite3.sh index a51ae637dc..0cef318d98 100755 --- a/source3/lib/ldb/tests/test-sqlite3.sh +++ b/source3/lib/ldb/tests/test-sqlite3.sh @@ -1,20 +1,23 @@ #!/bin/sh -LDB_URL="sqlite://sqltest.ldb" +LDB_URL="sqlite3://sqltest.ldb" export LDB_URL -PATH=bin:$PATH -export PATH - rm -f sqltest.ldb if [ -z "$LDBDIR" ]; then - LDBDIR="." + LDBDIR=`dirname $0`/.. export LDBDIR fi -. $LDBDIR/tests/test-generic.sh +PATH=bin:$PATH +export PATH + +LDB_SPECIALS=0 +export LDB_SPECIALS + +$LDBDIR/tests/test-generic.sh #. $LDBDIR/tests/test-extended.sh diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index 09bb99c096..928519f3bb 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -29,6 +29,7 @@ #if (_SAMBA_BUILD_ >= 4) #include "lib/cmdline/popt_common.h" #include "lib/ldb/samba/ldif_handlers.h" +#include "auth/gensec/gensec.h" #include "auth/auth.h" #include "db_wrap.h" #endif |