Mercurial > dovecot > core-2.2
changeset 11018:2e08ce368bc0 HEAD
Added support for userdb lookup to fail with a reason (many API changes).
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 31 Mar 2010 19:21:09 +0300 |
parents | ce7ed594d99e |
children | b40ec803421e |
files | doc/auth-protocol.txt src/doveadm/doveadm-auth.c src/doveadm/doveadm-mail.c src/dsync/dsync.c src/imap/main.c src/lib-auth/auth-master.c src/lib-auth/auth-master.h src/lib-master/master-auth.c src/lib-master/master-auth.h src/lib-master/master-login-auth.c src/lib-master/master-login-auth.h src/lib-master/master-login.c src/lib-master/master-login.h src/lib-storage/mail-storage-service.c src/lib-storage/mail-storage-service.h src/lmtp/commands.c src/login-common/client-common-auth.c src/login-common/sasl-server.c src/login-common/sasl-server.h src/pop3/main.c |
diffstat | 20 files changed, 253 insertions(+), 124 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/auth-protocol.txt Wed Mar 31 19:18:01 2010 +0300 +++ b/doc/auth-protocol.txt Wed Mar 31 19:21:09 2010 +0300 @@ -164,7 +164,7 @@ M: "USER" TAB <id> TAB <userid> TAB service=<service> [TAB <parameters>] S: "NOTFOUND" TAB <id> - S: "FAIL" TAB <id> TAB <error message> + S: "FAIL" TAB <id> [TAB <parameters>] S: "USER" TAB <id> TAB <userid> [TAB <parameters>] Master commands can request information about existing authentication @@ -180,7 +180,10 @@ FAIL reply means an internal error occurred. Usually either a configuration mistake or temporary error caused by lost resource (eg. database down). -Also unknown request IDs are reported as FAILs. +Also unknown request IDs are reported as FAILs. Currently the only +specified parameter is "reason", which is used when user is wanted to be +put into "temporarily disabled" state and the reason string will be shown +to user on login or to LMTP RCPT TO reply. USER reply is sent if request succeeded. It can return parameters:
--- a/src/doveadm/doveadm-auth.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/doveadm/doveadm-auth.c Wed Mar 31 19:21:09 2010 +0300 @@ -37,9 +37,14 @@ conn = auth_master_init(auth_socket_path, 0); ret = auth_master_user_lookup(conn, input->username, &input->info, pool, &username, &fields); - if (ret < 0) - i_fatal("userdb lookup failed"); - else if (ret == 0) { + if (ret < 0) { + if (fields[0] == NULL) + i_fatal("userdb lookup failed for %s", input->username); + else { + i_fatal("userdb lookup failed for %s: %s", + input->username, fields[0]); + } + } else if (ret == 0) { printf("userdb lookup: user %s doesn't exist\n", input->username); } else {
--- a/src/doveadm/doveadm-mail.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/doveadm/doveadm-mail.c Wed Mar 31 19:21:09 2010 +0300 @@ -99,11 +99,12 @@ return ret; } - if (mail_storage_service_next(storage_service, service_user, - &mail_user, &error) < 0) { - *error_r = t_strdup_printf("User init failed: %s", error); + ret = mail_storage_service_next(storage_service, service_user, + &mail_user); + if (ret < 0) { + *error_r = "User init failed"; mail_storage_service_user_free(&service_user); - return -2; + return ret; } cmd(mail_user, args);
--- a/src/dsync/dsync.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/dsync/dsync.c Wed Mar 31 19:21:09 2010 +0300 @@ -147,8 +147,8 @@ &service_user, &error) <= 0) i_fatal("User lookup failed: %s", error); if (mail_storage_service_next(storage_service, service_user, - &mail_user, &error) < 0) - i_fatal("User init failed: %s", error); + &mail_user) < 0) + i_fatal("User init failed"); if (mirror_cmd != NULL) { /* user initialization may exec doveconf, so do our forking @@ -170,8 +170,8 @@ if (settings_parse_line(set_parser, set_line) < 0) i_unreached(); if (mail_storage_service_next(storage_service, service_user, - &mail_user2, &error) < 0) - i_fatal("User init failed: %s", error); + &mail_user2) < 0) + i_fatal("User init failed"); worker2 = dsync_worker_init_local(mail_user2, alt_char);
--- a/src/imap/main.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/imap/main.c Wed Mar 31 19:21:09 2010 +0300 @@ -15,6 +15,7 @@ #include "master-login.h" #include "mail-user.h" #include "mail-storage-service.h" +#include "imap-resp-code.h" #include "imap-commands.h" #include "imap-fetch.h" @@ -104,52 +105,72 @@ } } +struct client_input { + const char *tag; + + const unsigned char *input; + unsigned int input_size; + bool send_untagged_capability; +}; + +static void +client_parse_input(const unsigned char *data, unsigned int len, + struct client_input *input_r) +{ + unsigned int taglen; + + i_assert(len > 0); + + memset(input_r, 0, sizeof(*input_r)); + + if (data[0] == '1') + input_r->send_untagged_capability = TRUE; + data++; len--; + + input_r->tag = t_strndup(data, len); + taglen = strlen(input_r->tag) + 1; + + if (len > taglen) { + input_r->input = data + taglen; + input_r->input_size = len - taglen; + } +} + static void client_add_input(struct client *client, const buffer_t *buf) { struct ostream *output; - const char *tag; - unsigned int data_pos; - bool send_untagged_capability = FALSE; + struct client_input input; if (buf != NULL && buf->used > 0) { - tag = t_strndup(buf->data, buf->used); - switch (*tag) { - case '0': - tag++; - break; - case '1': - send_untagged_capability = TRUE; - tag++; - break; - } - data_pos = strlen(tag) + 1; - if (data_pos > buf->used && - !i_stream_add_data(client->input, - CONST_PTR_OFFSET(buf->data, data_pos), - buf->used - data_pos)) + client_parse_input(buf->data, buf->used, &input); + if (input.input_size > 0 && + !i_stream_add_data(client->input, input.input, + input.input_size)) i_panic("Couldn't add client input to stream"); } else { /* IMAPLOGINTAG environment is compatible with mailfront */ - tag = getenv("IMAPLOGINTAG"); + memset(&input, 0, sizeof(input)); + input.tag = getenv("IMAPLOGINTAG"); } output = client->output; o_stream_ref(output); o_stream_cork(output); - if (tag == NULL) { + if (input.tag == NULL) { client_send_line(client, t_strconcat( "* PREAUTH [CAPABILITY ", str_c(client->capability_string), "] " "Logged in as ", client->user->username, NULL)); - } else if (send_untagged_capability) { + } else if (input.send_untagged_capability) { /* client doesn't seem to understand tagged capabilities. send untagged instead and hope that it works. */ client_send_line(client, t_strconcat("* CAPABILITY ", str_c(client->capability_string), NULL)); - client_send_line(client, t_strconcat(tag, " OK Logged in", NULL)); + client_send_line(client, + t_strconcat(input.tag, " OK Logged in", NULL)); } else { client_send_line(client, t_strconcat( - tag, " OK [CAPABILITY ", + input.tag, " OK [CAPABILITY ", str_c(client->capability_string), "] Logged in", NULL)); } (void)client_handle_input(client); @@ -241,6 +262,18 @@ } } +static void login_client_failed(const struct master_login_client *client, + const char *errormsg) +{ + struct client_input input; + const char *msg; + + client_parse_input(client->data, client->auth_req.data_size, &input); + msg = t_strdup_printf("%s NO ["IMAP_RESP_CODE_UNAVAILABLE"] %s\r\n", + input.tag, errormsg); + (void)write(client->fd, msg, strlen(msg)); +} + static void client_connected(const struct master_service_connection *conn) { if (master_login == NULL) { @@ -315,7 +348,8 @@ } else { master_login = master_login_init(master_service, "auth-master", postlogin_socket_path, - login_client_connected); + login_client_connected, + login_client_failed); io_loop_set_running(current_ioloop); }
--- a/src/lib-auth/auth-master.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-auth/auth-master.c Wed Mar 31 19:21:09 2010 +0300 @@ -50,6 +50,7 @@ struct auth_master_lookup_ctx { struct auth_master_connection *conn; + const char *user; const char *expected_reply; int return_value; @@ -135,19 +136,21 @@ return 0; } -static int parse_reply(struct auth_master_connection *conn, - const char *cmd, const char *const *args, - const char *expected_reply) +static int parse_reply(const char *cmd, const char *const *args, + const char *expected_reply, const char *user, bool debug) { - io_loop_stop(conn->ioloop); - if (strcmp(cmd, expected_reply) == 0) return 1; if (strcmp(cmd, "NOTFOUND") == 0) return 0; if (strcmp(cmd, "FAIL") == 0) { - i_error("Lookup failed: %s", - *args != NULL ? *args : "Internal failure"); + if (*args == NULL) { + i_error("user %s: Auth %s lookup failed", + user, expected_reply); + } else if (debug) { + i_debug("user %s: Auth %s lookup returned temporary failure: %s", + user, expected_reply, *args); + } return -1; } i_error("Unknown reply: %s", cmd); @@ -159,17 +162,31 @@ { struct auth_master_lookup_ctx *ctx = context; unsigned int i, len; + bool debug = (ctx->conn->flags & AUTH_MASTER_FLAG_DEBUG) != 0; + + io_loop_stop(ctx->conn->ioloop); ctx->return_value = - parse_reply(ctx->conn, cmd, args, ctx->expected_reply); - if (ctx->return_value > 0) { - len = str_array_length(args); + parse_reply(cmd, args, ctx->expected_reply, ctx->user, debug); + + len = str_array_length(args); + if (ctx->return_value >= 0) { ctx->fields = p_new(ctx->pool, const char *, len + 1); for (i = 0; i < len; i++) ctx->fields[i] = p_strdup(ctx->pool, args[i]); - if ((ctx->conn->flags & AUTH_MASTER_FLAG_DEBUG) != 0) - i_debug("auth input: %s", t_strarray_join(args, " ")); + } else { + /* put the reason string into first field */ + ctx->fields = p_new(ctx->pool, const char *, 2); + for (i = 0; i < len; i++) { + if (strncmp(args[i], "reason=", 7) == 0) { + ctx->fields[0] = + p_strdup(ctx->pool, args[i] + 7); + break; + } + } } + if (debug) + i_debug("auth input: %s", t_strarray_join(args, " ")); return TRUE; } @@ -398,6 +415,8 @@ if (!is_valid_string(user) || !is_valid_string(info->service)) { /* non-allowed characters, the user can't exist */ + *username_r = NULL; + *fields_r = NULL; return 0; } @@ -406,6 +425,7 @@ ctx.return_value = -1; ctx.pool = pool; ctx.expected_reply = "USER"; + ctx.user = user; conn->reply_callback = auth_lookup_reply_callback; conn->reply_context = &ctx; @@ -422,7 +442,7 @@ if (ctx.return_value <= 0 || ctx.fields[0] == NULL) { *username_r = NULL; - *fields_r = NULL; + *fields_r = ctx.fields; if (ctx.return_value > 0) { i_error("Userdb lookup didn't return username"); ctx.return_value = -1; @@ -467,6 +487,7 @@ if (!is_valid_string(user) || !is_valid_string(info->service)) { /* non-allowed characters, the user can't exist */ + *fields_r = NULL; return 0; } @@ -475,6 +496,7 @@ ctx.return_value = -1; ctx.pool = pool; ctx.expected_reply = "PASS"; + ctx.user = user; conn->reply_callback = auth_lookup_reply_callback; conn->reply_context = &ctx;
--- a/src/lib-auth/auth-master.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-auth/auth-master.h Wed Mar 31 19:21:09 2010 +0300 @@ -27,7 +27,9 @@ auth_master_init(const char *auth_socket_path, enum auth_master_flags flags); void auth_master_deinit(struct auth_master_connection **conn); -/* Do a USER lookup. Returns -1 = error, 0 = user not found, 1 = ok */ +/* Do a USER lookup. Returns -1 = error, 0 = user not found, 1 = ok. + When returning -1 and fields[0] isn't NULL, it contains an error message + that should be shown to user. */ int auth_master_user_lookup(struct auth_master_connection *conn, const char *user, const struct auth_user_info *info, pool_t pool, const char **username_r,
--- a/src/lib-master/master-auth.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-auth.c Wed Mar 31 19:21:09 2010 +0300 @@ -58,7 +58,6 @@ master_auth_connection_deinit(struct master_auth_connection **_conn) { struct master_auth_connection *conn = *_conn; - struct master_auth_reply reply; *_conn = NULL; @@ -67,11 +66,8 @@ POINTER_CAST(conn->tag)); } - if (conn->callback != NULL) { - memset(&reply, 0, sizeof(reply)); - reply.status = MASTER_AUTH_STATUS_INTERNAL_ERROR; - conn->callback(&reply, conn->context); - } + if (conn->callback != NULL) + conn->callback(NULL, conn->context); if (conn->io != NULL) io_remove(&conn->io);
--- a/src/lib-master/master-auth.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-auth.h Wed Mar 31 19:21:09 2010 +0300 @@ -17,6 +17,9 @@ to make sure there's space to transfer the command tag */ #define MASTER_AUTH_MAX_DATA_SIZE (1024*2) +#define MASTER_AUTH_ERRMSG_INTERNAL_FAILURE \ + "Internal error occurred. Refer to server log for more information." + enum mail_auth_request_flags { /* Connection has TLS compression enabled */ MAIL_AUTH_REQUEST_FLAG_TLS_COMPRESSION = 0x01 @@ -60,6 +63,7 @@ pid_t mail_pid; }; +/* reply=NULL if the auth lookup was cancelled due to some error */ typedef void master_auth_callback_t(const struct master_auth_reply *reply, void *context);
--- a/src/lib-master/master-login-auth.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-login-auth.c Wed Mar 31 19:21:09 2010 +0300 @@ -59,7 +59,8 @@ iter = hash_table_iterate_init(auth->requests); while (hash_table_iterate(iter, &key, &value)) { struct master_login_auth_request *request = value; - request->callback(NULL, request->context); + request->callback(NULL, MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, + request->context); i_free(request); } hash_table_iterate_deinit(&iter); @@ -135,7 +136,7 @@ request = master_login_auth_lookup_request(auth, id); if (request != NULL) { - request->callback(list + 1, request->context); + request->callback(list + 1, NULL, request->context); i_free(request); } return TRUE; @@ -152,28 +153,39 @@ request = master_login_auth_lookup_request(auth, id); if (request != NULL) { i_error("Authenticated user not found from userdb"); - request->callback(NULL, request->context); + request->callback(NULL, MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, + request->context); i_free(request); } return TRUE; } static bool -master_login_auth_input_fail(struct master_login_auth *auth, const char *args) +master_login_auth_input_fail(struct master_login_auth *auth, + const char *args_line) { struct master_login_auth_request *request; - const char *error; - unsigned int id; + const char *const *args, *error = NULL; + unsigned int i, id; - error = strchr(args, '\t'); - if (error != NULL) - error++; + args = t_strsplit(args_line, "\t"); + if (args[0] == NULL) { + i_error("Auth server sent broken FAIL line"); + return FALSE; + } + for (i = 1; args[i] != NULL; i++) { + if (strncmp(args[i], "reason=", 7) == 0) + error = args[i] + 7; + } - id = (unsigned int)strtoul(args, NULL, 10); + id = (unsigned int)strtoul(args[0], NULL, 10); request = master_login_auth_lookup_request(auth, id); if (request != NULL) { - i_error("Internal auth failure"); - request->callback(NULL, request->context); + if (error != NULL) + i_error("Internal auth failure"); + request->callback(NULL, error != NULL ? error : + MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, + request->context); i_free(request); } return TRUE; @@ -266,7 +278,8 @@ str = t_str_new(128); if (auth->fd == -1) { if (master_login_auth_connect(auth) < 0) { - callback(NULL, context); + callback(NULL, MASTER_AUTH_ERRMSG_INTERNAL_FAILURE, + context); return; } str_printfa(str, "VERSION\t%u\t%u\n",
--- a/src/lib-master/master-login-auth.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-login-auth.h Wed Mar 31 19:21:09 2010 +0300 @@ -5,7 +5,7 @@ typedef void master_login_auth_request_callback_t(const char *const *auth_args, - void *context); + const char *errormsg, void *context); struct master_login_auth *master_login_auth_init(const char *auth_socket_path); void master_login_auth_deinit(struct master_login_auth **auth);
--- a/src/lib-master/master-login.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-login.c Wed Mar 31 19:21:09 2010 +0300 @@ -39,6 +39,7 @@ struct master_login { struct master_service *service; master_login_callback_t *callback; + master_login_failure_callback_t *failure_callback; struct master_login_connection *conns; struct master_login_auth *auth; char *postlogin_socket_path; @@ -52,13 +53,15 @@ struct master_login * master_login_init(struct master_service *service, const char *auth_socket_path, const char *postlogin_socket_path, - master_login_callback_t *callback) + master_login_callback_t *callback, + master_login_failure_callback_t *failure_callback) { struct master_login *login; login = i_new(struct master_login, 1); login->service = service; login->callback = callback; + login->failure_callback = failure_callback; login->auth = master_login_auth_init(auth_socket_path); login->postlogin_socket_path = i_strdup(postlogin_socket_path); @@ -316,7 +319,8 @@ } static void -master_login_auth_callback(const char *const *auth_args, void *context) +master_login_auth_callback(const char *const *auth_args, const char *errormsg, + void *context) { struct master_login_client *client = context; struct master_auth_reply reply; @@ -324,14 +328,17 @@ memset(&reply, 0, sizeof(reply)); reply.tag = client->auth_req.tag; - reply.status = auth_args != NULL ? MASTER_AUTH_STATUS_OK : + reply.status = errormsg == NULL ? MASTER_AUTH_STATUS_OK : MASTER_AUTH_STATUS_INTERNAL_ERROR; reply.mail_pid = getpid(); o_stream_send(client->conn->output, &reply, sizeof(reply)); - if (auth_args == NULL || auth_args[0] == NULL) { - if (auth_args != NULL) + if (errormsg != NULL || auth_args[0] == NULL) { + if (auth_args != NULL) { i_error("login client: Username missing from auth reply"); + errormsg = MASTER_AUTH_ERRMSG_INTERNAL_FAILURE; + } + client->conn->login->failure_callback(client, errormsg); master_login_client_free(&client); return; }
--- a/src/lib-master/master-login.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-master/master-login.h Wed Mar 31 19:21:09 2010 +0300 @@ -14,11 +14,15 @@ typedef void master_login_callback_t(const struct master_login_client *client, const char *username, const char *const *extra_fields); +typedef void +master_login_failure_callback_t(const struct master_login_client *client, + const char *errormsg); struct master_login * master_login_init(struct master_service *service, const char *auth_socket_path, const char *postlogin_socket_path, - master_login_callback_t *callback); + master_login_callback_t *callback, + master_login_failure_callback_t *failure_callback); void master_login_deinit(struct master_login **login); void master_login_add(struct master_login *login, int fd);
--- a/src/lib-storage/mail-storage-service.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-storage/mail-storage-service.c Wed Mar 31 19:21:09 2010 +0300 @@ -36,6 +36,9 @@ #define MAX_TIME_BACKWARDS_SLEEP 5 #define MAX_NOWARN_FORWARD_SECS 10 +#define ERRSTR_INVALID_USER_SETTINGS \ + "Invalid user settings. Refer to server log for more information." + struct mail_storage_service_ctx { pool_t pool; struct master_service *service; @@ -213,9 +216,13 @@ } *user = new_username; } else if (ret == 0) - *error_r = "unknown user"; - else - *error_r = "userdb lookup failed"; + *error_r = "Unknown user"; + else if (**fields_r != NULL) { + *error_r = t_strdup(**fields_r); + ret = -2; + } else { + *error_r = MAIL_ERRSTR_CRITICAL_MSG; + } return ret; } @@ -670,8 +677,11 @@ dyn_parsers); if (master_service_settings_cache_read(ctx->set_cache, &set_input, - parser_r, error_r) < 0) + parser_r, error_r) < 0) { + *error_r = t_strdup_printf( + "Error reading configuration: %s", *error_r); return -1; + } } else { dyn_parsers_update_parent(pool, &set_input.roots, dyn_parsers); if (master_service_settings_read(ctx->service, &set_input, @@ -746,7 +756,7 @@ const char *username = input->username; const struct setting_parser_info *user_info; const struct mail_user_settings *user_set; - const char *const *userdb_fields; + const char *const *userdb_fields, *error; struct auth_user_reply reply; const struct setting_parser_context *set_parser; pool_t user_pool, temp_pool; @@ -756,8 +766,10 @@ if (mail_storage_service_read_settings(ctx, input, user_pool, &user_info, &set_parser, - error_r) < 0) { + &error) < 0) { + i_error("user %s: %s", username, error); pool_unref(&user_pool); + *error_r = MAIL_ERRSTR_CRITICAL_MSG; return -1; } user_set = settings_parser_get_list(set_parser)[1]; @@ -790,7 +802,7 @@ user->user_info = user_info; user->set_parser = settings_parser_dup(set_parser, user_pool); - if (!settings_parser_check(user->set_parser, user_pool, error_r)) + if (!settings_parser_check(user->set_parser, user_pool, &error)) i_unreached(); user->user_set = settings_parser_get_list(user->set_parser)[1]; @@ -803,8 +815,12 @@ if (userdb_fields != NULL) { auth_user_fields_parse(userdb_fields, temp_pool, &reply); - if (user_reply_handle(user, &reply, error_r) < 0) + if (user_reply_handle(user, &reply, &error) < 0) { + i_error("user %s: Invalid settings in userdb: %s", + username, error); + *error_r = ERRSTR_INVALID_USER_SETTINGS; ret = -2; + } } pool_unref(&temp_pool); @@ -820,8 +836,7 @@ int mail_storage_service_next(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, - struct mail_user **mail_user_r, - const char **error_r) + struct mail_user **mail_user_r) { const struct mail_user_settings *user_set = user->user_set; const char *home, *chroot, *error; @@ -839,10 +854,10 @@ user_set->mail_chroot); if (*home != '/' && *home != '\0') { - *error_r = t_strdup_printf("user %s: " + i_error("user %s: " "Relative home directory paths not supported: %s", user->input.username, home); - return -1; + return -2; } if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0) @@ -852,8 +867,8 @@ if (service_drop_privileges(user_set, user->system_groups_user, home, chroot, disallow_root, temp_priv_drop, FALSE, &error) < 0) { - *error_r = t_strdup_printf( - "Couldn't drop privileges: %s", error); + i_error("user %s: Couldn't drop privileges: %s", + user->input.username, error); return -1; } if (!temp_priv_drop || @@ -884,8 +899,11 @@ t_strconcat(chroot, "/", home, NULL)); } if (mail_storage_service_init_post(ctx, user, home, - mail_user_r, error_r) < 0) - return -1; + mail_user_r, &error) < 0) { + i_error("user %s: Initialization failed: %s", + user->input.username, error); + return -2; + } return 0; } @@ -913,18 +931,18 @@ const char **error_r) { struct mail_storage_service_user *user; - const char *error; int ret; - ret = mail_storage_service_lookup(ctx, input, &user, &error); - if (ret <= 0) { - *error_r = t_strdup_printf("User lookup failed: %s", error); + ret = mail_storage_service_lookup(ctx, input, &user, error_r); + if (ret <= 0) return ret; - } - if (mail_storage_service_next(ctx, user, mail_user_r, &error) < 0) { + + ret = mail_storage_service_next(ctx, user, mail_user_r); + if (ret < 0) { mail_storage_service_user_free(&user); - *error_r = t_strdup_printf("User init failed: %s", error); - return -2; + *error_r = ret == -2 ? ERRSTR_INVALID_USER_SETTINGS : + MAIL_ERRSTR_CRITICAL_MSG; + return ret; } *user_r = user; return 1;
--- a/src/lib-storage/mail-storage-service.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lib-storage/mail-storage-service.h Wed Mar 31 19:21:09 2010 +0300 @@ -61,20 +61,19 @@ void mail_storage_service_init_settings(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input); /* Returns 1 if ok, 0 if user wasn't found, -1 if fatal error, - -2 if user had invalid settings. */ + -2 if error is user-specific (e.g. invalid settings). + Error can be safely shown to untrusted users. */ int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, struct mail_storage_service_user **user_r, const char **error_r); -/* Returns 0 if ok, -1 if user had invalid settings. */ +/* Returns 0 if ok, -1 if fatal error, -2 if error is user-specific. */ int mail_storage_service_next(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user, - struct mail_user **mail_user_r, - const char **error_r); + struct mail_user **mail_user_r); void mail_storage_service_restrict_setenv(struct mail_storage_service_ctx *ctx, struct mail_storage_service_user *user); -/* Combine lookup() and next() into one call. If either one fails with - "invalid settings", this function returns -2. */ +/* Combine lookup() and next() into one call. */ int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx, const struct mail_storage_service_input *input, struct mail_storage_service_user **user_r,
--- a/src/lmtp/commands.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/lmtp/commands.c Wed Mar 31 19:21:09 2010 +0300 @@ -28,7 +28,9 @@ #include <stdlib.h> #define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error" -#define ERRSTR_TEMP_USERDB_FAIL "451 4.3.0 <%s> Temporary user lookup failure" +#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> " +#define ERRSTR_TEMP_USERDB_FAIL \ + ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure" #define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*30) @@ -199,7 +201,7 @@ struct lmtp_proxy_settings set; struct auth_user_info info; struct mail_storage_service_input input; - const char *args, *const *fields, *orig_username = username; + const char *args, *const *fields, *errstr, *orig_username = username; pool_t pool; int ret; @@ -219,10 +221,11 @@ ret = auth_master_pass_lookup(auth_conn, username, &info, pool, &fields); if (ret <= 0) { + errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) : + t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address); pool_unref(&pool); if (ret < 0) { - client_send_line(client, ERRSTR_TEMP_USERDB_FAIL, - address); + client_send_line(client, "%s", errstr); return TRUE; } else { /* user not found from passdb. try userdb also. */ @@ -332,7 +335,7 @@ { struct mail_recipient rcpt; struct mail_storage_service_input input; - const char *address, *username, *detail; + const char *address, *username, *detail, *prefix; const char *error = NULL, *arg, *const *argv; unsigned int len; int ret = 0; @@ -384,8 +387,9 @@ &rcpt.service_user, &error); if (ret < 0) { - i_error("User lookup failed: %s", error); - client_send_line(client, ERRSTR_TEMP_USERDB_FAIL, username); + prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX, + username); + client_send_line(client, "%s%s", prefix, error); return 0; } if (ret == 0) { @@ -449,9 +453,7 @@ i_set_failure_prefix(t_strdup_printf("lmtp(%s, %s): ", my_pid, username)); if (mail_storage_service_next(storage_service, rcpt->service_user, - &client->state.dest_user, - &error) < 0) { - i_error("%s", error); + &client->state.dest_user) < 0) { client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, rcpt->address); return -1;
--- a/src/login-common/client-common-auth.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/login-common/client-common-auth.c Wed Mar 31 19:21:09 2010 +0300 @@ -378,6 +378,7 @@ i_assert(!client->destroyed || sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED || + sasl_reply == SASL_SERVER_REPLY_MASTER_ABORTED || sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED); switch (sasl_reply) { @@ -428,6 +429,10 @@ client_destroy_success(client, data); } break; + case SASL_SERVER_REPLY_MASTER_ABORTED: + /* mail process already sent the error message to client */ + client_destroy_success(client, data); + break; case SASL_SERVER_REPLY_CONTINUE: client->v.auth_send_challenge(client, data);
--- a/src/login-common/sasl-server.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/login-common/sasl-server.c Wed Mar 31 19:21:09 2010 +0300 @@ -94,12 +94,15 @@ client->master_tag = 0; client->authenticating = FALSE; - switch (reply->status) { - case MASTER_AUTH_STATUS_OK: - sasl_reply = SASL_SERVER_REPLY_SUCCESS; - break; - case MASTER_AUTH_STATUS_INTERNAL_ERROR: - break; + if (reply != NULL) { + switch (reply->status) { + case MASTER_AUTH_STATUS_OK: + sasl_reply = SASL_SERVER_REPLY_SUCCESS; + break; + case MASTER_AUTH_STATUS_INTERNAL_ERROR: + sasl_reply = SASL_SERVER_REPLY_MASTER_ABORTED; + break; + } } client->mail_pid = reply->mail_pid; call_client_callback(client, sasl_reply, data, NULL);
--- a/src/login-common/sasl-server.h Wed Mar 31 19:18:01 2010 +0300 +++ b/src/login-common/sasl-server.h Wed Mar 31 19:21:09 2010 +0300 @@ -8,6 +8,7 @@ SASL_SERVER_REPLY_AUTH_FAILED, SASL_SERVER_REPLY_AUTH_ABORTED, SASL_SERVER_REPLY_MASTER_FAILED, + SASL_SERVER_REPLY_MASTER_ABORTED, SASL_SERVER_REPLY_CONTINUE };
--- a/src/pop3/main.c Wed Mar 31 19:18:01 2010 +0300 +++ b/src/pop3/main.c Wed Mar 31 19:21:09 2010 +0300 @@ -161,6 +161,15 @@ } } +static void login_client_failed(const struct master_login_client *client, + const char *errormsg) +{ + const char *msg; + + msg = t_strdup_printf("-ERR [IN-USE] %s\r\n", errormsg); + (void)write(client->fd, msg, strlen(msg)); +} + static void client_connected(const struct master_service_connection *conn) { if (master_login == NULL) { @@ -231,7 +240,8 @@ } else { master_login = master_login_init(master_service, "auth-master", postlogin_socket_path, - login_client_connected); + login_client_connected, + login_client_failed); io_loop_set_running(current_ioloop); }