From 3e2c696e45b24b0192ab7b1ddaf1dd4d79571609 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 24 Sep 2006 02:49:04 +0000 Subject: r18866: Jeremy and Volker have given the go-ahead on the group mapping ldb code. Yay! This first commit copies lib/ldb/ from Samba4. A huge congratulations should go to Simo on this - he has put an enormous amount of work into ldb, and it's great to see it go into the Samba3 tree. (This used to be commit bbedf2e34315f5c420a3a05dfe22b1d5cf79f042) --- source3/lib/ldb/Doxyfile | 26 + source3/lib/ldb/Makefile.in | 159 ++ source3/lib/ldb/README_gcov.txt | 29 + source3/lib/ldb/aclocal.m4 | 1 + source3/lib/ldb/autogen.sh | 17 + source3/lib/ldb/common/attrib_handlers.c | 392 ++++ source3/lib/ldb/common/ldb.c | 1075 ++++++++++ source3/lib/ldb/common/ldb_attributes.c | 295 +++ source3/lib/ldb/common/ldb_controls.c | 106 + source3/lib/ldb/common/ldb_debug.c | 105 + source3/lib/ldb/common/ldb_dn.c | 944 +++++++++ source3/lib/ldb/common/ldb_ldif.c | 748 +++++++ source3/lib/ldb/common/ldb_match.c | 431 ++++ source3/lib/ldb/common/ldb_modules.c | 442 ++++ source3/lib/ldb/common/ldb_msg.c | 802 ++++++++ source3/lib/ldb/common/ldb_parse.c | 817 ++++++++ source3/lib/ldb/common/ldb_utf8.c | 149 ++ source3/lib/ldb/common/qsort.c | 254 +++ source3/lib/ldb/config.guess | 1466 +++++++++++++ source3/lib/ldb/config.mk | 323 +++ source3/lib/ldb/config.sub | 1579 ++++++++++++++ source3/lib/ldb/configure.ac | 74 + source3/lib/ldb/docs/builddocs.sh | 52 + source3/lib/ldb/docs/design.txt | 41 + source3/lib/ldb/docs/installdocs.sh | 17 + source3/lib/ldb/examples.dox | 16 + source3/lib/ldb/examples/ldbreader.c | 125 ++ source3/lib/ldb/examples/ldifreader.c | 129 ++ source3/lib/ldb/include/dlinklist.h | 111 + source3/lib/ldb/include/includes.h | 34 + source3/lib/ldb/include/ldb.h | 1407 +++++++++++++ source3/lib/ldb/include/ldb_errors.h | 311 +++ source3/lib/ldb/include/ldb_private.h | 220 ++ source3/lib/ldb/install-sh | 238 +++ source3/lib/ldb/ldap.m4 | 89 + source3/lib/ldb/ldb.pc.in | 12 + source3/lib/ldb/ldb_ildap/ldb_ildap.c | 825 ++++++++ source3/lib/ldb/ldb_ldap/ldb_ldap.c | 831 ++++++++ source3/lib/ldb/ldb_sqlite3/README | 7 + source3/lib/ldb/ldb_sqlite3/base160.c | 155 ++ source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2145 ++++++++++++++++++++ source3/lib/ldb/ldb_sqlite3/schema | 363 ++++ source3/lib/ldb/ldb_sqlite3/trees.ps | 1760 ++++++++++++++++ source3/lib/ldb/ldb_tdb/ldb_cache.c | 545 +++++ source3/lib/ldb/ldb_tdb/ldb_index.c | 1159 +++++++++++ source3/lib/ldb/ldb_tdb/ldb_pack.c | 294 +++ source3/lib/ldb/ldb_tdb/ldb_search.c | 543 +++++ source3/lib/ldb/ldb_tdb/ldb_tdb.c | 1065 ++++++++++ source3/lib/ldb/ldb_tdb/ldb_tdb.h | 127 ++ source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 174 ++ source3/lib/ldb/libldb.m4 | 33 + source3/lib/ldb/mainpage.dox | 80 + source3/lib/ldb/man/ad2oLschema.1.xml | 87 + source3/lib/ldb/man/ldb.3.xml | 262 +++ source3/lib/ldb/man/ldbadd.1.xml | 105 + source3/lib/ldb/man/ldbdel.1.xml | 105 + source3/lib/ldb/man/ldbedit.1.xml | 200 ++ source3/lib/ldb/man/ldbmodify.1.xml | 93 + source3/lib/ldb/man/ldbrename.1.xml | 107 + source3/lib/ldb/man/ldbsearch.1.xml | 119 ++ source3/lib/ldb/man/oLschema2ldif.1.xml | 79 + source3/lib/ldb/modules/asq.c | 471 +++++ source3/lib/ldb/modules/ldb_map.c | 1361 +++++++++++++ source3/lib/ldb/modules/ldb_map.h | 158 ++ source3/lib/ldb/modules/ldb_map_inbound.c | 724 +++++++ source3/lib/ldb/modules/ldb_map_outbound.c | 1155 +++++++++++ source3/lib/ldb/modules/ldb_map_private.h | 115 ++ source3/lib/ldb/modules/objectclass.c | 694 +++++++ source3/lib/ldb/modules/operational.c | 312 +++ source3/lib/ldb/modules/paged_results.c | 567 ++++++ source3/lib/ldb/modules/paged_searches.c | 468 +++++ source3/lib/ldb/modules/rdn_name.c | 337 +++ source3/lib/ldb/modules/schema.c | 488 +++++ source3/lib/ldb/modules/skel.c | 137 ++ source3/lib/ldb/modules/sort.c | 445 ++++ source3/lib/ldb/samba/README | 7 + source3/lib/ldb/samba/ldif_handlers.c | 480 +++++ source3/lib/ldb/sqlite3.m4 | 61 + source3/lib/ldb/swig/Ldb.py | 179 ++ source3/lib/ldb/swig/ldb.i | 240 +++ source3/lib/ldb/tests/init.ldif | 40 + source3/lib/ldb/tests/init_slapd.sh | 41 + source3/lib/ldb/tests/kill_slapd.sh | 12 + source3/lib/ldb/tests/ldapi_url.sh | 11 + source3/lib/ldb/tests/photo.ldif | 5 + source3/lib/ldb/tests/samba4.png | Bin 0 -> 6239 bytes .../ldb/tests/schema-tests/schema-add-test.ldif | 66 + .../ldb/tests/schema-tests/schema-mod-test-1.ldif | 5 + .../ldb/tests/schema-tests/schema-mod-test-2.ldif | 5 + .../ldb/tests/schema-tests/schema-mod-test-3.ldif | 5 + .../ldb/tests/schema-tests/schema-mod-test-4.ldif | 5 + .../ldb/tests/schema-tests/schema-mod-test-5.ldif | 5 + source3/lib/ldb/tests/schema-tests/schema.ldif | 112 + source3/lib/ldb/tests/slapd.conf | 26 + source3/lib/ldb/tests/start_slapd.sh | 14 + source3/lib/ldb/tests/test-attribs.ldif | 15 + source3/lib/ldb/tests/test-config.ldif | 67 + source3/lib/ldb/tests/test-default-config.ldif | 17 + source3/lib/ldb/tests/test-extended.sh | 69 + source3/lib/ldb/tests/test-generic.sh | 119 ++ source3/lib/ldb/tests/test-index.ldif | 11 + source3/lib/ldb/tests/test-ldap.sh | 54 + source3/lib/ldb/tests/test-modify.ldif | 23 + source3/lib/ldb/tests/test-schema.sh | 34 + source3/lib/ldb/tests/test-sqlite3.sh | 22 + source3/lib/ldb/tests/test-tdb-features.sh | 119 ++ source3/lib/ldb/tests/test-tdb.sh | 24 + source3/lib/ldb/tests/test-wildcard.ldif | 5 + source3/lib/ldb/tests/test-wrong_attributes.ldif | 3 + source3/lib/ldb/tests/test.ldif | 416 ++++ source3/lib/ldb/tests/testdata.txt | 8 + source3/lib/ldb/tests/testsearch.txt | 5 + source3/lib/ldb/tools/ad2oLschema.c | 630 ++++++ source3/lib/ldb/tools/cmdline.c | 747 +++++++ source3/lib/ldb/tools/cmdline.h | 54 + source3/lib/ldb/tools/convert.c | 166 ++ source3/lib/ldb/tools/convert.h | 10 + source3/lib/ldb/tools/ldbadd.c | 120 ++ source3/lib/ldb/tools/ldbdel.c | 119 ++ source3/lib/ldb/tools/ldbedit.c | 333 +++ source3/lib/ldb/tools/ldbmodify.c | 124 ++ source3/lib/ldb/tools/ldbrename.c | 85 + source3/lib/ldb/tools/ldbsearch.c | 321 +++ source3/lib/ldb/tools/ldbtest.c | 410 ++++ source3/lib/ldb/tools/oLschema2ldif.c | 608 ++++++ source3/lib/ldb/web/index.html | 89 + 126 files changed, 37877 insertions(+) create mode 100644 source3/lib/ldb/Doxyfile create mode 100644 source3/lib/ldb/Makefile.in create mode 100644 source3/lib/ldb/README_gcov.txt create mode 100644 source3/lib/ldb/aclocal.m4 create mode 100755 source3/lib/ldb/autogen.sh create mode 100644 source3/lib/ldb/common/attrib_handlers.c create mode 100644 source3/lib/ldb/common/ldb.c create mode 100644 source3/lib/ldb/common/ldb_attributes.c create mode 100644 source3/lib/ldb/common/ldb_controls.c create mode 100644 source3/lib/ldb/common/ldb_debug.c create mode 100644 source3/lib/ldb/common/ldb_dn.c create mode 100644 source3/lib/ldb/common/ldb_ldif.c create mode 100644 source3/lib/ldb/common/ldb_match.c create mode 100644 source3/lib/ldb/common/ldb_modules.c create mode 100644 source3/lib/ldb/common/ldb_msg.c create mode 100644 source3/lib/ldb/common/ldb_parse.c create mode 100644 source3/lib/ldb/common/ldb_utf8.c create mode 100644 source3/lib/ldb/common/qsort.c create mode 100755 source3/lib/ldb/config.guess create mode 100644 source3/lib/ldb/config.mk create mode 100755 source3/lib/ldb/config.sub create mode 100644 source3/lib/ldb/configure.ac create mode 100755 source3/lib/ldb/docs/builddocs.sh create mode 100644 source3/lib/ldb/docs/design.txt create mode 100755 source3/lib/ldb/docs/installdocs.sh create mode 100644 source3/lib/ldb/examples.dox create mode 100644 source3/lib/ldb/examples/ldbreader.c create mode 100644 source3/lib/ldb/examples/ldifreader.c create mode 100644 source3/lib/ldb/include/dlinklist.h create mode 100644 source3/lib/ldb/include/includes.h create mode 100644 source3/lib/ldb/include/ldb.h create mode 100644 source3/lib/ldb/include/ldb_errors.h create mode 100644 source3/lib/ldb/include/ldb_private.h create mode 100755 source3/lib/ldb/install-sh create mode 100644 source3/lib/ldb/ldap.m4 create mode 100644 source3/lib/ldb/ldb.pc.in create mode 100644 source3/lib/ldb/ldb_ildap/ldb_ildap.c create mode 100644 source3/lib/ldb/ldb_ldap/ldb_ldap.c create mode 100644 source3/lib/ldb/ldb_sqlite3/README create mode 100644 source3/lib/ldb/ldb_sqlite3/base160.c create mode 100644 source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c create mode 100644 source3/lib/ldb/ldb_sqlite3/schema create mode 100644 source3/lib/ldb/ldb_sqlite3/trees.ps create mode 100644 source3/lib/ldb/ldb_tdb/ldb_cache.c create mode 100644 source3/lib/ldb/ldb_tdb/ldb_index.c create mode 100644 source3/lib/ldb/ldb_tdb/ldb_pack.c create mode 100644 source3/lib/ldb/ldb_tdb/ldb_search.c create mode 100644 source3/lib/ldb/ldb_tdb/ldb_tdb.c create mode 100644 source3/lib/ldb/ldb_tdb/ldb_tdb.h create mode 100644 source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c create mode 100644 source3/lib/ldb/libldb.m4 create mode 100644 source3/lib/ldb/mainpage.dox create mode 100644 source3/lib/ldb/man/ad2oLschema.1.xml create mode 100644 source3/lib/ldb/man/ldb.3.xml create mode 100644 source3/lib/ldb/man/ldbadd.1.xml create mode 100644 source3/lib/ldb/man/ldbdel.1.xml create mode 100644 source3/lib/ldb/man/ldbedit.1.xml create mode 100644 source3/lib/ldb/man/ldbmodify.1.xml create mode 100644 source3/lib/ldb/man/ldbrename.1.xml create mode 100644 source3/lib/ldb/man/ldbsearch.1.xml create mode 100644 source3/lib/ldb/man/oLschema2ldif.1.xml create mode 100644 source3/lib/ldb/modules/asq.c create mode 100644 source3/lib/ldb/modules/ldb_map.c create mode 100644 source3/lib/ldb/modules/ldb_map.h create mode 100644 source3/lib/ldb/modules/ldb_map_inbound.c create mode 100644 source3/lib/ldb/modules/ldb_map_outbound.c create mode 100644 source3/lib/ldb/modules/ldb_map_private.h create mode 100644 source3/lib/ldb/modules/objectclass.c create mode 100644 source3/lib/ldb/modules/operational.c create mode 100644 source3/lib/ldb/modules/paged_results.c create mode 100644 source3/lib/ldb/modules/paged_searches.c create mode 100644 source3/lib/ldb/modules/rdn_name.c create mode 100644 source3/lib/ldb/modules/schema.c create mode 100644 source3/lib/ldb/modules/skel.c create mode 100644 source3/lib/ldb/modules/sort.c create mode 100644 source3/lib/ldb/samba/README create mode 100644 source3/lib/ldb/samba/ldif_handlers.c create mode 100644 source3/lib/ldb/sqlite3.m4 create mode 100644 source3/lib/ldb/swig/Ldb.py create mode 100644 source3/lib/ldb/swig/ldb.i create mode 100644 source3/lib/ldb/tests/init.ldif create mode 100755 source3/lib/ldb/tests/init_slapd.sh create mode 100755 source3/lib/ldb/tests/kill_slapd.sh create mode 100755 source3/lib/ldb/tests/ldapi_url.sh create mode 100644 source3/lib/ldb/tests/photo.ldif create mode 100644 source3/lib/ldb/tests/samba4.png create mode 100644 source3/lib/ldb/tests/schema-tests/schema-add-test.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif create mode 100644 source3/lib/ldb/tests/schema-tests/schema.ldif create mode 100644 source3/lib/ldb/tests/slapd.conf create mode 100755 source3/lib/ldb/tests/start_slapd.sh create mode 100644 source3/lib/ldb/tests/test-attribs.ldif create mode 100644 source3/lib/ldb/tests/test-config.ldif create mode 100644 source3/lib/ldb/tests/test-default-config.ldif create mode 100755 source3/lib/ldb/tests/test-extended.sh create mode 100755 source3/lib/ldb/tests/test-generic.sh create mode 100644 source3/lib/ldb/tests/test-index.ldif create mode 100755 source3/lib/ldb/tests/test-ldap.sh create mode 100644 source3/lib/ldb/tests/test-modify.ldif create mode 100755 source3/lib/ldb/tests/test-schema.sh create mode 100755 source3/lib/ldb/tests/test-sqlite3.sh create mode 100644 source3/lib/ldb/tests/test-tdb-features.sh create mode 100755 source3/lib/ldb/tests/test-tdb.sh create mode 100644 source3/lib/ldb/tests/test-wildcard.ldif create mode 100644 source3/lib/ldb/tests/test-wrong_attributes.ldif create mode 100644 source3/lib/ldb/tests/test.ldif create mode 100644 source3/lib/ldb/tests/testdata.txt create mode 100644 source3/lib/ldb/tests/testsearch.txt create mode 100644 source3/lib/ldb/tools/ad2oLschema.c create mode 100644 source3/lib/ldb/tools/cmdline.c create mode 100644 source3/lib/ldb/tools/cmdline.h create mode 100644 source3/lib/ldb/tools/convert.c create mode 100644 source3/lib/ldb/tools/convert.h create mode 100644 source3/lib/ldb/tools/ldbadd.c create mode 100644 source3/lib/ldb/tools/ldbdel.c create mode 100644 source3/lib/ldb/tools/ldbedit.c create mode 100644 source3/lib/ldb/tools/ldbmodify.c create mode 100644 source3/lib/ldb/tools/ldbrename.c create mode 100644 source3/lib/ldb/tools/ldbsearch.c create mode 100644 source3/lib/ldb/tools/ldbtest.c create mode 100644 source3/lib/ldb/tools/oLschema2ldif.c create mode 100644 source3/lib/ldb/web/index.html (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/Doxyfile b/source3/lib/ldb/Doxyfile new file mode 100644 index 0000000000..07b12b516a --- /dev/null +++ b/source3/lib/ldb/Doxyfile @@ -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 diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in new file mode 100644 index 0000000000..106e493530 --- /dev/null +++ b/source3/lib/ldb/Makefile.in @@ -0,0 +1,159 @@ +#!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=-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=-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)/schema.o $(MODDIR)/rdn_name.o \ + $(MODDIR)/objectclass.o \ + $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o + +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 + +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 $@ + +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) + 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]"` diff --git a/source3/lib/ldb/README_gcov.txt b/source3/lib/ldb/README_gcov.txt new file mode 100644 index 0000000000..2abd9378f4 --- /dev/null +++ b/source3/lib/ldb/README_gcov.txt @@ -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. diff --git a/source3/lib/ldb/aclocal.m4 b/source3/lib/ldb/aclocal.m4 new file mode 100644 index 0000000000..5605e476ba --- /dev/null +++ b/source3/lib/ldb/aclocal.m4 @@ -0,0 +1 @@ +m4_include(libreplace.m4) diff --git a/source3/lib/ldb/autogen.sh b/source3/lib/ldb/autogen.sh new file mode 100755 index 0000000000..500cab87d5 --- /dev/null +++ b/source3/lib/ldb/autogen.sh @@ -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 + diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c new file mode 100644 index 0000000000..8e437964f4 --- /dev/null +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -0,0 +1,392 @@ +/* + 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" + +/* + 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 +*/ +static 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 +*/ +static 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 +*/ +static 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 +*/ +static 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; + char *b1, *b2, *u1, *u2; + 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: + /* non need to recheck from the start, just from the first utf8 char found */ + b1 = u1 = ldb_casefold(ldb, mem_ctx, s1); + b2 = u2 = ldb_casefold(ldb, mem_ctx, 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 +*/ +static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + struct ldb_dn *dn; + int ret = -1; + + out->length = 0; + out->data = NULL; + + dn = ldb_dn_explode_casefold(ldb, (char *)in->data); + if (dn == NULL) { + return -1; + } + + out->data = (uint8_t *)ldb_dn_linearize(mem_ctx, dn); + if (out->data == NULL) { + goto done; + } + out->length = strlen((char *)out->data); + + ret = 0; + +done: + talloc_free(dn); + + return ret; +} + +/* + compare two dns +*/ +static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + struct ldb_dn *dn1 = NULL, *dn2 = NULL; + int ret; + + dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data); + if (dn1 == NULL) return -1; + + dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data); + if (dn2 == NULL) { + talloc_free(dn1); + return -1; + } + + ret = ldb_dn_compare(ldb, dn1, dn2); + + talloc_free(dn1); + talloc_free(dn2); + return ret; +} + +/* + compare two objectclasses, looking at subclasses +*/ +static 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 +*/ +static int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *v1, const struct ldb_val *v2) +{ + time_t t1, 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 +*/ +static 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;inext) { + if (strncmp(backend->name, url, strlen(backend->name)) == 0) { + return backend->connect_fn; + } + } + + return NULL; +} + +/* + register a new ldb backend +*/ +int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn) +{ + struct ldb_backend *backend = talloc(talloc_autofree_context(), struct ldb_backend); + + if (ldb_find_backend(url_prefix)) { + return LDB_SUCCESS; + } + + /* Maybe check for duplicity here later on? */ + + backend->name = talloc_strdup(backend, url_prefix); + backend->connect_fn = connectfn; + DLIST_ADD(ldb_backends, backend); + + return LDB_SUCCESS; +} + +/* + Return the ldb module form of a database. The URL can either be one of the following forms + ldb://path + ldapi://path + + flags is made up of LDB_FLG_* + + the options are passed uninterpreted to the backend, and are + backend specific. + + This allows modules to get at only the backend module, for example where a module + may wish to direct certain requests at a particular backend. +*/ +int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[], + struct ldb_module **backend_module) +{ + int ret; + char *backend; + ldb_connect_fn fn; + + if (strchr(url, ':') != NULL) { + backend = talloc_strndup(ldb, url, strchr(url, ':')-url); + } else { + /* Default to tdb */ + backend = talloc_strdup(ldb, "tdb"); + } + + fn = ldb_find_backend(backend); + + if (fn == NULL) { + if (ldb_try_load_dso(ldb, backend) == 0) { + fn = ldb_find_backend(backend); + } + } + + talloc_free(backend); + + if (fn == NULL) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to find backend for '%s'\n", url); + return LDB_ERR_OTHER; + } + + ret = fn(ldb, url, ldb->flags, options, backend_module); + + if (ret != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to '%s'\n", url); + return ret; + } + return ret; +} + +/* + try to autodetect a basedn if none specified. This fixes one of my + pet hates about ldapsearch, which is that you have to get a long, + complex basedn right to make any use of it. +*/ +static const struct ldb_dn *ldb_set_default_basedn(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + int ret; + static const char *attrs[] = { "defaultNamingContext", NULL }; + struct ldb_result *res; + struct ldb_dn *basedn=NULL; + + basedn = ldb_get_opaque(ldb, "default_baseDN"); + if (basedn) { + return basedn; + } + + tmp_ctx = talloc_new(ldb); + ret = ldb_search(ldb, ldb_dn_new(tmp_ctx), LDB_SCOPE_BASE, + "(objectClass=*)", attrs, &res); + if (ret == LDB_SUCCESS) { + if (res->count == 1) { + basedn = ldb_msg_find_attr_as_dn(ldb, res->msgs[0], "defaultNamingContext"); + ldb_set_opaque(ldb, "default_baseDN", basedn); + } + talloc_free(res); + } + + talloc_free(tmp_ctx); + return basedn; +} + +const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb) +{ + return ldb_get_opaque(ldb, "default_baseDN"); +} + +/* + connect to a database. The URL can either be one of the following forms + ldb://path + ldapi://path + + flags is made up of LDB_FLG_* + + the options are passed uninterpreted to the backend, and are + backend specific +*/ +int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]) +{ + int ret; + + ldb->flags = flags; + + ret = ldb_connect_backend(ldb, url, options, &ldb->modules); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (ldb_load_modules(ldb, options) != LDB_SUCCESS) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for '%s'\n", url); + return LDB_ERR_OTHER; + } + + /* TODO: get timeout from options if available there */ + ldb->default_timeout = 300; /* set default to 5 minutes */ + + /* set the default base dn */ + ldb_set_default_basedn(ldb); + + return LDB_SUCCESS; +} + +void ldb_set_errstring(struct ldb_context *ldb, const char *err_string) +{ + if (ldb->err_string) { + talloc_free(ldb->err_string); + } + ldb->err_string = talloc_strdup(ldb, err_string); +} + +void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) +{ + va_list ap; + + if (ldb->err_string) { + talloc_free(ldb->err_string); + } + + va_start(ap, format); + ldb->err_string = talloc_vasprintf(ldb, format, ap); + va_end(ap); +} + +void ldb_reset_err_string(struct ldb_context *ldb) +{ + if (ldb->err_string) { + talloc_free(ldb->err_string); + ldb->err_string = NULL; + } +} + +#define FIRST_OP(ldb, op) do { \ + module = ldb->modules; \ + while (module && module->ops->op == NULL) module = module->next; \ + if (module == NULL) { \ + ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \ + return LDB_ERR_OPERATIONS_ERROR; \ + } \ +} while (0) + +/* + start a transaction +*/ +static int ldb_transaction_start_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, start_transaction); + + ldb_reset_err_string(ldb); + + status = module->ops->start_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction start: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +/* + commit a transaction +*/ +static int ldb_transaction_commit_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, end_transaction); + + ldb_reset_err_string(ldb); + + status = module->ops->end_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction commit: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +/* + cancel a transaction +*/ +static int ldb_transaction_cancel_internal(struct ldb_context *ldb) +{ + struct ldb_module *module; + int status; + FIRST_OP(ldb, del_transaction); + + status = module->ops->del_transaction(module); + if (status != LDB_SUCCESS) { + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, + "ldb transaction cancel: %s (%d)", + ldb_strerror(status), + status); + } + } + return status; +} + +int ldb_transaction_start(struct ldb_context *ldb) +{ + /* disable autotransactions */ + ldb->transaction_active++; + + return ldb_transaction_start_internal(ldb); +} + +int ldb_transaction_commit(struct ldb_context *ldb) +{ + /* renable autotransactions (when we reach 0) */ + if (ldb->transaction_active > 0) + ldb->transaction_active--; + + return ldb_transaction_commit_internal(ldb); +} + +int ldb_transaction_cancel(struct ldb_context *ldb) +{ + /* renable autotransactions (when we reach 0) */ + if (ldb->transaction_active > 0) + ldb->transaction_active--; + + return ldb_transaction_cancel_internal(ldb); +} + +static int ldb_autotransaction_start(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_start_internal(ldb); +} + +static int ldb_autotransaction_commit(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_commit_internal(ldb); +} + +static int ldb_autotransaction_cancel(struct ldb_context *ldb) +{ + /* explicit transaction active, ignore autotransaction request */ + if (ldb->transaction_active) + return LDB_SUCCESS; + + return ldb_transaction_cancel_internal(ldb); +} + +/* autostarts a transacion if none active */ +static int ldb_autotransaction_request(struct ldb_context *ldb, struct ldb_request *req) +{ + int ret; + + ret = ldb_autotransaction_start(ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_autotransaction_commit(ldb); + } + ldb_autotransaction_cancel(ldb); + + if (ldb->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret); + } + + return ret; +} + +int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + if (!handle) { + return LDB_SUCCESS; + } + + return handle->module->ops->wait(handle, type); +} + +/* set the specified timeout or, if timeout is 0 set the default timeout */ +/* timeout == -1 means no timeout */ +int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout) +{ + if (req == NULL) return LDB_ERR_OPERATIONS_ERROR; + + if (timeout != 0) { + req->timeout = timeout; + } else { + req->timeout = ldb->default_timeout; + } + req->starttime = time(NULL); + + return LDB_SUCCESS; +} + +/* calculates the new timeout based on the previous starttime and timeout */ +int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq) +{ + time_t now; + + if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR; + + now = time(NULL); + + if (oldreq == NULL) + return ldb_set_timeout(ldb, newreq, 0); + + if ((now - oldreq->starttime) > oldreq->timeout) { + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + newreq->starttime = oldreq->starttime; + newreq->timeout = oldreq->timeout - (now - oldreq->starttime); + + return LDB_SUCCESS; +} + +/* + start an ldb request + NOTE: the request must be a talloc context. + returns LDB_ERR_* on errors. +*/ +int ldb_request(struct ldb_context *ldb, struct ldb_request *req) +{ + struct ldb_module *module; + int ret; + + ldb_reset_err_string(ldb); + + /* call the first module in the chain */ + switch (req->operation) { + case LDB_SEARCH: + FIRST_OP(ldb, search); + ret = module->ops->search(module, req); + break; + case LDB_ADD: + FIRST_OP(ldb, add); + ret = module->ops->add(module, req); + break; + case LDB_MODIFY: + FIRST_OP(ldb, modify); + ret = module->ops->modify(module, req); + break; + case LDB_DELETE: + FIRST_OP(ldb, del); + ret = module->ops->del(module, req); + break; + case LDB_RENAME: + FIRST_OP(ldb, rename); + ret = module->ops->rename(module, req); + break; + case LDB_SEQUENCE_NUMBER: + FIRST_OP(ldb, sequence_number); + ret = module->ops->sequence_number(module, req); + break; + default: + FIRST_OP(ldb, request); + ret = module->ops->request(module, req); + break; + } + + return ret; +} + +/* + search the database given a LDAP-like search expression + + returns an LDB error code + + Use talloc_free to free the ldb_message returned in 'res', if successful + +*/ +static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct ldb_result *res; + int n; + + if (!context) { + ldb_set_errstring(ldb, "NULL Context in callback"); + return LDB_ERR_OPERATIONS_ERROR; + } + + res = *((struct ldb_result **)context); + + if (!res || !ares) { + goto error; + } + + if (ares->type == LDB_REPLY_ENTRY) { + res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); + if (! res->msgs) { + goto error; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_move(res->msgs, &ares->message); + res->count++; + } + + if (ares->type == LDB_REPLY_REFERRAL) { + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + goto error; + } + + res->refs[n] = talloc_move(res->refs, &ares->referral); + res->refs[n + 1] = NULL; + } + + talloc_steal(res, ares->controls); + talloc_free(ares); + return LDB_SUCCESS; + +error: + talloc_free(ares); + talloc_free(res); + *((struct ldb_result **)context) = NULL; + return LDB_ERR_OPERATIONS_ERROR; +} + +int ldb_build_search_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_SEARCH; + if (base == NULL) { + req->op.search.base = ldb_dn_new(req); + } else { + req->op.search.base = base; + } + req->op.search.scope = scope; + + req->op.search.tree = ldb_parse_tree(req, expression); + if (req->op.search.tree == NULL) { + ldb_set_errstring(ldb, "Unable to parse search expression"); + talloc_free(req); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->op.search.attrs = attrs; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + return LDB_SUCCESS; +} + +int ldb_build_add_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_ADD; + req->op.add.message = message; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_mod_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_MODIFY; + req->op.mod.message = message; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_del_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_dn *dn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_DELETE; + req->op.del.dn = dn; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +int ldb_build_rename_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + struct ldb_dn *olddn, + struct ldb_dn *newdn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback) +{ + struct ldb_request *req; + + *ret_req = NULL; + + req = talloc(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_RENAME; + req->op.rename.olddn = olddn; + req->op.rename.newdn = newdn; + req->controls = controls; + req->context = context; + req->callback = callback; + + *ret_req = req; + + return LDB_SUCCESS; +} + +/* + note that ldb_search() will automatically replace a NULL 'base' value with the + defaultNamingContext from the rootDSE if available. +*/ +int ldb_search(struct ldb_context *ldb, + const struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_result **res) +{ + struct ldb_request *req; + int ret; + + *res = talloc_zero(ldb, struct ldb_result); + if (! *res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb, ldb, + base?base:ldb_get_default_basedn(ldb), + scope, + expression, + attrs, + NULL, + res, + ldb_search_callback); + + if (ret != LDB_SUCCESS) goto done; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + +done: + if (ret != LDB_SUCCESS) { + talloc_free(*res); + *res = NULL; + } + + return ret; +} + +/* + add a record to the database. Will fail if a record with the given class and key + already exists +*/ +int ldb_add(struct ldb_context *ldb, + const struct ldb_message *message) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&req, ldb, ldb, + message, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + +/* + modify the specified attributes of a record +*/ +int ldb_modify(struct ldb_context *ldb, + const struct ldb_message *message) +{ + struct ldb_request *req; + int ret; + + ret = ldb_msg_sanity_check(ldb, message); + if (ret != LDB_SUCCESS) return ret; + + ret = ldb_build_mod_req(&req, ldb, ldb, + message, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + delete a record from the database +*/ +int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_del_req(&req, ldb, ldb, + dn, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + +/* + rename a record in the database +*/ +int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_request *req; + int ret; + + ret = ldb_build_rename_req(&req, ldb, ldb, + olddn, + newdn, + NULL, + NULL, + NULL); + + if (ret != LDB_SUCCESS) return ret; + + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + /* do request and autostart a transaction */ + ret = ldb_autotransaction_request(ldb, req); + + talloc_free(req); + return ret; +} + + +/* + return the global sequence number +*/ +int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num) +{ + struct ldb_request *req; + int ret; + + req = talloc(ldb, struct ldb_request); + if (req == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_SEQUENCE_NUMBER; + req->controls = NULL; + req->context = NULL; + req->callback = NULL; + ldb_set_timeout(ldb, req, 0); /* use default timeout */ + + req->op.seq_num.type = type; + /* do request and autostart a transaction */ + ret = ldb_request(ldb, req); + + if (ret == LDB_SUCCESS) { + *seq_num = req->op.seq_num.seq_num; + } + + talloc_free(req); + return ret; +} + + + +/* + return extended error information +*/ +const char *ldb_errstring(struct ldb_context *ldb) +{ + if (ldb->err_string) { + return ldb->err_string; + } + + return NULL; +} + +/* + return a string explaining what a ldb error constant meancs +*/ +const char *ldb_strerror(int ldb_err) +{ + switch (ldb_err) { + case LDB_SUCCESS: + return "Success"; + case LDB_ERR_OPERATIONS_ERROR: + return "Operations error"; + case LDB_ERR_PROTOCOL_ERROR: + return "Protocol error"; + case LDB_ERR_TIME_LIMIT_EXCEEDED: + return "Time limit exceeded"; + case LDB_ERR_SIZE_LIMIT_EXCEEDED: + return "Size limit exceeded"; + case LDB_ERR_COMPARE_FALSE: + return "Compare false"; + case LDB_ERR_COMPARE_TRUE: + return "Compare true"; + case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED: + return "Auth method not supported"; + case LDB_ERR_STRONG_AUTH_REQUIRED: + return "Strong auth required"; +/* 9 RESERVED */ + case LDB_ERR_REFERRAL: + return "Referral error"; + case LDB_ERR_ADMIN_LIMIT_EXCEEDED: + return "Admin limit exceeded"; + case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION: + return "Unsupported critical extension"; + case LDB_ERR_CONFIDENTIALITY_REQUIRED: + return "Confidentiality required"; + case LDB_ERR_SASL_BIND_IN_PROGRESS: + return "SASL bind in progress"; + case LDB_ERR_NO_SUCH_ATTRIBUTE: + return "No such attribute"; + case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE: + return "Undefined attribute type"; + case LDB_ERR_INAPPROPRIATE_MATCHING: + return "Inappropriate matching"; + case LDB_ERR_CONSTRAINT_VIOLATION: + return "Constraint violation"; + case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS: + return "Attribute or value exists"; + case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX: + return "Invalid attribute syntax"; +/* 22-31 unused */ + case LDB_ERR_NO_SUCH_OBJECT: + return "No such object"; + case LDB_ERR_ALIAS_PROBLEM: + return "Alias problem"; + case LDB_ERR_INVALID_DN_SYNTAX: + return "Invalid DN syntax"; +/* 35 RESERVED */ + case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM: + return "Alias dereferencing problem"; +/* 37-47 unused */ + case LDB_ERR_INAPPROPRIATE_AUTHENTICATION: + return "Inappropriate authentication"; + case LDB_ERR_INVALID_CREDENTIALS: + return "Invalid credentials"; + case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: + return "insufficient access rights"; + case LDB_ERR_BUSY: + return "Busy"; + case LDB_ERR_UNAVAILABLE: + return "Unavailable"; + case LDB_ERR_UNWILLING_TO_PERFORM: + return "Unwilling to perform"; + case LDB_ERR_LOOP_DETECT: + return "Loop detect"; +/* 55-63 unused */ + case LDB_ERR_NAMING_VIOLATION: + return "Naming violation"; + case LDB_ERR_OBJECT_CLASS_VIOLATION: + return "Object class violation"; + case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF: + return "Not allowed on non-leaf"; + case LDB_ERR_NOT_ALLOWED_ON_RDN: + return "Not allowed on RDN"; + case LDB_ERR_ENTRY_ALREADY_EXISTS: + return "Entry already exists"; + case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED: + return "Object class mods prohibited"; +/* 70 RESERVED FOR CLDAP */ + case LDB_ERR_AFFECTS_MULTIPLE_DSAS: + return "Affects multiple DSAs"; +/* 72-79 unused */ + case LDB_ERR_OTHER: + return "Other"; + } + + return "Unknown error"; +} + +/* + set backend specific opaque parameters +*/ +int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value) +{ + struct ldb_opaque *o; + + /* allow updating an existing value */ + for (o=ldb->opaque;o;o=o->next) { + if (strcmp(o->name, name) == 0) { + o->value = value; + return LDB_SUCCESS; + } + } + + o = talloc(ldb, struct ldb_opaque); + if (o == NULL) { + ldb_oom(ldb); + return LDB_ERR_OTHER; + } + o->next = ldb->opaque; + o->name = name; + o->value = value; + ldb->opaque = o; + return LDB_SUCCESS; +} + +/* + get a previously set opaque value +*/ +void *ldb_get_opaque(struct ldb_context *ldb, const char *name) +{ + struct ldb_opaque *o; + for (o=ldb->opaque;o;o=o->next) { + if (strcmp(o->name, name) == 0) { + return o->value; + } + } + return NULL; +} diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c new file mode 100644 index 0000000000..c8a7909b4c --- /dev/null +++ b/source3/lib/ldb/common/ldb_attributes.c @@ -0,0 +1,295 @@ +/* + 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) +{ + struct ldb_attrib_handler *h; + h = talloc_realloc(ldb, ldb->schema.attrib_handlers, + struct ldb_attrib_handler, + ldb->schema.num_attrib_handlers + num_handlers); + if (h == NULL) { + ldb_oom(ldb); + return -1; + } + ldb->schema.attrib_handlers = h; + memcpy(h + ldb->schema.num_attrib_handlers, + handlers, sizeof(*h) * num_handlers); + ldb->schema.num_attrib_handlers += num_handlers; + return 0; +} + + +/* + default function for read/write/canonicalise +*/ +static int ldb_default_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 (out->data == NULL && in->data != NULL) { + return -1; + } + + return 0; +} + +/* + default function for comparison +*/ +static int ldb_default_cmp(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); +} + +/* + default handler function pointers +*/ +static const struct ldb_attrib_handler ldb_default_attrib_handler = { + .attr = NULL, + .ldif_read_fn = ldb_default_copy, + .ldif_write_fn = ldb_default_copy, + .canonicalise_fn = ldb_default_copy, + .comparison_fn = ldb_default_cmp, +}; + +/* + 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; + const struct ldb_attrib_handler *def = &ldb_default_attrib_handler; + /* TODO: should be replaced with a binary search, with a sort on add */ + for (i=0;ischema.num_attrib_handlers;i++) { + if (strcmp(ldb->schema.attrib_handlers[i].attr, "*") == 0) { + def = &ldb->schema.attrib_handlers[i]; + } + if (ldb_attr_cmp(attrib, ldb->schema.attrib_handlers[i].attr) == 0) { + return &ldb->schema.attrib_handlers[i]; + } + } + 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; + } + 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 }, + { "ncName", 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;ischema.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;ischema.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;ischema.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; + } +} diff --git a/source3/lib/ldb/common/ldb_controls.c b/source3/lib/ldb/common/ldb_controls.c new file mode 100644 index 0000000000..d2729c82ab --- /dev/null +++ b/source3/lib/ldb/common/ldb_controls.c @@ -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; +} diff --git a/source3/lib/ldb/common/ldb_debug.c b/source3/lib/ldb/common/ldb_debug.c new file mode 100644 index 0000000000..2548a5495a --- /dev/null +++ b/source3/lib/ldb/common/ldb_debug.c @@ -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); +} + diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c new file mode 100644 index 0000000000..a0f48723ab --- /dev/null +++ b/source3/lib/ldb/common/ldb_dn.c @@ -0,0 +1,944 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldb dn explode and utility functions + * + * Description: - explode a dn into it's own basic elements + * and put them in a structure + * - manipulate ldb_dn structures + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#define LDB_DN_NULL_FAILED(x) if (!(x)) goto failed + +#define LDB_SPECIAL "@SPECIAL" + +int ldb_dn_is_special(const struct ldb_dn *dn) +{ + if (dn == NULL || dn->comp_num != 1) return 0; + + return ! strcmp(dn->components[0].name, LDB_SPECIAL); +} + +int ldb_dn_check_special(const struct ldb_dn *dn, const char *check) +{ + if (dn == NULL || dn->comp_num != 1) return 0; + + return ! strcmp((char *)dn->components[0].value.data, check); +} + +char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value) +{ + const char *p, *s, *src; + char *d, *dst; + int len; + + if (!value.length) + return NULL; + + p = s = src = (const char *)value.data; + len = value.length; + + /* allocate destination string, it will be at most 3 times the source */ + dst = d = talloc_array(mem_ctx, char, len * 3 + 1); + LDB_DN_NULL_FAILED(dst); + + while (p - src < len) { + + p += strcspn(p, ",=\n+<>#;\\\""); + + if (p - src == len) /* found no escapable chars */ + break; + + memcpy(d, s, p - s); /* copy the part of the string before the stop */ + d += (p - s); /* move to current position */ + + if (*p) { /* it is a normal escapable character */ + *d++ = '\\'; + *d++ = *p++; + } else { /* we have a zero byte in the string */ + strncpy(d, "\00", 3); /* escape the zero */ + d = d + 3; + p++; /* skip the zero */ + } + s = p; /* move forward */ + } + + /* copy the last part (with zero) and return */ + memcpy(d, s, &src[len] - s + 1); + + return dst; + +failed: + talloc_free(dst); + return NULL; +} + +static struct ldb_val ldb_dn_unescape_value(void *mem_ctx, const char *src) +{ + struct ldb_val value; + unsigned x; + char *p, *dst = NULL, *end; + + memset(&value, 0, sizeof(value)); + + LDB_DN_NULL_FAILED(src); + + dst = p = talloc_memdup(mem_ctx, src, strlen(src) + 1); + LDB_DN_NULL_FAILED(dst); + + end = &dst[strlen(dst)]; + + while (*p) { + p += strcspn(p, ",=\n+<>#;\\\""); + + if (*p == '\\') { + if (strchr(",=\n+<>#;\\\"", p[1])) { + memmove(p, p + 1, end - (p + 1) + 1); + end--; + p++; + continue; + } + + if (sscanf(p + 1, "%02x", &x) == 1) { + *p = (unsigned char)x; + memmove(p + 1, p + 3, end - (p + 3) + 1); + end -= 2; + p++; + continue; + } + } + + /* a string with not escaped specials is invalid (tested) */ + if (*p != '\0') { + goto failed; + } + } + + value.length = end - dst; + value.data = (uint8_t *)dst; + return value; + +failed: + talloc_free(dst); + return value; +} + +/* check if the string contains quotes + * skips leading and trailing spaces + * - returns 0 if no quotes found + * - returns 1 if quotes are found and put their position + * in *quote_start and *quote_end parameters + * - return -1 if there are open quotes + */ + +static int get_quotes_position(const char *source, int *quote_start, int *quote_end) +{ + const char *p; + + if (source == NULL || quote_start == NULL || quote_end == NULL) return -1; + + p = source; + + /* check if there are quotes surrounding the value */ + p += strspn(p, " \n"); /* skip white spaces */ + + if (*p == '\"') { + *quote_start = p - source; + + p++; + while (*p != '\"') { + p = strchr(p, '\"'); + LDB_DN_NULL_FAILED(p); + + if (*(p - 1) == '\\') + p++; + } + + *quote_end = p - source; + return 1; + } + + return 0; + +failed: + return -1; +} + +static char *seek_to_separator(char *string, const char *separators) +{ + char *p, *q; + int ret, qs, qe, escaped; + + if (string == NULL || separators == NULL) return NULL; + + p = strchr(string, '='); + LDB_DN_NULL_FAILED(p); + + p++; + + /* check if there are quotes surrounding the value */ + + ret = get_quotes_position(p, &qs, &qe); + if (ret == -1) + return NULL; + + if (ret == 1) { /* quotes found */ + + p += qe; /* positioning after quotes */ + p += strspn(p, " \n"); /* skip white spaces after the quote */ + + if (strcspn(p, separators) != 0) /* if there are characters between quotes */ + return NULL; /* and separators, the dn is invalid */ + + return p; /* return on the separator */ + } + + /* no quotes found seek to separators */ + q = p; + do { + escaped = 0; + ret = strcspn(q, separators); + + if (q[ret - 1] == '\\') { + escaped = 1; + q = q + ret + 1; + } + } while (escaped); + + if (ret == 0 && p == q) /* no separators ?! bail out */ + return NULL; + + return q + ret; + +failed: + return NULL; +} + +static char *ldb_dn_trim_string(char *string, const char *edge) +{ + char *s, *p; + + /* seek out edge from start of string */ + s = string + strspn(string, edge); + + /* backwards skip from end of string */ + p = &s[strlen(s) - 1]; + while (p > s && strchr(edge, *p)) { + *p = '\0'; + p--; + } + + return s; +} + +/* we choosed to not support multpile valued components */ +static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw_component) +{ + struct ldb_dn_component dc; + char *p; + int ret, qs, qe; + + memset(&dc, 0, sizeof(dc)); + + if (raw_component == NULL) { + return dc; + } + + /* find attribute type/value separator */ + p = strchr(raw_component, '='); + LDB_DN_NULL_FAILED(p); + + *p++ = '\0'; /* terminate name and point to value */ + + /* copy and trim name in the component */ + dc.name = talloc_strdup(mem_ctx, ldb_dn_trim_string(raw_component, " \n")); + if (!dc.name) + return dc; + + if (! ldb_valid_attr_name(dc.name)) { + goto failed; + } + + ret = get_quotes_position(p, &qs, &qe); + + switch (ret) { + case 0: /* no quotes trim the string */ + p = ldb_dn_trim_string(p, " \n"); + dc.value = ldb_dn_unescape_value(mem_ctx, p); + break; + + case 1: /* quotes found get the unquoted string */ + p[qe] = '\0'; + p = p + qs + 1; + dc.value.length = strlen(p); + dc.value.data = talloc_memdup(mem_ctx, p, dc.value.length + 1); + break; + + default: /* mismatched quotes ot other error, bail out */ + goto failed; + } + + if (dc.value.length == 0) { + goto failed; + } + + return dc; + +failed: + talloc_free(dc.name); + dc.name = NULL; + return dc; +} + +struct ldb_dn *ldb_dn_new(void *mem_ctx) +{ + struct ldb_dn *edn; + + edn = talloc(mem_ctx, struct ldb_dn); + LDB_DN_NULL_FAILED(edn); + + /* Initially there are no components */ + edn->comp_num = 0; + edn->components = NULL; + + return edn; + +failed: + return NULL; +} + +struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn) +{ + struct ldb_dn *edn; /* the exploded dn */ + char *pdn, *p; + + if (dn == NULL) return NULL; + + /* Allocate a structure to hold the exploded DN */ + edn = ldb_dn_new(mem_ctx); + pdn = NULL; + + /* Empty DNs */ + if (dn[0] == '\0') { + return edn; + } + + /* Special DNs case */ + if (dn[0] == '@') { + edn->comp_num = 1; + edn->components = talloc(edn, struct ldb_dn_component); + if (edn->components == NULL) goto failed; + edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL); + if (edn->components[0].name == NULL) goto failed; + edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn); + if (edn->components[0].value.data== NULL) goto failed; + edn->components[0].value.length = strlen(dn); + return edn; + } + + pdn = p = talloc_strdup(edn, dn); + LDB_DN_NULL_FAILED(pdn); + + /* get the components */ + do { + char *t; + + /* terminate the current component and return pointer to the next one */ + t = seek_to_separator(p, ",;"); + LDB_DN_NULL_FAILED(t); + + if (*t) { /* here there is a separator */ + *t = '\0'; /*terminate */ + t++; /* a separtor means another component follows */ + } + + /* allocate space to hold the dn component */ + edn->components = talloc_realloc(edn, edn->components, + struct ldb_dn_component, + edn->comp_num + 1); + if (edn->components == NULL) + goto failed; + + /* store the exploded component in the main structure */ + edn->components[edn->comp_num] = ldb_dn_explode_component(edn, p); + LDB_DN_NULL_FAILED(edn->components[edn->comp_num].name); + + edn->comp_num++; + + /* jump to the next component if any */ + p = t; + + } while(*p); + + talloc_free(pdn); + return edn; + +failed: + talloc_free(pdn); + talloc_free(edn); + return NULL; +} + +struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn) +{ + struct ldb_dn *edn; /* the exploded dn */ + + if (dn == NULL) return NULL; + + if (strncasecmp(dn, "comp_num = 1; + edn->components = talloc(edn, struct ldb_dn_component); + if (edn->components == NULL) goto failed; + edn->components[0].name = talloc_strdup(edn->components, LDB_SPECIAL); + if (edn->components[0].name == NULL) goto failed; + edn->components[0].value.data = (uint8_t *)talloc_strdup(edn->components, dn); + if (edn->components[0].value.data== NULL) goto failed; + edn->components[0].value.length = strlen(dn); + return edn; + + } + + return ldb_dn_explode(mem_ctx, dn); + +failed: + talloc_free(edn); + return NULL; +} + +char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn) +{ + char *dn, *value; + int i; + + if (edn == NULL) return NULL; + + /* Special DNs */ + if (ldb_dn_is_special(edn)) { + dn = talloc_strdup(mem_ctx, (char *)edn->components[0].value.data); + return dn; + } + + dn = talloc_strdup(mem_ctx, ""); + LDB_DN_NULL_FAILED(dn); + + for (i = 0; i < edn->comp_num; i++) { + value = ldb_dn_escape_value(dn, edn->components[i].value); + LDB_DN_NULL_FAILED(value); + + if (i == 0) { + dn = talloc_asprintf_append(dn, "%s=%s", edn->components[i].name, value); + } else { + dn = talloc_asprintf_append(dn, ",%s=%s", edn->components[i].name, value); + } + LDB_DN_NULL_FAILED(dn); + + talloc_free(value); + } + + return dn; + +failed: + talloc_free(dn); + return NULL; +} + +/* Determine if dn is below base, in the ldap tree. Used for + * evaluating a subtree search. + * 0 if they match, otherwise non-zero + */ + +int ldb_dn_compare_base(struct ldb_context *ldb, + const struct ldb_dn *base, + const struct ldb_dn *dn) +{ + int ret; + int n0, n1; + + if (base == NULL || base->comp_num == 0) return 0; + if (dn == NULL || dn->comp_num == 0) return -1; + + /* if the base has more componts than the dn, then they differ */ + if (base->comp_num > dn->comp_num) { + return (dn->comp_num - base->comp_num); + } + + n0 = base->comp_num - 1; + n1 = dn->comp_num - 1; + while (n0 >= 0 && n1 >= 0) { + const struct ldb_attrib_handler *h; + + /* compare names (attribute names are guaranteed to be ASCII only) */ + ret = ldb_attr_cmp(base->components[n0].name, + dn->components[n1].name); + if (ret) { + return ret; + } + + /* names match, compare values */ + h = ldb_attrib_handler(ldb, base->components[n0].name); + ret = h->comparison_fn(ldb, ldb, &(base->components[n0].value), + &(dn->components[n1].value)); + if (ret) { + return ret; + } + n1--; + n0--; + } + + return 0; +} + +/* compare DNs using casefolding compare functions. + + If they match, then return 0 + */ + +int ldb_dn_compare(struct ldb_context *ldb, + const struct ldb_dn *edn0, + const struct ldb_dn *edn1) +{ + if (edn0 == NULL || edn1 == NULL) return edn1 - edn0; + + if (edn0->comp_num != edn1->comp_num) + return (edn1->comp_num - edn0->comp_num); + + return ldb_dn_compare_base(ldb, edn0, edn1); +} + +int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1) +{ + struct ldb_dn *edn0; + struct ldb_dn *edn1; + int ret; + + if (dn0 == NULL || dn1 == NULL) return dn1 - dn0; + + edn0 = ldb_dn_explode_casefold(ldb, dn0); + if (edn0 == NULL) return 1; + + edn1 = ldb_dn_explode_casefold(ldb, dn1); + if (edn1 == NULL) { + talloc_free(edn0); + return -1; + } + + ret = ldb_dn_compare(ldb, edn0, edn1); + + talloc_free(edn0); + talloc_free(edn1); + + return ret; +} + +/* + casefold a dn. We need to casefold the attribute names, and canonicalize + attribute values of case insensitive attributes. +*/ +struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +{ + struct ldb_dn *cedn; + int i; + + if (edn == NULL) return NULL; + + cedn = ldb_dn_new(ldb); + if (!cedn) { + return NULL; + } + + cedn->comp_num = edn->comp_num; + cedn->components = talloc_array(cedn, struct ldb_dn_component, edn->comp_num); + if (!cedn->components) { + talloc_free(cedn); + return NULL; + } + + for (i = 0; i < edn->comp_num; i++) { + struct ldb_dn_component dc; + const struct ldb_attrib_handler *h; + + dc.name = ldb_attr_casefold(cedn, edn->components[i].name); + if (!dc.name) { + talloc_free(cedn); + return NULL; + } + + h = ldb_attrib_handler(ldb, dc.name); + if (h->canonicalise_fn(ldb, cedn, &(edn->components[i].value), &(dc.value)) != 0) { + talloc_free(cedn); + return NULL; + } + + cedn->components[i] = dc; + } + + return cedn; +} + +struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn) +{ + struct ldb_dn *edn, *cdn; + + if (dn == NULL) return NULL; + + edn = ldb_dn_explode(ldb, dn); + if (edn == NULL) return NULL; + + cdn = ldb_dn_casefold(ldb, edn); + + talloc_free(edn); + return cdn; +} + +char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +{ + struct ldb_dn *cdn; + char *dn; + + if (edn == NULL) return NULL; + + /* Special DNs */ + if (ldb_dn_is_special(edn)) { + dn = talloc_strdup(ldb, (char *)edn->components[0].value.data); + return dn; + } + + cdn = ldb_dn_casefold(ldb, edn); + if (cdn == NULL) return NULL; + + dn = ldb_dn_linearize(ldb, cdn); + if (dn == NULL) { + talloc_free(cdn); + return NULL; + } + + talloc_free(cdn); + return dn; +} + +static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) +{ + struct ldb_dn_component dst; + + memset(&dst, 0, sizeof(dst)); + + if (src == NULL) { + return dst; + } + + dst.value = ldb_val_dup(mem_ctx, &(src->value)); + if (dst.value.data == NULL) { + return dst; + } + + dst.name = talloc_strdup(mem_ctx, src->name); + if (dst.name == NULL) { + talloc_free(dst.value.data); + } + + return dst; +} + +/* copy specified number of elements of a dn into a new one + element are copied from top level up to the unique rdn + num_el may be greater than dn->comp_num (see ldb_dn_make_child) +*/ +struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el) +{ + struct ldb_dn *newdn; + int i, n, e; + + if (dn == NULL) return NULL; + if (num_el <= 0) return NULL; + + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = num_el; + n = newdn->comp_num - 1; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + + if (dn->comp_num == 0) return newdn; + e = dn->comp_num - 1; + + for (i = 0; i < newdn->comp_num; i++) { + newdn->components[n - i] = ldb_dn_copy_component(newdn->components, + &(dn->components[e - i])); + if ((e - i) == 0) { + return newdn; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn) +{ + if (dn == NULL) return NULL; + return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num); +} + +struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn) +{ + if (dn == NULL) return NULL; + return ldb_dn_copy_partial(mem_ctx, dn, dn->comp_num - 1); +} + +struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr, + const char *val) +{ + struct ldb_dn_component *dc; + + if (attr == NULL || val == NULL) return NULL; + + dc = talloc(mem_ctx, struct ldb_dn_component); + if (dc == NULL) return NULL; + + dc->name = talloc_strdup(dc, attr); + if (dc->name == NULL) { + talloc_free(dc); + return NULL; + } + + dc->value.data = (uint8_t *)talloc_strdup(dc, val); + if (dc->value.data == NULL) { + talloc_free(dc); + return NULL; + } + + dc->value.length = strlen(val); + + return dc; +} + +struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, + const char * value, + const struct ldb_dn *base) +{ + struct ldb_dn *newdn; + if (! ldb_valid_attr_name(attr)) return NULL; + if (value == NULL || value == '\0') return NULL; + + if (base != NULL) { + newdn = ldb_dn_copy_partial(mem_ctx, base, base->comp_num + 1); + LDB_DN_NULL_FAILED(newdn); + } else { + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = 1; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + } + + newdn->components[0].name = talloc_strdup(newdn->components, attr); + LDB_DN_NULL_FAILED(newdn->components[0].name); + + newdn->components[0].value.data = (uint8_t *)talloc_strdup(newdn->components, value); + LDB_DN_NULL_FAILED(newdn->components[0].value.data); + newdn->components[0].value.length = strlen((char *)newdn->components[0].value.data); + + return newdn; + +failed: + talloc_free(newdn); + return NULL; + +} + +struct ldb_dn *ldb_dn_make_child(void *mem_ctx, const struct ldb_dn_component *component, + const struct ldb_dn *base) +{ + if (component == NULL) return NULL; + + return ldb_dn_build_child(mem_ctx, component->name, + (char *)component->value.data, base); +} + +struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2) +{ + int i; + struct ldb_dn *newdn; + + if (dn2 == NULL && dn1 == NULL) { + return NULL; + } + + if (dn2 == NULL) { + newdn = ldb_dn_new(mem_ctx); + LDB_DN_NULL_FAILED(newdn); + + newdn->comp_num = dn1->comp_num; + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + } else { + int comp_num = dn2->comp_num; + if (dn1 != NULL) comp_num += dn1->comp_num; + newdn = ldb_dn_copy_partial(mem_ctx, dn2, comp_num); + } + + if (dn1 == NULL) { + return newdn; + } + + for (i = 0; i < dn1->comp_num; i++) { + newdn->components[i] = ldb_dn_copy_component(newdn->components, + &(dn1->components[i])); + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) +{ + struct ldb_dn *dn; + char *child_str; + va_list ap; + + if (child_fmt == NULL) return NULL; + + va_start(ap, child_fmt); + child_str = talloc_vasprintf(mem_ctx, child_fmt, ap); + va_end(ap); + + if (child_str == NULL) return NULL; + + dn = ldb_dn_compose(mem_ctx, ldb_dn_explode(mem_ctx, child_str), base); + + talloc_free(child_str); + + return dn; +} + +struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn) +{ + struct ldb_dn_component *rdn; + + if (dn == NULL) return NULL; + + if (dn->comp_num < 1) { + return NULL; + } + + rdn = talloc(mem_ctx, struct ldb_dn_component); + if (rdn == NULL) return NULL; + + *rdn = ldb_dn_copy_component(mem_ctx, &dn->components[0]); + if (rdn->name == NULL) { + talloc_free(rdn); + return NULL; + } + + return rdn; +} + +/* Create a 'canonical name' string from a DN: + + ie dc=samba,dc=org -> samba.org/ + uid=administrator,ou=users,dc=samba,dc=org = samba.org/users/administrator + + There are two formats, the EX format has the last / replaced with a newline (\n). + +*/ +static char *ldb_dn_canonical(void *mem_ctx, const struct ldb_dn *dn, int ex_format) { + int i; + char *cracked = NULL; + + /* Walk backwards down the DN, grabbing 'dc' components at first */ + for (i = dn->comp_num - 1 ; i >= 0; i--) { + if (ldb_attr_cmp(dn->components[i].name, "dc") != 0) { + break; + } + if (cracked) { + cracked = talloc_asprintf(mem_ctx, "%s.%s", + ldb_dn_escape_value(mem_ctx, dn->components[i].value), + cracked); + } else { + cracked = ldb_dn_escape_value(mem_ctx, dn->components[i].value); + } + if (!cracked) { + return NULL; + } + } + + /* Only domain components? Finish here */ + if (i < 0) { + if (ex_format) { + cracked = talloc_asprintf(mem_ctx, "%s\n", cracked); + } else { + cracked = talloc_asprintf(mem_ctx, "%s/", cracked); + } + return cracked; + } + + /* Now walk backwards appending remaining components */ + for (; i > 0; i--) { + cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + if (!cracked) { + return NULL; + } + } + + /* Last one, possibly a newline for the 'ex' format */ + if (ex_format) { + cracked = talloc_asprintf(mem_ctx, "%s\n%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + } else { + cracked = talloc_asprintf(mem_ctx, "%s/%s", cracked, + ldb_dn_escape_value(mem_ctx, dn->components[i].value)); + } + return cracked; +} + +/* Wrapper functions for the above, for the two different string formats */ +char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 0); + +} + +char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn) { + return ldb_dn_canonical(mem_ctx, dn, 1); +} diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c new file mode 100644 index 0000000000..c5084aaa6c --- /dev/null +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -0,0 +1,748 @@ +/* + 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 = 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> (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 (;idata; + + if (val->length == 0) { + return 0; + } + + if (p[0] == ' ' || p[0] == ':') { + return 1; + } + + for (i=0; ilength; 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;imsg; + + ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_linearize(msg->dn, 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); + return -1; + } + ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name); + CHECK_RET; + } + + for (i=0;inum_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;jelements[i].num_values;j++) { + struct ldb_val v; + ret = h->ldif_write_fn(ldb, ldb, &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; + } + + 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_explode(msg, (char *)value.data); + + if (msg->dn == NULL) { + 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) != 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 = 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 = 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 = 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); +} diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c new file mode 100644 index 0000000000..64e52d285d --- /dev/null +++ b/source3/lib/ldb/common/ldb_match.c @@ -0,0 +1,431 @@ +/* + 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, + const struct ldb_dn *base, + const 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(ldb, base, dn) == 0) { + ret = 1; + } + break; + + case LDB_SCOPE_ONELEVEL: + if (dn->comp_num == (base->comp_num + 1)) { + if (ldb_dn_compare_base(ldb, base, dn) == 0) { + ret = 1; + } + } + break; + + case LDB_SCOPE_SUBTREE: + default: + if (ldb_dn_compare_base(ldb, 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_explode_casefold(ldb, + (char *)tree->u.equality.value.data); + if (valuedn == NULL) { + return 0; + } + + ret = ldb_dn_compare(ldb, 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;inum_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;iu.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;inum_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;iu.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;iu.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, + const 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); +} diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c new file mode 100644 index 0000000000..06a8a4bcf6 --- /dev/null +++ b/source3/lib/ldb/common/ldb_modules.c @@ -0,0 +1,442 @@ + +/* + 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 *talloc_strdup_no_spaces(struct ldb_context *ldb, const char *string) +{ + int i, len; + char *trimmed; + + trimmed = talloc_strdup(ldb, string); + if (!trimmed) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in talloc_strdup_trim_spaces()\n"); + 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 = talloc_strdup_no_spaces(mem_ctx, string); + if ( ! modstr) { + 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_LDAP +#define LDAP_INIT ldb_ldap_init, +#else +#define LDAP_INIT +#endif + +#ifdef HAVE_SQLITE3 +#define SQLITE3_INIT ldb_sqlite3_init, +#else +#define SQLITE3_INIT +#endif + +#define STATIC_ldb_MODULES \ + { \ + LDAP_INIT \ + SQLITE3_INIT \ + ldb_tdb_init, \ + ldb_schema_init, \ + ldb_operational_init, \ + ldb_rdn_name_init, \ + ldb_objectclass_init, \ + ldb_paged_results_init, \ + ldb_sort_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); + +#ifdef HAVE_DLOPEN +#ifdef _SAMBA_BUILD_ + path = talloc_asprintf(ldb, "%s/ldb/%s.%s", dyn_MODULESDIR, name, dyn_SHLIBEXT); +#else + path = talloc_asprintf(ldb, "%s/%s.%s", MODULESDIR, name, SHLIBEXT); +#endif + + ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path); + + handle = dlopen(path, 0); + 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; + } + + 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_explode(mem_ctx, "@MODULES"); + if (mods_dn == NULL) { + talloc_free(mem_ctx); + return -1; + } + + ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res); + if (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); +} diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c new file mode 100644 index 0000000000..52c6b82484 --- /dev/null +++ b/source3/lib/ldb/common/ldb_msg.c @@ -0,0 +1,802 @@ +/* + 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;inum_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;inum_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 *els; + + 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++; + + 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) != 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 *el; + struct ldb_val *vals; + + el = ldb_msg_find_element(msg, attr_name); + if (!el) { + ldb_msg_add_empty(msg, attr_name, 0); + el = ldb_msg_find_element(msg, attr_name); + } + if (!el) { + return LDB_ERR_OPERATIONS_ERROR; + } + + 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++; + + 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; + ret = ldb_msg_add_value(msg, attr_name, val); + if (ret == LDB_SUCCESS) { + struct ldb_message_element *el; + el = ldb_msg_find_element(msg, attr_name); + 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); + + return ldb_msg_add_value(msg, attr_name, &val); +} + +/* + 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;inum_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(void *mem_ctx, + const struct ldb_message *msg, + const char *attr_name) +{ + const struct ldb_val *v; + + v = ldb_msg_find_ldb_val(msg, attr_name); + if (!v || !v->data) { + return NULL; + } + return ldb_dn_explode(mem_ctx, (const char *)v->data); +} + +/* + 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;inum_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;inum_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;jnum_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;inum_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+1num_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;inum_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;inum_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) != 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; + } + if (msg->dn->comp_num == 0) { + /* root dse has empty dn */ + ldb_set_errstring(ldb, "DN on new ldb message is '' (not permitted)!"); + return LDB_ERR_ENTRY_ALREADY_EXISTS; + } + + /* 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_linearize(mem_ctx, 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) +*/ +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--; + } +} + +/* + return a LDAP formatted time string +*/ +char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t) +{ + struct tm *tm = gmtime(&t); + + if (!tm) { + return NULL; + } + + /* formatted like: 20040408072012.0Z */ + return talloc_asprintf(mem_ctx, + "%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); +} + + +/* + 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(value); + val.length = strlen(value); + + if (ldb_msg_find_val(el, &val)) + return 1; + + return 0; +} diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c new file mode 100644 index 0000000000..d9044a8b0c --- /dev/null +++ b/source3/lib/ldb/common/ldb_parse.c @@ -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: + ::= '(' ')' + ::= | | | + ::= '&' + ::= '|' + ::= '!' + ::= | + ::= + ::= '=' | '~=' | '<=' | '>=' +*/ + +/* + 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 = talloc_size(mem_ctx, slen+1); + ret.length = 0; + if (ret.data == NULL) return ret; + + for (i=j=0;idata == 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 = 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 = 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; +} + +/* + ::= +*/ +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 + ::= '&' + ::= '|' + ::= | +*/ +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; +} + + +/* + ::= '!' +*/ +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 + ::= | | | +*/ +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; +} + + +/* + ::= '(' ')' +*/ +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 ::= | +*/ +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;iu.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;iu.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; + } +} diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c new file mode 100644 index 0000000000..d2d12b8f51 --- /dev/null +++ b/source3/lib/ldb/common/ldb_utf8.c @@ -0,0 +1,149 @@ +/* + 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; +} + +/* + compare two attribute names + attribute names are restricted by rfc2251 so using + strcasecmp and toupper here is ok. + return 0 for match +*/ +int ldb_attr_cmp(const char *attr1, const char *attr2) +{ + return strcasecmp(attr1, attr2); +} + +char *ldb_attr_casefold(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; +} + +/* + we accept either 'dn' or 'distinguishedName' for a distinguishedName +*/ +int ldb_attr_dn(const char *attr) +{ + if (ldb_attr_cmp(attr, "dn") == 0 || + ldb_attr_cmp(attr, "distinguishedName") == 0) { + return 0; + } + return -1; +} diff --git a/source3/lib/ldb/common/qsort.c b/source3/lib/ldb/common/qsort.c new file mode 100644 index 0000000000..ef7be2c14e --- /dev/null +++ b/source3/lib/ldb/common/qsort.c @@ -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 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; + } + } + } + } +} diff --git a/source3/lib/ldb/config.guess b/source3/lib/ldb/config.guess new file mode 100755 index 0000000000..ad5281e66e --- /dev/null +++ b/source3/lib/ldb/config.guess @@ -0,0 +1,1466 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/source3/lib/ldb/config.mk b/source3/lib/ldb/config.mk new file mode 100644 index 0000000000..6a23005b8f --- /dev/null +++ b/source3/lib/ldb/config.mk @@ -0,0 +1,323 @@ +################################################ +# 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_schema +# [MODULE::ldb_schema] +# INIT_FUNCTION = ldb_schema_init +# SUBSYSTEM = ldb +# OBJ_FILES = \ +# modules/schema.o +# # End MODULE ldb_schema +# ################################################ + +################################################ +# 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 +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 +PUBLIC_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 LIBSAMBA-UTIL LIBPOPT POPT_SAMBA POPT_CREDENTIALS +PRIVATE_DEPENDENCIES = 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 +####################### diff --git a/source3/lib/ldb/config.sub b/source3/lib/ldb/config.sub new file mode 100755 index 0000000000..1c366dfde9 --- /dev/null +++ b/source3/lib/ldb/config.sub @@ -0,0 +1,1579 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/source3/lib/ldb/configure.ac b/source3/lib/ldb/configure.ac new file mode 100644 index 0000000000..70a4100451 --- /dev/null +++ b/source3/lib/ldb/configure.ac @@ -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_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_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) diff --git a/source3/lib/ldb/docs/builddocs.sh b/source3/lib/ldb/docs/builddocs.sh new file mode 100755 index 0000000000..449dcb2681 --- /dev/null +++ b/source3/lib/ldb/docs/builddocs.sh @@ -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 diff --git a/source3/lib/ldb/docs/design.txt b/source3/lib/ldb/docs/design.txt new file mode 100644 index 0000000000..0bb278b5b4 --- /dev/null +++ b/source3/lib/ldb/docs/design.txt @@ -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 diff --git a/source3/lib/ldb/docs/installdocs.sh b/source3/lib/ldb/docs/installdocs.sh new file mode 100755 index 0000000000..6cc7b74ad5 --- /dev/null +++ b/source3/lib/ldb/docs/installdocs.sh @@ -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 diff --git a/source3/lib/ldb/examples.dox b/source3/lib/ldb/examples.dox new file mode 100644 index 0000000000..ef4b4f0a40 --- /dev/null +++ b/source3/lib/ldb/examples.dox @@ -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. + +*/ diff --git a/source3/lib/ldb/examples/ldbreader.c b/source3/lib/ldb/examples/ldbreader.c new file mode 100644 index 0000000000..207c6c3d42 --- /dev/null +++ b/source3/lib/ldb/examples/ldbreader.c @@ -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; +} diff --git a/source3/lib/ldb/examples/ldifreader.c b/source3/lib/ldb/examples/ldifreader.c new file mode 100644 index 0000000000..3b8591e73f --- /dev/null +++ b/source3/lib/ldb/examples/ldifreader.c @@ -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; +} diff --git a/source3/lib/ldb/include/dlinklist.h b/source3/lib/ldb/include/dlinklist.h new file mode 100644 index 0000000000..3779a4cc61 --- /dev/null +++ b/source3/lib/ldb/include/dlinklist.h @@ -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) diff --git a/source3/lib/ldb/include/includes.h b/source3/lib/ldb/include/includes.h new file mode 100644 index 0000000000..ce0d40e101 --- /dev/null +++ b/source3/lib/ldb/include/includes.h @@ -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_*/ diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h new file mode 100644 index 0000000000..cf4a1f282b --- /dev/null +++ b/source3/lib/ldb/include/ldb.h @@ -0,0 +1,1407 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2004 + 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 for base ldb API + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + */ + +/** + \file ldb.h Samba's ldb database + + This header file provides the main API for ldb. +*/ + +#ifndef _LDB_H_ + +/*! \cond DOXYGEN_IGNORE */ +#define _LDB_H_ 1 +/*! \endcond */ + +/* + major restrictions as compared to normal LDAP: + + - no async calls. + - each record must have a unique key field + - the key must be representable as a NULL terminated C string and may not + contain a comma or braces + + major restrictions as compared to tdb: + + - no explicit locking calls + UPDATE: we have transactions now, better than locking --SSS. + +*/ + +#ifndef ldb_val +/** + Result value + + An individual lump of data in a result comes in this format. The + pointer will usually be to a UTF-8 string if the application is + sensible, but it can be to anything you like, including binary data + blobs of arbitrary size. + + \note the data is null (0x00) terminated, but the length does not + include the terminator. +*/ +struct ldb_val { + uint8_t *data; /*!< result data */ + size_t length; /*!< length of data */ +}; +#endif + +/*! \cond DOXYGEN_IGNORE */ +#ifndef PRINTF_ATTRIBUTE +#define PRINTF_ATTRIBUTE(a,b) +#endif +/*! \endcond */ + +/** + internal ldb exploded dn structures +*/ +struct ldb_dn_component { + char *name; + struct ldb_val value; +}; + +struct ldb_dn { + int comp_num; + struct ldb_dn_component *components; +}; + +/** + There are a number of flags that are used with ldap_modify() in + ldb_message_element.flags fields. The LDA_FLAGS_MOD_ADD, + LDA_FLAGS_MOD_DELETE and LDA_FLAGS_MOD_REPLACE flags are used in + ldap_modify() calls to specify whether attributes are being added, + deleted or modified respectively. +*/ +#define LDB_FLAG_MOD_MASK 0x3 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being added. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_ADD 1 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being replaced. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_REPLACE 2 + +/** + Flag value used in ldap_modify() to indicate that attributes are + being deleted. + + \sa LDB_FLAG_MOD_MASK +*/ +#define LDB_FLAG_MOD_DELETE 3 + +/** + OID for logic AND comaprison. + + This is the well known object ID for a logical AND comparitor. +*/ +#define LDB_OID_COMPARATOR_AND "1.2.840.113556.1.4.803" + +/** + OID for logic OR comparison. + + This is the well known object ID for a logical OR comparitor. +*/ +#define LDB_OID_COMPARATOR_OR "1.2.840.113556.1.4.804" + +/** + results are given back as arrays of ldb_message_element +*/ +struct ldb_message_element { + unsigned int flags; + const char *name; + unsigned int num_values; + struct ldb_val *values; +}; + + +/** + a ldb_message represents all or part of a record. It can contain an arbitrary + number of elements. +*/ +struct ldb_message { + struct ldb_dn *dn; + unsigned int num_elements; + struct ldb_message_element *elements; + void *private_data; /* private to the backend */ +}; + +enum ldb_changetype { + LDB_CHANGETYPE_NONE=0, + LDB_CHANGETYPE_ADD, + LDB_CHANGETYPE_DELETE, + LDB_CHANGETYPE_MODIFY +}; + +/** + LDIF record + + This structure contains a LDIF record, as returned from ldif_read() + and equivalent functions. +*/ +struct ldb_ldif { + enum ldb_changetype changetype; /*!< The type of change */ + struct ldb_message *msg; /*!< The changes */ +}; + +enum ldb_scope {LDB_SCOPE_DEFAULT=-1, + LDB_SCOPE_BASE=0, + LDB_SCOPE_ONELEVEL=1, + LDB_SCOPE_SUBTREE=2}; + +struct ldb_context; + +/* + the fuction type for the callback used in traversing the database +*/ +typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *); + + +/* debugging uses one of the following levels */ +enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, + LDB_DEBUG_WARNING, LDB_DEBUG_TRACE}; + +/** + the user can optionally supply a debug function. The function + is based on the vfprintf() style of interface, but with the addition + of a severity level +*/ +struct ldb_debug_ops { + void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + void *context; +}; + +/** + The user can optionally supply a custom utf8 functions, + to handle comparisons and casefolding. +*/ +struct ldb_utf8_fns { + void *context; + char *(*casefold)(void *context, void *mem_ctx, const char *s); +}; + +/** + Flag value for database connection mode. + + If LDB_FLG_RDONLY is used in ldb_connect, then the database will be + opened read-only, if possible. +*/ +#define LDB_FLG_RDONLY 1 + +/** + Flag value for database connection mode. + + If LDB_FLG_NOSYNC is used in ldb_connect, then the database will be + opened without synchronous operations, if possible. +*/ +#define LDB_FLG_NOSYNC 2 + +/** + Flag value to specify autoreconnect mode. + + If LDB_FLG_RECONNECT is used in ldb_connect, then the backend will + be opened in a way that makes it try to auto reconnect if the + connection is dropped (actually make sense only with ldap). +*/ +#define LDB_FLG_RECONNECT 4 + +/* + structures for ldb_parse_tree handling code +*/ +enum ldb_parse_op { LDB_OP_AND=1, LDB_OP_OR=2, LDB_OP_NOT=3, + LDB_OP_EQUALITY=4, LDB_OP_SUBSTRING=5, + LDB_OP_GREATER=6, LDB_OP_LESS=7, LDB_OP_PRESENT=8, + LDB_OP_APPROX=9, LDB_OP_EXTENDED=10 }; + +struct ldb_parse_tree { + enum ldb_parse_op operation; + union { + struct { + struct ldb_parse_tree *child; + } isnot; + struct { + const char *attr; + struct ldb_val value; + } equality; + struct { + const char *attr; + int start_with_wildcard; + int end_with_wildcard; + struct ldb_val **chunks; + } substring; + struct { + const char *attr; + } present; + struct { + const char *attr; + struct ldb_val value; + } comparison; + struct { + const char *attr; + int dnAttributes; + char *rule_id; + struct ldb_val value; + } extended; + struct { + unsigned int num_elements; + struct ldb_parse_tree **elements; + } list; + } u; +}; + +struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s); +char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree); + +/** + Encode a binary blob + + This function encodes a binary blob using the encoding rules in RFC + 2254 (Section 4). This function also escapes any non-printable + characters. + + \param ctx the memory context to allocate the return string in. + \param val the (potentially) binary data to be encoded + + \return the encoded data as a null terminated string + + \sa RFC 2252. +*/ +char *ldb_binary_encode(void *ctx, struct ldb_val val); + +/** + Encode a string + + This function encodes a string using the encoding rules in RFC 2254 + (Section 4). This function also escapes any non-printable + characters. + + \param mem_ctx the memory context to allocate the return string in. + \param string the string to be encoded + + \return the encoded data as a null terminated string + + \sa RFC 2252. +*/ +char *ldb_binary_encode_string(void *mem_ctx, const char *string); + +/* + functions for controlling attribute handling +*/ +typedef int (*ldb_attr_handler_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, struct ldb_val *); +typedef int (*ldb_attr_comparison_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, const struct ldb_val *); + +struct ldb_attrib_handler { + const char *attr; + + /* LDB_ATTR_FLAG_* */ + unsigned flags; + + /* convert from ldif to binary format */ + ldb_attr_handler_t ldif_read_fn; + + /* convert from binary to ldif format */ + ldb_attr_handler_t ldif_write_fn; + + /* canonicalise a value, for use by indexing and dn construction */ + ldb_attr_handler_t canonicalise_fn; + + /* compare two values */ + ldb_attr_comparison_t comparison_fn; +}; + +/** + The attribute is not returned by default +*/ +#define LDB_ATTR_FLAG_HIDDEN (1<<0) + +/** + The attribute is constructed from other attributes +*/ +#define LDB_ATTR_FLAG_CONSTRUCTED (1<<1) + +/** + LDAP attribute syntax for a DN + + This is the well-known LDAP attribute syntax for a DN. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_DN "1.3.6.1.4.1.1466.115.121.1.12" + +/** + LDAP attribute syntax for a Directory String + + This is the well-known LDAP attribute syntax for a Directory String. + + \sa RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_DIRECTORY_STRING "1.3.6.1.4.1.1466.115.121.1.15" + +/** + LDAP attribute syntax for an integer + + This is the well-known LDAP attribute syntax for an integer. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_INTEGER "1.3.6.1.4.1.1466.115.121.1.27" + +/** + LDAP attribute syntax for an octet string + + This is the well-known LDAP attribute syntax for an octet string. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_OCTET_STRING "1.3.6.1.4.1.1466.115.121.1.40" + +/** + LDAP attribute syntax for UTC time. + + This is the well-known LDAP attribute syntax for a UTC time. + + See RFC 2252, Section 4.3.2 +*/ +#define LDB_SYNTAX_UTC_TIME "1.3.6.1.4.1.1466.115.121.1.53" + +#define LDB_SYNTAX_OBJECTCLASS "LDB_SYNTAX_OBJECTCLASS" + +/* sorting helpers */ +typedef int (*ldb_qsort_cmp_fn_t) (void *v1, void *v2, void *opaque); + +/** + OID for the paged results control. This control is included in the + searchRequest and searchResultDone messages as part of the controls + field of the LDAPMessage, as defined in Section 4.1.12 of + LDAP v3. + + \sa RFC 2696. +*/ +#define LDB_CONTROL_PAGED_RESULTS_OID "1.2.840.113556.1.4.319" + +/** + OID for specifying the returned elements of the ntSecurityDescriptor + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SD_FLAGS_OID "1.2.840.113556.1.4.801" + +/** + OID for specifying an advanced scope for the search (one partition) + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_DOMAIN_SCOPE_OID "1.2.840.113556.1.4.1339" + +/** + OID for specifying an advanced scope for a search + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SEARCH_OPTIONS_OID "1.2.840.113556.1.4.1340" + +/** + OID for notification + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_NOTIFICATION_OID "1.2.840.113556.1.4.528" + +/** + OID for getting deleted objects + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_SHOW_DELETED_OID "1.2.840.113556.1.4.417" + +/** + OID for extended DN + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_EXTENDED_DN_OID "1.2.840.113556.1.4.529" + +/** + OID for LDAP server sort result extension. + + This control is included in the searchRequest message as part of + the controls field of the LDAPMessage, as defined in Section 4.1.12 + of LDAP v3. The controlType is set to + "1.2.840.113556.1.4.473". The criticality MAY be either TRUE or + FALSE (where absent is also equivalent to FALSE) at the client's + option. + + \sa RFC 2891. +*/ +#define LDB_CONTROL_SERVER_SORT_OID "1.2.840.113556.1.4.473" + +/** + OID for LDAP server sort result response extension. + + This control is included in the searchResultDone message as part of + the controls field of the LDAPMessage, as defined in Section 4.1.12 of + LDAP v3. + + \sa RFC 2891. +*/ +#define LDB_CONTROL_SORT_RESP_OID "1.2.840.113556.1.4.474" + +/** + OID for LDAP Attribute Scoped Query extension. + + This control is included in SearchRequest or SearchResponse + messages as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_ASQ_OID "1.2.840.113556.1.4.1504" + +/** + OID for LDAP Directory Sync extension. + + This control is included in SearchRequest or SearchResponse + messages as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_DIRSYNC_OID "1.2.840.113556.1.4.841" + + +/** + OID for LDAP Virtual List View Request extension. + + This control is included in SearchRequest messages + as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_VLV_REQ_OID "2.16.840.1.113730.3.4.9" + +/** + OID for LDAP Virtual List View Response extension. + + This control is included in SearchResponse messages + as part of the controls field of the LDAPMessage. +*/ +#define LDB_CONTROL_VLV_RESP_OID "2.16.840.1.113730.3.4.10" + +/** + OID to let modifies don't give an error when adding an existing + attribute with the same value or deleting an nonexisting one attribute + + \sa Microsoft documentation of this OID +*/ +#define LDB_CONTROL_PERMISSIVE_MODIFY_OID "1.2.840.113556.1.4.1413" + +/** + OID for LDAP Extended Operation START_TLS. + + This Extended operation is used to start a new TLS + channel on top of a clear text channel. +*/ +#define LDB_EXTENDED_START_TLS_OID "1.3.6.1.4.1.1466.20037" + +/** + OID for LDAP Extended Operation START_TLS. + + This Extended operation is used to start a new TLS + channel on top of a clear text channel. +*/ +#define LDB_EXTENDED_DYNAMIC_OID "1.3.6.1.4.1.1466.101.119.1" + +/** + OID for LDAP Extended Operation START_TLS. + + This Extended operation is used to start a new TLS + channel on top of a clear text channel. +*/ +#define LDB_EXTENDED_FAST_BIND_OID "1.2.840.113556.1.4.1781" + +struct ldb_sd_flags_control { + /* + * request the owner 0x00000001 + * request the group 0x00000002 + * request the DACL 0x00000004 + * request the SACL 0x00000008 + */ + unsigned secinfo_flags; +}; + +struct ldb_search_options_control { + /* + * DOMAIN_SCOPE 0x00000001 + * this limits the search to one partition, + * and no referrals will be returned. + * (Note this doesn't limit the entries by there + * objectSid belonging to a domain! Builtin and Foreign Sids + * are still returned) + * + * PHANTOM_ROOT 0x00000002 + * this search on the whole tree on a domain controller + * over multiple partitions without referrals. + * (This is the default behavior on the Global Catalog Port) + */ + unsigned search_options; +}; + +struct ldb_paged_control { + int size; + int cookie_len; + char *cookie; +}; + +struct ldb_extended_dn_control { + int type; +}; + +struct ldb_server_sort_control { + char *attributeName; + char *orderingRule; + int reverse; +}; + +struct ldb_sort_resp_control { + int result; + char *attr_desc; +}; + +struct ldb_asq_control { + int request; + char *source_attribute; + int src_attr_len; + int result; +}; + +struct ldb_dirsync_control { + int flags; + int max_attributes; + int cookie_len; + char *cookie; +}; + +struct ldb_vlv_req_control { + int beforeCount; + int afterCount; + int type; + union { + struct { + int offset; + int contentCount; + } byOffset; + struct { + int value_len; + char *value; + } gtOrEq; + } match; + int ctxid_len; + char *contextId; +}; + +struct ldb_vlv_resp_control { + int targetPosition; + int contentCount; + int vlv_result; + int ctxid_len; + char *contextId; +}; + +struct ldb_control { + const char *oid; + int critical; + void *data; +}; + +enum ldb_request_type { + LDB_SEARCH, + LDB_ADD, + LDB_MODIFY, + LDB_DELETE, + LDB_RENAME, + LDB_EXTENDED, + LDB_REQ_REGISTER_CONTROL, + LDB_REQ_REGISTER_PARTITION, + LDB_SEQUENCE_NUMBER +}; + +enum ldb_reply_type { + LDB_REPLY_ENTRY, + LDB_REPLY_REFERRAL, + LDB_REPLY_EXTENDED, + LDB_REPLY_DONE +}; + +enum ldb_wait_type { + LDB_WAIT_ALL, + LDB_WAIT_NONE +}; + +enum ldb_state { + LDB_ASYNC_INIT, + LDB_ASYNC_PENDING, + LDB_ASYNC_DONE +}; + +struct ldb_result { + unsigned int count; + struct ldb_message **msgs; + char **refs; + struct ldb_control **controls; +}; + +struct ldb_extended { + const char *oid; + const char *value; + int value_len; +}; + +struct ldb_reply { + enum ldb_reply_type type; + struct ldb_message *message; + struct ldb_extended *response; + char *referral; + struct ldb_control **controls; +}; + +struct ldb_handle { + int status; + enum ldb_state state; + void *private_data; + struct ldb_module *module; +}; + +struct ldb_search { + const struct ldb_dn *base; + enum ldb_scope scope; + const struct ldb_parse_tree *tree; + const char * const *attrs; + struct ldb_result *res; +}; + +struct ldb_add { + const struct ldb_message *message; +}; + +struct ldb_modify { + const struct ldb_message *message; +}; + +struct ldb_delete { + const struct ldb_dn *dn; +}; + +struct ldb_rename { + const struct ldb_dn *olddn; + const struct ldb_dn *newdn; +}; + +struct ldb_register_control { + const char *oid; +}; + +struct ldb_register_partition { + const struct ldb_dn *dn; +}; + +struct ldb_sequence_number { + enum ldb_sequence_type { + LDB_SEQ_HIGHEST_SEQ, + LDB_SEQ_HIGHEST_TIMESTAMP, + LDB_SEQ_NEXT + } type; + uint64_t seq_num; + uint32_t flags; +}; + +typedef int (*ldb_request_callback_t)(struct ldb_context *, void *, struct ldb_reply *); +struct ldb_request { + + enum ldb_request_type operation; + + union { + struct ldb_search search; + struct ldb_add add; + struct ldb_modify mod; + struct ldb_delete del; + struct ldb_rename rename; + struct ldb_register_control reg_control; + struct ldb_register_partition reg_partition; + struct ldb_sequence_number seq_num; + } op; + + struct ldb_control **controls; + + void *context; + ldb_request_callback_t callback; + + int timeout; + time_t starttime; + struct ldb_handle *handle; +}; + +int ldb_request(struct ldb_context *ldb, struct ldb_request *request); + +int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type); + +int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout); +int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq); + +/** + Initialise ldbs' global information + + This is required before any other LDB call + + \return 0 if initialisation succeeded, -1 otherwise +*/ +int ldb_global_init(void); + +/** + Initialise an ldb context + + This is required before any other LDB call. + + \param mem_ctx pointer to a talloc memory context. Pass NULL if there is + no suitable context available. + + \return pointer to ldb_context that should be free'd (using talloc_free()) + at the end of the program. +*/ +struct ldb_context *ldb_init(void *mem_ctx); + +/** + Connect to a database. + + This is typically called soon after ldb_init(), and is required prior to + any search or database modification operations. + + The URL can be one of the following forms: + - tdb://path + - ldapi://path + - ldap://host + - sqlite://path + + \param ldb the context associated with the database (from ldb_init()) + \param url the URL of the database to connect to, as noted above + \param flags a combination of LDB_FLG_* to modify the connection behaviour + \param options backend specific options - passed uninterpreted to the backend + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note It is an error to connect to a database that does not exist in readonly mode + (that is, with LDB_FLG_RDONLY). However in read-write mode, the database will be + created if it does not exist. +*/ +int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]); + +/* + return an automatic baseDN from the defaultNamingContext of the rootDSE + This value have been set in an opaque pointer at connection time +*/ +const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); + +/** + Search the database + + This function searches the database, and returns + records that match an LDAP-like search expression + + \param ldb the context associated with the database (from ldb_init()) + \param base the Base Distinguished Name for the query (pass NULL for root DN) + \param scope the search scope for the query + \param expression the search expression to use for this query + \param attrs the search attributes for the query (pass NULL if none required) + \param res the return result + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note use talloc_free() to free the ldb_result returned +*/ +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 **res); + +/* + like ldb_search() but takes a parse tree +*/ +int ldb_search_bytree(struct ldb_context *ldb, + const struct ldb_dn *base, + enum ldb_scope scope, + struct ldb_parse_tree *tree, + const char * const *attrs, struct ldb_result **res); + +/** + Add a record to the database. + + This function adds a record to the database. This function will fail + if a record with the specified class and key already exists in the + database. + + \param ldb the context associated with the database (from + ldb_init()) + \param message the message containing the record to add. + + \return result code (LDB_SUCCESS if the record was added, otherwise + a failure code) +*/ +int ldb_add(struct ldb_context *ldb, + const struct ldb_message *message); + +/** + Modify the specified attributes of a record + + This function modifies a record that is in the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param message the message containing the changes required. + + \return result code (LDB_SUCCESS if the record was modified as + requested, otherwise a failure code) +*/ +int ldb_modify(struct ldb_context *ldb, + const struct ldb_message *message); + +/** + Rename a record in the database + + This function renames a record in the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param olddn the DN for the record to be renamed. + \param newdn the new DN + + \return result code (LDB_SUCCESS if the record was renamed as + requested, otherwise a failure code) +*/ +int ldb_rename(struct ldb_context *ldb, const struct ldb_dn *olddn, const struct ldb_dn *newdn); + +/** + Delete a record from the database + + This function deletes a record from the database. + + \param ldb the context associated with the database (from + ldb_init()) + \param dn the DN for the record to be deleted. + + \return result code (LDB_SUCCESS if the record was deleted, + otherwise a failure code) +*/ +int ldb_delete(struct ldb_context *ldb, const struct ldb_dn *dn); + +/** + start a transaction +*/ +int ldb_transaction_start(struct ldb_context *ldb); + +/** + commit a transaction +*/ +int ldb_transaction_commit(struct ldb_context *ldb); + +/** + cancel a transaction +*/ +int ldb_transaction_cancel(struct ldb_context *ldb); + + +/** + return extended error information from the last call +*/ +const char *ldb_errstring(struct ldb_context *ldb); + +/** + return a string explaining what a ldb error constant meancs +*/ +const char *ldb_strerror(int ldb_err); + +/** + setup the default utf8 functions + FIXME: these functions do not yet handle utf8 +*/ +void ldb_set_utf8_default(struct ldb_context *ldb); + +/** + Casefold a string + + \param ldb the ldb context + \param mem_ctx the memory context to allocate the result string + memory from. + \param s the string that is to be folded + \return a copy of the string, converted to upper case + + \note The default function is not yet UTF8 aware. Provide your own + set of functions through ldb_set_utf8_fns() +*/ +char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s); + +/** + Check the attribute name is valid according to rfc2251 + \param s tthe string to check + + \return 1 if the name is ok +*/ +int ldb_valid_attr_name(const char *s); + +/* + ldif manipulation functions +*/ +/** + Write an LDIF message + + This function writes an LDIF message using a caller supplied write + function. + + \param ldb the ldb context (from ldb_init()) + \param fprintf_fn a function pointer for the write function. This must take + a private data pointer, followed by a format string, and then a variable argument + list. + \param private_data pointer that will be provided back to the write + function. This is useful for maintaining state or context. + \param ldif the message to write out + + \return the total number of bytes written, or an error code as returned + from the write function. + + \sa ldb_ldif_write_file for a more convenient way to write to a + file stream. + + \sa ldb_ldif_read for the reader equivalent to this function. +*/ +int ldb_ldif_write(struct ldb_context *ldb, + int (*fprintf_fn)(void *, const char *, ...) PRINTF_ATTRIBUTE(2,3), + void *private_data, + const struct ldb_ldif *ldif); + +/** + Clean up an LDIF message + + This function cleans up a LDIF message read using ldb_ldif_read() + or related functions (such as ldb_ldif_read_string() and + ldb_ldif_read_file(). + + \param ldb the ldb context (from ldb_init()) + \param msg the message to clean up and free + +*/ +void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *msg); + +/** + Read an LDIF message + + This function creates an LDIF message using a caller supplied read + function. + + \param ldb the ldb context (from ldb_init()) + \param fgetc_fn a function pointer for the read function. This must + take a private data pointer, and must return a pointer to an + integer corresponding to the next byte read (or EOF if there is no + more data to be read). + \param private_data pointer that will be provided back to the read + function. This is udeful for maintaining state or context. + + \return the LDIF message that has been read in + + \note You must free the LDIF message when no longer required, using + ldb_ldif_read_free(). + + \sa ldb_ldif_read_file for a more convenient way to read from a + file stream. + + \sa ldb_ldif_read_string for a more convenient way to read from a + string (char array). + + \sa ldb_ldif_write for the writer equivalent to this function. +*/ +struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, + int (*fgetc_fn)(void *), void *private_data); + +/** + Read an LDIF message from a file + + This function reads the next LDIF message from the contents of a + file stream. If you want to get all of the LDIF messages, you will + need to repeatedly call this function, until it returns NULL. + + \param ldb the ldb context (from ldb_init()) + \param f the file stream to read from (typically from fdopen()) + + \sa ldb_ldif_read_string for an equivalent function that will read + from a string (char array). + + \sa ldb_ldif_write_file for the writer equivalent to this function. + +*/ +struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f); + +/** + Read an LDIF message from a string + + This function reads the next LDIF message from the contents of a char + array. If you want to get all of the LDIF messages, you will need + to repeatedly call this function, until it returns NULL. + + \param ldb the ldb context (from ldb_init()) + \param s pointer to the char array to read from + + \sa ldb_ldif_read_file for an equivalent function that will read + from a file stream. + + \sa ldb_ldif_write for a more general (arbitrary read function) + version of this function. +*/ +struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s); + +/** + Write an LDIF message to a file + + \param ldb the ldb context (from ldb_init()) + \param f the file stream to write to (typically from fdopen()) + \param msg the message to write out + + \return the total number of bytes written, or a negative error code + + \sa ldb_ldif_read_file for the reader equivalent to this function. +*/ +int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *msg); + +/** + Base64 encode a buffer + + \param mem_ctx the memory context that the result is allocated + from. + \param buf pointer to the array that is to be encoded + \param len the number of elements in the array to be encoded + + \return pointer to an array containing the encoded data + + \note The caller is responsible for freeing the result +*/ +char *ldb_base64_encode(void *mem_ctx, const char *buf, int len); + +/** + Base64 decode a buffer + + This function decodes a base64 encoded string in place. + + \param s the string to decode. + + \return the length of the returned (decoded) string. + + \note the string is null terminated, but the null terminator is not + included in the length. +*/ +int ldb_base64_decode(char *s); + +int ldb_attrib_add_handlers(struct ldb_context *ldb, + const struct ldb_attrib_handler *handlers, + unsigned num_handlers); + +/* The following definitions come from lib/ldb/common/ldb_dn.c */ + +int ldb_dn_is_special(const struct ldb_dn *dn); +int ldb_dn_check_special(const struct ldb_dn *dn, const char *check); +char *ldb_dn_escape_value(void *mem_ctx, struct ldb_val value); +struct ldb_dn *ldb_dn_new(void *mem_ctx); +struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn); +struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn); +char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn); +char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn); +int ldb_dn_compare_base(struct ldb_context *ldb, const struct ldb_dn *base, const struct ldb_dn *dn); +int ldb_dn_compare(struct ldb_context *ldb, const struct ldb_dn *edn0, const struct ldb_dn *edn1); +struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn); +struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn); +struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el); +struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr, + const char *val); +struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, + const char * value, + const struct ldb_dn *base); +struct ldb_dn *ldb_dn_make_child(void *mem_ctx, + const struct ldb_dn_component *component, + const struct ldb_dn *base); +struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2); +struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) PRINTF_ATTRIBUTE(3,4); +struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn); + +/* useful functions for ldb_message structure manipulation */ +int ldb_dn_cmp(struct ldb_context *ldb, const char *dn1, const char *dn2); + +/** + Compare two attributes + + This function compares to attribute names. Note that this is a + case-insensitive comparison. + + \param attr1 the first attribute name to compare + \param attr2 the second attribute name to compare + + \return 0 if the attribute names are the same, or only differ in + case; non-zero if there are any differences +*/ +int ldb_attr_cmp(const char *attr1, const char *attr2); +char *ldb_attr_casefold(void *mem_ctx, const char *s); +int ldb_attr_dn(const char *attr); + +/** + Create an empty message + + \param mem_ctx the memory context to create in. You can pass NULL + to get the top level context, however the ldb context (from + ldb_init()) may be a better choice +*/ +struct ldb_message *ldb_msg_new(void *mem_ctx); + +/** + Find an element within an message +*/ +struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, + const char *attr_name); + +/** + Compare two ldb_val values + + \param v1 first ldb_val structure to be tested + \param v2 second ldb_val structure to be tested + + \return 1 for a match, 0 if there is any difference +*/ +int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2); + +/** + find a value within an ldb_message_element + + \param el the element to search + \param val the value to search for + + \note This search is case sensitive +*/ +struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, + struct ldb_val *val); + +/** + add a new empty element to a ldb_message +*/ +int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags); + +/** + add a element to a ldb_message +*/ +int ldb_msg_add(struct ldb_message *msg, + const struct ldb_message_element *el, + int flags); +int ldb_msg_add_value(struct ldb_message *msg, + const char *attr_name, + const struct ldb_val *val); +int ldb_msg_add_steal_value(struct ldb_message *msg, + const char *attr_name, + struct ldb_val *val); +int ldb_msg_add_steal_string(struct ldb_message *msg, + const char *attr_name, char *str); +int ldb_msg_add_string(struct ldb_message *msg, + const char *attr_name, const char *str); +int ldb_msg_add_fmt(struct ldb_message *msg, + const char *attr_name, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); + +/** + compare two message elements - return 0 on match +*/ +int ldb_msg_element_compare(struct ldb_message_element *el1, + struct ldb_message_element *el2); + +/** + Find elements in a message. + + This function finds elements and converts to a specific type, with + a give default value if not found. Assumes that elements are + single valued. +*/ +const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name); +int ldb_msg_find_attr_as_int(const struct ldb_message *msg, + const char *attr_name, + int default_value); +unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, + const char *attr_name, + unsigned int default_value); +int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, + const char *attr_name, + int64_t default_value); +uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, + const char *attr_name, + uint64_t default_value); +double ldb_msg_find_attr_as_double(const struct ldb_message *msg, + const char *attr_name, + double default_value); +int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, + const char *attr_name, + int default_value); +const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, + const char *attr_name, + const char *default_value); + +struct ldb_dn *ldb_msg_find_attr_as_dn(void *mem_ctx, + const struct ldb_message *msg, + const char *attr_name); + +void ldb_msg_sort_elements(struct ldb_message *msg); + +struct ldb_message *ldb_msg_copy_shallow(void *mem_ctx, + const struct ldb_message *msg); +struct ldb_message *ldb_msg_copy(void *mem_ctx, + const struct ldb_message *msg); + +struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, + const struct ldb_message *msg); + + +struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, + struct ldb_message *msg1, + struct ldb_message *msg2); + +int ldb_msg_check_string_attribute(const struct ldb_message *msg, + const char *name, + const char *value); + +/** + Integrity check an ldb_message + + This function performs basic sanity / integrity checks on an + ldb_message. + + \param msg the message to check + + \return LDB_SUCCESS if the message is OK, or a non-zero error code + (one of LDB_ERR_INVALID_DN_SYNTAX, LDB_ERR_ENTRY_ALREADY_EXISTS or + LDB_ERR_INVALID_ATTRIBUTE_SYNTAX) if there is a problem with a + message. +*/ +int ldb_msg_sanity_check(struct ldb_context *ldb, + const struct ldb_message *msg); + +/** + Duplicate an ldb_val structure + + This function copies an ldb value structure. + + \param mem_ctx the memory context that the duplicated value will be + allocated from + \param v the ldb_val to be duplicated. + + \return the duplicated ldb_val structure. +*/ +struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v); + +/** + this allows the user to set a debug function for error reporting +*/ +int ldb_set_debug(struct ldb_context *ldb, + void (*debug)(void *context, enum ldb_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0), + void *context); + +/** + this allows the user to set custom utf8 function for error reporting +*/ +void ldb_set_utf8_fns(struct ldb_context *ldb, + void *context, + char *(*casefold)(void *, void *, const char *)); + +/** + this sets up debug to print messages on stderr +*/ +int ldb_set_debug_stderr(struct ldb_context *ldb); + +/* control backend specific opaque values */ +int ldb_set_opaque(struct ldb_context *ldb, const char *name, void *value); +void *ldb_get_opaque(struct ldb_context *ldb, const char *name); + +const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb, + const char *attrib); + + +const char **ldb_attr_list_copy(void *mem_ctx, const char * const *attrs); +const char **ldb_attr_list_copy_add(void *mem_ctx, const char * const *attrs, const char *new_attr); +int ldb_attr_in_list(const char * const *attrs, const char *attr); + + +void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree, + const char *attr, + const char *replace); + +int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace); +int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace); +void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr); + +/** + Convert a time structure to a string + + This function converts a time_t structure to an LDAP formatted time + string. + + \param mem_ctx the memory context to allocate the return string in + \param t the time structure to convert + + \return the formatted string, or NULL if the time structure could + not be converted +*/ +char *ldb_timestring(void *mem_ctx, time_t t); + +/** + Convert a string to a time structure + + This function converts an LDAP formatted time string to a time_t + structure. + + \param s the string to convert + + \return the time structure, or 0 if the string cannot be converted +*/ +time_t ldb_string_to_time(const char *s); + +char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn); +char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn); + + +void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp); +#endif diff --git a/source3/lib/ldb/include/ldb_errors.h b/source3/lib/ldb/include/ldb_errors.h new file mode 100644 index 0000000000..3b04c7c17f --- /dev/null +++ b/source3/lib/ldb/include/ldb_errors.h @@ -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 + The OpenLDAP Project. + */ + +/** + 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_ */ diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h new file mode 100644 index 0000000000..96b71ff3b4 --- /dev/null +++ b/source3/lib/ldb/include/ldb_private.h @@ -0,0 +1,220 @@ +/* + 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; +}; + +#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_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, + const 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); + +/** + 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 diff --git a/source3/lib/ldb/install-sh b/source3/lib/ldb/install-sh new file mode 100755 index 0000000000..58719246f0 --- /dev/null +++ b/source3/lib/ldb/install-sh @@ -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 diff --git a/source3/lib/ldb/ldap.m4 b/source3/lib/ldb/ldap.m4 new file mode 100644 index 0000000000..911c1364c8 --- /dev/null +++ b/source3/lib/ldb/ldap.m4 @@ -0,0 +1,89 @@ +######################################################## +# 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 + #include ], + [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]) + 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}]) diff --git a/source3/lib/ldb/ldb.pc.in b/source3/lib/ldb/ldb.pc.in new file mode 100644 index 0000000000..8b0536e21e --- /dev/null +++ b/source3/lib/ldb/ldb.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +modulesdir=@modulesdir@ + +Name: ldb +Description: An LDAP-like embedded database +Version: 4.0 +Libs: @LIBS@ -L${libdir} -lldb +Cflags: -I${includedir} @CFLAGS@ +Modulesdir: ${modulesdir} diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c new file mode 100644 index 0000000000..5b69ac06c9 --- /dev/null +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -0,0 +1,825 @@ +/* + 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" + +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_explode_or_special(ares->message, search->dn); + if (ares->message->dn == NULL) { + 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_linearize(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_linearize(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_linearize(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_linearize(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_linearize(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", + req->op.rename.newdn->components[0].name, + ldb_dn_escape_value(msg, req->op.rename.newdn->components[0].value)); + if (msg->r.ModifyDNRequest.newrdn == NULL) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->r.ModifyDNRequest.newsuperior = + ldb_dn_linearize(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; + } + (*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); +} diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c new file mode 100644 index 0000000000..9de67e5ad7 --- /dev/null +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -0,0 +1,831 @@ +/* + 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 + +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;inum_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;jnum_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;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); + if (!el->values[i].data) { + return -1; + } + 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_linearize(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_linearize(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_linearize(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_linearize(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_linearize(lldb_ac, req->op.rename.olddn); + if (old_dn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + newrdn = talloc_asprintf(lldb_ac, "%s=%s", + req->op.rename.newdn->components[0].name, + ldb_dn_escape_value(lldb, req->op.rename.newdn->components[0].value)); + if (!newrdn) { + return LDB_ERR_OPERATIONS_ERROR; + } + + parentdn = ldb_dn_linearize(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); + + 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_explode_or_special(ares->message, dn); + if (ares->message->dn == NULL) { + 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) { + ldb_set_errstring(ac->module->ldb, errmsgp); + ldap_memfree(errmsgp); + } + if (referralsp) ldap_value_free(referralsp); + if (serverctrlsp) ldap_controls_free(serverctrlsp); + + ldap_msgfree(result); + return ret; + +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) { + ldb_oom(ldb); + talloc_free(lldb); + return -1; + } + (*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); +} diff --git a/source3/lib/ldb/ldb_sqlite3/README b/source3/lib/ldb/ldb_sqlite3/README new file mode 100644 index 0000000000..6cda0a7759 --- /dev/null +++ b/source3/lib/ldb/ldb_sqlite3/README @@ -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 diff --git a/source3/lib/ldb/ldb_sqlite3/base160.c b/source3/lib/ldb/ldb_sqlite3/base160.c new file mode 100644 index 0000000000..4286979123 --- /dev/null +++ b/source3/lib/ldb/ldb_sqlite3/base160.c @@ -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; +} diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c new file mode 100644 index 0000000000..91256222b1 --- /dev/null +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -0,0 +1,2145 @@ +/* + ldb database library + + Copyright (C) Derrell Lipman 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 sqlite3 backend + * + * Description: core files for SQLITE3 backend + * + * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#include + +struct lsqlite3_private { + int trans_count; + char **options; + sqlite3 *sqlite; +}; + +struct lsql_context { + struct ldb_module *module; + + /* search stuff */ + long long current_eid; + const char * const * attrs; + struct ldb_reply *ares; + + /* async stuff */ + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); +}; + +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +{ + struct lsql_context *ac; + struct ldb_handle *h; + + h = talloc_zero(lsqlite3, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc(h, struct lsql_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; + + return h; +} + +/* + * Macros used throughout + */ + +#ifndef FALSE +# define FALSE (0) +# define TRUE (! FALSE) +#endif + +#define RESULT_ATTR_TABLE "temp_result_attrs" + +//#define TEMPTAB /* for testing, create non-temporary table */ +#define TEMPTAB "TEMPORARY" + +/* + * Static variables + */ +sqlite3_stmt * stmtGetEID = NULL; + +static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...) +{ + char *str, *ret; + va_list ap; + + va_start(ap, fmt); + str = sqlite3_vmprintf(fmt, ap); + va_end(ap); + + if (str == NULL) return NULL; + + ret = talloc_strdup(mem_ctx, str); + if (ret == NULL) { + sqlite3_free(str); + return NULL; + } + + sqlite3_free(str); + return ret; +} + +static 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' +}; + + +/* + * 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 + */ +static void +base160_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + long long val; + char result[5]; + + val = sqlite3_value_int64(argv[0]); + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; + + sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT); +} + + +/* + * base160next_sql() + * + * This function enhances sqlite by adding a "base160_next()" function which is + * accessible via queries. + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) is + * operated on. + * + * Input: + * A character string: 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. + * + * Output: + * Upon return, the trailing four digits (one tree level) will have been + * incremented by 1. + */ +static void +base160next_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + int len; + char * pTab; + char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0])); + char * pStart = pBase160; + + /* + * We need a minimum of four digits, and we will always get a multiple + * of four digits. + */ + if (pBase160 != NULL && + (len = strlen(pBase160)) >= 4 && + len % 4 == 0) { + + if (pBase160 == NULL) { + + sqlite3_result_null(hContext); + return; + } + + 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]; + } + } + + sqlite3_result_text(hContext, + pStart, + strlen(pStart), + free); + } else { + sqlite3_result_value(hContext, argv[0]); + if (pBase160 != NULL) { + free(pBase160); + } + } +} + +static char *parsetree_to_sql(struct ldb_module *module, + void *mem_ctx, + const struct ldb_parse_tree *t) +{ + const struct ldb_attrib_handler *h; + struct ldb_val value, subval; + char *wild_card_string; + char *child, *tmp; + char *ret = NULL; + char *attr; + int i; + + + switch(t->operation) { + case LDB_OP_AND: + + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; + + for (i = 1; i < t->u.list.num_elements; i++) { + + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; + + tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child); + if (tmp == NULL) return NULL; + } + + ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp); + + return ret; + + case LDB_OP_OR: + + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; + + for (i = 1; i < t->u.list.num_elements; i++) { + + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; + + tmp = talloc_asprintf_append(tmp, " UNION %s ", child); + if (tmp == NULL) return NULL; + } + + return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp); + + case LDB_OP_NOT: + + child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child); + if (child == NULL) return NULL; + + return talloc_asprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE eid NOT IN ( %s ) ", child); + + case LDB_OP_EQUALITY: + /* + * For simple searches, we want to retrieve the list of EIDs that + * match the criteria. + */ + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + if (strcasecmp(t->u.equality.attr, "objectclass") == 0) { + /* + * For object classes, we want to search for all objectclasses + * that are subclasses as well. + */ + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values\n" + "WHERE norm_attr_name = 'OBJECTCLASS' " + "AND norm_attr_value IN\n" + " (SELECT class_name FROM ldb_object_classes\n" + " WHERE tree_key GLOB\n" + " (SELECT tree_key FROM ldb_object_classes\n" + " WHERE class_name = '%q'\n" + " ) || '*'\n" + " )\n", value.data); + + } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { + /* DN query is a special ldb case */ + char *cdn = ldb_dn_linearize_casefold(module->ldb, + ldb_dn_explode(module->ldb, + (const char *)value.data)); + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE norm_dn = '%q'", cdn); + + } else { + /* A normal query. */ + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value = '%q'", + attr, + value.data); + + } + + case LDB_OP_SUBSTRING: + + wild_card_string = talloc_strdup(mem_ctx, + (t->u.substring.start_with_wildcard)?"*":""); + if (wild_card_string == NULL) return NULL; + + for (i = 0; t->u.substring.chunks[i]; i++) { + wild_card_string = talloc_asprintf_append(wild_card_string, "%s*", + t->u.substring.chunks[i]->data); + if (wild_card_string == NULL) return NULL; + } + + if ( ! t->u.substring.end_with_wildcard ) { + /* remove last wildcard */ + wild_card_string[strlen(wild_card_string) - 1] = '\0'; + } + + attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); + + subval.data = (void *)wild_card_string; + subval.length = strlen(wild_card_string) + 1; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value GLOB '%q'", + attr, + value.data); + + case LDB_OP_GREATER: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_LESS: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_PRESENT: + if (strcasecmp(t->u.present.attr, "dn") == 0) { + return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); + } + + attr = ldb_attr_casefold(mem_ctx, t->u.present.attr); + if (attr == NULL) return NULL; + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' ", + attr); + + case LDB_OP_APPROX: + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = '%q' " + "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ", + attr, + value.data, + attr); + + case LDB_OP_EXTENDED: +#warning "work out how to handle bitops" + return NULL; + + default: + break; + }; + + /* should never occur */ + abort(); + return NULL; +} + +/* + * query_int() + * + * This function is used for the common case of queries that return a single + * integer value. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. + */ +static int +query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...) +{ + int ret; + int bLoop; + char * p; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); + + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return SQLITE_NOMEM; + } + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + p, + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + break; + } + + /* One row expected */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + break; + } + + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(pStmt, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + bLoop = FALSE; + } + + /* All done with variable argument list */ + va_end(args); + + + /* Free the memory we allocated for our query string */ + sqlite3_free(p); + + return ret; +} + +/* + * This is a bad hack to support ldap style comparisons whithin sqlite. + * val is the attribute in the row currently under test + * func is the desired test "<=" ">=" "~" ":" + * cmp is the value to compare against (eg: "test") + * attr is the attribute name the value of which we want to test + */ + +static void lsqlite3_compare(sqlite3_context *ctx, int argc, + sqlite3_value **argv) +{ + struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx); + const char *val = (const char *)sqlite3_value_text(argv[0]); + const char *func = (const char *)sqlite3_value_text(argv[1]); + const char *cmp = (const char *)sqlite3_value_text(argv[2]); + const char *attr = (const char *)sqlite3_value_text(argv[3]); + const struct ldb_attrib_handler *h; + struct ldb_val valX; + struct ldb_val valY; + int ret; + + switch (func[0]) { + /* greater */ + case '>': /* >= */ + h = ldb_attrib_handler(ldb, attr); + valX.data = (void *)cmp; + valX.length = strlen(cmp); + valY.data = (void *)val; + valY.length = strlen(val); + ret = h->comparison_fn(ldb, ldb, &valY, &valX); + if (ret >= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* lesser */ + case '<': /* <= */ + h = ldb_attrib_handler(ldb, attr); + valX.data = (void *)cmp; + valX.length = strlen(cmp); + valY.data = (void *)val; + valY.length = strlen(val); + ret = h->comparison_fn(ldb, ldb, &valY, &valX); + if (ret <= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* approx */ + case '~': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + /* bitops */ + case ':': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + default: + break; + } + + sqlite3_result_error(ctx, "Value must start with a special operation char (<>~:)!", -1); + return; +} + + +/* rename a record */ +static int lsqlite3_safe_rollback(sqlite3 *sqlite) +{ + char *errmsg; + int ret; + + /* execute */ + ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_safe_rollback: Error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + + return 0; +} + +/* return an eid as result */ +static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char **names) +{ + long long *eid = (long long *)result; + + if (col_num != 1) return SQLITE_ABORT; + if (strcasecmp(names[0], "eid") != 0) return SQLITE_ABORT; + + *eid = atoll(cols[0]); + return SQLITE_OK; +} + +/* + * add a single set of ldap message values to a ldb_message + */ +static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names) +{ + struct ldb_handle *handle = talloc_get_type(result, struct ldb_handle); + struct lsql_context *ac = talloc_get_type(handle->private_data, struct lsql_context); + struct ldb_message *msg; + long long eid; + int i; + + /* eid, dn, attr_name, attr_value */ + if (col_num != 4) + return SQLITE_ABORT; + + eid = atoll(cols[0]); + + if (eid != ac->current_eid) { /* here begin a new entry */ + + /* call the async callback for the last entry + * except the first time */ + if (ac->current_eid != 0) { + ac->ares->message = ldb_msg_canonicalize(ac->module->ldb, ac->ares->message); + if (ac->ares->message == NULL) + return SQLITE_ABORT; + + handle->status = ac->callback(ac->module->ldb, ac->context, ac->ares); + if (handle->status != LDB_SUCCESS) + return SQLITE_ABORT; + } + + /* start over */ + ac->ares = talloc_zero(ac, struct ldb_reply); + if (!ac->ares) + return SQLITE_ABORT; + + ac->ares->message = ldb_msg_new(ac->ares); + if (!ac->ares->message) + return SQLITE_ABORT; + + ac->ares->type = LDB_REPLY_ENTRY; + ac->current_eid = eid; + } + + msg = ac->ares->message; + + if (msg->dn == NULL) { + msg->dn = ldb_dn_explode(msg, cols[1]); + if (msg->dn == NULL) + return SQLITE_ABORT; + } + + if (ac->attrs) { + int found = 0; + for (i = 0; ac->attrs[i]; i++) { + if (strcasecmp(cols[2], ac->attrs[i]) == 0) { + found = 1; + break; + } + } + if (!found) return SQLITE_OK; + } + + if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) { + return SQLITE_ABORT; + } + + return SQLITE_OK; +} + + +/* + * lsqlite3_get_eid() + * lsqlite3_get_eid_ndn() + * + * These functions are used for the very common case of retrieving an EID value + * given a (normalized) DN. + */ + +static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char *norm_dn) +{ + char *errmsg; + char *query; + long long eid = -1; + long long ret; + + /* get object eid */ + query = lsqlite3_tprintf(mem_ctx, "SELECT eid " + "FROM ldb_entry " + "WHERE norm_dn = '%q';", norm_dn); + if (query == NULL) return -1; + + ret = sqlite3_exec(sqlite, query, lsqlite3_eid_callback, &eid, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_get_eid: Fatal Error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + + return eid; +} + +static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn *dn) +{ + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid = -1; + char *cdn; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(dn)) { + return -1; + } + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_get_eid local context"); + if (local_ctx == NULL) { + return -1; + } + + cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, dn)); + if (!cdn) goto done; + + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); + +done: + talloc_free(local_ctx); + return eid; +} + +/* + * Interface functions referenced by lsqlite3_ops + */ + +static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct ldb_result *res = NULL; + + if (!context) { + ldb_set_errstring(ldb, "NULL Context in callback"); + goto error; + } + + res = *((struct ldb_result **)context); + + if (!res || !ares) { + goto error; + } + + if (ares->type == LDB_REPLY_ENTRY) { + res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); + if (! res->msgs) { + goto error; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_move(res->msgs, &ares->message); + res->count++; + } else { + ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); + goto error; + } + + talloc_free(ares); + return LDB_SUCCESS; + +error: + if (ares) talloc_free(ares); + if (res) talloc_free(res); + if (context) *((struct ldb_result **)context) = NULL; + return LDB_ERR_OPERATIONS_ERROR; +} + +/* search for matching records, by tree */ +int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + char *norm_basedn; + char *sqlfilter; + char *errmsg; + char *query = NULL; + int ret; + + *handle = init_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + talloc_free(*handle); + return LDB_ERR_OPERATIONS_ERROR; + } + + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + + if (base) { + norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); + if (norm_basedn == NULL) { + ret = LDB_ERR_INVALID_DN_SYNTAX; + goto failed; + } + } else norm_basedn = talloc_strdup(lsql_ac, ""); + + if (*norm_basedn == '\0' && + (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto failed; + } + + /* Convert filter into a series of SQL conditions (constraints) */ + sqlfilter = parsetree_to_sql(module, lsql_ac, tree); + + switch(scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_SUBTREE: + if (*norm_basedn != '\0') { + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE (ldb_entry.norm_dn GLOB('*,%q')\n" + " OR ldb_entry.norm_dn = '%q')\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter); + } else { + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + sqlfilter); + } + + break; + + case LDB_SCOPE_BASE: + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.norm_dn = '%q'\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + sqlfilter); + break; + + case LDB_SCOPE_ONELEVEL: + query = lsqlite3_tprintf(lsql_ac, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE norm_dn GLOB('*,%q')\n" + " AND NOT norm_dn GLOB('*,*,%q')\n" + " AND ldb_entry.eid IN\n(%s)\n" + " )\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter); + break; + } + + if (query == NULL) { + goto failed; + } + + /* * / + printf ("%s\n", query); + / * */ + + lsql_ac->current_eid = 0; + lsql_ac->attrs = attrs; + lsql_ac->ares = NULL; + + (*handle)->state = LDB_ASYNC_PENDING; + + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + goto failed; + } + + /* complete the last message if any */ + if (lsql_ac->ares) { + lsql_ac->ares->message = ldb_msg_canonicalize(module->ldb, lsql_ac->ares->message); + if (lsql_ac->ares->message == NULL) + goto failed; + + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if ((*handle)->status != LDB_SUCCESS) + goto failed; + } + + (*handle)->state = LDB_ASYNC_DONE; + + return LDB_SUCCESS; + +failed: + talloc_free(*handle); + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* base, + enum ldb_scope scope, struct ldb_parse_tree * tree, + const char * const * attrs, struct ldb_result ** res) +{ + struct ldb_handle *handle; + int ret; + + *res = talloc_zero(module, struct ldb_result); + if (! *res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = lsql_search_async(module, base, scope, tree, attrs, + res, &lsql_search_sync_callback, + &handle); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(handle, LDB_WAIT_ALL); + talloc_free(handle); + } + + if (ret != LDB_SUCCESS) { + talloc_free(*res); + } + + return ret; +} + +/* add a record */ +static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + long long eid; + char *dn, *ndn; + char *errmsg; + char *query; + int i; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; + } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { + struct ldb_dn *c; + + c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "insert subclasses into object class tree" + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto failed; + } + +/* + c = ldb_dn_explode(local_ctx, "@INDEXLIST"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "should we handle indexes somehow ?" + goto failed; + } +*/ + /* Others are implicitly ignored */ + return LDB_SUCCESS; + } + + /* create linearized and normalized dns */ + dn = ldb_dn_linearize(lsql_ac, msg->dn); + ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, msg->dn)); + if (dn == NULL || ndn == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + query = lsqlite3_tprintf(lsql_ac, + /* Add new entry */ + "INSERT OR ABORT INTO ldb_entry " + "('dn', 'norm_dn') " + "VALUES ('%q', '%q');", + dn, ndn); + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_attrib_handler *h; + char *attr; + int j; + + /* Get a case-folded copy of the attribute name */ + attr = ldb_attr_casefold(lsql_ac, el->name); + if (attr == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + h = ldb_attrib_handler(module->ldb, el->name); + + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + char *insert; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + insert = lsqlite3_tprintf(lsql_ac, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + if (insert == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + } + } + + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + + return LDB_SUCCESS; + +failed: + talloc_free(*handle); + return ret; +} + +static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_handle *handle; + int ret; + + ret = lsql_add_async(module, msg, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_wait(handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + + +/* modify a record */ +static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + long long eid; + char *errmsg; + int i; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; + } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { + struct ldb_dn *c; + + c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "modify subclasses into object class tree" + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto failed; + } + + /* Others are implicitly ignored */ + return LDB_SUCCESS; + } + + eid = lsqlite3_get_eid(module, msg->dn); + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_attrib_handler *h; + int flags = el->flags & LDB_FLAG_MOD_MASK; + char *attr; + char *mod; + int j; + + /* Get a case-folded copy of the attribute name */ + attr = ldb_attr_casefold(lsql_ac, el->name); + if (attr == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + h = ldb_attrib_handler(module->ldb, el->name); + + switch (flags) { + + case LDB_FLAG_MOD_REPLACE: + + /* remove all attributes before adding the replacements */ + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + + /* MISSING break is INTENTIONAL */ + + case LDB_FLAG_MOD_ADD: +#warning "We should throw an error if no value is provided!" + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + mod = lsqlite3_tprintf(lsql_ac, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + } + + break; + + case LDB_FLAG_MOD_DELETE: +#warning "We should throw an error if the attribute we are trying to delete does not exist!" + if (el->num_values == 0) { + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + } + + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + mod = lsqlite3_tprintf(lsql_ac, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q' " + "AND norm_attr_value = '%q';", + eid, attr, value.data); + + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OTHER; + goto failed; + } + } + + break; + } + } + + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + + return LDB_SUCCESS; + +failed: + talloc_free(*handle); + return ret; +} + +static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_handle *handle; + int ret; + + ret = lsql_modify_async(module, msg, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_wait(handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + +/* delete a record */ +static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + long long eid; + char *errmsg; + char *query; + int ret = LDB_ERR_OPERATIONS_ERROR; + + + *handle = init_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; + } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + eid = lsqlite3_get_eid(module, dn); + if (eid == -1) { + goto failed; + } + + query = lsqlite3_tprintf(lsql_ac, + /* Delete entry */ + "DELETE FROM ldb_entry WHERE eid = %lld; " + /* Delete attributes */ + "DELETE FROM ldb_attribute_values WHERE eid = %lld; ", + eid, eid); + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OPERATIONS_ERROR; + goto failed; + } + + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + + return LDB_SUCCESS; + +failed: + talloc_free(*handle); + return ret; +} + +static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ldb_handle *handle; + int ret; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(dn)) { + return LDB_SUCCESS; + } + + ret = lsql_delete_async(module, dn, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_wait(handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + +/* rename a record */ +static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_context *lsql_ac; + char *new_dn, *new_cdn, *old_cdn; + char *errmsg; + char *query; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; + } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + /* create linearized and normalized dns */ + old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, olddn)); + new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, newdn)); + new_dn = ldb_dn_linearize(lsql_ac, newdn); + if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { + goto failed; + } + + /* build the SQL query */ + query = lsqlite3_tprintf(lsql_ac, + "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' " + "WHERE norm_dn = '%q';", + new_dn, new_cdn, old_cdn); + if (query == NULL) { + goto failed; + } + + /* execute */ + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + ldb_set_errstring(module->ldb, errmsg); + free(errmsg); + } + ret = LDB_ERR_OPERATIONS_ERROR; + goto failed; + } + + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + + return LDB_SUCCESS; + +failed: + talloc_free(*handle); + return ret; +} + +static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_handle *handle; + int ret; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { + return LDB_SUCCESS; + } + + + ret = lsql_rename_async(module, olddn, newdn, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_wait(handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + +static int lsql_start_trans(struct ldb_module * module) +{ + int ret; + char *errmsg; + struct lsqlite3_private * lsqlite3 = module->private_data; + + if (lsqlite3->trans_count == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_start_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + }; + + lsqlite3->trans_count++; + + return 0; +} + +static int lsql_end_trans(struct ldb_module *module) +{ + int ret; + char *errmsg; + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; + + if (lsqlite3->trans_count == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_end_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + } + + return 0; +} + +static int lsql_del_trans(struct ldb_module *module) +{ + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; + + if (lsqlite3->trans_count == 0) { + return lsqlite3_safe_rollback(lsqlite3->sqlite); + } + + return -1; +} + +/* + * Static functions + */ + +static int initialize(struct lsqlite3_private *lsqlite3, + struct ldb_context *ldb, const char *url, int flags) +{ + TALLOC_CTX *local_ctx; + long long queryInt; + int rollback = 0; + char *errmsg; + char *schema; + int ret; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); + if (local_ctx == NULL) { + return -1; + } + + schema = lsqlite3_tprintf(local_ctx, + + + "CREATE TABLE ldb_info AS " + " SELECT 'LDB' AS database_type," + " '1.0' AS version;" + + /* + * The entry table holds the information about an entry. + * This table is used to obtain the EID of the entry and to + * support scope=one and scope=base. The parent and child + * table is included in the entry table since all the other + * attributes are dependent on EID. + */ + "CREATE TABLE ldb_entry " + "(" + " eid INTEGER PRIMARY KEY AUTOINCREMENT," + " dn TEXT UNIQUE NOT NULL," + " norm_dn TEXT UNIQUE NOT NULL" + ");" + + + "CREATE TABLE ldb_object_classes" + "(" + " class_name TEXT PRIMARY KEY," + " parent_class_name TEXT," + " tree_key TEXT UNIQUE," + " max_child_num INTEGER DEFAULT 0" + ");" + + /* + * We keep a full listing of attribute/value pairs here + */ + "CREATE TABLE ldb_attribute_values" + "(" + " eid INTEGER REFERENCES ldb_entry," + " attr_name TEXT," + " norm_attr_name TEXT," + " attr_value TEXT," + " norm_attr_value TEXT " + ");" + + + /* + * Indexes + */ + "CREATE INDEX ldb_attribute_values_eid_idx " + " ON ldb_attribute_values (eid);" + + "CREATE INDEX ldb_attribute_values_name_value_idx " + " ON ldb_attribute_values (attr_name, norm_attr_value);" + + + + /* + * Triggers + */ + + "CREATE TRIGGER ldb_object_classes_insert_tr" + " AFTER INSERT" + " ON ldb_object_classes" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_object_classes" + " SET tree_key = COALESCE(tree_key, " + " (" + " SELECT tree_key || " + " (SELECT base160(max_child_num + 1)" + " FROM ldb_object_classes" + " WHERE class_name = " + " new.parent_class_name)" + " FROM ldb_object_classes " + " WHERE class_name = new.parent_class_name " + " ));" + " UPDATE ldb_object_classes " + " SET max_child_num = max_child_num + 1" + " WHERE class_name = new.parent_class_name;" + " END;" + + /* + * Table initialization + */ + + "INSERT INTO ldb_object_classes " + " (class_name, tree_key) " + " VALUES " + " ('TOP', '0001');"); + + /* Skip protocol indicator of url */ + if (strncmp(url, "sqlite://", 9) != 0) { + return SQLITE_MISUSE; + } + + /* Update pointer to just after the protocol indicator */ + url += 9; + + /* Try to open the (possibly empty/non-existent) database */ + if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { + return ret; + } + + /* In case this is a new database, enable auto_vacuum */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA auto_vacuum = 1;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + if (flags & LDB_FLG_NOSYNC) { + /* DANGEROUS */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } + + /* */ + + /* Establish a busy timeout of 30 seconds */ + if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, + 30000)) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to increment a tree_key */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160_next", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160next_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to convert int to base160 */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to perform various comparisons */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite, /* handle */ + "ldap_compare", /* function name */ + 4, /* number of args */ + SQLITE_ANY, /* preferred text type */ + ldb , /* user data */ + lsqlite3_compare, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Begin a transaction */ + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: initialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + rollback = 1; + + /* Determine if this is a new database. No tables means it is. */ + if (query_int(lsqlite3, + &queryInt, + "SELECT COUNT(*)\n" + " FROM sqlite_master\n" + " WHERE type = 'table';") != 0) { + goto failed; + } + + if (queryInt == 0) { + /* + * Create the database schema + */ + ret = sqlite3_exec(lsqlite3->sqlite, schema, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } else { + /* + * Ensure that the database we opened is one of ours + */ + if (query_int(lsqlite3, + &queryInt, + "SELECT " + " (SELECT COUNT(*) = 2" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_entry', " + " 'ldb_object_classes' " + " ) " + " ) " + " AND " + " (SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0'" + " );") != 0 || + queryInt != 1) { + + /* It's not one that we created. See ya! */ + goto failed; + } + } + + /* Commit the transaction */ + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: iniialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + return SQLITE_OK; + +failed: + if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); + sqlite3_close(lsqlite3->sqlite); + return -1; +} + +static int destructor(struct lsqlite3_private *lsqlite3) +{ + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} + +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +static int lsql_request(struct ldb_module *module, struct ldb_request *req) +{ + /* check for oustanding critical controls and return an error if found */ + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_sqlite3 backend!\n"); + } + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + switch (req->operation) { + + case LDB_SEARCH: + return lsql_search_bytree(module, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + &req->op.search.res); + + case LDB_ADD: + return lsql_add(module, req->op.add.message); + + case LDB_MODIFY: + return lsql_modify(module, req->op.mod.message); + + case LDB_DELETE: + return lsql_delete(module, req->op.del.dn); + + case LDB_RENAME: + return lsql_rename(module, + req->op.rename.olddn, + req->op.rename.newdn); + + case LDB_SEARCH: + return lsql_search_async(module, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->context, + req->callback, + &req->handle); +/* + case LDB_ADD: + return lsql_add_async(module, + req->op.add.message, + req->context, + req->callback, + &req->handle); + + case LDB_MODIFY: + return lsql_modify_async(module, + req->op.mod.message, + req->context, + req->callback, + &req->handle); +*/ + case LDB_DELETE: + return lsql_delete_async(module, + req->op.del.dn, + req->context, + req->callback, + &req->handle); + + case LDB_RENAME: + return lsql_rename_async(module, + req->op.rename.olddn, + req->op.rename.newdn, + req->context, + req->callback, + &req->handle); + + default: + return LDB_ERR_OPERATIONS_ERROR; + + } +} + +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .wait = lsql_wait, +}; + +/* + * connect to the database + */ +static int lsqlite3_connect(struct ldb_context *ldb, + const char *url, + unsigned int flags, + const char *options[], + struct ldb_module **module) +{ + int i; + int ret; + struct lsqlite3_private * lsqlite3 = NULL; + + lsqlite3 = talloc(ldb, struct lsqlite3_private); + if (!lsqlite3) { + goto failed; + } + + lsqlite3->sqlite = NULL; + lsqlite3->options = NULL; + lsqlite3->trans_count = 0; + + ret = initialize(lsqlite3, ldb, url, flags); + if (ret != SQLITE_OK) { + goto failed; + } + + talloc_set_destructor(lsqlite3, destructor); + + + + *module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); + goto failed; + } + (*module)->ldb = ldb; + (*module)->prev = (*module)->next = NULL; + (*module)->private_data = lsqlite3; + (*module)->ops = &lsqlite3_ops; + + if (options) { + /* + * take a copy of the options array, so we don't have to rely + * on the caller keeping it around (it might be dynamic) + */ + for (i=0;options[i];i++) ; + + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); + if (!lsqlite3->options) { + goto failed; + } + + for (i=0;options[i];i++) { + + lsqlite3->options[i+1] = NULL; + lsqlite3->options[i] = + talloc_strdup(lsqlite3->options, options[i]); + if (!lsqlite3->options[i]) { + goto failed; + } + } + } + + return 0; + +failed: + if (lsqlite3->sqlite != NULL) { + (void) sqlite3_close(lsqlite3->sqlite); + } + talloc_free(lsqlite3); + return -1; +} + +int ldb_sqlite3_init(void) +{ + return ldb_register_backend("sqlite3", lsqlite3_connect); +} diff --git a/source3/lib/ldb/ldb_sqlite3/schema b/source3/lib/ldb/ldb_sqlite3/schema new file mode 100644 index 0000000000..08dc50de08 --- /dev/null +++ b/source3/lib/ldb/ldb_sqlite3/schema @@ -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'; + diff --git a/source3/lib/ldb/ldb_sqlite3/trees.ps b/source3/lib/ldb/ldb_sqlite3/trees.ps new file mode 100644 index 0000000000..433a064816 --- /dev/null +++ b/source3/lib/ldb/ldb_sqlite3/trees.ps @@ -0,0 +1,1760 @@ +%!PS-Adobe-2.0 +%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software +%%Title: trees.dvi +%%Pages: 7 +%%PageOrder: Ascend +%%BoundingBox: 0 0 596 842 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -f trees.dvi +%DVIPSParameters: dpi=600, compressed +%DVIPSSource: TeX output 2000.05.06:2055 +%%BeginProcSet: texc.pro +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3 +1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx +0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx +sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{ +rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp +gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B +/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{ +/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{ +A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy +get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse} +ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp +fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17 +{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add +chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{ +1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop} +forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +TeXDict begin 39158280 55380996 1000 600 600 (trees.dvi) +@start +%DVIPSBitmapFont: Fa cmr10 10 6 +/Fa 6 55 df<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B +120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A2 +6C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>40 +D<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7F +A21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A2 +5BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<15301578B3A6007FB812 +F8B912FCA26C17F8C80078C8FCB3A6153036367BAF41>43 D48 DI54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fb cmr7 7 3 +/Fb 3 55 df48 D<13381378EA01F8121F12FE12E01200B3AB487EB512F8A2 +15267BA521>I54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fc cmmi10 10 1 +/Fc 1 69 df<0103B7FC4916E018F8903B0007F80007FE4BEB00FFF03F80020FED1FC018 +0F4B15E0F007F0021F1503A24B15F81801143F19FC5DA2147FA292C8FCA25C18035CA213 +0119F84A1507A2130319F04A150FA2010717E0181F4A16C0A2010FEE3F80A24AED7F0018 +7E011F16FE4D5A4A5D4D5A013F4B5A4D5A4A4A5A057FC7FC017F15FEEE03FC91C7EA0FF0 +49EC7FC0B8C8FC16FC16C03E397DB845>68 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fd ectt1000 10 73 +/Fd 73 126 df37 +D39 +D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A5B12075B120F +5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA26C7E7F12077F +12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438164272B92C> +I<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F14C0130FEB07E0 +A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714E0A2EB0FC0131F +1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270164279B92C>I< +EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF003FB512F8000F14 +E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FFE7CFFEEBC7C7EB +07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<147014F8AF003FB6 +12E0B712F8A4C700F8C7FCB0147025267DAB2C>II<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>46 +D<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F +92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA213 +7E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA212 +7021417BB92C>II<1307497EA2131F +A2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14 +E01C3477B32C>II<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F881 +9038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C127E +B4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C5C +000114C06C6C90C7FCEB0FF823347CB22C>53 DI<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A +5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A +A5133F91C8FCAA131E23357CB32C>I59 D<1502ED0F80151F157F15 +FF913803FE00EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390 +C8FCEA07FCEA1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE0 +6D7EEB07FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED +0200212A7BAD2C>I<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F0 +25127DA12C>I<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07 +FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC +0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1F +F8EA3FE0EAFF8090C9FC12FC5A1220212A7BAD2C>I<14FE497EA4497FA214EFA2130781 +A214C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA3 +4880A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC +497E27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F015 +03A2ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001F +E0ED07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612 +E016C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD49 +13FFEBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A00 +7EEC00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C +130716E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F001001380 +25357DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED +0FE0A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0 +153FED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0 +B712F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FC +A5163C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803 +F0C7FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C +7E26337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC +01497E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE +5AA8913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D +137F6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC2635 +7DB32C>II<007FB512F8B612FCA36C14 +F839000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0 +ED01F8A8007FB6FCB7FCA36C15F025337DB22C>IIII<007FB512C0B612 +F88115FF6C15802603F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2 +ED0FE0ED3FC015FF90B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337E +B22C>II<387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA2 +6F7EA64B5AA2153F4BC7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F +81A8160FEE1F80A5D87FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90 +381FF80790B5EA0F804814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE +143F5A151FA46CEC0F00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C +14F06C6C7F01077F9038007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FC +A56CEC0FC0A26CEC1F806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0 +D8700790C7FC23357CB32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400 +B3AF90383FFFFCA2497F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C +13C03B03F00001F800B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AEC +E0FF6DB5C7FC6D5B010313F86D5B9038003F802B3480B22C>III<3A3FFF03FFE0484913F0148714076C6D13E03A01 +F800FE007F0000495A13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D +90C7FCA26D5AA26D5AA2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB +7F01017E7FEBFE00497F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE +6C15FC497E27337EB22C>II<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC +17416FB92C>91 D<127012F8A27E127C127E123E123F7EA27F120F7F12077F12037F1201 +7F12007F137C137E133EA2133F7F80130F80130780130380130180130080147C147E143E +A2143F8081140F81140781140381140181140081157CA2157E153E153F811680150FA2ED +070021417BB92C>I<387FFFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC1741 +7DB92C>II<007FB6FCB71280A46C150021067B7D +2C>I<1338137CEA01FC1203EA07F813F0EA0FC0EA1F80A2EA3F00123E127E127CA212FC +5AA3EAFFC013E013F013F8A2127FA2123F13F0EA1FE0EA07C00E1D72B82C>I<3801FFF0 +000713FE001F6D7E15E048809038C01FF81407EC01FC381F80000006C77EC8127EA3ECFF +FE131F90B5FC1203120F48EB807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003 +383FE01F6CB612FC6C15FE6C14BF0001EBFE1F3A003FF007FC27247CA32C>II<90 +3803FFE0011F13F8017F13FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC +5A127EA25AA8127EA2127F6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A +6C5C6C6C5B011F13E0010390C7FC21247AA32C>III103 +DI< +1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA7387FFFC080B5FC7EA2EA0007B3A8007F +B512FCB612FEA36C14FC1F3479B32C>I107 D<387FFFE0B57EA37EEA0003B3B3A5007F +B61280B712C0A36C158022337BB22C>I<3A7F83F007E09039CFFC1FF83AFFDFFE3FFCD8 +7FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C487E01F013E001E013C0A301C01380B3 +3B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC4913F0023F137F2D2481A32C>I<397F +F01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC00019038F03F80ECC01F02807FEC000F5B +5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029247FA32C>II<397FF01FE0 +39FFF8FFF801FB13FE90B6FC6C158000019038F07FC09138801FE091380007F049EB03F8 +5BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE0 +9138E07FC091B51280160001FB5B01F813F8EC3FC091C8FCAD387FFFE0B57EA36C5B2736 +7FA32C>I<903903FC078090391FFF0FC0017F13CF48B512EF4814FF3807FE07380FF001 +48487E49137F4848133F90C7FC48141F127E150F5AA87E007E141FA26C143F7F6C6C137F +6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F6D130FEB07F890C7FCAD0203B5FC4A +1480A36E140029367DA32C>II<90387FF8700003B512F8120F5A5A387FC00F387E00034813015AA36CEB +00F0007F140013F0383FFFC06C13FE6CEBFF80000314E0C66C13F8010113FCEB0007EC00 +FE0078147F00FC143F151F7EA26C143F6D133E6D13FE9038F007FC90B5FC15F815E000F8 +148039701FFC0020247AA32C>I<131E133FA9007FB6FCB71280A36C1500D8003FC8FCB1 +ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB51280160001035B6D13F89038003FE023 +2E7EAD2C>I<3A7FF003FF80486C487FA3007F7F0001EB000FB3A3151FA2153F6D137F39 +00FE03FF90B7FC6D15807F6D13CF902603FE07130029247FA32C>I<3A3FFF03FFF04801 +8713F8A36C010313F03A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC090 +3807EF80EB03FF6D90C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83 +E090381F01F0013F7FEB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC +140127247EA32C>120 D<3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F +806C7E151F6D140012005D6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815D +A2EB07C1ECC3E0A2EB03E3ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA2 +14FC5CA2EA0C01003F5BEA7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E0 +27367EA32C>I<15FF02071380141F147F91B512004913C04AC7FCEB03F85CB31307EB1F +E013FF007F5BB55A49C8FC6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E +1380141F14070200130021417BB92C>123 D<127812FCB3B3B3A9127806416DB92C>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fe ecti1000 10 33 +/Fe 33 122 df28 D<150C151C153815F0EC01E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303 +495A5C130F49C7FCA2133EA25BA25BA2485AA212035B12075BA2120F5BA2121FA290C8FC +A25AA2123EA2127EA2127CA412FC5AAD1278A57EA3121C121EA2120E7EA26C7E6C7EA212 +001E5274BD22>40 D<140C140E80EC0380A2EC01C015E0A2140015F0A21578A4157C153C +AB157CA715FCA215F8A21401A215F0A21403A215E0A21407A215C0140F1580A2141F1500 +A2143EA25CA25CA2495AA2495A5C1307495A91C7FC5B133E133C5B5B485A12035B48C8FC +120E5A12785A12C01E527FBD22>I<4B7EA3150393C8FCA35D1506A3150E150CA3151C15 +18A315381530A31570B912E0A2C80060C8FC15E05DA314015DA3140392C9FCA35C1406A3 +140E140CA3141C1418A2333275AD40>43 DI<120E +EA3F80127F12FFA31300127E123C0909778819>46 D<0103B612FEEFFFC018F0903B0007 +F8000FF84BEB03FCEF00FE020F157FF03F804B141F19C0021F150F19E05D1807143F19F0 +5DA2147FA292C8FCA25C180F5CA2130119E04A151FA2130319C04A153FA201071780187F +4A1600A2010F16FEA24A4A5A60011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC01 +7FEC03F84C5A91C7EA1FC04949B45A007F90B548C8FCB712F016803C397CB83F>68 +D<0103B512F8A390390007F8005DA2140FA25DA2141FA25DA2143FA25DA2147FA292C7FC +A25CA25CA21301A25CA21303A25CA21307A25CA2130FA25CA2131FA25CA2133FA25CA213 +7FA291C8FC497EB6FCA25C25397CB820>73 D<0107B512FCA25E9026000FF8C7FC5D5D14 +1FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A25CA213 +0F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317C091C7 +1207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>76 +D79 +D81 D<92383FC00E913901FFF01C020713FC91 +391FC07E3C91393F001F7C027CEB0FF84A130749481303495A4948EB01F0A2495AA2011F +15E091C7FCA34915C0A36E90C7FCA2806D7E14FCECFF806D13F015FE6D6D7E6D14E00100 +80023F7F14079138007FFC150F15031501A21500A2167C120EA3001E15FC5EA3003E4A5A +A24B5AA2007F4A5A4B5A6D49C7FC6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F13 +8026C003FCC8FC2F3D7ABA2F>83 D<0007B812E0A25AD9F800EB001F01C049EB07C0485A +D900011403121E001C5C003C17801403123800785C00701607140700F01700485CA2140F +C792C7FC5DA2141FA25DA2143FA25DA2147FA292C9FCA25CA25CA21301A25CA21303A25C +A21307A25CA2130FA25CEB3FF0007FB512F8B6FCA2333971B83B>I<14F8EB07FE90381F +871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F5CA2EA3F801403007F +5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F1587007C017F1300ECFF +076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677A42A>97 +D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE9038EF0F +80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A127EA214 +0F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03E0383E07 +C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E090381F00 +70017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC485AA2127F +90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F806CEB3E00 +380F81F83803FFE0C690C7FC1D2677A426>II<147F903803FFC090380FC1E09038 +3F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F80397F81 +FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0EC03C06C +EB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>IIIII108 +DII<147F903803FFC090380FC1F090381F00F8 +017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7FCA215FF5A +4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003EEB3F00147E +6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391FE03FF09039 +3CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA01E113C15C +A2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC80035E013F495A +6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA21201A25BA212 +03A25B1207B512C0A3293580A42A>I<3903C003F0390FF01FFC391E783C0F381C7C703A +3C3EE03F8038383FC0EB7F800078150000701300151CD8F07E90C7FCEAE0FE5BA2120012 +015BA312035BA312075BA3120F5BA3121F5BA3123F90C9FC120E212679A423>114 +D<14FE903807FF8090380F83C090383E00E04913F00178137001F813F00001130313F0A2 +15E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F6D13807F010F13C01300143F141F14 +0F123E127E00FE1480A348EB1F0012E06C133E00705B6C5B381E03E06CB45AD801FEC7FC +1C267AA422>II<01F013 +0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14 +0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14 +0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>118 +D<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F0180 +13C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FEA25C +A21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307010E +EB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>120 +D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913 +1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D +A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48 +133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023 +3679A428>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Ff cmsy10 10 1 +/Ff 1 16 df15 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fg ecbx1000 10 36 +/Fg 36 119 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF +8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390 +C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D45 +DI<141E143E +14FE1307137FB5FCA3138FEA000FB3B3A5007FB61280A4213679B530>49 +DI54 D58 D66 DII73 +D76 DII< +EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF0 +6D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A200 +3F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C +4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9 +C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>III83 D85 DII<13 +FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC00280EB +3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE06E14 +C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A7EB9 +35>98 D100 +D<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC +1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F +6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025 +257DA42C>II<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C13 +8F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907 +FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E0 +6C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C +6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I< +EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8 +A4153B7DBA1B>105 D<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED +1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F80 +6E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>107 +D<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601 +FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA +CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0 +A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007 +13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801 +FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81 +491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C +6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9038FE03F000FFEB +0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC +91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFEF8000F13FF381FC00F +383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C +14F06C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14 +F8EB80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B +5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E09038 +3FFFC06D1380903803FE001D357EB425>I118 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fh ecrm1000 10 89 +/Fh 89 126 df<486C1360000314E039070001C0000EEB038048EB070000181306003813 +0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0 +A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80 +3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7 +12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I21 D27 +DI30 D36 D<141FEC7FC0903801F0 +E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530A21570 +5D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF8000107ED +0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E015302601C07F +1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC007E90 +3807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B701306 +6C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFFF0C690 +26FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3127F12 +1C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014E0EB01 +C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123E +A35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E +7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E +6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F +80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A +5A13527CBD20>I<1530B3A8B912FCA2C80030C8FCB3A836367BAF41>43 +D<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A +12600A19798817>II<121C127FEAFF80A5EA7F00121C09097988 +17>I<1506A2150E150CA2151C151815381530A215701560A215E015C0A214011580A214 +0315005C1406A2140E140CA2141C1418A214381430A21470146014E05CA213015CA21303 +91C7FCA25B1306A2130E130C131C1318A213381330A213701360A213E05BA212015B1203 +90C8FCA25A1206A2120E120CA2121C1218A21238123012701260A212E05AA21F537BBD2A +>II +III<1538A2157815F8A214011403 +1407A2140F141F141B14331473146314C313011483EB030313071306130C131C13181330 +1370136013C01201EA038013005A120E120C5A123812305A12E0B712F8A3C73803F800AA +4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038F003F890B5FC5D5D1580 +92C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038E007E03907C003F0496C +7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713005D12FC00605C12704A +5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC38007FFCEB1FE021397CB62A +>II<12301238123E003FB612E0A316C05A168016 +000070C712060060140E5D5D00E014304814705D5DC712014A5A4AC7FC1406140E5CA25C +1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5137FA96DC8FC131E233A +7BB72A>III<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>I<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A +1206120E5A5A5A12600A3479A317>II<007FB812F8B912FCCCFCB0B912FC6C17F836147B9E41>I<12E01278121EEA07C0 +EA01F0EA003C130FEB03C0EB00F0143C140FEC03E0EC00F8151EED0780ED01E0ED007816 +1EEE07C0EE01F0EE003C170FEF03C0A2EF0F00173CEE01F0EE07C0041EC7FC1678ED01E0 +ED0780031EC8FC15F8EC03E0020FC9FC143C14F0EB03C0010FCAFC133CEA01F0EA07C000 +1ECBFC127812E0322E79AB41>II<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA202 +0E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D90180 +7F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7E +A213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65 +DI<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03 +FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48 +48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312 +3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0 +5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D +7BBA3C>IIIIIII<013FB512 +E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C +5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>IIIIIIIII< +D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F +003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13 +F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0 +151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D +EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I< +003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730 +A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>IIII89 D<003FB7FCA39039FC0001FE +01C0130349495A003EC7FC003C4A5A5E0038141F00784A5A12704B5A5E006014FF4A90C7 +FCA24A5A5DC712074A5AA24A5A5D143F4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB +0180A2495A5C137F495A16034890C7FC5B1203485AEE0700485A495C001F5D48485C5E48 +48495A49130FB8FCA329397BB833>II93 D<007FB81280B912C0A26C17 +803204797041>95 D97 DIIII<147E903803FF8090 +380FC1E0EB1F8790383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FC +B3AB487E387FFFF8A31C3B7FBA19>IIIIIII<2703F00FF0EB1FE000FFD93FFCEB +7FF8913AF03F01E07E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC +49D907F8EB0FC0A2495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445 +>I<3903F00FF000FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7E +A25BA35BB3A3486C497EB500C1B51280A329257EA42E>II<3903F01F +E000FFEB7FF89038F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F8 +49130116FC150016FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614 +C09039F7803F009038F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E> +II<3807E01F00FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E0 +9038FC0080491300A45BB3A2487EB512F0A31C257EA421>II<1318A51338A31378A313F812011203 +1207001FB5FCB6FCA2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFE +EB01F81A347FB220>IIIIII<003FB512FCA2EB8003D83E0013F8003CEB07F00038 +EB0FE012300070EB1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495A +A290387F000613FEA2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48 +EB03FC90B5FCA21F247EA325>II<126012F0B3B3B3 +B3A91260045377BD17>I<12FCEAFFC0EA07F0EA01FCEA007E7F80131F80130FB3A78013 +07806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C130F5CB3A7131F5C +133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fi ecbx1440 14.4 34 +/Fi 34 118 df28 D45 D<151E153E15FE1403140F147FEB07FF00 +03B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A6007FB712FCA52E4E76CD42>49 +DI<913807FFC0027F13FC0103B67E010F15E090 +261FF80313F890267FC0007F01FEC7EA3FFE48488148486E138013FE486C6C6D13C08048 +17E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0 +030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E09238007FF8EE3FFE707E70 +138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218 +FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD80FF04A1380D807FE91387F +FE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114FCD9001F1380374F7BCD42 +>I<17FC1601A216031607160FA2161F163F167FA216FF5D5DA25D5D5D167F153E157E15 +FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14FC495A5C495A1307495A5C +49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E127E5ABA1280A5C901FCC7 +FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FEEC01FED9FFF0133F91B65A +5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFCAC913807FF80023F13F891 +B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E496E7E01F86E7E5B70138049 +16C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212FF7FA218F0A25B5E6C4816 +E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CECFFFCD803FE4913F02701FF +E00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFCC8FC354F7ACD42>I58 +D<932603FFF01407047F01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF +5B020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F +498249498292CA7E4948834948835A4A83485B4885A2484984A2485B87A2485B87A25AA2 +98C8FC91CFFCA2B5FCAE7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F +7E806C7F137F6D7E816D6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F +01FCEC3FE30203903AFFE001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02 +801303040301F8CAFC595479D267>71 D73 D76 +D78 D80 D<93381FFF800303B512FC033FECFFC0 +92B712F00207D9F80113FE021F903AC0003FFF804A48C700077FDAFFF8020113F049496E +7F49496F7E49496F7E49496F7E4990C96C7F4948707F4948707F01FF854849707F4A8248 +86A24849717E48864A83A2481B80A248497113C0A4481BE0A291CB7EA3B51AF0AF6C1BE0 +A36E5FA26C1BC0A36C1B806E5FA26C1B006E5F6C62A26C6DD903FC4A5A6CDB0FFF5D6E49 +EBC0016C4B01E05C6D6C90277E07F0035B6E9039F801F807902A3FFF01F000780F5B6D04 +7C5C6DD981E06D4890C7FC6D01E191381F7FFE010101F1EDFFF86DD9F9F06D5BDA3FFF16 +C06E6D013F5B02079027FE01FFFEC8FC020190B612F8DA003F4B141003071838DB001FEB +83F893C7EA03FC1C7885726C14F8F2C003F2F01F97B512F084A31CE085A27314C01C8085 +1C00735B735B735B735B9638003FC0556A79D263>III<003FBB12FCA59126C0007FEB000301FCC7ED003FD87FF0F00FFE491807 +49180349180190C81600A2007E1A7EA3007C1A3EA500FC1A3F481A1FA6C91700B3B3AC49 +B912C0A550517BD05B>I97 D<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93FFCEB +07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A007F92 +C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D147E +6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F80203 +138031387CB63A>99 D<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13F8 +49B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F48498048 +4980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C6D +5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B5120F +010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE01 +076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E488248 +90C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F12 +3FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC495A +D91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB63C +>IIII<133FEBFFC0 +487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6B6 +12F0A51C547CD324>I108 +DII<913801FFC0023F13FE91B67E010315E001 +0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883 +488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F +A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE +6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>II<90393FF001FCB590 +380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF7 +80A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114 +D<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0130F484813034848 +1301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C +14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14C0EC003F030713E0 +150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE90 +39FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA6 +14FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B512FEB7FCA426007F +FCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F +1380DA03FEC7FC294D7ECB33>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fj ecrm0900 9 5 +/Fj 5 109 df<123C127E12FFA4127E123C08087A8715>46 D97 DI104 +D108 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fk ecbx0900 9 7 +/Fk 7 117 df65 D97 DI<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0 +A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8 +07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF +EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049 +1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407 +5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB +007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38 +E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807 +FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fl ecrm1200 12 25 +/Fl 25 122 df<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A3120113 +80120313005A1206120E5A5A5A12600B1D78891B>44 D<14FF010713E090381F81F89038 +3E007C01FC133F4848EB1F8049130F4848EB07C04848EB03E0A2000F15F0491301001F15 +F8A2003F15FCA390C8FC4815FEA54815FFB3A46C15FEA56D1301003F15FCA3001F15F8A2 +6C6CEB03F0A36C6CEB07E0000315C06D130F6C6CEB1F806C6CEB3F00013E137C90381F81 +F8903807FFE0010090C7FC28447CC131>48 D50 D54 D<16C04B7EA34B7EA34B7EA34B7EA3ED +19FEA3ED30FFA203707FED607FA203E07FEDC03FA2020180ED801FA2DA03007F160FA202 +06801607A24A6D7EA34A6D7EA34A6D7EA20270810260147FA202E08191B7FCA249820280 +C7121FA249C87F170FA20106821707A2496F7EA3496F7EA3496F7EA201788313F8486C83 +D80FFF03037FB500E0027FEBFFC0A342477DC649>65 DI68 D77 +D<003FB912F8A3903BF0001FF8001F01806D481303003EC7150048187C0078183CA20070 +181CA30060180CA5481806A5C81600B3B3A54B7EED7FFE49B77EA33F447DC346>84 +D +I97 +D99 D<167FED3FFFA315018182B3EC7F80903803 +FFF090380FC07C90383F000E017E1307496D5AD803F87F48487F5B000F81485AA2485AA2 +127FA290C8FC5AAB7E7FA2123FA26C7EA2000F5D7F6C6C5B00035C6C6C9038077F806C6C +010E13C0013F011C13FE90380FC0F8903803FFE09026007F0013002F467DC436>II103 D105 D108 D<3901FC01FE00FF903807FFC091381E +07F091383801F8000701707F0003EBE0002601FDC07F5C01FF147F91C7FCA25BA35BB3A8 +486CECFF80B5D8F83F13FEA32F2C7DAB36>110 DI<3903F803F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC00 +7E153C01FF13005BA45BB3A748B4FCB512FEA3202C7DAB26>114 +D<90383FE0183901FFFC383907E01F78390F0003F8001E1301481300007C1478127800F8 +1438A21518A27EA27E6C6C13006C7E13FC383FFFE06C13FC6C13FF6C14C06C14E0C614F0 +011F13F81300EC0FFC140300C0EB01FE1400157E7E153EA27EA36C143C6C147C15786C14 +F86CEB01F039F38003E039F1F00F8039E07FFE0038C00FF01F2E7DAC26>I<1306A5130E +A4131EA3133E137EA213FE12011207001FB512F0B6FCA2C648C7FCB3A4150CAA017E131C +017F1318A26D133890381F8030ECC070903807E0E0903801FFC09038007F001E3E7EBC26 +>III< +B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E0000150C6D141C6D1418A2 +6E1338013F1430A26D6C5BA26E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801 +FC06A2ECFE0E0100130CA2EC7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA214 +06A35CA25CA2123C007E5BB4FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03 +F02E3F7EAA33>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fm ecbx1200 12 47 +/Fm 47 123 df<0118140C017C143E01FC147E48485C4848495A495C4848495A4848495A +001F140F90C75B003E4AC7FCA2003C141E007C143E0078143CA200F8147CA2481478D8F1 +F014F8D8F7FCEB7BFEB46CEB7FFF6D1580028014C0A36C80A36C806C496C13806C486D13 +006C486D5AD801F0EB00F82A2283C427>16 DI28 D46 D48 DIII<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715 +C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B +485A485A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A53141 +7DC038>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8 +FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E +01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317 +F05B5D6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEB +FFFC6CB612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0 +027F13FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE04849 +5A5A1400485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381F +FF8000FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C0 +5B6F13E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D +4913806C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC903800 +3FF02D427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A248168000 +7EC8EA3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A +5A14035D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A +6D5A2F447AC238>I58 D<1A60F101F01907191FF17FC0953801FF00F007FCF01FF0F07FC04D48C7FCEF07 +FCEF3FF0EFFFC0040390C8FCEE0FFCEE3FE0EEFF80DB03FEC9FCED0FF8ED3FE0EDFF80DA +07FECAFCEC1FF8EC7FE0903801FF80D907FCCBFCEB1FF0EB7FC04848CCFCEA07FCEA1FF0 +EA7FC048CDFCA2EA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FC903801FF809038 +007FE0EC1FF8EC07FE913800FF80ED3FE0ED0FF8ED03FE923800FF80EE3FE0EE0FFCEE03 +FF040013C0EF3FF0EF07FCEF01FF9438007FC0F01FF0F007FCF001FF9538007FC0F11FF0 +19071901F10060444277B957>60 D<126012F812FE6C7EEA3FE0EA0FF8EA03FEC66C7EEB +3FE0EB0FF8EB03FE903800FFC0EC3FF0EC0FFCEC03FF9138007FC0ED1FF0ED07FCED01FF +9238007FC0EE1FF0EE07FE933801FF809338007FE0EF1FF8EF03FE943800FF80F03FE0F0 +0FF8F003FE953800FF80F13FE0F10FF0A2F13FE0F1FF80953803FE00F00FF8F03FE0F0FF +80DD03FEC7FCEF1FF8EF7FE0933801FF80DC07FEC8FCEE1FF0EE7FC04B48C9FCED07FCED +1FF0ED7FC0DA03FFCAFCEC0FFCEC3FF0ECFFC0D903FECBFCEB0FF8EB3FE0EBFF80D803FE +CCFCEA0FF8EA3FE0EAFF8048CDFC12F81260444277B957>62 D<923803FFF0037FEBFF80 +0203B612F0020F15FC913A3FFC000FFFDAFFC0010013C0D903FEC8EA1FF0D907F0ED03F8 +D91FC0ED00FE4948167F017ECAEA1F8049717E4848717E49DAFF8013034848010F01F06D +7E4848013F01FC6D7E92B6FC4848489026C07F80137C49489026001FC0133C484948D907 +E0133E001E49486D6C131E003E49480101141F023F913800FFE0003C4A82007C017F1880 +007819074A5AA300F81AC04848491603AB6C6C7F12781B801A076E7E127C003C133F003E +6E1700021F4A5C001E6D6C5B001F6D6C49EBF01E6C6D6C011F143E6D6CD9C07F6D5A6C6C +6C90B5383FFFF8033FD9FC0F5B6C6C010FD9F0035B6C6C0100903980007F806D91CBFC6C +7E137E6D7E6D6CEF7FC0D907F0EE03FFD903FE043F1300902600FFC0913803FFF8DA3FFC +49B512C0020FB748C7FC020316E0DA007F02FCC8FC030349C9FC4A477AC557>64 +DIIII73 D77 D<923807FFC092B512FE0207ECFFC0021F15F0 +91267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E4948 +6F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F049 +82003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19 +F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D +6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C002 +004AC8FC030713C047467AC454>79 D83 D<007FBA12E0BB12F0A46C19E04406776757>95 D<903801FFE0011F13FE017F6D +7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0 +90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B +127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF8 +6CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 DIIIIIII<137C48B4FC4813804813C0A24813E0A56C13 +C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520> +I108 D<90277F8007FEEC0FFC +B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D +8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E +A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038 +3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02 +F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>II<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F +FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF +3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F +FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>II<90387F807FB53881FFE002 +8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED +01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F +381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F +FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000 +F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A +00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>II< +D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7 +13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I +I120 +D<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B00 +3C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A49 +48130F49481400A2485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4 +292C7DAB32>122 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fn ecrm1728 17.28 8 +/Fn 8 117 df68 D70 D97 D102 D<1378EA01FE487E487FA66C +90C7FC6C5AEA007890C8FCB3A2EB0780EA0FFFB5FCA41203C6FCA2137FB3B3AC497E487F +B61280A4195F7BDE25>105 D<010FEB07F8D80FFFEB1FFEB590387FFF809238F81FC091 +3801E03F913903C07FE00003EB0780C6EB0F00140E6D5A0218EB3FC00238EB1F800230EB +0600027090C7FCA2146014E0A25CA55CB3B0497E4813F0B612F8A42B3F7BBE34>114 +D<9138FFC003010FEBF807017FEBFE0F3A01FF003F9FD803F0EB07DF48486DB4FCD80F80 +1300001F8148C8FC003E81007E81127C00FC81A4827EA27E7F6C7E6D91C7FC13F8EA3FFE +381FFFE06C13FF15F0000314FE6C6E7E6C6C14E0011F14F801078001008002077FDA003F +13801507030113C0ED007F00E0ED3FE0161F17F06C150F1607A36C1503A37EA26C16E016 +077E17C06D140F6D15806D141FD8FDF0EC3F00D8F8F8147E017C495A3AF01F801FF06DB5 +12C0D8E00391C7FC39C0007FF02C417CBF35>I<1470A714F0A51301A31303A21307A213 +0FA2131F133F137F13FF1203000F90B6FCB8FCA326000FF0C8FCB3AEEE01C0AE6D6CEB03 +80A316076D6C14005E6D6C130E6D6C131E6E6C5A91383FE0F86EB45A020713C0020090C7 +FC2A597ED734>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fo ecbx1728 17.28 18 +/Fo 18 117 df68 D<942603FFF8151C94B66C +143C040F03F0147C047F03FC14FC0303B81301030FDAC00113C0033F01F8C7381FF00392 +B500C0913807F807020349C83801FE0F020F01F89238007F1F4A01E0EE3FBF4A49EE0FFF +91B5CA7E494983494983494983495B4949187F4B183F491A1F495B90B5CC120FA2484919 +075A4A19035A4A19015AA24A19005AA348491A7CA35A9AC8FCA35CA2B5FCB07EA26E043F +B81280A47E96C7000701FCC7FCA26C7FA37E80A27E807E807E6C7FA26D7F6D7F7F816D7F +6D6D5F6D7F6D6D5F6D6D7E023F6D5E6E01F05E6E6DEEFE7F020301FF923801FC3F020002 +C0913807F80F033F01FC91381FF007030F903BFFE001FFC001030391B6EA8000DB007F4B +C7123C040F03F8140C040003C091C8FC050301F8CBFC696677E37A>71 +D82 D<001FBD12F0A59126F8000191C7123F4801C0 +060713F849C71700491A7F01F01A1F491A0F491A07A2491A03A290C81801A2007EF300FC +A4007C1C7CA7481C3EA5C91900B3B3B3A5023FB912F8A55F617AE06C>84 +D<913803FFF0027F13FF0103B612E0010F15F890263FFC0013FED97FC090381FFF8049C7 +6C7F4801C06D7F486D6D7F6E6D7F48836E7F84177F84A36C496E7FA26C5B6C5B013FC8FC +90C9FCA75F0307B6FC4AB7FC141F91B5EAF03F0103EBFE00010F13F0013F1380D9FFFEC7 +FC485B485B485B485B485B485BA24890C8FC1A7CA2485AA35FA394B5FC7F6C5D6EEB03DF +6CDB07CFEBC0F86C6DEB0F8F6C6DD91F07EBF3F06C01F8017E14FF6C9027FE01FC0314E0 +C690B5D8F00114C0013F9126C0007F1380010791C7383FFE009026003FF8EC07F846437B +C14D>97 D<903807FF80B6FCA5C6FC7F7FB3A9933801FFE0041F13FE047FEBFFC00381B6 +12F0922687FC0113FC923A9FE0003FFEDBBF8090380FFF8003FEC76C7F4B6E7F4B6E7F4B +6E7F4B824B157F4B82737EA21B80851BC0A31BE085A41BF0AE1BE0A44F13C0A31B80A24F +1300A262197F6F5E6F4B5A4E5B6F4A5BDAFCF84A5BDAF87E4A5B4A6C4A90C7FC9126E01F +C0EB7FFC913BC00FF803FFF8DA8003B612E091C71580013E023F01FCC8FC90C800031380 +4C657CE356>II101 DII105 D<903807FF80B6FCA5C6FC7F7FB3B3B3B3AFB7 +12E0A523647CE32A>108 D110 D<92381FFF804AB512F8020F +14FF023F15C09126FFFC0313F001039039E0007FFC490180EB1FFED91FFEC73807FF8049 +486E7F49486E7F49486E7F48496F7EA248496F7E4884A248496F7EA2481980A24819C091 +C97EA24819E0A5B518F0AD6C19E0A46C6D4B13C0A36C1980A26C6D4B1300A26C606E157F +6C606C6D4B5A6C606D6C4A5B6D6C4A5B6D6C4A5B6D6C6C011F90C7FC010301E0EB7FFC6D +9039FC03FFF86D6CB612E0020F92C8FC020114F8DA001F138044437CC14D>I<903B07FF +8001FFE0B6011F13FE047FEBFFC00381B612F0922687FC0313FC923A9FE0007FFEC6DABF +806D6C7E6D01FEC7000F7F6D496E7F4B824B6E7F4B6E7F4B804B82737EA21B80851BC0A2 +851BE0A4851BF0AE4F13E0A41BC061A21B80A24F1300A24F5AA26F4A5B6F4A5B626F4A5B +6F4A5B03FE4A5B03BF027F90C7FCDB9FC0EBFFFC92268FF8075B0383B612E00380158004 +3F01FCC8FC0403138093CBFCB3A4B712E0A54C5D7CC056>I114 DII E +%EndDVIPSBitmapFont +end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%PaperSize: A4 + +%%EndSetup +%%Page: 1 1 +1 0 bop 290 639 a Fo(Genealogical)56 b(Represen)l(tation)e(of)f(T)-13 +b(rees)52 b(in)g(Databases)1686 822 y Fn(First)46 b(Draft)1247 +1063 y Fm(Miguel)36 b(Sofer)i()1359 1179 +y Fl(Univ)m(ersidad)33 b(T)-8 b(orcuato)33 b(Di)f(T)-8 +b(ella)1728 1295 y(Buenos)33 b(Aires)1797 1411 y(Argen)m(tina)1746 +1606 y(Ma)m(y)h(6,)e(2000)1839 1905 y Fk(Abstract)441 +2035 y Fj(blah)25 b(blah)h(.)13 b(.)g(.)118 2310 y Fi(1)131 +b(In)l(tro)t(duction)118 2491 y Fh(T)-7 b(rees)28 b(are)h(a)g(v)n(ery)f +(frequen)n(t)h(data)f(structure.)41 b(They)30 b(are)e(the)h(natural)g +(represen)n(tation)e(for)i(instance)g(for)f(organiza-)118 +2591 y(tional)f(c)n(harts,)g(threaded)g(discussion)g(groups,)f(some)h +(bills)g(of)h(materials,)e(.)14 b(.)g(.)243 2691 y(A)n(t)28 +b(least)f(t)n(w)n(o)f(alternativ)n(e)h(represen)n(tations)e(for)i +(trees)g(in)h(RDBMs)g(are)e(kno)n(wn)h(and)h(used:)220 +2857 y(1.)41 b Fg(P)m(oin)m(ters:)k Fh(a)31 b(\034eld)h(in)h(the)f(c)n +(hild)g(record)e(references)h(the)h(paren)n(t)f(no)r(de.)50 +b(This)32 b(seems)g(to)f(b)r(e)i(the)f(canonical)326 +2956 y(represen)n(tation.)38 b(Some)29 b(DB)g(engines)f(pro)n(vide)g +(sp)r(ecial)g(SQL)g(extensions)g(to)h(simplify)g(tree)g(searc)n(hes;)e +(Oracle)326 3056 y(tree)d(extensions)g(are)g(an)h(example)f(\(see)h +(for)f(instance)g([1]\);)i(DB2's)f(WITH)g(can)f(b)r(e)i(used)e(for)h +(this)g(purp)r(ose)f(to)r(o)326 3156 y(\(see)j([3],)g(pp)h(139-162\).) +220 3322 y(2.)41 b Fg(Nested)35 b(Sets:)43 b Fh(t)n(w)n(o)30 +b(n)n(umeric)h(\034elds)g(in)g(ev)n(ery)f(no)r(de)h(record)f(co)r(de)h +(the)g(tree)g(structure.)47 b(I)31 b(can't)g(pro)n(vide)f(a)326 +3421 y(b)r(etter)e(or)e(briefer)h(description)g(of)h(this)g(metho)r(d)g +(than)f(the)h(four)f(articles)g([2].)118 3587 y(These)g(t)n(w)n(o)g +(metho)r(ds)h(o\033er)f(di\033eren)n(t)h(adv)-5 b(an)n(tages)25 +b(and)j(disadv)-5 b(an)n(tages:)243 3753 y Ff(\017)41 +b Fh(P)n(oin)n(ters)30 b(are)g(extremely)g(e\036cien)n(t)h(for)f(no)r +(de)h(insertion)f(and/or)g(deletion,)h(but)h(require)e(recursiv)n(e)f +(table)i(ac-)326 3853 y(cesses)e(to)h(searc)n(h)f(the)h(tree)g(\(I)h +(do)f(not)g(kno)n(w)f(the)i(implemen)n(tation)f(details)g(of)g(the)h +(Oracle)e(tree)g(extensions,)326 3953 y(whic)n(h)e(as)g(far)g(as)g(I)g +(kno)n(w)g(ma)n(y)g(solv)n(e)f(this)i(problem)f(in)n(ternally;)g(they)g +(de\034nitely)h(solv)n(e)f(it)g(for)g(the)h(end)g(user\).)243 +4119 y Ff(\017)41 b Fh(Nested)30 b(sets)g(are)f(v)n(ery)f(e\036cien)n +(t)i(for)g(tree)f(searc)n(hes,)g(but)i(are)e(rather)f(exp)r(ensiv)n(e)i +(for)f(no)r(de)h(insertion)f(and/or)326 4218 y(deletion:)37 +b(they)27 b(require)g(up)r(dating)g(p)r(oten)n(tially)h(man)n(y)f(no)r +(des.)243 4384 y(W)-7 b(e)30 b(prop)r(ose)f(here)h(a)g(di\033eren)n(t)h +(represen)n(tation,)e(based)g(on)i(no)r(de)f(iden)n(ti\034ers)g(whic)n +(h)g(are)f(\020genealogical)f(iden)n(ti-)118 4484 y(\034ers\021:)44 +b(they)32 b(con)n(tain)f(the)h(complete)f(genealogy)f(of)h(the)h(no)r +(de,)h(i.e.,)g(the)f(list)g(of)g(ancestors)d(up)j(to)g(the)g(ro)r(ot)f +(of)g(the)118 4584 y(tree.)243 4683 y(This)j(allo)n(ws)f(to)i(replace)e +(man)n(y)h(searc)n(hes)f(in)h(database)g(tables)g(with)h(string)f(op)r +(erations)f(on)h(the)h(index.)58 b(The)118 4783 y(result,)24 +b(as)f(explained)h(in)g(Section)g(3)f(is)h(that)g(tree)f(searc)n(hes)f +(pro)r(ceed)h(at)h(\020nested)f(sets\021)30 b(sp)r(eed,)25 +b(while)f(no)r(de)g(insertions)118 4882 y(and)k(deletions)f(are)f(as)h +(fast)h(as)f(with)h(p)r(oin)n(ters.)243 4982 y(The)i(ob)n(vious)f(do)n +(wnside)h(of)h(the)g(metho)r(d)g(is)f(that)h(the)g(primary)f(k)n(ey)f +(in)i(the)g(tree)f(needs)h(to)f(b)r(e)h(a)g(v)-5 b(ariable)29 +b(size)118 5082 y(text)j(\034eld,)h(and)f(that)g(the)g(iden)n +(ti\034ers)f(ma)n(y)g(b)r(e)i(extremelly)e(long)g(for)g(deep)h(trees.) +49 b(W)-7 b(e)32 b(will)g(pro)n(vide)e(estimates)i(of)118 +5181 y(the)c(size)f(required)g(as)g(a)g(function)h(of)g(the)f +(magnitude)h(of)f(the)h(tree.)1987 5653 y(1)p eop +%%Page: 2 2 +2 1 bop 118 291 a Fi(2)131 b(Genealogical)45 b(iden)l(ti\034ers)g(for)f +(trees)118 489 y Fm(2.1)112 b(De\034nition)118 642 y +Fh(W)-7 b(e)28 b(de\034ne)g Fe(gene)l(alo)l(gic)l(al)k(identi\034ers)j +Fh(recursiv)n(ely)25 b(as)i(follo)n(ws:)326 808 y Fg(De\034nition:)59 +b Fe(The)42 b(gene)l(alo)l(gic)l(al)h(identi\034er)f(\(gID\))e(of)i(a)f +(no)l(de)h(is)f(obtaine)l(d)h(by)g(app)l(ending)g(a)f(child)326 +908 y(identi\034er)30 b(to)g(the)g(gene)l(alo)l(gic)l(al)h +(identi\034er)g(of)f(the)g(p)l(ar)l(ent)f(no)l(de.)243 +1074 y Fh(Remark)40 b(that)h(genealogical)e(iden)n(ti\034ers)i(are)f +(rather)g(w)n(ell)h(kno)n(wn)f(and)h(used;)48 b(common)41 +b(examples)f(are)g(the)118 1174 y(\020path+\034le-name\021)33 +b(in)28 b(a)f(computer)g(\034le)h(system)f(and)h(the)f(URLs)h(within)g +(a)f(WWW.)243 1273 y(The)d(name)g(\020genealogical)e(iden)n +(ti\034er\021)30 b(is)24 b(suggested)g(b)n(y)g(the)g(fact)h(that)f(the) +h(v)-5 b(alue)24 b(of)g(the)h(iden)n(ti\034er)f(con)n(tains)f(the)118 +1373 y(complete)30 b(genealogy)d(of)j(the)g(no)r(de:)41 +b(it)30 b(con)n(tains)e(as)h(a)h(substring)f(the)h(gID)f(of)h(its)g +(father,)g(whic)n(h)f(in)h(turn)g(con)n(tains)118 1472 +y(as)d(a)g(substring)g(the)h(gID)g(of)f(the)h(grandfather,)e(.)14 +b(.)g(.)243 1572 y(The)27 b(ro)r(ot)g(no)r(de)h(of)f(the)h(tree)f(has)g +(a)h(gID)f(with)h(v)-5 b(alue)28 b(\021)34 b(\(the)28 +b(empt)n(y)g(string\),)f(as)g(it)h(has)f(no)g(paren)n(t.)118 +1804 y Fm(2.2)112 b(Child)36 b(iden)m(ti\034ers)118 1958 +y Fh(The)26 b(ob)n(vious)e(c)n(hild)i(iden)n(ti\034er)g(is)f(a)h +(zero-based)d(coun)n(ter:)35 b(iden)n(tify)26 b(the)h(c)n(hild)e(b)n(y) +h(the)g(n)n(um)n(b)r(er)f(of)h(older)f(brethren)g(it)118 +2057 y(has.)243 2157 y(W)-7 b(e)25 b(could)f(represen)n(t)g(the)h(coun) +n(ter)f(in)h(base)f(10;)h(this)g(ho)n(w)n(ev)n(er)e(is)i(extremely)f(w) +n(asteful)g(of)h(resources.)34 b(It)25 b(is)g(m)n(uc)n(h)118 +2257 y(b)r(etter)33 b(to)f(represen)n(t)f(the)h(coun)n(ter)g(in)g(as)g +(large)e(a)i(base)g(as)f(p)r(ossible:)46 b(in)n(terpret)32 +b(as)f(n)n(um)n(b)r(ers)h(a)g(set)g(of)g(c)n(haracters)118 +2356 y(larger)26 b(than)h({0,1,.)14 b(.)g(.)g(9}.)243 +2456 y(As)26 b(tree)f(op)r(erations)f(will)i(in)n(v)n(olv)n(e)f(string) +g(op)r(erations)f(on)i(the)g(indices,)g(in)g(order)f(to)g(a)n(v)n(oid)g +(a)g(\020quoting)g(hell\021)33 b(it)26 b(is)118 2555 +y(desirable)d(to)h(a)n(v)n(oid)e(using)h(an)n(y)g(c)n(haracter)f(with)i +(a)g(sp)r(ecial)f(meaning)h(in)g(LIKE)g(expressions)e(or)g(regular)g +(expressions;)118 2655 y(i.e.,)28 b(w)n(e)f(will)h(not)f(use)h(an)n(y)f +(of)g(the)h(sym)n(b)r(ols)70 b Fd(.)44 b(*)f(^)g(\\)g([)g(])g({)h(})f +(\()g(\))g(<)g(>)71 b Fh(?)37 b(|)28 b(&)f($)243 2755 +y(W)-7 b(e)28 b(prop)r(ose)e(to)h(reserv)n(e)f(also)g(/)i(as)f(a)g +(separator)e(\(see)i(\020V)-7 b(ariable)27 b(Sized)g(gID\021)34 +b(b)r(elo)n(w\).)243 2854 y(If)g(w)n(e)f(limit)i(ourselv)n(es)d(to)i +(ascii)f(c)n(haracters,)g(and)h(a)n(v)n(oid)e(to)i(b)r(e)g(safe)f(a)h +(lot)g(of)g(other)f(c)n(haracters,)g(w)n(e)g(can)h(use)118 +2954 y(n)n(um)n(b)r(ers)27 b(in)h(base)f(64)g(b)n(y)g(represen)n(ting) +243 3120 y Ff(\017)41 b Fh(0-9)26 b(with)i('0'-'9')f(\(dec)g(ascii)g +(co)r(de)h(48-57\))243 3286 y Ff(\017)41 b Fh(10)26 b(with)i(':')37 +b(\(dec)28 b(ascii)f(co)r(de)h(58\))243 3452 y Ff(\017)41 +b Fh(11)26 b(with)i(';')g(\(dec)g(ascii)f(co)r(de)g(59\))243 +3618 y Ff(\017)41 b Fh(12-37)25 b(with)j('A'-'Z')g(\(dec)f(ascii)g(co)r +(de)h(65-90\))243 3784 y Ff(\017)41 b Fh(38-63)25 b(with)j('a'-'z')f +(\(dec)h(ascii)f(co)r(de)g(97-122\))118 3950 y(By)g(using)g(base)f(64,) +h(up)g(to)h(4096)d(c)n(hildren)i(can)f(b)r(e)i(represen)n(ted)e(using)h +(t)n(w)n(o)f(suc)n(h)h(digits,)g(up)h(to)f(262144)d(with)k(three)118 +4050 y(digits,)g(and)f(up)h(to)f(16777216)d(with)k(four)f(digits.)243 +4149 y(If)37 b(the)g(RDBMs)g(supp)r(orts)f(in)n(ternational)g(c)n +(haracters,)h(it)g(is)g(p)r(ossible)f(to)h(further)f(increase)g(the)h +(base;)k(as)36 b(an)118 4249 y(example,)30 b(b)n(y)f(using)g(the)h(95)f +(additional)g(c)n(haracters)e(of)i(the)h(latin-1)f(c)n(haracter)e(set,) +k(w)n(e)e(could)g(co)r(de)g(n)n(um)n(b)r(ers)g(in)h(a)118 +4349 y(base)f(up)g(to)g(160)f(\025)g(remark)g(that)h(ev)n(ery)f(single) +h(digit)g(is)g(still)h(one)e(b)n(yte)h(in)h(this)f(represen)n(tation.) +40 b(This)29 b(means)f(that)118 4448 y(w)n(e)f(expand)h(the)f(sym)n(b)r +(ols)g(ab)r(o)n(v)n(e)f(b)n(y)i(represen)n(ting)243 4614 +y Ff(\017)41 b Fh(64-159)25 b(with)j(dec)f(latin1)g(co)r(de)h(160-255) +243 4780 y(In)23 b(base)g(160,)g(up)g(to)h(25600)d(c)n(hildren)i(can)f +(b)r(e)i(represen)n(ted)e(using)h(t)n(w)n(o)g(digits,)h(up)g(to)f +(4096000)d(with)k(three)f(digits,)118 4880 y(and)28 b(up)f(to)h +(6.5E+08)e(with)i(four)f(digits.)243 4980 y(Remark)g(that)h(base)f(con) +n(v)n(ersions)f(only)h(need)i(to)e(b)r(e)i(p)r(erformed)e(at)h +(insertion)g(time,)g(when)h(the)f(index)g(of)g(a)g(new)118 +5079 y(no)r(de)g(is)f(computed.)37 b(They)28 b(will)f(therefore)g(only) +g(ha)n(v)n(e)f(an)i(impact)f(on)h(insertion)f(timings.)1987 +5653 y(2)p eop +%%Page: 3 3 +3 2 bop 118 291 a Fm(2.3)112 b(Coun)m(ters:)50 b(\020delimited\021)44 +b(vs.)51 b(\020\034xed)38 b(size\021)118 444 y Fh(The)33 +b(standard)g(represen)n(tation)e(of)i(gID)h(uses)e(a)h(v)-5 +b(ariable)32 b(size)h(c)n(hild)h(iden)n(ti\034er,)g(and)f(delimiters)g +(to)h(separate)d(the)118 543 y(gID)f(of)g(the)h(c)n(hild)f(no)r(de)g +(from)f(the)i(gID)f(of)g(its)g(paren)n(t.)43 b(F)-7 b(or)30 +b(example,)g(w)n(e)g(can)f(represen)n(t)g(the)i(\034fth)g(c)n(hild)f +(of)g(no)r(de)118 643 y('/23/27/1')24 b(as)j('/23/27/1/4'.)32 +b(Let)c(us)f(call)g(this)h(a)f Fg(vgID)h Fh(represen)n(tation)e(\(V)-7 +b(ariable)27 b(Size)h(Genealogical)d(ID\).)243 743 y(This)30 +b(represen)n(tation)f(allo)n(ws)f(for)i(an)n(y)g(n)n(um)n(b)r(er)g(of)g +(c)n(hildren)g(of)h(a)f(no)r(de,)h(sub)5 b(ject)30 b(only)g(to)g(the)h +(limitations)f(the)118 842 y(RDBMS)e(ma)n(y)f(ha)n(v)n(e)f(as)h(to)h +(the)g(length)f(of)h(a)f(v)-5 b(ariable)27 b(sized)g(string.)243 +942 y(Alternativ)n(ely)-7 b(,)24 b(w)n(e)f(could)h(c)n(ho)r(ose)f(to)h +(limit)g(from)g(the)g(outset)g(the)g(quan)n(tit)n(y)g(of)f(c)n(hildren) +h(that)g(a)g(no)r(de)g(ma)n(y)f(ha)n(v)n(e;)118 1042 +y(this)28 b(limit)g(w)n(ould)f(dep)r(end)i(of)e(course)f(on)i(the)g +(application.)36 b(Let)27 b(us)h(call)f(this)h(a)f Fg(fgID)h +Fh(represen)n(tation.)243 1141 y(F)-7 b(or)25 b(example,)h(if)g(no)g +(no)r(de)f(is)h(allo)n(w)n(ed)f(to)g(ha)n(v)n(e)g(more)g(than)h(25600)d +(c)n(hildren,)j(w)n(e)g(could)f(represen)n(t)g(the)h(coun)n(ters)118 +1241 y(alw)n(a)n(ys)36 b(with)i(2)f(digits.)67 b(The)38 +b(no)r(de)f(whic)n(h)h(w)n(as)f(previously)f('/23/27/1/4')d(is)k(no)n +(w)g('23270104'.)64 b(If)38 b(w)n(e)f(require)118 1340 +y(a)g(three)g(digit)h(represen)n(tation)d(of)i(no)r(des)g(\(up)h(to)f +(ab)r(out)h(4)f(million)g(c)n(hildren\),)j(then)d(it)h(will)g(b)r(e)f +(represen)n(ted)f(as)118 1440 y('023027001004'.)118 1672 +y Fm(2.4)112 b(Ordering)37 b(of)h(no)s(des)118 1825 y +Fh(F)-7 b(or)35 b(some)g(applications)g(it)h(is)f(necessary)f(to)i +(obtain)f(subtrees)g(ordered)f(according)g(to)i(some)f(sp)r(ecial)g +(rules.)60 b(F)-7 b(or)118 1925 y(instance:)220 2090 +y(1.)41 b(the)34 b(complete)g(subtree)f(starting)g(at)h(a)f(no)r(de)h +(is)g(listed)g(immediately)g(after)f(the)i(no)r(de)f(in)g(question)f +(\(\020depth)326 2189 y(\034rst\021\))220 2354 y(2.)41 +b(no)r(des)27 b(with)h(a)f(common)g(paren)n(t)g(are)g(listed)g(c)n +(hronologically)243 2519 y(F)-7 b(or)39 b(instance,)k(the)d(displa)n(y) +f(of)h(an)f(organization)f(c)n(hart)h(is)g(usually)h(required)e(to)i +(satisfy)g(at)f(least)h(the)g(\034rst)118 2619 y(condition.)h(In)29 +b(a)g(threaded)f(discussion)h(group)e(one)i(wishes)g(to)f(satisfy)h(b)r +(oth)h(conditions)e(to)h(displa)n(y)f(the)h(messages)118 +2718 y(in)20 b(a)g(thread)g(\025)f(the)i(threads)e(themselv)n(es)h +(\(i.e.,)i(c)n(hildren)e(of)g(the)g(ro)r(ot)f(no)r(de\))i(are)e +(usually)g(listed)i(in)f(in)n(v)n(erse)f(c)n(hronolical)118 +2818 y(order.)243 2917 y(T)-7 b(o)35 b(mak)n(e)f(a)h(particular)f +(ordering)g(e\036cien)n(t,)j(it)f(w)n(ould)f(b)r(e)h(a)f(nice)g +(feature)g(if)h(it)g(could)f(b)r(e)h(made)f(to)g(coincide)118 +3017 y(with)28 b(a)f(lexicographic)f(ordering)f(of)j(the)g(indices)f +(\025i.e.,)g(as)g(pro)r(duced)g(b)n(y)h(an)f(\020ORDER)h(BY)f(id)h +(ASC\021)35 b(in)27 b(SQL.)h(The)118 3117 y(lexicographic)d(ordering)h +(of)h(fgID)h(satis\034es)e(b)r(oth)i(conditions.)36 b(The)27 +b(lexicographic)f(ordering)f(of)i(vgID)g(as)g(describ)r(ed)118 +3216 y(ab)r(o)n(v)n(e)34 b(satis\034es)g(the)h(\034rst)g(requisite)f +(if)i(the)f(separator)d(has)j(the)g(minimal)g(binary)g(represen)n +(tation)e(of)i(all)f(allo)n(w)n(ed)118 3316 y(sym)n(b)r(ols)c(in)h(an)f +(index)h(\025)f(this)h(is)g(wh)n(y)f(w)n(e)g(reserv)n(ed)f(/)h(for)g +(the)i(separator.)43 b(But)31 b(the)g(second)f(prop)r(ert)n(y)g(is)g +(missing:)118 3416 y(for)d(instance,)g(the)h(index)g('/1/10')d(is)j +(lexicographically)d(b)r(efore)i('/1/2'.)243 3515 y(If)c(the)h(second)e +(prop)r(ert)n(y)g(is)i(also)e(required)g(for)h(vgID,)g(w)n(e)f(can)h +(sp)r(ecify)h(the)f(c)n(hild)h(iden)n(ti\034ers)e(with)i(coun)n(ters)e +(built)118 3615 y(in)28 b(the)g(follo)n(wing)e(w)n(a)n(y:)36 +b(represen)n(t)26 b(a)h(n)n(um)n(b)r(er)h(b)n(y)f(a)g(string)g(of)g +(digits,)h(where)243 3779 y Ff(\017)41 b Fh(the)25 b(\034rst)g(digit)h +Fc(D)896 3791 y Fb(0)958 3779 y Fh(represen)n(ts)e(the)i(length)f(in)h +(digits)f(of)g(the)h(decimal)f(expansion)f(of)i(the)f(n)n(um)n(b)r(er,) +h(min)n(us)f(one)243 3945 y Ff(\017)41 b Fh(the)28 b(follo)n(wing)e +Fa(\()p Fc(D)920 3957 y Fb(0)976 3945 y Fa(+)18 b(1\))27 +b Fh(digits)h(are)e(the)i(decimal)g(expansion)e(of)i(the)g(n)n(um)n(b)r +(er)118 4109 y(Let)g(us)f(call)h(these)f(iden)n(ti\034ers)g +Fg(m-vgID)p Fh(,)g(\020m\021)34 b(for)27 b(mo)r(di\034ed.)243 +4209 y(As)e(an)f(example,)h(the)g(no)r(de)g(whic)n(h)g(w)n(as)f +(previously)f(represen)n(ted)h(b)n(y)g(/15/3/182)d(will,)k(after)g +(this)g(mo)r(di\034cation,)118 4309 y(ha)n(v)n(e)h(the)i(index)g +(/115/03/2182.)243 4408 y(The)37 b(lexicographic)f(ordering)g(of)i +(m-vgID)f(is)h(the)g(desired)f(ordering)f(of)h(the)h(tree)g(no)r(des.) +67 b(The)38 b(cost)f(of)g(this)118 4508 y(prop)r(ert)n(y)31 +b(is)i(that)f(\(a\))h(the)g(ID)f(are)g(no)n(w)g(longer,)g(\(b\))h(no)f +(no)r(de)g(can)g(ha)n(v)n(e)g(more)f(than)i Fa(160)3106 +4478 y Fb(160)3240 4508 y Fh(c)n(hildren)f(\(actually)-7 +b(,)118 4607 y(this)32 b(is)g(a)f(non-issue\),)h(and)f(\(c\))h(the)g +(index)g(structure)f(is)h(redundan)n(t,)g(some)f(formally)f(correct)h +(indices)g(are)g(in)n(v)-5 b(alid)118 4707 y(\025e.g.,)24 +b(/316/013/11.)30 b(The)24 b(third)g(issue)g(can)g(b)r(e)g(addressed)f +(b)n(y)g(k)n(eeping)g(a)h(strict)g(con)n(trol)e(on)i(the)g(generation)f +(of)h(new)118 4807 y(indices)k(to)f(insure)g(that)h(all)f(indices)h +(are)e(formally)h(correct.)243 4906 y(The)32 b(issue)f(of)h(the)g(rev)n +(erse)e(c)n(hronological)f(indexing)j(of)f(threads)h(in)g(threaded)f +(discussion)g(groups)g(can)g(b)r(e)h(ad-)118 5006 y(dressed)d(easily)f +(enough)h(in)h(fgID:)f(coun)n(t)g(\020do)n(wn\021)36 +b(instead)29 b(of)g(\020up\021)36 b(the)30 b(c)n(hildren)f(of)g(the)h +(ro)r(ot)e(no)r(de)i(\025)f(this)h(implies)118 5106 y(only)e(an)g +(inconsequen)n(tial)f(mo)r(di\034cation)h(of)g(the)g(no)r(de)h +(insertion)e(routine,)h(as)g(sho)n(wn)f(b)r(elo)n(w.)38 +b(The)29 b(problem)e(is)h(less)118 5205 y(trivial)i(with)g(vgID;)h(in)f +(this)h(case,)f(ma)n(yb)r(e)f(a)h(thread)g(iden)n(ti\034er)g(should)g +(b)r(e)h(k)n(ept)f(in)g(a)g(di\033eren)n(t)g(\034eld)h(-)f(i.e.,)h +(repre-)118 5305 y(sen)n(ting)h(the)h(structure)f(as)g(a)h(forest)f +(rather)f(than)i(a)f(tree,)i(where)e(the)h(thread_id)f(\034eld)h +(selects)f(the)h(\020tree\021)38 b(in)33 b(the)118 5404 +y(forest.)1987 5653 y(3)p eop +%%Page: 4 4 +4 3 bop 118 291 a Fi(3)131 b(T)-11 b(ree)45 b(op)t(erations)e(using)h +(genealogical)g(indices)118 472 y Fh(In)32 b(this)f(section)g(w)n(e)g +(sho)n(w)g(ho)n(w)g(to)g(implemen)n(t)h(v)-5 b(arious)30 +b(tree)h(op)r(erations)f(using)h(gID)g(as)g(the)h(primary)e(k)n(ey)h +(in)g(the)118 572 y(no)r(de)d(table.)243 672 y(Some)h(implemen)n +(tation)h(issues)g(are)f(relev)-5 b(an)n(t)29 b(here,)h(esp)r(ecially)f +(concerning)g(the)h(utilisation)g(of)g(indices)g(b)n(y)f(the)118 +771 y(DB)f(engine.)243 871 y(W)-7 b(e)28 b(discuss)f(a)g(tree)g +(represen)n(ted)f(in)i(a)f(table)h(of)f(the)h(form)326 +1034 y Fd(CREATE)41 b(TABLE)g(tree)h(\()456 1134 y(gid)304 +b(text)42 b(PRIMARY)f(KEY,)456 1234 y(nchildren)f(integer)h(DEFAULT)f +(0,)456 1333 y(\\ldots)h(the)i(actual)e(node)h(data)326 +1433 y(\);)118 1597 y Fh(The)26 b(\034eld)g(\020nc)n(hildren\021)32 +b(is)26 b(a)f(coun)n(ter)g(for)g(the)i(n)n(um)n(b)r(er)e(of)h(c)n +(hildren)f(that)h(the)h(no)r(de)f(has)f Fe(ever)35 b +Fh(had;)27 b(w)n(e)e(assume)g(here)118 1696 y(it)j(is)g(not)f(up)r +(dated)h(when)g(no)r(des)f(or)g(subtrees)g(are)f(deleted.)243 +1796 y(Section)h(4)g(pro)n(vides)f(a)i(complete)f(implemen)n(tation)h +(of)f(these)h(op)r(erations)e(for)h(fgID)h(in)g(P)n(ostgreSQL.)118 +2028 y Fm(3.1)112 b(Computing)37 b(the)g(lev)m(el)f(of)h(a)h(no)s(de) +118 2181 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations)g(\(no)g(table)g +(ac)l(c)l(ess\))243 2280 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r +(eration,)f(no)i(table)f(access)g(is)g(required.)243 +2460 y Ff(\017)41 b Fg(vgID:)27 b Fh(coun)n(t)h(the)g(n)n(um)n(b)r(er)f +(of)g(separators)e(\('/'\))j(in)g(the)g(PK)243 2625 y +Ff(\017)41 b Fg(fgID:)27 b Fh(coun)n(t)g(the)h(n)n(um)n(b)r(er)g(of)f +(c)n(haracters)e(in)j(the)g(PK,)g(divide)g(b)n(y)f(the)h(\034xed)f +(size)h(of)f(the)h(coun)n(ters.)118 2857 y Fm(3.2)112 +b(Selecting)36 b(or)h(deleting)f(a)i(subtree)118 3010 +y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +3173 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(/26/5/7)e(is)i(selected)g(b)n(y)508 3338 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7\045')d(AND)j(id)h(<)g('/26/5/70')243 +3503 y Ff(\017)e Fg(m-vgID:)26 b Fh(The)h(subtree)h(ro)r(oted)e(at)i +(/126/05/07)22 b(is)28 b(selected)f(b)n(y)508 3668 y +Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07\045')243 +3833 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(260507)e(is)i(selected)h(b)n(y)508 3997 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')118 4229 y Fm(3.3)112 +b(Selecting)36 b(the)h(direct)f(c)m(hildren)g(of)i(a)g(no)s(de)118 +4382 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +4562 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(/26/5/7)c(are)j(selected)g(b)n(y)508 4727 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7/\045')d(AND)j(id)h(NOT)f(LIKE)g +('26/5/7/\045/\045')243 4892 y Ff(\017)f Fg(m-vgID:)26 +b Fh(The)h(direct)h(c)n(hildren)f(of)g(/26/5/7)e(are)h(selected)i(b)n +(y)508 5056 y Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07/\045')37 +b(AND)43 b(id)f(NOT)h(LIKE)f('/126/05/07/\045/\045)o(')243 +5221 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(260507)c(are)j(selected)g(b)n(y)508 5386 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')d(AND)k(char_length\(id\))37 +b(=)43 b(\(char_length\('26)o(05)o(07')o(\)+)o(2\))1987 +5653 y Fh(4)p eop +%%Page: 5 5 +5 4 bop 118 291 a Fm(3.4)112 b(Inserting)37 b(a)h(no)s(de)g(or)f(a)h +(subtree)118 444 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l +(e)l(e)f(+)h(string)f(and)h(math)g(op)l(er)l(ations)243 +543 y Fh(Insertion)f(is)g(a)h(pro)r(cedural)e(op)r(eration.)42 +b(As)30 b(eac)n(h)f(RDBMS)h(has)f(a)h(di\033eren)n(t)f(w)n(a)n(y)g(of)g +(de\034ning)h(pro)r(cedures,)f(w)n(e)118 643 y(will)f(just)g(describ)r +(e)f(here)g(the)h(necessary)e(steps.)37 b(Examples)27 +b(for)g(P)n(ostgreSQL)f(are)h(pro)n(vided)f(in)i(4.)243 +743 y(In)22 b(order)f(to)h(insert)g(a)g(new)g(c)n(hild)h(of)f +(\020daddy\021)28 b(\(either)23 b(one)f(of)g(/26/5/7,)e(/126/05/07)d +(or)22 b(260507)d(in)k(the)f(examples)118 842 y(ab)r(o)n(v)n(e\))27 +b(y)n(ou)f(ha)n(v)n(e)h(to)220 1008 y(1.)41 b(add)27 +b(one)g(to)h(the)g(n)n(um)n(b)r(er)f(of)g(c)n(hildren)h(of)f +(\020daddy\021)508 1174 y Fd(UPDATE)41 b(tree)h(SET)h(nchildren)c(=)k +(\(nchildren)d(+)j(1\))g(WHERE)e(ID)i(=)g(``daddy'';)220 +1340 y Fh(2.)e(enco)r(de)27 b(the)h(n)n(um)n(b)r(er)f(of)g(c)n(hildren) +g(of)h(\020daddy\021)33 b(in)28 b(base)f(160,)f(bring)h(it)h(to)f(the)h +(correct)e(format)h(dep)r(ending)h(on)326 1440 y(the)c(v)-5 +b(arian)n(t)23 b(of)h(gID)g(\(pad)g(with)h(0)e(or)g(not,)i(prep)r(end)f +(a)g(digit)g(coun)n(ter)f(or)g(not,)i(prep)r(end)f(/)g(or)f(not,)i +(coun)n(t)e(do)n(wn)326 1540 y(or)j(up,)i(.)14 b(.)g(.)g(\))37 +b(and)28 b(app)r(end)f(it)h(to)g(daddy's)f(gID)g(to)h(obtain)f(the)h +(new)g(no)r(de's)f(gID.)220 1706 y(3.)41 b(insert)27 +b(the)h(new)f(no)r(de)243 1872 y(When)35 b(inserting)g(a)f(subtree,)j +(the)e(index)g(of)g(the)h(ro)r(ot)e(of)h(the)g(subtree)g(has)f(to)h(b)r +(e)h(computed)f(as)f(ab)r(o)n(v)n(e,)i(and)118 1971 y(prep)r(ended)28 +b(to)f(the)h(index)g(of)f(eac)n(h)g(no)r(de)h(of)f(the)h(subtree)f(b)r +(efore)h(insertion.)243 2071 y(Remark)e(that)i(only)f(the)h(paren)n(t)f +(no)r(de)h(has)f(to)g(b)r(e)h(up)r(dated)g(on)f(insertion.)118 +2303 y Fm(3.5)112 b(Selecting)36 b(the)h(ancestors)h(of)g(a)g(no)s(de) +118 2457 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +2556 y Fh(Y)-7 b(ou)27 b(can)g(sp)r(ecify)h(all)g(ancestors)d(of)j(a)f +(no)r(de)h(in)f(a)h(single)f(SQL)g(statemen)n(t;)g(for)g(instance)h +(for)f(vgID)326 2722 y Fd(...)42 b(WHERE)f('/25/6/7')f(LIKE)i(\(id)g +(||)h('/\045'\))f(AND)g(id)h(<)g('/25/6/7')118 2888 y +Fh(The)31 b(second)e(part)h(of)h(the)g(clause,)f(while)h(logically)e +(redundan)n(t,)h(is)h(a)f(\020hin)n(t\021)37 b(to)30 +b(the)h(optimizer.)45 b(A)n(t)31 b(least)f(in)g(P)n(ost-)118 +2988 y(greSQL,)c(without)i(it)g(the)g(optimizer)f(will)h(c)n(ho)r(ose)e +(a)i(sequen)n(tial)e(scan)h(of)h(the)g(table)f(and)h(disregard)d(the)j +(index.)118 3220 y Fm(3.6)112 b(Selecting)36 b(all)g(lea)m(v)m(es)118 +3374 y Fg(Cost:)h Fe(sc)l(an)30 b(of)g(the)g(tr)l(e)l(e)243 +3473 y Fh(A)e(leaf)f(is)g(a)h(no)r(de)f(without)h(descendan)n(ts:)36 +b(it)28 b(has)f(0)g(c)n(hildren.)37 b(Hence)326 3639 +y Fd(...)42 b(WHERE)f(nchildren)f(=)j(0)118 3805 y Fh(If)28 +b(this)g(t)n(yp)r(e)g(of)f(query)g(is)h(often)f(necessary)-7 +b(,)26 b(y)n(ou)h(ma)n(y)g(b)r(e)h(w)n(ell)f(advised)g(to)g(k)n(eep)g +(an)h(index)f(on)h(tree\(nc)n(hildren\).)118 4038 y Fm(3.7)112 +b(Determining)35 b(if)i(A)g(is)g(a)h(descendan)m(t)g(of)g(B)118 +4191 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations,)h(no)f(table)g(ac)l +(c)l(ess)243 4291 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r(eration)f +(on)i(the)g(indices,)f(no)g(table)h(access)e(is)i(necessary)-7 +b(.)118 4565 y Fi(4)131 b(Putting)45 b(it)f(all)h(together:)57 +b(a)44 b(P)l(ostgreSQL)f(implemen)l(tation)118 4747 y +Fh(h)n(ttp://www.p)r(ostgresql.org/mhonarc/pgsq)o(l-sql/)o(20)o(00)o +(-0)o(4/)o(msg0)o(02)o(67)o(.h)n(tml)243 4847 y(W)-7 +b(e)30 b(describ)r(e)g(here)g(a)g(small)f(pac)n(k)-5 +b(age)29 b(that)i(can)e(b)r(e)i(used)f(for)g(implemen)n(ting)g(gID)g +(on)g(P)n(ostgreSQL.)f(It)i(can)e(b)r(e)118 4946 y(found)f(at)f()243 5046 y(The)21 b(pac)n(k)-5 b(age)21 b(uses)g(the)h(pro) +r(cedural)e(language)h(PL/PGsql.)35 b(A)22 b(b)r(etter)g(implemen)n +(tation)g(w)n(ould)f(probably)g(de\034ne)118 5145 y(the)28 +b(gID)g(as)f(new)g(P)n(ostgres)f(t)n(yp)r(es,)i(and)f(co)r(de)g(all)h +(this)g(in)f(C.)243 5245 y(The)g(\034les)h(should)f(b)r(e)h(loaded)f +(in)h(alphab)r(etical)f(order.)1987 5653 y(5)p eop +%%Page: 6 6 +6 5 bop 118 291 a Fm(4.1)112 b(tree0_enco)s(ding.sql)118 +444 y Fh(This)28 b(\034le)f(de\034nes)h(and)f(p)r(opulates)h(the)f +(table)h(_b160_digits)d(of)j(\020digits\021)33 b(in)28 +b(base)f(160,)326 604 y Fd(CREATE)41 b(TABLE)g(\\_b160\\_digits)d +(\(deci)j(integer,)f(code)i(char\);)118 764 y Fh(and)28 +b(the)f(t)n(w)n(o)g(functions)326 924 y Fd(CREATE)41 +b(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er\))d(RETURNS)j(string) +413 1024 y(AS)j('....')e(LANGUAGE)f('plpgsql';)326 1124 +y(CREATE)h(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er,)o(in)o(te)o +(ger)o(\))d(RETURNS)k(string)413 1223 y(AS)i('....')e(LANGUAGE)f +('plpgsql';)118 1384 y Fh(The)22 b(\034rst)h(function)f(returns)g(a)g +(v)-5 b(ariable)21 b(size)h(enco)r(ding;)i(the)f(second)e(a)h(\034xed)h +(size)f(enco)r(ding)g(\(the)h(second)e(parameter)118 +1483 y(is)g(the)h(size\),)g(and)f(raises)e(an)i(exception)g(if)h(the)f +(n)n(um)n(b)r(er)g(is)g(to)r(o)g(large)e(to)i(b)r(e)h(represen)n(ted)e +(with)h(the)h(requested)e(n)n(um)n(b)r(er)118 1583 y(of)28 +b(digits.)118 1814 y Fm(4.2)112 b(tree1_de\034ne.sql)118 +1967 y Fh(This)28 b(\034le)f(pro)n(vides)f(a)i(function)326 +2127 y Fd(CREATE)41 b(FUNCTION)f(_tree_create\(tex)o(t,)o(in)o(teg)o +(er)o(,t)o(ext)o(,t)o(ex)o(t\))d(RETURNS)k(bpchar)413 +2227 y(AS)i('....')e(LANGUAGE)f('plpgsql';)118 2387 y +Fh(that)e(creates)f(a)h(tree)f(infrastructure)g(of)h(either)g(fgID)g +(or)f(vgID.)h(Assuming)f(y)n(ou)g(ha)n(v)n(e)g(a)h(table)f(\020m)n +(ytable\021)44 b(with)118 2487 y(primary)26 b(k)n(ey)h(\020m)n +(yid\021,)g(then)h(calling)326 2647 y Fd(SELECT)41 b(_tree_create\('m)o +(yt)o(ree)o(',)o(2,')o(my)o(ta)o(ble)o(',)o('m)o(yid)o('\))o(;)118 +2807 y Fh(will)28 b(cause:)220 2967 y(1.)41 b(the)28 +b(creation)e(of)i(a)f(table)508 3131 y Fd(CREATE)41 b(TABLE)h +(mytree_bkg\()683 3230 y(gid)g(text)g(PRIMARY)e(KEY,)683 +3330 y(nchildren)f(int,)683 3429 y(sid)j(integer)f(REFERENCES)e +(mytable\(myid\))508 3529 y(\);)508 3629 y(CREATE)i(UNIQUE)g(INDEX)h +(mytree_bkg_sid)37 b(ON)43 b(mytree_bkg\(sid\);)326 3792 +y Fh(for)27 b(the)h(tree)f(structure.)220 3955 y(2.)41 +b(the)28 b(creation)e(of)i(a)f(view)508 4118 y Fd(CREATE)41 +b(VIEW)h(mytree)f(AS)639 4218 y(SELECT)g(t.gid,n.*)900 +4317 y(FROM)h(mytable)f(n,)i(mytree_bkg)c(t)900 4417 +y(WHERE)j(t.sid=n.myid;)326 4580 y Fh(with:)35 b(a)23 +b(trigger)e(on)i(UPD)n(A)-7 b(TE)25 b(that)e(blo)r(c)n(ks)g(up)r +(dating)g(the)h(gid)f(and)g(allo)n(ws)f(up)r(dating)h(the)g(no)r(de)h +(data,)f(a)g(rule)326 4680 y(on)k(DELETE)i(that)f(deletes)f(the)h +(corresp)r(onding)e(en)n(try)h(b)r(oth)h(in)g(m)n(ytree_bkg)d(and)j(m)n +(ytable,)f(and)g(a)g(trigger)326 4779 y(ON)h(INSER)-7 +b(T)30 b(that)f(raises)e(an)h(exception)g(and)g(informs)h(the)f(user)g +(to)h(use)f(the)h(insertion)f(function)h(describ)r(ed)326 +4879 y(b)r(elo)n(w.)220 5042 y(3.)41 b(t)n(w)n(o)26 b(insertion)h +(functions)h(that)g(compute)g(automatically)e(the)i(gID)g(of)f(the)h +(new)g(no)r(de:)425 5205 y Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert\(text,text,in)n(teger,text\))d(for)h(insertion)g(sim)n +(ultaneosly)f(in)i(b)r(oth)g(tables:)508 5305 y(m)n +(ytree_insert\('2201','hello',0,'not)15 b(m)n(uc)n(h'\))j(inserts)g(a)g +(new)g(c)n(hild)h(of)f(2201)f(with)h(data1='hello',)h(data2=0)508 +5404 y(and)28 b(data3='not)e(m)n(uc)n(h')1987 5653 y(6)p +eop +%%Page: 7 7 +7 6 bop 425 291 a Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert_no)r(de\(text,in)n(teger\))c(for)i(insertion)g(in)h(m)n +(ytree_bkg)508 390 y(m)n(ytree_insert\('2201',25\))c(inserts)j(in)h(m)n +(ytree_bkg)e(a)h(new)h(c)n(hild)f(of)h(2201)d(with)j(sid=25)220 +556 y(4.)41 b(a)27 b(function)h(m)n(ytree_mo)n(v)n(e\(text,text\))e +(that)i(mo)n(v)n(es)e(subtrees:)326 656 y(m)n(ytree_mo)n(v)n +(e\('2201','23'\))d(mo)n(v)n(es)j(the)i(subtree)f(ro)r(oted)g(at)g +(2201)f(to)h(a)h(place)f(b)r(elo)n(w)g(23)f(\(ma)n(yb)r(e)i(2307\))220 +822 y(5.)41 b(a)c(function)g(m)n(ytree_len\(\))g(that)h(returns)e(the)i +(length)f(of)g(the)h(enco)r(dings)f(used)g(in)h(the)f(gID)g(\(2)h +(here;)j(0)c(if)326 922 y(v)-5 b(ariable)26 b(size\).)118 +1196 y Fi(5)131 b(Non-tree)44 b(hierarc)l(hies)118 1378 +y Fh(sequence)22 b(as)f(id,)j(table)e(with)h(\(id,g-index\))f(with)g(p) +r(ossibly)g(man)n(y)g(g-indices)f(for)h(eac)n(h)f(id)h(\(if)h(TOO)f +(man)n(y)-7 b(,)23 b(bad)f(mo)r(del:)118 1478 y(list)28 +b(all)f(genealogies,)f(i.e.,)h(paths)h(from)f(the)h(ro)r(ot\))118 +1752 y Fi(References)160 1934 y Fh([1])41 b(Philip)28 +b(Greenspun,)g Fe(T)-6 b(r)l(e)l(es)29 b(in)h(Or)l(acle)g(SQL)p +Fh(,)d(in)h Fg(SQL)k(for)g(W)-8 b(eb)31 b(Nerds)289 2033 +y Fh()160 2200 +y([2])41 b(Jo)r(e)27 b(Celk)n(o,)f Fe(SQL)j(for)i(Smarties)p +Fh(,)d(in)g Fg(DBMS)j(Online)p Fh(,)26 b(Marc)n(h)h(to)g(June)h(1996) +289 2299 y()289 +2399 y()289 +2498 y()289 +2598 y()160 +2764 y([3])41 b(Graeme)26 b(Birc)n(hall,)h Fg(DB2)32 +b(UDB)g(V6.1)f(SQL)h(Co)s(okb)s(o)s(ok)p Fh(,)289 2864 +y()1987 5653 +y(7)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c new file mode 100644 index 0000000000..d6d66dd37f --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -0,0 +1,545 @@ +/* + 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;inum_elements;i++) { + const struct ldb_attrib_handler *h; + /* this is rather ugly - a consequence of const handling */ + h = ldb_attrib_handler(module->ldb, msg->elements[i].name); + ldb_remove_attrib_handler(module->ldb, msg->elements[i].name); + if (strcmp(h->attr, msg->elements[i].name) == 0) { + talloc_steal(msg, h->attr); + } + } + + 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;inum_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_explode(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;inum_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 = talloc_strdup(module, msg->elements[i].name); + 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_explode(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;inum_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + for (j=0;jnum_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;inum_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 = ⪙ + msg->dn = ldb_dn_explode(msg, 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; + double seq; + + 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; + } + } + + talloc_free(ltdb->cache->baseinfo); + ltdb->cache->baseinfo = talloc(ltdb->cache, struct ldb_message); + if (ltdb->cache->baseinfo == NULL) goto failed; + + baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO); + if (baseinfo_dn == NULL) goto failed; + + if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) == -1) { + goto failed; + } + + /* possibly initialise the baseinfo */ + if (!ltdb->cache->baseinfo->dn) { + if (ltdb_baseinfo_init(module) != 0) { + goto failed; + } + if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) != 1) { + goto failed; + } + } + + /* 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_double(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0); + if (seq == ltdb->sequence_number) { + goto done; + } + ltdb->sequence_number = seq; + + talloc_free(ltdb->cache->last_attribute.name); + memset(<db->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_explode(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_dn); + talloc_free(indexlist_dn); + return 0; + +failed: + 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_explode(msg, 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; +} + diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c new file mode 100644 index 0000000000..59c1645ba8 --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -0,0 +1,1159 @@ +/* + 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 backend - indexing + * + * Description: indexing routines for ldb tdb backend + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#include "ldb/ldb_tdb/ldb_tdb.h" + +/* + find an element in a list, using the given comparison function and + assuming that the list is already sorted using comp_fn + + return -1 if not found, or the index of the first occurance of needle if found +*/ +static int ldb_list_find(const void *needle, + const void *base, size_t nmemb, size_t size, + comparison_fn_t comp_fn) +{ + const char *base_p = base; + size_t min_i, max_i, test_i; + + if (nmemb == 0) { + return -1; + } + + min_i = 0; + max_i = nmemb-1; + + while (min_i < max_i) { + int r; + + test_i = (min_i + max_i) / 2; + /* the following cast looks strange, but is + correct. The key to understanding it is that base_p + is a pointer to an array of pointers, so we have to + dereference it after casting to void **. The strange + const in the middle gives us the right type of pointer + after the dereference (tridge) */ + r = comp_fn(needle, *(void * const *)(base_p + (size * test_i))); + if (r == 0) { + /* scan back for first element */ + while (test_i > 0 && + comp_fn(needle, *(void * const *)(base_p + (size * (test_i-1)))) == 0) { + test_i--; + } + return test_i; + } + if (r < 0) { + if (test_i == 0) { + return -1; + } + max_i = test_i - 1; + } + if (r > 0) { + min_i = test_i + 1; + } + } + + if (comp_fn(needle, *(void * const *)(base_p + (size * min_i))) == 0) { + return min_i; + } + + return -1; +} + +struct dn_list { + unsigned int count; + char **dn; +}; + +/* + return the dn key to be used for an index + caller frees +*/ +static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, + const char *attr, const struct ldb_val *value) +{ + struct ldb_dn *ret; + char *dn; + struct ldb_val v; + const struct ldb_attrib_handler *h; + char *attr_folded; + + attr_folded = ldb_attr_casefold(ldb, attr); + if (!attr_folded) { + return NULL; + } + + h = ldb_attrib_handler(ldb, attr); + if (h->canonicalise_fn(ldb, ldb, value, &v) != 0) { + /* canonicalisation can be refused. For example, + a attribute that takes wildcards will refuse to canonicalise + if the value contains a wildcard */ + talloc_free(attr_folded); + return NULL; + } + if (ldb_should_b64_encode(&v)) { + char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length); + if (!vstr) return NULL; + dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr); + talloc_free(vstr); + if (v.data != value->data) { + talloc_free(v.data); + } + talloc_free(attr_folded); + if (dn == NULL) return NULL; + goto done; + } + + dn = talloc_asprintf(ldb, "%s:%s:%.*s", + LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data); + + if (v.data != value->data) { + talloc_free(v.data); + } + talloc_free(attr_folded); + +done: + ret = ldb_dn_explode(ldb, dn); + talloc_free(dn); + return ret; +} + +/* + see if a attribute value is in the list of indexed attributes +*/ +static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr, + unsigned int *v_idx, const char *key) +{ + unsigned int i, j; + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, key) == 0) { + const struct ldb_message_element *el = + &msg->elements[i]; + for (j=0;jnum_values;j++) { + if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) { + if (v_idx) { + *v_idx = j; + } + return i; + } + } + } + } + return -1; +} + +/* used in sorting dn lists */ +static int list_cmp(const char **s1, const char **s2) +{ + return strcmp(*s1, *s2); +} + +/* + return a list of dn's that might match a simple indexed search or + */ +static int ltdb_index_dn_simple(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_dn *dn; + int ret; + unsigned int i, j; + struct ldb_message *msg; + + list->count = 0; + list->dn = NULL; + + /* if the attribute isn't in the list of indexed attributes then + this node needs a full search */ + if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) { + return -1; + } + + /* the attribute is indexed. Pull the list of DNs that match the + search criterion */ + dn = ldb_dn_key(ldb, tree->u.equality.attr, &tree->u.equality.value); + if (!dn) return -1; + + msg = talloc(list, struct ldb_message); + if (msg == NULL) { + return -1; + } + + ret = ltdb_search_dn1(module, dn, msg); + talloc_free(dn); + if (ret == 0 || ret == -1) { + return ret; + } + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el; + + if (strcmp(msg->elements[i].name, LTDB_IDX) != 0) { + continue; + } + + el = &msg->elements[i]; + + list->dn = talloc_array(list, char *, el->num_values); + if (!list->dn) { + break; + } + + for (j=0;jnum_values;j++) { + list->dn[list->count] = + talloc_strdup(list->dn, (char *)el->values[j].data); + if (!list->dn[list->count]) { + return -1; + } + list->count++; + } + } + + talloc_free(msg); + + if (list->count > 1) { + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp); + } + + return 1; +} + + +static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *); + +/* + return a list of dn's that might match a simple indexed search on + the special objectclass attribute + */ +static int ltdb_index_dn_objectclass(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int ret; + const char *target = (const char *)tree->u.equality.value.data; + const char **subclasses; + + list->count = 0; + list->dn = NULL; + + ret = ltdb_index_dn_simple(module, tree, index_list, list); + + subclasses = ldb_subclass_list(module->ldb, target); + + if (subclasses == NULL) { + return ret; + } + + for (i=0;subclasses[i];i++) { + struct ldb_parse_tree tree2; + struct dn_list *list2; + tree2.operation = LDB_OP_EQUALITY; + tree2.u.equality.attr = LTDB_OBJECTCLASS; + if (!tree2.u.equality.attr) { + return -1; + } + tree2.u.equality.value.data = + (uint8_t *)talloc_strdup(list, subclasses[i]); + if (tree2.u.equality.value.data == NULL) { + return -1; + } + tree2.u.equality.value.length = strlen(subclasses[i]); + list2 = talloc(list, struct dn_list); + if (list2 == NULL) { + talloc_free(tree2.u.equality.value.data); + return -1; + } + if (ltdb_index_dn_objectclass(module, &tree2, + index_list, list2) == 1) { + if (list->count == 0) { + *list = *list2; + ret = 1; + } else { + list_union(ldb, list, list2); + talloc_free(list2); + } + } + talloc_free(tree2.u.equality.value.data); + } + + return ret; +} + +/* + return a list of dn's that might match a leaf indexed search + */ +static int ltdb_index_dn_leaf(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) { + return ltdb_index_dn_objectclass(module, tree, index_list, list); + } + if (ldb_attr_dn(tree->u.equality.attr) == 0) { + list->dn = talloc_array(list, char *, 1); + if (list->dn == NULL) { + ldb_oom(module->ldb); + return -1; + } + list->dn[0] = talloc_strdup(list, (char *)tree->u.equality.value.data); + if (list->dn[0] == NULL) { + ldb_oom(module->ldb); + return -1; + } + list->count = 1; + return 1; + } + return ltdb_index_dn_simple(module, tree, index_list, list); +} + + +/* + list intersection + list = list & list2 + relies on the lists being sorted +*/ +static int list_intersect(struct ldb_context *ldb, + struct dn_list *list, const struct dn_list *list2) +{ + struct dn_list *list3; + unsigned int i; + + if (list->count == 0 || list2->count == 0) { + /* 0 & X == 0 */ + return 0; + } + + list3 = talloc(ldb, struct dn_list); + if (list3 == NULL) { + return -1; + } + + list3->dn = talloc_array(list3, char *, list->count); + if (!list3->dn) { + talloc_free(list3); + return -1; + } + list3->count = 0; + + for (i=0;icount;i++) { + if (ldb_list_find(list->dn[i], list2->dn, list2->count, + sizeof(char *), (comparison_fn_t)strcmp) != -1) { + list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]); + list3->count++; + } else { + talloc_free(list->dn[i]); + } + } + + talloc_free(list->dn); + list->dn = talloc_move(list, &list3->dn); + list->count = list3->count; + talloc_free(list3); + + return 0; +} + + +/* + list union + list = list | list2 + relies on the lists being sorted +*/ +static int list_union(struct ldb_context *ldb, + struct dn_list *list, const struct dn_list *list2) +{ + unsigned int i; + char **d; + unsigned int count = list->count; + + if (list->count == 0 && list2->count == 0) { + /* 0 | 0 == 0 */ + return 0; + } + + d = talloc_realloc(list, list->dn, char *, list->count + list2->count); + if (!d) { + return -1; + } + list->dn = d; + + for (i=0;icount;i++) { + if (ldb_list_find(list2->dn[i], list->dn, count, + sizeof(char *), (comparison_fn_t)strcmp) == -1) { + list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]); + if (!list->dn[list->count]) { + return -1; + } + list->count++; + } + } + + if (list->count != count) { + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp); + } + + return 0; +} + +static int ltdb_index_dn(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list); + + +/* + OR two index results + */ +static int ltdb_index_dn_or(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int ret; + + ret = -1; + list->dn = NULL; + list->count = 0; + + for (i=0;iu.list.num_elements;i++) { + struct dn_list *list2; + int v; + + list2 = talloc(module, struct dn_list); + if (list2 == NULL) { + return -1; + } + + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + + if (v == 0) { + /* 0 || X == X */ + if (ret == -1) { + ret = 0; + } + talloc_free(list2); + continue; + } + + if (v == -1) { + /* 1 || X == 1 */ + talloc_free(list->dn); + talloc_free(list2); + return -1; + } + + if (ret == -1) { + ret = 1; + list->dn = talloc_move(list, &list2->dn); + list->count = list2->count; + } else { + if (list_union(ldb, list, list2) == -1) { + talloc_free(list2); + return -1; + } + ret = 1; + } + talloc_free(list2); + } + + if (list->count == 0) { + return 0; + } + + return ret; +} + + +/* + NOT an index results + */ +static int ltdb_index_dn_not(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + /* the only way to do an indexed not would be if we could + negate the not via another not or if we knew the total + number of database elements so we could know that the + existing expression covered the whole database. + + instead, we just give up, and rely on a full index scan + (unless an outer & manages to reduce the list) + */ + return -1; +} + +/* + AND two index results + */ +static int ltdb_index_dn_and(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int ret; + + ret = -1; + list->dn = NULL; + list->count = 0; + + for (i=0;iu.list.num_elements;i++) { + struct dn_list *list2; + int v; + + list2 = talloc(module, struct dn_list); + if (list2 == NULL) { + return -1; + } + + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + + if (v == 0) { + /* 0 && X == 0 */ + talloc_free(list->dn); + talloc_free(list2); + return 0; + } + + if (v == -1) { + talloc_free(list2); + continue; + } + + if (ret == -1) { + ret = 1; + talloc_free(list->dn); + list->dn = talloc_move(list, &list2->dn); + list->count = list2->count; + } else { + if (list_intersect(ldb, list, list2) == -1) { + talloc_free(list2); + return -1; + } + } + + talloc_free(list2); + + if (list->count == 0) { + talloc_free(list->dn); + return 0; + } + } + + return ret; +} + +/* + return a list of dn's that might match a indexed search or + -1 if an error. return 0 for no matches, or 1 for matches + */ +static int ltdb_index_dn(struct ldb_module *module, + const struct ldb_parse_tree *tree, + const struct ldb_message *index_list, + struct dn_list *list) +{ + int ret = -1; + + switch (tree->operation) { + case LDB_OP_AND: + ret = ltdb_index_dn_and(module, tree, index_list, list); + break; + + case LDB_OP_OR: + ret = ltdb_index_dn_or(module, tree, index_list, list); + break; + + case LDB_OP_NOT: + ret = ltdb_index_dn_not(module, tree, index_list, list); + break; + + case LDB_OP_EQUALITY: + ret = ltdb_index_dn_leaf(module, tree, index_list, list); + break; + + case LDB_OP_SUBSTRING: + case LDB_OP_GREATER: + case LDB_OP_LESS: + case LDB_OP_PRESENT: + case LDB_OP_APPROX: + case LDB_OP_EXTENDED: + /* we can't index with fancy bitops yet */ + ret = -1; + break; + } + + return ret; +} + +/* + filter a candidate dn_list from an indexed search into a set of results + extracting just the given attributes +*/ +static int ltdb_index_filter(const struct dn_list *dn_list, + struct ldb_handle *handle) +{ + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ldb_reply *ares = NULL; + unsigned int i; + + for (i = 0; i < dn_list->count; i++) { + struct ldb_dn *dn; + int ret; + + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + + dn = ldb_dn_explode(ares->message, dn_list->dn[i]); + if (dn == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_dn1(ac->module, dn, ares->message); + talloc_free(dn); + if (ret == 0) { + /* the record has disappeared? yes, this can happen */ + talloc_free(ares); + continue; + } + + if (ret == -1) { + /* an internal error */ + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { + talloc_free(ares); + continue; + } + + /* 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 LDB_ERR_OPERATIONS_ERROR; + } + + 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) { + handle->state = LDB_ASYNC_DONE; + return handle->status; + } + } + + return LDB_SUCCESS; +} + +/* + search the database with a LDAP-like expression using indexes + returns -1 if an indexed search is not possible, in which + case the caller should call ltdb_search_full() +*/ +int ltdb_search_indexed(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); + struct dn_list *dn_list; + int ret; + + if (ltdb->cache->indexlist->num_elements == 0 && + ac->scope != LDB_SCOPE_BASE) { + /* no index list? must do full search */ + return -1; + } + + dn_list = talloc(handle, struct dn_list); + if (dn_list == NULL) { + return -1; + } + + if (ac->scope == LDB_SCOPE_BASE) { + /* with BASE searches only one DN can match */ + dn_list->dn = talloc_array(dn_list, char *, 1); + if (dn_list->dn == NULL) { + ldb_oom(ac->module->ldb); + return -1; + } + dn_list->dn[0] = ldb_dn_linearize(dn_list, ac->base); + if (dn_list->dn[0] == NULL) { + ldb_oom(ac->module->ldb); + return -1; + } + dn_list->count = 1; + ret = 1; + } else { + ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list); + } + + if (ret == 1) { + /* we've got a candidate list - now filter by the full tree + and extract the needed attributes */ + ret = ltdb_index_filter(dn_list, handle); + handle->status = ret; + handle->state = LDB_ASYNC_DONE; + } + + talloc_free(dn_list); + + return ret; +} + +/* + add a index element where this is the first indexed DN for this value +*/ +static int ltdb_index_add1_new(struct ldb_context *ldb, + struct ldb_message *msg, + struct ldb_message_element *el, + const char *dn) +{ + struct ldb_message_element *el2; + + /* add another entry */ + el2 = talloc_realloc(msg, msg->elements, + struct ldb_message_element, msg->num_elements+1); + if (!el2) { + return -1; + } + + msg->elements = el2; + msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX); + if (!msg->elements[msg->num_elements].name) { + return -1; + } + msg->elements[msg->num_elements].num_values = 0; + msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val); + if (!msg->elements[msg->num_elements].values) { + return -1; + } + msg->elements[msg->num_elements].values[0].length = strlen(dn); + msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn); + msg->elements[msg->num_elements].num_values = 1; + msg->num_elements++; + + return 0; +} + + +/* + add a index element where this is not the first indexed DN for this + value +*/ +static int ltdb_index_add1_add(struct ldb_context *ldb, + struct ldb_message *msg, + struct ldb_message_element *el, + int idx, + const char *dn) +{ + struct ldb_val *v2; + unsigned int i; + + /* for multi-valued attributes we can end up with repeats */ + for (i=0;ielements[idx].num_values;i++) { + if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) { + return 0; + } + } + + v2 = talloc_realloc(msg->elements, msg->elements[idx].values, + struct ldb_val, + msg->elements[idx].num_values+1); + if (!v2) { + return -1; + } + msg->elements[idx].values = v2; + + msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn); + msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn); + msg->elements[idx].num_values++; + + return 0; +} + +/* + add an index entry for one message element +*/ +static int ltdb_index_add1(struct ldb_module *module, const char *dn, + struct ldb_message_element *el, int v_idx) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_message *msg; + struct ldb_dn *dn_key; + int ret; + unsigned int i; + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + errno = ENOMEM; + return -1; + } + + dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]); + if (!dn_key) { + talloc_free(msg); + errno = ENOMEM; + return -1; + } + talloc_steal(msg, dn_key); + + ret = ltdb_search_dn1(module, dn_key, msg); + if (ret == -1) { + talloc_free(msg); + return -1; + } + + if (ret == 0) { + msg->dn = dn_key; + msg->num_elements = 0; + msg->elements = NULL; + } + + for (i=0;inum_elements;i++) { + if (strcmp(LTDB_IDX, msg->elements[i].name) == 0) { + break; + } + } + + if (i == msg->num_elements) { + ret = ltdb_index_add1_new(ldb, msg, el, dn); + } else { + ret = ltdb_index_add1_add(ldb, msg, el, i, dn); + } + + if (ret == 0) { + ret = ltdb_store(module, msg, TDB_REPLACE); + } + + talloc_free(msg); + + return ret; +} + +static int ltdb_index_add0(struct ldb_module *module, const char *dn, + struct ldb_message_element *elements, int num_el) +{ + struct ltdb_private *ltdb = module->private_data; + int ret; + unsigned int i, j; + + if (dn[0] == '@') { + return 0; + } + + if (ltdb->cache->indexlist->num_elements == 0) { + /* no indexed fields */ + return 0; + } + + for (i = 0; i < num_el; i++) { + ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name, + NULL, LTDB_IDXATTR); + if (ret == -1) { + continue; + } + for (j = 0; j < elements[i].num_values; j++) { + ret = ltdb_index_add1(module, dn, &elements[i], j); + if (ret == -1) { + return -1; + } + } + } + + return 0; +} + +/* + add the index entries for a new record + return -1 on failure +*/ +int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ltdb_private *ltdb = module->private_data; + char *dn; + int ret; + + dn = ldb_dn_linearize(ltdb, msg->dn); + if (dn == NULL) { + return -1; + } + + ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements); + + talloc_free(dn); + + return ret; +} + + +/* + delete an index entry for one message element +*/ +int ltdb_index_del_value(struct ldb_module *module, const char *dn, + struct ldb_message_element *el, int v_idx) +{ + struct ldb_context *ldb = module->ldb; + struct ldb_message *msg; + struct ldb_dn *dn_key; + int ret, i; + unsigned int j; + + if (dn[0] == '@') { + return 0; + } + + dn_key = ldb_dn_key(ldb, el->name, &el->values[v_idx]); + if (!dn_key) { + return -1; + } + + msg = talloc(dn_key, struct ldb_message); + if (msg == NULL) { + talloc_free(dn_key); + return -1; + } + + ret = ltdb_search_dn1(module, dn_key, msg); + if (ret == -1) { + talloc_free(dn_key); + return -1; + } + + if (ret == 0) { + /* it wasn't indexed. Did we have an earlier error? If we did then + its gone now */ + talloc_free(dn_key); + return 0; + } + + i = ldb_msg_find_idx(msg, dn, &j, LTDB_IDX); + if (i == -1) { + ldb_debug(ldb, LDB_DEBUG_ERROR, + "ERROR: dn %s not found in %s\n", dn, + ldb_dn_linearize(dn_key, dn_key)); + /* it ain't there. hmmm */ + talloc_free(dn_key); + return 0; + } + + if (j != msg->elements[i].num_values - 1) { + memmove(&msg->elements[i].values[j], + &msg->elements[i].values[j+1], + (msg->elements[i].num_values-(j+1)) * + sizeof(msg->elements[i].values[0])); + } + msg->elements[i].num_values--; + + if (msg->elements[i].num_values == 0) { + ret = ltdb_delete_noindex(module, dn_key); + } else { + ret = ltdb_store(module, msg, TDB_REPLACE); + } + + talloc_free(dn_key); + + return ret; +} + +/* + delete the index entries for a record + return -1 on failure +*/ +int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ltdb_private *ltdb = module->private_data; + int ret; + char *dn; + unsigned int i, j; + + if (ldb_dn_is_special(msg->dn)) { + return 0; + } + + dn = ldb_dn_linearize(ltdb, msg->dn); + if (dn == NULL) { + return -1; + } + + /* find the list of indexed fields */ + if (ltdb->cache->indexlist->num_elements == 0) { + /* no indexed fields */ + return 0; + } + + for (i = 0; i < msg->num_elements; i++) { + ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name, + NULL, LTDB_IDXATTR); + if (ret == -1) { + continue; + } + for (j = 0; j < msg->elements[i].num_values; j++) { + ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); + if (ret == -1) { + talloc_free(dn); + return -1; + } + } + } + + talloc_free(dn); + return 0; +} + + +/* + traversal function that deletes all @INDEX records +*/ +static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + const char *dn = "DN=" LTDB_INDEX ":"; + if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) { + return tdb_delete(tdb, key); + } + return 0; +} + +/* + traversal function that adds @INDEX records during a re index +*/ +static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +{ + struct ldb_module *module = state; + struct ldb_message *msg; + char *dn = NULL; + int ret; + TDB_DATA key2; + + if (strncmp((char *)key.dptr, "DN=@", 4) == 0 || + strncmp((char *)key.dptr, "DN=", 3) != 0) { + return 0; + } + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + return -1; + } + + ret = ltdb_unpack_data(module, &data, msg); + if (ret != 0) { + talloc_free(msg); + return -1; + } + + /* check if the DN key has changed, perhaps due to the + case insensitivity of an element changing */ + key2 = ltdb_key(module, msg->dn); + if (key2.dptr == NULL) { + /* probably a corrupt record ... darn */ + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n", + ldb_dn_linearize(msg, msg->dn)); + talloc_free(msg); + return 0; + } + if (strcmp((char *)key2.dptr, (char *)key.dptr) != 0) { + tdb_delete(tdb, key); + tdb_store(tdb, key2, data, 0); + } + talloc_free(key2.dptr); + + if (msg->dn == NULL) { + dn = (char *)key.dptr + 3; + } else { + dn = ldb_dn_linearize(msg->dn, msg->dn); + } + + ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements); + + talloc_free(msg); + + return ret; +} + +/* + force a complete reindex of the database +*/ +int ltdb_reindex(struct ldb_module *module) +{ + struct ltdb_private *ltdb = module->private_data; + int ret; + + if (ltdb_cache_reload(module) != 0) { + return -1; + } + + /* first traverse the database deleting any @INDEX records */ + ret = tdb_traverse(ltdb->tdb, delete_index, NULL); + if (ret == -1) { + return -1; + } + + /* now traverse adding any indexes for normal LDB records */ + ret = tdb_traverse(ltdb->tdb, re_index, module); + if (ret == -1) { + return -1; + } + + return 0; +} diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c new file mode 100644 index 0000000000..c6edf663ae --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c @@ -0,0 +1,294 @@ +/* + 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; + char *dn; + uint8_t *p; + size_t len; + + dn = ldb_dn_linearize(ldb, 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;inum_elements;i++) { + if (attribute_storable_values(&message->elements[i]) == 0) { + continue; + } + + real_elements++; + + size += 1 + strlen(message->elements[i].name) + 4; + for (j=0;jelements[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) { + talloc_free(dn); + 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;inum_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;jelements[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; + } + } + + talloc_free(dn); + 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_explode(message, (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;inum_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;jelements[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; +} diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c new file mode 100644 index 0000000000..7cdb2b672f --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -0,0 +1,543 @@ +/* + 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;inum_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_linearize(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;inum_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, const 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; +} + +/* the lock key for search locking. Note that this is not a DN, its + just an arbitrary key to give to tdb. Also note that as we and + using transactions for all write operations and transactions take + care of their own locks, we don't need to do any locking anywhere + other than in ldb_search() */ +#define LDBLOCK "INT_LDBLOCK" + +/* + 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; + TDB_DATA key; + + key.dptr = discard_const(LDBLOCK); + key.dsize = strlen(LDBLOCK); + + return tdb_chainlock_read(ltdb->tdb, key); +} + +/* + unlock the database after a ltdb_lock_read() +*/ +static int ltdb_unlock_read(struct ldb_module *module) +{ + struct ltdb_private *ltdb = module->private_data; + TDB_DATA key; + + key.dptr = discard_const(LDBLOCK); + key.dsize = strlen(LDBLOCK); + + return tdb_chainunlock_read(ltdb->tdb, key); +} + +/* + 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_explode(ares->message, (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 ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; + + if (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->context, req->callback); + 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; +} + diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c new file mode 100644 index 0000000000..8f676654a6 --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -0,0 +1,1065 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 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_tdb + * + * Component: ldb tdb backend + * + * Description: core functions for tdb backend + * + * Author: Andrew Tridgell + * Author: Stefan Metzmacher + * + * Modifications: + * + * - description: make the module use asyncronous calls + * date: Feb 2006 + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#include "ldb/ldb_tdb/ldb_tdb.h" + + +/* + map a tdb error code to a ldb error code +*/ +static int ltdb_err_map(enum TDB_ERROR tdb_code) +{ + switch (tdb_code) { + case TDB_SUCCESS: + return LDB_SUCCESS; + case TDB_ERR_CORRUPT: + case TDB_ERR_OOM: + case TDB_ERR_EINVAL: + return LDB_ERR_OPERATIONS_ERROR; + case TDB_ERR_IO: + return LDB_ERR_PROTOCOL_ERROR; + case TDB_ERR_LOCK: + case TDB_ERR_NOLOCK: + return LDB_ERR_BUSY; + case TDB_ERR_LOCK_TIMEOUT: + return LDB_ERR_TIME_LIMIT_EXCEEDED; + case TDB_ERR_EXISTS: + return LDB_ERR_ENTRY_ALREADY_EXISTS; + case TDB_ERR_NOEXIST: + return LDB_ERR_NO_SUCH_OBJECT; + case TDB_ERR_RDONLY: + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + return LDB_ERR_OTHER; +} + + +struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +{ + struct ltdb_context *ac; + struct ldb_handle *h; + + h = talloc_zero(ltdb, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return NULL; + } + + h->module = module; + + ac = talloc_zero(h, struct ltdb_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; + + return h; +} + +/* + form a TDB_DATA for a record key + caller frees + + note that the key for a record can depend on whether the + dn refers to a case sensitive index record or not +*/ +struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ldb_context *ldb = module->ldb; + TDB_DATA key; + char *key_str = NULL; + char *dn_folded = NULL; + + /* + most DNs are case insensitive. The exception is index DNs for + case sensitive attributes + + there are 3 cases dealt with in this code: + + 1) if the dn doesn't start with @ then uppercase the attribute + names and the attributes values of case insensitive attributes + 2) if the dn starts with @ then leave it alone - the indexing code handles + the rest + */ + + dn_folded = ldb_dn_linearize_casefold(ldb, dn); + if (!dn_folded) { + goto failed; + } + + key_str = talloc_asprintf(ldb, "DN=%s", dn_folded); + + talloc_free(dn_folded); + + if (!key_str) { + goto failed; + } + + key.dptr = (uint8_t *)key_str; + key.dsize = strlen(key_str) + 1; + + return key; + +failed: + errno = ENOMEM; + key.dptr = NULL; + key.dsize = 0; + return key; +} + +/* + check special dn's have valid attributes + currently only @ATTRIBUTES is checked +*/ +int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg) +{ + int i, j; + + if (! ldb_dn_is_special(msg->dn) || + ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { + return 0; + } + + /* we have @ATTRIBUTES, let's check attributes are fine */ + /* should we check that we deny multivalued attributes ? */ + for (i = 0; i < msg->num_elements; i++) { + for (j = 0; j < msg->elements[i].num_values; j++) { + if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) { + ldb_set_errstring(module->ldb, "Invalid attribute value in an @ATTRIBUTES entry"); + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + } + } + + return 0; +} + + +/* + we've made a modification to a dn - possibly reindex and + update sequence number +*/ +static int ltdb_modified(struct ldb_module *module, const struct ldb_dn *dn) +{ + int ret = 0; + + if (ldb_dn_is_special(dn) && + (ldb_dn_check_special(dn, LTDB_INDEXLIST) || + ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) { + ret = ltdb_reindex(module); + } + + if (ret == 0 && + !(ldb_dn_is_special(dn) && + ldb_dn_check_special(dn, LTDB_BASEINFO)) ) { + ret = ltdb_increase_sequence_number(module); + } + + return ret; +} + +/* + store a record into the db +*/ +int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs) +{ + struct ltdb_private *ltdb = module->private_data; + TDB_DATA tdb_key, tdb_data; + int ret; + + tdb_key = ltdb_key(module, msg->dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + ret = ltdb_pack_data(module, msg, &tdb_data); + if (ret == -1) { + talloc_free(tdb_key.dptr); + return LDB_ERR_OTHER; + } + + ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs); + if (ret == -1) { + ret = ltdb_err_map(tdb_error(ltdb->tdb)); + goto done; + } + + ret = ltdb_index_add(module, msg); + if (ret == -1) { + tdb_delete(ltdb->tdb, tdb_key); + } + +done: + talloc_free(tdb_key.dptr); + talloc_free(tdb_data.dptr); + + return ret; +} + + +static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg) +{ + int ret; + + ret = ltdb_check_special_dn(module, msg); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_store(module, msg, TDB_INSERT); + + if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { + char *dn; + + dn = ldb_dn_linearize(module, msg->dn); + if (!dn) { + return ret; + } + ldb_asprintf_errstring(module->ldb, "Entry %s already exists", dn); + talloc_free(dn); + return ret; + } + + if (ret == LDB_SUCCESS) { + ret = ltdb_modified(module, msg->dn); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + + return ret; +} + +/* + add a record to the database +*/ +static int ltdb_add(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; + int tret, ret = LDB_SUCCESS; + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + } + + req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_add_internal(module, req->op.add.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + delete a record from the database, not updating indexes (used for deleting + index records) +*/ +int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ltdb_private *ltdb = module->private_data; + TDB_DATA tdb_key; + int ret; + + tdb_key = ltdb_key(module, dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + ret = tdb_delete(ltdb->tdb, tdb_key); + talloc_free(tdb_key.dptr); + + if (ret != 0) { + ret = ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return ret; +} + +static int ltdb_delete_internal(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ldb_message *msg; + int ret; + + msg = talloc(module, struct ldb_message); + if (msg == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* in case any attribute of the message was indexed, we need + to fetch the old record */ + ret = ltdb_search_dn1(module, dn, msg); + if (ret != 1) { + /* not finding the old record is an error */ + talloc_free(msg); + return LDB_ERR_NO_SUCH_OBJECT; + } + + ret = ltdb_delete_noindex(module, dn); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + return LDB_ERR_NO_SUCH_OBJECT; + } + + /* remove any indexed attributes */ + ret = ltdb_index_del(module, msg); + if (ret != LDB_SUCCESS) { + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_modified(module, dn); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(msg); + return LDB_SUCCESS; +} + +/* + delete a record from the database +*/ +static int ltdb_delete(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; + int tret, ret = LDB_SUCCESS; + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + } + + req->handle = NULL; + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_delete_internal(module, req->op.del.dn); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + find an element by attribute name. At the moment this does a linear search, it should + be re-coded to use a binary search once all places that modify records guarantee + sorted order + + return the index of the first matching element if found, otherwise -1 +*/ +static int find_element(const struct ldb_message *msg, const char *name) +{ + unsigned int i; + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { + return i; + } + } + return -1; +} + + +/* + add an element to an existing record. Assumes a elements array that we + can call re-alloc on, and assumed that we can re-use the data pointers from the + passed in additional values. Use with care! + + returns 0 on success, -1 on failure (and sets errno) +*/ +static int msg_add_element(struct ldb_context *ldb, + struct ldb_message *msg, struct ldb_message_element *el) +{ + struct ldb_message_element *e2; + unsigned int i; + + e2 = talloc_realloc(msg, msg->elements, struct ldb_message_element, + msg->num_elements+1); + if (!e2) { + errno = ENOMEM; + return -1; + } + + msg->elements = e2; + + e2 = &msg->elements[msg->num_elements]; + + e2->name = el->name; + e2->flags = el->flags; + e2->values = NULL; + if (el->num_values != 0) { + e2->values = talloc_array(msg->elements, struct ldb_val, el->num_values); + if (!e2->values) { + errno = ENOMEM; + return -1; + } + } + for (i=0;inum_values;i++) { + e2->values[i] = el->values[i]; + } + e2->num_values = el->num_values; + + msg->num_elements++; + + return 0; +} + +/* + delete all elements having a specified attribute name +*/ +static int msg_delete_attribute(struct ldb_module *module, + struct ldb_context *ldb, + struct ldb_message *msg, const char *name) +{ + char *dn; + unsigned int i, j; + + dn = ldb_dn_linearize(ldb, msg->dn); + if (dn == NULL) { + return -1; + } + + for (i=0;inum_elements;i++) { + if (ldb_attr_cmp(msg->elements[i].name, name) == 0) { + for (j=0;jelements[i].num_values;j++) { + ltdb_index_del_value(module, dn, &msg->elements[i], j); + } + talloc_free(msg->elements[i].values); + if (msg->num_elements > (i+1)) { + memmove(&msg->elements[i], + &msg->elements[i+1], + sizeof(struct ldb_message_element)* + (msg->num_elements - (i+1))); + } + msg->num_elements--; + i--; + msg->elements = talloc_realloc(msg, msg->elements, + struct ldb_message_element, + msg->num_elements); + } + } + + talloc_free(dn); + return 0; +} + +/* + delete all elements matching an attribute name/value + + return 0 on success, -1 on failure +*/ +static int msg_delete_element(struct ldb_module *module, + struct ldb_message *msg, + const char *name, + const struct ldb_val *val) +{ + struct ldb_context *ldb = module->ldb; + unsigned int i; + int found; + struct ldb_message_element *el; + const struct ldb_attrib_handler *h; + + found = find_element(msg, name); + if (found == -1) { + return -1; + } + + el = &msg->elements[found]; + + h = ldb_attrib_handler(ldb, el->name); + + for (i=0;inum_values;i++) { + if (h->comparison_fn(ldb, ldb, &el->values[i], val) == 0) { + if (inum_values-1) { + memmove(&el->values[i], &el->values[i+1], + sizeof(el->values[i])*(el->num_values-(i+1))); + } + el->num_values--; + if (el->num_values == 0) { + return msg_delete_attribute(module, ldb, msg, name); + } + return 0; + } + } + + return -1; +} + + +/* + modify a record - internal interface + + yuck - this is O(n^2). Luckily n is usually small so we probably + get away with it, but if we ever have really large attribute lists + then we'll need to look at this again +*/ +int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_context *ldb = module->ldb; + struct ltdb_private *ltdb = module->private_data; + TDB_DATA tdb_key, tdb_data; + struct ldb_message *msg2; + unsigned i, j; + int ret; + + tdb_key = ltdb_key(module, msg->dn); + if (!tdb_key.dptr) { + return LDB_ERR_OTHER; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + if (!tdb_data.dptr) { + talloc_free(tdb_key.dptr); + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + msg2 = talloc(tdb_key.dptr, struct ldb_message); + if (msg2 == NULL) { + talloc_free(tdb_key.dptr); + return LDB_ERR_OTHER; + } + + ret = ltdb_unpack_data(module, &tdb_data, msg2); + if (ret == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } + + if (!msg2->dn) { + msg2->dn = msg->dn; + } + + for (i=0;inum_elements;i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct ldb_message_element *el2; + struct ldb_val *vals; + char *dn; + + switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { + + case LDB_FLAG_MOD_ADD: + /* add this element to the message. fail if it + already exists */ + ret = find_element(msg2, el->name); + + if (ret == -1) { + if (msg_add_element(ldb, msg2, el) != 0) { + ret = LDB_ERR_OTHER; + goto failed; + } + continue; + } + + el2 = &msg2->elements[ret]; + + /* An attribute with this name already exists, add all + * values if they don't already exist. */ + + for (j=0;jnum_values;j++) { + if (ldb_msg_find_val(el2, &el->values[j])) { + ldb_set_errstring(module->ldb, "Type or value exists"); + ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + goto failed; + } + } + + vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val, + el2->num_values + el->num_values); + + if (vals == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + for (j=0;jnum_values;j++) { + vals[el2->num_values + j] = + ldb_val_dup(vals, &el->values[j]); + } + + el2->values = vals; + el2->num_values += el->num_values; + + break; + + case LDB_FLAG_MOD_REPLACE: + /* replace all elements of this attribute name with the elements + listed. The attribute not existing is not an error */ + msg_delete_attribute(module, ldb, msg2, msg->elements[i].name); + + /* add the replacement element, if not empty */ + if (msg->elements[i].num_values != 0 && + msg_add_element(ldb, msg2, &msg->elements[i]) != 0) { + ret = LDB_ERR_OTHER; + goto failed; + } + break; + + case LDB_FLAG_MOD_DELETE: + + dn = ldb_dn_linearize(msg2, msg->dn); + if (dn == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } + + /* we could be being asked to delete all + values or just some values */ + if (msg->elements[i].num_values == 0) { + if (msg_delete_attribute(module, ldb, msg2, + msg->elements[i].name) != 0) { + ldb_asprintf_errstring(module->ldb, "No such attribute: %s for delete on %s", msg->elements[i].name, dn); + ret = LDB_ERR_NO_SUCH_ATTRIBUTE; + goto failed; + } + break; + } + for (j=0;jelements[i].num_values;j++) { + if (msg_delete_element(module, + msg2, + msg->elements[i].name, + &msg->elements[i].values[j]) != 0) { + ldb_asprintf_errstring(module->ldb, "No matching attribute value when deleting attribute: %s on %s", msg->elements[i].name, dn); + ret = LDB_ERR_NO_SUCH_ATTRIBUTE; + goto failed; + } + if (ltdb_index_del_value(module, dn, &msg->elements[i], j) != 0) { + ret = LDB_ERR_OTHER; + goto failed; + } + } + break; + default: + ldb_asprintf_errstring(module->ldb, "Invalid ldb_modify flags on %s: 0x%x", + msg->elements[i].name, + msg->elements[i].flags & LDB_FLAG_MOD_MASK); + ret = LDB_ERR_PROTOCOL_ERROR; + goto failed; + } + } + + /* we've made all the mods - save the modified record back into the database */ + ret = ltdb_store(module, msg2, TDB_MODIFY); + if (ret != LDB_SUCCESS) { + goto failed; + } + + if (ltdb_modified(module, msg->dn) != LDB_SUCCESS) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto failed; + } + + talloc_free(tdb_key.dptr); + free(tdb_data.dptr); + return ret; + +failed: + talloc_free(tdb_key.dptr); + free(tdb_data.dptr); + return ret; +} + +/* + modify a record +*/ +static int ltdb_modify(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; + int tret, ret = LDB_SUCCESS; + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + } + + req->handle = NULL; + + req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + tret = ltdb_check_special_dn(module, req->op.mod.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_cache_load(module) != 0) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + tret = ltdb_modify_internal(module, req->op.mod.message); + if (tret != LDB_SUCCESS) { + req->handle->status = tret; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* + rename a record +*/ +static int ltdb_rename(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_message *msg; + int tret, ret = LDB_SUCCESS; + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + } + + req->handle = NULL; + + if (ltdb_cache_load(module) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + + msg = talloc(ltdb_ac, struct ldb_message); + if (msg == NULL) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + /* in case any attribute of the message was indexed, we need + to fetch the old record */ + tret = ltdb_search_dn1(module, req->op.rename.olddn, msg); + if (tret != 1) { + /* not finding the old record is an error */ + req->handle->status = LDB_ERR_NO_SUCH_OBJECT; + goto done; + } + + msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); + if (!msg->dn) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + tret = ltdb_add_internal(module, msg); + if (tret != LDB_SUCCESS) { + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + tret = ltdb_delete_internal(module, req->op.rename.olddn); + if (tret != LDB_SUCCESS) { + ltdb_delete_internal(module, req->op.rename.newdn); + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; + } + + if (ltdb_ac->callback) { + ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + } +done: + req->handle->state = LDB_ASYNC_DONE; + return ret; +} + +static int ltdb_start_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = module->private_data; + + if (tdb_transaction_start(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return LDB_SUCCESS; +} + +static int ltdb_end_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = module->private_data; + + if (tdb_transaction_commit(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return LDB_SUCCESS; +} + +static int ltdb_del_trans(struct ldb_module *module) +{ + struct ltdb_private *ltdb = module->private_data; + + if (tdb_transaction_cancel(ltdb->tdb) != 0) { + return ltdb_err_map(tdb_error(ltdb->tdb)); + } + + return LDB_SUCCESS; +} + +static int ltdb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +static int ltdb_request(struct ldb_module *module, struct ldb_request *req) +{ + /* check for oustanding critical controls and return an error if found */ + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + } + + /* search, add, modify, delete, rename are handled by their own, no other op supported */ + return LDB_ERR_OPERATIONS_ERROR; +} + +/* + return sequenceNumber from @BASEINFO +*/ +static int ltdb_sequence_number(struct ldb_module *module, struct ldb_request *req) +{ + TALLOC_CTX *tmp_ctx = talloc_new(req); + struct ldb_message *msg = NULL; + struct ldb_dn *dn = ldb_dn_explode(tmp_ctx, LTDB_BASEINFO); + int tret; + + if (tmp_ctx == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = talloc(tmp_ctx, struct ldb_message); + if (msg == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->op.seq_num.flags = 0; + + tret = ltdb_search_dn1(module, dn, msg); + if (tret != 1) { + talloc_free(tmp_ctx); + req->op.seq_num.seq_num = 0; + /* zero is as good as anything when we don't know */ + return LDB_SUCCESS; + } + + switch (req->op.seq_num.type) { + case LDB_SEQ_HIGHEST_SEQ: + req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); + break; + case LDB_SEQ_NEXT: + req->op.seq_num.seq_num = ldb_msg_find_attr_as_uint64(msg, LTDB_SEQUENCE_NUMBER, 0); + req->op.seq_num.seq_num++; + break; + case LDB_SEQ_HIGHEST_TIMESTAMP: + { + const char *date = ldb_msg_find_attr_as_string(msg, LTDB_MOD_TIMESTAMP, NULL); + if (date) { + req->op.seq_num.seq_num = ldb_string_to_time(date); + } else { + req->op.seq_num.seq_num = 0; + /* zero is as good as anything when we don't know */ + } + break; + } + } + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + +static const struct ldb_module_ops ltdb_ops = { + .name = "tdb", + .search = ltdb_search, + .add = ltdb_add, + .modify = ltdb_modify, + .del = ltdb_delete, + .rename = ltdb_rename, + .request = ltdb_request, + .start_transaction = ltdb_start_trans, + .end_transaction = ltdb_end_trans, + .del_transaction = ltdb_del_trans, + .wait = ltdb_wait, + .sequence_number = ltdb_sequence_number +}; + +/* + connect to the database +*/ +static int ltdb_connect(struct ldb_context *ldb, const char *url, + unsigned int flags, const char *options[], + struct ldb_module **module) +{ + const char *path; + int tdb_flags, open_flags; + struct ltdb_private *ltdb; + + /* parse the url */ + if (strchr(url, ':')) { + if (strncmp(url, "tdb://", 6) != 0) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url); + return -1; + } + path = url+6; + } else { + path = url; + } + + tdb_flags = TDB_DEFAULT; + + /* check for the 'nosync' option */ + if (flags & LDB_FLG_NOSYNC) { + tdb_flags |= TDB_NOSYNC; + } + + if (flags & LDB_FLG_RDONLY) { + open_flags = O_RDONLY; + } else { + open_flags = O_CREAT | O_RDWR; + } + + ltdb = talloc_zero(ldb, struct ltdb_private); + if (!ltdb) { + ldb_oom(ldb); + return -1; + } + + /* note that we use quite a large default hash size */ + ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, + tdb_flags, open_flags, 0666, ldb); + if (!ltdb->tdb) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path); + talloc_free(ltdb); + return -1; + } + + ltdb->sequence_number = 0; + + *module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); + talloc_free(ltdb); + return -1; + } + (*module)->ldb = ldb; + (*module)->prev = (*module)->next = NULL; + (*module)->private_data = ltdb; + (*module)->ops = <db_ops; + + return 0; +} + +int ldb_tdb_init(void) +{ + return ldb_register_backend("tdb", ltdb_connect); +} diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.h b/source3/lib/ldb/ldb_tdb/ldb_tdb.h new file mode 100644 index 0000000000..670d3b6801 --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.h @@ -0,0 +1,127 @@ + +#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; + + struct ltdb_cache { + struct ldb_message *baseinfo; + 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; + const 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, const 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, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)); +struct TDB_DATA ltdb_key(struct ldb_module *module, const 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, const 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); + diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c new file mode 100644 index 0000000000..b28bf77450 --- /dev/null +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -0,0 +1,174 @@ +/* + 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) { + talloc_reference(mem_ctx, w); + 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; +} + diff --git a/source3/lib/ldb/libldb.m4 b/source3/lib/ldb/libldb.m4 new file mode 100644 index 0000000000..845563b4a1 --- /dev/null +++ b/source3/lib/ldb/libldb.m4 @@ -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) diff --git a/source3/lib/ldb/mainpage.dox b/source3/lib/ldb/mainpage.dox new file mode 100644 index 0000000000..bbd8d9c502 --- /dev/null +++ b/source3/lib/ldb/mainpage.dox @@ -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 OpenLDAP +project.

+ +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.

+ +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 talloc + - 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 functions + - a list of examples + - a list of data structures + - a list of constants + +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 +tools directory. + +ldb makes use of the LDAP Data Interchange Format (LDIF), which is +documented in RFC +2849. + +\section Support + +ldb does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list, and the Samba +bugzilla 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 Andrew Tridgell. + +*/ diff --git a/source3/lib/ldb/man/ad2oLschema.1.xml b/source3/lib/ldb/man/ad2oLschema.1.xml new file mode 100644 index 0000000000..6ae8996477 --- /dev/null +++ b/source3/lib/ldb/man/ad2oLschema.1.xml @@ -0,0 +1,87 @@ + + + + + + ad2oLschema + 1 + + + + + ad2oLschema + Converts AC-like LDAP schemas to OpenLDAP + compatible schema files + + + + + ad2oLschema + -I INPUT-FILE + -O OUTPUT-FILE + + + + + DESCRIPTION + + ad2oLschema is a simple tool that converts AD-like LDIF + schema files into OpenLDAP schema files. + + + + + OPTIONS + + + + -H url + URL to an LDB or LDAP server with an AD schema to read. + + + + -I input-file AD schema + to read. If neither this nor -H is specified, the + schema file will be read from standard input. + + + + + -O output-file + File to write OpenLDAP version of schema to. + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + ad2oLschema was written by Andrew Bartlett. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + + + diff --git a/source3/lib/ldb/man/ldb.3.xml b/source3/lib/ldb/man/ldb.3.xml new file mode 100644 index 0000000000..6a3a789034 --- /dev/null +++ b/source3/lib/ldb/man/ldb.3.xml @@ -0,0 +1,262 @@ + + + + + + ldb + 3 + + + + ldb + The Samba Project + A light-weight database library + + + + #include <ldb.h> + + + + description + + +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. + + + +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. + + + +It 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. + + + +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. + + + +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. + + + +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. + + + + + TOOLS + + + + ldbsearch(1) + - command line ldb search utility + + + + ldbedit(1) + - edit all or part of a ldb database using your favourite editor + + + + ldbadd(1) + - add records to a ldb database using LDIF formatted input + + + + ldbdel(1) + - delete records from a ldb database + + + + ldbmodify(1) + - modify records in a ldb database using LDIF formatted input + + + + + + FUNCTIONS + + + + ldb_connect(3) + - connect to a ldb backend + + + + ldb_search(3) + - perform a database search + + + + ldb_add(3) + - add a record to the database + + + + ldb_delete(3) + - delete a record from the database + + + + ldb_modify(3) + - modify a record in the database + + + + ldb_errstring(3) + - retrieve extended error information from the last operation + + + + ldb_ldif_write(3) + - write a LDIF formatted message + + + + ldb_ldif_write_file(3) + - write a LDIF formatted message to a file + + + + ldb_ldif_read(3) + - read a LDIF formatted message + + + + ldb_ldif_read_free(3) + - free the result of a ldb_ldif_read() + + + + ldb_ldif_read_file(3) + - read a LDIF message from a file + + + + ldb_ldif_read_string(3) + - read a LDIF message from a string + + + + ldb_msg_find_element(3) + - find an element in a ldb_message + + + + ldb_val_equal_exact(3) + - compare two ldb_val structures + + + + ldb_msg_find_val(3) + - find an element by value + + + + ldb_msg_add_empty(3) + - add an empty message element to a ldb_message + + + + + ldb_msg_add(3) + - add a non-empty message element to a ldb_message + + + + + ldb_msg_element_compare(3) + - compare two ldb_message_element structures + + + + + ldb_msg_find_int(3) + - return an integer value from a ldb_message + + + + + ldb_msg_find_uint(3) + - return an unsigned integer value from a ldb_message + + + + + ldb_msg_find_double(3) + - return a double value from a ldb_message + + + + + ldb_msg_find_string(3) + - return a string value from a ldb_message + + + + + ldb_set_alloc(3) + - set the memory allocation function to be used by ldb + + + + + ldb_set_debug(3) + - set a debug handler to be used by ldb + + + + + ldb_set_debug_stderr(3) + - set a debug handler for stderr output + + + + + + Author + + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + +ldb is released under the GNU Lesser General Public License version 2 +or later. Please see the file COPYING for license details. + + + diff --git a/source3/lib/ldb/man/ldbadd.1.xml b/source3/lib/ldb/man/ldbadd.1.xml new file mode 100644 index 0000000000..7ad0f835d0 --- /dev/null +++ b/source3/lib/ldb/man/ldbadd.1.xml @@ -0,0 +1,105 @@ + + + + + + ldbadd + 1 + + + + + ldbadd + Command-line utility for adding records to an LDB + + + + + ldbadd + -h + -H LDB-URL + ldif-file1 + ldif-file2 + ... + + + + + DESCRIPTION + + 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. + + + If - is specified as a ldb file, the ldif input is read from + standard input. + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/source3/lib/ldb/man/ldbdel.1.xml b/source3/lib/ldb/man/ldbdel.1.xml new file mode 100644 index 0000000000..7dfc7366f6 --- /dev/null +++ b/source3/lib/ldb/man/ldbdel.1.xml @@ -0,0 +1,105 @@ + + + + + + ldbdel + 1 + + + + + ldbdel + Command-line program for deleting LDB records + + + + + ldbdel + -h + -H LDB-URL + dn + ... + + + + + DESCRIPTION + + ldbdel deletes records from an ldb(7) database. + It deletes the records identified by the dn's specified + on the command-line. + + ldbdel uses either the database that is specified with + the -H option or the database specified by the LDB_URL environment + variable. + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbadd, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + ldbdel was written by Andrew Tridgell. + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/source3/lib/ldb/man/ldbedit.1.xml b/source3/lib/ldb/man/ldbedit.1.xml new file mode 100644 index 0000000000..15c69b1b25 --- /dev/null +++ b/source3/lib/ldb/man/ldbedit.1.xml @@ -0,0 +1,200 @@ + + + + + + ldbedit + 1 + + + + + ldbedit + Edit LDB databases using your preferred editor + + + + + ldbedit + -? + --usage + -s base|one|sub + -b basedn + -a + -e editor + -H LDB-URL + expression + attributes + + + + + DESCRIPTION + + 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. + + + + + + + OPTIONS + + + + -? + --help + + + Show list of available options, and a phrase describing what that option + does. + + + + + + --usage + + + Show list of available options. This is similar to the help option, + however it does not provide any description, and is hence shorter. + + + + + + -H <ldb-url> + + + LDB URL to connect to. For a tdb database, + this will be of the form + tdb://filename. + For a LDAP connection over unix domain + sockets, this will be of the form + ldapi://socket. For + a (potentially remote) LDAP connection over + TCP, this will be of the form + ldap://hostname. For + an SQLite database, this will be of the form + sqlite://filename. + + + + + + -s one|sub|base + Search scope to use. One-level, subtree or base. + + + + -a + -all + + 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=*". + + + + + + -e editor + --editor editor + + 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. + + + + + + -b basedn + Specify Base Distinguished Name to use. + + + + -v + --verbose + + Make ldbedit more verbose about the + operations that are being performed. Without + this option, ldbedit will only provide a + summary change line. + + + + + + + + + + ENVIRONMENT + + + + LDB_URL + + LDB URL to connect to. This can be + overridden by using the -H command-line option.) + + + + + VISUAL and EDITOR + + + Environment variables used to determine what + editor to use. VISUAL takes precedence over + EDITOR, and both are overridden by the + -e command-line option. + + + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify(1), ldbdel(1), ldif(5), vi(1) + + + + + AUTHOR + + + ldb was written by + Andrew Tridgell. + + + + If you wish to report a problem or make a suggestion then please see + the web site for + current contact and maintainer information. + + + + This manpage was written by Jelmer Vernooij and updated + by Brad Hards. + + + + + diff --git a/source3/lib/ldb/man/ldbmodify.1.xml b/source3/lib/ldb/man/ldbmodify.1.xml new file mode 100644 index 0000000000..bc19647785 --- /dev/null +++ b/source3/lib/ldb/man/ldbmodify.1.xml @@ -0,0 +1,93 @@ + + + + + + ldbmodify + 1 + + + + + ldbmodify + Modify records in a LDB database + + + + + ldbmodify + -H LDB-URL + ldif-file + + + + + DESCRIPTION + + + 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. + + + For now, see ldapmodify(1) for details on the LDIF file format. + + + + + + OPTIONS + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbedit + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/source3/lib/ldb/man/ldbrename.1.xml b/source3/lib/ldb/man/ldbrename.1.xml new file mode 100644 index 0000000000..391ec84ccc --- /dev/null +++ b/source3/lib/ldb/man/ldbrename.1.xml @@ -0,0 +1,107 @@ + + + + + + ldbrename + 1 + + + + + ldbrename + Edit LDB databases using your favorite editor + + + + + ldbrename + -h + -o options + olddn + newdb + + + + + DESCRIPTION + + 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. + + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + -o options + Extra ldb options, such as + modules. + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/source3/lib/ldb/man/ldbsearch.1.xml b/source3/lib/ldb/man/ldbsearch.1.xml new file mode 100644 index 0000000000..ed3749b920 --- /dev/null +++ b/source3/lib/ldb/man/ldbsearch.1.xml @@ -0,0 +1,119 @@ + + + + + + ldbsearch + 1 + + + + + ldbsearch + Search for records in a LDB database + + + + + ldbsearch + -h + -s base|one|sub + -b basedn + -i + -H LDB-URL + expression + attributes + + + + + DESCRIPTION + + 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. + + + + + + + OPTIONS + + + + -h + + Show list of available options. + + + + -H <ldb-url> + + LDB URL to connect to. See ldb(7) for details. + + + + + -s one|sub|base + Search scope to use. One-level, subtree or base. + + + + -i + Read search expressions from stdin. + + + + -b basedn + Specify Base DN to use. + + + + + + + + ENVIRONMENT + + + LDB_URL + LDB URL to connect to (can be overrided by using the + -H command-line option.) + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbedit(1) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/source3/lib/ldb/man/oLschema2ldif.1.xml b/source3/lib/ldb/man/oLschema2ldif.1.xml new file mode 100644 index 0000000000..b1e681be4e --- /dev/null +++ b/source3/lib/ldb/man/oLschema2ldif.1.xml @@ -0,0 +1,79 @@ + + + + + + oLschema2ldif + 1 + + + + + oLschema2ldif + Converts LDAP schema's to LDB-compatible LDIF + + + + + oLschema2ldif + -I INPUT-FILE + -O OUTPUT-FILE + + + + + DESCRIPTION + + oLschema2ldif is a simple tool that converts standard OpenLDAP schema files to a LDIF format that is understood by LDB. + + + + + OPTIONS + + + + -I input-file + OpenLDAP schema to read. If none are specified, +the schema file will be read from standard input. + + + + + -O output-file + File to write ldif version of schema to. + + + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + ldb(7), ldbmodify, ldbdel, ldif(5) + + + + + AUTHOR + + ldb was written by + Andrew Tridgell. + oLschema2ldif was written by Simo Sorce. + + + +If you wish to report a problem or make a suggestion then please see +the web site for +current contact and maintainer information. + + + + + diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c new file mode 100644 index 0000000000..229a6eacd9 --- /dev/null +++ b/source3/lib/ldb/modules/asq.c @@ -0,0 +1,471 @@ +/* + 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); + + 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); + + /* 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); + + /* 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); + + /* 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_explode(ac->reqs[i], (const char *)el->values[i].data); + if (ac->reqs[i]->op.search.base == NULL) { + 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); + + + 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); + + 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_ERROR, "asq: Unable to register control with rootdse!\n"); + return LDB_ERR_OTHER; + } + + 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); +} diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c new file mode 100644 index 0000000000..0c58687ddb --- /dev/null +++ b/source3/lib/ldb/modules/ldb_map.c @@ -0,0 +1,1361 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 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. +*/ + +/* + * Name: ldb + * + * Component: ldb ldb_map module + * + * Description: Map portions of data into a different format on a + * remote partition. + * + * Author: Jelmer Vernooij, Martin Kuehl + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#include "ldb/modules/ldb_map.h" +#include "ldb/modules/ldb_map_private.h" + +/* Description of the provided ldb requests: + - special attribute 'isMapped' + + - search: + - if parse tree can be split + - search remote records w/ remote attrs and parse tree + - otherwise + - enumerate all remote records + - for each remote result + - map remote result to local message + - search local result + - is present + - merge local into remote result + - run callback on merged result + - otherwise + - run callback on remote result + + - add: + - split message into local and remote part + - if local message is not empty + - add isMapped to local message + - add local message + - add remote message + + - modify: + - split message into local and remote part + - if local message is not empty + - add isMapped to local message + - search for local record + - if present + - modify local record + - otherwise + - add local message + - modify remote record + + - delete: + - search for local record + - if present + - delete local record + - delete remote record + + - rename: + - search for local record + - if present + - rename local record + - modify local isMapped + - rename remote record +*/ + + + +/* Private data structures + * ======================= */ + +/* Global private data */ +/* Extract mappings from private data. */ +const struct ldb_map_context *map_get_context(struct ldb_module *module) +{ + const struct map_private *data = talloc_get_type(module->private_data, struct map_private); + return data->context; +} + +/* Create a generic request context. */ +static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req) +{ + struct map_context *ac; + + ac = talloc_zero(h, struct map_context); + if (ac == NULL) { + map_oom(h->module); + return NULL; + } + + ac->module = h->module; + ac->orig_req = req; + + return ac; +} + +/* Create a search request context. */ +struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares) +{ + struct map_search_context *sc; + + sc = talloc_zero(ac, struct map_search_context); + if (sc == NULL) { + map_oom(ac->module); + return NULL; + } + + sc->ac = ac; + sc->local_res = NULL; + sc->remote_res = ares; + + return sc; +} + +/* Create a request context and handle. */ +struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module) +{ + struct map_context *ac; + struct ldb_handle *h; + + h = talloc_zero(req, struct ldb_handle); + if (h == NULL) { + map_oom(module); + return NULL; + } + + h->module = module; + + ac = map_init_context(h, req); + if (ac == NULL) { + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + return h; +} + + +/* Dealing with DNs for different partitions + * ========================================= */ + +/* Check whether any data should be stored in the local partition. */ +BOOL map_check_local_db(struct ldb_module *module) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (!data->remote_base_dn || !data->local_base_dn) { + return False; + } + + return True; +} + +/* WARK: verbatim copy from ldb_dn.c */ +static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) +{ + struct ldb_dn_component dst; + + memset(&dst, 0, sizeof(dst)); + + if (src == NULL) { + return dst; + } + + dst.value = ldb_val_dup(mem_ctx, &(src->value)); + if (dst.value.data == NULL) { + return dst; + } + + dst.name = talloc_strdup(mem_ctx, src->name); + if (dst.name == NULL) { + talloc_free(dst.value.data); + } + + return dst; +} + +/* Copy a DN but replace the old with the new base DN. */ +static struct ldb_dn *ldb_dn_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base) +{ + struct ldb_dn *new; + int i, offset; + + /* Perhaps we don't need to rebase at all? */ + if (!old_base || !new_base) { + return ldb_dn_copy(mem_ctx, old); + } + + offset = old->comp_num - old_base->comp_num; + new = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); + for (i = 0; i < offset; i++) { + new->components[i] = ldb_dn_copy_component(new->components, &(old->components[i])); + } + + return new; +} + +/* Copy a DN with the base DN of the local partition. */ +static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) +{ + return ldb_dn_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn); +} + +/* Copy a DN with the base DN of the remote partition. */ +static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) +{ + return ldb_dn_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn); +} + +/* Run a request and make sure it targets the remote partition. */ +/* TODO: free old DNs and messages? */ +int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_message *msg; + + switch (request->operation) { + case LDB_SEARCH: + if (request->op.search.base) { + request->op.search.base = ldb_dn_rebase_remote(request, data, request->op.search.base); + } else { + request->op.search.base = data->remote_base_dn; + /* TODO: adjust scope? */ + } + break; + + case LDB_ADD: + msg = ldb_msg_copy_shallow(request, request->op.add.message); + msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); + request->op.add.message = msg; + break; + + case LDB_MODIFY: + msg = ldb_msg_copy_shallow(request, request->op.mod.message); + msg->dn = ldb_dn_rebase_remote(msg, data, msg->dn); + request->op.mod.message = msg; + break; + + case LDB_DELETE: + request->op.del.dn = ldb_dn_rebase_remote(request, data, request->op.del.dn); + break; + + case LDB_RENAME: + request->op.rename.olddn = ldb_dn_rebase_remote(request, data, request->op.rename.olddn); + request->op.rename.newdn = ldb_dn_rebase_remote(request, data, request->op.rename.newdn); + break; + + default: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Invalid remote request!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_request(module, request); +} + + +/* Finding mappings for attributes and objectClasses + * ================================================= */ + +/* Find an objectClass mapping by the local name. */ +static const struct ldb_map_objectclass *map_objectclass_find_local(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->objectclass_maps && data->objectclass_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->objectclass_maps[i].local_name, name) == 0) { + return &data->objectclass_maps[i]; + } + } + + return NULL; +} + +/* Find an objectClass mapping by the remote name. */ +static const struct ldb_map_objectclass *map_objectclass_find_remote(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->objectclass_maps && data->objectclass_maps[i].remote_name; i++) { + if (ldb_attr_cmp(data->objectclass_maps[i].remote_name, name) == 0) { + return &data->objectclass_maps[i]; + } + } + + return NULL; +} + +/* Find an attribute mapping by the local name. */ +const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name) +{ + int i; + + for (i = 0; data->attribute_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->attribute_maps[i].local_name, name) == 0) { + return &data->attribute_maps[i]; + } + } + for (i = 0; data->attribute_maps[i].local_name; i++) { + if (ldb_attr_cmp(data->attribute_maps[i].local_name, "*") == 0) { + return &data->attribute_maps[i]; + } + } + + return NULL; +} + +/* Find an attribute mapping by the remote name. */ +const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name) +{ + const struct ldb_map_attribute *map; + const struct ldb_map_attribute *wildcard = NULL; + int i, j; + + for (i = 0; data->attribute_maps[i].local_name; i++) { + map = &data->attribute_maps[i]; + if (ldb_attr_cmp(map->local_name, "*") == 0) { + wildcard = &data->attribute_maps[i]; + } + + switch (map->type) { + case MAP_IGNORE: + break; + + case MAP_KEEP: + if (ldb_attr_cmp(map->local_name, name) == 0) { + return map; + } + break; + + case MAP_RENAME: + case MAP_CONVERT: + if (ldb_attr_cmp(map->u.rename.remote_name, name) == 0) { + return map; + } + break; + + case MAP_GENERATE: + for (j = 0; map->u.generate.remote_names && map->u.generate.remote_names[j]; j++) { + if (ldb_attr_cmp(map->u.generate.remote_names[j], name) == 0) { + return map; + } + } + break; + } + } + + /* We didn't find it, so return the wildcard record if one was configured */ + return wildcard; +} + + +/* Mapping attributes + * ================== */ + +/* Check whether an attribute will be mapped into the remote partition. */ +BOOL map_attr_check_remote(const struct ldb_map_context *data, const char *attr) +{ + const struct ldb_map_attribute *map = map_attr_find_local(data, attr); + + if (map == NULL) { + return False; + } + if (map->type == MAP_IGNORE) { + return False; + } + + return True; +} + +/* Map an attribute name into the remote partition. */ +const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr) +{ + if (map == NULL) { + return talloc_strdup(mem_ctx, attr); + } + + switch (map->type) { + case MAP_KEEP: + return talloc_strdup(mem_ctx, attr); + + case MAP_RENAME: + case MAP_CONVERT: + return talloc_strdup(mem_ctx, map->u.rename.remote_name); + + default: + return NULL; + } +} + +/* Map an attribute name back into the local partition. */ +const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr) +{ + if (map == NULL) { + return talloc_strdup(mem_ctx, attr); + } + + if (map->type == MAP_KEEP) { + return talloc_strdup(mem_ctx, attr); + } + + return talloc_strdup(mem_ctx, map->local_name); +} + + +/* Merge two lists of attributes into a single one. */ +int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs) +{ + int i, j, k; + + for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ; + for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ; + + *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1); + if (*attrs == NULL) { + map_oom(module); + return -1; + } + + for (k = 0; k < j; k++) { + (*attrs)[i+k] = more_attrs[k]; + } + + (*attrs)[i+k] = NULL; + + return 0; +} + +/* Mapping ldb values + * ================== */ + +/* Map an ldb value into the remote partition. */ +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +{ + if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) { + return map->u.convert.convert_local(module, mem_ctx, &val); + } + + return ldb_val_dup(mem_ctx, &val); +} + +/* Map an ldb value back into the local partition. */ +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +{ + if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) { + return map->u.convert.convert_remote(module, mem_ctx, &val); + } + + return ldb_val_dup(mem_ctx, &val); +} + + +/* Mapping DNs + * =========== */ + +/* Check whether a DN is below the local baseDN. */ +BOOL ldb_dn_check_local(struct ldb_module *module, const struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (!data->local_base_dn) { + return True; + } + + return ldb_dn_compare_base(module->ldb, data->local_base_dn, dn) == 0; +} + +/* Map a DN into the remote partition. */ +struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *newdn; + struct ldb_dn_component *old, *new; + const struct ldb_map_attribute *map; + enum ldb_map_attr_type map_type; + int i; + + if (dn == NULL) { + return NULL; + } + + newdn = ldb_dn_copy(mem_ctx, dn); + if (newdn == NULL) { + map_oom(module); + return NULL; + } + + /* For each RDN, map the component name and possibly the value */ + for (i = 0; i < newdn->comp_num; i++) { + old = &dn->components[i]; + new = &newdn->components[i]; + map = map_attr_find_local(data, old->name); + + /* Unknown attribute - leave this RDN as is and hope the best... */ + if (map == NULL) { + map_type = MAP_KEEP; + } else { + map_type = map->type; + } + + switch (map_type) { + case MAP_IGNORE: + case MAP_GENERATE: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "MAP_IGNORE/MAP_GENERATE attribute '%s' " + "used in DN!\n", old->name); + goto failed; + + case MAP_CONVERT: + if (map->u.convert.convert_local == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "'convert_local' not set for attribute '%s' " + "used in DN!\n", old->name); + goto failed; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + new->name = discard_const_p(char, map_attr_map_local(newdn->components, map, old->name)); + new->value = ldb_val_map_local(module, newdn->components, map, old->value); + break; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +/* Map a DN into the local partition. */ +struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *newdn; + struct ldb_dn_component *old, *new; + const struct ldb_map_attribute *map; + enum ldb_map_attr_type map_type; + int i; + + if (dn == NULL) { + return NULL; + } + + newdn = ldb_dn_copy(mem_ctx, dn); + if (newdn == NULL) { + map_oom(module); + return NULL; + } + + /* For each RDN, map the component name and possibly the value */ + for (i = 0; i < newdn->comp_num; i++) { + old = &dn->components[i]; + new = &newdn->components[i]; + map = map_attr_find_remote(data, old->name); + + /* Unknown attribute - leave this RDN as is and hope the best... */ + if (map == NULL) { + map_type = MAP_KEEP; + } else { + map_type = map->type; + } + + switch (map_type) { + case MAP_IGNORE: + case MAP_GENERATE: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "MAP_IGNORE/MAP_GENERATE attribute '%s' " + "used in DN!\n", old->name); + goto failed; + + case MAP_CONVERT: + if (map->u.convert.convert_remote == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "'convert_remote' not set for attribute '%s' " + "used in DN!\n", old->name); + goto failed; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + new->name = discard_const_p(char, map_attr_map_remote(newdn->components, map, old->name)); + new->value = ldb_val_map_remote(module, newdn->components, map, old->value); + break; + } + } + + return newdn; + +failed: + talloc_free(newdn); + return NULL; +} + +/* Map a DN and its base into the local partition. */ +/* TODO: This should not be required with GUIDs. */ +struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn) +{ + const struct ldb_map_context *data = map_get_context(module); + struct ldb_dn *dn1, *dn2; + + dn1 = ldb_dn_rebase_local(mem_ctx, data, dn); + dn2 = ldb_dn_map_remote(module, mem_ctx, dn1); + + talloc_free(dn1); + return dn2; +} + + +/* Converting DNs and objectClasses (as ldb values) + * ================================================ */ + +/* Map a DN contained in an ldb value into the remote partition. */ +static struct ldb_val ldb_dn_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn; + struct ldb_val newval; + + dn = ldb_dn_explode(mem_ctx, (char *)val->data); + newdn = ldb_dn_map_local(module, mem_ctx, dn); + talloc_free(dn); + + newval.length = 0; + newval.data = (uint8_t *)ldb_dn_linearize(mem_ctx, newdn); + if (newval.data) { + newval.length = strlen((char *)newval.data); + } + talloc_free(newdn); + + return newval; +} + +/* Map a DN contained in an ldb value into the local partition. */ +static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn; + struct ldb_val newval; + + dn = ldb_dn_explode(mem_ctx, (char *)val->data); + newdn = ldb_dn_map_remote(module, mem_ctx, dn); + talloc_free(dn); + + newval.length = 0; + newval.data = (uint8_t *)ldb_dn_linearize(mem_ctx, newdn); + if (newval.data) { + newval.length = strlen((char *)newval.data); + } + talloc_free(newdn); + + return newval; +} + +/* Map an objectClass into the remote partition. */ +static struct ldb_val map_objectclass_convert_local(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + const struct ldb_map_context *data = map_get_context(module); + const char *name = (char *)val->data; + const struct ldb_map_objectclass *map = map_objectclass_find_local(data, name); + struct ldb_val newval; + + if (map) { + newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->remote_name); + newval.length = strlen((char *)newval.data); + return newval; + } + + return ldb_val_dup(mem_ctx, val); +} + +/* Generate a remote message with a mapped objectClass. */ +static void map_objectclass_generate_remote(struct ldb_module *module, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local) +{ + struct ldb_message_element *el, *oc; + struct ldb_val val; + BOOL found_extensibleObject = False; + int i; + + /* Find old local objectClass */ + oc = ldb_msg_find_element(old, local_attr); + if (oc == NULL) { + return; + } + + /* Prepare new element */ + el = talloc_zero(remote, struct ldb_message_element); + if (el == NULL) { + ldb_oom(module->ldb); + return; /* TODO: fail? */ + } + + /* Copy local objectClass element, reverse space for an extra value */ + el->num_values = oc->num_values + 1; + el->values = talloc_array(el, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return; /* TODO: fail? */ + } + + /* Copy local element name "objectClass" */ + el->name = talloc_strdup(el, local_attr); + + /* Convert all local objectClasses */ + for (i = 0; i < el->num_values - 1; i++) { + el->values[i] = map_objectclass_convert_local(module, el->values, &oc->values[i]); + if (ldb_attr_cmp((char *)el->values[i].data, "extensibleObject") == 0) { + found_extensibleObject = True; + } + } + + if (!found_extensibleObject) { + val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject"); + val.length = strlen((char *)val.data); + + /* Append additional objectClass "extensibleObject" */ + el->values[i] = val; + } else { + el->num_values--; + } + + /* Add new objectClass to remote message */ + ldb_msg_add(remote, el, 0); +} + +/* Map an objectClass into the local partition. */ +static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) +{ + const struct ldb_map_context *data = map_get_context(module); + const char *name = (char *)val->data; + const struct ldb_map_objectclass *map = map_objectclass_find_remote(data, name); + struct ldb_val newval; + + if (map) { + newval.data = (uint8_t*)talloc_strdup(mem_ctx, map->local_name); + newval.length = strlen((char *)newval.data); + return newval; + } + + return ldb_val_dup(mem_ctx, val); +} + +/* Generate a local message with a mapped objectClass. */ +static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *remote_attr, const struct ldb_message *remote) +{ + struct ldb_message_element *el, *oc; + struct ldb_val val; + int i; + + /* Find old remote objectClass */ + oc = ldb_msg_find_element(remote, remote_attr); + if (oc == NULL) { + return NULL; + } + + /* Prepare new element */ + el = talloc_zero(mem_ctx, struct ldb_message_element); + if (el == NULL) { + ldb_oom(module->ldb); + return NULL; + } + + /* Copy remote objectClass element */ + el->num_values = oc->num_values; + el->values = talloc_array(el, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return NULL; + } + + /* Copy remote element name "objectClass" */ + el->name = talloc_strdup(el, remote_attr); + + /* Convert all remote objectClasses */ + for (i = 0; i < el->num_values; i++) { + el->values[i] = map_objectclass_convert_remote(module, el->values, &oc->values[i]); + } + + val.data = (uint8_t *)talloc_strdup(el->values, "extensibleObject"); + val.length = strlen((char *)val.data); + + /* Remove last value if it was "extensibleObject" */ + if (ldb_val_equal_exact(&val, &el->values[i-1])) { + el->num_values--; + el->values = talloc_realloc(el, el->values, struct ldb_val, el->num_values); + if (el->values == NULL) { + talloc_free(el); + ldb_oom(module->ldb); + return NULL; + } + } + + return el; +} + +/* Mappings for searches on objectClass= assuming a one-to-one + * mapping. Needed because this is a generate operator for the + * add/modify code */ +static int map_objectclass_convert_operator(struct ldb_module *module, void *mem_ctx, + struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + + static const struct ldb_map_attribute objectclass_map = { + .local_name = "objectClass", + .type = MAP_CONVERT, + .u = { + .convert = { + .remote_name = "objectClass", + .convert_local = map_objectclass_convert_local, + .convert_remote = map_objectclass_convert_remote, + }, + }, + }; + + return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, &objectclass_map); +} + +/* Auxiliary request construction + * ============================== */ + +/* Store the DN of a single search result in context. */ +static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_context *ac; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback")); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(context, struct map_context); + + /* We are interested only in the single reply */ + if (ares->type != LDB_REPLY_ENTRY) { + talloc_free(ares); + return LDB_SUCCESS; + } + + /* We have already found a remote DN */ + if (ac->local_dn) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local DN */ + ac->local_dn = ares->message->dn; + + return LDB_SUCCESS; +} + +/* Build a request to search a record by its DN. */ +struct ldb_request *map_search_base_req(struct map_context *ac, const struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback) +{ + struct ldb_request *req; + + req = talloc_zero(ac, struct ldb_request); + if (req == NULL) { + map_oom(ac->module); + return NULL; + } + + req->operation = LDB_SEARCH; + req->op.search.base = dn; + req->op.search.scope = LDB_SCOPE_BASE; + req->op.search.attrs = attrs; + + if (tree) { + req->op.search.tree = tree; + } else { + req->op.search.tree = ldb_parse_tree(req, NULL); + if (req->op.search.tree == NULL) { + talloc_free(req); + return NULL; + } + } + + req->controls = NULL; + req->context = context; + req->callback = callback; + ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req); + + return req; +} + +/* Build a request to search the local record by its DN. */ +struct ldb_request *map_search_self_req(struct map_context *ac, const struct ldb_dn *dn) +{ + /* attrs[] is returned from this function in + * ac->search_req->op.search.attrs, so it must be static, as + * otherwise the compiler can put it on the stack */ + static const char * const attrs[] = { IS_MAPPED, NULL }; + struct ldb_parse_tree *tree; + + /* Limit search to records with 'IS_MAPPED' present */ + /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */ + tree = talloc_zero(ac, struct ldb_parse_tree); + if (tree == NULL) { + map_oom(ac->module); + return NULL; + } + + tree->operation = LDB_OP_PRESENT; + tree->u.present.attr = talloc_strdup(tree, IS_MAPPED); + + return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback); +} + +/* Build a request to update the 'IS_MAPPED' attribute */ +struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_request *req; + struct ldb_message *msg; + const char *dn; + + /* Prepare request */ + req = talloc_zero(ac, struct ldb_request); + if (req == NULL) { + map_oom(ac->module); + return NULL; + } + + /* Prepare message */ + msg = ldb_msg_new(req); + if (msg == NULL) { + map_oom(ac->module); + goto failed; + } + + /* Update local 'IS_MAPPED' to the new remote DN */ + msg->dn = discard_const_p(struct ldb_dn, olddn); + dn = ldb_dn_linearize(msg, newdn); + if (dn == NULL) { + goto failed; + } + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE) != 0) { + goto failed; + } + if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { + goto failed; + } + + req->operation = LDB_MODIFY; + req->op.mod.message = msg; + req->controls = NULL; + req->handle = NULL; + req->context = NULL; + req->callback = NULL; + + return req; + +failed: + talloc_free(req); + return NULL; +} + + +/* Asynchronous call structure + * =========================== */ + +/* Figure out which request is currently pending. */ +static struct ldb_request *map_get_req(struct map_context *ac) +{ + switch (ac->step) { + case MAP_SEARCH_SELF_MODIFY: + case MAP_SEARCH_SELF_DELETE: + case MAP_SEARCH_SELF_RENAME: + return ac->search_req; + + case MAP_ADD_REMOTE: + case MAP_MODIFY_REMOTE: + case MAP_DELETE_REMOTE: + case MAP_RENAME_REMOTE: + return ac->remote_req; + + case MAP_RENAME_FIXUP: + return ac->down_req; + + case MAP_ADD_LOCAL: + case MAP_MODIFY_LOCAL: + case MAP_DELETE_LOCAL: + case MAP_RENAME_LOCAL: + return ac->local_req; + + case MAP_SEARCH_REMOTE: + /* Can't happen */ + break; + } + + return NULL; /* unreachable; silences a warning */ +} + +typedef int (*map_next_function)(struct ldb_handle *handle); + +/* Figure out the next request to run. */ +static map_next_function map_get_next(struct map_context *ac) +{ + switch (ac->step) { + case MAP_SEARCH_REMOTE: + return NULL; + + case MAP_ADD_LOCAL: + return map_add_do_remote; + case MAP_ADD_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_MODIFY: + return map_modify_do_local; + case MAP_MODIFY_LOCAL: + return map_modify_do_remote; + case MAP_MODIFY_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_DELETE: + return map_delete_do_local; + case MAP_DELETE_LOCAL: + return map_delete_do_remote; + case MAP_DELETE_REMOTE: + return NULL; + + case MAP_SEARCH_SELF_RENAME: + return map_rename_do_local; + case MAP_RENAME_LOCAL: + return map_rename_do_fixup; + case MAP_RENAME_FIXUP: + return map_rename_do_remote; + case MAP_RENAME_REMOTE: + return NULL; + } + + return NULL; /* unreachable; silences a warning */ +} + +/* Wait for the current pending request to finish and continue with the next. */ +static int map_wait_next(struct ldb_handle *handle) +{ + struct map_context *ac; + struct ldb_request *req; + map_next_function next; + int ret; + + if (handle == NULL || handle->private_data == NULL) { + 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 map_context); + + if (ac->step == MAP_SEARCH_REMOTE) { + int i; + for (i = 0; i < ac->num_searches; i++) { + req = ac->search_reqs[i]; + ret = ldb_wait(req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (req->handle->status != LDB_SUCCESS) { + handle->status = req->handle->status; + goto done; + } + if (req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + } + } else { + + req = map_get_req(ac); + + ret = ldb_wait(req->handle, LDB_WAIT_NONE); + + if (ret != LDB_SUCCESS) { + handle->status = ret; + goto done; + } + if (req->handle->status != LDB_SUCCESS) { + handle->status = req->handle->status; + goto done; + } + if (req->handle->state != LDB_ASYNC_DONE) { + return LDB_SUCCESS; + } + + next = map_get_next(ac); + if (next) { + return next(handle); + } + } + + ret = LDB_SUCCESS; + +done: + handle->state = LDB_ASYNC_DONE; + return ret; +} + +/* Wait for all current pending requests to finish. */ +static int map_wait_all(struct ldb_handle *handle) +{ + int ret; + + while (handle->state != LDB_ASYNC_DONE) { + ret = map_wait_next(handle); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return handle->status; +} + +/* Wait for pending requests to finish. */ +static int map_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + if (type == LDB_WAIT_ALL) { + return map_wait_all(handle); + } else { + return map_wait_next(handle); + } +} + + +/* Module initialization + * ===================== */ + +/* Provided module operations */ +static const struct ldb_module_ops map_ops = { + .name = "ldb_map", + .add = map_add, + .modify = map_modify, + .del = map_delete, + .rename = map_rename, + .search = map_search, + .wait = map_wait, +}; + +/* Builtin mappings for DNs and objectClasses */ +static const struct ldb_map_attribute builtin_attribute_maps[] = { + { + .local_name = "dn", + .type = MAP_CONVERT, + .u = { + .convert = { + .remote_name = "dn", + .convert_local = ldb_dn_convert_local, + .convert_remote = ldb_dn_convert_remote, + }, + }, + }, + { + .local_name = "objectClass", + .type = MAP_GENERATE, + .convert_operator = map_objectclass_convert_operator, + .u = { + .generate = { + .remote_names = { "objectClass", NULL }, + .generate_local = map_objectclass_generate_local, + .generate_remote = map_objectclass_generate_remote, + }, + }, + }, + { + .local_name = NULL, + } +}; + +/* Find the special 'MAP_DN_NAME' record and store local and remote + * base DNs in private data. */ +static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, const char *name) +{ + static const char * const attrs[] = { MAP_DN_FROM, MAP_DN_TO, NULL }; + struct ldb_dn *dn; + struct ldb_message *msg; + struct ldb_result *res; + int ret; + + if (!name) { + data->local_base_dn = NULL; + data->remote_base_dn = NULL; + return LDB_SUCCESS; + } + + dn = ldb_dn_string_compose(data, NULL, "%s=%s", MAP_DN_NAME, name); + if (dn == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Failed to construct '%s' DN!\n", MAP_DN_NAME); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE, NULL, attrs, &res); + talloc_free(dn); + if (ret != LDB_SUCCESS) { + return ret; + } + if (res->count == 0) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "No results for '%s=%s'!\n", MAP_DN_NAME, name); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + if (res->count > 1) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Too many results for '%s=%s'!\n", MAP_DN_NAME, name); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + msg = res->msgs[0]; + data->local_base_dn = ldb_msg_find_attr_as_dn(data, msg, MAP_DN_FROM); + data->remote_base_dn = ldb_msg_find_attr_as_dn(data, msg, MAP_DN_TO); + talloc_free(res); + + return LDB_SUCCESS; +} + +/* Store attribute maps and objectClass maps in private data. */ +static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data, + const struct ldb_map_attribute *attrs, + const struct ldb_map_objectclass *ocls, + const char * const *wildcard_attributes) +{ + int i, j, last; + last = 0; + + /* Count specified attribute maps */ + for (i = 0; attrs[i].local_name; i++) /* noop */ ; + /* Count built-in attribute maps */ + for (j = 0; builtin_attribute_maps[j].local_name; j++) /* noop */ ; + + /* Store list of attribute maps */ + data->attribute_maps = talloc_array(data, struct ldb_map_attribute, i+j+1); + if (data->attribute_maps == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Specified ones go first */ + for (i = 0; attrs[i].local_name; i++) { + data->attribute_maps[last] = attrs[i]; + last++; + } + + /* Built-in ones go last */ + for (i = 0; builtin_attribute_maps[i].local_name; i++) { + data->attribute_maps[last] = builtin_attribute_maps[i]; + last++; + } + + /* Ensure 'local_name == NULL' for the last entry */ + memset(&data->attribute_maps[last], 0, sizeof(struct ldb_map_attribute)); + + /* Store list of objectClass maps */ + data->objectclass_maps = ocls; + + data->wildcard_attributes = wildcard_attributes; + + return LDB_SUCCESS; +} + +/* Copy the list of provided module operations. */ +struct ldb_module_ops ldb_map_get_ops(void) +{ + return map_ops; +} + +/* Initialize global private data. */ +int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, + const struct ldb_map_objectclass *ocls, + const char * const *wildcard_attributes, + const char *name) +{ + struct map_private *data; + int ret; + + /* Prepare private data */ + data = talloc_zero(module, struct map_private); + if (data == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + module->private_data = data; + + data->context = talloc_zero(data, struct ldb_map_context); + if (!data->context) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local and remote baseDNs */ + ret = map_init_dns(module, data->context, name); + if (ret != LDB_SUCCESS) { + talloc_free(data); + return ret; + } + + /* Store list of attribute and objectClass maps */ + ret = map_init_maps(module, data->context, attrs, ocls, wildcard_attributes); + if (ret != LDB_SUCCESS) { + talloc_free(data); + return ret; + } + + return LDB_SUCCESS; +} + +/* Usage note for initialization of this module: + * + * ldb_map is meant to be used from a different module that sets up + * the mappings and gets registered in ldb. + * + * 'ldb_map_init' initializes the private data of this module and + * stores the attribute and objectClass maps in there. It also looks + * up the '@MAP' special DN so requests can be redirected to the + * remote partition. + * + * This function should be called from the 'init_context' op of the + * module using ldb_map. + * + * 'ldb_map_get_ops' returns a copy of ldb_maps module operations. + * + * It should be called from the initialize function of the using + * module, which should then override the 'init_context' op with a + * function making the appropriate calls to 'ldb_map_init'. + */ diff --git a/source3/lib/ldb/modules/ldb_map.h b/source3/lib/ldb/modules/ldb_map.h new file mode 100644 index 0000000000..c5c455bcb2 --- /dev/null +++ b/source3/lib/ldb/modules/ldb_map.h @@ -0,0 +1,158 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 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; */ + const struct ldb_dn *local_base_dn; + const 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__ */ diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c new file mode 100644 index 0000000000..404b2ce528 --- /dev/null +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -0,0 +1,724 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 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_linearize(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 */ + dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn); + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + 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; +} diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c new file mode 100644 index 0000000000..e1b207f6eb --- /dev/null +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -0,0 +1,1155 @@ +/* + ldb database mapping module + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Martin Kuehl 2006 + Copyright (C) Andrew Bartlett 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 attributes + * ================== */ + +/* Select attributes that stay in the local partition. */ +static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs) +{ + const struct ldb_map_context *data = map_get_context(module); + const char **result; + int i, last; + + if (attrs == NULL) + return NULL; + + last = 0; + result = talloc_array(mem_ctx, const char *, 1); + if (result == NULL) { + goto failed; + } + result[0] = NULL; + + for (i = 0; attrs[i]; i++) { + /* Wildcards and ignored attributes are kept locally */ + if ((ldb_attr_cmp(attrs[i], "*") == 0) || + (!map_attr_check_remote(data, attrs[i]))) { + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, attrs[i]); + result[last+1] = NULL; + last++; + } + } + + return result; + +failed: + talloc_free(result); + map_oom(module); + return NULL; +} + +/* Collect attributes that are mapped into the remote partition. */ +static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, const char * const *attrs) +{ + const struct ldb_map_context *data = map_get_context(module); + const char **result; + const struct ldb_map_attribute *map; + const char *name=NULL; + int i, j, last; + int ret; + + last = 0; + result = talloc_array(mem_ctx, const char *, 1); + if (result == NULL) { + goto failed; + } + result[0] = NULL; + + for (i = 0; attrs[i]; i++) { + /* Wildcards are kept remotely, too */ + if (ldb_attr_cmp(attrs[i], "*") == 0) { + const char **new_attrs = NULL; + ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs); + if (ret != LDB_SUCCESS) { + goto failed; + } + ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes); + if (ret != LDB_SUCCESS) { + goto failed; + } + + attrs = new_attrs; + break; + } + } + + for (i = 0; attrs[i]; i++) { + /* Wildcards are kept remotely, too */ + if (ldb_attr_cmp(attrs[i], "*") == 0) { + /* Add all 'include in wildcard' attributes */ + name = attrs[i]; + goto named; + } + + /* Add remote names of mapped attrs */ + map = map_attr_find_local(data, attrs[i]); + if (map == NULL) { + continue; + } + + switch (map->type) { + case MAP_IGNORE: + continue; + + case MAP_KEEP: + name = attrs[i]; + goto named; + + case MAP_RENAME: + case MAP_CONVERT: + name = map->u.rename.remote_name; + goto named; + + case MAP_GENERATE: + /* Add all remote names of "generate" attrs */ + for (j = 0; map->u.generate.remote_names[j]; j++) { + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, map->u.generate.remote_names[j]); + result[last+1] = NULL; + last++; + } + continue; + } + + named: /* We found a single remote name, add that */ + result = talloc_realloc(mem_ctx, result, const char *, last+2); + if (result == NULL) { + goto failed; + } + + result[last] = talloc_strdup(result, name); + result[last+1] = NULL; + last++; + } + + return result; + +failed: + talloc_free(result); + map_oom(module); + return NULL; +} + +/* Split attributes that stay in the local partition from those that + * are mapped into the remote partition. */ +static int map_attrs_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs) +{ + *local_attrs = map_attrs_select_local(module, local_ctx, attrs); + *remote_attrs = map_attrs_collect_remote(module, remote_ctx, attrs); + + return 0; +} + +/* Mapping message elements + * ======================== */ + +/* Add an element to a message, overwriting any old identically named elements. */ +static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el) +{ + struct ldb_message_element *old; + + old = ldb_msg_find_element(msg, el->name); + + /* no local result, add as new element */ + if (old == NULL) { + if (ldb_msg_add_empty(msg, el->name, 0) != 0) { + return -1; + } + + old = ldb_msg_find_element(msg, el->name); + if (old == NULL) { + return -1; + } + } + + *old = *el; /* copy new element */ + + return 0; +} + +/* Map a message element back into the local partition. */ +static struct ldb_message_element *ldb_msg_el_map_remote(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_remote(el, map, old->name); + + for (i = 0; i < el->num_values; i++) { + el->values[i] = ldb_val_map_remote(module, el->values, map, old->values[i]); + } + + return el; +} + +/* Merge a remote message element into a local message. */ +static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const char *attr_name, 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_remote(data, attr_name); + struct ldb_message_element *el=NULL; + + /* Unknown attribute in remote message: + * skip, attribute was probably auto-generated */ + if (map == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Skipping attribute '%s': no mapping found\n", + old->name); + return 0; + } + + switch (map->type) { + case MAP_IGNORE: + return -1; + + case MAP_CONVERT: + if (map->u.convert.convert_remote == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Skipping attribute '%s': " + "'convert_remote' not set\n", + old->name); + return 0; + } + /* fall through */ + case MAP_KEEP: + case MAP_RENAME: + el = ldb_msg_el_map_remote(module, local, map, old); + break; + + case MAP_GENERATE: + if (map->u.generate.generate_local == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " + "Skipping attribute '%s': " + "'generate_local' not set\n", + old->name); + return 0; + } + + el = map->u.generate.generate_local(module, local, old->name, remote); + break; + } + + if (el == NULL) { + return -1; + } + + return ldb_msg_replace(local, el); +} + +/* Mapping messages + * ================ */ + +/* Merge two local messages into a single one. */ +static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2) +{ + int i, ret; + + for (i = 0; i < msg2->num_elements; i++) { + ret = ldb_msg_replace(msg1, &msg2->elements[i]); + if (ret) { + return ret; + } + } + + return 0; +} + +/* Merge a local and a remote message into a single local one. */ +static int ldb_msg_merge_remote(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote) +{ + int i, ret; + + /* Try to map each attribute back; + * Add to local message is possible, + * Overwrite old local attribute if necessary */ + for (i = 0; i < remote->num_elements; i++) { + ret = ldb_msg_el_merge(module, local, remote, remote->elements[i].name, &remote->elements[i]); + if (ret) { + return ret; + } + } + + return 0; +} + +/* Mapping search results + * ====================== */ + +/* Map a search result back into the local partition. */ +static int map_reply_remote(struct ldb_module *module, struct ldb_reply *ares) +{ + struct ldb_message *msg; + struct ldb_dn *dn; + int ret; + + /* There is no result message, skip */ + if (ares->type != LDB_REPLY_ENTRY) { + return 0; + } + + /* Create a new result message */ + msg = ldb_msg_new(ares); + if (msg == NULL) { + map_oom(module); + return -1; + } + + /* Merge remote message into new message */ + ret = ldb_msg_merge_remote(module, msg, ares->message); + if (ret) { + talloc_free(msg); + return ret; + } + + /* Create corresponding local DN */ + dn = ldb_dn_map_rebase_remote(module, msg, ares->message->dn); + if (dn == NULL) { + talloc_free(msg); + return -1; + } + msg->dn = dn; + + /* Store new message with new DN as the result */ + talloc_free(ares->message); + ares->message = msg; + + return 0; +} + +/* Mapping parse trees + * =================== */ + +/* Check whether a parse tree can safely be split in two. */ +static BOOL ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree) +{ + const struct ldb_parse_tree *subtree = tree; + BOOL negate = False; + + while (subtree) { + switch (subtree->operation) { + case LDB_OP_NOT: + negate = !negate; + subtree = subtree->u.isnot.child; + continue; + + case LDB_OP_AND: + return !negate; /* if negate: False */ + + case LDB_OP_OR: + return negate; /* if negate: True */ + + default: + return True; /* simple parse tree */ + } + } + + return True; /* no parse tree */ +} + +/* Collect a list of attributes required to match a given parse tree. */ +static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree) +{ + const char **new_attrs; + int i, ret; + + if (tree == NULL) { + return 0; + } + + switch (tree->operation) { + case LDB_OP_OR: + case LDB_OP_AND: /* attributes stored in list of subtrees */ + for (i = 0; i < tree->u.list.num_elements; i++) { + ret = ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.list.elements[i]); + if (ret) { + return ret; + } + } + return 0; + + case LDB_OP_NOT: /* attributes stored in single subtree */ + return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child); + + default: /* single attribute in tree */ + new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr); + talloc_free(*attrs); + *attrs = new_attrs; + return 0; + } + + return -1; +} + +static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree); + +/* Select a negated subtree that queries attributes in the local partition */ +static int map_subtree_select_local_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + struct ldb_parse_tree *child; + int ret; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Generate new subtree */ + ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child); + if (ret) { + talloc_free(*new); + return ret; + } + + /* Prune tree without subtree */ + if (child == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + (*new)->u.isnot.child = child; + + return ret; +} + +/* Select a list of subtrees that query attributes in the local partition */ +static int map_subtree_select_local_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + int i, j, ret=0; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Prepare list of subtrees */ + (*new)->u.list.num_elements = 0; + (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements); + if ((*new)->u.list.elements == NULL) { + map_oom(module); + talloc_free(*new); + return -1; + } + + /* Generate new list of subtrees */ + j = 0; + for (i = 0; i < tree->u.list.num_elements; i++) { + struct ldb_parse_tree *child; + ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]); + if (ret) { + talloc_free(*new); + return ret; + } + + if (child) { + (*new)->u.list.elements[j] = child; + j++; + } + } + + /* Prune tree without subtrees */ + if (j == 0) { + talloc_free(*new); + *new = NULL; + return 0; + } + + /* Fix subtree list size */ + (*new)->u.list.num_elements = j; + (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements); + + return ret; +} + +/* Select a simple subtree that queries attributes in the local partition */ +static int map_subtree_select_local_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + return 0; +} + +/* Select subtrees that query attributes in the local partition */ +static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + const struct ldb_map_context *data = map_get_context(module); + + if (tree == NULL) { + return 0; + } + + if (tree->operation == LDB_OP_NOT) { + return map_subtree_select_local_not(module, mem_ctx, new, tree); + } + + if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) { + return map_subtree_select_local_list(module, mem_ctx, new, tree); + } + + if (map_attr_check_remote(data, tree->u.equality.attr)) { + *new = NULL; + return 0; + } + + return map_subtree_select_local_simple(module, mem_ctx, new, tree); +} + +static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree); + +/* Collect a negated subtree that queries attributes in the remote partition */ +static int map_subtree_collect_remote_not(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + struct ldb_parse_tree *child; + int ret; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Generate new subtree */ + ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child); + if (ret) { + talloc_free(*new); + return ret; + } + + /* Prune tree without subtree */ + if (child == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + (*new)->u.isnot.child = child; + + return ret; +} + +/* Collect a list of subtrees that query attributes in the remote partition */ +static int map_subtree_collect_remote_list(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + int i, j, ret=0; + + /* Prepare new tree */ + *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree)); + if (*new == NULL) { + map_oom(module); + return -1; + } + + /* Prepare list of subtrees */ + (*new)->u.list.num_elements = 0; + (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements); + if ((*new)->u.list.elements == NULL) { + map_oom(module); + talloc_free(*new); + return -1; + } + + /* Generate new list of subtrees */ + j = 0; + for (i = 0; i < tree->u.list.num_elements; i++) { + struct ldb_parse_tree *child; + ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]); + if (ret) { + talloc_free(*new); + return ret; + } + + if (child) { + (*new)->u.list.elements[j] = child; + j++; + } + } + + /* Prune tree without subtrees */ + if (j == 0) { + talloc_free(*new); + *new = NULL; + return 0; + } + + /* Fix subtree list size */ + (*new)->u.list.num_elements = j; + (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements); + + return ret; +} + +/* Collect a simple subtree that queries attributes in the remote partition */ +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) +{ + const char *attr; + + /* Prepare new tree */ + *new = talloc(mem_ctx, struct ldb_parse_tree); + if (*new == NULL) { + map_oom(module); + return -1; + } + **new = *tree; + + if (map->type == MAP_KEEP) { + /* Nothing to do here */ + return 0; + } + + /* Store attribute and value in new tree */ + switch (tree->operation) { + case LDB_OP_PRESENT: + attr = map_attr_map_local(*new, map, tree->u.present.attr); + (*new)->u.present.attr = attr; + break; + case LDB_OP_SUBSTRING: + { + attr = map_attr_map_local(*new, map, tree->u.substring.attr); + (*new)->u.substring.attr = attr; + break; + } + case LDB_OP_EQUALITY: + attr = map_attr_map_local(*new, map, tree->u.equality.attr); + (*new)->u.equality.attr = attr; + break; + case LDB_OP_LESS: + case LDB_OP_GREATER: + case LDB_OP_APPROX: + attr = map_attr_map_local(*new, map, tree->u.comparison.attr); + (*new)->u.comparison.attr = attr; + break; + case LDB_OP_EXTENDED: + attr = map_attr_map_local(*new, map, tree->u.extended.attr); + (*new)->u.extended.attr = attr; + break; + default: /* unknown kind of simple subtree */ + talloc_free(*new); + return -1; + } + + if (attr == NULL) { + talloc_free(*new); + *new = NULL; + return 0; + } + + if (map->type == MAP_RENAME) { + /* Nothing more to do here, the attribute has been renamed */ + return 0; + } + + /* Store attribute and value in new tree */ + switch (tree->operation) { + case LDB_OP_PRESENT: + break; + case LDB_OP_SUBSTRING: + { + int i; + /* Map value */ + (*new)->u.substring.chunks = NULL; + for (i=0; tree->u.substring.chunks[i]; i++) { + (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2); + if (!(*new)->u.substring.chunks) { + talloc_free(*new); + *new = NULL; + return 0; + } + (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val); + if (!(*new)->u.substring.chunks[i]) { + talloc_free(*new); + *new = NULL; + return 0; + } + *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, *tree->u.substring.chunks[i]); + (*new)->u.substring.chunks[i+1] = NULL; + } + break; + } + case LDB_OP_EQUALITY: + (*new)->u.equality.value = ldb_val_map_local(module, *new, map, tree->u.equality.value); + break; + case LDB_OP_LESS: + case LDB_OP_GREATER: + case LDB_OP_APPROX: + (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, tree->u.comparison.value); + break; + case LDB_OP_EXTENDED: + (*new)->u.extended.value = ldb_val_map_local(module, *new, map, tree->u.extended.value); + (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id); + break; + default: /* unknown kind of simple subtree */ + talloc_free(*new); + return -1; + } + + return 0; +} + +/* Collect subtrees that query attributes in the remote partition */ +static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map; + + if (tree == NULL) { + return 0; + } + + if (tree->operation == LDB_OP_NOT) { + return map_subtree_collect_remote_not(module, mem_ctx, new, tree); + } + + if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) { + return map_subtree_collect_remote_list(module, mem_ctx, new, tree); + } + + if (!map_attr_check_remote(data, tree->u.equality.attr)) { + *new = NULL; + return 0; + } + + map = map_attr_find_local(data, tree->u.equality.attr); + if (map->convert_operator) { + return map->convert_operator(module, mem_ctx, new, tree); + } + + if (map->type == MAP_GENERATE) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " + "Skipping attribute '%s': " + "'convert_operator' not set\n", + tree->u.equality.attr); + *new = NULL; + return 0; + } + + return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map); +} + +/* Split subtrees that query attributes in the local partition from + * those that query the remote partition. */ +static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, struct ldb_parse_tree **local_tree, struct ldb_parse_tree **remote_tree, const struct ldb_parse_tree *tree) +{ + int ret; + + *local_tree = NULL; + *remote_tree = NULL; + + /* No original tree */ + if (tree == NULL) { + return 0; + } + + /* Generate local tree */ + ret = map_subtree_select_local(module, local_ctx, local_tree, tree); + if (ret) { + return ret; + } + + /* Generate remote tree */ + ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree); + if (ret) { + talloc_free(*local_tree); + return ret; + } + + return 0; +} + +/* Collect a list of attributes required either explicitly from a + * given list or implicitly from a given parse tree; split the + * collected list into local and remote parts. */ +static int map_attrs_collect_and_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *search_attrs, const struct ldb_parse_tree *tree) +{ + void *tmp_ctx; + const char **tree_attrs; + int ret; + + /* Clear initial lists of partitioned attributes */ + *local_attrs = NULL; + *remote_attrs = NULL; + + /* There is no tree, just partition the searched attributes */ + if (tree == NULL) { + return map_attrs_partition(module, local_ctx, remote_ctx, local_attrs, remote_attrs, search_attrs); + } + + /* Create context for temporary memory */ + tmp_ctx = talloc_new(local_ctx); + if (tmp_ctx == NULL) { + goto oom; + } + + /* Prepare list of attributes from tree */ + tree_attrs = talloc_array(tmp_ctx, const char *, 1); + if (tree_attrs == NULL) { + talloc_free(tmp_ctx); + goto oom; + } + tree_attrs[0] = NULL; + + /* Collect attributes from tree */ + ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree); + if (ret) { + goto done; + } + + /* Merge attributes from search operation */ + ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs); + if (ret) { + goto done; + } + + /* Split local from remote attributes */ + ret = map_attrs_partition(module, local_ctx, remote_ctx, local_attrs, remote_attrs, tree_attrs); + +done: + /* Free temporary memory */ + talloc_free(tmp_ctx); + return ret; + +oom: + map_oom(module); + return -1; +} + + +/* Outbound requests: search + * ========================= */ + +/* Pass a merged search result up the callback chain. */ +int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares) +{ + int i; + + /* No callback registered, stop */ + if (req->callback == NULL) { + return LDB_SUCCESS; + } + + /* Only records need special treatment */ + if (ares->type != LDB_REPLY_ENTRY) { + return req->callback(ldb, req->context, ares); + } + + /* Merged result doesn't match original query, skip */ + if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) { + ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: " + "Skipping record '%s': " + "doesn't match original search\n", + ldb_dn_linearize(ldb, ares->message->dn)); + return LDB_SUCCESS; + } + + /* Limit result to requested attrs */ + if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) { + for (i = 0; i < ares->message->num_elements; i++) { + const struct ldb_message_element *el = &ares->message->elements[i]; + if (!ldb_attr_in_list(req->op.search.attrs, el->name)) { + ldb_msg_remove_attr(ares->message, el->name); + } + } + } + + return req->callback(ldb, req->context, ares); +} + +/* Merge the remote and local parts of a search result. */ +int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_search_context *sc; + int ret; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "NULL Context or Result in `map_local_merge_callback`")); + return LDB_ERR_OPERATIONS_ERROR; + } + + sc = talloc_get_type(context, struct map_search_context); + + switch (ares->type) { + case LDB_REPLY_ENTRY: + /* We have already found a local record */ + if (sc->local_res) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "Too many results to base search for local entry")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Store local result */ + sc->local_res = ares; + + /* Merge remote into local message */ + ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message); + if (ret) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + return map_up_callback(ldb, sc->ac->orig_req, ares); + + case LDB_REPLY_DONE: + /* No local record found, continue with remote record */ + if (sc->local_res == NULL) { + return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res); + } + return LDB_SUCCESS; + + default: + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "Unexpected result type in base search for local entry")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } +} + +/* Search the local part of a remote search result. */ +int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +{ + struct map_context *ac; + struct map_search_context *sc; + struct ldb_request *req; + int ret; + + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " + "NULL Context or Result in `map_remote_search_callback`")); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_get_type(context, struct map_context); + + /* It's not a record, stop searching */ + if (ares->type != LDB_REPLY_ENTRY) { + return map_up_callback(ldb, ac->orig_req, ares); + } + + /* Map result record into a local message */ + ret = map_reply_remote(ac->module, ares); + if (ret) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* There is no local db, stop searching */ + if (!map_check_local_db(ac->module)) { + return map_up_callback(ldb, ac->orig_req, ares); + } + + /* Prepare local search context */ + sc = map_init_search_context(ac, ares); + if (sc == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Prepare local search request */ + /* TODO: use GUIDs here instead? */ + + ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2); + if (ac->search_reqs == NULL) { + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->search_reqs[ac->num_searches] + = req = map_search_base_req(ac, ares->message->dn, + NULL, NULL, sc, map_local_merge_callback); + if (req == NULL) { + talloc_free(sc); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->num_searches++; + ac->search_reqs[ac->num_searches] = NULL; + + return ldb_next_request(ac->module, req); +} + +/* Search a record. */ +int map_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_handle *h; + struct map_context *ac; + struct ldb_parse_tree *local_tree, *remote_tree; + const char **local_attrs, **remote_attrs; + int ret; + + const char *wildcard[] = { "*", NULL }; + const char * const *attrs; + + /* Do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.search.base)) + return ldb_next_request(module, req); + + /* No mapping requested, skip to next module */ + if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) { + return ldb_next_request(module, req); + } + + /* TODO: How can we be sure about which partition we are + * targetting when there is no search base? */ + + /* 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); + + ac->search_reqs = talloc_array(ac, struct ldb_request *, 2); + if (ac->search_reqs == NULL) { + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->num_searches = 1; + ac->search_reqs[1] = NULL; + + /* Prepare the remote operation */ + ac->search_reqs[0] = talloc(ac, struct ldb_request); + if (ac->search_reqs[0] == NULL) { + goto oom; + } + + *(ac->search_reqs[0]) = *req; /* copy the request */ + + ac->search_reqs[0]->handle = h; /* return our own handle to deal with this call */ + + ac->search_reqs[0]->context = ac; + ac->search_reqs[0]->callback = map_remote_search_callback; + + /* It is easier to deal with the two different ways of + * expressing the wildcard in the same codepath */ + attrs = req->op.search.attrs; + if (attrs == NULL) { + attrs = wildcard; + } + + /* Split local from remote attrs */ + ret = map_attrs_collect_and_partition(module, ac, ac->search_reqs[0], &local_attrs, &remote_attrs, attrs, req->op.search.tree); + if (ret) { + goto failed; + } + + ac->local_attrs = local_attrs; + ac->search_reqs[0]->op.search.attrs = remote_attrs; + + /* Split local from remote tree */ + ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], &local_tree, &remote_tree, req->op.search.tree); + if (ret) { + goto failed; + } + + if (((local_tree != NULL) && (remote_tree != NULL)) && + (!ldb_parse_tree_check_splittable(req->op.search.tree))) { + /* The query can't safely be split, enumerate the remote partition */ + local_tree = NULL; + remote_tree = NULL; + } + + if (local_tree == NULL) { + /* Construct default local parse tree */ + local_tree = talloc_zero(ac, struct ldb_parse_tree); + if (local_tree == NULL) { + map_oom(ac->module); + goto failed; + } + + local_tree->operation = LDB_OP_PRESENT; + local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED); + } + if (remote_tree == NULL) { + /* Construct default remote parse tree */ + remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL); + if (remote_tree == NULL) { + goto failed; + } + } + + ac->local_tree = local_tree; + ac->search_reqs[0]->op.search.tree = remote_tree; + + ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]); + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = MAP_SEARCH_REMOTE; + + ret = ldb_next_remote_request(module, ac->search_reqs[0]); + if (ret == LDB_SUCCESS) { + req->handle = h; + } + return ret; + +oom: + map_oom(module); +failed: + talloc_free(h); + return LDB_ERR_OPERATIONS_ERROR; +} diff --git a/source3/lib/ldb/modules/ldb_map_private.h b/source3/lib/ldb/modules/ldb_map_private.h new file mode 100644 index 0000000000..7fb2745179 --- /dev/null +++ b/source3/lib/ldb/modules/ldb_map_private.h @@ -0,0 +1,115 @@ + +/* 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; + + const struct ldb_dn *local_dn; + const struct ldb_parse_tree *local_tree; + const char * const *local_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, const 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, struct ldb_val val); +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val); + +struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); + +struct ldb_request *map_search_base_req(struct map_context *ac, const 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, const struct ldb_dn *dn); +struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb_dn *olddn, const 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); diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c new file mode 100644 index 0000000000..493ecdaad4 --- /dev/null +++ b/source3/lib/ldb/modules/objectclass.c @@ -0,0 +1,694 @@ +/* + ldb database library + + Copyright (C) Simo Sorce 2006 + Copyright (C) Andrew Bartlett 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); + + 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); + + 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->module->ldb, 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); + 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); +} + diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c new file mode 100644 index 0000000000..c327a96f90 --- /dev/null +++ b/source3/lib/ldb/modules/operational.c @@ -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;ildb, 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;iop.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;iattrs[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); +} diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c new file mode 100644 index 0000000000..3ab575ef6b --- /dev/null +++ b/source3/lib/ldb/modules/paged_results.c @@ -0,0 +1,567 @@ +/* + 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_ERROR, "paged_request: Unable to register control with rootdse!\n"); + talloc_free(req); + return LDB_ERR_OTHER; + } + + 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); +} + diff --git a/source3/lib/ldb/modules/paged_searches.c b/source3/lib/ldb/modules/paged_searches.c new file mode 100644 index 0000000000..c7d163307d --- /dev/null +++ b/source3/lib/ldb/modules/paged_searches.c @@ -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); + 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); +} + diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c new file mode 100644 index 0000000000..fce1d34ac0 --- /dev/null +++ b/source3/lib/ldb/modules/rdn_name.c @@ -0,0 +1,337 @@ +/* + 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; + struct ldb_dn_component *rdn; + 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 = ldb_dn_get_rdn(msg, msg->dn); + if (rdn == NULL) { + talloc_free(down_req); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Perhaps someone above us tried to set this? */ + if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { + attribute->num_values = 0; + } + + if (ldb_msg_add_value(msg, "name", &rdn->value) != 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->value) != 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->value, &attribute->values[i]) == 0) { + /* overwrite so it matches in case */ + attribute->values[i] = rdn->value; + break; + } + } + if (i == attribute->num_values) { + ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, + "RDN mismatch on %s: %s", + ldb_dn_linearize(msg, msg->dn), rdn->name); + 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; + struct ldb_dn_component *rdn; + struct ldb_message *msg; + + ac = talloc_get_type(h->private_data, struct rename_context); + + rdn = ldb_dn_get_rdn(ac, ac->orig_req->op.rename.newdn); + if (rdn == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->mod_req = talloc_zero(ac, struct ldb_request); + + ac->mod_req->operation = LDB_MODIFY; + 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; + } + + if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_msg_add_value(msg, "name", &rdn->value) != 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); +} diff --git a/source3/lib/ldb/modules/schema.c b/source3/lib/ldb/modules/schema.c new file mode 100644 index 0000000000..556a35060d --- /dev/null +++ b/source3/lib/ldb/modules/schema.c @@ -0,0 +1,488 @@ +/* + ldb database library + + 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 schema module + * + * Description: add schema check functionality + * + * Author: Simo Sorce + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +#define SCHEMA_FLAG_RESET 0 +#define SCHEMA_FLAG_MOD_MASK 0x003 +#define SCHEMA_FLAG_MOD_ADD 0x001 +#define SCHEMA_FLAG_MOD_REPLACE 0x002 +#define SCHEMA_FLAG_MOD_DELETE 0x003 +#define SCHEMA_FLAG_AUXILIARY 0x010 +#define SCHEMA_FLAG_ABSTRACT 0x020 +#define SCHEMA_FLAG_STRUCTURAL 0x040 +#define SCHEMA_FLAG_CHECKED 0x100 + + +/* TODO: check attributes syntaxes + check there's only one structrual class (or a chain of structural classes) +*/ + +struct schema_attribute { + int flags; + char *name; +}; + +struct schema_attribute_list { + struct schema_attribute *attr; + int num; +}; + +struct schema_structures { + struct schema_attribute_list entry_attrs; + struct schema_attribute_list objectclasses; + struct schema_attribute_list required_attrs; + struct schema_attribute_list optional_attrs; +}; + +static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name) +{ + unsigned int i; + for (i = 0; i < list->num; i++) { + if (ldb_attr_cmp(list->attr[i].name, attr_name) == 0) { + return &(list->attr[i]); + } + } + return NULL; +} + +/* get all the attributes and objectclasses found in msg and put them in schema_structure + attributes go in the entry_attrs structure for later checking + objectclasses go in the objectclasses structure */ +static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg, int flag_mask) +{ + int i, j, anum, cnum; + + ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr, + struct schema_attribute, + ss->entry_attrs.num + msg->num_elements); + if (ss->entry_attrs.attr == NULL) { + return -1; + } + + for (i = 0, anum = ss->entry_attrs.num; i < msg->num_elements; i++) { + + if (ldb_attr_cmp(msg->elements[i].name, "objectclass") == 0) { + + ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr, + struct schema_attribute, + ss->objectclasses.num + msg->elements[i].num_values); + if (ss->objectclasses.attr == NULL) { + return -1; + } + + for (j = 0, cnum = ss->objectclasses.num; j < msg->elements[i].num_values; j++) { + ss->objectclasses.attr[cnum+j].name = (char *)msg->elements[i].values[j].data; + ss->objectclasses.attr[cnum+j].flags = msg->elements[i].flags & flag_mask; + } + ss->objectclasses.num += msg->elements[i].num_values; + } + + /* TODO: Check for proper attribute Syntax ! */ + + ss->entry_attrs.attr[anum+i].flags = msg->elements[i].flags & flag_mask; + ss->entry_attrs.attr[anum+i].name = talloc_reference(ss->entry_attrs.attr, + msg->elements[i].name); + if (ss->entry_attrs.attr[anum+i].name == NULL) { + return -1; + } + } + ss->entry_attrs.num += msg->num_elements; + + return 0; +} + +static int get_entry_attributes(struct ldb_context *ldb, const struct ldb_dn *dn, struct schema_structures *ss) +{ + struct ldb_result *srch; + int ret; + + ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &srch); + if (ret != 1) { + return ret; + } + talloc_steal(ss, srch); + + /* set flags to 0 as flags on search have undefined values */ + ret = get_msg_attributes(ss, *(srch->msgs), 0); + if (ret != 0) { + talloc_free(srch); + return ret; + } + + return 0; +} + +/* add all attributes in el avoiding duplicates in schema_attribute_list */ +static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el) +{ + int i, j, vals; + + vals = el->num_values; + list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals); + if (list->attr == NULL) { + return -1; + } + for (i = 0, j = 0; i < vals; i++) { + int c, found, len; + + found = 0; + for (c = 0; c < list->num; c++) { + len = strlen(list->attr[c].name); + if (len == el->values[i].length) { + if (ldb_attr_cmp(list->attr[c].name, + (char *)el->values[i].data) == 0) { + found = 1; + break; + } + } + } + if (!found) { + list->attr[j + list->num].name = (char *)el->values[i].data; + list->attr[j + list->num].flags = flags; + j++; + } + } + list->num += j; + + return 0; +} + + +/* we need to get all attributes referenced by the entry objectclasses, + recursively get parent objectlasses attributes */ +static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct) +{ + struct ldb_result *srch; + int i, j; + int ret; + + for (i = 0; i < schema_struct->objectclasses.num; i++) { + char *filter; + + if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) { + continue; + } + filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name); + if (filter == NULL) { + return -1; + } + + ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch); + if (ret != 1) { + return ret; + } + talloc_steal(schema_struct, srch); + + if (ret <= 0) { + /* Schema DB Error: Error occurred retrieving + Object Class Description */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "Error retrieving Objectclass %s.\n", + schema_struct->objectclasses.attr[i].name); + return -1; + } + if (ret > 1) { + /* Schema DB Error: Too Many Records */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "Too many records found retrieving Objectclass %s.\n", + schema_struct->objectclasses.attr[i].name); + return -1; + } + + /* Add inherited classes eliminating duplicates */ + /* fill in required_attrs and optional_attrs attribute lists */ + for (j = 0; j < srch->msgs[0]->num_elements; j++) { + int is_aux, is_class; + + is_aux = 0; + is_class = 0; + if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "systemAuxiliaryclass") == 0) { + is_aux = SCHEMA_FLAG_AUXILIARY; + is_class = 1; + } + if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "auxiliaryClass") == 0) { + is_aux = SCHEMA_FLAG_AUXILIARY; + is_class = 1; + } + if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "subClassOf") == 0) { + is_class = 1; + } + + if (is_class) { + if (add_attribute_uniq(schema_struct, + &schema_struct->objectclasses, + is_aux, + &srch->msgs[0]->elements[j]) != 0) { + return -1; + } + } else { + + if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mustContain") == 0 || + ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMustContain") == 0) { + if (add_attribute_uniq(schema_struct, + &schema_struct->required_attrs, + SCHEMA_FLAG_RESET, + &srch->msgs[0]->elements[j]) != 0) { + return -1; + } + } + + if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mayContain") == 0 || + ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMayContain") == 0) { + + if (add_attribute_uniq(schema_struct, + &schema_struct->optional_attrs, + SCHEMA_FLAG_RESET, + &srch->msgs[0]->elements[j]) != 0) { + return -1; + } + } + } + } + } + + return 0; +} + +/* add_record */ +static int schema_add(struct ldb_module *module, struct ldb_request *req) +{ + const struct ldb_message *msg = req->op.add.message; + struct schema_structures *entry_structs; + unsigned int i; + int ret; + + /* First implementation: + Build up a list of required_attrs and optional_attrs attributes from each objectclass + Check all the required_attrs attributes are present and all the other attributes + are optional_attrs attributes + Throw an error in case a check fail + Free all structures and commit the change + */ + + /* do not check on our control entries */ + if (ldb_dn_is_special(msg->dn)) { + return ldb_next_request(module, req); + } + + /* TODO: check parent exists */ + + entry_structs = talloc_zero(module, struct schema_structures); + if (!entry_structs) { + return -1; + } + + ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK); + if (ret != 0) { + talloc_free(entry_structs); + return ret; + } + + ret = get_attr_list_recursive(module, entry_structs); + if (ret != 0) { + talloc_free(entry_structs); + return ret; + } + + /* now check all required_attrs attributes are present */ + for (i = 0; i < entry_structs->required_attrs.num; i++) { + struct schema_attribute *attr; + + attr = schema_find_attribute(&entry_structs->entry_attrs, + entry_structs->required_attrs.attr[i].name); + + if (attr == NULL) { /* not found */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "The required_attrs attribute %s is missing.\n", + entry_structs->required_attrs.attr[i].name); + talloc_free(entry_structs); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + /* mark the attribute as checked */ + attr->flags = SCHEMA_FLAG_CHECKED; + } + + /* now check all others atribs are at least optional_attrs */ + for (i = 0; i < entry_structs->entry_attrs.num; i++) { + + if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) { + struct schema_attribute *attr; + + attr = schema_find_attribute(&entry_structs->optional_attrs, + entry_structs->entry_attrs.attr[i].name); + + if (attr == NULL) { /* not found */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "The attribute %s is not referenced by any objectclass.\n", + entry_structs->entry_attrs.attr[i].name); + talloc_free(entry_structs); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + } + } + + talloc_free(entry_structs); + + return ldb_next_request(module, req); +} + +/* modify_record */ +static int schema_modify(struct ldb_module *module, struct ldb_request *req) +{ + const struct ldb_message *msg = req->op.mod.message; + struct schema_structures *entry_structs; + unsigned int i; + int ret; + + /* First implementation: + Retrieve the ldap entry and get the objectclasses, + add msg contained objectclasses if any. + Build up a list of required_attrs and optional_attrs attributes from each objectclass + Check all the attributes are optional_attrs or required_attrs. + Throw an error in case a check fail. + Free all structures and commit the change. + */ + + /* do not check on our control entries */ + if (ldb_dn_is_special(msg->dn)) { + return ldb_next_request(module, req); + } + + /* allocate object structs */ + entry_structs = talloc_zero(module, struct schema_structures); + if (!entry_structs) { + return -1; + } + + /* now search for the stored entry objectclasses and attributes*/ + ret = get_entry_attributes(module->ldb, msg->dn, entry_structs); + if (ret != 0) { + talloc_free(entry_structs); + return ret; + } + + /* get list of values to modify */ + ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK); + if (ret != 0) { + talloc_free(entry_structs); + return ret; + } + + ret = get_attr_list_recursive(module, entry_structs); + if (ret != 0) { + talloc_free(entry_structs); + return ret; + } + + /* now check all required_attrs attributes are present */ + for (i = 0; i < entry_structs->required_attrs.num; i++) { + struct schema_attribute *attr; + + attr = schema_find_attribute(&entry_structs->entry_attrs, + entry_structs->required_attrs.attr[i].name); + + if (attr == NULL) { /* not found */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "The required_attrs attribute %s is missing.\n", + entry_structs->required_attrs.attr[i].name); + talloc_free(entry_structs); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + /* check we are not trying to delete a required attribute */ + /* TODO: consider multivalued attrs */ + if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) { + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "Trying to delete the required attribute %s.\n", + attr->name); + talloc_free(entry_structs); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + /* mark the attribute as checked */ + attr->flags = SCHEMA_FLAG_CHECKED; + } + + /* now check all others atribs are at least optional_attrs */ + for (i = 0; i < entry_structs->entry_attrs.num; i++) { + + if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) { + struct schema_attribute *attr; + + attr = schema_find_attribute(&entry_structs->optional_attrs, + entry_structs->entry_attrs.attr[i].name); + + if (attr == NULL) { /* not found */ + ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, + "The attribute %s is not referenced by any objectclass.\n", + entry_structs->entry_attrs.attr[i].name); + talloc_free(entry_structs); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + } + } + + talloc_free(entry_structs); + + return ldb_next_request(module, req); +} + +static int schema_request(struct ldb_module *module, struct ldb_request *req) +{ + switch (req->operation) { + + case LDB_ADD: + return schema_add(module, req); + + case LDB_MODIFY: + return schema_modify(module, req); + + default: + return ldb_next_request(module, req); + + } +} + +static const struct ldb_module_ops schema_ops = { + .name = "schema", + .request = schema_request +}; + +int ldb_schema_init(void) +{ + return ldb_register_module(&schema_ops); +} diff --git a/source3/lib/ldb/modules/skel.c b/source3/lib/ldb/modules/skel.c new file mode 100644 index 0000000000..2adef580b1 --- /dev/null +++ b/source3/lib/ldb/modules/skel.c @@ -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); +} diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c new file mode 100644 index 0000000000..3a0598c528 --- /dev/null +++ b/source3/lib/ldb/modules/sort.c @@ -0,0 +1,445 @@ +/* + 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_ERROR, "server_sort: Unable to register control with rootdse!\n"); + talloc_free(req); + return LDB_ERR_OTHER; + } + + 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); +} diff --git a/source3/lib/ldb/samba/README b/source3/lib/ldb/samba/README new file mode 100644 index 0000000000..3fa47159ca --- /dev/null +++ b/source3/lib/ldb/samba/README @@ -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. diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c new file mode 100644 index 0000000000..b490c8f005 --- /dev/null +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -0,0 +1,480 @@ +/* + 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 "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) +{ + /* see if the input if null-terninated */ + if (v->data[v->length] != '\0') 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; + + /* see if the input if null-terninated */ + if (v->data[v->length] != '\0') return False; + + if (v->length < 33) 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, 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; + + dn1 = ldb_dn_explode(mem_ctx, (char *)in->data); + if (dn1 == NULL) { + oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length); + } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { + oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, + dn1->components[0].value.length); + } else { + return -1; + } + + oc1 = ldb_casefold(ldb, mem_ctx, oc1); + out->data = (void *)oc1; + out->length = strlen(oc1); + 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_explode(mem_ctx, (char *)v1->data); + if (dn1 == NULL) { + oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length); + } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { + oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, + dn1->components[0].value.length); + } else { + oc1 = NULL; + } + + dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data); + if (dn2 == NULL) { + oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length); + } else if (dn2->comp_num >= 2 && strcasecmp(dn2->components[0].name, "cn") == 0) { + oc2 = talloc_strndup(mem_ctx, (char *)dn2->components[0].value.data, + dn2->components[0].value.length); + } else { + 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, + } +}; + +/* + 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)); +} diff --git a/source3/lib/ldb/sqlite3.m4 b/source3/lib/ldb/sqlite3.m4 new file mode 100644 index 0000000000..49e3807730 --- /dev/null +++ b/source3/lib/ldb/sqlite3.m4 @@ -0,0 +1,61 @@ +######################################################## +# 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_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}]) diff --git a/source3/lib/ldb/swig/Ldb.py b/source3/lib/ldb/swig/Ldb.py new file mode 100644 index 0000000000..c7e6191c8a --- /dev/null +++ b/source3/lib/ldb/swig/Ldb.py @@ -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) diff --git a/source3/lib/ldb/swig/ldb.i b/source3/lib/ldb/swig/ldb.i new file mode 100644 index 0000000000..09d3461c2a --- /dev/null +++ b/source3/lib/ldb/swig/ldb.i @@ -0,0 +1,240 @@ +/* + Unix SMB/CIFS implementation. + + Swig interface to ldb. + + Copyright (C) 2005,2006 Tim Potter + Copyright (C) 2006 Simo Sorce + + ** 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); diff --git a/source3/lib/ldb/tests/init.ldif b/source3/lib/ldb/tests/init.ldif new file mode 100644 index 0000000000..2e0b83c769 --- /dev/null +++ b/source3/lib/ldb/tests/init.ldif @@ -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 diff --git a/source3/lib/ldb/tests/init_slapd.sh b/source3/lib/ldb/tests/init_slapd.sh new file mode 100755 index 0000000000..cf06acd08b --- /dev/null +++ b/source3/lib/ldb/tests/init_slapd.sh @@ -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 <

ldb

+ +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 OpenLDAP +project.

+ +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.

+ +ldb is the database engine used in Samba4. + +

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 or remote LDAP backends +
  • integration with talloc +
  • 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 +
+ +

Documentation

+ +Currently ldb is completely lacking in programmer or user +documentation. This is your opportunity to make a contribution! Start +with the public functions declared in ldb.h +and the example code in the tools +directory. Documentation in the same docbook format used by Samba +would be preferred. + +

Discussion and bug reports

+ +ldb does not currently have its own mailing list or bug tracking +system. For now, please use the samba-technical +mailing list, and the Samba +bugzilla bug tracking system. + +

Download

+ +You can download the latest release either via rsync or anonymous +svn. To fetch via svn use the following commands: + +
+  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
+  svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/replace libreplace
+
+ +To fetch via rsync use these commands: + +
+  rsync -Pavz samba.org::ftp/unpacked/ldb .
+  rsync -Pavz samba.org::ftp/unpacked/tdb .
+  rsync -Pavz samba.org::ftp/unpacked/talloc .
+  rsync -Pavz samba.org::ftp/unpacked/libreplace .
+
+ +and build in ldb. It will find the other libraries in the directory +above automatically. + +
+ +Andrew Tridgell
+ldb AT tridgell.net +
+ + + -- cgit From ba68916c9a243f032c78e6c229b236901d6f8a1e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 25 Sep 2006 04:55:07 +0000 Subject: r18889: Add some const. What's the policy here? Should I do this in Samba4 as well? Volker (This used to be commit fd020a1998db7660ab093c136207df4fb09720cb) --- source3/lib/ldb/common/ldb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 760a311383..eca550f0f2 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -613,7 +613,7 @@ int ldb_build_search_req(struct ldb_request **ret_req, int ldb_build_add_req(struct ldb_request **ret_req, struct ldb_context *ldb, void *mem_ctx, - struct ldb_message *message, + const struct ldb_message *message, struct ldb_control **controls, void *context, ldb_request_callback_t callback) @@ -642,7 +642,7 @@ int ldb_build_add_req(struct ldb_request **ret_req, int ldb_build_mod_req(struct ldb_request **ret_req, struct ldb_context *ldb, void *mem_ctx, - struct ldb_message *message, + const struct ldb_message *message, struct ldb_control **controls, void *context, ldb_request_callback_t callback) @@ -671,7 +671,7 @@ int ldb_build_mod_req(struct ldb_request **ret_req, int ldb_build_del_req(struct ldb_request **ret_req, struct ldb_context *ldb, void *mem_ctx, - struct ldb_dn *dn, + const struct ldb_dn *dn, struct ldb_control **controls, void *context, ldb_request_callback_t callback) @@ -700,8 +700,8 @@ int ldb_build_del_req(struct ldb_request **ret_req, int ldb_build_rename_req(struct ldb_request **ret_req, struct ldb_context *ldb, void *mem_ctx, - struct ldb_dn *olddn, - struct ldb_dn *newdn, + const struct ldb_dn *olddn, + const struct ldb_dn *newdn, struct ldb_control **controls, void *context, ldb_request_callback_t callback) -- cgit From b70ee55a7cec1a9774f6ab56e92d0d9dd36ca217 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 25 Sep 2006 16:29:26 +0000 Subject: r18900: Next attempt to fix the Solaris build. Not sure about whether to merge this one. Tridge? Metze? Volker (This used to be commit d0eef2f6e870031538959f2308a3414fc68ef18c) --- source3/lib/ldb/common/ldb_modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 06a8a4bcf6..c6cf1e88eb 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -137,7 +137,7 @@ static const struct ldb_module_ops *ldb_find_module_ops(const char *name) #ifndef STATIC_ldb_MODULES -#ifdef HAVE_LDAP +#if defined(HAVE_LDAP) && defined(HAVE_LDAP_INITIALIZE) #define LDAP_INIT ldb_ldap_init, #else #define LDAP_INIT -- cgit From ed724f90479af3ee0d9583cef17f3d2365c327dd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 25 Sep 2006 16:47:50 +0000 Subject: r18901: try to fix the samba3 build without having ldap vl: you were a few seconds faster than me...:-) metze (This used to be commit 63e5727471bdf686f292a36aa43267213fb6e2f3) --- source3/lib/ldb/common/ldb_modules.c | 4 ++-- source3/lib/ldb/configure.ac | 4 ++-- source3/lib/ldb/ldap.m4 | 1 + source3/lib/ldb/sqlite3.m4 | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index c6cf1e88eb..adbbe58e10 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -137,13 +137,13 @@ static const struct ldb_module_ops *ldb_find_module_ops(const char *name) #ifndef STATIC_ldb_MODULES -#if defined(HAVE_LDAP) && defined(HAVE_LDAP_INITIALIZE) +#ifdef HAVE_LDB_LDAP #define LDAP_INIT ldb_ldap_init, #else #define LDAP_INIT #endif -#ifdef HAVE_SQLITE3 +#ifdef HAVE_LDB_SQLITE3 #define SQLITE3_INIT ldb_sqlite3_init, #else #define SQLITE3_INIT diff --git a/source3/lib/ldb/configure.ac b/source3/lib/ldb/configure.ac index 70a4100451..e1e9d49cee 100644 --- a/source3/lib/ldb/configure.ac +++ b/source3/lib/ldb/configure.ac @@ -54,7 +54,7 @@ m4_include(libtdb.m4) m4_include(ldap.m4) if test x"$with_ldap_support" = x"yes"; then LIBS="$LIBS -llber -lldap" - CFLAGS="$CFLAGS -DHAVE_LDAP=1" + CFLAGS="$CFLAGS -DHAVE_LDB_LDAP=1" EXTRA_OBJ="$EXTRA_OBJ ldb_ldap/ldb_ldap.o" TESTS="$TESTS test-ldap.sh" fi @@ -62,7 +62,7 @@ fi m4_include(sqlite3.m4) if test x"$with_sqlite3_support" = x"yes"; then LIBS="$LIBS -lsqlite3" - CFLAGS="$CFLAGS -DHAVE_SQLITE3=1" + CFLAGS="$CFLAGS -DHAVE_LDB_SQLITE3=1" EXTRA_OBJ="$EXTRA_OBJ ldb_sqlite3/ldb_sqlite3.o" TESTS="$TESTS test-sqlite3.sh" fi diff --git a/source3/lib/ldb/ldap.m4 b/source3/lib/ldb/ldap.m4 index 911c1364c8..417083ed61 100644 --- a/source3/lib/ldb/ldap.m4 +++ b/source3/lib/ldb/ldap.m4 @@ -69,6 +69,7 @@ if test x"$with_ldap_support" != x"no"; then 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) diff --git a/source3/lib/ldb/sqlite3.m4 b/source3/lib/ldb/sqlite3.m4 index 49e3807730..d0a74ee53c 100644 --- a/source3/lib/ldb/sqlite3.m4 +++ b/source3/lib/ldb/sqlite3.m4 @@ -40,6 +40,7 @@ if test x"$with_sqlite3_support" != x"no"; then 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 -- cgit From 45c0a4874bcfc25f6ab28531d771ba0198191bbe Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 26 Sep 2006 01:21:34 +0000 Subject: r18910: Change ldb_msg_add_string() to not actually add an attribute if the string is zero length. This allows callers to not have to worry about creating an invalid ldap attribute. See extensive discussion on samba-technical list :-) (This used to be commit 9e66df05a4df3d3c7b02048d80e2661103d1d40a) --- source3/lib/ldb/common/ldb_msg.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 52c6b82484..a4ba045669 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -227,6 +227,11 @@ int ldb_msg_add_string(struct ldb_message *msg, val.data = discard_const_p(uint8_t, str); val.length = strlen(str); + if (val.length == 0) { + /* allow empty strings as non-existant attributes */ + return 0; + } + return ldb_msg_add_value(msg, attr_name, &val); } -- cgit From 0cc2cee8d5ccd95cd4cd10a060e2b3e703b6fba1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 27 Sep 2006 03:34:50 +0000 Subject: r18939: don't rely on the umask being right in ldb creation. Both Samba3 and Samba4 smbd force the umask to 0, which meant we ended up with ldb being world writable. This isn't really an ideal fix, as it means ldb no longer honors umask (as it should do, like all good libraries). Unfortunately the 'proper' fix is too complex for now this also merges a tiny code style fix from s4 to s3 (This used to be commit dd8ec8725f168f4286bbfc00d69cd56089ba3543) --- source3/lib/ldb/common/ldb.c | 4 +++- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index eca550f0f2..00bf5e79ba 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -819,7 +819,9 @@ int ldb_modify(struct ldb_context *ldb, int ret; ret = ldb_msg_sanity_check(ldb, message); - if (ret != LDB_SUCCESS) return ret; + if (ret != LDB_SUCCESS) { + return ret; + } ret = ldb_build_mod_req(&req, ldb, ldb, message, diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 8f676654a6..5d43783903 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -1036,7 +1036,7 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, /* note that we use quite a large default hash size */ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, - tdb_flags, open_flags, 0666, ldb); + tdb_flags, open_flags, 0644, ldb); if (!ltdb->tdb) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path); talloc_free(ltdb); -- cgit From 101428b7e5e29d856c7500f8aeae5411c75c037a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 4 Oct 2006 18:22:51 +0000 Subject: r19067: Fix a potential NULL dereference (This used to be commit 6a8937ed03f0ee62eb81da798e0c38b405d44731) --- source3/lib/ldb/common/ldb_dn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index a0f48723ab..204dd3b462 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -345,6 +345,10 @@ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn) /* Allocate a structure to hold the exploded DN */ edn = ldb_dn_new(mem_ctx); + if (edn == NULL) { + return NULL; + } + pdn = NULL; /* Empty DNs */ -- cgit From a65c6b3914cc1e79501d0613e353ac0398a00cb4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 4 Oct 2006 19:12:01 +0000 Subject: r19071: Backport to SAMBA_3_0 as well (This used to be commit df148a5def06956ecd8392d259f1c408c62100fa) --- source3/lib/ldb/ldb_tdb/ldb_cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index d6d66dd37f..a6092c45f9 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -318,7 +318,7 @@ 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; - double seq; + uint64_t seq; if (ltdb->cache == NULL) { ltdb->cache = talloc_zero(ltdb, struct ltdb_cache); @@ -356,7 +356,7 @@ int ltdb_cache_load(struct ldb_module *module) /* 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_double(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0); + seq = ldb_msg_find_attr_as_uint64(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0); if (seq == ltdb->sequence_number) { goto done; } -- cgit From 14502053e92d20d9004ffa03767b201c05619a87 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 4 Oct 2006 19:32:55 +0000 Subject: r19072: Fix a potential NULL dereference. Simo/Tridge, not merging yet to 4_0, I'd like you to comment. Volker (This used to be commit ba18c58f1fb618447ba39bae6ef8f4e6c00c4d32) --- source3/lib/ldb/common/ldb_utf8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c index d2d12b8f51..86ed40535a 100644 --- a/source3/lib/ldb/common/ldb_utf8.c +++ b/source3/lib/ldb/common/ldb_utf8.c @@ -126,7 +126,7 @@ char *ldb_attr_casefold(void *mem_ctx, const char *s) { int i; char *ret = talloc_strdup(mem_ctx, s); - if (!s) { + if (!ret) { errno = ENOMEM; return NULL; } -- cgit From 38c4955c2ac3438526b3c590bce9a9ba259e83d4 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 4 Oct 2006 20:15:23 +0000 Subject: r19075: Fix a potential NULL dereference (This used to be commit 0ab5d7692c2c0fe798a067866cb236ea9c304463) --- source3/lib/ldb/common/ldb_dn.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 204dd3b462..a52569119f 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -674,6 +674,7 @@ static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_d dst.name = talloc_strdup(mem_ctx, src->name); if (dst.name == NULL) { talloc_free(dst.value.data); + dst.value.data = NULL; } return dst; @@ -826,6 +827,9 @@ struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const str for (i = 0; i < dn1->comp_num; i++) { newdn->components[i] = ldb_dn_copy_component(newdn->components, &(dn1->components[i])); + if (newdn->components[i].value.data == NULL) { + goto failed; + } } return newdn; -- cgit From faaec2f04ad355f7da4346a81003d3caa432923f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 4 Oct 2006 20:22:08 +0000 Subject: r19076: ldb_dn_copy_partial can fail (This used to be commit c247cf3fba13ce1a32878efcc922eadfcbc2b092) --- source3/lib/ldb/common/ldb_dn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index a52569119f..f1d0f185ad 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -818,6 +818,7 @@ struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const str int comp_num = dn2->comp_num; if (dn1 != NULL) comp_num += dn1->comp_num; newdn = ldb_dn_copy_partial(mem_ctx, dn2, comp_num); + LDB_DN_NULL_FAILED(newdn); } if (dn1 == NULL) { -- cgit From 407873df53db6fb7302ffda53de214e64cd75a09 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 4 Oct 2006 20:59:06 +0000 Subject: r19079: talloc_array can fail (This used to be commit 7b6738522a80740824f3b96e73e7c48a0623b1b1) --- source3/lib/ldb/common/ldb_dn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index f1d0f185ad..f9b044d5b8 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -698,6 +698,7 @@ struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int n newdn->comp_num = num_el; n = newdn->comp_num - 1; newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + if (newdn->components == NULL) goto failed; if (dn->comp_num == 0) return newdn; e = dn->comp_num - 1; -- cgit From a0a47d8149207fcfb9aa937d8d6a7c1ff2c8f417 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 6 Oct 2006 11:05:03 +0000 Subject: r19124: merge from samba4: pass LDFLAGS from configure to Makefile metze (This used to be commit 7ba9fddacb97153405bf0bec16b3a868e4e323e0) --- source3/lib/ldb/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in index 106e493530..ce23f309d3 100644 --- a/source3/lib/ldb/Makefile.in +++ b/source3/lib/ldb/Makefile.in @@ -22,7 +22,7 @@ CFLAGS=-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=-Llib -lldb @LIBS@ @POPT_LIBS@ +LIB_FLAGS=@LDFLAGS@ -Llib -lldb @LIBS@ @POPT_LIBS@ LDB_TDB_DIR=ldb_tdb LDB_TDB_OBJ=$(LDB_TDB_DIR)/ldb_tdb.o \ -- cgit From fd1cf23567566b65cdeecdbc04f58f29e29edd79 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Oct 2006 14:39:47 +0000 Subject: r19132: Fix some C++ warnings. Is there interest to have them in Samba4 as well? I have some problems resolving the last 3 ones in attrib_handlers.c. In line 251 the function ldb_dn_explode_casefold is called with mem_ctx as the first argument. Looking at ldb_dn_explode_casefold I see that the first argument it expects is a struct ldb_context. I could certainly add a cast to (struct ldb_context *) to that call, but I would assume that this is the wrong fix. Is it possible that attrib_handlers.c:251 and :254 should have ldb and not mem_ctx as the first argument? Can anybody from Samba4 clarify this for me and apply the correct fix? Thanks a lot. Volker (This used to be commit 26f2cb71ebf00b2c6f356da5f32384f7fa083521) --- source3/lib/ldb/common/ldb.c | 4 ++-- source3/lib/ldb/common/ldb_dn.c | 5 +++-- source3/lib/ldb/common/ldb_ldif.c | 11 +++++++---- source3/lib/ldb/common/ldb_modules.c | 3 ++- source3/lib/ldb/common/ldb_msg.c | 2 +- source3/lib/ldb/common/ldb_parse.c | 8 ++++---- 6 files changed, 19 insertions(+), 14 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 00bf5e79ba..b54febf208 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -160,7 +160,7 @@ static const struct ldb_dn *ldb_set_default_basedn(struct ldb_context *ldb) struct ldb_result *res; struct ldb_dn *basedn=NULL; - basedn = ldb_get_opaque(ldb, "default_baseDN"); + basedn = (struct ldb_dn *)ldb_get_opaque(ldb, "default_baseDN"); if (basedn) { return basedn; } @@ -182,7 +182,7 @@ static const struct ldb_dn *ldb_set_default_basedn(struct ldb_context *ldb) const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb) { - return ldb_get_opaque(ldb, "default_baseDN"); + return (const struct ldb_dn *)ldb_get_opaque(ldb, "default_baseDN"); } /* diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index f9b044d5b8..5ff27d1a37 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -112,7 +112,7 @@ static struct ldb_val ldb_dn_unescape_value(void *mem_ctx, const char *src) LDB_DN_NULL_FAILED(src); - dst = p = talloc_memdup(mem_ctx, src, strlen(src) + 1); + dst = p = (char *)talloc_memdup(mem_ctx, src, strlen(src) + 1); LDB_DN_NULL_FAILED(dst); end = &dst[strlen(dst)]; @@ -300,7 +300,8 @@ static struct ldb_dn_component ldb_dn_explode_component(void *mem_ctx, char *raw p[qe] = '\0'; p = p + qs + 1; dc.value.length = strlen(p); - dc.value.data = talloc_memdup(mem_ctx, p, dc.value.length + 1); + dc.value.data = (uint8_t *)talloc_memdup(mem_ctx, p, + dc.value.length + 1); break; default: /* mismatched quotes ot other error, bail out */ diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c index c5084aaa6c..0c31f25cc7 100644 --- a/source3/lib/ldb/common/ldb_ldif.c +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -72,7 +72,7 @@ static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value) goto done; } - value->data = talloc_size(mem_ctx, statbuf.st_size + 1); + value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1); if (value->data == NULL) { ret = -1; goto done; @@ -680,7 +680,8 @@ struct ldif_read_file_state { static int fgetc_file(void *private_data) { - struct ldif_read_file_state *state = private_data; + struct ldif_read_file_state *state = + (struct ldif_read_file_state *)private_data; return fgetc(state->f); } @@ -701,7 +702,8 @@ struct ldif_read_string_state { static int fgetc_string(void *private_data) { - struct ldif_read_string_state *state = private_data; + struct ldif_read_string_state *state = + (struct ldif_read_string_state *)private_data; if (state->s[0] != 0) { return *state->s++; } @@ -730,7 +732,8 @@ static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBU static int fprintf_file(void *private_data, const char *fmt, ...) { - struct ldif_write_file_state *state = private_data; + struct ldif_write_file_state *state = + (struct ldif_write_file_state *)private_data; int ret; va_list ap; diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index adbbe58e10..5ad56213b6 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -81,7 +81,8 @@ const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *m int i; /* spaces not admitted */ - modstr = talloc_strdup_no_spaces(mem_ctx, string); + modstr = talloc_strdup_no_spaces((struct ldb_context *)mem_ctx, + string); if ( ! modstr) { return NULL; } diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index a4ba045669..f6fbb04afb 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -797,7 +797,7 @@ int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *na if (el == NULL) return 0; - val.data = discard_const(value); + val.data = (uint8_t *)discard_const(value); val.length = strlen(value); if (ldb_msg_find_val(el, &val)) diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index d9044a8b0c..ec6ba420b4 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -67,7 +67,7 @@ struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str) struct ldb_val ret; int slen = str?strlen(str):0; - ret.data = talloc_size(mem_ctx, slen+1); + ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1); ret.length = 0; if (ret.data == NULL) return ret; @@ -134,7 +134,7 @@ char *ldb_binary_encode(void *mem_ctx, struct ldb_val val) char *ldb_binary_encode_string(void *mem_ctx, const char *string) { struct ldb_val val; - val.data = discard_const(string); + val.data = (uint8_t *)discard_const(string); val.length = strlen(string); return ldb_binary_encode(mem_ctx, val); } @@ -285,7 +285,7 @@ static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char * } /* save name */ - name = talloc_memdup(mem_ctx, t, t1 - t + 1); + name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1); if (name == NULL) return 0; name[t1 - t] = '\0'; @@ -326,7 +326,7 @@ static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char * while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++; - val = talloc_memdup(mem_ctx, t, p - t + 1); + val = (char *)talloc_memdup(mem_ctx, t, p - t + 1); if (val == NULL) { talloc_free(name); return 0; -- cgit From 695c6fbe007445e8e63c7d820b14322ece3edbf5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 6 Oct 2006 14:50:07 +0000 Subject: r19133: More C++ warnings -- Merge across? (This used to be commit c879ed3d1edffeda629dc1e05031dca91c1a1e30) --- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 5d43783903..2dbcb7a811 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -219,7 +219,8 @@ static int ltdb_modified(struct ldb_module *module, const struct ldb_dn *dn) */ int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key, tdb_data; int ret; @@ -332,7 +333,8 @@ done: */ int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key; int ret; @@ -589,7 +591,8 @@ static int msg_delete_element(struct ldb_module *module, int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg) { struct ldb_context *ldb = module->ldb; - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); TDB_DATA tdb_key, tdb_data; struct ldb_message *msg2; unsigned i, j; @@ -873,7 +876,8 @@ done: static int ltdb_start_trans(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); if (tdb_transaction_start(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); @@ -884,7 +888,8 @@ static int ltdb_start_trans(struct ldb_module *module) static int ltdb_end_trans(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); if (tdb_transaction_commit(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); @@ -895,7 +900,8 @@ static int ltdb_end_trans(struct ldb_module *module) static int ltdb_del_trans(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + talloc_get_type(module->private_data, struct ltdb_private); if (tdb_transaction_cancel(ltdb->tdb) != 0) { return ltdb_err_map(tdb_error(ltdb->tdb)); -- cgit From 3652a2360fcbd254f6b15c54176505c0c59a97e7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 6 Oct 2006 15:06:54 +0000 Subject: r19135: fix bugs... - passing mem_ctx as ldb_context is a bad idea! - naming a static function talloc_ is also bad and misleading metze (This used to be commit 0523ad249335c6094854bc9cefb46e2095f4c0ba) --- source3/lib/ldb/common/ldb_modules.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 5ad56213b6..2a6bc5abae 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -44,14 +44,13 @@ #define LDB_MODULE_PREFIX "modules:" #define LDB_MODULE_PREFIX_LEN 8 -static char *talloc_strdup_no_spaces(struct ldb_context *ldb, const char *string) +static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string) { int i, len; char *trimmed; - trimmed = talloc_strdup(ldb, string); + trimmed = talloc_strdup(mem_ctx, string); if (!trimmed) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in talloc_strdup_trim_spaces()\n"); return NULL; } @@ -81,9 +80,9 @@ const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *m int i; /* spaces not admitted */ - modstr = talloc_strdup_no_spaces((struct ldb_context *)mem_ctx, - string); + 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; } -- cgit From a6e45f0da5b7a187f652fb80d172007d36a5e855 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 6 Oct 2006 15:17:02 +0000 Subject: r19137: that looks nicer:-) metze (This used to be commit db40552d9471f4a8ce2c5c724319a4eb242ed24a) --- source3/lib/ldb/common/ldb_msg.c | 2 +- source3/lib/ldb/common/ldb_parse.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index f6fbb04afb..809d965745 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -797,7 +797,7 @@ int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *na if (el == NULL) return 0; - val.data = (uint8_t *)discard_const(value); + val.data = discard_const_p(uint8_t, value); val.length = strlen(value); if (ldb_msg_find_val(el, &val)) diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index ec6ba420b4..26f88769e6 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -134,7 +134,7 @@ char *ldb_binary_encode(void *mem_ctx, struct ldb_val val) char *ldb_binary_encode_string(void *mem_ctx, const char *string) { struct ldb_val val; - val.data = (uint8_t *)discard_const(string); + val.data = discard_const_p(uint8_t, string); val.length = strlen(string); return ldb_binary_encode(mem_ctx, val); } -- cgit From b61d1e665e4f4bf0b8e2d3bdc8fa1135279a903d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 6 Oct 2006 16:14:41 +0000 Subject: r19145: talloc_reference() can fail! metze (This used to be commit e4f2183684da90a67bc6a635d008b72a6dd3d0dd) --- source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c index b28bf77450..c9eac013fc 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -134,7 +134,9 @@ struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, if (stat(path, &st) == 0) { for (w=tdb_list;w;w=w->next) { if (st.st_dev == w->device && st.st_ino == w->inode) { - talloc_reference(mem_ctx, w); + if (!talloc_reference(mem_ctx, w)) { + return NULL; + } return w->tdb; } } -- cgit From 628fc4b53a33b604e1c28d38ff5fd91459434814 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 7 Oct 2006 10:24:16 +0000 Subject: r19163: pass always a mem_ctx to functions and a ldb_context where needed It would be nice if someone can merge that to samba4, otherwise I'll merge that to samba4 on monday metze (This used to be commit 6bc42f31ce294f2bd50ffbd536e1ee42607ef799) --- source3/lib/ldb/common/attrib_handlers.c | 6 +++--- source3/lib/ldb/common/ldb_dn.c | 27 +++++++++++++++------------ source3/lib/ldb/common/ldb_match.c | 2 +- source3/lib/ldb/include/ldb.h | 6 +++--- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index 8e437964f4..c4c83c52a6 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -220,7 +220,7 @@ static int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx, out->length = 0; out->data = NULL; - dn = ldb_dn_explode_casefold(ldb, (char *)in->data); + dn = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)in->data); if (dn == NULL) { return -1; } @@ -248,10 +248,10 @@ static int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx, struct ldb_dn *dn1 = NULL, *dn2 = NULL; int ret; - dn1 = ldb_dn_explode_casefold(mem_ctx, (char *)v1->data); + dn1 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v1->data); if (dn1 == NULL) return -1; - dn2 = ldb_dn_explode_casefold(mem_ctx, (char *)v2->data); + dn2 = ldb_dn_explode_casefold(ldb, mem_ctx, (char *)v2->data); if (dn2 == NULL) { talloc_free(dn1); return -1; diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 5ff27d1a37..a63ff9c8e3 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -554,10 +554,10 @@ int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1) if (dn0 == NULL || dn1 == NULL) return dn1 - dn0; - edn0 = ldb_dn_explode_casefold(ldb, dn0); + edn0 = ldb_dn_explode_casefold(ldb, ldb, dn0); if (edn0 == NULL) return 1; - edn1 = ldb_dn_explode_casefold(ldb, dn1); + edn1 = ldb_dn_explode_casefold(ldb, ldb, dn1); if (edn1 == NULL) { talloc_free(edn0); return -1; @@ -575,14 +575,14 @@ int ldb_dn_cmp(struct ldb_context *ldb, const char *dn0, const char *dn1) casefold a dn. We need to casefold the attribute names, and canonicalize attribute values of case insensitive attributes. */ -struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn) { struct ldb_dn *cedn; - int i; + int i, ret; if (edn == NULL) return NULL; - cedn = ldb_dn_new(ldb); + cedn = ldb_dn_new(mem_ctx); if (!cedn) { return NULL; } @@ -598,14 +598,17 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn struct ldb_dn_component dc; const struct ldb_attrib_handler *h; - dc.name = ldb_attr_casefold(cedn, edn->components[i].name); + dc.name = ldb_attr_casefold(cedn->components, edn->components[i].name); if (!dc.name) { talloc_free(cedn); return NULL; } h = ldb_attrib_handler(ldb, dc.name); - if (h->canonicalise_fn(ldb, cedn, &(edn->components[i].value), &(dc.value)) != 0) { + ret = h->canonicalise_fn(ldb, cedn->components, + &(edn->components[i].value), + &(dc.value)); + if (ret != 0) { talloc_free(cedn); return NULL; } @@ -616,7 +619,7 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn return cedn; } -struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn) +struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn) { struct ldb_dn *edn, *cdn; @@ -625,13 +628,13 @@ struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn) edn = ldb_dn_explode(ldb, dn); if (edn == NULL) return NULL; - cdn = ldb_dn_casefold(ldb, edn); + cdn = ldb_dn_casefold(ldb, mem_ctx, edn); talloc_free(edn); return cdn; } -char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn) +char *ldb_dn_linearize_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn) { struct ldb_dn *cdn; char *dn; @@ -640,11 +643,11 @@ char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *ed /* Special DNs */ if (ldb_dn_is_special(edn)) { - dn = talloc_strdup(ldb, (char *)edn->components[0].value.data); + dn = talloc_strdup(mem_ctx, (char *)edn->components[0].value.data); return dn; } - cdn = ldb_dn_casefold(ldb, edn); + cdn = ldb_dn_casefold(ldb, mem_ctx, edn); if (cdn == NULL) return NULL; dn = ldb_dn_linearize(ldb, cdn); diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c index 64e52d285d..1fd12da7f3 100644 --- a/source3/lib/ldb/common/ldb_match.c +++ b/source3/lib/ldb/common/ldb_match.c @@ -149,7 +149,7 @@ static int ldb_match_equality(struct ldb_context *ldb, int ret; if (ldb_attr_dn(tree->u.equality.attr) == 0) { - valuedn = ldb_dn_explode_casefold(ldb, + valuedn = ldb_dn_explode_casefold(ldb, ldb, (char *)tree->u.equality.value.data); if (valuedn == NULL) { return 0; diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index cf4a1f282b..0761280d90 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -1145,11 +1145,11 @@ struct ldb_dn *ldb_dn_new(void *mem_ctx); struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn); struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn); char *ldb_dn_linearize(void *mem_ctx, const struct ldb_dn *edn); -char *ldb_dn_linearize_casefold(struct ldb_context *ldb, const struct ldb_dn *edn); +char *ldb_dn_linearize_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn); int ldb_dn_compare_base(struct ldb_context *ldb, const struct ldb_dn *base, const struct ldb_dn *dn); int ldb_dn_compare(struct ldb_context *ldb, const struct ldb_dn *edn0, const struct ldb_dn *edn1); -struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, const struct ldb_dn *edn); -struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, const char *dn); +struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const struct ldb_dn *edn); +struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn); struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el); struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn); struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn); diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 2dbcb7a811..9b502b5911 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -138,7 +138,7 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn) the rest */ - dn_folded = ldb_dn_linearize_casefold(ldb, dn); + dn_folded = ldb_dn_linearize_casefold(ldb, ldb, dn); if (!dn_folded) { goto failed; } -- cgit From 617c39ab5ffbefcd7d0536c72ffbb0c36ce04215 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 07:05:08 +0000 Subject: r19182: merge from samba4: add ldb_set_create_perms() function to set the create_perms after ldb_init() and before ldb_connect() metze (This used to be commit dd9d469eef337954b6aee4c86ac0691f52812456) --- source3/lib/ldb/common/ldb.c | 11 +++++++++++ source3/lib/ldb/include/ldb.h | 1 + source3/lib/ldb/include/ldb_private.h | 2 ++ source3/lib/ldb/ldb_tdb/ldb_tdb.c | 3 ++- 4 files changed, 16 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index b54febf208..28d1c7235a 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -52,6 +52,7 @@ struct ldb_context *ldb_init(void *mem_ctx) } ldb_set_utf8_default(ldb); + ldb_set_create_perms(ldb, 0666); return ldb; } @@ -455,6 +456,16 @@ int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *o return LDB_SUCCESS; } + +/* + set the permissions for new files to be passed to open() in + backends that use local files + */ +void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms) +{ + ldb->create_perms = perms; +} + /* start an ldb request NOTE: the request must be a talloc context. diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 0761280d90..d2f3bd53d3 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -781,6 +781,7 @@ int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type); int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout); int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq); +void ldb_set_create_perms(struct ldb_context *ldb, unsigned int perms); /** Initialise ldbs' global information diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index 96b71ff3b4..3cacd5e292 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -119,6 +119,8 @@ struct ldb_context { int default_timeout; unsigned int flags; + + unsigned int create_perms; }; #ifndef ARRAY_SIZE diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 9b502b5911..608120e3a7 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -1042,7 +1042,8 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, /* note that we use quite a large default hash size */ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, - tdb_flags, open_flags, 0644, ldb); + tdb_flags, open_flags, + ldb->create_perms, ldb); if (!ltdb->tdb) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'\n", path); talloc_free(ltdb); -- cgit From d63a3e05a23ffb016578c3daa8b48d6fc32e1e8c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 07:15:27 +0000 Subject: r19183: merge from samba4: don't crash on invalid utf8 chars metze (This used to be commit 71e1f8550f96eaaae7e4fc4d02eb36f1d894abc8) --- source3/lib/ldb/common/attrib_handlers.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index c4c83c52a6..07a0ec6eb8 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -184,10 +184,19 @@ static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, return (int)(toupper(*s1)) - (int)(toupper(*s2)); utf8str: - /* non need to recheck from the start, just from the first utf8 char found */ + /* no need to recheck from the start, just from the first utf8 char found */ b1 = u1 = ldb_casefold(ldb, mem_ctx, s1); b2 = u2 = ldb_casefold(ldb, mem_ctx, s2); - + + if (u1 && u2) { + /* Both strings converted correctly */ + } 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; @@ -202,9 +211,10 @@ utf8str: while (*u2 == ' ') u2++; } ret = (int)(*u1 - *u2); + talloc_free(b1); talloc_free(b2); - + return ret; } -- cgit From ca79df9061d82c31969bf18af6ed0a43352659e3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 07:24:00 +0000 Subject: r19185: merge comment from samba4 metze (This used to be commit 256b83820168d14df2b15a75d8681be5f418ddf8) --- source3/lib/ldb/modules/asq.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 229a6eacd9..354bbf2bc8 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -370,6 +370,10 @@ static int asq_wait_none(struct ldb_handle *handle) 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) { -- cgit From 25e233db5768f3dd90a87c5986dedbd75c2e439d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 08:22:59 +0000 Subject: r19190: merge from samba4: remove wrong check and statement. to manipulate rootDSE we use ldb_dn_new() as base and that has 0 elements. metze (This used to be commit b81cae4180452d2a14c445392fd828032e6eddec) --- source3/lib/ldb/common/ldb_msg.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 809d965745..7e001f9180 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -229,7 +229,7 @@ int ldb_msg_add_string(struct ldb_message *msg, if (val.length == 0) { /* allow empty strings as non-existant attributes */ - return 0; + return LDB_SUCCESS; } return ldb_msg_add_value(msg, attr_name, &val); @@ -596,11 +596,6 @@ int ldb_msg_sanity_check(struct ldb_context *ldb, ldb_set_errstring(ldb, "ldb message lacks a DN!"); return LDB_ERR_INVALID_DN_SYNTAX; } - if (msg->dn->comp_num == 0) { - /* root dse has empty dn */ - ldb_set_errstring(ldb, "DN on new ldb message is '' (not permitted)!"); - return LDB_ERR_ENTRY_ALREADY_EXISTS; - } /* basic syntax checks */ for (i = 0; i < msg->num_elements; i++) { -- cgit From 85281ec52619180ebde44c6a48616292e341be3b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 08:25:27 +0000 Subject: r19191: merge from samba4: fix checker warnings metze (This used to be commit 93a0fe093b4614a18e99d0c3a71c5c8af2e57e4f) --- source3/lib/ldb/common/ldb_dn.c | 1 + source3/lib/ldb/common/ldb_modules.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index a63ff9c8e3..d035b0d3c2 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -598,6 +598,7 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const str struct ldb_dn_component dc; const struct ldb_attrib_handler *h; + memset(&dc, 0, sizeof(dc)); dc.name = ldb_attr_casefold(cedn->components, edn->components[i].name); if (!dc.name) { talloc_free(cedn); diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 2a6bc5abae..d627f3b9fa 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -324,7 +324,7 @@ int ldb_load_modules(struct ldb_context *ldb, const char *options[]) } ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res); - if (res) talloc_steal(mods_dn, 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 { -- cgit From c9b797b3baadf2ab1d385fc7c83d1770309e5eb7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 08:26:58 +0000 Subject: r19192: merge from samba4: ensure that data values from ldap libs are null terminated, to allow ldb_msg_find_attr_as_string() to work correctly. Thanks to Jim Myers for spotting this! metze (This used to be commit a5ea82bb05fb9d5c1842f9a105f6a10e39141c89) --- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index 9de67e5ad7..10563816b9 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -210,10 +210,15 @@ static int lldb_add_msg_attr(struct ldb_context *ldb, } for (i=0;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); + /* 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++; } -- cgit From 442f5526a043be624e35c8ab2de60de2630cd619 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 9 Oct 2006 08:32:51 +0000 Subject: r19193: merge from samba4: fixed another checker warning and a possible error on allocation failure metze (This used to be commit d64583a763ffcff27f0bd6761196f7d554d44849) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 59c1645ba8..8a9a82a98c 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -232,13 +232,15 @@ static int ltdb_index_dn_simple(struct ldb_module *module, list->dn = talloc_array(list, char *, el->num_values); if (!list->dn) { - break; + talloc_free(msg); + return -1; } for (j=0;jnum_values;j++) { list->dn[list->count] = talloc_strdup(list->dn, (char *)el->values[j].data); if (!list->dn[list->count]) { + talloc_free(msg); return -1; } list->count++; -- cgit From 7a390a0dabcdadb30196662b6cdec512bf81dcb4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 21 Oct 2006 00:10:19 +0000 Subject: r19430: merge recent ldb changes from Samba4. This includes memory leak fixes and significant speedups (This used to be commit bb5c205fef90aa8b89ba400fb9f2f37a111676a8) --- source3/lib/ldb/common/ldb.c | 18 +++++++++------- source3/lib/ldb/common/ldb_attributes.c | 14 +++++++++++++ source3/lib/ldb/common/ldb_dn.c | 9 ++++++-- source3/lib/ldb/common/ldb_ldif.c | 12 ++++++++++- source3/lib/ldb/common/ldb_modules.c | 1 + source3/lib/ldb/include/ldb.h | 3 +++ source3/lib/ldb/ldb_ildap/ldb_ildap.c | 1 + source3/lib/ldb/ldb_ldap/ldb_ldap.c | 13 +++++++++--- source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + source3/lib/ldb/ldb_tdb/ldb_cache.c | 33 +++++++++++++++++------------- source3/lib/ldb/ldb_tdb/ldb_index.c | 12 +++++------ source3/lib/ldb/ldb_tdb/ldb_search.c | 24 +++------------------- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 27 +++++++++++++++--------- source3/lib/ldb/ldb_tdb/ldb_tdb.h | 8 +++++--- source3/lib/ldb/modules/ldb_map.c | 2 ++ source3/lib/ldb/modules/ldb_map_outbound.c | 11 +++++++++- source3/lib/ldb/modules/objectclass.c | 2 +- source3/lib/ldb/samba/ldif_handlers.c | 10 +++++---- source3/lib/ldb/tests/test-generic.sh | 17 +++++++++++---- source3/lib/ldb/tests/test-tdb.sh | 7 +++++++ source3/lib/ldb/tests/test.ldif | 5 ----- source3/lib/ldb/tools/ad2oLschema.c | 4 ++-- source3/lib/ldb/tools/ldbadd.c | 16 +++++++-------- source3/lib/ldb/tools/ldbdel.c | 4 ++-- source3/lib/ldb/tools/ldbmodify.c | 22 ++++++++------------ source3/lib/ldb/tools/ldbsearch.c | 2 +- 26 files changed, 170 insertions(+), 108 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 28d1c7235a..7648abf795 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -208,7 +208,8 @@ int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, co } if (ldb_load_modules(ldb, options) != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for '%s'\n", url); + ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for %s: %s\n", + url, ldb_errstring(ldb)); return LDB_ERR_OTHER; } @@ -536,8 +537,9 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld if (!res || !ares) { goto error; } - - if (ares->type == LDB_REPLY_ENTRY) { + + switch (ares->type) { + case LDB_REPLY_ENTRY: res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); if (! res->msgs) { goto error; @@ -547,9 +549,8 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld res->msgs[res->count] = talloc_move(res->msgs, &ares->message); res->count++; - } - - if (ares->type == LDB_REPLY_REFERRAL) { + break; + case LDB_REPLY_REFERRAL: if (res->refs) { for (n = 0; res->refs[n]; n++) /*noop*/ ; } else { @@ -563,8 +564,11 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld res->refs[n] = talloc_move(res->refs, &ares->referral); res->refs[n + 1] = NULL; + case LDB_REPLY_DONE: + /* Should do something here to detect if this never + * happens */ + break; } - talloc_steal(res, ares->controls); talloc_free(ares); return LDB_SUCCESS; diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c index c8a7909b4c..2d9f0e6cf8 100644 --- a/source3/lib/ldb/common/ldb_attributes.c +++ b/source3/lib/ldb/common/ldb_attributes.c @@ -39,6 +39,7 @@ int ldb_set_attrib_handlers(struct ldb_context *ldb, const struct ldb_attrib_handler *handlers, unsigned num_handlers) { + int i; struct ldb_attrib_handler *h; h = talloc_realloc(ldb, ldb->schema.attrib_handlers, struct ldb_attrib_handler, @@ -50,6 +51,16 @@ int ldb_set_attrib_handlers(struct ldb_context *ldb, ldb->schema.attrib_handlers = h; memcpy(h + ldb->schema.num_attrib_handlers, handlers, sizeof(*h) * num_handlers); + for (i=0;ischema.num_attrib_handlers+i].flags & LDB_ATTR_FLAG_ALLOCATED) { + h[ldb->schema.num_attrib_handlers+i].attr = talloc_strdup(ldb->schema.attrib_handlers, + h[ldb->schema.num_attrib_handlers+i].attr); + if (h[ldb->schema.num_attrib_handlers+i].attr == NULL) { + ldb_oom(ldb); + return -1; + } + } + } ldb->schema.num_attrib_handlers += num_handlers; return 0; } @@ -129,6 +140,9 @@ void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib) if (h == &ldb_default_attrib_handler) { return; } + if (h->flags & LDB_ATTR_FLAG_ALLOCATED) { + talloc_free(h->attr); + } i = h - ldb->schema.attrib_handlers; if (i < ldb->schema.num_attrib_handlers - 1) { memmove(&ldb->schema.attrib_handlers[i], diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index d035b0d3c2..e937a2b7fc 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -337,6 +337,9 @@ failed: return NULL; } +/* + explode a DN string into a ldb_dn structure +*/ struct ldb_dn *ldb_dn_explode(void *mem_ctx, const char *dn) { struct ldb_dn *edn; /* the exploded dn */ @@ -848,7 +851,7 @@ failed: struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) { - struct ldb_dn *dn; + struct ldb_dn *dn, *dn1; char *child_str; va_list ap; @@ -860,9 +863,11 @@ struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, c if (child_str == NULL) return NULL; - dn = ldb_dn_compose(mem_ctx, ldb_dn_explode(mem_ctx, child_str), base); + dn1 = ldb_dn_explode(mem_ctx, child_str); + dn = ldb_dn_compose(mem_ctx, dn1, base); talloc_free(child_str); + talloc_free(dn1); return dn; } diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c index 0c31f25cc7..4992eb01ad 100644 --- a/source3/lib/ldb/common/ldb_ldif.c +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -232,6 +232,8 @@ static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *priva return total; } +#undef CHECK_RET + /* encode as base64 to a file */ @@ -264,6 +266,9 @@ static const struct { {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 */ @@ -272,10 +277,13 @@ int ldb_ldif_write(struct ldb_context *ldb, 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_linearize(msg->dn, msg->dn)); @@ -290,6 +298,7 @@ int ldb_ldif_write(struct ldb_context *ldb, 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); @@ -320,7 +329,7 @@ int ldb_ldif_write(struct ldb_context *ldb, for (j=0;jelements[i].num_values;j++) { struct ldb_val v; - ret = h->ldif_write_fn(ldb, ldb, &msg->elements[i].values[j], &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:: ", @@ -541,6 +550,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, if (!chunk) { goto failed; } + talloc_steal(ldif, chunk); msg->private_data = chunk; s = chunk; diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index d627f3b9fa..325cab6dfd 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -266,6 +266,7 @@ int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, str if (current == NULL) { return LDB_ERR_OPERATIONS_ERROR; } + talloc_set_name(current, "ldb_module: %s", module_list[i]); current->ldb = ldb; current->ops = ops; diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index d2f3bd53d3..0af734eb13 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -357,6 +357,9 @@ struct ldb_attrib_handler { */ #define LDB_ATTR_FLAG_HIDDEN (1<<0) +/* the attribute handler name should be freed when released */ +#define LDB_ATTR_FLAG_ALLOCATED (1<<1) + /** The attribute is constructed from other attributes */ diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 5b69ac06c9..3843d2b825 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -776,6 +776,7 @@ static int ildb_connect(struct ldb_context *ldb, const char *url, 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; diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index 10563816b9..410ad64b4a 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -497,9 +497,11 @@ static int lldb_parse_result(struct ldb_handle *handle, LDAPMessage *result) char **referralsp = NULL; LDAPControl **serverctrlsp = NULL; int ret = LDB_SUCCESS; - + type = ldap_msgtype(result); + handle->status = 0; + switch (type) { case LDAP_RES_SEARCH_ENTRY: @@ -631,15 +633,19 @@ static int lldb_parse_result(struct ldb_handle *handle, LDAPMessage *result) } if (matcheddnp) ldap_memfree(matcheddnp); - if (errmsgp) { + 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 ret; + return lldb_ldap_to_ldb(handle->status); error: handle->state = LDB_ASYNC_DONE; @@ -816,6 +822,7 @@ static int lldb_connect(struct ldb_context *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; diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 91256222b1..8dd25db1d6 100644 --- a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2101,6 +2101,7 @@ static int lsqlite3_connect(struct ldb_context *ldb, ldb_oom(ldb); goto failed; } + talloc_set_name_const(*module, "ldb_sqlite3 backend"); (*module)->ldb = ldb; (*module)->prev = (*module)->next = NULL; (*module)->private_data = lsqlite3; diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index a6092c45f9..467f1ac34d 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -71,13 +71,7 @@ static void ltdb_attributes_unload(struct ldb_module *module) msg = ltdb->cache->attributes; for (i=0;inum_elements;i++) { - const struct ldb_attrib_handler *h; - /* this is rather ugly - a consequence of const handling */ - h = ldb_attrib_handler(module->ldb, msg->elements[i].name); ldb_remove_attrib_handler(module->ldb, msg->elements[i].name); - if (strcmp(h->attr, msg->elements[i].name) == 0) { - talloc_steal(msg, h->attr); - } } talloc_free(ltdb->cache->attributes); @@ -163,7 +157,8 @@ static int ltdb_attributes_load(struct ldb_module *module) goto failed; } h2 = *h; - h2.attr = talloc_strdup(module, msg->elements[i].name); + h2.attr = msg->elements[i].name; + h2.flags |= LDB_ATTR_FLAG_ALLOCATED; if (ldb_set_attrib_handlers(module->ldb, &h2, 1) != 0) { goto failed; } @@ -319,6 +314,13 @@ int ltdb_cache_load(struct ldb_module *module) 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); @@ -333,30 +335,31 @@ int ltdb_cache_load(struct ldb_module *module) } } - talloc_free(ltdb->cache->baseinfo); - ltdb->cache->baseinfo = talloc(ltdb->cache, struct ldb_message); - if (ltdb->cache->baseinfo == NULL) goto failed; + baseinfo = talloc(ltdb->cache, struct ldb_message); + if (baseinfo == NULL) goto failed; baseinfo_dn = ldb_dn_explode(module->ldb, LTDB_BASEINFO); if (baseinfo_dn == NULL) goto failed; - if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) == -1) { + if (ltdb_search_dn1(module, baseinfo_dn, baseinfo) == -1) { goto failed; } /* possibly initialise the baseinfo */ - if (!ltdb->cache->baseinfo->dn) { + if (!baseinfo->dn) { if (ltdb_baseinfo_init(module) != 0) { goto failed; } - if (ltdb_search_dn1(module, baseinfo_dn, ltdb->cache->baseinfo) != 1) { + 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(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0); + seq = ldb_msg_find_attr_as_uint64(baseinfo, LTDB_SEQUENCE_NUMBER, 0); if (seq == ltdb->sequence_number) { goto done; } @@ -395,11 +398,13 @@ int ltdb_cache_load(struct ldb_module *module) } 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; diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 8a9a82a98c..0c9d1f33a1 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -1030,6 +1030,12 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) char *dn; unsigned int i, j; + /* find the list of indexed fields */ + if (ltdb->cache->indexlist->num_elements == 0) { + /* no indexed fields */ + return 0; + } + if (ldb_dn_is_special(msg->dn)) { return 0; } @@ -1039,12 +1045,6 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) return -1; } - /* find the list of indexed fields */ - if (ltdb->cache->indexlist->num_elements == 0) { - /* no indexed fields */ - return 0; - } - for (i = 0; i < msg->num_elements; i++) { ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name, NULL, LTDB_IDXATTR); diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index 7cdb2b672f..4b76c437b6 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -248,25 +248,13 @@ int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct l return 1; } -/* the lock key for search locking. Note that this is not a DN, its - just an arbitrary key to give to tdb. Also note that as we and - using transactions for all write operations and transactions take - care of their own locks, we don't need to do any locking anywhere - other than in ldb_search() */ -#define LDBLOCK "INT_LDBLOCK" - /* 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; - TDB_DATA key; - - key.dptr = discard_const(LDBLOCK); - key.dsize = strlen(LDBLOCK); - - return tdb_chainlock_read(ltdb->tdb, key); + return tdb_lockall_read(ltdb->tdb); } /* @@ -275,12 +263,7 @@ static int ltdb_lock_read(struct ldb_module *module) static int ltdb_unlock_read(struct ldb_module *module) { struct ltdb_private *ltdb = module->private_data; - TDB_DATA key; - - key.dptr = discard_const(LDBLOCK); - key.dsize = strlen(LDBLOCK); - - return tdb_chainunlock_read(ltdb->tdb, key); + return tdb_unlockall_read(ltdb->tdb); } /* @@ -499,12 +482,11 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + 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; diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 608120e3a7..3f9db39097 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -79,13 +79,12 @@ static int ltdb_err_map(enum TDB_ERROR tdb_code) struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) + struct ldb_request *req) { struct ltdb_context *ac; struct ldb_handle *h; - h = talloc_zero(ltdb, struct ldb_handle); + h = talloc_zero(req, struct ldb_handle); if (h == NULL) { ldb_set_errstring(module->ldb, "Out of Memory"); return NULL; @@ -106,8 +105,8 @@ struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module h->status = LDB_SUCCESS; ac->module = module; - ac->context = context; - ac->callback = callback; + ac->context = req->context; + ac->callback = req->callback; return h; } @@ -307,7 +306,7 @@ static int ltdb_add(struct ldb_module *module, struct ldb_request *req) } } - req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -387,6 +386,7 @@ static int ltdb_delete_internal(struct ldb_module *module, const struct ldb_dn * ret = ltdb_modified(module, dn); if (ret != LDB_SUCCESS) { + talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } @@ -416,7 +416,7 @@ static int ltdb_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -772,7 +772,7 @@ static int ltdb_modify(struct ldb_module *module, struct ldb_request *req) req->handle = NULL; - req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -826,7 +826,7 @@ static int ltdb_rename(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - req->handle = init_ltdb_handle(ltdb, module, req->context, req->callback); + req->handle = init_ltdb_handle(ltdb, module, req); if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1021,7 +1021,7 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, path = url; } - tdb_flags = TDB_DEFAULT; + tdb_flags = TDB_DEFAULT | TDB_SEQNUM; /* check for the 'nosync' option */ if (flags & LDB_FLG_NOSYNC) { @@ -1058,11 +1058,18 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, talloc_free(ltdb); return -1; } + talloc_set_name_const(*module, "ldb_tdb backend"); (*module)->ldb = ldb; (*module)->prev = (*module)->next = NULL; (*module)->private_data = ltdb; (*module)->ops = <db_ops; + if (ltdb_cache_load(*module) != 0) { + talloc_free(*module); + talloc_free(ltdb); + return -1; + } + return 0; } diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.h b/source3/lib/ldb/ldb_tdb/ldb_tdb.h index 670d3b6801..42f3dc2421 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.h @@ -21,8 +21,11 @@ struct ltdb_private { 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 *baseinfo; struct ldb_message *indexlist; struct ldb_message *attributes; struct ldb_message *subclasses; @@ -110,8 +113,7 @@ 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, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)); + struct ldb_request *req); struct TDB_DATA ltdb_key(struct ldb_module *module, const 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, const struct ldb_dn *dn); diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index 0c58687ddb..f9ae66a2aa 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -1233,11 +1233,13 @@ static int map_init_dns(struct ldb_module *module, struct ldb_map_context *data, if (res->count == 0) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "No results for '%s=%s'!\n", MAP_DN_NAME, name); + talloc_free(res); return LDB_ERR_CONSTRAINT_VIOLATION; } if (res->count > 1) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "Too many results for '%s=%s'!\n", MAP_DN_NAME, name); + talloc_free(res); return LDB_ERR_CONSTRAINT_VIOLATION; } diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index e1b207f6eb..cd33f29043 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -202,7 +202,16 @@ static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_ele } } - *old = *el; /* copy new element */ + /* copy new element */ + *old = *el; + + /* and make sure we reference the contents */ + if (!talloc_reference(msg->elements, el->name)) { + return -1; + } + if (!talloc_reference(msg->elements, el->values)) { + return -1; + } return 0; } diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c index 493ecdaad4..e4040a8e3d 100644 --- a/source3/lib/ldb/modules/objectclass.c +++ b/source3/lib/ldb/modules/objectclass.c @@ -464,7 +464,7 @@ static int objectclass_search_self(struct ldb_handle *h) { 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->module->ldb, NULL); + 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; diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c index b490c8f005..46eac2295d 100644 --- a/source3/lib/ldb/samba/ldif_handlers.c +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -296,7 +296,7 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c const struct ldb_val *in, struct ldb_val *out) { struct ldb_dn *dn1 = NULL; - char *oc1; + char *oc1, *oc2; dn1 = ldb_dn_explode(mem_ctx, (char *)in->data); if (dn1 == NULL) { @@ -308,9 +308,11 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c return -1; } - oc1 = ldb_casefold(ldb, mem_ctx, oc1); - out->data = (void *)oc1; - out->length = strlen(oc1); + oc2 = ldb_casefold(ldb, mem_ctx, oc1); + out->data = (void *)oc2; + out->length = strlen(oc2); + talloc_free(oc1); + talloc_free(dn1); return 0; } diff --git a/source3/lib/ldb/tests/test-generic.sh b/source3/lib/ldb/tests/test-generic.sh index e4085c6d65..14337cc135 100755 --- a/source3/lib/ldb/tests/test-generic.sh +++ b/source3/lib/ldb/tests/test-generic.sh @@ -10,6 +10,12 @@ echo "LDB_URL: $LDB_URL" echo "Adding base elements" $VALGRIND ldbadd $LDBDIR/tests/test.ldif || exit 1 +echo "Adding again - should fail" +ldbadd $LDBDIR/tests/test.ldif 2> /dev/null && { + echo "Should have failed to add again - gave $?" + exit 1 +} + echo "Modifying elements" $VALGRIND ldbmodify $LDBDIR/tests/test-modify.ldif || exit 1 @@ -32,8 +38,11 @@ if [ $LDB_SPECIALS = 1 ]; then $VALGRIND ldbadd $LDBDIR/tests/test-index.ldif || exit 1 fi -echo "Adding attributes" -$VALGRIND ldbadd $LDBDIR/tests/test-wrong_attributes.ldif || exit 1 +echo "Adding bad attributes - should fail" +$VALGRIND ldbadd $LDBDIR/tests/test-wrong_attributes.ldif && { + echo "Should fhave failed - gave $?" + exit 1 +} echo "testing indexed search" $VALGRIND ldbsearch '(uid=uham)' || exit 1 @@ -75,7 +84,7 @@ echo "Testing binary file attribute value" mkdir -p tests/tmp cp $LDBDIR/tests/samba4.png tests/tmp/samba4.png $VALGRIND ldbmodify $LDBDIR/tests/photo.ldif || exit 1 -count=`$VALGRIND ldbsearch '(cn=Ursula Hampster)' jpegPhoto | grep '^dn' | wc -l` +count=`$VALGRIND ldbsearch '(cn=Hampster Ursula)' jpegPhoto | grep '^dn' | wc -l` if [ $count != 1 ]; then echo returned $count records - expected 1 exit 1 @@ -88,7 +97,7 @@ echo "Testing compare" count=`$VALGRIND ldbsearch '(cn>=t)' cn | grep '^dn' | wc -l` if [ $count != 2 ]; then echo returned $count records - expected 2 - echo "this fails on opsnLdap ..." + echo "this fails on openLdap ..." fi count=`$VALGRIND ldbsearch '(cn<=t)' cn | grep '^dn' | wc -l` diff --git a/source3/lib/ldb/tests/test-tdb.sh b/source3/lib/ldb/tests/test-tdb.sh index e1052d1651..7c4f5205b4 100755 --- a/source3/lib/ldb/tests/test-tdb.sh +++ b/source3/lib/ldb/tests/test-tdb.sh @@ -17,6 +17,13 @@ if [ -z "$LDBDIR" ]; then export LDBDIR fi +cat <changetype != LDB_CHANGETYPE_ADD && @@ -74,12 +74,12 @@ static int process_file(struct ldb_context *ldb, FILE *f) ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); failures++; } else { - count++; + (*count)++; } ldb_ldif_read_free(ldb, ldif); } - return count; + return ret; } @@ -87,7 +87,7 @@ static int process_file(struct ldb_context *ldb, FILE *f) int main(int argc, const char **argv) { struct ldb_context *ldb; - int i, count=0; + int i, ret=0, count=0; struct ldb_cmdline *options; ldb_global_init(); @@ -97,7 +97,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - count += process_file(ldb, stdin); + ret = process_file(ldb, stdin, &count); } else { for (i=0;iargc;i++) { const char *fname = options->argv[i]; @@ -107,7 +107,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - count += process_file(ldb, f); + ret = process_file(ldb, f, &count); fclose(f); } } @@ -116,5 +116,5 @@ int main(int argc, const char **argv) printf("Added %d records with %d failures\n", count, failures); - return 0; + return ret; } diff --git a/source3/lib/ldb/tools/ldbdel.c b/source3/lib/ldb/tools/ldbdel.c index aee911efaf..94f1da9903 100644 --- a/source3/lib/ldb/tools/ldbdel.c +++ b/source3/lib/ldb/tools/ldbdel.c @@ -76,7 +76,7 @@ static void usage(void) int main(int argc, const char **argv) { struct ldb_context *ldb; - int ret, i; + int ret = 0, i; struct ldb_cmdline *options; ldb_global_init(); @@ -115,5 +115,5 @@ int main(int argc, const char **argv) talloc_free(ldb); - return 0; + return ret; } diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c index 24f9386266..962045ef7d 100644 --- a/source3/lib/ldb/tools/ldbmodify.c +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -53,10 +53,10 @@ static void usage(void) /* process modifies for one file */ -static int process_file(struct ldb_context *ldb, FILE *f) +static int process_file(struct ldb_context *ldb, FILE *f, int *count) { struct ldb_ldif *ldif; - int ret = -1, count = 0; + int ret = LDB_SUCCESS; while ((ldif = ldb_ldif_read_file(ldb, f))) { switch (ldif->changetype) { @@ -71,24 +71,24 @@ static int process_file(struct ldb_context *ldb, FILE *f) ret = ldb_modify(ldb, ldif->msg); break; } - if (ret != 0) { + if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); failures++; } else { - count++; + (*count)++; } ldb_ldif_read_free(ldb, ldif); } - return count; + return ret; } int main(int argc, const char **argv) { struct ldb_context *ldb; int count=0; - int i; + int i, ret=LDB_SUCCESS; struct ldb_cmdline *options; ldb_global_init(); @@ -98,7 +98,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - count += process_file(ldb, stdin); + ret = process_file(ldb, stdin, &count); } else { for (i=0;iargc;i++) { const char *fname = options->argv[i]; @@ -108,7 +108,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - count += process_file(ldb, f); + ret = process_file(ldb, f, &count); } } @@ -116,9 +116,5 @@ int main(int argc, const char **argv) printf("Modified %d records with %d failures\n", count, failures); - if (failures != 0) { - return -1; - } - - return 0; + return ret; } diff --git a/source3/lib/ldb/tools/ldbsearch.c b/source3/lib/ldb/tools/ldbsearch.c index 23d8115c20..837dfc9088 100644 --- a/source3/lib/ldb/tools/ldbsearch.c +++ b/source3/lib/ldb/tools/ldbsearch.c @@ -215,7 +215,7 @@ static int do_search(struct ldb_context *ldb, req->operation = LDB_SEARCH; req->op.search.base = basedn; req->op.search.scope = options->scope; - req->op.search.tree = ldb_parse_tree(ldb, expression); + req->op.search.tree = ldb_parse_tree(req, expression); if (req->op.search.tree == NULL) return -1; req->op.search.attrs = attrs; req->controls = sctx->req_ctrls; -- cgit From 1fd4184da7b1f17a1f89b5963a8ad80174847155 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 24 Oct 2006 20:15:13 +0000 Subject: r19485: Fix Coverity # 319 (This used to be commit d9f1697c1f09e1f01c15d8fc210b7b5b7c7ec7bb) --- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index 410ad64b4a..a17e80cde0 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -817,7 +817,7 @@ static int lldb_connect(struct ldb_context *ldb, } *module = talloc(ldb, struct ldb_module); - if (!module) { + if (*module == NULL) { ldb_oom(ldb); talloc_free(lldb); return -1; -- cgit From 3a22bdf89ee71a72dc3e84aee6e1d10474b8852b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 24 Oct 2006 20:20:39 +0000 Subject: r19486: Probably Coverity is wrong here, but this fixes their ID 317. Not sure whether to merge it to 4_0. I want it in 3_0 because it took a bit to persuade myself that el can not be NULL here. Volker (This used to be commit c0c035b1c8b9d80cd205cde16ad3e838e2d44459) --- source3/lib/ldb/common/ldb_msg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 7e001f9180..0d9cb47882 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -209,7 +209,9 @@ int ldb_msg_add_steal_value(struct ldb_message *msg, ret = ldb_msg_add_value(msg, attr_name, val); if (ret == LDB_SUCCESS) { struct ldb_message_element *el; - el = ldb_msg_find_element(msg, attr_name); + if (!(el = ldb_msg_find_element(msg, attr_name))) { + return LDB_ERR_OPERATIONS_ERROR; + } talloc_steal(el->values, val->data); } return ret; -- cgit From 151237477bef0d8fdcf926fa0fbe048580a58be5 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 25 Oct 2006 02:06:05 +0000 Subject: r19491: backport changes from samba4 (This used to be commit aa464c9fda978f615230241921f83884a60f4c6f) --- source3/lib/ldb/common/ldb_ldif.c | 2 +- source3/lib/ldb/common/ldb_msg.c | 40 +++++++++++++++++++----------- source3/lib/ldb/include/ldb.h | 8 ++++-- source3/lib/ldb/modules/ldb_map.c | 2 +- source3/lib/ldb/modules/ldb_map_inbound.c | 2 +- source3/lib/ldb/modules/ldb_map_outbound.c | 7 +----- source3/lib/ldb/modules/objectclass.c | 6 ++--- source3/lib/ldb/modules/rdn_name.c | 12 ++++----- 8 files changed, 44 insertions(+), 35 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c index 4992eb01ad..135ce9eecd 100644 --- a/source3/lib/ldb/common/ldb_ldif.c +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -613,7 +613,7 @@ struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb, } if (empty) { - if (ldb_msg_add_empty(msg, (char *)value.data, flags) != 0) { + if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) { goto failed; } continue; diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 0d9cb47882..46ab721e2e 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -119,7 +119,10 @@ struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v) /* add an empty element to a message */ -int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) +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; @@ -146,6 +149,10 @@ int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags) msg->elements = els; msg->num_elements++; + if (return_el) { + *return_el = &els[msg->num_elements-1]; + } + return LDB_SUCCESS; } @@ -156,7 +163,7 @@ 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) != 0) { + if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } @@ -171,18 +178,19 @@ int ldb_msg_add(struct ldb_message *msg, */ int ldb_msg_add_value(struct ldb_message *msg, const char *attr_name, - const struct ldb_val *val) + 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) { - ldb_msg_add_empty(msg, attr_name, 0); - el = ldb_msg_find_element(msg, attr_name); - } - if (!el) { - return LDB_ERR_OPERATIONS_ERROR; + 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); @@ -194,6 +202,10 @@ int ldb_msg_add_value(struct ldb_message *msg, el->values[el->num_values] = *val; el->num_values++; + if (return_el) { + *return_el = el; + } + return LDB_SUCCESS; } @@ -206,12 +218,10 @@ int ldb_msg_add_steal_value(struct ldb_message *msg, struct ldb_val *val) { int ret; - ret = ldb_msg_add_value(msg, attr_name, val); + struct ldb_message_element *el; + + ret = ldb_msg_add_value(msg, attr_name, val, &el); if (ret == LDB_SUCCESS) { - struct ldb_message_element *el; - if (!(el = ldb_msg_find_element(msg, attr_name))) { - return LDB_ERR_OPERATIONS_ERROR; - } talloc_steal(el->values, val->data); } return ret; @@ -234,7 +244,7 @@ int ldb_msg_add_string(struct ldb_message *msg, return LDB_SUCCESS; } - return ldb_msg_add_value(msg, attr_name, &val); + return ldb_msg_add_value(msg, attr_name, &val, NULL); } /* @@ -578,7 +588,7 @@ struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, if (!el) { if (ldb_msg_add_empty(mod, msg1->elements[i].name, - LDB_FLAG_MOD_DELETE) != 0) { + LDB_FLAG_MOD_DELETE, NULL) != 0) { return NULL; } } diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 0af734eb13..2c332b2f9d 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -1227,7 +1227,10 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, /** add a new empty element to a ldb_message */ -int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags); +int ldb_msg_add_empty(struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el); /** add a element to a ldb_message @@ -1237,7 +1240,8 @@ int ldb_msg_add(struct ldb_message *msg, int flags); int ldb_msg_add_value(struct ldb_message *msg, const char *attr_name, - const struct ldb_val *val); + const struct ldb_val *val, + struct ldb_message_element **return_el); int ldb_msg_add_steal_value(struct ldb_message *msg, const char *attr_name, struct ldb_val *val); diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index f9ae66a2aa..1cdeeeb293 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -964,7 +964,7 @@ struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb if (dn == NULL) { goto failed; } - if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE) != 0) { + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_REPLACE, NULL) != 0) { goto failed; } if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c index 404b2ce528..b83a17e502 100644 --- a/source3/lib/ldb/modules/ldb_map_inbound.c +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -345,7 +345,7 @@ int map_modify_do_local(struct ldb_handle *handle) /* Add local 'IS_MAPPED' */ /* TODO: use GUIDs here instead */ dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn); - if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD) != 0) { + if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index cd33f29043..ff3b5c3aa2 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -192,12 +192,7 @@ static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_ele /* no local result, add as new element */ if (old == NULL) { - if (ldb_msg_add_empty(msg, el->name, 0) != 0) { - return -1; - } - - old = ldb_msg_find_element(msg, el->name); - if (old == NULL) { + if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) { return -1; } } diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c index e4040a8e3d..191238f9c9 100644 --- a/source3/lib/ldb/modules/objectclass.c +++ b/source3/lib/ldb/modules/objectclass.c @@ -250,7 +250,7 @@ static int objectclass_add(struct ldb_module *module, struct ldb_request *req) } ldb_msg_remove_attr(msg, "objectClass"); - ret = ldb_msg_add_empty(msg, "objectClass", 0); + ret = ldb_msg_add_empty(msg, "objectClass", 0, NULL); if (ret != LDB_SUCCESS) { talloc_free(mem_ctx); @@ -351,7 +351,7 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req * because we need it sorted */ ldb_msg_remove_attr(msg, "objectClass"); - ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE); + ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE, NULL); if (ret != LDB_SUCCESS) { talloc_free(mem_ctx); @@ -537,7 +537,7 @@ static int objectclass_do_mod(struct ldb_handle *h) { * 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); + 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); diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c index fce1d34ac0..510a43dbc9 100644 --- a/source3/lib/ldb/modules/rdn_name.c +++ b/source3/lib/ldb/modules/rdn_name.c @@ -91,7 +91,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) attribute->num_values = 0; } - if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } @@ -99,7 +99,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) attribute = rdn_name_find_attribute(msg, rdn->name); if (!attribute) { - if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) { + if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } @@ -213,16 +213,16 @@ static int rdn_name_rename_do_mod(struct ldb_handle *h) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE) != 0) { + if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) { + if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE) != 0) { + if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } -- cgit From 3dcb61adcb40d3026cb95f36c1bbd72b56554486 Mon Sep 17 00:00:00 2001 From: James Peach Date: Mon, 6 Nov 2006 18:39:48 +0000 Subject: r19576: Correct trivial typo. (This used to be commit a0ada1aa342722fa7f90715a312b5d81f02f937b) --- source3/lib/ldb/man/ldb.3.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/man/ldb.3.xml b/source3/lib/ldb/man/ldb.3.xml index 6a3a789034..19d9a89e10 100644 --- a/source3/lib/ldb/man/ldb.3.xml +++ b/source3/lib/ldb/man/ldb.3.xml @@ -37,7 +37,7 @@ architecture. -It a taxonomy of databases ldb would sit half way between key/value +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 -- cgit From 82cd90292fea984f6a1ef335bd86c1b4c6d6c684 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 13 Nov 2006 10:43:12 +0000 Subject: r19688: Fix a deadcode warning by Coverity. Simo, I'm not sure this is the correct fix. So I'd like you to look at it and merge to 4 if appropriate. Volker (This used to be commit afd7f12124b02b594063535f93903a8a598a0587) --- source3/lib/ldb/modules/schema.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/schema.c b/source3/lib/ldb/modules/schema.c index 556a35060d..221263a869 100644 --- a/source3/lib/ldb/modules/schema.c +++ b/source3/lib/ldb/modules/schema.c @@ -201,12 +201,7 @@ static int get_attr_list_recursive(struct ldb_module *module, struct schema_stru } ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch); - if (ret != 1) { - return ret; - } - talloc_steal(schema_struct, srch); - - if (ret <= 0) { + if (ret != LDB_SUCCESS) { /* Schema DB Error: Error occurred retrieving Object Class Description */ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, @@ -214,7 +209,10 @@ static int get_attr_list_recursive(struct ldb_module *module, struct schema_stru schema_struct->objectclasses.attr[i].name); return -1; } - if (ret > 1) { + + talloc_steal(schema_struct, srch); + + if (srch->count > 1) { /* Schema DB Error: Too Many Records */ ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, "Too many records found retrieving Objectclass %s.\n", -- cgit From 750947dbe4e547413d875c2eb307224b97d019b3 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 13 Nov 2006 13:38:04 +0000 Subject: r19690: Remove this ancient module, I never realized it was ported over. (This used to be commit 3ef6ef7cc89b6421b9e8ec301cbd55ccd09e4d20) --- source3/lib/ldb/Makefile.in | 2 +- source3/lib/ldb/config.mk | 10 - source3/lib/ldb/modules/schema.c | 486 --------------------------------------- 3 files changed, 1 insertion(+), 497 deletions(-) delete mode 100644 source3/lib/ldb/modules/schema.c (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in index ce23f309d3..c27ecf68c8 100644 --- a/source3/lib/ldb/Makefile.in +++ b/source3/lib/ldb/Makefile.in @@ -37,7 +37,7 @@ COMMON_OBJ=$(COMDIR)/ldb.o $(COMDIR)/ldb_ldif.o \ $(COMDIR)/attrib_handlers.o $(COMDIR)/ldb_controls.o $(COMDIR)/qsort.o MODDIR=modules -MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/schema.o $(MODDIR)/rdn_name.o \ +MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/rdn_name.o \ $(MODDIR)/objectclass.o \ $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o diff --git a/source3/lib/ldb/config.mk b/source3/lib/ldb/config.mk index 6a23005b8f..4e3ba273d6 100644 --- a/source3/lib/ldb/config.mk +++ b/source3/lib/ldb/config.mk @@ -75,16 +75,6 @@ OBJ_FILES = \ # End MODULE ldb_rdn_name ################################################ -# ################################################ -# # Start MODULE ldb_schema -# [MODULE::ldb_schema] -# INIT_FUNCTION = ldb_schema_init -# SUBSYSTEM = ldb -# OBJ_FILES = \ -# modules/schema.o -# # End MODULE ldb_schema -# ################################################ - ################################################ # Start MODULE ldb_ildap [MODULE::ldb_ildap] diff --git a/source3/lib/ldb/modules/schema.c b/source3/lib/ldb/modules/schema.c deleted file mode 100644 index 221263a869..0000000000 --- a/source3/lib/ldb/modules/schema.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - ldb database library - - 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 schema module - * - * Description: add schema check functionality - * - * Author: Simo Sorce - */ - -#include "includes.h" -#include "ldb/include/includes.h" - -#define SCHEMA_FLAG_RESET 0 -#define SCHEMA_FLAG_MOD_MASK 0x003 -#define SCHEMA_FLAG_MOD_ADD 0x001 -#define SCHEMA_FLAG_MOD_REPLACE 0x002 -#define SCHEMA_FLAG_MOD_DELETE 0x003 -#define SCHEMA_FLAG_AUXILIARY 0x010 -#define SCHEMA_FLAG_ABSTRACT 0x020 -#define SCHEMA_FLAG_STRUCTURAL 0x040 -#define SCHEMA_FLAG_CHECKED 0x100 - - -/* TODO: check attributes syntaxes - check there's only one structrual class (or a chain of structural classes) -*/ - -struct schema_attribute { - int flags; - char *name; -}; - -struct schema_attribute_list { - struct schema_attribute *attr; - int num; -}; - -struct schema_structures { - struct schema_attribute_list entry_attrs; - struct schema_attribute_list objectclasses; - struct schema_attribute_list required_attrs; - struct schema_attribute_list optional_attrs; -}; - -static struct schema_attribute *schema_find_attribute(struct schema_attribute_list *list, const char *attr_name) -{ - unsigned int i; - for (i = 0; i < list->num; i++) { - if (ldb_attr_cmp(list->attr[i].name, attr_name) == 0) { - return &(list->attr[i]); - } - } - return NULL; -} - -/* get all the attributes and objectclasses found in msg and put them in schema_structure - attributes go in the entry_attrs structure for later checking - objectclasses go in the objectclasses structure */ -static int get_msg_attributes(struct schema_structures *ss, const struct ldb_message *msg, int flag_mask) -{ - int i, j, anum, cnum; - - ss->entry_attrs.attr = talloc_realloc(ss, ss->entry_attrs.attr, - struct schema_attribute, - ss->entry_attrs.num + msg->num_elements); - if (ss->entry_attrs.attr == NULL) { - return -1; - } - - for (i = 0, anum = ss->entry_attrs.num; i < msg->num_elements; i++) { - - if (ldb_attr_cmp(msg->elements[i].name, "objectclass") == 0) { - - ss->objectclasses.attr = talloc_realloc(ss, ss->objectclasses.attr, - struct schema_attribute, - ss->objectclasses.num + msg->elements[i].num_values); - if (ss->objectclasses.attr == NULL) { - return -1; - } - - for (j = 0, cnum = ss->objectclasses.num; j < msg->elements[i].num_values; j++) { - ss->objectclasses.attr[cnum+j].name = (char *)msg->elements[i].values[j].data; - ss->objectclasses.attr[cnum+j].flags = msg->elements[i].flags & flag_mask; - } - ss->objectclasses.num += msg->elements[i].num_values; - } - - /* TODO: Check for proper attribute Syntax ! */ - - ss->entry_attrs.attr[anum+i].flags = msg->elements[i].flags & flag_mask; - ss->entry_attrs.attr[anum+i].name = talloc_reference(ss->entry_attrs.attr, - msg->elements[i].name); - if (ss->entry_attrs.attr[anum+i].name == NULL) { - return -1; - } - } - ss->entry_attrs.num += msg->num_elements; - - return 0; -} - -static int get_entry_attributes(struct ldb_context *ldb, const struct ldb_dn *dn, struct schema_structures *ss) -{ - struct ldb_result *srch; - int ret; - - ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &srch); - if (ret != 1) { - return ret; - } - talloc_steal(ss, srch); - - /* set flags to 0 as flags on search have undefined values */ - ret = get_msg_attributes(ss, *(srch->msgs), 0); - if (ret != 0) { - talloc_free(srch); - return ret; - } - - return 0; -} - -/* add all attributes in el avoiding duplicates in schema_attribute_list */ -static int add_attribute_uniq(void *mem_ctx, struct schema_attribute_list *list, int flags, struct ldb_message_element *el) -{ - int i, j, vals; - - vals = el->num_values; - list->attr = talloc_realloc(mem_ctx, list->attr, struct schema_attribute, list->num + vals); - if (list->attr == NULL) { - return -1; - } - for (i = 0, j = 0; i < vals; i++) { - int c, found, len; - - found = 0; - for (c = 0; c < list->num; c++) { - len = strlen(list->attr[c].name); - if (len == el->values[i].length) { - if (ldb_attr_cmp(list->attr[c].name, - (char *)el->values[i].data) == 0) { - found = 1; - break; - } - } - } - if (!found) { - list->attr[j + list->num].name = (char *)el->values[i].data; - list->attr[j + list->num].flags = flags; - j++; - } - } - list->num += j; - - return 0; -} - - -/* we need to get all attributes referenced by the entry objectclasses, - recursively get parent objectlasses attributes */ -static int get_attr_list_recursive(struct ldb_module *module, struct schema_structures *schema_struct) -{ - struct ldb_result *srch; - int i, j; - int ret; - - for (i = 0; i < schema_struct->objectclasses.num; i++) { - char *filter; - - if ((schema_struct->objectclasses.attr[i].flags & SCHEMA_FLAG_MOD_MASK) == SCHEMA_FLAG_MOD_DELETE) { - continue; - } - filter = talloc_asprintf(schema_struct, "lDAPDisplayName=%s", schema_struct->objectclasses.attr[i].name); - if (filter == NULL) { - return -1; - } - - ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &srch); - if (ret != LDB_SUCCESS) { - /* Schema DB Error: Error occurred retrieving - Object Class Description */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "Error retrieving Objectclass %s.\n", - schema_struct->objectclasses.attr[i].name); - return -1; - } - - talloc_steal(schema_struct, srch); - - if (srch->count > 1) { - /* Schema DB Error: Too Many Records */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "Too many records found retrieving Objectclass %s.\n", - schema_struct->objectclasses.attr[i].name); - return -1; - } - - /* Add inherited classes eliminating duplicates */ - /* fill in required_attrs and optional_attrs attribute lists */ - for (j = 0; j < srch->msgs[0]->num_elements; j++) { - int is_aux, is_class; - - is_aux = 0; - is_class = 0; - if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "systemAuxiliaryclass") == 0) { - is_aux = SCHEMA_FLAG_AUXILIARY; - is_class = 1; - } - if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "auxiliaryClass") == 0) { - is_aux = SCHEMA_FLAG_AUXILIARY; - is_class = 1; - } - if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "subClassOf") == 0) { - is_class = 1; - } - - if (is_class) { - if (add_attribute_uniq(schema_struct, - &schema_struct->objectclasses, - is_aux, - &srch->msgs[0]->elements[j]) != 0) { - return -1; - } - } else { - - if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mustContain") == 0 || - ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMustContain") == 0) { - if (add_attribute_uniq(schema_struct, - &schema_struct->required_attrs, - SCHEMA_FLAG_RESET, - &srch->msgs[0]->elements[j]) != 0) { - return -1; - } - } - - if (ldb_attr_cmp(srch->msgs[0]->elements[j].name, "mayContain") == 0 || - ldb_attr_cmp(srch->msgs[0]->elements[j].name, "SystemMayContain") == 0) { - - if (add_attribute_uniq(schema_struct, - &schema_struct->optional_attrs, - SCHEMA_FLAG_RESET, - &srch->msgs[0]->elements[j]) != 0) { - return -1; - } - } - } - } - } - - return 0; -} - -/* add_record */ -static int schema_add(struct ldb_module *module, struct ldb_request *req) -{ - const struct ldb_message *msg = req->op.add.message; - struct schema_structures *entry_structs; - unsigned int i; - int ret; - - /* First implementation: - Build up a list of required_attrs and optional_attrs attributes from each objectclass - Check all the required_attrs attributes are present and all the other attributes - are optional_attrs attributes - Throw an error in case a check fail - Free all structures and commit the change - */ - - /* do not check on our control entries */ - if (ldb_dn_is_special(msg->dn)) { - return ldb_next_request(module, req); - } - - /* TODO: check parent exists */ - - entry_structs = talloc_zero(module, struct schema_structures); - if (!entry_structs) { - return -1; - } - - ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK); - if (ret != 0) { - talloc_free(entry_structs); - return ret; - } - - ret = get_attr_list_recursive(module, entry_structs); - if (ret != 0) { - talloc_free(entry_structs); - return ret; - } - - /* now check all required_attrs attributes are present */ - for (i = 0; i < entry_structs->required_attrs.num; i++) { - struct schema_attribute *attr; - - attr = schema_find_attribute(&entry_structs->entry_attrs, - entry_structs->required_attrs.attr[i].name); - - if (attr == NULL) { /* not found */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "The required_attrs attribute %s is missing.\n", - entry_structs->required_attrs.attr[i].name); - talloc_free(entry_structs); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - - /* mark the attribute as checked */ - attr->flags = SCHEMA_FLAG_CHECKED; - } - - /* now check all others atribs are at least optional_attrs */ - for (i = 0; i < entry_structs->entry_attrs.num; i++) { - - if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) { - struct schema_attribute *attr; - - attr = schema_find_attribute(&entry_structs->optional_attrs, - entry_structs->entry_attrs.attr[i].name); - - if (attr == NULL) { /* not found */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "The attribute %s is not referenced by any objectclass.\n", - entry_structs->entry_attrs.attr[i].name); - talloc_free(entry_structs); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - } - } - - talloc_free(entry_structs); - - return ldb_next_request(module, req); -} - -/* modify_record */ -static int schema_modify(struct ldb_module *module, struct ldb_request *req) -{ - const struct ldb_message *msg = req->op.mod.message; - struct schema_structures *entry_structs; - unsigned int i; - int ret; - - /* First implementation: - Retrieve the ldap entry and get the objectclasses, - add msg contained objectclasses if any. - Build up a list of required_attrs and optional_attrs attributes from each objectclass - Check all the attributes are optional_attrs or required_attrs. - Throw an error in case a check fail. - Free all structures and commit the change. - */ - - /* do not check on our control entries */ - if (ldb_dn_is_special(msg->dn)) { - return ldb_next_request(module, req); - } - - /* allocate object structs */ - entry_structs = talloc_zero(module, struct schema_structures); - if (!entry_structs) { - return -1; - } - - /* now search for the stored entry objectclasses and attributes*/ - ret = get_entry_attributes(module->ldb, msg->dn, entry_structs); - if (ret != 0) { - talloc_free(entry_structs); - return ret; - } - - /* get list of values to modify */ - ret = get_msg_attributes(entry_structs, msg, SCHEMA_FLAG_MOD_MASK); - if (ret != 0) { - talloc_free(entry_structs); - return ret; - } - - ret = get_attr_list_recursive(module, entry_structs); - if (ret != 0) { - talloc_free(entry_structs); - return ret; - } - - /* now check all required_attrs attributes are present */ - for (i = 0; i < entry_structs->required_attrs.num; i++) { - struct schema_attribute *attr; - - attr = schema_find_attribute(&entry_structs->entry_attrs, - entry_structs->required_attrs.attr[i].name); - - if (attr == NULL) { /* not found */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "The required_attrs attribute %s is missing.\n", - entry_structs->required_attrs.attr[i].name); - talloc_free(entry_structs); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - - /* check we are not trying to delete a required attribute */ - /* TODO: consider multivalued attrs */ - if ((attr->flags & SCHEMA_FLAG_MOD_DELETE) != 0) { - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "Trying to delete the required attribute %s.\n", - attr->name); - talloc_free(entry_structs); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - - /* mark the attribute as checked */ - attr->flags = SCHEMA_FLAG_CHECKED; - } - - /* now check all others atribs are at least optional_attrs */ - for (i = 0; i < entry_structs->entry_attrs.num; i++) { - - if (entry_structs->entry_attrs.attr[i].flags != SCHEMA_FLAG_CHECKED) { - struct schema_attribute *attr; - - attr = schema_find_attribute(&entry_structs->optional_attrs, - entry_structs->entry_attrs.attr[i].name); - - if (attr == NULL) { /* not found */ - ldb_debug_set(module->ldb, LDB_DEBUG_ERROR, - "The attribute %s is not referenced by any objectclass.\n", - entry_structs->entry_attrs.attr[i].name); - talloc_free(entry_structs); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - } - } - - talloc_free(entry_structs); - - return ldb_next_request(module, req); -} - -static int schema_request(struct ldb_module *module, struct ldb_request *req) -{ - switch (req->operation) { - - case LDB_ADD: - return schema_add(module, req); - - case LDB_MODIFY: - return schema_modify(module, req); - - default: - return ldb_next_request(module, req); - - } -} - -static const struct ldb_module_ops schema_ops = { - .name = "schema", - .request = schema_request -}; - -int ldb_schema_init(void) -{ - return ldb_register_module(&schema_ops); -} -- cgit From 4d12d3a5c82b95df15743353c1f6fa31d64b4ec5 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 13 Nov 2006 14:22:56 +0000 Subject: r19692: Another fix. (This used to be commit a86a56fed3eb06b4b4a04329d42a9f57bad16271) --- source3/lib/ldb/common/ldb_modules.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 325cab6dfd..8bcafa36a8 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -154,7 +154,6 @@ static const struct ldb_module_ops *ldb_find_module_ops(const char *name) LDAP_INIT \ SQLITE3_INIT \ ldb_tdb_init, \ - ldb_schema_init, \ ldb_operational_init, \ ldb_rdn_name_init, \ ldb_objectclass_init, \ -- cgit From 866a3b6e40952193d5bcd812ec7079cf7434e600 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 15 Nov 2006 17:34:20 +0000 Subject: r19725: sync samba3's ldb with samba4 metze (This used to be commit 207643e9c9c75546f38a09f12ea0b574b08086c5) --- source3/lib/ldb/Makefile.in | 18 +- source3/lib/ldb/common/ldb.c | 32 +- source3/lib/ldb/common/ldb_dn.c | 119 +++++-- source3/lib/ldb/common/ldb_match.c | 2 +- source3/lib/ldb/common/ldb_modules.c | 16 +- source3/lib/ldb/common/ldb_msg.c | 8 +- source3/lib/ldb/config.mk | 4 +- source3/lib/ldb/include/ldb.h | 215 ++++++++--- source3/lib/ldb/include/ldb_private.h | 1 + source3/lib/ldb/ldb.pc.in | 5 +- source3/lib/ldb/ldb_ildap/ldb_ildap.c | 5 +- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 4 +- source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 550 +++++++++-------------------- source3/lib/ldb/ldb_tdb/ldb_search.c | 2 +- source3/lib/ldb/modules/asq.c | 3 +- source3/lib/ldb/modules/ldb_map.c | 120 +++---- source3/lib/ldb/modules/ldb_map_inbound.c | 2 +- source3/lib/ldb/modules/ldb_map_outbound.c | 11 +- source3/lib/ldb/modules/ldb_map_private.h | 4 +- source3/lib/ldb/modules/paged_results.c | 4 +- source3/lib/ldb/modules/rdn_name.c | 46 +-- source3/lib/ldb/modules/sort.c | 4 +- source3/lib/ldb/nssldb/README.txt | 34 ++ source3/lib/ldb/nssldb/ldb-grp.c | 427 ++++++++++++++++++++++ source3/lib/ldb/nssldb/ldb-nss.c | 402 +++++++++++++++++++++ source3/lib/ldb/nssldb/ldb-nss.h | 86 +++++ source3/lib/ldb/nssldb/ldb-pwd.c | 241 +++++++++++++ source3/lib/ldb/samba/ldif_handlers.c | 32 +- source3/lib/ldb/standalone.sh | 25 ++ source3/lib/ldb/tests/test-sqlite3.sh | 15 +- source3/lib/ldb/tools/cmdline.c | 1 + 31 files changed, 1810 insertions(+), 628 deletions(-) create mode 100644 source3/lib/ldb/nssldb/README.txt create mode 100644 source3/lib/ldb/nssldb/ldb-grp.c create mode 100644 source3/lib/ldb/nssldb/ldb-nss.c create mode 100644 source3/lib/ldb/nssldb/ldb-nss.h create mode 100644 source3/lib/ldb/nssldb/ldb-pwd.c create mode 100755 source3/lib/ldb/standalone.sh (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/Makefile.in b/source3/lib/ldb/Makefile.in index c27ecf68c8..a091b4832e 100644 --- a/source3/lib/ldb/Makefile.in +++ b/source3/lib/ldb/Makefile.in @@ -18,7 +18,7 @@ SLAPD = @SLAPD@ EXTRA_OBJ=@EXTRA_OBJ@ TESTS=test-tdb.sh @TESTS@ -CFLAGS=-I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ +CFLAGS=-g -I$(srcdir)/include -Iinclude -I$(srcdir) -I$(srcdir)/.. \ @POPT_CFLAGS@ -I@tallocdir@ -I@tdbdir@/include -I@libreplacedir@ \ -DLIBDIR=\"$(libdir)\" -DSHLIBEXT=\"@SHLIBEXT@\" -DUSE_MMAP=1 @CFLAGS@ @@ -41,6 +41,10 @@ MODULES_OBJ=$(MODDIR)/operational.o $(MODDIR)/rdn_name.o \ $(MODDIR)/objectclass.o \ $(MODDIR)/paged_results.o $(MODDIR)/sort.o $(MODDIR)/asq.o +NSSDIR=nssldb +NSS_OBJ= $(NSSDIR)/ldb-nss.o $(NSSDIR)/ldb-pwd.o $(NSSDIR)/ldb-grp.o +NSS_LIB = lib/libnss_ldb.so.2 + OBJS = $(MODULES_OBJ) $(COMMON_OBJ) $(LDB_TDB_OBJ) @TDBOBJ@ @TALLOCOBJ@ @POPTOBJ@ @LIBREPLACEOBJ@ $(EXTRA_OBJ) LDB_LIB = lib/libldb.a @@ -53,6 +57,13 @@ EXAMPLES = examples/ldbreader examples/ldifreader DIRS = lib bin common ldb_tdb ldb_ldap ldb_sqlite3 modules tools examples +default: all + +nss: nssdir all $(NSS_LIB) + +nssdir: + @mkdir -p $(NSSDIR) + all: showflags dirs $(OBJS) $(LDB_LIB) $(BINS) $(EXAMPLES) manpages showflags: @@ -72,6 +83,9 @@ lib/libldb.a: $(OBJS) ar -rv $@ $(OBJS) @-ranlib $@ +lib/libnss_ldb.so.2: $(NSS_OBJ) $(LIBS) + $(CC) -shared -Wl,-soname,libnss_ldb.so.2 -o lib/libnss_ldb.so.2 $(NSS_OBJ) $(OBJS) $(LIB_FLAGS) + bin/ldbadd: tools/ldbadd.o tools/cmdline.o $(LIBS) $(CC) -o bin/ldbadd tools/ldbadd.o tools/cmdline.o $(LIB_FLAGS) @@ -112,7 +126,7 @@ doxygen: clean: rm -f *.o */*.o *.gcov */*.gc?? tdbtest.ldb* - rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) + rm -f $(BINS) $(TDB_OBJ) $(TALLOC_OBJ) $(LDB_LIB) $(NSS_LIB) rm -f man/*.1 man/*.3 man/*.html rm -f $(EXAMPLES) rm -rf apidocs/ diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 7648abf795..9e0ee6ebca 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -522,7 +522,7 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req) Use talloc_free to free the ldb_message returned in 'res', if successful */ -static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct ldb_result *res; int n; @@ -532,12 +532,13 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld return LDB_ERR_OPERATIONS_ERROR; } - res = *((struct ldb_result **)context); + res = talloc_get_type(context, struct ldb_result); if (!res || !ares) { + ldb_set_errstring(ldb, "NULL res or ares in callback"); goto error; } - + switch (ares->type) { case LDB_REPLY_ENTRY: res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); @@ -564,19 +565,17 @@ static int ldb_search_callback(struct ldb_context *ldb, void *context, struct ld res->refs[n] = talloc_move(res->refs, &ares->referral); res->refs[n + 1] = NULL; + case LDB_REPLY_EXTENDED: case LDB_REPLY_DONE: - /* Should do something here to detect if this never - * happens */ + /* TODO: we should really support controls on entries and referrals too! */ + res->controls = talloc_move(res, &ares->controls); break; } - talloc_steal(res, ares->controls); talloc_free(ares); return LDB_SUCCESS; error: talloc_free(ares); - talloc_free(res); - *((struct ldb_result **)context) = NULL; return LDB_ERR_OPERATIONS_ERROR; } @@ -752,16 +751,19 @@ int ldb_search(struct ldb_context *ldb, enum ldb_scope scope, const char *expression, const char * const *attrs, - struct ldb_result **res) + struct ldb_result **_res) { struct ldb_request *req; int ret; + struct ldb_result *res; + + *_res = NULL; - *res = talloc_zero(ldb, struct ldb_result); - if (! *res) { + res = talloc_zero(ldb, struct ldb_result); + if (!res) { return LDB_ERR_OPERATIONS_ERROR; } - + ret = ldb_build_search_req(&req, ldb, ldb, base?base:ldb_get_default_basedn(ldb), scope, @@ -769,7 +771,7 @@ int ldb_search(struct ldb_context *ldb, attrs, NULL, res, - ldb_search_callback); + ldb_search_default_callback); if (ret != LDB_SUCCESS) goto done; @@ -785,10 +787,10 @@ int ldb_search(struct ldb_context *ldb, done: if (ret != LDB_SUCCESS) { - talloc_free(*res); - *res = NULL; + talloc_free(res); } + *_res = res; return ret; } diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index e937a2b7fc..48f471bf6f 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -41,6 +41,19 @@ #define LDB_SPECIAL "@SPECIAL" +/** + internal ldb exploded dn structures +*/ +struct ldb_dn_component { + char *name; + struct ldb_val value; +}; + +struct ldb_dn { + int comp_num; + struct ldb_dn_component *components; +}; + int ldb_dn_is_special(const struct ldb_dn *dn) { if (dn == NULL || dn->comp_num != 1) return 0; @@ -688,6 +701,26 @@ static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_d return dst; } +/* Copy a DN but replace the old with the new base DN. */ +struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base) +{ + struct ldb_dn *new_dn; + int i, offset; + + /* Perhaps we don't need to rebase at all? */ + if (!old_base || !new_base) { + return ldb_dn_copy(mem_ctx, old); + } + + offset = old->comp_num - old_base->comp_num; + new_dn = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); + for (i = 0; i < offset; i++) { + new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &(old->components[i])); + } + + return new_dn; +} + /* copy specified number of elements of a dn into a new one element are copied from top level up to the unique rdn num_el may be greater than dn->comp_num (see ldb_dn_make_child) @@ -799,15 +832,6 @@ failed: } -struct ldb_dn *ldb_dn_make_child(void *mem_ctx, const struct ldb_dn_component *component, - const struct ldb_dn *base) -{ - if (component == NULL) return NULL; - - return ldb_dn_build_child(mem_ctx, component->name, - (char *)component->value.data, base); -} - struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2) { int i; @@ -872,28 +896,6 @@ struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, c return dn; } -struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn) -{ - struct ldb_dn_component *rdn; - - if (dn == NULL) return NULL; - - if (dn->comp_num < 1) { - return NULL; - } - - rdn = talloc(mem_ctx, struct ldb_dn_component); - if (rdn == NULL) return NULL; - - *rdn = ldb_dn_copy_component(mem_ctx, &dn->components[0]); - if (rdn->name == NULL) { - talloc_free(rdn); - return NULL; - } - - return rdn; -} - /* Create a 'canonical name' string from a DN: ie dc=samba,dc=org -> samba.org/ @@ -962,3 +964,58 @@ char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn) { char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn) { return ldb_dn_canonical(mem_ctx, dn, 1); } + +int ldb_dn_get_comp_num(const struct ldb_dn *dn) +{ + return dn->comp_num; +} + +const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num) +{ + if (num >= dn->comp_num) return NULL; + return dn->components[num].name; +} + +const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num) +{ + if (num >= dn->comp_num) return NULL; + return &dn->components[num].value; +} + +const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn) { + if (dn->comp_num == 0) return NULL; + return dn->components[0].name; +} + +const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn) { + if (dn->comp_num == 0) return NULL; + return &dn->components[0].value; +} + +int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val) +{ + char *n; + struct ldb_val v; + + if (num >= dn->comp_num) { + return LDB_ERR_OTHER; + } + + n = talloc_strdup(dn, name); + if ( ! n) { + return LDB_ERR_OTHER; + } + + v.length = val.length; + v.data = (uint8_t *)talloc_memdup(dn, val.data, v.length+1); + if ( ! v.data) { + return LDB_ERR_OTHER; + } + + talloc_free(dn->components[num].name); + talloc_free(dn->components[num].value.data); + dn->components[num].name = n; + dn->components[num].value = v; + + return LDB_SUCCESS; +} diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c index 1fd12da7f3..0cd220ad60 100644 --- a/source3/lib/ldb/common/ldb_match.c +++ b/source3/lib/ldb/common/ldb_match.c @@ -58,7 +58,7 @@ static int ldb_match_scope(struct ldb_context *ldb, break; case LDB_SCOPE_ONELEVEL: - if (dn->comp_num == (base->comp_num + 1)) { + if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) { if (ldb_dn_compare_base(ldb, base, dn) == 0) { ret = 1; } diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 8bcafa36a8..a6997b324a 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -159,6 +159,7 @@ static const struct ldb_module_ops *ldb_find_module_ops(const char *name) ldb_objectclass_init, \ ldb_paged_results_init, \ ldb_sort_init, \ + ldb_asq_init, \ NULL \ } #endif @@ -205,17 +206,26 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) char *path; void *handle; int (*init_fn) (void); + char *modulesdir; #ifdef HAVE_DLOPEN + if (getenv("LD_LDB_MODULE_PATH") != NULL) { + modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH")); + } else { #ifdef _SAMBA_BUILD_ - path = talloc_asprintf(ldb, "%s/ldb/%s.%s", dyn_MODULESDIR, name, dyn_SHLIBEXT); + modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR); #else - path = talloc_asprintf(ldb, "%s/%s.%s", MODULESDIR, name, SHLIBEXT); + modulesdir = talloc_strdup(ldb, MODULESDIR); #endif + } + + path = talloc_asprintf(ldb, "%s/%s.%s", modulesdir, name, SHLIBEXT); + + talloc_free(modulesdir); ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path); - handle = dlopen(path, 0); + handle = dlopen(path, RTLD_NOW); if (handle == NULL) { ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror()); return -1; diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 46ab721e2e..9cb4cf5ed0 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -119,10 +119,10 @@ struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v) /* add an empty element to a message */ -int ldb_msg_add_empty(struct ldb_message *msg, - const char *attr_name, - int flags, - struct ldb_message_element **return_el) +int ldb_msg_add_empty( struct ldb_message *msg, + const char *attr_name, + int flags, + struct ldb_message_element **return_el) { struct ldb_message_element *els; diff --git a/source3/lib/ldb/config.mk b/source3/lib/ldb/config.mk index 4e3ba273d6..cd80adf721 100644 --- a/source3/lib/ldb/config.mk +++ b/source3/lib/ldb/config.mk @@ -167,7 +167,9 @@ OBJ_FILES = \ common/ldb_controls.o \ common/qsort.o PUBLIC_DEPENDENCIES = \ - LIBTALLOC + LIBTALLOC \ + DYNCONFIG \ + SOCKET_WRAPPER MANPAGE = man/ldb.3 PUBLIC_HEADERS = include/ldb.h include/ldb_errors.h # diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 2c332b2f9d..17a2ec7556 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -3,7 +3,7 @@ Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2004 - Copyright (C) Simo Sorce 2005 + Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -86,18 +86,9 @@ struct ldb_val { #endif /*! \endcond */ -/** - internal ldb exploded dn structures -*/ -struct ldb_dn_component { - char *name; - struct ldb_val value; -}; - -struct ldb_dn { - int comp_num; - struct ldb_dn_component *components; -}; +/* opaque ldb_dn structures, see ldb_dn.c for internals */ +struct ldb_dn_component; +struct ldb_dn; /** There are a number of flags that are used with ldap_modify() in @@ -193,12 +184,6 @@ enum ldb_scope {LDB_SCOPE_DEFAULT=-1, struct ldb_context; -/* - the fuction type for the callback used in traversing the database -*/ -typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *); - - /* debugging uses one of the following levels */ enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, LDB_DEBUG_WARNING, LDB_DEBUG_TRACE}; @@ -333,22 +318,25 @@ char *ldb_binary_encode_string(void *mem_ctx, const char *string); typedef int (*ldb_attr_handler_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, struct ldb_val *); typedef int (*ldb_attr_comparison_t)(struct ldb_context *, void *mem_ctx, const struct ldb_val *, const struct ldb_val *); +/* + attribute handler structure + + attr -> The attribute name + flags -> LDB_ATTR_FLAG_* + ldif_read_fn -> convert from ldif to binary format + ldif_write_fn -> convert from binary to ldif format + canonicalise_fn -> canonicalise a value, for use by indexing and dn construction + comparison_fn -> compare two values +*/ + struct ldb_attrib_handler { - const char *attr; - /* LDB_ATTR_FLAG_* */ + const char *attr; unsigned flags; - /* convert from ldif to binary format */ ldb_attr_handler_t ldif_read_fn; - - /* convert from binary to ldif format */ ldb_attr_handler_t ldif_write_fn; - - /* canonicalise a value, for use by indexing and dn construction */ ldb_attr_handler_t canonicalise_fn; - - /* compare two values */ ldb_attr_comparison_t comparison_fn; }; @@ -839,6 +827,145 @@ int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, co */ const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); + +/** + The Default iasync search callback function + + \param ldb the context associated with the database (from ldb_init()) + \param context the callback context + \param ares a single reply from the async core + + \return result code (LDB_SUCCESS on success, or a failure code) + + \note this function expects the context to always be an struct ldb_result pointer + AND a talloc context, this function will steal on the context each message + from the ares reply passed on by the async core so that in the end all the + messages will be in the context (ldb_result) memory tree. + Freeing the passed context (ldb_result tree) will free all the resources + (the request need to be freed separately and the result doe not depend on the + request that can be freed as sson as the search request is finished) +*/ + +int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares); + +/** + Helper function to build a search request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) + \param scope the search scope for the query + \param expression the search expression to use for this query + \param attrs the search attributes for the query (pass NULL if none required) + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_search_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build an add request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param message contains the entry to be added + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_add_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a modify request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param message contains the entry to be modified + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_mod_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_message *message, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a delete request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param dn the DN to be deleted + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_del_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *dn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + +/** + Helper function to build a rename request + + \param ret_req the request structure is returned here (talloced on mem_ctx) + \param ldb the context associated with the database (from ldb_init()) + \param mem_ctx a talloc emmory context (used as parent of ret_req) + \param olddn the old DN + \param newdn the new DN + \param controls an array of controls + \param context the callback function context + \param the callback function to handle the async replies + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ + +int ldb_build_rename_req(struct ldb_request **ret_req, + struct ldb_context *ldb, + void *mem_ctx, + const struct ldb_dn *olddn, + const struct ldb_dn *newdn, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback); + /** Search the database @@ -846,7 +973,7 @@ const struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); records that match an LDAP-like search expression \param ldb the context associated with the database (from ldb_init()) - \param base the Base Distinguished Name for the query (pass NULL for root DN) + \param base the Base Distinguished Name for the query (use ldb_dn_new() for an empty one) \param scope the search scope for the query \param expression the search expression to use for this query \param attrs the search attributes for the query (pass NULL if none required) @@ -1156,18 +1283,25 @@ struct ldb_dn *ldb_dn_casefold(struct ldb_context *ldb, void *mem_ctx, const str struct ldb_dn *ldb_dn_explode_casefold(struct ldb_context *ldb, void *mem_ctx, const char *dn); struct ldb_dn *ldb_dn_copy_partial(void *mem_ctx, const struct ldb_dn *dn, int num_el); struct ldb_dn *ldb_dn_copy(void *mem_ctx, const struct ldb_dn *dn); +struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base); struct ldb_dn *ldb_dn_get_parent(void *mem_ctx, const struct ldb_dn *dn); struct ldb_dn_component *ldb_dn_build_component(void *mem_ctx, const char *attr, const char *val); struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, const char * value, const struct ldb_dn *base); -struct ldb_dn *ldb_dn_make_child(void *mem_ctx, - const struct ldb_dn_component *component, - const struct ldb_dn *base); struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const struct ldb_dn *dn2); struct ldb_dn *ldb_dn_string_compose(void *mem_ctx, const struct ldb_dn *base, const char *child_fmt, ...) PRINTF_ATTRIBUTE(3,4); -struct ldb_dn_component *ldb_dn_get_rdn(void *mem_ctx, const struct ldb_dn *dn); +char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn); +char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn); +int ldb_dn_get_comp_num(const struct ldb_dn *dn); +const char *ldb_dn_get_component_name(const struct ldb_dn *dn, unsigned int num); +const struct ldb_val *ldb_dn_get_component_val(const struct ldb_dn *dn, unsigned int num); +const char *ldb_dn_get_rdn_name(const struct ldb_dn *dn); +const struct ldb_val *ldb_dn_get_rdn_val(const struct ldb_dn *dn); +int ldb_dn_set_component(struct ldb_dn *dn, int num, const char *name, const struct ldb_val val); + + /* useful functions for ldb_message structure manipulation */ int ldb_dn_cmp(struct ldb_context *ldb, const char *dn1, const char *dn2); @@ -1228,9 +1362,9 @@ struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, add a new empty element to a ldb_message */ int ldb_msg_add_empty(struct ldb_message *msg, - const char *attr_name, - int flags, - struct ldb_message_element **return_el); + const char *attr_name, + int flags, + struct ldb_message_element **return_el); /** add a element to a ldb_message @@ -1239,9 +1373,9 @@ int ldb_msg_add(struct ldb_message *msg, const struct ldb_message_element *el, int flags); int ldb_msg_add_value(struct ldb_message *msg, - const char *attr_name, - const struct ldb_val *val, - struct ldb_message_element **return_el); + const char *attr_name, + const struct ldb_val *val, + struct ldb_message_element **return_el); int ldb_msg_add_steal_value(struct ldb_message *msg, const char *attr_name, struct ldb_val *val); @@ -1407,9 +1541,6 @@ char *ldb_timestring(void *mem_ctx, time_t t); */ time_t ldb_string_to_time(const char *s); -char *ldb_dn_canonical_string(void *mem_ctx, const struct ldb_dn *dn); -char *ldb_dn_canonical_ex_string(void *mem_ctx, const struct ldb_dn *dn); - void ldb_qsort (void *const pbase, size_t total_elems, size_t size, void *opaque, ldb_qsort_cmp_fn_t cmp); #endif diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index 3cacd5e292..3902bb2fc2 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -170,6 +170,7 @@ int ldb_operational_init(void); int ldb_paged_results_init(void); int ldb_rdn_name_init(void); int ldb_schema_init(void); +int ldb_asq_init(void); int ldb_sort_init(void); int ldb_ldap_init(void); int ldb_ildap_init(void); diff --git a/source3/lib/ldb/ldb.pc.in b/source3/lib/ldb/ldb.pc.in index 8b0536e21e..815d663a7c 100644 --- a/source3/lib/ldb/ldb.pc.in +++ b/source3/lib/ldb/ldb.pc.in @@ -7,6 +7,9 @@ modulesdir=@modulesdir@ Name: ldb Description: An LDAP-like embedded database Version: 4.0 -Libs: @LIBS@ -L${libdir} -lldb +Requires.private: tdb +Requires: talloc +Libs: -L${libdir} -lldb Cflags: -I${includedir} @CFLAGS@ Modulesdir: ${modulesdir} +URL: http://ldb.samba.org/ diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 3843d2b825..51ae031cf9 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -49,6 +49,7 @@ #include "libcli/ldap/ldap.h" #include "libcli/ldap/ldap_client.h" #include "auth/auth.h" +#include "auth/credentials/credentials.h" struct ildb_private { struct ldap_connection *ldap; @@ -639,8 +640,8 @@ static int ildb_rename(struct ldb_module *module, struct ldb_request *req) msg->r.ModifyDNRequest.newrdn = talloc_asprintf(msg, "%s=%s", - req->op.rename.newdn->components[0].name, - ldb_dn_escape_value(msg, req->op.rename.newdn->components[0].value)); + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(msg, *ldb_dn_get_rdn_val(req->op.rename.newdn))); if (msg->r.ModifyDNRequest.newrdn == NULL) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index a17e80cde0..cdc1a500f8 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -463,8 +463,8 @@ static int lldb_rename(struct ldb_module *module, struct ldb_request *req) } newrdn = talloc_asprintf(lldb_ac, "%s=%s", - req->op.rename.newdn->components[0].name, - ldb_dn_escape_value(lldb, req->op.rename.newdn->components[0].value)); + ldb_dn_get_rdn_name(req->op.rename.newdn), + ldb_dn_escape_value(lldb, *(ldb_dn_get_rdn_val(req->op.rename.newdn)))); if (!newrdn) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8dd25db1d6..4f9b0f6370 100644 --- a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Derrell Lipman 2005 - Copyright (C) Simo Sorce 2005 + Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -57,9 +57,9 @@ struct lsql_context { int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; -static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, + struct ldb_module *module, + struct ldb_request *req) { struct lsql_context *ac; struct ldb_handle *h; @@ -85,8 +85,8 @@ static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct h->status = LDB_SUCCESS; ac->module = module; - ac->context = context; - ac->callback = callback; + ac->context = req->context; + ac->callback = req->callback; return h; } @@ -370,6 +370,7 @@ static char *parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ char *cdn = ldb_dn_linearize_casefold(module->ldb, + mem_ctx, ldb_dn_explode(module->ldb, (const char *)value.data)); @@ -828,7 +829,7 @@ static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn return -1; } - cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, dn)); + cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, local_ctx, dn)); if (!cdn) goto done; eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); @@ -842,53 +843,8 @@ done: * Interface functions referenced by lsqlite3_ops */ -static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct ldb_result *res = NULL; - - if (!context) { - ldb_set_errstring(ldb, "NULL Context in callback"); - goto error; - } - - res = *((struct ldb_result **)context); - - if (!res || !ares) { - goto error; - } - - if (ares->type == LDB_REPLY_ENTRY) { - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); - if (! res->msgs) { - goto error; - } - - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_move(res->msgs, &ares->message); - res->count++; - } else { - ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); - goto error; - } - - talloc_free(ares); - return LDB_SUCCESS; - -error: - if (ares) talloc_free(ares); - if (res) talloc_free(res); - if (context) *((struct ldb_result **)context) = NULL; - return LDB_ERR_OPERATIONS_ERROR; -} - /* search for matching records, by tree */ -int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +int lsql_search(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; @@ -898,32 +854,29 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, char *query = NULL; int ret; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - talloc_free(*handle); + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); - if (base) { - norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); + if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; + + if (req->op.search.base) { + norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.search.base)); if (norm_basedn == NULL) { ret = LDB_ERR_INVALID_DN_SYNTAX; goto failed; } } else norm_basedn = talloc_strdup(lsql_ac, ""); - if (*norm_basedn == '\0' && - (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { - ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; - } - /* Convert filter into a series of SQL conditions (constraints) */ - sqlfilter = parsetree_to_sql(module, lsql_ac, tree); + sqlfilter = parsetree_to_sql(module, lsql_ac, req->op.search.tree); - switch(scope) { + switch(req->op.search.scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: if (*norm_basedn != '\0') { @@ -1033,12 +986,12 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, / * */ lsql_ac->current_eid = 0; - lsql_ac->attrs = attrs; + lsql_ac->attrs = req->op.search.attrs; lsql_ac->ares = NULL; - (*handle)->state = LDB_ASYNC_PENDING; + req->handle->state = LDB_ASYNC_PENDING; - ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, req->handle, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { ldb_set_errstring(module->ldb, errmsg); @@ -1053,70 +1006,39 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, if (lsql_ac->ares->message == NULL) goto failed; - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); - if ((*handle)->status != LDB_SUCCESS) + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if (req->handle->status != LDB_SUCCESS) goto failed; } - (*handle)->state = LDB_ASYNC_DONE; + req->handle->state = LDB_ASYNC_DONE; return LDB_SUCCESS; failed: - talloc_free(*handle); return LDB_ERR_OPERATIONS_ERROR; } -static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* base, - enum ldb_scope scope, struct ldb_parse_tree * tree, - const char * const * attrs, struct ldb_result ** res) -{ - struct ldb_handle *handle; - int ret; - - *res = talloc_zero(module, struct ldb_result); - if (! *res) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = lsql_search_async(module, base, scope, tree, attrs, - res, &lsql_search_sync_callback, - &handle); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(handle, LDB_WAIT_ALL); - talloc_free(handle); - } - - if (ret != LDB_SUCCESS) { - talloc_free(*res); - } - - return ret; -} - /* add a record */ -static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_add(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.add.message; long long eid; char *dn, *ndn; char *errmsg; char *query; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1126,26 +1048,28 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } /* c = ldb_dn_explode(local_ctx, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" - goto failed; + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } */ - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } /* create linearized and normalized dns */ dn = ldb_dn_linearize(lsql_ac, msg->dn); - ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, msg->dn)); + ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, msg->dn)); if (dn == NULL || ndn == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1156,7 +1080,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, dn, ndn); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1166,13 +1090,13 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1185,7 +1109,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1199,7 +1123,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } insert = lsqlite3_tprintf(lsql_ac, @@ -1211,7 +1135,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, el->values[j].data, value.data); if (insert == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); @@ -1221,58 +1145,38 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_add_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } - /* modify a record */ -static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_modify(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.mod.message; long long eid; char *errmsg; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1282,17 +1186,18 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } eid = lsqlite3_get_eid(module, msg->dn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1307,7 +1212,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1324,7 +1229,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1334,7 +1239,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } /* MISSING break is INTENTIONAL */ @@ -1349,7 +1254,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1362,7 +1267,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1372,7 +1277,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1388,7 +1293,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1398,7 +1303,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1410,7 +1315,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1422,7 +1327,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1432,7 +1337,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1440,57 +1345,37 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_modify_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* delete a record */ -static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_delete(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; long long eid; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; - eid = lsqlite3_get_eid(module, dn); + eid = lsqlite3_get_eid(module, req->op.del.dn); if (eid == -1) { - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1501,7 +1386,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, eid, eid); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1510,68 +1395,43 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, ldb_set_errstring(module->ldb, errmsg); free(errmsg); } - ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + req->handle->status = LDB_ERR_OPERATIONS_ERROR; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(dn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_delete_async(module, dn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); + +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* rename a record */ -static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_rename(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; char *new_dn, *new_cdn, *old_cdn; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* create linearized and normalized dns */ - old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, olddn)); - new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, newdn)); - new_dn = ldb_dn_linearize(lsql_ac, newdn); + old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.olddn)); + new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.newdn)); + new_dn = ldb_dn_linearize(lsql_ac, req->op.rename.newdn); if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { - goto failed; + goto done; } /* build the SQL query */ @@ -1580,7 +1440,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old "WHERE norm_dn = '%q';", new_dn, new_cdn, old_cdn); if (query == NULL) { - goto failed; + goto done; } /* execute */ @@ -1591,38 +1451,15 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old free(errmsg); } ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_rename_async(module, olddn, newdn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } @@ -1687,6 +1524,41 @@ static int lsql_del_trans(struct ldb_module *module) return -1; } +static int destructor(struct lsqlite3_private *lsqlite3) +{ + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} + +static int lsql_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .search = lsql_search, + .add = lsql_add, + .modify = lsql_modify, + .del = lsql_delete, + .rename = lsql_rename, + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .wait = lsql_wait, +}; + /* * Static functions */ @@ -1796,12 +1668,12 @@ static int initialize(struct lsqlite3_private *lsqlite3, " ('TOP', '0001');"); /* Skip protocol indicator of url */ - if (strncmp(url, "sqlite://", 9) != 0) { + if (strncmp(url, "sqlite3://", 10) != 0) { return SQLITE_MISUSE; } /* Update pointer to just after the protocol indicator */ - url += 9; + url += 10; /* Try to open the (possibly empty/non-existent) database */ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { @@ -1959,112 +1831,6 @@ failed: return -1; } -static int destructor(struct lsqlite3_private *lsqlite3) -{ - if (lsqlite3->sqlite) { - sqlite3_close(lsqlite3->sqlite); - } - return 0; -} - -static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - return handle->status; -} - -static int lsql_request(struct ldb_module *module, struct ldb_request *req) -{ - /* check for oustanding critical controls and return an error if found */ - - if (req->controls != NULL) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_sqlite3 backend!\n"); - } - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - switch (req->operation) { - - case LDB_SEARCH: - return lsql_search_bytree(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - &req->op.search.res); - - case LDB_ADD: - return lsql_add(module, req->op.add.message); - - case LDB_MODIFY: - return lsql_modify(module, req->op.mod.message); - - case LDB_DELETE: - return lsql_delete(module, req->op.del.dn); - - case LDB_RENAME: - return lsql_rename(module, - req->op.rename.olddn, - req->op.rename.newdn); - - case LDB_SEARCH: - return lsql_search_async(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - req->context, - req->callback, - &req->handle); -/* - case LDB_ADD: - return lsql_add_async(module, - req->op.add.message, - req->context, - req->callback, - &req->handle); - - case LDB_MODIFY: - return lsql_modify_async(module, - req->op.mod.message, - req->context, - req->callback, - &req->handle); -*/ - case LDB_DELETE: - return lsql_delete_async(module, - req->op.del.dn, - req->context, - req->callback, - &req->handle); - - case LDB_RENAME: - return lsql_rename_async(module, - req->op.rename.olddn, - req->op.rename.newdn, - req->context, - req->callback, - &req->handle); - - default: - return LDB_ERR_OPERATIONS_ERROR; - - } -} - -/* - * Table of operations for the sqlite3 backend - */ -static const struct ldb_module_ops lsqlite3_ops = { - .name = "sqlite", - .request = lsql_request, - .start_transaction = lsql_start_trans, - .end_transaction = lsql_end_trans, - .del_transaction = lsql_del_trans, - .wait = lsql_wait, -}; - /* * connect to the database */ diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index 4b76c437b6..884eccd362 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -464,7 +464,7 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) struct ldb_reply *ares; int ret; - if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + if ((req->op.search.base == NULL || ldb_dn_get_comp_num(req->op.search.base) == 0) && (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) return LDB_ERR_OPERATIONS_ERROR; diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 354bbf2bc8..2fed6aac50 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -454,8 +454,7 @@ static int asq_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Unable to register control with rootdse!\n"); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n"); } return ldb_next_init(module); diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index 1cdeeeb293..32e64f3eb2 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -181,60 +181,16 @@ BOOL map_check_local_db(struct ldb_module *module) return True; } -/* WARK: verbatim copy from ldb_dn.c */ -static struct ldb_dn_component ldb_dn_copy_component(void *mem_ctx, struct ldb_dn_component *src) -{ - struct ldb_dn_component dst; - - memset(&dst, 0, sizeof(dst)); - - if (src == NULL) { - return dst; - } - - dst.value = ldb_val_dup(mem_ctx, &(src->value)); - if (dst.value.data == NULL) { - return dst; - } - - dst.name = talloc_strdup(mem_ctx, src->name); - if (dst.name == NULL) { - talloc_free(dst.value.data); - } - - return dst; -} - -/* Copy a DN but replace the old with the new base DN. */ -static struct ldb_dn *ldb_dn_rebase(void *mem_ctx, const struct ldb_dn *old, const struct ldb_dn *old_base, const struct ldb_dn *new_base) -{ - struct ldb_dn *new; - int i, offset; - - /* Perhaps we don't need to rebase at all? */ - if (!old_base || !new_base) { - return ldb_dn_copy(mem_ctx, old); - } - - offset = old->comp_num - old_base->comp_num; - new = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); - for (i = 0; i < offset; i++) { - new->components[i] = ldb_dn_copy_component(new->components, &(old->components[i])); - } - - return new; -} - /* Copy a DN with the base DN of the local partition. */ static struct ldb_dn *ldb_dn_rebase_local(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) { - return ldb_dn_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn); + return ldb_dn_copy_rebase(mem_ctx, dn, data->remote_base_dn, data->local_base_dn); } /* Copy a DN with the base DN of the remote partition. */ static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, const struct ldb_dn *dn) { - return ldb_dn_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn); + return ldb_dn_copy_rebase(mem_ctx, dn, data->local_base_dn, data->remote_base_dn); } /* Run a request and make sure it targets the remote partition. */ @@ -460,23 +416,23 @@ int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attr * ================== */ /* Map an ldb value into the remote partition. */ -struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) { - return map->u.convert.convert_local(module, mem_ctx, &val); + return map->u.convert.convert_local(module, mem_ctx, val); } - return ldb_val_dup(mem_ctx, &val); + return ldb_val_dup(mem_ctx, val); } /* Map an ldb value back into the local partition. */ -struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val) +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) { - return map->u.convert.convert_remote(module, mem_ctx, &val); + return map->u.convert.convert_remote(module, mem_ctx, val); } - return ldb_val_dup(mem_ctx, &val); + return ldb_val_dup(mem_ctx, val); } @@ -500,10 +456,11 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const { const struct ldb_map_context *data = map_get_context(module); struct ldb_dn *newdn; - struct ldb_dn_component *old, *new; const struct ldb_map_attribute *map; enum ldb_map_attr_type map_type; - int i; + const char *name; + struct ldb_val value; + int i, ret; if (dn == NULL) { return NULL; @@ -516,10 +473,8 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const } /* For each RDN, map the component name and possibly the value */ - for (i = 0; i < newdn->comp_num; i++) { - old = &dn->components[i]; - new = &newdn->components[i]; - map = map_attr_find_local(data, old->name); + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_local(data, ldb_dn_get_component_name(dn, i)); /* Unknown attribute - leave this RDN as is and hope the best... */ if (map == NULL) { @@ -533,21 +488,30 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const case MAP_GENERATE: ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "MAP_IGNORE/MAP_GENERATE attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; case MAP_CONVERT: if (map->u.convert.convert_local == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "'convert_local' not set for attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; } /* fall through */ case MAP_KEEP: case MAP_RENAME: - new->name = discard_const_p(char, map_attr_map_local(newdn->components, map, old->name)); - new->value = ldb_val_map_local(module, newdn->components, map, old->value); + name = map_attr_map_local(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_local(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + break; } } @@ -564,10 +528,11 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const { const struct ldb_map_context *data = map_get_context(module); struct ldb_dn *newdn; - struct ldb_dn_component *old, *new; const struct ldb_map_attribute *map; enum ldb_map_attr_type map_type; - int i; + const char *name; + struct ldb_val value; + int i, ret; if (dn == NULL) { return NULL; @@ -580,10 +545,8 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const } /* For each RDN, map the component name and possibly the value */ - for (i = 0; i < newdn->comp_num; i++) { - old = &dn->components[i]; - new = &newdn->components[i]; - map = map_attr_find_remote(data, old->name); + for (i = 0; i < ldb_dn_get_comp_num(newdn); i++) { + map = map_attr_find_remote(data, ldb_dn_get_component_name(dn, i)); /* Unknown attribute - leave this RDN as is and hope the best... */ if (map == NULL) { @@ -597,21 +560,30 @@ struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const case MAP_GENERATE: ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "MAP_IGNORE/MAP_GENERATE attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; case MAP_CONVERT: if (map->u.convert.convert_remote == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "'convert_remote' not set for attribute '%s' " - "used in DN!\n", old->name); + "used in DN!\n", ldb_dn_get_component_name(dn, i)); goto failed; } /* fall through */ case MAP_KEEP: case MAP_RENAME: - new->name = discard_const_p(char, map_attr_map_remote(newdn->components, map, old->name)); - new->value = ldb_val_map_remote(module, newdn->components, map, old->value); + name = map_attr_map_remote(newdn, map, ldb_dn_get_component_name(dn, i)); + if (name == NULL) goto failed; + + value = ldb_val_map_remote(module, newdn, map, ldb_dn_get_component_val(dn, i)); + if (value.data == NULL) goto failed; + + ret = ldb_dn_set_component(newdn, i, name, value); + if (ret != LDB_SUCCESS) { + goto failed; + } + break; } } @@ -1296,13 +1268,13 @@ static int map_init_maps(struct ldb_module *module, struct ldb_map_context *data } /* Copy the list of provided module operations. */ -struct ldb_module_ops ldb_map_get_ops(void) +_PUBLIC_ struct ldb_module_ops ldb_map_get_ops(void) { return map_ops; } /* Initialize global private data. */ -int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, +_PUBLIC_ int ldb_map_init(struct ldb_module *module, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char * const *wildcard_attributes, const char *name) diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c index b83a17e502..38454b2b11 100644 --- a/source3/lib/ldb/modules/ldb_map_inbound.c +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -56,7 +56,7 @@ static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *modul el->name = map_attr_map_local(el, map, old->name); for (i = 0; i < el->num_values; i++) { - el->values[i] = ldb_val_map_local(module, el->values, map, old->values[i]); + el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]); } return el; diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index ff3b5c3aa2..dc213f36d1 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -195,6 +195,7 @@ static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_ele if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) { return -1; } + talloc_free(old->name); } /* copy new element */ @@ -234,7 +235,7 @@ static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *modu el->name = map_attr_map_remote(el, map, old->name); for (i = 0; i < el->num_values; i++) { - el->values[i] = ldb_val_map_remote(module, el->values, map, old->values[i]); + el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]); } return el; @@ -728,21 +729,21 @@ int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, *new = NULL; return 0; } - *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, *tree->u.substring.chunks[i]); + *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]); (*new)->u.substring.chunks[i+1] = NULL; } break; } case LDB_OP_EQUALITY: - (*new)->u.equality.value = ldb_val_map_local(module, *new, map, tree->u.equality.value); + (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value); break; case LDB_OP_LESS: case LDB_OP_GREATER: case LDB_OP_APPROX: - (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, tree->u.comparison.value); + (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value); break; case LDB_OP_EXTENDED: - (*new)->u.extended.value = ldb_val_map_local(module, *new, map, tree->u.extended.value); + (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value); (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id); break; default: /* unknown kind of simple subtree */ diff --git a/source3/lib/ldb/modules/ldb_map_private.h b/source3/lib/ldb/modules/ldb_map_private.h index 7fb2745179..ae53ebbdd4 100644 --- a/source3/lib/ldb/modules/ldb_map_private.h +++ b/source3/lib/ldb/modules/ldb_map_private.h @@ -77,8 +77,8 @@ const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *ma const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr); int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs); -struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val); -struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val); +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); +struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val); struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn); diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c index 3ab575ef6b..c4b1ecf26b 100644 --- a/source3/lib/ldb/modules/paged_results.c +++ b/source3/lib/ldb/modules/paged_results.c @@ -544,9 +544,7 @@ static int paged_request_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "paged_request: Unable to register control with rootdse!\n"); - talloc_free(req); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n"); } talloc_free(req); diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c index 510a43dbc9..bab5f6a014 100644 --- a/source3/lib/ldb/modules/rdn_name.c +++ b/source3/lib/ldb/modules/rdn_name.c @@ -58,7 +58,8 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) struct ldb_request *down_req; struct ldb_message *msg; struct ldb_message_element *attribute; - struct ldb_dn_component *rdn; + const char *rdn_name; + struct ldb_val rdn_val; int i, ret; ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n"); @@ -80,43 +81,45 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - rdn = ldb_dn_get_rdn(msg, msg->dn); - if (rdn == NULL) { + rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (rdn_name == NULL) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn)); + /* Perhaps someone above us tried to set this? */ if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) { attribute->num_values = 0; } - if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } - attribute = rdn_name_find_attribute(msg, rdn->name); + attribute = rdn_name_find_attribute(msg, rdn_name); if (!attribute) { - if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } } else { - const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn->name); + const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn_name); for (i = 0; i < attribute->num_values; i++) { - if (handler->comparison_fn(module->ldb, msg, &rdn->value, &attribute->values[i]) == 0) { + if (handler->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) { /* overwrite so it matches in case */ - attribute->values[i] = rdn->value; + attribute->values[i] = rdn_val; break; } } if (i == attribute->num_values) { ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, - "RDN mismatch on %s: %s", - ldb_dn_linearize(msg, msg->dn), rdn->name); + "RDN mismatch on %s: %s (%s)", + ldb_dn_linearize(msg, msg->dn), rdn_name, rdn_val.data); talloc_free(down_req); return LDB_ERR_OPERATIONS_ERROR; } @@ -190,16 +193,12 @@ static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) static int rdn_name_rename_do_mod(struct ldb_handle *h) { struct rename_context *ac; - struct ldb_dn_component *rdn; + const char *rdn_name; + struct ldb_val rdn_val; struct ldb_message *msg; ac = talloc_get_type(h->private_data, struct rename_context); - rdn = ldb_dn_get_rdn(ac, ac->orig_req->op.rename.newdn); - if (rdn == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ac->mod_req = talloc_zero(ac, struct ldb_request); ac->mod_req->operation = LDB_MODIFY; @@ -213,16 +212,23 @@ static int rdn_name_rename_do_mod(struct ldb_handle *h) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { + rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn); + if (rdn_name == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn)); + + if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, rdn->name, &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - if (ldb_msg_add_value(msg, "name", &rdn->value, NULL) != 0) { + if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c index 3a0598c528..4fa03f8bfa 100644 --- a/source3/lib/ldb/modules/sort.c +++ b/source3/lib/ldb/modules/sort.c @@ -423,9 +423,7 @@ static int server_sort_init(struct ldb_module *module) ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "server_sort: Unable to register control with rootdse!\n"); - talloc_free(req); - return LDB_ERR_OTHER; + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n"); } talloc_free(req); diff --git a/source3/lib/ldb/nssldb/README.txt b/source3/lib/ldb/nssldb/README.txt new file mode 100644 index 0000000000..ddba62b380 --- /dev/null +++ b/source3/lib/ldb/nssldb/README.txt @@ -0,0 +1,34 @@ + +This test code requires a tdb that is configured for to use the asq module. +You can do that adding the following record to a tdb: + +dn: @MODULES +@LIST: asq + +Other modules can be used as well (like rdn_name for example) + +The uidNumber 0 and the gidNumber 0 are considered invalid. + +The user records should contain the followin attributes: +uid (required) the user name +userPassword (optional) the user password (if not present "LDB" is + returned in the password field) +uidNumber (required) the user uid +gidNumber (required) the user primary gid +gecos (optional) the GECOS +homeDirectory (required) the home directory +loginShell (required) the login shell +memberOf (required) all the groups the user is member of should + be reported here using their DNs. The + primary group as well. + +The group accounts should contain the following attributes: +cn (required) the group name +uesrPassword (optional) the group password (if not present "LDB" is + returned in the password field) +gidNumber (required) the group gid +member (optional) the DNs of the member users, also the ones + that have this group as primary + + +SSS diff --git a/source3/lib/ldb/nssldb/ldb-grp.c b/source3/lib/ldb/nssldb/ldb-grp.c new file mode 100644 index 0000000000..f33ec65c55 --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-grp.c @@ -0,0 +1,427 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_gr_attrs[] = { + "cn", + "userPassword", + "gidNumber", + NULL +}; + +const char *_ldb_nss_mem_attrs[] = { + "uid", + NULL +}; + +#define _NSS_LDB_ENOMEM(amem) \ + do { \ + if ( ! amem) { \ + errno = ENOMEM; \ + talloc_free(memctx); \ + return NSS_STATUS_UNAVAIL; \ + } \ + } while(0) + +/* This setgrent, getgrent, endgrent is not very efficient */ + +NSS_STATUS _nss_ldb_setgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res != NULL) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_GRENT_FILTER, + _ldb_nss_gr_attrs, + &_ldb_nss_ctx->gr_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endgrent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->gr_cur = 0; + if (_ldb_nss_ctx->gr_res) { + talloc_free(_ldb_nss_ctx->gr_res); + _ldb_nss_ctx->gr_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrent_r(struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->gr_cur >= _ldb_nss_ctx->gr_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + res = talloc_zero(_ldb_nss_ctx->gr_res, struct ldb_result); + if ( ! res) { + errno = *errnop = ENOMEM; + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return NSS_STATUS_UNAVAIL; + } + + ret = _ldb_nss_group_request(&res, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + talloc_free(res); + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + return ret; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->gr_res->msgs[_ldb_nss_ctx->gr_cur], + res); + + talloc_free(res); + + if (ret != NSS_STATUS_SUCCESS) { + if (ret != NSS_STATUS_TRYAGAIN) { + _ldb_nss_ctx->gr_cur++; /* skip this entry */ + } + return ret; + } + + /* this entry is ok, increment counter to nex entry */ + _ldb_nss_ctx->gr_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getgrnam_r(const char *name, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_getgrgid_r(gid_t gid, struct group *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + TALLOC_CTX *ctx; + struct ldb_result *gr_res; + struct ldb_result *mem_res; + + if (gid == 0) { /* we don't serve root gid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + ctx = talloc_new(_ldb_nss_ctx->ldb); + if ( ! ctx) { + *errnop = errno = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(ctx, _LDB_NSS_GRGID_FILTER, gid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_gr_attrs, + &gr_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(ctx, gr_res); + + /* if none found return */ + if (gr_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (gr_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + mem_res = talloc_zero(ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + gr_res->msgs[0]->dn, + _ldb_nss_mem_attrs, + "member"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_group(result_buf, + buffer, + buflen, + errnop, + gr_res->msgs[0], + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; +done: + talloc_free(ctx); + return ret; +} + +NSS_STATUS _nss_ldb_initgroups_dyn(const char *user, gid_t group, long int *start, long int *size, gid_t **groups, long int limit, int *errnop) +{ + int ret; + char *filter; + const char * attrs[] = { "uidNumber", "gidNumber", NULL }; + struct ldb_result *uid_res; + struct ldb_result *mem_res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + mem_res = talloc_zero(_ldb_nss_ctx, struct ldb_result); + if ( ! mem_res) { + errno = *errnop = ENOMEM; + return NSS_STATUS_UNAVAIL; + } + + /* build the filter for this name */ + filter = talloc_asprintf(mem_res, _LDB_NSS_PWNAM_FILTER, user); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + attrs, + &uid_res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + talloc_steal(mem_res, uid_res); + + /* if none found return */ + if (uid_res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (uid_res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + ret = _ldb_nss_group_request(&mem_res, + uid_res->msgs[0]->dn, + attrs, + "memberOf"); + + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno; + goto done; + } + + ret = _ldb_nss_fill_initgr(group, + limit, + start, + size, + groups, + errnop, + mem_res); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + ret = NSS_STATUS_SUCCESS; + +done: + talloc_free(mem_res); + return ret; +} diff --git a/source3/lib/ldb/nssldb/ldb-nss.c b/source3/lib/ldb/nssldb/ldb-nss.c new file mode 100644 index 0000000000..614f6e170f --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-nss.c @@ -0,0 +1,402 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +struct _ldb_nss_context *_ldb_nss_ctx = NULL; + +NSS_STATUS _ldb_nss_init(void) +{ + int ret; + + pid_t mypid = getpid(); + + if (_ldb_nss_ctx != NULL) { + if (_ldb_nss_ctx->pid == mypid) { + /* already initialized */ + return NSS_STATUS_SUCCESS; + } else { + /* we are in a forked child now, reinitialize */ + talloc_free(_ldb_nss_ctx); + _ldb_nss_ctx = NULL; + } + } + + _ldb_nss_ctx = talloc_named(NULL, 0, "_ldb_nss_ctx(%u)", mypid); + if (_ldb_nss_ctx == NULL) { + return NSS_STATUS_UNAVAIL; + } + + _ldb_nss_ctx->pid = mypid; + + ret = ldb_global_init(); + if (ret != 0) { + goto failed; + } + + _ldb_nss_ctx->ldb = ldb_init(_ldb_nss_ctx); + if (_ldb_nss_ctx->ldb == NULL) { + goto failed; + } + + ret = ldb_connect(_ldb_nss_ctx->ldb, _LDB_NSS_URL, LDB_FLG_RDONLY, NULL); + if (ret != LDB_SUCCESS) { + goto failed; + } + + _ldb_nss_ctx->base = ldb_dn_explode(_ldb_nss_ctx, _LDB_NSS_BASEDN); + if (_ldb_nss_ctx->base == NULL) { + goto failed; + } + + _ldb_nss_ctx->pw_cur = 0; + _ldb_nss_ctx->pw_res = NULL; + _ldb_nss_ctx->gr_cur = 0; + _ldb_nss_ctx->gr_res = NULL; + + return NSS_STATUS_SUCCESS; + +failed: + /* talloc_free(_ldb_nss_ctx); */ + _ldb_nss_ctx = NULL; + return NSS_STATUS_UNAVAIL; +} + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg) +{ + int len; + int bufpos; + const char *tmp; + + bufpos = 0; + + /* get username */ + tmp = ldb_msg_find_attr_as_string(msg, "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(msg, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_passwd = &buffer[bufpos]; + bufpos += len; + + /* this backend never serves an uid 0 user */ + result->pw_uid = ldb_msg_find_attr_as_int(msg, "uidNumber", 0); + if (result->pw_uid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + result->pw_gid = ldb_msg_find_attr_as_int(msg, "gidNumber", 0); + if (result->pw_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* get gecos */ + tmp = ldb_msg_find_attr_as_string(msg, "gecos", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_gecos = &buffer[bufpos]; + bufpos += len; + + /* get homeDirectory */ + tmp = ldb_msg_find_attr_as_string(msg, "homeDirectory", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_dir = &buffer[bufpos]; + bufpos += len; + + /* get shell */ + tmp = ldb_msg_find_attr_as_string(msg, "loginShell", NULL); + if (tmp == NULL) { + tmp = ""; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->pw_shell = &buffer[bufpos]; + bufpos += len; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members) +{ + const char *tmp; + size_t len; + size_t bufpos; + size_t lsize; + int i; + + bufpos = 0; + + /* get group name */ + tmp = ldb_msg_find_attr_as_string(group, "cn", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_name = &buffer[bufpos]; + bufpos += len; + + /* get userPassword */ + tmp = ldb_msg_find_attr_as_string(group, "userPassword", NULL); + if (tmp == NULL) { + tmp = "LDB"; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_passwd = &buffer[bufpos]; + bufpos += len; + + result->gr_gid = ldb_msg_find_attr_as_int(group, "gidNumber", 0); + if (result->gr_gid == 0) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + /* check if there is enough memory for the list of pointers */ + lsize = (members->count + 1) * sizeof(char *); + + /* align buffer on pointer boundary */ + bufpos += (sizeof(char*) - ((unsigned long)(buffer) % sizeof(char*))); + if ((buflen - bufpos) < lsize) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + + result->gr_mem = (char **)&buffer[bufpos]; + bufpos += lsize; + + for (i = 0; i < members->count; i++) { + tmp = ldb_msg_find_attr_as_string(members->msgs[i], "uid", NULL); + if (tmp == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + len = strlen(tmp)+1; + if (bufpos + len > buflen) { + /* buffer too small */ + *errnop = errno = EAGAIN; + return NSS_STATUS_TRYAGAIN; + } + memcpy(&buffer[bufpos], tmp, len); + result->gr_mem[i] = &buffer[bufpos]; + bufpos += len; + } + + result->gr_mem[i] = NULL; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist) +{ + NSS_STATUS ret; + int i; + + for (i = 0; i < grlist->count; i++) { + + if (limit && (*start > limit)) { + /* TODO: warn no all groups were reported */ + *errnop = 0; + ret = NSS_STATUS_SUCCESS; + goto done; + } + + if (*start == *size) { + /* buffer full, enlarge it */ + long int gs; + gid_t *gm; + + gs = (*size) + 32; + if (limit && (gs > limit)) { + gs = limit; + } + + gm = (gid_t *)realloc((*groups), gs * sizeof(gid_t)); + if ( ! gm) { + *errnop = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + *groups = gm; + *size = gs; + } + + (*groups)[*start] = ldb_msg_find_attr_as_int(grlist->msgs[i], "gidNumber", 0); + if ((*groups)[*start] == 0 || (*groups)[*start] == group) { + /* skip root group or primary group */ + continue; + } + (*start)++; + + } + + *errnop = 0; + ret = NSS_STATUS_SUCCESS; +done: + return ret; +} + +#define _LDB_NSS_ALLOC_CHECK(mem) do { if (!mem) { errno = ENOMEM; return NSS_STATUS_UNAVAIL; } } while(0) + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **_res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr) +{ + struct ldb_control **ctrls; + struct ldb_control *ctrl; + struct ldb_asq_control *asqc; + struct ldb_request *req; + int ret; + struct ldb_result *res = *_res; + + ctrls = talloc_array(res, struct ldb_control *, 2); + _LDB_NSS_ALLOC_CHECK(ctrls); + + ctrl = talloc(ctrls, struct ldb_control); + _LDB_NSS_ALLOC_CHECK(ctrl); + + asqc = talloc(ctrl, struct ldb_asq_control); + _LDB_NSS_ALLOC_CHECK(asqc); + + asqc->source_attribute = talloc_strdup(asqc, mattr); + _LDB_NSS_ALLOC_CHECK(asqc->source_attribute); + + asqc->request = 1; + asqc->src_attr_len = strlen(asqc->source_attribute); + ctrl->oid = LDB_CONTROL_ASQ_OID; + ctrl->critical = 1; + ctrl->data = asqc; + ctrls[0] = ctrl; + ctrls[1] = NULL; + + ret = ldb_build_search_req( + &req, + _ldb_nss_ctx->ldb, + res, + group_dn, + LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, + ctrls, + res, + ldb_search_default_callback); + + if (ret != LDB_SUCCESS) { + errno = ENOENT; + return NSS_STATUS_UNAVAIL; + } + + ldb_set_timeout(_ldb_nss_ctx->ldb, req, 0); + + ret = ldb_request(_ldb_nss_ctx->ldb, req); + + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } else { + talloc_free(req); + return NSS_STATUS_UNAVAIL; + } + + talloc_free(req); + return NSS_STATUS_SUCCESS; +} + diff --git a/source3/lib/ldb/nssldb/ldb-nss.h b/source3/lib/ldb/nssldb/ldb-nss.h new file mode 100644 index 0000000000..c780a21e81 --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-nss.h @@ -0,0 +1,86 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _LDB_NSS +#define _LDB_NSS + +#include "includes.h" +#include "ldb/include/includes.h" + +#include +#include +#include + +#define _LDB_NSS_URL "etc/users.ldb" +#define _LDB_NSS_BASEDN "CN=Users,CN=System" +#define _LDB_NSS_PWENT_FILTER "(&(objectClass=posixAccount)(!(uidNumber=0))(!(gidNumber=0)))" +#define _LDB_NSS_PWUID_FILTER "(&(objectClass=posixAccount)(uidNumber=%d)(!(gidNumber=0)))" +#define _LDB_NSS_PWNAM_FILTER "(&(objectClass=posixAccount)(uid=%s)(!(uidNumber=0))(!(gidNumber=0)))" + +#define _LDB_NSS_GRENT_FILTER "(&(objectClass=posixGroup)(!(gidNumber=0)))" +#define _LDB_NSS_GRGID_FILTER "(&(objectClass=posixGroup)(gidNumber=%d)))" +#define _LDB_NSS_GRNAM_FILTER "(&(objectClass=posixGroup)(cn=%s)(!(gidNumber=0)))" + +typedef enum nss_status NSS_STATUS; + +struct _ldb_nss_context { + + pid_t pid; + + struct ldb_context *ldb; + const struct ldb_dn *base; + + int pw_cur; + struct ldb_result *pw_res; + + int gr_cur; + struct ldb_result *gr_res; +}; + +NSS_STATUS _ldb_nss_init(void); + +NSS_STATUS _ldb_nss_fill_passwd(struct passwd *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *msg); + +NSS_STATUS _ldb_nss_fill_group(struct group *result, + char *buffer, + int buflen, + int *errnop, + struct ldb_message *group, + struct ldb_result *members); + +NSS_STATUS _ldb_nss_fill_initgr(gid_t group, + long int limit, + long int *start, + long int *size, + gid_t **groups, + int *errnop, + struct ldb_result *grlist); + +NSS_STATUS _ldb_nss_group_request(struct ldb_result **res, + struct ldb_dn *group_dn, + const char * const *attrs, + const char *mattr); + +#endif /* _LDB_NSS */ diff --git a/source3/lib/ldb/nssldb/ldb-pwd.c b/source3/lib/ldb/nssldb/ldb-pwd.c new file mode 100644 index 0000000000..e4bafdcf7c --- /dev/null +++ b/source3/lib/ldb/nssldb/ldb-pwd.c @@ -0,0 +1,241 @@ +/* + LDB nsswitch module + + Copyright (C) Simo Sorce 2006 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "ldb-nss.h" + +extern struct _ldb_nss_context *_ldb_nss_ctx; + +const char *_ldb_nss_pw_attrs[] = { + "uid", + "userPassword", + "uidNumber", + "gidNumber", + "gecos", + "homeDirectory", + "loginShell", + NULL +}; + +NSS_STATUS _nss_ldb_setpwent(void) +{ + int ret; + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res != NULL) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + _LDB_NSS_PWENT_FILTER, + _ldb_nss_pw_attrs, + &_ldb_nss_ctx->pw_res); + if (ret != LDB_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_endpwent(void) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur = 0; + if (_ldb_nss_ctx->pw_res) { + talloc_free(_ldb_nss_ctx->pw_res); + _ldb_nss_ctx->pw_res = NULL; + } + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwent_r(struct passwd *result_buf, + char *buffer, + int buflen, + int *errnop) +{ + int ret; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + *errnop = 0; + + if (_ldb_nss_ctx->pw_cur >= _ldb_nss_ctx->pw_res->count) { + /* already returned all entries */ + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + _ldb_nss_ctx->pw_res->msgs[_ldb_nss_ctx->pw_cur]); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + _ldb_nss_ctx->pw_cur++; + + return NSS_STATUS_SUCCESS; +} + +NSS_STATUS _nss_ldb_getpwuid_r(uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + if (uid == 0) { /* we don't serve root uid by policy */ + *errnop = errno = ENOENT; + return NSS_STATUS_NOTFOUND; + } + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this uid */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWUID_FILTER, uid); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOMEM; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + +NSS_STATUS _nss_ldb_getpwnam_r(const char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) +{ + int ret; + char *filter; + struct ldb_result *res; + + ret = _ldb_nss_init(); + if (ret != NSS_STATUS_SUCCESS) { + return ret; + } + + /* build the filter for this name */ + filter = talloc_asprintf(_ldb_nss_ctx, _LDB_NSS_PWNAM_FILTER, name); + if (filter == NULL) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* search the entry */ + ret = ldb_search(_ldb_nss_ctx->ldb, + _ldb_nss_ctx->base, + LDB_SCOPE_SUBTREE, + filter, + _ldb_nss_pw_attrs, + &res); + if (ret != LDB_SUCCESS) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* if none found return */ + if (res->count == 0) { + *errnop = errno = ENOENT; + ret = NSS_STATUS_NOTFOUND; + goto done; + } + + if (res->count != 1) { + /* this is a fatal error */ + *errnop = errno = ENOENT; + ret = NSS_STATUS_UNAVAIL; + goto done; + } + + /* fill in the passwd struct */ + ret = _ldb_nss_fill_passwd(result_buf, + buffer, + buflen, + errnop, + res->msgs[0]); + +done: + talloc_free(filter); + talloc_free(res); + return ret; +} + diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c index 46eac2295d..8abfb87238 100644 --- a/source3/lib/ldb/samba/ldif_handlers.c +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -80,10 +80,12 @@ static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx, static BOOL ldb_comparision_objectSid_isString(const struct ldb_val *v) { - /* see if the input if null-terninated */ - if (v->data[v->length] != '\0') return False; - + if (v->length < 3) { + return False; + } + if (strncmp("S-", (const char *)v->data, 2) != 0) return False; + return True; } @@ -179,11 +181,11 @@ static BOOL ldb_comparision_objectGUID_isString(const struct ldb_val *v) struct GUID guid; NTSTATUS status; - /* see if the input if null-terninated */ - if (v->data[v->length] != '\0') return False; - if (v->length < 33) return False; + /* see if the input if null-terninated (safety check for the below) */ + if (v->data[v->length] != '\0') return False; + status = GUID_from_string((const char *)v->data, &guid); if (!NT_STATUS_IS_OK(status)) { return False; @@ -301,9 +303,9 @@ static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_c dn1 = ldb_dn_explode(mem_ctx, (char *)in->data); if (dn1 == NULL) { oc1 = talloc_strndup(mem_ctx, (char *)in->data, in->length); - } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { - oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, - dn1->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn1); + oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { return -1; } @@ -326,9 +328,9 @@ static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx dn1 = ldb_dn_explode(mem_ctx, (char *)v1->data); if (dn1 == NULL) { oc1 = talloc_strndup(mem_ctx, (char *)v1->data, v1->length); - } else if (dn1->comp_num >= 1 && strcasecmp(dn1->components[0].name, "cn") == 0) { - oc1 = talloc_strndup(mem_ctx, (char *)dn1->components[0].value.data, - dn1->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn1) >= 1 && strcasecmp(ldb_dn_get_rdn_name(dn1), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn1); + oc1 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { oc1 = NULL; } @@ -336,9 +338,9 @@ static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx dn2 = ldb_dn_explode(mem_ctx, (char *)v2->data); if (dn2 == NULL) { oc2 = talloc_strndup(mem_ctx, (char *)v2->data, v2->length); - } else if (dn2->comp_num >= 2 && strcasecmp(dn2->components[0].name, "cn") == 0) { - oc2 = talloc_strndup(mem_ctx, (char *)dn2->components[0].value.data, - dn2->components[0].value.length); + } else if (ldb_dn_get_comp_num(dn2) >= 2 && strcasecmp(ldb_dn_get_rdn_name(dn2), "cn") == 0) { + const struct ldb_val *val = ldb_dn_get_rdn_val(dn2); + oc2 = talloc_strndup(mem_ctx, (char *)val->data, val->length); } else { oc2 = NULL; } diff --git a/source3/lib/ldb/standalone.sh b/source3/lib/ldb/standalone.sh new file mode 100755 index 0000000000..fa1b9bafe3 --- /dev/null +++ b/source3/lib/ldb/standalone.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +cd ../replace +make clean + +cd ../talloc +make clean + +cd ../tdb +make clean + +cd ../ldb +make clean + +./autogen.sh + +rm -fr build +mkdir build +cd build + +../configure $* +make dirs +make all + +cd .. diff --git a/source3/lib/ldb/tests/test-sqlite3.sh b/source3/lib/ldb/tests/test-sqlite3.sh index a51ae637dc..0cef318d98 100755 --- a/source3/lib/ldb/tests/test-sqlite3.sh +++ b/source3/lib/ldb/tests/test-sqlite3.sh @@ -1,20 +1,23 @@ #!/bin/sh -LDB_URL="sqlite://sqltest.ldb" +LDB_URL="sqlite3://sqltest.ldb" export LDB_URL -PATH=bin:$PATH -export PATH - rm -f sqltest.ldb if [ -z "$LDBDIR" ]; then - LDBDIR="." + LDBDIR=`dirname $0`/.. export LDBDIR fi -. $LDBDIR/tests/test-generic.sh +PATH=bin:$PATH +export PATH + +LDB_SPECIALS=0 +export LDB_SPECIALS + +$LDBDIR/tests/test-generic.sh #. $LDBDIR/tests/test-extended.sh diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index 09bb99c096..928519f3bb 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -29,6 +29,7 @@ #if (_SAMBA_BUILD_ >= 4) #include "lib/cmdline/popt_common.h" #include "lib/ldb/samba/ldif_handlers.h" +#include "auth/gensec/gensec.h" #include "auth/auth.h" #include "db_wrap.h" #endif -- cgit From 0fa75c6797ce70502aa0051dc70c69de424f7ccb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 16 Nov 2006 11:02:34 +0000 Subject: r19739: fix compiler warning metze (This used to be commit b7965ac26cbfdfe60f929e2fa3a295b8c57d220d) --- source3/lib/ldb/common/ldb_attributes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c index 2d9f0e6cf8..26c1aac5a5 100644 --- a/source3/lib/ldb/common/ldb_attributes.c +++ b/source3/lib/ldb/common/ldb_attributes.c @@ -141,7 +141,7 @@ void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib) return; } if (h->flags & LDB_ATTR_FLAG_ALLOCATED) { - talloc_free(h->attr); + talloc_free(discard_const_p(char, h->attr)); } i = h - ldb->schema.attrib_handlers; if (i < ldb->schema.num_attrib_handlers - 1) { -- cgit From 5a77ccfbfc070ccb77004cb47e2a582883e4862c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 16 Nov 2006 11:11:09 +0000 Subject: r19741: fix compiler warnings metze (This used to be commit 18171cf54b22f9f2d73753db580934bd10e95e3d) --- source3/lib/ldb/common/attrib_handlers.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index 07a0ec6eb8..cb1dfa105f 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -154,7 +154,8 @@ static 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; - char *b1, *b2, *u1, *u2; + const char *u1, *u2; + char *b1, *b2; int ret; while (*s1 == ' ') s1++; while (*s2 == ' ') s2++; @@ -185,11 +186,14 @@ static int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx, utf8str: /* no need to recheck from the start, just from the first utf8 char found */ - b1 = u1 = ldb_casefold(ldb, mem_ctx, s1); - b2 = u2 = ldb_casefold(ldb, mem_ctx, s2); + b1 = ldb_casefold(ldb, mem_ctx, s1); + b2 = ldb_casefold(ldb, mem_ctx, s2); - if (u1 && u2) { + 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 */ -- cgit From 9e7e5938abd9d542966a54374ca652679f42e8ee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 16 Nov 2006 11:18:05 +0000 Subject: r19744: merge from samba4 metze (This used to be commit fe61e6ebf7d771ce6441198bf2e330d53bf7b10e) --- source3/lib/ldb/common/ldb_msg.c | 14 +- source3/lib/ldb/include/ldb_private.h | 2 + source3/lib/ldb/modules/ldb_map.c | 21 +-- source3/lib/ldb/modules/ldb_map_outbound.c | 212 +++++++++++++++++++++++------ source3/lib/ldb/modules/ldb_map_private.h | 2 + 5 files changed, 198 insertions(+), 53 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 9cb4cf5ed0..65d1ecacb7 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -654,7 +654,7 @@ const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs) /* copy an attribute list. This only copies the array, not the elements - (ie. the elements are left as the same pointers) + (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) { @@ -737,6 +737,18 @@ void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr) } } +/* + 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 */ diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index 3902bb2fc2..f4049188ad 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -211,6 +211,8 @@ 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 */ diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index 32e64f3eb2..bbd7b9603d 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -390,13 +390,14 @@ const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *m /* Merge two lists of attributes into a single one. */ -int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attrs, const char * const *more_attrs) +int map_attrs_merge(struct ldb_module *module, void *mem_ctx, + const char ***attrs, const char * const *more_attrs) { int i, j, k; for (i = 0; *attrs && (*attrs)[i]; i++) /* noop */ ; for (j = 0; more_attrs && more_attrs[j]; j++) /* noop */ ; - + *attrs = talloc_realloc(mem_ctx, *attrs, const char *, i+j+1); if (*attrs == NULL) { map_oom(module); @@ -404,7 +405,7 @@ int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attr } for (k = 0; k < j; k++) { - (*attrs)[i+k] = more_attrs[k]; + (*attrs)[i + k] = more_attrs[k]; } (*attrs)[i+k] = NULL; @@ -416,7 +417,8 @@ int map_attrs_merge(struct ldb_module *module, void *mem_ctx, const char ***attr * ================== */ /* Map an ldb value into the remote partition. */ -struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_val *val) +struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, + const struct ldb_map_attribute *map, const struct ldb_val *val) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_local)) { return map->u.convert.convert_local(module, mem_ctx, val); @@ -426,7 +428,8 @@ struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const } /* Map an ldb value back into the local partition. */ -struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, 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) { if (map && (map->type == MAP_CONVERT) && (map->u.convert.convert_remote)) { return map->u.convert.convert_remote(module, mem_ctx, val); @@ -679,7 +682,7 @@ static void map_objectclass_generate_remote(struct ldb_module *module, const cha int i; /* Find old local objectClass */ - oc = ldb_msg_find_element(old, local_attr); + oc = ldb_msg_find_element(old, "objectClass"); if (oc == NULL) { return; } @@ -743,14 +746,14 @@ static struct ldb_val map_objectclass_convert_remote(struct ldb_module *module, } /* Generate a local message with a mapped objectClass. */ -static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *remote_attr, const struct ldb_message *remote) +static struct ldb_message_element *map_objectclass_generate_local(struct ldb_module *module, void *mem_ctx, const char *local_attr, const struct ldb_message *remote) { struct ldb_message_element *el, *oc; struct ldb_val val; int i; /* Find old remote objectClass */ - oc = ldb_msg_find_element(remote, remote_attr); + oc = ldb_msg_find_element(remote, "objectClass"); if (oc == NULL) { return NULL; } @@ -772,7 +775,7 @@ static struct ldb_message_element *map_objectclass_generate_local(struct ldb_mod } /* Copy remote element name "objectClass" */ - el->name = talloc_strdup(el, remote_attr); + el->name = talloc_strdup(el, local_attr); /* Convert all remote objectClasses */ for (i = 0; i < el->num_values; i++) { diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index dc213f36d1..6305e6666f 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -75,7 +75,8 @@ failed: } /* Collect attributes that are mapped into the remote partition. */ -static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, const char * const *attrs) +static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx, + const char * const *attrs) { const struct ldb_map_context *data = map_get_context(module); const char **result; @@ -172,10 +173,10 @@ failed: /* Split attributes that stay in the local partition from those that * are mapped into the remote partition. */ -static int map_attrs_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs) +static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs) { - *local_attrs = map_attrs_select_local(module, local_ctx, attrs); - *remote_attrs = map_attrs_collect_remote(module, remote_ctx, attrs); + *local_attrs = map_attrs_select_local(module, mem_ctx, attrs); + *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs); return 0; } @@ -213,7 +214,11 @@ static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_ele } /* Map a message element back into the local partition. */ -static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old) +static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module, + void *mem_ctx, + const struct ldb_map_attribute *map, + const char *attr_name, + const struct ldb_message_element *old) { struct ldb_message_element *el; int i; @@ -232,7 +237,12 @@ static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *modu return NULL; } - el->name = map_attr_map_remote(el, map, old->name); + el->name = talloc_strdup(el, attr_name); + if (el->name == NULL) { + talloc_free(el); + map_oom(module); + return NULL; + } for (i = 0; i < el->num_values; i++) { el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]); @@ -242,37 +252,64 @@ static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *modu } /* Merge a remote message element into a local message. */ -static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const char *attr_name, const struct ldb_message_element *old) +static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local, + struct ldb_message *remote, const char *attr_name) { const struct ldb_map_context *data = map_get_context(module); - const struct ldb_map_attribute *map = map_attr_find_remote(data, attr_name); - struct ldb_message_element *el=NULL; + const struct ldb_map_attribute *map; + struct ldb_message_element *old, *el=NULL; + const char *remote_name = NULL; + + /* We handle wildcards in ldb_msg_el_merge_wildcard */ + if (ldb_attr_cmp(attr_name, "*") == 0) { + return 0; + } + + map = map_attr_find_local(data, attr_name); /* Unknown attribute in remote message: * skip, attribute was probably auto-generated */ if (map == NULL) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: " - "Skipping attribute '%s': no mapping found\n", - old->name); return 0; } switch (map->type) { case MAP_IGNORE: - return -1; + break; + case MAP_CONVERT: + remote_name = map->u.convert.remote_name; + break; + case MAP_KEEP: + remote_name = attr_name; + break; + case MAP_RENAME: + remote_name = map->u.rename.remote_name; + break; + case MAP_GENERATE: + break; + } + + switch (map->type) { + case MAP_IGNORE: + return 0; case MAP_CONVERT: if (map->u.convert.convert_remote == NULL) { ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "Skipping attribute '%s': " "'convert_remote' not set\n", - old->name); + attr_name); return 0; } /* fall through */ case MAP_KEEP: case MAP_RENAME: - el = ldb_msg_el_map_remote(module, local, map, old); + old = ldb_msg_find_element(remote, remote_name); + if (old) { + el = ldb_msg_el_map_remote(module, local, map, attr_name, old); + } else { + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } break; case MAP_GENERATE: @@ -280,21 +317,68 @@ static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: " "Skipping attribute '%s': " "'generate_local' not set\n", - old->name); + attr_name); return 0; } - el = map->u.generate.generate_local(module, local, old->name, remote); + el = map->u.generate.generate_local(module, local, attr_name, remote); + if (!el) { + /* Generation failure is probably due to lack of source attributes */ + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } break; } if (el == NULL) { - return -1; + return LDB_ERR_OPERATIONS_ERROR; } return ldb_msg_replace(local, el); } +/* Handle wildcard parts of merging a remote message element into a local message. */ +static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local, + struct ldb_message *remote) +{ + const struct ldb_map_context *data = map_get_context(module); + const struct ldb_map_attribute *map = map_attr_find_local(data, "*"); + struct ldb_message_element *el=NULL; + int i, ret; + + /* Perhaps we have a mapping for "*" */ + if (map && map->type == MAP_KEEP) { + /* We copy everything over, and hope that anything with a + more specific rule is overwritten */ + for (i = 0; i < remote->num_elements; i++) { + el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name, + &remote->elements[i]); + if (el == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_msg_replace(local, el); + if (ret) { + return ret; + } + } + } + + /* Now walk the list of possible mappings, and apply each */ + for (i = 0; data->attribute_maps[i].local_name; i++) { + ret = ldb_msg_el_merge(module, local, remote, + data->attribute_maps[i].local_name); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + continue; + } else if (ret) { + return ret; + } else { + continue; + } + } + + return 0; +} + /* Mapping messages * ================ */ @@ -314,16 +398,36 @@ static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *ms } /* Merge a local and a remote message into a single local one. */ -static int ldb_msg_merge_remote(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote) +static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local, + struct ldb_message *remote) { int i, ret; + const char * const *attrs = ac->all_attrs; + if (!attrs) { + ret = ldb_msg_el_merge_wildcard(ac->module, local, remote); + if (ret) { + return ret; + } + } + + for (i = 0; attrs && attrs[i]; i++) { + if (ldb_attr_cmp(attrs[i], "*") == 0) { + ret = ldb_msg_el_merge_wildcard(ac->module, local, remote); + if (ret) { + return ret; + } + break; + } + } /* Try to map each attribute back; * Add to local message is possible, * Overwrite old local attribute if necessary */ - for (i = 0; i < remote->num_elements; i++) { - ret = ldb_msg_el_merge(module, local, remote, remote->elements[i].name, &remote->elements[i]); - if (ret) { + for (i = 0; attrs && attrs[i]; i++) { + ret = ldb_msg_el_merge(ac->module, local, remote, + attrs[i]); + if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) { + } else if (ret) { return ret; } } @@ -335,7 +439,7 @@ static int ldb_msg_merge_remote(struct ldb_module *module, struct ldb_message *l * ====================== */ /* Map a search result back into the local partition. */ -static int map_reply_remote(struct ldb_module *module, struct ldb_reply *ares) +static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares) { struct ldb_message *msg; struct ldb_dn *dn; @@ -349,19 +453,19 @@ static int map_reply_remote(struct ldb_module *module, struct ldb_reply *ares) /* Create a new result message */ msg = ldb_msg_new(ares); if (msg == NULL) { - map_oom(module); + map_oom(ac->module); return -1; } /* Merge remote message into new message */ - ret = ldb_msg_merge_remote(module, msg, ares->message); + ret = ldb_msg_merge_remote(ac, msg, ares->message); if (ret) { talloc_free(msg); return ret; } /* Create corresponding local DN */ - dn = ldb_dn_map_rebase_remote(module, msg, ares->message->dn); + dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn); if (dn == NULL) { talloc_free(msg); return -1; @@ -419,7 +523,8 @@ static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx case LDB_OP_OR: case LDB_OP_AND: /* attributes stored in list of subtrees */ for (i = 0; i < tree->u.list.num_elements; i++) { - ret = ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.list.elements[i]); + ret = ldb_parse_tree_collect_attrs(module, mem_ctx, + attrs, tree->u.list.elements[i]); if (ret) { return ret; } @@ -827,23 +932,34 @@ static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, /* Collect a list of attributes required either explicitly from a * given list or implicitly from a given parse tree; split the * collected list into local and remote parts. */ -static int map_attrs_collect_and_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *search_attrs, const struct ldb_parse_tree *tree) +static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac, + const char * const *search_attrs, + const struct ldb_parse_tree *tree) { void *tmp_ctx; const char **tree_attrs; + const char **remote_attrs; + const char **local_attrs; int ret; /* Clear initial lists of partitioned attributes */ - *local_attrs = NULL; - *remote_attrs = NULL; + + /* Clear initial lists of partitioned attributes */ /* There is no tree, just partition the searched attributes */ if (tree == NULL) { - return map_attrs_partition(module, local_ctx, remote_ctx, local_attrs, remote_attrs, search_attrs); + ret = map_attrs_partition(module, ac, + &local_attrs, &remote_attrs, search_attrs); + if (ret == 0) { + ac->local_attrs = local_attrs; + ac->remote_attrs = remote_attrs; + ac->all_attrs = search_attrs; + } + return ret; } /* Create context for temporary memory */ - tmp_ctx = talloc_new(local_ctx); + tmp_ctx = talloc_new(ac); if (tmp_ctx == NULL) { goto oom; } @@ -869,8 +985,15 @@ static int map_attrs_collect_and_partition(struct ldb_module *module, void *loca } /* Split local from remote attributes */ - ret = map_attrs_partition(module, local_ctx, remote_ctx, local_attrs, remote_attrs, tree_attrs); - + ret = map_attrs_partition(module, ac, &local_attrs, + &remote_attrs, tree_attrs); + + if (ret == 0) { + ac->local_attrs = local_attrs; + ac->remote_attrs = remote_attrs; + talloc_steal(ac, tree_attrs); + ac->all_attrs = tree_attrs; + } done: /* Free temporary memory */ talloc_free(tmp_ctx); @@ -911,10 +1034,12 @@ int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, stru /* Limit result to requested attrs */ if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) { - for (i = 0; i < ares->message->num_elements; i++) { - const struct ldb_message_element *el = &ares->message->elements[i]; + for (i = 0; i < ares->message->num_elements; ) { + struct ldb_message_element *el = &ares->message->elements[i]; if (!ldb_attr_in_list(req->op.search.attrs, el->name)) { - ldb_msg_remove_attr(ares->message, el->name); + ldb_msg_remove_element(ares->message, el); + } else { + i++; } } } @@ -995,7 +1120,7 @@ int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ld } /* Map result record into a local message */ - ret = map_reply_remote(ac->module, ares); + ret = map_reply_remote(ac, ares); if (ret) { talloc_free(ares); return LDB_ERR_OPERATIONS_ERROR; @@ -1042,7 +1167,6 @@ int map_search(struct ldb_module *module, struct ldb_request *req) struct ldb_handle *h; struct map_context *ac; struct ldb_parse_tree *local_tree, *remote_tree; - const char **local_attrs, **remote_attrs; int ret; const char *wildcard[] = { "*", NULL }; @@ -1096,16 +1220,18 @@ int map_search(struct ldb_module *module, struct ldb_request *req) } /* Split local from remote attrs */ - ret = map_attrs_collect_and_partition(module, ac, ac->search_reqs[0], &local_attrs, &remote_attrs, attrs, req->op.search.tree); + ret = map_attrs_collect_and_partition(module, ac, + attrs, req->op.search.tree); if (ret) { goto failed; } - ac->local_attrs = local_attrs; - ac->search_reqs[0]->op.search.attrs = remote_attrs; + ac->search_reqs[0]->op.search.attrs = ac->remote_attrs; /* Split local from remote tree */ - ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], &local_tree, &remote_tree, req->op.search.tree); + ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], + &local_tree, &remote_tree, + req->op.search.tree); if (ret) { goto failed; } diff --git a/source3/lib/ldb/modules/ldb_map_private.h b/source3/lib/ldb/modules/ldb_map_private.h index ae53ebbdd4..8a08d0a5b6 100644 --- a/source3/lib/ldb/modules/ldb_map_private.h +++ b/source3/lib/ldb/modules/ldb_map_private.h @@ -36,6 +36,8 @@ struct map_context { const 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; -- cgit From 433869019bdaa7f21467769eb5398f2973fa54f3 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:35:22 +0000 Subject: r19889: Fix klokwork ID 2187 (This used to be commit 1bd660fb9139238229fc6a80566c03f473cad094) --- source3/lib/ldb/modules/asq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 2fed6aac50..bee8038d9f 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -105,6 +105,9 @@ static int asq_terminate(struct ldb_handle *handle) 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; -- cgit From d128defd315045c000f73e268a3efea761a84afd Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:38:23 +0000 Subject: r19890: Fix klokwork ID 2188 (This used to be commit 4d44388929f75d1480a8222a7cd2f575494a2b62) --- source3/lib/ldb/modules/asq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index bee8038d9f..da5afde212 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -161,7 +161,9 @@ static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_ goto error; } - ac = talloc_get_type(context, struct asq_context); + if (!(ac = talloc_get_type(context, struct asq_context))) { + goto error; + } /* we are interested only in the single reply (base search) we receive here */ if (ares->type == LDB_REPLY_ENTRY) { -- cgit From 76b2e7ba1337591edd9fbfe777a47e3413a77c32 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:39:34 +0000 Subject: r19891: Fix klokwork id 2189 (This used to be commit b6933c3043b73b68a30f57f681185a79c8e205c2) --- source3/lib/ldb/modules/asq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index da5afde212..36ea0da256 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -187,7 +187,9 @@ static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_ goto error; } - ac = talloc_get_type(context, struct asq_context); + if (!(ac = talloc_get_type(context, struct asq_context))) { + goto error; + } /* we are interested only in the single reply (base search) we receive here */ if (ares->type == LDB_REPLY_ENTRY) { -- cgit From 7230ce8cd0e463ca5f353bc6bc0fad8f7819c550 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:41:06 +0000 Subject: r19892: Fix klokwork id 2190 (This used to be commit 235e8c9653a9199f2766c5c4a2d1f1d4f2801a3b) --- source3/lib/ldb/modules/asq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 36ea0da256..e0c866d259 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -241,7 +241,10 @@ static int asq_search(struct ldb_module *module, struct ldb_request *req) if (!h) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct asq_context); + if (!(ac = talloc_get_type(h->private_data, struct asq_context))) { + + return LDB_ERR_OPERATIONS_ERROR; + } req->handle = h; -- cgit From 7968602097ffaa310745cc93ab99f493509aac62 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:42:21 +0000 Subject: r19893: Fix klokwork id 2191 (This used to be commit a301a4a12d554d9d3ba00c2780deb9eafc44e1a8) --- source3/lib/ldb/modules/asq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index e0c866d259..5bda383b44 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -296,7 +296,10 @@ static int asq_requests(struct ldb_handle *handle) { struct ldb_message_element *el; int i; - ac = talloc_get_type(handle->private_data, struct asq_context); + if (!(ac = talloc_get_type(handle->private_data, + struct asq_context))) { + return LDB_ERR_OPERATIONS_ERROR; + } /* look up the DNs */ if (ac->base_res == NULL) { -- cgit From 40dc09e009ca91225345e7f27936b38133bf7131 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:43:26 +0000 Subject: r19894: Fix klokwork id 2192 (This used to be commit 4b075f347b5449b199be19221187ce66916384cf) --- source3/lib/ldb/modules/asq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 5bda383b44..7d23202303 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -361,8 +361,10 @@ static int asq_wait_none(struct ldb_handle *handle) handle->state = LDB_ASYNC_PENDING; handle->status = LDB_SUCCESS; - ac = talloc_get_type(handle->private_data, struct asq_context); - + if (!(ac = talloc_get_type(handle->private_data, + struct asq_context))) { + return LDB_ERR_OPERATIONS_ERROR; + } switch (ac->step) { case ASQ_SEARCH_BASE: -- cgit From f494d7d31f59c171110b1d1a16b0720763c18acf Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:53:56 +0000 Subject: r19895: Fix klokwork id 2278 (This used to be commit 8ccff6a4dd92dfad4942b562cd1bb27d22d59661) --- source3/lib/ldb/tools/cmdline.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index 928519f3bb..b20919ff97 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -269,7 +269,10 @@ struct ldb_control **parse_controls(void *mem_ctx, char **control_strings) fprintf(stderr, " note: b = boolean, n = number, s = string, o = b64 binary blob\n"); return NULL; } - ctrl[i] = talloc(ctrl, struct ldb_control); + if (!(ctrl[i] = talloc(ctrl, struct ldb_control))) { + fprintf(stderr, "talloc failed\n"); + return NULL; + } ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID; ctrl[i]->critical = crit; control = talloc(ctrl[i], struct ldb_vlv_req_control); -- cgit From f6dece8b4d651560ba72ea7efbc665d53aba64eb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 16:55:11 +0000 Subject: r19896: Fix klokwork id 2279 (This used to be commit 558a13a755ff39c9f15ba4f0a2639ffe30c996ac) --- source3/lib/ldb/tools/cmdline.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index b20919ff97..8eb7a7e952 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -275,7 +275,11 @@ struct ldb_control **parse_controls(void *mem_ctx, char **control_strings) } ctrl[i]->oid = LDB_CONTROL_VLV_REQ_OID; ctrl[i]->critical = crit; - control = talloc(ctrl[i], struct ldb_vlv_req_control); + if (!(control = talloc(ctrl[i], + struct ldb_vlv_req_control))) { + fprintf(stderr, "talloc failed\n"); + return NULL; + } control->beforeCount = bc; control->afterCount = ac; if (attr[0]) { -- cgit From ca3300cbd14d93f7bb9b43e813a2bc4f9f9cc7d3 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 17:07:49 +0000 Subject: r19898: Fix klokwork ids 3127, 3128, 3129, 3130 (This used to be commit 3250d20d27d4f85421052e877077526975b16e02) --- source3/lib/ldb/common/ldb_dn.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 48f471bf6f..7a1d8a910b 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -441,7 +441,9 @@ struct ldb_dn *ldb_dn_explode_or_special(void *mem_ctx, const char *dn) */ /* Allocate a structure to hold the exploded DN */ - edn = ldb_dn_new(mem_ctx); + if (!(edn = ldb_dn_new(mem_ctx))) { + return NULL; + } edn->comp_num = 1; edn->components = talloc(edn, struct ldb_dn_component); @@ -713,7 +715,10 @@ struct ldb_dn *ldb_dn_copy_rebase(void *mem_ctx, const struct ldb_dn *old, const } offset = old->comp_num - old_base->comp_num; - new_dn = ldb_dn_copy_partial(mem_ctx, new_base, offset + new_base->comp_num); + if (!(new_dn = ldb_dn_copy_partial(mem_ctx, new_base, + offset + new_base->comp_num))) { + return NULL; + } for (i = 0; i < offset; i++) { new_dn->components[i] = ldb_dn_copy_component(new_dn->components, &(old->components[i])); } @@ -815,6 +820,7 @@ struct ldb_dn *ldb_dn_build_child(void *mem_ctx, const char *attr, newdn->comp_num = 1; newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + LDB_DN_NULL_FAILED(newdn->components); } newdn->components[0].name = talloc_strdup(newdn->components, attr); @@ -847,6 +853,7 @@ struct ldb_dn *ldb_dn_compose(void *mem_ctx, const struct ldb_dn *dn1, const str newdn->comp_num = dn1->comp_num; newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + LDB_DN_NULL_FAILED(newdn->components); } else { int comp_num = dn2->comp_num; if (dn1 != NULL) comp_num += dn1->comp_num; -- cgit From a12fb3afdda89dd5d5eec6c9371512f668645446 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 17:11:29 +0000 Subject: r19899: Fix some C++ warnings and klokwork ID 3147 (This used to be commit c5e041661ec6dd63188ad0a09a228192b6dfd2b3) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 0c9d1f33a1..2a862c02d6 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -47,7 +47,7 @@ static int ldb_list_find(const void *needle, const void *base, size_t nmemb, size_t size, comparison_fn_t comp_fn) { - const char *base_p = base; + const char *base_p = (const char *)base; size_t min_i, max_i, test_i; if (nmemb == 0) { @@ -897,7 +897,8 @@ static int ltdb_index_add1(struct ldb_module *module, const char *dn, static int ltdb_index_add0(struct ldb_module *module, const char *dn, struct ldb_message_element *elements, int num_el) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; int ret; unsigned int i, j; @@ -933,7 +934,8 @@ static int ltdb_index_add0(struct ldb_module *module, const char *dn, */ int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; char *dn; int ret; @@ -1025,7 +1027,8 @@ int ltdb_index_del_value(struct ldb_module *module, const char *dn, */ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; int ret; char *dn; unsigned int i, j; @@ -1082,7 +1085,7 @@ static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, vo */ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) { - struct ldb_module *module = state; + struct ldb_module *module = (struct ldb_module *)state; struct ldb_message *msg; char *dn = NULL; int ret; @@ -1123,7 +1126,10 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void * if (msg->dn == NULL) { dn = (char *)key.dptr + 3; } else { - dn = ldb_dn_linearize(msg->dn, msg->dn); + if (!(dn = ldb_dn_linearize(msg->dn, msg->dn))) { + talloc_free(msg); + return -1; + } } ret = ltdb_index_add0(module, dn, msg->elements, msg->num_elements); @@ -1138,7 +1144,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void * */ int ltdb_reindex(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; int ret; if (ltdb_cache_reload(module) != 0) { -- cgit From 2685e167fa12d696bf3882e888629f95b81e7683 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 25 Nov 2006 17:14:39 +0000 Subject: r19900: Fix klokwork ID 3148, 3149 (This used to be commit 1f3e20ef3985a0a16e8945907611654ef5e884c4) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 2a862c02d6..d7a8e5e9b5 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -642,6 +642,10 @@ static int ltdb_index_filter(const struct dn_list *dn_list, struct ldb_reply *ares = NULL; unsigned int i; + if (!ac) { + return LDB_ERR_OPERATIONS_ERROR; + } + for (i = 0; i < dn_list->count; i++) { struct ldb_dn *dn; int ret; @@ -722,6 +726,10 @@ int ltdb_search_indexed(struct ldb_handle *handle) struct dn_list *dn_list; int ret; + if ((ac == NULL) || (ltdb == NULL)) { + return -1; + } + if (ltdb->cache->indexlist->num_elements == 0 && ac->scope != LDB_SCOPE_BASE) { /* no index list? must do full search */ -- cgit From 847644bdac520a3cca7f30ffa50c0de3eeedf6d9 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 27 Nov 2006 08:41:41 +0000 Subject: r19917: Fix warnings (This used to be commit cf4309b9048a8417104cac660421a3dcd2e96ffe) --- source3/lib/ldb/common/attrib_handlers.c | 2 +- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 10 +++++++--- source3/lib/ldb/ldb_tdb/ldb_cache.c | 29 +++++++++++++++++++---------- source3/lib/ldb/ldb_tdb/ldb_pack.c | 8 ++++---- source3/lib/ldb/ldb_tdb/ldb_search.c | 9 ++++++--- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 8 +++++--- source3/lib/ldb/modules/operational.c | 2 +- 8 files changed, 44 insertions(+), 26 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index cb1dfa105f..a289f3c32a 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -296,7 +296,7 @@ static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx, } for (i=0;subclasses[i];i++) { struct ldb_val vs; - vs.data = discard_const(subclasses[i]); + vs.data = (uint8 *)discard_const(subclasses[i]); vs.length = strlen(subclasses[i]); if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) { return 0; diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index cdc1a500f8..6dc52b2484 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -154,7 +154,8 @@ static LDAPMod **lldb_msg_to_mods(void *mem_ctx, const struct ldb_message *msg, 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_val = + (char *)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; @@ -212,7 +213,8 @@ static int lldb_add_msg_attr(struct ldb_context *ldb, for (i=0;ivalues[i].data = talloc_size(el->values, bval[i]->bv_len+1); + el->values[i].data = + (uint8_t *)talloc_size(el->values, bval[i]->bv_len+1); if (!el->values[i].data) { errno = ENOMEM; return -1; @@ -270,7 +272,9 @@ static int lldb_search(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree); + expression = ldb_filter_from_tree( + lldb_ac, + CONST_DISCARD(struct ldb_parse_tree *, req->op.search.tree)); if (expression == NULL) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index 467f1ac34d..632e22762f 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -60,7 +60,8 @@ static const struct { */ static void ltdb_attributes_unload(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg; int i; @@ -107,7 +108,8 @@ static int ltdb_attributes_flags(struct ldb_message_element *el, unsigned *v) */ static int ltdb_attributes_load(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg = ltdb->cache->attributes; struct ldb_dn *dn; int i; @@ -175,7 +177,8 @@ failed: */ static int ltdb_subclasses_load(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg = ltdb->cache->subclasses; struct ldb_dn *dn; int i, j; @@ -210,7 +213,8 @@ failed: */ static void ltdb_subclasses_unload(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg; int i; @@ -234,7 +238,8 @@ static void ltdb_subclasses_unload(struct ldb_module *module) */ static int ltdb_baseinfo_init(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg; struct ldb_message_element el; struct ldb_val val; @@ -287,7 +292,8 @@ failed: */ static void ltdb_cache_free(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; ltdb->sequence_number = 0; talloc_free(ltdb->cache); @@ -310,11 +316,12 @@ int ltdb_cache_reload(struct ldb_module *module) */ int ltdb_cache_load(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_dn *baseinfo_dn = NULL; struct ldb_dn *indexlist_dn = NULL; uint64_t seq; - struct ldb_message *baseinfo; + struct ldb_message *baseinfo = NULL; /* a very fast check to avoid extra database reads */ if (ltdb->cache != NULL && @@ -416,7 +423,8 @@ failed: */ int ltdb_increase_sequence_number(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; struct ldb_message *msg; struct ldb_message_element el[2]; struct ldb_val val; @@ -493,7 +501,8 @@ int ltdb_increase_sequence_number(struct ldb_module *module) */ int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; const struct ldb_message_element *attr_el; int i, j, ret=0; diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c index c6edf663ae..50dc20524f 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c @@ -114,7 +114,7 @@ int ltdb_pack_data(struct ldb_module *module, } /* allocate it */ - data->dptr = talloc_array(ldb, uint8_t, size); + data->dptr = talloc_array(ldb, char, size); if (!data->dptr) { talloc_free(dn); errno = ENOMEM; @@ -122,7 +122,7 @@ int ltdb_pack_data(struct ldb_module *module, } data->dsize = size; - p = data->dptr; + p = (uint8_t *)data->dptr; put_uint32(p, 0, LTDB_PACKING_FORMAT); put_uint32(p, 4, real_elements); p += 8; @@ -173,7 +173,7 @@ int ltdb_unpack_data(struct ldb_module *module, message->elements = NULL; - p = data->dptr; + p = (uint8_t *)data->dptr; if (data->dsize < 8) { errno = EIO; goto failed; @@ -268,7 +268,7 @@ int ltdb_unpack_data(struct ldb_module *module, } message->elements[i].values[j].length = len; - message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1); + message->elements[i].values[j].data = (uint8_t *)talloc_size(message->elements[i].values, len+1); if (message->elements[i].values[j].data == NULL) { errno = ENOMEM; goto failed; diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index 884eccd362..7a6fe263fd 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -211,7 +211,8 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, */ int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; int ret; TDB_DATA tdb_key, tdb_data; @@ -253,7 +254,8 @@ int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct l */ static int ltdb_lock_read(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; return tdb_lockall_read(ltdb->tdb); } @@ -262,7 +264,8 @@ static int ltdb_lock_read(struct ldb_module *module) */ static int ltdb_unlock_read(struct ldb_module *module) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_private *ltdb = + (struct ltdb_private *)module->private_data; return tdb_unlockall_read(ltdb->tdb); } diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 3f9db39097..232195dfcd 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -150,7 +150,7 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn) goto failed; } - key.dptr = (uint8_t *)key_str; + key.dptr = (char *)key_str; key.dsize = strlen(key_str) + 1; return key; diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c index c9eac013fc..4f3acad9ea 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -59,8 +59,8 @@ static int ltdb_wrap_destructor(struct ltdb_wrap *w) } #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, ...) +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, ...) { /* 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 */ @@ -147,7 +147,9 @@ struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, return NULL; } - w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, log_ctx_p, NULL); + w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, + (const struct tdb_logging_context *)log_ctx_p, + NULL); if (w->tdb == NULL) { talloc_free(w); return NULL; diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c index c327a96f90..555ae5e9f6 100644 --- a/source3/lib/ldb/modules/operational.c +++ b/source3/lib/ldb/modules/operational.c @@ -244,7 +244,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req searchable, but are stored using a different name in the backend */ for (i=0;iop.search.tree, + ldb_parse_tree_attr_replace(CONST_DISCARD(struct ldb_parse_tree *,req->op.search.tree), parse_tree_sub[i].attr, parse_tree_sub[i].replace); } -- cgit From 762b86ff0deb072871081f2684f63778e36ad3ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 28 Nov 2006 17:47:41 +0000 Subject: r19935: always use discard_const_p() in lib/ldb/ metze (This used to be commit 4a5da57306ad8cce5522ee72349cb85b447e295c) --- source3/lib/ldb/common/attrib_handlers.c | 2 +- source3/lib/ldb/include/includes.h | 3 +-- source3/lib/ldb/ldb_ildap/ldb_ildap.c | 5 +++-- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 2 +- source3/lib/ldb/modules/operational.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index a289f3c32a..2b699aeaa8 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -296,7 +296,7 @@ static int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx, } for (i=0;subclasses[i];i++) { struct ldb_val vs; - vs.data = (uint8 *)discard_const(subclasses[i]); + vs.data = discard_const_p(uint8_t, subclasses[i]); vs.length = strlen(subclasses[i]); if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) { return 0; diff --git a/source3/lib/ldb/include/includes.h b/source3/lib/ldb/include/includes.h index ce0d40e101..7a2e112241 100644 --- a/source3/lib/ldb/include/includes.h +++ b/source3/lib/ldb/include/includes.h @@ -18,8 +18,7 @@ -#define discard_const(ptr) ((void *)((intptr_t)(ptr))) -#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) +#define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) #include "replace.h" #include "system/filesys.h" diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 51ae031cf9..87f38b5fc7 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -470,11 +470,12 @@ static int ildb_search(struct ldb_module *module, struct ldb_request *req) 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); + msg->r.SearchRequest.tree = discard_const_p(struct ldb_parse_tree, 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->r.SearchRequest.attributes = discard_const_p(char *, req->op.search.attrs), + msg->controls = req->controls; return ildb_request_send(module, msg, req->context, req->callback, req->timeout, &(req->handle)); diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index 6dc52b2484..c45fa108f2 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -274,7 +274,7 @@ static int lldb_search(struct ldb_module *module, struct ldb_request *req) expression = ldb_filter_from_tree( lldb_ac, - CONST_DISCARD(struct ldb_parse_tree *, req->op.search.tree)); + discard_const_p(struct ldb_parse_tree, req->op.search.tree)); if (expression == NULL) { return LDB_ERR_OPERATIONS_ERROR; } diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c index 555ae5e9f6..953cbd593e 100644 --- a/source3/lib/ldb/modules/operational.c +++ b/source3/lib/ldb/modules/operational.c @@ -244,7 +244,7 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req searchable, but are stored using a different name in the backend */ for (i=0;iop.search.tree), + ldb_parse_tree_attr_replace(discard_const_p(struct ldb_parse_tree, req->op.search.tree), parse_tree_sub[i].attr, parse_tree_sub[i].replace); } -- cgit From 1c2ed583026631b94fc61a63e609eca2ad099bc1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 29 Nov 2006 06:09:24 +0000 Subject: r19942: Fix Coverity id 333, a dereference before a NULL check. Metze, you wanted to port talloc_get_type_abort() to 4. Should I just use it in 3-ldb? Volker (This used to be commit ba0df1c915c49afad629df789375440225968633) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index d7a8e5e9b5..2c88d7e19d 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -721,12 +721,15 @@ static int ltdb_index_filter(const struct dn_list *dn_list, */ int ltdb_search_indexed(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); + struct ltdb_context *ac; + struct ltdb_private *ltdb; struct dn_list *dn_list; int ret; - if ((ac == NULL) || (ltdb == NULL)) { + if (!(ac = talloc_get_type(handle->private_data, + struct ltdb_context)) || + !(ltdb = talloc_get_type(ac->module->private_data, + struct ltdb_private))) { return -1; } -- cgit From 1710dd1fe248ff82613e50ebb97be079e4f31bf4 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 5 Dec 2006 06:25:12 +0000 Subject: r20036: Merge ldb_search_exp_fmt -- Thanks simo (This used to be commit fa6fa1268b33334d17869d0f096cf7600e88f993) --- source3/lib/ldb/common/ldb.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 9e0ee6ebca..512ad84efa 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -794,6 +794,45 @@ done: return ret; } +/* + a useful search function where you can easily define the expression and that + takes a memory context where results are allocated +*/ + +int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result **result, + struct ldb_dn *base, enum ldb_scope scope, const char * const *attrs, + const char *exp_fmt, ...) +{ + struct ldb_result *res; + char *expression; + va_list ap; + int ret; + + res = NULL; + *result = NULL; + + va_start(ap, exp_fmt); + expression = talloc_vasprintf(mem_ctx, exp_fmt, ap); + va_end(ap); + + if ( ! expression) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search(ldb, base, scope, expression, attrs, &res); + + if (ret == LDB_SUCCESS) { + talloc_steal(mem_ctx, res); + *result = res; + } else { + talloc_free(res); + } + + talloc_free(expression); + + return ret; +} + /* add a record to the database. Will fail if a record with the given class and key already exists -- cgit From 91adcd0bae35d178ae8803605a705911de7d093d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 5 Dec 2006 16:20:39 +0000 Subject: r20046: Add ldb_search_exp_fmt and port comment to 4 (This used to be commit 1fe41c96f53b0d83e8779050e2149a5e70b5dad0) --- source3/lib/ldb/include/ldb.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 17a2ec7556..44f9e5f3df 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -989,6 +989,16 @@ int ldb_search(struct ldb_context *ldb, const char *expression, const char * const *attrs, struct ldb_result **res); +/* + * a useful search function where you can easily define the expression and + * that takes a memory context where results are allocated +*/ + +int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + struct ldb_result **result, struct ldb_dn *base, + enum ldb_scope scope, const char * const *attrs, + const char *exp_fmt, ...); + /* like ldb_search() but takes a parse tree */ -- cgit From 8a20dd0ff1b3ba293f311ddfe247953df1728b27 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 6 Dec 2006 11:01:27 +0000 Subject: r20049: Reformatting (This used to be commit 75555ae1c8039b7bbca796dd16609de08230265a) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 106 +++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 39 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 2c88d7e19d..c9a5dc9b05 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -41,7 +41,8 @@ find an element in a list, using the given comparison function and assuming that the list is already sorted using comp_fn - return -1 if not found, or the index of the first occurance of needle if found + return -1 if not found, or the index of the first occurance of needle if + found */ static int ldb_list_find(const void *needle, const void *base, size_t nmemb, size_t size, @@ -128,7 +129,8 @@ static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, if (ldb_should_b64_encode(&v)) { char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length); if (!vstr) return NULL; - dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr); + dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, + vstr); talloc_free(vstr); if (v.data != value->data) { talloc_free(v.data); @@ -138,8 +140,8 @@ static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, goto done; } - dn = talloc_asprintf(ldb, "%s:%s:%.*s", - LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data); + dn = talloc_asprintf(ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, + (int)v.length, (char *)v.data); if (v.data != value->data) { talloc_free(v.data); @@ -164,7 +166,8 @@ static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr, const struct ldb_message_element *el = &msg->elements[i]; for (j=0;jnum_values;j++) { - if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) { + if (ldb_attr_cmp((char *)el->values[j].data, + attr) == 0) { if (v_idx) { *v_idx = j; } @@ -201,7 +204,8 @@ static int ltdb_index_dn_simple(struct ldb_module *module, /* if the attribute isn't in the list of indexed attributes then this node needs a full search */ - if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) { + if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, + LTDB_IDXATTR) == -1) { return -1; } @@ -237,8 +241,8 @@ static int ltdb_index_dn_simple(struct ldb_module *module, } for (j=0;jnum_values;j++) { - list->dn[list->count] = - talloc_strdup(list->dn, (char *)el->values[j].data); + list->dn[list->count] = talloc_strdup( + list->dn, (char *)el->values[j].data); if (!list->dn[list->count]) { talloc_free(msg); return -1; @@ -250,14 +254,16 @@ static int ltdb_index_dn_simple(struct ldb_module *module, talloc_free(msg); if (list->count > 1) { - qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp); + qsort(list->dn, list->count, sizeof(char *), + (comparison_fn_t) list_cmp); } return 1; } -static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *); +static int list_union(struct ldb_context *, struct dn_list *, + const struct dn_list *); /* return a list of dn's that might match a simple indexed search on @@ -329,7 +335,8 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, struct dn_list *list) { if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) { - return ltdb_index_dn_objectclass(module, tree, index_list, list); + return ltdb_index_dn_objectclass(module, tree, index_list, + list); } if (ldb_attr_dn(tree->u.equality.attr) == 0) { list->dn = talloc_array(list, char *, 1); @@ -337,7 +344,8 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, ldb_oom(module->ldb); return -1; } - list->dn[0] = talloc_strdup(list, (char *)tree->u.equality.value.data); + list->dn[0] = talloc_strdup( + list, (char *)tree->u.equality.value.data); if (list->dn[0] == NULL) { ldb_oom(module->ldb); return -1; @@ -380,7 +388,8 @@ static int list_intersect(struct ldb_context *ldb, for (i=0;icount;i++) { if (ldb_list_find(list->dn[i], list2->dn, list2->count, sizeof(char *), (comparison_fn_t)strcmp) != -1) { - list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]); + list3->dn[list3->count] = talloc_move( + list3->dn, &list->dn[i]); list3->count++; } else { talloc_free(list->dn[i]); @@ -422,7 +431,8 @@ static int list_union(struct ldb_context *ldb, for (i=0;icount;i++) { if (ldb_list_find(list2->dn[i], list->dn, count, sizeof(char *), (comparison_fn_t)strcmp) == -1) { - list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]); + list->dn[list->count] = talloc_strdup( + list->dn, list2->dn[i]); if (!list->dn[list->count]) { return -1; } @@ -431,7 +441,8 @@ static int list_union(struct ldb_context *ldb, } if (list->count != count) { - qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp); + qsort(list->dn, list->count, sizeof(char *), + (comparison_fn_t)list_cmp); } return 0; @@ -468,7 +479,8 @@ static int ltdb_index_dn_or(struct ldb_module *module, return -1; } - v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + v = ltdb_index_dn(module, tree->u.list.elements[i], + index_list, list2); if (v == 0) { /* 0 || X == X */ @@ -552,7 +564,8 @@ static int ltdb_index_dn_and(struct ldb_module *module, return -1; } - v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); + v = ltdb_index_dn(module, tree->u.list.elements[i], + index_list, list2); if (v == 0) { /* 0 && X == 0 */ @@ -638,7 +651,8 @@ static int ltdb_index_dn(struct ldb_module *module, static int ltdb_index_filter(const struct dn_list *dn_list, struct ldb_handle *handle) { - struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); + struct ltdb_context *ac = talloc_get_type(handle->private_data, + struct ltdb_context); struct ldb_reply *ares = NULL; unsigned int i; @@ -686,7 +700,8 @@ static int ltdb_index_filter(const struct dn_list *dn_list, return LDB_ERR_OPERATIONS_ERROR; } - if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, + ac->base, ac->scope)) { talloc_free(ares); continue; } @@ -703,7 +718,8 @@ static int ltdb_index_filter(const struct dn_list *dn_list, ares->type = LDB_REPLY_ENTRY; handle->state = LDB_ASYNC_PENDING; - handle->status = ac->callback(ac->module->ldb, ac->context, ares); + handle->status = ac->callback(ac->module->ldb, ac->context, + ares); if (handle->status != LDB_SUCCESS) { handle->state = LDB_ASYNC_DONE; @@ -759,7 +775,8 @@ int ltdb_search_indexed(struct ldb_handle *handle) dn_list->count = 1; ret = 1; } else { - ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list); + ret = ltdb_index_dn(ac->module, ac->tree, + ltdb->cache->indexlist, dn_list); } if (ret == 1) { @@ -787,23 +804,26 @@ static int ltdb_index_add1_new(struct ldb_context *ldb, /* add another entry */ el2 = talloc_realloc(msg, msg->elements, - struct ldb_message_element, msg->num_elements+1); + struct ldb_message_element, msg->num_elements+1); if (!el2) { return -1; } msg->elements = el2; - msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX); + msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, + LTDB_IDX); if (!msg->elements[msg->num_elements].name) { return -1; } msg->elements[msg->num_elements].num_values = 0; - msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val); + msg->elements[msg->num_elements].values = talloc(msg->elements, + struct ldb_val); if (!msg->elements[msg->num_elements].values) { return -1; } msg->elements[msg->num_elements].values[0].length = strlen(dn); - msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn); + msg->elements[msg->num_elements].values[0].data = + discard_const_p(uint8_t, dn); msg->elements[msg->num_elements].num_values = 1; msg->num_elements++; @@ -826,7 +846,8 @@ static int ltdb_index_add1_add(struct ldb_context *ldb, /* for multi-valued attributes we can end up with repeats */ for (i=0;ielements[idx].num_values;i++) { - if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) { + if (strcmp(dn, + (char *)msg->elements[idx].values[i].data) == 0) { return 0; } } @@ -839,8 +860,10 @@ static int ltdb_index_add1_add(struct ldb_context *ldb, } msg->elements[idx].values = v2; - msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn); - msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn); + msg->elements[idx].values[msg->elements[idx].num_values].length = + strlen(dn); + msg->elements[idx].values[msg->elements[idx].num_values].data = + discard_const_p(uint8_t, dn); msg->elements[idx].num_values++; return 0; @@ -923,8 +946,8 @@ static int ltdb_index_add0(struct ldb_module *module, const char *dn, } for (i = 0; i < num_el; i++) { - ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name, - NULL, LTDB_IDXATTR); + ret = ldb_msg_find_idx(ltdb->cache->indexlist, + elements[i].name, NULL, LTDB_IDXATTR); if (ret == -1) { continue; } @@ -997,8 +1020,8 @@ int ltdb_index_del_value(struct ldb_module *module, const char *dn, } if (ret == 0) { - /* it wasn't indexed. Did we have an earlier error? If we did then - its gone now */ + /* it wasn't indexed. Did we have an earlier error? If we did + then its gone now */ talloc_free(dn_key); return 0; } @@ -1060,13 +1083,15 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) } for (i = 0; i < msg->num_elements; i++) { - ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name, - NULL, LTDB_IDXATTR); + ret = ldb_msg_find_idx(ltdb->cache->indexlist, + msg->elements[i].name, NULL, + LTDB_IDXATTR); if (ret == -1) { continue; } for (j = 0; j < msg->elements[i].num_values; j++) { - ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); + ret = ltdb_index_del_value(module, dn, + &msg->elements[i], j); if (ret == -1) { talloc_free(dn); return -1; @@ -1082,7 +1107,8 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) /* traversal function that deletes all @INDEX records */ -static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, + void *state) { const char *dn = "DN=" LTDB_INDEX ":"; if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) { @@ -1094,7 +1120,8 @@ static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, vo /* traversal function that adds @INDEX records during a re index */ -static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) +static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, + void *state) { struct ldb_module *module = (struct ldb_module *)state; struct ldb_message *msg; @@ -1123,8 +1150,9 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void * key2 = ltdb_key(module, msg->dn); if (key2.dptr == NULL) { /* probably a corrupt record ... darn */ - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n", - ldb_dn_linearize(msg, msg->dn)); + ldb_debug(module->ldb, LDB_DEBUG_ERROR, + "Invalid DN in re_index: %s\n", + ldb_dn_linearize(msg, msg->dn)); talloc_free(msg); return 0; } -- cgit From c0d74d11bc205b4fef80f8faa81df2dee5613368 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 6 Dec 2006 11:45:33 +0000 Subject: r20050: Remove a bogus NULL check, LTDB_OBJECTCLASS is a static string (This used to be commit f64866a43fbc21666e919cafdf3002a8e43c60af) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index c9a5dc9b05..e84dac3f90 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -296,9 +296,6 @@ static int ltdb_index_dn_objectclass(struct ldb_module *module, struct dn_list *list2; tree2.operation = LDB_OP_EQUALITY; tree2.u.equality.attr = LTDB_OBJECTCLASS; - if (!tree2.u.equality.attr) { - return -1; - } tree2.u.equality.value.data = (uint8_t *)talloc_strdup(list, subclasses[i]); if (tree2.u.equality.value.data == NULL) { -- cgit From 4a1efb1abe1882173d25dbd6c4ebdbf53521b42c Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 6 Dec 2006 14:40:47 +0000 Subject: r20054: Revert my changes, Simo promised to work on it :-) (This used to be commit 4b5cf0c9cffe9903c86ac7e8b41c303fdbde5bac) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 109 ++++++++++++++---------------------- 1 file changed, 42 insertions(+), 67 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index e84dac3f90..2c88d7e19d 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -41,8 +41,7 @@ find an element in a list, using the given comparison function and assuming that the list is already sorted using comp_fn - return -1 if not found, or the index of the first occurance of needle if - found + return -1 if not found, or the index of the first occurance of needle if found */ static int ldb_list_find(const void *needle, const void *base, size_t nmemb, size_t size, @@ -129,8 +128,7 @@ static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, if (ldb_should_b64_encode(&v)) { char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length); if (!vstr) return NULL; - dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, - vstr); + dn = talloc_asprintf(ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr); talloc_free(vstr); if (v.data != value->data) { talloc_free(v.data); @@ -140,8 +138,8 @@ static struct ldb_dn *ldb_dn_key(struct ldb_context *ldb, goto done; } - dn = talloc_asprintf(ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, - (int)v.length, (char *)v.data); + dn = talloc_asprintf(ldb, "%s:%s:%.*s", + LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data); if (v.data != value->data) { talloc_free(v.data); @@ -166,8 +164,7 @@ static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr, const struct ldb_message_element *el = &msg->elements[i]; for (j=0;jnum_values;j++) { - if (ldb_attr_cmp((char *)el->values[j].data, - attr) == 0) { + if (ldb_attr_cmp((char *)el->values[j].data, attr) == 0) { if (v_idx) { *v_idx = j; } @@ -204,8 +201,7 @@ static int ltdb_index_dn_simple(struct ldb_module *module, /* if the attribute isn't in the list of indexed attributes then this node needs a full search */ - if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, - LTDB_IDXATTR) == -1) { + if (ldb_msg_find_idx(index_list, tree->u.equality.attr, NULL, LTDB_IDXATTR) == -1) { return -1; } @@ -241,8 +237,8 @@ static int ltdb_index_dn_simple(struct ldb_module *module, } for (j=0;jnum_values;j++) { - list->dn[list->count] = talloc_strdup( - list->dn, (char *)el->values[j].data); + list->dn[list->count] = + talloc_strdup(list->dn, (char *)el->values[j].data); if (!list->dn[list->count]) { talloc_free(msg); return -1; @@ -254,16 +250,14 @@ static int ltdb_index_dn_simple(struct ldb_module *module, talloc_free(msg); if (list->count > 1) { - qsort(list->dn, list->count, sizeof(char *), - (comparison_fn_t) list_cmp); + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) list_cmp); } return 1; } -static int list_union(struct ldb_context *, struct dn_list *, - const struct dn_list *); +static int list_union(struct ldb_context *, struct dn_list *, const struct dn_list *); /* return a list of dn's that might match a simple indexed search on @@ -296,6 +290,9 @@ static int ltdb_index_dn_objectclass(struct ldb_module *module, struct dn_list *list2; tree2.operation = LDB_OP_EQUALITY; tree2.u.equality.attr = LTDB_OBJECTCLASS; + if (!tree2.u.equality.attr) { + return -1; + } tree2.u.equality.value.data = (uint8_t *)talloc_strdup(list, subclasses[i]); if (tree2.u.equality.value.data == NULL) { @@ -332,8 +329,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, struct dn_list *list) { if (ldb_attr_cmp(tree->u.equality.attr, LTDB_OBJECTCLASS) == 0) { - return ltdb_index_dn_objectclass(module, tree, index_list, - list); + return ltdb_index_dn_objectclass(module, tree, index_list, list); } if (ldb_attr_dn(tree->u.equality.attr) == 0) { list->dn = talloc_array(list, char *, 1); @@ -341,8 +337,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, ldb_oom(module->ldb); return -1; } - list->dn[0] = talloc_strdup( - list, (char *)tree->u.equality.value.data); + list->dn[0] = talloc_strdup(list, (char *)tree->u.equality.value.data); if (list->dn[0] == NULL) { ldb_oom(module->ldb); return -1; @@ -385,8 +380,7 @@ static int list_intersect(struct ldb_context *ldb, for (i=0;icount;i++) { if (ldb_list_find(list->dn[i], list2->dn, list2->count, sizeof(char *), (comparison_fn_t)strcmp) != -1) { - list3->dn[list3->count] = talloc_move( - list3->dn, &list->dn[i]); + list3->dn[list3->count] = talloc_move(list3->dn, &list->dn[i]); list3->count++; } else { talloc_free(list->dn[i]); @@ -428,8 +422,7 @@ static int list_union(struct ldb_context *ldb, for (i=0;icount;i++) { if (ldb_list_find(list2->dn[i], list->dn, count, sizeof(char *), (comparison_fn_t)strcmp) == -1) { - list->dn[list->count] = talloc_strdup( - list->dn, list2->dn[i]); + list->dn[list->count] = talloc_strdup(list->dn, list2->dn[i]); if (!list->dn[list->count]) { return -1; } @@ -438,8 +431,7 @@ static int list_union(struct ldb_context *ldb, } if (list->count != count) { - qsort(list->dn, list->count, sizeof(char *), - (comparison_fn_t)list_cmp); + qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)list_cmp); } return 0; @@ -476,8 +468,7 @@ static int ltdb_index_dn_or(struct ldb_module *module, return -1; } - v = ltdb_index_dn(module, tree->u.list.elements[i], - index_list, list2); + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); if (v == 0) { /* 0 || X == X */ @@ -561,8 +552,7 @@ static int ltdb_index_dn_and(struct ldb_module *module, return -1; } - v = ltdb_index_dn(module, tree->u.list.elements[i], - index_list, list2); + v = ltdb_index_dn(module, tree->u.list.elements[i], index_list, list2); if (v == 0) { /* 0 && X == 0 */ @@ -648,8 +638,7 @@ static int ltdb_index_dn(struct ldb_module *module, static int ltdb_index_filter(const struct dn_list *dn_list, struct ldb_handle *handle) { - struct ltdb_context *ac = talloc_get_type(handle->private_data, - struct ltdb_context); + struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); struct ldb_reply *ares = NULL; unsigned int i; @@ -697,8 +686,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list, return LDB_ERR_OPERATIONS_ERROR; } - if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, - ac->base, ac->scope)) { + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { talloc_free(ares); continue; } @@ -715,8 +703,7 @@ static int ltdb_index_filter(const struct dn_list *dn_list, ares->type = LDB_REPLY_ENTRY; handle->state = LDB_ASYNC_PENDING; - handle->status = ac->callback(ac->module->ldb, ac->context, - ares); + handle->status = ac->callback(ac->module->ldb, ac->context, ares); if (handle->status != LDB_SUCCESS) { handle->state = LDB_ASYNC_DONE; @@ -772,8 +759,7 @@ int ltdb_search_indexed(struct ldb_handle *handle) dn_list->count = 1; ret = 1; } else { - ret = ltdb_index_dn(ac->module, ac->tree, - ltdb->cache->indexlist, dn_list); + ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list); } if (ret == 1) { @@ -801,26 +787,23 @@ static int ltdb_index_add1_new(struct ldb_context *ldb, /* add another entry */ el2 = talloc_realloc(msg, msg->elements, - struct ldb_message_element, msg->num_elements+1); + struct ldb_message_element, msg->num_elements+1); if (!el2) { return -1; } msg->elements = el2; - msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, - LTDB_IDX); + msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, LTDB_IDX); if (!msg->elements[msg->num_elements].name) { return -1; } msg->elements[msg->num_elements].num_values = 0; - msg->elements[msg->num_elements].values = talloc(msg->elements, - struct ldb_val); + msg->elements[msg->num_elements].values = talloc(msg->elements, struct ldb_val); if (!msg->elements[msg->num_elements].values) { return -1; } msg->elements[msg->num_elements].values[0].length = strlen(dn); - msg->elements[msg->num_elements].values[0].data = - discard_const_p(uint8_t, dn); + msg->elements[msg->num_elements].values[0].data = discard_const_p(uint8_t, dn); msg->elements[msg->num_elements].num_values = 1; msg->num_elements++; @@ -843,8 +826,7 @@ static int ltdb_index_add1_add(struct ldb_context *ldb, /* for multi-valued attributes we can end up with repeats */ for (i=0;ielements[idx].num_values;i++) { - if (strcmp(dn, - (char *)msg->elements[idx].values[i].data) == 0) { + if (strcmp(dn, (char *)msg->elements[idx].values[i].data) == 0) { return 0; } } @@ -857,10 +839,8 @@ static int ltdb_index_add1_add(struct ldb_context *ldb, } msg->elements[idx].values = v2; - msg->elements[idx].values[msg->elements[idx].num_values].length = - strlen(dn); - msg->elements[idx].values[msg->elements[idx].num_values].data = - discard_const_p(uint8_t, dn); + msg->elements[idx].values[msg->elements[idx].num_values].length = strlen(dn); + msg->elements[idx].values[msg->elements[idx].num_values].data = discard_const_p(uint8_t, dn); msg->elements[idx].num_values++; return 0; @@ -943,8 +923,8 @@ static int ltdb_index_add0(struct ldb_module *module, const char *dn, } for (i = 0; i < num_el; i++) { - ret = ldb_msg_find_idx(ltdb->cache->indexlist, - elements[i].name, NULL, LTDB_IDXATTR); + ret = ldb_msg_find_idx(ltdb->cache->indexlist, elements[i].name, + NULL, LTDB_IDXATTR); if (ret == -1) { continue; } @@ -1017,8 +997,8 @@ int ltdb_index_del_value(struct ldb_module *module, const char *dn, } if (ret == 0) { - /* it wasn't indexed. Did we have an earlier error? If we did - then its gone now */ + /* it wasn't indexed. Did we have an earlier error? If we did then + its gone now */ talloc_free(dn_key); return 0; } @@ -1080,15 +1060,13 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) } for (i = 0; i < msg->num_elements; i++) { - ret = ldb_msg_find_idx(ltdb->cache->indexlist, - msg->elements[i].name, NULL, - LTDB_IDXATTR); + ret = ldb_msg_find_idx(ltdb->cache->indexlist, msg->elements[i].name, + NULL, LTDB_IDXATTR); if (ret == -1) { continue; } for (j = 0; j < msg->elements[i].num_values; j++) { - ret = ltdb_index_del_value(module, dn, - &msg->elements[i], j); + ret = ltdb_index_del_value(module, dn, &msg->elements[i], j); if (ret == -1) { talloc_free(dn); return -1; @@ -1104,8 +1082,7 @@ int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg) /* traversal function that deletes all @INDEX records */ -static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *state) +static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) { const char *dn = "DN=" LTDB_INDEX ":"; if (strncmp((char *)key.dptr, dn, strlen(dn)) == 0) { @@ -1117,8 +1094,7 @@ static int delete_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, /* traversal function that adds @INDEX records during a re index */ -static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, - void *state) +static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) { struct ldb_module *module = (struct ldb_module *)state; struct ldb_message *msg; @@ -1147,9 +1123,8 @@ static int re_index(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, key2 = ltdb_key(module, msg->dn); if (key2.dptr == NULL) { /* probably a corrupt record ... darn */ - ldb_debug(module->ldb, LDB_DEBUG_ERROR, - "Invalid DN in re_index: %s\n", - ldb_dn_linearize(msg, msg->dn)); + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Invalid DN in re_index: %s\n", + ldb_dn_linearize(msg, msg->dn)); talloc_free(msg); return 0; } -- cgit From e59e787b4868acffad49b6264e319d585643d5ab Mon Sep 17 00:00:00 2001 From: Herb Lewis Date: Wed, 20 Dec 2006 01:10:04 +0000 Subject: r20269: merge -r20264:20267 from SAMBA_3_0_24 more no previous prototype warnings (This used to be commit 41be182f78762372ae13759ede5d2bd40a71d7f5) --- source3/lib/ldb/common/ldb_msg.c | 4 ++++ source3/lib/ldb/common/ldb_parse.c | 2 ++ source3/lib/ldb/ldb_tdb/ldb_cache.c | 2 ++ source3/lib/ldb/ldb_tdb/ldb_tdb.c | 1 + source3/lib/ldb/modules/paged_results.c | 2 ++ 5 files changed, 11 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index 65d1ecacb7..bf217d2787 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -35,6 +35,10 @@ #include "includes.h" #include "ldb/include/includes.h" +void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f); +int ldb_msg_element_compare_name(struct ldb_message_element *el1, + struct ldb_message_element *el2); + /* create a new ldb_message in a given memory context (NULL for top level) */ diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index 26f88769e6..5c5709f929 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -45,6 +45,8 @@ #include "ldb/include/includes.h" #include "system/locale.h" +struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str); + /* a filter is defined by: ::= '(' ')' diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index 632e22762f..c90885bfab 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -42,6 +42,8 @@ #define LTDB_FLAG_HIDDEN (1<<2) #define LTDB_FLAG_OBJECTCLASS (1<<3) +int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name); + /* valid attribute flags */ static const struct { const char *name; diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 232195dfcd..34daba69bf 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -47,6 +47,7 @@ #include "ldb/ldb_tdb/ldb_tdb.h" +int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg); /* map a tdb error code to a ldb error code diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c index c4b1ecf26b..02d15fe8a6 100644 --- a/source3/lib/ldb/modules/paged_results.c +++ b/source3/lib/ldb/modules/paged_results.c @@ -75,6 +75,8 @@ struct private_data { }; +int store_destructor(struct results_store *store); + int store_destructor(struct results_store *store) { if (store->prev) { -- cgit From 63f43ad5e46b73675a3e3aea9abae2d647c05715 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Feb 2007 12:42:28 +0000 Subject: r21312: merge from SAMBA_4_0: fix memory hierachy, and access to already freed memory metze (This used to be commit 05a23dd75655a80667627e00e0a441b54ec92b22) --- source3/lib/ldb/ldb_tdb/ldb_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 2c88d7e19d..672bc1f625 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -337,7 +337,7 @@ static int ltdb_index_dn_leaf(struct ldb_module *module, ldb_oom(module->ldb); return -1; } - list->dn[0] = talloc_strdup(list, (char *)tree->u.equality.value.data); + list->dn[0] = talloc_strdup(list->dn, (char *)tree->u.equality.value.data); if (list->dn[0] == NULL) { ldb_oom(module->ldb); return -1; -- cgit From bc2b6436d0f5f3e9ffdfaeb7f1b32996a83d5478 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 29 Mar 2007 09:35:51 +0000 Subject: r22009: change TDB_DATA from char * to unsigned char * and fix all compiler warnings in the users metze (This used to be commit 3a28443079c141a6ce8182c65b56ca210e34f37f) --- source3/lib/ldb/ldb_tdb/ldb_pack.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c index 50dc20524f..45fcf354a5 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c @@ -114,7 +114,7 @@ int ltdb_pack_data(struct ldb_module *module, } /* allocate it */ - data->dptr = talloc_array(ldb, char, size); + data->dptr = talloc_array(ldb, uint8_t, size); if (!data->dptr) { talloc_free(dn); errno = ENOMEM; diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 34daba69bf..fead100f72 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -151,7 +151,7 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn) goto failed; } - key.dptr = (char *)key_str; + key.dptr = (uint8_t *)key_str; key.dsize = strlen(key_str) + 1; return key; -- cgit From 8b3ea388bce4faf65a3a1722a456f82686863071 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 15 Apr 2007 21:14:37 +0000 Subject: r22229: discard_const_p is in lib/replace now metze (This used to be commit 8dea4ebe98ec5bdb7fd55b54e9b14a52db817f4f) --- source3/lib/ldb/include/includes.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/include/includes.h b/source3/lib/ldb/include/includes.h index 7a2e112241..e2bcca2b04 100644 --- a/source3/lib/ldb/include/includes.h +++ b/source3/lib/ldb/include/includes.h @@ -16,10 +16,6 @@ #define dyn_MODULESDIR dyn_LIBDIR #endif - - -#define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) - #include "replace.h" #include "system/filesys.h" #include "system/network.h" -- cgit From 9bf4687932853873bae1df460762f3d96c5d332f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Jun 2007 14:25:52 +0000 Subject: r23337: fix a crash bug...I wonder why only HP-UX 11.00 ans 11.11 noticed it via a SIGBUS... I missed to remove the samba3 specifc code path to tdb_open_ex() when I synced lib/tdb/ with samba4. The explicit cast in on tdb_open_ex() dropped the compiler warning :-( metze (This used to be commit 815d2101715d6646fc15ac9f2853cf727cf7fcd8) --- source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c index 4f3acad9ea..03c9ae85b2 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -58,22 +58,6 @@ static int ltdb_wrap_destructor(struct ltdb_wrap *w) return 0; } -#if defined(_SAMBA_BUILD_) && (_SAMBA_BUILD_ <= 3) -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, ...) -{ - /* 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, ...) { @@ -106,7 +90,6 @@ static void ltdb_log_fn(struct tdb_context *tdb, enum tdb_debug_level level, con 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 @@ -122,14 +105,10 @@ struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, { 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) { @@ -147,9 +126,7 @@ struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, return NULL; } - w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, - (const struct tdb_logging_context *)log_ctx_p, - NULL); + w->tdb = tdb_open_ex(path, hash_size, tdb_flags, open_flags, mode, &log_ctx, NULL); if (w->tdb == NULL) { talloc_free(w); return NULL; -- cgit From 422722aad2e50465627a2f7b249c251652297a7b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 6 Jun 2007 13:02:14 +0000 Subject: r23367: check the "use mmap" option for ldb too (This used to be commit 15345bbc73b28d07c069fde33d3d4c1f21f107d3) --- source3/lib/ldb/include/ldb.h | 5 +++++ source3/lib/ldb/ldb_tdb/ldb_tdb.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 44f9e5f3df..f96b90a1b2 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -233,6 +233,11 @@ struct ldb_utf8_fns { */ #define LDB_FLG_RECONNECT 4 +/** + Flag to tell backends not to use mmap +*/ +#define LDB_FLG_NOMMAP 8 + /* structures for ldb_parse_tree handling code */ diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index fead100f72..8b53982fdb 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -1029,6 +1029,11 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, tdb_flags |= TDB_NOSYNC; } + /* and nommap option */ + if (flags & LDB_FLG_NOMMAP) { + tdb_flags |= TDB_NOMMAP; + } + if (flags & LDB_FLG_RDONLY) { open_flags = O_RDONLY; } else { -- cgit From d824b98f80ba186030cbb70b3a1e5daf80469ecd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 9 Jul 2007 19:25:36 +0000 Subject: r23779: Change from v2 or later to v3 or later. Jeremy. (This used to be commit 407e6e695b8366369b7c76af1ff76869b45347b3) --- source3/lib/ldb/include/dlinklist.h | 2 +- source3/lib/ldb/modules/ldb_map.c | 2 +- source3/lib/ldb/modules/ldb_map.h | 2 +- source3/lib/ldb/modules/ldb_map_inbound.c | 2 +- source3/lib/ldb/modules/ldb_map_outbound.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/include/dlinklist.h b/source3/lib/ldb/include/dlinklist.h index 3779a4cc61..7c6efcb117 100644 --- a/source3/lib/ldb/include/dlinklist.h +++ b/source3/lib/ldb/include/dlinklist.h @@ -5,7 +5,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index bbd7b9603d..b4019fdadb 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -10,7 +10,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/source3/lib/ldb/modules/ldb_map.h b/source3/lib/ldb/modules/ldb_map.h index c5c455bcb2..4eb30669a9 100644 --- a/source3/lib/ldb/modules/ldb_map.h +++ b/source3/lib/ldb/modules/ldb_map.h @@ -10,7 +10,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c index 38454b2b11..d00ff3b82f 100644 --- a/source3/lib/ldb/modules/ldb_map_inbound.c +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -10,7 +10,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index 6305e6666f..5807b6a281 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -11,7 +11,7 @@ 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, -- cgit From 2a9b4da0fa00d4ada504f49fafcadab7b0094331 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 9 Jul 2007 19:46:27 +0000 Subject: r23780: Find and fix more GPL2 -> GPL3. Jeremy. (This used to be commit c2f7ab1c175ecff0cf44d0bbc4763ba9f7d7803f) --- source3/lib/ldb/config.guess | 2 +- source3/lib/ldb/config.sub | 2 +- source3/lib/ldb/swig/Ldb.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/config.guess b/source3/lib/ldb/config.guess index ad5281e66e..30af5be004 100755 --- a/source3/lib/ldb/config.guess +++ b/source3/lib/ldb/config.guess @@ -7,7 +7,7 @@ timestamp='2005-08-03' # This file 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 +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but diff --git a/source3/lib/ldb/config.sub b/source3/lib/ldb/config.sub index 1c366dfde9..f0fcaf6361 100755 --- a/source3/lib/ldb/config.sub +++ b/source3/lib/ldb/config.sub @@ -11,7 +11,7 @@ timestamp='2005-07-08' # # This file 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 +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, diff --git a/source3/lib/ldb/swig/Ldb.py b/source3/lib/ldb/swig/Ldb.py index c7e6191c8a..8cc7663cc3 100644 --- a/source3/lib/ldb/swig/Ldb.py +++ b/source3/lib/ldb/swig/Ldb.py @@ -7,7 +7,7 @@ # # 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 +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, -- cgit From 5e54558c6dea67b56bbfaba5698f3a434d3dffb6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 00:52:41 +0000 Subject: r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text (This used to be commit b0132e94fc5fef936aa766fb99a306b3628e9f07) --- source3/lib/ldb/include/dlinklist.h | 3 +-- source3/lib/ldb/modules/ldb_map.c | 3 +-- source3/lib/ldb/modules/ldb_map.h | 3 +-- source3/lib/ldb/modules/ldb_map_inbound.c | 3 +-- source3/lib/ldb/modules/ldb_map_outbound.c | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/include/dlinklist.h b/source3/lib/ldb/include/dlinklist.h index 7c6efcb117..d3252751db 100644 --- a/source3/lib/ldb/include/dlinklist.h +++ b/source3/lib/ldb/include/dlinklist.h @@ -14,8 +14,7 @@ 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. + along with this program. If not, see . */ /* To use these macros you must have a structure containing a next and diff --git a/source3/lib/ldb/modules/ldb_map.c b/source3/lib/ldb/modules/ldb_map.c index b4019fdadb..54e1758c1e 100644 --- a/source3/lib/ldb/modules/ldb_map.c +++ b/source3/lib/ldb/modules/ldb_map.c @@ -19,8 +19,7 @@ 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. + along with this program. If not, see . */ /* diff --git a/source3/lib/ldb/modules/ldb_map.h b/source3/lib/ldb/modules/ldb_map.h index 4eb30669a9..4457c6fc1d 100644 --- a/source3/lib/ldb/modules/ldb_map.h +++ b/source3/lib/ldb/modules/ldb_map.h @@ -19,8 +19,7 @@ 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. + along with this program. If not, see . */ #ifndef __LDB_MAP_H__ diff --git a/source3/lib/ldb/modules/ldb_map_inbound.c b/source3/lib/ldb/modules/ldb_map_inbound.c index d00ff3b82f..0508e724ab 100644 --- a/source3/lib/ldb/modules/ldb_map_inbound.c +++ b/source3/lib/ldb/modules/ldb_map_inbound.c @@ -19,8 +19,7 @@ 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. + along with this program. If not, see . */ #include "includes.h" diff --git a/source3/lib/ldb/modules/ldb_map_outbound.c b/source3/lib/ldb/modules/ldb_map_outbound.c index 5807b6a281..a02d26dcea 100644 --- a/source3/lib/ldb/modules/ldb_map_outbound.c +++ b/source3/lib/ldb/modules/ldb_map_outbound.c @@ -20,8 +20,7 @@ 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. + along with this program. If not, see . */ #include "includes.h" -- cgit From 2c09988e46d4e917b1c53c9bda3f81a48bba4952 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 01:44:42 +0000 Subject: r23790: LGPLv3+ conversion for our LGPLv2+ library code (This used to be commit 1b78cace504f60c0f525765fbf59d9cc6506cd4d) --- source3/lib/ldb/common/attrib_handlers.c | 2 +- source3/lib/ldb/common/ldb.c | 2 +- source3/lib/ldb/common/ldb_attributes.c | 2 +- source3/lib/ldb/common/ldb_controls.c | 2 +- source3/lib/ldb/common/ldb_debug.c | 2 +- source3/lib/ldb/common/ldb_dn.c | 2 +- source3/lib/ldb/common/ldb_ldif.c | 2 +- source3/lib/ldb/common/ldb_match.c | 2 +- source3/lib/ldb/common/ldb_modules.c | 2 +- source3/lib/ldb/common/ldb_msg.c | 2 +- source3/lib/ldb/common/ldb_parse.c | 2 +- source3/lib/ldb/common/ldb_utf8.c | 2 +- source3/lib/ldb/examples/ldbreader.c | 2 +- source3/lib/ldb/examples/ldifreader.c | 2 +- source3/lib/ldb/include/ldb.h | 2 +- source3/lib/ldb/include/ldb_errors.h | 2 +- source3/lib/ldb/include/ldb_private.h | 2 +- source3/lib/ldb/ldb_ildap/ldb_ildap.c | 2 +- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 2 +- source3/lib/ldb/ldb_sqlite3/base160.c | 2 +- source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_cache.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_index.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_pack.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_search.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 2 +- source3/lib/ldb/modules/asq.c | 2 +- source3/lib/ldb/modules/objectclass.c | 2 +- source3/lib/ldb/modules/operational.c | 2 +- source3/lib/ldb/modules/paged_results.c | 2 +- source3/lib/ldb/modules/paged_searches.c | 2 +- source3/lib/ldb/modules/rdn_name.c | 2 +- source3/lib/ldb/modules/skel.c | 2 +- source3/lib/ldb/modules/sort.c | 2 +- source3/lib/ldb/samba/ldif_handlers.c | 2 +- source3/lib/ldb/swig/ldb.i | 2 +- source3/lib/ldb/tools/ad2oLschema.c | 2 +- source3/lib/ldb/tools/cmdline.c | 2 +- source3/lib/ldb/tools/cmdline.h | 2 +- source3/lib/ldb/tools/convert.c | 2 +- source3/lib/ldb/tools/ldbadd.c | 2 +- source3/lib/ldb/tools/ldbdel.c | 2 +- source3/lib/ldb/tools/ldbedit.c | 2 +- source3/lib/ldb/tools/ldbmodify.c | 2 +- source3/lib/ldb/tools/ldbrename.c | 2 +- source3/lib/ldb/tools/ldbsearch.c | 2 +- source3/lib/ldb/tools/ldbtest.c | 2 +- source3/lib/ldb/tools/oLschema2ldif.c | 2 +- 49 files changed, 49 insertions(+), 49 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index 2b699aeaa8..e646a45ae6 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 512ad84efa..8a1003886a 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c index 26c1aac5a5..14131564cc 100644 --- a/source3/lib/ldb/common/ldb_attributes.c +++ b/source3/lib/ldb/common/ldb_attributes.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_controls.c b/source3/lib/ldb/common/ldb_controls.c index d2729c82ab..eb30714049 100644 --- a/source3/lib/ldb/common/ldb_controls.c +++ b/source3/lib/ldb/common/ldb_controls.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_debug.c b/source3/lib/ldb/common/ldb_debug.c index 2548a5495a..b615d5e0f8 100644 --- a/source3/lib/ldb/common/ldb_debug.c +++ b/source3/lib/ldb/common/ldb_debug.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 7a1d8a910b..291fc40e57 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c index 135ce9eecd..e81491f662 100644 --- a/source3/lib/ldb/common/ldb_ldif.c +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c index 0cd220ad60..ca21d6541a 100644 --- a/source3/lib/ldb/common/ldb_match.c +++ b/source3/lib/ldb/common/ldb_match.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index a6997b324a..270c088acd 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index bf217d2787..cd79779ddc 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index 5c5709f929..b574b4f020 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c index 86ed40535a..572cb607fc 100644 --- a/source3/lib/ldb/common/ldb_utf8.c +++ b/source3/lib/ldb/common/ldb_utf8.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/examples/ldbreader.c b/source3/lib/ldb/examples/ldbreader.c index 207c6c3d42..92c3de2ca7 100644 --- a/source3/lib/ldb/examples/ldbreader.c +++ b/source3/lib/ldb/examples/ldbreader.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/examples/ldifreader.c b/source3/lib/ldb/examples/ldifreader.c index 3b8591e73f..3696b05814 100644 --- a/source3/lib/ldb/examples/ldifreader.c +++ b/source3/lib/ldb/examples/ldifreader.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index f96b90a1b2..564f66e2c3 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -12,7 +12,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/include/ldb_errors.h b/source3/lib/ldb/include/ldb_errors.h index 3b04c7c17f..45747948dc 100644 --- a/source3/lib/ldb/include/ldb_errors.h +++ b/source3/lib/ldb/include/ldb_errors.h @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index f4049188ad..4e978822df 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -12,7 +12,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 87f38b5fc7..525d008134 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index c45fa108f2..3aec6633d9 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_sqlite3/base160.c b/source3/lib/ldb/ldb_sqlite3/base160.c index 4286979123..f51ef6ad3e 100644 --- a/source3/lib/ldb/ldb_sqlite3/base160.c +++ b/source3/lib/ldb/ldb_sqlite3/base160.c @@ -6,7 +6,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4f9b0f6370..ec5296dc3d 100644 --- a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index c90885bfab..cc85479f88 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 672bc1f625..379f5a5994 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c index 45fcf354a5..df01dfb438 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index 7a6fe263fd..d4965ed660 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index 8b53982fdb..dd3aba7662 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -13,7 +13,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c index 03c9ae85b2..46de53d54e 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 7d23202303..0b6eb48c08 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c index 191238f9c9..8b6d9fd582 100644 --- a/source3/lib/ldb/modules/objectclass.c +++ b/source3/lib/ldb/modules/objectclass.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c index 953cbd593e..84dff527cb 100644 --- a/source3/lib/ldb/modules/operational.c +++ b/source3/lib/ldb/modules/operational.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c index 02d15fe8a6..16ad85d4c4 100644 --- a/source3/lib/ldb/modules/paged_results.c +++ b/source3/lib/ldb/modules/paged_results.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/paged_searches.c b/source3/lib/ldb/modules/paged_searches.c index c7d163307d..bf17122cfb 100644 --- a/source3/lib/ldb/modules/paged_searches.c +++ b/source3/lib/ldb/modules/paged_searches.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c index bab5f6a014..3277ad002c 100644 --- a/source3/lib/ldb/modules/rdn_name.c +++ b/source3/lib/ldb/modules/rdn_name.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/skel.c b/source3/lib/ldb/modules/skel.c index 2adef580b1..fbf17e091c 100644 --- a/source3/lib/ldb/modules/skel.c +++ b/source3/lib/ldb/modules/skel.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c index 4fa03f8bfa..87545e30e4 100644 --- a/source3/lib/ldb/modules/sort.c +++ b/source3/lib/ldb/modules/sort.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c index 8abfb87238..e34ab517c8 100644 --- a/source3/lib/ldb/samba/ldif_handlers.c +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/swig/ldb.i b/source3/lib/ldb/swig/ldb.i index 09d3461c2a..050f684916 100644 --- a/source3/lib/ldb/swig/ldb.i +++ b/source3/lib/ldb/swig/ldb.i @@ -13,7 +13,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ad2oLschema.c b/source3/lib/ldb/tools/ad2oLschema.c index 62c6e01c2e..afc8419d4e 100644 --- a/source3/lib/ldb/tools/ad2oLschema.c +++ b/source3/lib/ldb/tools/ad2oLschema.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index 8eb7a7e952..6811413dea 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/cmdline.h b/source3/lib/ldb/tools/cmdline.h index 0855f77575..5cf9b3cc3a 100644 --- a/source3/lib/ldb/tools/cmdline.h +++ b/source3/lib/ldb/tools/cmdline.h @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/convert.c b/source3/lib/ldb/tools/convert.c index 2320970030..00760c992f 100644 --- a/source3/lib/ldb/tools/convert.c +++ b/source3/lib/ldb/tools/convert.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c index 9595703e92..004b511caf 100644 --- a/source3/lib/ldb/tools/ldbadd.c +++ b/source3/lib/ldb/tools/ldbadd.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbdel.c b/source3/lib/ldb/tools/ldbdel.c index 94f1da9903..02776b7e20 100644 --- a/source3/lib/ldb/tools/ldbdel.c +++ b/source3/lib/ldb/tools/ldbdel.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbedit.c b/source3/lib/ldb/tools/ldbedit.c index 17ade152b7..3f9a9c73e8 100644 --- a/source3/lib/ldb/tools/ldbedit.c +++ b/source3/lib/ldb/tools/ldbedit.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c index 962045ef7d..f4d5a61acb 100644 --- a/source3/lib/ldb/tools/ldbmodify.c +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbrename.c b/source3/lib/ldb/tools/ldbrename.c index 9c0870721d..f3fc7969e2 100644 --- a/source3/lib/ldb/tools/ldbrename.c +++ b/source3/lib/ldb/tools/ldbrename.c @@ -11,7 +11,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbsearch.c b/source3/lib/ldb/tools/ldbsearch.c index 837dfc9088..b7e2ce7f68 100644 --- a/source3/lib/ldb/tools/ldbsearch.c +++ b/source3/lib/ldb/tools/ldbsearch.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/ldbtest.c b/source3/lib/ldb/tools/ldbtest.c index 6cc8dfe19b..aa185f12b8 100644 --- a/source3/lib/ldb/tools/ldbtest.c +++ b/source3/lib/ldb/tools/ldbtest.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source3/lib/ldb/tools/oLschema2ldif.c b/source3/lib/ldb/tools/oLschema2ldif.c index a9e157e323..74f713e938 100644 --- a/source3/lib/ldb/tools/oLschema2ldif.c +++ b/source3/lib/ldb/tools/oLschema2ldif.c @@ -10,7 +10,7 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -- cgit From fd881dad3fb03888b79cc84f287c093d163475c7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 02:31:50 +0000 Subject: r23794: convert more code from LGPLv2+ to LGPLv3+ (This used to be commit f3df6cd87e1927f41e95af51d750a71278282e15) --- source3/lib/ldb/nssldb/ldb-grp.c | 8 +++----- source3/lib/ldb/nssldb/ldb-nss.c | 8 +++----- source3/lib/ldb/nssldb/ldb-nss.h | 8 +++----- source3/lib/ldb/nssldb/ldb-pwd.c | 8 +++----- 4 files changed, 12 insertions(+), 20 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/nssldb/ldb-grp.c b/source3/lib/ldb/nssldb/ldb-grp.c index f33ec65c55..f8121b25ca 100644 --- a/source3/lib/ldb/nssldb/ldb-grp.c +++ b/source3/lib/ldb/nssldb/ldb-grp.c @@ -6,17 +6,15 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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. + You should have received a copy of the GNU Library General Public License + along with this program. If not, see . */ #include "ldb-nss.h" diff --git a/source3/lib/ldb/nssldb/ldb-nss.c b/source3/lib/ldb/nssldb/ldb-nss.c index 614f6e170f..9f3368118f 100644 --- a/source3/lib/ldb/nssldb/ldb-nss.c +++ b/source3/lib/ldb/nssldb/ldb-nss.c @@ -6,17 +6,15 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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. + You should have received a copy of the GNU Library General Public License + along with this program. If not, see . */ #include "ldb-nss.h" diff --git a/source3/lib/ldb/nssldb/ldb-nss.h b/source3/lib/ldb/nssldb/ldb-nss.h index c780a21e81..64262f486b 100644 --- a/source3/lib/ldb/nssldb/ldb-nss.h +++ b/source3/lib/ldb/nssldb/ldb-nss.h @@ -6,17 +6,15 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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. + You should have received a copy of the GNU Library General Public License + along with this program. If not, see . */ #ifndef _LDB_NSS diff --git a/source3/lib/ldb/nssldb/ldb-pwd.c b/source3/lib/ldb/nssldb/ldb-pwd.c index e4bafdcf7c..1134b9b99d 100644 --- a/source3/lib/ldb/nssldb/ldb-pwd.c +++ b/source3/lib/ldb/nssldb/ldb-pwd.c @@ -6,17 +6,15 @@ 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. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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. + You should have received a copy of the GNU Library General Public License + along with this program. If not, see . */ #include "ldb-nss.h" -- cgit From 9fa1c63578733077c0aaaeeb2fc97c3b191089cc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 03:42:26 +0000 Subject: r23798: updated old Temple Place FSF addresses to new URL (This used to be commit c676a971142d7176fd5dbf21405fca14515a0a76) --- source3/lib/ldb/common/attrib_handlers.c | 3 +-- source3/lib/ldb/common/ldb.c | 3 +-- source3/lib/ldb/common/ldb_attributes.c | 3 +-- source3/lib/ldb/common/ldb_controls.c | 3 +-- source3/lib/ldb/common/ldb_debug.c | 3 +-- source3/lib/ldb/common/ldb_dn.c | 3 +-- source3/lib/ldb/common/ldb_ldif.c | 3 +-- source3/lib/ldb/common/ldb_match.c | 3 +-- source3/lib/ldb/common/ldb_modules.c | 3 +-- source3/lib/ldb/common/ldb_msg.c | 3 +-- source3/lib/ldb/common/ldb_parse.c | 3 +-- source3/lib/ldb/common/ldb_utf8.c | 3 +-- source3/lib/ldb/common/qsort.c | 4 +--- source3/lib/ldb/include/ldb.h | 3 +-- source3/lib/ldb/include/ldb_errors.h | 3 +-- source3/lib/ldb/include/ldb_private.h | 3 +-- source3/lib/ldb/ldb_ildap/ldb_ildap.c | 3 +-- source3/lib/ldb/ldb_ldap/ldb_ldap.c | 3 +-- source3/lib/ldb/ldb_sqlite3/base160.c | 3 +-- source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_cache.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_index.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_pack.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_search.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 3 +-- source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c | 3 +-- source3/lib/ldb/modules/asq.c | 3 +-- source3/lib/ldb/modules/objectclass.c | 3 +-- source3/lib/ldb/modules/operational.c | 3 +-- source3/lib/ldb/modules/paged_results.c | 3 +-- source3/lib/ldb/modules/paged_searches.c | 3 +-- source3/lib/ldb/modules/rdn_name.c | 3 +-- source3/lib/ldb/modules/skel.c | 3 +-- source3/lib/ldb/modules/sort.c | 3 +-- source3/lib/ldb/samba/ldif_handlers.c | 3 +-- source3/lib/ldb/swig/ldb.i | 3 +-- source3/lib/ldb/tools/ad2oLschema.c | 3 +-- source3/lib/ldb/tools/cmdline.c | 3 +-- source3/lib/ldb/tools/cmdline.h | 3 +-- source3/lib/ldb/tools/convert.c | 3 +-- source3/lib/ldb/tools/ldbadd.c | 3 +-- source3/lib/ldb/tools/ldbdel.c | 3 +-- source3/lib/ldb/tools/ldbedit.c | 3 +-- source3/lib/ldb/tools/ldbmodify.c | 3 +-- source3/lib/ldb/tools/ldbrename.c | 3 +-- source3/lib/ldb/tools/ldbsearch.c | 3 +-- source3/lib/ldb/tools/ldbtest.c | 3 +-- source3/lib/ldb/tools/oLschema2ldif.c | 3 +-- 48 files changed, 48 insertions(+), 97 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/attrib_handlers.c b/source3/lib/ldb/common/attrib_handlers.c index e646a45ae6..5f26db6776 100644 --- a/source3/lib/ldb/common/attrib_handlers.c +++ b/source3/lib/ldb/common/attrib_handlers.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* attribute handlers for well known attribute types, selected by syntax OID diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index 8a1003886a..e469c49399 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_attributes.c b/source3/lib/ldb/common/ldb_attributes.c index 14131564cc..5ecbdc7940 100644 --- a/source3/lib/ldb/common/ldb_attributes.c +++ b/source3/lib/ldb/common/ldb_attributes.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* register handlers for specific attributes and objectclass relationships diff --git a/source3/lib/ldb/common/ldb_controls.c b/source3/lib/ldb/common/ldb_controls.c index eb30714049..9b49470941 100644 --- a/source3/lib/ldb/common/ldb_controls.c +++ b/source3/lib/ldb/common/ldb_controls.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_debug.c b/source3/lib/ldb/common/ldb_debug.c index b615d5e0f8..3c9442ea9c 100644 --- a/source3/lib/ldb/common/ldb_debug.c +++ b/source3/lib/ldb/common/ldb_debug.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 291fc40e57..155c48514a 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_ldif.c b/source3/lib/ldb/common/ldb_ldif.c index e81491f662..a6ed1b6055 100644 --- a/source3/lib/ldb/common/ldb_ldif.c +++ b/source3/lib/ldb/common/ldb_ldif.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_match.c b/source3/lib/ldb/common/ldb_match.c index ca21d6541a..066c997cee 100644 --- a/source3/lib/ldb/common/ldb_match.c +++ b/source3/lib/ldb/common/ldb_match.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 270c088acd..c2fec2aea8 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_msg.c b/source3/lib/ldb/common/ldb_msg.c index cd79779ddc..a8a6e93f12 100644 --- a/source3/lib/ldb/common/ldb_msg.c +++ b/source3/lib/ldb/common/ldb_msg.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index b574b4f020..782e8a8863 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c index 572cb607fc..c576453b27 100644 --- a/source3/lib/ldb/common/ldb_utf8.c +++ b/source3/lib/ldb/common/ldb_utf8.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/common/qsort.c b/source3/lib/ldb/common/qsort.c index ef7be2c14e..79dd64128f 100644 --- a/source3/lib/ldb/common/qsort.c +++ b/source3/lib/ldb/common/qsort.c @@ -13,9 +13,7 @@ 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. */ + License along with the GNU C Library; if not, see . */ /* If you consider tuning this algorithm, you should consult first: Engineering a sort function; Jon Bentley and M. Douglas McIlroy; diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 564f66e2c3..0a745742d9 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -20,8 +20,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/include/ldb_errors.h b/source3/lib/ldb/include/ldb_errors.h index 45747948dc..9362233fd5 100644 --- a/source3/lib/ldb/include/ldb_errors.h +++ b/source3/lib/ldb/include/ldb_errors.h @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/include/ldb_private.h b/source3/lib/ldb/include/ldb_private.h index 4e978822df..368a903f2d 100644 --- a/source3/lib/ldb/include/ldb_private.h +++ b/source3/lib/ldb/include/ldb_private.h @@ -20,8 +20,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_ildap/ldb_ildap.c b/source3/lib/ldb/ldb_ildap/ldb_ildap.c index 525d008134..bc0fe66a1a 100644 --- a/source3/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source3/lib/ldb/ldb_ildap/ldb_ildap.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_ldap/ldb_ldap.c b/source3/lib/ldb/ldb_ldap/ldb_ldap.c index 3aec6633d9..51445d651f 100644 --- a/source3/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source3/lib/ldb/ldb_ldap/ldb_ldap.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_sqlite3/base160.c b/source3/lib/ldb/ldb_sqlite3/base160.c index f51ef6ad3e..423e2b6841 100644 --- a/source3/lib/ldb/ldb_sqlite3/base160.c +++ b/source3/lib/ldb/ldb_sqlite3/base160.c @@ -14,8 +14,7 @@ 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 + License along with this library; if not, see . */ diff --git a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index ec5296dc3d..cb516b6e75 100644 --- a/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_cache.c b/source3/lib/ldb/ldb_tdb/ldb_cache.c index cc85479f88..16e8c55aec 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source3/lib/ldb/ldb_tdb/ldb_cache.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_index.c b/source3/lib/ldb/ldb_tdb/ldb_index.c index 379f5a5994..5545661f7a 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_index.c +++ b/source3/lib/ldb/ldb_tdb/ldb_index.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_pack.c b/source3/lib/ldb/ldb_tdb/ldb_pack.c index df01dfb438..3f3d1ccca7 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source3/lib/ldb/ldb_tdb/ldb_pack.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_search.c b/source3/lib/ldb/ldb_tdb/ldb_search.c index d4965ed660..9ef8eb9295 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_search.c +++ b/source3/lib/ldb/ldb_tdb/ldb_search.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index dd3aba7662..cdcfe5a046 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -21,8 +21,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c index 46de53d54e..2fff74d59a 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ #include "includes.h" diff --git a/source3/lib/ldb/modules/asq.c b/source3/lib/ldb/modules/asq.c index 0b6eb48c08..413257f20a 100644 --- a/source3/lib/ldb/modules/asq.c +++ b/source3/lib/ldb/modules/asq.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/objectclass.c b/source3/lib/ldb/modules/objectclass.c index 8b6d9fd582..03e0967f0e 100644 --- a/source3/lib/ldb/modules/objectclass.c +++ b/source3/lib/ldb/modules/objectclass.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/operational.c b/source3/lib/ldb/modules/operational.c index 84dff527cb..7c8e03c337 100644 --- a/source3/lib/ldb/modules/operational.c +++ b/source3/lib/ldb/modules/operational.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* handle operational attributes diff --git a/source3/lib/ldb/modules/paged_results.c b/source3/lib/ldb/modules/paged_results.c index 16ad85d4c4..63f9ee6752 100644 --- a/source3/lib/ldb/modules/paged_results.c +++ b/source3/lib/ldb/modules/paged_results.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/paged_searches.c b/source3/lib/ldb/modules/paged_searches.c index bf17122cfb..99085d2764 100644 --- a/source3/lib/ldb/modules/paged_searches.c +++ b/source3/lib/ldb/modules/paged_searches.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/rdn_name.c b/source3/lib/ldb/modules/rdn_name.c index 3277ad002c..af2d77d41f 100644 --- a/source3/lib/ldb/modules/rdn_name.c +++ b/source3/lib/ldb/modules/rdn_name.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/skel.c b/source3/lib/ldb/modules/skel.c index fbf17e091c..be3cefc84e 100644 --- a/source3/lib/ldb/modules/skel.c +++ b/source3/lib/ldb/modules/skel.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/modules/sort.c b/source3/lib/ldb/modules/sort.c index 87545e30e4..9d82cae544 100644 --- a/source3/lib/ldb/modules/sort.c +++ b/source3/lib/ldb/modules/sort.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/samba/ldif_handlers.c b/source3/lib/ldb/samba/ldif_handlers.c index e34ab517c8..689a668c9e 100644 --- a/source3/lib/ldb/samba/ldif_handlers.c +++ b/source3/lib/ldb/samba/ldif_handlers.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ #include "includes.h" diff --git a/source3/lib/ldb/swig/ldb.i b/source3/lib/ldb/swig/ldb.i index 050f684916..fa460e3d6c 100644 --- a/source3/lib/ldb/swig/ldb.i +++ b/source3/lib/ldb/swig/ldb.i @@ -21,8 +21,7 @@ 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 + License along with this library; if not, see . */ %module ldb diff --git a/source3/lib/ldb/tools/ad2oLschema.c b/source3/lib/ldb/tools/ad2oLschema.c index afc8419d4e..fc51cb12d8 100644 --- a/source3/lib/ldb/tools/ad2oLschema.c +++ b/source3/lib/ldb/tools/ad2oLschema.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/cmdline.c b/source3/lib/ldb/tools/cmdline.c index 6811413dea..4744ab4989 100644 --- a/source3/lib/ldb/tools/cmdline.c +++ b/source3/lib/ldb/tools/cmdline.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ #include "includes.h" diff --git a/source3/lib/ldb/tools/cmdline.h b/source3/lib/ldb/tools/cmdline.h index 5cf9b3cc3a..ae295d68a4 100644 --- a/source3/lib/ldb/tools/cmdline.h +++ b/source3/lib/ldb/tools/cmdline.h @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ #include diff --git a/source3/lib/ldb/tools/convert.c b/source3/lib/ldb/tools/convert.c index 00760c992f..879ff697c8 100644 --- a/source3/lib/ldb/tools/convert.c +++ b/source3/lib/ldb/tools/convert.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ #include "convert.h" diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c index 004b511caf..4dde2a1ef5 100644 --- a/source3/lib/ldb/tools/ldbadd.c +++ b/source3/lib/ldb/tools/ldbadd.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbdel.c b/source3/lib/ldb/tools/ldbdel.c index 02776b7e20..a6d32f422f 100644 --- a/source3/lib/ldb/tools/ldbdel.c +++ b/source3/lib/ldb/tools/ldbdel.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbedit.c b/source3/lib/ldb/tools/ldbedit.c index 3f9a9c73e8..f8d180495b 100644 --- a/source3/lib/ldb/tools/ldbedit.c +++ b/source3/lib/ldb/tools/ldbedit.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c index f4d5a61acb..368b4cf996 100644 --- a/source3/lib/ldb/tools/ldbmodify.c +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbrename.c b/source3/lib/ldb/tools/ldbrename.c index f3fc7969e2..d6c3a4ab62 100644 --- a/source3/lib/ldb/tools/ldbrename.c +++ b/source3/lib/ldb/tools/ldbrename.c @@ -19,8 +19,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbsearch.c b/source3/lib/ldb/tools/ldbsearch.c index b7e2ce7f68..e5cec0fa66 100644 --- a/source3/lib/ldb/tools/ldbsearch.c +++ b/source3/lib/ldb/tools/ldbsearch.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/ldbtest.c b/source3/lib/ldb/tools/ldbtest.c index aa185f12b8..b7fa874ad3 100644 --- a/source3/lib/ldb/tools/ldbtest.c +++ b/source3/lib/ldb/tools/ldbtest.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* diff --git a/source3/lib/ldb/tools/oLschema2ldif.c b/source3/lib/ldb/tools/oLschema2ldif.c index 74f713e938..c31c258759 100644 --- a/source3/lib/ldb/tools/oLschema2ldif.c +++ b/source3/lib/ldb/tools/oLschema2ldif.c @@ -18,8 +18,7 @@ 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 + License along with this library; if not, see . */ /* -- cgit From 674b835241c53af7d31af402bd900e95ac83fcca Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 03:52:17 +0000 Subject: r23799: updated old Franklin Street FSF addresses to new URL (This used to be commit 43cd589773148fe3d243892768ce187604dd0c33) --- source3/lib/ldb/config.guess | 4 +--- source3/lib/ldb/config.sub | 4 +--- source3/lib/ldb/examples/ldbreader.c | 4 +--- source3/lib/ldb/examples/ldifreader.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/config.guess b/source3/lib/ldb/config.guess index 30af5be004..354dbe175a 100755 --- a/source3/lib/ldb/config.guess +++ b/source3/lib/ldb/config.guess @@ -16,9 +16,7 @@ timestamp='2005-08-03' # 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., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a diff --git a/source3/lib/ldb/config.sub b/source3/lib/ldb/config.sub index f0fcaf6361..23cd6fd75c 100755 --- a/source3/lib/ldb/config.sub +++ b/source3/lib/ldb/config.sub @@ -20,9 +20,7 @@ timestamp='2005-07-08' # 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., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a diff --git a/source3/lib/ldb/examples/ldbreader.c b/source3/lib/ldb/examples/ldbreader.c index 92c3de2ca7..baf0e9ab65 100644 --- a/source3/lib/ldb/examples/ldbreader.c +++ b/source3/lib/ldb/examples/ldbreader.c @@ -18,9 +18,7 @@ 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 + License along with this library; if not, see . */ /** \example ldbreader.c diff --git a/source3/lib/ldb/examples/ldifreader.c b/source3/lib/ldb/examples/ldifreader.c index 3696b05814..0c7e876465 100644 --- a/source3/lib/ldb/examples/ldifreader.c +++ b/source3/lib/ldb/examples/ldifreader.c @@ -18,9 +18,7 @@ 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 + License along with this library; if not, see . */ /** \example ldifreader.c -- cgit From 28b9d61076912adbc0c6571c71688aa6831506bf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 04:04:46 +0000 Subject: r23800: LGPL is now called GNU Lesser General Public License not GNU Library General Public License (This used to be commit 727a6cf2cba8da6b40610409b264e86e6908eb0c) --- source3/lib/ldb/nssldb/ldb-grp.c | 4 ++-- source3/lib/ldb/nssldb/ldb-nss.c | 4 ++-- source3/lib/ldb/nssldb/ldb-nss.h | 4 ++-- source3/lib/ldb/nssldb/ldb-pwd.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/nssldb/ldb-grp.c b/source3/lib/ldb/nssldb/ldb-grp.c index f8121b25ca..71e27a9161 100644 --- a/source3/lib/ldb/nssldb/ldb-grp.c +++ b/source3/lib/ldb/nssldb/ldb-grp.c @@ -4,7 +4,7 @@ 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 + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ 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 + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ diff --git a/source3/lib/ldb/nssldb/ldb-nss.c b/source3/lib/ldb/nssldb/ldb-nss.c index 9f3368118f..0e5850eab3 100644 --- a/source3/lib/ldb/nssldb/ldb-nss.c +++ b/source3/lib/ldb/nssldb/ldb-nss.c @@ -4,7 +4,7 @@ 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 + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ 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 + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ diff --git a/source3/lib/ldb/nssldb/ldb-nss.h b/source3/lib/ldb/nssldb/ldb-nss.h index 64262f486b..1b1866abb9 100644 --- a/source3/lib/ldb/nssldb/ldb-nss.h +++ b/source3/lib/ldb/nssldb/ldb-nss.h @@ -4,7 +4,7 @@ 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 + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ 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 + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ diff --git a/source3/lib/ldb/nssldb/ldb-pwd.c b/source3/lib/ldb/nssldb/ldb-pwd.c index 1134b9b99d..44b0ab21ee 100644 --- a/source3/lib/ldb/nssldb/ldb-pwd.c +++ b/source3/lib/ldb/nssldb/ldb-pwd.c @@ -4,7 +4,7 @@ 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 + modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -13,7 +13,7 @@ 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 + You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ -- cgit From 153cfb9c83534b09f15cc16205d7adb19b394928 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 05:23:25 +0000 Subject: r23801: The FSF has moved around a lot. This fixes their Mass Ave address. (This used to be commit 87c91e4362c51819032bfbebbb273c52e203b227) --- source3/lib/ldb/swig/Ldb.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/swig/Ldb.py b/source3/lib/ldb/swig/Ldb.py index 8cc7663cc3..4be3eec704 100644 --- a/source3/lib/ldb/swig/Ldb.py +++ b/source3/lib/ldb/swig/Ldb.py @@ -16,8 +16,7 @@ # 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. +# along with this program; if not, see . # # -- cgit From d4bfafa29c62c69b002b1ca9f527c51c00fd3fd6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 26 Nov 2007 15:28:13 +0100 Subject: Fix bug 5055 (This used to be commit 8bcd2df841bae63e7d58c35d4728b7d853471697) --- source3/lib/ldb/common/ldb_dn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_dn.c b/source3/lib/ldb/common/ldb_dn.c index 155c48514a..7ef3c38024 100644 --- a/source3/lib/ldb/common/ldb_dn.c +++ b/source3/lib/ldb/common/ldb_dn.c @@ -26,7 +26,7 @@ * * Component: ldb dn explode and utility functions * - * Description: - explode a dn into it's own basic elements + * Description: - explode a dn into its own basic elements * and put them in a structure * - manipulate ldb_dn structures * -- cgit From 7faee02d0d351c5c039e8f1be7e82ce3a93cbe96 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 10 Dec 2007 11:30:37 -0800 Subject: Remove the char[1024] strings from dynconfig. Replace them with malloc'ing accessor functions. Should save a lot of static space :-). Jeremy. (This used to be commit 52dc5eaef2106015b3a8b659e818bdb15ad94b05) --- source3/lib/ldb/common/ldb_modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index c2fec2aea8..68c4535e4d 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -212,7 +212,7 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH")); } else { #ifdef _SAMBA_BUILD_ - modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR); + modulesdir = talloc_asprintf(ldb, "%s/ldb", get_dyn_LIBDIR()); #else modulesdir = talloc_strdup(ldb, MODULESDIR); #endif -- cgit From 4f4f1dfbb6b66c13de32bdc78fc13c030f10d71d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 21 Mar 2008 11:52:34 +0100 Subject: Fix Coverity ID 473 Simo, S4 also has this bug, you might want to merge the fix. (This used to be commit b82cf75c825298444781697072d83a163c43df4b) --- source3/lib/ldb/ldb_tdb/ldb_tdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/ldb_tdb/ldb_tdb.c b/source3/lib/ldb/ldb_tdb/ldb_tdb.c index cdcfe5a046..27cc0c69c6 100644 --- a/source3/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source3/lib/ldb/ldb_tdb/ldb_tdb.c @@ -1058,7 +1058,7 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, ltdb->sequence_number = 0; *module = talloc(ldb, struct ldb_module); - if (!module) { + if ((*module) == NULL) { ldb_oom(ldb); talloc_free(ltdb); return -1; -- cgit From 3d28e7533f4513643762de5768f44b63033bca27 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 23 Mar 2008 18:08:13 +0100 Subject: Fix Coverity ID 472 Simo, S4 also has this code. You might want to cherry-pick. Volker (This used to be commit 94c29f55937e50dcf49124d28ad4e82c7fb4133e) --- source3/lib/ldb/tools/ldbedit.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/tools/ldbedit.c b/source3/lib/ldb/tools/ldbedit.c index f8d180495b..0e1fd38e4c 100644 --- a/source3/lib/ldb/tools/ldbedit.c +++ b/source3/lib/ldb/tools/ldbedit.c @@ -319,12 +319,10 @@ int main(int argc, const char **argv) do_edit(ldb, result->msgs, result->count, options->editor); - if (result) { - ret = talloc_free(result); - if (ret == -1) { - fprintf(stderr, "talloc_free failed\n"); - exit(1); - } + ret = talloc_free(result); + if (ret == -1) { + fprintf(stderr, "talloc_free failed\n"); + exit(1); } talloc_free(ldb); -- cgit From 1bc1b1ac0af4baef266e3f9ea9adb7d8d252cc03 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 13 Jun 2008 16:05:31 +0200 Subject: Fix a handle leak for error returns in ldb_try_load_dso Coverity ID 464 (cherry picked from commit 496d44d2f21661c85bf07e8eb7cae6298fefd900) (This used to be commit f30bc6503de6c712101e04fe26c004eeffcd300e) --- source3/lib/ldb/common/ldb_modules.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 68c4535e4d..d898f3df03 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -206,6 +206,7 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) void *handle; int (*init_fn) (void); char *modulesdir; + int ret; #ifdef HAVE_DLOPEN if (getenv("LD_LDB_MODULE_PATH") != NULL) { @@ -234,12 +235,17 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) if (init_fn == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror()); + dlclose(handle); return -1; } talloc_free(path); - return init_fn(); + ret = init_fn(); + if (ret == -1) { + dlclose(handle); + } + return ret; #else ldb_debug(ldb, LDB_DEBUG_TRACE, "no dlopen() - not trying to load %s module\n", name); return -1; -- cgit From 3cf5395ad56bc32974de9f7284e9584825df2704 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 20 Jun 2008 14:30:02 +0200 Subject: Use "init_shared_module" instead of "init_module" for initializing .so's (This used to be commit 0c2fd687b25e32d446ef799927db6933bc61223d) --- source3/lib/ldb/common/ldb_modules.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index d898f3df03..71a0220501 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -231,10 +231,12 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) return -1; } - init_fn = (int (*)(void))dlsym(handle, "init_module"); + init_fn = (int (*)(void))dlsym(handle, "init_shared_module"); if (init_fn == NULL) { - ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror()); + ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol " + "`init_shared_module' found in %s: %s\n", path, + dlerror()); dlclose(handle); return -1; } -- cgit From 993d80fd22b7c0a6e2eec5ab899f51e077c529cb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 23 Jun 2008 07:14:46 +0200 Subject: init_shared_module -> init_samba_module (This used to be commit 9b174871a87677f7dfbd897a80e526f203906bea) --- source3/lib/ldb/common/ldb_modules.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_modules.c b/source3/lib/ldb/common/ldb_modules.c index 71a0220501..fa7f685d97 100644 --- a/source3/lib/ldb/common/ldb_modules.c +++ b/source3/lib/ldb/common/ldb_modules.c @@ -231,11 +231,11 @@ int ldb_try_load_dso(struct ldb_context *ldb, const char *name) return -1; } - init_fn = (int (*)(void))dlsym(handle, "init_shared_module"); + init_fn = (int (*)(void))dlsym(handle, "init_samba_module"); if (init_fn == NULL) { ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol " - "`init_shared_module' found in %s: %s\n", path, + "`init_samba_module' found in %s: %s\n", path, dlerror()); dlclose(handle); return -1; -- cgit From df1554192683aacc518c4a95715089d4eab51192 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Mon, 14 Jul 2008 16:40:36 +0200 Subject: Fix typo. retieve -> retrieve Karolin (This used to be commit 37c64130701ab13b6f34998ac17fec2d128c2e08) --- source3/lib/ldb/common/ldb_parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb_parse.c b/source3/lib/ldb/common/ldb_parse.c index 782e8a8863..bcc92c5b5c 100644 --- a/source3/lib/ldb/common/ldb_parse.c +++ b/source3/lib/ldb/common/ldb_parse.c @@ -322,7 +322,7 @@ static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char * while (isspace((unsigned char)*p)) p++; - /* retieve value */ + /* retrieve value */ t = p; while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++; -- cgit From dee5f093570a6586f4cf6d9dec4b002c33160862 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Wed, 27 Aug 2008 13:23:20 +0200 Subject: ldb: Fix permissions of new ldg files. This one fixes together with 2eaf4ed62 bug #5715 and CVE-2008-3789. Thanks to Steve Langasek for reporting! Karolin (cherry picked from commit b666d0a4b597218f5f5020bf36d80d84dcbf7259) (This used to be commit 73f54df7fedc8f0db022f902100fd5eb1b629fb2) --- source3/lib/ldb/common/ldb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c index e469c49399..743711b967 100644 --- a/source3/lib/ldb/common/ldb.c +++ b/source3/lib/ldb/common/ldb.c @@ -51,7 +51,7 @@ struct ldb_context *ldb_init(void *mem_ctx) } ldb_set_utf8_default(ldb); - ldb_set_create_perms(ldb, 0666); + ldb_set_create_perms(ldb, 0600); return ldb; } -- cgit From 79297bc1326a6231ea465a6344717d525595cc22 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 25 Feb 2008 14:03:07 -0500 Subject: Update homepages for talloc, tdb and ldb subprojects (cherry picked from commit 8cb07814bc6627fc8eba228eafd13336e3ca3758) (This used to be commit 7d85b8d076d6b5b1773c44cd527e016b5d319da5) --- source3/lib/ldb/web/index.html | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'source3/lib/ldb') diff --git a/source3/lib/ldb/web/index.html b/source3/lib/ldb/web/index.html index 2715a0d8bd..4c569caa25 100644 --- a/source3/lib/ldb/web/index.html +++ b/source3/lib/ldb/web/index.html @@ -41,9 +41,9 @@ The main features that separate ldb from other solutions are: Currently ldb is completely lacking in programmer or user documentation. This is your opportunity to make a contribution! Start with the public functions declared in ldb.h +href="http://samba.org/ftp/unpacked/ldb/include/ldb.h">ldb.h and the example code in the tools +href="http://samba.org/ftp/unpacked/ldb/tools/">tools directory. Documentation in the same docbook format used by Samba would be preferred. @@ -52,21 +52,17 @@ would be preferred. ldb does not currently have its own mailing list or bug tracking system. For now, please use the samba-technical -mailing list, and the Samba -bugzilla bug tracking system. +mailing list or the ldb +mailing list, and the Samba bugzilla bug tracking system.

Download

-You can download the latest release either via rsync or anonymous -svn. To fetch via svn use the following commands: - -
-  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
-  svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/replace libreplace
-
- +You can download the latest release either via rsync or thtough git.
+
+To fetch via git see the following guide:
+Using Git for Samba Development
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/ldb directory.
+
To fetch via rsync use these commands:
-- 
cgit