[dovecot-cvs] dovecot/src/auth Makefile.am, 1.24, 1.25 auth-client-connection.c, 1.5, 1.6 auth-client-interface.h, 1.4, 1.5 auth-master-connection.c, 1.6, 1.7 auth-master-connection.h, 1.2, 1.3 auth-master-interface.h, 1.3, 1.4 main.c, 1.23, 1.24 mech-anonymous.c, 1.3, 1.4 mech-cram-md5.c, 1.3, 1.4 mech-digest-md5.c, 1.19, 1.20 mech-plain.c, 1.16, 1.17 mech.c, 1.21, 1.22 mech.h, 1.15, 1.16 passdb.c, 1.14, 1.15 auth-mech-desc.h, 1.3, NONE

cras at procontrol.fi cras at procontrol.fi
Sun May 30 00:40:33 EEST 2004


Update of /home/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv30244/auth

Modified Files:
	Makefile.am auth-client-connection.c auth-client-interface.h 
	auth-master-connection.c auth-master-connection.h 
	auth-master-interface.h main.c mech-anonymous.c 
	mech-cram-md5.c mech-digest-md5.c mech-plain.c mech.c mech.h 
	passdb.c 
Removed Files:
	auth-mech-desc.h 
Log Message:
Removed hardcoded mechanism lists. It's now possible to add them
dynamically. Added support for SASL initial response.



Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- a/Makefile.am	10 May 2004 01:47:09 -0000	1.24
+++ b/Makefile.am	29 May 2004 21:40:30 -0000	1.25
@@ -58,7 +58,6 @@
 	auth-client-interface.h \
 	auth-master-connection.h \
 	auth-master-interface.h \
-	auth-mech-desc.h \
 	auth-module.h \
 	db-ldap.h \
 	db-mysql.h \

Index: auth-client-connection.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-client-connection.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- a/auth-client-connection.c	3 Dec 2003 00:40:21 -0000	1.5
+++ b/auth-client-connection.c	29 May 2004 21:40:30 -0000	1.6
@@ -109,19 +109,26 @@
 	   structures, as it may not be aligned properly. */
 	memcpy(&type, data, sizeof(type));
 
-	if (type == AUTH_CLIENT_REQUEST_NEW) {
+	conn->refcount++;
+	switch (type) {
+	case 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));
+		if (size < sizeof(request) + request.data_size)
+			return;
 
 		/* we have a full init request */
 		conn->refcount++;
-		mech_request_new(conn, &request, request_callback);
-	} else if (type == AUTH_CLIENT_REQUEST_CONTINUE) {
+		mech_request_new(conn, &request, data + sizeof(request),
+				 request_callback);
+		i_stream_skip(conn->input, sizeof(request) + request.data_size);
+		break;
+	}
+	case AUTH_CLIENT_REQUEST_CONTINUE: {
                 struct auth_client_request_continue request;
 
 		if (size < sizeof(request))
@@ -131,8 +138,6 @@
 		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),
@@ -140,12 +145,16 @@
 
 		/* clear any sensitive data from memory */
 		safe_memset(data + sizeof(request), 0, request.data_size);
-	} else {
+		i_stream_skip(conn->input, sizeof(request) + request.data_size);
+		break;
+	}
+	default:
 		/* unknown request */
-		i_error("BUG: Auth client %u sent us unknown request %u",
+		i_error("BUG: Auth client %u sent us unknown request type %u",
 			conn->pid, type);
 		auth_client_connection_destroy(conn);
 	}
+	auth_client_connection_unref(conn);
 }
 
 static void auth_client_input(void *context)
@@ -198,8 +207,9 @@
 	conn->next = master->clients;
 	master->clients = conn;
 
-	if (o_stream_send(conn->output, &master->handshake_reply,
-			  sizeof(master->handshake_reply)) < 0) {
+	if (o_stream_send(conn->output, master->handshake_reply,
+			  sizeof(*master->handshake_reply) +
+			  master->handshake_reply->data_size) < 0) {
 		auth_client_connection_destroy(conn);
 		conn = NULL;
 	}
@@ -298,9 +308,6 @@
 
 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);
 }
 

Index: auth-client-interface.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-client-interface.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- a/auth-client-interface.h	29 May 2004 17:06:50 -0000	1.4
+++ b/auth-client-interface.h	29 May 2004 21:40:30 -0000	1.5
@@ -4,22 +4,10 @@
 /* max. size for auth_client_request_continue.data[] */
 #define AUTH_CLIENT_MAX_REQUEST_DATA_SIZE 4096
 
