[dovecot-cvs] dovecot/src/auth auth-master-connection.c, 1.7, 1.8 auth-master-connection.h, 1.3, 1.4 auth-master-interface.h, 1.4, 1.5 common.h, 1.6, 1.7 main.c, 1.26, 1.27

cras at procontrol.fi cras at procontrol.fi
Wed Jun 23 20:50:46 EEST 2004


Update of /home/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv5259/src/auth

Modified Files:
	auth-master-connection.c auth-master-connection.h 
	auth-master-interface.h common.h main.c 
Log Message:
Dovecot can now connect to externally running dovecot-auth.



Index: auth-master-connection.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-connection.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- auth-master-connection.c	29 May 2004 21:40:30 -0000	1.7
+++ auth-master-connection.c	23 Jun 2004 17:50:44 -0000	1.8
@@ -18,11 +18,20 @@
 static struct auth_master_reply failure_reply =
 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
+struct auth_listener {
+	struct auth_master_connection *master;
+	int client_listener;
+	int fd;
+	char *path;
+	struct io *io;
+};
+
 struct master_userdb_request {
 	struct auth_master_connection *conn;
 	unsigned int tag;
 };
 
+static void auth_master_connection_close(struct auth_master_connection *conn);
 static int auth_master_connection_unref(struct auth_master_connection *conn);
 
 static size_t reply_add(buffer_t *buf, const char *str)
@@ -89,7 +98,7 @@
 		ret = o_stream_send(conn->output, reply, reply_size);
 		if (ret < 0) {
 			/* master died, kill ourself too */
-			io_loop_stop(ioloop);
+			auth_master_connection_close(conn);
 			break;
 		}
 
@@ -100,7 +109,7 @@
 		i_warning("Master transmit buffer full, blocking..");
 		if (o_stream_flush(conn->output) < 0) {
 			/* transmit error, probably master died */
-			io_loop_stop(ioloop);
+			auth_master_connection_close(conn);
 			break;
 		}
 	}
@@ -169,7 +178,7 @@
 			  sizeof(conn->request_buf) - conn->request_pos);
 	if (ret < 0) {
 		/* master died, kill ourself too */
-		io_loop_stop(ioloop);
+                auth_master_connection_close(conn);
 		return;
 	}
 
@@ -224,8 +233,23 @@
 	master->handshake_reply = buffer_free_without_data(buf);
 }
 
+static void
+auth_master_connection_set_fd(struct auth_master_connection *conn, int fd)
+{
+	if (conn->output != NULL)
+		o_stream_unref(conn->output);
+	if (conn->io != NULL)
+		io_remove(conn->io);
+
+	conn->output = o_stream_create_file(fd, default_pool,
+					    MAX_OUTBUF_SIZE, FALSE);
+	conn->io = io_add(fd, IO_READ, master_input, conn);
+
+	conn->fd = fd;
+}
+
 struct auth_master_connection *
-auth_master_connection_new(int fd, unsigned int pid)
+auth_master_connection_create(int fd, unsigned int pid)
 {
 	struct auth_master_connection *conn;
 
@@ -235,42 +259,54 @@
 	conn->fd = fd;
 	conn->listeners_buf =
 		buffer_create_dynamic(default_pool, 64, (size_t)-1);
-	if (fd != -1) {
-		conn->output = o_stream_create_file(fd, default_pool,
-						    MAX_OUTBUF_SIZE, FALSE);
-		conn->io = io_add(fd, IO_READ, master_input, conn);
-	}
+	if (fd != -1)
+                auth_master_connection_set_fd(conn, fd);
 	master_get_handshake_reply(conn);
 	return conn;
 }
 
 void auth_master_connection_send_handshake(struct auth_master_connection *conn)
 {
+	struct auth_master_handshake_reply reply;
+
 	/* just a note to master that we're ok. if we die before,
 	   master should shutdown itself. */
-	if (conn->output != NULL)
-		o_stream_send(conn->output, "O", 1);
+	if (conn->output != NULL) {
+		memset(&reply, 0, sizeof(reply));
+		reply.server_pid = conn->pid;
+		o_stream_send(conn->output, &reply, sizeof(reply));
+	}
 }
 
