diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 17:36:47 +0000 |
commit | 0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch) | |
tree | 3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/imap-login | |
parent | Initial commit. (diff) | |
download | dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip |
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/imap-login')
-rw-r--r-- | src/imap-login/Makefile.am | 41 | ||||
-rw-r--r-- | src/imap-login/Makefile.in | 897 | ||||
-rw-r--r-- | src/imap-login/client-authenticate.c | 213 | ||||
-rw-r--r-- | src/imap-login/client-authenticate.h | 16 | ||||
-rw-r--r-- | src/imap-login/imap-login-client.c | 571 | ||||
-rw-r--r-- | src/imap-login/imap-login-client.h | 97 | ||||
-rw-r--r-- | src/imap-login/imap-login-cmd-id.c | 281 | ||||
-rw-r--r-- | src/imap-login/imap-login-commands.c | 70 | ||||
-rw-r--r-- | src/imap-login/imap-login-commands.h | 25 | ||||
-rw-r--r-- | src/imap-login/imap-login-settings.c | 95 | ||||
-rw-r--r-- | src/imap-login/imap-login-settings.h | 14 | ||||
-rw-r--r-- | src/imap-login/imap-proxy.c | 530 | ||||
-rw-r--r-- | src/imap-login/imap-proxy.h | 12 |
13 files changed, 2862 insertions, 0 deletions
diff --git a/src/imap-login/Makefile.am b/src/imap-login/Makefile.am new file mode 100644 index 0000000..904f530 --- /dev/null +++ b/src/imap-login/Makefile.am @@ -0,0 +1,41 @@ +pkglibexecdir = $(libexecdir)/dovecot + +pkglibexec_PROGRAMS = imap-login + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-auth \ + -I$(top_srcdir)/src/lib-sasl \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/login-common \ + $(BINARY_CFLAGS) + +imap_login_LDADD = \ + $(LIBDOVECOT_LOGIN) \ + $(LIBDOVECOT) \ + $(SSL_LIBS) \ + $(BINARY_LDFLAGS) + +imap_login_DEPENDENCIES = \ + $(LIBDOVECOT_LOGIN) \ + $(LIBDOVECOT_DEPS) + +imap_login_SOURCES = \ + imap-login-client.c \ + client-authenticate.c \ + imap-login-cmd-id.c \ + imap-login-commands.c \ + imap-login-settings.c \ + imap-proxy.c + +noinst_HEADERS = \ + client-authenticate.h \ + imap-proxy.h + +pkginc_libdir=$(pkgincludedir) +pkginc_lib_HEADERS = \ + imap-login-client.h \ + imap-login-commands.h \ + imap-login-settings.h diff --git a/src/imap-login/Makefile.in b/src/imap-login/Makefile.in new file mode 100644 index 0000000..bbf5afa --- /dev/null +++ b/src/imap-login/Makefile.in @@ -0,0 +1,897 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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@ +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@ +pkglibexec_PROGRAMS = imap-login$(EXEEXT) +subdir = src/imap-login +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__installdirs = "$(DESTDIR)$(pkglibexecdir)" \ + "$(DESTDIR)$(pkginc_libdir)" +PROGRAMS = $(pkglibexec_PROGRAMS) +am_imap_login_OBJECTS = imap-login-client.$(OBJEXT) \ + client-authenticate.$(OBJEXT) imap-login-cmd-id.$(OBJEXT) \ + imap-login-commands.$(OBJEXT) imap-login-settings.$(OBJEXT) \ + imap-proxy.$(OBJEXT) +imap_login_OBJECTS = $(am_imap_login_OBJECTS) +am__DEPENDENCIES_1 = +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 = +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)/client-authenticate.Po \ + ./$(DEPDIR)/imap-login-client.Po \ + ./$(DEPDIR)/imap-login-cmd-id.Po \ + ./$(DEPDIR)/imap-login-commands.Po \ + ./$(DEPDIR)/imap-login-settings.Po ./$(DEPDIR)/imap-proxy.Po +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 = $(imap_login_SOURCES) +DIST_SOURCES = $(imap_login_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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; }; \ + } +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) +pkglibexecdir = $(libexecdir)/dovecot +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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-auth \ + -I$(top_srcdir)/src/lib-sasl \ + -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/login-common \ + $(BINARY_CFLAGS) + +imap_login_LDADD = \ + $(LIBDOVECOT_LOGIN) \ + $(LIBDOVECOT) \ + $(SSL_LIBS) \ + $(BINARY_LDFLAGS) + +imap_login_DEPENDENCIES = \ + $(LIBDOVECOT_LOGIN) \ + $(LIBDOVECOT_DEPS) + +imap_login_SOURCES = \ + imap-login-client.c \ + client-authenticate.c \ + imap-login-cmd-id.c \ + imap-login-commands.c \ + imap-login-settings.c \ + imap-proxy.c + +noinst_HEADERS = \ + client-authenticate.h \ + imap-proxy.h + +pkginc_libdir = $(pkgincludedir) +pkginc_lib_HEADERS = \ + imap-login-client.h \ + imap-login-commands.h \ + imap-login-settings.h + +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/imap-login/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/imap-login/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-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-pkglibexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files + +clean-pkglibexecPROGRAMS: + @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +imap-login$(EXEEXT): $(imap_login_OBJECTS) $(imap_login_DEPENDENCIES) $(EXTRA_imap_login_DEPENDENCIES) + @rm -f imap-login$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(imap_login_OBJECTS) $(imap_login_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client-authenticate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-login-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-login-cmd-id.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-login-commands.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-login-settings.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-proxy.Po@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 $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(pkglibexecdir)" "$(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-pkglibexecPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/client-authenticate.Po + -rm -f ./$(DEPDIR)/imap-login-client.Po + -rm -f ./$(DEPDIR)/imap-login-cmd-id.Po + -rm -f ./$(DEPDIR)/imap-login-commands.Po + -rm -f ./$(DEPDIR)/imap-login-settings.Po + -rm -f ./$(DEPDIR)/imap-proxy.Po + -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-pkglibexecPROGRAMS + +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)/client-authenticate.Po + -rm -f ./$(DEPDIR)/imap-login-client.Po + -rm -f ./$(DEPDIR)/imap-login-cmd-id.Po + -rm -f ./$(DEPDIR)/imap-login-commands.Po + -rm -f ./$(DEPDIR)/imap-login-settings.Po + -rm -f ./$(DEPDIR)/imap-proxy.Po + -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-pkglibexecPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-pkglibexecPROGRAMS \ + 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-pkglibexecPROGRAMS 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-pkglibexecPROGRAMS + +.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/imap-login/client-authenticate.c b/src/imap-login/client-authenticate.c new file mode 100644 index 0000000..c8c3db2 --- /dev/null +++ b/src/imap-login/client-authenticate.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "login-common.h" +#include "base64.h" +#include "buffer.h" +#include "ioloop.h" +#include "istream.h" +#include "ostream.h" +#include "safe-memset.h" +#include "str.h" +#include "str-sanitize.h" +#include "net.h" +#include "imap-resp-code.h" +#include "imap-parser.h" +#include "imap-url.h" +#include "auth-client.h" +#include "imap-login-client.h" +#include "client-authenticate.h" +#include "imap-proxy.h" + + +void client_authenticate_get_capabilities(struct client *client, string_t *str) +{ + const struct auth_mech_desc *mech; + unsigned int i, count; + + mech = sasl_server_get_advertised_mechs(client, &count); + for (i = 0; i < count; i++) { + str_append_c(str, ' '); + str_append(str, "AUTH="); + str_append(str, mech[i].name); + } +} + +void imap_client_auth_result(struct client *client, + enum client_auth_result result, + const struct client_auth_reply *reply, + const char *text) +{ + struct imap_url url; + string_t *referral; + + switch (result) { + case CLIENT_AUTH_RESULT_SUCCESS: + /* nothing to be done for IMAP */ + break; + case CLIENT_AUTH_RESULT_REFERRAL_SUCCESS: + case CLIENT_AUTH_RESULT_REFERRAL_NOLOGIN: + /* IMAP referral + + [nologin] referral host=.. [port=..] [destuser=..] + [reason=..] + + NO [REFERRAL imap://destuser;AUTH=..@host:port/] Can't login. + OK [...] Logged in, but you should use this server instead. + .. [REFERRAL ..] (Reason from auth server) + */ + referral = t_str_new(128); + + i_zero(&url); + url.userid = reply->destuser; + url.auth_type = client->auth_mech_name; + url.host.name = reply->host; + if (reply->port != 143) + url.port = reply->port; + str_append(referral, "REFERRAL "); + str_append(referral, imap_url_create(&url)); + + if (result == CLIENT_AUTH_RESULT_REFERRAL_SUCCESS) { + client_send_reply_code(client, IMAP_CMD_REPLY_OK, + str_c(referral), text); + } else { + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + str_c(referral), text); + } + break; + case CLIENT_AUTH_RESULT_INVALID_BASE64: + case CLIENT_AUTH_RESULT_ABORTED: + client_send_reply(client, IMAP_CMD_REPLY_BAD, text); + break; + case CLIENT_AUTH_RESULT_AUTHFAILED_REASON: + case CLIENT_AUTH_RESULT_MECH_INVALID: + if (text[0] == '[') + client_send_reply(client, IMAP_CMD_REPLY_NO, text); + else { + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + "ALERT", text); + } + break; + case CLIENT_AUTH_RESULT_AUTHZFAILED: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_AUTHZFAILED, text); + break; + case CLIENT_AUTH_RESULT_TEMPFAIL: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_UNAVAILABLE, text); + break; + case CLIENT_AUTH_RESULT_SSL_REQUIRED: + case CLIENT_AUTH_RESULT_MECH_SSL_REQUIRED: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_PRIVACYREQUIRED, text); + break; + case CLIENT_AUTH_RESULT_PASS_EXPIRED: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_EXPIRED, text); + break; + case CLIENT_AUTH_RESULT_LOGIN_DISABLED: + case CLIENT_AUTH_RESULT_ANONYMOUS_DENIED: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_CONTACTADMIN, text); + break; + case CLIENT_AUTH_RESULT_AUTHFAILED: + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_AUTHFAILED, text); + break; + } +} + +static int +imap_client_auth_begin(struct imap_client *imap_client, const char *mech_name, + const char *init_resp) +{ + char *prefix; + + prefix = i_strdup_printf("%d%s", + imap_client->client_ignores_capability_resp_code ? 1 : 0, + imap_client->cmd_tag); + + i_free(imap_client->common.master_data_prefix); + imap_client->common.master_data_prefix = (void *)prefix; + imap_client->common.master_data_prefix_len = strlen(prefix)+1; + + if (*init_resp == '\0') + init_resp = NULL; + else if (strcmp(init_resp, "=") == 0) + init_resp = ""; + return client_auth_begin(&imap_client->common, mech_name, init_resp); +} + +int cmd_authenticate(struct imap_client *imap_client, bool *parsed_r) +{ + /* NOTE: This command's input is handled specially because the + SASL-IR can be large. */ + struct client *client = &imap_client->common; + const unsigned char *data; + size_t i, size; + int ret; + + *parsed_r = FALSE; + + /* <auth mechanism name> [<initial SASL response>] */ + if (!imap_client->auth_mech_name_parsed) { + data = i_stream_get_data(client->input, &size); + for (i = 0; i < size; i++) { + if (data[i] == ' ' || + data[i] == '\r' || data[i] == '\n') + break; + } + if (i == size) + return 0; + if (i == 0) { + /* empty mechanism name */ + imap_client->skip_line = TRUE; + return -1; + } + i_free(client->auth_mech_name); + client->auth_mech_name = i_strndup(data, i); + imap_client->auth_mech_name_parsed = TRUE; + if (data[i] == ' ') + i++; + i_stream_skip(client->input, i); + } + + /* get SASL-IR, if any */ + if ((ret = client_auth_read_line(client)) <= 0) + return ret; + + *parsed_r = TRUE; + imap_client->auth_mech_name_parsed = FALSE; + return imap_client_auth_begin(imap_client, + t_strdup(client->auth_mech_name), + t_strdup(str_c(client->auth_response))); +} + +int cmd_login(struct imap_client *imap_client, const struct imap_arg *args) +{ + struct client *client = &imap_client->common; + const char *user, *pass; + string_t *plain_login, *base64; + + /* two arguments: username and password */ + if (!imap_arg_get_astring(&args[0], &user) || + !imap_arg_get_astring(&args[1], &pass) || + !IMAP_ARG_IS_EOL(&args[2])) + return -1; + + if (!client_check_plaintext_auth(client, TRUE)) { + if (client->virtual_user == NULL) + client->virtual_user = i_strdup(user); + return 1; + } + + /* authorization ID \0 authentication ID \0 pass */ + plain_login = t_buffer_create(64); + buffer_append_c(plain_login, '\0'); + buffer_append(plain_login, user, strlen(user)); + buffer_append_c(plain_login, '\0'); + buffer_append(plain_login, pass, strlen(pass)); + + base64 = t_buffer_create(MAX_BASE64_ENCODED_SIZE(plain_login->used)); + base64_encode(plain_login->data, plain_login->used, base64); + return imap_client_auth_begin(imap_client, "PLAIN", str_c(base64)); +} diff --git a/src/imap-login/client-authenticate.h b/src/imap-login/client-authenticate.h new file mode 100644 index 0000000..68e05ef --- /dev/null +++ b/src/imap-login/client-authenticate.h @@ -0,0 +1,16 @@ +#ifndef CLIENT_AUTHENTICATE_H +#define CLIENT_AUTHENTICATE_H + +struct imap_arg; + +void client_authenticate_get_capabilities(struct client *client, string_t *str); + +void imap_client_auth_result(struct client *client, + enum client_auth_result result, + const struct client_auth_reply *reply, + const char *text); + +int cmd_login(struct imap_client *client, const struct imap_arg *args); +int cmd_authenticate(struct imap_client *imap_client, bool *parsed_r); + +#endif diff --git a/src/imap-login/imap-login-client.c b/src/imap-login/imap-login-client.c new file mode 100644 index 0000000..29ade52 --- /dev/null +++ b/src/imap-login/imap-login-client.c @@ -0,0 +1,571 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "login-common.h" +#include "buffer.h" +#include "ioloop.h" +#include "istream.h" +#include "ostream.h" +#include "safe-memset.h" +#include "str.h" +#include "imap-parser.h" +#include "imap-id.h" +#include "imap-resp-code.h" +#include "master-service.h" +#include "master-service-ssl-settings.h" +#include "master-auth.h" +#include "imap-login-client.h" +#include "client-authenticate.h" +#include "auth-client.h" +#include "imap-proxy.h" +#include "imap-quote.h" +#include "imap-login-commands.h" +#include "imap-login-settings.h" + +#if LOGIN_MAX_INBUF_SIZE < 1024+2 +# error LOGIN_MAX_INBUF_SIZE too short to fit all ID command parameters +#endif + +/* Disconnect client when it sends too many bad commands */ +#define CLIENT_MAX_BAD_COMMANDS 3 + +/* Skip incoming data until newline is found, + returns TRUE if newline was found. */ +bool client_skip_line(struct imap_client *client) +{ + const unsigned char *data; + size_t i, data_size; + + data = i_stream_get_data(client->common.input, &data_size); + + for (i = 0; i < data_size; i++) { + if (data[i] == '\n') { + i_stream_skip(client->common.input, i+1); + return TRUE; + } + } + + return FALSE; +} + +bool client_handle_parser_error(struct imap_client *client, + struct imap_parser *parser) +{ + const char *msg; + enum imap_parser_error parse_error; + + msg = imap_parser_get_error(parser, &parse_error); + switch (parse_error) { + case IMAP_PARSE_ERROR_NONE: + i_unreached(); + case IMAP_PARSE_ERROR_LITERAL_TOO_BIG: + client_send_reply(&client->common, + IMAP_CMD_REPLY_BYE, msg); + client_destroy(&client->common, msg); + return FALSE; + default: + break; + } + + client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, msg); + client->cmd_finished = TRUE; + client->skip_line = TRUE; + return TRUE; +} + +static bool is_login_cmd_disabled(struct client *client) +{ + if (client->secured) { + if (sasl_server_find_available_mech(client, "PLAIN") == NULL) { + /* no PLAIN authentication, can't use LOGIN command */ + return TRUE; + } + return FALSE; + } + if (client->set->disable_plaintext_auth) + return TRUE; + if (strcmp(client->ssl_set->ssl, "required") == 0) + return TRUE; + return FALSE; +} + +static const char *get_capability(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + string_t *cap_str = t_str_new(256); + bool explicit_capability = FALSE; + + if (*imap_client->set->imap_capability == '\0') + str_append(cap_str, CAPABILITY_BANNER_STRING); + else if (*imap_client->set->imap_capability != '+') { + explicit_capability = TRUE; + str_append(cap_str, imap_client->set->imap_capability); + } else { + str_append(cap_str, CAPABILITY_BANNER_STRING); + str_append_c(cap_str, ' '); + str_append(cap_str, imap_client->set->imap_capability + 1); + } + + if (!explicit_capability) { + if (imap_client->set->imap_literal_minus) + str_append(cap_str, " LITERAL-"); + else + str_append(cap_str, " LITERAL+"); + } + + if (client_is_tls_enabled(client) && !client->tls) + str_append(cap_str, " STARTTLS"); + if (is_login_cmd_disabled(client)) + str_append(cap_str, " LOGINDISABLED"); + + client_authenticate_get_capabilities(client, cap_str); + return str_c(cap_str); +} + +static int cmd_capability(struct imap_client *imap_client, + const struct imap_arg *args ATTR_UNUSED) +{ + struct client *client = &imap_client->common; + + /* Client is required to send CAPABILITY after STARTTLS, so the + capability resp-code workaround checks only pre-STARTTLS + CAPABILITY commands. */ + if (!client->starttls) + imap_client->client_ignores_capability_resp_code = TRUE; + client_send_raw(client, t_strconcat( + "* CAPABILITY ", get_capability(client), "\r\n", NULL)); + client_send_reply(client, IMAP_CMD_REPLY_OK, + "Pre-login capabilities listed, post-login capabilities have more."); + return 1; +} + +static int cmd_starttls(struct imap_client *client, + const struct imap_arg *args ATTR_UNUSED) +{ + client_cmd_starttls(&client->common); + return 1; +} + +static void +imap_client_notify_starttls(struct client *client, + bool success, const char *text) +{ + if (success) + client_send_reply(client, IMAP_CMD_REPLY_OK, text); + else + client_send_reply(client, IMAP_CMD_REPLY_BAD, text); +} + +static int cmd_noop(struct imap_client *client, + const struct imap_arg *args ATTR_UNUSED) +{ + client_send_reply(&client->common, IMAP_CMD_REPLY_OK, + "NOOP completed."); + return 1; +} + +static int cmd_logout(struct imap_client *client, + const struct imap_arg *args ATTR_UNUSED) +{ + client_send_reply(&client->common, IMAP_CMD_REPLY_BYE, "Logging out"); + client_send_reply(&client->common, IMAP_CMD_REPLY_OK, + "Logout completed."); + client_destroy(&client->common, CLIENT_UNAUTHENTICATED_LOGOUT_MSG); + return 1; +} + +static int cmd_enable(struct imap_client *client, + const struct imap_arg *args ATTR_UNUSED) +{ + client_send_raw(&client->common, "* ENABLED\r\n"); + client_send_reply(&client->common, IMAP_CMD_REPLY_OK, + "ENABLE ignored in non-authenticated state."); + return 1; +} + +static int client_command_execute(struct imap_client *client, const char *cmd, + const struct imap_arg *args) +{ + struct imap_login_command *login_cmd; + + login_cmd = imap_login_command_lookup(cmd); + if (login_cmd == NULL) + return -2; + return login_cmd->func(client, args); +} + +static bool client_invalid_command(struct imap_client *client) +{ + if (client->cmd_tag == NULL || *client->cmd_tag == '\0') + client->cmd_tag = "*"; + if (++client->common.bad_counter >= CLIENT_MAX_BAD_COMMANDS) { + client_send_reply(&client->common, IMAP_CMD_REPLY_BYE, + "Too many invalid IMAP commands."); + client_destroy(&client->common, "Too many invalid commands"); + return FALSE; + } + client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, + "Error in IMAP command received by server."); + return TRUE; +} + +static int client_parse_command(struct imap_client *client, + const struct imap_arg **args_r) +{ + switch (imap_parser_read_args(client->parser, 0, 0, args_r)) { + case -1: + /* error */ + if (!client_handle_parser_error(client, client->parser)) { + /* client destroyed */ + return 0; + } + return -1; + case -2: + /* not enough data */ + return 0; + default: + /* we read the entire line - skip over the CRLF */ + if (!client_skip_line(client)) + i_unreached(); + return 1; + } +} + +static bool client_handle_input(struct imap_client *client) +{ + const char *tag, *name; + int ret; + + i_assert(!client->common.authenticating); + + if (client->cmd_finished) { + /* clear the previous command from memory. don't do this + immediately after handling command since we need the + cmd_tag to stay some time after authentication commands. */ + client->cmd_tag = NULL; + client->cmd_name = NULL; + imap_parser_reset(client->parser); + + /* remove \r\n */ + if (client->skip_line) { + if (!client_skip_line(client)) + return FALSE; + client->skip_line = FALSE; + } + + client->cmd_finished = FALSE; + } + + if (client->cmd_tag == NULL) { + ret = imap_parser_read_tag(client->parser, &tag); + if (ret == 0) + return FALSE; /* need more data */ + if (ret < 0 || strlen(tag) > IMAP_TAG_MAX_LEN) { + /* the tag is invalid, don't allow it and don't + send it back. this attempts to prevent any + potentially dangerous replies in case someone tries + to access us using HTTP protocol. */ + client->skip_line = TRUE; + client->cmd_finished = TRUE; + if (!client_invalid_command(client)) + return FALSE; + return client_handle_input(client); + } + client->cmd_tag = tag; + } + + if (client->cmd_name == NULL) { + ret = imap_parser_read_command_name(client->parser, &name); + if (ret == 0) + return FALSE; /* need more data */ + if (ret < 0) { + client->skip_line = TRUE; + client->cmd_finished = TRUE; + if (!client_invalid_command(client)) + return FALSE; + return client_handle_input(client); + } + client->cmd_name = name; + } + return client->common.v.input_next_cmd(&client->common); +} + +static bool imap_client_input_next_cmd(struct client *_client) +{ + struct imap_client *client = (struct imap_client *)_client; + const struct imap_arg *args; + bool parsed; + int ret; + + if (strcasecmp(client->cmd_name, "AUTHENTICATE") == 0) { + /* SASL-IR may need more space than input buffer's size, + so we'll handle it as a special case. */ + ret = cmd_authenticate(client, &parsed); + if (ret == 0 && !parsed) + return FALSE; + } else if (strcasecmp(client->cmd_name, "ID") == 0) { + /* ID extensions allows max. 30 parameters, + each max. 1024 bytes long. that brings us over the input + buffer's size, so handle the parameters one at a time */ + ret = cmd_id(client); + if (ret == 0) + return FALSE; + if (ret < 0) + ret = 1; /* don't send the error reply again */ + } else { + ret = client_parse_command(client, &args); + if (ret < 0) + return TRUE; + if (ret == 0) + return FALSE; + ret = *client->cmd_tag == '\0' ? -1 : + client_command_execute(client, client->cmd_name, args); + } + + client->cmd_finished = TRUE; + if (ret == -2 && strcasecmp(client->cmd_tag, "LOGIN") == 0) { + client_send_reply(&client->common, IMAP_CMD_REPLY_BAD, + "First parameter in line is IMAP's command tag, " + "not the command name. Add that before the command, " + "like: a login user pass"); + } else if (ret < 0) { + if (!client_invalid_command(client)) + return FALSE; + } + + return ret != 0 && !client->common.destroyed; +} + +static void imap_client_input(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + if (!client_read(client)) + return; + + client_ref(client); + o_stream_cork(imap_client->common.output); + for (;;) { + if (!auth_client_is_connected(auth_client)) { + /* we're not currently connected to auth process - + don't allow any commands */ + client_notify_status(client, FALSE, + AUTH_SERVER_WAITING_MSG); + timeout_remove(&client->to_auth_waiting); + + client->input_blocked = TRUE; + break; + } else { + if (!client_handle_input(imap_client)) + break; + } + } + o_stream_uncork(imap_client->common.output); + client_unref(&client); +} + +static struct client *imap_client_alloc(pool_t pool) +{ + struct imap_client *imap_client; + + imap_client = p_new(pool, struct imap_client, 1); + return &imap_client->common; +} + +static void imap_client_create(struct client *client, void **other_sets) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + imap_client->set = other_sets[0]; + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, + IMAP_LOGIN_MAX_LINE_LENGTH); + if (imap_client->set->imap_literal_minus) + imap_parser_enable_literal_minus(imap_client->parser); + client->io = io_add_istream(client->input, client_input, client); +} + +static void imap_client_destroy(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + i_free_and_null(imap_client->proxy_backend_capability); + imap_parser_unref(&imap_client->parser); +} + +static void imap_client_notify_auth_ready(struct client *client) +{ + string_t *greet; + + greet = t_str_new(128); + str_append(greet, "* OK "); + str_printfa(greet, "[CAPABILITY %s] ", get_capability(client)); + str_append(greet, client->set->login_greeting); + str_append(greet, "\r\n"); + + client_send_raw(client, str_c(greet)); + + client->banner_sent = TRUE; +} + +static void imap_client_starttls(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + imap_parser_unref(&imap_client->parser); + imap_client->parser = + imap_parser_create(imap_client->common.input, + imap_client->common.output, + IMAP_LOGIN_MAX_LINE_LENGTH); + + /* CRLF is lost from buffer when streams are reopened. */ + imap_client->skip_line = FALSE; +} + +static void ATTR_NULL(3) +client_send_reply_raw(struct client *client, + const char *prefix, const char *resp_code, + const char *text, bool tagged) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + T_BEGIN { + string_t *line = t_str_new(256); + + if (tagged) + str_append(line, imap_client->cmd_tag); + else + str_append_c(line, '*'); + str_append_c(line, ' '); + str_append(line, prefix); + str_append_c(line, ' '); + if (resp_code != NULL) + str_printfa(line, "[%s] ", resp_code); + str_append(line, text); + str_append(line, "\r\n"); + + client_send_raw_data(client, str_data(line), str_len(line)); + } T_END; +} + +void client_send_reply_code(struct client *client, enum imap_cmd_reply reply, + const char *resp_code, const char *text) +{ + const char *prefix = "NO"; + bool tagged = TRUE; + + switch (reply) { + case IMAP_CMD_REPLY_OK: + prefix = "OK"; + break; + case IMAP_CMD_REPLY_NO: + break; + case IMAP_CMD_REPLY_BAD: + prefix = "BAD"; + break; + case IMAP_CMD_REPLY_BYE: + prefix = "BYE"; + tagged = FALSE; + break; + } + client_send_reply_raw(client, prefix, resp_code, text, tagged); +} + +void client_send_reply(struct client *client, enum imap_cmd_reply reply, + const char *text) +{ + client_send_reply_code(client, reply, NULL, text); +} + +static void +imap_client_notify_status(struct client *client, bool bad, const char *text) +{ + if (bad) + client_send_reply_raw(client, "BAD", "ALERT", text, FALSE); + else + client_send_reply_raw(client, "OK", NULL, text, FALSE); +} + +static void +imap_client_notify_disconnect(struct client *client, + enum client_disconnect_reason reason, + const char *text) +{ + if (reason == CLIENT_DISCONNECT_INTERNAL_ERROR) { + client_send_reply_code(client, IMAP_CMD_REPLY_BYE, + IMAP_RESP_CODE_UNAVAILABLE, text); + } else { + client_send_reply_code(client, IMAP_CMD_REPLY_BYE, NULL, text); + } +} + +static void imap_login_preinit(void) +{ + login_set_roots = imap_login_setting_roots; +} + +static const struct imap_login_command imap_login_commands[] = { + { "LOGIN", cmd_login }, + { "CAPABILITY", cmd_capability }, + { "STARTTLS", cmd_starttls }, + { "NOOP", cmd_noop }, + { "LOGOUT", cmd_logout }, + { "ENABLE", cmd_enable } +}; + +static void imap_login_init(void) +{ + imap_login_commands_init(); + imap_login_commands_register(imap_login_commands, + N_ELEMENTS(imap_login_commands)); +} + +static void imap_login_deinit(void) +{ + clients_destroy_all(); + imap_login_commands_deinit(); +} + +static struct client_vfuncs imap_client_vfuncs = { + .alloc = imap_client_alloc, + .create = imap_client_create, + .destroy = imap_client_destroy, + .notify_auth_ready = imap_client_notify_auth_ready, + .notify_disconnect = imap_client_notify_disconnect, + .notify_status = imap_client_notify_status, + .notify_starttls = imap_client_notify_starttls, + .starttls = imap_client_starttls, + .input = imap_client_input, + .auth_result = imap_client_auth_result, + .proxy_reset = imap_proxy_reset, + .proxy_parse_line = imap_proxy_parse_line, + .proxy_failed = imap_proxy_failed, + .proxy_get_state = imap_proxy_get_state, + .send_raw_data = client_common_send_raw_data, + .input_next_cmd = imap_client_input_next_cmd, + .free = client_common_default_free, +}; + +static struct login_binary imap_login_binary = { + .protocol = "imap", + .process_name = "imap-login", + .default_port = 143, + .default_ssl_port = 993, + + .event_category = { + .name = "imap", + }, + + .client_vfuncs = &imap_client_vfuncs, + .preinit = imap_login_preinit, + .init = imap_login_init, + .deinit = imap_login_deinit, + + .sasl_support_final_reply = FALSE, + .anonymous_login_acceptable = TRUE, +}; + +int main(int argc, char *argv[]) +{ + return login_binary_run(&imap_login_binary, argc, argv); +} diff --git a/src/imap-login/imap-login-client.h b/src/imap-login/imap-login-client.h new file mode 100644 index 0000000..002829b --- /dev/null +++ b/src/imap-login/imap-login-client.h @@ -0,0 +1,97 @@ +#ifndef IMAP_LOGIN_CLIENT_H +#define IMAP_LOGIN_CLIENT_H + +#include "net.h" +#include "imap-id.h" +#include "client-common.h" + +/* Master prefix is: <1|0><imap tag><NUL> */ +#define IMAP_TAG_MAX_LEN (LOGIN_MAX_MASTER_PREFIX_LEN-2) + +/* maximum length for IMAP command line. */ +#define IMAP_LOGIN_MAX_LINE_LENGTH 8192 + +enum imap_client_id_state { + IMAP_CLIENT_ID_STATE_LIST = 0, + IMAP_CLIENT_ID_STATE_KEY, + IMAP_CLIENT_ID_STATE_VALUE +}; + +/* Multiple commands can be sent pipelined, so the sent_state is a bitmask */ +enum imap_proxy_sent_state { + IMAP_PROXY_SENT_STATE_ID = 0x01, + IMAP_PROXY_SENT_STATE_STARTTLS = 0x02, + IMAP_PROXY_SENT_STATE_CAPABILITY = 0x04, + IMAP_PROXY_SENT_STATE_AUTHENTICATE = 0x08, + IMAP_PROXY_SENT_STATE_AUTH_CONTINUE = 0x10, + IMAP_PROXY_SENT_STATE_LOGIN = 0x20, + + IMAP_PROXY_SENT_STATE_COUNT = 6 +}; + +enum imap_proxy_rcvd_state { + IMAP_PROXY_RCVD_STATE_NONE, + IMAP_PROXY_RCVD_STATE_BANNER, + IMAP_PROXY_RCVD_STATE_ID, + IMAP_PROXY_RCVD_STATE_STARTTLS, + IMAP_PROXY_RCVD_STATE_CAPABILITY, + IMAP_PROXY_RCVD_STATE_AUTH_CONTINUE, + IMAP_PROXY_RCVD_STATE_LOGIN, + + IMAP_PROXY_RCVD_STATE_COUNT +}; + +struct imap_client_cmd_id { + struct imap_parser *parser; + + enum imap_client_id_state state; + char key[IMAP_ID_KEY_MAX_LEN+1]; + + char **log_keys; + string_t *log_reply; +}; + +struct imap_client { + struct client common; + + const struct imap_login_settings *set; + struct imap_parser *parser; + char *proxy_backend_capability; + + const char *cmd_tag, *cmd_name; + struct imap_client_cmd_id *cmd_id; + + enum imap_proxy_sent_state proxy_sent_state; + enum imap_proxy_rcvd_state proxy_rcvd_state; + + bool cmd_finished:1; + bool proxy_sasl_ir:1; + bool proxy_logindisabled:1; + bool proxy_seen_banner:1; + bool skip_line:1; + bool id_logged:1; + bool proxy_capability_request_sent:1; + bool client_ignores_capability_resp_code:1; + bool auth_mech_name_parsed:1; +}; + +bool client_skip_line(struct imap_client *client); + +enum imap_cmd_reply { + IMAP_CMD_REPLY_OK, + IMAP_CMD_REPLY_NO, + IMAP_CMD_REPLY_BAD, + IMAP_CMD_REPLY_BYE +}; + +void client_send_reply(struct client *client, + enum imap_cmd_reply reply, const char *text); +void client_send_reply_code(struct client *client, + enum imap_cmd_reply reply, const char *resp_code, + const char *text) ATTR_NULL(3); +bool client_handle_parser_error(struct imap_client *client, + struct imap_parser *parser); + +int cmd_id(struct imap_client *client); + +#endif diff --git a/src/imap-login/imap-login-cmd-id.c b/src/imap-login/imap-login-cmd-id.c new file mode 100644 index 0000000..a1c6294 --- /dev/null +++ b/src/imap-login/imap-login-cmd-id.c @@ -0,0 +1,281 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "login-common.h" +#include "str.h" +#include "imap-parser.h" +#include "imap-quote.h" +#include "imap-login-settings.h" +#include "imap-login-client.h" + +struct imap_id_param_handler { + const char *key; + bool key_is_prefix; + + void (*callback)(struct imap_client *client, + const char *key, const char *value); +}; + +static void +cmd_id_x_originating_ip(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + (void)net_addr2ip(value, &client->common.ip); +} + +static void +cmd_id_x_originating_port(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + (void)net_str2port(value, &client->common.remote_port); +} + +static void +cmd_id_x_connected_ip(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + (void)net_addr2ip(value, &client->common.local_ip); +} + +static void +cmd_id_x_connected_port(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + (void)net_str2port(value, &client->common.local_port); +} + +static void +cmd_id_x_proxy_ttl(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + if (str_to_uint(value, &client->common.proxy_ttl) < 0) { + /* nothing */ + } +} + +static void +cmd_id_x_session_id(struct imap_client *client, + const char *key ATTR_UNUSED, const char *value) +{ + if (strlen(value) <= LOGIN_MAX_SESSION_ID_LEN) { + client->common.session_id = + p_strdup(client->common.pool, value); + } +} + +static void +cmd_id_x_forward_(struct imap_client *client, + const char *key, const char *value) +{ + i_assert(strncasecmp(key, "x-forward-", 10) == 0); + client_add_forward_field(&client->common, key+10, value); +} + +static const struct imap_id_param_handler imap_login_id_params[] = { + { "x-originating-ip", FALSE, cmd_id_x_originating_ip }, + { "x-originating-port", FALSE, cmd_id_x_originating_port }, + { "x-connected-ip", FALSE, cmd_id_x_connected_ip }, + { "x-connected-port", FALSE, cmd_id_x_connected_port }, + { "x-proxy-ttl", FALSE, cmd_id_x_proxy_ttl }, + { "x-session-id", FALSE, cmd_id_x_session_id }, + { "x-session-ext-id", FALSE, cmd_id_x_session_id }, + { "x-forward-", TRUE, cmd_id_x_forward_ }, + + { NULL, FALSE, NULL } +}; + +static const struct imap_id_param_handler * +imap_id_param_handler_find(const char *key) +{ + for (unsigned int i = 0; imap_login_id_params[i].key != NULL; i++) { + unsigned int prefix_len = strlen(imap_login_id_params[i].key); + + if (strncasecmp(imap_login_id_params[i].key, key, prefix_len) == 0 && + (key[prefix_len] == '\0' || + imap_login_id_params[i].key_is_prefix)) + return &imap_login_id_params[i]; + } + return NULL; +} + +static bool +client_try_update_info(struct imap_client *client, + const char *key, const char *value) +{ + const struct imap_id_param_handler *handler; + + handler = imap_id_param_handler_find(key); + if (handler == NULL) + return FALSE; + + /* do not try to process NIL values as client-info, + but store them for non-reserved keys */ + if (client->common.trusted && !client->id_logged && value != NULL) + handler->callback(client, key, value); + return TRUE; +} + +static void cmd_id_handle_keyvalue(struct imap_client *client, + const char *key, const char *value) +{ + bool client_id_str; + /* length of key + length of value (NIL for NULL) and two set of + quotes and space */ + size_t kvlen = strlen(key) + 2 + 1 + + (value == NULL ? 3 : strlen(value)) + 2; + + client_id_str = !client_try_update_info(client, key, value); + + if (client->set->imap_id_retain && client_id_str && + (client->common.client_id == NULL || + str_len(client->common.client_id) + kvlen < LOGIN_MAX_CLIENT_ID_LEN)) { + if (client->common.client_id == NULL) { + client->common.client_id = str_new(client->common.preproxy_pool, 64); + } else { + str_append_c(client->common.client_id, ' '); + } + imap_append_quoted(client->common.client_id, key); + str_append_c(client->common.client_id, ' '); + if (value == NULL) + str_append(client->common.client_id, "NIL"); + else + imap_append_quoted(client->common.client_id, value); + } + + if (client->cmd_id->log_reply != NULL && + (client->cmd_id->log_keys == NULL || + str_array_icase_find((void *)client->cmd_id->log_keys, key))) + imap_id_log_reply_append(client->cmd_id->log_reply, key, value); +} + +static int cmd_id_handle_args(struct imap_client *client, + const struct imap_arg *arg) +{ + struct imap_client_cmd_id *id = client->cmd_id; + const char *key, *value; + + switch (id->state) { + case IMAP_CLIENT_ID_STATE_LIST: + if (arg->type == IMAP_ARG_NIL) + return 1; + if (arg->type != IMAP_ARG_LIST) + return -1; + if (client->set->imap_id_log[0] == '\0') { + /* no ID logging */ + } else if (client->id_logged) { + /* already logged the ID reply */ + } else { + id->log_reply = str_new(default_pool, 64); + if (strcmp(client->set->imap_id_log, "*") == 0) { + /* log all keys */ + } else { + /* log only specified keys */ + id->log_keys = p_strsplit_spaces(default_pool, + client->set->imap_id_log, " "); + } + } + id->state = IMAP_CLIENT_ID_STATE_KEY; + break; + case IMAP_CLIENT_ID_STATE_KEY: + if (!imap_arg_get_string(arg, &key)) + return -1; + if (i_strocpy(id->key, key, sizeof(id->key)) < 0) + return -1; + id->state = IMAP_CLIENT_ID_STATE_VALUE; + break; + case IMAP_CLIENT_ID_STATE_VALUE: + if (!imap_arg_get_nstring(arg, &value)) + return -1; + cmd_id_handle_keyvalue(client, id->key, value); + id->state = IMAP_CLIENT_ID_STATE_KEY; + break; + } + return 0; +} + +static void cmd_id_finish(struct imap_client *client) +{ + /* finished handling the parameters */ + if (!client->id_logged) { + client->id_logged = TRUE; + + if (client->cmd_id->log_reply != NULL) { + e_info(client->common.event, "ID sent: %s", + str_c(client->cmd_id->log_reply)); + } + } + + client_send_raw(&client->common, + t_strdup_printf("* ID %s\r\n", + imap_id_reply_generate(client->set->imap_id_send))); + client_send_reply(&client->common, IMAP_CMD_REPLY_OK, "ID completed."); +} + +static void cmd_id_free(struct imap_client *client) +{ + struct imap_client_cmd_id *id = client->cmd_id; + + str_free(&id->log_reply); + if (id->log_keys != NULL) + p_strsplit_free(default_pool, id->log_keys); + imap_parser_unref(&id->parser); + + i_free_and_null(client->cmd_id); + client->skip_line = TRUE; +} + +int cmd_id(struct imap_client *client) +{ + struct imap_client_cmd_id *id; + enum imap_parser_flags parser_flags; + const struct imap_arg *args; + int ret; + + if (client->common.client_id != NULL) + str_truncate(client->common.client_id, 0); + + if (client->cmd_id == NULL) { + client->cmd_id = id = i_new(struct imap_client_cmd_id, 1); + id->parser = imap_parser_create(client->common.input, + client->common.output, + IMAP_LOGIN_MAX_LINE_LENGTH); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(id->parser); + parser_flags = IMAP_PARSE_FLAG_STOP_AT_LIST; + } else { + id = client->cmd_id; + parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST; + } + + while ((ret = imap_parser_read_args(id->parser, 1, parser_flags, &args)) > 0) { + i_assert(ret == 1); + + if ((ret = cmd_id_handle_args(client, args)) < 0) { + client_send_reply(&client->common, + IMAP_CMD_REPLY_BAD, + "Invalid ID parameters"); + cmd_id_free(client); + return -1; + } + if (ret > 0) { + /* NIL parameter */ + ret = 0; + break; + } + imap_parser_reset(id->parser); + parser_flags = IMAP_PARSE_FLAG_INSIDE_LIST; + } + if (ret == 0) { + /* finished the line */ + cmd_id_finish(client); + cmd_id_free(client); + return 1; + } else if (ret == -1) { + if (!client_handle_parser_error(client, id->parser)) + return 0; + cmd_id_free(client); + return -1; + } else { + i_assert(ret == -2); + return 0; + } +} diff --git a/src/imap-login/imap-login-commands.c b/src/imap-login/imap-login-commands.c new file mode 100644 index 0000000..8d4878d --- /dev/null +++ b/src/imap-login/imap-login-commands.c @@ -0,0 +1,70 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "login-common.h" +#include "array.h" +#include "imap-login-commands.h" + +static ARRAY(struct imap_login_command *) imap_login_commands; +static pool_t imap_login_commands_pool; + +struct imap_login_command *imap_login_command_lookup(const char *name) +{ + struct imap_login_command *cmd; + + array_foreach_elem(&imap_login_commands, cmd) { + if (strcasecmp(cmd->name, name) == 0) + return cmd; + } + return NULL; +} + +void imap_login_commands_register(const struct imap_login_command *commands, + unsigned int count) +{ + struct imap_login_command *cmd; + unsigned int i; + + for (i = 0; i < count; i++) { + cmd = p_new(imap_login_commands_pool, struct imap_login_command, 1); + cmd->name = p_strdup(imap_login_commands_pool, commands[i].name); + cmd->func = commands[i].func; + array_push_back(&imap_login_commands, &cmd); + } +} + +static void +imap_login_command_unregister(const struct imap_login_command *unreg_cmd) +{ + struct imap_login_command *const *cmdp; + + array_foreach(&imap_login_commands, cmdp) { + if ((*cmdp)->func == unreg_cmd->func && + strcmp((*cmdp)->name, unreg_cmd->name) == 0) { + array_delete(&imap_login_commands, + array_foreach_idx(&imap_login_commands, cmdp), 1); + return; + } + } + i_panic("imap_login_command_unregister: Command '%s' not found", unreg_cmd->name); +} + +void imap_login_commands_unregister(const struct imap_login_command *commands, + unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + imap_login_command_unregister(&commands[i]); +} + +void imap_login_commands_init(void) +{ + imap_login_commands_pool = + pool_alloconly_create("imap login commands", 128); + p_array_init(&imap_login_commands, imap_login_commands_pool, 8); +} + +void imap_login_commands_deinit(void) +{ + pool_unref(&imap_login_commands_pool); +} diff --git a/src/imap-login/imap-login-commands.h b/src/imap-login/imap-login-commands.h new file mode 100644 index 0000000..d9ecd1c --- /dev/null +++ b/src/imap-login/imap-login-commands.h @@ -0,0 +1,25 @@ +#ifndef IMAP_LOGIN_COMMANDS_H +#define IMAP_LOGIN_COMMANDS_H + +struct imap_arg; +struct imap_client; + +typedef int imap_login_command_t(struct imap_client *client, + const struct imap_arg *args); + +struct imap_login_command { + const char *name; + imap_login_command_t *func; +}; + +struct imap_login_command *imap_login_command_lookup(const char *name); + +void imap_login_commands_register(const struct imap_login_command *commands, + unsigned int count); +void imap_login_commands_unregister(const struct imap_login_command *commands, + unsigned int count); + +void imap_login_commands_init(void); +void imap_login_commands_deinit(void); + +#endif diff --git a/src/imap-login/imap-login-settings.c b/src/imap-login/imap-login-settings.c new file mode 100644 index 0000000..74ab65c --- /dev/null +++ b/src/imap-login/imap-login-settings.c @@ -0,0 +1,95 @@ +/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "settings-parser.h" +#include "service-settings.h" +#include "login-settings.h" +#include "imap-login-settings.h" + +#include <stddef.h> + +/* <settings checks> */ +static struct inet_listener_settings imap_login_inet_listeners_array[] = { + { .name = "imap", .address = "", .port = 143 }, + { .name = "imaps", .address = "", .port = 993, .ssl = TRUE } +}; +static struct inet_listener_settings *imap_login_inet_listeners[] = { + &imap_login_inet_listeners_array[0], + &imap_login_inet_listeners_array[1] +}; +static buffer_t imap_login_inet_listeners_buf = { + { { imap_login_inet_listeners, sizeof(imap_login_inet_listeners) } } +}; +/* </settings checks> */ + +struct service_settings imap_login_service_settings = { + .name = "imap-login", + .protocol = "imap", + .type = "login", + .executable = "imap-login", + .user = "$default_login_user", + .group = "", + .privileged_group = "", + .extra_groups = "", + .chroot = "login", + + .drop_priv_before_exec = FALSE, + + .process_min_avail = 0, + .process_limit = 0, + .client_limit = 0, + .service_count = 1, + .idle_kill = 0, + .vsz_limit = UOFF_T_MAX, + + .unix_listeners = ARRAY_INIT, + .fifo_listeners = ARRAY_INIT, + .inet_listeners = { { &imap_login_inet_listeners_buf, + sizeof(imap_login_inet_listeners[0]) } } +}; + +#undef DEF +#define DEF(type, name) \ + SETTING_DEFINE_STRUCT_##type(#name, name, struct imap_login_settings) + +static const struct setting_define imap_login_setting_defines[] = { + DEF(STR, imap_capability), + DEF(STR, imap_id_send), + DEF(STR, imap_id_log), + DEF(BOOL, imap_literal_minus), + DEF(BOOL, imap_id_retain), + + SETTING_DEFINE_LIST_END +}; + +static const struct imap_login_settings imap_login_default_settings = { + .imap_capability = "", + .imap_id_send = "name *", + .imap_id_log = "", + .imap_literal_minus = FALSE, + .imap_id_retain = FALSE, +}; + +static const struct setting_parser_info *imap_login_setting_dependencies[] = { + &login_setting_parser_info, + NULL +}; + +static const struct setting_parser_info imap_login_setting_parser_info = { + .module_name = "imap-login", + .defines = imap_login_setting_defines, + .defaults = &imap_login_default_settings, + + .type_offset = SIZE_MAX, + .struct_size = sizeof(struct imap_login_settings), + + .parent_offset = SIZE_MAX, + .dependencies = imap_login_setting_dependencies +}; + +const struct setting_parser_info *imap_login_setting_roots[] = { + &login_setting_parser_info, + &imap_login_setting_parser_info, + NULL +}; diff --git a/src/imap-login/imap-login-settings.h b/src/imap-login/imap-login-settings.h new file mode 100644 index 0000000..51ce1a8 --- /dev/null +++ b/src/imap-login/imap-login-settings.h @@ -0,0 +1,14 @@ +#ifndef IMAP_LOGIN_SETTINGS_H +#define IMAP_LOGIN_SETTINGS_H + +struct imap_login_settings { + const char *imap_capability; + const char *imap_id_send; + const char *imap_id_log; + bool imap_literal_minus; + bool imap_id_retain; +}; + +extern const struct setting_parser_info *imap_login_setting_roots[]; + +#endif diff --git a/src/imap-login/imap-proxy.c b/src/imap-login/imap-proxy.c new file mode 100644 index 0000000..aa5a5aa --- /dev/null +++ b/src/imap-login/imap-proxy.c @@ -0,0 +1,530 @@ +/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */ + +#include "login-common.h" +#include "array.h" +#include "ioloop.h" +#include "istream.h" +#include "ostream.h" +#include "base64.h" +#include "str.h" +#include "str-sanitize.h" +#include "safe-memset.h" +#include "dsasl-client.h" +#include "imap-login-client.h" +#include "client-authenticate.h" +#include "imap-resp-code.h" +#include "imap-quote.h" +#include "imap-proxy.h" + +static const char *imap_proxy_sent_state_names[IMAP_PROXY_SENT_STATE_COUNT] = { + "id", "starttls", "capability", + "authenticate", "auth-continue", "login" +}; +static const char *imap_proxy_rcvd_state_names[IMAP_PROXY_RCVD_STATE_COUNT] = { + "none", "banner", "id", "starttls", "capability", + "auth-continue", "login" +}; + +static void proxy_write_id(struct imap_client *client, string_t *str) +{ + i_assert(client->common.proxy_ttl > 1); + + str_append(str, "I ID ("); + if (client->common.client_id != NULL && + str_len(client->common.client_id) > 0) { + str_append_str(str, client->common.client_id); + str_append_c(str, ' '); + } + str_printfa(str, "\"x-session-id\" \"%s\" " + "\"x-originating-ip\" \"%s\" " + "\"x-originating-port\" \"%u\" " + "\"x-connected-ip\" \"%s\" " + "\"x-connected-port\" \"%u\" " + "\"x-proxy-ttl\" \"%u\"", + client_get_session_id(&client->common), + net_ip2addr(&client->common.ip), + client->common.remote_port, + net_ip2addr(&client->common.local_ip), + client->common.local_port, + client->common.proxy_ttl - 1); + + /* append any forward_ variables to request */ + for(const char *const *ptr = client->common.auth_passdb_args; *ptr != NULL; ptr++) { + if (strncasecmp(*ptr, "forward_", 8) == 0) { + const char *key = t_strconcat("x-forward-", + t_strcut((*ptr)+8, '='), + NULL); + const char *val = i_strchr_to_next(*ptr, '='); + str_append_c(str, ' '); + imap_append_string(str, key); + str_append_c(str, ' '); + imap_append_nstring(str, val); + } + } + + str_append(str, ")\r\n"); +} + +static int proxy_write_starttls(struct imap_client *client, string_t *str) +{ + enum login_proxy_ssl_flags ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy); + if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) { + if (client->proxy_backend_capability != NULL && + !str_array_icase_find(t_strsplit(client->proxy_backend_capability, " "), "STARTTLS")) { + login_proxy_failed(client->common.login_proxy, + login_proxy_get_event(client->common.login_proxy), + LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG, + "STARTTLS not supported"); + return -1; + } + str_append(str, "S STARTTLS\r\n"); + client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_STARTTLS; + return 1; + } + return 0; +} + +static int proxy_write_login(struct imap_client *client, string_t *str) +{ + struct dsasl_client_settings sasl_set; + const unsigned char *output; + size_t len; + const char *mech_name, *error; + + /* Send CAPABILITY command if we don't know the capabilities yet. + Also as kind of a Dovecot-backend workaround if the client insisted + on sending CAPABILITY command (even though our banner already sent + it), send the (unnecessary) CAPABILITY command to backend as well + to avoid sending the CAPABILITY reply twice (untagged and OK resp + code). */ + if (!client->proxy_capability_request_sent && + (client->proxy_backend_capability == NULL || + client->client_ignores_capability_resp_code)) { + client->proxy_capability_request_sent = TRUE; + client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_CAPABILITY; + str_append(str, "C CAPABILITY\r\n"); + if (client->common.proxy_nopipelining) { + /* authenticate only after receiving C OK reply. */ + return 0; + } + } + + if (client->common.proxy_mech == NULL) { + /* logging in normally - use LOGIN command */ + if (client->proxy_logindisabled && + login_proxy_get_ssl_flags(client->common.login_proxy) == 0) { + login_proxy_failed(client->common.login_proxy, + login_proxy_get_event(client->common.login_proxy), + LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG, + "LOGINDISABLED advertised, but SSL/TLS not enabled"); + return -1; + } + str_append(str, "L LOGIN "); + imap_append_string(str, client->common.proxy_user); + str_append_c(str, ' '); + imap_append_string(str, client->common.proxy_password); + str_append(str, "\r\n"); + + client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_LOGIN; + return 0; + } + + i_assert(client->common.proxy_sasl_client == NULL); + i_zero(&sasl_set); + sasl_set.authid = client->common.proxy_master_user != NULL ? + client->common.proxy_master_user : client->common.proxy_user; + sasl_set.authzid = client->common.proxy_user; + sasl_set.password = client->common.proxy_password; + client->common.proxy_sasl_client = + dsasl_client_new(client->common.proxy_mech, &sasl_set); + mech_name = dsasl_client_mech_get_name(client->common.proxy_mech); + + str_append(str, "L AUTHENTICATE "); + str_append(str, mech_name); + if (client->proxy_sasl_ir) { + if (dsasl_client_output(client->common.proxy_sasl_client, + &output, &len, &error) < 0) { + const char *reason = t_strdup_printf( + "SASL mechanism %s init failed: %s", + mech_name, error); + login_proxy_failed(client->common.login_proxy, + login_proxy_get_event(client->common.login_proxy), + LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason); + return -1; + } + str_append_c(str, ' '); + if (len == 0) + str_append_c(str, '='); + else + base64_encode(output, len, str); + } + str_append(str, "\r\n"); + client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_AUTHENTICATE; + return 0; +} + +static int proxy_input_banner(struct imap_client *client, + struct ostream *output, const char *line) +{ + const char *const *capabilities = NULL; + string_t *str; + int ret; + + if (!str_begins(line, "* OK ")) { + const char *reason = t_strdup_printf("Invalid banner: %s", + str_sanitize(line, 160)); + login_proxy_failed(client->common.login_proxy, + login_proxy_get_event(client->common.login_proxy), + LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason); + return -1; + } + + str = t_str_new(128); + if (str_begins(line + 5, "[CAPABILITY ")) { + capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " "); + if (str_array_icase_find(capabilities, "SASL-IR")) + client->proxy_sasl_ir = TRUE; + if (str_array_icase_find(capabilities, "LOGINDISABLED")) + client->proxy_logindisabled = TRUE; + i_free(client->proxy_backend_capability); + client->proxy_backend_capability = + i_strdup(t_strcut(line + 5 + 12, ']')); + if (str_array_icase_find(capabilities, "ID") && + !client->common.proxy_not_trusted) { + client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_ID; + proxy_write_id(client, str); + if (client->common.proxy_nopipelining) { + /* write login or starttls after I OK */ + o_stream_nsend(output, str_data(str), str_len(str)); + return 0; + } + } + } + + if ((ret = proxy_write_starttls(client, str)) < 0) { + return -1; + } else if (ret == 0) { + if (proxy_write_login(client, str) < 0) + return -1; + } + + o_stream_nsend(output, str_data(str), str_len(str)); + return 0; +} + +static void +client_send_login_reply(struct imap_client *client, string_t *str, + const char *line) +{ + const char *capability; + bool tagged_capability; + + capability = client->proxy_backend_capability; + tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0; + if (tagged_capability) + capability = t_strcut(line + 12, ']'); + + if (client->client_ignores_capability_resp_code && capability != NULL) { + /* client has used CAPABILITY command, so it didn't understand + the capabilities in the banner. send the backend's untagged + CAPABILITY reply and hope that the client understands it */ + str_printfa(str, "* CAPABILITY %s\r\n", capability); + } + str_append(str, client->cmd_tag); + str_append(str, " OK "); + if (!client->client_ignores_capability_resp_code && + !tagged_capability && capability != NULL) { + str_printfa(str, "[CAPABILITY %s] ", capability); + if (*line == '[') { + /* we need to send the capability. + skip over this resp-code */ + while (*line != ']' && *line != '\0') + line++; + if (*line == ' ') line++; + } + } + str_append(str, line); + str_append(str, "\r\n"); +} + +static bool auth_resp_code_is_tempfail(const char *resp_code) +{ + /* Dovecot uses [UNAVAILABLE] for failures that can be retried. + Non-retriable failures are [SERVERBUG]. */ + return strcasecmp(resp_code, IMAP_RESP_CODE_UNAVAILABLE) == 0; +} + +int imap_proxy_parse_line(struct client *client, const char *line) +{ + struct imap_client *imap_client = (struct imap_client *)client; + struct ostream *output; + string_t *str; + const unsigned char *data; + size_t data_len; + const char *error; + int ret; + + i_assert(!client->destroyed); + + output = login_proxy_get_ostream(client->login_proxy); + if (!imap_client->proxy_seen_banner) { + /* this is a banner */ + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_BANNER; + imap_client->proxy_seen_banner = TRUE; + if (proxy_input_banner(imap_client, output, line) < 0) + return -1; + return 0; + } else if (*line == '+') { + /* AUTHENTICATE started. finish it. */ + if (client->proxy_sasl_client == NULL) { + /* used literals with LOGIN command, just ignore. */ + return 0; + } + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_AUTHENTICATE); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_AUTH_CONTINUE; + + str = t_str_new(128); + if (line[1] != ' ' || + base64_decode(line+2, strlen(line+2), NULL, str) < 0) { + const char *reason = t_strdup_printf( + "Invalid base64 data in AUTHENTICATE response"); + login_proxy_failed(client->login_proxy, + login_proxy_get_event(client->login_proxy), + LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason); + return -1; + } + ret = dsasl_client_input(client->proxy_sasl_client, + str_data(str), str_len(str), &error); + if (ret == 0) { + ret = dsasl_client_output(client->proxy_sasl_client, + &data, &data_len, &error); + } + if (ret < 0) { + const char *reason = t_strdup_printf( + "Invalid authentication data: %s", error); + login_proxy_failed(client->login_proxy, + login_proxy_get_event(client->login_proxy), + LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason); + return -1; + } + i_assert(ret == 0); + + str_truncate(str, 0); + base64_encode(data, data_len, str); + str_append(str, "\r\n"); + + imap_client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_AUTH_CONTINUE; + o_stream_nsend(output, str_data(str), str_len(str)); + return 0; + } else if (str_begins(line, "S ")) { + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_STARTTLS); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_STARTTLS; + + if (!str_begins(line, "S OK ")) { + /* STARTTLS failed */ + const char *reason = t_strdup_printf( + "STARTTLS failed: %s", + str_sanitize(line + 5, 160)); + login_proxy_failed(client->login_proxy, + login_proxy_get_event(client->login_proxy), + LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason); + return -1; + } + /* STARTTLS successful, begin TLS negotiation. */ + if (login_proxy_starttls(client->login_proxy) < 0) + return -1; + /* i/ostreams changed. */ + output = login_proxy_get_ostream(client->login_proxy); + str = t_str_new(128); + if (proxy_write_login(imap_client, str) < 0) + return -1; + o_stream_nsend(output, str_data(str), str_len(str)); + return 1; + } else if (str_begins(line, "L OK ")) { + /* Login successful. Send this line to client. */ + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_LOGIN); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_LOGIN; + str = t_str_new(128); + client_send_login_reply(imap_client, str, line + 5); + o_stream_nsend(client->output, str_data(str), str_len(str)); + + client_proxy_finish_destroy_client(client); + return 1; + } else if (str_begins(line, "L ")) { + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_LOGIN); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_LOGIN; + + line += 2; + const char *log_line = line; + if (strncasecmp(log_line, "NO ", 3) == 0) + log_line += 3; + enum login_proxy_failure_type failure_type = + LOGIN_PROXY_FAILURE_TYPE_AUTH; +#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]" + if (str_begins(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED)) { + /* the remote sent a generic "authentication failed" + error. replace it with our one, so that in case + the remote is sending a different error message + an attacker can't find out what users exist in + the system. */ + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_AUTHFAILED, + AUTH_FAILED_MSG); + } else if (str_begins(line, "NO [")) { + /* remote sent some other resp-code. forward it. */ + const char *resp_code = t_strcut(line + 4, ']'); + if (auth_resp_code_is_tempfail(resp_code)) + failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL; + else { + client_send_raw(client, t_strconcat( + imap_client->cmd_tag, " ", line, "\r\n", NULL)); + } + } else { + /* there was no [resp-code], so remote isn't Dovecot + v1.2+. we could either forward the line as-is and + leak information about what users exist in this + system, or we could hide other errors than password + failures. since other errors are pretty rare, + it's safer to just hide them. they're still + available in logs though. */ + client_send_reply_code(client, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_AUTHFAILED, + AUTH_FAILED_MSG); + } + + login_proxy_failed(client->login_proxy, + login_proxy_get_event(client->login_proxy), + failure_type, log_line); + return -1; + } else if (strncasecmp(line, "* CAPABILITY ", 13) == 0) { + i_free(imap_client->proxy_backend_capability); + imap_client->proxy_backend_capability = i_strdup(line + 13); + return 0; + } else if (str_begins(line, "C ")) { + /* Reply to CAPABILITY command we sent */ + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_CAPABILITY); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_CAPABILITY; + if (str_begins(line, "C OK ") && + HAS_NO_BITS(imap_client->proxy_sent_state, + IMAP_PROXY_SENT_STATE_AUTHENTICATE | + IMAP_PROXY_SENT_STATE_LOGIN)) { + /* pipelining was disabled, send the login now. */ + str = t_str_new(128); + if (proxy_write_login(imap_client, str) < 0) + return -1; + o_stream_nsend(output, str_data(str), str_len(str)); + return 1; + } + return 0; + } else if (strncasecmp(line, "I ", 2) == 0) { + /* Reply to ID command we sent, ignore it unless + pipelining is disabled, in which case send + either STARTTLS or login */ + imap_client->proxy_sent_state &= ENUM_NEGATE(IMAP_PROXY_SENT_STATE_ID); + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_ID; + + if (client->proxy_nopipelining) { + str = t_str_new(128); + if ((ret = proxy_write_starttls(imap_client, str)) < 0) { + return -1; + } else if (ret == 0) { + if (proxy_write_login(imap_client, str) < 0) + return -1; + } + o_stream_nsend(output, str_data(str), str_len(str)); + return 1; + } + return 0; + } else if (strncasecmp(line, "* ID ", 5) == 0) { + /* Reply to ID command we sent, ignore it */ + return 0; + } else if (str_begins(line, "* BYE ")) { + /* Login unexpectedly failed (due to some internal error). + Don't forward the BYE to the client, since we're not going + to disconnect it. It could be a possibility to convert these + to NO replies, but they're likely not going to provide + anything useful. */ + return 0; + } else if (str_begins(line, "* ")) { + /* untagged reply. just forward it. */ + client_send_raw(client, t_strconcat(line, "\r\n", NULL)); + return 0; + } else { + /* tagged reply, shouldn't happen. */ + e_error(login_proxy_get_event(client->login_proxy), + "Unexpected input, ignoring: %s", + str_sanitize(line, 160)); + return 0; + } +} + +void imap_proxy_reset(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + + imap_client->proxy_sasl_ir = FALSE; + imap_client->proxy_logindisabled = FALSE; + imap_client->proxy_seen_banner = FALSE; + imap_client->proxy_capability_request_sent = FALSE; + imap_client->proxy_sent_state = 0; + imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_NONE; +} + +static void +imap_proxy_send_failure_reply(struct imap_client *imap_client, + enum login_proxy_failure_type type, + const char *reason) +{ + switch (type) { + case LOGIN_PROXY_FAILURE_TYPE_CONNECT: + case LOGIN_PROXY_FAILURE_TYPE_INTERNAL: + case LOGIN_PROXY_FAILURE_TYPE_REMOTE: + case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL: + client_send_reply_code(&imap_client->common, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_UNAVAILABLE, + LOGIN_PROXY_FAILURE_MSG); + break; + case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG: + case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG: + client_send_reply_code(&imap_client->common, IMAP_CMD_REPLY_NO, + IMAP_RESP_CODE_SERVERBUG, + LOGIN_PROXY_FAILURE_MSG); + break; + case LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL: + client_send_raw(&imap_client->common, t_strconcat( + imap_client->cmd_tag, " NO ", reason, "\r\n", NULL)); + break; + case LOGIN_PROXY_FAILURE_TYPE_AUTH: + /* reply was already sent */ + break; + } +} + +void imap_proxy_failed(struct client *client, + enum login_proxy_failure_type type, + const char *reason, bool reconnecting) +{ + struct imap_client *imap_client = + container_of(client, struct imap_client, common); + + if (!reconnecting) + imap_proxy_send_failure_reply(imap_client, type, reason); + client_common_proxy_failed(client, type, reason, reconnecting); +} + +const char *imap_proxy_get_state(struct client *client) +{ + struct imap_client *imap_client = (struct imap_client *)client; + string_t *str = t_str_new(128); + + for (unsigned int i = 0; i < IMAP_PROXY_SENT_STATE_COUNT; i++) { + if ((imap_client->proxy_sent_state & (1 << i)) != 0) { + if (str_len(str) > 0) + str_append_c(str, '+'); + str_append(str, imap_proxy_sent_state_names[i]); + } + } + str_append_c(str, '/'); + str_append(str, imap_proxy_rcvd_state_names[imap_client->proxy_rcvd_state]); + return str_c(str); +} diff --git a/src/imap-login/imap-proxy.h b/src/imap-login/imap-proxy.h new file mode 100644 index 0000000..71c2f64 --- /dev/null +++ b/src/imap-login/imap-proxy.h @@ -0,0 +1,12 @@ +#ifndef IMAP_PROXY_H +#define IMAP_PROXY_H + +void imap_proxy_reset(struct client *client); +int imap_proxy_parse_line(struct client *client, const char *line); + +void imap_proxy_failed(struct client *client, + enum login_proxy_failure_type type, + const char *reason, bool reconnecting); +const char *imap_proxy_get_state(struct client *client); + +#endif |