-/* sizeof(struct auth_client_request_new->protocol) */
-#define AUTH_CLIENT_PROTOCOL_BUF_SIZE 12
-
 /* 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_CRAM_MD5	= 0x08,
-
-	AUTH_MECH_COUNT
-};
-
 enum auth_client_request_new_flags {
 	AUTH_CLIENT_FLAG_SSL_VALID_CLIENT_CERT = 0x01
 };
@@ -40,10 +28,19 @@
 	unsigned int client_pid; /* unique identifier for client process */
 };
 
+struct auth_client_handshake_mech_desc {
+	uint32_t name_idx;
+	unsigned int plaintext:1;
+	unsigned int advertise:1;
+};
+
 /* Server -> Client */
 struct auth_client_handshake_reply {
 	unsigned int server_pid; /* unique auth process identifier */
-	enum auth_mech auth_mechanisms; /* valid authentication mechanisms */
+
+	uint32_t mech_count;
+	uint32_t data_size;
+	/* struct auth_client_handshake_mech_desc mech_desc[auth_mech_count]; */
 };
 
 /* New authentication request */
@@ -51,17 +48,24 @@
 	enum auth_client_request_type type; /* AUTH_CLIENT_REQUEST_NEW */
 	unsigned int id; /* unique ID for the request */
 
-	enum auth_mech mech;
 	enum auth_client_request_new_flags flags;
-	char protocol[AUTH_CLIENT_PROTOCOL_BUF_SIZE];
+
+	uint32_t protocol_idx;
+	uint32_t mech_idx;
+	uint32_t initial_resp_idx;
+
+	uint32_t data_size;
+	/* unsigned char data[]; */
 };
+#define AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request) \
+        ((request)->initial_resp_idx != (request)->data_size)
 
 /* 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;
+	uint32_t data_size;
 	/* unsigned char data[]; */
 };
 
@@ -73,10 +77,10 @@
 
 	/* 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 */
+	uint32_t username_idx; /* NUL-terminated */
+	uint32_t reply_idx; /* last, non-NUL terminated */
 
-	size_t data_size;
+	uint32_t data_size;
 	/* unsigned char data[]; */
 };
 

Index: auth-master-connection.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-connection.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- a/auth-master-connection.c	29 May 2004 16:43:22 -0000	1.6
+++ b/auth-master-connection.c	29 May 2004 21:40:30 -0000	1.7
@@ -182,6 +182,48 @@
 	}
 }
 
+static void master_get_handshake_reply(struct auth_master_connection *master)
+{
+	struct mech_module_list *list;
+	buffer_t *buf;
+	struct auth_client_handshake_reply reply;
+	struct auth_client_handshake_mech_desc mech_desc;
+	uint32_t mech_desc_offset;
+
+	memset(&reply, 0, sizeof(reply));
+	memset(&mech_desc, 0, sizeof(mech_desc));
+
+	reply.server_pid = master->pid;
+
+	buf = buffer_create_dynamic(default_pool, 128, (size_t)-1);
+
+	for (list = mech_modules; list != NULL; list = list->next)
+		reply.mech_count++;
+	buffer_set_used_size(buf, sizeof(reply) +
+			     sizeof(mech_desc) * reply.mech_count);
+
+	mech_desc_offset = sizeof(reply);
+	for (list = mech_modules; list != NULL; list = list->next) {
+		mech_desc.name_idx = buffer_get_used_size(buf) - sizeof(reply);
+		mech_desc.plaintext = list->module.plaintext;
+		mech_desc.advertise = list->module.advertise;
+
+		memcpy(buffer_get_space_unsafe(buf, mech_desc_offset,
+					       sizeof(mech_desc)),
+		       &mech_desc, sizeof(mech_desc));
+		buffer_append(buf, list->module.mech_name,
+			      strlen(list->module.mech_name) + 1);
+
+		mech_desc_offset += sizeof(mech_desc);
+	}
+
+	reply.data_size = buffer_get_used_size(buf);
+	memcpy(buffer_get_space_unsafe(buf, 0, sizeof(reply)),
+	       &reply, sizeof(reply));
+
+	master->handshake_reply = buffer_free_without_data(buf);
+}
+
 struct auth_master_connection *
 auth_master_connection_new(int fd, unsigned int pid)
 {
@@ -198,6 +240,7 @@
 						    MAX_OUTBUF_SIZE, FALSE);
 		conn->io = io_add(fd, IO_READ, master_input, conn);
 	}
