changeset 1702:43815588dd6b HEAD

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