dovecot-1.2: Added support for userdb checkpassword. Patch by Sa...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Oct 22 00:29:59 EEST 2008
details: http://hg.dovecot.org/dovecot-1.2/rev/33eae1ca0be0
changeset: 8307:33eae1ca0be0
user: Timo Sirainen <tss at iki.fi>
date: Wed Oct 22 00:29:54 2008 +0300
description:
Added support for userdb checkpassword. Patch by Sascha Wilde.
diffstat:
8 files changed, 585 insertions(+), 251 deletions(-)
configure.in | 4
src/auth/Makefile.am | 3
src/auth/db-checkpassword.c | 209 +++++++++++++++++++++++++++
src/auth/db-checkpassword.h | 54 +++++++
src/auth/mech-winbind.c | 1
src/auth/passdb-checkpassword.c | 295 +++++----------------------------------
src/auth/userdb-checkpassword.c | 268 +++++++++++++++++++++++++++++++++++
src/auth/userdb.c | 2
diffs (truncated from 1008 to 300 lines):
diff -r 3e8f847f68a4 -r 33eae1ca0be0 configure.in
--- a/configure.in Wed Oct 22 00:28:46 2008 +0300
+++ b/configure.in Wed Oct 22 00:29:54 2008 +0300
@@ -1,5 +1,5 @@ AC_PREREQ([2.59])
AC_PREREQ([2.59])
-AC_INIT([Dovecot],[1.2.alpha2],[dovecot at dovecot.org])
+AC_INIT([Dovecot],[1.2.alpha3],[dovecot at dovecot.org])
AC_CONFIG_SRCDIR([src])
AM_INIT_AUTOMAKE
@@ -1762,7 +1762,9 @@ fi
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"
fi
if test $want_bsdauth != no; then
diff -r 3e8f847f68a4 -r 33eae1ca0be0 src/auth/Makefile.am
--- a/src/auth/Makefile.am Wed Oct 22 00:28:46 2008 +0300
+++ b/src/auth/Makefile.am Wed Oct 22 00:29:54 2008 +0300
@@ -67,6 +67,7 @@ dovecot_auth_SOURCES = \
auth-stream.c \
auth-worker-client.c \
auth-worker-server.c \
+ db-checkpassword.c \
db-sql.c \
db-passwd-file.c \
main.c \
@@ -98,6 +99,7 @@ dovecot_auth_SOURCES = \
passdb-sql.c \
userdb.c \
userdb-blocking.c \
+ userdb-checkpassword.c \
userdb-nss.c \
userdb-passwd.c \
userdb-passwd-file.c \
@@ -125,6 +127,7 @@ headers = \
db-sql.h \
db-passwd-file.h \
common.h \
+ db-checkpassword.h \
mech.h \
mycrypt.h \
otp-skey-common.h \
diff -r 3e8f847f68a4 -r 33eae1ca0be0 src/auth/db-checkpassword.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/db-checkpassword.c Wed Oct 22 00:29:54 2008 +0300
@@ -0,0 +1,209 @@
+/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
+
+#include "common.h"
+
+#if defined(PASSDB_CHECKPASSWORD) || defined(USERDB_CHECKPASSWORD)
+
+#include "db-checkpassword.h"
+
+static void env_put_extra_fields(const char *extra_fields)
+{
+ const char *const *tmp;
+ const char *key, *p;
+
+ for (tmp = t_strsplit(extra_fields, "\t"); *tmp != NULL; tmp++) {
+ key = t_str_ucase(t_strcut(*tmp, '='));
+ p = strchr(*tmp, '=');
+ if (p == NULL)
+ env_put(t_strconcat(key, "=1", NULL));
+ else
+ env_put(t_strconcat(key, p, NULL));
+ }
+}
+
+static void checkpassword_request_close(struct chkpw_auth_request *request)
+{
+ if (request->io_in != NULL)
+ io_remove(&request->io_in);
+ if (request->io_out != NULL)
+ io_remove(&request->io_out);
+
+ if (request->fd_in != -1) {
+ if (close(request->fd_in) < 0)
+ i_error("checkpassword: close() failed: %m");
+ request->fd_in = -1;
+ }
+ if (request->fd_out != -1) {
+ if (close(request->fd_out) < 0)
+ i_error("checkpassword: close() failed: %m");
+ }
+}
+
+void checkpassword_request_free(struct chkpw_auth_request *request)
+{
+ checkpassword_request_close(request);
+ if (request->input_buf != NULL)
+ str_free(&request->input_buf);
+
+ if (request->password != NULL) {
+ safe_memset(request->password, 0, strlen(request->password));
+ i_free(request->password);
+ }
+ i_free(request);
+}
+
+enum checkpassword_sigchld_handler_result
+checkpassword_sigchld_handler(const struct child_wait_status *child_wait_status,
+ struct chkpw_auth_request *request)
+{
+ int status = child_wait_status->status;
+ pid_t pid = child_wait_status->pid;
+
+ if (request == NULL) {
+ i_error("checkpassword: sighandler called for unknown child %d", pid);
+ return SIGCHLD_RESULT_UNKNOWN_CHILD;
+ }
+
+ if (WIFSIGNALED(status)) {
+ i_error("checkpassword: Child %s died with signal %d",
+ dec2str(pid), WTERMSIG(status));
+ return SIGCHLD_RESULT_DEAD_CHILD;
+ } else if (WIFEXITED(status)) {
+ request->exited = TRUE;
+ request->exit_status = WEXITSTATUS(status);
+
+ auth_request_log_debug(request->request,
+ "checkpassword", "exit_status=%d",
+ request->exit_status);
+ return SIGCHLD_RESULT_OK;
+ } else {
+ /* shouldn't happen */
+ auth_request_log_debug(request->request, "checkpassword",
+ "Child exited with status=%d", status);
+ return SIGCHLD_RESULT_UNKNOWN_ERROR;
+ }
+}
+
+void checkpassword_setup_env(struct auth_request *request)
+{
+ /* 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(t_strconcat("SERVICE=", request->service, NULL));
+ if (request->local_ip.family != 0) {
+ env_put(t_strconcat("TCPLOCALIP=",
+ net_ip2addr(&request->local_ip), NULL));
+ /* FIXME: for backwards compatibility only,
+ remove some day */
+ env_put(t_strconcat("LOCAL_IP=",
+ net_ip2addr(&request->local_ip), NULL));
+ }
+ if (request->remote_ip.family != 0) {
+ env_put(t_strconcat("TCPREMOTEIP=",
+ net_ip2addr(&request->remote_ip), NULL));
+ /* FIXME: for backwards compatibility only,
+ remove some day */
+ env_put(t_strconcat("REMOTE_IP=",
+ net_ip2addr(&request->remote_ip), NULL));
+ }
+ if (request->local_port != 0) {
+ env_put(t_strdup_printf("TCPLOCALPORT=%u",
+ request->local_port));
+ }
+ if (request->remote_port != 0) {
+ env_put(t_strdup_printf("TCPREMOTEPORT=%u",
+ request->remote_port));
+ }
+ if (request->master_user != NULL) {
+ env_put(t_strconcat("MASTER_USER=",
+ request->master_user, NULL));
+ }
+ if (request->extra_fields != NULL) {
+ const char *fields =
+ auth_stream_reply_export(request->extra_fields);
+
+ /* extra fields could come from master db */
+ env_put_extra_fields(fields);
+ }
+}
+
+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) {
+ if (ret < 0) {
+ auth_request_log_error(request->request,
+ "checkpassword", "read() failed: %m");
+ }
+
+ auth_request_log_debug(request->request, "checkpassword",
+ "Received no input");
+ checkpassword_request_close(request);
+ request->half_finish_callback(request);
+ } else {
+ if (request->input_buf == NULL)
+ request->input_buf = str_new(default_pool, 512);
+ str_append_n(request->input_buf, buf, ret);
+
+ auth_request_log_debug(request->request, "checkpassword",
+ "Received input: %s", str_c(request->input_buf));
+ }
+}
+
+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 = buffer_create_dynamic(pool_datastack_create(), 512+1);
+ buffer_append(buf, auth_request->user, strlen(auth_request->user)+1);
+ if (request->password != NULL)
+ buffer_append(buf, request->password, strlen(request->password)+1);
+ else
+ buffer_append_c(buf, '\0');
+ buffer_append_c(buf, '\0');
+ data = buffer_get_data(buf, &size);
+
+ if (size > 512) {
+ auth_request_log_error(request->request, "checkpassword",
+ "output larger than 512 bytes: %"PRIuSIZE_T, size);
+ request->finish_callback(request,
+ request->internal_failure_code);
+ return;
+ }
+
+ ret = write(request->fd_out, data + request->write_pos,
+ size - request->write_pos);
+ if (ret <= 0) {
+ if (ret < 0) {
+ auth_request_log_error(request->request,
+ "checkpassword", "write() failed: %m");
+ }
+ request->finish_callback(request,
+ request->internal_failure_code);
+ return;
+ }
+
+ request->write_pos += ret;
+ if (request->write_pos < size)
+ return;
+
+ io_remove(&request->io_out);
+
+ if (close(request->fd_out) < 0)
+ i_error("checkpassword: close() failed: %m");
+ request->fd_out = -1;
+}
+
+#endif
diff -r 3e8f847f68a4 -r 33eae1ca0be0 src/auth/db-checkpassword.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/db-checkpassword.h Wed Oct 22 00:29:54 2008 +0300
@@ -0,0 +1,54 @@
+#ifndef CHECKPASSWORD_COMMON_H
+#define CHECKPASSWORD_COMMON_H
+
+#include "auth-request.h"
+#include "lib-signals.h"
+#include "buffer.h"
+#include "str.h"
+#include "ioloop.h"
+#include "hash.h"
+#include "env-util.h"
+#include "safe-memset.h"
+#include "child-wait.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+struct chkpw_auth_request {
+ int fd_out, fd_in;
+ struct io *io_out, *io_in;
+ pid_t pid;
+
+ string_t *input_buf;
+ char *password;
+ unsigned int write_pos;
+
+ struct auth_request *request;
+ void *callback;
+ void (*half_finish_callback)();
+ void (*finish_callback)();
+ int internal_failure_code;
+
+ int exit_status;
+ unsigned int exited:1;
+};
More information about the dovecot-cvs
mailing list