changeset 907:218e68ab290d HEAD

Initial support for Cyrus SASL 2 library. I couldn't get it to work yet though :)
author Timo Sirainen <tss@iki.fi>
date Sun, 05 Jan 2003 17:19:50 +0200
parents b176f913d092
children bc55266563cd
files configure.in src/auth/Makefile.am src/auth/auth-cyrus-sasl2.c src/auth/auth-digest-md5.c src/auth/auth-interface.h src/auth/auth-mech-desc.h src/auth/auth-plain.c src/auth/auth.c src/auth/auth.h src/auth/login-connection.c src/auth/userinfo.c src/login/auth-connection.c src/login/auth-connection.h src/login/client-authenticate.c src/master/auth-process.c src/master/settings.c src/master/settings.h
diffstat 17 files changed, 414 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Sun Jan 05 15:19:09 2003 +0200
+++ b/configure.in	Sun Jan 05 17:19:50 2003 +0200
@@ -97,6 +97,15 @@
 	fi,
 	want_vpopmail=yes)
 
+AC_ARG_WITH(cyrus-sasl2,
+[  --with-cyrus-sasl2      Build with Cyrus SASL 2 library support],
+	if test x$withval = xno; then
+		want_cyrus_sasl2=no
+	else
+		want_cyrus_sasl2=yes
+	fi,
+	want_cyrus_sasl2=no)
+
 AC_ARG_WITH(rawlog,
 [  --with-rawlog           Build support for logging user traffic],
 	if test x$withval = xyes; then
@@ -703,6 +712,18 @@
 AC_SUBST(VPOPMAIL_CFLAGS)
 AC_SUBST(VPOPMAIL_LIBS)
 
+if test $want_cyrus_sasl2 = yes; then
+	AC_CHECK_LIB(sasl2, sasl_server_start, [
+		AC_CHECK_HEADER(sasl/sasl.h, [
+			AC_DEFINE(USE_CYRUS_SASL2,,
+				  Define if you want to use Cyrus SASL library)
+			SASL_LIBS="-lsasl2"
+		])
+	])
+fi
+
+AC_SUBST(SASL_LIBS)
+
 if test $need_crypt = yes; then
 	AC_CHECK_LIB(crypt, crypt, [
 		USERINFO_LIBS="$USERINFO_LIBS -lcrypt"
--- a/src/auth/Makefile.am	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/Makefile.am	Sun Jan 05 17:19:50 2003 +0200
@@ -9,10 +9,12 @@
 imap_auth_LDADD = \
 	../lib/liblib.a \
 	$(USERINFO_LIBS) \
+	$(SASL_LIBS) \
 	$(VPOPMAIL_LIBS)
 
 imap_auth_SOURCES = \
 	auth.c \
+	auth-cyrus-sasl2.c \
 	auth-plain.c \
 	auth-digest-md5.c \
 	cookie.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/auth-cyrus-sasl2.c	Sun Jan 05 17:19:50 2003 +0200
@@ -0,0 +1,239 @@
+/* Copyright (C) 2003 Timo Sirainen */
+
+#include "common.h"
+#include "auth.h"
+#include "cookie.h"
+
+#ifdef USE_CYRUS_SASL2
+
+#include <stdlib.h>
+#include <sasl/sasl.h>
+
+#include "auth-mech-desc.h"
+
+struct auth_context {
+	sasl_conn_t *conn;
+	int success;
+};
+
+static const char *auth_mech_to_str(enum auth_mech mech)
+{
+	int i;
+
+	for (i = 0; i < AUTH_MECH_COUNT; i++) {
+		if (auth_mech_desc[i].mech == mech)
+			return auth_mech_desc[i].name;
+	}
+
+	return NULL;
+}
+
+static void auth_sasl_continue(struct cookie_data *cookie,
+			       struct auth_continued_request_data *request,
+			       const unsigned char *data,
+			       AuthCallback callback, void *context)
+{
+	struct auth_context *ctx = cookie->context;
+	struct auth_reply_data reply;
+	const char *serverout;
+	unsigned int serveroutlen;
+	int ret;
+
+	ret = sasl_server_step(ctx->conn, data, request->data_size,
+			       &serverout, &serveroutlen);
+
+	memset(&reply, 0, sizeof(reply));
+	reply.id = request->id;
+	memcpy(reply.cookie, cookie->cookie, AUTH_COOKIE_SIZE);
+
+	if (ret == SASL_CONTINUE) {
+		reply.result = AUTH_RESULT_CONTINUE;
+	} else if (ret == SASL_OK) {
+		/* success */
+		reply.result = AUTH_RESULT_SUCCESS;
+		ctx->success = TRUE;
+	} else {
+		/* failure */
+		reply.result = AUTH_RESULT_FAILURE;
+		cookie_remove(cookie->cookie);
+	}
+
+	reply.data_size = serveroutlen;
+        callback(&reply, serverout, context);
+}
+
+static int auth_sasl_fill_reply(struct cookie_data *cookie,
+				struct auth_cookie_reply_data *reply)
+{
+	struct auth_context *ctx = cookie->context;
+	const char *canon_user;
+        const struct propval *prop;
+	int ret;
+
+	if (!ctx->success)
+		return FALSE;
+
+	/* get our username */
+	ret = sasl_getprop(ctx->conn, SASL_USERNAME,
+			   (const void **) &canon_user);
+	if (ret != SASL_OK) {
+		i_warning("sasl_getprop() failed: %s",
+			  sasl_errstring(ret, NULL, NULL));
+		return FALSE;
+	}
+
+	memset(reply, 0, sizeof(*reply));
+	reply->success = TRUE;
+
+	if (strocpy(reply->virtual_user, canon_user,
+		    sizeof(reply->virtual_user)) < 0)
+		i_panic("virtual_user overflow");
+
+	/* get other properties */
+	prop = prop_get(sasl_auxprop_getctx(ctx->conn));
+	for (; prop != NULL && prop->name != NULL; prop++) {
+		if (prop->nvalues == 0 || prop->values[0] == NULL)
+			continue;
+
+		if (strcasecmp(prop->name, SASL_AUX_UIDNUM) == 0)
+			reply->uid = atoi(prop->values[0]);
+		else if (strcasecmp(prop->name, SASL_AUX_GIDNUM) == 0)
+			reply->gid = atoi(prop->values[0]);
+		else if (strcasecmp(prop->name, SASL_AUX_HOMEDIR) == 0) {
+			if (strocpy(reply->home, prop->values[0],
+				    sizeof(reply->home)) < 0)
+				i_panic("home overflow");
+		} else if (strcasecmp(prop->name, SASL_AUX_UNIXMBX) == 0) {
+			if (strocpy(reply->mail, prop->values[0],
+				    sizeof(reply->mail)) < 0)
+				i_panic("mail overflow");
+		}
+	}
+
+	return TRUE;
+}
+
+static void auth_sasl_free(struct cookie_data *cookie)
+{
+	struct auth_context *ctx = cookie->context;
+
+	sasl_dispose(&ctx->conn);
+	i_free(ctx);
+	i_free(cookie);
+}
+
+void auth_cyrus_sasl_init(unsigned int login_pid,
+			  struct auth_init_request_data *request,
+			  AuthCallback callback, void *context)
+{
+	static const char *propnames[] = {
+		SASL_AUX_UIDNUM,
+		SASL_AUX_GIDNUM,
+		SASL_AUX_HOMEDIR,
+		SASL_AUX_UNIXMBX,
+		NULL
+	};
+	struct cookie_data *cookie;
+	struct auth_reply_data reply;
+	struct auth_context *ctx;
+	const char *mech, *serverout;
+	unsigned int serveroutlen;
+	sasl_security_properties_t sec_props;
+	sasl_conn_t *conn;
+	int ret;
+
+	mech = auth_mech_to_str(request->mech);
+	if (mech == NULL)
+		i_fatal("Login asked for unknown mechanism %d", request->mech);
+
+	/* create new SASL connection */
+	ret = sasl_server_new("imap", NULL, NULL, NULL, NULL, NULL, 0, &conn);
+	if (ret != SASL_OK) {
+		i_fatal("sasl_server_new() failed: %s",
+			sasl_errstring(ret, NULL, NULL));
+	}
+
+	/* don't allow SASL security layer */
+	memset(&sec_props, 0, sizeof(sec_props));
+	sec_props.min_ssf = 0;
+	sec_props.max_ssf = 1;
+
+	if (sasl_setprop(conn, SASL_SEC_PROPS, &sec_props) != SASL_OK) {
+		i_fatal("sasl_setprop(SASL_SEC_PROPS) failed: %s",
+			sasl_errstring(ret, NULL, NULL));
+	}
+
+	ret = sasl_auxprop_request(conn, propnames);
+	if (ret != SASL_OK) {
+		i_fatal("sasl_auxprop_request() failed: %s",
+			sasl_errstring(ret, NULL, NULL));
+	}
+
+	/* initialize reply */
+	memset(&reply, 0, sizeof(reply));
+	reply.id = request->id;
+
+	/* start the exchange */
+	ret = sasl_server_start(conn, mech, NULL, 0, &serverout, &serveroutlen);
+	if (ret != SASL_CONTINUE) {
+		reply.result = AUTH_RESULT_FAILURE;
+		serverout = NULL;
+		serveroutlen = 0;
+		sasl_dispose(&conn);
+	} else {
+		cookie = i_new(struct cookie_data, 1);
+		cookie->login_pid = login_pid;
+		cookie->auth_fill_reply = auth_sasl_fill_reply;
+		cookie->auth_continue = auth_sasl_continue;
+		cookie->free = auth_sasl_free;
+		ctx = cookie->context = i_new(struct auth_context, 1);
+		ctx->conn = conn;
+
+		cookie_add(cookie);
+
+		reply.result = AUTH_RESULT_CONTINUE;
+		memcpy(reply.cookie, cookie->cookie, AUTH_COOKIE_SIZE);
+	}
+
+	reply.data_size = serveroutlen;
+	callback(&reply, serverout, context);
+}
+
+static int sasl_log(void *context __attr_unused__,
+		    int level, const char *message)
+{
+	switch (level) {
+	case SASL_LOG_ERR:
+		i_error("SASL authentication error: %s", message);
+		break;
+	case SASL_LOG_WARN:
+		i_warning("SASL authentication warning: %s", message);
+		break;
+	case SASL_LOG_NOTE:
+		/*i_info("SASL authentication info: %s", message);*/
+		break;
+	case SASL_LOG_FAIL:
+		/*i_info("SASL authentication failure: %s", message);*/
+		break;
+	}
+
+	return SASL_OK;
+}
+
+static const struct sasl_callback sasl_callbacks[] = {
+	{ SASL_CB_LOG, &sasl_log, NULL },
+	{ SASL_CB_LIST_END, NULL, NULL }
+};
+
+void auth_cyrus_sasl_init_lib(void)
+{
+	int ret;
+
+	ret = sasl_server_init(sasl_callbacks, "imap-auth");
+	if (ret != SASL_OK) {
+		i_fatal("sasl_server_init() failed: %s",
+			sasl_errstring(ret, NULL, NULL));
+	}
+}
+
+#endif
--- a/src/auth/auth-digest-md5.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/auth-digest-md5.c	Sun Jan 05 17:19:50 2003 +0200
@@ -548,15 +548,14 @@
 		reply.result = AUTH_RESULT_CONTINUE;
 
 		reply.data_size = strlen(auth->rspauth);
-		callback(&reply, (const unsigned char *) auth->rspauth,
-			 context);
+		callback(&reply, auth->rspauth, context);
 		auth->authenticated = TRUE;
 		return;
 	}
 
 	/* failed */
 	reply.result = AUTH_RESULT_FAILURE;
-	callback(&reply, (const unsigned char *) error, context);
+	callback(&reply, error, context);
 	cookie_remove(cookie->cookie);
 }
 
@@ -614,12 +613,12 @@
 
 	challenge = get_digest_challenge(auth);
 	reply.data_size = strlen(challenge);
-	callback(&reply, (const unsigned char *) challenge, context);
+	callback(&reply, challenge, context);
 
 	t_pop();
 }
 
 struct auth_module auth_digest_md5 = {
-	AUTH_METHOD_DIGEST_MD5,
+	AUTH_MECH_DIGEST_MD5,
 	auth_digest_md5_init
 };
