diff options
Diffstat (limited to 'src/lib-ldap')
-rw-r--r-- | src/lib-ldap/Makefile.am | 42 | ||||
-rw-r--r-- | src/lib-ldap/Makefile.in | 890 | ||||
-rw-r--r-- | src/lib-ldap/ldap-client.c | 74 | ||||
-rw-r--r-- | src/lib-ldap/ldap-client.h | 102 | ||||
-rw-r--r-- | src/lib-ldap/ldap-compare.c | 121 | ||||
-rw-r--r-- | src/lib-ldap/ldap-connection-pool.c | 113 | ||||
-rw-r--r-- | src/lib-ldap/ldap-connection-pool.h | 27 | ||||
-rw-r--r-- | src/lib-ldap/ldap-connection.c | 714 | ||||
-rw-r--r-- | src/lib-ldap/ldap-entry.c | 72 | ||||
-rw-r--r-- | src/lib-ldap/ldap-iterator.c | 29 | ||||
-rw-r--r-- | src/lib-ldap/ldap-private.h | 129 | ||||
-rw-r--r-- | src/lib-ldap/ldap-search.c | 169 |
12 files changed, 2482 insertions, 0 deletions
diff --git a/src/lib-ldap/Makefile.am b/src/lib-ldap/Makefile.am new file mode 100644 index 0000000..14f53a6 --- /dev/null +++ b/src/lib-ldap/Makefile.am @@ -0,0 +1,42 @@ +pkglib_LTLIBRARIES = libdovecot-ldap.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-test \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/lib-ssl-iostream \ + $(LDAP_CFLAGS) + +libdovecot_ldap_la_SOURCES = \ + ldap-client.c \ + ldap-connection.c \ + ldap-connection-pool.c \ + ldap-iterator.c \ + ldap-search.c \ + ldap-compare.c \ + ldap-entry.c + +libdovecot_ldap_la_DEPENDENCIES = ../lib-dovecot/libdovecot.la +libdovecot_ldap_la_LDFLAGS = -export-dynamic +libdovecot_ldap_la_LIBADD = ../lib-dovecot/libdovecot.la $(LDAP_LIBS) + +headers = \ + ldap-client.h + +noinst_HEADERS = \ + ldap-connection-pool.h \ + ldap-private.h + +pkginc_libdir=$(pkgincludedir) +pkginc_lib_HEADERS = $(headers) + +test_libs = \ + ../lib-test/libtest.la \ + ../lib-ssl-iostream/libssl_iostream.la \ + ../lib/liblib.la + +check-local: + for bin in $(test_programs); do \ + if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \ + done diff --git a/src/lib-ldap/Makefile.in b/src/lib-ldap/Makefile.in new file mode 100644 index 0000000..f161de9 --- /dev/null +++ b/src/lib-ldap/Makefile.in @@ -0,0 +1,890 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/lib-ldap +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \ + $(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \ + $(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \ + $(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \ + $(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \ + $(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \ + $(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \ + $(top_srcdir)/m4/flexible_array_member.m4 \ + $(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \ + $(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \ + $(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \ + $(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \ + $(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \ + $(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \ + $(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \ + $(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \ + $(top_srcdir)/m4/pr_set_dumpable.m4 \ + $(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \ + $(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \ + $(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \ + $(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \ + $(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \ + $(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \ + $(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \ + $(top_srcdir)/m4/typeof_dev_t.m4 \ + $(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \ + $(top_srcdir)/m4/want_apparmor.m4 \ + $(top_srcdir)/m4/want_bsdauth.m4 \ + $(top_srcdir)/m4/want_bzlib.m4 \ + $(top_srcdir)/m4/want_cassandra.m4 \ + $(top_srcdir)/m4/want_cdb.m4 \ + $(top_srcdir)/m4/want_checkpassword.m4 \ + $(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \ + $(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \ + $(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \ + $(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \ + $(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \ + $(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \ + $(top_srcdir)/m4/want_prefetch.m4 \ + $(top_srcdir)/m4/want_shadow.m4 \ + $(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \ + $(top_srcdir)/m4/want_sqlite.m4 \ + $(top_srcdir)/m4/want_stemmer.m4 \ + $(top_srcdir)/m4/want_systemd.m4 \ + $(top_srcdir)/m4/want_textcat.m4 \ + $(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \ + $(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(pkginc_lib_HEADERS) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkglibdir)" \ + "$(DESTDIR)$(pkginc_libdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +am__DEPENDENCIES_1 = +am_libdovecot_ldap_la_OBJECTS = ldap-client.lo ldap-connection.lo \ + ldap-connection-pool.lo ldap-iterator.lo ldap-search.lo \ + ldap-compare.lo ldap-entry.lo +libdovecot_ldap_la_OBJECTS = $(am_libdovecot_ldap_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libdovecot_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdovecot_ldap_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/ldap-client.Plo \ + ./$(DEPDIR)/ldap-compare.Plo \ + ./$(DEPDIR)/ldap-connection-pool.Plo \ + ./$(DEPDIR)/ldap-connection.Plo ./$(DEPDIR)/ldap-entry.Plo \ + ./$(DEPDIR)/ldap-iterator.Plo ./$(DEPDIR)/ldap-search.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libdovecot_ldap_la_SOURCES) +DIST_SOURCES = $(libdovecot_ldap_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APPARMOR_LIBS = @APPARMOR_LIBS@ +AR = @AR@ +AUTH_CFLAGS = @AUTH_CFLAGS@ +AUTH_LIBS = @AUTH_LIBS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINARY_CFLAGS = @BINARY_CFLAGS@ +BINARY_LDFLAGS = @BINARY_LDFLAGS@ +BISON = @BISON@ +CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@ +CASSANDRA_LIBS = @CASSANDRA_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CDB_LIBS = @CDB_LIBS@ +CFLAGS = @CFLAGS@ +CLUCENE_CFLAGS = @CLUCENE_CFLAGS@ +CLUCENE_LIBS = @CLUCENE_LIBS@ +COMPRESS_LIBS = @COMPRESS_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CRYPT_LIBS = @CRYPT_LIBS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DICT_LIBS = @DICT_LIBS@ +DLLIB = @DLLIB@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FLEX = @FLEX@ +FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@ +FUZZER_LDFLAGS = @FUZZER_LDFLAGS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KRB5CONFIG = @KRB5CONFIG@ +KRB5_CFLAGS = @KRB5_CFLAGS@ +KRB5_LIBS = @KRB5_LIBS@ +LD = @LD@ +LDAP_LIBS = @LDAP_LIBS@ +LDFLAGS = @LDFLAGS@ +LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@ +LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@ +LIBCAP = @LIBCAP@ +LIBDOVECOT = @LIBDOVECOT@ +LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@ +LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@ +LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@ +LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@ +LIBDOVECOT_LDA = @LIBDOVECOT_LDA@ +LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@ +LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@ +LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@ +LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@ +LIBDOVECOT_LUA = @LIBDOVECOT_LUA@ +LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@ +LIBDOVECOT_SQL = @LIBDOVECOT_SQL@ +LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@ +LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@ +LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@ +LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@ +LIBICONV = @LIBICONV@ +LIBICU_CFLAGS = @LIBICU_CFLAGS@ +LIBICU_LIBS = @LIBICU_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@ +LIBSODIUM_LIBS = @LIBSODIUM_LIBS@ +LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@ +LIBTIRPC_LIBS = @LIBTIRPC_LIBS@ +LIBTOOL = @LIBTOOL@ +LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ +LIBWRAP_LIBS = @LIBWRAP_LIBS@ +LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LIBS = @LUA_LIBS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MODULE_LIBS = @MODULE_LIBS@ +MODULE_SUFFIX = @MODULE_SUFFIX@ +MYSQL_CFLAGS = @MYSQL_CFLAGS@ +MYSQL_CONFIG = @MYSQL_CONFIG@ +MYSQL_LIBS = @MYSQL_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOPLUGIN_LDFLAGS = @NOPLUGIN_LDFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PANDOC = @PANDOC@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PGSQL_CFLAGS = @PGSQL_CFLAGS@ +PGSQL_LIBS = @PGSQL_LIBS@ +PG_CONFIG = @PG_CONFIG@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +QUOTA_LIBS = @QUOTA_LIBS@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RPCGEN = @RPCGEN@ +RUN_TEST = @RUN_TEST@ +SED = @SED@ +SETTING_FILES = @SETTING_FILES@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SQLITE_CFLAGS = @SQLITE_CFLAGS@ +SQLITE_LIBS = @SQLITE_LIBS@ +SQL_CFLAGS = @SQL_CFLAGS@ +SQL_LIBS = @SQL_LIBS@ +SSL_CFLAGS = @SSL_CFLAGS@ +SSL_LIBS = @SSL_LIBS@ +STRIP = @STRIP@ +SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ +SYSTEMD_LIBS = @SYSTEMD_LIBS@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +ZSTD_CFLAGS = @ZSTD_CFLAGS@ +ZSTD_LIBS = @ZSTD_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dict_drivers = @dict_drivers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rundir = @rundir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sql_drivers = @sql_drivers@ +srcdir = @srcdir@ +ssldir = @ssldir@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +systemdservicetype = @systemdservicetype@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +pkglib_LTLIBRARIES = libdovecot-ldap.la +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-test \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/lib-ssl-iostream \ + $(LDAP_CFLAGS) + +libdovecot_ldap_la_SOURCES = \ + ldap-client.c \ + ldap-connection.c \ + ldap-connection-pool.c \ + ldap-iterator.c \ + ldap-search.c \ + ldap-compare.c \ + ldap-entry.c + +libdovecot_ldap_la_DEPENDENCIES = ../lib-dovecot/libdovecot.la +libdovecot_ldap_la_LDFLAGS = -export-dynamic +libdovecot_ldap_la_LIBADD = ../lib-dovecot/libdovecot.la $(LDAP_LIBS) +headers = \ + ldap-client.h + +noinst_HEADERS = \ + ldap-connection-pool.h \ + ldap-private.h + +pkginc_libdir = $(pkgincludedir) +pkginc_lib_HEADERS = $(headers) +test_libs = \ + ../lib-test/libtest.la \ + ../lib-ssl-iostream/libssl_iostream.la \ + ../lib/liblib.la + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-ldap/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib-ldap/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libdovecot-ldap.la: $(libdovecot_ldap_la_OBJECTS) $(libdovecot_ldap_la_DEPENDENCIES) $(EXTRA_libdovecot_ldap_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdovecot_ldap_la_LINK) -rpath $(pkglibdir) $(libdovecot_ldap_la_OBJECTS) $(libdovecot_ldap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-client.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-compare.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-connection-pool.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-connection.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-entry.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-iterator.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldap-search.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkginc_libHEADERS: $(pkginc_lib_HEADERS) + @$(NORMAL_INSTALL) + @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \ + done + +uninstall-pkginc_libHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(pkginc_libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/ldap-client.Plo + -rm -f ./$(DEPDIR)/ldap-compare.Plo + -rm -f ./$(DEPDIR)/ldap-connection-pool.Plo + -rm -f ./$(DEPDIR)/ldap-connection.Plo + -rm -f ./$(DEPDIR)/ldap-entry.Plo + -rm -f ./$(DEPDIR)/ldap-iterator.Plo + -rm -f ./$(DEPDIR)/ldap-search.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkginc_libHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/ldap-client.Plo + -rm -f ./$(DEPDIR)/ldap-compare.Plo + -rm -f ./$(DEPDIR)/ldap-connection-pool.Plo + -rm -f ./$(DEPDIR)/ldap-connection.Plo + -rm -f ./$(DEPDIR)/ldap-entry.Plo + -rm -f ./$(DEPDIR)/ldap-iterator.Plo + -rm -f ./$(DEPDIR)/ldap-search.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am \ + check-local clean clean-generic clean-libtool \ + clean-pkglibLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkginc_libHEADERS \ + install-pkglibLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-pkginc_libHEADERS uninstall-pkglibLTLIBRARIES + +.PRECIOUS: Makefile + + +check-local: + for bin in $(test_programs); do \ + if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/lib-ldap/ldap-client.c b/src/lib-ldap/ldap-client.c new file mode 100644 index 0000000..bbae910 --- /dev/null +++ b/src/lib-ldap/ldap-client.c @@ -0,0 +1,74 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ldap-connection-pool.h" +#include "ldap-private.h" + +/* Max number of ldap-connections that can be created. For now this is + unlimited since we're assuming our callers aren't calling us with many + different settings. */ +#define LDAP_CONN_POOL_MAX_CONNECTIONS UINT_MAX + +struct ldap_client { + struct ldap_connection_list *list; +}; + +static struct ldap_connection_pool *ldap_conn_pool = NULL; + +int ldap_client_init(const struct ldap_client_settings *set, + struct ldap_client **client_r, const char **error_r) +{ + struct ldap_client *client; + + if (ldap_conn_pool == NULL) + ldap_conn_pool = ldap_connection_pool_init(LDAP_CONN_POOL_MAX_CONNECTIONS); + + client = i_new(struct ldap_client, 1); + if (ldap_connection_pool_get(ldap_conn_pool, client, set, + &client->list, error_r) < 0) { + i_free(client); + return -1; + } + *client_r = client; + return 0; +} + +void ldap_client_deinit(struct ldap_client **_client) +{ + struct ldap_client *client = *_client; + + *_client = NULL; + + ldap_connection_pool_unref(ldap_conn_pool, &client->list); + i_free(client); +} + +void ldap_client_switch_ioloop(struct ldap_client *client) +{ + ldap_connection_switch_ioloop(client->list->conn); +} + +#undef ldap_search_start +void ldap_search_start(struct ldap_client *client, + const struct ldap_search_input *input, + ldap_result_callback_t *callback, void *context) +{ + /* FIXME: we could support multiple concurrent LDAP connections to + the same host. */ + ldap_connection_search_start(client->list->conn, input, callback, context); +} + +#undef ldap_compare_start +void ldap_compare_start(struct ldap_client *client, + const struct ldap_compare_input *input, + ldap_result_callback_t *callback, void *context) +{ + ldap_connection_compare_start(client->list->conn, input, callback, context); +} + +void ldap_clients_cleanup(void) +{ + if (ldap_conn_pool != NULL && + !ldap_connection_pool_have_references(ldap_conn_pool)) + ldap_connection_pool_deinit(&ldap_conn_pool); +} diff --git a/src/lib-ldap/ldap-client.h b/src/lib-ldap/ldap-client.h new file mode 100644 index 0000000..1a231dd --- /dev/null +++ b/src/lib-ldap/ldap-client.h @@ -0,0 +1,102 @@ +#ifndef LDAP_CLIENT_H +#define LDAP_CLIENT_H + +enum ldap_scope { + LDAP_SEARCH_SCOPE_BASE = 0x0000, + LDAP_SEARCH_SCOPE_ONE = 0x0001, + LDAP_SEARCH_SCOPE_SUBTREE = 0x0002 +}; + +struct ldap_client; +struct ldap_result; +struct ldap_search_iterator; +struct ldap_entry; + +/* Called when the LDAP result has finished. The callback must verify first + if the result is valid or not by calling ldap_result_has_failed() or + ldap_result_get_error(). The result is freed automatically after this + callback finishes. */ +typedef void ldap_result_callback_t(struct ldap_result *result, void *context); + +struct ldap_client_settings { + /* NOTE: when adding here, remember to update + ldap_connection_have_settings() and ldap_connection_init() */ + const char *uri; + const char *bind_dn; + const char *password; + + const struct ssl_iostream_settings *ssl_set; + + unsigned int timeout_secs; + unsigned int max_idle_time_secs; + unsigned int debug; + bool require_ssl; + bool start_tls; +}; + +struct ldap_search_input { + const char *base_dn; + const char *filter; + const char *const *attributes; + enum ldap_scope scope; + + unsigned int size_limit; + + unsigned int timeout_secs; +}; + +struct ldap_compare_input { + const char *dn; + const char *attr; + const char *value; + + unsigned int timeout_secs; +}; + +/* Initialize LDAP. Returns 0 on success, or -1 and error_r if initialization + failed with the given settings. */ +int ldap_client_init(const struct ldap_client_settings *set, + struct ldap_client **client_r, const char **error_r); +void ldap_client_deinit(struct ldap_client **client); +void ldap_client_switch_ioloop(struct ldap_client *client); + +/* Deinitialize all pooled LDAP connections if there are no references left. + This allows freeing the memory at deinit, but still allows multiple + independent code parts to use lib-ldap and call this function. */ +void ldap_clients_cleanup(void); + +void ldap_search_start(struct ldap_client *client, + const struct ldap_search_input *input, + ldap_result_callback_t *callback, + void *context); +#define ldap_search_start(client, input, callback, context) \ + ldap_search_start(client, input - \ + CALLBACK_TYPECHECK(callback, void (*)( \ + struct ldap_result *, typeof(context))), \ + (ldap_result_callback_t *)callback, context) + +/* Returns TRUE if the LDAP query failed and result must not be used further. */ +bool ldap_result_has_failed(struct ldap_result *result); +/* Returns the error string if the query had failed, or NULL if it hasn't. */ +const char *ldap_result_get_error(struct ldap_result *result); + +struct ldap_search_iterator* ldap_search_iterator_init(struct ldap_result *result); +const struct ldap_entry *ldap_search_iterator_next(struct ldap_search_iterator *iter); +void ldap_search_iterator_deinit(struct ldap_search_iterator **iter); + +void ldap_compare_start(struct ldap_client *client, + const struct ldap_compare_input *input, + ldap_result_callback_t *callback, void *context); +#define ldap_compare_start(client, input, callback, context) \ + ldap_compare_start(client, input - \ + CALLBACK_TYPECHECK(callback, void (*)( \ + struct ldap_result *, typeof(context))), \ + (ldap_result_callback_t *)callback, context) +/* Returns TRUE if the comparison matched, FALSE if not. */ +bool ldap_compare_result(struct ldap_result *result); + +const char *ldap_entry_dn(const struct ldap_entry *entry); +const char *const *ldap_entry_get_attributes(const struct ldap_entry *entry); +const char *const *ldap_entry_get_attribute(const struct ldap_entry *entry, const char *attribute); + +#endif diff --git a/src/lib-ldap/ldap-compare.c b/src/lib-ldap/ldap-compare.c new file mode 100644 index 0000000..9b17373 --- /dev/null +++ b/src/lib-ldap/ldap-compare.c @@ -0,0 +1,121 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ldap-private.h" + +static int +ldap_compare_callback(struct ldap_connection *conn, + struct ldap_op_queue_entry *req, + LDAPMessage *message, bool *finished_r) +{ + int msgtype = ldap_msgtype(message); + struct ldap_result res; + char *result_errmsg; + int ret, result_err; + + if (msgtype != LDAP_RES_COMPARE) { + *finished_r = FALSE; + return 0; + } + *finished_r = TRUE; + + ret = ldap_parse_result(conn->conn, message, + &result_err, NULL, + &result_errmsg, NULL, NULL, 0); + i_zero(&res); + res.openldap_ret = ret; + if (ret != LDAP_SUCCESS) { + res.error_string = t_strdup_printf( + "ldap_parse_result() failed to parse compare: %s", + ldap_err2string(ret)); + } else if (result_err == LDAP_COMPARE_TRUE) { + res.compare_true = TRUE; + } else if (result_err == LDAP_COMPARE_FALSE) { + res.compare_true = FALSE; + } else { + const struct ldap_compare_input *input = &req->input.compare; + const char *error = result_errmsg != NULL ? + result_errmsg : ldap_err2string(result_err); + res.openldap_ret = result_err; + res.error_string = t_strdup_printf( + "ldap_compare_ext(dn=%s, attr=%s) failed: %s", + input->dn, input->attr, error); + } + + req->result_callback(&res, req->result_callback_ctx); + + if (result_errmsg != NULL) + ldap_memfree(result_errmsg); + return res.openldap_ret; +} + +static int +ldap_compare_send(struct ldap_connection *conn, struct ldap_op_queue_entry *req, + const char **error_r) +{ + const struct ldap_compare_input *input = &req->input.compare; + struct berval bv = { + .bv_len = strlen(input->value), + .bv_val = (void*)input->value + }; + + LDAPControl manageDSAIT = { + LDAP_CONTROL_MANAGEDSAIT, {0, 0}, 0 + }; + + /* try to use ManageDSAIT if available */ + LDAPControl *sctrls[] = { + &manageDSAIT, + NULL + }; + + int ret = ldap_compare_ext(conn->conn, + input->dn, + input->attr, + &bv, + sctrls, + NULL, + &(req->msgid)); + + if (ret != LDAP_SUCCESS) { + *error_r = t_strdup_printf( + "ldap_compare_ext(dn=%s, attr=%s) failed: %s", + input->dn, input->attr, ldap_err2string(ret)); + } + return ret; +} + +void ldap_connection_compare_start(struct ldap_connection *conn, + const struct ldap_compare_input *input, + ldap_result_callback_t *callback, + void *context) +{ + struct ldap_op_queue_entry *req; + pool_t pool = pool_alloconly_create(MEMPOOL_GROWING "ldap compare", 128); + req = p_new(pool, struct ldap_op_queue_entry, 1); + req->pool = pool; + + req->internal_response_cb = ldap_compare_callback; + + req->input.compare = *input; + req->result_callback = callback; + req->result_callback_ctx = context; + + /* copy strings */ + req->input.compare.dn = p_strdup(req->pool, input->dn); + req->input.compare.attr = p_strdup(req->pool, input->attr); + req->input.compare.value = p_strdup(req->pool, input->value); + + req->send_request_cb = ldap_compare_send; + req->timeout_secs = input->timeout_secs; + + ldap_connection_queue_request(conn, req); +} + +bool ldap_compare_result(struct ldap_result *result) +{ + i_assert(result->openldap_ret == LDAP_SUCCESS); + i_assert(result->error_string == NULL); + + return result->compare_true; +} diff --git a/src/lib-ldap/ldap-connection-pool.c b/src/lib-ldap/ldap-connection-pool.c new file mode 100644 index 0000000..7635ce0 --- /dev/null +++ b/src/lib-ldap/ldap-connection-pool.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "llist.h" +#include "ldap-private.h" +#include "ldap-connection-pool.h" + +struct ldap_connection_pool { + struct ldap_connection_list *conn_list; + unsigned int conn_count; + + unsigned int max_connections; +}; + +static void ldap_connection_list_remove(struct ldap_connection_pool *pool, + struct ldap_connection_list *list) +{ + DLLIST_REMOVE(&pool->conn_list, list); + pool->conn_count--; + + ldap_connection_deinit(&list->conn); + i_free(list); +} + +static void +ldap_connection_pool_shrink_to(struct ldap_connection_pool *pool, + unsigned int max_count) +{ + struct ldap_connection_list *list, *next; + + list = pool->conn_list; + for (; list != NULL && pool->conn_count > max_count; list = next) { + next = list->next; + if (list->refcount == 0) + ldap_connection_list_remove(pool, list); + } +} + +struct ldap_connection_pool * +ldap_connection_pool_init(unsigned int max_connections) +{ + struct ldap_connection_pool *pool; + + pool = i_new(struct ldap_connection_pool, 1); + pool->max_connections = max_connections; + return pool; +} + +void ldap_connection_pool_deinit(struct ldap_connection_pool **_pool) +{ + struct ldap_connection_pool *pool = *_pool; + + *_pool = NULL; + + ldap_connection_pool_shrink_to(pool, 0); + i_assert(pool->conn_list == NULL); + i_free(pool); +} + +int ldap_connection_pool_get(struct ldap_connection_pool *pool, + struct ldap_client *client, + const struct ldap_client_settings *set, + struct ldap_connection_list **list_r, + const char **error_r) +{ + struct ldap_connection_list *list; + struct ldap_connection *conn; + + for (list = pool->conn_list; list != NULL; list = list->next) { + if (ldap_connection_have_settings(list->conn, set)) { + list->refcount++; + *list_r = list; + return 0; + } + } + if (ldap_connection_init(client, set, &conn, error_r) < 0) + return -1; + + list = i_new(struct ldap_connection_list, 1); + list->conn = conn; + list->refcount++; + + DLLIST_PREPEND(&pool->conn_list, list); + pool->conn_count++; + + ldap_connection_pool_shrink_to(pool, pool->max_connections); + *list_r = list; + return 0; +} + +void ldap_connection_pool_unref(struct ldap_connection_pool *pool, + struct ldap_connection_list **_list) +{ + struct ldap_connection_list *list = *_list; + + *_list = NULL; + + i_assert(list->refcount > 0); + + if (--list->refcount == 0) + ldap_connection_pool_shrink_to(pool, pool->max_connections); +} + +bool ldap_connection_pool_have_references(struct ldap_connection_pool *pool) +{ + struct ldap_connection_list *list; + + for (list = pool->conn_list; list != NULL; list = list->next) { + if (list->refcount > 0) + return TRUE; + } + return FALSE; +} diff --git a/src/lib-ldap/ldap-connection-pool.h b/src/lib-ldap/ldap-connection-pool.h new file mode 100644 index 0000000..00cf165 --- /dev/null +++ b/src/lib-ldap/ldap-connection-pool.h @@ -0,0 +1,27 @@ +#ifndef LDAP_CONNECTION_POOL_H +#define LDAP_CONNECTION_POOL_H + +struct ldap_client; +struct ldap_client_settings; + +struct ldap_connection_list { + struct ldap_connection_list *prev, *next; + struct ldap_connection *conn; + int refcount; +}; + +struct ldap_connection_pool * +ldap_connection_pool_init(unsigned int max_connections); +void ldap_connection_pool_deinit(struct ldap_connection_pool **_pool); +/* Returns TRUE if there are connections with refcount>0 */ +bool ldap_connection_pool_have_references(struct ldap_connection_pool *pool); + +int ldap_connection_pool_get(struct ldap_connection_pool *pool, + struct ldap_client *client, + const struct ldap_client_settings *set, + struct ldap_connection_list **list_r, + const char **error_r); +void ldap_connection_pool_unref(struct ldap_connection_pool *pool, + struct ldap_connection_list **list); + +#endif diff --git a/src/lib-ldap/ldap-connection.c b/src/lib-ldap/ldap-connection.c new file mode 100644 index 0000000..95a91ea --- /dev/null +++ b/src/lib-ldap/ldap-connection.c @@ -0,0 +1,714 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "aqueue.h" +#include "ioloop.h" +#include "ldap-private.h" + +static +void ldap_connection_read_more(struct ldap_connection *conn); +static +int ldap_connect_next_message(struct ldap_connection *conn, struct ldap_op_queue_entry *req, bool *finished_r); +static +void ldap_connection_abort_request(struct ldap_op_queue_entry *req); +static +void ldap_connection_request_destroy(struct ldap_op_queue_entry **req); +static +int ldap_connection_connect(struct ldap_connection *conn); +static +void ldap_connection_send_next(struct ldap_connection *conn); + +void ldap_connection_deinit(struct ldap_connection **_conn) +{ + struct ldap_connection *conn = *_conn; + + *_conn = NULL; + + ldap_connection_kill(conn); + + unsigned int n = aqueue_count(conn->request_queue); + for (unsigned int i = 0; i < n; i++) { + struct ldap_op_queue_entry *req = + array_idx_elem(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + timeout_remove(&req->to_abort); + } + pool_unref(&conn->pool); +} + +static +int ldap_connection_setup(struct ldap_connection *conn, const char **error_r) +{ + int ret, opt; + + ret = ldap_initialize(&conn->conn, conn->set.uri); + if (ret != LDAP_SUCCESS) { + *error_r = t_strdup_printf("ldap_initialize(uri=%s) failed: %s", + conn->set.uri, ldap_err2string(ret)); + return -1; + } + + if (conn->ssl_set.verify_remote_cert) { + opt = LDAP_OPT_X_TLS_HARD; + } else { + opt = LDAP_OPT_X_TLS_ALLOW; + } + + ldap_set_option(conn->conn, LDAP_OPT_X_TLS, &opt); + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_REQUIRE_CERT, &opt); +#ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN + /* refuse to connect to SSLv2 as it's completely insecure */ + opt = LDAP_OPT_X_TLS_PROTOCOL_SSL3; + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_PROTOCOL_MIN, &opt); +#endif + opt = conn->set.timeout_secs; + /* default timeout */ + ldap_set_option(conn->conn, LDAP_OPT_TIMEOUT, &opt); + ldap_set_option(conn->conn, LDAP_OPT_NETWORK_TIMEOUT, &opt); + /* timelimit */ + ldap_set_option(conn->conn, LDAP_OPT_TIMELIMIT, &opt); + + if (conn->ssl_set.ca_file != NULL) + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_CACERTFILE, conn->ssl_set.ca_file); + if (conn->ssl_set.ca_dir != NULL) + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_CACERTDIR, conn->ssl_set.ca_dir); + + if (conn->ssl_set.cert.cert != NULL) + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_CERTFILE, conn->ssl_set.cert.cert); + if (conn->ssl_set.cert.key != NULL) + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_KEYFILE, conn->ssl_set.cert.key); + + opt = conn->set.debug; + ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &opt); + + opt = LDAP_VERSION3; + ldap_set_option(conn->conn, LDAP_OPT_PROTOCOL_VERSION, &opt); + + ldap_set_option(conn->conn, LDAP_OPT_REFERRALS, 0); + +#ifdef LDAP_OPT_X_TLS_NEWCTX + opt = 0; + ldap_set_option(conn->conn, LDAP_OPT_X_TLS_NEWCTX, &opt); +#endif + + return 0; +} + +bool ldap_connection_have_settings(struct ldap_connection *conn, + const struct ldap_client_settings *set) +{ + const struct ldap_client_settings *conn_set = &conn->set; + + if (strcmp(conn_set->uri, set->uri) != 0) + return FALSE; + if (null_strcmp(conn_set->bind_dn, set->bind_dn) != 0) + return FALSE; + if (null_strcmp(conn_set->password, set->password) != 0) + return FALSE; + if (conn_set->timeout_secs != set->timeout_secs || + conn_set->max_idle_time_secs != set->max_idle_time_secs || + conn_set->debug != set->debug || + conn_set->require_ssl != set->require_ssl || + conn_set->start_tls != set->start_tls) + return FALSE; + + if (set->ssl_set == NULL || !set->start_tls) + return TRUE; + + /* check SSL settings */ + if (null_strcmp(conn->ssl_set.min_protocol, set->ssl_set->min_protocol) != 0) + return FALSE; + if (null_strcmp(conn->ssl_set.cipher_list, set->ssl_set->cipher_list) != 0) + return FALSE; + if (null_strcmp(conn->ssl_set.ca_file, set->ssl_set->ca_file) != 0) + return FALSE; + if (null_strcmp(conn->ssl_set.cert.cert, set->ssl_set->cert.cert) != 0) + return FALSE; + if (null_strcmp(conn->ssl_set.cert.key, set->ssl_set->cert.key) != 0) + return FALSE; + return TRUE; +} + +int ldap_connection_init(struct ldap_client *client, + const struct ldap_client_settings *set, + struct ldap_connection **conn_r, const char **error_r) +{ + i_assert(set->uri != NULL); + + if (set->require_ssl && + !set->start_tls && + strncmp("ldaps://",set->uri,8) != 0) { + *error_r = t_strdup_printf("ldap_connection_init(uri=%s) failed: %s", set->uri, + "uri does not start with ldaps and ssl required without start TLS"); + return -1; + } + + pool_t pool = pool_alloconly_create("ldap connection", 1024); + struct ldap_connection *conn = p_new(pool, struct ldap_connection, 1); + conn->pool = pool; + + conn->client = client; + conn->set = *set; + /* deep copy relevant strings */ + conn->set.uri = p_strdup(pool, set->uri); + conn->set.bind_dn = p_strdup(pool, set->bind_dn); + if (set->password != NULL) { + conn->set.password = p_strdup(pool, set->password); + ber_str2bv(conn->set.password, strlen(conn->set.password), 0, &conn->cred); + } + /* cannot use these */ + conn->ssl_set.ca = NULL; + conn->ssl_set.cert.key_password = NULL; + conn->ssl_set.cert_username_field = NULL; + conn->ssl_set.crypto_device = NULL; + + if (set->ssl_set != NULL) { + /* keep in sync with ldap_connection_have_settings() */ + conn->set.ssl_set = &conn->ssl_set; + conn->ssl_set.min_protocol = p_strdup(pool, set->ssl_set->min_protocol); + conn->ssl_set.cipher_list = p_strdup(pool, set->ssl_set->cipher_list); + conn->ssl_set.ca_file = p_strdup(pool, set->ssl_set->ca_file); + conn->ssl_set.cert.cert = p_strdup(pool, set->ssl_set->cert.cert); + conn->ssl_set.cert.key = p_strdup(pool, set->ssl_set->cert.key); + } + i_assert(ldap_connection_have_settings(conn, set)); + + if (ldap_connection_setup(conn, error_r) < 0) { + ldap_connection_deinit(&conn); + return -1; + } + + p_array_init(&conn->request_array, conn->pool, 10); + conn->request_queue = aqueue_init(&conn->request_array.arr); + + *conn_r = conn; + return 0; +} + +void ldap_connection_switch_ioloop(struct ldap_connection *conn) +{ + if (conn->io != NULL) + conn->io = io_loop_move_io(&conn->io); + if (conn->to_disconnect != NULL) + conn->to_disconnect = io_loop_move_timeout(&conn->to_disconnect); + if (conn->to_reconnect != NULL) + conn->to_reconnect = io_loop_move_timeout(&conn->to_reconnect); + unsigned int n = aqueue_count(conn->request_queue); + + for (unsigned int i = 0; i < n; i++) { + struct ldap_op_queue_entry *req = + array_idx_elem(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + if (req->to_abort != NULL) + req->to_abort = io_loop_move_timeout(&req->to_abort); + } +} + +static void +ldap_connection_result_failure(struct ldap_connection *conn, + struct ldap_op_queue_entry *req, + int ret, const char *error) +{ + struct ldap_result res; + i_zero(&res); + res.conn = conn; + res.openldap_ret = ret; + res.error_string = error; + if (req->result_callback != NULL) + req->result_callback(&res, req->result_callback_ctx); + else + i_error("%s", error); + ldap_connection_kill(conn); +} + +static +void ldap_connection_result_success(struct ldap_connection *conn, + struct ldap_op_queue_entry *req) +{ + struct ldap_result res; + i_zero(&res); + res.conn = conn; + res.openldap_ret = LDAP_SUCCESS; + if (req->result_callback != NULL) + req->result_callback(&res, req->result_callback_ctx); +} + +static struct ldap_op_queue_entry * +ldap_connection_next_unsent_request(struct ldap_connection *conn, + unsigned int *index_r) +{ + struct ldap_op_queue_entry *last_req = NULL; + *index_r = 0; + + for (unsigned int i = 0; i < aqueue_count(conn->request_queue); i++) { + struct ldap_op_queue_entry *req = + array_idx_elem(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + if (req->msgid > -1) + break; + *index_r = i; + last_req = req; + } + return last_req; +} + +static +void ldap_connection_send_next(struct ldap_connection *conn) +{ + unsigned int index; + struct ldap_op_queue_entry *req; + + timeout_remove(&conn->to_reconnect); + + if (conn->state == LDAP_STATE_DISCONNECT) { + if (ldap_connection_connect(conn) == -1) + conn->to_reconnect = timeout_add(1000, ldap_connection_send_next, conn); + return; + } + + if (conn->state != LDAP_STATE_CONNECT) { + return; + } + + if (conn->pending > 10) return; /* try again later */ + + req = ldap_connection_next_unsent_request(conn, &index); + /* nothing to actually send */ + if (req == NULL) return; + + i_assert(req->msgid == -1); + + const char *error; + int ret; + if ((ret = req->send_request_cb(conn, req, &error)) != LDAP_SUCCESS) { + /* did not succeed */ + struct ldap_result res; + + i_zero(&res); + res.openldap_ret = ret; + res.error_string = error; + if (req->result_callback != NULL) + req->result_callback(&res, req->result_callback_ctx); + + ldap_connection_request_destroy(&req); + aqueue_delete(conn->request_queue, index); + } else conn->pending++; +} + +static +void ldap_connection_request_destroy(struct ldap_op_queue_entry **_req) +{ + struct ldap_op_queue_entry *req = *_req; + + *_req = NULL; + + timeout_remove(&req->to_abort); + pool_unref(&req->pool); +} + +void ldap_connection_queue_request(struct ldap_connection *conn, struct ldap_op_queue_entry *req) +{ + req->msgid = -1; + req->conn = conn; + aqueue_append(conn->request_queue, &req); + if (req->timeout_secs > 0) + req->to_abort = timeout_add(req->timeout_secs * 1000, ldap_connection_abort_request, req); + + ldap_connection_send_next(conn); +} + +static int +ldap_connection_connect_parse(struct ldap_connection *conn, + struct ldap_op_queue_entry *req, + LDAPMessage *message, bool *finished_r) +{ + int ret, result_err; + char *retoid, *result_errmsg; + int msgtype = ldap_msgtype(message); + + *finished_r = TRUE; + ret = ldap_parse_result(conn->conn, message, &result_err, NULL, + &result_errmsg, NULL, NULL, 0); + + switch(conn->state) { + case LDAP_STATE_TLS: + if (msgtype != LDAP_RES_EXTENDED) { + *finished_r = FALSE; + return LDAP_SUCCESS; + } + if (ret != 0) { + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_start_tls(uri=%s) failed: %s", + conn->set.uri, ldap_err2string(ret))); + return ret; + } else if (result_err != 0) { + if (conn->set.require_ssl) { + ldap_connection_result_failure(conn, req, result_err, t_strdup_printf( + "ldap_start_tls(uri=%s) failed: %s", + conn->set.uri, result_errmsg)); + ldap_memfree(result_errmsg); + return LDAP_INVALID_CREDENTIALS; /* make sure it disconnects */ + } + } else { + ret = ldap_parse_extended_result(conn->conn, message, &retoid, NULL, 0); + /* retoid can be NULL even if ret == 0 */ + if (ret == 0) { + ret = ldap_install_tls(conn->conn); + if (ret != 0) { + // if this fails we have to abort + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_start_tls(uri=%s) failed: %s", + conn->set.uri, ldap_err2string(ret))); + return LDAP_INVALID_CREDENTIALS; + } + } + if (ret != LDAP_SUCCESS) { + if (conn->set.require_ssl) { + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_start_tls(uri=%s) failed: %s", + conn->set.uri, ldap_err2string(ret))); + return LDAP_UNAVAILABLE; + } + } else { + if (conn->set.debug > 0) + i_debug("Using TLS connection to remote LDAP server"); + } + ldap_memfree(retoid); + } + conn->state = LDAP_STATE_AUTH; + return ldap_connect_next_message(conn, req, finished_r); + case LDAP_STATE_AUTH: + if (ret != LDAP_SUCCESS) { + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_parse_result() failed for connect: %s", + ldap_err2string(ret))); + return ret; + } + if (result_err != LDAP_SUCCESS) { + const char *error = result_errmsg != NULL ? + result_errmsg : ldap_err2string(result_err); + ldap_connection_result_failure(conn, req, result_err, t_strdup_printf( + "Connect failed: %s", error)); + ldap_memfree(result_errmsg); + return result_err; + } + if (msgtype != LDAP_RES_BIND) return 0; + ret = ldap_parse_sasl_bind_result(conn->conn, message, &conn->scred, 0); + if (ret != LDAP_SUCCESS) { + const char *error = t_strdup_printf( + "Cannot bind with server: %s", ldap_err2string(ret)); + ldap_connection_result_failure(conn, req, ret, error); + return 1; + } + conn->state = LDAP_STATE_CONNECT; + return ldap_connect_next_message(conn, req, finished_r); + default: + i_unreached(); + } + i_unreached(); +} + +static +void ldap_connection_abort_request(struct ldap_op_queue_entry *req) +{ + struct ldap_result res; + + /* too bad */ + timeout_remove(&req->to_abort); + if (req->msgid > -1) + ldap_abandon_ext(req->conn->conn, req->msgid, NULL, NULL); + + i_zero(&res); + res.openldap_ret = LDAP_TIMEOUT; + res.error_string = "Aborting LDAP request after timeout"; + if (req->result_callback != NULL) + req->result_callback(&res, req->result_callback_ctx); + + unsigned int n = aqueue_count(req->conn->request_queue); + for (unsigned int i = 0; i < n; i++) { + struct ldap_op_queue_entry *arr_req = + array_idx_elem(&req->conn->request_array, + aqueue_idx(req->conn->request_queue, i)); + if (req == arr_req) { + aqueue_delete(req->conn->request_queue, i); + ldap_connection_request_destroy(&req); + return; + } + } + i_unreached(); +} + +static +void ldap_connection_abort_all_requests(struct ldap_connection *conn) +{ + struct ldap_result res; + i_zero(&res); + res.openldap_ret = LDAP_TIMEOUT; + res.error_string = "Aborting LDAP requests due to failure"; + + unsigned int n = aqueue_count(conn->request_queue); + for (unsigned int i = 0; i < n; i++) { + struct ldap_op_queue_entry **reqp = + array_idx_modifiable(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + timeout_remove(&(*reqp)->to_abort); + if ((*reqp)->result_callback != NULL) + (*reqp)->result_callback(&res, (*reqp)->result_callback_ctx); + ldap_connection_request_destroy(reqp); + } + aqueue_clear(conn->request_queue); +} + +static int +ldap_connect_next_message(struct ldap_connection *conn, + struct ldap_op_queue_entry *req, bool *finished_r) +{ + int ret; + + *finished_r = TRUE; + + switch(conn->state) { + case LDAP_STATE_DISCONNECT: + /* if we should not disable SSL, and the URI is not ldaps:// */ + if (!conn->set.start_tls || strstr(conn->set.uri, "ldaps://") == NULL) { + ret = ldap_start_tls(conn->conn, NULL, NULL, &req->msgid); + if (ret != LDAP_SUCCESS) { + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_start_tls(uri=%s) failed: %s", + conn->set.uri, ldap_err2string(ret))); + return ret; + } + conn->state = LDAP_STATE_TLS; + break; + } + conn->state = LDAP_STATE_AUTH; + /* fall through */ + case LDAP_STATE_AUTH: + ret = ldap_sasl_bind(conn->conn, + conn->set.bind_dn, + LDAP_SASL_SIMPLE, + &conn->cred, + NULL, + NULL, + &req->msgid); + if (ret != LDAP_SUCCESS) { + ldap_connection_result_failure(conn, req, ret, t_strdup_printf( + "ldap_sasl_bind(uri=%s, dn=%s) failed: %s", + conn->set.uri, conn->set.bind_dn, ldap_err2string(ret))); + return ret; + } + break; + case LDAP_STATE_CONNECT: + ldap_connection_result_success(conn, req); + return LDAP_SUCCESS; /* we are done here */ + default: + i_unreached(); + }; + + req->conn = conn; + *finished_r = FALSE; + return LDAP_SUCCESS; +} + +static +int ldap_connection_connect(struct ldap_connection *conn) +{ + const char *error; + int fd; + Sockbuf *sb; + bool finished; + + if (conn->conn == NULL) { + /* try to reconnect after disconnection */ + if (ldap_connection_setup(conn, &error) < 0) + i_error("%s", error); + } + + pool_t pool = pool_alloconly_create(MEMPOOL_GROWING "ldap bind", 128); + struct ldap_op_queue_entry *req = p_new(pool, struct ldap_op_queue_entry, 1); + req->pool = pool; + + req->internal_response_cb = ldap_connection_connect_parse; + req->timeout_secs = conn->set.timeout_secs; + + if (ldap_connect_next_message(conn, req, &finished) != LDAP_SUCCESS || + conn->conn == NULL) { + pool_unref(&pool); + return -1; + } + conn->pending++; + aqueue_append(conn->request_queue, &req); + /* start timeout */ + if (req->timeout_secs > 0) + req->to_abort = timeout_add(req->timeout_secs * 1000, ldap_connection_abort_request, req); + + ldap_get_option(conn->conn, LDAP_OPT_SOCKBUF, &sb); + ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &fd); + conn->io = io_add(fd, IO_READ, ldap_connection_read_more, conn); + if (conn->set.max_idle_time_secs > 0) + conn->to_disconnect = timeout_add(conn->set.max_idle_time_secs * 1000, ldap_connection_kill, conn); + return 0; +} + +void ldap_connection_kill(struct ldap_connection *conn) +{ + io_remove_closed(&conn->io); + timeout_remove(&conn->to_disconnect); + timeout_remove(&conn->to_reconnect); + if (conn->request_queue != NULL) { + unsigned int n = aqueue_count(conn->request_queue); + + for (unsigned int i = 0; i < n; i++) { + struct ldap_op_queue_entry *req = + array_idx_elem(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + if (req->msgid > -1) + ldap_abandon_ext(conn->conn, req->msgid, NULL, NULL); + req->msgid = -1; + } + } + if (conn->conn != NULL) { + ldap_unbind_ext(conn->conn, NULL, NULL); + ldap_memfree(conn->scred); + } + conn->conn = NULL; + conn->state = LDAP_STATE_DISCONNECT; +} + +int ldap_connection_check(struct ldap_connection *conn) +{ + /* it's not connected */ + if (conn->state == LDAP_STATE_DISCONNECT) return -1; + return 0; +} + +static struct ldap_op_queue_entry * +ldap_connection_find_req_by_msgid(struct ldap_connection *conn, int msgid, + unsigned int *idx_r) +{ + unsigned int i, n = aqueue_count(conn->request_queue); + for (i = 0; i < n; i++) { + struct ldap_op_queue_entry *req = + array_idx_elem(&conn->request_array, + aqueue_idx(conn->request_queue, i)); + if (req->msgid == msgid) { + *idx_r = i; + return req; + } + } + return NULL; +} + +static int +ldap_connection_handle_message(struct ldap_connection *conn, + LDAPMessage *message) +{ + struct ldap_op_queue_entry *req; + unsigned int i = 0; + bool finished = FALSE; + int err = LDAP_SUCCESS; + + /* we need to look at who it was for */ + req = ldap_connection_find_req_by_msgid(conn, ldap_msgid(message), &i); + if (req != NULL) + err = req->internal_response_cb(conn, req, message, &finished); + ldap_msgfree(message); + + switch(err) { + case LDAP_SUCCESS: + break; + case LDAP_SERVER_DOWN: +#ifdef LDAP_CONNECT_ERROR + case LDAP_CONNECT_ERROR: +#endif + case LDAP_UNAVAILABLE: + case LDAP_OPERATIONS_ERROR: + case LDAP_BUSY: + /* requeue */ + ldap_connection_kill(conn); + ldap_connection_send_next(conn); + finished = FALSE; + break; + case LDAP_INVALID_CREDENTIALS: { + /* fail everything */ + ldap_connection_kill(conn); + ldap_connection_abort_all_requests(conn); + return 0; + } + case LDAP_SIZELIMIT_EXCEEDED: + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_NO_SUCH_ATTRIBUTE: + case LDAP_UNDEFINED_TYPE: + case LDAP_INAPPROPRIATE_MATCHING: + case LDAP_CONSTRAINT_VIOLATION: + case LDAP_TYPE_OR_VALUE_EXISTS: + case LDAP_INVALID_SYNTAX: + case LDAP_NO_SUCH_OBJECT: + case LDAP_ALIAS_PROBLEM: + case LDAP_INVALID_DN_SYNTAX: + case LDAP_IS_LEAF: + case LDAP_ALIAS_DEREF_PROBLEM: + case LDAP_FILTER_ERROR: + case LDAP_LOCAL_ERROR: + finished = TRUE; + break; + default: + /* ignore */ + break; + } + + if (finished) { + i_assert(req != NULL); + ldap_connection_request_destroy(&req); + conn->pending--; + aqueue_delete(conn->request_queue, i); + return 1; + } + return 0; +} + +static +void ldap_connection_read_more(struct ldap_connection *conn) +{ + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 0 + }; + + LDAPMessage *message; + int ret; + + /* try get a message */ + ret = ldap_result(conn->conn, LDAP_RES_ANY, 0, &tv, &message); + if (ret > 0) + ret = ldap_connection_handle_message(conn, message); + + if (ret == -1) { + if (ldap_get_option(conn->conn, LDAP_OPT_RESULT_CODE, &ret) != LDAP_SUCCESS) + i_unreached(); + if (ret != LDAP_SERVER_DOWN) + i_error("ldap_result() failed: %s", ldap_err2string(ret)); + else + i_error("Connection lost to LDAP server, reconnecting"); + /* kill me */ + ldap_connection_kill(conn); + } else if (ret != 0) { + ldap_connection_send_next(conn); + } + /* reset timeout */ + if (conn->to_disconnect != NULL) + timeout_reset(conn->to_disconnect); +} + +bool ldap_result_has_failed(struct ldap_result *result) +{ + i_assert((result->openldap_ret == LDAP_SUCCESS) == (result->error_string == NULL)); + return result->openldap_ret != LDAP_SUCCESS; +} + +const char *ldap_result_get_error(struct ldap_result *result) +{ + i_assert((result->openldap_ret == LDAP_SUCCESS) == (result->error_string == NULL)); + return result->error_string; +} diff --git a/src/lib-ldap/ldap-entry.c b/src/lib-ldap/ldap-entry.c new file mode 100644 index 0000000..639b931 --- /dev/null +++ b/src/lib-ldap/ldap-entry.c @@ -0,0 +1,72 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ldap-private.h" + +int ldap_entry_init(struct ldap_entry *obj, struct ldap_result *result, + LDAPMessage *message) +{ + ARRAY_TYPE(const_string) attr_names; + struct berval **values; + int count; + BerElement *bptr; + char *tmp; + tmp = ldap_get_dn(result->conn->conn, message); + obj->dn = p_strdup(result->pool, tmp); + obj->result = result; + ldap_memfree(tmp); + + tmp = ldap_first_attribute(result->conn->conn, message, &bptr); + + p_array_init(&attr_names, result->pool, 8); + p_array_init(&obj->attributes, result->pool, 8); + + while(tmp != NULL) { + struct ldap_attribute *attr = p_new(result->pool, struct ldap_attribute, 1); + attr->name = p_strdup(result->pool, tmp); + array_push_back(&attr_names, &attr->name); + values = ldap_get_values_len(result->conn->conn, message, tmp); + if (values != NULL) { + count = ldap_count_values_len(values); + p_array_init(&attr->values, result->pool, count); + for(int i = 0; i < count; i++) { + const char *ptr = p_strndup(result->pool, values[i]->bv_val, values[i]->bv_len); + array_push_back(&attr->values, &ptr); + } + ldap_value_free_len(values); + } + array_append_zero(&attr->values); + ldap_memfree(tmp); + array_push_back(&obj->attributes, attr); + tmp = ldap_next_attribute(result->conn->conn, message, bptr); + } + + ber_free(bptr, 0); + + array_append_zero(&attr_names); + obj->attr_names = array_front(&attr_names); + + return 0; +} + +const char *ldap_entry_dn(const struct ldap_entry *entry) +{ + return entry->dn; +} + +const char *const *ldap_entry_get_attributes(const struct ldap_entry *entry) +{ + return entry->attr_names; +} + +const char *const *ldap_entry_get_attribute(const struct ldap_entry *entry, const char *attribute) +{ + const struct ldap_attribute *attr; + array_foreach(&entry->attributes, attr) { + if (strcasecmp(attr->name, attribute) == 0) { + return array_front(&attr->values); + } + } + return NULL; +} diff --git a/src/lib-ldap/ldap-iterator.c b/src/lib-ldap/ldap-iterator.c new file mode 100644 index 0000000..d825f6c --- /dev/null +++ b/src/lib-ldap/ldap-iterator.c @@ -0,0 +1,29 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ldap-private.h" + +struct ldap_search_iterator* ldap_search_iterator_init(struct ldap_result *result) +{ + struct ldap_search_iterator *iter; + + i_assert(result->openldap_ret == LDAP_SUCCESS); + i_assert(result->error_string == NULL); + + iter = p_new(result->pool, struct ldap_search_iterator, 1); + iter->result = result; + return iter; +} + +const struct ldap_entry *ldap_search_iterator_next(struct ldap_search_iterator *iter) +{ + if (iter->idx >= array_count(&iter->result->entries)) + return NULL; + return array_idx(&iter->result->entries, iter->idx++); +} + +void ldap_search_iterator_deinit(struct ldap_search_iterator **iter) +{ + *iter = NULL; +} diff --git a/src/lib-ldap/ldap-private.h b/src/lib-ldap/ldap-private.h new file mode 100644 index 0000000..fa724f4 --- /dev/null +++ b/src/lib-ldap/ldap-private.h @@ -0,0 +1,129 @@ +#ifndef LDAP_PRIVATE_H +#define LDAP_PRIVATE_H + +#include "iostream-ssl.h" +#include "ldap-client.h" + +#include <ldap.h> + +#define DOVE_LDAP_CONTINUE 0 +#define DOVE_LDAP_COMPLETE 1 +#define DOVE_LDAP_REQUEUE 2 + +struct ldap_connection; +struct ldap_result; + +struct ldap_op_queue_entry; +/* Handle an LDAP response. Returns 0 on success, otherwise the OpenLDAP error + number. */ +typedef int ldap_response_callback_t(struct ldap_connection *conn, + struct ldap_op_queue_entry *entry, + LDAPMessage *msg, bool *finished_r); +/* Send the request. Returns 0 on success, otherwise the OpenLDAP error number + and sets error_r string. */ +typedef int ldap_send_request_t(struct ldap_connection *conn, + struct ldap_op_queue_entry *entry, + const char **error_r); + +struct ldap_op_queue_entry { + pool_t pool; + struct ldap_connection *conn; + ldap_response_callback_t *internal_response_cb; + void *ctx; + + int msgid; + + unsigned int timeout_secs; + struct timeout *to_abort; + + ldap_send_request_t *send_request_cb; + + ldap_result_callback_t *result_callback; + void *result_callback_ctx; + + struct { + struct ldap_search_input search; + struct ldap_compare_input compare; + } input; +}; + +struct ldap_connection { + pool_t pool; + struct ldap_client *client; + + LDAP *conn; + enum { + LDAP_STATE_DISCONNECT, + LDAP_STATE_TLS, + LDAP_STATE_AUTH, + LDAP_STATE_CONNECT + } state; + + BerValue cred; /* needed for SASL */ + BerVarray scred; + + struct ldap_client_settings set; + struct ssl_iostream_settings ssl_set; + + struct aqueue *request_queue; + ARRAY(struct ldap_op_queue_entry *) request_array; + + unsigned int sent; + unsigned int pending; + + struct io *io; + struct timeout *to_disconnect; + struct timeout *to_reconnect; +}; + +struct ldap_attribute { + const char *name; + ARRAY_TYPE(const_string) values; +}; + +struct ldap_entry { + struct ldap_result *result; + char *dn; + ARRAY(struct ldap_attribute) attributes; + const char *const *attr_names; +}; + +struct ldap_result { + pool_t pool; + struct ldap_connection *conn; + + ARRAY(struct ldap_entry) entries; + int openldap_ret; + bool compare_true; + const char *error_string; +}; + +struct ldap_search_iterator { + unsigned int idx; + struct ldap_result *result; +}; + +int ldap_connection_init(struct ldap_client *client, + const struct ldap_client_settings *set, + struct ldap_connection **conn_r, const char **error_r); +void ldap_connection_deinit(struct ldap_connection **_conn); +void ldap_connection_switch_ioloop(struct ldap_connection *conn); +bool ldap_connection_have_settings(struct ldap_connection *conn, + const struct ldap_client_settings *set); + +void ldap_connection_search_start(struct ldap_connection *conn, + const struct ldap_search_input *input, + ldap_result_callback_t *callback, + void *context); +void ldap_connection_compare_start(struct ldap_connection *conn, + const struct ldap_compare_input *input, + ldap_result_callback_t *callback, + void *context); + +void ldap_connection_kill(struct ldap_connection *conn); +int ldap_connection_check(struct ldap_connection *conn); +void ldap_connection_queue_request(struct ldap_connection *conn, struct ldap_op_queue_entry *req); + +int ldap_entry_init(struct ldap_entry *obj, struct ldap_result *result, LDAPMessage *message); + +#endif diff --git a/src/lib-ldap/ldap-search.c b/src/lib-ldap/ldap-search.c new file mode 100644 index 0000000..694fd6d --- /dev/null +++ b/src/lib-ldap/ldap-search.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ldap-private.h" + +#include <stdio.h> +#include <sys/time.h> + +struct ldap_search_ctx { + const struct ldap_search_input *input; + struct ldap_result res; +}; + +static void +ldap_search_result_failure(struct ldap_op_queue_entry *req, + int ret, const char *error) +{ + struct ldap_search_ctx *sctx = req->ctx; + sctx->res.openldap_ret = ret; + sctx->res.error_string = error; + req->result_callback(&sctx->res, req->result_callback_ctx); +} + +static void ldap_search_result_success(struct ldap_op_queue_entry *req) +{ + struct ldap_search_ctx *sctx = req->ctx; + sctx->res.openldap_ret = LDAP_SUCCESS; + req->result_callback(&sctx->res, req->result_callback_ctx); +} + +static int +ldap_search_callback(struct ldap_connection *conn, + struct ldap_op_queue_entry *req, + LDAPMessage *message, bool *finished_r) +{ + struct ldap_search_ctx *sctx = req->ctx; + int msgtype = ldap_msgtype(message); + char *result_errmsg = NULL; + int ret, result_err; + + if (msgtype != LDAP_RES_SEARCH_ENTRY && + msgtype != LDAP_RES_SEARCH_RESULT) { + *finished_r = FALSE; + return LDAP_SUCCESS; + } + *finished_r = TRUE; + + ret = ldap_parse_result(conn->conn, message, &result_err, NULL, + &result_errmsg, NULL, NULL, 0); + if (ret == LDAP_NO_RESULTS_RETURNED) { + /*ret = LDAP_SUCCESS;*/ + } else if (ret != LDAP_SUCCESS) { + ldap_search_result_failure(req, ret, t_strdup_printf( + "ldap_parse_result() failed for search: %s", ldap_err2string(ret))); + return ret; + } else if (result_err != LDAP_SUCCESS) { + const struct ldap_search_input *input = &req->input.search; + const char *error = result_errmsg != NULL ? + result_errmsg : ldap_err2string(result_err); + ldap_search_result_failure(req, result_err, t_strdup_printf( + "ldap_search_ext(base=%s, scope=%d, filter=%s) failed: %s", + input->base_dn, input->scope, input->filter, error)); + ldap_memfree(result_errmsg); + return result_err; + } + + LDAPMessage *res = ldap_first_entry(conn->conn, message); + + while(res != NULL) { + struct ldap_entry *obj = p_new(req->pool, struct ldap_entry, 1); + ldap_entry_init(obj, &sctx->res, message); + array_push_back(&sctx->res.entries, obj); + res = ldap_next_entry(conn->conn, res); + } + + if (msgtype == LDAP_RES_SEARCH_RESULT) { + ldap_search_result_success(req); + return LDAP_SUCCESS; + } + + *finished_r = FALSE; + return LDAP_SUCCESS; +} + +static int +ldap_search_send(struct ldap_connection *conn, struct ldap_op_queue_entry *req, + const char **error_r) +{ + const struct ldap_search_input *input = &req->input.search; + LDAPControl manageDSAIT = { + LDAP_CONTROL_MANAGEDSAIT, {0, 0}, 0 + }; + /* try to use ManageDSAIT if available */ + LDAPControl *sctrls[] = { + &manageDSAIT, + NULL + }; + + struct timeval tv = { + .tv_sec = req->timeout_secs, + .tv_usec = 0 + }; + + int ret = ldap_search_ext(conn->conn, + input->base_dn, + input->scope, + input->filter, + (char**)input->attributes, + 0, + sctrls, + NULL, + &tv, + input->size_limit, + &req->msgid); + + if (ret != LDAP_SUCCESS) { + *error_r = t_strdup_printf( + "ldap_search_ext(base=%s, scope=%d, filter=%s) failed: %s", + input->base_dn, input->scope, input->filter, + ldap_err2string(ret)); + } + return ret; +} + +void ldap_connection_search_start(struct ldap_connection *conn, + const struct ldap_search_input *input, + ldap_result_callback_t *callback, + void *context) +{ + struct ldap_op_queue_entry *req; + pool_t pool = pool_alloconly_create(MEMPOOL_GROWING "ldap search", 128); + req = p_new(pool, struct ldap_op_queue_entry, 1); + req->pool = pool; + + struct ldap_search_ctx *sctx = p_new(pool, struct ldap_search_ctx, 1); + sctx->res.conn = conn; + sctx->res.pool = pool; + + p_array_init(&sctx->res.entries, req->pool, 8); + + req->internal_response_cb = ldap_search_callback; + + req->result_callback = callback; + req->result_callback_ctx = context; + req->input.search = *input; + + /* copy strings */ + req->input.search.base_dn = p_strdup(req->pool, input->base_dn); + req->input.search.filter = p_strdup(req->pool, input->filter); + + if (input->attributes != NULL) { + ARRAY_TYPE(const_string) arr; + p_array_init(&arr, req->pool, 8); + for (const char *const *ptr = input->attributes; *ptr != NULL; ptr++) { + const char *tmp = p_strdup(req->pool, *ptr); + array_push_back(&arr, &tmp); + } + array_append_zero(&arr); + req->input.search.attributes = array_front_modifiable(&arr); + } + + req->send_request_cb = ldap_search_send; + sctx->input = &req->input.search; + req->ctx = sctx; + req->timeout_secs = input->timeout_secs; + + ldap_connection_queue_request(conn, req); +} |