]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Cleanups and fixes to auth-master API.
authorTimo Sirainen <tss@iki.fi>
Sat, 1 Nov 2008 12:20:36 +0000 (14:20 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 1 Nov 2008 12:20:36 +0000 (14:20 +0200)
--HG--
branch : HEAD

src/deliver/Makefile.am
src/deliver/auth-client.c
src/deliver/auth-client.h
src/deliver/deliver.c
src/lib-auth/auth-master.c
src/lib-auth/auth-master.h

index 7319fa1042232154ef647d3805e391445bbaeeea..9625d2a499451ffbc2ca02403bb5f5f0e149269d 100644 (file)
@@ -4,6 +4,7 @@ pkglibexec_PROGRAMS = deliver
 
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-auth \
        -I$(top_srcdir)/src/lib-dict \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-index \
index 6158590ef793efe0f37b6a0e7678caf83d80aaae..d160049d60b7b9ae8f128c6b44301597362e4a04 100644 (file)
@@ -9,7 +9,7 @@
 #include "env-util.h"
 #include "restrict-access.h"
 #include "auth-client.h"
-#include "../lib-auth/auth-master.h"
+#include "auth-master.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -17,8 +17,6 @@
 #include <grp.h>
 #include <sysexits.h>
 
-static int return_value;
-
 static bool parse_uid(const char *str, uid_t *uid_r)
 {
        struct passwd *pw;
@@ -57,44 +55,51 @@ static bool parse_gid(const char *str, gid_t *gid_r)
        return TRUE;
 }
 
-static void set_env(struct auth_user_reply *reply, const char *user, uid_t euid)
+static int set_env(struct auth_user_reply *reply,
+                  const char *user, uid_t euid)
 {
        const char *extra_groups;
        unsigned int len;
 
        if (reply->uid == 0) {
                i_error("userdb(%s) returned 0 as uid", user);
-               return;
+               return -1;
        } else if (reply->uid == (uid_t)-1) {
                if (getenv("MAIL_UID") != NULL) {
-                       if (!parse_uid(getenv("MAIL_UID"), &reply->uid) || reply->uid == 0) {
+                       if (!parse_uid(getenv("MAIL_UID"), &reply->uid) ||
+                           reply->uid == 0) {
                                i_error("mail_uid setting is invalid");
-                               return;
+                               return -1;
                        }
                } else {
                        i_error("User %s is missing UID (set mail_uid)", user);
-                       return;
+                       return -1;
                }
        }
        if (reply->gid == 0) {
                i_error("userdb(%s) returned 0 as gid", user);
-               return;
+               return -1;
        } else if (reply->gid == (gid_t)-1) {
                if (getenv("MAIL_GID") != NULL) {
-                       if (!parse_gid(getenv("MAIL_GID"), &reply->gid) || reply->gid == 0) {
+                       if (!parse_gid(getenv("MAIL_GID"), &reply->gid) ||
+                           reply->gid == 0) {
                                i_error("mail_gid setting is invalid");
-                               return;
+                               return -1;
                        }
                } else {
                        i_error("User %s is missing GID (set mail_gid)", user);
-                       return;
+                       return -1;
                }
        }
 
-       if (euid != reply->uid)
-               env_put(t_strconcat("RESTRICT_SETUID=", dec2str(reply->uid), NULL));
-       if (euid == 0 || getegid() != reply->gid)
-               env_put(t_strconcat("RESTRICT_SETGID=", dec2str(reply->gid), NULL));
+       if (euid != reply->uid) {
+               env_put(t_strconcat("RESTRICT_SETUID=",
+                                   dec2str(reply->uid), NULL));
+       }
+       if (euid == 0 || getegid() != reply->gid) {
+               env_put(t_strconcat("RESTRICT_SETGID=",
+                                   dec2str(reply->gid), NULL));
+       }
 
        if (reply->chroot == NULL)
                reply->chroot = getenv("MAIL_CHROOT");
@@ -116,40 +121,32 @@ static void set_env(struct auth_user_reply *reply, const char *user, uid_t euid)
                env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
                                    extra_groups, NULL));
        }
-
-       return_value = EX_OK;
+       return 0;
 }
 
 int auth_client_lookup_and_restrict(const char *auth_socket,
-                                   const char *user, uid_t euid,
-                                   pool_t pool,
-                                   ARRAY_TYPE(string) **extra_fields_r)
+                                   const char *user, uid_t euid, pool_t pool,
+                                   ARRAY_TYPE(const_string) *extra_fields_r)
 {
         struct auth_connection *conn;
-       struct auth_user_reply *reply;
+       struct auth_user_reply reply;
        bool debug = getenv("DEBUG") != NULL;
+       int ret = EX_TEMPFAIL;
 
        conn = auth_master_init(auth_socket, debug);
-       reply = i_new(struct auth_user_reply, 1);
-
-       return_value = EX_TEMPFAIL;
-
-       switch (auth_master_user_lookup(conn, user, "deliver", pool, reply)) {
-       case -1:
-               break;
+       switch (auth_master_user_lookup(conn, user, "deliver", pool, &reply)) {
        case 0:
-               return_value = EX_NOUSER;
+               ret = EX_NOUSER;
                break;
        case 1:
-               set_env(reply, user, euid);
-               if (return_value == EX_OK)
+               if (set_env(&reply, user, euid) == 0) {
                        restrict_access_by_env(TRUE);
+                       ret = EX_OK;
+               }
                break;
        }
-       
-       *extra_fields_r = reply->extra_fields;
-       i_free(reply);
-       auth_master_deinit(conn);
 
-       return return_value;
+       *extra_fields_r = reply.extra_fields;
+       auth_master_deinit(conn);
+       return ret;
 }
index 2908802dd70c327b6d201c9b8e6f16993a2e6ffe..e48043c77b7dbc094c9e16d1af6441b29d794261 100644 (file)
@@ -2,8 +2,7 @@
 #define AUTH_CLIENT_H
 
 int auth_client_lookup_and_restrict(const char *auth_socket,
-                                   const char *user, uid_t euid,
-                                   pool_t pool,
-                                   ARRAY_TYPE(string) **extra_fields_r);
+                                   const char *user, uid_t euid, pool_t pool,
+                                   ARRAY_TYPE(const_string) *extra_fields_r);
 
 #endif