+	master_get_handshake_reply(conn);
 	return conn;
 }
 
@@ -241,6 +284,7 @@
 		i_free(l[i]);
 	}
 	buffer_free(conn->listeners_buf);
+	conn->listeners_buf = NULL;
 
 	auth_master_connection_unref(conn);
 }
@@ -252,6 +296,7 @@
 
 	if (conn->output != NULL)
 		o_stream_unref(conn->output);
+	i_free(conn->handshake_reply);
 	i_free(conn);
 	return FALSE;
 }
@@ -280,7 +325,7 @@
 	l->master = conn;
 	l->fd = fd;
 	l->path = i_strdup(path);
-	l->io = io_add(fd, IO_READ, auth_accept, &l);
+	l->io = io_add(fd, IO_READ, auth_accept, l);
 
 	buffer_append(conn->listeners_buf, &l, sizeof(l));
 }

Index: auth-master-connection.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-connection.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- a/auth-master-connection.h	29 May 2004 16:43:22 -0000	1.2
+++ b/auth-master-connection.h	29 May 2004 21:40:30 -0000	1.3
@@ -15,7 +15,7 @@
 	unsigned int request_pos;
 	unsigned char request_buf[sizeof(struct auth_master_request)];
 
-	struct auth_client_handshake_reply handshake_reply;
+	struct auth_client_handshake_reply *handshake_reply;
 	struct auth_client_connection *clients;
 	struct timeout *to_clients;
 

Index: auth-master-interface.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-interface.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- a/auth-master-interface.h	22 Aug 2003 02:42:13 -0000	1.3
+++ b/auth-master-interface.h	29 May 2004 21:40:30 -0000	1.4
@@ -21,11 +21,11 @@
 	/* variable width fields are packed into data[]. These variables
 	   contain indexes to the data, they're all NUL-terminated.
 	   Ignore if it points outside data_size. */
-	size_t system_user_idx;
-	size_t virtual_user_idx;
-	size_t home_idx, mail_idx, chroot_idx;
+	uint32_t system_user_idx;
+	uint32_t virtual_user_idx;
+	uint32_t home_idx, mail_idx, chroot_idx;
 
-	size_t data_size;
+	uint32_t data_size;
 	/* unsigned char data[]; */
 };
 

Index: main.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/main.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- a/main.c	29 May 2004 16:43:22 -0000	1.23
+++ b/main.c	29 May 2004 21:40:30 -0000	1.24
@@ -132,7 +132,7 @@
 		env = getenv("AUTH_SOCKETS");
 	}
 
-	if (env != NULL) {
+	if (env != NULL && *env != '\0') {
 		master = auth_master_connection_new(-1, 0);
 		master_add_unix_listeners(master, env);
 		auth_client_connections_init(master);

Index: mech-anonymous.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-anonymous.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- a/mech-anonymous.c	22 Aug 2003 04:57:49 -0000	1.3
+++ b/mech-anonymous.c	29 May 2004 21:40:30 -0000	1.4
@@ -5,15 +5,14 @@
 
 static int
 mech_anonymous_auth_continue(struct auth_request *auth_request,
-			     struct auth_client_request_continue *request,
-			     const unsigned char *data,
+			     const unsigned char *data, size_t data_size,
 			     mech_callback_t *callback)
 {
 	i_assert(anonymous_username != NULL);
 
 	if (verbose) {
 		i_info("mech-anonymous: login by %s",
-		       t_strndup(data, request->data_size));
+		       t_strndup(data, data_size));
 	}
 
 	auth_request->callback = callback;
@@ -22,37 +21,62 @@
 	return TRUE;
 }
 
+static int
+mech_anonymous_auth_initial(struct auth_request *auth_request,
+			    struct auth_client_request_new *request,
+			    const unsigned char *data,
+			    mech_callback_t *callback)
+{
+	struct auth_client_request_reply reply;
+	size_t data_size;
+
+	if (AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) {
+		data += request->initial_resp_idx;
+		data_size = request->data_size - request->initial_resp_idx;
+
+		return auth_request->auth_continue(auth_request, data,
+						   data_size, callback);
+	}
+
+	/* initialize reply */
+	memset(&reply, 0, sizeof(reply));
+	reply.id = auth_request->id;
+	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
+
+	callback(&reply, NULL, auth_request->conn);
+	return TRUE;
+}
+
 static void
 mech_anonymous_auth_free(struct auth_request *auth_request)
 {
 	pool_unref(auth_request->pool);
 }
 
-static struct auth_request *
-mech_anonymous_auth_new(struct auth_client_connection *conn, unsigned int id,
-			mech_callback_t *callback)
+static struct auth_request *mech_anonymous_auth_new(void)
 {
         struct auth_request *auth_request;
-	struct auth_client_request_reply reply;
 	pool_t pool;
 
 	pool = pool_alloconly_create("anonymous_auth_request", 256);
 	auth_request = p_new(pool, struct auth_request, 1);
 	auth_request->refcount = 1;
 	auth_request->pool = pool;
+	auth_request->auth_initial = mech_anonymous_auth_initial;
 	auth_request->auth_continue = mech_anonymous_auth_continue;
         auth_request->auth_free = mech_anonymous_auth_free;
 
-	/* initialize reply */
-	memset(&reply, 0, sizeof(reply));
-	reply.id = id;
-	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
-
-	callback(&reply, NULL, conn);
 	return auth_request;
 }
 
 struct mech_module mech_anonymous = {
-	AUTH_MECH_ANONYMOUS,
+	"ANONYMOUS",
+
+	MEMBER(plaintext) FALSE,
+	MEMBER(advertise) TRUE,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) FALSE,
+
 	mech_anonymous_auth_new
 };