-void auth_master_connection_free(struct auth_master_connection *conn)
+static void auth_master_connection_close(struct auth_master_connection *conn)
 {
-	struct auth_client_listener **l;
+	if (!standalone)
+		io_loop_stop(ioloop);
+
+	if (close(conn->fd) < 0)
+		i_error("close(): %m");
+	conn->fd = -1;
+
+	o_stream_close(conn->output);
+	conn->output = NULL;
+
+	io_remove(conn->io);
+	conn->io = NULL;
+}
+
+void auth_master_connection_destroy(struct auth_master_connection *conn)
+{
+	struct auth_listener **l;
 	size_t i, size;
 
 	if (conn->destroyed)
 		return;
 	conn->destroyed = TRUE;
 
-	if (conn->fd != -1) {
-		if (close(conn->fd) < 0)
-			i_error("close(): %m");
-		conn->fd = -1;
-
-		o_stream_close(conn->output);
+	auth_client_connections_deinit(conn);
 
-		io_remove(conn->io);
-		conn->io = NULL;
-	}
+	if (conn->fd != -1)
+		auth_master_connection_close(conn);
 
 	l = buffer_get_modifyable_data(conn->listeners_buf, &size);
 	size /= sizeof(*l);
@@ -303,7 +339,7 @@
 
 static void auth_accept(void *context)
 {
-	struct auth_client_listener *l = context;
+	struct auth_listener *l = context;
 	int fd;
 
 	fd = net_accept(l->fd, NULL, NULL);
@@ -312,17 +348,24 @@
 			i_fatal("accept() failed: %m");
 	} else {
 		net_set_nonblock(fd, TRUE);
-		(void)auth_client_connection_create(l->master, fd);
+		if (l->client_listener)
+			(void)auth_client_connection_create(l->master, fd);
+		else {
+			/* we'll just replace the previous master.. */
+			auth_master_connection_set_fd(l->master, fd);
+                        auth_master_connection_send_handshake(l->master);
+		}
 	}
 }
 
 void auth_master_connection_add_listener(struct auth_master_connection *conn,
-					 int fd, const char *path)
+					 int fd, const char *path, int client)
 {
-	struct auth_client_listener *l;
+	struct auth_listener *l;
 
-	l = i_new(struct auth_client_listener, 1);
+	l = i_new(struct auth_listener, 1);
 	l->master = conn;
+	l->client_listener = client;
 	l->fd = fd;
 	l->path = i_strdup(path);
 	l->io = io_add(fd, IO_READ, auth_accept, l);

Index: auth-master-connection.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-connection.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- auth-master-connection.h	29 May 2004 21:40:30 -0000	1.3
+++ auth-master-connection.h	23 Jun 2004 17:50:44 -0000	1.4
@@ -22,21 +22,14 @@
 	unsigned int destroyed:1;
 };
 
-struct auth_client_listener {
-	struct auth_master_connection *master;
-	int fd;
-	char *path;
-	struct io *io;
-};
-
 #define AUTH_MASTER_IS_DUMMY(master) (master->fd == -1)
 
 struct auth_master_connection *
-auth_master_connection_new(int fd, unsigned int pid);
+auth_master_connection_create(int fd, unsigned int pid);
 void auth_master_connection_send_handshake(struct auth_master_connection *conn);
-void auth_master_connection_free(struct auth_master_connection *conn);
+void auth_master_connection_destroy(struct auth_master_connection *conn);
 
 void auth_master_connection_add_listener(struct auth_master_connection *conn,
-					 int fd, const char *path);
+					 int fd, const char *path, int client);
 
 #endif

Index: auth-master-interface.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/auth-master-interface.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- auth-master-interface.h	29 May 2004 21:40:30 -0000	1.4
+++ auth-master-interface.h	23 Jun 2004 17:50:44 -0000	1.5
@@ -3,6 +3,11 @@
 
 #define AUTH_MASTER_MAX_REPLY_DATA_SIZE 4096
 
