changeset 2766:26a091f3add6 HEAD

Implemented support for LOGIN-REFERRALS using "referral" and "reason" parameters from auth server.
author Timo Sirainen <tss@iki.fi>
date Mon, 18 Oct 2004 04:13:25 +0300
parents 428bba43a387
children 54dfccbe7f11
files configure.in src/imap-login/client-authenticate.c src/imap-login/client.c src/lib-auth/auth-server-request.c src/login-common/sasl-server.c src/login-common/sasl-server.h src/pop3-login/client-authenticate.c src/pop3-login/client.c
diffstat 8 files changed, 150 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Mon Oct 18 04:00:42 2004 +0300
+++ b/configure.in	Mon Oct 18 04:13:25 2004 +0300
@@ -1,7 +1,7 @@
 AC_INIT(src)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(dovecot, 1.0-test48)
+AM_INIT_AUTOMAKE(dovecot, 1.0-test49)
 
 AM_MAINTAINER_MODE
 
@@ -1326,7 +1326,7 @@
 dnl ** capabilities
 dnl **
 
-capability="IMAP4rev1 SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN LISTEXT NAMESPACE"
+capability="IMAP4rev1 SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN LISTEXT NAMESPACE LOGIN-REFERRALS"
 AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities)
 
 CFLAGS="$CFLAGS $EXTRA_CFLAGS"
--- a/src/imap-login/client-authenticate.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/imap-login/client-authenticate.c	Mon Oct 18 04:13:25 2004 +0300
@@ -76,8 +76,54 @@
 	safe_memset(line, 0, strlen(line));
 }
 