Index: mech-cram-md5.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-cram-md5.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- a/mech-cram-md5.c	11 Nov 2003 09:59:27 -0000	1.3
+++ b/mech-cram-md5.c	29 May 2004 21:40:30 -0000	1.4
@@ -149,15 +149,14 @@
 
 static int
 mech_cram_md5_auth_continue(struct auth_request *auth_request,
-	struct auth_client_request_continue *request __attr_unused__,
-	const unsigned char *data,
-	mech_callback_t *callback)
+			    const unsigned char *data, size_t data_size,
+			    mech_callback_t *callback)
 {
 	struct cram_auth_request *auth =
 		(struct cram_auth_request *)auth_request;
 	const char *error;
 
-	if (parse_cram_response(auth, data, request->data_size, &error)) {
+	if (parse_cram_response(auth, data, data_size, &error)) {
 		auth_request->callback = callback;
 
 		auth_request->user =
@@ -186,16 +185,43 @@
 	return FALSE;
 }
 
+static int
+mech_cram_md5_auth_initial(struct auth_request *auth_request,
+			   struct auth_client_request_new *request,
+			   const unsigned char *data __attr_unused__,
+			   mech_callback_t *callback)
+{
+	struct cram_auth_request *auth =
+		(struct cram_auth_request *)auth_request;
+
+	struct auth_client_request_reply reply;
+
+	if (AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) {
+		/* No initial response in CRAM-MD5 */
+		return FALSE;
+	}
+
+	auth->challenge = p_strdup(auth->pool, get_cram_challenge());
+
+	/* initialize reply */
+	mech_init_auth_client_reply(&reply);
+	reply.id = request->id;
+	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
+
+	/* send the initial challenge */
+	reply.reply_idx = 0;
+	reply.data_size = strlen(auth->challenge);
+	callback(&reply, auth->challenge, auth_request->conn);
+	return TRUE;
+}
+
 static void mech_cram_md5_auth_free(struct auth_request *auth_request)
 {
 	pool_unref(auth_request->pool);
 }
 
-static struct auth_request *
-mech_cram_md5_auth_new(struct auth_client_connection *conn,
-		       unsigned int id, mech_callback_t *callback)
+static struct auth_request *mech_cram_md5_auth_new(void)
 {
-	struct auth_client_request_reply reply;
 	struct cram_auth_request *auth;
 	pool_t pool;
 
@@ -205,25 +231,21 @@
 
 	auth->auth_request.refcount = 1;
 	auth->auth_request.pool = pool;
+	auth->auth_request.auth_initial = mech_cram_md5_auth_initial;
 	auth->auth_request.auth_continue = mech_cram_md5_auth_continue;
 	auth->auth_request.auth_free = mech_cram_md5_auth_free;
 
-	auth->challenge = p_strdup(auth->pool, get_cram_challenge());
-
-	/* initialize reply */
-	mech_init_auth_client_reply(&reply);
-	reply.id = id;
-	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
-
-	/* send the initial challenge */
-	reply.reply_idx = 0;
-	reply.data_size = strlen(auth->challenge);
-	callback(&reply, auth->challenge, conn);
-
 	return &auth->auth_request;
 }
 
 struct mech_module mech_cram_md5 = {
-	AUTH_MECH_CRAM_MD5,
+	"CRAM-MD5",
+
+	MEMBER(plaintext) FALSE,
+	MEMBER(advertise) TRUE,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) TRUE,
+
 	mech_cram_md5_auth_new
 };

Index: mech-digest-md5.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-digest-md5.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- a/mech-digest-md5.c	6 Jan 2004 05:09:22 -0000	1.19
+++ b/mech-digest-md5.c	29 May 2004 21:40:30 -0000	1.20
@@ -525,8 +525,7 @@
 
 static int
 mech_digest_md5_auth_continue(struct auth_request *auth_request,
-			      struct auth_client_request_continue *request,
-			      const unsigned char *data,
+			      const unsigned char *data, size_t data_size,
 			      mech_callback_t *callback)
 {
 	struct digest_auth_request *auth =
@@ -536,7 +535,7 @@
 
 	/* initialize reply */
 	mech_init_auth_client_reply(&reply);
-	reply.id = request->id;
+	reply.id = auth_request->id;
 
 	if (auth->authenticated) {
 		/* authentication is done, we were just waiting the last
@@ -545,7 +544,7 @@
 		return TRUE;
 	}
 
-	if (parse_digest_response(auth, data, request->data_size, &error)) {
+	if (parse_digest_response(auth, data, data_size, &error)) {
 		auth_request->callback = callback;
 
 		realm = auth->realm != NULL ? auth->realm : default_realm;
@@ -582,19 +581,50 @@
 	return FALSE;
 }
 
+static int
+mech_digest_md5_auth_initial(struct auth_request *auth_request,
+			     struct auth_client_request_new *request,
+			     const unsigned char *data __attr_unused__,
+			     mech_callback_t *callback)
+{
+	struct digest_auth_request *auth =
+		(struct digest_auth_request *)auth_request;
+	struct auth_client_request_reply reply;
+	string_t *challenge;
+	size_t data_size;
+
+	if (AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) {
+		/* FIXME: support subsequent authentication? */
+		data += request->initial_resp_idx;
+		data_size = request->data_size - request->initial_resp_idx;
+
+		return auth_request->auth_continue(auth_request, data,
+						   data_size, callback);
+	}
+
+	/* initialize reply */
+	mech_init_auth_client_reply(&reply);
+	reply.id = request->id;
+	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
+
+	/* send the initial challenge */
+	reply.reply_idx = 0;
+	challenge = get_digest_challenge(auth);
+	reply.data_size = str_len(challenge);
+	callback(&reply, str_data(challenge), auth_request->conn);
+	return TRUE;
+}
+
 static void mech_digest_md5_auth_free(struct auth_request *auth_request)
 {
 	pool_unref(auth_request->pool);
 }
 
 static struct auth_request *
-mech_digest_md5_auth_new(struct auth_client_connection *conn,
-			 unsigned int id, mech_callback_t *callback)
+mech_digest_md5_auth_new(void)
 {
-	struct auth_client_request_reply reply;
 	struct digest_auth_request *auth;
 	pool_t pool;
-	string_t *challenge;
 
 	pool = pool_alloconly_create("digest_md5_auth_request", 2048);
 	auth = p_new(pool, struct digest_auth_request, 1);
@@ -602,25 +632,21 @@
 
 	auth->auth_request.refcount = 1;
 	auth->auth_request.pool = pool;
+	auth->auth_request.auth_initial = mech_digest_md5_auth_initial;
 	auth->auth_request.auth_continue = mech_digest_md5_auth_continue;
 	auth->auth_request.auth_free = mech_digest_md5_auth_free;
 	auth->qop = QOP_AUTH;
-
-	/* initialize reply */
-	mech_init_auth_client_reply(&reply);
-	reply.id = id;
-	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
-
-	/* send the initial challenge */
-	reply.reply_idx = 0;
-	challenge = get_digest_challenge(auth);
-	reply.data_size = str_len(challenge);
-	callback(&reply, str_data(challenge), conn);
-
 	return &auth->auth_request;
 }
 
 struct mech_module mech_digest_md5 = {
-	AUTH_MECH_DIGEST_MD5,
+	"DIGEST-MD5",
+
+	MEMBER(plaintext) FALSE,
+	MEMBER(advertise) TRUE,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) TRUE,
+
 	mech_digest_md5_auth_new
 };

