doc/Makefile
src/Makefile
src/lib/Makefile
+src/lib-auth/Makefile
src/lib-charset/Makefile
src/lib-imap/Makefile
src/lib-index/Makefile
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
$(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 \
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 \
db-pgsql.h \
db-passwd-file.h \
common.h \
- login-connection.h \
- master-connection.h \
md5crypt.h \
mech.h \
mycrypt.h \
--- /dev/null
+/* 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
+#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
+#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
+++ /dev/null
-#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
+/* 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
+#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
unsigned int tag;
unsigned int id;
- unsigned int login_pid;
+ unsigned int client_pid;
};
struct auth_master_reply {
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-#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
#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>
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__)
i_fatal("accept() failed: %m");
} else {
net_set_nonblock(fd, TRUE);
- (void)login_connection_create(fd);
+ (void)auth_client_connection_create(master, fd);
}
}
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)
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();
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-#ifndef __MASTER_CONNECTION_H
-#define __MASTER_CONNECTION_H
-
-void master_connection_init(void);
-void master_connection_deinit(void);
-
-#endif
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)
{
}
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);
/* 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;
{
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;
}
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) {
}
/* 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;
}
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;
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;
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;
}
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);
/* 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;
#include "buffer.h"
#include "hash.h"
#include "mech.h"
-#include "login-connection.h"
+#include "auth-client-connection.h"
#include <stdlib.h>
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)
{
}
}
-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;
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;
}
}
-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)
{
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)
{
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);
}
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));
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);
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')
#ifndef __MECH_H
#define __MECH_H
-#include "auth-login-interface.h"
+#include "auth-client-interface.h"
-struct login_connection;
+struct auth_client_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;
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);
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);
};
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,
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);
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)
client-authenticate.c
noinst_HEADERS = \
- common.h \
client.h \
client-authenticate.h
#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);
}
}
- 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)
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;
}
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)
}
client_destroy(client, reason);
- client_unref(client);
}
static void client_send_auth_data(struct imap_client *client,
}
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 */
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;
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 */
} 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 */
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);
} else {
client_send_tagline(client, t_strconcat(
"NO Authentication failed: ", error, NULL));
- client_unref(client);
}
return TRUE;
#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 */
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;
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,
return;
}
- client_ref(client);
+ client->refcount++;
o_stream_cork(client->output);
while (client_handle_input(client)) ;
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;
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;
}
}
-void clients_notify_auth_process(void)
+void clients_notify_auth_connected(void)
{
hash_foreach(clients, client_hash_check_io, NULL);
}
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);
+++ /dev/null
-#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
+*.la
+*.lo
+*.o
+.deps
+.libs
+Makefile
+Makefile.in
+so_locations
--- /dev/null
+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
+/* 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
+#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
+/* 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
+#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
+/* 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
+#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
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 \
noinst_HEADERS = \
auth-common.h \
- auth-connection.h \
client-common.h \
common.h \
master.h \
#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;
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) {
}
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;
}
#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
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-#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
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;
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);
#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);
#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>
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;
(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)
/* 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);
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;
ssl_proxy_deinit();
- auth_connection_deinit();
+ auth_client_free(auth_client);
clients_deinit();
master_deinit();
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)];
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;
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;
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);
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)
client-authenticate.c
noinst_HEADERS = \
- common.h \
client.h \
client-authenticate.h
#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"
#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);
}
}
- 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;
}
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;
}
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)
}
client_destroy(client, reason);
- client_unref(client);
}
static void client_send_auth_data(struct pop3_client *client,
}
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 */
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;
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);
} 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 */
} 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 */
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);
} else {
client_send_line(client, t_strconcat(
"-ERR Authentication failed: ", error, NULL));
- client_unref(client);
}
return TRUE;
#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) */
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;
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 &&
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;
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;
}
}
-void clients_notify_auth_process(void)
+void clients_notify_auth_connected(void)
{
hash_foreach(clients, client_hash_check_io, NULL);
}
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);
+++ /dev/null
-#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