--- a/src/auth/auth-interface.h	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/auth-interface.h	Sun Jan 05 17:19:50 2003 +0200
@@ -25,17 +25,17 @@
 	AUTH_RESULT_FAILURE
 };
 
-enum auth_method {
-	AUTH_METHOD_PLAIN	= 0x01,
-	AUTH_METHOD_DIGEST_MD5	= 0x02,
+enum auth_mech {
+	AUTH_MECH_PLAIN		= 0x01,
+	AUTH_MECH_DIGEST_MD5	= 0x02,
 
-	AUTH_METHODS_COUNT	= 2
+	AUTH_MECH_COUNT		= 2
 };
 
 /* Initialization reply, sent after client is connected */
 struct auth_init_data {
 	unsigned int auth_process; /* unique auth process identifier */
-	enum auth_method auth_methods; /* valid authentication methods */
+	enum auth_mech auth_mechanisms; /* valid authentication mechanisms */
 };
 
 /* Initialization handshake from client. */
@@ -47,7 +47,7 @@
 struct auth_init_request_data {
 	enum auth_request_type type; /* AUTH_REQUEST_INIT */
 
-	enum auth_method method;
+	enum auth_mech mech;
 	unsigned int id; /* AuthReplyData.id will contain this value */
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/auth-mech-desc.h	Sun Jan 05 17:19:50 2003 +0200
@@ -0,0 +1,16 @@
+#ifndef __AUTH_MECH_DESC_H
+#define __AUTH_MECH_DESC_H
+
+struct auth_mech_desc {
+	enum auth_mech mech;
+	const char *name;
+	int plaintext;
+	int advertise;
+};
+
+static struct auth_mech_desc auth_mech_desc[AUTH_MECH_COUNT] = {
+	{ AUTH_MECH_PLAIN,		"PLAIN",	TRUE, FALSE },
+	{ AUTH_MECH_DIGEST_MD5,		"DIGEST-MD5",	FALSE, TRUE }
+};
+
+#endif
--- a/src/auth/auth-plain.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/auth-plain.c	Sun Jan 05 17:19:50 2003 +0200
@@ -107,6 +107,6 @@
 }
 
 struct auth_module auth_plain = {
-	AUTH_METHOD_PLAIN,
+	AUTH_MECH_PLAIN,
 	auth_plain_init
 };
--- a/src/auth/auth.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/auth.c	Sun Jan 05 17:19:50 2003 +0200
@@ -12,9 +12,10 @@
 	struct auth_module module;
 };
 