Index: mech-plain.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech-plain.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- a/mech-plain.c	21 Sep 2003 16:21:36 -0000	1.16
+++ b/mech-plain.c	29 May 2004 21:40:30 -0000	1.17
@@ -13,8 +13,8 @@
 
 static int
 mech_plain_auth_continue(struct auth_request *auth_request,
-			 struct auth_client_request_continue *request,
-			 const unsigned char *data, mech_callback_t *callback)
+			 const unsigned char *data, size_t data_size,
+			 mech_callback_t *callback)
 {
 	const char *authid, *authenid;
 	char *pass;
@@ -28,13 +28,13 @@
 	authenid = NULL; pass = "";
 
 	count = 0;
-	for (i = 0; i < request->data_size; i++) {
+	for (i = 0; i < data_size; i++) {
 		if (data[i] == '\0') {
 			if (++count == 1)
 				authenid = (const char *) data + i+1;
 			else {
 				i++;
-				len = request->data_size - i;
+				len = data_size - i;
 				pass = p_strndup(unsafe_data_stack_pool,
 						 data+i, len);
 				break;
@@ -76,37 +76,61 @@
 	return TRUE;
 }
 
+static int
+mech_plain_auth_initial(struct auth_request *auth_request,
+			struct auth_client_request_new *request,
+			const unsigned char *data,
+			mech_callback_t *callback)
+{
+	struct auth_client_request_reply reply;
+	size_t data_size;
+
+	if (AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) {
+		data += request->initial_resp_idx;
+		data_size = request->data_size - request->initial_resp_idx;
+
+		return auth_request->auth_continue(auth_request, data,
+						   data_size, callback);
+	}
+
+	/* initialize reply */
+	memset(&reply, 0, sizeof(reply));
+	reply.id = request->id;
+	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
+
+	callback(&reply, NULL, auth_request->conn);
+	return TRUE;
+}
+
 static void
 mech_plain_auth_free(struct auth_request *auth_request)
 {
 	pool_unref(auth_request->pool);
 }
 
-static struct auth_request *
-mech_plain_auth_new(struct auth_client_connection *conn, unsigned int id,
-		    mech_callback_t *callback)
+static struct auth_request *mech_plain_auth_new(void)
 {
         struct auth_request *auth_request;
-	struct auth_client_request_reply reply;
 	pool_t pool;
 
 	pool = pool_alloconly_create("plain_auth_request", 256);
 	auth_request = p_new(pool, struct auth_request, 1);
 	auth_request->refcount = 1;
 	auth_request->pool = pool;
+	auth_request->auth_initial = mech_plain_auth_initial;
 	auth_request->auth_continue = mech_plain_auth_continue;
         auth_request->auth_free = mech_plain_auth_free;
-
-	/* initialize reply */
-	memset(&reply, 0, sizeof(reply));
-	reply.id = id;
-	reply.result = AUTH_CLIENT_RESULT_CONTINUE;
-
-	callback(&reply, NULL, conn);
 	return auth_request;
 }
 
 struct mech_module mech_plain = {
-	AUTH_MECH_PLAIN,
+	"PLAIN",
+
+	MEMBER(plaintext) TRUE,
+	MEMBER(advertise) FALSE,
+
+	MEMBER(passdb_need_plain) TRUE,
+	MEMBER(passdb_need_credentials) FALSE,
+
 	mech_plain_auth_new
 };

Index: mech.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- a/mech.c	29 May 2004 17:06:50 -0000	1.21
+++ b/mech.c	29 May 2004 21:40:30 -0000	1.22
@@ -5,19 +5,14 @@
 #include "buffer.h"
 #include "hash.h"
 #include "mech.h"
+#include "str.h"
 #include "var-expand.h"
 #include "auth-client-connection.h"
 #include "auth-master-connection.h"
 
 #include <stdlib.h>
 
-struct mech_module_list {
-	struct mech_module_list *next;
-
-	struct mech_module module;
-};
-
-enum auth_mech auth_mechanisms;
+struct mech_module_list *mech_modules;
 const char *const *auth_realms;
 const char *default_realm;
 const char *anonymous_username;
@@ -25,17 +20,12 @@
 
 static int set_use_cyrus_sasl;
 static int ssl_require_client_cert;
-static struct mech_module_list *mech_modules;
 static struct auth_client_request_reply failure_reply;
 
 void mech_register_module(struct mech_module *module)
 {
 	struct mech_module_list *list;
 
-	i_assert((auth_mechanisms & module->mech) == 0);
-
-	auth_mechanisms |= module->mech;
-
 	list = i_new(struct mech_module_list, 1);
 	list->module = *module;
 
@@ -47,13 +37,8 @@
 {
 	struct mech_module_list **pos, *list;
 
-	if ((auth_mechanisms & module->mech) == 0)
-		return; /* not registered */
-
-        auth_mechanisms &= ~module->mech;
-
 	for (pos = &mech_modules; *pos != NULL; pos = &(*pos)->next) {
-		if ((*pos)->module.mech == module->mech) {
+		if (strcmp((*pos)->module.mech_name, module->mech_name) == 0) {
 			list = *pos;
 			*pos = (*pos)->next;
 			i_free(list);
@@ -62,17 +47,56 @@
 	}
 }
 
+const string_t *auth_mechanisms_get_list(void)
+{
+	struct mech_module_list *list;
+	string_t *str;
+
+	str = t_str_new(128);
+	for (list = mech_modules; list != NULL; list = list->next)
+		str_append(str, list->module.mech_name);
+
+	return str;
+}
+
+static struct mech_module *mech_module_find(const char *name)
+{
+	struct mech_module_list *list;
+
+	for (list = mech_modules; list != NULL; list = list->next) {
+		if (strcmp(list->module.mech_name, name) == 0)
+			return &list->module;
+	}
+	return NULL;
+}
+
 void mech_request_new(struct auth_client_connection *conn,
 		      struct auth_client_request_new *request,
+		      const unsigned char *data,
 		      mech_callback_t *callback)
 {
-	struct mech_module_list *list;
+        struct mech_module *mech;
 	struct auth_request *auth_request;
 
-	if ((auth_mechanisms & request->mech) == 0) {
+	/* make sure data is NUL-terminated */
+	if (request->data_size == 0 || request->initial_resp_idx == 0 ||
+	    request->mech_idx >= request->data_size ||
+	    request->protocol_idx >= request->data_size ||
+	    request->initial_resp_idx > request->data_size ||
+	    data[request->initial_resp_idx-1] != '\0') {
+		i_error("BUG: Auth client %u sent corrupted request",
+			conn->pid);
+		failure_reply.id = request->id;
+		callback(&failure_reply, NULL, conn);
+		return;
+	}
+
+	mech = mech_module_find((const char *)data + request->mech_idx);
+	if (mech == NULL) {
 		/* unsupported mechanism */
 		i_error("BUG: Auth client %u requested unsupported "
-			"auth mechanism %d", conn->pid, request->mech);
+			"auth mechanism %s", conn->pid,
+			(const char *)data + request->mech_idx);
 		failure_reply.id = request->id;
 		callback(&failure_reply, NULL, conn);
 		return;
@@ -89,32 +113,26 @@
 	}
 
 #ifdef USE_CYRUS_SASL2
-	if (set_use_cyrus_sasl) {
+	if (set_use_cyrus_sasl)
 		auth_request = mech_cyrus_sasl_new(conn, request, callback);
-	} else
+	else
 #endif
-	{
-		auth_request = NULL;
-
-		for (list = mech_modules; list != NULL; list = list->next) {
-			if (list->module.mech == request->mech) {
-				auth_request =
-					list->module.auth_new(conn, request->id,
-							      callback);
-				break;
-			}
-		}
-	}
+		auth_request = mech->auth_new();
 
 	if (auth_request != NULL) {
 		auth_request->created = ioloop_time;
 		auth_request->conn = conn;
 		auth_request->id = request->id;
-		strocpy(auth_request->protocol, request->protocol,
-			sizeof(auth_request->protocol));
+		auth_request->protocol =
+			p_strdup(auth_request->pool,
+				 (const char *)data + request->protocol_idx);
 
 		hash_insert(conn->auth_requests, POINTER_CAST(request->id),
 			    auth_request);
+
+		if (!auth_request->auth_initial(auth_request, request, data,
+						callback))
+			mech_request_free(auth_request, request->id);
 	}
 }
 
@@ -133,7 +151,8 @@
 		callback(&failure_reply, NULL, conn);
 	} else {
 		if (!auth_request->auth_continue(auth_request,
-						 request, data, callback))
+						 data, request->data_size,
+						 callback))
 			mech_request_free(auth_request, request->id);
 	}
 }
@@ -276,7 +295,6 @@
 	const char *env;
 
         mech_modules = NULL;
-	auth_mechanisms = 0;
 
 	memset(&failure_reply, 0, sizeof(failure_reply));
 	failure_reply.result = AUTH_CLIENT_RESULT_FAILURE;
@@ -312,7 +330,7 @@
 		mechanisms++;
 	}
 
-	if (auth_mechanisms == 0)
+	if (mech_modules == NULL)
 		i_fatal("No authentication mechanisms configured");
 
 	/* get our realm - note that we allocate from data stack so

Index: mech.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/mech.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- a/mech.h	29 May 2004 17:06:50 -0000	1.15
+++ b/mech.h	29 May 2004 21:40:30 -0000	1.16
@@ -19,26 +19,38 @@
 	unsigned int id;
 	time_t created;
 
-	char protocol[AUTH_CLIENT_PROTOCOL_BUF_SIZE];
+	char *protocol;
 	mech_callback_t *callback;
 
+	int (*auth_initial)(struct auth_request *auth_request,
+                            struct auth_client_request_new *request,
+			    const unsigned char *data,
+			    mech_callback_t *callback);
 	int (*auth_continue)(struct auth_request *auth_request,
-			     struct auth_client_request_continue *request,
-			     const unsigned char *data,
+			     const unsigned char *data, size_t data_size,
 			     mech_callback_t *callback);
 	void (*auth_free)(struct auth_request *auth_request);
 	/* ... mechanism specific data ... */
 };
 
 struct mech_module {
-	enum auth_mech mech;
+	const char *mech_name;
 
-	struct auth_request *(*auth_new)(struct auth_client_connection *conn,
-					 unsigned int id,
-					 mech_callback_t *callback);
+	unsigned int plaintext:1;
+	unsigned int advertise:1;
+	unsigned int passdb_need_plain:1;
+	unsigned int passdb_need_credentials:1;
+
+	struct auth_request *(*auth_new)(void);
 };
 
-extern enum auth_mech auth_mechanisms;
+struct mech_module_list {
+	struct mech_module_list *next;
+
+	struct mech_module module;
+};
+
+extern struct mech_module_list *mech_modules;
 extern const char *const *auth_realms;
 extern const char *default_realm;
 extern const char *anonymous_username;
@@ -48,8 +60,11 @@
 void mech_register_module(struct mech_module *module);
 void mech_unregister_module(struct mech_module *module);
 
+const string_t *auth_mechanisms_get_list(void);
+
 void mech_request_new(struct auth_client_connection *conn,
 		      struct auth_client_request_new *request,
+		      const unsigned char *data,
 		      mech_callback_t *callback);
 void mech_request_continue(struct auth_client_connection *conn,
 			   struct auth_client_request_continue *request,
@@ -70,6 +85,7 @@
 struct auth_request *
 mech_cyrus_sasl_new(struct auth_client_connection *conn,
 		    struct auth_client_request_new *request,
+		    const unsigned char *data,
 		    mech_callback_t *callback);
 
 void auth_request_ref(struct auth_request *request);

Index: passdb.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- a/passdb.c	10 May 2004 01:47:09 -0000	1.14
+++ b/passdb.c	29 May 2004 21:40:30 -0000	1.15
@@ -71,6 +71,26 @@
 	callback(password, auth_request);
 }
 
+static void
+mech_list_verify_passdb(struct passdb_module *passdb, const char *name)
+{
+	struct mech_module_list *list;
+
+	for (list = mech_modules; list != NULL; list = list->next) {
+		if (list->module.passdb_need_plain &&
+		    passdb->verify_plain == NULL)
+			break;
+		if (list->module.passdb_need_credentials &&
+		    passdb->lookup_credentials == NULL)
+			break;
+	}
+
+	if (list != NULL) {
+		i_fatal("Passdb %s doesn't support %s method",
+			name, list->module.mech_name);
+	}
+}
+
 void passdb_init(void)
 {
 	const char *name, *args;
@@ -135,17 +155,7 @@
 	if (passdb->init != NULL)
 		passdb->init(args != NULL ? args+1 : "");
 
-	if ((auth_mechanisms & AUTH_MECH_PLAIN) &&
-	    passdb->verify_plain == NULL)
-		i_fatal("Passdb %s doesn't support PLAIN method", name);
-
-	if ((auth_mechanisms & AUTH_MECH_CRAM_MD5) &&
-	    passdb->lookup_credentials == NULL)
-		i_fatal("Passdb %s doesn't support CRAM-MD5 method", name);
-
-	if ((auth_mechanisms & AUTH_MECH_DIGEST_MD5) &&
-	    passdb->lookup_credentials == NULL)
-		i_fatal("Passdb %s doesn't support DIGEST-MD5 method", name);
+	mech_list_verify_passdb(passdb, name);
 }
 
 void passdb_deinit(void)

--- auth-mech-desc.h DELETED ---



More information about the dovecot-cvs mailing list