+static int client_handle_success_args(struct imap_client *client,
+				      const char *const *args, int nologin)
+{
+	const char *reason = NULL, *referral = NULL;
+	string_t *reply;
+
+	for (; *args != NULL; args++) {
+		if (strcmp(*args, "nologin") == 0)
+			nologin = TRUE;
+		else if (strncmp(*args, "reason=", 7) == 0)
+			reason = *args + 7;
+		else  if (strncmp(*args, "referral=", 9) == 0)
+			referral = *args + 9;
+	}
+
+	if (!nologin && referral == NULL)
+		return FALSE;
+
+	reply = t_str_new(128);
+	str_append(reply, nologin ? "NO " : "OK ");
+	if (referral != NULL)
+		str_printfa(reply, "[REFERRAL %s] ", referral);
+
+	if (reason != NULL)
+		str_append(reply, reason);
+	else if (!nologin)
+		str_append(reply, "Logged in.");
+	else if (referral != NULL)
+		str_append(reply, "Try this server instead.");
+	else
+		str_append(reply, "Login disabled.");
+
+	client_send_tagline(client, str_c(reply));
+	if (!nologin) {
+		client_destroy(client, t_strconcat(
+			"Login: ", client->common.virtual_user, NULL));
+	} else {
+		/* get back to normal client input. */
+		if (client->io != NULL)
+			io_remove(client->io);
+		client->io = io_add(client->common.fd, IO_READ,
+				    client_input, client);
+	}
+	return TRUE;
+}
+
 static void sasl_callback(struct client *_client, enum sasl_server_reply reply,
-			  const char *data)
+			  const char *data, const char *const *args)
 {
 	struct imap_client *client = (struct imap_client *)_client;
 	struct const_iovec iov[3];
@@ -86,11 +132,21 @@
 
 	switch (reply) {
 	case SASL_SERVER_REPLY_SUCCESS:
+		if (args != NULL) {
+			if (client_handle_success_args(client, args, FALSE))
+				break;
+		}
+
 		client_send_tagline(client, "OK Logged in.");
 		client_destroy(client, t_strconcat(
 			"Login: ", client->common.virtual_user, NULL));
 		break;
 	case SASL_SERVER_REPLY_AUTH_FAILED:
+		if (args != NULL) {
+			if (client_handle_success_args(client, args, TRUE))
+				break;
+		}
+
 		if (data == NULL)
 			client_send_tagline(client, "Authentication failed");
 		else {
--- a/src/imap-login/client.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/imap-login/client.c	Mon Oct 18 04:13:25 2004 +0300
@@ -483,6 +483,7 @@
 	o_stream_unref(client->output);
 
 	i_free(client->common.virtual_user);
+	i_free(client->common.auth_mech_name);
 	i_free(client);
 
 	main_unref();
--- a/src/lib-auth/auth-server-request.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/lib-auth/auth-server-request.c	Mon Oct 18 04:13:25 2004 +0300
@@ -201,14 +201,16 @@
 {
 	struct auth_request *request;
         struct auth_server_connection *next;
-	const char *error;
+	const char *error, *const *list;
 	unsigned int id;
 
-	error = strchr(args, '\t');
-	if (error != NULL)
-		error++;
+	list = t_strsplit(args, "\t");
+	if (list[0] == NULL) {
+		i_error("BUG: Authentication server sent broken OK line");
+		return FALSE;
+	}
 
-	id = (unsigned int)strtoul(args, NULL, 10);
+	id = (unsigned int)strtoul(list[0], NULL, 10);
 
 	request = hash_lookup(conn->requests, POINTER_CAST(id));
 	if (request == NULL) {
@@ -216,6 +218,14 @@
 		return TRUE;
 	}
 
+	if (list[1] == NULL) {
+		error = NULL;
+		list++;
+	} else {
+		error = *list[1] == '\0' ? NULL : list[1];
+		list += 2;
+	}
+
 	hash_remove(conn->requests, POINTER_CAST(request->id));
 	if (request->retrying) {
 		next = request->next_conn == NULL ? NULL :
@@ -241,7 +251,7 @@
 		}
 	}
 
-	request->callback(request, -1, error, NULL, request->context);
+	request->callback(request, -1, error, list, request->context);
 	auth_client_request_free(request);
 	return TRUE;
 }
--- a/src/login-common/sasl-server.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/login-common/sasl-server.c	Mon Oct 18 04:13:25 2004 +0300
@@ -28,11 +28,8 @@
 static void master_callback(struct client *client, int success)
 {
 	client->authenticating = FALSE;
-	i_free(client->auth_mech_name);
-	client->auth_mech_name = NULL;
-
 	client->sasl_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
-			      SASL_SERVER_REPLY_MASTER_FAILED, NULL);
+			      SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
 }
 
 static void authenticate_callback(struct auth_request *request, int status,
@@ -40,7 +37,8 @@
 				  const char *const *args, void *context)
 {
 	struct client *client = context;
-	const char *error;
+	unsigned int i;
+	int nologin;
 
 	if (!client->authenticating) {
 		/* client aborted */
@@ -60,33 +58,47 @@
 		}
 
 		client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
-				      data_base64);
+				      data_base64, NULL);
 		break;
 	case 1:
 		client->auth_request = NULL;
 
-		for (; *args != NULL; args++) {
-			if (strncmp(*args, "user=", 5) == 0) {
+		nologin = FALSE;
+		for (i = 0; args[i] != NULL; i++) {
+			if (strncmp(args[i], "user=", 5) == 0) {
 				i_free(client->virtual_user);
-				client->virtual_user = i_strdup(*args + 5);
+				client->virtual_user = i_strdup(args[i] + 5);
+			}
+			if (strcmp(args[i], "nologin") == 0) {
+				/* user can't login */
+				nologin = TRUE;
 			}
 		}
 
-		master_request_login(client, master_callback,
+		if (nologin) {
+			client->authenticating = FALSE;
+			client->sasl_callback(client, SASL_SERVER_REPLY_SUCCESS,
+					      NULL, args);
+		} else {
+			master_request_login(client, master_callback,
 				auth_client_request_get_server_pid(request),
 				auth_client_request_get_id(request));
+		}
 		break;
 	case -1:
 		client->auth_request = NULL;
 
-		/* see if we have error message */
-		if (data_base64 != NULL) {
-			error = t_strconcat("Authentication failed: ",
-					    (const char *)data_base64, NULL);
-		} else {
-			error = NULL;
+		/* base64 contains error message, if there is one */
+		if (verbose_auth && data_base64 != NULL) {
+			client_syslog(client, "Authenticate %s failed: %s",
+				      str_sanitize(client->auth_mech_name,
+						   MAX_MECH_NAME),
+				      (const char *)data_base64);
 		}
-		sasl_server_auth_cancel(client, error);
+
+		client->authenticating = FALSE;
+		client->sasl_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
+				      (const char *)data_base64, args);
 		break;
 	}
 }
@@ -101,6 +113,7 @@
 	const char *error;
 
 	client->authenticating = TRUE;
+	i_free(client->auth_mech_name);
 	client->auth_mech_name = i_strdup(mech_name);
 	client->sasl_callback = callback;
 
@@ -144,13 +157,12 @@
 	}
 
 	client->authenticating = FALSE;
