dovecot: Added "proxy_maybe" field. If it's used instead of "pro...

dovecot at dovecot.org dovecot at dovecot.org
Sun Jan 6 03:13:23 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/fb03422c0760
changeset: 7122:fb03422c0760
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jan 06 03:13:20 2008 +0200
description:
Added "proxy_maybe" field. If it's used instead of "proxy" and the
proxy destination matches the current connection, the user is logged in
normally instead of the login failing with "Proxying loops".

diffstat:

5 files changed, 114 insertions(+), 16 deletions(-)
src/auth/auth-request-handler.c |    2 
src/auth/auth-request.c         |   91 ++++++++++++++++++++++++++++++++-------
src/auth/auth-request.h         |    2 
src/auth/auth-stream.c          |   32 +++++++++++++
src/auth/auth-stream.h          |    3 +

diffs (208 lines):

diff -r 05bc8679c886 -r fb03422c0760 src/auth/auth-request-handler.c
--- a/src/auth/auth-request-handler.c	Sun Jan 06 03:11:02 2008 +0200
+++ b/src/auth/auth-request-handler.c	Sun Jan 06 03:13:20 2008 +0200
@@ -209,6 +209,8 @@ static void auth_callback(struct auth_re
 		handler->callback(str_c(str), handler->context);
 		break;
 	case AUTH_CLIENT_RESULT_SUCCESS:
+		auth_request_proxy_finish(request);
+
 		str_printfa(str, "OK\t%u\tuser=%s", request->id, request->user);
 		if (reply_size > 0) {
 			str_append(str, "\tresp=");
diff -r 05bc8679c886 -r fb03422c0760 src/auth/auth-request.c
--- a/src/auth/auth-request.c	Sun Jan 06 03:11:02 2008 +0200
+++ b/src/auth/auth-request.c	Sun Jan 06 03:13:20 2008 +0200
@@ -967,6 +967,33 @@ auth_request_set_password(struct auth_re
 	}
 }
 
+static void auth_request_set_reply_field(struct auth_request *request,
+					 const char *name, const char *value)
+{
+	if (strcmp(name, "nologin") == 0) {
+		/* user can't actually login - don't keep this
+		   reply for master */
+		request->no_login = TRUE;
+		value = NULL;
+	} else if (strcmp(name, "proxy") == 0) {
+		/* we're proxying authentication for this user. send
+		   password back if using plaintext authentication. */
+		request->proxy = TRUE;
+		value = NULL;
+	} else if (strcmp(name, "proxy_maybe") == 0) {
+		/* like "proxy", but log in normally if we're proxying to
+		   ourself */
+		request->proxy = TRUE;
+		request->proxy_maybe = TRUE;
+		name = "proxy";
+		value = NULL;
+	}
+
+	if (request->extra_fields == NULL)
+		request->extra_fields = auth_stream_reply_init(request);
+	auth_stream_reply_add(request->extra_fields, name, value);
+}
+
 void auth_request_set_field(struct auth_request *request,
 			    const char *name, const char *value,
 			    const char *default_scheme)
@@ -1046,22 +1073,8 @@ void auth_request_set_field(struct auth_
 			auth_request_init_userdb_reply(request);
 		auth_request_set_userdb_field(request, name + 7, value);
 	} else {
-		if (strcmp(name, "nologin") == 0) {
-			/* user can't actually login - don't keep this
-			   reply for master */
-			request->no_login = TRUE;
-			value = NULL;
-		} else if (strcmp(name, "proxy") == 0) {
-			/* we're proxying authentication for this user. send
-			   password back if using plaintext authentication. */
-			request->proxy = TRUE;
-			request->no_login = TRUE;
-			value = NULL;
-		}
-
-		if (request->extra_fields == NULL)
-			request->extra_fields = auth_stream_reply_init(request);
-		auth_stream_reply_add(request->extra_fields, name, value);
+		/* these fields are returned to client */
+		auth_request_set_reply_field(request, name, value);
 		return;
 	}
 
@@ -1211,6 +1224,52 @@ void auth_request_set_userdb_field_value
 		/* add only one */
 		auth_request_set_userdb_field(request, name, *values);
 	}