+/* Server -> Master */
+struct auth_master_handshake_reply {
+	unsigned int server_pid;
+};
+
 struct auth_master_request {
 	unsigned int tag;
 

Index: common.h
===================================================================
RCS file: /home/cvs/dovecot/src/auth/common.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- common.h	8 Feb 2003 17:13:36 -0000	1.6
+++ common.h	23 Jun 2004 17:50:44 -0000	1.7
@@ -8,5 +8,6 @@
 
 extern struct ioloop *ioloop;
 extern int verbose, verbose_debug;
+extern int standalone;
 
 #endif

Index: main.c
===================================================================
RCS file: /home/cvs/dovecot/src/auth/main.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- main.c	31 May 2004 20:10:02 -0000	1.26
+++ main.c	23 Jun 2004 17:50:44 -0000	1.27
@@ -15,12 +15,17 @@
 #include "auth-master-connection.h"
 #include "auth-client-connection.h"
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
 
 struct ioloop *ioloop;
 int verbose = FALSE, verbose_debug = FALSE;
+int standalone = FALSE;
 
 static buffer_t *masters_buf;
 
@@ -64,26 +69,120 @@
 	restrict_access_by_env(FALSE);
 }
 
-static void master_add_unix_listeners(struct auth_master_connection *master,
-				      const char *sockets_list)
+static uid_t get_uid(const char *user)
 {
-	const char *const *sockets;
-	int fd;
+	struct passwd *pw;
 
-	sockets = t_strsplit(sockets_list, ":");
-	while (*sockets != NULL) {
-		fd = net_listen_unix(*sockets);
-		if (fd == -1) {
-			i_fatal("net_listen_unix(%s) failed: %m",
-				*sockets);
+	if (user == NULL)
+		return (uid_t)-1;
+
+	if ((pw = getpwnam(user)) == NULL)
+		i_fatal("User doesn't exist: %s", user);
+	return pw->pw_uid;
+}
+
+static gid_t get_gid(const char *group)
+{
+	struct group *gr;
+
+	if (group == NULL)
+		return (gid_t)-1;
+
+	if ((gr = getgrnam(group)) == NULL)
+		i_fatal("Group doesn't exist: %s", group);
+	return gr->gr_gid;
+}
+
+static int create_unix_listener(const char *env)
+{
+	const char *path, *mode, *user, *group;
+	mode_t old_umask;
+	unsigned int mask;
+	uid_t uid;
+	gid_t gid;
+	int fd, i;
+
+	path = getenv(env);
+	if (path == NULL)
+		return -1;
+
+	mode = getenv(t_strdup_printf("%s_MODE", env));
+	if (mode == NULL)
+		mask = 0177; /* default to 0600 */
+	else {
+		if (sscanf(mode, "%o", &mask) != 1)
+			i_fatal("%s: Invalid mode %s", env, mode);
+		mask = (mask ^ 0777) & 0777;
+	}
+
+	old_umask = umask(mask);
+	for (i = 0; i < 5; i++) {
+		fd = net_listen_unix(path);
+		if (fd != -1)
+			break;
+
+		if (errno != EADDRINUSE)
+			i_fatal("net_listen_unix(%s) failed: %m", path);
+
+		/* see if it really exists */
+		if (net_connect_unix(path) != -1 || errno != ECONNREFUSED)
+			i_fatal("Socket already exists: %s", path);
+
+		/* delete and try again */
+		if (unlink(path) < 0)
+			i_fatal("unlink(%s) failed: %m", path);
+	}
+	umask(old_umask);
+
+	user = getenv(t_strdup_printf("%s_USER", env));
+	group = getenv(t_strdup_printf("%s_GROUP", env));
+
+	uid = get_uid(user); gid = get_gid(group);
+	if (chown(path, uid, gid) < 0) {
+		i_fatal("chown(%s, %s, %s) failed: %m",
+			path, dec2str(uid), dec2str(gid));
+	}
+
+	return fd;
+}
+
+static void add_extra_listeners(void)
+{
+	struct auth_master_connection *master;
+	const char *str, *client_path, *master_path;
+	int client_fd, master_fd;
+	unsigned int i;
+
+	for (i = 1;; i++) {
+		t_push();
+		client_path = getenv(t_strdup_printf("AUTH_%u", i));
+		master_path = getenv(t_strdup_printf("AUTH_%u_MASTER", i));
+		if (client_path == NULL && master_path == NULL) {
+			t_pop();
+			break;
 		}
 
-		auth_master_connection_add_listener(master, fd, *sockets);
-		sockets++;
+		str = t_strdup_printf("AUTH_%u", i);
+		client_fd = create_unix_listener(str);
+		str = t_strdup_printf("AUTH_%u_MASTER", i);
+		master_fd = create_unix_listener(str);
+
+		master = auth_master_connection_create(-1, getpid());
+		if (master_fd != -1) {
+			auth_master_connection_add_listener(master, master_fd,
+							    master_path, FALSE);
+		}
+		if (client_fd != -1) {
+			auth_master_connection_add_listener(master, client_fd,
+							    client_path, TRUE);
+		}
+		auth_client_connections_init(master);
+		buffer_append(masters_buf, &master, sizeof(master));
+		t_pop();
 	}
 }
 
-static void main_init(void)
+static void main_init(int nodaemon)
 {
 	struct auth_master_connection *master, **master_p;
 	size_t i, size;
@@ -103,47 +202,45 @@
 	masters_buf = buffer_create_dynamic(default_pool, 64, (size_t)-1);
 
 	env = getenv("AUTH_PROCESS");
-	if (env == NULL) {
+	standalone = env == NULL;
+	if (standalone) {
 		/* starting standalone */
-		env = getenv("AUTH_SOCKETS");
-		if (env == NULL)
-			i_fatal("AUTH_SOCKETS environment not set");
-
-		switch (fork()) {
-		case -1:
-			i_fatal("fork() failed: %m");
-		case 0:
-			break;
-		default:
-			exit(0);
+		if (getenv("AUTH_1") == NULL) {
+			i_fatal("dovecot-auth is usually started through "
+				"dovecot master process. If you wish to run "
+				"it standalone, you'll need to set AUTH_* "
+				"environment variables (AUTH_1 isn't set).");
 		}
 
-		if (setsid() < 0)
-			i_fatal("setsid() failed: %m");
+		if (!nodaemon) {
+			switch (fork()) {
+			case -1:
+				i_fatal("fork() failed: %m");
+			case 0:
+				break;
+			default:
+				exit(0);
+			}
 
-		if (chdir("/") < 0)
-			i_fatal("chdir(/) failed: %m");
+			if (setsid() < 0)
+				i_fatal("setsid() failed: %m");
+
+			if (chdir("/") < 0)
+				i_fatal("chdir(/) failed: %m");
+		}
        } else {
 		pid = atoi(env);
 		if (pid == 0)
 			i_fatal("AUTH_PROCESS can't be 0");
 
-		master = auth_master_connection_new(MASTER_SOCKET_FD, pid);
+		master = auth_master_connection_create(MASTER_SOCKET_FD, pid);
 		auth_master_connection_add_listener(master, LOGIN_LISTEN_FD,
-						    NULL);
+						    NULL, TRUE);
 		auth_client_connections_init(master);
 		buffer_append(masters_buf, &master, sizeof(master));
-
-		/* accept also alternative listeners under dummy master */
-		env = getenv("AUTH_SOCKETS");
 	}
 
-	if (env != NULL && *env != '\0') {
-		master = auth_master_connection_new(-1, 0);
-		master_add_unix_listeners(master, env);
-		auth_client_connections_init(master);
-		buffer_append(masters_buf, &master, sizeof(master));
-	}
+	add_extra_listeners();
 
 	/* everything initialized, notify masters that all is well */
 	master_p = buffer_get_modifyable_data(masters_buf, &size);
@@ -164,10 +261,8 @@
 
 	master = buffer_get_modifyable_data(masters_buf, &size);
 	size /= sizeof(*master);
-	for (i = 0; i < size; i++) {
-		auth_client_connections_deinit(master[i]);
-		auth_master_connection_free(master[i]);
-	}
+	for (i = 0; i < size; i++)
+		auth_master_connection_destroy(master[i]);
 
         password_schemes_deinit();
 	passdb_deinit();
@@ -179,10 +274,11 @@
 	closelog();
 }
 
-int main(int argc __attr_unused__, char *argv[] __attr_unused__)
+int main(int argc, char *argv[])
 {
 #ifdef DEBUG
-        fd_debug_verify_leaks(4, 1024);
+	if (getenv("GDB") == NULL)
+		fd_debug_verify_leaks(4, 1024);
 #endif
 	/* NOTE: we start rooted, so keep the code minimal until
 	   restrict_access_by_env() is called */
@@ -191,7 +287,7 @@
 
 	ioloop = io_loop_create(system_pool);
 
-	main_init();
+	main_init(argc > 1 && strcmp(argv[1], "-F") == 0);
         io_loop_run(ioloop);
 	main_deinit();
 



More information about the dovecot-cvs mailing list