diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-lda/Makefile.am | 35 | ||||
-rw-r--r-- | src/lib-lda/Makefile.in | 878 | ||||
-rw-r--r-- | src/lib-lda/lda-settings.c | 80 | ||||
-rw-r--r-- | src/lib-lda/lda-settings.h | 21 | ||||
-rw-r--r-- | src/lib-lda/mail-deliver.c | 810 | ||||
-rw-r--r-- | src/lib-lda/mail-deliver.h | 185 | ||||
-rw-r--r-- | src/lib-lda/mail-send.c | 216 | ||||
-rw-r--r-- | src/lib-lda/mail-send.h | 11 | ||||
-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 |
20 files changed, 4718 insertions, 0 deletions
diff --git a/src/lib-lda/Makefile.am b/src/lib-lda/Makefile.am new file mode 100644 index 0000000..3ea04f3 --- /dev/null +++ b/src/lib-lda/Makefile.am @@ -0,0 +1,35 @@ +noinst_LTLIBRARIES = liblda.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-smtp \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-smtp \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-ssl-iostream + +liblda_la_SOURCES = \ + lda-settings.c \ + mail-deliver.c \ + mail-send.c + +headers = \ + lda-settings.h \ + mail-deliver.h \ + mail-send.h + +pkginc_libdir=$(pkgincludedir) +pkginc_lib_HEADERS = $(headers) + +deps=../lib-storage/libdovecot-storage.la ../lib-dovecot/libdovecot.la + +pkglib_LTLIBRARIES = libdovecot-lda.la +libdovecot_lda_la_SOURCES = +libdovecot_lda_la_LIBADD = liblda.la $(deps) +libdovecot_lda_la_DEPENDENCIES = liblda.la $(deps) +libdovecot_lda_la_LDFLAGS = -export-dynamic + + diff --git a/src/lib-lda/Makefile.in b/src/lib-lda/Makefile.in new file mode 100644 index 0000000..9d2713a --- /dev/null +++ b/src/lib-lda/Makefile.in @@ -0,0 +1,878 @@ +# 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-lda +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 $(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 = $(noinst_LTLIBRARIES) $(pkglib_LTLIBRARIES) +am_libdovecot_lda_la_OBJECTS = +libdovecot_lda_la_OBJECTS = $(am_libdovecot_lda_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_lda_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdovecot_lda_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +liblda_la_LIBADD = +am_liblda_la_OBJECTS = lda-settings.lo mail-deliver.lo mail-send.lo +liblda_la_OBJECTS = $(am_liblda_la_OBJECTS) +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)/lda-settings.Plo \ + ./$(DEPDIR)/mail-deliver.Plo ./$(DEPDIR)/mail-send.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_lda_la_SOURCES) $(liblda_la_SOURCES) +DIST_SOURCES = $(libdovecot_lda_la_SOURCES) $(liblda_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 = $(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@ +noinst_LTLIBRARIES = liblda.la +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-smtp \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-smtp \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/lib-ssl-iostream + +liblda_la_SOURCES = \ + lda-settings.c \ + mail-deliver.c \ + mail-send.c + +headers = \ + lda-settings.h \ + mail-deliver.h \ + mail-send.h + +pkginc_libdir = $(pkgincludedir) +pkginc_lib_HEADERS = $(headers) +deps = ../lib-storage/libdovecot-storage.la ../lib-dovecot/libdovecot.la +pkglib_LTLIBRARIES = libdovecot-lda.la +libdovecot_lda_la_SOURCES = +libdovecot_lda_la_LIBADD = liblda.la $(deps) +libdovecot_lda_la_DEPENDENCIES = liblda.la $(deps) +libdovecot_lda_la_LDFLAGS = -export-dynamic +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-lda/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib-lda/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_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}; \ + } + +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-lda.la: $(libdovecot_lda_la_OBJECTS) $(libdovecot_lda_la_DEPENDENCIES) $(EXTRA_libdovecot_lda_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdovecot_lda_la_LINK) -rpath $(pkglibdir) $(libdovecot_lda_la_OBJECTS) $(libdovecot_lda_la_LIBADD) $(LIBS) + +liblda.la: $(liblda_la_OBJECTS) $(liblda_la_DEPENDENCIES) $(EXTRA_liblda_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(liblda_la_OBJECTS) $(liblda_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda-settings.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-deliver.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-send.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 +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-noinstLTLIBRARIES \ + clean-pkglibLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/lda-settings.Plo + -rm -f ./$(DEPDIR)/mail-deliver.Plo + -rm -f ./$(DEPDIR)/mail-send.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)/lda-settings.Plo + -rm -f ./$(DEPDIR)/mail-deliver.Plo + -rm -f ./$(DEPDIR)/mail-send.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: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + 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 + + +# 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-lda/lda-settings.c b/src/lib-lda/lda-settings.c new file mode 100644 index 0000000..1bb02f8 --- /dev/null +++ b/src/lib-lda/lda-settings.c @@ -0,0 +1,80 @@ +/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hostpid.h" +#include "settings-parser.h" +#include "mail-storage-settings.h" +#include "smtp-submit-settings.h" +#include "lda-settings.h" + +#include <stddef.h> + +static bool lda_settings_check(void *_set, pool_t pool, const char **error_r); + +#undef DEF +#undef DEFLIST +#define DEF(type, name) \ + SETTING_DEFINE_STRUCT_##type(#name, name, struct lda_settings) +#define DEFLIST(field, name, defines) \ + { .type = SET_DEFLIST, .key = name, \ + .offset = offsetof(struct lda_settings, field), \ + .list_info = defines } + +static const struct setting_define lda_setting_defines[] = { + DEF(STR, hostname), + DEF(STR, rejection_subject), + DEF(STR, rejection_reason), + DEF(STR, deliver_log_format), + DEF(STR, recipient_delimiter), + DEF(STR, lda_original_recipient_header), + DEF(BOOL, quota_full_tempfail), + DEF(BOOL, lda_mailbox_autocreate), + DEF(BOOL, lda_mailbox_autosubscribe), + + SETTING_DEFINE_LIST_END +}; + +static const struct lda_settings lda_default_settings = { + .hostname = "", + .rejection_subject = "Rejected: %s", + .rejection_reason = + "Your message to <%t> was automatically rejected:%n%r", + .deliver_log_format = "msgid=%m: %$", + .recipient_delimiter = "+", + .lda_original_recipient_header = "", + .quota_full_tempfail = FALSE, + .lda_mailbox_autocreate = FALSE, + .lda_mailbox_autosubscribe = FALSE +}; + +static const struct setting_parser_info *lda_setting_dependencies[] = { + &mail_user_setting_parser_info, + &smtp_submit_setting_parser_info, + NULL +}; + +const struct setting_parser_info lda_setting_parser_info = { + .module_name = "lda", + .defines = lda_setting_defines, + .defaults = &lda_default_settings, + + .type_offset = SIZE_MAX, + .struct_size = sizeof(struct lda_settings), + + .parent_offset = SIZE_MAX, + +#ifndef CONFIG_BINARY + .check_func = lda_settings_check, +#endif + .dependencies = lda_setting_dependencies +}; + +static bool lda_settings_check(void *_set, pool_t pool, + const char **error_r ATTR_UNUSED) +{ + struct lda_settings *set = _set; + + if (*set->hostname == '\0') + set->hostname = p_strdup(pool, my_hostdomain()); + return TRUE; +} diff --git a/src/lib-lda/lda-settings.h b/src/lib-lda/lda-settings.h new file mode 100644 index 0000000..8b0c209 --- /dev/null +++ b/src/lib-lda/lda-settings.h @@ -0,0 +1,21 @@ +#ifndef LDA_SETTINGS_H +#define LDA_SETTINGS_H + +struct mail_user_settings; + +struct lda_settings { + const char *hostname; + const char *rejection_subject; + const char *rejection_reason; + const char *deliver_log_format; + const char *recipient_delimiter; + const char *lda_original_recipient_header; + + bool quota_full_tempfail; + bool lda_mailbox_autocreate; + bool lda_mailbox_autosubscribe; +}; + +extern const struct setting_parser_info lda_setting_parser_info; + +#endif diff --git a/src/lib-lda/mail-deliver.c b/src/lib-lda/mail-deliver.c new file mode 100644 index 0000000..e0f69da --- /dev/null +++ b/src/lib-lda/mail-deliver.c @@ -0,0 +1,810 @@ +/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "array.h" +#include "str.h" +#include "str-sanitize.h" +#include "time-util.h" +#include "unichar.h" +#include "var-expand.h" +#include "message-address.h" +#include "smtp-address.h" +#include "lda-settings.h" +#include "mail-storage.h" +#include "mail-namespace.h" +#include "mail-storage-private.h" +#include "mail-duplicate.h" +#include "mail-deliver.h" + +#define DUPLICATE_DB_NAME "lda-dupes" + +#define MAIL_DELIVER_USER_CONTEXT(obj) \ + MODULE_CONTEXT_REQUIRE(obj, mail_deliver_user_module) +#define MAIL_DELIVER_STORAGE_CONTEXT(obj) \ + MODULE_CONTEXT_REQUIRE(obj, mail_deliver_storage_module) + +struct event_category event_category_mail_delivery = { + .name = "local-delivery", +}; + +struct mail_deliver_user { + union mail_user_module_context module_ctx; + struct mail_deliver_context *deliver_ctx; + bool want_storage_id; +}; + +deliver_mail_func_t *deliver_mail = NULL; + +struct mail_deliver_mailbox { + union mailbox_module_context module_ctx; +}; + +struct mail_deliver_transaction { + union mailbox_transaction_module_context module_ctx; + + struct mail_deliver_fields deliver_fields; +}; + +static const char *lda_log_wanted_headers[] = { + "From", "Message-ID", "Subject", + NULL +}; +static enum mail_fetch_field lda_log_wanted_fetch_fields = + MAIL_FETCH_PHYSICAL_SIZE | MAIL_FETCH_VIRTUAL_SIZE; +static MODULE_CONTEXT_DEFINE_INIT(mail_deliver_user_module, + &mail_user_module_register); +static MODULE_CONTEXT_DEFINE_INIT(mail_deliver_storage_module, + &mail_storage_module_register); + +static struct message_address * +mail_deliver_get_message_address(struct mail *mail, const char *header) +{ + struct message_address *addr; + const char *str; + + if (mail_get_first_header(mail, header, &str) <= 0) + return NULL; + addr = message_address_parse(pool_datastack_create(), + (const unsigned char *)str, + strlen(str), 1, 0); + if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL || + *addr->mailbox == '\0' || *addr->domain == '\0') + return NULL; + return addr; +} + +const struct smtp_address * +mail_deliver_get_address(struct mail *mail, const char *header) +{ + struct message_address *addr; + struct smtp_address *smtp_addr; + + addr = mail_deliver_get_message_address(mail, header); + if (addr == NULL || + smtp_address_create_from_msg_temp(addr, &smtp_addr) < 0) + return NULL; + return smtp_addr; +} + +static void +mail_deliver_update_event(struct mail_deliver_context *ctx) +{ + event_add_str(ctx->event, "message_id", ctx->fields.message_id); + event_add_str(ctx->event, "message_subject", ctx->fields.subject); + event_add_str(ctx->event, "message_from", ctx->fields.from); + if (ctx->fields.psize != UOFF_T_MAX) + event_add_int(ctx->event, "message_size", ctx->fields.psize); + if (ctx->fields.vsize != UOFF_T_MAX) + event_add_int(ctx->event, "message_vsize", ctx->fields.vsize); +} + +static void +update_str_field(pool_t pool, const char **old_str, const char *new_str) +{ + if (new_str == NULL || new_str[0] == '\0') + *old_str = NULL; + else if (*old_str == NULL || strcmp(*old_str, new_str) != 0) + *old_str = p_strdup(pool, new_str); +} + +static void +mail_deliver_fields_update(struct mail_deliver_fields *fields, pool_t pool, + struct mail *mail) +{ + const char *message_id = NULL, *subject = NULL, *from_envelope = NULL; + static struct message_address *from_addr; + const char *from; + + if (fields->filled) + return; + fields->filled = TRUE; + + if (mail_get_message_id(mail, &message_id) > 0) + message_id = str_sanitize(message_id, 200); + update_str_field(pool, &fields->message_id, message_id); + + if (mail_get_first_header_utf8(mail, "Subject", &subject) > 0) + subject = str_sanitize(subject, 80); + update_str_field(pool, &fields->subject, subject); + + from_addr = mail_deliver_get_message_address(mail, "From"); + from = (from_addr == NULL ? NULL : + t_strconcat(from_addr->mailbox, "@", from_addr->domain, NULL)); + update_str_field(pool, &fields->from, from); + + if (mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE, &from_envelope) > 0) + from_envelope = str_sanitize(from_envelope, 80); + update_str_field(pool, &fields->from_envelope, from_envelope); + + if (mail_get_physical_size(mail, &fields->psize) < 0) + fields->psize = 0; + if (mail_get_virtual_size(mail, &fields->vsize) < 0) + fields->vsize = 0; +} + +const struct var_expand_table * +mail_deliver_ctx_get_log_var_expand_table(struct mail_deliver_context *ctx, + const char *message) +{ + unsigned int delivery_time_msecs; + + /* If a mail was saved/copied, the fields are already filled and the + following call is ignored. Otherwise, only the source mail exists. */ + mail_deliver_fields_update(&ctx->fields, ctx->pool, ctx->src_mail); + /* This call finishes a mail delivery. With Sieve there may be multiple + mail deliveries. */ + ctx->fields.filled = FALSE; + + mail_deliver_update_event(ctx); + + io_loop_time_refresh(); + delivery_time_msecs = timeval_diff_msecs(&ioloop_timeval, + &ctx->delivery_time_started); + + const struct var_expand_table stack_tab[] = { + { '$', message, NULL }, + { 'm', ctx->fields.message_id != NULL ? + ctx->fields.message_id : "unspecified", "msgid" }, + { 's', ctx->fields.subject, "subject" }, + { 'f', ctx->fields.from, "from" }, + { 'e', ctx->fields.from_envelope, "from_envelope" }, + { 'p', dec2str(ctx->fields.psize), "size" }, + { 'w', dec2str(ctx->fields.vsize), "vsize" }, + { '\0', dec2str(delivery_time_msecs), "delivery_time" }, + { '\0', dec2str(ctx->session_time_msecs), "session_time" }, + { '\0', smtp_address_encode(ctx->rcpt_params.orcpt.addr), "to_envelope" }, + { '\0', ctx->fields.storage_id, "storage_id" }, + { '\0', NULL, NULL } + }; + return p_memdup(unsafe_data_stack_pool, stack_tab, sizeof(stack_tab)); +} + +void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) +{ + va_list args; + string_t *str; + const struct var_expand_table *tab; + const char *msg, *error; + + if (*ctx->set->deliver_log_format == '\0') + return; + + va_start(args, fmt); + msg = t_strdup_vprintf(fmt, args); + + str = t_str_new(256); + tab = mail_deliver_ctx_get_log_var_expand_table(ctx, msg); + if (var_expand(str, ctx->set->deliver_log_format, tab, &error) <= 0) { + e_error(ctx->event, + "Failed to expand deliver_log_format=%s: %s", + ctx->set->deliver_log_format, error); + } + + e_info(ctx->event, "%s", str_c(str)); + va_end(args); +} + +struct mail_deliver_session *mail_deliver_session_init(void) +{ + struct mail_deliver_session *session; + pool_t pool; + + pool = pool_alloconly_create("mail deliver session", 1024); + session = p_new(pool, struct mail_deliver_session, 1); + session->pool = pool; + return session; +} + +void mail_deliver_session_deinit(struct mail_deliver_session **_session) +{ + struct mail_deliver_session *session = *_session; + + *_session = NULL; + pool_unref(&session->pool); +} + +int mail_deliver_save_open(struct mail_deliver_save_open_context *ctx, + const char *name, struct mailbox **box_r, + enum mail_error *error_r, const char **error_str_r) +{ + struct mailbox *box; + enum mailbox_flags flags = MAILBOX_FLAG_POST_SESSION; + + *box_r = NULL; + *error_r = MAIL_ERROR_NONE; + *error_str_r = NULL; + + if (!uni_utf8_str_is_valid(name)) { + *error_str_r = "Mailbox name not valid UTF-8"; + *error_r = MAIL_ERROR_PARAMS; + return -1; + } + + if (ctx->lda_mailbox_autocreate) + flags |= MAILBOX_FLAG_AUTO_CREATE; + if (ctx->lda_mailbox_autosubscribe) + flags |= MAILBOX_FLAG_AUTO_SUBSCRIBE; + *box_r = box = mailbox_alloc_for_user(ctx->user, name, flags); + + if (mailbox_open(box) == 0) + return 0; + *error_str_r = mailbox_get_last_internal_error(box, error_r); + return -1; +} + +static bool mail_deliver_check_duplicate(struct mail_deliver_session *session, + struct mailbox *box) +{ + struct mailbox_metadata metadata; + const guid_128_t *guid; + + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) { + /* just play it safe and assume a duplicate */ + return TRUE; + } + + /* there shouldn't be all that many recipients, + so just do a linear search */ + if (!array_is_created(&session->inbox_guids)) + p_array_init(&session->inbox_guids, session->pool, 8); + array_foreach(&session->inbox_guids, guid) { + if (memcmp(metadata.guid, *guid, sizeof(metadata.guid)) == 0) + return TRUE; + } + array_push_back(&session->inbox_guids, &metadata.guid); + return FALSE; +} + +void mail_deliver_deduplicate_guid_if_needed(struct mail_deliver_session *session, + struct mail_save_context *save_ctx) +{ + struct mailbox_transaction_context *trans = + mailbox_save_get_transaction(save_ctx); + struct mailbox *box = mailbox_transaction_get_mailbox(trans); + guid_128_t guid; + + if (strcmp(mailbox_get_name(box), "INBOX") != 0) + return; + + /* avoid storing duplicate GUIDs to delivered mails to INBOX. this + happens if mail is delivered to same user multiple times within a + session. the problem with this is that if GUIDs are used as POP3 + UIDLs, some clients can't handle the duplicates well. */ + if (mail_deliver_check_duplicate(session, box)) { + guid_128_generate(guid); + mailbox_save_set_guid(save_ctx, guid_128_to_string(guid)); + } +} + +void mail_deliver_init(struct mail_deliver_context *ctx, + struct mail_deliver_input *input) +{ + i_zero(ctx); + ctx->set = input->set; + ctx->smtp_set = input->smtp_set; + + ctx->session = input->session; + ctx->pool = input->session->pool; + pool_ref(ctx->pool); + + ctx->session_time_msecs = input->session_time_msecs; + ctx->delivery_time_started = input->delivery_time_started; + ctx->session_id = p_strdup(ctx->pool, input->session_id); + ctx->src_mail = input->src_mail; + ctx->save_dest_mail = input->save_dest_mail; + + ctx->mail_from = smtp_address_clone(ctx->pool, input->mail_from); + smtp_params_mail_copy(ctx->pool, &ctx->mail_params, + &input->mail_params); + ctx->rcpt_to = smtp_address_clone(ctx->pool, input->rcpt_to); + smtp_params_rcpt_copy(ctx->pool, &ctx->rcpt_params, + &input->rcpt_params); + ctx->rcpt_user = input->rcpt_user; + ctx->rcpt_default_mailbox = p_strdup(ctx->pool, + input->rcpt_default_mailbox); + + ctx->event = event_create(input->event_parent); + event_add_category(ctx->event, &event_category_mail_delivery); + + mail_deliver_fields_update(&ctx->fields, ctx->pool, ctx->src_mail); + mail_deliver_update_event(ctx); + + if (ctx->rcpt_to != NULL) { + event_add_str(ctx->event, "rcpt_to", + smtp_address_encode(ctx->rcpt_to)); + } + smtp_params_rcpt_add_to_event(&ctx->rcpt_params, ctx->event); +} + +void mail_deliver_deinit(struct mail_deliver_context *ctx) +{ + event_unref(&ctx->event); + pool_unref(&ctx->pool); +} + +static struct mail * +mail_deliver_open_mail(struct mailbox *box, uint32_t uid, + enum mail_fetch_field wanted_fields, + struct mailbox_transaction_context **trans_r) +{ + struct mailbox_transaction_context *t; + struct mail *mail; + + *trans_r = NULL; + + if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FAST) < 0) + return NULL; + + t = mailbox_transaction_begin(box, 0, __func__); + mail = mail_alloc(t, wanted_fields, NULL); + + if (!mail_set_uid(mail, uid)) { + mail_free(&mail); + mailbox_transaction_rollback(&t); + } + *trans_r = t; + return mail; +} + +int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, + enum mail_flags flags, const char *const *keywords, + struct mail_storage **storage_r) +{ + struct mail_deliver_save_open_context open_ctx; + struct mailbox *box; + enum mailbox_transaction_flags trans_flags; + struct mailbox_transaction_context *t; + struct mail_save_context *save_ctx; + struct mailbox_header_lookup_ctx *headers_ctx; + struct mail_keywords *kw; + struct mail *dest_mail; + enum mail_error error; + const char *mailbox_name, *errstr, *guid; + struct mail_transaction_commit_changes changes; + bool default_save; + int ret = 0; + + i_assert(ctx->dest_mail == NULL); + + default_save = strcmp(mailbox, ctx->rcpt_default_mailbox) == 0; + if (default_save) + ctx->tried_default_save = TRUE; + + i_zero(&open_ctx); + open_ctx.user = ctx->rcpt_user; + open_ctx.lda_mailbox_autocreate = ctx->set->lda_mailbox_autocreate; + open_ctx.lda_mailbox_autosubscribe = ctx->set->lda_mailbox_autosubscribe; + + mailbox_name = str_sanitize(mailbox, 80); + if (mail_deliver_save_open(&open_ctx, mailbox, &box, + &error, &errstr) < 0) { + if (box != NULL) { + *storage_r = mailbox_get_storage(box); + mailbox_free(&box); + } + mail_deliver_log(ctx, "save failed to open mailbox %s: %s", + mailbox_name, errstr); + return -1; + } + *storage_r = mailbox_get_storage(box); + + trans_flags = MAILBOX_TRANSACTION_FLAG_EXTERNAL; + if (ctx->save_dest_mail) + trans_flags |= MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS; + t = mailbox_transaction_begin(box, trans_flags, __func__); + + kw = str_array_length(keywords) == 0 ? NULL : + mailbox_keywords_create_valid(box, keywords); + save_ctx = mailbox_save_alloc(t); + if (ctx->mail_from != NULL) { + mailbox_save_set_from_envelope(save_ctx, + smtp_address_encode(ctx->mail_from)); + } + mailbox_save_set_flags(save_ctx, flags, kw); + + headers_ctx = mailbox_header_lookup_init(box, lda_log_wanted_headers); + dest_mail = mailbox_save_get_dest_mail(save_ctx); + mail_add_temp_wanted_fields(dest_mail, lda_log_wanted_fetch_fields, NULL); + mailbox_header_lookup_unref(&headers_ctx); + mail_deliver_deduplicate_guid_if_needed(ctx->session, save_ctx); + + if (mailbox_save_using_mail(&save_ctx, ctx->src_mail) < 0) + ret = -1; + if (kw != NULL) + mailbox_keywords_unref(&kw); + + if (ret < 0) + mailbox_transaction_rollback(&t); + else + ret = mailbox_transaction_commit_get_changes(&t, &changes); + + if (ret == 0) { + ctx->saved_mail = TRUE; + if (ctx->save_dest_mail) { + /* copying needs the message body. with maildir we also + need to get the GUID in case the message gets + expunged. get these early so the copying won't fail + later on. */ + i_assert(array_count(&changes.saved_uids) == 1); + const struct seq_range *range = + array_front(&changes.saved_uids); + i_assert(range->seq1 == range->seq2); + ctx->dest_mail = mail_deliver_open_mail(box, range->seq1, + MAIL_FETCH_STREAM_BODY | MAIL_FETCH_GUID, &t); + if (ctx->dest_mail == NULL) { + i_assert(t == NULL); + } else if (mail_get_special(ctx->dest_mail, MAIL_FETCH_GUID, &guid) < 0) { + mail_free(&ctx->dest_mail); + mailbox_transaction_rollback(&t); + } + } + mail_deliver_log(ctx, "saved mail to %s", mailbox_name); + pool_unref(&changes.pool); + } else { + mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name, + mail_storage_get_last_internal_error(*storage_r, &error)); + } + + if (ctx->dest_mail == NULL) + mailbox_free(&box); + return ret; +} + +const struct smtp_address * +mail_deliver_get_return_address(struct mail_deliver_context *ctx) +{ + struct message_address *addr; + struct smtp_address *smtp_addr; + const char *path; + int ret; + + if (!smtp_address_isnull(ctx->mail_from)) + return ctx->mail_from; + + if ((ret=mail_get_first_header(ctx->src_mail, + "Return-Path", &path)) <= 0) { + if (ret < 0) { + struct mailbox *box = ctx->src_mail->box; + e_warning(ctx->event, + "Failed read return-path header: %s", + mailbox_get_last_internal_error(box, NULL)); + } + return NULL; + } + if (message_address_parse_path(pool_datastack_create(), + (const unsigned char *)path, + strlen(path), &addr) < 0 || + smtp_address_create_from_msg(ctx->pool, addr, &smtp_addr) < 0) { + e_warning(ctx->event, "Failed to parse return-path header"); + return NULL; + } + return smtp_addr; +} + +const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx) +{ + static int count = 0; + struct mail_user *user = ctx->rcpt_user; + const struct mail_storage_settings *mail_set = + mail_user_set_get_storage_set(user); + + return t_strdup_printf("<dovecot-%s-%s-%d@%s>", + dec2str(ioloop_timeval.tv_sec), + dec2str(ioloop_timeval.tv_usec), + count++, mail_set->hostname); +} + +static bool mail_deliver_is_tempfailed(struct mail_deliver_context *ctx, + struct mail_storage *storage) +{ + enum mail_error error; + + if (ctx->tempfail_error != NULL) + return TRUE; + if (storage != NULL) { + (void)mail_storage_get_last_error(storage, &error); + return error == MAIL_ERROR_TEMP; + } + return FALSE; +} + +static int +mail_do_deliver(struct mail_deliver_context *ctx, + struct mail_storage **storage_r) +{ + int ret; + + *storage_r = NULL; + if (deliver_mail == NULL) + ret = -1; + else { + ctx->dup_db = mail_duplicate_db_init(ctx->rcpt_user, + DUPLICATE_DB_NAME); + if (deliver_mail(ctx, storage_r) <= 0) { + /* if message was saved, don't bounce it even though + the script failed later. */ + ret = ctx->saved_mail ? 0 : -1; + } else { + /* success. message may or may not have been saved. */ + ret = 0; + } + mail_duplicate_db_deinit(&ctx->dup_db); + if (ret < 0 && mail_deliver_is_tempfailed(ctx, *storage_r)) + return -1; + } + + if (ret < 0 && !ctx->tried_default_save) { + /* plugins didn't handle this. save into the default mailbox. */ + ret = mail_deliver_save(ctx, ctx->rcpt_default_mailbox, 0, NULL, + storage_r); + if (ret < 0 && mail_deliver_is_tempfailed(ctx, *storage_r)) + return -1; + } + if (ret < 0 && strcasecmp(ctx->rcpt_default_mailbox, "INBOX") != 0) { + /* still didn't work. try once more to save it + to INBOX. */ + ret = mail_deliver_save(ctx, "INBOX", 0, NULL, storage_r); + } + return ret; +} + +int mail_deliver(struct mail_deliver_context *ctx, + enum mail_deliver_error *error_code_r, + const char **error_r) +{ + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(ctx->rcpt_user); + struct event_passthrough *e; + struct mail_storage *storage = NULL; + enum mail_deliver_error error_code = MAIL_DELIVER_ERROR_NONE; + const char *error = NULL; + int ret; + + i_assert(muser->deliver_ctx == NULL); + + mail_deliver_fields_update(&ctx->fields, ctx->pool, ctx->src_mail); + mail_deliver_update_event(ctx); + + muser->want_storage_id = + var_has_key(ctx->set->deliver_log_format, '\0', "storage_id"); + + muser->deliver_ctx = ctx; + + e = event_create_passthrough(ctx->event)-> + set_name("mail_delivery_started"); + e_debug(e->event(), "Local delivery started"); + + ret = mail_do_deliver(ctx, &storage); + + if (ret >= 0) + i_assert(ret == 0); /* ret > 0 has no defined meaning */ + else if (ctx->tempfail_error != NULL) { + error = ctx->tempfail_error; + error_code = MAIL_DELIVER_ERROR_TEMPORARY; + } else if (storage != NULL) { + enum mail_error mail_error; + + error = mail_storage_get_last_error(storage, &mail_error); + if (mail_error == MAIL_ERROR_NOQUOTA) { + error_code = MAIL_DELIVER_ERROR_NOQUOTA; + } else { + error_code = MAIL_DELIVER_ERROR_TEMPORARY; + } + } else { + /* This shouldn't happen */ + e_error(ctx->event, "BUG: Saving failed to unknown storage"); + error = "Temporary internal error"; + error_code = MAIL_DELIVER_ERROR_INTERNAL; + } + + e = event_create_passthrough(ctx->event)-> + set_name("mail_delivery_finished"); + if (ret == 0) { + e_debug(e->event(), "Local delivery finished successfully"); + } else { + e->add_str("error", error); + e_debug(e->event(), "Local delivery failed: %s", error); + } + + muser->deliver_ctx = NULL; + + *error_code_r = error_code; + *error_r = error; + return ret; +} + +deliver_mail_func_t *mail_deliver_hook_set(deliver_mail_func_t *new_hook) +{ + deliver_mail_func_t *old_hook = deliver_mail; + + deliver_mail = new_hook; + return old_hook; +} + +static int mail_deliver_save_finish(struct mail_save_context *ctx) +{ + struct mailbox *box = ctx->transaction->box; + struct mail_deliver_mailbox *mbox = MAIL_DELIVER_STORAGE_CONTEXT(box); + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(box->storage->user); + struct mail_deliver_transaction *dt = + MAIL_DELIVER_STORAGE_CONTEXT(ctx->transaction); + + if (mbox->module_ctx.super.save_finish(ctx) < 0) + return -1; + + /* initialize most of the fields from dest_mail */ + mail_deliver_fields_update(&dt->deliver_fields, + muser->deliver_ctx->pool, + ctx->dest_mail); + return 0; +} + +static int mail_deliver_copy(struct mail_save_context *ctx, struct mail *mail) +{ + struct mailbox *box = ctx->transaction->box; + struct mail_deliver_mailbox *mbox = MAIL_DELIVER_STORAGE_CONTEXT(box); + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(box->storage->user); + struct mail_deliver_transaction *dt = + MAIL_DELIVER_STORAGE_CONTEXT(ctx->transaction); + + if (mbox->module_ctx.super.copy(ctx, mail) < 0) + return -1; + + /* initialize most of the fields from dest_mail */ + mail_deliver_fields_update(&dt->deliver_fields, + muser->deliver_ctx->pool, + ctx->dest_mail); + return 0; +} + +static void +mail_deliver_fields_update_post_commit(struct mailbox *orig_box, uint32_t uid) +{ + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(orig_box->storage->user); + struct mailbox *box; + struct mailbox_transaction_context *t; + struct mail *mail; + const char *storage_id; + + if (!muser->want_storage_id) + return; + + /* getting storage_id requires a whole new mailbox view that is + synced, so it'll contain the newly written mail. this is racy, so + it's possible another process has already deleted the mail. */ + box = mailbox_alloc(orig_box->list, orig_box->vname, 0); + mail = mail_deliver_open_mail(box, uid, MAIL_FETCH_STORAGE_ID, &t); + if (mail != NULL) { + if (mail_get_special(mail, MAIL_FETCH_STORAGE_ID, &storage_id) < 0 || + storage_id[0] == '\0') + storage_id = NULL; + muser->deliver_ctx->fields.storage_id = + p_strdup(muser->deliver_ctx->pool, storage_id); + mail_free(&mail); + (void)mailbox_transaction_commit(&t); + } else { + muser->deliver_ctx->fields.storage_id = NULL; + } + mailbox_free(&box); +} + +static struct mailbox_transaction_context * +mail_deliver_transaction_begin(struct mailbox *box, + enum mailbox_transaction_flags flags, + const char *reason) +{ + struct mail_deliver_mailbox *mbox = MAIL_DELIVER_STORAGE_CONTEXT(box); + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(box->storage->user); + struct mailbox_transaction_context *t; + struct mail_deliver_transaction *dt; + + i_assert(muser->deliver_ctx != NULL); + + t = mbox->module_ctx.super.transaction_begin(box, flags, reason); + dt = p_new(muser->deliver_ctx->pool, struct mail_deliver_transaction, 1); + + MODULE_CONTEXT_SET(t, mail_deliver_storage_module, dt); + return t; +} + +static int +mail_deliver_transaction_commit(struct mailbox_transaction_context *ctx, + struct mail_transaction_commit_changes *changes_r) +{ + struct mailbox *box = ctx->box; + struct mail_deliver_mailbox *mbox = MAIL_DELIVER_STORAGE_CONTEXT(box); + struct mail_deliver_transaction *dt = MAIL_DELIVER_STORAGE_CONTEXT(ctx); + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(box->storage->user); + + i_assert(muser->deliver_ctx != NULL); + + /* sieve creates multiple transactions, saves the mails and + then commits all of them at the end. we'll need to keep + switching the deliver_ctx->fields for each commit. + + we also want to do this only for commits generated by sieve. + other plugins or storage backends may be creating transactions as + well, which we need to ignore. */ + if ((box->flags & MAILBOX_FLAG_POST_SESSION) != 0) { + muser->deliver_ctx->fields = dt->deliver_fields; + mail_deliver_update_event(muser->deliver_ctx); + } + + if (mbox->module_ctx.super.transaction_commit(ctx, changes_r) < 0) + return -1; + + if (array_count(&changes_r->saved_uids) > 0) { + const struct seq_range *range = + array_front(&changes_r->saved_uids); + + mail_deliver_fields_update_post_commit(box, range->seq1); + } + return 0; +} + +static void mail_deliver_mail_user_created(struct mail_user *user) +{ + struct mail_deliver_user *muser; + + muser = p_new(user->pool, struct mail_deliver_user, 1); + MODULE_CONTEXT_SET(user, mail_deliver_user_module, muser); +} + +static void mail_deliver_mailbox_allocated(struct mailbox *box) +{ + struct mailbox_vfuncs *v = box->vlast; + struct mail_deliver_mailbox *mbox; + struct mail_deliver_user *muser = + MAIL_DELIVER_USER_CONTEXT(box->storage->user); + + /* we are doing something other than lda/lmtp delivery + and should not be involved */ + if (muser->deliver_ctx == NULL) + return; + + mbox = p_new(box->pool, struct mail_deliver_mailbox, 1); + mbox->module_ctx.super = *v; + box->vlast = &mbox->module_ctx.super; + v->save_finish = mail_deliver_save_finish; + v->copy = mail_deliver_copy; + v->transaction_begin = mail_deliver_transaction_begin; + v->transaction_commit = mail_deliver_transaction_commit; + + MODULE_CONTEXT_SET(box, mail_deliver_storage_module, mbox); + } + +static struct mail_storage_hooks mail_deliver_hooks = { + .mail_user_created = mail_deliver_mail_user_created, + .mailbox_allocated = mail_deliver_mailbox_allocated +}; + +void mail_deliver_hooks_init(void) +{ + mail_storage_hooks_add_internal(&mail_deliver_hooks); +} diff --git a/src/lib-lda/mail-deliver.h b/src/lib-lda/mail-deliver.h new file mode 100644 index 0000000..5396a82 --- /dev/null +++ b/src/lib-lda/mail-deliver.h @@ -0,0 +1,185 @@ +#ifndef MAIL_DELIVER_H +#define MAIL_DELIVER_H + +#include "guid.h" +#include "mail-types.h" +#include "mail-error.h" +#include "smtp-params.h" + +#include <sys/time.h> + +struct smtp_address; +struct mail_storage; +struct mail_save_context; +struct mailbox; + +enum mail_deliver_error { + MAIL_DELIVER_ERROR_NONE = 0, + + /* Temporary error */ + MAIL_DELIVER_ERROR_TEMPORARY, + /* Delivery rejected */ + MAIL_DELIVER_ERROR_REJECTED, + /* Out of storage quota for mailbox or user */ + MAIL_DELIVER_ERROR_NOQUOTA, + /* Internal error (BUG) */ + MAIL_DELIVER_ERROR_INTERNAL, +}; + +struct mail_deliver_session { + pool_t pool; + + /* List of INBOX GUIDs where this mail has already been saved to */ + ARRAY(guid_128_t) inbox_guids; +}; + +struct mail_deliver_input { + const struct lda_settings *set; + const struct smtp_submit_settings *smtp_set; + struct mail_deliver_session *session; + struct event *event_parent; + + unsigned int session_time_msecs; + struct timeval delivery_time_started; + + /* Session ID, used as log line prefix if non-NULL. */ + const char *session_id; + /* Mail to save */ + struct mail *src_mail; + + /* Envelope sender, if known. */ + const struct smtp_address *mail_from; + /* MAIL parameters */ + struct smtp_params_mail mail_params; + + /* Envelope recipient (final recipient) */ + const struct smtp_address *rcpt_to; + /* RCPT parameters (can contain original recipient) */ + struct smtp_params_rcpt rcpt_params; + /* Destination user */ + struct mail_user *rcpt_user; + /* Mailbox where mail should be saved, unless e.g. Sieve does + something to it. */ + const char *rcpt_default_mailbox; + + bool save_dest_mail:1; +}; + +struct mail_deliver_fields { + const char *message_id; + const char *subject; + const char *from; + const char *from_envelope; + const char *storage_id; + + uoff_t psize, vsize; + + bool filled:1; +}; + +struct mail_deliver_context { + pool_t pool; + const struct lda_settings *set; + const struct smtp_submit_settings *smtp_set; + struct mail_deliver_session *session; + struct event *event; + + unsigned int session_time_msecs; + struct timeval delivery_time_started; + + struct mail_duplicate_db *dup_db; + + /* Session ID, used as log line prefix if non-NULL. */ + const char *session_id; + /* Mail to save */ + struct mail *src_mail; + + /* Envelope sender, if known. */ + const struct smtp_address *mail_from; + /* MAIL parameters */ + struct smtp_params_mail mail_params; + + /* Envelope recipient (final recipient) */ + const struct smtp_address *rcpt_to; + /* RCPT parameters (can contain original recipient) */ + struct smtp_params_rcpt rcpt_params; + /* Destination user */ + struct mail_user *rcpt_user; + /* Mailbox where mail should be saved, unless e.g. Sieve does + something to it. */ + const char *rcpt_default_mailbox; + + /* Filled with destination mail, if save_dest_mail=TRUE. + The caller must free the mail, its transaction and close + the mailbox. */ + struct mail *dest_mail; + + /* Recorded field values for the transaction */ + struct mail_deliver_fields fields; + + /* Error message for a temporary failure. This is necessary only when + there is no storage where to get the error message from. */ + const char *tempfail_error; + + bool tried_default_save; + bool saved_mail; + bool save_dest_mail; + /* Delivery failed because user is out of quota / disk space */ + bool mailbox_full; + /* Send DSN instead of MDN */ + bool dsn; +}; + +struct mail_deliver_save_open_context { + struct mail_user *user; + bool lda_mailbox_autocreate; + bool lda_mailbox_autosubscribe; +}; + +typedef int deliver_mail_func_t(struct mail_deliver_context *ctx, + struct mail_storage **storage_r); + +extern deliver_mail_func_t *deliver_mail; + +const struct var_expand_table * +mail_deliver_ctx_get_log_var_expand_table(struct mail_deliver_context *ctx, + const char *message); +void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) + ATTR_FORMAT(2, 3); + +const struct smtp_address * +mail_deliver_get_address(struct mail *mail, const char *header); +const struct smtp_address * +mail_deliver_get_return_address(struct mail_deliver_context *ctx); +const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx); + +struct mail_deliver_session *mail_deliver_session_init(void); +void mail_deliver_session_deinit(struct mail_deliver_session **session); + +void mail_deliver_init(struct mail_deliver_context *ctx, + struct mail_deliver_input *input); +void mail_deliver_deinit(struct mail_deliver_context *ctx); + +/* Try to open mailbox for saving. Returns 0 if ok, -1 if error. The box may + be returned even with -1, and the caller must free it then. */ +int mail_deliver_save_open(struct mail_deliver_save_open_context *ctx, + const char *name, struct mailbox **box_r, + enum mail_error *error_r, const char **error_str_r); +int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, + enum mail_flags flags, const char *const *keywords, + struct mail_storage **storage_r) ATTR_NULL(4); +void mail_deliver_deduplicate_guid_if_needed(struct mail_deliver_session *session, + struct mail_save_context *save_ctx); + +int mail_deliver(struct mail_deliver_context *ctx, + enum mail_deliver_error *error_code_r, + const char **error_r); + +/* Sets the deliver_mail hook and returns the previous hook, + which the new_hook should call if it's non-NULL. */ +deliver_mail_func_t *mail_deliver_hook_set(deliver_mail_func_t *new_hook); + +/* Must be called before any storage is created. */ +void mail_deliver_hooks_init(void); + +#endif diff --git a/src/lib-lda/mail-send.c b/src/lib-lda/mail-send.c new file mode 100644 index 0000000..2027b0b --- /dev/null +++ b/src/lib-lda/mail-send.c @@ -0,0 +1,216 @@ +/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "hostpid.h" +#include "istream.h" +#include "ostream.h" +#include "str.h" +#include "str-sanitize.h" +#include "var-expand.h" +#include "message-date.h" +#include "message-size.h" +#include "message-address.h" +#include "istream-header-filter.h" +#include "mail-storage.h" +#include "mail-storage-settings.h" +#include "iostream-ssl.h" +#include "lda-settings.h" +#include "mail-deliver.h" +#include "smtp-address.h" +#include "smtp-submit.h" +#include "mail-send.h" + +#include <sys/wait.h> + +static const struct var_expand_table * +get_var_expand_table(struct mail *mail, + const struct smtp_address *recipient, + const char *reason) +{ + const char *subject; + if (mail_get_first_header(mail, "Subject", &subject) <= 0) + subject = ""; + + const struct var_expand_table stack_tab[] = { + { 'n', "\r\n", "crlf" }, + { 'r', reason, "reason" }, + { 's', str_sanitize(subject, 80), "subject" }, + { 't', smtp_address_encode(recipient), "to" }, + { '\0', NULL, NULL } + }; + struct var_expand_table *tab; + + tab = t_malloc_no0(sizeof(stack_tab)); + memcpy(tab, stack_tab, sizeof(stack_tab)); + return tab; +} + +int mail_send_rejection(struct mail_deliver_context *ctx, + const struct smtp_address *recipient, + const char *reason) +{ + struct mail_user *user = ctx->rcpt_user; + struct ssl_iostream_settings ssl_set; + struct mail *mail = ctx->src_mail; + struct istream *input; + struct smtp_submit_input smtp_input; + struct smtp_submit *smtp_submit; + struct ostream *output; + const struct message_address *postmaster_addr; + const struct smtp_address *return_addr; + const char *hdr, *value, *msgid, *orig_msgid, *boundary, *error; + const struct var_expand_table *vtable; + string_t *str; + int ret; + + if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0) + orig_msgid = NULL; + + if (mail_get_first_header(mail, "Auto-Submitted", &value) > 0 && + strcasecmp(value, "no") != 0) { + i_info("msgid=%s: Auto-submitted message discarded: %s", + orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), + str_sanitize(reason, 512)); + return 0; + } + + return_addr = mail_deliver_get_return_address(ctx); + if (smtp_address_isnull(return_addr)) { + i_info("msgid=%s: Return-Path missing, rejection reason: %s", + orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), + str_sanitize(reason, 512)); + return 0; + } + + if (!mail_user_get_postmaster_address(user, &postmaster_addr, &error)) { + i_error("msgid=%s: Invalid postmaster_address - can't send rejection: %s", + orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), error); + return -1; + } + + e_debug(mail_event(mail), "Sending a rejection to <%s>: %s", + smtp_address_encode(return_addr), + str_sanitize(reason, 512)); + + vtable = get_var_expand_table(mail, recipient, reason); + + mail_user_init_ssl_client_settings(user, &ssl_set); + + i_zero(&smtp_input); + smtp_input.ssl = &ssl_set; + smtp_submit = smtp_submit_init_simple(&smtp_input, ctx->smtp_set, NULL); + smtp_submit_add_rcpt(smtp_submit, return_addr); + output = smtp_submit_send(smtp_submit); + + msgid = mail_deliver_get_new_message_id(ctx); + boundary = t_strdup_printf("%s/%s", my_pid, user->set->hostname); + + str = t_str_new(512); + str_printfa(str, "Message-ID: %s\r\n", msgid); + str_printfa(str, "Date: %s\r\n", message_date_create(ioloop_time)); + str_append(str, "From: "); + message_address_write(str, postmaster_addr); + str_append(str, "\r\n"); + str_printfa(str, "To: <%s>\r\n", smtp_address_encode(return_addr)); + str_append(str, "MIME-Version: 1.0\r\n"); + str_printfa(str, "Content-Type: " + "multipart/report; report-type=%s;\r\n" + "\tboundary=\"%s\"\r\n", + ctx->dsn ? "delivery-status" : "disposition-notification", + boundary); + str_append(str, "Subject: "); + if (var_expand(str, ctx->set->rejection_subject, + vtable, &error) <= 0) { + i_error("Failed to expand rejection_subject=%s: %s", + ctx->set->rejection_subject, error); + } + str_append(str, "\r\n"); + + str_append(str, "Auto-Submitted: auto-replied (rejected)\r\n"); + str_append(str, "Precedence: bulk\r\n"); + str_append(str, "\r\nThis is a MIME-encapsulated message\r\n\r\n"); + + /* human readable status report */ + str_printfa(str, "--%s\r\n", boundary); + str_append(str, "Content-Type: text/plain; charset=utf-8\r\n"); + str_append(str, "Content-Disposition: inline\r\n"); + str_append(str, "Content-Transfer-Encoding: 8bit\r\n\r\n"); + + if (var_expand(str, ctx->set->rejection_reason, + vtable, &error) <= 0) { + i_error("Failed to expand rejection_reason=%s: %s", + ctx->set->rejection_reason, error); + } + str_append(str, "\r\n"); + + if (ctx->dsn) { + /* DSN status report: For LDA rejects. currently only used when + user is out of quota */ + str_printfa(str, "--%s\r\n" + "Content-Type: message/delivery-status\r\n\r\n", + boundary); + str_printfa(str, "Reporting-MTA: dns; %s\r\n", user->set->hostname); + if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0) + str_printfa(str, "Original-Recipient: rfc822; %s\r\n", hdr); + str_printfa(str, "Final-Recipient: rfc822; %s\r\n", + smtp_address_encode(recipient)); + str_append(str, "Action: failed\r\n"); + str_printfa(str, "Status: %s\r\n", ctx->mailbox_full ? "5.2.2" : "5.2.0"); + } else { + /* MDN status report: For Sieve "reject" */ + str_printfa(str, "--%s\r\n" + "Content-Type: message/disposition-notification\r\n\r\n", + boundary); + str_printfa(str, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n", + user->set->hostname); + if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0) + str_printfa(str, "Original-Recipient: rfc822; %s\r\n", hdr); + str_printfa(str, "Final-Recipient: rfc822; %s\r\n", + smtp_address_encode(recipient)); + + if (orig_msgid != NULL) + str_printfa(str, "Original-Message-ID: %s\r\n", orig_msgid); + str_append(str, "Disposition: " + "automatic-action/MDN-sent-automatically; deleted\r\n"); + } + str_append(str, "\r\n"); + + /* original message's headers */ + str_printfa(str, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary); + o_stream_nsend(output, str_data(str), str_len(str)); + + if (mail_get_hdr_stream(mail, NULL, &input) == 0) { + /* Note: If you add more headers, they need to be sorted. + We'll drop Content-Type because we're not including the message + body, and having a multipart Content-Type may confuse some + MIME parsers when they don't see the message boundaries. */ + static const char *const exclude_headers[] = { + "Content-Type" + }; + + input = i_stream_create_header_filter(input, + HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR | + HEADER_FILTER_HIDE_BODY, exclude_headers, + N_ELEMENTS(exclude_headers), + *null_header_filter_callback, NULL); + + o_stream_nsend_istream(output, input); + i_stream_unref(&input); + } + + str_truncate(str, 0); + str_printfa(str, "\r\n\r\n--%s--\r\n", boundary); + o_stream_nsend(output, str_data(str), str_len(str)); + if ((ret = smtp_submit_run(smtp_submit, &error)) < 0) { + i_error("msgid=%s: Temporarily failed to send rejection: %s", + orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), + str_sanitize(error, 512)); + } else if (ret == 0) { + i_info("msgid=%s: Permanently failed to send rejection: %s", + orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), + str_sanitize(error, 512)); + } + smtp_submit_deinit(&smtp_submit); + return ret < 0 ? -1 : 0; +} diff --git a/src/lib-lda/mail-send.h b/src/lib-lda/mail-send.h new file mode 100644 index 0000000..88f87ed --- /dev/null +++ b/src/lib-lda/mail-send.h @@ -0,0 +1,11 @@ +#ifndef MAIL_SEND_H +#define MAIL_SEND_H + +struct mail; +struct mail_deliver_context; + +int mail_send_rejection(struct mail_deliver_context *ctx, + const struct smtp_address *recipient, + const char *reason); + +#endif 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); +} |