From: Aki Tuomi Date: Sun, 27 Mar 2022 17:21:33 +0000 (+0300) Subject: auth: Remove checkpassword driver X-Git-Tag: 2.4.0~4183 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b9eab89e686dc19c9f508e65efd40a829e2a8e83;p=thirdparty%2Fdovecot%2Fcore.git auth: Remove checkpassword driver --- diff --git a/.gitignore b/.gitignore index 8bd3b1e445..331354aec8 100644 --- a/.gitignore +++ b/.gitignore @@ -110,7 +110,6 @@ doc/example-config/README doc/wiki/*.txt doc/wiki/Makefile.am src/anvil/anvil -src/auth/checkpassword-reply src/auth/auth src/config/all-settings.c src/config/config diff --git a/configure.ac b/configure.ac index 11c2c56703..f537b695d0 100644 --- a/configure.ac +++ b/configure.ac @@ -256,7 +256,6 @@ AM_CONDITIONAL(BUILD_DOCS, test "$want_docs" = "yes") dnl always enable all of the passbs and userdbs that don't require extra libs want_passwd=yes want_passwd_file=yes -want_checkpassword=yes want_prefetch_userdb=yes AC_ISC_POSIX @@ -537,7 +536,6 @@ DOVECOT_WANT_LUA DOVECOT_WANT_PREFETCH DOVECOT_WANT_PASSWD DOVECOT_WANT_PAM -DOVECOT_WANT_CHECKPASSWORD DOVECOT_WANT_BSDAUTH DOVECOT_WANT_GSSAPI DOVECOT_WANT_LDAP diff --git a/doc/example-config/conf.d/10-auth.conf b/doc/example-config/conf.d/10-auth.conf index af58f64bd2..555306aa99 100644 --- a/doc/example-config/conf.d/10-auth.conf +++ b/doc/example-config/conf.d/10-auth.conf @@ -118,5 +118,4 @@ auth_mechanisms = plain #!include auth-sql.conf.ext #!include auth-ldap.conf.ext #!include auth-passwdfile.conf.ext -#!include auth-checkpassword.conf.ext #!include auth-static.conf.ext diff --git a/doc/example-config/conf.d/Makefile.am b/doc/example-config/conf.d/Makefile.am index 1950fd518b..9f4797e5e6 100644 --- a/doc/example-config/conf.d/Makefile.am +++ b/doc/example-config/conf.d/Makefile.am @@ -2,7 +2,6 @@ pkgsysconfdir = $(sysconfdir)/dovecot exampledir = $(docdir)/example-config/conf.d example_DATA = \ - auth-checkpassword.conf.ext \ auth-deny.conf.ext \ auth-dict.conf.ext \ auth-ldap.conf.ext \ diff --git a/doc/example-config/conf.d/auth-checkpassword.conf.ext b/doc/example-config/conf.d/auth-checkpassword.conf.ext deleted file mode 100644 index b2fb13a2ac..0000000000 --- a/doc/example-config/conf.d/auth-checkpassword.conf.ext +++ /dev/null @@ -1,21 +0,0 @@ -# Authentication for checkpassword users. Included from 10-auth.conf. -# -# - -passdb { - driver = checkpassword - args = /usr/bin/checkpassword -} - -# passdb lookup should return also userdb info -userdb { - driver = prefetch -} - -# Standard checkpassword doesn't support direct userdb lookups. -# If you need checkpassword userdb, the checkpassword must support -# Dovecot-specific extensions. -#userdb { -# driver = checkpassword -# args = /usr/bin/checkpassword -#} diff --git a/m4/want_checkpassword.m4 b/m4/want_checkpassword.m4 deleted file mode 100644 index 696adb47ec..0000000000 --- a/m4/want_checkpassword.m4 +++ /dev/null @@ -1,11 +0,0 @@ -AC_DEFUN([DOVECOT_WANT_CHECKPASSWORD], [ - if test $want_checkpassword != no; then - AC_DEFINE(PASSDB_CHECKPASSWORD,, [Build with checkpassword passdb support]) - AC_DEFINE(USERDB_CHECKPASSWORD,, [Build with checkpassword userdb support]) - passdb="$passdb checkpassword" - userdb="$userdb checkpassword" - else - not_passdb="$not_passdb checkpassword" - not_userdb="$not_userdb checkpassword" - fi -]) diff --git a/src/auth/Makefile.am b/src/auth/Makefile.am index c7c34719bd..2ec06b4414 100644 --- a/src/auth/Makefile.am +++ b/src/auth/Makefile.am @@ -33,7 +33,7 @@ auth_module_LTLIBRARIES = \ pkglibexecdir = $(libexecdir)/dovecot -pkglibexec_PROGRAMS = auth checkpassword-reply +pkglibexec_PROGRAMS = auth AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ @@ -105,7 +105,6 @@ libauth_la_SOURCES = \ auth-token.c \ auth-worker-connection.c \ auth-worker-server.c \ - db-checkpassword.c \ db-dict.c \ db-dict-cache-key.c \ db-oauth2.c \ @@ -129,7 +128,6 @@ libauth_la_SOURCES = \ passdb-blocking.c \ passdb-bsdauth.c \ passdb-cache.c \ - passdb-checkpassword.c \ passdb-dict.c \ passdb-oauth2.c \ passdb-passwd.c \ @@ -140,7 +138,6 @@ libauth_la_SOURCES = \ passdb-template.c \ userdb.c \ userdb-blocking.c \ - userdb-checkpassword.c \ userdb-dict.c \ userdb-passwd.c \ userdb-passwd-file.c \ @@ -176,7 +173,6 @@ headers = \ db-ldap.h \ db-sql.h \ db-passwd-file.h \ - db-checkpassword.h \ db-oauth2.h \ mech.h \ mycrypt.h \ @@ -223,13 +219,6 @@ libauthdb_imap_la_SOURCES = passdb-imap.c pkginc_libdir=$(pkgincludedir) pkginc_lib_HEADERS = $(headers) -checkpassword_reply_CPPFLAGS = $(AM_CPPFLAGS) $(BINARY_CFLAGS) -checkpassword_reply_LDADD = $(LIBDOVECOT) $(BINARY_LDFLAGS) -checkpassword_reply_DEPENDENCIES = $(LIBDOVECOT_DEPS) - -checkpassword_reply_sources = \ - checkpassword-reply.c - test_programs = \ test-libpassword \ test-auth-cache \ diff --git a/src/auth/checkpassword-reply.c b/src/auth/checkpassword-reply.c deleted file mode 100644 index 71f231aaaf..0000000000 --- a/src/auth/checkpassword-reply.c +++ /dev/null @@ -1,110 +0,0 @@ -/* simple checkpassword wrapper to send userdb data back to dovecot-auth */ - -#include "lib.h" -#include "str.h" -#include "strescape.h" -#include "write-full.h" - -#include - -int main(void) -{ - string_t *str; - const char *user, *home, *authorized, *orig_uid_env; - const char *extra_env, *key, *value, *const *tmp; - bool uid_found = FALSE, gid_found = FALSE; - uid_t orig_uid; - - lib_init(); - str = t_str_new(1024); - - orig_uid_env = getenv("ORIG_UID"); - if (orig_uid_env == NULL || str_to_uid(orig_uid_env, &orig_uid) < 0) - orig_uid = (uid_t)-1; - - /* ORIG_UID should have the auth process's UID that forked us. - if the checkpassword changed the UID, this could be a security hole - because the UID's other processes can ptrace this process and write - any kind of a reply to fd 4. so we can run only if: - - a) INSECURE_SETUID environment is set. - b) process isn't ptraceable (this binary is setuid/setgid) - c) checkpassword didn't actually change the UID (but used - userdb_uid instead) - */ - if (getenv("INSECURE_SETUID") == NULL && - (orig_uid == (uid_t)-1 || orig_uid != getuid()) && - getuid() == geteuid() && getgid() == getegid()) { - if (orig_uid_env == NULL) { - i_error("checkpassword: ORIG_UID environment was dropped by checkpassword. " - "Can't verify if we're safe to run. See " - "http://wiki2.dovecot.org/AuthDatabase/CheckPassword#Security"); - } else { - i_error("checkpassword: The checkpassword couldn't be run securely. See " - "http://wiki2.dovecot.org/AuthDatabase/CheckPassword#Security"); - } - return 111; - } - - user = getenv("USER"); - if (user != NULL) { - if (strchr(user, '\t') != NULL) { - i_error("checkpassword: USER contains TAB"); - return 1; - } - str_printfa(str, "user="); - str_append_tabescaped(str, user); - str_append_c(str, '\t'); - } - - home = getenv("HOME"); - if (home != NULL) { - if (strchr(home, '\t') != NULL) { - i_error("checkpassword: HOME contains TAB"); - return 1; - } - str_printfa(str, "userdb_home="); - str_append_tabescaped(str, home); - str_append_c(str, '\t'); - } - - extra_env = getenv("EXTRA"); - if (extra_env != NULL) { - for (tmp = t_strsplit(extra_env, " "); *tmp != NULL; tmp++) { - value = getenv(*tmp); - if (value != NULL) { - key = t_str_lcase(*tmp); - if (strcmp(key, "userdb_uid") == 0) - uid_found = TRUE; - else if (strcmp(key, "userdb_gid") == 0) - gid_found = TRUE; - str_append_tabescaped(str, key); - str_append_c(str, '='); - str_append_tabescaped(str, value); - str_append_c(str, '\t'); - } - } - } - if (!uid_found) - str_printfa(str, "userdb_uid=%s\t", dec2str(getuid())); - if (!gid_found) - str_printfa(str, "userdb_gid=%s\t", dec2str(getgid())); - - i_assert(str_len(str) > 0); - - if (write_full(4, str_data(str), str_len(str)) < 0) { - i_error("checkpassword: write_full() failed: %m"); - lib_exit(111); - } - authorized = getenv("AUTHORIZED"); - if (authorized == NULL) { - /* authentication */ - return 0; - } else if (strcmp(authorized, "2") == 0) { - /* successful passdb/userdb lookup */ - return 2; - } else { - i_error("checkpassword: Script doesn't support passdb/userdb lookup"); - return 111; - } -} diff --git a/src/auth/db-checkpassword.c b/src/auth/db-checkpassword.c deleted file mode 100644 index 7d52eeff2d..0000000000 --- a/src/auth/db-checkpassword.c +++ /dev/null @@ -1,563 +0,0 @@ -/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */ - -#include "auth-common.h" - -#if defined(PASSDB_CHECKPASSWORD) || defined(USERDB_CHECKPASSWORD) - -#include "lib-signals.h" -#include "array.h" -#include "buffer.h" -#include "str.h" -#include "ioloop.h" -#include "hash.h" -#include "execv-const.h" -#include "env-util.h" -#include "safe-memset.h" -#include "strescape.h" -#include "child-wait.h" -#include "db-checkpassword.h" - -#include -#include - -#define CHECKPASSWORD_MAX_REQUEST_LEN 512 - -struct chkpw_auth_request { - struct db_checkpassword *db; - struct auth_request *request; - char *auth_password; - - db_checkpassword_callback_t *callback; - void (*request_callback)(); - - pid_t pid; - int fd_out, fd_in; - struct io *io_out, *io_in; - - string_t *input_buf; - size_t output_pos, output_len; - - int exit_status; - bool exited:1; -}; - -struct db_checkpassword { - char *checkpassword_path, *checkpassword_reply_path; - - HASH_TABLE(void *, struct chkpw_auth_request *) clients; - struct child_wait *child_wait; -}; - -static void -env_put_extra_fields(const ARRAY_TYPE(auth_field) *extra_fields) -{ - const struct auth_field *field; - const char *key, *value; - - array_foreach(extra_fields, field) { - key = t_str_ucase(field->key); - value = field->value != NULL ? field->value : "1"; - env_put(key, value); - } -} - -static void checkpassword_request_close(struct chkpw_auth_request *request) -{ - io_remove(&request->io_in); - io_remove(&request->io_out); - - i_close_fd(&request->fd_in); - i_close_fd(&request->fd_out); -} - -static void checkpassword_request_free(struct chkpw_auth_request **_request) -{ - struct chkpw_auth_request *request = *_request; - - *_request = NULL; - - if (!request->exited) { - hash_table_remove(request->db->clients, - POINTER_CAST(request->pid)); - child_wait_remove_pid(request->db->child_wait, request->pid); - } - checkpassword_request_close(request); - - if (request->auth_password != NULL) { - safe_memset(request->auth_password, 0, - strlen(request->auth_password)); - i_free(request->auth_password); - } - auth_request_unref(&request->request); - str_free(&request->input_buf); - i_free(request); -} - -static void checkpassword_finish(struct chkpw_auth_request **_request, - enum db_checkpassword_status status) -{ - struct chkpw_auth_request *request = *_request; - const char *const *extra_fields; - - *_request = NULL; - - extra_fields = t_strsplit_tabescaped(str_c(request->input_buf)); - request->callback(request->request, status, extra_fields, - request->request_callback); - checkpassword_request_free(&request); -} - -static void checkpassword_internal_failure(struct chkpw_auth_request **request) -{ - checkpassword_finish(request, DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE); -} - -static void -checkpassword_request_finish_auth(struct chkpw_auth_request *request) -{ - switch (request->exit_status) { - /* standard checkpassword exit codes: */ - case 1: - e_info(authdb_event(request->request), - "Login failed (status=%d)", - request->exit_status); - checkpassword_finish(&request, DB_CHECKPASSWORD_STATUS_FAILURE); - break; - case 0: - if (request->input_buf->used == 0) { - e_error(authdb_event(request->request), - "Received no input"); - checkpassword_internal_failure(&request); - break; - } - checkpassword_finish(&request, DB_CHECKPASSWORD_STATUS_OK); - break; - case 2: - /* checkpassword is called with wrong parameters? unlikely */ - e_error(authdb_event(request->request), - "Child %s exited with status 2 (tried to use " - "userdb-only checkpassword program for passdb?)", - dec2str(request->pid)); - checkpassword_internal_failure(&request); - break; - case 111: - /* temporary problem, treat as internal error */ - default: - /* whatever error.. */ - e_error(authdb_event(request->request), - "Child %s exited with status %d", - dec2str(request->pid), request->exit_status); - checkpassword_internal_failure(&request); - break; - } -} - -static void -checkpassword_request_finish_lookup(struct chkpw_auth_request *request) -{ - switch (request->exit_status) { - case 3: - /* User does not exist. */ - e_info(authdb_event(request->request), - "User unknown"); - checkpassword_finish(&request, DB_CHECKPASSWORD_STATUS_FAILURE); - break; - case 2: - /* This is intentionally not 0. checkpassword-reply exits with - 2 on success when AUTHORIZED is set. */ - if (request->input_buf->used == 0) { - e_error(authdb_event(request->request), - "Received no input"); - checkpassword_internal_failure(&request); - break; - } - checkpassword_finish(&request, DB_CHECKPASSWORD_STATUS_OK); - break; - default: - /* whatever error... */ - e_error(authdb_event(request->request), - "Child %s exited with status %d", - dec2str(request->pid), request->exit_status); - checkpassword_internal_failure(&request); - break; - } -} - -static void -checkpassword_request_half_finish(struct chkpw_auth_request *request) -{ - /* the process must have exited, and the input fd must have closed */ - if (!request->exited || request->fd_in != -1) - return; - - if (request->auth_password != NULL) - checkpassword_request_finish_auth(request); - else - checkpassword_request_finish_lookup(request); -} - -static void env_put_auth_vars(struct auth_request *request) -{ - const struct var_expand_table *tab; - unsigned int i; - - tab = auth_request_get_var_expand_table(request, NULL); - for (i = 0; tab[i].key != '\0' || tab[i].long_key != NULL; i++) { - /* avoid keeping passwords in environment .. just in case - an attacker might find it from there. environment is no - longer world-readable in modern OSes, but maybe the attacker - could be running with the same UID. of course then the - attacker could usually ptrace() the process, except that is - disabled on some secured systems. so, although I find it - highly unlikely anyone could actually attack Dovecot this - way in a real system, be safe just in case. besides, lets - try to keep at least minimally compatible with the - checkpassword API. */ - if (tab[i].long_key != NULL && tab[i].value != NULL && - strcasecmp(tab[i].long_key, "password") != 0) { - env_put(t_strdup_printf("AUTH_%s", - t_str_ucase(tab[i].long_key)), - tab[i].value); - } - } -} - -static void checkpassword_setup_env(struct auth_request *request) -{ - const struct auth_request_fields *fields = &request->fields; - - /* Besides passing the standard username and password in a - pipe, also pass some other possibly interesting information - via environment. Use UCSPI names for local/remote IPs. */ - env_put("PROTO", "TCP"); /* UCSPI */ - env_put("ORIG_UID", dec2str(getuid())); - env_put("SERVICE", fields->service); - if (fields->local_ip.family != 0) { - env_put("TCPLOCALIP", net_ip2addr(&fields->local_ip)); - /* FIXME: for backwards compatibility only, - remove some day */ - env_put("LOCAL_IP", net_ip2addr(&fields->local_ip)); - } - if (fields->remote_ip.family != 0) { - env_put("TCPREMOTEIP", net_ip2addr(&fields->remote_ip)); - /* FIXME: for backwards compatibility only, - remove some day */ - env_put("REMOTE_IP", net_ip2addr(&fields->remote_ip)); - } - if (fields->local_port != 0) - env_put("TCPLOCALPORT", dec2str(fields->local_port)); - if (fields->remote_port != 0) - env_put("TCPREMOTEPORT", dec2str(fields->remote_port)); - if (fields->master_user != NULL) - env_put("MASTER_USER", fields->master_user); - if (!auth_fields_is_empty(fields->extra_fields)) { - const ARRAY_TYPE(auth_field) *extra_fields = - auth_fields_export(fields->extra_fields); - - /* extra fields could come from master db */ - env_put_extra_fields(extra_fields); - } - env_put_auth_vars(request); -} - -static const char * -checkpassword_get_cmd(struct auth_request *request, const char *args, - const char *checkpassword_reply_path) -{ - string_t *str; - const char *error; - - str = t_str_new(256); - if (auth_request_var_expand(str, args, request, NULL, &error) <= 0) { - e_error(authdb_event(request), - "Failed to expand checkpassword_path=%s: %s", - args, error); - } - - return t_strconcat(str_c(str), " ", checkpassword_reply_path, NULL); -} - -static void checkpassword_child_input(struct chkpw_auth_request *request) -{ - unsigned char buf[1024]; - ssize_t ret; - - ret = read(request->fd_in, buf, sizeof(buf)); - if (ret > 0) { - str_append_data(request->input_buf, buf, ret); - return; - } - - if (ret < 0) { - e_error(authdb_event(request->request), - "read() failed: %m"); - checkpassword_internal_failure(&request); - } else if (memchr(str_data(request->input_buf), '\0', - str_len(request->input_buf)) != NULL) { - e_error(authdb_event(request->request), - "NUL characters in checkpassword reply"); - checkpassword_internal_failure(&request); - } else if (strchr(str_c(request->input_buf), '\n') != NULL) { - e_error(authdb_event(request->request), - "LF characters in checkpassword reply"); - checkpassword_internal_failure(&request); - } else { - e_debug(authdb_event(request->request), - "Received input: %s", str_c(request->input_buf)); - checkpassword_request_close(request); - checkpassword_request_half_finish(request); - } -} - -static void checkpassword_child_output(struct chkpw_auth_request *request) -{ - /* Send: username \0 password \0 timestamp \0. - Must be 512 bytes or less. The "timestamp" parameter is actually - useful only for APOP authentication. We don't support it, so - keep it empty */ - struct auth_request *auth_request = request->request; - buffer_t *buf; - const unsigned char *data; - size_t size; - ssize_t ret; - - buf = t_buffer_create(CHECKPASSWORD_MAX_REQUEST_LEN); - buffer_append(buf, auth_request->fields.user, - strlen(auth_request->fields.user)+1); - if (request->auth_password != NULL) { - buffer_append(buf, request->auth_password, - strlen(request->auth_password)+1); - } else { - buffer_append_c(buf, '\0'); - } - buffer_append_c(buf, '\0'); - data = buffer_get_data(buf, &size); - - i_assert(size == request->output_len); - /* already checked this */ - i_assert(size <= CHECKPASSWORD_MAX_REQUEST_LEN); - - ret = write(request->fd_out, data + request->output_pos, - size - request->output_pos); - if (ret <= 0) { - if (ret < 0) { - e_error(authdb_event(request->request), - "write() failed: %m"); - } else { - e_error(authdb_event(request->request), - "write() returned 0"); - } - checkpassword_internal_failure(&request); - return; - } - - request->output_pos += ret; - if (request->output_pos < size) - return; - - /* finished sending the data */ - io_remove(&request->io_out); - - if (close(request->fd_out) < 0) - e_error(authdb_event(request->request), "close() failed: %m"); - request->fd_out = -1; -} - -static void ATTR_NORETURN -checkpassword_exec(struct db_checkpassword *db, struct auth_request *request, - int fd_in, int fd_out, bool authenticate) -{ - const char *cmd, *const *args; - - /* fd 3 is used to send the username+password for the script - fd 4 is used to communicate with checkpassword-reply */ - if (dup2(fd_out, 3) < 0 || dup2(fd_in, 4) < 0) { - e_error(authdb_event(request), - "dup2() failed: %m"); - lib_exit(111); - } - - if (!authenticate) { - /* We want to retrieve passdb/userdb data and don't do - authorization, so we need to signalize the - checkpassword program that the password shall be - ignored by setting AUTHORIZED. This needs a - special checkpassword program which knows how to - handle this. */ - env_put("AUTHORIZED", "1"); - if (request->wanted_credentials_scheme != NULL) { - /* passdb credentials lookup */ - env_put("CREDENTIALS_LOOKUP", "1"); - env_put("SCHEME", request->wanted_credentials_scheme); - } - } - checkpassword_setup_env(request); - cmd = checkpassword_get_cmd(request, db->checkpassword_path, - db->checkpassword_reply_path); - e_debug(authdb_event(request), "execute: %s", cmd); - - /* very simple argument splitting. */ - args = t_strsplit(cmd, " "); - execv_const(args[0], args); -} - -static void sigchld_handler(const struct child_wait_status *status, - struct db_checkpassword *db) -{ - struct chkpw_auth_request *request = - hash_table_lookup(db->clients, POINTER_CAST(status->pid)); - - i_assert(request != NULL); - - hash_table_remove(db->clients, POINTER_CAST(status->pid)); - request->exited = TRUE; - - if (WIFSIGNALED(status->status)) { - e_error(authdb_event(request->request), - "Child %s died with signal %d", - dec2str(status->pid), WTERMSIG(status->status)); - checkpassword_internal_failure(&request); - } else if (WIFEXITED(status->status)) { - request->exit_status = WEXITSTATUS(status->status); - - e_debug(authdb_event(request->request), - "exit_status=%d", request->exit_status); - checkpassword_request_half_finish(request); - } else { - /* shouldn't happen */ - e_debug(authdb_event(request->request), - "Child %s exited with status=%d", - dec2str(status->pid), status->status); - checkpassword_internal_failure(&request); - } -} - -void db_checkpassword_call(struct db_checkpassword *db, - struct auth_request *request, - const char *auth_password, - db_checkpassword_callback_t *callback, - void (*request_callback)()) -{ - struct chkpw_auth_request *chkpw_auth_request; - size_t output_len; - int fd_in[2], fd_out[2]; - pid_t pid; - - /* \0 \0 timestamp \0 */ - output_len = strlen(request->fields.user) + 3; - if (auth_password != NULL) - output_len += strlen(auth_password); - if (output_len > CHECKPASSWORD_MAX_REQUEST_LEN) { - e_info(authdb_event(request), - "Username+password combination too long (%zu bytes)", - output_len); - callback(request, DB_CHECKPASSWORD_STATUS_FAILURE, - NULL, request_callback); - return; - } - - fd_in[0] = -1; - if (pipe(fd_in) < 0 || pipe(fd_out) < 0) { - e_error(authdb_event(request), - "pipe() failed: %m"); - if (fd_in[0] != -1) { - i_close_fd(&fd_in[0]); - i_close_fd(&fd_in[1]); - } - callback(request, DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE, - NULL, request_callback); - return; - } - - pid = fork(); - if (pid == -1) { - e_error(authdb_event(request), - "fork() failed: %m"); - i_close_fd(&fd_in[0]); - i_close_fd(&fd_in[1]); - i_close_fd(&fd_out[0]); - i_close_fd(&fd_out[1]); - callback(request, DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE, - NULL, request_callback); - return; - } - - if (pid == 0) { - /* child */ - i_close_fd(&fd_in[0]); - i_close_fd(&fd_out[1]); - checkpassword_exec(db, request, fd_in[1], fd_out[0], - auth_password != NULL); - /* not reached */ - } - - if (close(fd_in[1]) < 0) { - e_error(authdb_event(request), - "close(fd_in[1]) failed: %m"); - } - if (close(fd_out[0]) < 0) { - e_error(authdb_event(request), - "close(fd_out[0]) failed: %m"); - } - - auth_request_ref(request); - chkpw_auth_request = i_new(struct chkpw_auth_request, 1); - chkpw_auth_request->db = db; - chkpw_auth_request->pid = pid; - chkpw_auth_request->fd_in = fd_in[0]; - chkpw_auth_request->fd_out = fd_out[1]; - chkpw_auth_request->auth_password = i_strdup(auth_password); - chkpw_auth_request->request = request; - chkpw_auth_request->output_len = output_len; - chkpw_auth_request->input_buf = str_new(default_pool, 256); - chkpw_auth_request->callback = callback; - chkpw_auth_request->request_callback = request_callback; - - chkpw_auth_request->io_in = - io_add(fd_in[0], IO_READ, checkpassword_child_input, - chkpw_auth_request); - chkpw_auth_request->io_out = - io_add(fd_out[1], IO_WRITE, checkpassword_child_output, - chkpw_auth_request); - - hash_table_insert(db->clients, POINTER_CAST(pid), chkpw_auth_request); - child_wait_add_pid(db->child_wait, pid); -} - -struct db_checkpassword * -db_checkpassword_init(const char *checkpassword_path, - const char *checkpassword_reply_path) -{ - struct db_checkpassword *db; - - db = i_new(struct db_checkpassword, 1); - db->checkpassword_path = i_strdup(checkpassword_path); - db->checkpassword_reply_path = i_strdup(checkpassword_reply_path); - hash_table_create_direct(&db->clients, default_pool, 0); - db->child_wait = - child_wait_new_with_pid((pid_t)-1, sigchld_handler, db); - return db; -} - -void db_checkpassword_deinit(struct db_checkpassword **_db) -{ - struct db_checkpassword *db = *_db; - struct hash_iterate_context *iter; - void *key; - struct chkpw_auth_request *request; - - *_db = NULL; - - iter = hash_table_iterate_init(db->clients); - while (hash_table_iterate(iter, db->clients, &key, &request)) - checkpassword_internal_failure(&request); - hash_table_iterate_deinit(&iter); - - child_wait_free(&db->child_wait); - hash_table_destroy(&db->clients); - i_free(db->checkpassword_reply_path); - i_free(db->checkpassword_path); - i_free(db); -} - -#endif diff --git a/src/auth/db-checkpassword.h b/src/auth/db-checkpassword.h deleted file mode 100644 index 64eedd8a2f..0000000000 --- a/src/auth/db-checkpassword.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CHECKPASSWORD_COMMON_H -#define CHECKPASSWORD_COMMON_H - -#include "auth-request.h" - -enum db_checkpassword_status { - DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE = -1, - /* auth unsuccessful / user not found */ - DB_CHECKPASSWORD_STATUS_FAILURE = 0, - DB_CHECKPASSWORD_STATUS_OK = 1 -}; - -typedef void db_checkpassword_callback_t(struct auth_request *request, - enum db_checkpassword_status status, - const char *const *extra_fields, - void (*request_callback)()); - -struct db_checkpassword * -db_checkpassword_init(const char *checkpassword_path, - const char *checkpassword_reply_path); -void db_checkpassword_deinit(struct db_checkpassword **db); - -void db_checkpassword_call(struct db_checkpassword *db, - struct auth_request *request, - const char *auth_password, - db_checkpassword_callback_t *callback, - void (*request_callback)()) ATTR_NULL(3); - -#endif diff --git a/src/auth/passdb-checkpassword.c b/src/auth/passdb-checkpassword.c deleted file mode 100644 index b351b94d72..0000000000 --- a/src/auth/passdb-checkpassword.c +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */ - -#include "auth-common.h" -#include "passdb.h" - -#ifdef PASSDB_CHECKPASSWORD - -#include "password-scheme.h" -#include "db-checkpassword.h" - -struct checkpassword_passdb_module { - struct passdb_module module; - struct db_checkpassword *db; -}; - -static void -auth_checkpassword_callback(struct auth_request *request, - enum db_checkpassword_status status, - const char *const *extra_fields, - verify_plain_callback_t *callback) -{ - const char *scheme, *crypted_pass = NULL; - unsigned int i; - - switch (status) { - case DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE: - callback(PASSDB_RESULT_INTERNAL_FAILURE, request); - return; - case DB_CHECKPASSWORD_STATUS_FAILURE: - callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); - return; - case DB_CHECKPASSWORD_STATUS_OK: - break; - } - for (i = 0; extra_fields[i] != NULL; i++) { - if (str_begins(extra_fields[i], "password=", &crypted_pass)) - ; - else if (extra_fields[i][0] != '\0') { - auth_request_set_field_keyvalue(request, - extra_fields[i], NULL); - } - } - if (crypted_pass != NULL) { - /* for cache */ - scheme = password_get_scheme(&crypted_pass); - if (scheme != NULL) { - auth_request_set_field(request, "password", - crypted_pass, scheme); - } else { - e_error(authdb_event(request), - "password field returned without {scheme} prefix"); - } - } - callback(PASSDB_RESULT_OK, request); -} - -static void -checkpassword_verify_plain(struct auth_request *request, const char *password, - verify_plain_callback_t *callback) -{ - struct passdb_module *_module = request->passdb->passdb; - struct checkpassword_passdb_module *module = - (struct checkpassword_passdb_module *)_module; - - db_checkpassword_call(module->db, request, password, - auth_checkpassword_callback, callback); -} - -static void -credentials_checkpassword_callback(struct auth_request *request, - enum db_checkpassword_status status, - const char *const *extra_fields, - lookup_credentials_callback_t *callback) -{ - const char *scheme, *crypted_pass = NULL; - unsigned int i; - - switch (status) { - case DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE: - callback(PASSDB_RESULT_INTERNAL_FAILURE, NULL, 0, request); - return; - case DB_CHECKPASSWORD_STATUS_FAILURE: - callback(PASSDB_RESULT_USER_UNKNOWN, NULL, 0, request); - return; - case DB_CHECKPASSWORD_STATUS_OK: - break; - } - for (i = 0; extra_fields[i] != NULL; i++) { - if (str_begins(extra_fields[i], "password=", &crypted_pass)) - ; - else if (extra_fields[i][0] != '\0') { - auth_request_set_field_keyvalue(request, - extra_fields[i], NULL); - } - } - scheme = password_get_scheme(&crypted_pass); - if (scheme == NULL) - scheme = request->wanted_credentials_scheme; - - passdb_handle_credentials(PASSDB_RESULT_OK, crypted_pass, scheme, - callback, request); -} - -static void -checkpassword_lookup_credentials(struct auth_request *request, - lookup_credentials_callback_t *callback) -{ - struct passdb_module *_module = request->passdb->passdb; - struct checkpassword_passdb_module *module = - (struct checkpassword_passdb_module *)_module; - - db_checkpassword_call(module->db, request, NULL, - credentials_checkpassword_callback, callback); -} - -static struct passdb_module * -checkpassword_preinit(pool_t pool, const char *args) -{ - struct checkpassword_passdb_module *module; - const char *checkpassword_path = args; - const char *checkpassword_reply_path = - PKG_LIBEXECDIR"/checkpassword-reply"; - - module = p_new(pool, struct checkpassword_passdb_module, 1); - module->db = db_checkpassword_init(checkpassword_path, - checkpassword_reply_path); - return &module->module; -} - -static void checkpassword_deinit(struct passdb_module *_module) -{ - struct checkpassword_passdb_module *module = - (struct checkpassword_passdb_module *)_module; - - db_checkpassword_deinit(&module->db); -} - -struct passdb_module_interface passdb_checkpassword = { - "checkpassword", - - checkpassword_preinit, - NULL, - checkpassword_deinit, - - checkpassword_verify_plain, - checkpassword_lookup_credentials, - NULL -}; -#else -struct passdb_module_interface passdb_checkpassword = { - .name = "checkpassword" -}; -#endif diff --git a/src/auth/passdb.c b/src/auth/passdb.c index e15825caec..eb4ac8ae82 100644 --- a/src/auth/passdb.c +++ b/src/auth/passdb.c @@ -317,7 +317,6 @@ extern struct passdb_module_interface passdb_lua; #endif extern struct passdb_module_interface passdb_passwd_file; extern struct passdb_module_interface passdb_pam; -extern struct passdb_module_interface passdb_checkpassword; extern struct passdb_module_interface passdb_ldap; extern struct passdb_module_interface passdb_sql; extern struct passdb_module_interface passdb_static; @@ -335,7 +334,6 @@ void passdbs_init(void) #endif passdb_register_module(&passdb_passwd_file); passdb_register_module(&passdb_pam); - passdb_register_module(&passdb_checkpassword); passdb_register_module(&passdb_ldap); passdb_register_module(&passdb_sql); passdb_register_module(&passdb_static); diff --git a/src/auth/userdb-checkpassword.c b/src/auth/userdb-checkpassword.c deleted file mode 100644 index dea676d138..0000000000 --- a/src/auth/userdb-checkpassword.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */ - -#include "auth-common.h" -#include "userdb.h" - -#ifdef USERDB_CHECKPASSWORD - -#include "db-checkpassword.h" - -struct checkpassword_userdb_module { - struct userdb_module module; - struct db_checkpassword *db; -}; - -static void -userdb_checkpassword_callback(struct auth_request *request, - enum db_checkpassword_status status, - const char *const *extra_fields, - userdb_callback_t *callback) -{ - unsigned int i; - - switch (status) { - case DB_CHECKPASSWORD_STATUS_INTERNAL_FAILURE: - callback(USERDB_RESULT_INTERNAL_FAILURE, request); - break; - case DB_CHECKPASSWORD_STATUS_FAILURE: - callback(USERDB_RESULT_USER_UNKNOWN, request); - break; - case DB_CHECKPASSWORD_STATUS_OK: - for (i = 0; extra_fields[i] != NULL; i++) { - if (!str_begins_with(extra_fields[i], "userdb_")) - continue; - auth_request_set_field_keyvalue(request, - extra_fields[i], NULL); - } - callback(USERDB_RESULT_OK, request); - break; - } -} - -static void -checkpassword_lookup(struct auth_request *request, userdb_callback_t *callback) -{ - struct userdb_module *_module = request->userdb->userdb; - struct checkpassword_userdb_module *module = - (struct checkpassword_userdb_module *)_module; - - db_checkpassword_call(module->db, request, NULL, - userdb_checkpassword_callback, callback); -} - -static struct userdb_module * -checkpassword_preinit(pool_t pool, const char *args) -{ - struct checkpassword_userdb_module *module; - const char *checkpassword_path = args; - const char *checkpassword_reply_path = - PKG_LIBEXECDIR"/checkpassword-reply"; - - module = p_new(pool, struct checkpassword_userdb_module, 1); - module->db = db_checkpassword_init(checkpassword_path, - checkpassword_reply_path); - return &module->module; -} - -static void checkpassword_deinit(struct userdb_module *_module) -{ - struct checkpassword_userdb_module *module = - (struct checkpassword_userdb_module *)_module; - - db_checkpassword_deinit(&module->db); -} - -struct userdb_module_interface userdb_checkpassword = { - "checkpassword", - - checkpassword_preinit, - NULL, - checkpassword_deinit, - - checkpassword_lookup, - - NULL, - NULL, - NULL -}; -#else -struct userdb_module_interface userdb_checkpassword = { - .name = "checkpassword" -}; -#endif diff --git a/src/auth/userdb.c b/src/auth/userdb.c index 738b6d623d..0849659102 100644 --- a/src/auth/userdb.c +++ b/src/auth/userdb.c @@ -226,7 +226,6 @@ extern struct userdb_module_interface userdb_passwd; extern struct userdb_module_interface userdb_passwd_file; extern struct userdb_module_interface userdb_ldap; extern struct userdb_module_interface userdb_sql; -extern struct userdb_module_interface userdb_checkpassword; extern struct userdb_module_interface userdb_dict; #ifdef HAVE_LUA extern struct userdb_module_interface userdb_lua; @@ -242,7 +241,6 @@ void userdbs_init(void) userdb_register_module(&userdb_static); userdb_register_module(&userdb_ldap); userdb_register_module(&userdb_sql); - userdb_register_module(&userdb_checkpassword); userdb_register_module(&userdb_dict); #ifdef HAVE_LUA userdb_register_module(&userdb_lua); diff --git a/src/master/main.c b/src/master/main.c index 5b6246b05e..b8d76cbdb2 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -710,9 +710,6 @@ static void print_build_options(void) #ifdef PASSDB_BSDAUTH " bsdauth" #endif -#ifdef PASSDB_CHECKPASSWORD - " checkpassword" -#endif #ifdef PASSDB_LDAP " ldap" #endif @@ -729,9 +726,6 @@ static void print_build_options(void) " sql" #endif "\nUserdb:" -#ifdef USERDB_CHECKPASSWORD - " checkpassword" -#endif #ifdef USERDB_LDAP " ldap" #ifndef BUILTIN_LDAP