changeset 22420:7ae7c3c159d1

lib-master: Allow userdb to return postlogin socket path. Returning "postlogin=socketpath" as userdb extra field overrides the postlogin socket path in the service { executable } parameter.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Sun, 23 Jul 2017 12:32:38 +0300
parents 55bd9d8ca7ce
children feb7448f94cd
files src/lib-master/master-login.c
diffstat 1 files changed, 30 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-master/master-login.c	Wed Aug 09 13:23:36 2017 +0300
+++ b/src/lib-master/master-login.c	Sun Jul 23 12:32:38 2017 +0300
@@ -40,6 +40,7 @@
 	struct timeout *to;
 	string_t *input;
 	char *username;
+	char *socket_path;
 };
 
 struct master_login {
@@ -231,13 +232,13 @@
 	if (close(pl->fd) < 0)
 		i_error("close(postlogin) failed: %m");
 	str_free(&pl->input);
+	i_free(pl->socket_path);
 	i_free(pl->username);
 	i_free(pl);
 }
 
 static void master_login_postlogin_input(struct master_login_postlogin *pl)
 {
-	struct master_login *login = pl->client->conn->login;
 	char buf[1024];
 	const char **auth_args, **p;
 	size_t len;
@@ -263,11 +264,10 @@
 			if (errno == EAGAIN)
 				return;
 
-			i_error("fd_read(%s) failed: %m",
-				login->postlogin_socket_path);
+			i_error("fd_read(%s) failed: %m", pl->socket_path);
 		} else if (str_len(pl->input) > 0) {
 			i_error("fd_read(%s) failed: disconnected",
-				login->postlogin_socket_path);
+				pl->socket_path);
 		} else {
 			i_info("Post-login script denied access to user %s",
 			       pl->username);
@@ -287,17 +287,16 @@
 
 static void master_login_postlogin_timeout(struct master_login_postlogin *pl)
 {
-	struct master_login *login = pl->client->conn->login;
-
 	i_error("%s: Timeout waiting for post-login script to finish, aborting",
-		login->postlogin_socket_path);
+		pl->socket_path);
 
 	master_login_client_free(&pl->client);
 	master_login_postlogin_free(pl);
 }
 
 static int master_login_postlogin(struct master_login_client *client,
-				  const char *const *auth_args)
+				  const char *const *auth_args,
+				  const char *socket_path)
 {
 	struct master_login *login = client->conn->login;
 	struct master_login_postlogin *pl;
@@ -306,10 +305,10 @@
 	int fd;
 	ssize_t ret;
 
-	fd = net_connect_unix_with_retries(login->postlogin_socket_path, 1000);
+	fd = net_connect_unix_with_retries(socket_path, 1000);
 	if (fd == -1) {
 		i_error("net_connect_unix(%s) failed: %m%s",
-			login->postlogin_socket_path, errno != EAGAIN ? "" :
+			socket_path, errno != EAGAIN ? "" :
 			" - http://wiki2.dovecot.org/SocketUnavailable");
 		return -1;
 	}
@@ -326,11 +325,9 @@
 	ret = fd_send(fd, client->fd, str_data(str), str_len(str));
 	if (ret != (ssize_t)str_len(str)) {
 		if (ret < 0) {
-			i_error("write(%s) failed: %m",
-				login->postlogin_socket_path);
+			i_error("write(%s) failed: %m", socket_path);
 		} else {
-			i_error("write(%s) failed: partial write",
-				login->postlogin_socket_path);
+			i_error("write(%s) failed: partial write", socket_path);
 		}
 		i_close_fd(&fd);
 		return -1;
@@ -340,6 +337,7 @@
 	pl = i_new(struct master_login_postlogin, 1);
 	pl->client = client;
 	pl->username = i_strdup(auth_args[0]);
+	pl->socket_path = i_strdup(socket_path);
 	pl->fd = fd;
 	pl->io = io_add(fd, IO_READ, master_login_postlogin_input, pl);
 	pl->to = timeout_add(login->postlogin_timeout_secs * 1000,
@@ -348,6 +346,16 @@
 	return 0;
 }
 
+static const char *
+auth_args_find_postlogin_socket(const char *const *auth_args)
+{
+	for (unsigned int i = 0; auth_args[i] != NULL; i++) {
+		if (strncmp(auth_args[i], "postlogin=", 10) == 0)
+			return auth_args[i]+10;
+	}
+	return NULL;
+}
+
 static void
 master_login_auth_callback(const char *const *auth_args, const char *errormsg,
 			   void *context)
@@ -355,6 +363,7 @@
 	struct master_login_client *client = context;
 	struct master_login_connection *conn = client->conn;
 	struct master_auth_reply reply;
+	const char *postlogin_socket_path;
 
 	i_zero(&reply);
 	reply.tag = client->auth_req.tag;
@@ -375,7 +384,11 @@
 	i_set_failure_prefix("%s(%s): ", client->conn->login->service->name,
 			     auth_args[0]);
 
-	if (conn->login->postlogin_socket_path == NULL)
+	postlogin_socket_path = auth_args_find_postlogin_socket(auth_args);
+	if (postlogin_socket_path == NULL)
+		postlogin_socket_path = conn->login->postlogin_socket_path;
+
+	if (postlogin_socket_path == NULL)
 		master_login_auth_finish(client, auth_args);
 	else {
 		/* we've sent the reply. the connection is no longer needed,
@@ -385,7 +398,8 @@
 		master_login_conn_unref(&conn);
 
 		/* execute post-login scripts before finishing auth */
-		if (master_login_postlogin(client, auth_args) < 0)
+		if (master_login_postlogin(client, auth_args,
+					   postlogin_socket_path) < 0)
 			master_login_client_free(&client);
 	}
 }