# HG changeset patch # User Timo Sirainen # Date 1254951974 14400 # Node ID 097588a7903c7d973df5e8207154ac13727032a2 # Parent 9716b5a4b14a16ea96f77ae54d9ed1175e12c0a9 lib-auth: Changed API to connect to only a single specified auth socket. Login processes now always connect to socket called "auth". diff -r 9716b5a4b14a -r 097588a7903c doc/example-config/conf.d/master.conf --- a/doc/example-config/conf.d/master.conf Wed Oct 07 17:44:38 2009 -0400 +++ b/doc/example-config/conf.d/master.conf Wed Oct 07 17:46:14 2009 -0400 @@ -36,8 +36,7 @@ # default unix_listener { - # The path must match the auth section name - path = login/default + path = login/auth mode = 0666 } diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/Makefile.am --- a/src/lib-auth/Makefile.am Wed Oct 07 17:44:38 2009 -0400 +++ b/src/lib-auth/Makefile.am Wed Oct 07 17:46:14 2009 -0400 @@ -5,16 +5,17 @@ libauth_la_SOURCES = \ auth-client.c \ + auth-client-request.c \ auth-master.c \ - auth-server-connection.c \ - auth-server-request.c + auth-server-connection.c headers = \ auth-client.h \ auth-client-interface.h \ + auth-client-private.h \ + auth-client-request.h \ auth-master.h \ - auth-server-connection.h \ - auth-server-request.h + auth-server-connection.h if INSTALL_HEADERS pkginc_libdir=$(pkgincludedir) diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-client-private.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-client-private.h Wed Oct 07 17:46:14 2009 -0400 @@ -0,0 +1,20 @@ +#ifndef AUTH_CLIENT_PRIVATE_H +#define AUTH_CLIENT_PRIVATE_H + +#include "auth-client.h" + +struct auth_client { + char *auth_socket_path; + unsigned int client_pid; + + struct auth_server_connection *conn; + + auth_connect_notify_callback_t *connect_notify_callback; + void *connect_notify_context; + + unsigned int request_id_counter; + + unsigned int debug:1; +}; + +#endif diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-client-request.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-client-request.c Wed Oct 07 17:46:14 2009 -0400 @@ -0,0 +1,173 @@ +/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "strescape.h" +#include "ostream.h" +#include "auth-client-private.h" +#include "auth-server-connection.h" +#include "auth-client-request.h" + +#include + +struct auth_client_request { + pool_t pool; + + struct auth_server_connection *conn; + unsigned int id; + + struct auth_request_info request_info; + + auth_request_callback_t *callback; + void *context; +}; + +static void auth_server_send_new_request(struct auth_server_connection *conn, + struct auth_client_request *request) +{ + struct auth_request_info *info = &request->request_info; + string_t *str; + + str = t_str_new(512); + str_printfa(str, "AUTH\t%u\t", request->id); + str_tabescape_write(str, info->mech); + str_append(str, "\tservice="); + str_tabescape_write(str, info->service); + + if ((info->flags & AUTH_REQUEST_FLAG_SECURED) != 0) + str_append(str, "\tsecured"); + if ((info->flags & AUTH_REQUEST_FLAG_VALID_CLIENT_CERT) != 0) + str_append(str, "\tvalid-client-cert"); + + if (info->cert_username != NULL) { + str_append(str, "\tcert_username="); + str_tabescape_write(str, info->cert_username); + } + if (info->local_ip.family != 0) + str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip)); + if (info->remote_ip.family != 0) + str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip)); + if (info->local_port != 0) + str_printfa(str, "\tlport=%u", info->local_port); + if (info->remote_port != 0) + str_printfa(str, "\trport=%u", info->remote_port); + if (info->initial_resp_base64 != NULL) { + str_append(str, "\tresp="); + str_tabescape_write(str, info->initial_resp_base64); + } + str_append_c(str, '\n'); + + if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) + i_error("Error sending request to auth server: %m"); +} + +struct auth_client_request * +auth_client_request_new(struct auth_client *client, + const struct auth_request_info *request_info, + auth_request_callback_t *callback, void *context) +{ + struct auth_client_request *request; + pool_t pool; + + pool = pool_alloconly_create("auth client request", 512); + request = p_new(pool, struct auth_client_request, 1); + request->pool = pool; + request->conn = client->conn; + + request->request_info = *request_info; + request->request_info.mech = p_strdup(pool, request_info->mech); + request->request_info.service = p_strdup(pool, request_info->service); + request->request_info.cert_username = + p_strdup(pool, request_info->cert_username); + request->request_info.initial_resp_base64 = + p_strdup(pool, request_info->initial_resp_base64); + + request->callback = callback; + request->context = context; + + request->id = + auth_server_connection_add_request(request->conn, request); + T_BEGIN { + auth_server_send_new_request(request->conn, request); + } T_END; + return request; +} + +void auth_client_request_continue(struct auth_client_request *request, + const char *data_base64) +{ + struct const_iovec iov[3]; + const char *prefix; + + prefix = t_strdup_printf("CONT\t%u\t", request->id); + + iov[0].iov_base = prefix; + iov[0].iov_len = strlen(prefix); + iov[1].iov_base = data_base64; + iov[1].iov_len = strlen(data_base64); + iov[2].iov_base = "\n"; + iov[2].iov_len = 1; + + if (o_stream_sendv(request->conn->output, iov, 3) < 0) + i_error("Error sending continue request to auth server: %m"); +} + +void auth_client_request_abort(struct auth_client_request **_request) +{ + struct auth_client_request *request = *_request; + + *_request = NULL; + + request->callback(request, AUTH_REQUEST_STATUS_FAIL, NULL, NULL, + request->context); + request->callback = NULL; +} + +unsigned int auth_client_request_get_id(struct auth_client_request *request) +{ + return request->id; +} + +unsigned int +auth_client_request_get_server_pid(struct auth_client_request *request) +{ + return request->conn->server_pid; +} + +bool auth_client_request_is_aborted(struct auth_client_request *request) +{ + return request->callback == NULL; +} + +void auth_client_request_server_input(struct auth_client_request *request, + enum auth_request_status status, + const char *const *args) +{ + const char *const *tmp, *base64_data = NULL; + + if (request->callback == NULL) { + /* aborted already */ + return; + } + + switch (status) { + case AUTH_REQUEST_STATUS_OK: + for (tmp = args; *tmp != NULL; tmp++) { + if (strncmp(*tmp, "resp=", 5) == 0) { + base64_data = *tmp + 5; + break; + } + } + break; + case AUTH_REQUEST_STATUS_CONTINUE: + base64_data = args[0]; + args = NULL; + break; + case AUTH_REQUEST_STATUS_FAIL: + break; + } + + request->callback(request, status, base64_data, args, request->context); + if (status != AUTH_REQUEST_STATUS_CONTINUE) + pool_unref(&request->pool); +} diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-client-request.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-client-request.h Wed Oct 07 17:46:14 2009 -0400 @@ -0,0 +1,12 @@ +#ifndef AUTH_CLIENT_REQUEST_H +#define AUTH_CLIENT_REQUEST_H + +struct auth_server_connection; + +bool auth_client_request_is_aborted(struct auth_client_request *request); + +void auth_client_request_server_input(struct auth_client_request *request, + enum auth_request_status status, + const char *const *args); + +#endif diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-client.c --- a/src/lib-auth/auth-client.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/lib-auth/auth-client.c Wed Oct 07 17:46:14 2009 -0400 @@ -1,118 +1,39 @@ -/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ +/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "buffer.h" -#include "ioloop.h" -#include "hash.h" -#include "auth-client.h" +#include "array.h" +#include "auth-client-private.h" #include "auth-server-connection.h" -#include -#include - -#define AUTH_CLIENT_SOCKET_MAX_WAIT_TIME 10 - -struct auth_client *auth_client_new(unsigned int client_pid) +struct auth_client * +auth_client_init(const char *auth_socket_path, unsigned int client_pid, + bool debug) { struct auth_client *client; client = i_new(struct auth_client, 1); - client->pid = client_pid; - client->available_auth_mechs = buffer_create_dynamic(default_pool, 128); - - auth_client_connect_missing_servers(client); + client->client_pid = client_pid; + client->auth_socket_path = i_strdup(auth_socket_path); + client->debug = debug; + client->conn = auth_server_connection_init(client); + (void)auth_server_connection_connect(client->conn); return client; } -void auth_client_free(struct auth_client **_client) +void auth_client_deinit(struct auth_client **_client) { struct auth_client *client = *_client; - struct auth_server_connection *next; - struct auth_mech_desc *mech; - size_t i, size; *_client = NULL; - mech = buffer_get_modifiable_data(client->available_auth_mechs, &size); - size /= sizeof(*mech); - for (i = 0; i < size; i++) - i_free(mech[i].name); - buffer_free(&client->available_auth_mechs); - - while (client->connections != NULL) { - next = client->connections->next; - auth_server_connection_destroy(&client->connections, FALSE); - client->connections = next; - } - - if (client->to_reconnect != NULL) - timeout_remove(&client->to_reconnect); + auth_server_connection_deinit(&client->conn); + i_free(client->auth_socket_path); i_free(client); } -void auth_client_reconnect(struct auth_client *client) -{ - struct auth_server_connection *next; - - while (client->connections != NULL) { - next = client->connections->next; - auth_server_connection_destroy(&client->connections, FALSE); - client->connections = next; - } - - auth_client_connect_missing_servers(client); -} - -const struct auth_mech_desc * -auth_client_get_available_mechs(struct auth_client *client, - unsigned int *mech_count) -{ - const struct auth_mech_desc *mechs; - size_t size; - - mechs = buffer_get_data(client->available_auth_mechs, &size); - *mech_count = size / sizeof(*mechs); - return mechs; -} - -const struct auth_mech_desc * -auth_client_find_mech(struct auth_client *client, const char *name) -{ - const struct auth_mech_desc *mech; - size_t i, size; - - mech = buffer_get_data(client->available_auth_mechs, &size); - size /= sizeof(*mech); - for (i = 0; i < size; i++) { - if (strcasecmp(mech[i].name, name) == 0) - return &mech[i]; - } - - return NULL; -} - -bool auth_client_reserve_connection(struct auth_client *client, - const char *mech, - struct auth_connect_id *id_r) -{ - struct auth_server_connection *conn; - const char *error; - - conn = auth_server_connection_find_mech(client, mech, &error); - if (conn == NULL) - return FALSE; - - id_r->server_pid = conn->server_pid; - id_r->connect_uid = conn->connect_uid; - - return TRUE; -} - bool auth_client_is_connected(struct auth_client *client) { - return !client->reconnect && - client->conn_waiting_handshake_count == 0 && - client->connections != NULL; + return client->conn->handshake_received; } void auth_client_set_connect_notify(struct auth_client *client, @@ -123,67 +44,31 @@ client->connect_notify_context = context; } -static void reconnect_timeout(struct auth_client *client) +const struct auth_mech_desc * +auth_client_get_available_mechs(struct auth_client *client, + unsigned int *mech_count) { - auth_client_connect_missing_servers(client); + return array_get(&client->conn->available_auth_mechs, mech_count); } -void auth_client_connect_missing_servers(struct auth_client *client) +const struct auth_mech_desc * +auth_client_find_mech(struct auth_client *client, const char *name) { - DIR *dirp; - struct dirent *dp; - struct stat st; - - /* we're chrooted */ - dirp = opendir("."); - if (dirp == NULL) { - i_fatal("opendir(.) failed when trying to get list of " - "authentication servers: %m"); - } - - client->reconnect = FALSE; - while ((dp = readdir(dirp)) != NULL) { - const char *name = dp->d_name; - - if (name[0] == '.') - continue; - - if (auth_server_connection_find_path(client, name) != NULL) { - /* already connected */ - continue; - } + const struct auth_mech_desc *mechs; + unsigned int i, count; - /* Normally they're sockets, but in UnixWare they're - created as fifos. */ - if (stat(name, &st) == 0 && - (S_ISSOCK(st.st_mode) || S_ISFIFO(st.st_mode))) { - if (auth_server_connection_new(client, name) == NULL) - client->reconnect = TRUE; - } + mechs = array_get(&client->conn->available_auth_mechs, &count); + for (i = 0; i < count; i++) { + if (strcasecmp(mechs[i].name, name) == 0) + return &mechs[i]; } - - if (client->connections == NULL && !client->reconnect) { - if (client->missing_sockets_start_time == 0) - client->missing_sockets_start_time = ioloop_time; - else if (ioloop_time - client->missing_sockets_start_time > - AUTH_CLIENT_SOCKET_MAX_WAIT_TIME) - i_fatal("No authentication sockets found"); - } + return NULL; +} - if (closedir(dirp) < 0) - i_error("closedir() failed: %m"); - - if (client->reconnect || client->connections == NULL) { - if (client->to_reconnect == NULL) { - client->to_reconnect = - timeout_add(1000, reconnect_timeout, client); - } - } else if (client->to_reconnect != NULL) - timeout_remove(&client->to_reconnect); - - if (client->connect_notify_callback != NULL) { - client->connect_notify_callback(client, - auth_client_is_connected(client), - client->connect_notify_context); - } +void auth_client_get_connect_id(struct auth_client *client, + unsigned int *server_pid_r, + unsigned int *connect_uid_r) +{ + *server_pid_r = client->conn->server_pid; + *connect_uid_r = client->conn->connect_uid; } diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-client.h --- a/src/lib-auth/auth-client.h Wed Oct 07 17:44:38 2009 -0400 +++ b/src/lib-auth/auth-client.h Wed Oct 07 17:46:14 2009 -0400 @@ -5,13 +5,19 @@ #include "auth-client-interface.h" struct auth_client; -struct auth_request; +struct auth_client_request; enum auth_request_flags { AUTH_REQUEST_FLAG_SECURED = 0x01, AUTH_REQUEST_FLAG_VALID_CLIENT_CERT = 0x02 }; +enum auth_request_status { + AUTH_REQUEST_STATUS_FAIL = -1, + AUTH_REQUEST_STATUS_CONTINUE, + AUTH_REQUEST_STATUS_OK +}; + struct auth_mech_desc { char *name; enum mech_security_flags flags; @@ -34,7 +40,8 @@ const char *initial_resp_base64; }; -typedef void auth_request_callback_t(struct auth_request *request, int status, +typedef void auth_request_callback_t(struct auth_client_request *request, + enum auth_request_status status, const char *data_base64, const char *const *args, void *context); @@ -42,11 +49,10 @@ bool connected, void *context); /* Create new authentication client. */ -struct auth_client *auth_client_new(unsigned int client_pid); -void auth_client_free(struct auth_client **client); - -/* Destroy all connections and reconnect. */ -void auth_client_reconnect(struct auth_client *client); +struct auth_client * +auth_client_init(const char *auth_socket_path, unsigned int client_pid, + bool debug); +void auth_client_deinit(struct auth_client **client); bool auth_client_is_connected(struct auth_client *client); void auth_client_set_connect_notify(struct auth_client *client, @@ -58,35 +64,27 @@ const struct auth_mech_desc * auth_client_find_mech(struct auth_client *client, const char *name); -/* Reserve connection for specific mechanism. The id can be given to - auth_client_request_new() to force it to use the same connection, or fail. - This is currently useful only for APOP authentication. Returns TRUE if - successfull. */ -bool auth_client_reserve_connection(struct auth_client *client, - const char *mech, - struct auth_connect_id *id_r); +/* Return current connection's identifiers. */ +void auth_client_get_connect_id(struct auth_client *client, + unsigned int *server_pid_r, + unsigned int *connect_uid_r); /* Create a new authentication request. callback is called whenever something - happens for the request. id can be NULL. */ -struct auth_request * -auth_client_request_new(struct auth_client *client, struct auth_connect_id *id, + happens for the request. */ +struct auth_client_request * +auth_client_request_new(struct auth_client *client, const struct auth_request_info *request_info, - auth_request_callback_t *callback, void *context, - const char **error_r); + auth_request_callback_t *callback, void *context); /* Continue authentication. Call when reply->result == AUTH_CLIENT_REQUEST_CONTINUE */ -void auth_client_request_continue(struct auth_request *request, +void auth_client_request_continue(struct auth_client_request *request, const char *data_base64); - /* Abort ongoing authentication request. */ -void auth_client_request_abort(struct auth_request *request); - +void auth_client_request_abort(struct auth_client_request **request); /* Return ID of this request. */ -unsigned int auth_client_request_get_id(struct auth_request *request); - +unsigned int auth_client_request_get_id(struct auth_client_request *request); /* Return the PID of the server that handled this request. */ -unsigned int auth_client_request_get_server_pid(struct auth_request *request); - -void auth_client_connect_missing_servers(struct auth_client *client); +unsigned int +auth_client_request_get_server_pid(struct auth_client_request *request); #endif diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-server-connection.c --- a/src/lib-auth/auth-server-connection.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/lib-auth/auth-server-connection.c Wed Oct 07 17:46:14 2009 -0400 @@ -1,158 +1,211 @@ /* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "buffer.h" +#include "array.h" #include "hash.h" #include "ioloop.h" #include "istream.h" #include "ostream.h" #include "network.h" -#include "auth-client.h" +#include "eacces-error.h" +#include "auth-client-private.h" +#include "auth-client-request.h" #include "auth-server-connection.h" -#include "auth-server-request.h" #include #include +#define AUTH_SERVER_CONN_MAX_LINE_LENGTH AUTH_CLIENT_MAX_LINE_LENGTH #define AUTH_HANDSHAKE_TIMEOUT (30*1000) - -static void auth_server_connection_unref(struct auth_server_connection *conn); - -static void update_available_auth_mechs(struct auth_server_connection *conn) -{ - struct auth_client *client = conn->client; - const struct auth_mech_desc *mech; - struct auth_mech_desc *new_mech; - unsigned int i; +#define AUTH_SERVER_RECONNECT_TIMEOUT_SECS 5 - mech = conn->available_auth_mechs; - for (i = 0; i < conn->available_auth_mechs_count; i++) { - if (auth_client_find_mech(client, mech[i].name) == NULL) { - new_mech = buffer_append_space_unsafe( - client->available_auth_mechs, sizeof(*mech)); - *new_mech = mech[i]; - new_mech->name = i_strdup(mech[i].name); - } - } -} +static void +auth_server_connection_disconnect(struct auth_server_connection *conn); -static bool -auth_client_input_mech(struct auth_server_connection *conn, const char *args) +static int +auth_server_input_mech(struct auth_server_connection *conn, + const char *const *args) { - const char *const *list; struct auth_mech_desc mech_desc; if (conn->handshake_received) { i_error("BUG: Authentication server already sent handshake"); - return FALSE; + return -1; } - - list = t_strsplit(args, "\t"); - if (list[0] == NULL) { + if (args[0] == NULL) { i_error("BUG: Authentication server sent broken MECH line"); - return FALSE; + return -1; } memset(&mech_desc, 0, sizeof(mech_desc)); - mech_desc.name = p_strdup(conn->pool, list[0]); + mech_desc.name = p_strdup(conn->pool, args[0]); if (strcmp(mech_desc.name, "PLAIN") == 0) conn->has_plain_mech = TRUE; - for (list++; *list != NULL; list++) { - if (strcmp(*list, "private") == 0) + for (args++; *args != NULL; args++) { + if (strcmp(*args, "private") == 0) mech_desc.flags |= MECH_SEC_PRIVATE; - else if (strcmp(*list, "anonymous") == 0) + else if (strcmp(*args, "anonymous") == 0) mech_desc.flags |= MECH_SEC_ANONYMOUS; - else if (strcmp(*list, "plaintext") == 0) + else if (strcmp(*args, "plaintext") == 0) mech_desc.flags |= MECH_SEC_PLAINTEXT; - else if (strcmp(*list, "dictionary") == 0) + else if (strcmp(*args, "dictionary") == 0) mech_desc.flags |= MECH_SEC_DICTIONARY; - else if (strcmp(*list, "active") == 0) + else if (strcmp(*args, "active") == 0) mech_desc.flags |= MECH_SEC_ACTIVE; - else if (strcmp(*list, "forward-secrecy") == 0) + else if (strcmp(*args, "forward-secrecy") == 0) mech_desc.flags |= MECH_SEC_FORWARD_SECRECY; - else if (strcmp(*list, "mutual-auth") == 0) + else if (strcmp(*args, "mutual-auth") == 0) mech_desc.flags |= MECH_SEC_MUTUAL_AUTH; } - buffer_append(conn->auth_mechs_buf, &mech_desc, sizeof(mech_desc)); - return TRUE; + array_append(&conn->available_auth_mechs, &mech_desc, 1); + return 0; } -static bool -auth_client_input_spid(struct auth_server_connection *conn, const char *args) +static int +auth_server_input_spid(struct auth_server_connection *conn, + const char *const *args) { if (conn->handshake_received) { i_error("BUG: Authentication server already sent handshake"); - return FALSE; + return -1; } - conn->server_pid = (unsigned int)strtoul(args, NULL, 10); - return TRUE; + conn->server_pid = (unsigned int)strtoul(args[0], NULL, 10); + return 0; } -static bool -auth_client_input_cuid(struct auth_server_connection *conn, const char *args) +static int +auth_server_input_cuid(struct auth_server_connection *conn, + const char *const *args) { if (conn->handshake_received) { i_error("BUG: Authentication server already sent handshake"); - return FALSE; + return -1; } - conn->connect_uid = (unsigned int)strtoul(args, NULL, 10); - return TRUE; + conn->connect_uid = (unsigned int)strtoul(args[0], NULL, 10); + return 0; } -static bool auth_client_input_done(struct auth_server_connection *conn) +static int auth_server_input_done(struct auth_server_connection *conn) { - conn->available_auth_mechs = conn->auth_mechs_buf->data; - conn->available_auth_mechs_count = - conn->auth_mechs_buf->used / sizeof(struct auth_mech_desc); - - if (conn->available_auth_mechs_count == 0) { + if (array_count(&conn->available_auth_mechs) == 0) { i_error("BUG: Authentication server returned no mechanisms"); - return FALSE; + return -1; } if (conn->to != NULL) timeout_remove(&conn->to); conn->handshake_received = TRUE; - conn->client->conn_waiting_handshake_count--; - update_available_auth_mechs(conn); - - if (conn->client->connect_notify_callback != NULL && - auth_client_is_connected(conn->client)) { + if (conn->client->connect_notify_callback != NULL) { conn->client->connect_notify_callback(conn->client, TRUE, conn->client->connect_notify_context); } - return TRUE; + return 0; +} + +static int +auth_server_lookup_request(struct auth_server_connection *conn, + const char *id_arg, bool remove, + struct auth_client_request **request_r) +{ + struct auth_client_request *request; + unsigned int id; + + if (id_arg == NULL) { + i_error("BUG: Authentication server input missing ID"); + return -1; + } + id = (unsigned int)strtoul(id_arg, NULL, 10); + + request = hash_table_lookup(conn->requests, POINTER_CAST(id)); + if (request == NULL) { + i_error("BUG: Authentication server sent unknown id %u", id); + return -1; + } + if (remove || auth_client_request_is_aborted(request)) + hash_table_remove(conn->requests, POINTER_CAST(id)); + + *request_r = request; + return 0; +} + +static int +auth_server_input_ok(struct auth_server_connection *conn, + const char *const *args) +{ + struct auth_client_request *request; + + if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0) + return -1; + auth_client_request_server_input(request, AUTH_REQUEST_STATUS_OK, + args + 1); + return 0; } -static bool -auth_client_input_line(struct auth_server_connection *conn, const char *line) +static int auth_server_input_cont(struct auth_server_connection *conn, + const char *const *args) +{ + struct auth_client_request *request; + + if (str_array_length(args) < 2) { + i_error("BUG: Authentication server sent broken CONT line"); + return -1; + } + + if (auth_server_lookup_request(conn, args[0], FALSE, &request) < 0) + return -1; + auth_client_request_server_input(request, AUTH_REQUEST_STATUS_CONTINUE, + args + 1); + return 0; +} + +static int auth_server_input_fail(struct auth_server_connection *conn, + const char *const *args) { - if (strncmp(line, "OK\t", 3) == 0) - return auth_client_input_ok(conn, line + 3); - else if (strncmp(line, "CONT\t", 5) == 0) - return auth_client_input_cont(conn, line + 5); - else if (strncmp(line, "FAIL\t", 5) == 0) - return auth_client_input_fail(conn, line + 5); - else if (strncmp(line, "MECH\t", 5) == 0) - return auth_client_input_mech(conn, line + 5); - else if (strncmp(line, "SPID\t", 5) == 0) - return auth_client_input_spid(conn, line + 5); - else if (strncmp(line, "CUID\t", 5) == 0) - return auth_client_input_cuid(conn, line + 5); - else if (strcmp(line, "DONE") == 0) - return auth_client_input_done(conn); + struct auth_client_request *request; + + if (auth_server_lookup_request(conn, args[0], TRUE, &request) < 0) + return -1; + auth_client_request_server_input(request, AUTH_REQUEST_STATUS_FAIL, + args + 1); + return 0; +} + +static int +auth_server_connection_input_line(struct auth_server_connection *conn, + const char *line) +{ + const char *const *args; + + if (conn->client->debug) + i_info("auth input: %s", line); + + args = t_strsplit(line, "\t"); + if (strcmp(args[0], "OK") == 0) + return auth_server_input_ok(conn, args + 1); + else if (strcmp(args[0], "CONT") == 0) + return auth_server_input_cont(conn, args + 1); + else if (strcmp(args[0], "FAIL") == 0) + return auth_server_input_fail(conn, args + 1); + else if (strcmp(args[0], "MECH") == 0) + return auth_server_input_mech(conn, args + 1); + else if (strcmp(args[0], "SPID") == 0) + return auth_server_input_spid(conn, args + 1); + else if (strcmp(args[0], "CUID") == 0) + return auth_server_input_cuid(conn, args + 1); + else if (strcmp(args[0], "DONE") == 0) + return auth_server_input_done(conn); else { - /* ignore unknown command */ - return TRUE; + i_error("Auth server sent unknown command: %s", args[0]); + return -1; } } -static void auth_client_input(struct auth_server_connection *conn) +static void auth_server_connection_input(struct auth_server_connection *conn) { const char *line; int ret; @@ -162,17 +215,17 @@ return; case -1: /* disconnected */ - auth_server_connection_destroy(&conn, TRUE); + auth_server_connection_disconnect(conn); return; case -2: /* buffer full - can't happen unless auth is buggy */ i_error("BUG: Auth server sent us more than %d bytes of data", - AUTH_CLIENT_MAX_LINE_LENGTH); - auth_server_connection_destroy(&conn, FALSE); + AUTH_SERVER_CONN_MAX_LINE_LENGTH); + auth_server_connection_disconnect(conn); return; } - if (conn->version_received) { + if (!conn->version_received) { line = i_stream_next_line(conn->input); if (line == NULL) return; @@ -183,45 +236,132 @@ AUTH_CLIENT_PROTOCOL_MAJOR_VERSION) { i_error("Authentication server not compatible with " "this client (mixed old and new binaries?)"); - auth_server_connection_destroy(&conn, FALSE); + auth_server_connection_disconnect(conn); return; } conn->version_received = TRUE; } - conn->refcount++; while ((line = i_stream_next_line(conn->input)) != NULL) { T_BEGIN { - ret = auth_client_input_line(conn, line); + ret = auth_server_connection_input_line(conn, line); } T_END; - if (!ret) { - auth_server_connection_destroy(&conn, FALSE); + if (ret < 0) { + auth_server_connection_disconnect(conn); break; } } - auth_server_connection_unref(conn); +} + +struct auth_server_connection * +auth_server_connection_init(struct auth_client *client) +{ + struct auth_server_connection *conn; + pool_t pool; + + pool = pool_alloconly_create("auth server connection", 1024); + conn = p_new(pool, struct auth_server_connection, 1); + conn->pool = pool; + + conn->client = client; + conn->fd = -1; + conn->requests = hash_table_create(default_pool, pool, 100, NULL, NULL); + i_array_init(&conn->available_auth_mechs, 8); + return conn; +} + +static void +auth_server_connection_remove_requests(struct auth_server_connection *conn) +{ + static const char *const temp_failure_args[] = { "temp", NULL }; + struct hash_iterate_context *iter; + void *key, *value; + + iter = hash_table_iterate_init(conn->requests); + while (hash_table_iterate(iter, &key, &value)) { + struct auth_client_request *request = value; + + auth_client_request_server_input(request, + AUTH_REQUEST_STATUS_FAIL, + temp_failure_args); + } + hash_table_iterate_deinit(&iter); +} + +static void auth_server_connection_close(struct auth_server_connection *conn) +{ + if (conn->to != NULL) + timeout_remove(&conn->to); + if (conn->io != NULL) + io_remove(&conn->io); + i_stream_destroy(&conn->input); + o_stream_destroy(&conn->output); + + if (close(conn->fd) < 0) + i_error("close(auth server connection) failed: %m"); + conn->fd = -1; + + auth_server_connection_remove_requests(conn); + + if (conn->client->connect_notify_callback != NULL) { + conn->client->connect_notify_callback(conn->client, FALSE, + conn->client->connect_notify_context); + } +} + +static void auth_server_reconnect_timeout(struct auth_server_connection *conn) +{ + timeout_remove(&conn->to); + (void)auth_server_connection_connect(conn); +} + +static void +auth_server_connection_disconnect(struct auth_server_connection *conn) +{ + time_t next_connect; + + auth_server_connection_close(conn); + + next_connect = conn->last_connect + AUTH_SERVER_RECONNECT_TIMEOUT_SECS; + conn->to = timeout_add(ioloop_time >= next_connect ? 0 : + (next_connect - ioloop_time) * 1000, + auth_server_reconnect_timeout, conn); +} + +void auth_server_connection_deinit(struct auth_server_connection **_conn) +{ + struct auth_server_connection *conn = *_conn; + + *_conn = NULL; + + auth_server_connection_close(conn); + + hash_table_destroy(&conn->requests); + array_free(&conn->available_auth_mechs); + pool_unref(&conn->pool); } static void auth_client_handshake_timeout(struct auth_server_connection *conn) { i_error("Timeout waiting for handshake from auth server. " "my pid=%u, input bytes=%"PRIuUOFF_T, - conn->client->pid, conn->input->v_offset); - auth_server_connection_destroy(&conn, TRUE); + conn->client->client_pid, conn->input->v_offset); + auth_server_connection_disconnect(conn); } -struct auth_server_connection * -auth_server_connection_new(struct auth_client *client, const char *path) +int auth_server_connection_connect(struct auth_server_connection *conn) { - struct auth_server_connection *conn; const char *handshake; - pool_t pool; int fd, try; + i_assert(conn->fd == -1); + + conn->last_connect = ioloop_time; + /* max. 1 second wait here. */ for (try = 0; try < 10; try++) { - fd = net_connect_unix(path); + fd = net_connect_unix(conn->client->auth_socket_path); if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED)) break; @@ -229,161 +369,48 @@ usleep(((rand() % 10) + 1) * 10000); } if (fd == -1) { - i_error("Can't connect to auth server at %s: %m", path); - return NULL; + if (errno == EACCES) { + i_error("auth: %s", + eacces_error_get("connect", + conn->client->auth_socket_path)); + } else { + i_error("auth: connect(%s) failed: %m", + conn->client->auth_socket_path); + } + return -1; } - - /* use blocking connection since we depend on auth server - - if it's slow, just wait */ - - pool = pool_alloconly_create("Auth connection", 1024); - conn = p_new(pool, struct auth_server_connection, 1); - conn->refcount = 1; - conn->pool = pool; - - conn->client = client; - conn->path = p_strdup(pool, path); conn->fd = fd; - conn->io = io_add(fd, IO_READ, auth_client_input, conn); - conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH, + conn->io = io_add(fd, IO_READ, auth_server_connection_input, conn); + conn->input = i_stream_create_fd(fd, AUTH_SERVER_CONN_MAX_LINE_LENGTH, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); - conn->requests = hash_table_create(default_pool, pool, 100, NULL, NULL); - conn->auth_mechs_buf = buffer_create_dynamic(default_pool, 256); - - conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT, - auth_client_handshake_timeout, conn); - conn->next = client->connections; - client->connections = conn; handshake = t_strdup_printf("VERSION\t%u\t%u\nCPID\t%u\n", AUTH_CLIENT_PROTOCOL_MAJOR_VERSION, AUTH_CLIENT_PROTOCOL_MINOR_VERSION, - client->pid); - - client->conn_waiting_handshake_count++; + conn->client->client_pid); if (o_stream_send_str(conn->output, handshake) < 0) { - errno = conn->output->stream_errno; i_warning("Error sending handshake to auth server: %m"); - auth_server_connection_destroy(&conn, TRUE); - return NULL; - } - return conn; -} - -void auth_server_connection_destroy(struct auth_server_connection **_conn, - bool reconnect) -{ - struct auth_server_connection *conn = *_conn; - struct auth_client *client = conn->client; - struct auth_server_connection **pos; - - *_conn = NULL; - - if (conn->fd == -1) - return; - - pos = &conn->client->connections; - for (; *pos != NULL; pos = &(*pos)->next) { - if (*pos == conn) { - *pos = conn->next; - break; - } + auth_server_connection_disconnect(conn); + return -1; } - if (!conn->handshake_received) - client->conn_waiting_handshake_count--; - - if (conn->to != NULL) - timeout_remove(&conn->to); - if (conn->io != NULL) - io_remove(&conn->io); - - i_stream_close(conn->input); - o_stream_close(conn->output); - - if (close(conn->fd) < 0) - i_error("close(auth) failed: %m"); - conn->fd = -1; - - auth_server_requests_remove_all(conn); - auth_server_connection_unref(conn); - - if (reconnect) - auth_client_connect_missing_servers(client); - else if (client->connect_notify_callback != NULL) { - client->connect_notify_callback(client, - auth_client_is_connected(client), - client->connect_notify_context); - } + conn->to = timeout_add(AUTH_HANDSHAKE_TIMEOUT, + auth_client_handshake_timeout, conn); + return 0; } -static void auth_server_connection_unref(struct auth_server_connection *conn) -{ - if (--conn->refcount > 0) - return; - i_assert(conn->refcount == 0); - - hash_table_destroy(&conn->requests); - buffer_free(&conn->auth_mechs_buf); - - i_stream_unref(&conn->input); - o_stream_unref(&conn->output); - pool_unref(&conn->pool); -} - -struct auth_server_connection * -auth_server_connection_find_path(struct auth_client *client, const char *path) +unsigned int +auth_server_connection_add_request(struct auth_server_connection *conn, + struct auth_client_request *request) { - struct auth_server_connection *conn; - - for (conn = client->connections; conn != NULL; conn = conn->next) { - if (strcmp(conn->path, path) == 0) - return conn; - } - - return NULL; -} - -struct auth_server_connection * -auth_server_connection_find_mech(struct auth_client *client, - const char *name, const char **error_r) -{ - struct auth_server_connection *conn, *match; - const struct auth_mech_desc *mech; - unsigned int i, n, match_n; + unsigned int id; - /* find a connection which has this mechanism. if there are multiple - available connections to use, do round robin load balancing */ - match = NULL; match_n = n = 0; - for (conn = client->connections; conn != NULL; conn = conn->next, n++) { - mech = conn->available_auth_mechs; - for (i = 0; i < conn->available_auth_mechs_count; i++) { - if (strcasecmp(mech[i].name, name) == 0) { - if (n > client->last_used_auth_process) { - client->last_used_auth_process = n; - return conn; - } - if (match == NULL) { - match = conn; - match_n = n; - } - break; - } - } + id = ++conn->client->request_id_counter; + if (id == 0) { + /* wrapped - ID 0 not allowed */ + id = ++conn->client->request_id_counter; } - - if (match != NULL) { - client->last_used_auth_process = match_n; - return match; - } - - if (auth_client_find_mech(client, name) == NULL) - *error_r = "Unsupported authentication mechanism"; - else { - *error_r = "Authentication server isn't connected, " - "try again later.."; - } - - return NULL; + hash_table_insert(conn->requests, POINTER_CAST(id), request); + return id; } diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-server-connection.h --- a/src/lib-auth/auth-server-connection.h Wed Oct 07 17:44:38 2009 -0400 +++ b/src/lib-auth/auth-server-connection.h Wed Oct 07 17:46:14 2009 -0400 @@ -1,34 +1,12 @@ #ifndef AUTH_SERVER_CONNECTION_H #define AUTH_SERVER_CONNECTION_H -struct auth_client { - unsigned int pid; - - struct auth_server_connection *connections; - struct timeout *to_reconnect; - - time_t missing_sockets_start_time; - unsigned int conn_waiting_handshake_count; - - buffer_t *available_auth_mechs; - unsigned int request_id_counter; - unsigned int last_used_auth_process; - - auth_connect_notify_callback_t *connect_notify_callback; - void *connect_notify_context; - - unsigned int reconnect:1; -}; - struct auth_server_connection { - struct auth_server_connection *next; - pool_t pool; - int refcount; struct auth_client *client; - const char *path; int fd; + time_t last_connect; struct io *io; struct timeout *to; @@ -38,9 +16,7 @@ unsigned int server_pid; unsigned int connect_uid; - buffer_t *auth_mechs_buf; - const struct auth_mech_desc *available_auth_mechs; - unsigned int available_auth_mechs_count; + ARRAY_DEFINE(available_auth_mechs, struct auth_mech_desc); struct hash_table *requests; @@ -50,15 +26,12 @@ }; struct auth_server_connection * -auth_server_connection_new(struct auth_client *client, const char *path); -void auth_server_connection_destroy(struct auth_server_connection **conn, - bool reconnect); +auth_server_connection_init(struct auth_client *client); +void auth_server_connection_deinit(struct auth_server_connection **conn); + +int auth_server_connection_connect(struct auth_server_connection *conn); -struct auth_server_connection * -auth_server_connection_find_path(struct auth_client *client, const char *path); - -struct auth_server_connection * -auth_server_connection_find_mech(struct auth_client *client, - const char *name, const char **error_r); - +unsigned int +auth_server_connection_add_request(struct auth_server_connection *conn, + struct auth_client_request *request); #endif diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-server-request.c --- a/src/lib-auth/auth-server-request.c Wed Oct 07 17:44:38 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,419 +0,0 @@ -/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "str.h" -#include "hash.h" -#include "ostream.h" -#include "auth-client.h" -#include "auth-server-connection.h" -#include "auth-server-request.h" - -#include - -struct auth_request { - struct auth_server_connection *conn; - - unsigned int id; - - char *mech, *service, *cert_username; - enum auth_request_flags flags; - struct ip_addr local_ip, remote_ip; - unsigned int local_port, remote_port; - - char *initial_resp_base64; - - auth_request_callback_t *callback; - void *context; - - struct auth_server_connection *next_conn; - char *plaintext_data; /* for resending to other servers */ - - unsigned int init_sent:1; - unsigned int retrying:1; -}; - -static int auth_server_send_new_request(struct auth_server_connection *conn, - struct auth_request *request, - const char **error_r); -static void auth_client_request_free(struct auth_request *request); - -static struct auth_server_connection * -get_next_plain_server(struct auth_server_connection *conn) -{ - conn = conn->next; - while (conn != NULL) { - if (conn->has_plain_mech) - return conn; - conn = conn->next; - } - return NULL; -} - -static void -auth_server_request_check_retry(struct auth_request *request, const char *data) -{ - const char *error; - - if (strcmp(request->mech, "PLAIN") == 0 && data != NULL && - request->plaintext_data == NULL && request->conn != NULL) { - request->next_conn = get_next_plain_server(request->conn); - if (request->next_conn != NULL) { - /* plaintext authentication - save the data so we can - try it for the next */ - request->plaintext_data = i_strdup(data); - - hash_table_insert(request->next_conn->requests, - POINTER_CAST(request->id), request); - if (auth_server_send_new_request(request->next_conn, - request, &error) == 0) - request->retrying = TRUE; - } - } -} - -static bool is_valid_string(const char *str) -{ - const char *p; - - /* make sure we're not sending any characters that have a special - meaning. */ - for (p = str; *p != '\0'; p++) { - if (*p == '\t' || *p == '\n' || *p == '\r') - return FALSE; - } - return TRUE; -} - -static int auth_server_send_new_request(struct auth_server_connection *conn, - struct auth_request *request, - const char **error_r) -{ - string_t *str; - - str = t_str_new(512); - - str_printfa(str, "AUTH\t%u\t%s\tservice=%s", - request->id, request->mech, request->service); - if ((request->flags & AUTH_REQUEST_FLAG_SECURED) != 0) - str_append(str, "\tsecured"); - if ((request->flags & AUTH_REQUEST_FLAG_VALID_CLIENT_CERT) != 0) - str_append(str, "\tvalid-client-cert"); - - if (request->cert_username != NULL) { - if (!is_valid_string(request->cert_username)) { - *error_r = "Invalid username in SSL certificate"; - return -1; - } - str_printfa(str, "\tcert_username=%s", request->cert_username); - } - if (request->local_ip.family != 0) - str_printfa(str, "\tlip=%s", net_ip2addr(&request->local_ip)); - if (request->remote_ip.family != 0) - str_printfa(str, "\trip=%s", net_ip2addr(&request->remote_ip)); - if (request->local_port != 0) - str_printfa(str, "\tlport=%u", request->local_port); - if (request->remote_port != 0) - str_printfa(str, "\trport=%u", request->remote_port); - if (request->initial_resp_base64 != NULL) { - /*if (!is_valid_string(request->initial_resp_base64)) { - *error_r = "Invalid base64 data in initial response"; - return -1; - }*/ - str_printfa(str, "\tresp=%s", request->initial_resp_base64); - } - str_append_c(str, '\n'); - - if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) { - errno = conn->output->stream_errno; - i_warning("Error sending request to auth server: %m"); - auth_server_connection_destroy(&conn, TRUE); - return -1; - } - - auth_server_request_check_retry(request, request->initial_resp_base64); - return 0; -} - -static void auth_server_send_continue(struct auth_server_connection *conn, - struct auth_request *request, - const char *data_base64) -{ - struct const_iovec iov[3]; - const char *prefix; - - prefix = t_strdup_printf("CONT\t%u\t", request->id); - - iov[0].iov_base = prefix; - iov[0].iov_len = strlen(prefix); - iov[1].iov_base = data_base64; - iov[1].iov_len = strlen(data_base64); - iov[2].iov_base = "\n"; - iov[2].iov_len = 1; - - if (o_stream_sendv(conn->output, iov, 3) < 0) { - errno = conn->output->stream_errno; - i_warning("Error sending continue request to auth server: %m"); - auth_server_connection_destroy(&conn, TRUE); - } -} - -bool auth_client_input_ok(struct auth_server_connection *conn, const char *args) -{ - const char *const *list, *const *args_list, *data_base64; - struct auth_request *request; - unsigned int id; - - list = t_strsplit(args, "\t"); - if (list[0] == NULL) { - i_error("BUG: Authentication server sent broken OK line"); - return FALSE; - } - - id = (unsigned int)strtoul(list[0], NULL, 10); - - request = hash_table_lookup(conn->requests, POINTER_CAST(id)); - if (request == NULL) { - /* We've already destroyed the request */ - return TRUE; - } - - hash_table_remove(request->conn->requests, POINTER_CAST(id)); - if (request->next_conn != NULL) { - hash_table_remove(request->next_conn->requests, - POINTER_CAST(id)); - } - request->conn = conn; - request->next_conn = NULL; - - data_base64 = NULL; - for (args_list = ++list; *list != NULL; list++) { - if (strncmp(*list, "resp=", 5) == 0) { - data_base64 = *list + 5; - break; - } - } - - request->callback(request, 1, data_base64, args_list, request->context); - auth_client_request_free(request); - return TRUE; -} - -bool auth_client_input_cont(struct auth_server_connection *conn, - const char *args) -{ - struct auth_request *request; - const char *data; - unsigned int id; - - data = strchr(args, '\t'); - if (data == NULL) { - i_error("BUG: Authentication server sent broken CONT line"); - return FALSE; - } - data++; - - id = (unsigned int)strtoul(args, NULL, 10); - - request = hash_table_lookup(conn->requests, POINTER_CAST(id)); - if (request == NULL) { - /* We've already destroyed the request */ - return TRUE; - } - - if (request->retrying) { - auth_server_send_continue(conn, request, - request->plaintext_data); - } else { - request->callback(request, 0, data, NULL, request->context); - } - return TRUE; -} - -bool auth_client_input_fail(struct auth_server_connection *conn, - const char *args) -{ - struct auth_request *request; - struct auth_server_connection *next; - const char *const *list, *error; - unsigned int id; - - list = t_strsplit(args, "\t"); - if (list[0] == NULL) { - i_error("BUG: Authentication server sent broken FAIL line"); - return FALSE; - } - - id = (unsigned int)strtoul(list[0], NULL, 10); - - request = hash_table_lookup(conn->requests, POINTER_CAST(id)); - if (request == NULL) { - /* We've already destroyed the request */ - return TRUE; - } - - hash_table_remove(conn->requests, POINTER_CAST(request->id)); - if (request->retrying) { - next = request->next_conn == NULL ? NULL : - get_next_plain_server(request->next_conn); - - if (conn == request->conn) - request->conn = request->next_conn; - request->next_conn = NULL; - - if (next == NULL) { - if (request->conn != NULL) { - /* the other one hasn't replied yet */ - return TRUE; - } - request->conn = conn; - } else { - hash_table_insert(next->requests, - POINTER_CAST(request->id), request); - request->next_conn = next; - - T_BEGIN { - (void)auth_server_send_new_request(next, - request, - &error); - } T_END; - return TRUE; - } - } - - request->callback(request, -1, NULL, list+1, request->context); - auth_client_request_free(request); - return TRUE; -} - -static void request_hash_remove(struct auth_server_connection *conn, - struct auth_request *request) -{ - static const char *const temp_failure_args[] = { "temp", NULL }; - - if (request->conn == conn) { - if (request->next_conn == NULL) { - request->callback(request, -1, NULL, temp_failure_args, - request->context); - request->conn = NULL; - } else { - request->conn = request->next_conn; - request->next_conn = NULL; - } - } else { - request->next_conn = NULL; - } -} - -void auth_server_requests_remove_all(struct auth_server_connection *conn) -{ - struct hash_iterate_context *iter; - void *key, *value; - - iter = hash_table_iterate_init(conn->requests); - while (hash_table_iterate(iter, &key, &value)) - request_hash_remove(conn, value); - hash_table_iterate_deinit(&iter); -} - -struct auth_request * -auth_client_request_new(struct auth_client *client, struct auth_connect_id *id, - const struct auth_request_info *request_info, - auth_request_callback_t *callback, void *context, - const char **error_r) -{ - struct auth_server_connection *conn; - struct auth_request *request; - - *error_r = "Temporary authentication failure."; - - if (id == NULL) { - conn = auth_server_connection_find_mech(client, - request_info->mech, - error_r); - } else { - *error_r = NULL; - conn = client->connections; - for (; conn != NULL; conn = conn->next) { - if (conn->connect_uid == id->connect_uid && - conn->server_pid == id->server_pid) - break; - } - } - - if (conn == NULL) - return NULL; - - request = i_new(struct auth_request, 1); - request->conn = conn; - request->mech = i_strdup(request_info->mech); - request->service = i_strdup(request_info->service); - request->cert_username = i_strdup(request_info->cert_username); - request->flags = request_info->flags; - request->local_ip = request_info->local_ip; - request->remote_ip = request_info->remote_ip; - request->local_port = request_info->local_port; - request->remote_port = request_info->remote_port; - request->id = ++client->request_id_counter; - - if (request_info->initial_resp_base64 != NULL) { - request->initial_resp_base64 = - i_strdup(request_info->initial_resp_base64); - } - - if (request->id == 0) { - /* wrapped - ID 0 not allowed */ - request->id = ++client->request_id_counter; - } - request->callback = callback; - request->context = context; - - T_BEGIN { - if (auth_server_send_new_request(conn, request, error_r) == 0) { - hash_table_insert(conn->requests, - POINTER_CAST(request->id), request); - } else { - auth_client_request_free(request); - request = NULL; - } - } T_END; - return request; -} - -void auth_client_request_continue(struct auth_request *request, - const char *data_base64) -{ - auth_server_send_continue(request->conn, request, data_base64); - auth_server_request_check_retry(request, data_base64); -} - -static void auth_client_request_free(struct auth_request *request) -{ - i_free(request->initial_resp_base64); - i_free(request->plaintext_data); - i_free(request->mech); - i_free(request->service); - i_free(request->cert_username); - i_free(request); -} - -void auth_client_request_abort(struct auth_request *request) -{ - void *id = POINTER_CAST(request->id); - - hash_table_remove(request->conn->requests, id); - if (request->next_conn != NULL) - hash_table_remove(request->next_conn->requests, id); - - request->callback(request, -1, NULL, NULL, request->context); - auth_client_request_free(request); -} - -unsigned int auth_client_request_get_id(struct auth_request *request) -{ - return request->id; -} - -unsigned int auth_client_request_get_server_pid(struct auth_request *request) -{ - return request->conn->server_pid; -} diff -r 9716b5a4b14a -r 097588a7903c src/lib-auth/auth-server-request.h --- a/src/lib-auth/auth-server-request.h Wed Oct 07 17:44:38 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -#ifndef AUTH_SERVER_REQUEST_H -#define AUTH_SERVER_REQUEST_H - -bool auth_client_input_ok(struct auth_server_connection *conn, - const char *args); -bool auth_client_input_cont(struct auth_server_connection *conn, - const char *args); -bool auth_client_input_fail(struct auth_server_connection *conn, - const char *args); - -void auth_server_requests_remove_all(struct auth_server_connection *conn); - -#endif diff -r 9716b5a4b14a -r 097588a7903c src/login-common/client-common.h --- a/src/login-common/client-common.h Wed Oct 07 17:44:38 2009 -0400 +++ b/src/login-common/client-common.h Wed Oct 07 17:46:14 2009 -0400 @@ -96,7 +96,7 @@ char *proxy_user, *proxy_master_user, *proxy_password; char *auth_mech_name; - struct auth_request *auth_request; + struct auth_client_request *auth_request; string_t *auth_response; unsigned int master_tag; diff -r 9716b5a4b14a -r 097588a7903c src/login-common/main.c --- a/src/login-common/main.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/login-common/main.c Wed Oct 07 17:46:14 2009 -0400 @@ -137,7 +137,7 @@ master_service_set_avail_overflow_callback(master_service, client_destroy_oldest); - auth_client = auth_client_new((unsigned int)getpid()); + auth_client = auth_client_init("auth", (unsigned int)getpid(), FALSE); auth_client_set_connect_notify(auth_client, auth_connect_notify, NULL); clients_init(); @@ -151,7 +151,7 @@ login_proxy_deinit(); if (auth_client != NULL) - auth_client_free(&auth_client); + auth_client_deinit(&auth_client); clients_deinit(); if (anvil_fd != -1) { diff -r 9716b5a4b14a -r 097588a7903c src/login-common/sasl-server.c --- a/src/login-common/sasl-server.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/login-common/sasl-server.c Wed Oct 07 17:46:14 2009 -0400 @@ -98,7 +98,7 @@ } static void -master_send_request(struct client *client, struct auth_request *request) +master_send_request(struct client *client, struct auth_client_request *request) { struct master_auth_request req; const unsigned char *data; @@ -159,9 +159,10 @@ client->set->mail_max_userip_connections; } -static void authenticate_callback(struct auth_request *request, int status, - const char *data_base64, - const char *const *args, void *context) +static void +authenticate_callback(struct auth_client_request *request, + enum auth_request_status status, const char *data_base64, + const char *const *args, void *context) { struct client *client = context; unsigned int i; @@ -175,12 +176,12 @@ i_assert(client->auth_request == request); switch (status) { - case 0: + case AUTH_REQUEST_STATUS_CONTINUE: /* continue */ client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE, data_base64, NULL); break; - case 1: + case AUTH_REQUEST_STATUS_OK: client->auth_request = NULL; nologin = FALSE; @@ -209,7 +210,7 @@ master_send_request(client, request); } break; - case -1: + case AUTH_REQUEST_STATUS_FAIL: client->auth_request = NULL; if (args != NULL) { @@ -237,7 +238,6 @@ { struct auth_request_info info; const struct auth_mech_desc *mech; - const char *error; client->auth_attempts++; client->authenticating = TRUE; @@ -274,12 +274,8 @@ info.initial_resp_base64 = initial_resp_base64; client->auth_request = - auth_client_request_new(auth_client, NULL, &info, - authenticate_callback, client, &error); - if (client->auth_request == NULL) { - sasl_server_auth_failed(client, - t_strconcat("Authentication failed: ", error, NULL)); - } + auth_client_request_new(auth_client, &info, + authenticate_callback, client); } static void sasl_server_auth_cancel(struct client *client, const char *reason, @@ -295,10 +291,8 @@ } client->authenticating = FALSE; - if (client->auth_request != NULL) { - auth_client_request_abort(client->auth_request); - client->auth_request = NULL; - } + if (client->auth_request != NULL) + auth_client_request_abort(&client->auth_request); call_client_callback(client, reply, reason, NULL); } diff -r 9716b5a4b14a -r 097588a7903c src/pop3-login/client-authenticate.c --- a/src/pop3-login/client-authenticate.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/pop3-login/client-authenticate.c Wed Oct 07 17:46:14 2009 -0400 @@ -155,6 +155,7 @@ struct client *client = &pop3_client->common; buffer_t *apop_data, *base64; const char *p; + unsigned int server_pid, connect_uid; if (pop3_client->apop_challenge == NULL) { if (client->set->verbose_auth) @@ -195,6 +196,17 @@ MAX_BASE64_ENCODED_SIZE(apop_data->used)); base64_encode(apop_data->data, apop_data->used, base64); + auth_client_get_connect_id(auth_client, &server_pid, &connect_uid); + if (pop3_client->apop_server_pid != server_pid || + pop3_client->apop_connect_uid != connect_uid) { + /* we reconnected to auth server and can't authenticate + with APOP in this session anymore. disconnecting the user + is probably the best solution now. */ + client_destroy(client, + "Reconnected to auth server, can't do APOP"); + return TRUE; + } + (void)client_auth_begin(client, "APOP", str_c(base64)); return TRUE; } diff -r 9716b5a4b14a -r 097588a7903c src/pop3-login/client.c --- a/src/pop3-login/client.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/pop3-login/client.c Wed Oct 07 17:46:14 2009 -0400 @@ -119,12 +119,11 @@ static char *get_apop_challenge(struct pop3_client *client) { - struct auth_connect_id *id = &client->auth_id; unsigned char buffer[16]; - buffer_t *buf; + buffer_t *buf; - if (!auth_client_reserve_connection(auth_client, "APOP", id)) - return NULL; + auth_client_get_connect_id(auth_client, &client->apop_server_pid, + &client->apop_connect_uid); random_fill(buffer, sizeof(buffer)); buf = buffer_create_static_hard(pool_datastack_create(), @@ -133,7 +132,8 @@ buffer_append_c(buf, '\0'); return i_strdup_printf("<%x.%x.%lx.%s@%s>", - id->server_pid, id->connect_uid, + client->apop_server_pid, + client->apop_connect_uid, (unsigned long)ioloop_time, (const char *)buf->data, my_hostname); } diff -r 9716b5a4b14a -r 097588a7903c src/pop3-login/client.h --- a/src/pop3-login/client.h Wed Oct 07 17:44:38 2009 -0400 +++ b/src/pop3-login/client.h Wed Oct 07 17:46:14 2009 -0400 @@ -19,7 +19,7 @@ char *last_user; char *apop_challenge; - struct auth_connect_id auth_id; + unsigned int apop_server_pid, apop_connect_uid; }; #endif diff -r 9716b5a4b14a -r 097588a7903c src/util/authtest.c --- a/src/util/authtest.c Wed Oct 07 17:44:38 2009 -0400 +++ b/src/util/authtest.c Wed Oct 07 17:46:14 2009 -0400 @@ -68,9 +68,11 @@ return ret == 0 ? 1 : 0; } -static void auth_callback(struct auth_request *request ATTR_UNUSED, int status, - const char *data_base64 ATTR_UNUSED, - const char *const *args, void *context) +static void +auth_callback(struct auth_client_request *request ATTR_UNUSED, + enum auth_request_status status, + const char *data_base64 ATTR_UNUSED, + const char *const *args, void *context) { const struct authtest_input *input = context; @@ -97,10 +99,8 @@ bool connected, void *context) { struct authtest_input *input = context; - struct auth_request *request; struct auth_request_info info; string_t *init_resp, *base64_resp; - const char *error; if (!connected) i_fatal("Couldn't connect to auth socket"); @@ -123,30 +123,25 @@ info.remote_port = input->info.remote_port; info.initial_resp_base64 = str_c(base64_resp); - request = auth_client_request_new(client, NULL, &info, - auth_callback, input, &error); - if (request == NULL) - i_fatal("passdb lookup failed: %s", error); + (void)auth_client_request_new(client, &info, + auth_callback, input); } static int authtest_passdb(struct authtest_input *input) { struct auth_client *client; - struct auth_server_connection *conn; if (auth_socket_path == NULL) auth_socket_path = PKG_RUNDIR"/auth-client"; - client = auth_client_new(getpid()); + client = auth_client_init(auth_socket_path, getpid(), FALSE); auth_client_set_connect_notify(client, auth_connected, input); - conn = auth_server_connection_new(client, auth_socket_path); io_loop_run(current_ioloop); auth_client_set_connect_notify(client, NULL, NULL); - auth_server_connection_destroy(&conn, FALSE); - auth_client_free(&client); + auth_client_deinit(&client); return 0; }