index 26ff8ce52f15f6480a8a3968ad7111c37006d9b2..15a272c06c4922ecc60f132d53bb85f6feeef5ba 100644 (file)
@@ -75,7 +75,7 @@ static void sig_die(int signo, void *context ATTR_UNUSED)
           which is too common at least while testing :) */
        if (signo != SIGINT)
                i_warning("Killed with signal %d", signo);
-       io_loop_stop(ioloop);
+       io_loop_stop(current_ioloop);
 }
 
 static const char *deliver_get_address(struct mail *mail, const char *header)
@@ -774,13 +774,13 @@ static void expand_envs(const char *user)
        }
 }
 
-static void putenv_extra_fields(ARRAY_TYPE(string) *extra_fields)
+static void putenv_extra_fields(const ARRAY_TYPE(const_string) *extra_fields)
 {
-       char **fields;
+       const char *const *fields;
        const char *key, *p;
        unsigned int i, count;
 
-       fields = array_get_modifiable(extra_fields, &count);
+       fields = array_get(extra_fields, &count);
        for (i = 0; i < count; i++) {
                p = strchr(fields[i], '=');
                if (p == NULL)
@@ -798,7 +798,7 @@ int main(int argc, char *argv[])
        const char *mailbox = "INBOX";
        const char *auth_socket;
        const char *home, *destaddr, *user, *value, *errstr, *path;
-       ARRAY_TYPE(string) *extra_fields;
+       ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT;
        struct mail_user *mail_user, *raw_mail_user;
        struct mail_namespace *raw_ns;
        struct mail_storage *storage;
@@ -814,7 +814,7 @@ int main(int argc, char *argv[])
        bool user_auth = FALSE;
        time_t mtime;
        int i, ret;
-       pool_t userdb_pool;
+       pool_t userdb_pool = NULL;
 
        i_set_failure_exit_callback(failure_exit_callback);
 
@@ -945,8 +945,6 @@ int main(int argc, char *argv[])
                                          TRUE, version);
        }
 
-       userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
-
        if (user_auth) {
                auth_socket = getenv("AUTH_SOCKET_PATH");
                if (auth_socket == NULL) {
@@ -957,6 +955,7 @@ int main(int argc, char *argv[])
                                                  NULL);
                }
 
