[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