[dovecot-cvs] dovecot/src/auth auth-cyrus-sasl2.c,NONE,1.1 auth-mech-desc.h,NONE,1.1 Makefile.am,1.5,1.6 auth-digest-md5.c,1.16,1.17 auth-interface.h,1.5,1.6 auth-plain.c,1.8,1.9 auth.c,1.7,1.8 auth.h,1.5,1.6 login-connection.c,1.11,1.12 userinfo.c,1.3,1.4

cras at procontrol.fi cras at procontrol.fi
Sun Jan 5 17:19:52 EET 2003


Update of /home/cvs/dovecot/src/auth
In directory danu:/tmp/cvs-serv2361/src/auth

Modified Files:
	Makefile.am auth-digest-md5.c auth-interface.h auth-plain.c 
	auth.c auth.h login-connection.c userinfo.c 
Added Files:
	auth-cyrus-sasl2.c auth-mech-desc.h 
Log Message:
Initial support for Cyrus SASL 2 library. I couldn't get it to work yet
though :)



--- NEW FILE: auth-cyrus-sasl2.c ---
/* 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

--- NEW FILE: auth-mech-desc.h ---
#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

Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- Makefile.am	26 Nov 2002 20:05:42 -0000	1.5
+++ Makefile.am	5 Jan 2003 15:19:50 -0000	1.6
@@ -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 \

Index: auth-digest-md5.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-digest-md5.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- auth-digest-md5.c	5 Jan 2003 13:09:51 -0000	1.16
+++ auth-digest-md5.c	5 Jan 2003 15:19:50 -0000	1.17
@@ -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
 };

Index: auth-interface.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-interface.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- auth-interface.h	5 Jan 2003 13:09:51 -0000	1.5
+++ auth-interface.h	5 Jan 2003 15:19:50 -0000	1.6
@@ -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 */
 };
 

Index: auth-plain.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-plain.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- auth-plain.c	5 Jan 2003 13:09:51 -0000	1.8
+++ auth-plain.c	5 Jan 2003 15:19:50 -0000	1.9
@@ -107,6 +107,6 @@
 }
 
 struct auth_module auth_plain = {
-	AUTH_METHOD_PLAIN,
+	AUTH_MECH_PLAIN,
 	auth_plain_init
 };

Index: auth.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- auth.c	5 Jan 2003 13:09:51 -0000	1.7
+++ auth.c	5 Jan 2003 15:19:50 -0000	1.8
@@ -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)

Index: auth.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- auth.h	5 Jan 2003 13:09:51 -0000	1.5
+++ auth.h	5 Jan 2003 15:19:50 -0000	1.6
@@ -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);
@@ -27,6 +27,11 @@
 			   struct auth_continued_request_data *request,
 			   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);

Index: login-connection.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/login-connection.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- login-connection.c	5 Jan 2003 13:09:51 -0000	1.11
+++ login-connection.c	5 Jan 2003 15:19:50 -0000	1.12
@@ -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;
 }

Index: userinfo.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/userinfo.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- userinfo.c	5 Jan 2003 13:09:51 -0000	1.3
+++ userinfo.c	5 Jan 2003 15:19:50 -0000	1.4
@@ -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);
 }




More information about the dovecot-cvs mailing list