changeset 7122:fb03422c0760 HEAD

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".
author Timo Sirainen <tss@iki.fi>
date Sun, 06 Jan 2008 03:13:20 +0200
parents 05bc8679c886
children 25e7c37c7c10
files src/auth/auth-request-handler.c src/auth/auth-request.c src/auth/auth-request.h src/auth/auth-stream.c src/auth/auth-stream.h
diffstat 5 files changed, 114 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 		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=");
--- 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 @@
 	}
 }
 
+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 @@
 			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;
 	}
 
@@ -1213,6 +1226,52 @@
 	}
 }
 
+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,
 				 const char *plain_password,
 				 const char *crypted_password,
--- 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 @@
 	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_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,
--- 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_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 @@
 {
 	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");
+}
--- 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_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