-	i_free(client->auth_mech_name);
-	client->auth_mech_name = NULL;
 
 	if (client->auth_request != NULL) {
 		auth_client_request_abort(client->auth_request);
 		client->auth_request = NULL;
 	}
 
-	client->sasl_callback(client, SASL_SERVER_REPLY_AUTH_FAILED, reason);
+	client->sasl_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
+			      reason, NULL);
 }
--- a/src/login-common/sasl-server.h	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/login-common/sasl-server.h	Mon Oct 18 04:13:25 2004 +0300
@@ -10,7 +10,7 @@
 
 typedef void sasl_server_callback_t(struct client *client,
 				    enum sasl_server_reply reply,
-				    const char *data);
+				    const char *data, const char *const *args);
 
 void sasl_server_auth_begin(struct client *client,
 			    const char *protocol, const char *mech_name,
--- a/src/pop3-login/client-authenticate.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/pop3-login/client-authenticate.c	Mon Oct 18 04:13:25 2004 +0300
@@ -77,8 +77,42 @@
 	safe_memset(line, 0, strlen(line));
 }
 
+static int client_handle_success_args(struct pop3_client *client,
+				      const char *const *args)
+{
+	const char *reason = NULL;
+	string_t *reply;
+	int nologin = FALSE;
+
+	for (; *args != NULL; args++) {
+		if (strcmp(*args, "nologin") == 0)
+			nologin = TRUE;
+		else if (strncmp(*args, "reason=", 7) == 0)
+			reason = *args + 7;
+	}
+
+	if (!nologin)
+		return FALSE;
+
+	reply = t_str_new(128);
+	str_append(reply, "-ERR ");
+	if (reason != NULL)
+		str_append(reply, reason);
+	else
+		str_append(reply, "Login disabled.");
+
+	client_send_line(client, str_c(reply));
+
+	/* get back to normal client input. */
+	if (client->io != NULL)
+		io_remove(client->io);
+	client->io = io_add(client->common.fd, IO_READ,
+			    client_input, client);
+	return TRUE;
+}
+
 static void sasl_callback(struct client *_client, enum sasl_server_reply reply,
-			  const char *data)
+			  const char *data, const char *const *args)
 {
 	struct pop3_client *client = (struct pop3_client *)_client;
 	struct const_iovec iov[3];
@@ -87,6 +121,11 @@
 
 	switch (reply) {
 	case SASL_SERVER_REPLY_SUCCESS:
+		if (args != NULL) {
+			if (client_handle_success_args(client, args))
+				break;
+		}
+
 		client_send_line(client, "+OK Logged in.");
 		client_destroy(client, t_strconcat(
 			"Login: ", client->common.virtual_user, NULL));
--- a/src/pop3-login/client.c	Mon Oct 18 04:00:42 2004 +0300
+++ b/src/pop3-login/client.c	Mon Oct 18 04:13:25 2004 +0300
@@ -381,6 +381,7 @@
 
 	i_free(client->apop_challenge);
 	i_free(client->common.virtual_user);
+	i_free(client->common.auth_mech_name);
 	i_free(client);
 
 	main_unref();