r18866: Jeremy and Volker have given the go-ahead on the group mapping ldb
authorAndrew Tridgell <tridge@samba.org>
Sun, 24 Sep 2006 02:49:04 +0000 (02:49 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:14:36 +0000 (12:14 -0500)
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)

126 files changed:
source3/lib/ldb/Doxyfile [new file with mode: 0644]
source3/lib/ldb/Makefile.in [new file with mode: 0644]
source3/lib/ldb/README_gcov.txt [new file with mode: 0644]
source3/lib/ldb/aclocal.m4 [new file with mode: 0644]
source3/lib/ldb/autogen.sh [new file with mode: 0755]
source3/lib/ldb/common/attrib_handlers.c [new file with mode: 0644]
source3/lib/ldb/common/ldb.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_attributes.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_controls.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_debug.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_dn.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_ldif.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_match.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_modules.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_msg.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_parse.c [new file with mode: 0644]
source3/lib/ldb/common/ldb_utf8.c [new file with mode: 0644]
source3/lib/ldb/common/qsort.c [new file with mode: 0644]
source3/lib/ldb/config.guess [new file with mode: 0755]
source3/lib/ldb/config.mk [new file with mode: 0644]
source3/lib/ldb/config.sub [new file with mode: 0755]
source3/lib/ldb/configure.ac [new file with mode: 0644]
source3/lib/ldb/docs/builddocs.sh [new file with mode: 0755]
source3/lib/ldb/docs/design.txt [new file with mode: 0644]
source3/lib/ldb/docs/installdocs.sh [new file with mode: 0755]
source3/lib/ldb/examples.dox [new file with mode: 0644]
source3/lib/ldb/examples/ldbreader.c [new file with mode: 0644]
source3/lib/ldb/examples/ldifreader.c [new file with mode: 0644]
source3/lib/ldb/include/dlinklist.h [new file with mode: 0644]
source3/lib/ldb/include/includes.h [new file with mode: 0644]
source3/lib/ldb/include/ldb.h [new file with mode: 0644]
source3/lib/ldb/include/ldb_errors.h [new file with mode: 0644]
source3/lib/ldb/include/ldb_private.h [new file with mode: 0644]
source3/lib/ldb/install-sh [new file with mode: 0755]
source3/lib/ldb/ldap.m4 [new file with mode: 0644]
source3/lib/ldb/ldb.pc.in [new file with mode: 0644]
source3/lib/ldb/ldb_ildap/ldb_ildap.c [new file with mode: 0644]
source3/lib/ldb/ldb_ldap/ldb_ldap.c [new file with mode: 0644]
source3/lib/ldb/ldb_sqlite3/README [new file with mode: 0644]
source3/lib/ldb/ldb_sqlite3/base160.c [new file with mode: 0644]
source3/lib/ldb/ldb_sqlite3/ldb_sqlite3.c [new file with mode: 0644]
source3/lib/ldb/ldb_sqlite3/schema [new file with mode: 0644]
source3/lib/ldb/ldb_sqlite3/trees.ps [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_cache.c [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_index.c [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_pack.c [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_search.c [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_tdb.c [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_tdb.h [new file with mode: 0644]
source3/lib/ldb/ldb_tdb/ldb_tdb_wrap.c [new file with mode: 0644]
source3/lib/ldb/libldb.m4 [new file with mode: 0644]
source3/lib/ldb/mainpage.dox [new file with mode: 0644]
source3/lib/ldb/man/ad2oLschema.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldb.3.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbadd.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbdel.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbedit.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbmodify.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbrename.1.xml [new file with mode: 0644]
source3/lib/ldb/man/ldbsearch.1.xml [new file with mode: 0644]
source3/lib/ldb/man/oLschema2ldif.1.xml [new file with mode: 0644]
source3/lib/ldb/modules/asq.c [new file with mode: 0644]
source3/lib/ldb/modules/ldb_map.c [new file with mode: 0644]
source3/lib/ldb/modules/ldb_map.h [new file with mode: 0644]
source3/lib/ldb/modules/ldb_map_inbound.c [new file with mode: 0644]
source3/lib/ldb/modules/ldb_map_outbound.c [new file with mode: 0644]
source3/lib/ldb/modules/ldb_map_private.h [new file with mode: 0644]
source3/lib/ldb/modules/objectclass.c [new file with mode: 0644]
source3/lib/ldb/modules/operational.c [new file with mode: 0644]
source3/lib/ldb/modules/paged_results.c [new file with mode: 0644]
source3/lib/ldb/modules/paged_searches.c [new file with mode: 0644]
source3/lib/ldb/modules/rdn_name.c [new file with mode: 0644]
source3/lib/ldb/modules/schema.c [new file with mode: 0644]
source3/lib/ldb/modules/skel.c [new file with mode: 0644]
source3/lib/ldb/modules/sort.c [new file with mode: 0644]
source3/lib/ldb/samba/README [new file with mode: 0644]
source3/lib/ldb/samba/ldif_handlers.c [new file with mode: 0644]
source3/lib/ldb/sqlite3.m4 [new file with mode: 0644]
source3/lib/ldb/swig/Ldb.py [new file with mode: 0644]
source3/lib/ldb/swig/ldb.i [new file with mode: 0644]
source3/lib/ldb/tests/init.ldif [new file with mode: 0644]
source3/lib/ldb/tests/init_slapd.sh [new file with mode: 0755]
source3/lib/ldb/tests/kill_slapd.sh [new file with mode: 0755]
source3/lib/ldb/tests/ldapi_url.sh [new file with mode: 0755]
source3/lib/ldb/tests/photo.ldif [new file with mode: 0644]
source3/lib/ldb/tests/samba4.png [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-add-test.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-mod-test-1.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-mod-test-2.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-mod-test-3.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-mod-test-4.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema-mod-test-5.ldif [new file with mode: 0644]
source3/lib/ldb/tests/schema-tests/schema.ldif [new file with mode: 0644]
source3/lib/ldb/tests/slapd.conf [new file with mode: 0644]
source3/lib/ldb/tests/start_slapd.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-attribs.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-config.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-default-config.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-extended.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-generic.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-index.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-ldap.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-modify.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-schema.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-sqlite3.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-tdb-features.sh [new file with mode: 0644]
source3/lib/ldb/tests/test-tdb.sh [new file with mode: 0755]
source3/lib/ldb/tests/test-wildcard.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test-wrong_attributes.ldif [new file with mode: 0644]
source3/lib/ldb/tests/test.ldif [new file with mode: 0644]
source3/lib/ldb/tests/testdata.txt [new file with mode: 0644]
source3/lib/ldb/tests/testsearch.txt [new file with mode: 0644]
source3/lib/ldb/tools/ad2oLschema.c [new file with mode: 0644]
source3/lib/ldb/tools/cmdline.c [new file with mode: 0644]
source3/lib/ldb/tools/cmdline.h [new file with mode: 0644]
source3/lib/ldb/tools/convert.c [new file with mode: 0644]
source3/lib/ldb/tools/convert.h [new file with mode: 0644]
source3/lib/ldb/tools/ldbadd.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbdel.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbedit.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbmodify.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbrename.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbsearch.c [new file with mode: 0644]
source3/lib/ldb/tools/ldbtest.c [new file with mode: 0644]
source3/lib/ldb/tools/oLschema2ldif.c [new file with mode: 0644]
source3/lib/ldb/web/index.html [new file with mode: 0644]

diff --git a/source3/lib/ldb/Doxyfile b/source3/lib/ldb/Doxyfile
new file mode 100644 (file)
index 0000000..07b12b5
--- /dev/null
@@ -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 (file)
index 0000000..106e493
--- /dev/null
@@ -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 (file)
index 0000000..2abd937
--- /dev/null
@@ -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 (file)
index 0000000..5605e47
--- /dev/null
@@ -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 (executable)
index 0000000..500cab8
--- /dev/null
@@ -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 (file)
index 0000000..8e43796
--- /dev/null
@@ -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;i<num_handlers;i++) {
+               if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
+                       return &ldb_standard_attribs[i];
+               }
+       }
+       return NULL;
+}
+
diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c
new file mode 100644 (file)
index 0000000..760a311
--- /dev/null
@@ -0,0 +1,1075 @@
+/* 
+   ldb database library
+
+   Copyright (C) Andrew Tridgell  2004
+   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: ldb
+ *
+ *  Component: ldb core API
+ *
+ *  Description: core API routines interfacing to ldb backends
+ *
+ *  Author: Andrew Tridgell
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/* 
+   initialise a ldb context
+   The mem_ctx is optional
+*/
+struct ldb_context *ldb_init(void *mem_ctx)
+{
+       struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context);
+       int ret;
+
+       ret = ldb_setup_wellknown_attributes(ldb);
+       if (ret != 0) {
+               talloc_free(ldb);
+               return NULL;
+       }
+
+       ldb_set_utf8_default(ldb);
+
+       return ldb;
+}
+
+static struct ldb_backend {
+       const char *name;
+       ldb_connect_fn connect_fn;
+       struct ldb_backend *prev, *next;
+} *ldb_backends = NULL;
+
+
+static ldb_connect_fn ldb_find_backend(const char *url)
+{
+       struct ldb_backend *backend;
+
+       for (backend = ldb_backends; backend; backend = backend->next) {
+               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 (file)
index 0000000..c8a7909
--- /dev/null
@@ -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;i<ldb->schema.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;i<ARRAY_SIZE(wellknown);i++) {
+               if (ldb_set_attrib_handler_syntax(ldb, wellknown[i].attr, 
+                                                 wellknown[i].syntax) != 0) {
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+
+/*
+  return the list of subclasses for a class
+*/
+const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname)
+{
+       int i;
+       for (i=0;i<ldb->schema.num_classes;i++) {
+               if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+                       return (const char **)ldb->schema.classes[i].subclasses;
+               }
+       }
+       return NULL;
+}
+
+
+/*
+  add a new subclass
+*/
+static int ldb_subclass_new(struct ldb_context *ldb, const char *classname, const char *subclass)
+{
+       struct ldb_subclass *s, *c;
+       s = talloc_realloc(ldb, ldb->schema.classes, struct ldb_subclass, ldb->schema.num_classes+1);
+       if (s == NULL) goto failed;
+
+       ldb->schema.classes = s;
+       c = &s[ldb->schema.num_classes];
+       c->name = talloc_strdup(s, classname);
+       if (c->name == NULL) goto failed;
+
+       c->subclasses = talloc_array(s, char *, 2);
+       if (c->subclasses == NULL) goto failed;
+
+       c->subclasses[0] = talloc_strdup(c->subclasses, subclass);
+       if (c->subclasses[0] == NULL) goto failed;
+       c->subclasses[1] = NULL;
+
+       ldb->schema.num_classes++;
+
+       return 0;
+failed:
+       ldb_oom(ldb);
+       return -1;
+}
+
+/*
+  add a subclass
+*/
+int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass)
+{
+       int i, n;
+       struct ldb_subclass *c;
+       char **s;
+
+       for (i=0;i<ldb->schema.num_classes;i++) {
+               if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+                       break;
+               }
+       }
+       if (i == ldb->schema.num_classes) {
+               return ldb_subclass_new(ldb, classname, subclass);
+       }
+       c = &ldb->schema.classes[i];
+       
+       for (n=0;c->subclasses[n];n++) /* noop */;
+
+       s = talloc_realloc(ldb->schema.classes, c->subclasses, char *, n+2);
+       if (s == NULL) {
+               ldb_oom(ldb);
+               return -1;
+       }
+
+       c->subclasses = s;
+       s[n] = talloc_strdup(s, subclass);
+       if (s[n] == NULL) {
+               ldb_oom(ldb);
+               return -1;
+       }
+       s[n+1] = NULL;
+
+       return 0;
+}
+
+/*
+  remove a set of subclasses for a class
+*/
+void ldb_subclass_remove(struct ldb_context *ldb, const char *classname)
+{
+       int i;
+       struct ldb_subclass *c;
+
+       for (i=0;i<ldb->schema.num_classes;i++) {
+               if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
+                       break;
+               }
+       }
+       if (i == ldb->schema.num_classes) {
+               return;
+       }
+
+       c = &ldb->schema.classes[i];
+       talloc_free(c->name);
+       talloc_free(c->subclasses);
+       if (ldb->schema.num_classes-(i+1) > 0) {
+               memmove(c, c+1, sizeof(*c) * (ldb->schema.num_classes-(i+1)));
+       }
+       ldb->schema.num_classes--;
+       if (ldb->schema.num_classes == 0) {
+               talloc_free(ldb->schema.classes);
+               ldb->schema.classes = NULL;
+       }
+}
diff --git a/source3/lib/ldb/common/ldb_controls.c b/source3/lib/ldb/common/ldb_controls.c
new file mode 100644 (file)
index 0000000..d2729c8
--- /dev/null
@@ -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 (file)
index 0000000..2548a54
--- /dev/null
@@ -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 (file)
index 0000000..a0f4872
--- /dev/null
@@ -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, "<GUID=", 6) == 0) {
+               /* this is special DN returned when the
+                * exploded_dn control is used
+                */
+
+               /* Allocate a structure to hold the exploded DN */
+               edn = ldb_dn_new(mem_ctx);
+
+               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;
+
+       }
+       
+       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 (file)
index 0000000..c5084aa
--- /dev/null
@@ -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<bytes;i++) {
+               byte_offset = (i*6)/8;
+               bit_offset = (i*6)%8;
+               if (bit_offset < 3) {
+                       idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
+               } else {
+                       idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
+                       if (byte_offset+1 < len) {
+                               idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
+                       }
+               }
+               out[i] = b64[idx];
+       }
+
+       for (;i<bytes+pad_bytes;i++)
+               out[i] = '=';
+       out[i] = 0;
+
+       return out;
+}
+
+/*
+  see if a buffer should be base64 encoded
+*/
+int ldb_should_b64_encode(const struct ldb_val *val)
+{
+       unsigned int i;
+       uint8_t *p = val->data;
+
+       if (val->length == 0) {
+               return 0;
+       }
+
+       if (p[0] == ' ' || p[0] == ':') {
+               return 1;
+       }
+
+       for (i=0; i<val->length; i++) {
+               if (!isprint(p[i]) || p[i] == '\n') {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* this macro is used to handle the return checking on fprintf_fn() */
+#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
+
+/*
+  write a line folded string onto a file
+*/
+static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private_data,
+                       const char *buf, size_t length, int start_pos)
+{
+       unsigned int i;
+       int total=0, ret;
+
+       for (i=0;i<length;i++) {
+               ret = fprintf_fn(private_data, "%c", buf[i]);
+               CHECK_RET;
+               if (i != (length-1) && (i + start_pos) % 77 == 0) {
+                       ret = fprintf_fn(private_data, "\n ");
+                       CHECK_RET;
+               }
+       }
+
+       return total;
+}
+
+/*
+  encode as base64 to a file
+*/
+static int base64_encode_f(struct ldb_context *ldb,
+                          int (*fprintf_fn)(void *, const char *, ...), 
+                          void *private_data,
+                          const char *buf, int len, int start_pos)
+{
+       char *b = ldb_base64_encode(ldb, buf, len);
+       int ret;
+
+       if (!b) {
+               return -1;
+       }
+
+       ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
+
+       talloc_free(b);
+       return ret;
+}
+
+
+static const struct {
+       const char *name;
+       enum ldb_changetype changetype;
+} ldb_changetypes[] = {
+       {"add",    LDB_CHANGETYPE_ADD},
+       {"delete", LDB_CHANGETYPE_DELETE},
+       {"modify", LDB_CHANGETYPE_MODIFY},
+       {NULL, 0}
+};
+
+/*
+  write to ldif, using a caller supplied write method
+*/
+int ldb_ldif_write(struct ldb_context *ldb,
+                  int (*fprintf_fn)(void *, const char *, ...), 
+                  void *private_data,
+                  const struct ldb_ldif *ldif)
+{
+       unsigned int i, j;
+       int total=0, ret;
+       const struct ldb_message *msg;
+
+       msg = ldif->msg;
+
+       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;i<msg->num_elements;i++) {
+               const struct ldb_attrib_handler *h;
+
+               h = ldb_attrib_handler(ldb, msg->elements[i].name);
+
+               if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
+                       switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
+                       case LDB_FLAG_MOD_ADD:
+                               fprintf_fn(private_data, "add: %s\n", 
+                                          msg->elements[i].name);
+                               break;
+                       case LDB_FLAG_MOD_DELETE:
+                               fprintf_fn(private_data, "delete: %s\n", 
+                                          msg->elements[i].name);
+                               break;
+                       case LDB_FLAG_MOD_REPLACE:
+                               fprintf_fn(private_data, "replace: %s\n", 
+                                          msg->elements[i].name);
+                               break;
+                       }
+               }
+
+               for (j=0;j<msg->elements[i].num_values;j++) {
+                       struct ldb_val v;
+                       ret = h->ldif_write_fn(ldb, 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 (file)
index 0000000..64e52d2
--- /dev/null
@@ -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;i<el->num_values;i++) {
+               if (h->comparison_fn(ldb, ldb, &tree->u.equality.value, 
+                                    &el->values[i]) == 0) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int ldb_wildcard_compare(struct ldb_context *ldb,
+                               const struct ldb_parse_tree *tree,
+                               const struct ldb_val value)
+{
+       const struct ldb_attrib_handler *h;
+       struct ldb_val val;
+       struct ldb_val cnk;
+       struct ldb_val *chunk;
+       char *p, *g;
+       uint8_t *save_p = NULL;
+       int c = 0;
+
+       h = ldb_attrib_handler(ldb, tree->u.substring.attr);
+
+       if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
+               return -1;
+
+       save_p = val.data;
+       cnk.data = NULL;
+
+       if ( ! tree->u.substring.start_with_wildcard ) {
+
+               chunk = tree->u.substring.chunks[c];
+               if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
+
+               /* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
+               if (cnk.length > val.length) {
+                       goto failed;
+               }
+               if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
+               val.length -= cnk.length;
+               val.data += cnk.length;
+               c++;
+               talloc_free(cnk.data);
+               cnk.data = NULL;
+       }
+
+       while (tree->u.substring.chunks[c]) {
+
+               chunk = tree->u.substring.chunks[c];
+               if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
+
+               /* FIXME: case of embedded nulls */
+               p = strstr((char *)val.data, (char *)cnk.data);
+               if (p == NULL) goto failed;
+               if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
+                       do { /* greedy */
+                               g = strstr((char *)p + cnk.length, (char *)cnk.data);
+                               if (g) p = g;
+                       } while(g);
+               }
+               val.length = val.length - (p - (char *)(val.data)) - cnk.length;
+               val.data = (uint8_t *)(p + cnk.length);
+               c++;
+               talloc_free(cnk.data);
+               cnk.data = NULL;
+       }
+
+       if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
+       talloc_free(save_p);
+       return 1;
+
+failed:
+       talloc_free(save_p);
+       talloc_free(cnk.data);
+       return 0;
+}
+
+/*
+  match a simple leaf node
+*/
+static int ldb_match_substring(struct ldb_context *ldb, 
+                              const struct ldb_message *msg,
+                              const struct ldb_parse_tree *tree,
+                              enum ldb_scope scope)
+{
+       unsigned int i;
+       struct ldb_message_element *el;
+
+       el = ldb_msg_find_element(msg, tree->u.substring.attr);
+       if (el == NULL) {
+               return 0;
+       }
+
+       for (i = 0; i < el->num_values; i++) {
+               if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+  bitwise-and comparator
+*/
+static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+       uint64_t i1, i2;
+       i1 = strtoull((char *)v1->data, NULL, 0);
+       i2 = strtoull((char *)v2->data, NULL, 0);
+       return ((i1 & i2) == i2);
+}
+
+/*
+  bitwise-or comparator
+*/
+static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+       uint64_t i1, i2;
+       i1 = strtoull((char *)v1->data, NULL, 0);
+       i2 = strtoull((char *)v2->data, NULL, 0);
+       return ((i1 & i2) != 0);
+}
+
+
+/*
+  extended match, handles things like bitops
+*/
+static int ldb_match_extended(struct ldb_context *ldb, 
+                             const struct ldb_message *msg,
+                             const struct ldb_parse_tree *tree,
+                             enum ldb_scope scope)
+{
+       int i;
+       const struct {
+               const char *oid;
+               int (*comparator)(const struct ldb_val *, const struct ldb_val *);
+       } rules[] = {
+               { LDB_OID_COMPARATOR_AND, ldb_comparator_and},
+               { LDB_OID_COMPARATOR_OR, ldb_comparator_or}
+       };
+       int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
+       struct ldb_message_element *el;
+
+       if (tree->u.extended.dnAttributes) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
+               return -1;
+       }
+       if (tree->u.extended.rule_id == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
+               return -1;
+       }
+       if (tree->u.extended.attr == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
+               return -1;
+       }
+
+       for (i=0;i<ARRAY_SIZE(rules);i++) {
+               if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
+                       comp = rules[i].comparator;
+                       break;
+               }
+       }
+       if (comp == NULL) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
+                         tree->u.extended.rule_id);
+               return -1;
+       }
+
+       /* find the message element */
+       el = ldb_msg_find_element(msg, tree->u.extended.attr);
+       if (el == NULL) {
+               return 0;
+       }
+
+       for (i=0;i<el->num_values;i++) {
+               int ret = comp(&el->values[i], &tree->u.extended.value);
+               if (ret == -1 || ret == 1) return ret;
+       }
+
+       return 0;
+}
+
+/*
+  return 0 if the given parse tree matches the given message. Assumes
+  the message is in sorted order
+
+  return 1 if it matches, and 0 if it doesn't match
+
+  this is a recursive function, and does short-circuit evaluation
+ */
+static int ldb_match_message(struct ldb_context *ldb, 
+                            const struct ldb_message *msg,
+                            const struct ldb_parse_tree *tree,
+                            enum ldb_scope scope)
+{
+       unsigned int i;
+       int v;
+
+       switch (tree->operation) {
+       case LDB_OP_AND:
+               for (i=0;i<tree->u.list.num_elements;i++) {
+                       v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
+                       if (!v) return 0;
+               }
+               return 1;
+
+       case LDB_OP_OR:
+               for (i=0;i<tree->u.list.num_elements;i++) {
+                       v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
+                       if (v) return 1;
+               }
+               return 0;
+
+       case LDB_OP_NOT:
+               return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
+
+       case LDB_OP_EQUALITY:
+               return ldb_match_equality(ldb, msg, tree, scope);
+
+       case LDB_OP_SUBSTRING:
+               return ldb_match_substring(ldb, msg, tree, scope);
+
+       case LDB_OP_GREATER:
+               return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
+
+       case LDB_OP_LESS:
+               return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
+
+       case LDB_OP_PRESENT:
+               return ldb_match_present(ldb, msg, tree, scope);
+
+       case LDB_OP_APPROX:
+               return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
+
+       case LDB_OP_EXTENDED:
+               return ldb_match_extended(ldb, msg, tree, scope);
+
+       }
+
+       return 0;
+}
+
+int ldb_match_msg(struct ldb_context *ldb,
+                 const struct ldb_message *msg,
+                 const struct ldb_parse_tree *tree,
+                 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 (file)
index 0000000..06a8a4b
--- /dev/null
@@ -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 (file)
index 0000000..52c6b82
--- /dev/null
@@ -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;i<msg->num_elements;i++) {
+               if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+                       return &msg->elements[i];
+               }
+       }
+       return NULL;
+}
+
+/*
+  see if two ldb_val structures contain exactly the same data
+  return 1 for a match, 0 for a mis-match
+*/
+int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
+{
+       if (v1->length != v2->length) return 0;
+
+       if (v1->length == 0) return 1;
+
+       if (memcmp(v1->data, v2->data, v1->length) == 0) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+  find a value in an element
+  assumes case sensitive comparison
+*/
+struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
+                                struct ldb_val *val)
+{
+       unsigned int i;
+       for (i=0;i<el->num_values;i++) {
+               if (ldb_val_equal_exact(val, &el->values[i])) {
+                       return &el->values[i];
+               }
+       }
+       return NULL;
+}
+
+/*
+  duplicate a ldb_val structure
+*/
+struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
+{
+       struct ldb_val v2;
+       v2.length = v->length;
+       if (v->data == NULL) {
+               v2.data = NULL;
+               return v2;
+       }
+
+       /* the +1 is to cope with buggy C library routines like strndup
+          that look one byte beyond */
+       v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
+       if (!v2.data) {
+               v2.length = 0;
+               return v2;
+       }
+
+       memcpy(v2.data, v->data, v->length);
+       ((char *)v2.data)[v->length] = 0;
+       return v2;
+}
+
+/*
+  add an empty element to a message
+*/
+int ldb_msg_add_empty(struct ldb_message *msg, const char *attr_name, int flags)
+{
+       struct ldb_message_element *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;i<el1->num_values;i++) {
+               if (!ldb_msg_find_val(el2, &el1->values[i])) {
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+  compare two ldb_message_element structures
+  comparing by element name
+*/
+int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
+                                struct ldb_message_element *el2)
+{
+       return ldb_attr_cmp(el1->name, el2->name);
+}
+
+/*
+  convenience functions to return common types from a message
+  these return the first value if the attribute is multi-valued
+*/
+const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
+{
+       struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
+       if (!el || el->num_values == 0) {
+               return NULL;
+       }
+       return &el->values[0];
+}
+
+int ldb_msg_find_attr_as_int(const struct ldb_message *msg, 
+                            const char *attr_name,
+                            int default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return strtol((const char *)v->data, NULL, 0);
+}
+
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
+                                      const char *attr_name,
+                                      unsigned int default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return strtoul((const char *)v->data, NULL, 0);
+}
+
+int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
+                                  const char *attr_name,
+                                  int64_t default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return strtoll((const char *)v->data, NULL, 0);
+}
+
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
+                                    const char *attr_name,
+                                    uint64_t default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return strtoull((const char *)v->data, NULL, 0);
+}
+
+double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
+                                  const char *attr_name,
+                                  double default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return strtod((const char *)v->data, NULL);
+}
+
+int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
+                             const char *attr_name,
+                             int default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       if (strcasecmp((const char *)v->data, "FALSE") == 0) {
+               return 0;
+       }
+       if (strcasecmp((const char *)v->data, "TRUE") == 0) {
+               return 1;
+       }
+       return default_value;
+}
+
+const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg, 
+                                       const char *attr_name,
+                                       const char *default_value)
+{
+       const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       if (!v || !v->data) {
+               return default_value;
+       }
+       return (const char *)v->data;
+}
+
+struct ldb_dn *ldb_msg_find_attr_as_dn(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;i<msg2->num_elements;i++) {
+               msg2->elements[i] = msg->elements[i];
+       }
+
+       return msg2;
+
+failed:
+       talloc_free(msg2);
+       return NULL;
+}
+
+
+/*
+  copy a message, allocating new memory for all parts
+*/
+struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx, 
+                                const struct ldb_message *msg)
+{
+       struct ldb_message *msg2;
+       int i, j;
+
+       msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
+       if (msg2 == NULL) return NULL;
+
+       msg2->dn = ldb_dn_copy(msg2, msg2->dn);
+       if (msg2->dn == NULL) goto failed;
+
+       for (i=0;i<msg2->num_elements;i++) {
+               struct ldb_message_element *el = &msg2->elements[i];
+               struct ldb_val *values = el->values;
+               el->name = talloc_strdup(msg2->elements, el->name);
+               if (el->name == NULL) goto failed;
+               el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
+               for (j=0;j<el->num_values;j++) {
+                       el->values[j] = ldb_val_dup(el->values, &values[j]);
+                       if (el->values[j].data == NULL && values[j].length != 0) {
+                               goto failed;
+                       }
+               }
+       }
+
+       return msg2;
+
+failed:
+       talloc_free(msg2);
+       return NULL;
+}
+
+
+/*
+  canonicalise a message, merging elements of the same name
+*/
+struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
+                                        const struct ldb_message *msg)
+{
+       int i;
+       struct ldb_message *msg2;
+
+       msg2 = ldb_msg_copy(ldb, msg);
+       if (msg2 == NULL) return NULL;
+
+       ldb_msg_sort_elements(msg2);
+
+       for (i=1;i<msg2->num_elements;i++) {
+               struct ldb_message_element *el1 = &msg2->elements[i-1];
+               struct ldb_message_element *el2 = &msg2->elements[i];
+               if (ldb_msg_element_compare_name(el1, el2) == 0) {
+                       el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
+                                                      el1->num_values + el2->num_values);
+                       if (el1->values == NULL) {
+                               return NULL;
+                       }
+                       memcpy(el1->values + el1->num_values,
+                              el2->values,
+                              sizeof(struct ldb_val) * el2->num_values);
+                       el1->num_values += el2->num_values;
+                       talloc_free(discard_const_p(char, el2->name));
+                       if (i+1<msg2->num_elements) {
+                               memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
+                                       (msg2->num_elements - (i+1)));
+                       }
+                       msg2->num_elements--;
+                       i--;
+               }
+       }
+
+       return msg2;
+}
+
+
+/*
+  return a ldb_message representing the differences between msg1 and msg2. If you
+  then use this in a ldb_modify() call it can be used to save edits to a message
+*/
+struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
+                                struct ldb_message *msg1,
+                                struct ldb_message *msg2)
+{
+       struct ldb_message *mod;
+       struct ldb_message_element *el;
+       unsigned int i;
+
+       mod = ldb_msg_new(ldb);
+
+       mod->dn = msg1->dn;
+       mod->num_elements = 0;
+       mod->elements = NULL;
+
+       msg2 = ldb_msg_canonicalize(ldb, msg2);
+       if (msg2 == NULL) {
+               return NULL;
+       }
+       
+       /* look in msg2 to find elements that need to be added
+          or modified */
+       for (i=0;i<msg2->num_elements;i++) {
+               el = ldb_msg_find_element(msg1, msg2->elements[i].name);
+
+               if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
+                       continue;
+               }
+
+               if (ldb_msg_add(mod, 
+                               &msg2->elements[i],
+                               el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
+                       return NULL;
+               }
+       }
+
+       /* look in msg1 to find elements that need to be deleted */
+       for (i=0;i<msg1->num_elements;i++) {
+               el = ldb_msg_find_element(msg2, msg1->elements[i].name);
+               if (!el) {
+                       if (ldb_msg_add_empty(mod, 
+                                             msg1->elements[i].name,
+                                             LDB_FLAG_MOD_DELETE) != 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 (file)
index 0000000..d9044a8
--- /dev/null
@@ -0,0 +1,817 @@
+/* 
+   ldb database library
+
+   Copyright (C) Andrew Tridgell  2004
+
+     ** NOTE! The following LGPL license applies to the ldb
+     ** library. This does NOT imply that all of Samba is released
+     ** under the LGPL
+   
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb expression parsing
+ *
+ *  Description: parse LDAP-like search expressions
+ *
+ *  Author: Andrew Tridgell
+ */
+
+/*
+  TODO:
+      - add RFC2254 binary string handling
+      - possibly add ~=, <= and >= handling
+      - expand the test suite
+      - add better parse error handling
+
+*/
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+#include "system/locale.h"
+
+/*
+a filter is defined by:
+               <filter> ::= '(' <filtercomp> ')'
+               <filtercomp> ::= <and> | <or> | <not> | <simple>
+               <and> ::= '&' <filterlist>
+               <or> ::= '|' <filterlist>
+               <not> ::= '!' <filter>
+               <filterlist> ::= <filter> | <filter> <filterlist>
+               <simple> ::= <attributetype> <filtertype> <attributevalue>
+               <filtertype> ::= '=' | '~=' | '<=' | '>='
+*/
+
+/*
+   decode a RFC2254 binary string representation of a buffer.
+   Used in LDAP filters.
+*/
+struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str)
+{
+       int i, j;
+       struct ldb_val ret;
+       int slen = str?strlen(str):0;
+
+       ret.data = talloc_size(mem_ctx, slen+1);
+       ret.length = 0;
+       if (ret.data == NULL) return ret;
+
+       for (i=j=0;i<slen;i++) {
+               if (str[i] == '\\') {
+                       unsigned c;
+                       if (sscanf(&str[i+1], "%02X", &c) != 1) {
+                               talloc_free(ret.data);
+                               memset(&ret, 0, sizeof(ret));
+                               return ret;
+                       }
+                       ((uint8_t *)ret.data)[j++] = c;
+                       i += 2;
+               } else {
+                       ((uint8_t *)ret.data)[j++] = str[i];
+               }
+       }
+       ret.length = j;
+       ((uint8_t *)ret.data)[j] = 0;
+
+       return ret;
+}
+
+
+/*
+   encode a blob as a RFC2254 binary string, escaping any
+   non-printable or '\' characters
+*/
+char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
+{
+       int i;
+       char *ret;
+       int len = val.length;
+       unsigned char *buf = val.data;
+
+       for (i=0;i<val.length;i++) {
+               if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
+                       len += 2;
+               }
+       }
+       ret = talloc_array(mem_ctx, char, len+1);
+       if (ret == NULL) return NULL;
+
+       len = 0;
+       for (i=0;i<val.length;i++) {
+               if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
+                       snprintf(ret+len, 4, "\\%02X", buf[i]);
+                       len += 3;
+               } else {
+                       ret[len++] = buf[i];
+               }
+       }
+
+       ret[len] = 0;
+
+       return ret;     
+}
+
+/*
+   encode a string as a RFC2254 binary string, escaping any
+   non-printable or '\' characters.  This routine is suitable for use
+   in escaping user data in ldap filters.
+*/
+char *ldb_binary_encode_string(void *mem_ctx, const char *string)
+{
+       struct ldb_val val;
+       val.data = discard_const(string);
+       val.length = strlen(string);
+       return ldb_binary_encode(mem_ctx, val);
+}
+
+/* find the first matching wildcard */
+static char *ldb_parse_find_wildcard(char *value)
+{
+       while (*value) {
+               value = strpbrk(value, "\\*");
+               if (value == NULL) return NULL;
+
+               if (value[0] == '\\') {
+                       if (value[1] == '\0') return NULL;
+                       value += 2;
+                       continue;
+               }
+
+               if (value[0] == '*') return value;
+       }
+
+       return NULL;
+}
+
+/* return a NULL terminated list of binary strings representing the value
+   chunks separated by wildcards that makes the value portion of the filter
+*/
+static struct ldb_val **ldb_wildcard_decode(void *mem_ctx, const char *string)
+{
+       struct ldb_val **ret = NULL;
+       int val = 0;
+       char *wc, *str;
+
+       wc = talloc_strdup(mem_ctx, string);
+       if (wc == NULL) return NULL;
+
+       while (wc && *wc) {
+               str = wc;
+               wc = ldb_parse_find_wildcard(str);
+               if (wc && *wc) {
+                       if (wc == str) {
+                               wc++;
+                               continue;
+                       }
+                       *wc = 0;
+                       wc++;
+               }
+
+               ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
+               if (ret == NULL) return NULL;
+
+               ret[val] = talloc(mem_ctx, struct ldb_val);
+               if (ret[val] == NULL) return NULL;
+
+               *(ret[val]) = ldb_binary_decode(mem_ctx, str);
+               if ((ret[val])->data == NULL) return NULL;
+
+               val++;
+       }
+
+       if (ret != NULL) {
+               ret[val] = NULL;
+       }
+
+       return ret;
+}
+
+static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s);
+
+
+/*
+  parse an extended match
+
+  possible forms:
+        (attr:oid:=value)
+        (attr:dn:oid:=value)
+        (attr:dn:=value)
+        (:dn:oid:=value)
+
+  the ':dn' part sets the dnAttributes boolean if present
+  the oid sets the rule_id string
+  
+*/
+static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret, 
+                                                char *attr, char *value)
+{
+       char *p1, *p2;
+
+       ret->operation = LDB_OP_EXTENDED;
+       ret->u.extended.value = ldb_binary_decode(ret, value);
+       if (ret->u.extended.value.data == NULL) goto failed;
+
+       p1 = strchr(attr, ':');
+       if (p1 == NULL) goto failed;
+       p2 = strchr(p1+1, ':');
+
+       *p1 = 0;
+       if (p2) *p2 = 0;
+
+       ret->u.extended.attr = attr;
+       if (strcmp(p1+1, "dn") == 0) {
+               ret->u.extended.dnAttributes = 1;
+               if (p2) {
+                       ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
+                       if (ret->u.extended.rule_id == NULL) goto failed;
+               } else {
+                       ret->u.extended.rule_id = NULL;
+               }
+       } else {
+               ret->u.extended.dnAttributes = 0;
+               ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
+               if (ret->u.extended.rule_id == NULL) goto failed;
+       }
+
+       return ret;
+
+failed:
+       talloc_free(ret);
+       return NULL;
+}
+
+static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char **value, const char **s)
+{
+       enum ldb_parse_op filter = 0;
+       char *name, *val, *k;
+       const char *p = *s;
+       const char *t, *t1;
+
+       /* retrieve attributetype name */
+       t = p;
+
+       while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */
+               p++;
+       }
+
+       if (*p == ':') { /* but extended searches have : and . chars too */
+               p = strstr(p, ":=");
+               if (p == NULL) { /* malformed attribute name */
+                       return 0;
+               }
+       }
+
+       t1 = p;
+
+       while (isspace((unsigned char)*p)) p++;
+
+       if (!strchr("=<>~:", *p)) {
+               return 0;
+       }
+
+       /* save name */
+       name = 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;
+}
+
+/*
+  <simple> ::= <attributetype> <filtertype> <attributevalue>
+*/
+static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char **s)
+{
+       char *attr, *value;
+       struct ldb_parse_tree *ret;
+       enum ldb_parse_op filtertype;
+
+       ret = talloc(mem_ctx, struct ldb_parse_tree);
+       if (!ret) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
+       if (!filtertype) {
+               talloc_free(ret);
+               return NULL;
+       }
+
+       switch (filtertype) {
+
+               case LDB_OP_PRESENT:
+                       ret->operation = LDB_OP_PRESENT;
+                       ret->u.present.attr = attr;
+                       break;
+
+               case LDB_OP_EQUALITY:
+
+                       if (strcmp(value, "*") == 0) {
+                               ret->operation = LDB_OP_PRESENT;
+                               ret->u.present.attr = attr;
+                               break;
+                       }
+
+                       if (ldb_parse_find_wildcard(value) != NULL) {
+                               ret->operation = LDB_OP_SUBSTRING;
+                               ret->u.substring.attr = attr;
+                               ret->u.substring.start_with_wildcard = 0;
+                               ret->u.substring.end_with_wildcard = 0;
+                               ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
+                               if (ret->u.substring.chunks == NULL){
+                                       talloc_free(ret);
+                                       return NULL;
+                               }
+                               if (value[0] == '*')
+                                       ret->u.substring.start_with_wildcard = 1;
+                               if (value[strlen(value) - 1] == '*')
+                                       ret->u.substring.end_with_wildcard = 1;
+                               talloc_free(value);
+
+                               break;
+                       }
+
+                       ret->operation = LDB_OP_EQUALITY;
+                       ret->u.equality.attr = attr;
+                       ret->u.equality.value = ldb_binary_decode(ret, value);
+                       if (ret->u.equality.value.data == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       talloc_free(value);
+                       break;
+
+               case LDB_OP_GREATER:
+                       ret->operation = LDB_OP_GREATER;
+                       ret->u.comparison.attr = attr;
+                       ret->u.comparison.value = ldb_binary_decode(ret, value);
+                       if (ret->u.comparison.value.data == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       talloc_free(value);
+                       break;
+
+               case LDB_OP_LESS:
+                       ret->operation = LDB_OP_LESS;
+                       ret->u.comparison.attr = attr;
+                       ret->u.comparison.value = ldb_binary_decode(ret, value);
+                       if (ret->u.comparison.value.data == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       talloc_free(value);
+                       break;
+
+               case LDB_OP_APPROX:
+                       ret->operation = LDB_OP_APPROX;
+                       ret->u.comparison.attr = attr;
+                       ret->u.comparison.value = ldb_binary_decode(ret, value);
+                       if (ret->u.comparison.value.data == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       talloc_free(value);
+                       break;
+
+               case LDB_OP_EXTENDED:
+
+                       ret = ldb_parse_extended(ret, attr, value);
+                       break;
+
+               default:
+                       talloc_free(ret);
+                       return NULL;
+       }
+
+       return ret;
+}
+
+
+/*
+  parse a filterlist
+  <and> ::= '&' <filterlist>
+  <or> ::= '|' <filterlist>
+  <filterlist> ::= <filter> | <filter> <filterlist>
+*/
+static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx, const char **s)
+{
+       struct ldb_parse_tree *ret, *next;
+       enum ldb_parse_op op;
+       const char *p = *s;
+
+       switch (*p) {
+               case '&':
+                       op = LDB_OP_AND;
+                       break;
+               case '|':
+                       op = LDB_OP_OR;
+                       break;
+               default:
+                       return NULL;
+       }
+       p++;
+
+       while (isspace((unsigned char)*p)) p++;
+
+       ret = talloc(mem_ctx, struct ldb_parse_tree);
+       if (!ret) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       ret->operation = op;
+       ret->u.list.num_elements = 1;
+       ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
+       if (!ret->u.list.elements) {
+               errno = ENOMEM;
+               talloc_free(ret);
+               return NULL;
+       }
+
+       ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
+       if (!ret->u.list.elements[0]) {
+               talloc_free(ret);
+               return NULL;
+       }
+
+       while (isspace((unsigned char)*p)) p++;
+
+       while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) {
+               struct ldb_parse_tree **e;
+               e = talloc_realloc(ret, ret->u.list.elements, 
+                                    struct ldb_parse_tree *, 
+                                    ret->u.list.num_elements + 1);
+               if (!e) {
+                       errno = ENOMEM;
+                       talloc_free(ret);
+                       return NULL;
+               }
+               ret->u.list.elements = e;
+               ret->u.list.elements[ret->u.list.num_elements] = next;
+               ret->u.list.num_elements++;
+               while (isspace((unsigned char)*p)) p++;
+       }
+
+       *s = p;
+
+       return ret;
+}
+
+
+/*
+  <not> ::= '!' <filter>
+*/
+static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char **s)
+{
+       struct ldb_parse_tree *ret;
+       const char *p = *s;
+
+       if (*p != '!') {
+               return NULL;
+       }
+       p++;
+
+       ret = talloc(mem_ctx, struct ldb_parse_tree);
+       if (!ret) {
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       ret->operation = LDB_OP_NOT;
+       ret->u.isnot.child = ldb_parse_filter(ret, &p);
+       if (!ret->u.isnot.child) {
+               talloc_free(ret);
+               return NULL;
+       }
+
+       *s = p;
+
+       return ret;
+}
+
+/*
+  parse a filtercomp
+  <filtercomp> ::= <and> | <or> | <not> | <simple>
+*/
+static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char **s)
+{
+       struct ldb_parse_tree *ret;
+       const char *p = *s;
+
+       while (isspace((unsigned char)*p)) p++;
+
+       switch (*p) {
+       case '&':
+               ret = ldb_parse_filterlist(mem_ctx, &p);
+               break;
+
+       case '|':
+               ret = ldb_parse_filterlist(mem_ctx, &p);
+               break;
+
+       case '!':
+               ret = ldb_parse_not(mem_ctx, &p);
+               break;
+
+       case '(':
+       case ')':
+               return NULL;
+
+       default:
+               ret = ldb_parse_simple(mem_ctx, &p);
+
+       }
+
+       *s = p;
+       return ret;
+}
+
+
+/*
+  <filter> ::= '(' <filtercomp> ')'
+*/
+static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s)
+{
+       struct ldb_parse_tree *ret;
+       const char *p = *s;
+
+       if (*p != '(') {
+               return NULL;
+       }
+       p++;
+
+       ret = ldb_parse_filtercomp(mem_ctx, &p);
+
+       if (*p != ')') {
+               return NULL;
+       }
+       p++;
+
+       while (isspace((unsigned char)*p)) {
+               p++;
+       }
+
+       *s = p;
+
+       return ret;
+}
+
+
+/*
+  main parser entry point. Takes a search string and returns a parse tree
+
+  expression ::= <simple> | <filter>
+*/
+struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s)
+{
+       if (s == NULL || *s == 0) {
+               s = "(|(objectClass=*)(distinguishedName=*))";
+       }
+
+       while (isspace((unsigned char)*s)) s++;
+
+       if (*s == '(') {
+               return ldb_parse_filter(mem_ctx, &s);
+       }
+
+       return ldb_parse_simple(mem_ctx, &s);
+}
+
+
+/*
+  construct a ldap parse filter given a parse tree
+*/
+char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree)
+{
+       char *s, *s2, *ret;
+       int i;
+
+       if (tree == NULL) {
+               return NULL;
+       }
+
+       switch (tree->operation) {
+       case LDB_OP_AND:
+       case LDB_OP_OR:
+               ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
+               if (ret == NULL) return NULL;
+               for (i=0;i<tree->u.list.num_elements;i++) {
+                       s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
+                       if (s == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       s2 = talloc_asprintf_append(ret, "%s", s);
+                       talloc_free(s);
+                       if (s2 == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       ret = s2;
+               }
+               s = talloc_asprintf_append(ret, ")");
+               if (s == NULL) {
+                       talloc_free(ret);
+                       return NULL;
+               }
+               return s;
+       case LDB_OP_NOT:
+               s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
+               if (s == NULL) return NULL;
+
+               ret = talloc_asprintf(mem_ctx, "(!%s)", s);
+               talloc_free(s);
+               return ret;
+       case LDB_OP_EQUALITY:
+               s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+               if (s == NULL) return NULL;
+               ret = talloc_asprintf(mem_ctx, "(%s=%s)", 
+                                     tree->u.equality.attr, s);
+               talloc_free(s);
+               return ret;
+       case LDB_OP_SUBSTRING:
+               ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
+                                     tree->u.substring.start_with_wildcard?"*":"");
+               if (ret == NULL) return NULL;
+               for (i = 0; tree->u.substring.chunks[i]; i++) {
+                       s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
+                       if (s2 == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       if (tree->u.substring.chunks[i+1] ||
+                           tree->u.substring.end_with_wildcard) {
+                               s = talloc_asprintf_append(ret, "%s*", s2);
+                       } else {
+                               s = talloc_asprintf_append(ret, "%s", s2);
+                       }
+                       if (s == NULL) {
+                               talloc_free(ret);
+                               return NULL;
+                       }
+                       ret = s;
+               }
+               s = talloc_asprintf_append(ret, ")");
+               if (s == NULL) {
+                       talloc_free(ret);
+                       return NULL;
+               }
+               ret = s;
+               return ret;
+       case LDB_OP_GREATER:
+               s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+               if (s == NULL) return NULL;
+               ret = talloc_asprintf(mem_ctx, "(%s>=%s)", 
+                                     tree->u.equality.attr, s);
+               talloc_free(s);
+               return ret;
+       case LDB_OP_LESS:
+               s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+               if (s == NULL) return NULL;
+               ret = talloc_asprintf(mem_ctx, "(%s<=%s)", 
+                                     tree->u.equality.attr, s);
+               talloc_free(s);
+               return ret;
+       case LDB_OP_PRESENT:
+               ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
+               return ret;
+       case LDB_OP_APPROX:
+               s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
+               if (s == NULL) return NULL;
+               ret = talloc_asprintf(mem_ctx, "(%s~=%s)", 
+                                     tree->u.equality.attr, s);
+               talloc_free(s);
+               return ret;
+       case LDB_OP_EXTENDED:
+               s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
+               if (s == NULL) return NULL;
+               ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)", 
+                                     tree->u.extended.attr?tree->u.extended.attr:"", 
+                                     tree->u.extended.dnAttributes?":dn":"",
+                                     tree->u.extended.rule_id?":":"", 
+                                     tree->u.extended.rule_id?tree->u.extended.rule_id:"", 
+                                     s);
+               talloc_free(s);
+               return ret;
+       }
+       
+       return NULL;
+}
+
+
+/*
+  replace any occurances of an attribute name in the parse tree with a
+  new name
+*/
+void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree, 
+                                const char *attr, 
+                                const char *replace)
+{
+       int i;
+       switch (tree->operation) {
+       case LDB_OP_AND:
+       case LDB_OP_OR:
+               for (i=0;i<tree->u.list.num_elements;i++) {
+                       ldb_parse_tree_attr_replace(tree->u.list.elements[i],
+                                                   attr, replace);
+               }
+               break;
+       case LDB_OP_NOT:
+               ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace);
+               break;
+       case LDB_OP_EQUALITY:
+       case LDB_OP_GREATER:
+       case LDB_OP_LESS:
+       case LDB_OP_APPROX:
+               if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
+                       tree->u.equality.attr = replace;
+               }
+               break;
+       case LDB_OP_SUBSTRING:
+               if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
+                       tree->u.substring.attr = replace;
+               }
+               break;
+       case LDB_OP_PRESENT:
+               if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) {
+                       tree->u.present.attr = replace;
+               }
+               break;
+       case LDB_OP_EXTENDED:
+               if (tree->u.extended.attr &&
+                   ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
+                       tree->u.extended.attr = replace;
+               }
+               break;
+       }
+}
diff --git a/source3/lib/ldb/common/ldb_utf8.c b/source3/lib/ldb/common/ldb_utf8.c
new file mode 100644 (file)
index 0000000..d2d12b8
--- /dev/null
@@ -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 (file)
index 0000000..ef7be2c
--- /dev/null
@@ -0,0 +1,254 @@
+/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* If you consider tuning this algorithm, you should consult first:
+   Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+   Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
+
+/* Modified to be used in samba4 by
+ * Simo Sorce <idra@samba.org>         2005
+ */
+
+#include "includes.h"
+#include "ldb/include/includes.h"
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size)                                                     \
+  do                                                                         \
+    {                                                                        \
+      register size_t __size = (size);                                       \
+      register char *__a = (a), *__b = (b);                                  \
+      do                                                                     \
+       {                                                                     \
+         char __tmp = *__a;                                                  \
+         *__a++ = *__b;                                                      \
+         *__b++ = __tmp;                                                     \
+       } while (--__size > 0);                                               \
+    } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+   This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+  {
+    char *lo;
+    char *hi;
+  } stack_node;
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+   log(MAX_THRESH)).  Since total_elements has type size_t, we get as
+   upper bound for log (total_elements):
+   bits per byte (CHAR_BIT) * sizeof(size_t).  */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+#define STACK_SIZE     (CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high)        ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define        POP(low, high)  ((void) (--top, (low = top->lo), (high = top->hi)))
+#define        STACK_NOT_EMPTY (stack < top)
+
+
+/* Order size using quicksort.  This implementation incorporates
+   four optimizations discussed in Sedgewick:
+
+   1. Non-recursive, using an explicit stack of pointer that store the
+      next array partition to sort.  To save time, this maximum amount
+      of space required to store an array of SIZE_MAX is allocated on the
+      stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
+      only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+      Pretty cheap, actually.
+
+   2. Chose the pivot element using a median-of-three decision tree.
+      This reduces the probability of selecting a bad pivot value and
+      eliminates certain extraneous comparisons.
+
+   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+      insertion sort to order the MAX_THRESH items within each partition.
+      This is a big win, since insertion sort is faster for small, mostly
+      sorted array segments.
+
+   4. The larger of the two sub-partitions is always pushed onto the
+      stack first, with the algorithm then concentrating on the
+      smaller partition.  This *guarantees* no more than log (total_elems)
+      stack size is needed (actually O(1) in this case)!  */
+
+void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
+               void *opaque, ldb_qsort_cmp_fn_t cmp)
+{
+  register char *base_ptr = (char *) pbase;
+
+  const size_t max_thresh = MAX_THRESH * size;
+
+  if (total_elems == 0)
+    /* Avoid lossage with unsigned arithmetic below.  */
+    return;
+
+  if (total_elems > MAX_THRESH)
+    {
+      char *lo = base_ptr;
+      char *hi = &lo[size * (total_elems - 1)];
+      stack_node stack[STACK_SIZE];
+      stack_node *top = stack;
+
+      PUSH (NULL, NULL);
+
+      while (STACK_NOT_EMPTY)
+        {
+          char *left_ptr;
+          char *right_ptr;
+
+         /* Select median value from among LO, MID, and HI. Rearrange
+            LO and HI so the three values are sorted. This lowers the
+            probability of picking a pathological pivot value and
+            skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+            the while loops. */
+
+         char *mid = lo + size * ((hi - lo) / size >> 1);
+
+         if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+           SWAP (mid, lo, size);
+         if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
+           SWAP (mid, hi, size);
+         else
+           goto jump_over;
+         if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
+           SWAP (mid, lo, size);
+       jump_over:;
+
+         left_ptr  = lo + size;
+         right_ptr = hi - size;
+
+         /* Here's the famous ``collapse the walls'' section of quicksort.
+            Gotta like those tight inner loops!  They are the main reason
+            that this algorithm runs much faster than others. */
+         do
+           {
+             while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
+               left_ptr += size;
+
+             while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
+               right_ptr -= size;
+
+             if (left_ptr < right_ptr)
+               {
+                 SWAP (left_ptr, right_ptr, size);
+                 if (mid == left_ptr)
+                   mid = right_ptr;
+                 else if (mid == right_ptr)
+                   mid = left_ptr;
+                 left_ptr += size;
+                 right_ptr -= size;
+               }
+             else if (left_ptr == right_ptr)
+               {
+                 left_ptr += size;
+                 right_ptr -= size;
+                 break;
+               }
+           }
+         while (left_ptr <= right_ptr);
+
+          /* Set up pointers for next iteration.  First determine whether
+             left and right partitions are below the threshold size.  If so,
+             ignore one or both.  Otherwise, push the larger partition's
+             bounds on the stack and continue sorting the smaller one. */
+
+          if ((size_t) (right_ptr - lo) <= max_thresh)
+            {
+              if ((size_t) (hi - left_ptr) <= max_thresh)
+               /* Ignore both small partitions. */
+                POP (lo, hi);
+              else
+               /* Ignore small left partition. */
+                lo = left_ptr;
+            }
+          else if ((size_t) (hi - left_ptr) <= max_thresh)
+           /* Ignore small right partition. */
+            hi = right_ptr;
+          else if ((right_ptr - lo) > (hi - left_ptr))
+            {
+             /* Push larger left partition indices. */
+              PUSH (lo, right_ptr);
+              lo = left_ptr;
+            }
+          else
+            {
+             /* Push larger right partition indices. */
+              PUSH (left_ptr, hi);
+              hi = right_ptr;
+            }
+        }
+    }
+
+  /* Once the BASE_PTR array is partially sorted by quicksort the rest
+     is completely sorted using insertion sort, since this is efficient
+     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+     of the array to sort, and END_PTR points at the very last element in
+     the array (*not* one beyond it!). */
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+
+  {
+    char *const end_ptr = &base_ptr[size * (total_elems - 1)];
+    char *tmp_ptr = base_ptr;
+    char *thresh = min(end_ptr, base_ptr + max_thresh);
+    register char *run_ptr;
+
+    /* Find smallest element in first threshold and place it at the
+       array's beginning.  This is the smallest array element,
+       and the operation speeds up insertion sort's inner loop. */
+
+    for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+      if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+        tmp_ptr = run_ptr;
+
+    if (tmp_ptr != base_ptr)
+      SWAP (tmp_ptr, base_ptr, size);
+
+    /* Insertion sort, running from left-hand-side up to right-hand-side.  */
+
+    run_ptr = base_ptr + size;
+    while ((run_ptr += size) <= end_ptr)
+      {
+       tmp_ptr = run_ptr - size;
+       while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
+         tmp_ptr -= size;
+
+       tmp_ptr += size;
+        if (tmp_ptr != run_ptr)
+          {
+            char *trav;
+
+           trav = run_ptr + size;
+           while (--trav >= run_ptr)
+              {
+                char c = *trav;
+                char *hi, *lo;
+
+                for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+                  *hi = *lo;
+                *hi = c;
+              }
+          }
+      }
+  }
+}
diff --git a/source3/lib/ldb/config.guess b/source3/lib/ldb/config.guess
new file mode 100755 (executable)
index 0000000..ad5281e
--- /dev/null
@@ -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 <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  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 <config-patches@gnu.org>."
+
+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 <stdio.h>  /* 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 <sys/systemcfg.h>
+
+               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 <stdlib.h>
+              #include <unistd.h>
+
+              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 <unistd.h>
+       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 <features.h>
+       #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' </usr/options/cb.name`
+               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+       elif /bin/uname -X 2>/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 <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # 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 <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#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 <sys/param.h>
+  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 <sys/param.h>
+#  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 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> 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 (file)
index 0000000..6a23005
--- /dev/null
@@ -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 = \
+ &nb