wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
PROJECT_NAME = LDB
OUTPUT_DIRECTORY = apidocs
REPEAT_BRIEF = YES
OPTIMIZE_OUTPUT_FOR_C = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
GENERATE_TODOLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
SHOW_USED_FILES = NO
SHOW_DIRECTORIES = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
INPUT = include .
FILE_PATTERNS = *.h *.dox
EXCLUDE = include/config.h include/dlinklist.h \
include/includes.h
EXAMPLE_PATH = examples
GENERATE_HTML = YES
HTML_OUTPUT = html
GENERATE_MAN = YES
ALWAYS_DETAILED_SEC = YES
JAVADOC_AUTOBRIEF = YES
+173
View File
@@ -0,0 +1,173 @@
#!gmake
#
CC = @CC@
GCOV = @GCOV@
XSLTPROC = @XSLTPROC@
DOXYGEN = @DOXYGEN@
prefix = @prefix@
exec_prefix = @exec_prefix@
datarootdir = @datarootdir@
includedir = @includedir@
libdir = @libdir@
bindir = @bindir@
mandir = @mandir@
VPATH = @srcdir@:@tdbdir@:@tallocdir@:@libreplacedir@:@poptdir@
srcdir = @srcdir@
builddir = @builddir@
SLAPD = @SLAPD@
EXTRA_OBJ=@EXTRA_OBJ@
TESTS=test-tdb.sh @TESTS@
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@
LIB_FLAGS=@LDFLAGS@ -Llib -lldb @LIBS@ @POPT_LIBS@
LDB_TDB_DIR=ldb_tdb
LDB_TDB_OBJ=$(LDB_TDB_DIR)/ldb_tdb.o \
$(LDB_TDB_DIR)/ldb_pack.o $(LDB_TDB_DIR)/ldb_search.o $(LDB_TDB_DIR)/ldb_index.o \
$(LDB_TDB_DIR)/ldb_cache.o $(LDB_TDB_DIR)/ldb_tdb_wrap.o
COMDIR=common
COMMON_OBJ=$(COMDIR)/ldb.o $(COMDIR)/ldb_ldif.o \
$(COMDIR)/ldb_parse.o $(COMDIR)/ldb_msg.o $(COMDIR)/ldb_utf8.o \
$(COMDIR)/ldb_debug.o $(COMDIR)/ldb_modules.o \
$(COMDIR)/ldb_dn.o $(COMDIR)/ldb_match.o $(COMDIR)/ldb_attributes.o \
$(COMDIR)/attrib_handlers.o $(COMDIR)/ldb_controls.o $(COMDIR)/qsort.o
MODDIR=modules
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
BINS = bin/ldbadd bin/ldbsearch bin/ldbdel bin/ldbmodify bin/ldbedit bin/ldbrename bin/ldbtest bin/oLschema2ldif
LIBS = $(LDB_LIB)
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:
@echo 'ldb will be compiled with flags:'
@echo ' CFLAGS = $(CFLAGS)'
@echo ' LIBS = $(LIBS)'
.c.o:
@echo Compiling $*.c
@mkdir -p `dirname $@`
@$(CC) $(CFLAGS) -c $< -o $@
dirs:
@mkdir -p $(DIRS)
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)
bin/ldbsearch: tools/ldbsearch.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbsearch tools/ldbsearch.o tools/cmdline.o $(LIB_FLAGS)
bin/ldbdel: tools/ldbdel.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbdel tools/ldbdel.o tools/cmdline.o $(LIB_FLAGS)
bin/ldbmodify: tools/ldbmodify.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbmodify tools/ldbmodify.o tools/cmdline.o $(LIB_FLAGS)
bin/ldbedit: tools/ldbedit.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbedit tools/ldbedit.o tools/cmdline.o $(LIB_FLAGS)
bin/ldbrename: tools/ldbrename.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbrename tools/ldbrename.o tools/cmdline.o $(LIB_FLAGS)
bin/ldbtest: tools/ldbtest.o tools/cmdline.o $(LIBS)
$(CC) -o bin/ldbtest tools/ldbtest.o tools/cmdline.o $(LIB_FLAGS)
bin/oLschema2ldif: tools/oLschema2ldif.o tools/cmdline.o tools/convert.o $(LIBS)
$(CC) -o bin/oLschema2ldif tools/oLschema2ldif.o tools/cmdline.o tools/convert.o $(LIB_FLAGS)
examples/ldbreader: examples/ldbreader.o $(LIBS)
$(CC) -o examples/ldbreader examples/ldbreader.o $(LIB_FLAGS)
examples/ldifreader: examples/ldifreader.o $(LIBS)
$(CC) -o examples/ldifreader examples/ldifreader.o $(LIB_FLAGS)
.SUFFIXES: .1 .1.xml .3 .3.xml .xml .html
manpages:
@$(srcdir)/docs/builddocs.sh "$(XSLTPROC)" "$(srcdir)"
doxygen:
test -z "$(DOXYGEN)" || (cd $(srcdir) && "$(DOXYGEN)")
clean:
rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb*
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/
rm -rf tests/schema/
distclean: clean
rm -f *~ */*~
rm -rf bin lib
rm -f config.log config.status config.cache include/config.h
rm -f ldb.pc
rm -f Makefile
realdistclean: distclean
rm -f configure.in include/config.h.in
test: all
for t in $(TESTS); do echo STARTING $${t}; $(srcdir)/tests/$${t} || exit 1; done
valgrindtest: all
for t in $(TESTS); do echo STARTING $${t}; VALGRIND="valgrind -q --db-attach=yes --num-callers=30" $(srcdir)/tests/$${t} || exit 1; done
installcheck: install test
install: all
mkdir -p $(includedir) $(libdir)/pkgconfig $(libdir) $(bindir)
cp $(srcdir)/include/ldb.h $(srcdir)/include/ldb_errors.h $(includedir)
cp $(LDB_LIB) $(libdir)
cp $(BINS) $(bindir)
cp ldb.pc $(libdir)/pkgconfig
$(srcdir)/docs/installdocs.sh $(mandir)
gcov:
$(GCOV) -po ldb_sqlite3 $(srcdir)/ldb_sqlite3/*.c 2| tee ldb_sqlite3.report.gcov
$(GCOV) -po ldb_ldap $(srcdir)/ldb_ldap/*.c 2| tee ldb_ldap.report.gcov
$(GCOV) -po ldb_tdb $(srcdir)/ldb_tdb/*.c 2| tee ldb_tdb.report.gcov
$(GCOV) -po common $(srcdir)/common/*.c 2| tee common.report.gcov
$(GCOV) -po modules $(srcdir)/modules/*.c 2| tee modules.report.gcov
$(GCOV) -po tools $(srcdir)/tools/*.c 2| tee tools.report.gcov
etags:
etags `find $(srcdir) -name "*.[ch]"`
ctags:
ctags `find $(srcdir) -name "*.[ch]"`
+29
View File
@@ -0,0 +1,29 @@
Here is how to use gcov to test code coverage in ldb.
Step 1: build ldb with gcov enabled
make clean all WITH_GCOV=1
Step 3: run the test suite
make test-tdb
Step 4: produce the gcov report
make gcov
Step 5: read the summary reports
less *.report.gcov
Step 6: examine the per-file reports
less ldb_tdb\#ldb_tdb.c.gcov
You can also combine steps 2 to 4 like this:
make clean all test-tdb gcov WITH_GCOV=1
Note that you should not expect 100% coverage, as some error paths
(such as memory allocation failures) are very hard to trigger. There
are ways of working around this, but they are quite tricky (they
involve allocation wrappers that "fork and fail on malloc").
The lines to look for in the per-file reports are the ones starting
with "#####". Those are lines that are never executed.
+1
View File
@@ -0,0 +1 @@
m4_include(libreplace.m4)
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
rm -rf autom4te.cache
rm -f configure config.h.in
IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace"
IPATHS="$IPATHS -I lib/talloc -I talloc -I ../talloc"
IPATHS="$IPATHS -I lib/tdb -I tdb -I ../tdb"
IPATHS="$IPATHS -I lib/popt -I popt -I ../popt"
autoheader $IPATHS || exit 1
autoconf $IPATHS || exit 1
rm -rf autom4te.cache
echo "Now run ./configure and then make."
exit 0
@@ -0,0 +1,407 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
attribute handlers for well known attribute types, selected by syntax OID
see rfc2252
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
#include "ldb/include/ldb_handlers.h"
/*
default handler that just copies a ldb_val.
*/
int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
*out = ldb_val_dup(mem_ctx, in);
if (in->length > 0 && out->data == NULL) {
ldb_oom(ldb);
return -1;
}
return 0;
}
/*
a case folding copy handler, removing leading and trailing spaces and
multiple internal spaces
We exploit the fact that utf8 never uses the space octet except for
the space itself
*/
int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
char *s, *t;
int l;
if (!in || !out || !(in->data)) {
return -1;
}
out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
if (out->data == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
return -1;
}
s = (char *)(out->data);
/* remove trailing spaces if any */
l = strlen(s);
while (l > 0 && s[l - 1] == ' ') l--;
s[l] = '\0';
/* remove leading spaces if any */
if (*s == ' ') {
for (t = s; *s == ' '; s++) ;
/* remove leading spaces by moving down the string */
memmove(t, s, l);
s = t;
}
/* check middle spaces */
while ((t = strchr(s, ' ')) != NULL) {
for (s = t; *s == ' '; s++) ;
if ((s - t) > 1) {
l = strlen(s);
/* remove all spaces but one by moving down the string */
memmove(t + 1, s, l);
}
}
out->length = strlen((char *)out->data);
return 0;
}
/*
canonicalise a ldap Integer
rfc2252 specifies it should be in decimal form
*/
int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
char *end;
long long i = strtoll((char *)in->data, &end, 0);
if (*end != 0) {
return -1;
}
out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
if (out->data == NULL) {
return -1;
}
out->length = strlen((char *)out->data);
return 0;
}
/*
compare two Integers
*/
int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
}
/*
compare two binary blobs
*/
int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) {
return v1->length - v2->length;
}
return memcmp(v1->data, v2->data, v1->length);
}
/*
compare two case insensitive strings, ignoring multiple whitespaces
and leading and trailing whitespaces
see rfc2252 section 8.1
try to optimize for the ascii case,
but if we find out an utf8 codepoint revert to slower but correct function
*/
int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
const char *u1, *u2;
char *b1, *b2;
int ret;
while (*s1 == ' ') s1++;
while (*s2 == ' ') s2++;
/* TODO: make utf8 safe, possibly with helper function from application */
while (*s1 && *s2) {
/* the first 127 (0x7F) chars are ascii and utf8 guarantes they
* never appear in multibyte sequences */
if (((unsigned char)s1[0]) & 0x80) goto utf8str;
if (((unsigned char)s2[0]) & 0x80) goto utf8str;
if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
break;
if (*s1 == ' ') {
while (s1[0] == s1[1]) s1++;
while (s2[0] == s2[1]) s2++;
}
s1++; s2++;
}
if (! (*s1 && *s2)) {
/* check for trailing spaces only if one of the pointers
* has reached the end of the strings otherwise we
* can mistakenly match.
* ex. "domain users" <-> "domainUpdates"
*/
while (*s1 == ' ') s1++;
while (*s2 == ' ') s2++;
}
return (int)(toupper(*s1)) - (int)(toupper(*s2));
utf8str:
/* no need to recheck from the start, just from the first utf8 char found */
b1 = ldb_casefold(ldb, mem_ctx, s1);
b2 = ldb_casefold(ldb, mem_ctx, s2);
if (b1 && b2) {
/* Both strings converted correctly */
u1 = b1;
u2 = b2;
} else {
/* One of the strings was not UTF8, so we have no options but to do a binary compare */
u1 = s1;
u2 = s2;
}
while (*u1 & *u2) {
if (*u1 != *u2)
break;
if (*u1 == ' ') {
while (u1[0] == u1[1]) u1++;
while (u2[0] == u2[1]) u2++;
}
u1++; u2++;
}
if (! (*u1 && *u2)) {
while (*u1 == ' ') u1++;
while (*u2 == ' ') u2++;
}
ret = (int)(*u1 - *u2);
talloc_free(b1);
talloc_free(b2);
return ret;
}
/*
canonicalise a attribute in DN format
*/
int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct ldb_dn *dn;
int ret = -1;
out->length = 0;
out->data = NULL;
dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data);
if ( ! ldb_dn_validate(dn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
if (out->data == NULL) {
goto done;
}
out->length = strlen((char *)out->data);
ret = 0;
done:
talloc_free(dn);
return ret;
}
/*
compare two dns
*/
int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
int ret;
dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data);
if ( ! ldb_dn_validate(dn1)) return -1;
dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data);
if ( ! ldb_dn_validate(dn2)) {
talloc_free(dn1);
return -1;
}
ret = ldb_dn_compare(dn1, dn2);
talloc_free(dn1);
talloc_free(dn2);
return ret;
}
/*
compare two objectclasses, looking at subclasses
*/
int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
int ret, i;
const char **subclasses;
ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
if (ret == 0) {
return 0;
}
subclasses = ldb_subclass_list(ldb, (char *)v1->data);
if (subclasses == NULL) {
return ret;
}
for (i=0;subclasses[i];i++) {
struct ldb_val vs;
vs.data = discard_const(subclasses[i]);
vs.length = strlen(subclasses[i]);
if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
return 0;
}
}
return ret;
}
/*
compare two utc time values. 1 second resolution
*/
int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
time_t t1, t2;
t1 = ldb_string_to_time((char *)v1->data);
t2 = ldb_string_to_time((char *)v2->data);
return (int)t2 - (int)t1;
}
/*
canonicalise a utc time
*/
int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
time_t t = ldb_string_to_time((char *)in->data);
out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
if (out->data == NULL) {
return -1;
}
out->length = strlen((char *)out->data);
return 0;
}
/*
table of standard attribute handlers
*/
static const struct ldb_attrib_handler ldb_standard_attribs[] = {
{
.attr = LDB_SYNTAX_INTEGER,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_Integer,
.comparison_fn = ldb_comparison_Integer
},
{
.attr = LDB_SYNTAX_OCTET_STRING,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_copy,
.comparison_fn = ldb_comparison_binary
},
{
.attr = LDB_SYNTAX_DIRECTORY_STRING,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_fold,
.comparison_fn = ldb_comparison_fold
},
{
.attr = LDB_SYNTAX_DN,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn
},
{
.attr = LDB_SYNTAX_OBJECTCLASS,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_fold,
.comparison_fn = ldb_comparison_objectclass
},
{
.attr = LDB_SYNTAX_UTC_TIME,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_utctime,
.comparison_fn = ldb_comparison_utctime
}
};
/*
return the attribute handlers for a given syntax name
*/
const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
const char *syntax)
{
int i;
unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
/* TODO: should be replaced with a binary search */
for (i=0;i<num_handlers;i++) {
if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
return &ldb_standard_attribs[i];
}
}
return NULL;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
register handlers for specific attributes and objectclass relationships
this allows a backend to store its schema information in any format
it likes (or to not have any schema information at all) while keeping the
message matching logic generic
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
add to the list of ldif handlers for this ldb context
*/
int ldb_set_attrib_handlers(struct ldb_context *ldb,
const struct ldb_attrib_handler *handlers,
unsigned num_handlers)
{
int i, j, n;
struct ldb_attrib_handler *h;
n = ldb->schema.num_attrib_handlers + num_handlers;
h = talloc_realloc(ldb, ldb->schema.attrib_handlers,
struct ldb_attrib_handler, n);
if (h == NULL) {
ldb_oom(ldb);
return -1;
}
ldb->schema.attrib_handlers = h;
for (i = 0; i < num_handlers; i++) {
for (j = 0; j < ldb->schema.num_attrib_handlers; j++) {
if (ldb_attr_cmp(handlers[i].attr, h[j].attr) < 0) {
memmove(h+j+1, h+j, sizeof(*h) * (ldb->schema.num_attrib_handlers-j));
break;
}
}
h[j] = handlers[i];
if (h[j].flags & LDB_ATTR_FLAG_ALLOCATED) {
h[j].attr = talloc_strdup(h, h[j].attr);
if (h[j].attr == NULL) {
ldb_oom(ldb);
return -1;
}
}
ldb->schema.num_attrib_handlers++;
}
return 0;
}
/*
default handler function pointers
*/
static const struct ldb_attrib_handler ldb_default_attrib_handler = {
.attr = NULL,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_copy,
.comparison_fn = ldb_comparison_binary,
};
/*
return the attribute handlers for a given attribute
*/
const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
const char *attrib)
{
int i, e, b = 0, r;
const struct ldb_attrib_handler *def = &ldb_default_attrib_handler;
/* as handlers are sorted, '*' must be the first if present */
if (strcmp(ldb->schema.attrib_handlers[0].attr, "*") == 0) {
def = &ldb->schema.attrib_handlers[0];
b = 1;
}
/* do a binary search on the array */
e = ldb->schema.num_attrib_handlers - 1;
while (b <= e) {
i = (b + e) / 2;
r = ldb_attr_cmp(attrib, ldb->schema.attrib_handlers[i].attr);
if (r == 0) {
return &ldb->schema.attrib_handlers[i];
}
if (r < 0) {
e = i - 1;
} else {
b = i + 1;
}
}
return def;
}
/*
add to the list of ldif handlers for this ldb context
*/
void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib)
{
const struct ldb_attrib_handler *h;
int i;
h = ldb_attrib_handler(ldb, attrib);
if (h == &ldb_default_attrib_handler) {
return;
}
if (h->flags & LDB_ATTR_FLAG_ALLOCATED) {
talloc_free(discard_const_p(char, h->attr));
}
i = h - ldb->schema.attrib_handlers;
if (i < ldb->schema.num_attrib_handlers - 1) {
memmove(&ldb->schema.attrib_handlers[i],
h+1, sizeof(*h) * (ldb->schema.num_attrib_handlers-(i+1)));
}
ldb->schema.num_attrib_handlers--;
}
/*
setup a attribute handler using a standard syntax
*/
int ldb_set_attrib_handler_syntax(struct ldb_context *ldb,
const char *attr, const char *syntax)
{
const struct ldb_attrib_handler *h = ldb_attrib_handler_syntax(ldb, syntax);
struct ldb_attrib_handler h2;
if (h == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Unknown syntax '%s'\n", syntax);
return -1;
}
h2 = *h;
h2.attr = attr;
return ldb_set_attrib_handlers(ldb, &h2, 1);
}
/*
setup the attribute handles for well known attributes
*/
int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
{
const struct {
const char *attr;
const char *syntax;
} wellknown[] = {
{ "dn", LDB_SYNTAX_DN },
{ "distinguishedName", LDB_SYNTAX_DN },
{ "cn", LDB_SYNTAX_DIRECTORY_STRING },
{ "dc", LDB_SYNTAX_DIRECTORY_STRING },
{ "ou", LDB_SYNTAX_DIRECTORY_STRING },
{ "objectClass", LDB_SYNTAX_OBJECTCLASS }
};
int i;
for (i=0;i<ARRAY_SIZE(wellknown);i++) {
if (ldb_set_attrib_handler_syntax(ldb, wellknown[i].attr,
wellknown[i].syntax) != 0) {
return -1;
}
}
return 0;
}
/*
return the list of subclasses for a class
*/
const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname)
{
int i;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
return (const char **)ldb->schema.classes[i].subclasses;
}
}
return NULL;
}
/*
add a new subclass
*/
static int ldb_subclass_new(struct ldb_context *ldb, const char *classname, const char *subclass)
{
struct ldb_subclass *s, *c;
s = talloc_realloc(ldb, ldb->schema.classes, struct ldb_subclass, ldb->schema.num_classes+1);
if (s == NULL) goto failed;
ldb->schema.classes = s;
c = &s[ldb->schema.num_classes];
c->name = talloc_strdup(s, classname);
if (c->name == NULL) goto failed;
c->subclasses = talloc_array(s, char *, 2);
if (c->subclasses == NULL) goto failed;
c->subclasses[0] = talloc_strdup(c->subclasses, subclass);
if (c->subclasses[0] == NULL) goto failed;
c->subclasses[1] = NULL;
ldb->schema.num_classes++;
return 0;
failed:
ldb_oom(ldb);
return -1;
}
/*
add a subclass
*/
int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass)
{
int i, n;
struct ldb_subclass *c;
char **s;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
break;
}
}
if (i == ldb->schema.num_classes) {
return ldb_subclass_new(ldb, classname, subclass);
}
c = &ldb->schema.classes[i];
for (n=0;c->subclasses[n];n++) /* noop */;
s = talloc_realloc(ldb->schema.classes, c->subclasses, char *, n+2);
if (s == NULL) {
ldb_oom(ldb);
return -1;
}
c->subclasses = s;
s[n] = talloc_strdup(s, subclass);
if (s[n] == NULL) {
ldb_oom(ldb);
return -1;
}
s[n+1] = NULL;
return 0;
}
/*
remove a set of subclasses for a class
*/
void ldb_subclass_remove(struct ldb_context *ldb, const char *classname)
{
int i;
struct ldb_subclass *c;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
break;
}
}
if (i == ldb->schema.num_classes) {
return;
}
c = &ldb->schema.classes[i];
talloc_free(c->name);
talloc_free(c->subclasses);
if (ldb->schema.num_classes-(i+1) > 0) {
memmove(c, c+1, sizeof(*c) * (ldb->schema.num_classes-(i+1)));
}
ldb->schema.num_classes--;
if (ldb->schema.num_classes == 0) {
talloc_free(ldb->schema.classes);
ldb->schema.classes = NULL;
}
}
+106
View File
@@ -0,0 +1,106 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb_controls.c
*
* Component: ldb controls utility functions
*
* Description: helper functions for control modules
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
/* check if a control with the specified "oid" exist and return it */
/* returns NULL if not found */
struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid)
{
int i;
/* check if there's a paged request control */
if (controls != NULL) {
for (i = 0; controls[i]; i++) {
if (strcmp(oid, controls[i]->oid) == 0) {
break;
}
}
return controls[i];
}
return NULL;
}
/* saves the current controls list into the "saver" and replace the one in req with a new one excluding
the "exclude" control */
/* returns False on error */
int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
{
struct ldb_control **lcs;
int i, j;
*saver = req->controls;
for (i = 0; req->controls[i]; i++);
if (i == 1) {
req->controls = NULL;
return 1;
}
lcs = talloc_array(req, struct ldb_control *, i);
if (!lcs) {
return 0;
}
for (i = 0, j = 0; (*saver)[i]; i++) {
if (exclude == (*saver)[i]) continue;
lcs[j] = (*saver)[i];
j++;
}
lcs[j] = NULL;
req->controls = lcs;
return 1;
}
/* check if there's any control marked as critical in the list */
/* return True if any, False if none */
int check_critical_controls(struct ldb_control **controls)
{
int i;
if (controls == NULL) {
return 0;
}
for (i = 0; controls[i]; i++) {
if (controls[i]->critical) {
return 1;
}
}
return 0;
}
+105
View File
@@ -0,0 +1,105 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb debug
*
* Description: functions for printing debug messages
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
this allows the user to choose their own debug function
*/
int ldb_set_debug(struct ldb_context *ldb,
void (*debug)(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap),
void *context)
{
ldb->debug_ops.debug = debug;
ldb->debug_ops.context = context;
return 0;
}
/*
debug function for ldb_set_debug_stderr
*/
static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap)
{
if (level <= LDB_DEBUG_WARNING) {
vfprintf(stderr, fmt, ap);
}
}
/*
convenience function to setup debug messages on stderr
messages of level LDB_DEBUG_WARNING and higher are printed
*/
int ldb_set_debug_stderr(struct ldb_context *ldb)
{
return ldb_set_debug(ldb, ldb_debug_stderr, ldb);
}
/*
log a message
*/
void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...)
{
va_list ap;
if (ldb->debug_ops.debug == NULL) {
ldb_set_debug_stderr(ldb);
}
va_start(ap, fmt);
ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap);
va_end(ap);
}
/*
log a message, and set the ldb error string to the same message
*/
void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = talloc_vasprintf(ldb, fmt, ap);
va_end(ap);
if (msg != NULL) {
ldb_set_errstring(ldb, msg);
ldb_debug(ldb, level, "%s", msg);
}
talloc_free(msg);
}
File diff suppressed because it is too large Load Diff
+761
View File
@@ -0,0 +1,761 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldif routines
*
* Description: ldif pack/unpack routines
*
* Author: Andrew Tridgell
*/
/*
see RFC2849 for the LDIF format definition
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
/*
*/
static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value)
{
struct stat statbuf;
char *buf;
int count, size, bytes;
int ret;
int f;
const char *fname = (const char *)value->data;
if (strncmp(fname, "file://", 7) != 0) {
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
fname += 7;
f = open(fname, O_RDONLY);
if (f == -1) {
return -1;
}
if (fstat(f, &statbuf) != 0) {
ret = -1;
goto done;
}
if (statbuf.st_size == 0) {
ret = -1;
goto done;
}
value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
if (value->data == NULL) {
ret = -1;
goto done;
}
value->data[statbuf.st_size] = 0;
count = 0;
size = statbuf.st_size;
buf = (char *)value->data;
while (count < statbuf.st_size) {
bytes = read(f, buf, size);
if (bytes == -1) {
talloc_free(value->data);
ret = -1;
goto done;
}
count += bytes;
buf += bytes;
size -= bytes;
}
value->length = statbuf.st_size;
ret = statbuf.st_size;
done:
close(f);
return ret;
}
/*
this base64 decoder was taken from jitterbug (written by tridge).
we might need to replace it with a new version
*/
int ldb_base64_decode(char *s)
{
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset=0, byte_offset, idx, i, n;
uint8_t *d = (uint8_t *)s;
char *p=NULL;
n=i=0;
while (*s && (p=strchr(b64,*s))) {
idx = (int)(p - b64);
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
d[byte_offset] &= ~((1<<(8-bit_offset))-1);
if (bit_offset < 3) {
d[byte_offset] |= (idx << (2-bit_offset));
n = byte_offset+1;
} else {
d[byte_offset] |= (idx >> (bit_offset-2));
d[byte_offset+1] = 0;
d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
n = byte_offset+2;
}
s++; i++;
}
if (bit_offset >= 3) {
n--;
}
if (*s && !p) {
/* the only termination allowed */
if (*s != '=') {
return -1;
}
}
/* null terminate */
d[n] = 0;
return n;
}
/*
encode as base64
caller frees
*/
char *ldb_base64_encode(void *mem_ctx, const char *buf, int len)
{
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset, byte_offset, idx, i;
const uint8_t *d = (const uint8_t *)buf;
int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
char *out;
out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
if (!out) return NULL;
for (i=0;i<bytes;i++) {
byte_offset = (i*6)/8;
bit_offset = (i*6)%8;
if (bit_offset < 3) {
idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
} else {
idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
if (byte_offset+1 < len) {
idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
}
}
out[i] = b64[idx];
}
for (;i<bytes+pad_bytes;i++)
out[i] = '=';
out[i] = 0;
return out;
}
/*
see if a buffer should be base64 encoded
*/
int ldb_should_b64_encode(const struct ldb_val *val)
{
unsigned int i;
uint8_t *p = val->data;
if (val->length == 0) {
return 0;
}
if (p[0] == ' ' || p[0] == ':') {
return 1;
}
for (i=0; i<val->length; i++) {
if (!isprint(p[i]) || p[i] == '\n') {
return 1;
}
}
return 0;
}
/* this macro is used to handle the return checking on fprintf_fn() */
#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
/*
write a line folded string onto a file
*/
static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
const char *buf, size_t length, int start_pos)
{
unsigned int i;
int total=0, ret;
for (i=0;i<length;i++) {
ret = fprintf_fn(private_data, "%c", buf[i]);
CHECK_RET;
if (i != (length-1) && (i + start_pos) % 77 == 0) {
ret = fprintf_fn(private_data, "\n ");
CHECK_RET;
}
}
return total;
}
#undef CHECK_RET
/*
encode as base64 to a file
*/
static int base64_encode_f(struct ldb_context *ldb,
int (*fprintf_fn)(void *, const char *, ...),
void *private_data,
const char *buf, int len, int start_pos)
{
char *b = ldb_base64_encode(ldb, buf, len);
int ret;
if (!b) {
return -1;
}
ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
talloc_free(b);
return ret;
}
static const struct {
const char *name;
enum ldb_changetype changetype;
} ldb_changetypes[] = {
{"add", LDB_CHANGETYPE_ADD},
{"delete", LDB_CHANGETYPE_DELETE},
{"modify", LDB_CHANGETYPE_MODIFY},
{NULL, 0}
};
/* this macro is used to handle the return checking on fprintf_fn() */
#define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
/*
write to ldif, using a caller supplied write method
*/
int ldb_ldif_write(struct ldb_context *ldb,
int (*fprintf_fn)(void *, const char *, ...),
void *private_data,
const struct ldb_ldif *ldif)
{
TALLOC_CTX *mem_ctx;
unsigned int i, j;
int total=0, ret;
const struct ldb_message *msg;
mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
msg = ldif->msg;
ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_get_linearized(msg->dn));
CHECK_RET;
if (ldif->changetype != LDB_CHANGETYPE_NONE) {
for (i=0;ldb_changetypes[i].name;i++) {
if (ldb_changetypes[i].changetype == ldif->changetype) {
break;
}
}
if (!ldb_changetypes[i].name) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d\n",
ldif->changetype);
talloc_free(mem_ctx);
return -1;
}
ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
CHECK_RET;
}
for (i=0;i<msg->num_elements;i++) {
const struct ldb_attrib_handler *h;
h = ldb_attrib_handler(ldb, msg->elements[i].name);
if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
fprintf_fn(private_data, "add: %s\n",
msg->elements[i].name);
break;
case LDB_FLAG_MOD_DELETE:
fprintf_fn(private_data, "delete: %s\n",
msg->elements[i].name);
break;
case LDB_FLAG_MOD_REPLACE:
fprintf_fn(private_data, "replace: %s\n",
msg->elements[i].name);
break;
}
}
for (j=0;j<msg->elements[i].num_values;j++) {
struct ldb_val v;
ret = h->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
CHECK_RET;
if (ldb_should_b64_encode(&v)) {
ret = fprintf_fn(private_data, "%s:: ",
msg->elements[i].name);
CHECK_RET;
ret = base64_encode_f(ldb, fprintf_fn, private_data,
(char *)v.data, v.length,
strlen(msg->elements[i].name)+3);
CHECK_RET;
ret = fprintf_fn(private_data, "\n");
CHECK_RET;
} else {
ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
CHECK_RET;
ret = fold_string(fprintf_fn, private_data,
(char *)v.data, v.length,
strlen(msg->elements[i].name)+2);
CHECK_RET;
ret = fprintf_fn(private_data, "\n");
CHECK_RET;
}
if (v.data != msg->elements[i].values[j].data) {
talloc_free(v.data);
}
}
if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
fprintf_fn(private_data, "-\n");
}
}
ret = fprintf_fn(private_data,"\n");
CHECK_RET;
return total;
}
#undef CHECK_RET
/*
pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
this routine removes any RFC2849 continuations and comments
caller frees
*/
static char *next_chunk(struct ldb_context *ldb,
int (*fgetc_fn)(void *), void *private_data)
{
size_t alloc_size=0, chunk_size = 0;
char *chunk = NULL;
int c;
int in_comment = 0;
while ((c = fgetc_fn(private_data)) != EOF) {
if (chunk_size+1 >= alloc_size) {
char *c2;
alloc_size += 1024;
c2 = talloc_realloc(ldb, chunk, char, alloc_size);
if (!c2) {
talloc_free(chunk);
errno = ENOMEM;
return NULL;
}
chunk = c2;
}
if (in_comment) {
if (c == '\n') {
in_comment = 0;
}
continue;
}
/* handle continuation lines - see RFC2849 */
if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
chunk_size--;
continue;
}
/* chunks are terminated by a double line-feed */
if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
chunk[chunk_size-1] = 0;
return chunk;
}
if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
in_comment = 1;
continue;
}
/* ignore leading blank lines */
if (chunk_size == 0 && c == '\n') {
continue;
}
chunk[chunk_size++] = c;
}
if (chunk) {
chunk[chunk_size] = 0;
}
return chunk;
}
/* simple ldif attribute parser */
static int next_attr(void *mem_ctx, char **s, const char **attr, struct ldb_val *value)
{
char *p;
int base64_encoded = 0;
int binary_file = 0;
if (strncmp(*s, "-\n", 2) == 0) {
value->length = 0;
*attr = "-";
*s += 2;
return 0;
}
p = strchr(*s, ':');
if (!p) {
return -1;
}
*p++ = 0;
if (*p == ':') {
base64_encoded = 1;
p++;
}
if (*p == '<') {
binary_file = 1;
p++;
}
*attr = *s;
while (*p == ' ' || *p == '\t') {
p++;
}
value->data = (uint8_t *)p;
p = strchr(p, '\n');
if (!p) {
value->length = strlen((char *)value->data);
*s = ((char *)value->data) + value->length;
} else {
value->length = p - (char *)value->data;
*s = p+1;
*p = 0;
}
if (base64_encoded) {
int len = ldb_base64_decode((char *)value->data);
if (len == -1) {
/* it wasn't valid base64 data */
return -1;
}
value->length = len;
}
if (binary_file) {
int len = ldb_read_data_file(mem_ctx, value);
if (len == -1) {
/* an error occured hile trying to retrieve the file */
return -1;
}
}
return 0;
}
/*
free a message from a ldif_read
*/
void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
{
talloc_free(ldif);
}
/*
read from a LDIF source, creating a ldb_message
*/
struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
int (*fgetc_fn)(void *), void *private_data)
{
struct ldb_ldif *ldif;
struct ldb_message *msg;
const char *attr=NULL;
char *chunk=NULL, *s;
struct ldb_val value;
unsigned flags = 0;
value.data = NULL;
ldif = talloc(ldb, struct ldb_ldif);
if (!ldif) return NULL;
ldif->msg = talloc(ldif, struct ldb_message);
if (ldif->msg == NULL) {
talloc_free(ldif);
return NULL;
}
ldif->changetype = LDB_CHANGETYPE_NONE;
msg = ldif->msg;
msg->dn = NULL;
msg->elements = NULL;
msg->num_elements = 0;
msg->private_data = NULL;
chunk = next_chunk(ldb, fgetc_fn, private_data);
if (!chunk) {
goto failed;
}
talloc_steal(ldif, chunk);
msg->private_data = chunk;
s = chunk;
if (next_attr(ldif, &s, &attr, &value) != 0) {
goto failed;
}
/* first line must be a dn */
if (ldb_attr_cmp(attr, "dn") != 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'\n",
attr);
goto failed;
}
msg->dn = ldb_dn_new(msg, ldb, (char *)value.data);
if ( ! ldb_dn_validate(msg->dn)) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'\n",
value.data);
goto failed;
}
while (next_attr(ldif, &s, &attr, &value) == 0) {
const struct ldb_attrib_handler *h;
struct ldb_message_element *el;
int ret, empty = 0;
if (ldb_attr_cmp(attr, "changetype") == 0) {
int i;
for (i=0;ldb_changetypes[i].name;i++) {
if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
ldif->changetype = ldb_changetypes[i].changetype;
break;
}
}
if (!ldb_changetypes[i].name) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Error: Bad ldif changetype '%s'\n",(char *)value.data);
}
flags = 0;
continue;
}
if (ldb_attr_cmp(attr, "add") == 0) {
flags = LDB_FLAG_MOD_ADD;
empty = 1;
}
if (ldb_attr_cmp(attr, "delete") == 0) {
flags = LDB_FLAG_MOD_DELETE;
empty = 1;
}
if (ldb_attr_cmp(attr, "replace") == 0) {
flags = LDB_FLAG_MOD_REPLACE;
empty = 1;
}
if (ldb_attr_cmp(attr, "-") == 0) {
flags = 0;
continue;
}
if (empty) {
if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
goto failed;
}
continue;
}
el = &msg->elements[msg->num_elements-1];
h = ldb_attrib_handler(ldb, attr);
if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
flags == el->flags) {
/* its a continuation */
el->values =
talloc_realloc(msg->elements, el->values,
struct ldb_val, el->num_values+1);
if (!el->values) {
goto failed;
}
ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[el->num_values]);
if (ret != 0) {
goto failed;
}
if (value.length == 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Error: Attribute value cannot be empty for attribute '%s'\n", el->name);
goto failed;
}
if (value.data != el->values[el->num_values].data) {
talloc_steal(el->values, el->values[el->num_values].data);
}
el->num_values++;
} else {
/* its a new attribute */
msg->elements = talloc_realloc(ldif, msg->elements,
struct ldb_message_element,
msg->num_elements+1);
if (!msg->elements) {
goto failed;
}
el = &msg->elements[msg->num_elements];
el->flags = flags;
el->name = talloc_strdup(msg->elements, attr);
el->values = talloc(msg->elements, struct ldb_val);
if (!el->values || !el->name) {
goto failed;
}
el->num_values = 1;
ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[0]);
if (ret != 0) {
goto failed;
}
if (value.data != el->values[0].data) {
talloc_steal(el->values, el->values[0].data);
}
msg->num_elements++;
}
}
return ldif;
failed:
talloc_free(ldif);
return NULL;
}
/*
a wrapper around ldif_read() for reading from FILE*
*/
struct ldif_read_file_state {
FILE *f;
};
static int fgetc_file(void *private_data)
{
struct ldif_read_file_state *state =
(struct ldif_read_file_state *)private_data;
return fgetc(state->f);
}
struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
{
struct ldif_read_file_state state;
state.f = f;
return ldb_ldif_read(ldb, fgetc_file, &state);
}
/*
a wrapper around ldif_read() for reading from const char*
*/
struct ldif_read_string_state {
const char *s;
};
static int fgetc_string(void *private_data)
{
struct ldif_read_string_state *state =
(struct ldif_read_string_state *)private_data;
if (state->s[0] != 0) {
return *state->s++;
}
return EOF;
}
struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
{
struct ldif_read_string_state state;
struct ldb_ldif *ldif;
state.s = *s;
ldif = ldb_ldif_read(ldb, fgetc_string, &state);
*s = state.s;
return ldif;
}
/*
wrapper around ldif_write() for a file
*/
struct ldif_write_file_state {
FILE *f;
};
static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
static int fprintf_file(void *private_data, const char *fmt, ...)
{
struct ldif_write_file_state *state =
(struct ldif_write_file_state *)private_data;
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(state->f, fmt, ap);
va_end(ap);
return ret;
}
int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
{
struct ldif_write_file_state state;
state.f = f;
return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
}
+430
View File
@@ -0,0 +1,430 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004-2005
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb expression matching
*
* Description: ldb expression matching
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
check if the scope matches in a search result
*/
static int ldb_match_scope(struct ldb_context *ldb,
struct ldb_dn *base,
struct ldb_dn *dn,
enum ldb_scope scope)
{
int ret = 0;
if (base == NULL || dn == NULL) {
return 1;
}
switch (scope) {
case LDB_SCOPE_BASE:
if (ldb_dn_compare(base, dn) == 0) {
ret = 1;
}
break;
case LDB_SCOPE_ONELEVEL:
if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
if (ldb_dn_compare_base(base, dn) == 0) {
ret = 1;
}
}
break;
case LDB_SCOPE_SUBTREE:
default:
if (ldb_dn_compare_base(base, dn) == 0) {
ret = 1;
}
break;
}
return ret;
}
/*
match if node is present
*/
static int ldb_match_present(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
if (ldb_attr_dn(tree->u.present.attr) == 0) {
return 1;
}
if (ldb_msg_find_element(msg, tree->u.present.attr)) {
return 1;
}
return 0;
}
static int ldb_match_comparison(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope,
enum ldb_parse_op comp_op)
{
unsigned int i;
struct ldb_message_element *el;
const struct ldb_attrib_handler *h;
int ret;
/* FIXME: APPROX comparison not handled yet */
if (comp_op == LDB_OP_APPROX) return 0;
el = ldb_msg_find_element(msg, tree->u.comparison.attr);
if (el == NULL) {
return 0;
}
h = ldb_attrib_handler(ldb, el->name);
for (i = 0; i < el->num_values; i++) {
ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
if (ret == 0) {
return 1;
}
if (ret > 0 && comp_op == LDB_OP_GREATER) {
return 1;
}
if (ret < 0 && comp_op == LDB_OP_LESS) {
return 1;
}
}
return 0;
}
/*
match a simple leaf node
*/
static int ldb_match_equality(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
struct ldb_message_element *el;
const struct ldb_attrib_handler *h;
struct ldb_dn *valuedn;
int ret;
if (ldb_attr_dn(tree->u.equality.attr) == 0) {
valuedn = ldb_dn_new(ldb, ldb, (char *)tree->u.equality.value.data);
if (valuedn == NULL) {
return 0;
}
ret = ldb_dn_compare(msg->dn, valuedn);
talloc_free(valuedn);
if (ret == 0) return 1;
return 0;
}
/* TODO: handle the "*" case derived from an extended search
operation without the attibute type defined */
el = ldb_msg_find_element(msg, tree->u.equality.attr);
if (el == NULL) {
return 0;
}
h = ldb_attrib_handler(ldb, el->name);
for (i=0;i<el->num_values;i++) {
if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
&el->values[i]) == 0) {
return 1;
}
}
return 0;
}
static int ldb_wildcard_compare(struct ldb_context *ldb,
const struct ldb_parse_tree *tree,
const struct ldb_val value)
{
const struct ldb_attrib_handler *h;
struct ldb_val val;
struct ldb_val cnk;
struct ldb_val *chunk;
char *p, *g;
uint8_t *save_p = NULL;
int c = 0;
h = ldb_attrib_handler(ldb, tree->u.substring.attr);
if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
return -1;
save_p = val.data;
cnk.data = NULL;
if ( ! tree->u.substring.start_with_wildcard ) {
chunk = tree->u.substring.chunks[c];
if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
/* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
if (cnk.length > val.length) {
goto failed;
}
if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
val.length -= cnk.length;
val.data += cnk.length;
c++;
talloc_free(cnk.data);
cnk.data = NULL;
}
while (tree->u.substring.chunks[c]) {
chunk = tree->u.substring.chunks[c];
if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
/* FIXME: case of embedded nulls */
p = strstr((char *)val.data, (char *)cnk.data);
if (p == NULL) goto failed;
if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
do { /* greedy */
g = strstr((char *)p + cnk.length, (char *)cnk.data);
if (g) p = g;
} while(g);
}
val.length = val.length - (p - (char *)(val.data)) - cnk.length;
val.data = (uint8_t *)(p + cnk.length);
c++;
talloc_free(cnk.data);
cnk.data = NULL;
}
if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
talloc_free(save_p);
return 1;
failed:
talloc_free(save_p);
talloc_free(cnk.data);
return 0;
}
/*
match a simple leaf node
*/
static int ldb_match_substring(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
struct ldb_message_element *el;
el = ldb_msg_find_element(msg, tree->u.substring.attr);
if (el == NULL) {
return 0;
}
for (i = 0; i < el->num_values; i++) {
if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
return 1;
}
}
return 0;
}
/*
bitwise-and comparator
*/
static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
{
uint64_t i1, i2;
i1 = strtoull((char *)v1->data, NULL, 0);
i2 = strtoull((char *)v2->data, NULL, 0);
return ((i1 & i2) == i2);
}
/*
bitwise-or comparator
*/
static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
{
uint64_t i1, i2;
i1 = strtoull((char *)v1->data, NULL, 0);
i2 = strtoull((char *)v2->data, NULL, 0);
return ((i1 & i2) != 0);
}
/*
extended match, handles things like bitops
*/
static int ldb_match_extended(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
int i;
const struct {
const char *oid;
int (*comparator)(const struct ldb_val *, const struct ldb_val *);
} rules[] = {
{ LDB_OID_COMPARATOR_AND, ldb_comparator_and},
{ LDB_OID_COMPARATOR_OR, ldb_comparator_or}
};
int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
struct ldb_message_element *el;
if (tree->u.extended.dnAttributes) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
return -1;
}
if (tree->u.extended.rule_id == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
return -1;
}
if (tree->u.extended.attr == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
return -1;
}
for (i=0;i<ARRAY_SIZE(rules);i++) {
if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
comp = rules[i].comparator;
break;
}
}
if (comp == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
tree->u.extended.rule_id);
return -1;
}
/* find the message element */
el = ldb_msg_find_element(msg, tree->u.extended.attr);
if (el == NULL) {
return 0;
}
for (i=0;i<el->num_values;i++) {
int ret = comp(&el->values[i], &tree->u.extended.value);
if (ret == -1 || ret == 1) return ret;
}
return 0;
}
/*
return 0 if the given parse tree matches the given message. Assumes
the message is in sorted order
return 1 if it matches, and 0 if it doesn't match
this is a recursive function, and does short-circuit evaluation
*/
static int ldb_match_message(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
int v;
switch (tree->operation) {
case LDB_OP_AND:
for (i=0;i<tree->u.list.num_elements;i++) {
v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
if (!v) return 0;
}
return 1;
case LDB_OP_OR:
for (i=0;i<tree->u.list.num_elements;i++) {
v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
if (v) return 1;
}
return 0;
case LDB_OP_NOT:
return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
case LDB_OP_EQUALITY:
return ldb_match_equality(ldb, msg, tree, scope);
case LDB_OP_SUBSTRING:
return ldb_match_substring(ldb, msg, tree, scope);
case LDB_OP_GREATER:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
case LDB_OP_LESS:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
case LDB_OP_PRESENT:
return ldb_match_present(ldb, msg, tree, scope);
case LDB_OP_APPROX:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
case LDB_OP_EXTENDED:
return ldb_match_extended(ldb, msg, tree, scope);
}
return 0;
}
int ldb_match_msg(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
struct ldb_dn *base,
enum ldb_scope scope)
{
if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
return 0;
}
return ldb_match_message(ldb, msg, tree, scope);
}
+452
View File
@@ -0,0 +1,452 @@
/*
ldb database library
Copyright (C) Simo Sorce 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb modules core
*
* Description: core modules routines
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
#if (_SAMBA_BUILD_ >= 4)
#include "build.h"
#include "dynconfig.h"
#endif
#define LDB_MODULE_PREFIX "modules:"
#define LDB_MODULE_PREFIX_LEN 8
static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
{
int i, len;
char *trimmed;
trimmed = talloc_strdup(mem_ctx, string);
if (!trimmed) {
return NULL;
}
len = strlen(trimmed);
for (i = 0; trimmed[i] != '\0'; i++) {
switch (trimmed[i]) {
case ' ':
case '\t':
case '\n':
memmove(&trimmed[i], &trimmed[i + 1], len -i -1);
break;
}
}
return trimmed;
}
/* modules are called in inverse order on the stack.
Lets place them as an admin would think the right order is.
Modules order is important */
const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string)
{
char **modules = NULL;
const char **m;
char *modstr, *p;
int i;
/* spaces not admitted */
modstr = ldb_modules_strdup_no_spaces(mem_ctx, string);
if ( ! modstr) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()\n");
return NULL;
}
modules = talloc_realloc(mem_ctx, modules, char *, 2);
if ( ! modules ) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
talloc_free(modstr);
return NULL;
}
talloc_steal(modules, modstr);
i = 0;
/* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */
while ((p = strrchr(modstr, ',')) != NULL) {
*p = '\0';
p++;
modules[i] = p;
i++;
modules = talloc_realloc(mem_ctx, modules, char *, i + 2);
if ( ! modules ) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
return NULL;
}
}
modules[i] = modstr;
modules[i + 1] = NULL;
m = (const char **)modules;
return m;
}
static struct ops_list_entry {
const struct ldb_module_ops *ops;
struct ops_list_entry *next;
} *registered_modules = NULL;
static const struct ldb_module_ops *ldb_find_module_ops(const char *name)
{
struct ops_list_entry *e;
for (e = registered_modules; e; e = e->next) {
if (strcmp(e->ops->name, name) == 0)
return e->ops;
}
return NULL;
}
#ifndef STATIC_ldb_MODULES
#ifdef HAVE_LDB_LDAP
#define LDAP_INIT ldb_ldap_init,
#else
#define LDAP_INIT
#endif
#ifdef HAVE_LDB_SQLITE3
#define SQLITE3_INIT ldb_sqlite3_init,
#else
#define SQLITE3_INIT
#endif
#define STATIC_ldb_MODULES \
{ \
LDAP_INIT \
SQLITE3_INIT \
ldb_tdb_init, \
ldb_operational_init, \
ldb_rdn_name_init, \
ldb_objectclass_init, \
ldb_paged_results_init, \
ldb_sort_init, \
ldb_asq_init, \
NULL \
}
#endif
int ldb_global_init(void)
{
static int (*static_init_fns[])(void) = STATIC_ldb_MODULES;
static int initialized = 0;
int ret = 0, i;
if (initialized)
return 0;
initialized = 1;
for (i = 0; static_init_fns[i]; i++) {
if (static_init_fns[i]() == -1)
ret = -1;
}
return ret;
}
int ldb_register_module(const struct ldb_module_ops *ops)
{
struct ops_list_entry *entry = talloc(talloc_autofree_context(), struct ops_list_entry);
if (ldb_find_module_ops(ops->name) != NULL)
return -1;
if (entry == NULL)
return -1;
entry->ops = ops;
entry->next = registered_modules;
registered_modules = entry;
return 0;
}
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_
modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR);
#else
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, RTLD_NOW);
if (handle == NULL) {
ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror());
return -1;
}
init_fn = (int (*)(void))dlsym(handle, "init_module");
if (init_fn == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror());
return -1;
}
talloc_free(path);
return init_fn();
#else
ldb_debug(ldb, LDB_DEBUG_TRACE, "no dlopen() - not trying to load %s module\n", name);
return -1;
#endif
}
int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out)
{
struct ldb_module *module;
int i;
module = backend;
for (i = 0; module_list[i] != NULL; i++) {
struct ldb_module *current;
const struct ldb_module_ops *ops;
ops = ldb_find_module_ops(module_list[i]);
if (ops == NULL) {
if (ldb_try_load_dso(ldb, module_list[i]) == 0) {
ops = ldb_find_module_ops(module_list[i]);
}
}
if (ops == NULL) {
ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n",
module_list[i]);
continue;
}
current = talloc_zero(ldb, struct ldb_module);
if (current == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
talloc_set_name(current, "ldb_module: %s", module_list[i]);
current->ldb = ldb;
current->ops = ops;
DLIST_ADD(module, current);
}
*out = module;
return LDB_SUCCESS;
}
int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module)
{
while (module && module->ops->init_context == NULL)
module = module->next;
if (module && module->ops->init_context &&
module->ops->init_context(module) != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "module initialization failed\n");
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
int ldb_load_modules(struct ldb_context *ldb, const char *options[])
{
const char **modules = NULL;
int i;
int ret;
TALLOC_CTX *mem_ctx = talloc_new(ldb);
if (!mem_ctx) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* find out which modules we are requested to activate */
/* check if we have a custom module list passd as ldb option */
if (options) {
for (i = 0; options[i] != NULL; i++) {
if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) {
modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]);
}
}
}
/* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */
if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) {
const char * const attrs[] = { "@LIST" , NULL};
struct ldb_result *res = NULL;
struct ldb_dn *mods_dn;
mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES");
if (mods_dn == NULL) {
talloc_free(mem_ctx);
return -1;
}
ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res);
talloc_steal(mods_dn, res);
if (ret == LDB_SUCCESS && (res->count == 0 || res->msgs[0]->num_elements == 0)) {
ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db\n");
} else {
if (ret != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out\n", ldb_errstring(ldb));
talloc_free(mem_ctx);
return -1;
}
if (res->count > 1) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count);
talloc_free(mem_ctx);
return -1;
}
modules = ldb_modules_list_from_string(ldb, mem_ctx,
(const char *)res->msgs[0]->elements[0].values[0].data);
}
talloc_free(mods_dn);
}
if (modules != NULL) {
ret = ldb_load_modules_list(ldb, modules, ldb->modules, &ldb->modules);
talloc_free(modules);
if (ret != LDB_SUCCESS) {
return ret;
}
} else {
ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database\n");
}
return ldb_init_module_chain(ldb, ldb->modules);
}
/*
by using this we allow ldb modules to only implement the functions they care about,
which makes writing a module simpler, and makes it more likely to keep working
when ldb is extended
*/
#define FIND_OP(module, op) do { \
struct ldb_context *ldb = module->ldb; \
module = module->next; \
while (module && module->ops->op == NULL) module = module->next; \
if (module == NULL) { \
ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
} while (0)
/*
helper functions to call the next module in chain
*/
int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
{
switch (request->operation) {
case LDB_SEARCH:
FIND_OP(module, search);
return module->ops->search(module, request);
case LDB_ADD:
FIND_OP(module, add);
return module->ops->add(module, request);
case LDB_MODIFY:
FIND_OP(module, modify);
return module->ops->modify(module, request);
case LDB_DELETE:
FIND_OP(module, del);
return module->ops->del(module, request);
case LDB_RENAME:
FIND_OP(module, rename);
return module->ops->rename(module, request);
case LDB_SEQUENCE_NUMBER:
FIND_OP(module, sequence_number);
return module->ops->sequence_number(module, request);
default:
FIND_OP(module, request);
return module->ops->request(module, request);
}
}
int ldb_next_init(struct ldb_module *module)
{
/* init is different in that it is not an error if modules
* do not require initialization */
module = module->next;
while (module && module->ops->init_context == NULL)
module = module->next;
if (module == NULL)
return LDB_SUCCESS;
return module->ops->init_context(module);
}
int ldb_next_start_trans(struct ldb_module *module)
{
FIND_OP(module, start_transaction);
return module->ops->start_transaction(module);
}
int ldb_next_end_trans(struct ldb_module *module)
{
FIND_OP(module, end_transaction);
return module->ops->end_transaction(module);
}
int ldb_next_del_trans(struct ldb_module *module)
{
FIND_OP(module, del_transaction);
return module->ops->del_transaction(module);
}
+846
View File
@@ -0,0 +1,846 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb message component utility functions
*
* Description: functions for manipulating ldb_message structures
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
create a new ldb_message in a given memory context (NULL for top level)
*/
struct ldb_message *ldb_msg_new(void *mem_ctx)
{
return talloc_zero(mem_ctx, struct ldb_message);
}
/*
find an element in a message by attribute name
*/
struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
const char *attr_name)
{
unsigned int i;
for (i=0;i<msg->num_elements;i++) {
if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
return &msg->elements[i];
}
}
return NULL;
}
/*
see if two ldb_val structures contain exactly the same data
return 1 for a match, 0 for a mis-match
*/
int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) return 0;
if (v1->length == 0) return 1;
if (memcmp(v1->data, v2->data, v1->length) == 0) {
return 1;
}
return 0;
}
/*
find a value in an element
assumes case sensitive comparison
*/
struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
struct ldb_val *val)
{
unsigned int i;
for (i=0;i<el->num_values;i++) {
if (ldb_val_equal_exact(val, &el->values[i])) {
return &el->values[i];
}
}
return NULL;
}
/*
duplicate a ldb_val structure
*/
struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
{
struct ldb_val v2;
v2.length = v->length;
if (v->data == NULL) {
v2.data = NULL;
return v2;
}
/* the +1 is to cope with buggy C library routines like strndup
that look one byte beyond */
v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
if (!v2.data) {
v2.length = 0;
return v2;
}
memcpy(v2.data, v->data, v->length);
((char *)v2.data)[v->length] = 0;
return v2;
}
/*
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)
{
struct ldb_message_element *els;
/* FIXME: we should probably leave this to the schema module to check */
if (! ldb_valid_attr_name(attr_name)) {
return LDB_ERR_OPERATIONS_ERROR;
}
els = talloc_realloc(msg, msg->elements,
struct ldb_message_element, msg->num_elements+1);
if (!els) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
els[msg->num_elements].values = NULL;
els[msg->num_elements].num_values = 0;
els[msg->num_elements].flags = flags;
els[msg->num_elements].name = talloc_strdup(els, attr_name);
if (!els[msg->num_elements].name) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
msg->elements = els;
msg->num_elements++;
if (return_el) {
*return_el = &els[msg->num_elements-1];
}
return LDB_SUCCESS;
}
/*
add an empty element to a message
*/
int ldb_msg_add(struct ldb_message *msg,
const struct ldb_message_element *el,
int flags)
{
if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->elements[msg->num_elements-1] = *el;
msg->elements[msg->num_elements-1].flags = flags;
return LDB_SUCCESS;
}
/*
add a value to a message
*/
int ldb_msg_add_value(struct ldb_message *msg,
const char *attr_name,
const struct ldb_val *val,
struct ldb_message_element **return_el)
{
struct ldb_message_element *el;
struct ldb_val *vals;
int ret;
el = ldb_msg_find_element(msg, attr_name);
if (!el) {
ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
if (ret != LDB_SUCCESS) {
return ret;
}
}
vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
if (!vals) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
el->values = vals;
el->values[el->num_values] = *val;
el->num_values++;
if (return_el) {
*return_el = el;
}
return LDB_SUCCESS;
}
/*
add a value to a message, stealing it into the 'right' place
*/
int ldb_msg_add_steal_value(struct ldb_message *msg,
const char *attr_name,
struct ldb_val *val)
{
int ret;
struct ldb_message_element *el;
ret = ldb_msg_add_value(msg, attr_name, val, &el);
if (ret == LDB_SUCCESS) {
talloc_steal(el->values, val->data);
}
return ret;
}
/*
add a string element to a message
*/
int ldb_msg_add_string(struct ldb_message *msg,
const char *attr_name, const char *str)
{
struct ldb_val val;
val.data = discard_const_p(uint8_t, str);
val.length = strlen(str);
if (val.length == 0) {
/* allow empty strings as non-existant attributes */
return LDB_SUCCESS;
}
return ldb_msg_add_value(msg, attr_name, &val, NULL);
}
/*
add a string element to a message, stealing it into the 'right' place
*/
int ldb_msg_add_steal_string(struct ldb_message *msg,
const char *attr_name, char *str)
{
struct ldb_val val;
val.data = (uint8_t *)str;
val.length = strlen(str);
return ldb_msg_add_steal_value(msg, attr_name, &val);
}
/*
add a printf formatted element to a message
*/
int ldb_msg_add_fmt(struct ldb_message *msg,
const char *attr_name, const char *fmt, ...)
{
struct ldb_val val;
va_list ap;
char *str;
va_start(ap, fmt);
str = talloc_vasprintf(msg, fmt, ap);
va_end(ap);
if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
val.data = (uint8_t *)str;
val.length = strlen(str);
return ldb_msg_add_steal_value(msg, attr_name, &val);
}
/*
compare two ldb_message_element structures
assumes case senistive comparison
*/
int ldb_msg_element_compare(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
unsigned int i;
if (el1->num_values != el2->num_values) {
return el1->num_values - el2->num_values;
}
for (i=0;i<el1->num_values;i++) {
if (!ldb_msg_find_val(el2, &el1->values[i])) {
return -1;
}
}
return 0;
}
/*
compare two ldb_message_element structures
comparing by element name
*/
int ldb_msg_element_compare_name(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
return ldb_attr_cmp(el1->name, el2->name);
}
/*
convenience functions to return common types from a message
these return the first value if the attribute is multi-valued
*/
const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
if (!el || el->num_values == 0) {
return NULL;
}
return &el->values[0];
}
int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtol((const char *)v->data, NULL, 0);
}
unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
const char *attr_name,
unsigned int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoul((const char *)v->data, NULL, 0);
}
int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
const char *attr_name,
int64_t default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoll((const char *)v->data, NULL, 0);
}
uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
const char *attr_name,
uint64_t default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoull((const char *)v->data, NULL, 0);
}
double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
const char *attr_name,
double default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtod((const char *)v->data, NULL);
}
int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
if (strcasecmp((const char *)v->data, "FALSE") == 0) {
return 0;
}
if (strcasecmp((const char *)v->data, "TRUE") == 0) {
return 1;
}
return default_value;
}
const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
const char *attr_name,
const char *default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return (const char *)v->data;
}
struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
void *mem_ctx,
const struct ldb_message *msg,
const char *attr_name)
{
struct ldb_dn *res_dn;
const struct ldb_val *v;
v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return NULL;
}
res_dn = ldb_dn_new(mem_ctx, ldb, (const char *)v->data);
if ( ! ldb_dn_validate(res_dn)) {
talloc_free(res_dn);
return NULL;
}
return res_dn;
}
/*
sort the elements of a message by name
*/
void ldb_msg_sort_elements(struct ldb_message *msg)
{
qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
(comparison_fn_t)ldb_msg_element_compare_name);
}
/*
shallow copy a message - copying only the elements array so that the caller
can safely add new elements without changing the message
*/
struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
int i;
msg2 = talloc(mem_ctx, struct ldb_message);
if (msg2 == NULL) return NULL;
*msg2 = *msg;
msg2->private_data = NULL;
msg2->elements = talloc_array(msg2, struct ldb_message_element,
msg2->num_elements);
if (msg2->elements == NULL) goto failed;
for (i=0;i<msg2->num_elements;i++) {
msg2->elements[i] = msg->elements[i];
}
return msg2;
failed:
talloc_free(msg2);
return NULL;
}
/*
copy a message, allocating new memory for all parts
*/
struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
int i, j;
msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
if (msg2 == NULL) return NULL;
msg2->dn = ldb_dn_copy(msg2, msg2->dn);
if (msg2->dn == NULL) goto failed;
for (i=0;i<msg2->num_elements;i++) {
struct ldb_message_element *el = &msg2->elements[i];
struct ldb_val *values = el->values;
el->name = talloc_strdup(msg2->elements, el->name);
if (el->name == NULL) goto failed;
el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
for (j=0;j<el->num_values;j++) {
el->values[j] = ldb_val_dup(el->values, &values[j]);
if (el->values[j].data == NULL && values[j].length != 0) {
goto failed;
}
}
}
return msg2;
failed:
talloc_free(msg2);
return NULL;
}
/*
canonicalise a message, merging elements of the same name
*/
struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
const struct ldb_message *msg)
{
int i;
struct ldb_message *msg2;
msg2 = ldb_msg_copy(ldb, msg);
if (msg2 == NULL) return NULL;
ldb_msg_sort_elements(msg2);
for (i=1;i<msg2->num_elements;i++) {
struct ldb_message_element *el1 = &msg2->elements[i-1];
struct ldb_message_element *el2 = &msg2->elements[i];
if (ldb_msg_element_compare_name(el1, el2) == 0) {
el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
el1->num_values + el2->num_values);
if (el1->values == NULL) {
return NULL;
}
memcpy(el1->values + el1->num_values,
el2->values,
sizeof(struct ldb_val) * el2->num_values);
el1->num_values += el2->num_values;
talloc_free(discard_const_p(char, el2->name));
if (i+1<msg2->num_elements) {
memmove(el2, el2+1, sizeof(struct ldb_message_element) *
(msg2->num_elements - (i+1)));
}
msg2->num_elements--;
i--;
}
}
return msg2;
}
/*
return a ldb_message representing the differences between msg1 and msg2. If you
then use this in a ldb_modify() call it can be used to save edits to a message
*/
struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
struct ldb_message *msg1,
struct ldb_message *msg2)
{
struct ldb_message *mod;
struct ldb_message_element *el;
unsigned int i;
mod = ldb_msg_new(ldb);
mod->dn = msg1->dn;
mod->num_elements = 0;
mod->elements = NULL;
msg2 = ldb_msg_canonicalize(ldb, msg2);
if (msg2 == NULL) {
return NULL;
}
/* look in msg2 to find elements that need to be added
or modified */
for (i=0;i<msg2->num_elements;i++) {
el = ldb_msg_find_element(msg1, msg2->elements[i].name);
if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
continue;
}
if (ldb_msg_add(mod,
&msg2->elements[i],
el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
return NULL;
}
}
/* look in msg1 to find elements that need to be deleted */
for (i=0;i<msg1->num_elements;i++) {
el = ldb_msg_find_element(msg2, msg1->elements[i].name);
if (!el) {
if (ldb_msg_add_empty(mod,
msg1->elements[i].name,
LDB_FLAG_MOD_DELETE, NULL) != 0) {
return NULL;
}
}
}
return mod;
}
int ldb_msg_sanity_check(struct ldb_context *ldb,
const struct ldb_message *msg)
{
int i, j;
/* basic check on DN */
if (msg->dn == NULL) {
/* TODO: return also an error string */
ldb_set_errstring(ldb, "ldb message lacks a DN!");
return LDB_ERR_INVALID_DN_SYNTAX;
}
/* basic syntax checks */
for (i = 0; i < msg->num_elements; i++) {
for (j = 0; j < msg->elements[i].num_values; j++) {
if (msg->elements[i].values[j].length == 0) {
TALLOC_CTX *mem_ctx = talloc_new(ldb);
/* an attribute cannot be empty */
/* TODO: return also an error string */
ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
msg->elements[i].name,
ldb_dn_get_linearized(msg->dn));
talloc_free(mem_ctx);
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
}
}
return LDB_SUCCESS;
}
/*
copy an attribute list. This only copies the array, not the elements
(ie. the elements are left as the same pointers)
*/
const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
{
const char **ret;
int i;
for (i=0;attrs[i];i++) /* noop */ ;
ret = talloc_array(mem_ctx, const char *, i+1);
if (ret == NULL) {
return NULL;
}
for (i=0;attrs[i];i++) {
ret[i] = attrs[i];
}
ret[i] = attrs[i];
return ret;
}
/*
copy an attribute list. This only copies the array, not the elements
(ie. the elements are left as the same pointers). The new attribute is added to the list.
*/
const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
{
const char **ret;
int i;
for (i=0;attrs[i];i++) /* noop */ ;
ret = talloc_array(mem_ctx, const char *, i+2);
if (ret == NULL) {
return NULL;
}
for (i=0;attrs[i];i++) {
ret[i] = attrs[i];
}
ret[i] = new_attr;
ret[i+1] = NULL;
return ret;
}
/*
return 1 if an attribute is in a list of attributes, or 0 otherwise
*/
int ldb_attr_in_list(const char * const *attrs, const char *attr)
{
int i;
for (i=0;attrs[i];i++) {
if (ldb_attr_cmp(attrs[i], attr) == 0) {
return 1;
}
}
return 0;
}
/*
rename the specified attribute in a search result
*/
int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el == NULL) {
return LDB_SUCCESS;
}
el->name = talloc_strdup(msg->elements, replace);
if (el->name == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
/*
copy the specified attribute in a search result to a new attribute
*/
int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el == NULL) {
return LDB_SUCCESS;
}
if (ldb_msg_add(msg, el, 0) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
return ldb_msg_rename_attr(msg, attr, replace);
}
/*
remove the specified attribute in a search result
*/
void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el) {
int n = (el - msg->elements);
if (n != msg->num_elements-1) {
memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
}
msg->num_elements--;
}
}
/*
remove the specified element in a search result
*/
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
{
int n = (el - msg->elements);
if (n != msg->num_elements-1) {
memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
}
msg->num_elements--;
}
/*
return a LDAP formatted time string
*/
char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
{
struct tm *tm = gmtime(&t);
char *ts;
int r;
if (!tm) {
return NULL;
}
/* we now excatly how long this string will be */
ts = talloc_array(mem_ctx, char, 18);
/* formatted like: 20040408072012.0Z */
r = snprintf(ts, 18,
"%04u%02u%02u%02u%02u%02u.0Z",
tm->tm_year+1900, tm->tm_mon+1,
tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec);
if (r != 17) {
talloc_free(ts);
return NULL;
}
return ts;
}
/*
convert a LDAP time string to a time_t. Return 0 if unable to convert
*/
time_t ldb_string_to_time(const char *s)
{
struct tm tm;
if (s == NULL) return 0;
memset(&tm, 0, sizeof(tm));
if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
return 0;
}
tm.tm_year -= 1900;
tm.tm_mon -= 1;
return timegm(&tm);
}
/*
dump a set of results to a file. Useful from within gdb
*/
void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
{
int i;
for (i = 0; i < result->count; i++) {
struct ldb_ldif ldif;
fprintf(f, "# record %d\n", i+1);
ldif.changetype = LDB_CHANGETYPE_NONE;
ldif.msg = result->msgs[i];
ldb_ldif_write_file(ldb, f, &ldif);
}
}
int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
{
struct ldb_message_element *el;
struct ldb_val val;
el = ldb_msg_find_element(msg, name);
if (el == NULL)
return 0;
val.data = discard_const_p(uint8_t, value);
val.length = strlen(value);
if (ldb_msg_find_val(el, &val))
return 1;
return 0;
}
+817
View File
@@ -0,0 +1,817 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb expression parsing
*
* Description: parse LDAP-like search expressions
*
* Author: Andrew Tridgell
*/
/*
TODO:
- add RFC2254 binary string handling
- possibly add ~=, <= and >= handling
- expand the test suite
- add better parse error handling
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
/*
a filter is defined by:
<filter> ::= '(' <filtercomp> ')'
<filtercomp> ::= <and> | <or> | <not> | <simple>
<and> ::= '&' <filterlist>
<or> ::= '|' <filterlist>
<not> ::= '!' <filter>
<filterlist> ::= <filter> | <filter> <filterlist>
<simple> ::= <attributetype> <filtertype> <attributevalue>
<filtertype> ::= '=' | '~=' | '<=' | '>='
*/
/*
decode a RFC2254 binary string representation of a buffer.
Used in LDAP filters.
*/
struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str)
{
int i, j;
struct ldb_val ret;
int slen = str?strlen(str):0;
ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
ret.length = 0;
if (ret.data == NULL) return ret;
for (i=j=0;i<slen;i++) {
if (str[i] == '\\') {
unsigned c;
if (sscanf(&str[i+1], "%02X", &c) != 1) {
talloc_free(ret.data);
memset(&ret, 0, sizeof(ret));
return ret;
}
((uint8_t *)ret.data)[j++] = c;
i += 2;
} else {
((uint8_t *)ret.data)[j++] = str[i];
}
}
ret.length = j;
((uint8_t *)ret.data)[j] = 0;
return ret;
}
/*
encode a blob as a RFC2254 binary string, escaping any
non-printable or '\' characters
*/
char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
{
int i;
char *ret;
int len = val.length;
unsigned char *buf = val.data;
for (i=0;i<val.length;i++) {
if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
len += 2;
}
}
ret = talloc_array(mem_ctx, char, len+1);
if (ret == NULL) return NULL;
len = 0;
for (i=0;i<val.length;i++) {
if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
snprintf(ret+len, 4, "\\%02X", buf[i]);
len += 3;
} else {
ret[len++] = buf[i];
}
}
ret[len] = 0;
return ret;
}
/*
encode a string as a RFC2254 binary string, escaping any
non-printable or '\' characters. This routine is suitable for use
in escaping user data in ldap filters.
*/
char *ldb_binary_encode_string(void *mem_ctx, const char *string)
{
struct ldb_val val;
val.data = discard_const_p(uint8_t, string);
val.length = strlen(string);
return ldb_binary_encode(mem_ctx, val);
}
/* find the first matching wildcard */
static char *ldb_parse_find_wildcard(char *value)
{
while (*value) {
value = strpbrk(value, "\\*");
if (value == NULL) return NULL;
if (value[0] == '\\') {
if (value[1] == '\0') return NULL;
value += 2;
continue;
}
if (value[0] == '*') return value;
}
return NULL;
}
/* return a NULL terminated list of binary strings representing the value
chunks separated by wildcards that makes the value portion of the filter
*/
static struct ldb_val **ldb_wildcard_decode(void *mem_ctx, const char *string)
{
struct ldb_val **ret = NULL;
int val = 0;
char *wc, *str;
wc = talloc_strdup(mem_ctx, string);
if (wc == NULL) return NULL;
while (wc && *wc) {
str = wc;
wc = ldb_parse_find_wildcard(str);
if (wc && *wc) {
if (wc == str) {
wc++;
continue;
}
*wc = 0;
wc++;
}
ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
if (ret == NULL) return NULL;
ret[val] = talloc(mem_ctx, struct ldb_val);
if (ret[val] == NULL) return NULL;
*(ret[val]) = ldb_binary_decode(mem_ctx, str);
if ((ret[val])->data == NULL) return NULL;
val++;
}
if (ret != NULL) {
ret[val] = NULL;
}
return ret;
}
static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s);
/*
parse an extended match
possible forms:
(attr:oid:=value)
(attr:dn:oid:=value)
(attr:dn:=value)
(:dn:oid:=value)
the ':dn' part sets the dnAttributes boolean if present
the oid sets the rule_id string
*/
static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
char *attr, char *value)
{
char *p1, *p2;
ret->operation = LDB_OP_EXTENDED;
ret->u.extended.value = ldb_binary_decode(ret, value);
if (ret->u.extended.value.data == NULL) goto failed;
p1 = strchr(attr, ':');
if (p1 == NULL) goto failed;
p2 = strchr(p1+1, ':');
*p1 = 0;
if (p2) *p2 = 0;
ret->u.extended.attr = attr;
if (strcmp(p1+1, "dn") == 0) {
ret->u.extended.dnAttributes = 1;
if (p2) {
ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
if (ret->u.extended.rule_id == NULL) goto failed;
} else {
ret->u.extended.rule_id = NULL;
}
} else {
ret->u.extended.dnAttributes = 0;
ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
if (ret->u.extended.rule_id == NULL) goto failed;
}
return ret;
failed:
talloc_free(ret);
return NULL;
}
static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char **value, const char **s)
{
enum ldb_parse_op filter = 0;
char *name, *val, *k;
const char *p = *s;
const char *t, *t1;
/* retrieve attributetype name */
t = p;
while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */
p++;
}
if (*p == ':') { /* but extended searches have : and . chars too */
p = strstr(p, ":=");
if (p == NULL) { /* malformed attribute name */
return 0;
}
}
t1 = p;
while (isspace((unsigned char)*p)) p++;
if (!strchr("=<>~:", *p)) {
return 0;
}
/* save name */
name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
if (name == NULL) return 0;
name[t1 - t] = '\0';
/* retrieve filtertype */
if (*p == '=') {
filter = LDB_OP_EQUALITY;
} else if (*(p + 1) == '=') {
switch (*p) {
case '<':
filter = LDB_OP_LESS;
p++;
break;
case '>':
filter = LDB_OP_GREATER;
p++;
break;
case '~':
filter = LDB_OP_APPROX;
p++;
break;
case ':':
filter = LDB_OP_EXTENDED;
p++;
break;
}
}
if (!filter) {
talloc_free(name);
return filter;
}
p++;
while (isspace((unsigned char)*p)) p++;
/* retieve value */
t = p;
while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
if (val == NULL) {
talloc_free(name);
return 0;
}
val[p - t] = '\0';
k = &(val[p - t]);
/* remove trailing spaces from value */
while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
*k = '\0';
*type = name;
*value = val;
*s = p;
return filter;
}
/*
<simple> ::= <attributetype> <filtertype> <attributevalue>
*/
static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char **s)
{
char *attr, *value;
struct ldb_parse_tree *ret;
enum ldb_parse_op filtertype;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
if (!filtertype) {
talloc_free(ret);
return NULL;
}
switch (filtertype) {
case LDB_OP_PRESENT:
ret->operation = LDB_OP_PRESENT;
ret->u.present.attr = attr;
break;
case LDB_OP_EQUALITY:
if (strcmp(value, "*") == 0) {
ret->operation = LDB_OP_PRESENT;
ret->u.present.attr = attr;
break;
}
if (ldb_parse_find_wildcard(value) != NULL) {
ret->operation = LDB_OP_SUBSTRING;
ret->u.substring.attr = attr;
ret->u.substring.start_with_wildcard = 0;
ret->u.substring.end_with_wildcard = 0;
ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
if (ret->u.substring.chunks == NULL){
talloc_free(ret);
return NULL;
}
if (value[0] == '*')
ret->u.substring.start_with_wildcard = 1;
if (value[strlen(value) - 1] == '*')
ret->u.substring.end_with_wildcard = 1;
talloc_free(value);
break;
}
ret->operation = LDB_OP_EQUALITY;
ret->u.equality.attr = attr;
ret->u.equality.value = ldb_binary_decode(ret, value);
if (ret->u.equality.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_GREATER:
ret->operation = LDB_OP_GREATER;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_LESS:
ret->operation = LDB_OP_LESS;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_APPROX:
ret->operation = LDB_OP_APPROX;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_EXTENDED:
ret = ldb_parse_extended(ret, attr, value);
break;
default:
talloc_free(ret);
return NULL;
}
return ret;
}
/*
parse a filterlist
<and> ::= '&' <filterlist>
<or> ::= '|' <filterlist>
<filterlist> ::= <filter> | <filter> <filterlist>
*/
static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret, *next;
enum ldb_parse_op op;
const char *p = *s;
switch (*p) {
case '&':
op = LDB_OP_AND;
break;
case '|':
op = LDB_OP_OR;
break;
default:
return NULL;
}
p++;
while (isspace((unsigned char)*p)) p++;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
ret->operation = op;
ret->u.list.num_elements = 1;
ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
if (!ret->u.list.elements) {
errno = ENOMEM;
talloc_free(ret);
return NULL;
}
ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
if (!ret->u.list.elements[0]) {
talloc_free(ret);
return NULL;
}
while (isspace((unsigned char)*p)) p++;
while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) {
struct ldb_parse_tree **e;
e = talloc_realloc(ret, ret->u.list.elements,
struct ldb_parse_tree *,
ret->u.list.num_elements + 1);
if (!e) {
errno = ENOMEM;
talloc_free(ret);
return NULL;
}
ret->u.list.elements = e;
ret->u.list.elements[ret->u.list.num_elements] = next;
ret->u.list.num_elements++;
while (isspace((unsigned char)*p)) p++;
}
*s = p;
return ret;
}
/*
<not> ::= '!' <filter>
*/
static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
if (*p != '!') {
return NULL;
}
p++;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
ret->operation = LDB_OP_NOT;
ret->u.isnot.child = ldb_parse_filter(ret, &p);
if (!ret->u.isnot.child) {
talloc_free(ret);
return NULL;
}
*s = p;
return ret;
}
/*
parse a filtercomp
<filtercomp> ::= <and> | <or> | <not> | <simple>
*/
static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
while (isspace((unsigned char)*p)) p++;
switch (*p) {
case '&':
ret = ldb_parse_filterlist(mem_ctx, &p);
break;
case '|':
ret = ldb_parse_filterlist(mem_ctx, &p);
break;
case '!':
ret = ldb_parse_not(mem_ctx, &p);
break;
case '(':
case ')':
return NULL;
default:
ret = ldb_parse_simple(mem_ctx, &p);
}
*s = p;
return ret;
}
/*
<filter> ::= '(' <filtercomp> ')'
*/
static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
if (*p != '(') {
return NULL;
}
p++;
ret = ldb_parse_filtercomp(mem_ctx, &p);
if (*p != ')') {
return NULL;
}
p++;
while (isspace((unsigned char)*p)) {
p++;
}
*s = p;
return ret;
}
/*
main parser entry point. Takes a search string and returns a parse tree
expression ::= <simple> | <filter>
*/
struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s)
{
if (s == NULL || *s == 0) {
s = "(|(objectClass=*)(distinguishedName=*))";
}
while (isspace((unsigned char)*s)) s++;
if (*s == '(') {
return ldb_parse_filter(mem_ctx, &s);
}
return ldb_parse_simple(mem_ctx, &s);
}
/*
construct a ldap parse filter given a parse tree
*/
char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree)
{
char *s, *s2, *ret;
int i;
if (tree == NULL) {
return NULL;
}
switch (tree->operation) {
case LDB_OP_AND:
case LDB_OP_OR:
ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
if (ret == NULL) return NULL;
for (i=0;i<tree->u.list.num_elements;i++) {
s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
if (s == NULL) {
talloc_free(ret);
return NULL;
}
s2 = talloc_asprintf_append(ret, "%s", s);
talloc_free(s);
if (s2 == NULL) {
talloc_free(ret);
return NULL;
}
ret = s2;
}
s = talloc_asprintf_append(ret, ")");
if (s == NULL) {
talloc_free(ret);
return NULL;
}
return s;
case LDB_OP_NOT:
s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(!%s)", s);
talloc_free(s);
return ret;
case LDB_OP_EQUALITY:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_SUBSTRING:
ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
tree->u.substring.start_with_wildcard?"*":"");
if (ret == NULL) return NULL;
for (i = 0; tree->u.substring.chunks[i]; i++) {
s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
if (s2 == NULL) {
talloc_free(ret);
return NULL;
}
if (tree->u.substring.chunks[i+1] ||
tree->u.substring.end_with_wildcard) {
s = talloc_asprintf_append(ret, "%s*", s2);
} else {
s = talloc_asprintf_append(ret, "%s", s2);
}
if (s == NULL) {
talloc_free(ret);
return NULL;
}
ret = s;
}
s = talloc_asprintf_append(ret, ")");
if (s == NULL) {
talloc_free(ret);
return NULL;
}
ret = s;
return ret;
case LDB_OP_GREATER:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_LESS:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_PRESENT:
ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
return ret;
case LDB_OP_APPROX:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_EXTENDED:
s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
tree->u.extended.attr?tree->u.extended.attr:"",
tree->u.extended.dnAttributes?":dn":"",
tree->u.extended.rule_id?":":"",
tree->u.extended.rule_id?tree->u.extended.rule_id:"",
s);
talloc_free(s);
return ret;
}
return NULL;
}
/*
replace any occurances of an attribute name in the parse tree with a
new name
*/
void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
const char *attr,
const char *replace)
{
int i;
switch (tree->operation) {
case LDB_OP_AND:
case LDB_OP_OR:
for (i=0;i<tree->u.list.num_elements;i++) {
ldb_parse_tree_attr_replace(tree->u.list.elements[i],
attr, replace);
}
break;
case LDB_OP_NOT:
ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace);
break;
case LDB_OP_EQUALITY:
case LDB_OP_GREATER:
case LDB_OP_LESS:
case LDB_OP_APPROX:
if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
tree->u.equality.attr = replace;
}
break;
case LDB_OP_SUBSTRING:
if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
tree->u.substring.attr = replace;
}
break;
case LDB_OP_PRESENT:
if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) {
tree->u.present.attr = replace;
}
break;
case LDB_OP_EXTENDED:
if (tree->u.extended.attr &&
ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
tree->u.extended.attr = replace;
}
break;
}
}
+138
View File
@@ -0,0 +1,138 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb utf8 handling
*
* Description: case folding and case comparison for UTF8 strings
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
/*
this allow the user to pass in a caseless comparison
function to handle utf8 caseless comparisons
*/
void ldb_set_utf8_fns(struct ldb_context *ldb,
void *context,
char *(*casefold)(void *, void *, const char *))
{
if (context)
ldb->utf8_fns.context = context;
if (casefold)
ldb->utf8_fns.casefold = casefold;
}
/*
a simple case folding function
NOTE: does not handle UTF8
*/
char *ldb_casefold_default(void *context, void *mem_ctx, const char *s)
{
int i;
char *ret = talloc_strdup(mem_ctx, s);
if (!s) {
errno = ENOMEM;
return NULL;
}
for (i=0;ret[i];i++) {
ret[i] = toupper((unsigned char)ret[i]);
}
return ret;
}
void ldb_set_utf8_default(struct ldb_context *ldb)
{
ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default);
}
char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s)
{
return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s);
}
/*
check the attribute name is valid according to rfc2251
returns 1 if the name is ok
*/
int ldb_valid_attr_name(const char *s)
{
int i;
if (!s || !s[0])
return 0;
/* handle special ldb_tdb wildcard */
if (strcmp(s, "*") == 0) return 1;
for (i = 0; s[i]; i++) {
if (! isascii(s[i])) {
return 0;
}
if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */
if (! (isalpha(s[i]) || (s[i] == '@'))) {
return 0;
}
} else {
if (! (isalnum(s[i]) || (s[i] == '-'))) {
return 0;
}
}
}
return 1;
}
char *ldb_attr_casefold(void *mem_ctx, const char *s)
{
int i;
char *ret = talloc_strdup(mem_ctx, s);
if (!ret) {
errno = ENOMEM;
return NULL;
}
for (i = 0; ret[i]; i++) {
ret[i] = toupper((unsigned char)ret[i]);
}
return ret;
}
/*
we accept either 'dn' or 'distinguishedName' for a distinguishedName
*/
int ldb_attr_dn(const char *attr)
{
if (ldb_attr_cmp(attr, "dn") == 0 ||
ldb_attr_cmp(attr, "distinguishedName") == 0) {
return 0;
}
return -1;
}
+254
View File
@@ -0,0 +1,254 @@
/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* If you consider tuning this algorithm, you should consult first:
Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
/* Modified to be used in samba4 by
* Simo Sorce <idra@samba.org> 2005
*/
#include "includes.h"
#include "ldb/include/includes.h"
/* Byte-wise swap two items of size SIZE. */
#define SWAP(a, b, size) \
do \
{ \
register size_t __size = (size); \
register char *__a = (a), *__b = (b); \
do \
{ \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
/* Discontinue quicksort algorithm when partition gets below this size.
This particular magic number was chosen to work best on a Sun 4/260. */
#define MAX_THRESH 4
/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
{
char *lo;
char *hi;
} stack_node;
/* The next 4 #defines implement a very fast in-line stack abstraction. */
/* The stack needs log (total_elements) entries (we could even subtract
log(MAX_THRESH)). Since total_elements has type size_t, we get as
upper bound for log (total_elements):
bits per byte (CHAR_BIT) * sizeof(size_t). */
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY (stack < top)
/* Order size using quicksort. This implementation incorporates
four optimizations discussed in Sedgewick:
1. Non-recursive, using an explicit stack of pointer that store the
next array partition to sort. To save time, this maximum amount
of space required to store an array of SIZE_MAX is allocated on the
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
Pretty cheap, actually.
2. Chose the pivot element using a median-of-three decision tree.
This reduces the probability of selecting a bad pivot value and
eliminates certain extraneous comparisons.
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
insertion sort to order the MAX_THRESH items within each partition.
This is a big win, since insertion sort is faster for small, mostly
sorted array segments.
4. The larger of the two sub-partitions is always pushed onto the
stack first, with the algorithm then concentrating on the
smaller partition. This *guarantees* no more than log (total_elems)
stack size is needed (actually O(1) in this case)! */
void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
void *opaque, ldb_qsort_cmp_fn_t cmp)
{
register char *base_ptr = (char *) pbase;
const size_t max_thresh = MAX_THRESH * size;
if (total_elems == 0)
/* Avoid lossage with unsigned arithmetic below. */
return;
if (total_elems > MAX_THRESH)
{
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH (NULL, NULL);
while (STACK_NOT_EMPTY)
{
char *left_ptr;
char *right_ptr;
/* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR in
the while loops. */
char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
SWAP (mid, lo, size);
if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
SWAP (mid, hi, size);
else
goto jump_over;
if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
SWAP (mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{
SWAP (left_ptr, right_ptr, size);
if (mid == left_ptr)
mid = right_ptr;
else if (mid == right_ptr)
mid = left_ptr;
left_ptr += size;
right_ptr -= size;
}
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
}
while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t) (right_ptr - lo) <= max_thresh)
{
if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP (lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH (lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH (left_ptr, hi);
hi = right_ptr;
}
}
}
/* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient
for partitions below MAX_THRESH size. BASE_PTR points to the beginning
of the array to sort, and END_PTR points at the very last element in
the array (*not* one beyond it!). */
#define min(x, y) ((x) < (y) ? (x) : (y))
{
char *const end_ptr = &base_ptr[size * (total_elems - 1)];
char *tmp_ptr = base_ptr;
char *thresh = min(end_ptr, base_ptr + max_thresh);
register char *run_ptr;
/* Find smallest element in first threshold and place it at the
array's beginning. This is the smallest array element,
and the operation speeds up insertion sort's inner loop. */
for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr = run_ptr;
if (tmp_ptr != base_ptr)
SWAP (tmp_ptr, base_ptr, size);
/* Insertion sort, running from left-hand-side up to right-hand-side. */
run_ptr = base_ptr + size;
while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr -= size;
tmp_ptr += size;
if (tmp_ptr != run_ptr)
{
char *trav;
trav = run_ptr + size;
while (--trav >= run_ptr)
{
char c = *trav;
char *hi, *lo;
for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
}
}
}
}
}
+1466
View File
File diff suppressed because it is too large Load Diff
+316
View File
@@ -0,0 +1,316 @@
################################################
# Start MODULE ldb_asq
[MODULE::ldb_asq]
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_asq_init
SUBSYSTEM = ldb
OBJ_FILES = \
modules/asq.o
# End MODULE ldb_asq
################################################
################################################
# Start MODULE ldb_server_sort
[MODULE::ldb_server_sort]
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_sort_init
SUBSYSTEM = ldb
OBJ_FILES = \
modules/sort.o
# End MODULE ldb_sort
################################################
################################################
# Start MODULE ldb_paged_results
[MODULE::ldb_paged_results]
INIT_FUNCTION = ldb_paged_results_init
PRIVATE_DEPENDENCIES = LIBTALLOC
SUBSYSTEM = ldb
OBJ_FILES = \
modules/paged_results.o
# End MODULE ldb_paged_results
################################################
################################################
# Start MODULE ldb_paged_results
[MODULE::ldb_paged_searches]
INIT_FUNCTION = ldb_paged_searches_init
PRIVATE_DEPENDENCIES = LIBTALLOC
SUBSYSTEM = ldb
OBJ_FILES = \
modules/paged_searches.o
# End MODULE ldb_paged_results
################################################
################################################
# Start MODULE ldb_operational
[MODULE::ldb_operational]
SUBSYSTEM = ldb
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_operational_init
OBJ_FILES = \
modules/operational.o
# End MODULE ldb_operational
################################################
################################################
# Start MODULE ldb_objectclass
[MODULE::ldb_objectclass]
INIT_FUNCTION = ldb_objectclass_init
PRIVATE_DEPENDENCIES = LIBTALLOC
SUBSYSTEM = ldb
OBJ_FILES = \
modules/objectclass.o
# End MODULE ldb_objectclass
################################################
################################################
# Start MODULE ldb_rdn_name
[MODULE::ldb_rdn_name]
SUBSYSTEM = ldb
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_rdn_name_init
OBJ_FILES = \
modules/rdn_name.o
# End MODULE ldb_rdn_name
################################################
################################################
# Start MODULE ldb_ildap
[MODULE::ldb_ildap]
SUBSYSTEM = ldb
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_ildap_init
ALIASES = ldapi ldaps ldap
OBJ_FILES = \
ldb_ildap/ldb_ildap.o
PUBLIC_DEPENDENCIES = \
LIBCLI_LDAP
# End MODULE ldb_ildap
################################################
################################################
# Start MODULE ldb_map
[MODULE::ldb_map]
PRIVATE_DEPENDENCIES = LIBTALLOC
SUBSYSTEM = ldb
OBJ_FILES = \
modules/ldb_map_inbound.o \
modules/ldb_map_outbound.o \
modules/ldb_map.o
# End MODULE ldb_map
################################################
################################################
# Start MODULE ldb_skel
[MODULE::ldb_skel]
SUBSYSTEM = ldb
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_skel_init
OBJ_FILES = modules/skel.o
# End MODULE ldb_skel
################################################
################################################
# Start MODULE ldb_sqlite3
[MODULE::ldb_sqlite3]
SUBSYSTEM = ldb
PRIVATE_DEPENDENCIES = LIBTALLOC
INIT_FUNCTION = ldb_sqlite3_init
OBJ_FILES = \
ldb_sqlite3/ldb_sqlite3.o
PUBLIC_DEPENDENCIES = \
SQLITE3 LIBTALLOC
# End MODULE ldb_sqlite3
################################################
################################################
# Start MODULE ldb_tdb
[MODULE::ldb_tdb]
SUBSYSTEM = ldb
INIT_FUNCTION = ldb_tdb_init
OBJ_FILES = \
ldb_tdb/ldb_tdb.o \
ldb_tdb/ldb_search.o \
ldb_tdb/ldb_pack.o \
ldb_tdb/ldb_index.o \
ldb_tdb/ldb_cache.o \
ldb_tdb/ldb_tdb_wrap.o
PUBLIC_DEPENDENCIES = \
LIBTDB LIBTALLOC
# End MODULE ldb_tdb
################################################
./lib/ldb/common/ldb_modules.o: lib/ldb/common/ldb_modules.c Makefile
@echo Compiling $<
@$(CC) -Iinclude $(CFLAGS) -Ilib/replace -Ilib/talloc -Ilib/ldb $(PICFLAG) -DLDBMODULESDIR=\"$(MODULESDIR)/ldb\" -DSHLIBEXT=\"$(SHLIBEXT)\" -c $< -o $@
################################################
# Start SUBSYSTEM ldb
[LIBRARY::ldb]
VERSION = 0.0.1
SO_VERSION = 0
DESCRIPTION = LDAP-like embedded database library
INIT_FUNCTION_TYPE = int (*) (void)
OBJ_FILES = \
common/ldb.o \
common/ldb_ldif.o \
common/ldb_parse.o \
common/ldb_msg.o \
common/ldb_utf8.o \
common/ldb_debug.o \
common/ldb_modules.o \
common/ldb_match.o \
common/ldb_attributes.o \
common/attrib_handlers.o \
common/ldb_dn.o \
common/ldb_controls.o \
common/qsort.o
PUBLIC_DEPENDENCIES = \
LIBTALLOC
PRIVATE_DEPENDENCIES = \
DYNCONFIG \
SOCKET_WRAPPER
MANPAGE = man/ldb.3
PUBLIC_HEADERS = include/ldb.h include/ldb_errors.h
#
# End SUBSYSTEM ldb
################################################
################################################
# Start SUBSYSTEM LDBSAMBA
[SUBSYSTEM::LDBSAMBA]
PRIVATE_DEPENDENCIES = ldb
PRIVATE_PROTO_HEADER = samba/ldif_handlers.h
PRIVATE_DEPENDENCIES = LIBSECURITY SAMDB
OBJ_FILES = \
samba/ldif_handlers.o
# End SUBSYSTEM LDBSAMBA
################################################
################################################
# Start SUBSYSTEM LIBLDB_CMDLINE
[SUBSYSTEM::LIBLDB_CMDLINE]
OBJ_FILES= \
tools/cmdline.o
PUBLIC_DEPENDENCIES = ldb LIBPOPT
PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL POPT_SAMBA POPT_CREDENTIALS gensec
# End SUBSYSTEM LIBLDB_CMDLINE
################################################
################################################
# Start BINARY ldbadd
[BINARY::ldbadd]
INSTALLDIR = BINDIR
OBJ_FILES = \
tools/ldbadd.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE LIBCLI_RESOLVE
MANPAGE = man/ldbadd.1
# End BINARY ldbadd
################################################
################################################
# Start BINARY ldbdel
[BINARY::ldbdel]
INSTALLDIR = BINDIR
OBJ_FILES= \
tools/ldbdel.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
MANPAGE = man/ldbdel.1
# End BINARY ldbdel
################################################
################################################
# Start BINARY ldbmodify
[BINARY::ldbmodify]
INSTALLDIR = BINDIR
OBJ_FILES= \
tools/ldbmodify.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
MANPAGE = man/ldbmodify.1
# End BINARY ldbmodify
################################################
################################################
# Start BINARY ldbsearch
[BINARY::ldbsearch]
INSTALLDIR = BINDIR
OBJ_FILES= \
tools/ldbsearch.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
MANPAGE = man/ldbsearch.1
# End BINARY ldbsearch
################################################
################################################
# Start BINARY ldbedit
[BINARY::ldbedit]
INSTALLDIR = BINDIR
OBJ_FILES= \
tools/ldbedit.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
MANPAGE = man/ldbedit.1
# End BINARY ldbedit
################################################
################################################
# Start BINARY ldbrename
[BINARY::ldbrename]
INSTALLDIR = BINDIR
OBJ_FILES= \
tools/ldbrename.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
MANPAGE = man/ldbrename.1
# End BINARY ldbrename
################################################
################################################
# Start BINARY ldbtest
[BINARY::ldbtest]
OBJ_FILES= \
tools/ldbtest.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
# End BINARY ldbtest
################################################
################################################
# Start BINARY oLschema2ldif
[BINARY::oLschema2ldif]
INSTALLDIR = BINDIR
MANPAGE = man/oLschema2ldif.1
OBJ_FILES= \
tools/convert.o \
tools/oLschema2ldif.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
# End BINARY oLschema2ldif
################################################
################################################
# Start BINARY ad2oLschema
[BINARY::ad2oLschema]
INSTALLDIR = BINDIR
MANPAGE = man/ad2oLschema.1
OBJ_FILES= \
tools/convert.o \
tools/ad2oLschema.o
PRIVATE_DEPENDENCIES = \
LIBLDB_CMDLINE
# End BINARY ad2oLschema
################################################
#######################
# Start LIBRARY swig_ldb
[LIBRARY::swig_ldb]
PUBLIC_DEPENDENCIES = ldb DYNCONFIG
LIBRARY_REALNAME = swig/_ldb.$(SHLIBEXT)
OBJ_FILES = swig/ldb_wrap.o
# End LIBRARY swig_ldb
#######################
+1579
View File
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
AC_PREREQ(2.50)
AC_DEFUN([AC_CHECK_LIB_EXT], [
AC_CHECK_LIB([$1],[$3],[$4],[$5],[$7])
ac_cv_lib_ext_$1_$3=$ac_cv_lib_$1_$3
])
AC_DEFUN([AC_CHECK_FUNC_EXT], [
AC_CHECK_FUNC([$1],[$3],[$4])
ac_cv_func_ext_$1=$ac_cv_func_$1
])
AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
AC_DEFUN([SMB_ENABLE], [echo -n ""])
AC_INIT(include/ldb.h)
AC_CONFIG_SRCDIR([common/ldb.c])
AC_LIBREPLACE_ALL_CHECKS
if test "$ac_cv_prog_gcc" = yes; then
CFLAGS="$CFLAGS -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings"
fi
WITH_GCOV=0
AC_ARG_ENABLE(gcov,
AS_HELP_STRING([--enable-gcov],[enable GCOV code coverage tests]),
[ WITH_GCOV=1])
AC_SUBST(WITH_GCOV)
if test x"$with_gcov_support" = x"yes"; then
CFLAGS="$CFLAGS -ftest-coverage -fprofile-arcs"
LIBS="$LIBS -lgcov"
fi
AC_PATH_PROG(XSLTPROC,xsltproc)
AC_PATH_PROG(DOXYGEN,doxygen)
AC_PATH_PROG(GCOV,gcov)
AC_PATH_PROG(SLAPD,slapd)
AC_CHECK_HEADERS(stdint.h dlfcn.h)
AC_CONFIG_HEADER(include/config.h)
AC_SEARCH_LIBS(dlopen, dl, AC_DEFINE(HAVE_DLOPEN, [1], [have dlopen]))
SHLIBEXT="so" # Should be set based on OS later on
AC_SUBST(SHLIBEXT)
AC_DEFINE_UNQUOTED(MODULESDIR, LIBDIR "/ldb" , [Modules directory] )
AC_SUBST(MODULESDIR)
TESTS=""
EXTRA_OBJ=""
m4_include(libpopt.m4)
m4_include(libtalloc.m4)
m4_include(libtdb.m4)
m4_include(ldap.m4)
if test x"$with_ldap_support" = x"yes"; then
LIBS="$LIBS -llber -lldap"
CFLAGS="$CFLAGS -DHAVE_LDB_LDAP=1"
EXTRA_OBJ="$EXTRA_OBJ ldb_ldap/ldb_ldap.o"
TESTS="$TESTS test-ldap.sh"
fi
m4_include(sqlite3.m4)
if test x"$with_sqlite3_support" = x"yes"; then
LIBS="$LIBS -lsqlite3"
CFLAGS="$CFLAGS -DHAVE_LDB_SQLITE3=1"
EXTRA_OBJ="$EXTRA_OBJ ldb_sqlite3/ldb_sqlite3.o"
TESTS="$TESTS test-sqlite3.sh"
fi
AC_SUBST(TESTS)
AC_SUBST(EXTRA_OBJ)
m4_include(libldb.m4)
AC_OUTPUT(Makefile ldb.pc)
+52
View File
@@ -0,0 +1,52 @@
#!/bin/sh
# build ldb docs
# tridge@samba.org August 2006
XSLTPROC="$1"
SRCDIR="$2"
if [ -z "$XSLTPROC" ] || [ ! -x "$XSLTPROC" ]; then
echo "xsltproc not installed"
exit 0
fi
MANXSL="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"
HTMLXSL="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"
mkdir -p man
for f in $SRCDIR/man/*.xml; do
base=`basename $f .xml`
out=man/"`basename $base`"
if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
echo Processing manpage $f
$XSLTPROC --nonet -o "$out" "$MANXSL" $f
ret=$?
if [ "$ret" = "4" ]; then
echo "ignoring stylesheet error 4 for $MANXSL"
exit 0
fi
if [ "$ret" != "0" ]; then
echo "xsltproc failed with error $ret"
exit $ret
fi
fi
done
for f in $SRCDIR/man/*.xml; do
base=`basename $f .xml`
out=man/"`basename $base`".html
if [ ! -f "$out" ] || [ "$f" -nt "$out" ]; then
echo Processing html $f
$XSLTPROC --nonet -o "$out" "$HTMLXSL" $f
ret=$?
if [ "$ret" = "4" ]; then
echo "ignoring stylesheet error 4 for $HTMLXSL"
exit 0
fi
if [ "$ret" != "0" ]; then
echo "xsltproc failed with error $ret"
exit $ret
fi
fi
done
+41
View File
@@ -0,0 +1,41 @@
The list of indexed fields
--------------------------
dn=@INDEXLIST
list of field names that are indexed
contains fields of type @IDXATTR which contain attriute names
of indexed fields
Data records
------------
for each user record in the db there is:
main record
key: DN=dn
data: packed attribute/value list
a index record for each indexed field in the record
Index Records
-------------
The index records contain the list of dn's that contain records
matching the index key
All index records are of the form:
dn=@INDEX:field:value
and contain fields of type @IDX which are the dns of the records
that have that value for some attribute
Search Expressions
------------------
Very similar to LDAP search expressions, but does not allow ~=, <= or >=
attrib0 := (field=value)
attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
# install ldb docs
# tridge@samba.org August 2006
MANDIR="$1"
MAN1="`/bin/ls man/*.1`"
MAN3="`/bin/ls man/*.3`"
if [ -z "$MAN1" ] && [ -z "$MAN3" ]; then
echo "No manpages have been built"
exit 0
fi
mkdir -p "$MANDIR/man1" "$MANDIR/man3"
cp $MAN1 "$MANDIR/man1/" || exit 1
cp $MAN3 "$MANDIR/man3/" || exit 1
+16
View File
@@ -0,0 +1,16 @@
/** \example ldbreader.c
The code below shows a simple LDB application.
It lists / dumps the records in a LDB database to standard output.
*/
/** \example ldifreader.c
The code below shows a simple LDB application.
It lists / dumps the entries in an LDIF file to standard output.
*/
+125
View File
@@ -0,0 +1,125 @@
/*
example code for the ldb database library
Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA
*/
/** \example ldbreader.c
The code below shows a simple LDB application.
It lists / dumps the records in a LDB database to standard output.
*/
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
/*
ldb_ldif_write takes a function pointer to a custom output
function. This version is about as simple as the output function can
be. In a more complex example, you'd likely be doing something with
the private data function (e.g. holding a file handle).
*/
static int vprintf_fn(void *private_data, const char *fmt, ...)
{
int retval;
va_list ap;
va_start(ap, fmt);
/* We just write to standard output */
retval = vprintf(fmt, ap);
va_end(ap);
/* Note that the function should return the number of
bytes written, or a negative error code */
return retval;
}
int main(int argc, const char **argv)
{
struct ldb_context *ldb;
const char *expression = "(dn=*)";
struct ldb_result *resultMsg;
int i;
/*
This is the always the first thing you want to do in an LDB
application - initialise up the context structure.
Note that you can use the context structure as a parent
for talloc allocations as well
*/
ldb = ldb_init(NULL);
/*
We now open the database. In this example we just hard code the connection path.
Also note that the database is being opened read-only. This means that the
call will fail unless the database already exists.
*/
if (LDB_SUCCESS != ldb_connect(ldb, "tdb://tdbtest.ldb", LDB_FLG_RDONLY, NULL) ){
printf("Problem on connection\n");
exit(-1);
}
/*
At this stage we have an open database, and can start using it. It is opened
read-only, so a query is possible.
We construct a search that just returns all the (sensible) contents. You can do
quite fine grained results with the LDAP search syntax, however it is a bit
confusing to start with. See RFC2254.
*/
if (LDB_SUCCESS != ldb_search(ldb, NULL, LDB_SCOPE_DEFAULT,
expression, NULL, &resultMsg) ) {
printf("Problem in search\n");
exit(-1);
}
printf("%i records returned\n", resultMsg->count);
/*
We can now iterate through the results, writing them out
(to standard output) with our custom output routine as defined
at the top of this file
*/
for (i = 0; i < resultMsg->count; ++i) {
struct ldb_ldif ldifMsg;
printf("Message: %i\n", i+1);
ldifMsg.changetype = LDB_CHANGETYPE_NONE;
ldifMsg.msg = resultMsg->msgs[i];
ldb_ldif_write(ldb, vprintf_fn, NULL, &ldifMsg);
}
/*
There are two objects to clean up - the result from the
ldb_search() query, and the original ldb context.
*/
talloc_free(resultMsg);
talloc_free(ldb);
return 0;
}
+129
View File
@@ -0,0 +1,129 @@
/*
example code for the ldb database library
Copyright (C) Brad Hards (bradh@frogmouth.net) 2005-2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA
*/
/** \example ldifreader.c
The code below shows a simple LDB application.
It lists / dumps the entries in an LDIF file to standard output.
*/
#include "includes.h"
#include "ldb/include/ldb.h"
#include "ldb/include/ldb_errors.h"
/*
ldb_ldif_write takes a function pointer to a custom output
function. This version is about as simple as the output function can
be. In a more complex example, you'd likely be doing something with
the private data function (e.g. holding a file handle).
*/
static int vprintf_fn(void *private_data, const char *fmt, ...)
{
int retval;
va_list ap;
va_start(ap, fmt);
/* We just write to standard output */
retval = vprintf(fmt, ap);
va_end(ap);
/* Note that the function should return the number of
bytes written, or a negative error code */
return retval;
}
int main(int argc, const char **argv)
{
struct ldb_context *ldb;
FILE *fileStream;
struct ldb_ldif *ldifMsg;
if (argc != 2) {
printf("Usage %s filename.ldif\n", argv[0]);
exit(1);
}
/*
This is the always the first thing you want to do in an LDB
application - initialise up the context structure.
Note that you can use the context structure as a parent
for talloc allocations as well
*/
ldb = ldb_init(NULL);
fileStream = fopen(argv[1], "r");
if (0 == fileStream) {
perror(argv[1]);
exit(1);
}
/*
We now work through the filestream to get each entry.
*/
while ( (ldifMsg = ldb_ldif_read_file(ldb, fileStream)) ) {
/*
Each message has a particular change type. For Add,
Modify and Delete, this will also appear in the
output listing (as changetype: add, changetype:
modify or changetype:delete, respectively).
*/
switch (ldifMsg->changetype) {
case LDB_CHANGETYPE_NONE:
printf("ChangeType: None\n");
break;
case LDB_CHANGETYPE_ADD:
printf("ChangeType: Add\n");
break;
case LDB_CHANGETYPE_MODIFY:
printf("ChangeType: Modify\n");
break;
case LDB_CHANGETYPE_DELETE:
printf("ChangeType: Delete\n");
break;
default:
printf("ChangeType: Unknown\n");
}
/*
We can now write out the results, using our custom
output routine as defined at the top of this file.
*/
ldb_ldif_write(ldb, vprintf_fn, NULL, ldifMsg);
/*
Clean up the message
*/
ldb_ldif_read_free(ldb, ldifMsg);
}
/*
Clean up the context
*/
talloc_free(ldb);
return 0;
}
+111
View File
@@ -0,0 +1,111 @@
/*
Unix SMB/CIFS implementation.
some simple double linked list macros
Copyright (C) Andrew Tridgell 1998
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* To use these macros you must have a structure containing a next and
prev pointer */
/* hook into the front of the list */
#define DLIST_ADD(list, p) \
do { \
if (!(list)) { \
(list) = (p); \
(p)->next = (p)->prev = NULL; \
} else { \
(list)->prev = (p); \
(p)->next = (list); \
(p)->prev = NULL; \
(list) = (p); \
}\
} while (0)
/* remove an element from a list - element doesn't have to be in list. */
#ifndef DLIST_REMOVE
#define DLIST_REMOVE(list, p) \
do { \
if ((p) == (list)) { \
(list) = (p)->next; \
if (list) (list)->prev = NULL; \
} else { \
if ((p)->prev) (p)->prev->next = (p)->next; \
if ((p)->next) (p)->next->prev = (p)->prev; \
} \
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
} while (0)
#endif
/* promote an element to the top of the list */
#define DLIST_PROMOTE(list, p) \
do { \
DLIST_REMOVE(list, p); \
DLIST_ADD(list, p); \
} while (0)
/* hook into the end of the list - needs a tmp pointer */
#define DLIST_ADD_END(list, p, type) \
do { \
if (!(list)) { \
(list) = (p); \
(p)->next = (p)->prev = NULL; \
} else { \
type tmp; \
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
tmp->next = (p); \
(p)->next = NULL; \
(p)->prev = tmp; \
} \
} while (0)
/* insert 'p' after the given element 'el' in a list. If el is NULL then
this is the same as a DLIST_ADD() */
#define DLIST_ADD_AFTER(list, p, el) \
do { \
if (!(list) || !(el)) { \
DLIST_ADD(list, p); \
} else { \
p->prev = el; \
p->next = el->next; \
el->next = p; \
if (p->next) p->next->prev = p; \
}\
} while (0)
/* demote an element to the end of the list, needs a tmp pointer */
#define DLIST_DEMOTE(list, p, tmp) \
do { \
DLIST_REMOVE(list, p); \
DLIST_ADD_END(list, p, tmp); \
} while (0)
/* concatenate two lists - putting all elements of the 2nd list at the
end of the first list */
#define DLIST_CONCATENATE(list1, list2, type) \
do { \
if (!(list1)) { \
(list1) = (list2); \
} else { \
type tmp; \
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
tmp->next = (list2); \
if (list2) { \
(list2)->prev = tmp; \
} \
} \
} while (0)
+34
View File
@@ -0,0 +1,34 @@
#ifndef _LDB_PRIVATE_INCLUDES_H_
#define _LDB_PRIVATE_INCLUDES_H_
/*
a temporary includes file until I work on the ldb build system
*/
#if (_SAMBA_BUILD_ >= 4)
/* tell ldb we have the internal ldap code */
#define HAVE_ILDAP 1
#endif
#if (_SAMBA_BUILD_ <= 3)
/* allow forbidden string functions - should be replaced with _m functions */
#undef strcasecmp
#undef strncasecmp
#define dyn_MODULESDIR dyn_LIBDIR
#endif
#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
#include "replace.h"
#include "system/filesys.h"
#include "system/network.h"
#include "system/time.h"
#include "talloc.h"
#include "ldb.h"
#include "ldb_errors.h"
#include "ldb_private.h"
#include "dlinklist.h"
#endif /*_LDB_PRIVATE_INCLUDES_H_*/
File diff suppressed because it is too large Load Diff
+311
View File
@@ -0,0 +1,311 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb header
*
* Description: defines error codes following RFC 2251 ldap error codes
*
* Author: Simo Sorce
*/
#ifndef _LDB_ERRORS_H_
/*! \cond DOXYGEN_IGNORE */
#define _LDB_ERRORS_H_ 1
/*! \endcond */
/**
\file ldb_errors.h
This header provides a set of result codes for LDB function calls.
Many LDB function calls return an integer value (int). As shown in
the function documentation, those return values may indicate
whether the function call worked correctly (in which case it
returns LDB_SUCCESS) or some problem occurred (in which case some
other value will be returned). As a special case,
LDB_ERR_COMPARE_FALSE or LDB_ERR_COMPARE_TRUE may be returned,
which does not indicate an error.
\note Not all error codes make sense for LDB, however they are
based on the LDAP error codes, and are kept for reference and to
avoid overlap.
\note Some of this documentation is based on information in
the OpenLDAP documentation, as developed and maintained by the
<a href="http://www.openldap.org/">The OpenLDAP Project</a>.
*/
/**
The function call succeeded.
If a function returns LDB_SUCCESS, then that function, and the
underlying transactions that may have been required, completed
successfully.
*/
#define LDB_SUCCESS 0
/**
The function call failed for some non-specific reason.
*/
#define LDB_ERR_OPERATIONS_ERROR 1
/**
The function call failed because of a protocol violation.
*/
#define LDB_ERR_PROTOCOL_ERROR 2
/**
The function call failed because a time limit was exceeded.
*/
#define LDB_ERR_TIME_LIMIT_EXCEEDED 3
/**
The function call failed because a size limit was exceeded.
*/
#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4
/**
The function was for value comparison, and the comparison operation
returned false.
\note This is a status value, and doesn't normally indicate an
error.
*/
#define LDB_ERR_COMPARE_FALSE 5
/**
The function was for value comparison, and the comparison operation
returned true.
\note This is a status value, and doesn't normally indicate an
error.
*/
#define LDB_ERR_COMPARE_TRUE 6
/**
The function used an authentication method that is not supported by
the database.
*/
#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7
/**
The function call required a underlying operation that required
strong authentication.
This will normally only occur if you are using LDB with a LDAP
backend.
*/
#define LDB_ERR_STRONG_AUTH_REQUIRED 8
/* 9 RESERVED */
/**
The function resulted in a referral to another server.
*/
#define LDB_ERR_REFERRAL 10
/**
The function failed because an administrative / policy limit was
exceeded.
*/
#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
/**
The function required an extension or capability that the
database cannot provide.
*/
#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
/**
The function involved a transaction or database operation that
could not be performed without a secure link.
*/
#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
/**
This is an intermediate result code for SASL bind operations that
have more than one step.
\note This is a result code that does not normally indicate an
error has occurred.
*/
#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
/**
The function referred to an attribute type that is not present in
the entry.
*/
#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
/**
The function referred to an attribute type that is invalid
*/
#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17
/**
The function required a filter type that is not available for the
specified attribute.
*/
#define LDB_ERR_INAPPROPRIATE_MATCHING 18
/**
The function would have violated an attribute constraint.
*/
#define LDB_ERR_CONSTRAINT_VIOLATION 19
/**
The function involved an attribute type or attribute value that
already exists in the entry.
*/
#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20
/**
The function used an invalid (incorrect syntax) attribute value.
*/
#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21
/* 22-31 unused */
/**
The function referred to an object that does not exist in the
database.
*/
#define LDB_ERR_NO_SUCH_OBJECT 32
/**
The function referred to an alias which points to a non-existant
object in the database.
*/
#define LDB_ERR_ALIAS_PROBLEM 33
/**
The function used a DN which was invalid (incorrect syntax).
*/
#define LDB_ERR_INVALID_DN_SYNTAX 34
/* 35 RESERVED */
/**
The function required dereferencing of an alias, and something went
wrong during the dereferencing process.
*/
#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36
/* 37-47 unused */
/**
The function passed in the wrong authentication method.
*/
#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48
/**
The function passed in or referenced incorrect credentials during
authentication.
*/
#define LDB_ERR_INVALID_CREDENTIALS 49
/**
The function required access permissions that the user does not
possess.
*/
#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50
/**
The function required a transaction or call that the database could
not perform because it is busy.
*/
#define LDB_ERR_BUSY 51
/**
The function required a transaction or call to a database that is
not available.
*/
#define LDB_ERR_UNAVAILABLE 52
/**
The function required a transaction or call to a database that the
database declined to perform.
*/
#define LDB_ERR_UNWILLING_TO_PERFORM 53
/**
The function failed because it resulted in a loop being detected.
*/
#define LDB_ERR_LOOP_DETECT 54
/* 55-63 unused */
/**
The function failed because it would have violated a naming rule.
*/
#define LDB_ERR_NAMING_VIOLATION 64
/**
The function failed because it would have violated the schema.
*/
#define LDB_ERR_OBJECT_CLASS_VIOLATION 65
/**
The function required an operation that is only allowed on leaf
objects, but the object is not a leaf.
*/
#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66
/**
The function required an operation that cannot be performed on a
Relative DN, but the object is a Relative DN.
*/
#define LDB_ERR_NOT_ALLOWED_ON_RDN 67
/**
The function failed because the entry already exists.
*/
#define LDB_ERR_ENTRY_ALREADY_EXISTS 68
/**
The function failed because modifications to an object class are
not allowable.
*/
#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69
/* 70 RESERVED FOR CLDAP */
/**
The function failed because it needed to be applied to multiple
databases.
*/
#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71
/* 72-79 unused */
/**
The function failed for unknown reasons.
*/
#define LDB_ERR_OTHER 80
/* 81-90 RESERVED for APIs */
#endif /* _LDB_ERRORS_H_ */
@@ -0,0 +1,68 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb header
*
* Description: defines attribute handlers
*
* Author: Simo Sorce
*/
int ldb_handler_copy( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
int ldb_handler_fold( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
int ldb_canonicalise_Integer( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
int ldb_comparison_Integer( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_comparison_binary( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_comparison_fold( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_canonicalise_dn( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
int ldb_comparison_dn( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_comparison_objectclass( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_comparison_utctime( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
int ldb_canonicalise_utctime( struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
+225
View File
@@ -0,0 +1,225 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
Copyright (C) Stefan Metzmacher 2004
Copyright (C) Simo Sorce 2004-2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb private header
*
* Description: defines internal ldb structures used by the subsystem and modules
*
* Author: Andrew Tridgell
* Author: Stefan Metzmacher
*/
#ifndef _LDB_PRIVATE_H_
#define _LDB_PRIVATE_H_ 1
struct ldb_context;
struct ldb_module_ops;
/* basic module structure */
struct ldb_module {
struct ldb_module *prev, *next;
struct ldb_context *ldb;
void *private_data;
const struct ldb_module_ops *ops;
};
/*
these function pointers define the operations that a ldb module must perform
they correspond exactly to the ldb_*() interface
*/
struct ldb_module_ops {
const char *name;
int (*init_context) (struct ldb_module *);
int (*search)(struct ldb_module *, struct ldb_request *); /* search */
int (*add)(struct ldb_module *, struct ldb_request *); /* add */
int (*modify)(struct ldb_module *, struct ldb_request *); /* modify */
int (*del)(struct ldb_module *, struct ldb_request *); /* delete */
int (*rename)(struct ldb_module *, struct ldb_request *); /* rename */
int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */
int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */
int (*start_transaction)(struct ldb_module *);
int (*end_transaction)(struct ldb_module *);
int (*del_transaction)(struct ldb_module *);
int (*wait)(struct ldb_handle *, enum ldb_wait_type);
int (*sequence_number)(struct ldb_module *, struct ldb_request *);
};
typedef int (*ldb_connect_fn) (struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[],
struct ldb_module **module);
/*
schema related information needed for matching rules
*/
struct ldb_schema {
/* attribute handling table */
unsigned num_attrib_handlers;
struct ldb_attrib_handler *attrib_handlers;
/* objectclass information */
unsigned num_classes;
struct ldb_subclass {
char *name;
char **subclasses;
} *classes;
};
/*
every ldb connection is started by establishing a ldb_context
*/
struct ldb_context {
/* the operations provided by the backend */
struct ldb_module *modules;
/* debugging operations */
struct ldb_debug_ops debug_ops;
/* custom utf8 functions */
struct ldb_utf8_fns utf8_fns;
/* backend specific opaque parameters */
struct ldb_opaque {
struct ldb_opaque *next;
const char *name;
void *value;
} *opaque;
struct ldb_schema schema;
char *err_string;
int transaction_active;
int default_timeout;
unsigned int flags;
unsigned int create_perms;
};
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
/*
simplify out of memory handling
*/
#define ldb_oom(ldb) ldb_debug_set(ldb, LDB_DEBUG_FATAL, "ldb out of memory at %s:%d\n", __FILE__, __LINE__)
/* The following definitions come from lib/ldb/common/ldb.c */
int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[],
struct ldb_module **backend_module);
/* The following definitions come from lib/ldb/common/ldb_modules.c */
const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string);
int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out);
int ldb_load_modules(struct ldb_context *ldb, const char *options[]);
int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module);
int ldb_next_request(struct ldb_module *module, struct ldb_request *request);
int ldb_next_start_trans(struct ldb_module *module);
int ldb_next_end_trans(struct ldb_module *module);
int ldb_next_del_trans(struct ldb_module *module);
int ldb_next_init(struct ldb_module *module);
void ldb_set_errstring(struct ldb_context *ldb, const char *err_string);
void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
void ldb_reset_err_string(struct ldb_context *ldb);
int ldb_register_module(const struct ldb_module_ops *);
int ldb_register_backend(const char *url_prefix, ldb_connect_fn);
int ldb_try_load_dso(struct ldb_context *ldb, const char *name);
/* The following definitions come from lib/ldb/common/ldb_debug.c */
void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
/* The following definitions come from lib/ldb/common/ldb_ldif.c */
int ldb_should_b64_encode(const struct ldb_val *val);
int ldb_objectclass_init(void);
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);
int ldb_tdb_init(void);
int ldb_sqlite3_init(void);
int ldb_match_msg(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
struct ldb_dn *base,
enum ldb_scope scope);
void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib);
const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
const char *syntax);
int ldb_set_attrib_handlers(struct ldb_context *ldb,
const struct ldb_attrib_handler *handlers,
unsigned num_handlers);
int ldb_setup_wellknown_attributes(struct ldb_context *ldb);
int ldb_set_attrib_handler_syntax(struct ldb_context *ldb,
const char *attr, const char *syntax);
/* The following definitions come from lib/ldb/common/ldb_attributes.c */
const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname);
void ldb_subclass_remove(struct ldb_context *ldb, const char *classname);
int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass);
int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out);
int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2);
/* The following definitions come from lib/ldb/common/ldb_controls.c */
struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid);
int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver);
int check_critical_controls(struct ldb_control **controls);
/* The following definitions come from lib/ldb/common/ldb_utf8.c */
char *ldb_casefold_default(void *context, void *mem_ctx, const char *s);
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el);
/**
Obtain current/next database sequence number
*/
int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num);
#define LDB_SEQ_GLOBAL_SEQUENCE 0x01
#define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02
#endif
+238
View File
@@ -0,0 +1,238 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0
+90
View File
@@ -0,0 +1,90 @@
########################################################
# Compile with LDAP support?
LDAP_LIBS=""
with_ldap_support=auto
AC_MSG_CHECKING([for LDAP support])
AC_ARG_WITH(ldap,
AS_HELP_STRING([--with-ldap],[LDAP backend support (default=yes)]),
[ case "$withval" in
yes|no)
with_ldap_support=$withval
;;
esac ])
AC_MSG_RESULT($with_ldap_support)
if test x"$with_ldap_support" != x"no"; then
##################################################################
# first test for ldap.h and lber.h
# (ldap.h is required for this test)
AC_CHECK_HEADERS(ldap.h lber.h)
if test x"$ac_cv_header_ldap_h" != x"yes"; then
if test x"$with_ldap_support" = x"yes"; then
AC_MSG_ERROR(ldap.h is needed for LDAP support)
else
AC_MSG_WARN(ldap.h is needed for LDAP support)
fi
with_ldap_support=no
fi
fi
if test x"$with_ldap_support" != x"no"; then
ac_save_LIBS=$LIBS
##################################################################
# we might need the lber lib on some systems. To avoid link errors
# this test must be before the libldap test
AC_CHECK_LIB_EXT(lber, LDAP_LIBS, ber_scanf)
########################################################
# now see if we can find the ldap libs in standard paths
AC_CHECK_LIB_EXT(ldap, LDAP_LIBS, ldap_init)
AC_CHECK_FUNC_EXT(ldap_domain2hostlist,$LDAP_LIBS)
########################################################
# If we have LDAP, does it's rebind procedure take 2 or 3 arguments?
# Check found in pam_ldap 145.
AC_CHECK_FUNC_EXT(ldap_set_rebind_proc,$LDAP_LIBS)
LIBS="$LIBS $LDAP_LIBS"
AC_CACHE_CHECK(whether ldap_set_rebind_proc takes 3 arguments, smb_ldap_cv_ldap_set_rebind_proc, [
AC_TRY_COMPILE([
#include <lber.h>
#include <ldap.h>],
[ldap_set_rebind_proc(0, 0, 0);],
[smb_ldap_cv_ldap_set_rebind_proc=3],
[smb_ldap_cv_ldap_set_rebind_proc=2]
)
])
AC_DEFINE_UNQUOTED(LDAP_SET_REBIND_PROC_ARGS, $smb_ldap_cv_ldap_set_rebind_proc, [Number of arguments to ldap_set_rebind_proc])
AC_CHECK_FUNC_EXT(ldap_initialize,$LDAP_LIBS)
if test x"$ac_cv_lib_ext_ldap_ldap_init" = x"yes" -a x"$ac_cv_func_ext_ldap_domain2hostlist" = x"yes"; then
AC_DEFINE(HAVE_LDAP,1,[Whether ldap is available])
AC_DEFINE(HAVE_LDB_LDAP,1,[Whether ldb_ldap is available])
with_ldap_support=yes
AC_MSG_CHECKING(whether LDAP support is used)
AC_MSG_RESULT(yes)
SMB_ENABLE(LDAP,YES)
else
if test x"$with_ldap_support" = x"yes"; then
AC_MSG_ERROR(libldap is needed for LDAP support)
else
AC_MSG_WARN(libldap is needed for LDAP support)
fi
LDAP_LIBS=""
with_ldap_support=no
fi
LIBS=$ac_save_LIBS
fi
SMB_EXT_LIB(LDAP,[${LDAP_LIBS}],[${LDAP_CFLAGS}],[${LDAP_CPPFLAGS}],[${LDAP_LDFLAGS}])
+15
View File
@@ -0,0 +1,15 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
modulesdir=@modulesdir@
Name: ldb
Description: An LDAP-like embedded database
Version: 4.0
Requires.private: tdb
Requires: talloc
Libs: -L${libdir} -lldb
Cflags: -I${includedir} @CFLAGS@
Modulesdir: ${modulesdir}
URL: http://ldb.samba.org/
+826
View File
@@ -0,0 +1,826 @@
/*
ldb database library - ildap backend
Copyright (C) Andrew Tridgell 2005
Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb_ildap
*
* Component: ldb ildap backend
*
* Description: This is a ldb backend for the internal ldap
* client library in Samba4. By using this backend we are
* independent of a system ldap library
*
* Author: Andrew Tridgell
*
* Modifications:
*
* - description: make the module use asyncronous calls
* date: Feb 2006
* author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "lib/events/events.h"
#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;
struct ldb_context *ldb;
};
struct ildb_context {
struct ldb_module *module;
struct ldap_request *req;
void *context;
int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
};
/*
convert a ldb_message structure to a list of ldap_mod structures
ready for ildap_add() or ildap_modify()
*/
static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods,
const struct ldb_message *msg, int use_flags)
{
struct ldap_mod **mods;
unsigned int i;
int n = 0;
/* allocate maximum number of elements needed */
mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
if (!mods) {
errno = ENOMEM;
return NULL;
}
mods[0] = NULL;
for (i = 0; i < msg->num_elements; i++) {
const struct ldb_message_element *el = &msg->elements[i];
mods[n] = talloc(mods, struct ldap_mod);
if (!mods[n]) {
goto failed;
}
mods[n + 1] = NULL;
mods[n]->type = 0;
mods[n]->attrib = *el;
if (use_flags) {
switch (el->flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
mods[n]->type = LDAP_MODIFY_ADD;
break;
case LDB_FLAG_MOD_DELETE:
mods[n]->type = LDAP_MODIFY_DELETE;
break;
case LDB_FLAG_MOD_REPLACE:
mods[n]->type = LDAP_MODIFY_REPLACE;
break;
}
}
n++;
}
*num_mods = n;
return mods;
failed:
talloc_free(mods);
return NULL;
}
/*
map an ildap NTSTATUS to a ldb error code
*/
static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status)
{
if (NT_STATUS_IS_OK(status)) {
return LDB_SUCCESS;
}
ldb_set_errstring(ildb->ldb, ldap_errstr(ildb->ldap, status));
if (NT_STATUS_IS_LDAP(status)) {
return NT_STATUS_LDAP_CODE(status);
}
return LDB_ERR_OPERATIONS_ERROR;
}
static void ildb_request_timeout(struct event_context *ev, struct timed_event *te,
struct timeval t, void *private_data)
{
struct ldb_handle *handle = talloc_get_type(private_data, struct ldb_handle);
struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
if (ac->req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(ac->req->conn->pending, ac->req);
}
handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED;
return;
}
static void ildb_callback(struct ldap_request *req)
{
struct ldb_handle *handle = talloc_get_type(req->async.private_data, struct ldb_handle);
struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
struct ildb_private *ildb = talloc_get_type(ac->module->private_data, struct ildb_private);
NTSTATUS status;
int i;
handle->status = LDB_SUCCESS;
if (!NT_STATUS_IS_OK(req->status)) {
handle->status = ildb_map_error(ildb, req->status);
return;
}
if (req->num_replies < 1) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return;
}
switch (req->type) {
case LDAP_TAG_ModifyRequest:
if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
handle->status = ildb_map_error(ildb, status);
if (ac->callback && handle->status == LDB_SUCCESS) {
/* FIXME: build a corresponding ares to pass on */
handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
}
handle->state = LDB_ASYNC_DONE;
break;
case LDAP_TAG_AddRequest:
if (req->replies[0]->type != LDAP_TAG_AddResponse) {
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
handle->status = ildb_map_error(ildb, status);
if (ac->callback && handle->status == LDB_SUCCESS) {
/* FIXME: build a corresponding ares to pass on */
handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
}
handle->state = LDB_ASYNC_DONE;
break;
case LDAP_TAG_DelRequest:
if (req->replies[0]->type != LDAP_TAG_DelResponse) {
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
handle->status = ildb_map_error(ildb, status);
if (ac->callback && handle->status == LDB_SUCCESS) {
/* FIXME: build a corresponding ares to pass on */
handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
}
handle->state = LDB_ASYNC_DONE;
break;
case LDAP_TAG_ModifyDNRequest:
if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
handle->status = ildb_map_error(ildb, status);
if (ac->callback && handle->status == LDB_SUCCESS) {
/* FIXME: build a corresponding ares to pass on */
handle->status = ac->callback(ac->module->ldb, ac->context, NULL);
}
handle->state = LDB_ASYNC_DONE;
break;
case LDAP_TAG_SearchRequest:
/* loop over all messages */
for (i = 0; i < req->num_replies; i++) {
struct ldap_SearchResEntry *search;
struct ldb_reply *ares = NULL;
struct ldap_message *msg;
int ret;
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return;
}
msg = req->replies[i];
switch (msg->type) {
case LDAP_TAG_SearchResultDone:
status = ldap_check_response(req->conn, &msg->r.GeneralResult);
if (!NT_STATUS_IS_OK(status)) {
handle->status = ildb_map_error(ildb, status);
return;
}
ares->controls = talloc_move(ares, &msg->controls);
if (msg->r.SearchResultDone.resultcode) {
if (msg->r.SearchResultDone.errormessage) {
ldb_set_errstring(ac->module->ldb, msg->r.SearchResultDone.errormessage);
}
}
handle->status = msg->r.SearchResultDone.resultcode;
handle->state = LDB_ASYNC_DONE;
ares->type = LDB_REPLY_DONE;
break;
case LDAP_TAG_SearchResultEntry:
ares->message = ldb_msg_new(ares);
if (!ares->message) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return;
}
search = &(msg->r.SearchResultEntry);
ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, search->dn);
if ( ! ldb_dn_validate(ares->message->dn)) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return;
}
ares->message->num_elements = search->num_attributes;
ares->message->elements = talloc_move(ares->message,
&search->attributes);
handle->status = LDB_SUCCESS;
handle->state = LDB_ASYNC_PENDING;
ares->type = LDB_REPLY_ENTRY;
break;
case LDAP_TAG_SearchResultReference:
ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral);
handle->status = LDB_SUCCESS;
handle->state = LDB_ASYNC_PENDING;
ares->type = LDB_REPLY_REFERRAL;
break;
default:
/* TAG not handled, fail ! */
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
ret = ac->callback(ac->module->ldb, ac->context, ares);
if (ret) {
handle->status = ret;
}
}
talloc_free(req->replies);
req->replies = NULL;
req->num_replies = 0;
break;
default:
handle->status = LDB_ERR_PROTOCOL_ERROR;
return;
}
}
static struct ldb_handle *init_ildb_handle(struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ildb_context *ildb_ac;
struct ldb_handle *h;
h = talloc_zero(ildb->ldap, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ildb_ac = talloc(h, struct ildb_context);
if (ildb_ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ildb_ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ildb_ac->module = module;
ildb_ac->context = context;
ildb_ac->callback = callback;
return h;
}
static int ildb_request_send(struct ldb_module *module, struct ldap_message *msg,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *),
int timeout,
struct ldb_handle **handle)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldb_handle *h = init_ildb_handle(module, context, callback);
struct ildb_context *ildb_ac;
struct ldap_request *req;
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ildb_ac = talloc_get_type(h->private_data, struct ildb_context);
req = ldap_request_send(ildb->ldap, msg);
if (req == NULL) {
ldb_set_errstring(module->ldb, "async send request failed");
return LDB_ERR_OPERATIONS_ERROR;
}
if (!req->conn) {
ldb_set_errstring(module->ldb, "connection to remote LDAP server dropped?");
return LDB_ERR_OPERATIONS_ERROR;
}
talloc_free(req->time_event);
req->time_event = NULL;
if (timeout) {
req->time_event = event_add_timed(req->conn->event.event_ctx, h,
timeval_current_ofs(timeout, 0),
ildb_request_timeout, h);
}
req->async.fn = ildb_callback;
req->async.private_data = (void *)h;
ildb_ac->req = talloc_move(ildb_ac, &req);
*handle = h;
return LDB_SUCCESS;
}
static int ildb_request_noop(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_handle *h = init_ildb_handle(module, req->context, req->callback);
struct ildb_context *ildb_ac;
int ret = LDB_SUCCESS;
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ildb_ac = talloc_get_type(h->private_data, struct ildb_context);
req->handle = h;
if (ildb_ac->callback) {
ret = ildb_ac->callback(module->ldb, ildb_ac->context, NULL);
}
req->handle->state = LDB_ASYNC_DONE;
return ret;
}
/*
search for matching records using an asynchronous function
*/
static int ildb_search(struct ldb_module *module, struct ldb_request *req)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldap_message *msg;
int n;
req->handle = NULL;
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
if (req->op.search.tree == NULL) {
ldb_set_errstring(module->ldb, "Invalid expression parse tree");
return LDB_ERR_OPERATIONS_ERROR;
}
msg = new_ldap_message(ildb);
if (msg == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
}
msg->type = LDAP_TAG_SearchRequest;
if (req->op.search.base == NULL) {
msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
} else {
msg->r.SearchRequest.basedn = ldb_dn_alloc_linearized(msg, req->op.search.base);
}
if (msg->r.SearchRequest.basedn == NULL) {
ldb_set_errstring(module->ldb, "Unable to determine baseDN");
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
if (req->op.search.scope == LDB_SCOPE_DEFAULT) {
msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE;
} else {
msg->r.SearchRequest.scope = req->op.search.scope;
}
msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
msg->r.SearchRequest.timelimit = 0;
msg->r.SearchRequest.sizelimit = 0;
msg->r.SearchRequest.attributesonly = 0;
msg->r.SearchRequest.tree = discard_const(req->op.search.tree);
for (n = 0; req->op.search.attrs && req->op.search.attrs[n]; n++) /* noop */ ;
msg->r.SearchRequest.num_attributes = n;
msg->r.SearchRequest.attributes = discard_const(req->op.search.attrs);
msg->controls = req->controls;
return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
}
/*
add a record
*/
static int ildb_add(struct ldb_module *module, struct ldb_request *req)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldap_message *msg;
struct ldap_mod **mods;
int i,n;
req->handle = NULL;
/* ignore ltdb specials */
if (ldb_dn_is_special(req->op.add.message->dn)) {
return ildb_request_noop(module, req);
}
msg = new_ldap_message(ildb->ldap);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->type = LDAP_TAG_AddRequest;
msg->r.AddRequest.dn = ldb_dn_alloc_linearized(msg, req->op.add.message->dn);
if (msg->r.AddRequest.dn == NULL) {
talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
mods = ildb_msg_to_mods(msg, &n, req->op.add.message, 0);
if (mods == NULL) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
msg->r.AddRequest.num_attributes = n;
msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
if (msg->r.AddRequest.attributes == NULL) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
for (i = 0; i < n; i++) {
msg->r.AddRequest.attributes[i] = mods[i]->attrib;
}
return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
}
/*
modify a record
*/
static int ildb_modify(struct ldb_module *module, struct ldb_request *req)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldap_message *msg;
struct ldap_mod **mods;
int i,n;
req->handle = NULL;
/* ignore ltdb specials */
if (ldb_dn_is_special(req->op.mod.message->dn)) {
return ildb_request_noop(module, req);
}
msg = new_ldap_message(ildb->ldap);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->type = LDAP_TAG_ModifyRequest;
msg->r.ModifyRequest.dn = ldb_dn_alloc_linearized(msg, req->op.mod.message->dn);
if (msg->r.ModifyRequest.dn == NULL) {
talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
mods = ildb_msg_to_mods(msg, &n, req->op.mod.message, 1);
if (mods == NULL) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
msg->r.ModifyRequest.num_mods = n;
msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
if (msg->r.ModifyRequest.mods == NULL) {
talloc_free(msg);
return LDB_ERR_OPERATIONS_ERROR;
}
for (i = 0; i < n; i++) {
msg->r.ModifyRequest.mods[i] = *mods[i];
}
return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
}
/*
delete a record
*/
static int ildb_delete(struct ldb_module *module, struct ldb_request *req)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldap_message *msg;
req->handle = NULL;
/* ignore ltdb specials */
if (ldb_dn_is_special(req->op.del.dn)) {
return ildb_request_noop(module, req);
}
msg = new_ldap_message(ildb->ldap);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->type = LDAP_TAG_DelRequest;
msg->r.DelRequest.dn = ldb_dn_alloc_linearized(msg, req->op.del.dn);
if (msg->r.DelRequest.dn == NULL) {
talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
}
/*
rename a record
*/
static int ildb_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private);
struct ldap_message *msg;
req->handle = NULL;
/* ignore ltdb specials */
if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) {
return ildb_request_noop(module, req);
}
msg = new_ldap_message(ildb->ldap);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->type = LDAP_TAG_ModifyDNRequest;
msg->r.ModifyDNRequest.dn = ldb_dn_alloc_linearized(msg, req->op.rename.olddn);
if (msg->r.ModifyDNRequest.dn == NULL) {
talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
msg->r.ModifyDNRequest.newrdn =
talloc_asprintf(msg, "%s=%s",
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;
}
msg->r.ModifyDNRequest.newsuperior =
ldb_dn_alloc_linearized(msg, ldb_dn_get_parent(msg, req->op.rename.newdn));
if (msg->r.ModifyDNRequest.newsuperior == NULL) {
talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
msg->r.ModifyDNRequest.deleteolddn = True;
return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle));
}
static int ildb_start_trans(struct ldb_module *module)
{
/* TODO implement a local locking mechanism here */
return LDB_SUCCESS;
}
static int ildb_end_trans(struct ldb_module *module)
{
/* TODO implement a local transaction mechanism here */
return LDB_SUCCESS;
}
static int ildb_del_trans(struct ldb_module *module)
{
/* TODO implement a local locking mechanism here */
return LDB_SUCCESS;
}
static int ildb_request(struct ldb_module *module, struct ldb_request *req)
{
return LDB_ERR_OPERATIONS_ERROR;
}
static int ildb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context);
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
if (!ac) {
return LDB_ERR_OPERATIONS_ERROR;
}
handle->state = LDB_ASYNC_INIT;
switch(type) {
case LDB_WAIT_NONE:
if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
return LDB_ERR_OTHER;
}
break;
case LDB_WAIT_ALL:
while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
return LDB_ERR_OTHER;
}
}
break;
default:
return LDB_ERR_OPERATIONS_ERROR;
}
return handle->status;
}
static const struct ldb_module_ops ildb_ops = {
.name = "ldap",
.search = ildb_search,
.add = ildb_add,
.modify = ildb_modify,
.del = ildb_delete,
.rename = ildb_rename,
.request = ildb_request,
.start_transaction = ildb_start_trans,
.end_transaction = ildb_end_trans,
.del_transaction = ildb_del_trans,
.wait = ildb_wait
};
/*
connect to the database
*/
static int ildb_connect(struct ldb_context *ldb, const char *url,
unsigned int flags, const char *options[],
struct ldb_module **module)
{
struct ildb_private *ildb = NULL;
NTSTATUS status;
struct cli_credentials *creds;
ildb = talloc(ldb, struct ildb_private);
if (!ildb) {
ldb_oom(ldb);
goto failed;
}
ildb->ldb = ldb;
ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "EventContext"));
if (!ildb->ldap) {
ldb_oom(ldb);
goto failed;
}
if (flags & LDB_FLG_RECONNECT) {
ldap_set_reconn_params(ildb->ldap, 10);
}
status = ldap_connect(ildb->ldap, url);
if (!NT_STATUS_IS_OK(status)) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to ldap URL '%s' - %s\n",
url, ldap_errstr(ildb->ldap, status));
goto failed;
}
*module = talloc(ldb, struct ldb_module);
if (!module) {
ldb_oom(ldb);
talloc_free(ildb);
return -1;
}
talloc_set_name_const(*module, "ldb_ildap backend");
(*module)->ldb = ldb;
(*module)->prev = (*module)->next = NULL;
(*module)->private_data = ildb;
(*module)->ops = &ildb_ops;
/* caller can optionally setup credentials using the opaque token 'credentials' */
creds = talloc_get_type(ldb_get_opaque(ldb, "credentials"), struct cli_credentials);
if (creds == NULL) {
struct auth_session_info *session_info = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
if (session_info) {
creds = session_info->credentials;
}
}
if (creds != NULL && cli_credentials_authentication_requested(creds)) {
const char *bind_dn = cli_credentials_get_bind_dn(creds);
if (bind_dn) {
const char *password = cli_credentials_get_password(creds);
status = ldap_bind_simple(ildb->ldap, bind_dn, password);
if (!NT_STATUS_IS_OK(status)) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
ldap_errstr(ildb->ldap, status));
goto failed;
}
} else {
status = ldap_bind_sasl(ildb->ldap, creds);
if (!NT_STATUS_IS_OK(status)) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to bind - %s\n",
ldap_errstr(ildb->ldap, status));
goto failed;
}
}
}
return 0;
failed:
talloc_free(ildb);
return -1;
}
int ldb_ildap_init(void)
{
return ldb_register_backend("ldap", ildb_connect) +
ldb_register_backend("ldapi", ildb_connect) +
ldb_register_backend("ldaps", ildb_connect);
}
+843
View File
@@ -0,0 +1,843 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb_ldap
*
* Component: ldb ldap backend
*
* Description: core files for LDAP backend
*
* Author: Andrew Tridgell
*
* Modifications:
*
* - description: make the module use asyncronous calls
* date: Feb 2006
* author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
#define LDAP_DEPRECATED 1
#include <ldap.h>
struct lldb_private {
LDAP *ldap;
};
struct lldb_context {
struct ldb_module *module;
int msgid;
int timeout;
time_t starttime;
void *context;
int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
};
static int lldb_ldap_to_ldb(int err) {
/* Ldap errors and ldb errors are defined to the same values */
return err;
}
static struct ldb_handle *init_handle(struct lldb_private *lldb, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *),
int timeout, time_t starttime)
{
struct lldb_context *ac;
struct ldb_handle *h;
h = talloc_zero(lldb, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc(h, struct lldb_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->context = context;
ac->callback = callback;
ac->timeout = timeout;
ac->starttime = starttime;
ac->msgid = 0;
return h;
}
/*
convert a ldb_message structure to a list of LDAPMod structures
ready for ldap_add() or ldap_modify()
*/
static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, int use_flags)
{
LDAPMod **mods;
unsigned int i, j;
int num_mods = 0;
/* allocate maximum number of elements needed */
mods = talloc_array(mem_ctx, LDAPMod *, msg->num_elements+1);
if (!mods) {
errno = ENOMEM;
return NULL;
}
mods[0] = NULL;
for (i=0;i<msg->num_elements;i++) {
const struct ldb_message_element *el = &msg->elements[i];
mods[num_mods] = talloc(mods, LDAPMod);
if (!mods[num_mods]) {
goto failed;
}
mods[num_mods+1] = NULL;
mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
if (use_flags) {
switch (el->flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
mods[num_mods]->mod_op |= LDAP_MOD_ADD;
break;
case LDB_FLAG_MOD_DELETE:
mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
break;
case LDB_FLAG_MOD_REPLACE:
mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
break;
}
}
mods[num_mods]->mod_type = discard_const_p(char, el->name);
mods[num_mods]->mod_vals.modv_bvals = talloc_array(mods[num_mods],
struct berval *,
1+el->num_values);
if (!mods[num_mods]->mod_vals.modv_bvals) {
goto failed;
}
for (j=0;j<el->num_values;j++) {
mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals,
struct berval);
if (!mods[num_mods]->mod_vals.modv_bvals[j]) {
goto failed;
}
mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data;
mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length;
}
mods[num_mods]->mod_vals.modv_bvals[j] = NULL;
num_mods++;
}
return mods;
failed:
talloc_free(mods);
return NULL;
}
/*
add a single set of ldap message values to a ldb_message
*/
static int lldb_add_msg_attr(struct ldb_context *ldb,
struct ldb_message *msg,
const char *attr, struct berval **bval)
{
int count, i;
struct ldb_message_element *el;
count = ldap_count_values_len(bval);
if (count <= 0) {
return -1;
}
el = talloc_realloc(msg, msg->elements, struct ldb_message_element,
msg->num_elements + 1);
if (!el) {
errno = ENOMEM;
return -1;
}
msg->elements = el;
el = &msg->elements[msg->num_elements];
el->name = talloc_strdup(msg->elements, attr);
if (!el->name) {
errno = ENOMEM;
return -1;
}
el->flags = 0;
el->num_values = 0;
el->values = talloc_array(msg->elements, struct ldb_val, count);
if (!el->values) {
errno = ENOMEM;
return -1;
}
for (i=0;i<count;i++) {
/* we have to ensure this is null terminated so that
ldb_msg_find_attr_as_string() can work */
el->values[i].data = talloc_size(el->values, bval[i]->bv_len+1);
if (!el->values[i].data) {
errno = ENOMEM;
return -1;
}
memcpy(el->values[i].data, bval[i]->bv_val, bval[i]->bv_len);
el->values[i].data[bval[i]->bv_len] = 0;
el->values[i].length = bval[i]->bv_len;
el->num_values++;
}
msg->num_elements++;
return 0;
}
/*
search for matching records
*/
static int lldb_search(struct ldb_module *module, struct ldb_request *req)
{
struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
struct lldb_context *lldb_ac;
struct timeval tv;
int ldap_scope;
char *search_base;
char *expression;
int ret;
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
if (req->op.search.tree == NULL) {
ldb_set_errstring(module->ldb, "Invalid expression parse tree");
return LDB_ERR_OPERATIONS_ERROR;
}
if (req->controls != NULL) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!\n");
}
req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
if (req->handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base);
if (req->op.search.base == NULL) {
search_base = talloc_strdup(lldb_ac, "");
}
if (search_base == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree);
if (expression == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
switch (req->op.search.scope) {
case LDB_SCOPE_BASE:
ldap_scope = LDAP_SCOPE_BASE;
break;
case LDB_SCOPE_ONELEVEL:
ldap_scope = LDAP_SCOPE_ONELEVEL;
break;
default:
ldap_scope = LDAP_SCOPE_SUBTREE;
break;
}
tv.tv_sec = req->timeout;
tv.tv_usec = 0;
ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope,
expression,
discard_const_p(char *, req->op.search.attrs),
0,
NULL,
NULL,
&tv,
LDAP_NO_LIMIT,
&lldb_ac->msgid);
if (ret != LDAP_SUCCESS) {
ldb_set_errstring(module->ldb, ldap_err2string(ret));
}
return lldb_ldap_to_ldb(ret);
}
/*
add a record
*/
static int lldb_add(struct ldb_module *module, struct ldb_request *req)
{
struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
struct lldb_context *lldb_ac;
LDAPMod **mods;
char *dn;
int ret;
/* ltdb specials should not reach this point */
if (ldb_dn_is_special(req->op.add.message->dn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
if (req->handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0);
if (mods == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
dn = ldb_dn_alloc_linearized(lldb_ac, req->op.add.message->dn);
if (dn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldap_add_ext(lldb->ldap, dn, mods,
NULL,
NULL,
&lldb_ac->msgid);
if (ret != LDAP_SUCCESS) {
ldb_set_errstring(module->ldb, ldap_err2string(ret));
}
return lldb_ldap_to_ldb(ret);
}
/*
modify a record
*/
static int lldb_modify(struct ldb_module *module, struct ldb_request *req)
{
struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
struct lldb_context *lldb_ac;
LDAPMod **mods;
char *dn;
int ret;
/* ltdb specials should not reach this point */
if (ldb_dn_is_special(req->op.mod.message->dn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
if (req->handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
if (mods == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn);
if (dn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldap_modify_ext(lldb->ldap, dn, mods,
NULL,
NULL,
&lldb_ac->msgid);
if (ret != LDAP_SUCCESS) {
ldb_set_errstring(module->ldb, ldap_err2string(ret));
}
return lldb_ldap_to_ldb(ret);
}
/*
delete a record
*/
static int lldb_delete(struct ldb_module *module, struct ldb_request *req)
{
struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
struct lldb_context *lldb_ac;
char *dnstr;
int ret;
/* ltdb specials should not reach this point */
if (ldb_dn_is_special(req->op.del.dn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
if (req->handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn);
ret = ldap_delete_ext(lldb->ldap, dnstr,
NULL,
NULL,
&lldb_ac->msgid);
if (ret != LDAP_SUCCESS) {
ldb_set_errstring(module->ldb, ldap_err2string(ret));
}
return lldb_ldap_to_ldb(ret);
}
/*
rename a record
*/
static int lldb_rename(struct ldb_module *module, struct ldb_request *req)
{
struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private);
struct lldb_context *lldb_ac;
char *old_dn;
char *newrdn;
char *parentdn;
int ret;
/* ltdb specials should not reach this point */
if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
req->handle = init_handle(lldb, module, req->context, req->callback, req->timeout, req->starttime);
if (req->handle == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
lldb_ac = talloc_get_type(req->handle->private_data, struct lldb_context);
old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn);
if (old_dn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
newrdn = talloc_asprintf(lldb_ac, "%s=%s",
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;
}
parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
if (!parentdn) {
return LDB_ERR_OPERATIONS_ERROR;
}
ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
1, NULL, NULL,
&lldb_ac->msgid);
if (ret != LDAP_SUCCESS) {
ldb_set_errstring(module->ldb, ldap_err2string(ret));
}
return lldb_ldap_to_ldb(ret);
}
static int lldb_parse_result(struct ldb_handle *handle, LDAPMessage *result)
{
struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context);
struct lldb_private *lldb = talloc_get_type(ac->module->private_data, struct lldb_private);
struct ldb_reply *ares = NULL;
LDAPMessage *msg;
int type;
char *matcheddnp = NULL;
char *errmsgp = NULL;
char **referralsp = NULL;
LDAPControl **serverctrlsp = NULL;
int ret = LDB_SUCCESS;
type = ldap_msgtype(result);
handle->status = 0;
switch (type) {
case LDAP_RES_SEARCH_ENTRY:
msg = ldap_first_entry(lldb->ldap, result);
if (msg != NULL) {
BerElement *berptr = NULL;
char *attr, *dn;
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
ares->message = ldb_msg_new(ares);
if (!ares->message) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
dn = ldap_get_dn(lldb->ldap, msg);
if (!dn) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, dn);
if ( ! ldb_dn_validate(ares->message->dn)) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
ldap_memfree(dn);
ares->message->num_elements = 0;
ares->message->elements = NULL;
ares->message->private_data = NULL;
/* loop over all attributes */
for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
attr;
attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
struct berval **bval;
bval = ldap_get_values_len(lldb->ldap, msg, attr);
if (bval) {
lldb_add_msg_attr(ac->module->ldb, ares->message, attr, bval);
ldap_value_free_len(bval);
}
}
if (berptr) ber_free(berptr, 0);
ares->type = LDB_REPLY_ENTRY;
ret = ac->callback(ac->module->ldb, ac->context, ares);
} else {
handle->status = LDB_ERR_PROTOCOL_ERROR;
handle->state = LDB_ASYNC_DONE;
}
break;
case LDAP_RES_SEARCH_REFERENCE:
if (ldap_parse_result(lldb->ldap, result, &handle->status,
&matcheddnp, &errmsgp,
&referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
if (referralsp == NULL) {
handle->status = LDB_ERR_PROTOCOL_ERROR;
goto error;
}
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
ares->referral = talloc_strdup(ares, *referralsp);
ares->type = LDB_REPLY_REFERRAL;
ret = ac->callback(ac->module->ldb, ac->context, ares);
break;
case LDAP_RES_SEARCH_RESULT:
if (ldap_parse_result(lldb->ldap, result, &handle->status,
&matcheddnp, &errmsgp,
&referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
ret = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
if (serverctrlsp != NULL) {
/* FIXME: transform the LDAPControl list into an ldb_control one */
ares->controls = NULL;
}
ares->type = LDB_REPLY_DONE;
handle->state = LDB_ASYNC_DONE;
ret = ac->callback(ac->module->ldb, ac->context, ares);
break;
case LDAP_RES_MODIFY:
case LDAP_RES_ADD:
case LDAP_RES_DELETE:
case LDAP_RES_MODDN:
if (ldap_parse_result(lldb->ldap, result, &handle->status,
&matcheddnp, &errmsgp,
&referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
goto error;
}
if (ac->callback && handle->status == LDB_SUCCESS) {
ares = NULL; /* FIXME: build a corresponding ares to pass on */
ret = ac->callback(ac->module->ldb, ac->context, ares);
}
handle->state = LDB_ASYNC_DONE;
break;
default:
ret = LDB_ERR_PROTOCOL_ERROR;
goto error;
}
if (matcheddnp) ldap_memfree(matcheddnp);
if (errmsgp && *errmsgp) {
ldb_set_errstring(ac->module->ldb, errmsgp);
} else if (handle->status) {
ldb_set_errstring(ac->module->ldb, ldap_err2string(handle->status));
}
if (errmsgp) {
ldap_memfree(errmsgp);
}
if (referralsp) ldap_value_free(referralsp);
if (serverctrlsp) ldap_controls_free(serverctrlsp);
ldap_msgfree(result);
return lldb_ldap_to_ldb(handle->status);
error:
handle->state = LDB_ASYNC_DONE;
ldap_msgfree(result);
return ret;
}
static int lldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context);
struct lldb_private *lldb = talloc_get_type(handle->module->private_data, struct lldb_private);
struct timeval timeout;
LDAPMessage *result;
int ret, lret;
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
if (!ac || !ac->msgid) {
return LDB_ERR_OPERATIONS_ERROR;
}
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
switch(type) {
case LDB_WAIT_NONE:
if ((ac->timeout != -1) &&
((ac->starttime + ac->timeout) > time(NULL))) {
return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
timeout.tv_sec = 0;
timeout.tv_usec = 0;
lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
if (lret == -1) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (lret == 0) {
ret = LDB_SUCCESS;
goto done;
}
return lldb_parse_result(handle, result);
case LDB_WAIT_ALL:
timeout.tv_usec = 0;
ret = LDB_ERR_OPERATIONS_ERROR;
while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
if (ac->timeout == -1) {
lret = ldap_result(lldb->ldap, ac->msgid, 0, NULL, &result);
} else {
timeout.tv_sec = ac->timeout - (time(NULL) - ac->starttime);
if (timeout.tv_sec <= 0)
return LDB_ERR_TIME_LIMIT_EXCEEDED;
lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result);
}
if (lret == -1) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (lret == 0) {
return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
ret = lldb_parse_result(handle, result);
if (ret != LDB_SUCCESS) {
return ret;
}
}
break;
default:
handle->state = LDB_ASYNC_DONE;
ret = LDB_ERR_OPERATIONS_ERROR;
}
done:
return ret;
}
static int lldb_start_trans(struct ldb_module *module)
{
/* TODO implement a local transaction mechanism here */
return LDB_SUCCESS;
}
static int lldb_end_trans(struct ldb_module *module)
{
/* TODO implement a local transaction mechanism here */
return LDB_SUCCESS;
}
static int lldb_del_trans(struct ldb_module *module)
{
/* TODO implement a local transaction mechanism here */
return LDB_SUCCESS;
}
static int lldb_request(struct ldb_module *module, struct ldb_request *req)
{
return LDB_ERR_OPERATIONS_ERROR;
}
static const struct ldb_module_ops lldb_ops = {
.name = "ldap",
.search = lldb_search,
.add = lldb_add,
.modify = lldb_modify,
.del = lldb_delete,
.rename = lldb_rename,
.request = lldb_request,
.start_transaction = lldb_start_trans,
.end_transaction = lldb_end_trans,
.del_transaction = lldb_del_trans,
.wait = lldb_wait
};
static int lldb_destructor(struct lldb_private *lldb)
{
ldap_unbind(lldb->ldap);
return 0;
}
/*
connect to the database
*/
static int lldb_connect(struct ldb_context *ldb,
const char *url,
unsigned int flags,
const char *options[],
struct ldb_module **module)
{
struct lldb_private *lldb = NULL;
int version = 3;
int ret;
lldb = talloc(ldb, struct lldb_private);
if (!lldb) {
ldb_oom(ldb);
goto failed;
}
lldb->ldap = NULL;
ret = ldap_initialize(&lldb->ldap, url);
if (ret != LDAP_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_initialize failed for URL '%s' - %s\n",
url, ldap_err2string(ret));
goto failed;
}
talloc_set_destructor(lldb, lldb_destructor);
ret = ldap_set_option(lldb->ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
if (ret != LDAP_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "ldap_set_option failed - %s\n",
ldap_err2string(ret));
goto failed;
}
*module = talloc(ldb, struct ldb_module);
if (*module == NULL) {
ldb_oom(ldb);
talloc_free(lldb);
return -1;
}
talloc_set_name_const(*module, "ldb_ldap backend");
(*module)->ldb = ldb;
(*module)->prev = (*module)->next = NULL;
(*module)->private_data = lldb;
(*module)->ops = &lldb_ops;
return 0;
failed:
talloc_free(lldb);
return -1;
}
int ldb_ldap_init(void)
{
return ldb_register_backend("ldap", lldb_connect) +
ldb_register_backend("ldapi", lldb_connect) +
ldb_register_backend("ldaps", lldb_connect);
}
+7
View File
@@ -0,0 +1,7 @@
trees.ps contains an explanation of the Genealogical Representation of Trees
in Databases which is being used in ldb_sqlite3. Note that we use fgID
representation with 4 bytes per level, so we can represent 6.5E+08 subclasses
of any object class. This should be adequate for our purposes. :-)
The following document is the primary basis for the schema currently being
used here: http://www.research.ibm.com/journal/sj/392/shi.html
+155
View File
@@ -0,0 +1,155 @@
/*
base160 code used by ldb_sqlite3
Copyright (C) 2004 Derrell Lipman
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* ldb_sqlite3_base160()
*
* Convert an integer value to a string containing the base 160 representation
* of the integer. We always convert to a string representation that is 4
* bytes in length, and we always null terminate.
*
* Parameters:
* val --
* The value to be converted
*
* result --
* Buffer in which the result is to be placed
*
* Returns:
* nothing
*/
static unsigned char base160tab[161] =
{
48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , /* 0-9 */
58 , 59 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , /* : ; A-H */
73 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , /* I-R */
83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 97 , 98 , /* S-Z , a-b */
99 , 100, 101, 102, 103, 104, 105, 106, 107, 108, /* c-l */
109, 110, 111, 112, 113, 114, 115, 116, 117, 118, /* m-v */
119, 120, 121, 122, 160, 161, 162, 163, 164, 165, /* w-z, latin1 */
166, 167, 168, 169, 170, 171, 172, 173, 174, 175, /* latin1 */
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, /* latin1 */
186, 187, 188, 189, 190, 191, 192, 193, 194, 195, /* latin1 */
196, 197, 198, 199, 200, 201, 202, 203, 204, 205, /* latin1 */
206, 207, 208, 209, 210, 211, 212, 213, 214, 215, /* latin1 */
216, 217, 218, 219, 220, 221, 222, 223, 224, 225, /* latin1 */
226, 227, 228, 229, 230, 231, 232, 233, 234, 235, /* latin1 */
236, 237, 238, 239, 240, 241, 242, 243, 244, 245, /* latin1 */
246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* latin1 */
'\0'
};
/*
* lsqlite3_base160()
*
* Convert an unsigned long integer into a base160 representation of the
* number.
*
* Parameters:
* val --
* value to be converted
*
* result --
* character array, 5 bytes long, into which the base160 representation
* will be placed. The result will be a four-digit representation of the
* number (with leading zeros prepended as necessary), and null
* terminated.
*
* Returns:
* Nothing
*/
void
lsqlite3_base160(unsigned long val,
unsigned char result[5])
{
int i;
for (i = 3; i >= 0; i--) {
result[i] = base160tab[val % 160];
val /= 160;
}
result[4] = '\0';
}
/*
* lsqlite3_base160Next()
*
* Retrieve the next-greater number in the base160 sequence for the terminal
* tree node (the last four digits). Only one tree level (four digits) are
* operated on.
*
* Parameters:
* base160 -- a character array containing either an empty string (in which
* case no operation is performed), or a string of base160 digits
* with a length of a multiple of four digits.
*
* Upon return, the trailing four digits (one tree level) will
* have been incremented by 1.
*
* Returns:
* base160 -- the modified array
*/
char *
lsqlite3_base160Next(char base160[])
{
int i;
int len;
unsigned char * pTab;
char * pBase160 = base160;
/*
* We need a minimum of four digits, and we will always get a multiple of
* four digits.
*/
if (len = strlen(pBase160)) >= 4)
{
pBase160 += strlen(pBase160) - 1;
/* We only carry through four digits: one level in the tree */
for (i = 0; i < 4; i++) {
/* What base160 value does this digit have? */
pTab = strchr(base160tab, *pBase160);
/* Is there a carry? */
if (pTab < base160tab + sizeof(base160tab) - 1) {
/* Nope. Just increment this value and we're done. */
*pBase160 = *++pTab;
break;
} else {
/*
* There's a carry. This value gets base160tab[0], we
* decrement the buffer pointer to get the next higher-order
* digit, and continue in the loop.
*/
*pBase160-- = base160tab[0];
}
}
}
return base160;
}
File diff suppressed because it is too large Load Diff
+363
View File
@@ -0,0 +1,363 @@
-- ------------------------------------------------------
PRAGMA auto_vacuum=1;
-- ------------------------------------------------------
BEGIN EXCLUSIVE;
-- ------------------------------------------------------
CREATE TABLE ldb_info AS
SELECT 'LDB' AS database_type,
'1.0' AS version;
/*
* Get the next USN value with:
* BEGIN EXCLUSIVE;
* UPDATE usn SET value = value + 1;
* SELECT value FROM usn;
* COMMIT;
*/
CREATE TABLE usn
(
value INTEGER
);
CREATE TABLE ldb_object
(
/* tree_key is auto-generated by the insert trigger */
tree_key TEXT PRIMARY KEY,
parent_tree_key TEXT,
dn TEXT,
attr_name TEXT REFERENCES ldb_attributes,
attr_value TEXT,
/*
* object_type can take on these values (to date):
* 1: object is a node of a DN
* 2: object is an attribute/value pair of its parent DN
*/
object_type INTEGER,
/*
* if object_type is 1, the node can have children.
* this tracks the maximum previously assigned child
* number so we can generate a new unique tree key for
* a new child object. note that this is always incremented,
* so if children are deleted, this will not represent
* the _number_ of children.
*/
max_child_num INTEGER,
/*
* Automatically maintained meta-data (a gift for metze)
*/
object_guid TEXT UNIQUE,
timestamp INTEGER, -- originating_time
invoke_id TEXT, -- GUID: originating_invocation_id
usn INTEGER, -- hyper: originating_usn
/* do not allow duplicate name/value pairs */
UNIQUE (parent_tree_key, attr_name, attr_value, object_type)
);
CREATE TABLE ldb_attributes
(
attr_name TEXT PRIMARY KEY,
parent_tree_key TEXT,
objectclass_p BOOLEAN DEFAULT 0,
case_insensitive_p BOOLEAN DEFAULT 0,
wildcard_p BOOLEAN DEFAULT 0,
hidden_p BOOLEAN DEFAULT 0,
integer_p BOOLEAN DEFAULT 0,
/* tree_key is auto-generated by the insert trigger */
tree_key TEXT, -- null if not a object/sub class
-- level 1 if an objectclass
-- level 1-n if a subclass
max_child_num INTEGER
);
-- ------------------------------------------------------
CREATE INDEX ldb_object_dn_idx
ON ldb_object (dn);
CREATE INDEX ldb_attributes_tree_key_ids
ON ldb_attributes (tree_key);
-- ------------------------------------------------------
/* Gifts for metze. Automatically updated meta-data */
CREATE TRIGGER ldb_object_insert_tr
AFTER INSERT
ON ldb_object
FOR EACH ROW
BEGIN
UPDATE ldb_object
SET max_child_num = max_child_num + 1
WHERE tree_key = new.parent_tree_key;
UPDATE usn SET value = value + 1;
UPDATE ldb_object
SET tree_key =
(SELECT
new.tree_key ||
base160(SELECT max_child_num
FROM ldb_object
WHERE tree_key =
new.parent_tree_key));
max_child_num = 0,
object_guid = random_guid(),
timestamp = strftime('%s', 'now'),
usn = (SELECT value FROM usn);
WHERE tree_key = new.tree_key;
END;
CREATE TRIGGER ldb_object_update_tr
AFTER UPDATE
ON ldb_object
FOR EACH ROW
BEGIN
UPDATE usn SET value = value + 1;
UPDATE ldb_object
SET timestamp = strftime('%s', 'now'),
usn = (SELECT value FROM usn);
WHERE tree_key = new.tree_key;
END;
CREATE TRIGGER ldb_attributes_insert_tr
AFTER INSERT
ON ldb_attributes
FOR EACH ROW
BEGIN
UPDATE ldb_attributes
SET max_child_num = max_child_num + 1
WHERE tree_key = new.parent_tree_key;
UPDATE ldb_attributes
SET tree_key =
(SELECT
new.tree_key ||
base160(SELECT max_child_num
FROM ldb_attributes
WHERE tree_key =
new.parent_tree_key));
max_child_num = 0
WHERE tree_key = new.tree_key;
END;
-- ------------------------------------------------------
/* Initialize usn */
INSERT INTO usn (value) VALUES (0);
/* Create root object */
INSERT INTO ldb_object
(tree_key, parent_tree_key,
dn,
object_type, max_child_num)
VALUES ('', NULL,
'',
1, 0);
/* We need an implicit "top" level object class */
INSERT INTO ldb_attributes (attr_name,
parent_tree_key)
SELECT 'top', '';
-- ------------------------------------------------------
COMMIT;
-- ------------------------------------------------------
/*
* dn: o=University of Michigan,c=US
* objectclass: organization
* objectclass: domainRelatedObject
*/
-- newDN
BEGIN;
INSERT OR IGNORE INTO ldb_object
(parent_tree_key
dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('',
'c=US',
'c', 'US', 1, 0);
INSERT INTO ldb_object
(parent_tree_key,
dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('0001',
'o=University of Michigan,c=US',
'o', 'University of Michigan', 1, 0);
-- newObjectClass
INSERT OR IGNORE INTO ldb_attributes
(attr_name, parent_tree_key, objectclass_p)
VALUES
('objectclass', '', 1);
INSERT INTO ldb_object
(parent_tree_key,
dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001',
NULL,
'objectclass', 'organization', 2, 0);
INSERT OR IGNORE INTO ldb_attributes
(attr_name, parent_tree_key, objectclass_p)
VALUES
('objectclass', '', 1);
INSERT INTO ldb_object
(parent_tree_key,
dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001',
NULL,
'objectclass', 'domainRelatedObject', 2, 0);
COMMIT;
/*
* dn: o=University of Michigan,c=US
* l: Ann Arbor, Michigan
* st: Michigan
* o: University of Michigan
* o: UMICH
* seeAlso:
* telephonenumber: +1 313 764-1817
*/
-- addAttrValuePair
BEGIN;
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'l', 'Ann Arbor, Michigan', 2, 0);
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'st', 'Michigan', 2, 0);
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'o', 'University of Michigan', 2, 0);
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'o', 'UMICH', 2, 0);
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'seeAlso', '', 2, 0);
INSERT INTO ldb_object
(parent_tree_key, dn,
attr_name, attr_value, object_type, max_child_num)
VALUES ('00010001', NULL,
'telephonenumber', '+1 313 764-1817', 2, 0);
COMMIT;
-- ----------------------------------------------------------------------
/*
* dn: @ATTRIBUTES
* uid: CASE_INSENSITIVE WILDCARD
* cn: CASE_INSENSITIVE
* ou: CASE_INSENSITIVE
* dn: CASE_INSENSITIVE
*/
-- newAttribute
BEGIN;
INSERT OR IGNORE INTO ldb_attributes
(attr_name, parent_tree_key, objectclass_p)
VALUES
('uid', '', 0);
UPDATE ldb_attributes
SET case_insensitive_p = 1,
wildcard_p = 1,
hidden_p = 0,
integer_p = 0
WHERE attr_name = 'uid'
UPDATE ldb_attributes
SET case_insensitive_p = 1,
wildcard_p = 0,
hidden_p = 0,
integer_p = 0
WHERE attr_name = 'cn'
UPDATE ldb_attributes
SET case_insensitive_p = 1,
wildcard_p = 0,
hidden_p = 0,
integer_p = 0
WHERE attr_name = 'ou'
UPDATE ldb_attributes
SET case_insensitive_p = 1,
wildcard_p = 0,
hidden_p = 0,
integer_p = 0
WHERE attr_name = 'dn'
-- ----------------------------------------------------------------------
/*
* dn: @SUBCLASSES
* top: domain
* top: person
* domain: domainDNS
* person: organizationalPerson
* person: fooPerson
* organizationalPerson: user
* organizationalPerson: OpenLDAPperson
* user: computer
*/
-- insertSubclass
/* NOT YET UPDATED!!! *
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'domain', /* next_tree_key('top') */ '00010001';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'person', /* next_tree_key('top') */ '00010002';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002';
INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key)
SELECT 'computer', /* next_tree_key('user') */ '0001000200010001';
File diff suppressed because it is too large Load Diff
+550
View File
@@ -0,0 +1,550 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb tdb cache functions
*
* Description: cache special records in a ldb/tdb
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
#define LTDB_FLAG_CASE_INSENSITIVE (1<<0)
#define LTDB_FLAG_INTEGER (1<<1)
#define LTDB_FLAG_HIDDEN (1<<2)
#define LTDB_FLAG_OBJECTCLASS (1<<3)
/* valid attribute flags */
static const struct {
const char *name;
int value;
} ltdb_valid_attr_flags[] = {
{ "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
{ "INTEGER", LTDB_FLAG_INTEGER },
{ "HIDDEN", LTDB_FLAG_HIDDEN },
{ "NONE", 0 },
{ NULL, 0 }
};
/*
de-register any special handlers for @ATTRIBUTES
*/
static void ltdb_attributes_unload(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg;
int i;
if (ltdb->cache->attributes == NULL) {
/* no previously loaded attributes */
return;
}
msg = ltdb->cache->attributes;
for (i=0;i<msg->num_elements;i++) {
ldb_remove_attrib_handler(module->ldb, msg->elements[i].name);
}
talloc_free(ltdb->cache->attributes);
ltdb->cache->attributes = NULL;
}
/*
add up the attrib flags for a @ATTRIBUTES element
*/
static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v)
{
int i;
unsigned value = 0;
for (i=0;i<el->num_values;i++) {
int j;
for (j=0;ltdb_valid_attr_flags[j].name;j++) {
if (strcmp(ltdb_valid_attr_flags[j].name,
(char *)el->values[i].data) == 0) {
value |= ltdb_valid_attr_flags[j].value;
break;
}
}
if (ltdb_valid_attr_flags[j].name == NULL) {
return -1;
}
}
*v = value;
return 0;
}
/*
register any special handlers from @ATTRIBUTES
*/
static int ltdb_attributes_load(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg = ltdb->cache->attributes;
struct ldb_dn *dn;
int i;
dn = ldb_dn_new(module, module->ldb, LTDB_ATTRIBUTES);
if (dn == NULL) goto failed;
if (ltdb_search_dn1(module, dn, msg) == -1) {
talloc_free(dn);
goto failed;
}
talloc_free(dn);
/* mapping these flags onto ldap 'syntaxes' isn't strictly correct,
but its close enough for now */
for (i=0;i<msg->num_elements;i++) {
unsigned flags;
const char *syntax;
const struct ldb_attrib_handler *h;
struct ldb_attrib_handler h2;
if (ltdb_attributes_flags(&msg->elements[i], &flags) != 0) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid @ATTRIBUTES element for '%s'\n", msg->elements[i].name);
goto failed;
}
switch (flags & ~LTDB_FLAG_HIDDEN) {
case 0:
syntax = LDB_SYNTAX_OCTET_STRING;
break;
case LTDB_FLAG_CASE_INSENSITIVE:
syntax = LDB_SYNTAX_DIRECTORY_STRING;
break;
case LTDB_FLAG_INTEGER:
syntax = LDB_SYNTAX_INTEGER;
break;
default:
ldb_debug(module->ldb, LDB_DEBUG_ERROR,
"Invalid flag combination 0x%x for '%s' in @ATTRIBUTES\n",
flags, msg->elements[i].name);
goto failed;
}
h = ldb_attrib_handler_syntax(module->ldb, syntax);
if (h == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR,
"Invalid attribute syntax '%s' for '%s' in @ATTRIBUTES\n",
syntax, msg->elements[i].name);
goto failed;
}
h2 = *h;
h2.attr = msg->elements[i].name;
h2.flags |= LDB_ATTR_FLAG_ALLOCATED;
if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) {
goto failed;
}
}
return 0;
failed:
return -1;
}
/*
register any subclasses from @SUBCLASSES
*/
static int ltdb_subclasses_load(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg = ltdb->cache->subclasses;
struct ldb_dn *dn;
int i, j;
dn = ldb_dn_new(module, module->ldb, LTDB_SUBCLASSES);
if (dn == NULL) goto failed;
if (ltdb_search_dn1(module, dn, msg) == -1) {
talloc_free(dn);
goto failed;
}
talloc_free(dn);
for (i=0;i<msg->num_elements;i++) {
struct ldb_message_element *el = &msg->elements[i];
for (j=0;j<el->num_values;j++) {
if (ldb_subclass_add(module->ldb, el->name,
(char *)el->values[j].data) != 0) {
goto failed;
}
}
}
return 0;
failed:
return -1;
}
/*
de-register any @SUBCLASSES
*/
static void ltdb_subclasses_unload(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg;
int i;
if (ltdb->cache->subclasses == NULL) {
/* no previously loaded subclasses */
return;
}
msg = ltdb->cache->subclasses;
for (i=0;i<msg->num_elements;i++) {
ldb_subclass_remove(module->ldb, msg->elements[i].name);
}
talloc_free(ltdb->cache->subclasses);
ltdb->cache->subclasses = NULL;
}
/*
initialise the baseinfo record
*/
static int ltdb_baseinfo_init(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg;
struct ldb_message_element el;
struct ldb_val val;
int ret;
/* the initial sequence number must be different from the one
set in ltdb_cache_free(). Thanks to Jon for pointing this
out. */
const char *initial_sequence_number = "1";
ltdb->sequence_number = atof(initial_sequence_number);
msg = talloc(ltdb, struct ldb_message);
if (msg == NULL) {
goto failed;
}
msg->num_elements = 1;
msg->elements = &el;
msg->dn = ldb_dn_new(msg, module->ldb, LTDB_BASEINFO);
if (!msg->dn) {
goto failed;
}
el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
if (!el.name) {
goto failed;
}
el.values = &val;
el.num_values = 1;
el.flags = 0;
val.data = (uint8_t *)talloc_strdup(msg, initial_sequence_number);
if (!val.data) {
goto failed;
}
val.length = 1;
ret = ltdb_store(module, msg, TDB_INSERT);
talloc_free(msg);
return ret;
failed:
talloc_free(msg);
errno = ENOMEM;
return -1;
}
/*
free any cache records
*/
static void ltdb_cache_free(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
ltdb->sequence_number = 0;
talloc_free(ltdb->cache);
ltdb->cache = NULL;
}
/*
force a cache reload
*/
int ltdb_cache_reload(struct ldb_module *module)
{
ltdb_attributes_unload(module);
ltdb_subclasses_unload(module);
ltdb_cache_free(module);
return ltdb_cache_load(module);
}
/*
load the cache records
*/
int ltdb_cache_load(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_dn *baseinfo_dn = NULL;
struct ldb_dn *indexlist_dn = NULL;
uint64_t seq;
struct ldb_message *baseinfo;
/* a very fast check to avoid extra database reads */
if (ltdb->cache != NULL &&
tdb_get_seqnum(ltdb->tdb) == ltdb->tdb_seqnum) {
return 0;
}
if (ltdb->cache == NULL) {
ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
if (ltdb->cache == NULL) goto failed;
ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
if (ltdb->cache->indexlist == NULL ||
ltdb->cache->subclasses == NULL ||
ltdb->cache->attributes == NULL) {
goto failed;
}
}
baseinfo = talloc(ltdb->cache, struct ldb_message);
if (baseinfo == NULL) goto failed;
baseinfo_dn = ldb_dn_new(module, module->ldb, LTDB_BASEINFO);
if (baseinfo_dn == NULL) goto failed;
if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) == -1) {
goto failed;
}
/* possibly initialise the baseinfo */
if (!baseinfo->dn) {
if (ltdb_baseinfo_init(module) != 0) {
goto failed;
}
if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) != 1) {
goto failed;
}
}
ltdb->tdb_seqnum = tdb_get_seqnum(ltdb->tdb);
/* if the current internal sequence number is the same as the one
in the database then assume the rest of the cache is OK */
seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0);
if (seq == ltdb->sequence_number) {
goto done;
}
ltdb->sequence_number = seq;
talloc_free(ltdb->cache->last_attribute.name);
memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
ltdb_attributes_unload(module);
ltdb_subclasses_unload(module);
talloc_free(ltdb->cache->indexlist);
talloc_free(ltdb->cache->subclasses);
ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
if (ltdb->cache->indexlist == NULL ||
ltdb->cache->subclasses == NULL ||
ltdb->cache->attributes == NULL) {
goto failed;
}
indexlist_dn = ldb_dn_new(module, module->ldb, LTDB_INDEXLIST);
if (indexlist_dn == NULL) goto failed;
if (ltdb_search_dn1(module, indexlist_dn, ltdb->cache->indexlist) == -1) {
goto failed;
}
if (ltdb_attributes_load(module) == -1) {
goto failed;
}
if (ltdb_subclasses_load(module) == -1) {
goto failed;
}
done:
talloc_free(baseinfo);
talloc_free(baseinfo_dn);
talloc_free(indexlist_dn);
return 0;
failed:
talloc_free(baseinfo);
talloc_free(baseinfo_dn);
talloc_free(indexlist_dn);
return -1;
}
/*
increase the sequence number to indicate a database change
*/
int ltdb_increase_sequence_number(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
struct ldb_message *msg;
struct ldb_message_element el[2];
struct ldb_val val;
struct ldb_val val_time;
time_t t = time(NULL);
char *s = NULL;
int ret;
msg = talloc(ltdb, struct ldb_message);
if (msg == NULL) {
errno = ENOMEM;
return -1;
}
s = talloc_asprintf(msg, "%llu", ltdb->sequence_number+1);
if (!s) {
errno = ENOMEM;
return -1;
}
msg->num_elements = ARRAY_SIZE(el);
msg->elements = el;
msg->dn = ldb_dn_new(msg, module->ldb, LTDB_BASEINFO);
if (msg->dn == NULL) {
talloc_free(msg);
errno = ENOMEM;
return -1;
}
el[0].name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
if (el[0].name == NULL) {
talloc_free(msg);
errno = ENOMEM;
return -1;
}
el[0].values = &val;
el[0].num_values = 1;
el[0].flags = LDB_FLAG_MOD_REPLACE;
val.data = (uint8_t *)s;
val.length = strlen(s);
el[1].name = talloc_strdup(msg, LTDB_MOD_TIMESTAMP);
if (el[1].name == NULL) {
talloc_free(msg);
errno = ENOMEM;
return -1;
}
el[1].values = &val_time;
el[1].num_values = 1;
el[1].flags = LDB_FLAG_MOD_REPLACE;
s = ldb_timestring(msg, t);
if (s == NULL) {
return -1;
}
val_time.data = (uint8_t *)s;
val_time.length = strlen(s);
ret = ltdb_modify_internal(module, msg);
talloc_free(msg);
if (ret == 0) {
ltdb->sequence_number += 1;
}
return ret;
}
/*
return the attribute flags from the @ATTRIBUTES record
for the given attribute
*/
int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
{
struct ltdb_private *ltdb = module->private_data;
const struct ldb_message_element *attr_el;
int i, j, ret=0;
if (ltdb->cache->last_attribute.name &&
ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
return ltdb->cache->last_attribute.flags;
}
/* objectclass is a special default case */
if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
}
attr_el = ldb_msg_find_element(ltdb->cache->attributes, attr_name);
if (!attr_el) {
/* check if theres a wildcard attribute */
attr_el = ldb_msg_find_element(ltdb->cache->attributes, "*");
if (!attr_el) {
return ret;
}
}
for (i = 0; i < attr_el->num_values; i++) {
for (j=0; ltdb_valid_attr_flags[j].name; j++) {
if (strcmp(ltdb_valid_attr_flags[j].name,
(char *)attr_el->values[i].data) == 0) {
ret |= ltdb_valid_attr_flags[j].value;
}
}
}
talloc_free(ltdb->cache->last_attribute.name);
ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
ltdb->cache->last_attribute.flags = ret;
return ret;
}
int ltdb_check_at_attributes_values(const struct ldb_val *value)
{
int i;
for (i = 0; ltdb_valid_attr_flags[i].name != NULL; i++) {
if ((strcmp(ltdb_valid_attr_flags[i].name, (char *)value->data) == 0)) {
return 0;
}
}
return -1;
}
File diff suppressed because it is too large Load Diff
+292
View File
@@ -0,0 +1,292 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb pack/unpack
*
* Description: pack/unpack routines for ldb messages as key/value blobs
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
/* change this if the data format ever changes */
#define LTDB_PACKING_FORMAT 0x26011967
/* old packing formats */
#define LTDB_PACKING_FORMAT_NODN 0x26011966
/* use a portable integer format */
static void put_uint32(uint8_t *p, int ofs, unsigned int val)
{
p += ofs;
p[0] = val&0xFF;
p[1] = (val>>8) & 0xFF;
p[2] = (val>>16) & 0xFF;
p[3] = (val>>24) & 0xFF;
}
static unsigned int pull_uint32(uint8_t *p, int ofs)
{
p += ofs;
return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
}
static int attribute_storable_values(const struct ldb_message_element *el)
{
if (el->num_values == 0) return 0;
if (ldb_attr_cmp(el->name, "dn") == 0) return 0;
if (ldb_attr_cmp(el->name, "distinguishedName") == 0) return 0;
return el->num_values;
}
/*
pack a ldb message into a linear buffer in a TDB_DATA
note that this routine avoids saving elements with zero values,
as these are equivalent to having no element
caller frees the data buffer after use
*/
int ltdb_pack_data(struct ldb_module *module,
const struct ldb_message *message,
struct TDB_DATA *data)
{
struct ldb_context *ldb = module->ldb;
unsigned int i, j, real_elements=0;
size_t size;
const char *dn;
uint8_t *p;
size_t len;
dn = ldb_dn_get_linearized(message->dn);
if (dn == NULL) {
errno = ENOMEM;
return -1;
}
/* work out how big it needs to be */
size = 8;
size += 1 + strlen(dn);
for (i=0;i<message->num_elements;i++) {
if (attribute_storable_values(&message->elements[i]) == 0) {
continue;
}
real_elements++;
size += 1 + strlen(message->elements[i].name) + 4;
for (j=0;j<message->elements[i].num_values;j++) {
size += 4 + message->elements[i].values[j].length + 1;
}
}
/* allocate it */
data->dptr = talloc_array(ldb, uint8_t, size);
if (!data->dptr) {
errno = ENOMEM;
return -1;
}
data->dsize = size;
p = data->dptr;
put_uint32(p, 0, LTDB_PACKING_FORMAT);
put_uint32(p, 4, real_elements);
p += 8;
/* the dn needs to be packed so we can be case preserving
while hashing on a case folded dn */
len = strlen(dn);
memcpy(p, dn, len+1);
p += len + 1;
for (i=0;i<message->num_elements;i++) {
if (attribute_storable_values(&message->elements[i]) == 0) {
continue;
}
len = strlen(message->elements[i].name);
memcpy(p, message->elements[i].name, len+1);
p += len + 1;
put_uint32(p, 0, message->elements[i].num_values);
p += 4;
for (j=0;j<message->elements[i].num_values;j++) {
put_uint32(p, 0, message->elements[i].values[j].length);
memcpy(p+4, message->elements[i].values[j].data,
message->elements[i].values[j].length);
p[4+message->elements[i].values[j].length] = 0;
p += 4 + message->elements[i].values[j].length + 1;
}
}
return 0;
}
/*
unpack a ldb message from a linear buffer in TDB_DATA
Free with ltdb_unpack_data_free()
*/
int ltdb_unpack_data(struct ldb_module *module,
const struct TDB_DATA *data,
struct ldb_message *message)
{
struct ldb_context *ldb = module->ldb;
uint8_t *p;
unsigned int remaining;
unsigned int i, j;
unsigned format;
size_t len;
message->elements = NULL;
p = data->dptr;
if (data->dsize < 8) {
errno = EIO;
goto failed;
}
format = pull_uint32(p, 0);
message->num_elements = pull_uint32(p, 4);
p += 8;
remaining = data->dsize - 8;
switch (format) {
case LTDB_PACKING_FORMAT_NODN:
message->dn = NULL;
break;
case LTDB_PACKING_FORMAT:
len = strnlen((char *)p, remaining);
if (len == remaining) {
errno = EIO;
goto failed;
}
message->dn = ldb_dn_new(message, ldb, (char *)p);
if (message->dn == NULL) {
errno = ENOMEM;
goto failed;
}
remaining -= len + 1;
p += len + 1;
break;
default:
errno = EIO;
goto failed;
}
if (message->num_elements == 0) {
message->elements = NULL;
return 0;
}
if (message->num_elements > remaining / 6) {
errno = EIO;
goto failed;
}
message->elements = talloc_array(message, struct ldb_message_element, message->num_elements);
if (!message->elements) {
errno = ENOMEM;
goto failed;
}
memset(message->elements, 0,
message->num_elements * sizeof(struct ldb_message_element));
for (i=0;i<message->num_elements;i++) {
if (remaining < 10) {
errno = EIO;
goto failed;
}
len = strnlen((char *)p, remaining-6);
if (len == remaining-6) {
errno = EIO;
goto failed;
}
message->elements[i].flags = 0;
message->elements[i].name = talloc_strndup(message->elements, (char *)p, len);
if (message->elements[i].name == NULL) {
errno = ENOMEM;
goto failed;
}
remaining -= len + 1;
p += len + 1;
message->elements[i].num_values = pull_uint32(p, 0);
message->elements[i].values = NULL;
if (message->elements[i].num_values != 0) {
message->elements[i].values = talloc_array(message->elements,
struct ldb_val,
message->elements[i].num_values);
if (!message->elements[i].values) {
errno = ENOMEM;
goto failed;
}
}
p += 4;
remaining -= 4;
for (j=0;j<message->elements[i].num_values;j++) {
len = pull_uint32(p, 0);
if (len > remaining-5) {
errno = EIO;
goto failed;
}
message->elements[i].values[j].length = len;
message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1);
if (message->elements[i].values[j].data == NULL) {
errno = ENOMEM;
goto failed;
}
memcpy(message->elements[i].values[j].data, p+4, len);
message->elements[i].values[j].data[len] = 0;
remaining -= len+4+1;
p += len+4+1;
}
}
if (remaining != 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Error: %d bytes unread in ltdb_unpack_data\n", remaining);
}
return 0;
failed:
talloc_free(message->elements);
return -1;
}
+525
View File
@@ -0,0 +1,525 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb search functions
*
* Description: functions to search ldb+tdb databases
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
/*
add one element to a message
*/
static int msg_add_element(struct ldb_message *ret,
const struct ldb_message_element *el,
int check_duplicates)
{
unsigned int i;
struct ldb_message_element *e2, *elnew;
if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
/* its already there */
return 0;
}
e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
if (!e2) {
return -1;
}
ret->elements = e2;
elnew = &e2[ret->num_elements];
elnew->name = talloc_strdup(ret->elements, el->name);
if (!elnew->name) {
return -1;
}
if (el->num_values) {
elnew->values = talloc_array(ret->elements, struct ldb_val, el->num_values);
if (!elnew->values) {
return -1;
}
} else {
elnew->values = NULL;
}
for (i=0;i<el->num_values;i++) {
elnew->values[i] = ldb_val_dup(elnew->values, &el->values[i]);
if (elnew->values[i].length != el->values[i].length) {
return -1;
}
}
elnew->num_values = el->num_values;
ret->num_elements++;
return 0;
}
/*
add the special distinguishedName element
*/
static int msg_add_distinguished_name(struct ldb_message *msg)
{
struct ldb_message_element el;
struct ldb_val val;
int ret;
el.flags = 0;
el.name = "distinguishedName";
el.num_values = 1;
el.values = &val;
val.data = (uint8_t *)ldb_dn_alloc_linearized(msg, msg->dn);
val.length = strlen((char *)val.data);
ret = msg_add_element(msg, &el, 1);
return ret;
}
/*
add all elements from one message into another
*/
static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
const struct ldb_message *msg)
{
struct ldb_context *ldb = module->ldb;
unsigned int i;
int check_duplicates = (ret->num_elements != 0);
if (msg_add_distinguished_name(ret) != 0) {
return -1;
}
for (i=0;i<msg->num_elements;i++) {
const struct ldb_attrib_handler *h;
h = ldb_attrib_handler(ldb, msg->elements[i].name);
if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
continue;
}
if (msg_add_element(ret, &msg->elements[i],
check_duplicates) != 0) {
return -1;
}
}
return 0;
}
/*
pull the specified list of attributes from a message
*/
static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
const struct ldb_message *msg,
const char * const *attrs)
{
struct ldb_message *ret;
int i;
ret = talloc(mem_ctx, struct ldb_message);
if (!ret) {
return NULL;
}
ret->dn = ldb_dn_copy(ret, msg->dn);
if (!ret->dn) {
talloc_free(ret);
return NULL;
}
ret->num_elements = 0;
ret->elements = NULL;
if (!attrs) {
if (msg_add_all_elements(module, ret, msg) != 0) {
talloc_free(ret);
return NULL;
}
return ret;
}
for (i=0;attrs[i];i++) {
struct ldb_message_element *el;
if (strcmp(attrs[i], "*") == 0) {
if (msg_add_all_elements(module, ret, msg) != 0) {
talloc_free(ret);
return NULL;
}
continue;
}
if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
if (msg_add_distinguished_name(ret) != 0) {
return NULL;
}
continue;
}
el = ldb_msg_find_element(msg, attrs[i]);
if (!el) {
continue;
}
if (msg_add_element(ret, el, 1) != 0) {
talloc_free(ret);
return NULL;
}
}
return ret;
}
/*
search the database for a single simple dn, returning all attributes
in a single message
return 1 on success, 0 on record-not-found and -1 on error
*/
int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg)
{
struct ltdb_private *ltdb = module->private_data;
int ret;
TDB_DATA tdb_key, tdb_data;
memset(msg, 0, sizeof(*msg));
/* form the key */
tdb_key = ltdb_key(module, dn);
if (!tdb_key.dptr) {
return -1;
}
tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
talloc_free(tdb_key.dptr);
if (!tdb_data.dptr) {
return 0;
}
msg->num_elements = 0;
msg->elements = NULL;
ret = ltdb_unpack_data(module, &tdb_data, msg);
free(tdb_data.dptr);
if (ret == -1) {
return -1;
}
if (!msg->dn) {
msg->dn = ldb_dn_copy(msg, dn);
}
if (!msg->dn) {
return -1;
}
return 1;
}
/*
lock the database for read - use by ltdb_search
*/
static int ltdb_lock_read(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
return tdb_lockall_read(ltdb->tdb);
}
/*
unlock the database after a ltdb_lock_read()
*/
static int ltdb_unlock_read(struct ldb_module *module)
{
struct ltdb_private *ltdb = module->private_data;
return tdb_unlockall_read(ltdb->tdb);
}
/*
add a set of attributes from a record to a set of results
return 0 on success, -1 on failure
*/
int ltdb_add_attr_results(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
const char * const attrs[],
unsigned int *count,
struct ldb_message ***res)
{
struct ldb_message *msg2;
struct ldb_message **res2;
/* pull the attributes that the user wants */
msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
if (!msg2) {
return -1;
}
/* add to the results list */
res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
if (!res2) {
talloc_free(msg2);
return -1;
}
(*res) = res2;
(*res)[*count] = talloc_move(*res, &msg2);
(*res)[(*count)+1] = NULL;
(*count)++;
return 0;
}
/*
filter the specified list of attributes from a message
removing not requested attrs.
*/
int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs)
{
int i, keep_all = 0;
if (attrs) {
/* check for special attrs */
for (i = 0; attrs[i]; i++) {
if (strcmp(attrs[i], "*") == 0) {
keep_all = 1;
break;
}
if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
if (msg_add_distinguished_name(msg) != 0) {
return -1;
}
}
}
} else {
keep_all = 1;
}
if (keep_all) {
if (msg_add_distinguished_name(msg) != 0) {
return -1;
}
return 0;
}
for (i = 0; i < msg->num_elements; i++) {
int j, found;
for (j = 0, found = 0; attrs[j]; j++) {
if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) {
found = 1;
break;
}
}
if (!found) {
ldb_msg_remove_attr(msg, msg->elements[i].name);
i--;
}
}
return 0;
}
/*
search function for a non-indexed search
*/
static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
{
struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle);
struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
struct ldb_reply *ares = NULL;
int ret;
if (key.dsize < 4 ||
strncmp((char *)key.dptr, "DN=", 3) != 0) {
return 0;
}
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
handle->state = LDB_ASYNC_DONE;
return -1;
}
ares->message = ldb_msg_new(ares);
if (!ares->message) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
handle->state = LDB_ASYNC_DONE;
talloc_free(ares);
return -1;
}
/* unpack the record */
ret = ltdb_unpack_data(ac->module, &data, ares->message);
if (ret == -1) {
talloc_free(ares);
return -1;
}
if (!ares->message->dn) {
ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3);
if (ares->message->dn == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
handle->state = LDB_ASYNC_DONE;
talloc_free(ares);
return -1;
}
}
/* see if it matches the given expression */
if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree,
ac->base, ac->scope)) {
talloc_free(ares);
return 0;
}
/* filter the attributes that the user wants */
ret = ltdb_filter_attrs(ares->message, ac->attrs);
if (ret == -1) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
handle->state = LDB_ASYNC_DONE;
talloc_free(ares);
return -1;
}
ares->type = LDB_REPLY_ENTRY;
handle->state = LDB_ASYNC_PENDING;
handle->status = ac->callback(ac->module->ldb, ac->context, ares);
if (handle->status != LDB_SUCCESS) {
/* don't try to free ares here, the callback is in charge of that */
return -1;
}
return 0;
}
/*
search the database with a LDAP-like expression.
this is the "full search" non-indexed variant
*/
static int ltdb_search_full(struct ldb_handle *handle)
{
struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context);
struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private);
int ret;
ret = tdb_traverse_read(ltdb->tdb, search_func, handle);
if (ret == -1) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
}
handle->state = LDB_ASYNC_DONE;
return LDB_SUCCESS;
}
/*
search the database with a LDAP-like expression.
choses a search method
*/
int ltdb_search(struct ldb_module *module, struct ldb_request *req)
{
struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private);
struct ltdb_context *ltdb_ac;
struct ldb_reply *ares;
int ret;
if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) &&
(req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL))
return LDB_ERR_OPERATIONS_ERROR;
if (ltdb_lock_read(module) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (ltdb_cache_load(module) != 0) {
ltdb_unlock_read(module);
return LDB_ERR_OPERATIONS_ERROR;
}
if (req->op.search.tree == NULL) {
ltdb_unlock_read(module);
return LDB_ERR_OPERATIONS_ERROR;
}
req->handle = init_ltdb_handle(ltdb, module, req);
if (req->handle == NULL) {
ltdb_unlock_read(module);
return LDB_ERR_OPERATIONS_ERROR;
}
ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context);
ltdb_ac->tree = req->op.search.tree;
ltdb_ac->scope = req->op.search.scope;
ltdb_ac->base = req->op.search.base;
ltdb_ac->attrs = req->op.search.attrs;
ret = ltdb_search_indexed(req->handle);
if (ret == -1) {
ret = ltdb_search_full(req->handle);
}
if (ret != LDB_SUCCESS) {
ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n");
req->handle->state = LDB_ASYNC_DONE;
req->handle->status = ret;
}
/* Finally send an LDB_REPLY_DONE packet when searching is finished */
ares = talloc_zero(req, struct ldb_reply);
if (!ares) {
ltdb_unlock_read(module);
return LDB_ERR_OPERATIONS_ERROR;
}
req->handle->state = LDB_ASYNC_DONE;
ares->type = LDB_REPLY_DONE;
ret = req->callback(module->ldb, req->context, ares);
req->handle->status = ret;
ltdb_unlock_read(module);
return LDB_SUCCESS;
}
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
#ifdef _SAMBA_BUILD_
#include "system/filesys.h"
#endif
#if (_SAMBA_BUILD_ >= 4)
#include "lib/tdb/include/tdb.h"
#elif defined(_SAMBA_BUILD_)
#include "tdb/include/tdb.h"
#else
#include "tdb.h"
#endif
/* this private structure is used by the ltdb backend in the
ldb_context */
struct ltdb_private {
TDB_CONTEXT *tdb;
unsigned int connect_flags;
/* a double is used for portability and ease of string
handling. It has plenty of digits of precision */
unsigned long long sequence_number;
/* the low level tdb seqnum - used to avoid loading BASEINFO when
possible */
int tdb_seqnum;
struct ltdb_cache {
struct ldb_message *indexlist;
struct ldb_message *attributes;
struct ldb_message *subclasses;
struct {
char *name;
int flags;
} last_attribute;
} *cache;
};
/*
the async local context
holds also internal search state during a full db search
*/
struct ltdb_context {
struct ldb_module *module;
/* search stuff */
const struct ldb_parse_tree *tree;
struct ldb_dn *base;
enum ldb_scope scope;
const char * const *attrs;
/* async stuff */
void *context;
int (*callback)(struct ldb_context *, void *, struct ldb_reply *);
};
/* special record types */
#define LTDB_INDEX "@INDEX"
#define LTDB_INDEXLIST "@INDEXLIST"
#define LTDB_IDX "@IDX"
#define LTDB_IDXATTR "@IDXATTR"
#define LTDB_BASEINFO "@BASEINFO"
#define LTDB_ATTRIBUTES "@ATTRIBUTES"
#define LTDB_SUBCLASSES "@SUBCLASSES"
/* special attribute types */
#define LTDB_SEQUENCE_NUMBER "sequenceNumber"
#define LTDB_MOD_TIMESTAMP "whenChanged"
#define LTDB_OBJECTCLASS "objectClass"
/* The following definitions come from lib/ldb/ldb_tdb/ldb_cache.c */
int ltdb_cache_reload(struct ldb_module *module);
int ltdb_cache_load(struct ldb_module *module);
int ltdb_increase_sequence_number(struct ldb_module *module);
int ltdb_check_at_attributes_values(const struct ldb_val *value);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_index.c */
struct ldb_parse_tree;
int ltdb_search_indexed(struct ldb_handle *handle);
int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg);
int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg);
int ltdb_reindex(struct ldb_module *module);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_pack.c */
int ltdb_pack_data(struct ldb_module *module,
const struct ldb_message *message,
struct TDB_DATA *data);
void ltdb_unpack_data_free(struct ldb_module *module,
struct ldb_message *message);
int ltdb_unpack_data(struct ldb_module *module,
const struct TDB_DATA *data,
struct ldb_message *message);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_search.c */
int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
const struct ldb_val *val);
void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg);
int ltdb_add_attr_results(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
const char * const attrs[],
unsigned int *count,
struct ldb_message ***res);
int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs);
int ltdb_search(struct ldb_module *module, struct ldb_request *req);
/* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */
struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module,
struct ldb_request *req);
struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn);
int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs);
int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn);
int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg);
int ltdb_index_del_value(struct ldb_module *module, const char *dn,
struct ldb_message_element *el, int v_idx);
struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
const char *path, int hash_size, int tdb_flags,
int open_flags, mode_t mode,
struct ldb_context *ldb);
+176
View File
@@ -0,0 +1,176 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/ldb_tdb/ldb_tdb.h"
/*
the purpose of this code is to work around the braindead posix locking
rules, to allow us to have a ldb open more than once while allowing
locking to work
*/
struct ltdb_wrap {
struct ltdb_wrap *next, *prev;
struct tdb_context *tdb;
dev_t device;
ino_t inode;
};
static struct ltdb_wrap *tdb_list;
/* destroy the last connection to a tdb */
static int ltdb_wrap_destructor(struct ltdb_wrap *w)
{
tdb_close(w->tdb);
if (w->next) {
w->next->prev = w->prev;
}
if (w->prev) {
w->prev->next = w->next;
}
if (w == tdb_list) {
tdb_list = w->next;
}
return 0;
}
#if defined(_SAMBA_BUILD_) && (_SAMBA_BUILD_ <= 3)
static void ltdb_log_fn(struct tdb_context *tdb, int level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
static void ltdb_log_fn(struct tdb_context *tdb, int level, const char *fmt, ...)
{
/* until we merge the tdb debug changes into samba3, we don't know
how serious the error is, and we can't go via the ldb loggin code */
va_list ap;
const char *name = tdb_name(tdb);
char *message;
va_start(ap, fmt);
message = talloc_vasprintf(NULL, fmt, ap);
va_end(ap);
DEBUG(3, ("ltdb: tdb(%s): %s", name, message));
talloc_free(message);
}
#else
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4);
static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
{
va_list ap;
const char *name = tdb_name(tdb);
struct ldb_context *ldb = talloc_get_type(tdb_get_logging_private(tdb), struct ldb_context);
enum ldb_debug_level ldb_level;
char *message;
va_start(ap, fmt);
message = talloc_vasprintf(ldb, fmt, ap);
va_end(ap);
switch (level) {
case TDB_DEBUG_FATAL:
ldb_level = LDB_DEBUG_FATAL;
break;
case TDB_DEBUG_ERROR:
ldb_level = LDB_DEBUG_ERROR;
break;
case TDB_DEBUG_WARNING:
ldb_level = LDB_DEBUG_WARNING;
break;
case TDB_DEBUG_TRACE:
ldb_level = LDB_DEBUG_TRACE;
break;
default:
ldb_level = LDB_DEBUG_FATAL;
}
ldb_debug(ldb, ldb_level, "ltdb: tdb(%s): %s", name, message);
talloc_free(message);
}
#endif
/*
wrapped connection to a tdb database. The caller should _not_ free
this as it is not a talloc structure (as tdb does not use talloc
yet). It will auto-close when the caller frees the mem_ctx that is
passed to this call
*/
struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx,
const char *path, int hash_size,
int tdb_flags,
int open_flags, mode_t mode,
struct ldb_context *ldb)
{
struct ltdb_wrap *w;
struct stat st;
#if defined(_SAMBA_BUILD_) && (_SAMBA_BUILD_ <= 3)
tdb_log_func log_ctx_p = ltdb_log_fn;
#else
struct tdb_logging_context log_ctx;
const struct tdb_logging_context *log_ctx_p = &log_ctx;
log_ctx.log_fn = ltdb_log_fn;
log_ctx.log_private = ldb;
#endif
if (stat(path, &st) == 0) {
for (w=tdb_list;w;w=w->next) {
if (st.st_dev == w->device && st.st_ino == w->inode) {
if (!talloc_reference(mem_ctx, w)) {
return NULL;
}
return w->tdb;
}
}
}
w = talloc(mem_ctx, struct ltdb_wrap);
if (w == NULL) {
return NULL;
}
w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, log_ctx_p, NULL);
if (w->tdb == NULL) {
talloc_free(w);
return NULL;
}
if (fstat(tdb_fd(w->tdb), &st) != 0) {
tdb_close(w->tdb);
talloc_free(w);
return NULL;
}
w->device = st.st_dev;
w->inode = st.st_ino;
talloc_set_destructor(w, ltdb_wrap_destructor);
w->next = tdb_list;
w->prev = NULL;
if (tdb_list) {
tdb_list->prev = w;
}
tdb_list = w;
return w->tdb;
}
+33
View File
@@ -0,0 +1,33 @@
SMB_ENABLE(ldb_sqlite3,$with_sqlite3_support)
AC_MSG_CHECKING([for Python])
PYTHON=
AC_ARG_WITH(python,
[ --with-python=PYTHONNAME build Python libraries],
[ case "${withval-python}" in
yes)
PYTHON=python
;;
no)
PYTHON=
;;
*)
PYTHON=${withval-python}
;;
esac ])
if test x"$PYTHON" != "x"; then
incdir=`python -c 'import sys; print "%s/include/python%d.%d" % (sys.prefix, sys.version_info[[0]], sys.version_info[[1]])'`
CPPFLAGS="$CPPFLAGS -I $incdir"
fi
if test x"$PYTHON" != "x"; then
AC_MSG_RESULT([${withval-python}])
else
AC_MSG_RESULT(no)
SMB_ENABLE(swig_ldb, NO)
fi
AC_SUBST(PYTHON)
+80
View File
@@ -0,0 +1,80 @@
/**
\mainpage ldb
\section Overview
ldb is a LDAP-like embedded database. It is not at all LDAP standards
compliant, so if you want a standards compliant database then please
see the excellent <a href="http://www.openldap.org/">OpenLDAP</a>
project.<p>
What ldb does is provide a fast database with an LDAP-like API
designed to be used within an application. In some ways it can be seen
as a intermediate solution between key-value pair databases and a real
LDAP database.<p>
ldb is the database engine used in Samba4.
\section Features
The main features that separate ldb from other solutions are:
- Safe multi-reader, multi-writer, using byte range locking
- LDAP-like API
- fast operation
- choice of local tdb, local sqlite3 or remote LDAP backends
- integration with <a href="http://talloc.samba.org">talloc</a>
- schema-less operation, for trivial setup
- modules for extensions (such as schema support)
- easy setup of indexes and attribute properties
- ldbedit tool for database editing (reminiscent of 'vipw')
- ldif for import/export
\section Documentation
ldb has limited programmer and administrator documentation:
- a list of <a href="globals_func.html">functions</a>
- a list of <a href="examples.html">examples</a>
- a list of <a href="annotated.html">data structures</a>
- a list of <a href="globals_defs.html">constants</a>
If you need more information than is presented in this document, you
may wish to look at the source code, especially the source code in the
<a href="http://samba.org/ftp/unpacked/samba4/source/lib/ldb/tools/">tools directory</a>.
ldb makes use of the LDAP Data Interchange Format (LDIF), which is
documented in <a href="http://www.ietf.org/rfc/rfc2849.txt">RFC
2849</a>.
\section Support
ldb does not currently have its own mailing list or bug tracking
system. For now, please use the <a
href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
mailing list, and the <a href="http://bugzilla.samba.org/">Samba
bugzilla</a> bug tracking system.
\section Download
You can download the latest release either via rsync or anonymous
svn. To fetch via svn use the following commands:
\verbatim
svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/ldb ldb
svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb
svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc talloc
\endverbatim
To fetch via rsync use these commands:
\verbatim
rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/ldb .
rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/tdb .
rsync -Pavz samba.org::ftp/unpacked/samba4/source/lib/talloc .
\endverbatim
\section Credits
ldb is another product of the prolific <a href="http://samba.org/~tridge/">Andrew Tridgell</a>.
*/
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ad2oLschema.1">
<refmeta>
<refentrytitle>ad2oLschema</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ad2oLschema</refname>
<refpurpose>Converts AC-like LDAP schemas to OpenLDAP
compatible schema files</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ad2oLschema</command>
<arg choice="opt">-I INPUT-FILE</arg>
<arg choice="opt">-O OUTPUT-FILE</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ad2oLschema is a simple tool that converts AD-like LDIF
schema files into OpenLDAP schema files.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-H url</term>
<listitem><para>URL to an LDB or LDAP server with an AD schema to read. </para></listitem>
</varlistentry>
<varlistentry>
<term>-I input-file</term> <listitem><para>AD schema
to read. If neither this nor -H is specified, the
schema file will be read from standard input.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-O output-file</term>
<listitem><para>File to write OpenLDAP version of schema to.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
ad2oLschema was written by <ulink
url="http://samba.org/~abartlet/">Andrew Bartlett</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
</refsect1>
</refentry>
+262
View File
@@ -0,0 +1,262 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldb.3">
<refmeta>
<refentrytitle>ldb</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>ldb</refname>
<refclass>The Samba Project</refclass>
<refpurpose>A light-weight database library</refpurpose>
</refnamediv>
<refsynopsisdiv>
<synopsis>#include &lt;ldb.h&gt;</synopsis>
</refsynopsisdiv>
<refsect1>
<title>description</title>
<para>
ldb is a light weight embedded database library and API. With a
programming interface that is very similar to LDAP, ldb can store its
data either in a tdb(3) database or in a real LDAP database.
</para>
<para>
When used with the tdb backend ldb does not require any database
daemon. Instead, ldb function calls are processed immediately by the
ldb library, which does IO directly on the database, while allowing
multiple readers/writers using operating system byte range locks. This
leads to an API with very low overheads, often resulting in speeds of
more than 10x what can be achieved with a more traditional LDAP
architecture.
</para>
<para>
In a taxonomy of databases ldb would sit half way between key/value
pair databases (such as berkley db or tdb) and a full LDAP
database. With a structured attribute oriented API like LDAP and good
indexing capabilities, ldb can be used for quite sophisticated
applications that need a light weight database, without the
administrative overhead of a full LDAP installation.
</para>
<para>
Included with ldb are a number of useful command line tools for
manipulating a ldb database. These tools are similar in style to the
equivalent ldap command line tools.
</para>
<para>
In its default mode of operation with a tdb backend, ldb can also be
seen as a "schema-less LDAP". By default ldb does not require a
schema, which greatly reduces the complexity of getting started with
ldb databases. As the complexity of you application grows you can take
advantage of some of the optional schema-like attributes that ldb
offers, or you can migrate to using the full LDAP api while keeping
your exiting ldb code.
</para>
<para>
If you are new to ldb, then I suggest starting with the manual pages
for ldbsearch(1) and ldbedit(1), and experimenting with a local
database. Then I suggest you look at the ldb_connect(3) and
ldb_search(3) manual pages.
</para>
</refsect1>
<refsect1>
<title>TOOLS</title>
<itemizedlist>
<listitem><para>
<application>ldbsearch(1)</application>
- command line ldb search utility
</para></listitem>
<listitem><para>
<application>ldbedit(1)</application>
- edit all or part of a ldb database using your favourite editor
</para></listitem>
<listitem><para>
<application>ldbadd(1)</application>
- add records to a ldb database using LDIF formatted input
</para></listitem>
<listitem><para>
<application>ldbdel(1)</application>
- delete records from a ldb database
</para></listitem>
<listitem><para>
<application>ldbmodify(1)</application>
- modify records in a ldb database using LDIF formatted input
</para></listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>FUNCTIONS</title>
<itemizedlist>
<listitem><para>
<function>ldb_connect(3)</function>
- connect to a ldb backend
</para></listitem>
<listitem><para>
<function>ldb_search(3)</function>
- perform a database search
</para></listitem>
<listitem><para>
<function>ldb_add(3)</function>
- add a record to the database
</para></listitem>
<listitem><para>
<function>ldb_delete(3)</function>
- delete a record from the database
</para></listitem>
<listitem><para>
<function>ldb_modify(3)</function>
- modify a record in the database
</para></listitem>
<listitem><para>
<function>ldb_errstring(3)</function>
- retrieve extended error information from the last operation
</para></listitem>
<listitem><para>
<function>ldb_ldif_write(3)</function>
- write a LDIF formatted message
</para></listitem>
<listitem><para>
<function>ldb_ldif_write_file(3)</function>
- write a LDIF formatted message to a file
</para></listitem>
<listitem><para>
<function>ldb_ldif_read(3)</function>
- read a LDIF formatted message
</para></listitem>
<listitem><para>
<function>ldb_ldif_read_free(3)</function>
- free the result of a ldb_ldif_read()
</para></listitem>
<listitem><para>
<function>ldb_ldif_read_file(3)</function>
- read a LDIF message from a file
</para></listitem>
<listitem><para>
<function>ldb_ldif_read_string(3)</function>
- read a LDIF message from a string
</para></listitem>
<listitem><para>
<function>ldb_msg_find_element(3)</function>
- find an element in a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_val_equal_exact(3)</function>
- compare two ldb_val structures
</para></listitem>
<listitem><para>
<function>ldb_msg_find_val(3)</function>
- find an element by value
</para></listitem>
<listitem><para>
<function>ldb_msg_add_empty(3)</function>
- add an empty message element to a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_msg_add(3)</function>
- add a non-empty message element to a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_msg_element_compare(3)</function>
- compare two ldb_message_element structures
</para></listitem>
<listitem><para>
<function>ldb_msg_find_int(3)</function>
- return an integer value from a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_msg_find_uint(3)</function>
- return an unsigned integer value from a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_msg_find_double(3)</function>
- return a double value from a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_msg_find_string(3)</function>
- return a string value from a ldb_message
</para></listitem>
<listitem><para>
<function>ldb_set_alloc(3)</function>
- set the memory allocation function to be used by ldb
</para></listitem>
<listitem><para>
<function>ldb_set_debug(3)</function>
- set a debug handler to be used by ldb
</para></listitem>
<listitem><para>
<function>ldb_set_debug_stderr(3)</function>
- set a debug handler for stderr output
</para></listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>Author</title>
<para>
ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>
ldb is released under the GNU Lesser General Public License version 2
or later. Please see the file COPYING for license details.
</para>
</refsect1>
</refentry>
+105
View File
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbadd.1">
<refmeta>
<refentrytitle>ldbadd</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbadd</refname>
<refpurpose>Command-line utility for adding records to an LDB</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbadd</command>
<arg choice="opt">-h</arg>
<arg choice="opt">-H LDB-URL</arg>
<arg choice="opt">ldif-file1</arg>
<arg choice="opt">ldif-file2</arg>
<arg choice="opt">...</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ldbadd adds records to an ldb(7) database. It reads
the ldif(5) files specified on the command line and adds
the records from these files to the LDB database, which is specified
by the -H option or the LDB_URL environment variable.
</para>
<para>If - is specified as a ldb file, the ldif input is read from
standard input.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-h</term>
<listitem><para>
Show list of available options.</para></listitem>
</varlistentry>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem><para>
LDB URL to connect to. See ldb(7) for details.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry><term>LDB_URL</term>
<listitem><para>LDB URL to connect to (can be overrided by using the
-H command-line option.)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>This manpage was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>
+105
View File
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbdel.1">
<refmeta>
<refentrytitle>ldbdel</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbdel</refname>
<refpurpose>Command-line program for deleting LDB records</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbdel</command>
<arg choice="opt">-h</arg>
<arg choice="opt">-H LDB-URL</arg>
<arg choice="opt">dn</arg>
<arg choice="opt">...</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ldbdel deletes records from an ldb(7) database.
It deletes the records identified by the dn's specified
on the command-line. </para>
<para>ldbdel uses either the database that is specified with
the -H option or the database specified by the LDB_URL environment
variable.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-h</term>
<listitem><para>
Show list of available options.</para></listitem>
</varlistentry>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem><para>
LDB URL to connect to. See ldb(7) for details.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry><term>LDB_URL</term>
<listitem><para>LDB URL to connect to (can be overrided by using the
-H command-line option.)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify, ldbadd, ldif(5)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>ldbdel was written by Andrew Tridgell.</para>
<para>This manpage was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>
+200
View File
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbedit.1">
<refmeta>
<refentrytitle>ldbedit</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbedit</refname>
<refpurpose>Edit LDB databases using your preferred editor</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbedit</command>
<arg choice="opt">-?</arg>
<arg choice="opt">--usage</arg>
<arg choice="opt">-s base|one|sub</arg>
<arg choice="opt">-b basedn</arg>
<arg choice="opt">-a</arg>
<arg choice="opt">-e editor</arg>
<arg choice="opt">-H LDB-URL</arg>
<arg choice="opt">expression</arg>
<arg rep="repeat" choice="opt">attributes</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ldbedit is a utility that allows you to edit LDB entries (in
tdb files, sqlite files or LDAP servers) using your preferred editor.
ldbedit generates an LDIF file based on your query, allows you to edit
the LDIF, and then merges that LDIF back into the LDB backend.
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-?</term>
<term>--help</term>
<listitem>
<para>
Show list of available options, and a phrase describing what that option
does.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>--usage</term>
<listitem>
<para>
Show list of available options. This is similar to the help option,
however it does not provide any description, and is hence shorter.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem>
<para>
LDB URL to connect to. For a tdb database,
this will be of the form
tdb://<replaceable>filename</replaceable>.
For a LDAP connection over unix domain
sockets, this will be of the form
ldapi://<replaceable>socket</replaceable>. For
a (potentially remote) LDAP connection over
TCP, this will be of the form
ldap://<replaceable>hostname</replaceable>. For
an SQLite database, this will be of the form
sqlite://<replaceable>filename</replaceable>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-s one|sub|base</term>
<listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
</varlistentry>
<varlistentry>
<term>-a</term>
<term>-all</term>
<listitem>
<para>Edit all records. This allows you to
apply the same change to a number of records
at once. You probably want to combine this
with an expression of the form
"objectclass=*".
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-e editor</term>
<term>--editor editor</term>
<listitem>
<para>Specify the editor that should be used (overrides
the VISUAL and EDITOR environment
variables). If this option is not used, and
neither VISUAL nor EDITOR environment variables
are set, then the vi editor will be used.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-b basedn</term>
<listitem><para>Specify Base Distinguished Name to use.</para></listitem>
</varlistentry>
<varlistentry>
<term>-v</term>
<term>--verbose</term>
<listitem>
<para>Make ldbedit more verbose about the
operations that are being performed. Without
this option, ldbedit will only provide a
summary change line.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry>
<term>LDB_URL</term>
<listitem>
<para>LDB URL to connect to. This can be
overridden by using the -H command-line option.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>VISUAL and EDITOR</term>
<listitem>
<para>
Environment variables used to determine what
editor to use. VISUAL takes precedence over
EDITOR, and both are overridden by the
-e command-line option.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify(1), ldbdel(1), ldif(5), vi(1)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para>
ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>
This manpage was written by Jelmer Vernooij and updated
by Brad Hards.
</para>
</refsect1>
</refentry>
+93
View File
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbmodify.1">
<refmeta>
<refentrytitle>ldbmodify</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbmodify</refname>
<refpurpose>Modify records in a LDB database</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbmodify</command>
<arg choice="opt">-H LDB-URL</arg>
<arg choice="opt">ldif-file</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>
ldbmodify changes, adds and deletes records in a LDB database.
The changes that should be made to the LDB database are read from
the specified LDIF-file. If - is specified as the filename, input is read from stdin.
</para>
<para>For now, see ldapmodify(1) for details on the LDIF file format.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem><para>
LDB URL to connect to. See ldb(7) for details.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry><term>LDB_URL</term>
<listitem><para>LDB URL to connect to (can be overrided by using the
-H command-line option.)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbedit</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>This manpage was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbrename.1">
<refmeta>
<refentrytitle>ldbrename</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbrename</refname>
<refpurpose>Edit LDB databases using your favorite editor</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbrename</command>
<arg choice="opt">-h</arg>
<arg choice="opt">-o options</arg>
<arg choice="req">olddn</arg>
<arg choice="req">newdb</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ldbrename is a utility that allows you to rename trees in
an LDB database based by DN. This utility takes
two arguments: the original
DN name of the top element and the DN to change it to.
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-h</term>
<listitem><para>
Show list of available options.</para></listitem>
</varlistentry>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem><para>
LDB URL to connect to. See ldb(7) for details.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-o options</term>
<listitem><para>Extra ldb options, such as
modules.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry><term>LDB_URL</term>
<listitem><para>LDB URL to connect to (can be overrided by using the
-H command-line option.)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>This manpage was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="ldbsearch.1">
<refmeta>
<refentrytitle>ldbsearch</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ldbsearch</refname>
<refpurpose>Search for records in a LDB database</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ldbsearch</command>
<arg choice="opt">-h</arg>
<arg choice="opt">-s base|one|sub</arg>
<arg choice="opt">-b basedn</arg>
<arg chioce="opt">-i</arg>
<arg choice="opt">-H LDB-URL</arg>
<arg choice="opt">expression</arg>
<arg choice="opt">attributes</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>ldbsearch searches a LDB database for records matching the
specified expression (see the ldapsearch(1) manpage for
a description of the expression format). For each
record, the specified attributes are printed.
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-h</term>
<listitem><para>
Show list of available options.</para></listitem>
</varlistentry>
<varlistentry>
<term>-H &lt;ldb-url&gt;</term>
<listitem><para>
LDB URL to connect to. See ldb(7) for details.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-s one|sub|base</term>
<listitem><para>Search scope to use. One-level, subtree or base.</para></listitem>
</varlistentry>
<varlistentry>
<term>-i</term>
<listitem><para>Read search expressions from stdin. </para></listitem>
</varlistentry>
<varlistentry>
<term>-b basedn</term>
<listitem><para>Specify Base DN to use.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>ENVIRONMENT</title>
<variablelist>
<varlistentry><term>LDB_URL</term>
<listitem><para>LDB URL to connect to (can be overrided by using the
-H command-line option.)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbedit(1)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
<para>This manpage was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<refentry id="oLschema2ldif.1">
<refmeta>
<refentrytitle>oLschema2ldif</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>oLschema2ldif</refname>
<refpurpose>Converts LDAP schema's to LDB-compatible LDIF</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>oLschema2ldif</command>
<arg choice="opt">-I INPUT-FILE</arg>
<arg choice="opt">-O OUTPUT-FILE</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>oLschema2ldif is a simple tool that converts standard OpenLDAP schema files to a LDIF format that is understood by LDB.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-I input-file</term>
<listitem><para>OpenLDAP schema to read. If none are specified,
the schema file will be read from standard input.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-O output-file</term>
<listitem><para>File to write ldif version of schema to.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 4.0 of the Samba suite.</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>ldb(7), ldbmodify, ldbdel, ldif(5)</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para> ldb was written by
<ulink url="http://samba.org/~tridge/">Andrew Tridgell</ulink>.
oLschema2ldif was written by <ulink url="mailto:idra@samba.org">Simo Sorce</ulink>.
</para>
<para>
If you wish to report a problem or make a suggestion then please see
the <ulink url="http://ldb.samba.org/"/> web site for
current contact and maintainer information.
</para>
</refsect1>
</refentry>
+488
View File
@@ -0,0 +1,488 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb attribute scoped query control module
*
* Description: this module searches all the the objects pointed
* by the DNs contained in the references attribute
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
struct asq_context {
enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
const char * const *req_attrs;
char *req_attribute;
enum {
ASQ_CTRL_SUCCESS = 0,
ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX = 21,
ASQ_CTRL_UNWILLING_TO_PERFORM = 53,
ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71
} asq_ret;
struct ldb_request *base_req;
struct ldb_reply *base_res;
struct ldb_request **reqs;
int num_reqs;
int cur_req;
struct ldb_control **controls;
};
static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
{
struct asq_context *ac;
struct ldb_handle *h;
h = talloc_zero(mem_ctx, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc_zero(h, struct asq_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
return h;
}
static int asq_terminate(struct ldb_handle *handle)
{
struct asq_context *ac;
struct ldb_reply *ares;
struct ldb_asq_control *asq;
int i;
ac = talloc_get_type(handle->private_data, struct asq_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
handle->status = LDB_SUCCESS;
handle->state = LDB_ASYNC_DONE;
ares = talloc_zero(ac, struct ldb_reply);
if (ares == NULL)
return LDB_ERR_OPERATIONS_ERROR;
ares->type = LDB_REPLY_DONE;
if (ac->controls) {
for (i = 0; ac->controls[i]; i++);
ares->controls = talloc_move(ares, &ac->controls);
} else {
i = 0;
}
ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2);
if (ares->controls == NULL)
return LDB_ERR_OPERATIONS_ERROR;
ares->controls[i] = talloc(ares->controls, struct ldb_control);
if (ares->controls[i] == NULL)
return LDB_ERR_OPERATIONS_ERROR;
ares->controls[i]->oid = LDB_CONTROL_ASQ_OID;
ares->controls[i]->critical = 0;
asq = talloc_zero(ares->controls[i], struct ldb_asq_control);
if (asq == NULL)
return LDB_ERR_OPERATIONS_ERROR;
asq->result = ac->asq_ret;
ares->controls[i]->data = asq;
ares->controls[i + 1] = NULL;
ac->up_callback(ac->module->ldb, ac->up_context, ares);
return LDB_SUCCESS;
}
static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct asq_context *ac;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct asq_context);
if (ac == NULL) {
goto error;
}
/* we are interested only in the single reply (base search) we receive here */
if (ares->type == LDB_REPLY_ENTRY) {
ac->base_res = talloc_move(ac, &ares);
} else {
talloc_free(ares);
}
return LDB_SUCCESS;
error:
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct asq_context *ac;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct asq_context);
if (ac == NULL) {
goto error;
}
/* we are interested only in the single reply (base search) we receive here */
if (ares->type == LDB_REPLY_ENTRY) {
/* pass the message up to the original callback as we
* do not have to elaborate on it any further */
return ac->up_callback(ac->module->ldb, ac->up_context, ares);
} else { /* ignore any REFERRAL or DONE reply */
talloc_free(ares);
}
return LDB_SUCCESS;
error:
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
static int asq_search(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_control *control;
struct ldb_asq_control *asq_ctrl;
struct asq_context *ac;
struct ldb_handle *h;
char **base_attrs;
int ret;
/* check if there's a paged request control */
control = get_control_from_list(req->controls, LDB_CONTROL_ASQ_OID);
if (control == NULL) {
/* not found go on */
return ldb_next_request(module, req);
}
req->handle = NULL;
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb,
"Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
if (!asq_ctrl) {
return LDB_ERR_PROTOCOL_ERROR;
}
h = init_handle(req, module, req->context, req->callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct asq_context);
req->handle = h;
/* check the search is well formed */
if (req->op.search.scope != LDB_SCOPE_BASE) {
ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
return asq_terminate(h);
}
ac->req_attrs = req->op.search.attrs;
ac->req_attribute = talloc_strdup(ac, asq_ctrl->source_attribute);
if (ac->req_attribute == NULL)
return LDB_ERR_OPERATIONS_ERROR;
/* get the object to retrieve the DNs to search */
ac->base_req = talloc_zero(req, struct ldb_request);
if (ac->base_req == NULL)
return LDB_ERR_OPERATIONS_ERROR;
ac->base_req->operation = req->operation;
ac->base_req->op.search.base = req->op.search.base;
ac->base_req->op.search.scope = LDB_SCOPE_BASE;
ac->base_req->op.search.tree = req->op.search.tree;
base_attrs = talloc_array(ac->base_req, char *, 2);
if (base_attrs == NULL)
return LDB_ERR_OPERATIONS_ERROR;
base_attrs[0] = talloc_strdup(base_attrs, asq_ctrl->source_attribute);
if (base_attrs[0] == NULL)
return LDB_ERR_OPERATIONS_ERROR;
base_attrs[1] = NULL;
ac->base_req->op.search.attrs = (const char * const *)base_attrs;
ac->base_req->context = ac;
ac->base_req->callback = asq_base_callback;
ldb_set_timeout_from_prev_req(module->ldb, req, ac->base_req);
ac->step = ASQ_SEARCH_BASE;
ret = ldb_request(module->ldb, ac->base_req);
if (ret != LDB_SUCCESS) {
return ret;
}
return LDB_SUCCESS;
}
static int asq_requests(struct ldb_handle *handle) {
struct asq_context *ac;
struct ldb_message_element *el;
int i;
ac = talloc_get_type(handle->private_data, struct asq_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* look up the DNs */
if (ac->base_res == NULL) {
return LDB_ERR_NO_SUCH_OBJECT;
}
el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
/* no values found */
if (el == NULL) {
ac->asq_ret = ASQ_CTRL_SUCCESS;
return asq_terminate(handle);
}
/* build up the requests call chain */
ac->num_reqs = el->num_values;
ac->cur_req = 0;
ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
if (ac->reqs == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
for (i = 0; i < el->num_values; i++) {
ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request);
if (ac->reqs[i] == NULL)
return LDB_ERR_OPERATIONS_ERROR;
ac->reqs[i]->operation = LDB_SEARCH;
ac->reqs[i]->op.search.base = ldb_dn_new(ac->reqs[i], ac->module->ldb, (const char *)el->values[i].data);
if ( ! ldb_dn_validate(ac->reqs[i]->op.search.base)) {
ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
return asq_terminate(handle);
}
ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE;
ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree;
ac->reqs[i]->op.search.attrs = ac->req_attrs;
ac->reqs[i]->context = ac;
ac->reqs[i]->callback = asq_reqs_callback;
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]);
}
ac->step = ASQ_SEARCH_MULTI;
return LDB_SUCCESS;
}
static int asq_wait_none(struct ldb_handle *handle)
{
struct asq_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
ac = talloc_get_type(handle->private_data, struct asq_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
switch (ac->step) {
case ASQ_SEARCH_BASE:
ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->base_req->handle->status != LDB_SUCCESS) {
handle->status = ac->base_req->handle->status;
goto done;
}
if (ac->base_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
ret = asq_requests(handle);
/* no break nor return,
* the set of requests is performed in ASQ_SEARCH_MULTI
*/
case ASQ_SEARCH_MULTI:
if (ac->reqs[ac->cur_req]->handle == NULL) {
ret = ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
if (ret != LDB_SUCCESS) {
return ret;
}
}
ret = ldb_wait(ac->reqs[ac->cur_req]->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->reqs[ac->cur_req]->handle->status != LDB_SUCCESS) {
handle->status = ac->reqs[ac->cur_req]->handle->status;
}
if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) {
ac->cur_req++;
}
if (ac->cur_req < ac->num_reqs) {
return LDB_SUCCESS;
}
return asq_terminate(handle);
default:
ret = LDB_ERR_OPERATIONS_ERROR;
goto done;
}
ret = LDB_SUCCESS;
done:
handle->state = LDB_ASYNC_DONE;
return ret;
}
static int asq_wait_all(struct ldb_handle *handle)
{
int ret;
while (handle->state != LDB_ASYNC_DONE) {
ret = asq_wait_none(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
}
return handle->status;
}
static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
return asq_wait_all(handle);
} else {
return asq_wait_none(handle);
}
}
static int asq_init(struct ldb_module *module)
{
struct ldb_request *req;
int ret;
req = talloc_zero(module, struct ldb_request);
if (req == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
req->operation = LDB_REQ_REGISTER_CONTROL;
req->op.reg_control.oid = LDB_CONTROL_ASQ_OID;
ret = ldb_request(module->ldb, req);
if (ret != LDB_SUCCESS) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
}
return ldb_next_init(module);
}
static const struct ldb_module_ops asq_ops = {
.name = "asq",
.search = asq_search,
.wait = asq_wait,
.init_context = asq_init
};
int ldb_asq_init(void)
{
return ldb_register_module(&asq_ops);
}
File diff suppressed because it is too large Load Diff
+158
View File
@@ -0,0 +1,158 @@
/*
ldb database mapping module
Copyright (C) Jelmer Vernooij 2005
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
* NOTICE: this module is NOT released under the GNU LGPL license as
* other ldb code. This module is release under the GNU GPL v2 or
* later license.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LDB_MAP_H__
#define __LDB_MAP_H__
/* ldb_map is a skeleton LDB module that can be used for any other modules
* that need to map attributes.
*
* The term 'remote' in this header refers to the connection where the
* original schema is used on while 'local' means the local connection
* that any upper layers will use.
*
* All local attributes will have to have a definition. Not all remote
* attributes need a definition as LDB is a lot less strict than LDAP
* (in other words, sending unknown attributes to an LDAP server hurts us,
* while returning too many attributes in ldb_search() doesn't)
*/
/* Name of the internal attribute pointing from the local to the
* remote part of a record */
#define IS_MAPPED "isMapped"
struct ldb_map_context;
/* convert a local ldb_val to a remote ldb_val */
typedef struct ldb_val (*ldb_map_convert_func) (struct ldb_module *module, void *mem_ctx, const struct ldb_val *val);
#define LDB_MAP_MAX_REMOTE_NAMES 10
/* map from local to remote attribute */
struct ldb_map_attribute {
const char *local_name; /* local name */
enum ldb_map_attr_type {
MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */
MAP_KEEP, /* Keep as is. Same name locally and remotely. */
MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */
MAP_CONVERT, /* Rename + convert data */
MAP_GENERATE /* Use generate function for generating new name/data.
Used for generating attributes based on
multiple remote attributes. */
} type;
/* if set, will be called for search expressions that contain this attribute */
int (*convert_operator)(struct ldb_module *, TALLOC_CTX *ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *);
union {
struct {
const char *remote_name;
} rename;
struct {
const char *remote_name;
/* Convert local to remote data */
ldb_map_convert_func convert_local;
/* Convert remote to local data */
/* an entry can have convert_remote set to NULL, as long as there as an entry with the same local_name
* that is non-NULL before it. */
ldb_map_convert_func convert_remote;
} convert;
struct {
/* Generate the local attribute from remote message */
struct ldb_message_element *(*generate_local)(struct ldb_module *, TALLOC_CTX *mem_ctx, const char *remote_attr, const struct ldb_message *remote);
/* Update remote message with information from local message */
void (*generate_remote)(struct ldb_module *, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local);
/* Name(s) for this attribute on the remote server. This is an array since
* one local attribute's data can be split up into several attributes
* remotely */
const char *remote_names[LDB_MAP_MAX_REMOTE_NAMES];
/* Names of additional remote attributes
* required for the generation. NULL
* indicates that `local_attr' suffices. */
/*
#define LDB_MAP_MAX_SELF_ATTRIBUTES 10
const char *self_attrs[LDB_MAP_MAX_SELF_ATTRIBUTES];
*/
} generate;
} u;
};
#define LDB_MAP_MAX_SUBCLASSES 10
#define LDB_MAP_MAX_MUSTS 10
#define LDB_MAP_MAX_MAYS 50
/* map from local to remote objectClass */
struct ldb_map_objectclass {
const char *local_name;
const char *remote_name;
const char *base_classes[LDB_MAP_MAX_SUBCLASSES];
const char *musts[LDB_MAP_MAX_MUSTS];
const char *mays[LDB_MAP_MAX_MAYS];
};
/* private context data */
struct ldb_map_context {
struct ldb_map_attribute *attribute_maps;
/* NOTE: Always declare base classes first here */
const struct ldb_map_objectclass *objectclass_maps;
/* Remote (often operational) attributes that should be added
* to any wildcard search */
const char * const *wildcard_attributes;
/* struct ldb_context *mapped_ldb; */
struct ldb_dn *local_base_dn;
struct ldb_dn *remote_base_dn;
};
/* Global private data */
struct map_private {
void *caller_private;
struct ldb_map_context *context;
};
/* Initialize global private data. */
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);
/* get copy of map_ops */
struct ldb_module_ops
ldb_map_get_ops(void);
#endif /* __LDB_MAP_H__ */
@@ -0,0 +1,724 @@
/*
ldb database mapping module
Copyright (C) Jelmer Vernooij 2005
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
* NOTICE: this module is NOT released under the GNU LGPL license as
* other ldb code. This module is release under the GNU GPL v2 or
* later license.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/modules/ldb_map.h"
#include "ldb/modules/ldb_map_private.h"
/* Mapping message elements
* ======================== */
/* Map a message element into the remote partition. */
static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
{
struct ldb_message_element *el;
int i;
el = talloc_zero(mem_ctx, struct ldb_message_element);
if (el == NULL) {
map_oom(module);
return NULL;
}
el->num_values = old->num_values;
el->values = talloc_array(el, struct ldb_val, el->num_values);
if (el->values == NULL) {
talloc_free(el);
map_oom(module);
return NULL;
}
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]);
}
return el;
}
/* Add a message element either to a local or to a remote message,
* depending on whether it goes into the local or remote partition. */
static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
{
const struct ldb_map_context *data = map_get_context(module);
const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
struct ldb_message_element *el=NULL;
/* Unknown attribute: ignore */
if (map == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
"Not mapping attribute '%s': no mapping found\n",
old->name);
goto local;
}
switch (map->type) {
case MAP_IGNORE:
goto local;
case MAP_CONVERT:
if (map->u.convert.convert_local == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
"Not mapping attribute '%s': "
"'convert_local' not set\n",
map->local_name);
goto local;
}
/* fall through */
case MAP_KEEP:
case MAP_RENAME:
el = ldb_msg_el_map_local(module, remote, map, old);
break;
case MAP_GENERATE:
if (map->u.generate.generate_remote == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
"Not mapping attribute '%s': "
"'generate_remote' not set\n",
map->local_name);
goto local;
}
/* TODO: if this attr requires context:
* make sure all context attrs are mappable (in 'names')
* make sure all context attrs have already been mapped?
* maybe postpone generation until they have been mapped?
*/
map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
return 0;
}
if (el == NULL) {
return -1;
}
return ldb_msg_add(remote, el, old->flags);
local:
el = talloc(local, struct ldb_message_element);
if (el == NULL) {
map_oom(module);
return -1;
}
*el = *old; /* copy the old element */
return ldb_msg_add(local, el, old->flags);
}
/* Mapping messages
* ================ */
/* Check whether a message will be (partially) mapped into the remote partition. */
static BOOL ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
{
const struct ldb_map_context *data = map_get_context(module);
BOOL ret;
int i;
for (i = 0; i < msg->num_elements; i++) {
ret = map_attr_check_remote(data, msg->elements[i].name);
if (ret) {
return ret;
}
}
return False;
}
/* Split message elements that stay in the local partition from those
* that are mapped into the remote partition. */
static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
{
/* const char * const names[]; */
int i, ret;
for (i = 0; i < msg->num_elements; i++) {
/* Skip 'IS_MAPPED' */
if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
"Skipping attribute '%s'\n",
msg->elements[i].name);
continue;
}
ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
if (ret) {
return ret;
}
}
return 0;
}
/* Inbound requests: add, modify, rename, delete
* ============================================= */
/* Add the remote record. */
int map_add_do_remote(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
ac->step = MAP_ADD_REMOTE;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_remote_request(ac->module, ac->remote_req);
}
/* Add the local record. */
int map_add_do_local(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
ac->step = MAP_ADD_LOCAL;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_request(ac->module, ac->local_req);
}
/* Add a record. */
int map_add(struct ldb_module *module, struct ldb_request *req)
{
const struct ldb_message *msg = req->op.add.message;
struct ldb_handle *h;
struct map_context *ac;
struct ldb_message *local, *remote;
const char *dn;
/* Do not manipulate our control entries */
if (ldb_dn_is_special(msg->dn)) {
return ldb_next_request(module, req);
}
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
if (!ldb_dn_check_local(module, msg->dn)) {
return ldb_next_request(module, req);
}
/* No mapping needed, fail */
if (!ldb_msg_check_remote(module, msg)) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Prepare context and handle */
h = map_init_handle(req, module);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct map_context);
/* Prepare the local operation */
ac->local_req = talloc(ac, struct ldb_request);
if (ac->local_req == NULL) {
goto oom;
}
*(ac->local_req) = *req; /* copy the request */
ac->local_req->context = NULL;
ac->local_req->callback = NULL;
/* Prepare the remote operation */
ac->remote_req = talloc(ac, struct ldb_request);
if (ac->remote_req == NULL) {
goto oom;
}
*(ac->remote_req) = *req; /* copy the request */
ac->remote_req->context = NULL;
ac->remote_req->callback = NULL;
/* Prepare the local message */
local = ldb_msg_new(ac->local_req);
if (local == NULL) {
goto oom;
}
local->dn = msg->dn;
/* Prepare the remote message */
remote = ldb_msg_new(ac->remote_req);
if (remote == NULL) {
goto oom;
}
remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
/* Split local from remote message */
ldb_msg_partition(module, local, remote, msg);
ac->local_req->op.add.message = local;
ac->remote_req->op.add.message = remote;
if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
/* No local data or db, just run the remote request */
talloc_free(ac->local_req);
req->handle = h; /* return our own handle to deal with this call */
return map_add_do_remote(h);
}
/* Store remote DN in 'IS_MAPPED' */
/* TODO: use GUIDs here instead */
dn = ldb_dn_alloc_linearized(local, remote->dn);
if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
goto failed;
}
req->handle = h; /* return our own handle to deal with this call */
return map_add_do_local(h);
oom:
map_oom(module);
failed:
talloc_free(h);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Modify the remote record. */
int map_modify_do_remote(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
ac->step = MAP_MODIFY_REMOTE;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_remote_request(ac->module, ac->remote_req);
}
/* Modify the local record. */
int map_modify_do_local(struct ldb_handle *handle)
{
struct map_context *ac;
struct ldb_message *msg;
char *dn;
ac = talloc_get_type(handle->private_data, struct map_context);
if (ac->local_dn == NULL) {
/* No local record present, add it instead */
msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
/* Add local 'IS_MAPPED' */
/* TODO: use GUIDs here instead */
if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
dn = ldb_dn_alloc_linearized(msg, ac->remote_req->op.mod.message->dn);
if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Turn request into 'add' */
ac->local_req->operation = LDB_ADD;
ac->local_req->op.add.message = msg;
/* TODO: Could I just leave msg in there? I think so,
* but it looks clearer this way. */
}
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
ac->step = MAP_MODIFY_LOCAL;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_request(ac->module, ac->local_req);
}
/* Modify a record. */
int map_modify(struct ldb_module *module, struct ldb_request *req)
{
const struct ldb_message *msg = req->op.mod.message;
struct ldb_handle *h;
struct map_context *ac;
struct ldb_message *local, *remote;
/* Do not manipulate our control entries */
if (ldb_dn_is_special(msg->dn)) {
return ldb_next_request(module, req);
}
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
if (!ldb_dn_check_local(module, msg->dn)) {
return ldb_next_request(module, req);
}
/* No mapping needed, skip to next module */
/* TODO: What if the remote part exists, the local doesn't,
* and this request wants to modify local data and thus
* add the local record? */
if (!ldb_msg_check_remote(module, msg)) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* Prepare context and handle */
h = map_init_handle(req, module);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct map_context);
/* Prepare the local operation */
ac->local_req = talloc(ac, struct ldb_request);
if (ac->local_req == NULL) {
goto oom;
}
*(ac->local_req) = *req; /* copy the request */
ac->local_req->context = NULL;
ac->local_req->callback = NULL;
/* Prepare the remote operation */
ac->remote_req = talloc(ac, struct ldb_request);
if (ac->remote_req == NULL) {
goto oom;
}
*(ac->remote_req) = *req; /* copy the request */
ac->remote_req->context = NULL;
ac->remote_req->callback = NULL;
/* Prepare the local message */
local = ldb_msg_new(ac->local_req);
if (local == NULL) {
goto oom;
}
local->dn = msg->dn;
/* Prepare the remote message */
remote = ldb_msg_new(ac->remote_req);
if (remote == NULL) {
goto oom;
}
remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
/* Split local from remote message */
ldb_msg_partition(module, local, remote, msg);
ac->local_req->op.mod.message = local;
ac->remote_req->op.mod.message = remote;
if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
/* No local data or db, just run the remote request */
talloc_free(ac->local_req);
req->handle = h; /* return our own handle to deal with this call */
return map_modify_do_remote(h);
}
/* prepare the search operation */
ac->search_req = map_search_self_req(ac, msg->dn);
if (ac->search_req == NULL) {
goto failed;
}
ac->step = MAP_SEARCH_SELF_MODIFY;
req->handle = h; /* return our own handle to deal with this call */
return ldb_next_request(module, ac->search_req);
oom:
map_oom(module);
failed:
talloc_free(h);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Delete the remote record. */
int map_delete_do_remote(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
ac->step = MAP_DELETE_REMOTE;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_remote_request(ac->module, ac->remote_req);
}
/* Delete the local record. */
int map_delete_do_local(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
/* No local record, continue remotely */
if (ac->local_dn == NULL) {
return map_delete_do_remote(handle);
}
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
ac->step = MAP_DELETE_LOCAL;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_request(ac->module, ac->local_req);
}
/* Delete a record. */
int map_delete(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_handle *h;
struct map_context *ac;
/* Do not manipulate our control entries */
if (ldb_dn_is_special(req->op.del.dn)) {
return ldb_next_request(module, req);
}
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
if (!ldb_dn_check_local(module, req->op.del.dn)) {
return ldb_next_request(module, req);
}
/* Prepare context and handle */
h = map_init_handle(req, module);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct map_context);
/* Prepare the local operation */
ac->local_req = talloc(ac, struct ldb_request);
if (ac->local_req == NULL) {
goto oom;
}
*(ac->local_req) = *req; /* copy the request */
ac->local_req->op.del.dn = req->op.del.dn;
ac->local_req->context = NULL;
ac->local_req->callback = NULL;
/* Prepare the remote operation */
ac->remote_req = talloc(ac, struct ldb_request);
if (ac->remote_req == NULL) {
goto oom;
}
*(ac->remote_req) = *req; /* copy the request */
ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
/* No local db, just run the remote request */
if (!map_check_local_db(ac->module)) {
req->handle = h; /* return our own handle to deal with this call */
return map_delete_do_remote(h);
}
ac->remote_req->context = NULL;
ac->remote_req->callback = NULL;
/* Prepare the search operation */
ac->search_req = map_search_self_req(ac, req->op.del.dn);
if (ac->search_req == NULL) {
goto failed;
}
req->handle = h; /* return our own handle to deal with this call */
ac->step = MAP_SEARCH_SELF_DELETE;
return ldb_next_request(module, ac->search_req);
oom:
map_oom(module);
failed:
talloc_free(h);
return LDB_ERR_OPERATIONS_ERROR;
}
/* Rename the remote record. */
int map_rename_do_remote(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
ac->step = MAP_RENAME_REMOTE;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_remote_request(ac->module, ac->remote_req);
}
/* Update the local 'IS_MAPPED' attribute. */
int map_rename_do_fixup(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
ac->step = MAP_RENAME_FIXUP;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_request(ac->module, ac->down_req);
}
/* Rename the local record. */
int map_rename_do_local(struct ldb_handle *handle)
{
struct map_context *ac;
ac = talloc_get_type(handle->private_data, struct map_context);
/* No local record, continue remotely */
if (ac->local_dn == NULL) {
return map_rename_do_remote(handle);
}
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
ac->step = MAP_RENAME_LOCAL;
handle->state = LDB_ASYNC_INIT;
handle->status = LDB_SUCCESS;
return ldb_next_request(ac->module, ac->local_req);
}
/* Rename a record. */
int map_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_handle *h;
struct map_context *ac;
/* Do not manipulate our control entries */
if (ldb_dn_is_special(req->op.rename.olddn)) {
return ldb_next_request(module, req);
}
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
(!ldb_dn_check_local(module, req->op.rename.newdn))) {
return ldb_next_request(module, req);
}
/* Rename into/out of the mapped partition requested, bail out */
if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
!ldb_dn_check_local(module, req->op.rename.newdn)) {
return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
}
/* Prepare context and handle */
h = map_init_handle(req, module);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct map_context);
/* Prepare the local operation */
ac->local_req = talloc(ac, struct ldb_request);
if (ac->local_req == NULL) {
goto oom;
}
*(ac->local_req) = *req; /* copy the request */
ac->local_req->op.rename.olddn = req->op.rename.olddn;
ac->local_req->op.rename.newdn = req->op.rename.newdn;
ac->local_req->context = NULL;
ac->local_req->callback = NULL;
/* Prepare the remote operation */
ac->remote_req = talloc(ac, struct ldb_request);
if (ac->remote_req == NULL) {
goto oom;
}
*(ac->remote_req) = *req; /* copy the request */
ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
ac->remote_req->context = NULL;
ac->remote_req->callback = NULL;
/* No local db, just run the remote request */
if (!map_check_local_db(ac->module)) {
req->handle = h; /* return our own handle to deal with this call */
return map_rename_do_remote(h);
}
/* Prepare the fixup operation */
/* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
if (ac->down_req == NULL) {
goto failed;
}
/* Prepare the search operation */
ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
if (ac->search_req == NULL) {
goto failed;
}
req->handle = h; /* return our own handle to deal with this call */
ac->step = MAP_SEARCH_SELF_RENAME;
return ldb_next_request(module, ac->search_req);
oom:
map_oom(module);
failed:
talloc_free(h);
return LDB_ERR_OPERATIONS_ERROR;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,117 @@
/* A handy macro to report Out of Memory conditions */
#define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
/* The type of search callback functions */
typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *);
/* The special DN from which the local and remote base DNs are fetched */
#define MAP_DN_NAME "@MAP"
#define MAP_DN_FROM "@FROM"
#define MAP_DN_TO "@TO"
/* Private data structures
* ======================= */
/* Context data for mapped requests */
struct map_context {
enum map_step {
MAP_SEARCH_REMOTE,
MAP_ADD_REMOTE,
MAP_ADD_LOCAL,
MAP_SEARCH_SELF_MODIFY,
MAP_MODIFY_REMOTE,
MAP_MODIFY_LOCAL,
MAP_SEARCH_SELF_DELETE,
MAP_DELETE_REMOTE,
MAP_DELETE_LOCAL,
MAP_SEARCH_SELF_RENAME,
MAP_RENAME_REMOTE,
MAP_RENAME_FIXUP,
MAP_RENAME_LOCAL
} step;
struct ldb_module *module;
struct ldb_dn *local_dn;
const struct ldb_parse_tree *local_tree;
const char * const *local_attrs;
const char * const *remote_attrs;
const char * const *all_attrs;
struct ldb_request *orig_req;
struct ldb_request *local_req;
struct ldb_request *remote_req;
struct ldb_request *down_req;
struct ldb_request *search_req;
/* for search, we may have a lot of contexts */
int num_searches;
struct ldb_request **search_reqs;
};
/* Context data for mapped search requests */
struct map_search_context {
struct map_context *ac;
struct ldb_reply *local_res;
struct ldb_reply *remote_res;
};
/* Common operations
* ================= */
/* The following definitions come from lib/ldb/modules/ldb_map.c */
const struct ldb_map_context *map_get_context(struct ldb_module *module);
struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares);
struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module);
int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request);
BOOL map_check_local_db(struct ldb_module *module);
BOOL map_attr_check_remote(const struct ldb_map_context *data, const char *attr);
BOOL ldb_dn_check_local(struct ldb_module *module, struct ldb_dn *dn);
const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name);
const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name);
const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
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, 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, struct ldb_dn *dn);
struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback);
struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn);
struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn);
int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map);
/* LDB Requests
* ============ */
/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */
int map_add_do_remote(struct ldb_handle *handle);
int map_add_do_local(struct ldb_handle *handle);
int map_add(struct ldb_module *module, struct ldb_request *req);
int map_modify_do_remote(struct ldb_handle *handle);
int map_modify_do_local(struct ldb_handle *handle);
int map_modify(struct ldb_module *module, struct ldb_request *req);
int map_delete_do_remote(struct ldb_handle *handle);
int map_delete_do_local(struct ldb_handle *handle);
int map_delete(struct ldb_module *module, struct ldb_request *req);
int map_rename_do_remote(struct ldb_handle *handle);
int map_rename_do_fixup(struct ldb_handle *handle);
int map_rename_do_local(struct ldb_handle *handle);
int map_rename(struct ldb_module *module, struct ldb_request *req);
/* The following definitions come from lib/ldb/modules/ldb_map_outbound.c */
int map_search(struct ldb_module *module, struct ldb_request *req);
+694
View File
@@ -0,0 +1,694 @@
/*
ldb database library
Copyright (C) Simo Sorce 2006
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: objectClass sorting module
*
* Description: sort the objectClass attribute into the class hierarchy
*
* Author: Andrew Bartlett
*/
#include "includes.h"
#include "ldb/include/includes.h"
struct oc_context {
enum oc_step {OC_DO_REQ, OC_SEARCH_SELF, OC_DO_MOD} step;
struct ldb_module *module;
struct ldb_request *orig_req;
struct ldb_request *down_req;
struct ldb_request *search_req;
struct ldb_reply *search_res;
struct ldb_request *mod_req;
};
struct class_list {
struct class_list *prev, *next;
const char *objectclass;
};
static struct ldb_handle *oc_init_handle(struct ldb_request *req, struct ldb_module *module)
{
struct oc_context *ac;
struct ldb_handle *h;
h = talloc_zero(req, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc_zero(h, struct oc_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->orig_req = req;
return h;
}
static int objectclass_sort(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
struct ldb_message_element *objectclass_element,
struct class_list **sorted_out)
{
int i;
int layer;
struct class_list *sorted = NULL, *parent_class = NULL,
*subclass = NULL, *unsorted = NULL, *current, *poss_subclass;
/* DESIGN:
*
* We work on 4 different 'bins' (implemented here as linked lists):
*
* * sorted: the eventual list, in the order we wish to push
* into the database. This is the only ordered list.
*
* * parent_class: The current parent class 'bin' we are
* trying to find subclasses for
*
* * subclass: The subclasses we have found so far
*
* * unsorted: The remaining objectClasses
*
* The process is a matter of filtering objectClasses up from
* unsorted into sorted. Order is irrelevent in the later 3 'bins'.
*
* We start with 'top' (found and promoted to parent_class
* initially). Then we find (in unsorted) all the direct
* subclasses of 'top'. parent_classes is concatenated onto
* the end of 'sorted', and subclass becomes the list in
* parent_class.
*
* We then repeat, until we find no more subclasses. Any left
* over classes are added to the end.
*
*/
/* Firstly, dump all the objectClass elements into the
* unsorted bin, except for 'top', which is special */
for (i=0; i < objectclass_element->num_values; i++) {
current = talloc(mem_ctx, struct class_list);
if (!current) {
ldb_set_errstring(module->ldb, "objectclass: out of memory allocating objectclass list");
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
current->objectclass = (const char *)objectclass_element->values[i].data;
/* this is the root of the tree. We will start
* looking for subclasses from here */
if (ldb_attr_cmp("top", current->objectclass) == 0) {
DLIST_ADD(parent_class, current);
} else {
DLIST_ADD(unsorted, current);
}
}
/* DEBUGGING aid: how many layers are we down now? */
layer = 0;
do {
layer++;
/* Find all the subclasses of classes in the
* parent_classes. Push them onto the subclass list */
/* Ensure we don't bother if there are no unsorted entries left */
for (current = parent_class; unsorted && current; current = current->next) {
const char **subclasses = ldb_subclass_list(module->ldb, current->objectclass);
/* Walk the list of possible subclasses in unsorted */
for (poss_subclass = unsorted; poss_subclass; ) {
struct class_list *next;
/* Save the next pointer, as the DLIST_ macros will change poss_subclass->next */
next = poss_subclass->next;
for (i = 0; subclasses && subclasses[i]; i++) {
if (ldb_attr_cmp(poss_subclass->objectclass, subclasses[i]) == 0) {
DLIST_REMOVE(unsorted, poss_subclass);
DLIST_ADD(subclass, poss_subclass);
break;
}
}
poss_subclass = next;
}
}
/* Now push the parent_classes as sorted, we are done with
these. Add to the END of the list by concatenation */
DLIST_CONCATENATE(sorted, parent_class, struct class_list *);
/* and now find subclasses of these */
parent_class = subclass;
subclass = NULL;
/* If we didn't find any subclasses we will fall out
* the bottom here */
} while (parent_class);
/* This shouldn't happen, and would break MMC, but we can't
* afford to loose objectClasses. Perhaps there was no 'top',
* or some other schema error?
*
* Detecting schema errors is the job of the schema module, so
* at this layer we just try not to loose data
*/
DLIST_CONCATENATE(sorted, unsorted, struct class_list *);
*sorted_out = sorted;
return LDB_SUCCESS;
}
static int objectclass_add(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_message_element *objectclass_element;
struct class_list *sorted, *current;
struct ldb_request *down_req;
struct ldb_message *msg;
int ret;
TALLOC_CTX *mem_ctx;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_add\n");
if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
}
objectclass_element = ldb_msg_find_element(req->op.add.message, "objectClass");
/* If no part of this add has an objectClass, then we don't
* need to make any changes. cn=rootdse doesn't have an objectClass */
if (!objectclass_element) {
return ldb_next_request(module, req);
}
mem_ctx = talloc_new(req);
if (mem_ctx == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
return ret;
}
/* prepare the first operation */
down_req = talloc(req, struct ldb_request);
if (down_req == NULL) {
ldb_set_errstring(module->ldb, "Out of memory!");
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
*down_req = *req; /* copy the request */
down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
if (down_req->op.add.message == NULL) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
ldb_msg_remove_attr(msg, "objectClass");
ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
/* We must completely replace the existing objectClass entry,
* because we need it sorted */
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
talloc_free(mem_ctx);
return ret;
}
}
talloc_free(mem_ctx);
ret = ldb_msg_sanity_check(module->ldb, msg);
if (ret != LDB_SUCCESS) {
return ret;
}
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
/* do not free down_req as the call results may be linked to it,
* it will be freed when the upper level request get freed */
if (ret == LDB_SUCCESS) {
req->handle = down_req->handle;
}
return ret;
}
static int objectclass_modify(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_message_element *objectclass_element;
struct ldb_message *msg;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "objectclass_modify\n");
if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
return ldb_next_request(module, req);
}
objectclass_element = ldb_msg_find_element(req->op.mod.message, "objectClass");
/* If no part of this touches the objectClass, then we don't
* need to make any changes. */
/* If the only operation is the deletion of the objectClass then go on */
if (!objectclass_element) {
return ldb_next_request(module, req);
}
switch (objectclass_element->flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_DELETE:
/* Delete everything? Probably totally illigal, but hey! */
if (objectclass_element->num_values == 0) {
return ldb_next_request(module, req);
}
break;
case LDB_FLAG_MOD_REPLACE:
{
struct ldb_request *down_req;
struct class_list *sorted, *current;
TALLOC_CTX *mem_ctx;
int ret;
mem_ctx = talloc_new(req);
if (mem_ctx == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* prepare the first operation */
down_req = talloc(req, struct ldb_request);
if (down_req == NULL) {
ldb_set_errstring(module->ldb, "Out of memory!");
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
*down_req = *req; /* copy the request */
down_req->op.mod.message = msg = ldb_msg_copy_shallow(down_req, req->op.mod.message);
if (down_req->op.add.message == NULL) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
ret = objectclass_sort(module, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
return ret;
}
/* We must completely replace the existing objectClass entry,
* because we need it sorted */
ldb_msg_remove_attr(msg, "objectClass");
ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
talloc_free(mem_ctx);
return ret;
}
}
talloc_free(mem_ctx);
ret = ldb_msg_sanity_check(module->ldb, msg);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
/* do not free down_req as the call results may be linked to it,
* it will be freed when the upper level request get freed */
if (ret == LDB_SUCCESS) {
req->handle = down_req->handle;
}
return ret;
}
}
{
struct ldb_handle *h;
struct oc_context *ac;
h = oc_init_handle(req, module);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct oc_context);
/* return or own handle to deal with this call */
req->handle = h;
/* prepare the first operation */
ac->down_req = talloc(ac, struct ldb_request);
if (ac->down_req == NULL) {
ldb_set_errstring(module->ldb, "Out of memory!");
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req) = *req; /* copy the request */
ac->down_req->context = NULL;
ac->down_req->callback = NULL;
ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
ac->step = OC_DO_REQ;
return ldb_next_request(module, ac->down_req);
}
}
static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct oc_context *ac;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(context, struct oc_context);
/* we are interested only in the single reply (base search) we receive here */
if (ares->type == LDB_REPLY_ENTRY) {
if (ac->search_res != NULL) {
ldb_set_errstring(ldb, "Too many results");
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->search_res = talloc_move(ac, &ares);
} else {
talloc_free(ares);
}
return LDB_SUCCESS;
}
static int objectclass_search_self(struct ldb_handle *h) {
struct oc_context *ac;
static const char * const attrs[] = { "objectClass", NULL };
ac = talloc_get_type(h->private_data, struct oc_context);
/* prepare the search operation */
ac->search_req = talloc_zero(ac, struct ldb_request);
if (ac->search_req == NULL) {
ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
ac->search_req->operation = LDB_SEARCH;
ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
ac->search_req->op.search.scope = LDB_SCOPE_BASE;
ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL);
if (ac->search_req->op.search.tree == NULL) {
ldb_set_errstring(ac->module->ldb, "objectclass: Internal error producing null search");
return LDB_ERR_OPERATIONS_ERROR;
}
ac->search_req->op.search.attrs = attrs;
ac->search_req->controls = NULL;
ac->search_req->context = ac;
ac->search_req->callback = get_self_callback;
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
ac->step = OC_SEARCH_SELF;
return ldb_next_request(ac->module, ac->search_req);
}
static int objectclass_do_mod(struct ldb_handle *h) {
struct oc_context *ac;
struct ldb_message_element *objectclass_element;
struct ldb_message *msg;
TALLOC_CTX *mem_ctx;
struct class_list *sorted, *current;
int ret;
ac = talloc_get_type(h->private_data, struct oc_context);
mem_ctx = talloc_new(ac);
if (mem_ctx == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->mod_req = talloc(ac, struct ldb_request);
if (ac->mod_req == NULL) {
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->mod_req->operation = LDB_MODIFY;
ac->mod_req->controls = NULL;
ac->mod_req->context = ac;
ac->mod_req->callback = NULL;
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
/* use a new message structure */
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
if (msg == NULL) {
ldb_set_errstring(ac->module->ldb, "objectclass: could not create new modify msg");
talloc_free(mem_ctx);
return LDB_ERR_OPERATIONS_ERROR;
}
/* This is now the objectClass list from the database */
objectclass_element = ldb_msg_find_element(ac->search_res->message,
"objectClass");
if (!objectclass_element) {
/* Where did it go? Move along now, nothing to see here */
talloc_free(mem_ctx);
return LDB_SUCCESS;
}
/* modify dn */
msg->dn = ac->orig_req->op.mod.message->dn;
ret = objectclass_sort(ac->module, mem_ctx, objectclass_element, &sorted);
if (ret != LDB_SUCCESS) {
return ret;
}
/* We must completely replace the existing objectClass entry.
* We could do a constrained add/del, but we are meant to be
* in a transaction... */
ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(ac->module->ldb, "objectclass: could not clear objectclass in modify msg");
talloc_free(mem_ctx);
return ret;
}
/* Move from the linked list back into an ldb msg */
for (current = sorted; current; current = current->next) {
ret = ldb_msg_add_string(msg, "objectClass", current->objectclass);
if (ret != LDB_SUCCESS) {
ldb_set_errstring(ac->module->ldb, "objectclass: could not re-add sorted objectclass to modify msg");
talloc_free(mem_ctx);
return ret;
}
}
ret = ldb_msg_sanity_check(ac->module->ldb, msg);
if (ret != LDB_SUCCESS) {
talloc_free(mem_ctx);
return ret;
}
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->step = OC_DO_MOD;
talloc_free(mem_ctx);
/* perform the search */
return ldb_next_request(ac->module, ac->mod_req);
}
static int oc_wait(struct ldb_handle *handle) {
struct oc_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
ac = talloc_get_type(handle->private_data, struct oc_context);
switch (ac->step) {
case OC_DO_REQ:
ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->down_req->handle->status != LDB_SUCCESS) {
handle->status = ac->down_req->handle->status;
goto done;
}
if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
/* mods done, go on */
return objectclass_search_self(handle);
case OC_SEARCH_SELF:
ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->search_req->handle->status != LDB_SUCCESS) {
handle->status = ac->search_req->handle->status;
goto done;
}
if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
/* self search done, go on */
return objectclass_do_mod(handle);
case OC_DO_MOD:
ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->mod_req->handle->status != LDB_SUCCESS) {
handle->status = ac->mod_req->handle->status;
goto done;
}
if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
break;
default:
ret = LDB_ERR_OPERATIONS_ERROR;
goto done;
}
ret = LDB_SUCCESS;
done:
handle->state = LDB_ASYNC_DONE;
return ret;
}
static int oc_wait_all(struct ldb_handle *handle) {
int ret;
while (handle->state != LDB_ASYNC_DONE) {
ret = oc_wait(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
}
return handle->status;
}
static int objectclass_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
return oc_wait_all(handle);
} else {
return oc_wait(handle);
}
}
static const struct ldb_module_ops objectclass_ops = {
.name = "objectclass",
.add = objectclass_add,
.modify = objectclass_modify,
.wait = objectclass_wait
};
int ldb_objectclass_init(void)
{
return ldb_register_module(&objectclass_ops);
}
+312
View File
@@ -0,0 +1,312 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
handle operational attributes
*/
/*
createTimestamp: HIDDEN, searchable, ldaptime, alias for whenCreated
modifyTimestamp: HIDDEN, searchable, ldaptime, alias for whenChanged
for the above two, we do the search as normal, and if
createTimestamp or modifyTimestamp is asked for, then do
additional searches for whenCreated and whenChanged and fill in
the resulting values
we also need to replace these with the whenCreated/whenChanged
equivalent in the search expression trees
whenCreated: not-HIDDEN, CONSTRUCTED, SEARCHABLE
whenChanged: not-HIDDEN, CONSTRUCTED, SEARCHABLE
on init we need to setup attribute handlers for these so
comparisons are done correctly. The resolution is 1 second.
on add we need to add both the above, for current time
on modify we need to change whenChanged
subschemaSubentry: HIDDEN, not-searchable,
points at DN CN=Aggregate,CN=Schema,CN=Configuration,$BASEDN
for this one we do the search as normal, then add the static
value if requested. How do we work out the $BASEDN from inside a
module?
structuralObjectClass: HIDDEN, CONSTRUCTED, not-searchable. always same as objectclass?
for this one we do the search as normal, then if requested ask
for objectclass, change the attribute name, and add it
allowedAttributesEffective: HIDDEN, CONSTRUCTED, not-searchable,
list of attributes that can be modified - requires schema lookup
attributeTypes: in schema only
objectClasses: in schema only
matchingRules: in schema only
matchingRuleUse: in schema only
creatorsName: not supported by w2k3?
modifiersName: not supported by w2k3?
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
construct a canonical name from a message
*/
static int construct_canonical_name(struct ldb_module *module, struct ldb_message *msg)
{
char *canonicalName;
canonicalName = ldb_dn_canonical_string(msg, msg->dn);
if (canonicalName == NULL) {
return -1;
}
return ldb_msg_add_steal_string(msg, "canonicalName", canonicalName);
}
/*
a list of attribute names that should be substituted in the parse
tree before the search is done
*/
static const struct {
const char *attr;
const char *replace;
} parse_tree_sub[] = {
{ "createTimestamp", "whenCreated" },
{ "modifyTimestamp", "whenChanged" }
};
/*
a list of attribute names that are hidden, but can be searched for
using another (non-hidden) name to produce the correct result
*/
static const struct {
const char *attr;
const char *replace;
int (*constructor)(struct ldb_module *, struct ldb_message *);
} search_sub[] = {
{ "createTimestamp", "whenCreated", NULL },
{ "modifyTimestamp", "whenChanged", NULL },
{ "structuralObjectClass", "objectClass", NULL },
{ "canonicalName", "distinguishedName", construct_canonical_name }
};
/*
post process a search result record. For any search_sub[] attributes that were
asked for, we need to call the appropriate copy routine to copy the result
into the message, then remove any attributes that we added to the search but were
not asked for by the user
*/
static int operational_search_post_process(struct ldb_module *module,
struct ldb_message *msg,
const char * const *attrs)
{
int i, a=0;
for (a=0;attrs && attrs[a];a++) {
for (i=0;i<ARRAY_SIZE(search_sub);i++) {
if (ldb_attr_cmp(attrs[a], search_sub[i].attr) != 0) {
continue;
}
/* construct the new attribute, using either a supplied
constructor or a simple copy */
if (search_sub[i].constructor) {
if (search_sub[i].constructor(module, msg) != 0) {
goto failed;
}
} else if (ldb_msg_copy_attr(msg,
search_sub[i].replace,
search_sub[i].attr) != 0) {
goto failed;
}
/* remove the added search attribute, unless it was asked for
by the user */
if (search_sub[i].replace == NULL ||
ldb_attr_in_list(attrs, search_sub[i].replace) ||
ldb_attr_in_list(attrs, "*")) {
continue;
}
ldb_msg_remove_attr(msg, search_sub[i].replace);
}
}
return 0;
failed:
ldb_debug_set(module->ldb, LDB_DEBUG_WARNING,
"operational_search_post_process failed for attribute '%s'\n",
attrs[a]);
return -1;
}
/*
hook search operations
*/
struct operational_context {
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
const char * const *attrs;
};
static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct operational_context *ac;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct operational_context);
if (ares->type == LDB_REPLY_ENTRY) {
/* for each record returned post-process to add any derived
attributes that have been asked for */
if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) {
goto error;
}
}
return ac->up_callback(ldb, ac->up_context, ares);
error:
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
static int operational_search(struct ldb_module *module, struct ldb_request *req)
{
struct operational_context *ac;
struct ldb_request *down_req;
const char **search_attrs = NULL;
int i, a, ret;
req->handle = NULL;
ac = talloc(req, struct operational_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->module = module;
ac->up_context = req->context;
ac->up_callback = req->callback;
ac->attrs = req->op.search.attrs;
down_req = talloc_zero(req, struct ldb_request);
if (down_req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
down_req->operation = req->operation;
down_req->op.search.base = req->op.search.base;
down_req->op.search.scope = req->op.search.scope;
down_req->op.search.tree = req->op.search.tree;
/* FIXME: I hink we should copy the tree and keep the original
* unmodified. SSS */
/* replace any attributes in the parse tree that are
searchable, but are stored using a different name in the
backend */
for (i=0;i<ARRAY_SIZE(parse_tree_sub);i++) {
ldb_parse_tree_attr_replace(req->op.search.tree,
parse_tree_sub[i].attr,
parse_tree_sub[i].replace);
}
/* in the list of attributes we are looking for, rename any
attributes to the alias for any hidden attributes that can
be fetched directly using non-hidden names */
for (a=0;ac->attrs && ac->attrs[a];a++) {
for (i=0;i<ARRAY_SIZE(search_sub);i++) {
if (ldb_attr_cmp(ac->attrs[a], search_sub[i].attr) == 0 &&
search_sub[i].replace) {
if (!search_attrs) {
search_attrs = ldb_attr_list_copy(req, ac->attrs);
if (search_attrs == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
}
search_attrs[a] = search_sub[i].replace;
}
}
}
/* use new set of attrs if any */
if (search_attrs) down_req->op.search.attrs = search_attrs;
else down_req->op.search.attrs = req->op.search.attrs;
down_req->controls = req->controls;
down_req->context = ac;
down_req->callback = operational_callback;
ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
/* perform the search */
ret = ldb_next_request(module, down_req);
/* do not free down_req as the call results may be linked to it,
* it will be freed when the upper level request get freed */
if (ret == LDB_SUCCESS) {
req->handle = down_req->handle;
}
return ret;
}
static int operational_init(struct ldb_module *ctx)
{
/* setup some standard attribute handlers */
ldb_set_attrib_handler_syntax(ctx->ldb, "whenCreated", LDB_SYNTAX_UTC_TIME);
ldb_set_attrib_handler_syntax(ctx->ldb, "whenChanged", LDB_SYNTAX_UTC_TIME);
ldb_set_attrib_handler_syntax(ctx->ldb, "subschemaSubentry", LDB_SYNTAX_DN);
ldb_set_attrib_handler_syntax(ctx->ldb, "structuralObjectClass", LDB_SYNTAX_OBJECTCLASS);
return ldb_next_init(ctx);
}
static const struct ldb_module_ops operational_ops = {
.name = "operational",
.search = operational_search,
.init_context = operational_init
};
int ldb_operational_init(void)
{
return ldb_register_module(&operational_ops);
}
@@ -0,0 +1,565 @@
/*
ldb database library
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
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: paged_result
*
* Component: ldb paged results control module
*
* Description: this module caches a complete search and sends back
* results in chunks as asked by the client
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
struct message_store {
/* keep the whole ldb_reply as an optimization
* instead of freeing and talloc-ing the container
* on each result */
struct ldb_reply *r;
struct message_store *next;
};
struct private_data;
struct results_store {
struct private_data *priv;
char *cookie;
time_t timestamp;
struct results_store *prev;
struct results_store *next;
struct message_store *first;
struct message_store *last;
int num_entries;
struct message_store *first_ref;
struct message_store *last_ref;
struct ldb_control **controls;
struct ldb_request *req;
};
struct private_data {
int next_free_id;
struct results_store *store;
};
int store_destructor(struct results_store *store)
{
if (store->prev) {
store->prev->next = store->next;
}
if (store->next) {
store->next->prev = store->prev;
}
if (store == store->priv->store) {
store->priv->store = NULL;
}
return 0;
}
static struct results_store *new_store(struct private_data *priv)
{
struct results_store *newr;
int new_id = priv->next_free_id++;
/* TODO: we should have a limit on the number of
* outstanding paged searches
*/
newr = talloc(priv, struct results_store);
if (!newr) return NULL;
newr->priv = priv;
newr->cookie = talloc_asprintf(newr, "%d", new_id);
if (!newr->cookie) {
talloc_free(newr);
return NULL;
}
newr->timestamp = time(NULL);
newr->first = NULL;
newr->num_entries = 0;
newr->first_ref = NULL;
newr->controls = NULL;
/* put this entry as first */
newr->prev = NULL;
newr->next = priv->store;
if (priv->store != NULL) priv->store->prev = newr;
priv->store = newr;
talloc_set_destructor(newr, store_destructor);
return newr;
}
struct paged_context {
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
int size;
struct results_store *store;
};
static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
{
struct paged_context *ac;
struct ldb_handle *h;
h = talloc_zero(mem_ctx, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc_zero(h, struct paged_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
return h;
}
static int paged_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct paged_context *ac = NULL;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct paged_context);
if (ares->type == LDB_REPLY_ENTRY) {
if (ac->store->first == NULL) {
ac->store->first = ac->store->last = talloc(ac->store, struct message_store);
} else {
ac->store->last->next = talloc(ac->store, struct message_store);
ac->store->last = ac->store->last->next;
}
if (ac->store->last == NULL) {
goto error;
}
ac->store->num_entries++;
ac->store->last->r = talloc_steal(ac->store->last, ares);
ac->store->last->next = NULL;
}
if (ares->type == LDB_REPLY_REFERRAL) {
if (ac->store->first_ref == NULL) {
ac->store->first_ref = ac->store->last_ref = talloc(ac->store, struct message_store);
} else {
ac->store->last_ref->next = talloc(ac->store, struct message_store);
ac->store->last_ref = ac->store->last_ref->next;
}
if (ac->store->last_ref == NULL) {
goto error;
}
ac->store->last_ref->r = talloc_steal(ac->store->last, ares);
ac->store->last_ref->next = NULL;
}
if (ares->type == LDB_REPLY_DONE) {
ac->store->controls = talloc_move(ac->store, &ares->controls);
talloc_free(ares);
}
return LDB_SUCCESS;
error:
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
static int paged_search(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_control *control;
struct private_data *private_data;
struct ldb_paged_control *paged_ctrl;
struct ldb_control **saved_controls;
struct paged_context *ac;
struct ldb_handle *h;
int ret;
/* check if there's a paged request control */
control = get_control_from_list(req->controls, LDB_CONTROL_PAGED_RESULTS_OID);
if (control == NULL) {
/* not found go on */
return ldb_next_request(module, req);
}
private_data = talloc_get_type(module->private_data, struct private_data);
req->handle = NULL;
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb,
"Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
if (!paged_ctrl) {
return LDB_ERR_PROTOCOL_ERROR;
}
h = init_handle(req, module, req->context, req->callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct paged_context);
ac->size = paged_ctrl->size;
/* check if it is a continuation search the store */
if (paged_ctrl->cookie_len == 0) {
ac->store = new_store(private_data);
if (ac->store == NULL) {
talloc_free(h);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
ac->store->req = talloc(ac->store, struct ldb_request);
if (!ac->store->req)
return LDB_ERR_OPERATIONS_ERROR;
ac->store->req->operation = req->operation;
ac->store->req->op.search.base = req->op.search.base;
ac->store->req->op.search.scope = req->op.search.scope;
ac->store->req->op.search.tree = req->op.search.tree;
ac->store->req->op.search.attrs = req->op.search.attrs;
ac->store->req->controls = req->controls;
/* save it locally and remove it from the list */
/* we do not need to replace them later as we
* are keeping the original req intact */
if (!save_controls(control, ac->store->req, &saved_controls)) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->store->req->context = ac;
ac->store->req->callback = paged_search_callback;
ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req);
ret = ldb_next_request(module, ac->store->req);
} else {
struct results_store *current = NULL;
for (current = private_data->store; current; current = current->next) {
if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
current->timestamp = time(NULL);
break;
}
}
if (current == NULL) {
talloc_free(h);
return LDB_ERR_UNWILLING_TO_PERFORM;
}
ac->store = current;
ret = LDB_SUCCESS;
}
req->handle = h;
/* check if it is an abandon */
if (ac->size == 0) {
talloc_free(ac->store);
h->status = LDB_SUCCESS;
h->state = LDB_ASYNC_DONE;
return LDB_SUCCESS;
}
/* TODO: age out old outstanding requests */
return ret;
}
static int paged_results(struct ldb_handle *handle)
{
struct paged_context *ac;
struct ldb_paged_control *paged;
struct ldb_reply *ares;
struct message_store *msg;
int i, num_ctrls, ret;
ac = talloc_get_type(handle->private_data, struct paged_context);
if (ac->store == NULL)
return LDB_ERR_OPERATIONS_ERROR;
while (ac->store->num_entries > 0 && ac->size > 0) {
msg = ac->store->first;
ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
if (ret != LDB_SUCCESS) {
handle->status = ret;
handle->state = LDB_ASYNC_DONE;
return ret;
}
ac->store->first = msg->next;
talloc_free(msg);
ac->store->num_entries--;
ac->size--;
}
handle->state = LDB_ASYNC_DONE;
while (ac->store->first_ref != NULL) {
msg = ac->store->first_ref;
ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
if (ret != LDB_SUCCESS) {
handle->status = ret;
handle->state = LDB_ASYNC_DONE;
return ret;
}
ac->store->first_ref = msg->next;
talloc_free(msg);
}
ares = talloc_zero(ac->store, struct ldb_reply);
if (ares == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
num_ctrls = 2;
i = 0;
if (ac->store->controls != NULL) {
ares->controls = ac->store->controls;
while (ares->controls[i]) i++; /* counting */
ares->controls = talloc_move(ares, &ac->store->controls);
num_ctrls += i;
}
ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, num_ctrls);
if (ares->controls == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->controls[i] = talloc(ares->controls, struct ldb_control);
if (ares->controls[i] == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->controls[i]->oid = talloc_strdup(ares->controls[i], LDB_CONTROL_PAGED_RESULTS_OID);
if (ares->controls[i]->oid == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->controls[i]->critical = 0;
ares->controls[i + 1] = NULL;
paged = talloc(ares->controls[i], struct ldb_paged_control);
if (paged == NULL) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->controls[i]->data = paged;
if (ac->size > 0) {
paged->size = 0;
paged->cookie = NULL;
paged->cookie_len = 0;
} else {
paged->size = ac->store->num_entries;
paged->cookie = talloc_strdup(paged, ac->store->cookie);
paged->cookie_len = strlen(paged->cookie) + 1;
}
ares->type = LDB_REPLY_DONE;
ret = ac->up_callback(ac->module->ldb, ac->up_context, ares);
handle->status = ret;
return ret;
}
static int paged_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
struct paged_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
handle->state = LDB_ASYNC_PENDING;
ac = talloc_get_type(handle->private_data, struct paged_context);
if (ac->store->req->handle->state == LDB_ASYNC_DONE) {
/* if lower level is finished we do not need to call it anymore */
/* return all we have until size == 0 or we empty storage */
ret = paged_results(handle);
/* we are done, if num_entries is zero free the storage
* as that mean we delivered the last batch */
if (ac->store->num_entries == 0) {
talloc_free(ac->store);
}
return ret;
}
if (type == LDB_WAIT_ALL) {
while (ac->store->req->handle->state != LDB_ASYNC_DONE) {
ret = ldb_wait(ac->store->req->handle, type);
if (ret != LDB_SUCCESS) {
handle->state = LDB_ASYNC_DONE;
handle->status = ret;
return ret;
}
}
ret = paged_results(handle);
/* we are done, if num_entries is zero free the storage
* as that mean we delivered the last batch */
if (ac->store->num_entries == 0) {
talloc_free(ac->store);
}
return ret;
}
ret = ldb_wait(ac->store->req->handle, type);
if (ret != LDB_SUCCESS) {
handle->state = LDB_ASYNC_DONE;
handle->status = ret;
return ret;
}
handle->status = ret;
if (ac->store->num_entries >= ac->size ||
ac->store->req->handle->state == LDB_ASYNC_DONE) {
ret = paged_results(handle);
/* we are done, if num_entries is zero free the storage
* as that mean we delivered the last batch */
if (ac->store->num_entries == 0) {
talloc_free(ac->store);
}
}
return ret;
}
static int paged_request_init(struct ldb_module *module)
{
struct private_data *data;
struct ldb_request *req;
int ret;
data = talloc(module, struct private_data);
if (data == NULL) {
return LDB_ERR_OTHER;
}
data->next_free_id = 1;
data->store = NULL;
module->private_data = data;
req = talloc(module, struct ldb_request);
if (req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
req->operation = LDB_REQ_REGISTER_CONTROL;
req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID;
req->controls = NULL;
ret = ldb_request(module->ldb, req);
if (ret != LDB_SUCCESS) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n");
}
talloc_free(req);
return ldb_next_init(module);
}
static const struct ldb_module_ops paged_ops = {
.name = "paged_results",
.search = paged_search,
.wait = paged_wait,
.init_context = paged_request_init
};
int ldb_paged_results_init(void)
{
return ldb_register_module(&paged_ops);
}
@@ -0,0 +1,468 @@
/*
ldb database library
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
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: paged_searches
*
* Component: ldb paged searches module
*
* Description: this module detects if the remote ldap server supports
* paged results and use them to transparently access all objects
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
#define PS_DEFAULT_PAGE_SIZE 500
/* 500 objects per query seem to be a decent compromise
* the default AD limit per request is 1000 entries */
struct private_data {
bool paged_supported;
};
struct ps_context {
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
struct ldb_request *orig_req;
struct ldb_request *new_req;
bool pending;
char **saved_referrals;
int num_referrals;
};
static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
{
struct ps_context *ac;
struct ldb_handle *h;
h = talloc_zero(mem_ctx, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc_zero(h, struct ps_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
ac->pending = False;
ac->saved_referrals = NULL;
ac->num_referrals = 0;
return h;
}
static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac)
{
struct ldb_paged_control *rep_control, *req_control;
/* look up our paged control */
if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) {
/* something wrong here */
return LDB_ERR_OPERATIONS_ERROR;
}
rep_control = talloc_get_type(ares->controls[0]->data, struct ldb_paged_control);
if (rep_control->cookie_len == 0) {
/* we are done */
ac->pending = False;
return LDB_SUCCESS;
}
/* more processing required */
/* let's fill in the request control with the new cookie */
/* if there's a reply control we must find a request
* control matching it */
if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ac->new_req->controls[0]->oid) != 0) {
/* something wrong here */
return LDB_ERR_OPERATIONS_ERROR;
}
req_control = talloc_get_type(ac->new_req->controls[0]->data, struct ldb_paged_control);
if (req_control->cookie) {
talloc_free(req_control->cookie);
}
req_control->cookie = talloc_memdup(req_control,
rep_control->cookie,
rep_control->cookie_len);
req_control->cookie_len = rep_control->cookie_len;
ac->pending = True;
return LDB_SUCCESS;
}
static int store_referral(char *referral, struct ps_context *ac)
{
ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2);
if (!ac->saved_referrals) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->saved_referrals[ac->num_referrals] = talloc_strdup(ac->saved_referrals, referral);
if (!ac->saved_referrals[ac->num_referrals]) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->num_referrals++;
ac->saved_referrals[ac->num_referrals] = NULL;
return LDB_SUCCESS;
}
static int send_referrals(struct ldb_context *ldb, struct ps_context *ac)
{
struct ldb_reply *ares;
int i;
for (i = 0; i < ac->num_referrals; i++) {
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
return LDB_ERR_OPERATIONS_ERROR;
}
ares->type = LDB_REPLY_REFERRAL;
ares->referral = ac->saved_referrals[i];
ac->up_callback(ldb, ac->up_context, ares);
}
return LDB_SUCCESS;
}
static int ps_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct ps_context *ac = NULL;
int ret = LDB_ERR_OPERATIONS_ERROR;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct ps_context);
switch (ares->type) {
case LDB_REPLY_ENTRY:
ac->up_callback(ldb, ac->up_context, ares);
break;
case LDB_REPLY_REFERRAL:
ret = store_referral(ares->referral, ac);
if (ret != LDB_SUCCESS) {
goto error;
}
break;
case LDB_REPLY_DONE:
ret = check_ps_continuation(ares, ac);
if (ret != LDB_SUCCESS) {
goto error;
}
if (!ac->pending) {
/* send referrals */
ret = send_referrals(ldb, ac);
if (ret != LDB_SUCCESS) {
goto error;
}
/* send REPLY_DONE */
ac->up_callback(ldb, ac->up_context, ares);
}
break;
default:
goto error;
}
return LDB_SUCCESS;
error:
talloc_free(ares);
return ret;
}
static int ps_search(struct ldb_module *module, struct ldb_request *req)
{
struct private_data *private_data;
struct ldb_paged_control *control;
struct ps_context *ac;
struct ldb_handle *h;
private_data = talloc_get_type(module->private_data, struct private_data);
/* check if paging is supported and if there is a any control */
if (!private_data || !private_data->paged_supported || req->controls) {
/* do not touch this request paged controls not
* supported or explicit controls have been set or we
* are just not setup yet */
return ldb_next_request(module, req);
}
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb,
"Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
h = init_handle(req, module, req->context, req->callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct ps_context);
ac->new_req = talloc(ac, struct ldb_request);
if (!ac->new_req) return LDB_ERR_OPERATIONS_ERROR;
ac->new_req->controls = talloc_array(ac->new_req, struct ldb_control *, 2);
if (!ac->new_req->controls) return LDB_ERR_OPERATIONS_ERROR;
ac->new_req->controls[0] = talloc(ac->new_req->controls, struct ldb_control);
if (!ac->new_req->controls[0]) return LDB_ERR_OPERATIONS_ERROR;
control = talloc(ac->new_req->controls[0], struct ldb_paged_control);
if (!control) return LDB_ERR_OPERATIONS_ERROR;
control->size = PS_DEFAULT_PAGE_SIZE;
control->cookie = NULL;
control->cookie_len = 0;
ac->new_req->controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
ac->new_req->controls[0]->critical = 1;
ac->new_req->controls[0]->data = control;
ac->new_req->controls[1] = NULL;
ac->new_req->operation = req->operation;
ac->new_req->op.search.base = req->op.search.base;
ac->new_req->op.search.scope = req->op.search.scope;
ac->new_req->op.search.tree = req->op.search.tree;
ac->new_req->op.search.attrs = req->op.search.attrs;
ac->new_req->context = ac;
ac->new_req->callback = ps_callback;
ldb_set_timeout_from_prev_req(module->ldb, req, ac->new_req);
req->handle = h;
return ldb_next_request(module, ac->new_req);
}
static int ps_continuation(struct ldb_handle *handle)
{
struct ps_context *ac;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(handle->private_data, struct ps_context);
/* reset the requests handle */
ac->new_req->handle = NULL;
return ldb_next_request(handle->module, ac->new_req);
}
static int ps_wait_none(struct ldb_handle *handle)
{
struct ps_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
ac = talloc_get_type(handle->private_data, struct ps_context);
ret = ldb_wait(ac->new_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->new_req->handle->status != LDB_SUCCESS) {
handle->status = ac->new_req->handle->status;
goto done;
}
if (ac->new_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
/* see if we need to send another request for the next batch */
if (ac->pending) {
ret = ps_continuation(handle);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
/* continue the search with the next request */
return LDB_SUCCESS;
}
ret = LDB_SUCCESS;
done:
handle->state = LDB_ASYNC_DONE;
return ret;
}
static int ps_wait_all(struct ldb_handle *handle)
{
int ret;
while (handle->state != LDB_ASYNC_DONE) {
ret = ps_wait_none(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
}
return handle->status;
}
static int ps_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
return ps_wait_all(handle);
} else {
return ps_wait_none(handle);
}
}
static int check_supported_paged(struct ldb_context *ldb, void *context,
struct ldb_reply *ares)
{
struct private_data *data;
data = talloc_get_type(context,
struct private_data);
if (ares->type == LDB_REPLY_ENTRY) {
if (ldb_msg_check_string_attribute(ares->message,
"supportedControl",
LDB_CONTROL_PAGED_RESULTS_OID)) {
data->paged_supported = True;
}
}
return LDB_SUCCESS;
}
static int ps_init(struct ldb_module *module)
{
static const char *attrs[] = { "supportedControl", NULL };
struct private_data *data;
int ret;
struct ldb_request *req;
data = talloc(module, struct private_data);
if (data == NULL) {
return LDB_ERR_OTHER;
}
module->private_data = data;
data->paged_supported = False;
req = talloc(module, struct ldb_request);
if (req == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
}
req->operation = LDB_SEARCH;
req->op.search.base = ldb_dn_new(req, module->ldb, NULL);
req->op.search.scope = LDB_SCOPE_BASE;
req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
if (req->op.search.tree == NULL) {
ldb_set_errstring(module->ldb, "Unable to parse search expression");
talloc_free(req);
return LDB_ERR_OPERATIONS_ERROR;
}
req->op.search.attrs = attrs;
req->controls = NULL;
req->context = data;
req->callback = check_supported_paged;
ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
ret = ldb_next_request(module, req);
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
talloc_free(req);
if (ret != LDB_SUCCESS) {
return ret;
}
return ldb_next_init(module);
}
static const struct ldb_module_ops ps_ops = {
.name = "paged_searches",
.search = ps_search,
.wait = ps_wait,
.init_context = ps_init
};
int ldb_paged_searches_init(void)
{
return ldb_register_module(&ps_ops);
}
+343
View File
@@ -0,0 +1,343 @@
/*
ldb database library
Copyright (C) Andrew Bartlet 2005
Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: rdb_name
*
* Component: ldb rdn name module
*
* Description: keep a consistent name attribute on objects manpulations
*
* Author: Andrew Bartlet
*
* Modifications:
* - made the module async
* Simo Sorce Mar 2006
*/
#include "includes.h"
#include "ldb/include/includes.h"
static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
{
int i;
for (i = 0; i < msg->num_elements; i++) {
if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
return &msg->elements[i];
}
}
return NULL;
}
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;
const char *rdn_name;
struct ldb_val rdn_val;
int i, ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
/* do not manipulate our control entries */
if (ldb_dn_is_special(req->op.add.message->dn)) {
return ldb_next_request(module, req);
}
down_req = talloc(req, struct ldb_request);
if (down_req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
*down_req = *req;
down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
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_val, NULL) != 0) {
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
attribute = rdn_name_find_attribute(msg, rdn_name);
if (!attribute) {
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);
for (i = 0; i < attribute->num_values; i++) {
if (handler->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) {
/* overwrite so it matches in case */
attribute->values[i] = rdn_val;
break;
}
}
if (i == attribute->num_values) {
ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
"RDN mismatch on %s: %s (%s)",
ldb_dn_get_linearized(msg->dn), rdn_name, rdn_val.data);
talloc_free(down_req);
return LDB_ERR_OPERATIONS_ERROR;
}
}
/* go on with the call chain */
ret = ldb_next_request(module, down_req);
/* do not free down_req as the call results may be linked to it,
* it will be freed when the upper level request get freed */
if (ret == LDB_SUCCESS) {
req->handle = down_req->handle;
}
return ret;
}
struct rename_context {
enum {RENAME_RENAME, RENAME_MODIFY} step;
struct ldb_request *orig_req;
struct ldb_request *down_req;
struct ldb_request *mod_req;
};
static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_handle *h;
struct rename_context *ac;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
/* do not manipulate our control entries */
if (ldb_dn_is_special(req->op.rename.newdn)) {
return ldb_next_request(module, req);
}
h = talloc_zero(req, struct ldb_handle);
if (h == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
h->module = module;
ac = talloc_zero(h, struct rename_context);
if (ac == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->orig_req = req;
ac->down_req = talloc(req, struct ldb_request);
if (ac->down_req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req) = *req;
ac->step = RENAME_RENAME;
req->handle = h;
/* rename first, modify "name" if rename is ok */
return ldb_next_request(module, ac->down_req);
}
static int rdn_name_rename_do_mod(struct ldb_handle *h) {
struct rename_context *ac;
const char *rdn_name;
struct ldb_val rdn_val;
struct ldb_message *msg;
ac = talloc_get_type(h->private_data, struct rename_context);
ac->mod_req = talloc_zero(ac, struct ldb_request);
ac->mod_req->operation = LDB_MODIFY;
ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn);
if (msg->dn == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
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_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_val, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req);
ac->step = RENAME_MODIFY;
/* do the mod call */
return ldb_request(h->module->ldb, ac->mod_req);
}
static int rename_wait(struct ldb_handle *handle)
{
struct rename_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
if (handle->state == LDB_ASYNC_DONE) {
return handle->status;
}
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
ac = talloc_get_type(handle->private_data, struct rename_context);
switch(ac->step) {
case RENAME_RENAME:
ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->down_req->handle->status != LDB_SUCCESS) {
handle->status = ac->down_req->handle->status;
goto done;
}
if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
/* rename operation done */
return rdn_name_rename_do_mod(handle);
case RENAME_MODIFY:
ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
if (ac->mod_req->handle->status != LDB_SUCCESS) {
handle->status = ac->mod_req->handle->status;
goto done;
}
if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
break;
default:
ret = LDB_ERR_OPERATIONS_ERROR;
goto done;
}
ret = LDB_SUCCESS;
done:
handle->state = LDB_ASYNC_DONE;
return ret;
}
static int rename_wait_all(struct ldb_handle *handle) {
int ret;
while (handle->state != LDB_ASYNC_DONE) {
ret = rename_wait(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
}
return handle->status;
}
static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
return rename_wait_all(handle);
} else {
return rename_wait(handle);
}
}
static const struct ldb_module_ops rdn_name_ops = {
.name = "rdn_name",
.add = rdn_name_add,
.rename = rdn_name_rename,
.wait = rdn_name_wait
};
int ldb_rdn_name_init(void)
{
return ldb_register_module(&rdn_name_ops);
}
+137
View File
@@ -0,0 +1,137 @@
/*
ldb database library
Copyright (C) Simo Sorce 2004
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb skel module
*
* Description: example module
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
struct private_data {
char *some_private_data;
};
/* search */
static int skel_search(struct ldb_module *module, struct ldb_request *req)
{
return ldb_next_request(module, req);
}
/* add */
static int skel_add(struct ldb_module *module, struct ldb_request *req){
return ldb_next_request(module, req);
}
/* modify */
static int skel_modify(struct ldb_module *module, struct ldb_request *req)
{
return ldb_next_request(module, req);
}
/* delete */
static int skel_delete(struct ldb_module *module, struct ldb_request *req)
{
return ldb_next_request(module, req);
}
/* rename */
static int skel_rename(struct ldb_module *module, struct ldb_request *req)
{
return ldb_next_request(module, req);
}
/* start a transaction */
static int skel_start_trans(struct ldb_module *module)
{
return ldb_next_start_trans(module);
}
/* end a transaction */
static int skel_end_trans(struct ldb_module *module)
{
return ldb_next_end_trans(module);
}
/* delete a transaction */
static int skel_del_trans(struct ldb_module *module)
{
return ldb_next_del_trans(module);
}
static int skel_destructor(struct ldb_module *ctx)
{
struct private_data *data = talloc_get_type(ctx->private_data, struct private_data);
/* put your clean-up functions here */
if (data->some_private_data) talloc_free(data->some_private_data);
return 0;
}
static int skel_request(struct ldb_module *module, struct ldb_request *req)
{
return ldb_next_request(module, req);
}
static int skel_init(struct ldb_module *ctx)
{
struct private_data *data;
data = talloc(ctx, struct private_data);
if (data == NULL) {
return 1;
}
data->some_private_data = NULL;
ctx->private_data = data;
talloc_set_destructor (ctx, skel_destructor);
return ldb_next_init(ctx);
}
static const struct ldb_module_ops skel_ops = {
.name = "skel",
.init_context = skel_init,
.search = skel_search,
.add = skel_add,
.modify = skel_modify,
.del = skel_delete,
.rename = skel_rename,
.request = skel_request,
.start_transaction = skel_start_trans,
.end_transaction = skel_end_trans,
.del_transaction = skel_del_trans,
};
int ldb_skel_init(void)
{
return ldb_register_module(&skel_ops);
}
+443
View File
@@ -0,0 +1,443 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Name: ldb
*
* Component: ldb server side sort control module
*
* Description: this module sorts the results of a search
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
struct opaque {
struct ldb_context *ldb;
const struct ldb_attrib_handler *h;
const char *attribute;
int reverse;
int result;
};
struct sort_context {
struct ldb_module *module;
void *up_context;
int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
char *attributeName;
char *orderingRule;
int reverse;
struct ldb_request *req;
struct ldb_message **msgs;
char **referrals;
struct ldb_control **controls;
int num_msgs;
int num_refs;
const struct ldb_attrib_handler *h;
int sort_result;
};
static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
void *context,
int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
{
struct sort_context *ac;
struct ldb_handle *h;
h = talloc_zero(mem_ctx, struct ldb_handle);
if (h == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
ac = talloc_zero(h, struct sort_context);
if (ac == NULL) {
ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
h->private_data = (void *)ac;
h->state = LDB_ASYNC_INIT;
h->status = LDB_SUCCESS;
ac->module = module;
ac->up_context = context;
ac->up_callback = callback;
return h;
}
static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
{
struct ldb_control **controls;
struct ldb_sort_resp_control *resp;
int i;
if (*ctrls) {
controls = *ctrls;
for (i = 0; controls[i]; i++);
controls = talloc_realloc(mem_ctx, controls, struct ldb_control *, i + 2);
} else {
i = 0;
controls = talloc_array(mem_ctx, struct ldb_control *, 2);
}
if (! controls )
return LDB_ERR_OPERATIONS_ERROR;
*ctrls = controls;
controls[i+1] = NULL;
controls[i] = talloc(controls, struct ldb_control);
if (! controls[i] )
return LDB_ERR_OPERATIONS_ERROR;
controls[i]->oid = LDB_CONTROL_SORT_RESP_OID;
controls[i]->critical = 0;
resp = talloc(controls[i], struct ldb_sort_resp_control);
if (! resp )
return LDB_ERR_OPERATIONS_ERROR;
resp->result = result;
resp->attr_desc = talloc_strdup(resp, desc);
if (! resp->attr_desc )
return LDB_ERR_OPERATIONS_ERROR;
controls[i]->data = resp;
return LDB_SUCCESS;
}
static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, void *opaque)
{
struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
struct ldb_message_element *el1, *el2;
if (ac->sort_result != 0) {
/* an error occurred previously,
* let's exit the sorting by returning always 0 */
return 0;
}
el1 = ldb_msg_find_element(*msg1, ac->attributeName);
el2 = ldb_msg_find_element(*msg2, ac->attributeName);
if (!el1 || !el2) {
/* the attribute was not found return and
* set an error */
ac->sort_result = 53;
return 0;
}
if (ac->reverse)
return ac->h->comparison_fn(ac->module->ldb, ac, &el2->values[0], &el1->values[0]);
return ac->h->comparison_fn(ac->module->ldb, ac, &el1->values[0], &el2->values[0]);
}
static int server_sort_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
struct sort_context *ac = NULL;
if (!context || !ares) {
ldb_set_errstring(ldb, "NULL Context or Result in callback");
goto error;
}
ac = talloc_get_type(context, struct sort_context);
if (ares->type == LDB_REPLY_ENTRY) {
ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
if (! ac->msgs) {
goto error;
}
ac->msgs[ac->num_msgs + 1] = NULL;
ac->msgs[ac->num_msgs] = talloc_move(ac->msgs, &ares->message);
ac->num_msgs++;
}
if (ares->type == LDB_REPLY_REFERRAL) {
ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
if (! ac->referrals) {
goto error;
}
ac->referrals[ac->num_refs + 1] = NULL;
ac->referrals[ac->num_refs] = talloc_move(ac->referrals, &ares->referral);
ac->num_refs++;
}
if (ares->type == LDB_REPLY_DONE) {
ac->controls = talloc_move(ac, &ares->controls);
}
talloc_free(ares);
return LDB_SUCCESS;
error:
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_control *control;
struct ldb_server_sort_control **sort_ctrls;
struct ldb_control **saved_controls;
struct sort_context *ac;
struct ldb_handle *h;
int ret;
/* check if there's a paged request control */
control = get_control_from_list(req->controls, LDB_CONTROL_SERVER_SORT_OID);
if (control == NULL) {
/* not found go on */
return ldb_next_request(module, req);
}
req->handle = NULL;
if (!req->callback || !req->context) {
ldb_set_errstring(module->ldb,
"Async interface called with NULL callback function or NULL context");
return LDB_ERR_OPERATIONS_ERROR;
}
h = init_handle(req, module, req->context, req->callback);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(h->private_data, struct sort_context);
sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
if (!sort_ctrls) {
return LDB_ERR_PROTOCOL_ERROR;
}
/* FIXME: we do not support more than one attribute for sorting right now */
/* FIXME: we need to check if the attribute type exist or return an error */
if (sort_ctrls[1] != NULL) {
if (control->critical) {
struct ldb_reply *ares;
ares = talloc_zero(req, struct ldb_reply);
if (!ares)
return LDB_ERR_OPERATIONS_ERROR;
/* 53 = unwilling to perform */
ares->type = LDB_REPLY_DONE;
if ((ret = build_response(ares, &ares->controls, 53, "sort control is not complete yet")) != LDB_SUCCESS) {
return ret;
}
h->status = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
h->state = LDB_ASYNC_DONE;
ret = ac->up_callback(module->ldb, ac->up_context, ares);
return ret;
} else {
/* just pass the call down and don't do any sorting */
ldb_next_request(module, req);
}
}
ac->attributeName = sort_ctrls[0]->attributeName;
ac->orderingRule = sort_ctrls[0]->orderingRule;
ac->reverse = sort_ctrls[0]->reverse;
ac->req = talloc(req, struct ldb_request);
if (!ac->req)
return LDB_ERR_OPERATIONS_ERROR;
ac->req->operation = req->operation;
ac->req->op.search.base = req->op.search.base;
ac->req->op.search.scope = req->op.search.scope;
ac->req->op.search.tree = req->op.search.tree;
ac->req->op.search.attrs = req->op.search.attrs;
ac->req->controls = req->controls;
/* save it locally and remove it from the list */
/* we do not need to replace them later as we
* are keeping the original req intact */
if (!save_controls(control, ac->req, &saved_controls)) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac->req->context = ac;
ac->req->callback = server_sort_search_callback;
ldb_set_timeout_from_prev_req(module->ldb, req, ac->req);
req->handle = h;
return ldb_next_request(module, ac->req);
}
static int server_sort_results(struct ldb_handle *handle)
{
struct sort_context *ac;
struct ldb_reply *ares;
int i, ret;
ac = talloc_get_type(handle->private_data, struct sort_context);
ac->h = ldb_attrib_handler(ac->module->ldb, ac->attributeName);
ac->sort_result = 0;
ldb_qsort(ac->msgs, ac->num_msgs,
sizeof(struct ldb_message *),
ac, (ldb_qsort_cmp_fn_t)sort_compare);
for (i = 0; i < ac->num_msgs; i++) {
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->type = LDB_REPLY_ENTRY;
ares->message = talloc_move(ares, &ac->msgs[i]);
handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
if (handle->status != LDB_SUCCESS) {
return handle->status;
}
}
for (i = 0; i < ac->num_refs; i++) {
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->type = LDB_REPLY_REFERRAL;
ares->referral = talloc_move(ares, &ac->referrals[i]);
handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
if (handle->status != LDB_SUCCESS) {
return handle->status;
}
}
ares = talloc_zero(ac, struct ldb_reply);
if (!ares) {
handle->status = LDB_ERR_OPERATIONS_ERROR;
return handle->status;
}
ares->type = LDB_REPLY_DONE;
ares->controls = talloc_move(ares, &ac->controls);
handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
if (handle->status != LDB_SUCCESS) {
return handle->status;
}
if ((ret = build_response(ac, &ac->controls, ac->sort_result, "sort control is not complete yet")) != LDB_SUCCESS) {
return ret;
}
return LDB_SUCCESS;
}
static int server_sort_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
struct sort_context *ac;
int ret;
if (!handle || !handle->private_data) {
return LDB_ERR_OPERATIONS_ERROR;
}
ac = talloc_get_type(handle->private_data, struct sort_context);
ret = ldb_wait(ac->req->handle, type);
if (ret != LDB_SUCCESS) {
handle->status = ret;
return ret;
}
handle->state = ac->req->handle->state;
handle->status = ac->req->handle->status;
if (handle->status != LDB_SUCCESS) {
return handle->status;
}
if (handle->state == LDB_ASYNC_DONE) {
ret = server_sort_results(handle);
}
return ret;
}
static int server_sort_init(struct ldb_module *module)
{
struct ldb_request *req;
int ret;
req = talloc(module, struct ldb_request);
if (req == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
req->operation = LDB_REQ_REGISTER_CONTROL;
req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID;
req->controls = NULL;
ret = ldb_request(module->ldb, req);
if (ret != LDB_SUCCESS) {
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n");
}
talloc_free(req);
return ldb_next_init(module);
}
static const struct ldb_module_ops server_sort_ops = {
.name = "server_sort",
.search = server_sort_search,
.wait = server_sort_wait,
.init_context = server_sort_init
};
int ldb_sort_init(void)
{
return ldb_register_module(&server_sort_ops);
}
+34
View File
@@ -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
+427
View File
@@ -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;
}
+402
View File
@@ -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_new(_ldb_nss_ctx, _ldb_nss_ctx->ldb, _LDB_NSS_BASEDN);
if ( ! ldb_dn_validate(_ldb_nss_ctx->base)) {
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;
}
+86
View File
@@ -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;
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 */
+241
View File
@@ -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;
}
+7
View File
@@ -0,0 +1,7 @@
This directory contains Samba specific extensions to ldb. It also
serves as example code on how to extend ldb for your own application.
The main extension Samba uses is to provide ldif encode/decode
routines for specific attributes, so users can get nice pretty
printing of attributes in ldbedit, while the attributes are stored in
the standard NDR format in the database.
+597
View File
@@ -0,0 +1,597 @@
/*
ldb database library - ldif handlers for Samba
Copyright (C) Andrew Tridgell 2005
Copyright (C) Andrew Bartlett 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "ldb/include/ldb_handlers.h"
#include "librpc/gen_ndr/ndr_security.h"
#include "librpc/gen_ndr/ndr_misc.h"
#include "dsdb/samdb/samdb.h"
#include "libcli/security/security.h"
/*
convert a ldif formatted objectSid to a NDR formatted blob
*/
static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct dom_sid *sid;
NTSTATUS status;
sid = dom_sid_parse_talloc(mem_ctx, (const char *)in->data);
if (sid == NULL) {
return -1;
}
status = ndr_push_struct_blob(out, mem_ctx, sid,
(ndr_push_flags_fn_t)ndr_push_dom_sid);
talloc_free(sid);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
return 0;
}
/*
convert a NDR formatted blob to a ldif formatted objectSid
*/
static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct dom_sid *sid;
NTSTATUS status;
sid = talloc(mem_ctx, struct dom_sid);
if (sid == NULL) {
return -1;
}
status = ndr_pull_struct_blob(in, sid, sid,
(ndr_pull_flags_fn_t)ndr_pull_dom_sid);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(sid);
return -1;
}
out->data = (uint8_t *)dom_sid_string(mem_ctx, sid);
talloc_free(sid);
if (out->data == NULL) {
return -1;
}
out->length = strlen((const char *)out->data);
return 0;
}
static BOOL ldb_comparision_objectSid_isString(const struct ldb_val *v)
{
if (v->length < 3) {
return False;
}
if (strncmp("S-", (const char *)v->data, 2) != 0) return False;
return True;
}
/*
compare two objectSids
*/
static int ldb_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (ldb_comparision_objectSid_isString(v1) && ldb_comparision_objectSid_isString(v2)) {
return strcmp((const char *)v1->data, (const char *)v2->data);
} else if (ldb_comparision_objectSid_isString(v1)
&& !ldb_comparision_objectSid_isString(v2)) {
struct ldb_val v;
int ret;
if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
return -1;
}
ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
talloc_free(v.data);
return ret;
} else if (!ldb_comparision_objectSid_isString(v1)
&& ldb_comparision_objectSid_isString(v2)) {
struct ldb_val v;
int ret;
if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
return -1;
}
ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
talloc_free(v.data);
return ret;
}
return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
}
/*
canonicalise a objectSid
*/
static int ldb_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
if (ldb_comparision_objectSid_isString(in)) {
return ldif_read_objectSid(ldb, mem_ctx, in, out);
}
return ldb_handler_copy(ldb, mem_ctx, in, out);
}
/*
convert a ldif formatted objectGUID to a NDR formatted blob
*/
static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct GUID guid;
NTSTATUS status;
status = GUID_from_string((const char *)in->data, &guid);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
status = ndr_push_struct_blob(out, mem_ctx, &guid,
(ndr_push_flags_fn_t)ndr_push_GUID);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
return 0;
}
/*
convert a NDR formatted blob to a ldif formatted objectGUID
*/
static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct GUID guid;
NTSTATUS status;
status = ndr_pull_struct_blob(in, mem_ctx, &guid,
(ndr_pull_flags_fn_t)ndr_pull_GUID);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
if (out->data == NULL) {
return -1;
}
out->length = strlen((const char *)out->data);
return 0;
}
static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v)
{
struct GUID guid;
NTSTATUS status;
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;
}
return True;
}
/*
compare two objectGUIDs
*/
static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
return strcmp((const char *)v1->data, (const char *)v2->data);
} else if (ldb_comparision_objectGUID_isString(v1)
&& !ldb_comparision_objectGUID_isString(v2)) {
struct ldb_val v;
int ret;
if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
return -1;
}
ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
talloc_free(v.data);
return ret;
} else if (!ldb_comparision_objectGUID_isString(v1)
&& ldb_comparision_objectGUID_isString(v2)) {
struct ldb_val v;
int ret;
if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
return -1;
}
ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
talloc_free(v.data);
return ret;
}
return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
}
/*
canonicalise a objectGUID
*/
static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
if (ldb_comparision_objectGUID_isString(in)) {
return ldif_read_objectGUID(ldb, mem_ctx, in, out);
}
return ldb_handler_copy(ldb, mem_ctx, in, out);
}
/*
convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
*/
static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct security_descriptor *sd;
NTSTATUS status;
sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
if (sd == NULL) {
return -1;
}
status = ndr_push_struct_blob(out, mem_ctx, sd,
(ndr_push_flags_fn_t)ndr_push_security_descriptor);
talloc_free(sd);
if (!NT_STATUS_IS_OK(status)) {
return -1;
}
return 0;
}
/*
convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
*/
static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct security_descriptor *sd;
NTSTATUS status;
sd = talloc(mem_ctx, struct security_descriptor);
if (sd == NULL) {
return -1;
}
status = ndr_pull_struct_blob(in, sd, sd,
(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(sd);
return -1;
}
out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
talloc_free(sd);
if (out->data == NULL) {
return -1;
}
out->length = strlen((const char *)out->data);
return 0;
}
/*
canonicolise an objectCategory. We use the short form as the cannoical form:
cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
*/
static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct ldb_dn *dn1 = NULL;
char *oc1, *oc2;
dn1 = ldb_dn_new(mem_ctx, ldb, (char *)in->data);
if ( ! ldb_dn_validate(dn1)) {
oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->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;
}
oc2 = ldb_casefold(ldb, mem_ctx, oc1);
out->data = (void *)oc2;
out->length = strlen(oc2);
talloc_free(oc1);
talloc_free(dn1);
return 0;
}
static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1,
const struct ldb_val *v2)
{
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
const char *oc1, *oc2;
dn1 = ldb_dn_new(mem_ctx, ldb, (char *)v1->data);
if ( ! ldb_dn_validate(dn1)) {
oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->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;
}
dn2 = ldb_dn_new(mem_ctx, ldb, (char *)v2->data);
if ( ! ldb_dn_validate(dn2)) {
oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->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;
}
oc1 = ldb_casefold(ldb, mem_ctx, oc1);
oc2 = ldb_casefold(ldb, mem_ctx, oc2);
if (!oc1 && oc2) {
return -1;
}
if (oc1 && !oc2) {
return 1;
}
if (!oc1 && !oc2) {
return -1;
}
return strcmp(oc1, oc2);
}
static const struct ldb_attrib_handler samba_handlers[] = {
{
.attr = "objectSid",
.flags = 0,
.ldif_read_fn = ldif_read_objectSid,
.ldif_write_fn = ldif_write_objectSid,
.canonicalise_fn = ldb_canonicalise_objectSid,
.comparison_fn = ldb_comparison_objectSid
},
{
.attr = "securityIdentifier",
.flags = 0,
.ldif_read_fn = ldif_read_objectSid,
.ldif_write_fn = ldif_write_objectSid,
.canonicalise_fn = ldb_canonicalise_objectSid,
.comparison_fn = ldb_comparison_objectSid
},
{
.attr = "ntSecurityDescriptor",
.flags = 0,
.ldif_read_fn = ldif_read_ntSecurityDescriptor,
.ldif_write_fn = ldif_write_ntSecurityDescriptor,
.canonicalise_fn = ldb_handler_copy,
.comparison_fn = ldb_comparison_binary
},
{
.attr = "objectGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "invocationId",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "schemaIDGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "attributeSecurityGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "parentGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "siteGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "pKTGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "fRSVersionGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "fRSReplicaSetGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "netbootGUID",
.flags = 0,
.ldif_read_fn = ldif_read_objectGUID,
.ldif_write_fn = ldif_write_objectGUID,
.canonicalise_fn = ldb_canonicalise_objectGUID,
.comparison_fn = ldb_comparison_objectGUID
},
{
.attr = "objectCategory",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldif_canonicalise_objectCategory,
.comparison_fn = ldif_comparison_objectCategory,
},
{
.attr = "member",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "memberOf",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "nCName",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "schemaNamingContext",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "configurationNamingContext",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "rootDomainNamingContext",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "defaultNamingContext",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "subRefs",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "dMDLocation",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "serverReference",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "masteredBy",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "msDs-masteredBy",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "subRefs",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
},
{
.attr = "fSMORoleOwner",
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn,
}
};
/*
register the samba ldif handlers
*/
int ldb_register_samba_handlers(struct ldb_context *ldb)
{
return ldb_set_attrib_handlers(ldb, samba_handlers, ARRAY_SIZE(samba_handlers));
}
+62
View File
@@ -0,0 +1,62 @@
########################################################
# Compile with SQLITE3 support?
SQLITE3_LIBS=""
with_sqlite3_support=no
AC_MSG_CHECKING([for SQLITE3 support])
AC_ARG_WITH(sqlite3,
AS_HELP_STRING([--with-sqlite3],[SQLITE3 backend support (default=no)]),
[ case "$withval" in
yes|no|auto)
with_sqlite3_support=$withval
;;
esac ])
AC_MSG_RESULT($with_sqlite3_support)
if test x"$with_sqlite3_support" != x"no"; then
##################################################################
# first test for sqlite3.h
AC_CHECK_HEADERS(sqlite3.h)
if test x"$ac_cv_header_sqlite3_h" != x"yes"; then
if test x"$with_sqlite3_support" = x"yes"; then
AC_MSG_ERROR(sqlite3.h is needed for SQLITE3 support)
else
AC_MSG_WARN(sqlite3.h is needed for SQLITE3 support)
fi
with_sqlite3_support=no
fi
fi
if test x"$with_sqlite3_support" != x"no"; then
ac_save_LIBS=$LIBS
########################################################
# now see if we can find the sqlite3 libs in standard paths
AC_CHECK_LIB_EXT(sqlite3, SQLITE3_LIBS, sqlite3_open)
if test x"$ac_cv_lib_ext_sqlite3_sqlite3_open" = x"yes"; then
AC_DEFINE(HAVE_SQLITE3,1,[Whether sqlite3 is available])
AC_DEFINE(HAVE_LDB_SQLITE3,1,[Whether ldb_sqlite3 is available])
AC_MSG_CHECKING(whether SQLITE3 support is used)
AC_MSG_RESULT(yes)
with_sqlite3_support=yes
SMB_ENABLE(SQLITE3,YES)
else
if test x"$with_sqlite3_support" = x"yes"; then
AC_MSG_ERROR(libsqlite3 is needed for SQLITE3 support)
else
AC_MSG_WARN(libsqlite3 is needed for SQLITE3 support)
fi
SQLITE3_LIBS=""
with_sqlite3_support=no
fi
LIBS=$ac_save_LIBS;
fi
SMB_EXT_LIB(SQLITE3,[${SQLITE3_LIBS}],[${SQLITE3_CFLAGS}],[${SQLITE3_CPPFLAGS}],[${SQLITE3_LDFLAGS}])
+25
View File
@@ -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 ..
+179
View File
@@ -0,0 +1,179 @@
"""Provide a more Pythonic and object-oriented interface to ldb."""
#
# Swig interface to Samba
#
# Copyright (C) Tim Potter 2006
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# Interface notes:
#
# - should an empty dn be represented as None, or an empty string?
#
# - should single-valued attributes be a string, or a list with one
# element?
#
from ldb import *
# Global initialisation
result = ldb_global_init()
if result != 0:
raise LdbError, (result, 'ldb_global_init failed')
# Ldb exceptions
class LdbError(Exception):
"""An exception raised when a ldb error occurs.
The exception data is a tuple consisting of the ldb number and a
string description of the error."""
pass
# Ldb classes
class LdbMessage:
"""A class representing a ldb message as a Python dictionary."""
def __init__(self):
self.mem_ctx = talloc_init(None)
self.msg = ldb_msg_new(self.mem_ctx)
def __del__(self):
if self.mem_ctx is not None:
talloc_free(self.mem_ctx)
self.mem_ctx = None
self.msg = None
# Make the dn attribute of the object dynamic
def __getattr__(self, attr):
if attr == 'dn':
return ldb_dn_linearize(None, self.msg.dn)
return self.__dict__[attr]
def __setattr__(self, attr, value):
if attr == 'dn':
self.msg.dn = ldb_dn_explode(self.msg, value)
if self.msg.dn == None:
err = LDB_ERR_INVALID_DN_SYNTAX
raise LdbError(err, ldb_strerror(err))
return
self.__dict__[attr] = value
# Get and set individual elements
def __getitem__(self, key):
elt = ldb_msg_find_element(self.msg, key)
if elt is None:
raise KeyError, "No such attribute '%s'" % key
return [ldb_val_array_getitem(elt.values, i)
for i in range(elt.num_values)]
def __setitem__(self, key, value):
ldb_msg_remove_attr(self.msg, key)
if type(value) in (list, tuple):
[ldb_msg_add_value(self.msg, key, v) for v in value]
else:
ldb_msg_add_value(self.msg, key, value)
# Dictionary interface
# TODO: move to iterator based interface
def len(self):
return self.msg.num_elements
def keys(self):
return [ldb_message_element_array_getitem(self.msg.elements, i).name
for i in range(self.msg.num_elements)]
def values(self):
return [self[k] for k in self.keys()]
def items(self):
return [(k, self[k]) for k in self.keys()]
# Misc stuff
def sanity_check(self):
return ldb_msg_sanity_check(self.msg)
class Ldb:
"""A class representing a binding to a ldb file."""
def __init__(self, url, flags = 0):
"""Initialise underlying ldb."""
self.mem_ctx = talloc_init('mem_ctx for ldb 0x%x' % id(self))
self.ldb_ctx = ldb_init(self.mem_ctx)
result = ldb_connect(self.ldb_ctx, url, flags, None)
if result != LDB_SUCCESS:
raise LdbError, (result, ldb_strerror(result))
def __del__(self):
"""Called when the object is to be garbage collected."""
self.close()
def close(self):
"""Close down a ldb."""
if self.mem_ctx is not None:
talloc_free(self.mem_ctx)
self.mem_ctx = None
self.ldb_ctx = None
def _ldb_call(self, fn, *args):
"""Call a ldb function with args. Raise a LdbError exception
if the function returns a non-zero return value."""
result = fn(*args)
if result != LDB_SUCCESS:
raise LdbError, (result, ldb_strerror(result))
def search(self, expression):
"""Search a ldb for a given expression."""
self._ldb_call(ldb_search, self.ldb_ctx, None, LDB_SCOPE_DEFAULT,
expression, None);
return [LdbMessage(ldb_message_ptr_array_getitem(result.msgs, ndx))
for ndx in range(result.count)]
def delete(self, dn):
"""Delete a dn."""
_dn = ldb_dn_explode(self.ldb_ctx, dn)
self._ldb_call(ldb_delete, self.ldb_ctx, _dn)
def rename(self, olddn, newdn):
"""Rename a dn."""
_olddn = ldb_dn_explode(self.ldb_ctx, olddn)
_newdn = ldb_dn_explode(self.ldb_ctx, newdn)
self._ldb_call(ldb_rename, self.ldb_ctx, _olddn, _newdn)
def add(self, m):
self._ldb_call(ldb_add, self.ldb_ctx, m.msg)
+240
View File
@@ -0,0 +1,240 @@
/*
Unix SMB/CIFS implementation.
Swig interface to ldb.
Copyright (C) 2005,2006 Tim Potter <tpot@samba.org>
Copyright (C) 2006 Simo Sorce <idra@samba.org>
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
** under the LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
%module ldb
%{
/* Some typedefs to help swig along */
typedef unsigned char uint8_t;
typedef unsigned long long uint64_t;
typedef long long int64_t;
/* Include headers */
#include "lib/ldb/include/ldb.h"
#include "lib/talloc/talloc.h"
%}
%include "carrays.i"
%include "exception.i"
/*
* Constants
*/
#define LDB_SUCCESS 0
#define LDB_ERR_OPERATIONS_ERROR 1
#define LDB_ERR_PROTOCOL_ERROR 2
#define LDB_ERR_TIME_LIMIT_EXCEEDED 3
#define LDB_ERR_SIZE_LIMIT_EXCEEDED 4
#define LDB_ERR_COMPARE_FALSE 5
#define LDB_ERR_COMPARE_TRUE 6
#define LDB_ERR_AUTH_METHOD_NOT_SUPPORTED 7
#define LDB_ERR_STRONG_AUTH_REQUIRED 8
/* 9 RESERVED */
#define LDB_ERR_REFERRAL 10
#define LDB_ERR_ADMIN_LIMIT_EXCEEDED 11
#define LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION 12
#define LDB_ERR_CONFIDENTIALITY_REQUIRED 13
#define LDB_ERR_SASL_BIND_IN_PROGRESS 14
#define LDB_ERR_NO_SUCH_ATTRIBUTE 16
#define LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE 17
#define LDB_ERR_INAPPROPRIATE_MATCHING 18
#define LDB_ERR_CONSTRAINT_VIOLATION 19
#define LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS 20
#define LDB_ERR_INVALID_ATTRIBUTE_SYNTAX 21
/* 22-31 unused */
#define LDB_ERR_NO_SUCH_OBJECT 32
#define LDB_ERR_ALIAS_PROBLEM 33
#define LDB_ERR_INVALID_DN_SYNTAX 34
/* 35 RESERVED */
#define LDB_ERR_ALIAS_DEREFERENCING_PROBLEM 36
/* 37-47 unused */
#define LDB_ERR_INAPPROPRIATE_AUTHENTICATION 48
#define LDB_ERR_INVALID_CREDENTIALS 49
#define LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS 50
#define LDB_ERR_BUSY 51
#define LDB_ERR_UNAVAILABLE 52
#define LDB_ERR_UNWILLING_TO_PERFORM 53
#define LDB_ERR_LOOP_DETECT 54
/* 55-63 unused */
#define LDB_ERR_NAMING_VIOLATION 64
#define LDB_ERR_OBJECT_CLASS_VIOLATION 65
#define LDB_ERR_NOT_ALLOWED_ON_NON_LEAF 66
#define LDB_ERR_NOT_ALLOWED_ON_RDN 67
#define LDB_ERR_ENTRY_ALREADY_EXISTS 68
#define LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED 69
/* 70 RESERVED FOR CLDAP */
#define LDB_ERR_AFFECTS_MULTIPLE_DSAS 71
/* 72-79 unused */
#define LDB_ERR_OTHER 80
enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
LDB_SCOPE_BASE=0,
LDB_SCOPE_ONELEVEL=1,
LDB_SCOPE_SUBTREE=2};
/*
* Wrap struct ldb_context
*/
/* The ldb functions will crash if a NULL ldb context is passed so
catch this before it happens. */
%typemap(check) struct ldb_context* {
if ($1 == NULL)
SWIG_exception(SWIG_ValueError,
"ldb context must be non-NULL");
}
/*
* Wrap a small bit of talloc
*/
/* Use talloc_init() to create a parameter to pass to ldb_init(). Don't
forget to free it using talloc_free() afterwards. */
TALLOC_CTX *talloc_init(char *name);
int talloc_free(TALLOC_CTX *ptr);
/*
* Wrap struct ldb_val
*/
%typemap(in) struct ldb_val *INPUT (struct ldb_val temp) {
$1 = &temp;
if (!PyString_Check($input)) {
PyErr_SetString(PyExc_TypeError, "string arg expected");
return NULL;
}
$1->length = PyString_Size($input);
$1->data = PyString_AsString($input);
}
%typemap(out) struct ldb_val {
$result = PyString_FromStringAndSize($1.data, $1.length);
}
/*
* Wrap struct ldb_result
*/
%typemap(in, numinputs=0) struct ldb_result **OUT (struct ldb_result *temp_ldb_result) {
$1 = &temp_ldb_result;
}
%typemap(argout) struct ldb_result ** {
resultobj = SWIG_NewPointerObj(*$1, SWIGTYPE_p_ldb_result, 0);
}
%types(struct ldb_result *);
/*
* Wrap struct ldb_message_element
*/
%array_functions(struct ldb_val, ldb_val_array);
struct ldb_message_element {
unsigned int flags;
const char *name;
unsigned int num_values;
struct ldb_val *values;
};
/*
* Wrap struct ldb_message
*/
%array_functions(struct ldb_message_element, ldb_message_element_array);
struct ldb_message {
struct ldb_dn *dn;
unsigned int num_elements;
struct ldb_message_element *elements;
void *private_data;
};
/*
* Wrap struct ldb_result
*/
%array_functions(struct ldb_message *, ldb_message_ptr_array);
struct ldb_result {
unsigned int count;
struct ldb_message **msgs;
char **refs;
struct ldb_control **controls;
};
/*
* Wrap ldb functions
*/
/* Initialisation */
int ldb_global_init(void);
struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx);
/* Error handling */
const char *ldb_errstring(struct ldb_context *ldb);
const char *ldb_strerror(int ldb_err);
/* Top-level ldb operations */
int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]);
int ldb_search(struct ldb_context *ldb, const struct ldb_dn *base, enum ldb_scope scope, const char *expression, const char * const *attrs, struct ldb_result **OUT);
int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn);
int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn);
int ldb_add(struct ldb_context *ldb, const struct ldb_message *message);
/* Ldb message operations */
struct ldb_message *ldb_msg_new(void *mem_ctx);
struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, const char *attr_name);
int ldb_msg_add_value(struct ldb_message *msg, const char *attr_name, const struct ldb_val *INPUT);
void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr);
int ldb_msg_sanity_check(struct ldb_message *msg);
/* DN operations */
struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn);
char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *dn);
+40
View File
@@ -0,0 +1,40 @@
dn: o=University of Michigan,c=TEST
objectclass: organization
objectclass: domainRelatedObject
l: Ann Arbor, Michigan
st: Michigan
o: University of Michigan
o: UMICH
o: UM
o: U-M
o: U of M
description: The University of Michigan at Ann Arbor
seeAlso:
postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
09 $ US
telephonenumber: +1 313 764-1817
associateddomain: example.com
dn: ou=People,o=University of Michigan,c=TEST
objectclass: organizationalUnit
objectclass: extensibleObject
ou: People
uidNumber: 0
gidNumber: 0
dn: ou=Ldb Test,ou=People,o=University of Michigan,c=TEST
objectclass: organizationalUnit
objectclass: extensibleObject
ou: People
ou: Ldb Test
uidNumber: 0
gidNumber: 0
dn: ou=LdbTspace,ou=People,o=University of Michigan,c=TEST
objectclass: organizationalUnit
objectclass: extensibleObject
ou: People
ou: LdbTspace
description: test white space removal in comparisons
uidNumber: 0
gidNumber: 0
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
if [ -z "$LDBDIR" ]; then
LDBDIR=`dirname $0`/..
export LDBDIR
fi
rm -rf tests/tmp/db
mkdir -p tests/tmp/db
if [ -f tests/tmp/slapd.pid ]; then
kill `cat tests/tmp/slapd.pid`
sleep 1
fi
if [ -f tests/tmp/slapd.pid ]; then
kill -9 `cat tests/tmp/slapd.pid`
rm -f tests/tmp/slapd.pid
fi
# we don't consider a slapadd failure as a test suite failure, as it
# has nothing to do with ldb
MODCONF=tests/tmp/modules.conf
rm -f $MODCONF
touch $MODCONF || exit 1
slaptest -u -f $LDBDIR/tests/slapd.conf > /dev/null 2>&1 || {
echo "enabling sladp modules"
cat > $MODCONF <<EOF
modulepath /usr/lib/ldap
moduleload back_bdb
EOF
}
slaptest -u -f $LDBDIR/tests/slapd.conf || {
echo "slaptest failed - skipping ldap tests"
exit 0
}
slapadd -f $LDBDIR/tests/slapd.conf < $LDBDIR/tests/init.ldif || exit 0
+12
View File
@@ -0,0 +1,12 @@
#!/bin/sh
if [ -z "$LDBDIR" ]; then
LDBDIR=`dirname $0`/..
export LDBDIR
fi
if [ -f tests/tmp/slapd.pid ]; then
echo "killing slapd process `cat tests/tmp/slapd.pid`"
kill -9 `cat tests/tmp/slapd.pid`
rm -f tests/tmp/slapd.pid
fi
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
# aargh, did LDAP ever have to expose this crap to users ...
BASE=`pwd`
TMPDIR=$BASE/tests/tmp
LDAPI_ESCAPE=`echo $TMPDIR/ldapi | sed 's|/|%2F|g'`
echo "ldapi://$LDAPI_ESCAPE"
+5
View File
@@ -0,0 +1,5 @@
dn: cn=Hampster Ursula,ou=Alumni Association,ou=People,o=University of Michigan,c=TEST
changetype: modify
add: jpegPhoto
jpegPhoto:< file://tests/tmp/samba4.png
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

@@ -0,0 +1,66 @@
dn: CN=Users,DC=schema,DC=test
objectClass: top
objectClass: container
cn: Users
description: Default container for upgraded user accounts
instanceType: 4
whenCreated: 20050116175504.0Z
whenChanged: 20050116175504.0Z
uSNCreated: 1
uSNChanged: 1
showInAdvancedViewOnly: FALSE
name: Users
objectGUID: b847056a-9934-d87b-8a1a-99fabe0863c8
systemFlags: 0x8c000000
objectCategory: CN=Container,CN=Schema,CN=Configuration,DC=schema,DC=test
isCriticalSystemObject: TRUE
nTSecurityDescriptor: foo
dn: CN=Administrator,CN=Users,DC=schema,DC=test
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Administrator
description: Built-in account for administering the computer/domain
instanceType: 4
whenCreated: 20050116175504.0Z
whenChanged: 20050116175504.0Z
uSNCreated: 1
memberOf: CN=Group Policy Creator Owners,CN=Users,DC=schema,DC=test
memberOf: CN=Domain Admins,CN=Users,DC=schema,DC=test
memberOf: CN=Enterprise Admins,CN=Users,DC=schema,DC=test
memberOf: CN=Schema Admins,CN=Users,DC=schema,DC=test
memberOf: CN=Administrators,CN=Builtin,DC=schema,DC=test
uSNChanged: 1
name: Administrator
objectGUID: 6c02f98c-46c6-aa38-5f13-a510cac04e6c
userAccountControl: 0x10200
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
pwdLastSet: 0
primaryGroupID: 513
objectSid: S-1-5-21-43662522-77495566-38969261-500
adminCount: 1
accountExpires: -1
logonCount: 0
sAMAccountName: Administrator
sAMAccountType: 0x30000000
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=schema,DC=test
isCriticalSystemObject: TRUE
unicodePwd: samba
nTSecurityDescriptor: foo
dn: CN=Test,CN=Users,DC=schema,DC=test
objectClass: top
objectClass: test
cn: Test
description: This is a test
objectCategory: CN=Test,CN=Schema,CN=Configuration,DC=schema,DC=test
nTSecurityDescriptor: foo
instanceType: 4
@@ -0,0 +1,5 @@
dn: CN=Test,CN=Users,DC=schema,DC=test
changetype: modify
replace: description
description: this test must not fail
@@ -0,0 +1,5 @@
dn: CN=Test,CN=Users,DC=schema,DC=test
changetype: modify
delete: description
# this test must not fail
@@ -0,0 +1,5 @@
dn: CN=Test,CN=Users,DC=schema,DC=test
changetype: modify
add: description
description: this test must not fail
@@ -0,0 +1,5 @@
dn: CN=Test,CN=Users,DC=schema,DC=test
changetype: modify
add: foo
foo: this test must fail
@@ -0,0 +1,5 @@
dn: CN=Test,CN=Users,DC=schema,DC=test
changetype: modify
delete: nTSecurityDescriptor
# this test must fail
@@ -0,0 +1,112 @@
dn: @INDEXLIST
@IDXATTR: name
@IDXATTR: sAMAccountName
@IDXATTR: objectSid
@IDXATTR: objectClass
@IDXATTR: member
@IDXATTR: uidNumber
@IDXATTR: gidNumber
@IDXATTR: unixName
@IDXATTR: privilege
@IDXATTR: lDAPDisplayName
dn: @ATTRIBUTES
realm: CASE_INSENSITIVE
userPrincipalName: CASE_INSENSITIVE
servicePrincipalName: CASE_INSENSITIVE
name: CASE_INSENSITIVE
dn: CASE_INSENSITIVE
sAMAccountName: CASE_INSENSITIVE
objectClass: CASE_INSENSITIVE
unicodePwd: HIDDEN
ntPwdHash: HIDDEN
ntPwdHistory: HIDDEN
lmPwdHash: HIDDEN
lmPwdHistory: HIDDEN
createTimestamp: HIDDEN
modifyTimestamp: HIDDEN
dn: @SUBCLASSES
top: domain
top: person
top: group
domain: domainDNS
domain: builtinDomain
person: organizationalPerson
organizationalPerson: user
user: computer
template: userTemplate
template: groupTemplate
dn: @MODULES
@LIST: timestamps,schema
dn: CN=Top,CN=Schema,CN=Configuration,DC=schema,DC=test
objectClass: top
objectClass: classSchema
lDAPDisplayName: top
cn: Top
uSNCreated: 1
uSNChanged: 1
subClassOf: top
systemMustContain: objectClass
systemMayContain: structuralObjectClass
systemMayContain: createTimeStamp
systemMayContain: modifyTimeStamp
systemMayContain: creatorsName
systemMayContain: modifiersName
systemMayContain: hasSubordinates
systemMayContain: subschemaSubentry
systemMayContain: collectiveSubentry
systemMayContain: entryUUID
systemMayContain: entryCSN
systemMayContain: namingCSN
systemMayContain: superiorUUID
systemMayContain: contextCSN
systemMayContain: whenCreated
systemMayContain: whenChanged
systemMayContain: uSNCreated
systemMayContain: uSNChanged
systemMayContain: distinguishedName
systemMayContain: name
systemMayContain: cn
systemMayContain: userPassword
systemMayContain: labeledURI
dn: CN=Class-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
objectClass: top
objectClass: classSchema
lDAPDisplayName: classSchema
cn: Class-Schema
uSNCreated: 2
uSNChanged: 2
lDAPDisplayName: classSchema
subClassOf: top
systemMustContain: cn
systemMustContain: subClassOf
systemMayContain: systemPossSuperiors
systemMayContain: systemOnly
systemMayContain: systemMustContain
systemMayContain: systemMayContain
systemMayContain: systemAuxiliaryClass
systemMayContain: possSuperiors
systemMayContain: mustContain
systemMayContain: mayContain
systemMayContain: lDAPDisplayName
systemMayContain: auxiliaryClass
dn: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=schema,DC=test
objectClass: top
objectClass: classSchema
cn: Attribute-Schema
uSNCreated: 3
uSNChanged: 3
lDAPDisplayName: attributeSchema
subClassOf: top
systemMustContain: oMSyntax
systemMustContain: lDAPDisplayName
systemMustContain: isSingleValued
systemMustContain: cn
systemMustContain: attributeSyntax
systemMustContain: attributeID
+26
View File
@@ -0,0 +1,26 @@
loglevel 0
include tests/schema/core.schema
include tests/schema/cosine.schema
include tests/schema/inetorgperson.schema
include tests/schema/openldap.schema
include tests/schema/nis.schema
pidfile tests/tmp/slapd.pid
argsfile tests/tmp/slapd.args
access to * by * write
allow update_anon bind_anon_dn
include tests/tmp/modules.conf
defaultsearchbase "o=University of Michigan,c=TEST"
backend bdb
database bdb
suffix "o=University of Michigan,c=TEST"
directory tests/tmp/db
index objectClass eq
index uid eq

Some files were not shown because too many files have changed in this diff Show More