+}
+
+static bool auth_request_proxy_is_self(struct auth_request *request)
+{
+	const char *const *tmp, *host = NULL, *port = NULL, *destuser = NULL;
+	struct ip_addr ip;
+
+	tmp = auth_stream_split(request->extra_fields);
+	for (; *tmp != NULL; tmp++) {
+		if (strncmp(*tmp, "host=", 5) == 0)
+			host = *tmp + 5;
+		else if (strncmp(*tmp, "port=", 5) == 0)
+			port = *tmp + 5;
+		if (strncmp(*tmp, "destuser=", 9) == 0)
+			destuser = *tmp + 9;
+	}
+
+	if (host == NULL || net_addr2ip(host, &ip) < 0) {
+		/* broken setup */
+		return FALSE;
+	}
+	if (!net_ip_compare(&ip, &request->local_ip))
+		return FALSE;
+
+	if (port != NULL && (unsigned int)atoi(port) != request->local_port)
+		return FALSE;
+	return destuser == NULL ||
+		strcmp(destuser, request->original_username) == 0;
+}
+
+void auth_request_proxy_finish(struct auth_request *request)
+{
+	if (!request->proxy_maybe || request->no_login)
+		return;
+
+	if (!auth_request_proxy_is_self(request)) {
+		request->no_login = TRUE;
+		return;
+	}
+
+	/* proxying to ourself - log in without proxying by dropping all the
+	   proxying fields. */
+	auth_stream_reply_remove(request->extra_fields, "proxy");
+	auth_stream_reply_remove(request->extra_fields, "host");
+	auth_stream_reply_remove(request->extra_fields, "port");
+	auth_stream_reply_remove(request->extra_fields, "destuser");
 }
 
 int auth_request_password_verify(struct auth_request *request,
diff -r 05bc8679c886 -r fb03422c0760 src/auth/auth-request.h
--- a/src/auth/auth-request.h	Sun Jan 06 03:11:02 2008 +0200
+++ b/src/auth/auth-request.h	Sun Jan 06 03:13:20 2008 +0200
@@ -90,6 +90,7 @@ struct auth_request {
 	unsigned int no_password:1;
 	unsigned int skip_password_check:1;
 	unsigned int proxy:1;
+	unsigned int proxy_maybe:1;
 	unsigned int cert_username:1;
 	unsigned int userdb_lookup:1;
 	unsigned int userdb_lookup_failed:1;
@@ -147,6 +148,7 @@ void auth_request_set_userdb_field_value
 void auth_request_set_userdb_field_values(struct auth_request *request,
 					  const char *name,
 					  const char *const *values);
+void auth_request_proxy_finish(struct auth_request *request);
 
 int auth_request_password_verify(struct auth_request *request,
 				 const char *plain_password,
diff -r 05bc8679c886 -r fb03422c0760 src/auth/auth-stream.c
--- a/src/auth/auth-stream.c	Sun Jan 06 03:11:02 2008 +0200
+++ b/src/auth/auth-stream.c	Sun Jan 06 03:13:20 2008 +0200
@@ -57,6 +57,33 @@ void auth_stream_reply_add(struct auth_s
 	}
 }
 
+void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key)
+{
+	const char *str = str_c(reply->str);
+	unsigned int i, start, key_len = strlen(key);
+
+	i = 0;
+	while (str[i] != '\0') {
+		start = i;
+		for (; str[i] != '\0'; i++) {
+			if (str[i] == '\t') {
+				i++;
+				break;
+			}
+		}
+
+		if (strncmp(str+start, key, key_len) == 0 &&
+		    (str[start+key_len] == '=' ||
+		     str[start+key_len] == '\t' ||
+		     str[start+key_len] == '\0')) {
+			str_delete(reply->str, start, i-start);
+			if (str_len(reply->str) == start && start > 0)
+				str_delete(reply->str, start - 1, 1);
+			break;
+		}
+	}
+}
+
 void auth_stream_reply_reset(struct auth_stream_reply *reply)
 {
 	str_truncate(reply->str, 0);
@@ -78,3 +105,8 @@ bool auth_stream_is_empty(struct auth_st
 {
 	return reply == NULL || str_len(reply->str) == 0;
 }
+
+const char *const *auth_stream_split(struct auth_stream_reply *reply)
+{
+	return t_strsplit(str_c(reply->str), "\t");
+}
diff -r 05bc8679c886 -r fb03422c0760 src/auth/auth-stream.h
--- a/src/auth/auth-stream.h	Sun Jan 06 03:11:02 2008 +0200
+++ b/src/auth/auth-stream.h	Sun Jan 06 03:13:20 2008 +0200
@@ -7,9 +7,12 @@ void auth_stream_reply_add(struct auth_s
 void auth_stream_reply_add(struct auth_stream_reply *reply,
 			   const char *key, const char *value);
 void auth_stream_reply_reset(struct auth_stream_reply *reply);
+void auth_stream_reply_remove(struct auth_stream_reply *reply, const char *key);
 
 void auth_stream_reply_import(struct auth_stream_reply *reply, const char *str);
 const char *auth_stream_reply_export(struct auth_stream_reply *reply);
 bool auth_stream_is_empty(struct auth_stream_reply *reply);
 
+const char *const *auth_stream_split(struct auth_stream_reply *reply);
+
 #endif


More information about the dovecot-cvs mailing list