Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1702:43815588dd6b HEAD
Moved client side code for auth process handling to lib-auth. Some other login process cleanups.
line wrap: on
line diff
--- a/configure.in Fri Aug 22 02:31:50 2003 +0300 +++ b/configure.in Fri Aug 22 05:42:12 2003 +0300 @@ -1096,6 +1096,7 @@ doc/Makefile src/Makefile src/lib/Makefile +src/lib-auth/Makefile src/lib-charset/Makefile src/lib-imap/Makefile src/lib-index/Makefile
--- a/src/Makefile.am Fri Aug 22 02:31:50 2003 +0300 +++ b/src/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -2,4 +2,4 @@ POP3D = pop3-login pop3 endif -SUBDIRS = lib lib-settings lib-charset lib-mail lib-imap lib-index lib-storage auth master login-common imap-login imap $(POP3D) util +SUBDIRS = lib lib-settings lib-charset lib-mail lib-imap lib-index lib-storage lib-auth auth master login-common imap-login imap $(POP3D) util
--- a/src/auth/Makefile.am Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -16,13 +16,13 @@ $(MODULE_LIBS) dovecot_auth_SOURCES = \ + auth-client-connection.c \ + auth-master-connection.c \ auth-module.c \ db-ldap.c \ db-pgsql.c \ db-passwd-file.c \ - login-connection.c \ main.c \ - master-connection.c \ md5crypt.c \ mech.c \ mech-anonymous.c \ @@ -48,7 +48,9 @@ userdb-pgsql.c noinst_HEADERS = \ - auth-login-interface.h \ + auth-client-connection.h \ + auth-client-interface.h \ + auth-master-connection.h \ auth-master-interface.h \ auth-mech-desc.h \ auth-module.h \ @@ -56,8 +58,6 @@ db-pgsql.h \ db-passwd-file.h \ common.h \ - login-connection.h \ - master-connection.h \ md5crypt.h \ mech.h \ mycrypt.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-client-connection.c Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,308 @@ +/* Copyright (C) 2002-2003 Timo Sirainen */ + +#include "common.h" +#include "ioloop.h" +#include "istream.h" +#include "ostream.h" +#include "network.h" +#include "hash.h" +#include "safe-memset.h" +#include "mech.h" +#include "auth-client-connection.h" +#include "auth-master-connection.h" + +#include <stdlib.h> +#include <syslog.h> + +#define MAX_INBUF_SIZE \ + (sizeof(struct auth_client_request_continue) + \ + AUTH_CLIENT_MAX_REQUEST_DATA_SIZE) +#define MAX_OUTBUF_SIZE (1024*50) + +static void auth_client_connection_unref(struct auth_client_connection *conn); + +static void request_callback(struct auth_client_request_reply *reply, + const void *data, + struct auth_client_connection *conn) +{ + ssize_t ret; + + ret = o_stream_send(conn->output, reply, sizeof(*reply)); + if ((size_t)ret == sizeof(*reply)) { + if (reply->data_size == 0) { + /* all sent */ + auth_client_connection_unref(conn); + return; + } + + ret = o_stream_send(conn->output, data, reply->data_size); + if ((size_t)ret == reply->data_size) { + /* all sent */ + auth_client_connection_unref(conn); + return; + } + } + + if (ret >= 0) { + i_warning("Auth client %u: Transmit buffer full, killing it", + conn->pid); + } + + auth_client_connection_destroy(conn); + auth_client_connection_unref(conn); +} + +struct auth_client_connection * +auth_client_connection_lookup(struct auth_master_connection *master, + unsigned int pid) +{ + struct auth_client_connection *conn; + + for (conn = master->clients; conn != NULL; conn = conn->next) { + if (conn->pid == pid) + return conn; + } + + return NULL; +} + +static void auth_client_input_handshake(struct auth_client_connection *conn) +{ + struct auth_client_handshake_request rec; + unsigned char *data; + size_t size; + + data = i_stream_get_modifyable_data(conn->input, &size); + if (size < sizeof(rec)) + return; + + /* Don't just cast because of alignment issues. */ + memcpy(&rec, data, sizeof(rec)); + i_stream_skip(conn->input, sizeof(rec)); + + if (rec.client_pid == 0) { + i_error("BUG: Auth client said it's PID 0"); + auth_client_connection_destroy(conn); + } else if (auth_client_connection_lookup(conn->master, + rec.client_pid) != NULL) { + /* well, it might have just reconnected very fast .. although + there's not much reason for it. */ + i_error("BUG: Auth client gave a PID %u of existing connection", + rec.client_pid); + auth_client_connection_destroy(conn); + } else { + conn->pid = rec.client_pid; + } +} + +static void auth_client_input_request(struct auth_client_connection *conn) +{ + enum auth_client_request_type type; + unsigned char *data; + size_t size; + + data = i_stream_get_modifyable_data(conn->input, &size); + if (size < sizeof(type)) + return; + + /* note that we can't directly cast the received data pointer into + structures, as it may not be aligned properly. */ + memcpy(&type, data, sizeof(type)); + + if (type == AUTH_CLIENT_REQUEST_NEW) { + struct auth_client_request_new request; + + if (size < sizeof(request)) + return; + + memcpy(&request, data, sizeof(request)); + i_stream_skip(conn->input, sizeof(request)); + + /* we have a full init request */ + conn->refcount++; + mech_request_new(conn, &request, request_callback); + } else if (type == AUTH_CLIENT_REQUEST_CONTINUE) { + struct auth_client_request_continue request; + + if (size < sizeof(request)) + return; + + memcpy(&request, data, sizeof(request)); + if (size < sizeof(request) + request.data_size) + return; + + i_stream_skip(conn->input, sizeof(request) + request.data_size); + + /* we have a full continued request */ + conn->refcount++; + mech_request_continue(conn, &request, data + sizeof(request), + request_callback); + + /* clear any sensitive data from memory */ + safe_memset(data + sizeof(request), 0, request.data_size); + } else { + /* unknown request */ + i_error("BUG: Auth client %u sent us unknown request %u", + conn->pid, type); + auth_client_connection_destroy(conn); + } +} + +static void auth_client_input(void *context) +{ + struct auth_client_connection *conn = context; + + switch (i_stream_read(conn->input)) { + case 0: + return; + case -1: + /* disconnected */ + auth_client_connection_destroy(conn); + return; + case -2: + /* buffer full */ + i_error("BUG: Auth client %u sent us more than %d bytes", + conn->pid, (int)MAX_INBUF_SIZE); + auth_client_connection_destroy(conn); + return; + } + + if (conn->pid == 0) + auth_client_input_handshake(conn); + else + auth_client_input_request(conn); +} + +struct auth_client_connection * +auth_client_connection_create(struct auth_master_connection *master, int fd) +{ + struct auth_client_connection *conn; + pool_t pool; + + pool = pool_alloconly_create("Auth client", 4096); + conn = p_new(pool, struct auth_client_connection, 1); + conn->pool = pool; + conn->master = master; + conn->refcount = 1; + + conn->fd = fd; + conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE, + FALSE); + conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE, + FALSE); + conn->io = io_add(fd, IO_READ, auth_client_input, conn); + + conn->auth_requests = hash_create(default_pool, conn->pool, + 0, NULL, NULL); + + conn->next = master->clients; + master->clients = conn; + + if (o_stream_send(conn->output, &master->handshake_reply, + sizeof(master->handshake_reply)) < 0) { + auth_client_connection_destroy(conn); + conn = NULL; + } + + return conn; +} + +static void auth_request_hash_destroy(void *key __attr_unused__, void *value, + void *context __attr_unused__) +{ + struct auth_request *auth_request = value; + + auth_request->auth_free(auth_request); +} + +void auth_client_connection_destroy(struct auth_client_connection *conn) +{ + struct auth_client_connection **pos; + + if (conn->fd == -1) + return; + + for (pos = &conn->master->clients; *pos != NULL; pos = &(*pos)->next) { + if (*pos == conn) { + *pos = conn->next; + break; + } + } + + i_stream_close(conn->input); + o_stream_close(conn->output); + + io_remove(conn->io); + conn->io = 0; + + net_disconnect(conn->fd); + conn->fd = -1; + + conn->master = NULL; + auth_client_connection_unref(conn); +} + +static void auth_client_connection_unref(struct auth_client_connection *conn) +{ + if (--conn->refcount > 0) + return; + + hash_foreach(conn->auth_requests, auth_request_hash_destroy, NULL); + hash_destroy(conn->auth_requests); + + i_stream_unref(conn->input); + o_stream_unref(conn->output); + + pool_unref(conn->pool); +} + +static void auth_request_hash_timeout_check(void *key __attr_unused__, + void *value, void *context) +{ + struct auth_client_connection *conn = context; + struct auth_request *auth_request = value; + + if (auth_request->created + AUTH_REQUEST_TIMEOUT < ioloop_time) { + i_warning("Login process has too old (%us) requests, " + "killing it.", + (unsigned int)(ioloop_time - auth_request->created)); + + auth_client_connection_destroy(conn); + hash_foreach_stop(); + } +} + +static void request_timeout(void *context __attr_unused__) +{ + struct auth_master_connection *master = context; + struct auth_client_connection *conn; + + for (conn = master->clients; conn != NULL; conn = conn->next) { + conn->refcount++; + hash_foreach(conn->auth_requests, + auth_request_hash_timeout_check, conn); + auth_client_connection_unref(conn); + } +} + +void auth_client_connections_init(struct auth_master_connection *master) +{ + master->handshake_reply.server_pid = master->pid; + master->handshake_reply.auth_mechanisms = auth_mechanisms; + + master->to_clients = timeout_add(5000, request_timeout, master); +} + +void auth_client_connections_deinit(struct auth_master_connection *master) +{ + struct auth_client_connection *next; + + while (master->clients != NULL) { + next = master->clients->next; + auth_client_connection_destroy(master->clients); + master->clients = next; + } + + timeout_remove(master->to_clients); + master->to_clients = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-client-connection.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,34 @@ +#ifndef __AUTH_CLIENT_CONNECTION_H +#define __AUTH_CLIENT_CONNECTION_H + +#include "auth-client-interface.h" + +struct auth_client_connection { + struct auth_client_connection *next; + + struct auth_master_connection *master; + int refcount; + + int fd; + struct io *io; + struct istream *input; + struct ostream *output; + + pool_t pool; + struct hash_table *auth_requests; + + unsigned int pid; +}; + +struct auth_client_connection * +auth_client_connection_create(struct auth_master_connection *master, int fd); +void auth_client_connection_destroy(struct auth_client_connection *conn); + +struct auth_client_connection * +auth_client_connection_lookup(struct auth_master_connection *master, + unsigned int pid); + +void auth_client_connections_init(struct auth_master_connection *master); +void auth_client_connections_deinit(struct auth_master_connection *master); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-client-interface.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,79 @@ +#ifndef __AUTH_CLIENT_INTERFACE_H +#define __AUTH_CLIENT_INTERFACE_H + +/* max. size for auth_client_request_continue.data[] */ +#define AUTH_CLIENT_MAX_REQUEST_DATA_SIZE 4096 + +/* Client process must finish with single authentication requests in this time, + or the whole connection will be killed. */ +#define AUTH_REQUEST_TIMEOUT 120 + +enum auth_mech { + AUTH_MECH_PLAIN = 0x01, + AUTH_MECH_DIGEST_MD5 = 0x02, + AUTH_MECH_ANONYMOUS = 0x04, + + AUTH_MECH_COUNT +}; + +enum auth_protocol { + AUTH_PROTOCOL_IMAP = 0x01, + AUTH_PROTOCOL_POP3 = 0x02 +}; + +enum auth_client_request_type { + AUTH_CLIENT_REQUEST_NEW = 1, + AUTH_CLIENT_REQUEST_CONTINUE +}; + +enum auth_client_result { + AUTH_CLIENT_RESULT_CONTINUE = 1, + AUTH_CLIENT_RESULT_SUCCESS, + AUTH_CLIENT_RESULT_FAILURE +}; + +/* Client -> Server */ +struct auth_client_handshake_request { + unsigned int client_pid; /* unique identifier for client process */ +}; + +/* Server -> Client */ +struct auth_client_handshake_reply { + unsigned int server_pid; /* unique auth process identifier */ + enum auth_mech auth_mechanisms; /* valid authentication mechanisms */ +}; + +/* New authentication request */ +struct auth_client_request_new { + enum auth_client_request_type type; /* AUTH_CLIENT_REQUEST_NEW */ + unsigned int id; /* unique ID for the request */ + + enum auth_mech mech; + enum auth_protocol protocol; +}; + +/* Continue authentication request */ +struct auth_client_request_continue { + enum auth_client_request_type type; /* AUTH_CLIENT_REQUEST_CONTINUE */ + unsigned int id; + + size_t data_size; + /* unsigned char data[]; */ +}; + +/* Reply to authentication */ +struct auth_client_request_reply { + unsigned int id; + + enum auth_client_result result; + + /* variable width data, indexes into data[]. + Ignore if it points outside data_size. */ + size_t username_idx; /* NUL-terminated */ + size_t reply_idx; /* last, non-NUL terminated */ + + size_t data_size; + /* unsigned char data[]; */ +}; + +#endif
--- a/src/auth/auth-login-interface.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -#ifndef __AUTH_LOGIN_INTERFACE_H -#define __AUTH_LOGIN_INTERFACE_H - -/* max. size for auth_login_request_continue.data[] */ -#define AUTH_LOGIN_MAX_REQUEST_DATA_SIZE 4096 - -/* Login process must finish with single authentication requests in this time, - or the whole connection will be killed. */ -#define AUTH_REQUEST_TIMEOUT 120 - -enum auth_mech { - AUTH_MECH_PLAIN = 0x01, - AUTH_MECH_DIGEST_MD5 = 0x02, - AUTH_MECH_ANONYMOUS = 0x04, - - AUTH_MECH_COUNT -}; - -enum auth_protocol { - AUTH_PROTOCOL_IMAP = 0x01, - AUTH_PROTOCOL_POP3 = 0x02 -}; - -enum auth_login_request_type { - AUTH_LOGIN_REQUEST_NEW = 1, - AUTH_LOGIN_REQUEST_CONTINUE -}; - -enum auth_login_result { - AUTH_LOGIN_RESULT_CONTINUE = 1, - AUTH_LOGIN_RESULT_SUCCESS, - AUTH_LOGIN_RESULT_FAILURE -}; - -/* Incoming handshake */ -struct auth_login_handshake_input { - unsigned int pid; /* unique identifier for client process */ -}; - -/* Outgoing handshake */ -struct auth_login_handshake_output { - unsigned int pid; /* unique auth process identifier */ - enum auth_mech auth_mechanisms; /* valid authentication mechanisms */ -}; - -/* New authentication request */ -struct auth_login_request_new { - enum auth_login_request_type type; /* AUTH_LOGIN_REQUEST_NEW */ - unsigned int id; /* unique ID for the request */ - - enum auth_mech mech; - enum auth_protocol protocol; -}; - -/* Continue authentication request */ -struct auth_login_request_continue { - enum auth_login_request_type type; /* AUTH_LOGIN_REQUEST_CONTINUE */ - unsigned int id; - - size_t data_size; - /* unsigned char data[]; */ -}; - -/* Reply to authentication */ -struct auth_login_reply { - unsigned int id; - - enum auth_login_result result; - - /* variable width data, indexes into data[]. - Ignore if it points outside data_size. */ - size_t username_idx; /* NUL-terminated */ - size_t reply_idx; /* last, non-NUL terminated */ - - size_t data_size; - /* unsigned char data[]; */ -}; - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-master-connection.c Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,224 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "buffer.h" +#include "hash.h" +#include "ioloop.h" +#include "ostream.h" +#include "network.h" +#include "mech.h" +#include "userdb.h" +#include "auth-client-connection.h" +#include "auth-master-connection.h" + +#define MAX_OUTBUF_SIZE (1024*50) + +static struct auth_master_reply failure_reply = +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +struct master_userdb_request { + struct auth_master_connection *conn; + unsigned int tag; +}; + +static int auth_master_connection_unref(struct auth_master_connection *conn); + +static size_t reply_add(buffer_t *buf, const char *str) +{ + size_t index; + + if (str == NULL || *str == '\0') + return (size_t)-1; + + index = buffer_get_used_size(buf) - sizeof(struct auth_master_reply); + buffer_append(buf, str, strlen(str)+1); + return index; +} + +static struct auth_master_reply * +fill_reply(const struct user_data *user, size_t *reply_size) +{ + struct auth_master_reply reply, *reply_p; + buffer_t *buf; + char *p; + + buf = buffer_create_dynamic(data_stack_pool, + sizeof(reply) + 256, (size_t)-1); + memset(&reply, 0, sizeof(reply)); + buffer_append(buf, &reply, sizeof(reply)); + + reply.success = TRUE; + + reply.uid = user->uid; + reply.gid = user->gid; + + reply.system_user_idx = reply_add(buf, user->system_user); + reply.virtual_user_idx = reply_add(buf, user->virtual_user); + reply.mail_idx = reply_add(buf, user->mail); + + p = user->home != NULL ? strstr(user->home, "/./") : NULL; + if (p == NULL) { + reply.home_idx = reply_add(buf, user->home); + reply.chroot_idx = reply_add(buf, NULL); + } else { + /* wu-ftpd like <chroot>/./<home> */ + reply.chroot_idx = + reply_add(buf, t_strdup_until(user->home, p)); + reply.home_idx = reply_add(buf, p + 3); + } + + *reply_size = buffer_get_used_size(buf); + reply.data_size = *reply_size - sizeof(reply); + + reply_p = buffer_get_space_unsafe(buf, 0, sizeof(reply)); + *reply_p = reply; + + return reply_p; +} + +static void master_send_reply(struct auth_master_connection *conn, + struct auth_master_reply *reply, + size_t reply_size, unsigned int tag) +{ + ssize_t ret; + + reply->tag = tag; + for (;;) { + ret = o_stream_send(conn->output, reply, reply_size); + if (ret < 0) { + /* master died, kill ourself too */ + io_loop_stop(ioloop); + break; + } + + if ((size_t)ret == reply_size) + break; + + /* buffer full, we have to block */ + i_warning("Master transmit buffer full, blocking.."); + if (o_stream_flush(conn->output) < 0) { + /* transmit error, probably master died */ + io_loop_stop(ioloop); + break; + } + } +} + +static void userdb_callback(struct user_data *user, void *context) +{ + struct master_userdb_request *master_request = context; + struct auth_master_reply *reply; + size_t reply_size; + + if (auth_master_connection_unref(master_request->conn)) { + if (user == NULL) { + master_send_reply(master_request->conn, &failure_reply, + sizeof(failure_reply), + master_request->tag); + } else { + reply = fill_reply(user, &reply_size); + master_send_reply(master_request->conn, reply, + reply_size, master_request->tag); + } + } + i_free(master_request); +} + +static void master_handle_request(struct auth_master_connection *conn, + struct auth_master_request *request) +{ + struct auth_client_connection *client_conn; + struct auth_request *auth_request; + struct master_userdb_request *master_request; + + client_conn = auth_client_connection_lookup(conn, request->client_pid); + auth_request = client_conn == NULL ? NULL : + hash_lookup(client_conn->auth_requests, + POINTER_CAST(request->id)); + + if (auth_request == NULL) { + if (verbose) { + i_info("Master request %u.%u not found", + request->client_pid, request->id); + } + master_send_reply(conn, &failure_reply, sizeof(failure_reply), + request->tag); + } else { + /* the auth request is finished, we don't need it anymore */ + mech_request_free(client_conn, auth_request, request->id); + + master_request = i_new(struct master_userdb_request, 1); + master_request->conn = conn; + master_request->tag = request->tag; + + conn->refcount++; + userdb->lookup(auth_request->user, userdb_callback, + master_request); + } +} + +static void master_input(void *context) +{ + struct auth_master_connection *conn = context; + int ret; + + ret = net_receive(conn->fd, + conn->request_buf + conn->request_pos, + sizeof(conn->request_buf) - conn->request_pos); + if (ret < 0) { + /* master died, kill ourself too */ + io_loop_stop(ioloop); + return; + } + + conn->request_pos += ret; + if (conn->request_pos >= sizeof(conn->request_buf)) { + /* reply is now read */ + master_handle_request(conn, (struct auth_master_request *) + conn->request_buf); + conn->request_pos = 0; + } +} + +struct auth_master_connection * +auth_master_connection_new(int fd, unsigned int pid) +{ + struct auth_master_connection *conn; + + conn = i_new(struct auth_master_connection, 1); + conn->refcount = 1; + conn->pid = pid; + conn->fd = fd; + conn->output = o_stream_create_file(MASTER_SOCKET_FD, default_pool, + MAX_OUTBUF_SIZE, FALSE); + conn->io = io_add(MASTER_SOCKET_FD, IO_READ, master_input, conn); + + /* just a note to master that we're ok. if we die before, + master should shutdown itself. */ + o_stream_send(conn->output, "O", 1); + return conn; +} + +void auth_master_connection_free(struct auth_master_connection *conn) +{ + if (conn->fd == -1) + return; + + conn->fd = -1; + o_stream_close(conn->output); + + io_remove(conn->io); + conn->io = NULL; + + auth_master_connection_unref(conn); +} + +static int auth_master_connection_unref(struct auth_master_connection *conn) +{ + if (--conn->refcount > 0) + return TRUE; + + o_stream_unref(conn->output); + i_free(conn); + return FALSE; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/auth-master-connection.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,26 @@ +#ifndef __AUTH_MASTER_CONNECTION_H +#define __AUTH_MASTER_CONNECTION_H + +#include "auth-master-interface.h" + +struct auth_master_connection { + unsigned int pid; + int refcount; + + int fd; + struct ostream *output; + struct io *io; + + unsigned int request_pos; + unsigned char request_buf[sizeof(struct auth_master_request)]; + + struct auth_client_handshake_reply handshake_reply; + struct auth_client_connection *clients; + struct timeout *to_clients; +}; + +struct auth_master_connection * +auth_master_connection_new(int fd, unsigned int pid); +void auth_master_connection_free(struct auth_master_connection *conn); + +#endif
--- a/src/auth/auth-master-interface.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/auth-master-interface.h Fri Aug 22 05:42:12 2003 +0300 @@ -7,7 +7,7 @@ unsigned int tag; unsigned int id; - unsigned int login_pid; + unsigned int client_pid; }; struct auth_master_reply {
--- a/src/auth/login-connection.c Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,318 +0,0 @@ -/* Copyright (C) 2002 Timo Sirainen */ - -#include "common.h" -#include "ioloop.h" -#include "istream.h" -#include "ostream.h" -#include "network.h" -#include "hash.h" -#include "safe-memset.h" -#include "mech.h" -#include "login-connection.h" - -#include <stdlib.h> -#include <syslog.h> - -#define MAX_INBUF_SIZE \ - (sizeof(struct auth_login_request_continue) + \ - AUTH_LOGIN_MAX_REQUEST_DATA_SIZE) -#define MAX_OUTBUF_SIZE (1024*50) - -static struct timeout *to; -static struct auth_login_handshake_output handshake_output; -static struct login_connection *connections; - -static void login_connection_unref(struct login_connection *conn); - -static void request_callback(struct auth_login_reply *reply, - const void *data, struct login_connection *conn) -{ - ssize_t ret; - - ret = o_stream_send(conn->output, reply, sizeof(*reply)); - if ((size_t)ret == sizeof(*reply)) { - if (reply->data_size == 0) { - /* all sent */ - login_connection_unref(conn); - return; - } - - ret = o_stream_send(conn->output, data, reply->data_size); - if ((size_t)ret == reply->data_size) { - /* all sent */ - login_connection_unref(conn); - return; - } - } - - if (ret >= 0) - i_warning("Transmit buffer full for login process, killing it"); - - login_connection_destroy(conn); - login_connection_unref(conn); -} - -struct login_connection *login_connection_lookup(unsigned int pid) -{ - struct login_connection *conn; - - for (conn = connections; conn != NULL; conn = conn->next) { - if (conn->pid == pid) - return conn; - } - - return NULL; -} - -static void login_input_handshake(struct login_connection *conn) -{ - struct auth_login_handshake_input rec; - unsigned char *data; - size_t size; - - data = i_stream_get_modifyable_data(conn->input, &size); - if (size < sizeof(struct auth_login_handshake_input)) - return; - - /* Don't just cast because of alignment issues. */ - memcpy(&rec, data, sizeof(rec)); - i_stream_skip(conn->input, sizeof(rec)); - - if (rec.pid == 0) { - i_error("BUG: login said it's PID 0"); - login_connection_destroy(conn); - } else if (login_connection_lookup(rec.pid) != NULL) { - /* well, it might have just reconnected very fast .. although - there's not much reason for it. */ - i_error("BUG: login gave a PID of existing connection"); - login_connection_destroy(conn); - } else { - conn->pid = rec.pid; - if (verbose_debug) { - i_info("Login process %d sent handshake: PID %s", - conn->fd, dec2str(conn->pid)); - } - } -} - -static void login_input_request(struct login_connection *conn) -{ - enum auth_login_request_type type; - unsigned char *data; - size_t size; - - data = i_stream_get_modifyable_data(conn->input, &size); - if (size < sizeof(type)) - return; - - /* note that we can't directly cast the received data pointer into - structures, as it may not be aligned properly. */ - memcpy(&type, data, sizeof(type)); - - if (type == AUTH_LOGIN_REQUEST_NEW) { - struct auth_login_request_new request; - - if (size < sizeof(request)) - return; - - memcpy(&request, data, sizeof(request)); - i_stream_skip(conn->input, sizeof(request)); - - /* we have a full init request */ - conn->refcount++; - mech_request_new(conn, &request, request_callback); - } else if (type == AUTH_LOGIN_REQUEST_CONTINUE) { - struct auth_login_request_continue request; - - if (size < sizeof(request)) - return; - - memcpy(&request, data, sizeof(request)); - if (size < sizeof(request) + request.data_size) - return; - - i_stream_skip(conn->input, sizeof(request) + request.data_size); - - /* we have a full continued request */ - conn->refcount++; - mech_request_continue(conn, &request, data + sizeof(request), - request_callback); - - /* clear any sensitive data from memory */ - safe_memset(data + sizeof(request), 0, request.data_size); - } else { - /* unknown request */ - i_error("BUG: login sent us unknown request %u", type); - login_connection_destroy(conn); - } -} - -static void login_input(void *context) -{ - struct login_connection *conn = context; - - switch (i_stream_read(conn->input)) { - case 0: - return; - case -1: - /* disconnected */ - login_connection_destroy(conn); - return; - case -2: - /* buffer full */ - i_error("BUG: login sent us more than %d bytes of data", - (int)MAX_INBUF_SIZE); - login_connection_destroy(conn); - return; - } - - if (conn->pid == 0) - login_input_handshake(conn); - else - login_input_request(conn); -} - -struct login_connection *login_connection_create(int fd) -{ - struct login_connection *conn; - - if (verbose_debug) - i_info("Login process %d connected", fd); - - conn = i_new(struct login_connection, 1); - conn->refcount = 1; - - conn->fd = fd; - conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE, - FALSE); - conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE, - FALSE); - conn->io = io_add(fd, IO_READ, login_input, conn); - - conn->pool = pool_alloconly_create("auth_request hash", 10240); - conn->auth_requests = hash_create(default_pool, conn->pool, - 0, NULL, NULL); - - conn->next = connections; - connections = conn; - - if (o_stream_send(conn->output, &handshake_output, - sizeof(handshake_output)) < 0) { - login_connection_destroy(conn); - conn = NULL; - } - - return conn; -} - -static void auth_request_hash_destroy(void *key __attr_unused__, void *value, - void *context __attr_unused__) -{ - struct auth_request *auth_request = value; - - auth_request->auth_free(auth_request); -} - -void login_connection_destroy(struct login_connection *conn) -{ - struct login_connection **pos; - - if (conn->fd == -1) - return; - - if (verbose_debug) - i_info("Login process %d disconnected", conn->fd); - - for (pos = &connections; *pos != NULL; pos = &(*pos)->next) { - if (*pos == conn) { - *pos = conn->next; - break; - } - } - - i_stream_close(conn->input); - o_stream_close(conn->output); - - io_remove(conn->io); - net_disconnect(conn->fd); - conn->fd = -1; - - login_connection_unref(conn); -} - -static void login_connection_unref(struct login_connection *conn) -{ - if (--conn->refcount > 0) - return; - - hash_foreach(conn->auth_requests, auth_request_hash_destroy, NULL); - hash_destroy(conn->auth_requests); - - i_stream_unref(conn->input); - o_stream_unref(conn->output); - - pool_unref(conn->pool); - i_free(conn); -} - -static void auth_request_hash_timeout_check(void *key __attr_unused__, - void *value, void *context) -{ - struct login_connection *conn = context; - struct auth_request *auth_request = value; - - if (auth_request->created + AUTH_REQUEST_TIMEOUT < ioloop_time) { - i_warning("Login process has too old (%us) requests, " - "killing it.", - (unsigned int)(ioloop_time - auth_request->created)); - - login_connection_destroy(conn); - hash_foreach_stop(); - } -} - -static void request_timeout(void *context __attr_unused__) -{ - struct login_connection *conn; - - for (conn = connections; conn != NULL; conn = conn->next) { - conn->refcount++; - hash_foreach(conn->auth_requests, - auth_request_hash_timeout_check, conn); - login_connection_unref(conn); - } -} - -void login_connections_init(void) -{ - const char *env; - unsigned int pid; - - env = getenv("AUTH_PROCESS"); - if (env == NULL) - i_fatal("AUTH_PROCESS environment is unset"); - - pid = atoi(env); - if (pid == 0) - i_fatal("AUTH_PROCESS can't be 0"); - - memset(&handshake_output, 0, sizeof(handshake_output)); - handshake_output.pid = pid; - handshake_output.auth_mechanisms = auth_mechanisms; - - connections = NULL; - to = timeout_add(5000, request_timeout, NULL); -} - -void login_connections_deinit(void) -{ - struct login_connection *next; - - while (connections != NULL) { - next = connections->next; - login_connection_destroy(connections); - connections = next; - } - - timeout_remove(to); -}
--- a/src/auth/login-connection.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -#ifndef __LOGIN_CONNECTION_H -#define __LOGIN_CONNECTION_H - -#include "auth-login-interface.h" - -struct login_connection { - struct login_connection *next; - int refcount; - - int fd; - struct io *io; - struct istream *input; - struct ostream *output; - - pool_t pool; - struct hash_table *auth_requests; - - unsigned int pid; -}; - -struct login_connection *login_connection_create(int fd); -void login_connection_destroy(struct login_connection *conn); - -struct login_connection *login_connection_lookup(unsigned int pid); - -void login_connections_init(void); -void login_connections_deinit(void); - -#endif
--- a/src/auth/main.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/main.c Fri Aug 22 05:42:12 2003 +0300 @@ -10,8 +10,8 @@ #include "mech.h" #include "userdb.h" #include "passdb.h" -#include "master-connection.h" -#include "login-connection.h" +#include "auth-master-connection.h" +#include "auth-client-connection.h" #include <stdlib.h> #include <syslog.h> @@ -19,6 +19,7 @@ struct ioloop *ioloop; int verbose = FALSE, verbose_debug = FALSE; +static struct auth_master_connection *master; static struct io *io_listen; static void sig_quit(int signo __attr_unused__) @@ -36,7 +37,7 @@ i_fatal("accept() failed: %m"); } else { net_set_nonblock(fd, TRUE); - (void)login_connection_create(fd); + (void)auth_client_connection_create(master, fd); } } @@ -69,21 +70,31 @@ static void main_init(void) { + const char *env; + unsigned int pid; + lib_init_signals(sig_quit); verbose = getenv("VERBOSE") != NULL; verbose_debug = getenv("VERBOSE_DEBUG") != NULL; + env = getenv("AUTH_PROCESS"); + if (env == NULL) + i_fatal("AUTH_PROCESS environment is unset"); + + pid = atoi(env); + if (pid == 0) + i_fatal("AUTH_PROCESS can't be 0"); + mech_init(); userdb_init(); passdb_init(); - login_connections_init(); - io_listen = io_add(LOGIN_LISTEN_FD, IO_READ, auth_accept, NULL); /* initialize master last - it sends the "we're ok" notification */ - master_connection_init(); + master = auth_master_connection_new(MASTER_SOCKET_FD, pid); + auth_client_connections_init(master); } static void main_deinit(void) @@ -93,13 +104,13 @@ io_remove(io_listen); - login_connections_deinit(); + auth_client_connections_deinit(master); passdb_deinit(); userdb_deinit(); mech_deinit(); - master_connection_deinit(); + auth_master_connection_free(master); random_deinit(); closelog();
--- a/src/auth/master-connection.c Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* Copyright (C) 2002 Timo Sirainen */ - -#include "common.h" -#include "buffer.h" -#include "hash.h" -#include "ioloop.h" -#include "ostream.h" -#include "network.h" -#include "mech.h" -#include "userdb.h" -#include "login-connection.h" -#include "master-connection.h" -#include "auth-master-interface.h" - -#define MAX_OUTBUF_SIZE (1024*50) - -static struct auth_master_reply failure_reply; - -static struct ostream *output; -static struct io *io_master; - -static unsigned int master_pos; -static char master_buf[sizeof(struct auth_master_request)]; - -static size_t reply_add(buffer_t *buf, const char *str) -{ - size_t index; - - if (str == NULL || *str == '\0') - return (size_t)-1; - - index = buffer_get_used_size(buf) - sizeof(struct auth_master_reply); - buffer_append(buf, str, strlen(str)+1); - return index; -} - -static struct auth_master_reply * -fill_reply(const struct user_data *user, size_t *reply_size) -{ - struct auth_master_reply reply, *reply_p; - buffer_t *buf; - char *p; - - buf = buffer_create_dynamic(data_stack_pool, - sizeof(reply) + 256, (size_t)-1); - memset(&reply, 0, sizeof(reply)); - buffer_append(buf, &reply, sizeof(reply)); - - reply.success = TRUE; - - reply.uid = user->uid; - reply.gid = user->gid; - - reply.system_user_idx = reply_add(buf, user->system_user); - reply.virtual_user_idx = reply_add(buf, user->virtual_user); - reply.mail_idx = reply_add(buf, user->mail); - - p = user->home != NULL ? strstr(user->home, "/./") : NULL; - if (p == NULL) { - reply.home_idx = reply_add(buf, user->home); - reply.chroot_idx = reply_add(buf, NULL); - } else { - /* wu-ftpd like <chroot>/./<home> */ - reply.chroot_idx = - reply_add(buf, t_strdup_until(user->home, p)); - reply.home_idx = reply_add(buf, p + 3); - } - - *reply_size = buffer_get_used_size(buf); - reply.data_size = *reply_size - sizeof(reply); - - reply_p = buffer_get_space_unsafe(buf, 0, sizeof(reply)); - *reply_p = reply; - - return reply_p; -} - -static void send_reply(struct auth_master_reply *reply, size_t reply_size, - unsigned int tag) -{ - ssize_t ret; - - reply->tag = tag; - for (;;) { - ret = o_stream_send(output, reply, reply_size); - if (ret < 0) { - /* master died, kill ourself too */ - io_loop_stop(ioloop); - break; - } - - if ((size_t)ret == reply_size) - break; - - /* buffer full, we have to block */ - i_warning("Master transmit buffer full, blocking.."); - if (o_stream_flush(output) < 0) { - /* transmit error, probably master died */ - io_loop_stop(ioloop); - break; - } - } -} - -static void userdb_callback(struct user_data *user, void *context) -{ - unsigned int tag = POINTER_CAST_TO(context, unsigned int); - struct auth_master_reply *reply; - size_t reply_size; - - if (user == NULL) - send_reply(&failure_reply, sizeof(failure_reply), tag); - else { - reply = fill_reply(user, &reply_size); - send_reply(reply, reply_size, tag); - } -} - -static void master_handle_request(struct auth_master_request *request) -{ - struct login_connection *login_conn; - struct auth_request *auth_request; - - login_conn = login_connection_lookup(request->login_pid); - auth_request = login_conn == NULL ? NULL : - hash_lookup(login_conn->auth_requests, - POINTER_CAST(request->id)); - - if (auth_request == NULL) { - if (verbose) { - i_info("Master request %u.%u not found", - request->login_pid, request->id); - } - send_reply(&failure_reply, sizeof(failure_reply), request->tag); - } else { - userdb->lookup(auth_request->user, userdb_callback, - POINTER_CAST(request->tag)); - mech_request_free(login_conn, auth_request, request->id); - } -} - -static void master_input(void *context __attr_unused__) -{ - int ret; - - ret = net_receive(MASTER_SOCKET_FD, master_buf + master_pos, - sizeof(master_buf) - master_pos); - if (ret < 0) { - /* master died, kill ourself too */ - io_loop_stop(ioloop); - return; - } - - master_pos += ret; - if (master_pos < sizeof(master_buf)) - return; - - /* reply is now read */ - master_handle_request((struct auth_master_request *) master_buf); - master_pos = 0; -} - -void master_connection_init(void) -{ - memset(&failure_reply, 0, sizeof(failure_reply)); - - master_pos = 0; - output = o_stream_create_file(MASTER_SOCKET_FD, default_pool, - MAX_OUTBUF_SIZE, FALSE); - io_master = io_add(MASTER_SOCKET_FD, IO_READ, master_input, NULL); - - /* just a note to master that we're ok. if we die before, - master should shutdown itself. */ - o_stream_send(output, "O", 1); -} - -void master_connection_deinit(void) -{ - o_stream_unref(output); - io_remove(io_master); -}
--- a/src/auth/master-connection.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -#ifndef __MASTER_CONNECTION_H -#define __MASTER_CONNECTION_H - -void master_connection_init(void); -void master_connection_deinit(void); - -#endif
--- a/src/auth/mech-anonymous.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/mech-anonymous.c Fri Aug 22 05:42:12 2003 +0300 @@ -5,7 +5,7 @@ static int mech_anonymous_auth_continue(struct auth_request *auth_request, - struct auth_login_request_continue *request, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback) { @@ -29,11 +29,11 @@ } static struct auth_request * -mech_anonymous_auth_new(struct login_connection *conn, unsigned int id, +mech_anonymous_auth_new(struct auth_client_connection *conn, unsigned int id, mech_callback_t *callback) { struct auth_request *auth_request; - struct auth_login_reply reply; + struct auth_client_request_reply reply; pool_t pool; pool = pool_alloconly_create("anonymous_auth_request", 256); @@ -45,7 +45,7 @@ /* initialize reply */ memset(&reply, 0, sizeof(reply)); reply.id = id; - reply.result = AUTH_LOGIN_RESULT_CONTINUE; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; callback(&reply, NULL, conn); return auth_request;
--- a/src/auth/mech-digest-md5.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/mech-digest-md5.c Fri Aug 22 05:42:12 2003 +0300 @@ -526,15 +526,15 @@ { struct digest_auth_request *auth = (struct digest_auth_request *) request; - struct auth_login_reply reply; + struct auth_client_request_reply reply; - mech_init_login_reply(&reply); + mech_init_auth_client_reply(&reply); reply.id = request->id; if (!verify_credentials(auth, result)) - reply.result = AUTH_LOGIN_RESULT_FAILURE; + reply.result = AUTH_CLIENT_RESULT_FAILURE; else { - reply.result = AUTH_LOGIN_RESULT_CONTINUE; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; reply.data_size = strlen(auth->rspauth); auth->authenticated = TRUE; } @@ -544,17 +544,17 @@ static int mech_digest_md5_auth_continue(struct auth_request *auth_request, - struct auth_login_request_continue *request, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback) { struct digest_auth_request *auth = (struct digest_auth_request *)auth_request; - struct auth_login_reply reply; + struct auth_client_request_reply reply; const char *error, *realm; /* initialize reply */ - mech_init_login_reply(&reply); + mech_init_auth_client_reply(&reply); reply.id = request->id; if (auth->authenticated) { @@ -596,7 +596,7 @@ } /* failed */ - reply.result = AUTH_LOGIN_RESULT_FAILURE; + reply.result = AUTH_CLIENT_RESULT_FAILURE; reply.data_size = strlen(error)+1; callback(&reply, error, auth_request->conn); return FALSE; @@ -608,10 +608,10 @@ } static struct auth_request * -mech_digest_md5_auth_new(struct login_connection *conn, +mech_digest_md5_auth_new(struct auth_client_connection *conn, unsigned int id, mech_callback_t *callback) { - struct auth_login_reply reply; + struct auth_client_request_reply reply; struct digest_auth_request *auth; pool_t pool; string_t *challenge; @@ -626,9 +626,9 @@ auth->qop = QOP_AUTH; /* initialize reply */ - mech_init_login_reply(&reply); + mech_init_auth_client_reply(&reply); reply.id = id; - reply.result = AUTH_LOGIN_RESULT_CONTINUE; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; /* send the initial challenge */ reply.reply_idx = 0;
--- a/src/auth/mech-plain.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/mech-plain.c Fri Aug 22 05:42:12 2003 +0300 @@ -13,7 +13,7 @@ static int mech_plain_auth_continue(struct auth_request *auth_request, - struct auth_login_request_continue *request, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback) { const char *authid, *authenid; @@ -82,11 +82,11 @@ } static struct auth_request * -mech_plain_auth_new(struct login_connection *conn, unsigned int id, +mech_plain_auth_new(struct auth_client_connection *conn, unsigned int id, mech_callback_t *callback) { struct auth_request *auth_request; - struct auth_login_reply reply; + struct auth_client_request_reply reply; pool_t pool; pool = pool_alloconly_create("plain_auth_request", 256); @@ -98,7 +98,7 @@ /* initialize reply */ memset(&reply, 0, sizeof(reply)); reply.id = id; - reply.result = AUTH_LOGIN_RESULT_CONTINUE; + reply.result = AUTH_CLIENT_RESULT_CONTINUE; callback(&reply, NULL, conn); return auth_request;
--- a/src/auth/mech.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/mech.c Fri Aug 22 05:42:12 2003 +0300 @@ -5,7 +5,7 @@ #include "buffer.h" #include "hash.h" #include "mech.h" -#include "login-connection.h" +#include "auth-client-connection.h" #include <stdlib.h> @@ -23,7 +23,7 @@ static int set_use_cyrus_sasl; static struct mech_module_list *mech_modules; -static struct auth_login_reply failure_reply; +static struct auth_client_request_reply failure_reply; void mech_register_module(struct mech_module *module) { @@ -59,8 +59,8 @@ } } -void mech_request_new(struct login_connection *conn, - struct auth_login_request_new *request, +void mech_request_new(struct auth_client_connection *conn, + struct auth_client_request_new *request, mech_callback_t *callback) { struct mech_module_list *list; @@ -68,8 +68,8 @@ if ((auth_mechanisms & request->mech) == 0) { /* unsupported mechanism */ - i_error("BUG: login requested unsupported " - "auth mechanism %d", request->mech); + i_error("BUG: Auth client %u requested unsupported " + "auth mechanism %d", conn->pid, request->mech); failure_reply.id = request->id; callback(&failure_reply, NULL, conn); return; @@ -104,8 +104,8 @@ } } -void mech_request_continue(struct login_connection *conn, - struct auth_login_request_continue *request, +void mech_request_continue(struct auth_client_connection *conn, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback) { @@ -124,22 +124,22 @@ } } -void mech_request_free(struct login_connection *conn, +void mech_request_free(struct auth_client_connection *conn, struct auth_request *auth_request, unsigned int id) { auth_request->auth_free(auth_request); hash_remove(conn->auth_requests, POINTER_CAST(id)); } -void mech_init_login_reply(struct auth_login_reply *reply) +void mech_init_auth_client_reply(struct auth_client_request_reply *reply) { memset(reply, 0, sizeof(*reply)); - reply->username_idx = (unsigned int)-1; - reply->reply_idx = (unsigned int)-1; + reply->username_idx = (size_t)-1; + reply->reply_idx = (size_t)-1; } -void *mech_auth_success(struct auth_login_reply *reply, +void *mech_auth_success(struct auth_client_request_reply *reply, struct auth_request *auth_request, const void *data, size_t data_size) { @@ -157,7 +157,7 @@ buffer_append(buf, data, data_size); } - reply->result = AUTH_LOGIN_RESULT_SUCCESS; + reply->result = AUTH_CLIENT_RESULT_SUCCESS; reply->data_size = buffer_get_used_size(buf); return buffer_get_modifyable_data(buf, NULL); } @@ -165,7 +165,7 @@ void mech_auth_finish(struct auth_request *auth_request, const void *data, size_t data_size, int success) { - struct auth_login_reply reply; + struct auth_client_request_reply reply; void *reply_data; memset(&reply, 0, sizeof(reply)); @@ -174,10 +174,10 @@ if (success) { reply_data = mech_auth_success(&reply, auth_request, data, data_size); - reply.result = AUTH_LOGIN_RESULT_SUCCESS; + reply.result = AUTH_CLIENT_RESULT_SUCCESS; } else { reply_data = NULL; - reply.result = AUTH_LOGIN_RESULT_FAILURE; + reply.result = AUTH_CLIENT_RESULT_FAILURE; } auth_request->callback(&reply, reply_data, auth_request->conn); @@ -213,7 +213,7 @@ auth_mechanisms = 0; memset(&failure_reply, 0, sizeof(failure_reply)); - failure_reply.result = AUTH_LOGIN_RESULT_FAILURE; + failure_reply.result = AUTH_CLIENT_RESULT_FAILURE; anonymous_username = getenv("ANONYMOUS_USERNAME"); if (anonymous_username != NULL && *anonymous_username == '\0')
--- a/src/auth/mech.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/auth/mech.h Fri Aug 22 05:42:12 2003 +0300 @@ -1,18 +1,19 @@ #ifndef __MECH_H #define __MECH_H -#include "auth-login-interface.h" +#include "auth-client-interface.h" + +struct auth_client_connection; -struct login_connection; - -typedef void mech_callback_t(struct auth_login_reply *reply, - const void *data, struct login_connection *conn); +typedef void mech_callback_t(struct auth_client_request_reply *reply, + const void *data, + struct auth_client_connection *conn); struct auth_request { pool_t pool; char *user; - struct login_connection *conn; + struct auth_client_connection *conn; unsigned int id; time_t created; @@ -20,7 +21,7 @@ mech_callback_t *callback; int (*auth_continue)(struct auth_request *auth_request, - struct auth_login_request_continue *request, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback); void (*auth_free)(struct auth_request *auth_request); @@ -30,7 +31,7 @@ struct mech_module { enum auth_mech mech; - struct auth_request *(*auth_new)(struct login_connection *conn, + struct auth_request *(*auth_new)(struct auth_client_connection *conn, unsigned int id, mech_callback_t *callback); }; @@ -44,18 +45,18 @@ void mech_register_module(struct mech_module *module); void mech_unregister_module(struct mech_module *module); -void mech_request_new(struct login_connection *conn, - struct auth_login_request_new *request, +void mech_request_new(struct auth_client_connection *conn, + struct auth_client_request_new *request, mech_callback_t *callback); -void mech_request_continue(struct login_connection *conn, - struct auth_login_request_continue *request, +void mech_request_continue(struct auth_client_connection *conn, + struct auth_client_request_continue *request, const unsigned char *data, mech_callback_t *callback); -void mech_request_free(struct login_connection *conn, +void mech_request_free(struct auth_client_connection *conn, struct auth_request *auth_request, unsigned int id); -void mech_init_login_reply(struct auth_login_reply *reply); -void *mech_auth_success(struct auth_login_reply *reply, +void mech_init_auth_client_reply(struct auth_client_request_reply *reply); +void *mech_auth_success(struct auth_client_request_reply *reply, struct auth_request *auth_request, const void *data, size_t data_size); void mech_auth_finish(struct auth_request *auth_request, @@ -64,9 +65,10 @@ int mech_is_valid_username(const char *username); void mech_cyrus_sasl_init_lib(void); -struct auth_request *mech_cyrus_sasl_new(struct login_connection *conn, - struct auth_login_request_new *request, - mech_callback_t *callback); +struct auth_request * +mech_cyrus_sasl_new(struct auth_client_connection *conn, + struct auth_client_request_new *request, + mech_callback_t *callback); void mech_init(void); void mech_deinit(void);
--- a/src/imap-login/Makefile.am Fri Aug 22 02:31:50 2003 +0300 +++ b/src/imap-login/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -4,12 +4,14 @@ INCLUDES = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-auth \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/login-common imap_login_LDADD = \ ../login-common/liblogin-common.a \ ../lib-imap/imap-parser.o \ + ../lib-auth/libauth.a \ ../lib/liblib.a \ $(SSL_LIBS) @@ -18,6 +20,5 @@ client-authenticate.c noinst_HEADERS = \ - common.h \ client.h \ client-authenticate.h
--- a/src/imap-login/client-authenticate.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/imap-login/client-authenticate.c Fri Aug 22 05:42:12 2003 +0300 @@ -9,26 +9,27 @@ #include "safe-memset.h" #include "str.h" #include "imap-parser.h" -#include "auth-connection.h" +#include "auth-client.h" #include "../auth/auth-mech-desc.h" #include "client.h" #include "client-authenticate.h" #include "auth-common.h" #include "master.h" -static enum auth_mech auth_mechs = 0; -static char *auth_mechs_capability = NULL; - const char *client_authenticate_get_capabilities(int tls) { + static enum auth_mech cached_auth_mechs = 0; + static char *cached_capability = NULL; + enum auth_mech auth_mechs; string_t *str; int i; - if (auth_mechs == available_auth_mechs) - return auth_mechs_capability; + auth_mechs = auth_client_get_available_mechs(auth_client); + if (auth_mechs == cached_auth_mechs) + return cached_capability; - auth_mechs = available_auth_mechs; - i_free(auth_mechs_capability); + cached_auth_mechs = auth_mechs; + i_free(cached_capability); str = t_str_new(128); @@ -43,8 +44,8 @@ } } - auth_mechs_capability = i_strdup_empty(str_c(str)); - return auth_mechs_capability; + cached_capability = i_strdup_empty(str_c(str)); + return cached_capability; } static struct auth_mech_desc *auth_mech_find(const char *name) @@ -65,8 +66,7 @@ client->authenticating = FALSE; if (client->common.auth_request != NULL) { - auth_abort_request(client->common.auth_request); - auth_request_unref(client->common.auth_request); + auth_client_request_abort(client->common.auth_request); client->common.auth_request = NULL; } @@ -80,8 +80,6 @@ io_remove(client->common.io); client->common.io = client->common.fd == -1 ? NULL : io_add(client->common.fd, IO_READ, client_input, client); - - client_unref(client); } static void master_callback(struct client *_client, int success) @@ -99,7 +97,6 @@ } client_destroy(client, reason); - client_unref(client); } static void client_send_auth_data(struct imap_client *client, @@ -122,15 +119,15 @@ } static void login_callback(struct auth_request *request, - struct auth_login_reply *reply, - const unsigned char *data, struct client *_client) + struct auth_client_request_reply *reply, + const unsigned char *data, void *context) { - struct imap_client *client = (struct imap_client *) _client; + struct imap_client *client = context; const char *error; const void *ptr; size_t size; - switch (auth_callback(request, reply, data, _client, + switch (auth_callback(request, reply, data, &client->common, master_callback, &error)) { case -1: /* login failed */ @@ -140,7 +137,7 @@ case 0: /* continue */ ptr = buffer_get_data(client->plain_login, &size); - auth_continue_request(request, ptr, size); + auth_client_request_continue(request, ptr, size); buffer_set_used_size(client->plain_login, 0); break; @@ -184,33 +181,34 @@ buffer_append_c(client->plain_login, '\0'); buffer_append(client->plain_login, pass, strlen(pass)); - client_ref(client); - if (auth_init_request(AUTH_MECH_PLAIN, AUTH_PROTOCOL_IMAP, - login_callback, &client->common, &error)) { - /* don't read any input from client until login is finished */ - if (client->common.io != NULL) { - io_remove(client->common.io); - client->common.io = NULL; - } - client->authenticating = TRUE; - return TRUE; - } else { + client->common.auth_request = + auth_client_request_new(auth_client, AUTH_MECH_PLAIN, + AUTH_PROTOCOL_IMAP, login_callback, + client, &error); + if (client->common.auth_request == NULL) { client_send_tagline(client, t_strconcat( "NO Login failed: ", error, NULL)); - client_unref(client); return TRUE; } + + /* don't read any input from client until login is finished */ + if (client->common.io != NULL) { + io_remove(client->common.io); + client->common.io = NULL; + } + + client->authenticating = TRUE; + return TRUE; } static void authenticate_callback(struct auth_request *request, - struct auth_login_reply *reply, - const unsigned char *data, - struct client *_client) + struct auth_client_request_reply *reply, + const unsigned char *data, void *context) { - struct imap_client *client = (struct imap_client *) _client; + struct imap_client *client = context; const char *error; - switch (auth_callback(request, reply, data, _client, + switch (auth_callback(request, reply, data, &client->common, master_callback, &error)) { case -1: /* login failed */ @@ -266,9 +264,9 @@ } else if (client->common.auth_request == NULL) { client_auth_abort(client, "Don't send unrequested data"); } else { - auth_continue_request(client->common.auth_request, - buffer_get_data(buf, NULL), - buffer_get_used_size(buf)); + auth_client_request_continue(client->common.auth_request, + buffer_get_data(buf, NULL), + buffer_get_used_size(buf)); } /* clear sensitive data */ @@ -306,9 +304,12 @@ return TRUE; } - client_ref(client); - if (auth_init_request(mech->mech, AUTH_PROTOCOL_IMAP, - authenticate_callback, &client->common, &error)) { + client->common.auth_request = + auth_client_request_new(auth_client, mech->mech, + AUTH_PROTOCOL_IMAP, + authenticate_callback, + client, &error); + if (client->common.auth_request != NULL) { /* following input data will go to authentication */ if (client->common.io != NULL) io_remove(client->common.io); @@ -318,7 +319,6 @@ } else { client_send_tagline(client, t_strconcat( "NO Authentication failed: ", error, NULL)); - client_unref(client); } return TRUE;
--- a/src/imap-login/client.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/imap-login/client.c Fri Aug 22 05:42:12 2003 +0300 @@ -12,7 +12,7 @@ #include "imap-parser.h" #include "client.h" #include "client-authenticate.h" -#include "auth-connection.h" +#include "auth-client.h" #include "ssl-proxy.h" /* max. size of one parameter in line */ @@ -41,6 +41,8 @@ static struct hash_table *clients; static struct timeout *to_idle; +static int client_unref(struct imap_client *client); + static void client_set_title(struct imap_client *client) { const char *addr; @@ -275,7 +277,7 @@ if (!client_read(client)) return; - if (!auth_is_connected()) { + if (!auth_client_is_connected(auth_client)) { /* we're not yet connected to auth process - don't allow any commands */ client_send_line(client, @@ -284,7 +286,7 @@ return; } - client_ref(client); + client->refcount++; o_stream_cork(client->output); while (client_handle_input(client)) ; @@ -386,6 +388,14 @@ i_stream_close(client->input); o_stream_close(client->output); + if (client->common.auth_request != NULL) { + auth_client_request_abort(client->common.auth_request); + client->common.auth_request = NULL; + } + + if (client->common.master_tag != 0) + master_request_abort(&client->common); + if (client->common.io != NULL) { io_remove(client->common.io); client->common.io = NULL; @@ -399,12 +409,7 @@ client_unref(client); } -void client_ref(struct imap_client *client) -{ - client->refcount++; -} - -int client_unref(struct imap_client *client) +static int client_unref(struct imap_client *client) { if (--client->refcount > 0) return TRUE; @@ -476,7 +481,7 @@ } } -void clients_notify_auth_process(void) +void clients_notify_auth_connected(void) { hash_foreach(clients, client_hash_check_io, NULL); }
--- a/src/imap-login/client.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/imap-login/client.h Fri Aug 22 05:42:12 2003 +0300 @@ -33,9 +33,6 @@ struct client *client_create(int fd, struct ip_addr *ip, int ssl); void client_destroy(struct imap_client *client, const char *reason); -void client_ref(struct imap_client *client); -int client_unref(struct imap_client *client); - void client_send_line(struct imap_client *client, const char *line); void client_send_tagline(struct imap_client *client, const char *line); void client_syslog(struct imap_client *client, const char *text);
--- a/src/imap-login/common.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#ifndef __COMMON_H -#define __COMMON_H - -#include "lib.h" -#include "../auth/auth-login-interface.h" - -extern int disable_plaintext_auth, process_per_connection, verbose_proctitle; -extern unsigned int max_logging_users; -extern unsigned int login_process_uid; - -void main_ref(void); -void main_unref(void); - -void main_close_listen(void); - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/.cvsignore Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,8 @@ +*.la +*.lo +*.o +.deps +.libs +Makefile +Makefile.in +so_locations
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,12 @@ +noinst_LIBRARIES = libauth.a + +INCLUDES = \ + -I$(top_srcdir)/src/lib + +libauth_a_SOURCES = \ + auth-client.c \ + auth-server-connection.c \ + auth-server-request.c + +noinst_HEADERS = \ + auth-client.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-client.c Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,111 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "ioloop.h" +#include "hash.h" +#include "auth-client.h" +#include "auth-server-connection.h" + +#include <dirent.h> +#include <sys/stat.h> + +struct auth_client *auth_client_new(unsigned int client_pid) +{ + struct auth_client *client; + + client = i_new(struct auth_client, 1); + client->pid = client_pid; + + auth_client_connect_missing_servers(client); + return client; +} + +void auth_client_free(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; + } + + if (client->to_reconnect != NULL) + timeout_remove(client->to_reconnect); + i_free(client); +} + +enum auth_mech auth_client_get_available_mechs(struct auth_client *client) +{ + return client->available_auth_mechs; +} + +int auth_client_is_connected(struct auth_client *client) +{ + return client->to_reconnect == NULL && + client->conn_waiting_handshake_count == 0; +} + +void auth_client_set_connect_notify(struct auth_client *client, + auth_connect_notify_callback_t *callback, + void *context) +{ + client->connect_notify_callback = callback; + client->connect_notify_context = context; +} + +static void reconnect_timeout(void *context) +{ + struct auth_client *client = context; + + auth_client_connect_missing_servers(client); +} + +void auth_client_connect_missing_servers(struct auth_client *client) +{ + DIR *dirp; + struct dirent *dp; + struct stat st; + int reconnect; + + /* we're chrooted into */ + dirp = opendir("."); + if (dirp == NULL) { + i_fatal("opendir(.) failed when trying to get list of " + "authentication servers: %m"); + } + + reconnect = FALSE; + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '.') + continue; + + if (auth_server_connection_find_path(client, dp->d_name) != NULL) { + /* already connected */ + continue; + } + + if (stat(dp->d_name, &st) == 0 && S_ISSOCK(st.st_mode)) { + if (auth_server_connection_new(client, + dp->d_name) == NULL) + reconnect = TRUE; + } + } + + if (closedir(dirp) < 0) + i_error("closedir() failed: %m"); + + if (reconnect || client->connections == NULL) { + if (client->to_reconnect == NULL) { + client->to_reconnect = + timeout_add(5000, reconnect_timeout, client); + } + } else if (client->to_reconnect != NULL) { + timeout_remove(client->to_reconnect); + client->to_reconnect = NULL; + } + + client->connect_notify_callback(client, + auth_client_is_connected(client), + client->connect_notify_context); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-client.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,51 @@ +#ifndef __AUTH_CLIENT_H +#define __AUTH_CLIENT_H + +#include "../auth/auth-client-interface.h" + +struct auth_client; +struct auth_request; + +/* reply is NULL if auth connection died */ +typedef void auth_request_callback_t(struct auth_request *request, + struct auth_client_request_reply *reply, + const unsigned char *data, void *context); + +typedef void auth_connect_notify_callback_t(struct auth_client *client, + int 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); + +int auth_client_is_connected(struct auth_client *client); +void auth_client_set_connect_notify(struct auth_client *client, + auth_connect_notify_callback_t *callback, + void *context); +enum auth_mech auth_client_get_available_mechs(struct auth_client *client); + +void auth_client_connect_missing_servers(struct auth_client *client); + +/* Create a new authentication request. callback is called whenever something + happens for the request. */ +struct auth_request * +auth_client_request_new(struct auth_client *client, + enum auth_mech mech, enum auth_protocol protocol, + auth_request_callback_t *callback, void *context, + const char **error_r); + +/* Continue authentication. Call when + reply->result == AUTH_CLIENT_REQUEST_CONTINUE */ +void auth_client_request_continue(struct auth_request *request, + const unsigned char *data, size_t data_size); + +/* Abort ongoing authentication request. */ +void auth_client_request_abort(struct auth_request *request); + +/* Return ID of this request. */ +unsigned int auth_client_request_get_id(struct auth_request *request); + +/* Return the PID of the server that handled this request. */ +unsigned int auth_client_request_get_server_pid(struct auth_request *request); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-server-connection.c Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,229 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "hash.h" +#include "ioloop.h" +#include "istream.h" +#include "ostream.h" +#include "network.h" +#include "auth-client.h" +#include "auth-server-connection.h" +#include "auth-server-request.h" + +#include <unistd.h> + +/* Maximum size for an auth reply. 50kB should be more than enough. */ +#define MAX_INBUF_SIZE (1024*50) + +#define MAX_OUTBUF_SIZE \ + (sizeof(struct auth_client_request_continue) + \ + AUTH_CLIENT_MAX_REQUEST_DATA_SIZE) + +static void update_available_auth_mechs(struct auth_client *client) +{ + struct auth_server_connection *conn; + + client->available_auth_mechs = 0; + for (conn = client->connections; conn != NULL; conn = conn->next) + client->available_auth_mechs |= conn->available_auth_mechs; +} + +static void auth_handle_handshake(struct auth_server_connection *conn, + struct auth_client_handshake_reply *handshake) +{ + if (handshake->server_pid == 0) { + i_error("BUG: Auth server said it's PID 0"); + auth_server_connection_destroy(conn, FALSE); + return; + } + + conn->pid = handshake->server_pid; + conn->available_auth_mechs = handshake->auth_mechanisms; + conn->handshake_received = TRUE; + + conn->client->conn_waiting_handshake_count--; + update_available_auth_mechs(conn->client); + + if (auth_client_is_connected(conn->client)) { + conn->client->connect_notify_callback(conn->client, TRUE, + conn->client->connect_notify_context); + } +} + +static void auth_client_input(void *context) +{ + struct auth_server_connection *conn = context; + struct auth_client_handshake_reply handshake; + const unsigned char *data; + size_t size; + + switch (i_stream_read(conn->input)) { + case 0: + return; + case -1: + /* disconnected */ + auth_server_connection_destroy(conn, TRUE); + 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", + MAX_INBUF_SIZE); + auth_server_connection_destroy(conn, FALSE); + return; + } + + if (!conn->handshake_received) { + data = i_stream_get_data(conn->input, &size); + if (size == sizeof(handshake)) { + memcpy(&handshake, data, sizeof(handshake)); + i_stream_skip(conn->input, sizeof(handshake)); + + auth_handle_handshake(conn, &handshake); + } else if (size > sizeof(handshake)) { + i_error("BUG: Auth server sent us too large handshake " + "(%"PRIuSIZE_T " vs %"PRIuSIZE_T")", size, + sizeof(handshake)); + auth_server_connection_destroy(conn, FALSE); + } + return; + } + + if (!conn->reply_received) { + data = i_stream_get_data(conn->input, &size); + if (size < sizeof(conn->reply)) + return; + + memcpy(&conn->reply, data, sizeof(conn->reply)); + i_stream_skip(conn->input, sizeof(conn->reply)); + conn->reply_received = TRUE; + } + + data = i_stream_get_data(conn->input, &size); + if (size < conn->reply.data_size) + return; + + /* we've got a full reply */ + conn->reply_received = FALSE; + auth_server_request_handle_reply(conn, &conn->reply, data); + i_stream_skip(conn->input, conn->reply.data_size); +} + +struct auth_server_connection * +auth_server_connection_new(struct auth_client *client, const char *path) +{ + struct auth_server_connection *conn; + struct auth_client_handshake_request handshake; + pool_t pool; + int fd; + + fd = net_connect_unix(path); + if (fd == -1) { + i_error("Can't connect to auth server at %s: %m", path); + return NULL; + } + + /* 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->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_file(fd, default_pool, MAX_INBUF_SIZE, + FALSE); + conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE, + FALSE); + conn->requests = hash_create(default_pool, pool, 100, NULL, NULL); + + conn->next = client->connections; + client->connections = conn; + + /* send our handshake */ + memset(&handshake, 0, sizeof(handshake)); + handshake.client_pid = client->pid; + + client->conn_waiting_handshake_count++; + if (o_stream_send(conn->output, &handshake, sizeof(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, + int reconnect) +{ + struct auth_client *client = conn->client; + struct auth_server_connection **pos; + + pos = &conn->client->connections; + for (; *pos != NULL; pos = &(*pos)->next) { + if (*pos == conn) { + *pos = conn->next; + break; + } + } + + if (!conn->handshake_received) + client->conn_waiting_handshake_count--; + + io_remove(conn->io); + if (close(conn->fd) < 0) + i_error("close(auth) failed: %m"); + conn->fd = -1; + + auth_server_requests_remove_all(conn); + hash_destroy(conn->requests); + + i_stream_unref(conn->input); + o_stream_unref(conn->output); + pool_unref(conn->pool); + + if (reconnect) + auth_client_connect_missing_servers(client); + else { + client->connect_notify_callback(client, + auth_client_is_connected(client), + client->connect_notify_context); + } +} + +struct auth_server_connection * +auth_server_connection_find_path(struct auth_client *client, const char *path) +{ + 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, + enum auth_mech mech, const char **error_r) +{ + struct auth_server_connection *conn; + + for (conn = client->connections; conn != NULL; conn = conn->next) { + if ((conn->available_auth_mechs & mech)) + return conn; + } + + if ((client->available_auth_mechs & mech) == 0) + *error_r = "Unsupported authentication mechanism"; + else { + *error_r = "Authentication server isn't connected, " + "try again later.."; + } + + return NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-server-connection.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,53 @@ +#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; + + unsigned int conn_waiting_handshake_count; + + enum auth_mech available_auth_mechs; + unsigned int request_id_counter; + + auth_connect_notify_callback_t *connect_notify_callback; + void *connect_notify_context; +}; + +struct auth_server_connection { + struct auth_server_connection *next; + + pool_t pool; + struct auth_client *client; + const char *path; + int fd; + + struct io *io; + struct istream *input; + struct ostream *output; + + unsigned int pid; + enum auth_mech available_auth_mechs; + struct auth_client_request_reply reply; + + struct hash_table *requests; + + unsigned int handshake_received:1; + unsigned int reply_received:1; +}; + +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, + int reconnect); + +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, + enum auth_mech mech, const char **error_r); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-server-request.c Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,134 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "hash.h" +#include "ostream.h" +#include "auth-client.h" +#include "auth-server-connection.h" +#include "auth-server-request.h" + +struct auth_request { + enum auth_mech mech; + struct auth_server_connection *conn; + + unsigned int id; + + auth_request_callback_t *callback; + void *context; + + unsigned int init_sent:1; +}; + +void auth_server_request_handle_reply(struct auth_server_connection *conn, + struct auth_client_request_reply *reply, + const unsigned char *data) +{ + struct auth_request *request; + + request = hash_lookup(conn->requests, POINTER_CAST(reply->id)); + if (request == NULL) { + i_error("BUG: Auth server sent us reply with unknown ID %u", + reply->id); + return; + } + + request->callback(request, reply, data, request->context); + + if (reply->result != AUTH_CLIENT_RESULT_CONTINUE) { + hash_remove(conn->requests, POINTER_CAST(request->id)); + i_free(request); + } +} + +static void request_hash_remove(void *key __attr_unused__, void *value, + void *context __attr_unused__) +{ + struct auth_request *request = value; + + request->callback(request, NULL, NULL, request->context); + request->conn = NULL; +} + +void auth_server_requests_remove_all(struct auth_server_connection *conn) +{ + hash_foreach(conn->requests, request_hash_remove, NULL); +} + +struct auth_request * +auth_client_request_new(struct auth_client *client, + enum auth_mech mech, enum auth_protocol protocol, + auth_request_callback_t *callback, void *context, + const char **error_r) +{ + struct auth_server_connection *conn; + struct auth_request *request; + struct auth_client_request_new auth_request; + + conn = auth_server_connection_find_mech(client, mech, error_r); + if (conn == NULL) + return NULL; + + request = i_new(struct auth_request, 1); + request->mech = mech; + request->conn = conn; + request->id = ++client->request_id_counter; + if (request->id == 0) { + /* wrapped - ID 0 not allowed */ + request->id = ++client->request_id_counter; + } + request->callback = callback; + request->context = context; + + hash_insert(conn->requests, POINTER_CAST(request->id), request); + + /* send request to auth */ + auth_request.type = AUTH_CLIENT_REQUEST_NEW; + auth_request.id = request->id; + auth_request.protocol = protocol; + auth_request.mech = request->mech; + if (o_stream_send(request->conn->output, &auth_request, + sizeof(auth_request)) < 0) { + errno = request->conn->output->stream_errno; + i_warning("Error sending request to auth process: %m"); + auth_server_connection_destroy(request->conn, TRUE); + } + return request; +} + +void auth_client_request_continue(struct auth_request *request, + const unsigned char *data, size_t data_size) +{ + struct auth_client_request_continue auth_request; + + /* send continued request to auth */ + auth_request.type = AUTH_CLIENT_REQUEST_CONTINUE; + auth_request.id = request->id; + auth_request.data_size = data_size; + + if (o_stream_send(request->conn->output, &auth_request, + sizeof(auth_request)) < 0 || + o_stream_send(request->conn->output, data, data_size) < 0) { + errno = request->conn->output->stream_errno; + i_warning("Error sending continue request to auth process: %m"); + auth_server_connection_destroy(request->conn, TRUE); + } +} + +void auth_client_request_abort(struct auth_request *request) +{ + void *id = POINTER_CAST(request->id); + + if (hash_lookup(request->conn->requests, id) != NULL) + hash_remove(request->conn->requests, id); + i_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->pid; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-auth/auth-server-request.h Fri Aug 22 05:42:12 2003 +0300 @@ -0,0 +1,10 @@ +#ifndef __AUTH_SERVER_REQUEST_H +#define __AUTH_SERVER_REQUEST_H + +void auth_server_request_handle_reply(struct auth_server_connection *conn, + struct auth_client_request_reply *reply, + const unsigned char *data); + +void auth_server_requests_remove_all(struct auth_server_connection *conn); + +#endif
--- a/src/login-common/Makefile.am Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -2,12 +2,12 @@ INCLUDES = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-auth \ -DPKG_RUNDIR=\""$(localstatedir)/run/$(PACKAGE)"\" \ -DSBINDIR=\""$(sbindir)"\" liblogin_common_a_SOURCES = \ auth-common.c \ - auth-connection.c \ main.c \ master.c \ ssl-proxy.c \ @@ -16,7 +16,6 @@ noinst_HEADERS = \ auth-common.h \ - auth-connection.h \ client-common.h \ common.h \ master.h \
--- a/src/login-common/auth-common.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/auth-common.c Fri Aug 22 05:42:12 2003 +0300 @@ -3,11 +3,11 @@ #include "common.h" #include "ioloop.h" #include "client-common.h" -#include "auth-connection.h" +#include "auth-client.h" #include "auth-common.h" -static const char *auth_login_get_str(struct auth_login_reply *reply, - const unsigned char *data, size_t idx) +static const char *auth_client_get_str(struct auth_client_request_reply *reply, + const unsigned char *data, size_t idx) { size_t stop; @@ -20,47 +20,44 @@ return t_strndup(data + idx, stop); } -int auth_callback(struct auth_request *request, struct auth_login_reply *reply, +int auth_callback(struct auth_request *request, + struct auth_client_request_reply *reply, const unsigned char *data, struct client *client, - master_callback_t *master_callback, const char **error) + master_callback_t *master_callback, const char **error_r) { const char *user; - *error = NULL; + *error_r = NULL; if (reply == NULL) { /* failed */ - if (client->auth_request != NULL) { - auth_request_unref(client->auth_request); - client->auth_request = NULL; - } - *error = "Authentication process died."; + client->auth_request = NULL; + *error_r = "Authentication process died."; return -1; } switch (reply->result) { - case AUTH_LOGIN_RESULT_CONTINUE: + case AUTH_CLIENT_RESULT_CONTINUE: if (client->auth_request != NULL) { i_assert(client->auth_request == request); } else { i_assert(client->auth_request == NULL); client->auth_request = request; - auth_request_ref(client->auth_request); } return 0; - case AUTH_LOGIN_RESULT_SUCCESS: - auth_request_unref(client->auth_request); + case AUTH_CLIENT_RESULT_SUCCESS: client->auth_request = NULL; - user = auth_login_get_str(reply, data, reply->username_idx); + user = auth_client_get_str(reply, data, reply->username_idx); i_free(client->virtual_user); client->virtual_user = i_strdup(user); - master_request_imap(client, master_callback, - request->conn->pid, request->id); + master_request_login(client, master_callback, + auth_client_request_get_server_pid(request), + auth_client_request_get_id(request)); /* disable IO until we're back from master */ if (client->io != NULL) { @@ -69,14 +66,13 @@ } return 1; - case AUTH_LOGIN_RESULT_FAILURE: + case AUTH_CLIENT_RESULT_FAILURE: /* see if we have error message */ - auth_request_unref(client->auth_request); client->auth_request = NULL; if (reply->data_size > 0 && data[reply->data_size-1] == '\0') { - *error = t_strconcat("Authentication failed: ", - (const char *) data, NULL); + *error_r = t_strconcat("Authentication failed: ", + (const char *) data, NULL); } return -1; }
--- a/src/login-common/auth-common.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/auth-common.h Fri Aug 22 05:42:12 2003 +0300 @@ -1,9 +1,10 @@ #ifndef __AUTH_COMMON_H #define __AUTH_COMMON_H -int auth_callback(struct auth_request *request, struct auth_login_reply *reply, +int auth_callback(struct auth_request *request, + struct auth_client_request_reply *reply, const unsigned char *data, struct client *client, - master_callback_t *master_callback, const char **error); + master_callback_t *master_callback, const char **error_r); #endif
--- a/src/login-common/auth-connection.c Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,443 +0,0 @@ -/* Copyright (C) 2002 Timo Sirainen */ - -#include "common.h" -#include "hash.h" -#include "ioloop.h" -#include "network.h" -#include "istream.h" -#include "ostream.h" -#include "client-common.h" -#include "auth-connection.h" - -#include <unistd.h> -#include <dirent.h> -#include <sys/stat.h> - -/* Maximum size for an auth reply. 50kB should be more than enough. */ -#define MAX_INBUF_SIZE (1024*50) - -#define MAX_OUTBUF_SIZE \ - (sizeof(struct auth_login_request_continue) + \ - AUTH_LOGIN_MAX_REQUEST_DATA_SIZE) - -enum auth_mech available_auth_mechs; - -static int auth_reconnect; -static unsigned int request_id_counter; -static struct auth_connection *auth_connections; -static struct timeout *to; -static unsigned int auth_waiting_handshake_count; - -static void auth_connection_destroy(struct auth_connection *conn); -static void auth_connection_unref(struct auth_connection *conn); - -static void auth_input(void *context); -static void auth_connect_missing(void); - -static struct auth_connection *auth_connection_find(const char *path) -{ - struct auth_connection *conn; - - for (conn = auth_connections; conn != NULL; conn = conn->next) { - if (strcmp(conn->path, path) == 0) - return conn; - } - - return NULL; -} - -static struct auth_connection *auth_connection_new(const char *path) -{ - struct auth_connection *conn; - struct auth_login_handshake_input handshake; - int fd; - - fd = net_connect_unix(path); - if (fd == -1) { - i_error("Can't connect to auth process at %s: %m", path); - auth_reconnect = TRUE; - return NULL; - } - - /* use blocking connection since we depend on auth process - - if it's slow, just wait */ - - conn = i_new(struct auth_connection, 1); - conn->refcount = 1; - conn->path = i_strdup(path); - conn->fd = fd; - conn->io = io_add(fd, IO_READ, auth_input, conn); - conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE, - FALSE); - conn->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE, - FALSE); - conn->requests = hash_create(default_pool, default_pool, 100, - NULL, NULL); - - conn->next = auth_connections; - auth_connections = conn; - - /* send our handshake */ - auth_waiting_handshake_count++; - memset(&handshake, 0, sizeof(handshake)); - handshake.pid = login_process_uid; - if (o_stream_send(conn->output, &handshake, sizeof(handshake)) < 0) { - errno = conn->output->stream_errno; - i_warning("Error sending handshake to auth process: %m"); - auth_connection_destroy(conn); - return NULL; - } - return conn; -} - -static void request_hash_remove(void *key __attr_unused__, void *value, - void *context __attr_unused__) -{ - struct auth_request *request = value; - - request->callback(request, NULL, NULL, request->context); -} - -static void request_hash_destroy(void *key __attr_unused__, void *value, - void *context __attr_unused__) -{ - struct auth_request *request = value; - - i_free(request); -} - -static void auth_connection_destroy(struct auth_connection *conn) -{ - struct auth_connection **pos; - - if (conn->fd == -1) - return; - - for (pos = &auth_connections; *pos != NULL; pos = &(*pos)->next) { - if (*pos == conn) { - *pos = conn->next; - break; - } - } - - if (!conn->handshake_received) - auth_waiting_handshake_count--; - - if (close(conn->fd) < 0) - i_error("close(auth) failed: %m"); - io_remove(conn->io); - conn->fd = -1; - - hash_foreach(conn->requests, request_hash_remove, NULL); - - auth_connection_unref(conn); - - if (auth_is_connected()) - clients_notify_auth_process(); -} - -static void auth_connection_unref(struct auth_connection *conn) -{ - if (--conn->refcount > 0) - return; - - hash_foreach(conn->requests, request_hash_destroy, NULL); - hash_destroy(conn->requests); - - i_stream_unref(conn->input); - o_stream_unref(conn->output); - i_free(conn->path); - i_free(conn); -} - -static struct auth_connection * -auth_connection_get(enum auth_mech mech, size_t size, const char **error) -{ - struct auth_connection *conn; - int found; - - found = FALSE; - for (conn = auth_connections; conn != NULL; conn = conn->next) { - if ((conn->available_auth_mechs & mech)) { - if (o_stream_have_space(conn->output, size) > 0) - return conn; - - found = TRUE; - } - } - - if (!found) { - if ((available_auth_mechs & mech) == 0) - *error = "Unsupported authentication mechanism"; - else { - *error = "Authentication server isn't connected, " - "try again later.."; - auth_reconnect = TRUE; - } - } else { - *error = "Authentication servers are busy, wait.."; - i_warning("Authentication servers are busy"); - } - - return NULL; -} - -static void update_available_auth_mechs(void) -{ - struct auth_connection *conn; - - available_auth_mechs = 0; - for (conn = auth_connections; conn != NULL; conn = conn->next) - available_auth_mechs |= conn->available_auth_mechs; -} - -static void auth_handle_handshake(struct auth_connection *conn, - struct auth_login_handshake_output *handshake) -{ - if (handshake->pid == 0) { - i_error("BUG: Auth process said it's PID 0"); - auth_connection_destroy(conn); - return; - } - - conn->pid = handshake->pid; - conn->available_auth_mechs = handshake->auth_mechanisms; - conn->handshake_received = TRUE; - - auth_waiting_handshake_count--; - update_available_auth_mechs(); - - if (auth_is_connected()) - clients_notify_auth_process(); -} - -static void auth_handle_reply(struct auth_connection *conn, - struct auth_login_reply *reply, - const unsigned char *data) -{ - struct auth_request *request; - - request = hash_lookup(conn->requests, POINTER_CAST(reply->id)); - if (request == NULL) { - i_error("BUG: Auth process sent us reply with unknown ID %u", - reply->id); - return; - } - - request->callback(request, reply, data, request->context); - - if (reply->result != AUTH_LOGIN_RESULT_CONTINUE) { - hash_remove(conn->requests, POINTER_CAST(request->id)); - i_free(request); - } -} - -static void auth_input(void *context) -{ - struct auth_connection *conn = context; - struct auth_login_handshake_output handshake; - const unsigned char *data; - size_t size; - - switch (i_stream_read(conn->input)) { - case 0: - return; - case -1: - /* disconnected */ - auth_reconnect = TRUE; - auth_connection_destroy(conn); - return; - case -2: - /* buffer full - can't happen unless auth is buggy */ - i_error("BUG: Auth process sent us more than %d bytes of data", - MAX_INBUF_SIZE); - auth_connection_destroy(conn); - return; - } - - if (!conn->handshake_received) { - data = i_stream_get_data(conn->input, &size); - if (size == sizeof(handshake)) { - memcpy(&handshake, data, sizeof(handshake)); - i_stream_skip(conn->input, sizeof(handshake)); - - auth_handle_handshake(conn, &handshake); - } else if (size > sizeof(handshake)) { - i_error("BUG: Auth process sent us too large handshake " - "(%"PRIuSIZE_T " vs %"PRIuSIZE_T")", size, - sizeof(handshake)); - auth_connection_destroy(conn); - } - return; - } - - if (!conn->reply_received) { - data = i_stream_get_data(conn->input, &size); - if (size < sizeof(conn->reply)) - return; - - memcpy(&conn->reply, data, sizeof(conn->reply)); - i_stream_skip(conn->input, sizeof(conn->reply)); - conn->reply_received = TRUE; - } - - data = i_stream_get_data(conn->input, &size); - if (size < conn->reply.data_size) - return; - - /* we've got a full reply */ - conn->reply_received = FALSE; - auth_handle_reply(conn, &conn->reply, data); - i_stream_skip(conn->input, conn->reply.data_size); -} - -int auth_init_request(enum auth_mech mech, enum auth_protocol protocol, - auth_callback_t callback, void *context, - const char **error) -{ - struct auth_connection *conn; - struct auth_request *request; - struct auth_login_request_new auth_request; - - if (auth_reconnect) - auth_connect_missing(); - - conn = auth_connection_get(mech, sizeof(auth_request), error); - if (conn == NULL) - return FALSE; - - /* create internal request structure */ - request = i_new(struct auth_request, 1); - request->mech = mech; - request->conn = conn; - request->id = ++request_id_counter; - if (request->id == 0) { - /* wrapped - ID 0 not allowed */ - request->id = ++request_id_counter; - } - request->callback = callback; - request->context = context; - - hash_insert(conn->requests, POINTER_CAST(request->id), request); - - /* send request to auth */ - auth_request.type = AUTH_LOGIN_REQUEST_NEW; - auth_request.protocol = protocol; - auth_request.mech = request->mech; - auth_request.id = request->id; - if (o_stream_send(request->conn->output, &auth_request, - sizeof(auth_request)) < 0) { - errno = request->conn->output->stream_errno; - i_warning("Error sending request to auth process: %m"); - auth_connection_destroy(request->conn); - } - return TRUE; -} - -void auth_continue_request(struct auth_request *request, - const unsigned char *data, size_t data_size) -{ - struct auth_login_request_continue auth_request; - - /* send continued request to auth */ - auth_request.type = AUTH_LOGIN_REQUEST_CONTINUE; - auth_request.id = request->id; - auth_request.data_size = data_size; - - if (o_stream_send(request->conn->output, &auth_request, - sizeof(auth_request)) < 0 || - o_stream_send(request->conn->output, data, data_size) < 0) { - errno = request->conn->output->stream_errno; - i_warning("Error sending continue request to auth process: %m"); - auth_connection_destroy(request->conn); - } -} - -void auth_abort_request(struct auth_request *request) -{ - void *id = POINTER_CAST(request->id); - - if (hash_lookup(request->conn->requests, id) != NULL) - hash_remove(request->conn->requests, id); - i_free(request); -} - -void auth_request_ref(struct auth_request *request) -{ - request->conn->refcount++; -} - -void auth_request_unref(struct auth_request *request) -{ - auth_connection_unref(request->conn); -} - -int auth_is_connected(void) -{ - return !auth_reconnect && auth_waiting_handshake_count == 0; -} - -static void auth_connect_missing(void) -{ - DIR *dirp; - struct dirent *dp; - struct stat st; - - auth_reconnect = TRUE; - - /* we're chrooted into */ - dirp = opendir("."); - if (dirp == NULL) { - i_error("opendir(\".\") failed when trying to get list of " - "authentication servers: %m"); - return; - } - - while ((dp = readdir(dirp)) != NULL) { - if (dp->d_name[0] == '.') - continue; - - if (auth_connection_find(dp->d_name) != NULL) { - /* already connected */ - continue; - } - - if (stat(dp->d_name, &st) == 0 && S_ISSOCK(st.st_mode)) { - if (auth_connection_new(dp->d_name) != NULL) - auth_reconnect = FALSE; - } - } - - (void)closedir(dirp); -} - -static void -auth_connect_missing_timeout(void *context __attr_unused__) -{ - if (auth_reconnect) - auth_connect_missing(); -} - -void auth_connection_init(void) -{ - auth_connections = NULL; - request_id_counter = 0; - auth_reconnect = FALSE; - auth_waiting_handshake_count = 0; - - auth_connect_missing(); - to = timeout_add(1000, auth_connect_missing_timeout, NULL); -} - -void auth_connection_deinit(void) -{ - struct auth_connection *next; - - while (auth_connections != NULL) { - next = auth_connections->next; - auth_connection_destroy(auth_connections); - auth_connections = next; - } - - timeout_remove(to); -}
--- a/src/login-common/auth-connection.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -#ifndef __AUTH_CONNECTION_H -#define __AUTH_CONNECTION_H - -struct client; -struct auth_request; - -/* reply is NULL if auth connection died */ -typedef void auth_callback_t(struct auth_request *request, - struct auth_login_reply *reply, - const unsigned char *data, struct client *client); - -struct auth_connection { - struct auth_connection *next; - int refcount; - - char *path; - int fd; - struct io *io; - struct istream *input; - struct ostream *output; - - unsigned int pid; - enum auth_mech available_auth_mechs; - struct auth_login_reply reply; - - struct hash_table *requests; - - unsigned int handshake_received:1; - unsigned int reply_received:1; -}; - -struct auth_request { - enum auth_mech mech; - struct auth_connection *conn; - - unsigned int id; - - auth_callback_t *callback; - void *context; - - unsigned int init_sent:1; -}; - -extern enum auth_mech available_auth_mechs; - -int auth_init_request(enum auth_mech mech, enum auth_protocol protocol, - auth_callback_t callback, void *context, - const char **error); - -void auth_continue_request(struct auth_request *request, - const unsigned char *data, size_t data_size); - -void auth_abort_request(struct auth_request *request); - -void auth_request_ref(struct auth_request *request); -void auth_request_unref(struct auth_request *request); - -int auth_is_connected(void); - -void auth_connection_init(void); -void auth_connection_deinit(void); - -#endif
--- a/src/login-common/client-common.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/client-common.h Fri Aug 22 05:42:12 2003 +0300 @@ -10,7 +10,8 @@ int fd; struct io *io; - struct auth_request *auth_request; + struct auth_request *auth_request; + unsigned int master_tag; master_callback_t *master_callback; char *virtual_user; @@ -20,7 +21,7 @@ struct client *client_create(int fd, struct ip_addr *ip, int ssl); unsigned int clients_get_count(void); -void clients_notify_auth_process(void); +void clients_notify_auth_connected(void); void clients_destroy_all(void); void clients_init(void);
--- a/src/login-common/common.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/common.h Fri Aug 22 05:42:12 2003 +0300 @@ -2,12 +2,12 @@ #define __COMMON_H #include "lib.h" -#include "../auth/auth-login-interface.h" extern int disable_plaintext_auth, process_per_connection, verbose_proctitle; extern int verbose_ssl; extern unsigned int max_logging_users; extern unsigned int login_process_uid; +extern struct auth_client *auth_client; void main_ref(void); void main_unref(void);
--- a/src/login-common/main.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/main.c Fri Aug 22 05:42:12 2003 +0300 @@ -7,9 +7,9 @@ #include "restrict-process-size.h" #include "process-title.h" #include "fd-close-on-exec.h" -#include "auth-connection.h" #include "master.h" #include "client-common.h" +#include "auth-client.h" #include "ssl-proxy.h" #include <stdlib.h> @@ -20,6 +20,7 @@ int verbose_ssl; unsigned int max_logging_users; unsigned int login_process_uid; +struct auth_client *auth_client; static struct ioloop *ioloop; static struct io *io_listen, *io_ssl_listen; @@ -113,6 +114,13 @@ (void)client_create(fd_ssl, &ip, TRUE); } +static void auth_connect_notify(struct auth_client *client __attr_unused__, + int connected, void *context __attr_unused__) +{ + if (connected) + clients_notify_auth_connected(); +} + static void open_logfile(const char *name) { if (getenv("USE_SYSLOG") != NULL) @@ -140,6 +148,7 @@ /* Refuse to run as root - we should never need it and it's dangerous with SSL. */ restrict_access_by_env(TRUE); + sleep(5); /* make sure we can't fork() */ restrict_process_size((unsigned int)-1, 1); @@ -169,7 +178,8 @@ closing_down = FALSE; main_refcount = 0; - auth_connection_init(); + auth_client = auth_client_new((unsigned int)getpid()); + auth_client_set_connect_notify(auth_client, auth_connect_notify, NULL); clients_init(); io_listen = io_ssl_listen = NULL; @@ -209,7 +219,7 @@ ssl_proxy_deinit(); - auth_connection_deinit(); + auth_client_free(auth_client); clients_deinit(); master_deinit();
--- a/src/login-common/master.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/master.c Fri Aug 22 05:42:12 2003 +0300 @@ -16,6 +16,7 @@ static int master_fd; static struct io *io_master; static struct hash_table *master_requests; +static unsigned int master_tag_counter; static unsigned int master_pos; static char master_buf[sizeof(struct master_login_reply)]; @@ -33,15 +34,17 @@ hash_remove(master_requests, POINTER_CAST(reply->tag)); } -void master_request_imap(struct client *client, master_callback_t *callback, - unsigned int auth_pid, unsigned int auth_id) +void master_request_login(struct client *client, master_callback_t *callback, + unsigned int auth_pid, unsigned int auth_id) { struct master_login_request req; i_assert(auth_pid != 0); memset(&req, 0, sizeof(req)); - req.tag = client->fd; + req.tag = ++master_tag_counter; + if (req.tag == 0) + req.tag = ++master_tag_counter; req.auth_pid = auth_pid; req.auth_id = auth_id; req.ip = client->ip; @@ -49,10 +52,20 @@ if (fd_send(master_fd, client->fd, &req, sizeof(req)) != sizeof(req)) i_fatal("fd_send(%d) failed: %m", client->fd); + client->master_tag = req.tag; client->master_callback = callback; + hash_insert(master_requests, POINTER_CAST(req.tag), client); } +void master_request_abort(struct client *client) +{ + client->master_tag = 0; + client->master_callback = NULL; + + hash_remove(master_requests, POINTER_CAST(client->master_tag)); +} + void master_notify_finished(void) { struct master_login_request req;
--- a/src/login-common/master.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/login-common/master.h Fri Aug 22 05:42:12 2003 +0300 @@ -7,8 +7,9 @@ typedef void master_callback_t(struct client *client, int success); -void master_request_imap(struct client *client, master_callback_t *callback, - unsigned int auth_pid, unsigned int auth_id); +void master_request_login(struct client *client, master_callback_t *callback, + unsigned int auth_pid, unsigned int auth_id); +void master_request_abort(struct client *client); /* Notify master that we're not listening for new connections anymore. */ void master_notify_finished(void);
--- a/src/pop3-login/Makefile.am Fri Aug 22 02:31:50 2003 +0300 +++ b/src/pop3-login/Makefile.am Fri Aug 22 05:42:12 2003 +0300 @@ -4,10 +4,12 @@ INCLUDES = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-auth \ -I$(top_srcdir)/src/login-common pop3_login_LDADD = \ ../login-common/liblogin-common.a \ + ../lib-auth/libauth.a \ ../lib/liblib.a \ $(SSL_LIBS) @@ -16,6 +18,5 @@ client-authenticate.c noinst_HEADERS = \ - common.h \ client.h \ client-authenticate.h
--- a/src/pop3-login/client-authenticate.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/pop3-login/client-authenticate.c Fri Aug 22 05:42:12 2003 +0300 @@ -8,7 +8,7 @@ #include "ostream.h" #include "safe-memset.h" #include "str.h" -#include "auth-connection.h" +#include "auth-client.h" #include "../auth/auth-mech-desc.h" #include "../pop3/capability.h" #include "master.h" @@ -17,17 +17,18 @@ #include "client-authenticate.h" #include "ssl-proxy.h" -static enum auth_mech auth_mechs = 0; -static char *auth_mechs_capability = NULL; - int cmd_capa(struct pop3_client *client, const char *args __attr_unused__) { + static enum auth_mech cached_auth_mechs = 0; + static char *cached_capability = NULL; + enum auth_mech auth_mechs; string_t *str; int i; - if (auth_mechs != available_auth_mechs) { - auth_mechs = available_auth_mechs; - i_free(auth_mechs_capability); + auth_mechs = auth_client_get_available_mechs(auth_client); + if (cached_auth_mechs != auth_mechs) { + cached_auth_mechs = auth_mechs; + i_free(cached_capability); str = t_str_new(128); @@ -42,13 +43,13 @@ } } - auth_mechs_capability = i_strdup(str_c(str)); + cached_capability = i_strdup(str_c(str)); } client_send_line(client, t_strconcat("+OK\r\n" POP3_CAPABILITY_REPLY, (ssl_initialized && !client->tls) ? "STLS\r\n" : "", - auth_mechs_capability, + cached_capability, "\r\n.", NULL)); return TRUE; } @@ -69,7 +70,7 @@ static void client_auth_abort(struct pop3_client *client, const char *msg) { if (client->common.auth_request != NULL) { - auth_abort_request(client->common.auth_request); + auth_client_request_abort(client->common.auth_request); client->common.auth_request = NULL; } @@ -82,8 +83,6 @@ io_remove(client->common.io); client->common.io = client->common.fd == -1 ? NULL : io_add(client->common.fd, IO_READ, client_input, client); - - client_unref(client); } static void master_callback(struct client *_client, int success) @@ -101,7 +100,6 @@ } client_destroy(client, reason); - client_unref(client); } static void client_send_auth_data(struct pop3_client *client, @@ -124,15 +122,15 @@ } static void login_callback(struct auth_request *request, - struct auth_login_reply *reply, - const unsigned char *data, struct client *_client) + struct auth_client_request_reply *reply, + const unsigned char *data, void *context) { - struct pop3_client *client = (struct pop3_client *) _client; + struct pop3_client *client = context; const char *error; const void *ptr; size_t size; - switch (auth_callback(request, reply, data, _client, + switch (auth_callback(request, reply, data, &client->common, master_callback, &error)) { case -1: /* login failed */ @@ -141,7 +139,7 @@ case 0: ptr = buffer_get_data(client->plain_login, &size); - auth_continue_request(request, ptr, size); + auth_client_request_continue(request, ptr, size); buffer_set_used_size(client->plain_login, 0); break; @@ -182,9 +180,11 @@ buffer_append_c(client->plain_login, '\0'); buffer_append(client->plain_login, args, strlen(args)); - client_ref(client); - if (auth_init_request(AUTH_MECH_PLAIN, AUTH_PROTOCOL_POP3, - login_callback, &client->common, &error)) { + client->common.auth_request = + auth_client_request_new(auth_client, AUTH_MECH_PLAIN, + AUTH_PROTOCOL_POP3, + login_callback, client, &error); + if (client->common.auth_request != NULL) { /* don't read any input from client until login is finished */ if (client->common.io != NULL) { io_remove(client->common.io); @@ -194,20 +194,18 @@ } else { client_send_line(client, t_strconcat("-ERR Login failed: ", error, NULL)); - client_unref(client); return TRUE; } } static void authenticate_callback(struct auth_request *request, - struct auth_login_reply *reply, - const unsigned char *data, - struct client *_client) + struct auth_client_request_reply *reply, + const unsigned char *data, void *context) { - struct pop3_client *client = (struct pop3_client *) _client; + struct pop3_client *client = context; const char *error; - switch (auth_callback(request, reply, data, _client, + switch (auth_callback(request, reply, data, &client->common, master_callback, &error)) { case -1: /* login failed */ @@ -255,9 +253,9 @@ } else if (client->common.auth_request == NULL) { client_auth_abort(client, "Don't send unrequested data"); } else { - auth_continue_request(client->common.auth_request, - buffer_get_data(buf, NULL), - buffer_get_used_size(buf)); + auth_client_request_continue(client->common.auth_request, + buffer_get_data(buf, NULL), + buffer_get_used_size(buf)); } /* clear sensitive data */ @@ -286,9 +284,11 @@ return TRUE; } - client_ref(client); - if (auth_init_request(mech->mech, AUTH_PROTOCOL_POP3, - authenticate_callback, &client->common, &error)) { + client->common.auth_request = + auth_client_request_new(auth_client, mech->mech, + AUTH_PROTOCOL_POP3, + authenticate_callback, client, &error); + if (client->common.auth_request != NULL) { /* following input data will go to authentication */ if (client->common.io != NULL) io_remove(client->common.io); @@ -297,7 +297,6 @@ } else { client_send_line(client, t_strconcat( "-ERR Authentication failed: ", error, NULL)); - client_unref(client); } return TRUE;
--- a/src/pop3-login/client.c Fri Aug 22 02:31:50 2003 +0300 +++ b/src/pop3-login/client.c Fri Aug 22 05:42:12 2003 +0300 @@ -11,7 +11,7 @@ #include "strescape.h" #include "client.h" #include "client-authenticate.h" -#include "auth-connection.h" +#include "auth-client.h" #include "ssl-proxy.h" /* max. length of input command line (spec says 512) */ @@ -35,6 +35,8 @@ static struct hash_table *clients; static struct timeout *to_idle; +static int client_unref(struct pop3_client *client); + static void client_set_title(struct pop3_client *client) { const char *addr; @@ -157,14 +159,14 @@ if (!client_read(client)) return; - if (!auth_is_connected()) { + if (!auth_client_is_connected(auth_client)) { /* we're not yet connected to auth process - don't allow any commands */ client->input_blocked = TRUE; return; } - client_ref(client); + client->refcount++; o_stream_cork(client->output); while (!client->output->closed && @@ -280,6 +282,14 @@ i_stream_close(client->input); o_stream_close(client->output); + if (client->common.auth_request != NULL) { + auth_client_request_abort(client->common.auth_request); + client->common.auth_request = NULL; + } + + if (client->common.master_tag != 0) + master_request_abort(&client->common); + if (client->common.io != NULL) { io_remove(client->common.io); client->common.io = NULL; @@ -291,12 +301,7 @@ client_unref(client); } -void client_ref(struct pop3_client *client) -{ - client->refcount++; -} - -int client_unref(struct pop3_client *client) +static int client_unref(struct pop3_client *client) { if (--client->refcount > 0) return TRUE; @@ -359,7 +364,7 @@ } } -void clients_notify_auth_process(void) +void clients_notify_auth_connected(void) { hash_foreach(clients, client_hash_check_io, NULL); }
--- a/src/pop3-login/client.h Fri Aug 22 02:31:50 2003 +0300 +++ b/src/pop3-login/client.h Fri Aug 22 05:42:12 2003 +0300 @@ -27,9 +27,6 @@ struct client *client_create(int fd, struct ip_addr *ip, int ssl); void client_destroy(struct pop3_client *client, const char *reason); -void client_ref(struct pop3_client *client); -int client_unref(struct pop3_client *client); - void client_send_line(struct pop3_client *client, const char *line); void client_syslog(struct pop3_client *client, const char *text);
--- a/src/pop3-login/common.h Fri Aug 22 02:31:50 2003 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -#ifndef __COMMON_H -#define __COMMON_H - -#include "lib.h" -#include "../auth/auth-login-interface.h" - -extern int disable_plaintext_auth, process_per_connection, verbose_proctitle; -extern unsigned int max_logging_users; -extern unsigned int login_process_uid; - -void main_ref(void); -void main_unref(void); - -void main_close_listen(void); - -#endif