-enum auth_method auth_methods;
+enum auth_mech auth_mechanisms;
 const char *const *auth_realms;
 
+static int set_use_cyrus_sasl;
 static struct auth_module_list *auth_modules;
 static struct auth_reply_data failure_reply;
 
@@ -22,9 +23,9 @@
 {
 	struct auth_module_list *list;
 
-	i_assert((auth_methods & module->method) == 0);
+	i_assert((auth_mechanisms & module->mech) == 0);
 
-	auth_methods |= module->method;
+	auth_mechanisms |= module->mech;
 
 	list = i_new(struct auth_module_list, 1);
 	memcpy(&list->module, module, sizeof(struct auth_module));
@@ -37,13 +38,13 @@
 {
 	struct auth_module_list **pos, *list;
 
-	if ((auth_methods & module->method) == 0)
+	if ((auth_mechanisms & module->mech) == 0)
 		return; /* not registered */
 
-        auth_methods &= ~module->method;
+        auth_mechanisms &= ~module->mech;
 
 	for (pos = &auth_modules; *pos != NULL; pos = &(*pos)->next) {
-		if ((*pos)->module.method == module->method) {
+		if ((*pos)->module.mech == module->mech) {
 			list = *pos;
 			*pos = (*pos)->next;
 			i_free(list);
@@ -58,23 +59,29 @@
 {
 	struct auth_module_list *list;
 
-	if ((auth_methods & request->method) == 0) {
-		/* unsupported method */
+	if ((auth_mechanisms & request->mech) == 0) {
+		/* unsupported mechanism */
 		i_error("BUG: imap-login requested unsupported "
-			"auth method %d", request->method);
+			"auth mechanism %d", request->mech);
 		failure_reply.id = request->id;
 		callback(&failure_reply, NULL, context);
 		return;
 	}
 
+#ifdef USE_CYRUS_SASL2
+	if (set_use_cyrus_sasl) {
+		auth_cyrus_sasl_init(login_pid, request, callback, context);
+		return;
+	}
+#endif
+
 	for (list = auth_modules; list != NULL; list = list->next) {
-		if (list->module.method == request->method) {
+		if (list->module.mech == request->mech) {
 			list->module.init(login_pid, request,
 					  callback, context);
 			return;
 		}
 	}
-
 	i_unreached();
 }
 
@@ -103,31 +110,32 @@
 
 void auth_init(void)
 {
-	const char *const *methods;
+	const char *const *mechanisms;
 	const char *env;
 
         auth_modules = NULL;
-	auth_methods = 0;
+	auth_mechanisms = 0;
 
 	memset(&failure_reply, 0, sizeof(failure_reply));
 	failure_reply.result = AUTH_RESULT_FAILURE;
 
-	/* register wanted methods */
-	env = getenv("METHODS");
+	/* register wanted mechanisms */
+	env = getenv("MECHANISMS");
 	if (env == NULL || *env == '\0')
-		i_fatal("METHODS environment is unset");
+		i_fatal("MECHANISMS environment is unset");
 
-	methods = t_strsplit(env, " ");
-	while (*methods != NULL) {
-		if (strcasecmp(*methods, "plain") == 0)
+	mechanisms = t_strsplit(env, " ");
+	while (*mechanisms != NULL) {
+		if (strcasecmp(*mechanisms, "PLAIN") == 0)
 			auth_register_module(&auth_plain);
-		else if (strcasecmp(*methods, "digest-md5") == 0)
+		else if (strcasecmp(*mechanisms, "DIGEST-MD5") == 0)
 			auth_register_module(&auth_digest_md5);
 		else {
-			i_fatal("Unknown authentication method '%s'",
-				*methods);
+			i_fatal("Unknown authentication mechanism '%s'",
+				*mechanisms);
 		}
-		methods++;
+
+		mechanisms++;
 	}
 
 	/* get our realm - note that we allocate from data stack so
@@ -137,6 +145,13 @@
 	if (env == NULL)
 		env = "";
 	auth_realms = t_strsplit(env, " ");
+
+	set_use_cyrus_sasl = getenv("USE_CYRUS_SASL") != NULL;
+
+#ifdef USE_CYRUS_SASL2
+	if (set_use_cyrus_sasl)
+		auth_cyrus_sasl_init_lib();
+#endif
 }
 
 void auth_deinit(void)
--- a/src/auth/auth.h	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/auth.h	Sun Jan 05 17:19:50 2003 +0200
@@ -4,17 +4,17 @@
 #include "auth-interface.h"
 
 typedef void (*AuthCallback)(struct auth_reply_data *reply,
-			     const unsigned char *data, void *context);
+			     const void *data, void *context);
 
 struct auth_module {
-	enum auth_method method;
+	enum auth_mech mech;
 
 	void (*init)(unsigned int login_pid,
 		     struct auth_init_request_data *request,
 		     AuthCallback callback, void *context);
 };
 
-extern enum auth_method auth_methods;
+extern enum auth_mech auth_mechanisms;
 extern const char *const *auth_realms;
 
 void auth_register_module(struct auth_module *module);
@@ -28,6 +28,11 @@
 			   const unsigned char *data,
 			   AuthCallback callback, void *context);
 
+void auth_cyrus_sasl_init_lib(void);
+void auth_cyrus_sasl_init(unsigned int login_pid,
+			  struct auth_init_request_data *request,
+			  AuthCallback callback, void *context);
+
 void auth_init(void);
 void auth_deinit(void);
 
--- a/src/auth/login-connection.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/login-connection.c	Sun Jan 05 17:19:50 2003 +0200
@@ -34,7 +34,7 @@
 static struct login_connection *connections;
 
 static void request_callback(struct auth_reply_data *reply,
-			     const unsigned char *data, void *context)
+			     const void *data, void *context)
 {
 	struct login_connection *conn = context;
 
@@ -226,7 +226,7 @@
 
 	memset(&auth_init_data, 0, sizeof(auth_init_data));
 	auth_init_data.auth_process = atoi(env);
-	auth_init_data.auth_methods = auth_methods;
+	auth_init_data.auth_mechanisms = auth_mechanisms;
 
 	connections = NULL;
 }
--- a/src/auth/userinfo.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/auth/userinfo.c	Sun Jan 05 17:19:50 2003 +0200
@@ -49,10 +49,10 @@
 		userinfo->init(args);
 	}
 
-	if ((auth_methods & AUTH_METHOD_PLAIN) &&
+	if ((auth_mechanisms & AUTH_MECH_PLAIN) &&
 	    userinfo->verify_plain == NULL)
 		i_fatal("Userinfo %s doesn't support PLAIN method", name);
-	if ((auth_methods & AUTH_METHOD_DIGEST_MD5) &&
+	if ((auth_mechanisms & AUTH_MECH_DIGEST_MD5) &&
 	    userinfo->lookup_digest_md5 == NULL)
 		i_fatal("Userinfo %s doesn't support DIGEST-MD5 method", name);
 }
--- a/src/login/auth-connection.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/login/auth-connection.c	Sun Jan 05 17:19:50 2003 +0200
@@ -27,7 +27,7 @@
 	struct ostream *output;
 
 	unsigned int auth_process;
-	enum auth_method available_auth_methods;
+	enum auth_mech available_auth_mechs;
         struct auth_reply_data in_reply;
 
         struct hash_table *requests;
@@ -36,7 +36,7 @@
 	unsigned int in_reply_received:1;
 };
 
-enum auth_method available_auth_methods;
+enum auth_mech available_auth_mechs;
 
 static int auth_reconnect;
 static unsigned int request_id_counter;
@@ -140,14 +140,14 @@
 }
 
 static struct auth_connection *
-auth_connection_get(enum auth_method method, size_t size, const char **error)
+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_methods & method)) {
+		if ((conn->available_auth_mechs & mech)) {
 			if (o_stream_have_space(conn->output, size) > 0)
 				return conn;
 
@@ -156,8 +156,8 @@
 	}
 
 	if (!found) {
-		if ((available_auth_methods & method) == 0)
-			*error = "Unsupported authentication method";
+		if ((available_auth_mechs & mech) == 0)
+			*error = "Unsupported authentication mechanism";
 		else {
 			*error = "Authentication server isn't connected, "
 				"try again later..";
@@ -171,23 +171,23 @@
 	return NULL;
 }
 
-static void update_available_auth_methods(void)
+static void update_available_auth_mechs(void)
 {
 	struct auth_connection *conn;
 
-        available_auth_methods = 0;
+        available_auth_mechs = 0;
 	for (conn = auth_connections; conn != NULL; conn = conn->next)
-                available_auth_methods |= conn->available_auth_methods;
+                available_auth_mechs |= conn->available_auth_mechs;
 }
 
 static void auth_handle_init(struct auth_connection *conn,
 			     struct auth_init_data *init_data)
 {
 	conn->auth_process = init_data->auth_process;
-	conn->available_auth_methods = init_data->auth_methods;
+	conn->available_auth_mechs = init_data->auth_mechanisms;
 	conn->init_received = TRUE;
 
-	update_available_auth_methods();
+	update_available_auth_mechs();
 }
 
 static void auth_handle_reply(struct auth_connection *conn,
@@ -281,7 +281,7 @@
 	i_stream_skip(conn->input, conn->in_reply.data_size);
 }
 
-int auth_init_request(enum auth_method method, AuthCallback callback,
+int auth_init_request(enum auth_mech mech, AuthCallback callback,
 		      void *context, const char **error)
 {
 	struct auth_connection *conn;
@@ -291,13 +291,13 @@
 	if (auth_reconnect)
 		auth_connect_missing();
 
-	conn = auth_connection_get(method, sizeof(request_data), error);
+	conn = auth_connection_get(mech, sizeof(request_data), error);
 	if (conn == NULL)
 		return FALSE;
 
 	/* create internal request structure */
 	request = i_new(struct auth_request, 1);
-	request->method = method;
+	request->mech = mech;
 	request->conn = conn;
 	request->id = ++request_id_counter;
 	request->callback = callback;
@@ -307,7 +307,7 @@
 
 	/* send request to auth */
 	request_data.type = AUTH_REQUEST_INIT;
-	request_data.method = request->method;
+	request_data.mech = request->mech;
 	request_data.id = request->id;
 	if (o_stream_send(request->conn->output, &request_data,
 			  sizeof(request_data)) < 0)
--- a/src/login/auth-connection.h	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/login/auth-connection.h	Sun Jan 05 17:19:50 2003 +0200
@@ -11,7 +11,7 @@
 			     size_t reply_data_size, void *context);
 
 struct auth_request {
-        enum auth_method method;
+        enum auth_mech mech;
         struct auth_connection *conn;
 
 	unsigned int id;
@@ -23,9 +23,9 @@
 	unsigned int init_sent:1;
 };
 
-extern enum auth_method available_auth_methods;
+extern enum auth_mech available_auth_mechs;
 
-int auth_init_request(enum auth_method method, AuthCallback callback,
+int auth_init_request(enum auth_mech mech, AuthCallback callback,
 		      void *context, const char **error);
 
 void auth_continue_request(struct auth_request *request,
--- a/src/login/client-authenticate.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/login/client-authenticate.c	Sun Jan 05 17:19:50 2003 +0200
@@ -9,58 +9,48 @@
 #include "safe-memset.h"
 #include "str.h"
 #include "auth-connection.h"
+#include "../auth/auth-mech-desc.h"
 #include "client.h"
 #include "client-authenticate.h"
 #include "master.h"
 
-struct auth_method_desc {
-	int method;
-	const char *name;
-	int plaintext;
-};
-
-static enum auth_method auth_methods = 0;
-static char *auth_methods_capability = NULL;
-
-static struct auth_method_desc auth_method_desc[AUTH_METHODS_COUNT] = {
-	{ AUTH_METHOD_PLAIN,		NULL,		TRUE },
-	{ AUTH_METHOD_DIGEST_MD5,	"DIGEST-MD5",	FALSE }
-};
+static enum auth_mech auth_mechs = 0;
+static char *auth_mechs_capability = NULL;
 
 const char *client_authenticate_get_capabilities(void)
 {
 	string_t *str;
 	int i;
 
-	if (auth_methods == available_auth_methods)
-		return auth_methods_capability;
+	if (auth_mechs == available_auth_mechs)
+		return auth_mechs_capability;
 
-	auth_methods = available_auth_methods;
-	i_free(auth_methods_capability);
+	auth_mechs = available_auth_mechs;
+	i_free(auth_mechs_capability);
 
 	str = t_str_new(128);
 
-	for (i = 0; i < AUTH_METHODS_COUNT; i++) {
-		if ((auth_methods & auth_method_desc[i].method) &&
-		    auth_method_desc[i].name != NULL) {
+	for (i = 0; i < AUTH_MECH_COUNT; i++) {
+		if ((auth_mechs & auth_mech_desc[i].mech) &&
+		    auth_mech_desc[i].name != NULL) {
 			str_append_c(str, ' ');
 			str_append(str, "AUTH=");
-			str_append(str, auth_method_desc[i].name);
+			str_append(str, auth_mech_desc[i].name);
 		}
 	}
 
-	auth_methods_capability = i_strdup_empty(str_c(str));
-	return auth_methods_capability;
+	auth_mechs_capability = i_strdup_empty(str_c(str));
+	return auth_mechs_capability;
 }
 
-static struct auth_method_desc *auth_method_find(const char *name)
+static struct auth_mech_desc *auth_mech_find(const char *name)
 {
 	int i;
 
-	for (i = 0; i < AUTH_METHODS_COUNT; i++) {
-		if (auth_method_desc[i].name != NULL &&
-		    strcasecmp(auth_method_desc[i].name, name) == 0)
-			return &auth_method_desc[i];
+	for (i = 0; i < AUTH_MECH_COUNT; i++) {
+		if (auth_mech_desc[i].name != NULL &&
+		    strcasecmp(auth_mech_desc[i].name, name) == 0)
+			return &auth_mech_desc[i];
 	}
 
 	return NULL;
@@ -202,8 +192,8 @@
 	buffer_append(client->plain_login, pass, strlen(pass));
 
 	client_ref(client);
-	if (auth_init_request(AUTH_METHOD_PLAIN,
-			      login_callback, client, &error)) {
+	if (auth_init_request(AUTH_MECH_PLAIN, login_callback,
+			      client, &error)) {
 		/* don't read any input from client until login is finished */
 		if (client->io != NULL) {
 			io_remove(client->io);
@@ -273,29 +263,29 @@
 	safe_memset(buffer_free_without_data(buf), 0, bufsize);
 }
 
-int cmd_authenticate(struct client *client, const char *method_name)
+int cmd_authenticate(struct client *client, const char *mech_name)
 {
-	struct auth_method_desc *method;
+	struct auth_mech_desc *mech;
 	const char *error;
 
-	if (*method_name == '\0')
+	if (*mech_name == '\0')
 		return FALSE;
 
-	method = auth_method_find(method_name);
-	if (method == NULL) {
+	mech = auth_mech_find(mech_name);
+	if (mech == NULL) {
 		client_send_tagline(client,
-				    "NO Unsupported authentication method.");
+				    "NO Unsupported authentication mechanism.");
 		return TRUE;
 	}
 
-	if (!client->tls && method->plaintext && disable_plaintext_auth) {
+	if (!client->tls && mech->plaintext && disable_plaintext_auth) {
 		client_send_tagline(client,
 				    "NO Plaintext authentication disabled.");
 		return TRUE;
 	}
 
 	client_ref(client);
-	if (auth_init_request(method->method, authenticate_callback,
+	if (auth_init_request(mech->mech, authenticate_callback,
 			      client, &error)) {
 		/* following input data will go to authentication */
 		if (client->io != NULL)
--- a/src/master/auth-process.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/master/auth-process.c	Sun Jan 05 17:19:50 2003 +0200
@@ -254,11 +254,13 @@
 
 	/* set other environment */
 	env_put(t_strconcat("AUTH_PROCESS=", dec2str(getpid()), NULL));
-	env_put(t_strconcat("METHODS=", config->methods, NULL));
+	env_put(t_strconcat("MECHANISMS=", config->mechanisms, NULL));
 	env_put(t_strconcat("REALMS=", config->realms, NULL));
 	env_put(t_strconcat("USERINFO=", config->userinfo, NULL));
-	env_put(t_strconcat("USERINFO_ARGS=", config->userinfo_args,
-				    NULL));
+	env_put(t_strconcat("USERINFO_ARGS=", config->userinfo_args, NULL));
+
+	if (config->use_cyrus_sasl)
+		env_put("USE_CYRUS_SASL=1");
 
 	restrict_process_size(config->process_size);
 
--- a/src/master/settings.c	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/master/settings.c	Sun Jan 05 17:19:50 2003 +0200
@@ -170,6 +170,18 @@
 	set_login_gid = pw->pw_gid;
 }
 
+static const char *get_bool(const char *value, int *result)
+{
+	if (strcasecmp(value, "yes") == 0)
+		*result = TRUE;
+	else if (strcasecmp(value, "no") == 0)
+		*result = FALSE;
+	else
+		return t_strconcat("Invalid boolean: ", value, NULL);
+
+	return NULL;
+}
+
 static void auth_settings_verify(void)
 {
 	struct auth_config *auth;
@@ -328,7 +340,7 @@
 static void auth_config_free(struct auth_config *auth)
 {
 	i_free(auth->name);
-	i_free(auth->methods);
+	i_free(auth->mechanisms);
 	i_free(auth->realms);
 	i_free(auth->userinfo);
 	i_free(auth->userinfo_args);
@@ -366,8 +378,10 @@
 		return "Authentication process name not defined yet";
 
 	/* check the easy string values first */
-	if (strcmp(key, "auth_methods") == 0)
-		ptr = &auth->methods;
+	if (strcmp(key, "auth_mechanisms") == 0)
+		ptr = &auth->mechanisms;
+	else if (strcmp(key, "auth_methods") == 0) /* backwards compatibility */
+		ptr = &auth->mechanisms;
 	else if (strcmp(key, "auth_realms") == 0)
 		ptr = &auth->realms;
 	else if (strcmp(key, "auth_executable") == 0)
@@ -400,6 +414,9 @@
 		return NULL;
 	}
 
+	if (strcmp(key, "auth_cyrus_sasl") == 0)
+		return get_bool(value, &auth->use_cyrus_sasl);
+
 	if (strcmp(key, "auth_count") == 0) {
 		int num;
 
@@ -445,14 +462,7 @@
 							   value, NULL);
 				break;
 			case SET_BOOL:
-				if (strcasecmp(value, "yes") == 0)
-					*((int *) set->ptr) = TRUE;
-				else if (strcasecmp(value, "no") == 0)
-					*((int *) set->ptr) = FALSE;
-				else
-					return t_strconcat("Invalid boolean: ",
-							   value, NULL);
-				break;
+				return get_bool(value, set->ptr);
 			}
 			return NULL;
 		}
--- a/src/master/settings.h	Sun Jan 05 15:19:09 2003 +0200
+++ b/src/master/settings.h	Sun Jan 05 17:19:50 2003 +0200
@@ -64,13 +64,15 @@
 	struct auth_config *next;
 
 	char *name;
-	char *methods;
+	char *mechanisms;
 	char *realms;
 	char *userinfo, *userinfo_args;
 	char *executable;
 	char *user;
 	char *chroot;
 
+	int use_cyrus_sasl;
+
 	unsigned int count;
 	unsigned int process_size;
 };