dovecot: PAM lookups are now always done in auth worker processes.
dovecot at dovecot.org
dovecot at dovecot.org
Tue Aug 7 13:46:59 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/74df0c0743c4
changeset: 6218:74df0c0743c4
user: Timo Sirainen <tss at iki.fi>
date: Tue Aug 07 13:46:55 2007 +0300
description:
PAM lookups are now always done in auth worker processes.
diffstat:
2 files changed, 79 insertions(+), 318 deletions(-)
dovecot-example.conf | 6
src/auth/passdb-pam.c | 391 +++++++++----------------------------------------
diffs (truncated from 543 to 300 lines):
diff -r 06743e1e4c13 -r 74df0c0743c4 dovecot-example.conf
--- a/dovecot-example.conf Tue Aug 07 13:34:49 2007 +0300
+++ b/dovecot-example.conf Tue Aug 07 13:46:55 2007 +0300
@@ -803,12 +803,8 @@ auth default {
# REMEMBER: You'll need /etc/pam.d/dovecot file created for PAM
# authentication to actually work. <doc/wiki/PasswordDatabase.PAM.txt>
passdb pam {
- # [blocking=yes] [session=yes] [setcred=yes] [failure_show_msg=yes]
+ # [session=yes] [setcred=yes] [failure_show_msg=yes]
# [cache_key=<key>] [<service name>]
- #
- # By default a new process is forked from dovecot-auth for each PAM lookup.
- # Setting blocking=yes uses the alternative way: dovecot-auth worker
- # processes do the PAM lookups.
#
# session=yes makes Dovecot open and immediately close PAM session. Some
# PAM plugins need this to work, such as pam_mkhomedir.
diff -r 06743e1e4c13 -r 74df0c0743c4 src/auth/passdb-pam.c
--- a/src/auth/passdb-pam.c Tue Aug 07 13:34:49 2007 +0300
+++ b/src/auth/passdb-pam.c Tue Aug 07 13:46:55 2007 +0300
@@ -12,9 +12,6 @@
#ifdef PASSDB_PAM
#include "lib-signals.h"
-#include "buffer.h"
-#include "ioloop.h"
-#include "hash.h"
#include "str.h"
#include "var-expand.h"
#include "network.h"
@@ -22,12 +19,6 @@
#include "safe-memset.h"
#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#define PAM_CHILD_TIMEOUT (60*2)
-#define PAM_CHILD_CHECK_TIMEOUT (10*1000)
#ifdef HAVE_SECURITY_PAM_APPL_H
# include <security/pam_appl.h>
@@ -55,26 +46,11 @@ struct pam_passdb_module {
unsigned int failure_show_msg:1;
};
-struct pam_auth_request {
- int refcount;
- int fd;
- struct io *io;
-
- time_t start_time;
- pid_t pid;
-
- struct auth_request *request;
- verify_plain_callback_t *callback;
-};
-
struct pam_conv_context {
struct auth_request *request;
const char *pass;
const char *failure_msg;
};
-
-static struct hash_table *pam_requests;
-static struct timeout *to;
static int
pam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
@@ -140,19 +116,17 @@ pam_userpass_conv(int num_msg, linux_con
return PAM_SUCCESS;
}
-static int pam_auth(struct auth_request *request,
- pam_handle_t *pamh, const char **error)
+static int try_pam_auth(struct auth_request *request, pam_handle_t *pamh)
{
struct passdb_module *_module = request->passdb->passdb;
struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
pam_item_t item;
int status;
- *error = NULL;
-
if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
- *error = t_strdup_printf("pam_authenticate() failed: %s",
- pam_strerror(pamh, status));
+ auth_request_log_error(request, "pam",
+ "pam_authenticate() failed: %s",
+ pam_strerror(pamh, status));
return status;
}
@@ -160,59 +134,70 @@ static int pam_auth(struct auth_request
if (module->pam_setcred) {
if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
PAM_SUCCESS) {
- *error = t_strdup_printf("pam_setcred() failed: %s",
- pam_strerror(pamh, status));
+ auth_request_log_error(request, "pam",
+ "pam_setcred() failed: %s",
+ pam_strerror(pamh, status));
return status;
}
}
#endif
if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
- *error = t_strdup_printf("pam_acct_mgmt() failed: %s",
- pam_strerror(pamh, status));
+ auth_request_log_error(request, "pam",
+ "pam_acct_mgmt() failed: %s",
+ pam_strerror(pamh, status));
return status;
}
if (module->pam_session) {
if ((status = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
- *error = t_strdup_printf(
- "pam_open_session() failed: %s",
- pam_strerror(pamh, status));
+ auth_request_log_error(request, "pam",
+ "pam_open_session() failed: %s",
+ pam_strerror(pamh, status));
return status;
}
if ((status = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
- *error = t_strdup_printf(
- "pam_close_session() failed: %s",
- pam_strerror(pamh, status));
- return status;
+ auth_request_log_error(request, "pam",
+ "pam_close_session() failed: %s",
+ pam_strerror(pamh, status));
+ return status;
}
}
- /* FIXME: this works only with blocking=yes */
status = pam_get_item(pamh, PAM_USER, &item);
if (status != PAM_SUCCESS) {
- *error = t_strdup_printf("pam_get_item() failed: %s",
- pam_strerror(pamh, status));
+ auth_request_log_error(request, "pam",
+ "pam_get_item(PAM_USER) failed: %s",
+ pam_strerror(pamh, status));
return status;
}
- auth_request_set_field(request, "user", item, NULL);
-
+ auth_request_set_field(request, "user", item, NULL);
return PAM_SUCCESS;
}
+static void set_pam_items(struct auth_request *request, pam_handle_t *pamh)
+{
+ const char *host;
+
+ /* These shouldn't fail, and we don't really care if they do. */
+ host = net_ip2addr(&request->remote_ip);
+ if (host != NULL)
+ (void)pam_set_item(pamh, PAM_RHOST, host);
+ (void)pam_set_item(pamh, PAM_RUSER, request->user);
+ /* TTY is needed by eg. pam_access module */
+ (void)pam_set_item(pamh, PAM_TTY, "dovecot");
+}
+
static enum passdb_result
-pam_verify_plain_child(struct auth_request *request, const char *service,
- const char *password, int fd)
+pam_verify_plain_call(struct auth_request *request, const char *service,
+ const char *password)
{
pam_handle_t *pamh;
struct pam_conv_context ctx;
struct pam_conv conv;
enum passdb_result result;
- int ret, status, status2;
- const char *str;
- size_t size;
- buffer_t *buf;
+ int status, status2;
conv.conv = pam_userpass_conv;
conv.appdata_ptr = &ctx;
@@ -223,164 +208,40 @@ pam_verify_plain_child(struct auth_reque
status = pam_start(service, request->user, &conv, &pamh);
if (status != PAM_SUCCESS) {
- result = PASSDB_RESULT_INTERNAL_FAILURE;
- str = t_strdup_printf("pam_start() failed: %s",
- pam_strerror(pamh, status));
- } else {
- const char *host = net_ip2addr(&request->remote_ip);
-
- /* Set some PAM items. They shouldn't fail, and we don't really
- care if they do. */
- if (host != NULL)
- (void)pam_set_item(pamh, PAM_RHOST, host);
- (void)pam_set_item(pamh, PAM_RUSER, request->user);
- /* TTY is needed by eg. pam_access module */
- (void)pam_set_item(pamh, PAM_TTY, "dovecot");
-
- status = pam_auth(request, pamh, &str);
- if ((status2 = pam_end(pamh, status)) == PAM_SUCCESS) {
- switch (status) {
- case PAM_SUCCESS:
- result = PASSDB_RESULT_OK;
- break;
- case PAM_USER_UNKNOWN:
- result = PASSDB_RESULT_USER_UNKNOWN;
- break;
- case PAM_NEW_AUTHTOK_REQD:
- case PAM_ACCT_EXPIRED:
- result = PASSDB_RESULT_PASS_EXPIRED;
- break;
- default:
- result = PASSDB_RESULT_PASSWORD_MISMATCH;
- break;
- }
- } else {
- result = PASSDB_RESULT_INTERNAL_FAILURE;
- str = t_strdup_printf("pam_end() failed: %s",
- pam_strerror(pamh, status2));
- }
- if (result != PASSDB_RESULT_OK && ctx.failure_msg != NULL) {
- auth_request_set_field(request, "reason",
- ctx.failure_msg, NULL);
- }
- }
-
- if (worker) {
- /* blocking=yes code path in auth worker */
- return result;
- }
-
- buf = buffer_create_dynamic(pool_datastack_create(), 512);
- buffer_append(buf, &result, sizeof(result));
-
- if (str != NULL)
- buffer_append(buf, str, strlen(str));
-
- /* Don't send larger writes than what would block. truncated error
- message isn't that bad.. */
- size = I_MIN(buf->used, PIPE_BUF);
- if ((ret = write(fd, buf->data, size)) != (int)size) {
- if (ret < 0)
- i_error("write() failed: %m");
- else {
- i_error("write() failed: %d != %"PRIuSIZE_T,
- ret, buf->used);
- }
+ auth_request_log_error(request, "pam", "pam_start() failed: %s",
+ pam_strerror(pamh, status));
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+ }
+
+ set_pam_items(request, pamh);
+ status = try_pam_auth(request, pamh);
+ if ((status2 = pam_end(pamh, status)) != PAM_SUCCESS) {
+ auth_request_log_error(request, "pam", "pam_end() failed: %s",
+ pam_strerror(pamh, status2));
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+ }
+
+ switch (status) {
+ case PAM_SUCCESS:
+ result = PASSDB_RESULT_OK;
+ break;
+ case PAM_USER_UNKNOWN:
+ result = PASSDB_RESULT_USER_UNKNOWN;
+ break;
+ case PAM_NEW_AUTHTOK_REQD:
+ case PAM_ACCT_EXPIRED:
+ result = PASSDB_RESULT_PASS_EXPIRED;
+ break;
+ default:
+ result = PASSDB_RESULT_PASSWORD_MISMATCH;
+ break;
+ }
+
+ if (result != PASSDB_RESULT_OK && ctx.failure_msg != NULL) {
+ auth_request_set_field(request, "reason",
+ ctx.failure_msg, NULL);
}
return result;
-}
-
-static void pam_child_input(struct pam_auth_request *request)
-{
- struct auth_request *auth_request = request->request;
- enum passdb_result result;
- char buf[PIPE_BUF + 1];
- ssize_t ret;
-
- /* POSIX guarantees that writing PIPE_BUF bytes or less to pipes is
- atomic. We rely on that. */
- ret = read(request->fd, buf, sizeof(buf)-1);
More information about the dovecot-cvs
mailing list