+               userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
                ret = auth_client_lookup_and_restrict(auth_socket,
                                                      user, process_euid,
                                                      userdb_pool,
@@ -968,9 +967,10 @@ int main(int argc, char *argv[])
                destaddr = user;
 
        expand_envs(user);
-       putenv_extra_fields(extra_fields);
-
-       pool_unref(&userdb_pool);
+       if (userdb_pool != NULL) {
+               putenv_extra_fields(&extra_fields);
+               pool_unref(&userdb_pool);
+       }
 
        /* Fix namespaces with empty locations */
        for (i = 1;; i++) {
index 96625ff059b50c91212040520fc34e478d55ea17..0b819bd02631f2639db3e93a40ce5f095ebe8c3d 100644 (file)
 /* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "lib-signals.h"
 #include "array.h"
 #include "ioloop.h"
 #include "network.h"
 #include "istream.h"
 #include "ostream.h"
-#include "env-util.h"
-#include "restrict-access.h"
 #include "auth-master.h"
 
 #include <stdlib.h>
 #include <unistd.h>
-#include <pwd.h>
-#include <grp.h>
-#include <sysexits.h>
 
-#define AUTH_REQUEST_TIMEOUT 60
+#define AUTH_PROTOCOL_MAJOR 1
+#define AUTH_PROTOCOL_MINOR 0
+
+#define AUTH_REQUEST_TIMEOUT_SECS 30
+#define AUTH_MASTER_IDLE_SECS 60
+
 #define MAX_INBUF_SIZE 8192
-#define MAX_OUTBUF_SIZE 512
+#define MAX_OUTBUF_SIZE 1024
 
 struct auth_connection {
+       char *auth_socket_path;
+
        int fd;
-       struct timeout *to;
+       struct ioloop *ioloop;
        struct io *io;
        struct istream *input;
        struct ostream *output;
+       struct timeout *to;
 
-       struct ioloop *ioloop;
-       const char *auth_socket;
-       const char *user;
+       unsigned int request_counter;
        pool_t pool;
+       const char *user;
        struct auth_user_reply *user_reply;
        int return_value;
 
+       unsigned int debug:1;
+       unsigned int sent_handshake:1;
        unsigned int handshaked:1;
-       bool debug;
+       unsigned int aborted:1;
 };
 
 static void auth_input(struct auth_connection *conn);
 
-struct auth_connection *auth_master_init(const char *auth_socket, bool debug)
+struct auth_connection *
+auth_master_init(const char *auth_socket_path, bool debug)
 {
        struct auth_connection *conn;
-       int fd, try;
-
-       /* max. 1 second wait here. */
-       for (try = 0; try < 10; try++) {
-               fd = net_connect_unix(auth_socket);
-               if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
-                       break;
-
-               /* busy. wait for a while. */
-               usleep(((rand() % 10) + 1) * 10000);
-       }
-       if (fd == -1) {
-               i_error("Can't connect to auth server at %s: %m", auth_socket);
-               return NULL;
-       }
 
        conn = i_new(struct auth_connection, 1);
-       conn->auth_socket = auth_socket;
-       conn->fd = fd;
-       conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
-       conn->output = o_stream_create_fd(fd, MAX_OUTBUF_SIZE, FALSE);
-       conn->io = io_add(fd, IO_READ, auth_input, conn);
-       conn->ioloop = current_ioloop;
+       conn->auth_socket_path = i_strdup(auth_socket_path);
+       conn->fd = -1;
        conn->debug = debug;
        return conn;
 }
 
 static void auth_connection_close(struct auth_connection *conn)
 {
-       if (conn->fd == -1)
-               return;
-
-       io_loop_stop(conn->ioloop);
-
        if (conn->to != NULL)
                timeout_remove(&conn->to);
-       io_remove(&conn->io);
-       i_stream_unref(&conn->input);
-       o_stream_unref(&conn->output);
-       if (close(conn->fd) < 0)
-               i_error("close() failed: %m");
+       if (conn->fd != -1) {
+               if (close(conn->fd) < 0)
+                       i_error("close(%s) failed: %m", conn->auth_socket_path);
+               conn->fd = -1;
+       }
 
-       conn->fd = -1;
+       conn->sent_handshake = FALSE;
+       conn->handshaked = FALSE;
 }
 
 void auth_master_deinit(struct auth_connection *conn)
 {
        auth_connection_close(conn);
+       i_free(conn->auth_socket_path);
        i_free(conn);
 }
 
-static void auth_parse_input(struct auth_connection *conn, const char *args)
+static void auth_request_lookup_abort(struct auth_connection *conn)
+{
+       io_loop_stop(conn->ioloop);
+       conn->aborted = TRUE;
+}
+
+static void auth_parse_input(struct auth_connection *conn,
+                            const char *const *args)
 {
        struct auth_user_reply *reply = conn->user_reply;
-       const char *const *tmp;
-       uid_t uid = (uid_t)-1;
-       gid_t gid = (gid_t)-1;
-       const char *chroot_dir = NULL;
-       const char *home_dir = NULL;
 
-       reply->extra_fields = p_new(conn->pool, ARRAY_TYPE(string), 1);
-       p_array_init(reply->extra_fields, conn->pool, 64);
+       memset(reply, 0, sizeof(*reply));
+       reply->uid = (uid_t)-1;
+       reply->gid = (gid_t)-1;
+       p_array_init(&reply->extra_fields, conn->pool, 64);
 
-       for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
+       for (; *args != NULL; args++) {
                if (conn->debug)
-                       i_info("auth input: %s", *tmp);
-
-               if (strncmp(*tmp, "uid=", 4) == 0)
-                       uid = strtoul(*tmp + 4, NULL, 10);
-               else if (strncmp(*tmp, "gid=", 4) == 0) {
-                       gid = strtoul(*tmp + 4, NULL, 10);
-
-               } else if (strncmp(*tmp, "chroot=", 7) == 0) {
-                       chroot_dir = *tmp + 7;
-               } else {
-                       char *field = p_strdup(conn->pool, *tmp);
-
-                       if (strncmp(field, "home=", 5) == 0)
-                               home_dir = field + 5;
-
-                       if (reply->extra_fields != NULL)
-                               array_append(reply->extra_fields, &field, 1);
+                       i_info("auth input: %s", *args);
+
+               if (strncmp(*args, "uid=", 4) == 0)
+                       reply->uid = strtoul(*args + 4, NULL, 10);
+               else if (strncmp(*args, "gid=", 4) == 0)
+                       reply->gid = strtoul(*args + 4, NULL, 10);
+               else if (strncmp(*args, "home=", 5) == 0)
+                       reply->home = p_strdup(conn->pool, *args + 5);
+               else if (strncmp(*args, "chroot=", 7) == 0)
+                       reply->chroot = p_strdup(conn->pool, *args + 7);
+               else {
+                       const char *field = p_strdup(conn->pool, *args);
+                       array_append(&reply->extra_fields, &field, 1);
                }
        }
+}
 
-       reply->uid = uid;
-       reply->gid = gid;
-       if (home_dir != NULL)
-               reply->home = p_strdup(conn->pool, home_dir);
-       else
-               reply->home = NULL;
-       reply->chroot = p_strdup(conn->pool, chroot_dir);
-       
-       conn->return_value = 1;
+static int auth_input_handshake(struct auth_connection *conn)
+{
+       const char *line, *const *tmp;
+
+       while ((line = i_stream_next_line(conn->input)) != NULL) {
+               tmp = t_strsplit(line, "\t");
+               if (strcmp(tmp[0], "VERSION") == 0 &&
+                   tmp[1] != NULL && tmp[2] != NULL) {
+                       if (strcmp(tmp[1], dec2str(AUTH_PROTOCOL_MAJOR)) != 0) {
+                               i_error("userdb lookup(%s): "
+                                       "Auth protocol version mismatch "
+                                       "(%s vs %d)", conn->user, tmp[1],
+                                       AUTH_PROTOCOL_MAJOR);
+                               auth_request_lookup_abort(conn);
+                               return -1;
+                       }
+               } else if (strcmp(tmp[0], "SPID") == 0) {
+                       conn->handshaked = TRUE;
+                       break;
+               }
+       }
+       return 0;
 }
 
 static void auth_input(struct auth_connection *conn)
 {
-       const char *line;
+       const char *line, *cmd, *const *args, *id, *wanted_id;
 
        switch (i_stream_read(conn->input)) {
        case 0:
                return;
        case -1:
                /* disconnected */
-               i_error("Auth lookup disconnected unexpectedly");
-               auth_connection_close(conn);
+               i_error("userdb lookup(%s): Disconnected unexpectedly",
+                       conn->user);
+               auth_request_lookup_abort(conn);
                return;
        case -2:
                /* buffer full */
-               i_error("BUG: Auth master sent us more than %d bytes",
-                       MAX_INBUF_SIZE);
-               auth_connection_close(conn);
+               i_error("userdb lookup(%s): BUG: Received more than %d bytes",
+                       conn->user, MAX_INBUF_SIZE);
+               auth_request_lookup_abort(conn);
                return;
        }
 
        if (!conn->handshaked) {
-               while ((line = i_stream_next_line(conn->input)) != NULL) {
-                       if (strncmp(line, "VERSION\t", 8) == 0) {
-                               if (strncmp(line + 8, "1\t", 2) != 0) {
-                                       i_error("Auth master version mismatch");
-                                       auth_connection_close(conn);
-                                       return;
-                               }
-                       } else if (strncmp(line, "SPID\t", 5) == 0) {
-                               conn->handshaked = TRUE;
-                               break;
-                       }
-               }
+               if (auth_input_handshake(conn) < 0)
+                       return;
        }
 
        line = i_stream_next_line(conn->input);
-       if (line != NULL) {
-               if (strncmp(line, "USER\t1\t", 7) == 0) {
-                       auth_parse_input(conn, line + 7);
-               } else if (strcmp(line, "NOTFOUND\t1") == 0)
+       if (line == NULL)
+               return;
+
+       args = t_strsplit(line, "\t");
+       cmd = *args; args++;
+       if (*args == NULL)
+               id = "";
+       else {
+               id = *args;
+               args++;
+       }
+
+       wanted_id = dec2str(conn->request_counter);
+       if (strcmp(id, wanted_id) == 0) {
+               io_loop_stop(conn->ioloop);
+               if (strcmp(cmd, "USER") == 0) {
+                       auth_parse_input(conn, args);
+                       conn->return_value = 1;
+                       return;
+               }
+               if (strcmp(cmd, "NOTFOUND") == 0) {
                        conn->return_value = 0;
-               else if (strncmp(line, "FAIL\t1", 6) == 0) {
-                       i_error("Auth lookup returned failure");
-                       conn->return_value = -1;
-               } else if (strncmp(line, "CUID\t", 5) == 0) {
-                       i_error("%s is an auth client socket. "
-                               "It should be a master socket.",
-                               conn->auth_socket);
-                       conn->return_value = -1;
-               } else {
-                       i_error("BUG: Unexpected input from auth master: %s",
-                               line);
+                       return;
                }
-               auth_connection_close(conn);
+               if (strcmp(cmd, "FAIL") == 0) {
+                       i_error("userdb lookup(%s) failed: %s",
+                               conn->user, *args != NULL ? *args :
+                               "Internal failure");
+                       return;
+               }
+       }
+       
+       if (strcmp(cmd, "CUID") == 0) {
+               i_error("userdb lookup(%s): %s is an auth client socket. "
+                       "It should be a master socket.",
+                       conn->user, conn->auth_socket_path);
+       } else {
+               i_error("userdb lookup(%s): BUG: Unexpected input: %s",
+                       conn->user, line);
        }
+       auth_request_lookup_abort(conn);
 }
 
+static int auth_master_connect(struct auth_connection *conn)
+{
+       int fd, try;
+
+       i_assert(conn->fd == -1);
+
+       /* max. 1 second wait here. */
+       for (try = 0; try < 10; try++) {
+               fd = net_connect_unix(conn->auth_socket_path);
+               if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
+                       break;
+
+               /* busy. wait for a while. */
+               usleep(((rand() % 10) + 1) * 10000);
+       }
+       if (fd == -1) {
+               i_error("userdb lookup: connect(%s) failed: %m",
+                       conn->auth_socket_path);
+               return -1;
+       }
+       conn->fd = fd;
+       return 0;
+}
 
-static void auth_client_timeout(struct auth_connection *conn)
+static void auth_request_timeout(struct auth_connection *conn)
 {
        if (!conn->handshaked)
-               i_error("Connecting to dovecot-auth timed out");
+               i_error("userdb lookup(%s): Connecting timed out", conn->user);
        else
-               i_error("User request from dovecot-auth timed out");
+               i_error("userdb lookup(%s): Request timed out", conn->user);
+       auth_request_lookup_abort(conn);
+}
+
+static void auth_idle_timeout(struct auth_connection *conn)
+{
        auth_connection_close(conn);
 }
 
+static void auth_master_set_io(struct auth_connection *conn)
+{
+       if (conn->to != NULL)
+               timeout_remove(&conn->to);
+
+       conn->ioloop = io_loop_create();
+       conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
+       conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
+       conn->io = io_add(conn->fd, IO_READ, auth_input, conn);
+       conn->to = timeout_add(1000*AUTH_REQUEST_TIMEOUT_SECS,
+                              auth_request_timeout, conn);
+       lib_signals_reset_ioloop();
+}
+
+static void auth_master_unset_io(struct auth_connection *conn,
+                                struct ioloop *prev_ioloop)
+{
+       io_loop_set_current(prev_ioloop);
+       lib_signals_reset_ioloop();
+       io_loop_set_current(conn->ioloop);
+
+       timeout_remove(&conn->to);
+       io_remove(&conn->io);
+       i_stream_unref(&conn->input);
+       o_stream_unref(&conn->output);
+       io_loop_destroy(&conn->ioloop);
+
+       conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
+                              auth_idle_timeout, conn);
+}
+
+static bool is_valid_string(const char *str)
+{
+       const char *p;
+
+       /* make sure we're not sending any characters that have a special
+          meaning. */
+       for (p = str; *p != '\0'; p++) {
+               if (*p == '\t' || *p == '\n' || *p == '\r')
+                       return FALSE;
+       }
+       return TRUE;
+}
+
 int auth_master_user_lookup(struct auth_connection *conn,
-                           const char *user,
-                           const char *service,
-                           pool_t pool,
-                           struct auth_user_reply *reply_r)
+                           const char *user, const char *service,
+                           pool_t pool, struct auth_user_reply *reply_r)
 {
-       if (conn == NULL)
-               return -1;
+       struct ioloop *prev_ioloop;
+       const char *str;
 
-       conn->user = user;
+       if (!is_valid_string(user) || !is_valid_string(service)) {
+               /* non-allowed characters, the user can't exist */
+               return 0;
+       }
+       if (conn->fd == -1) {
+               if (auth_master_connect(conn) < 0)
+                       return -1;
+       }
+
+       prev_ioloop = current_ioloop;
+       auth_master_set_io(conn);
        conn->return_value = -1;
-       conn->to = timeout_add(1000*AUTH_REQUEST_TIMEOUT,
-                              auth_client_timeout, conn);
        conn->pool = pool;
+       conn->user = user;
        conn->user_reply = reply_r;
+       if (++conn->request_counter == 0) {
+               /* avoid zero */
+               conn->request_counter++;
+       }
+
+       o_stream_cork(conn->output);
+       if (!conn->sent_handshake) {
+               str = t_strdup_printf("VERSION\t%d\t%d\n",
+                                     AUTH_PROTOCOL_MAJOR, AUTH_PROTOCOL_MINOR);
+               o_stream_send_str(conn->output, str);
+               conn->sent_handshake = TRUE;
+       }
 
-       o_stream_send_str(conn->output,
-                         t_strconcat("VERSION\t1\t0\n"
-                                     "USER\t1\t", user, "\t"
-                                     "service=", service, "\n",
-                                     NULL));
+       str = t_strdup_printf("USER\t%u\t%s\tservice=%s\n",
+                             conn->request_counter, user, service);
+       o_stream_send_str(conn->output, str);
+       o_stream_uncork(conn->output);
 
-       io_loop_run(conn->ioloop);
+       if (conn->output->stream_errno != 0) {
+               errno = conn->output->stream_errno;
+               i_error("write(auth socket) failed: %m");
+       } else {
+               io_loop_run(conn->ioloop);
+       }
+
+       auth_master_unset_io(conn, prev_ioloop);
+       if (conn->aborted) {
+               conn->aborted = FALSE;
+               auth_connection_close(conn);
+       }
+       conn->user = NULL;
+       conn->pool = NULL;
+       conn->user_reply = NULL;
        return conn->return_value;
 }
index c8a5ec7e051cdac85958036dbf898f8a33205589..0560996c2d97f31be62fc4859961da1be7d57aca 100644 (file)
@@ -5,17 +5,16 @@ struct auth_user_reply {
        uid_t uid;
        gid_t gid;
        const char *home, *chroot;
-       ARRAY_TYPE(string) *extra_fields;
+       ARRAY_TYPE(const_string) extra_fields;
 };
 
-struct auth_connection *auth_master_init(const char *auth_socket, bool debug);
+struct auth_connection *
+auth_master_init(const char *auth_socket_path, bool debug);
 void auth_master_deinit(struct auth_connection *conn);
 
 /* Returns -1 = error, 0 = user not found, 1 = ok */
 int auth_master_user_lookup(struct auth_connection *conn,
-                           const char *user,
-                           const char *service,
-                           pool_t pool,
-                           struct auth_user_reply *reply_r);
+                           const char *user, const char *service,
+                           pool_t pool, struct auth_user_reply *reply_r);
 
 #endif