]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
New generic userdb lookup api `auth-master' in lib-auth.
authorSascha Wilde <wilde@intevation.de>
Fri, 24 Oct 2008 14:06:07 +0000 (16:06 +0200)
committerSascha Wilde <wilde@intevation.de>
Fri, 24 Oct 2008 14:06:07 +0000 (16:06 +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/Makefile.am
src/lib-auth/auth-master.c [new file with mode: 0644]
src/lib-auth/auth-master.h [new file with mode: 0644]

index 025c3673441a468d9ac9962087343e9c1baa028f..7319fa1042232154ef647d3805e391445bbaeeea 100644 (file)
@@ -20,7 +20,7 @@ deliver_LDFLAGS = -export-dynamic
 # get some functions included which only plugins use. liblib should probably
 # be a shared library so this wouldn't be needed..
 unused_objects = \
-       ../lib/mountpoint.o
+       ../lib/mountpoint.o
 
 libs = \
        ../lib-storage/register/libstorage-register.a \
@@ -30,6 +30,7 @@ libs = \
        ../lib-mail/libmail.a \
        ../lib-dict/libdict.a \
        ../lib-charset/libcharset.a \
+       ../lib-auth/libauth.a \
        ../lib/liblib.a \
        $(unused_objects)
 
index be58ad6043ecb237fdbb3dedd7cf627c0d7086f6..6158590ef793efe0f37b6a0e7678caf83d80aaae 100644 (file)
@@ -9,6 +9,7 @@
 #include "env-util.h"
 #include "restrict-access.h"
 #include "auth-client.h"
+#include "../lib-auth/auth-master.h"
 
 #include <stdlib.h>
 #include <unistd.h>
 #include <grp.h>
 #include <sysexits.h>
 
-#define AUTH_REQUEST_TIMEOUT 60
-#define MAX_INBUF_SIZE 8192
-#define MAX_OUTBUF_SIZE 512
-
 static int return_value;
 
-struct auth_connection {
-       int fd;
-       struct timeout *to;
-       struct io *io;
-       struct istream *input;
-       struct ostream *output;
-
-       struct ioloop *ioloop;
-       uid_t euid;
-       const char *auth_socket;
-       const char *user;
-       ARRAY_TYPE(string) *extra_fields;
-
-       unsigned int handshaked:1;
-};
-
-static void auth_connection_destroy(struct auth_connection *conn)
-{
-       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");
-       i_free(conn);
-}
-
 static bool parse_uid(const char *str, uid_t *uid_r)
 {
        struct passwd *pw;
@@ -90,90 +57,59 @@ static bool parse_gid(const char *str, gid_t *gid_r)
        return TRUE;
 }
 
-static void auth_parse_input(struct auth_connection *conn, const char *args)
+static void set_env(struct auth_user_reply *reply, const char *user, uid_t euid)
 {
-       const char *const *tmp, *extra_groups;
-       uid_t uid = 0;
-       gid_t gid = 0;
-       const char *chroot_dir = getenv("MAIL_CHROOT");
-       const char *home_dir = NULL;
-       bool debug = getenv("DEBUG") != NULL;
+       const char *extra_groups;
        unsigned int len;
 
-       for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
-               if (debug)
-                       i_info("auth input: %s", *tmp);
-
-               if (strncmp(*tmp, "uid=", 4) == 0) {
-                       uid = strtoul(*tmp + 4, NULL, 10);
-
-                       if (uid == 0) {
-                               i_error("userdb(%s) returned 0 as uid",
-                                       conn->user);
-                               return_value = EX_TEMPFAIL;
-                       }
-               } else if (strncmp(*tmp, "gid=", 4) == 0) {
-                       gid = strtoul(*tmp + 4, NULL, 10);
-
-                       if (gid == 0) {
-                               i_error("userdb(%s) returned 0 as gid",
-                                       conn->user);
-                               return_value = EX_TEMPFAIL;
+       if (reply->uid == 0) {
+               i_error("userdb(%s) returned 0 as uid", user);
+               return;
+       } else if (reply->uid == (uid_t)-1) {
+               if (getenv("MAIL_UID") != NULL) {
+                       if (!parse_uid(getenv("MAIL_UID"), &reply->uid) || reply->uid == 0) {
+                               i_error("mail_uid setting is invalid");
+                               return;
                        }
-               } else if (strncmp(*tmp, "chroot=", 7) == 0) {
-                       chroot_dir = *tmp + 7;
                } else {
-                       char *field = i_strdup(*tmp);
-
-                       if (strncmp(field, "home=", 5) == 0)
-                               home_dir = field + 5;
-
-                       array_append(conn->extra_fields, &field, 1);
-               }
-       }
-
-       if (uid == 0 && getenv("MAIL_UID") != NULL) {
-               if (!parse_uid(getenv("MAIL_UID"), &uid) || uid == 0) {
-                       i_error("mail_uid setting is invalid");
-                       return_value = EX_TEMPFAIL;
+                       i_error("User %s is missing UID (set mail_uid)", user);
                        return;
                }
        }
-       if (uid == 0) {
-               i_error("User %s is missing UID (set mail_uid)", conn->user);
-               return_value = EX_TEMPFAIL;
+       if (reply->gid == 0) {
+               i_error("userdb(%s) returned 0 as gid", user);
                return;
-       }
-       if (gid == 0 && getenv("MAIL_GID") != NULL) {
-               if (!parse_gid(getenv("MAIL_GID"), &gid) || gid == 0) {
-                       i_error("mail_gid setting is invalid");
-                       return_value = EX_TEMPFAIL;
+       } else if (reply->gid == (gid_t)-1) {
+               if (getenv("MAIL_GID") != NULL) {
+                       if (!parse_gid(getenv("MAIL_GID"), &reply->gid) || reply->gid == 0) {
+                               i_error("mail_gid setting is invalid");
+                               return;
+                       }
+               } else {
+                       i_error("User %s is missing GID (set mail_gid)", user);
                        return;
                }
        }
-       if (gid == 0) {
-               i_error("User %s is missing GID (set mail_gid)", conn->user);
-               return_value = EX_TEMPFAIL;
-               return;
-       }
-
-       if (conn->euid != uid)
-               env_put(t_strconcat("RESTRICT_SETUID=", dec2str(uid), NULL));
-       if (conn->euid == 0 || getegid() != gid)
-               env_put(t_strconcat("RESTRICT_SETGID=", dec2str(gid), NULL));
 
-       if (chroot_dir != NULL) {
-               len = strlen(chroot_dir);
-               if (len > 2 && strcmp(chroot_dir + len - 2, "/.") == 0 &&
-                   home_dir != NULL &&
-                   strncmp(home_dir, chroot_dir, len - 2) == 0) {
+       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");
+       if (reply->chroot != NULL) {
+               len = strlen(reply->chroot);
+               if (len > 2 && strcmp(reply->chroot + len - 2, "/.") == 0 &&
+                   reply->home != NULL &&
+                   strncmp(reply->home, reply->chroot, len - 2) == 0) {
                        /* strip chroot dir from home dir */
-                       home_dir += len - 2;
+                       reply->home += len - 2;
                }
-               env_put(t_strconcat("RESTRICT_CHROOT=", chroot_dir, NULL));
+               env_put(t_strconcat("RESTRICT_CHROOT=", reply->chroot, NULL));
        }
-       if (home_dir != NULL)
-               env_put(t_strconcat("HOME=", home_dir, NULL));
+       if (reply->home != NULL)
+               env_put(t_strconcat("HOME=", reply->home, NULL));
 
        extra_groups = getenv("MAIL_EXTRA_GROUPS");
        if (extra_groups != NULL) {
@@ -181,127 +117,39 @@ static void auth_parse_input(struct auth_connection *conn, const char *args)
                                    extra_groups, NULL));
        }
 
-       restrict_access_by_env(TRUE);
        return_value = EX_OK;
 }
 
-static void auth_input(struct auth_connection *conn)
-{
-       const char *line;
-
-       switch (i_stream_read(conn->input)) {
-       case 0:
-               return;
-       case -1:
-               /* disconnected */
-               i_error("Auth lookup disconnected unexpectedly");
-               auth_connection_destroy(conn);
-               return;
-       case -2:
-               /* buffer full */
-               i_error("BUG: Auth master sent us more than %d bytes",
-                       MAX_INBUF_SIZE);
-               auth_connection_destroy(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_destroy(conn);
-                                       return;
-                               }
-                       } else if (strncmp(line, "SPID\t", 5) == 0) {
-                               conn->handshaked = TRUE;
-                               break;
-                       }
-               }
-       }
-
-       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)
-                       return_value = EX_NOUSER;
-               else if (strncmp(line, "FAIL\t1", 6) == 0) {
-                       i_error("Auth lookup returned failure");
-                       return_value = EX_TEMPFAIL;
-               } 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);
-               } else {
-                       i_error("BUG: Unexpected input from auth master: %s",
-                               line);
-               }
-               auth_connection_destroy(conn);
-       }
-}
-
-static struct auth_connection *auth_connection_new(const char *auth_socket)
-{
-       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->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);
-       return conn;
-}
-
-static void auth_client_timeout(struct auth_connection *conn)
-{
-       if (!conn->handshaked)
-               i_error("Connecting to dovecot-auth timed out");
-       else
-               i_error("User request from dovecot-auth timed out");
-       auth_connection_destroy(conn);
-}
-
-int auth_client_lookup_and_restrict(struct ioloop *ioloop,
-                                   const char *auth_socket,
+int auth_client_lookup_and_restrict(const char *auth_socket,
                                    const char *user, uid_t euid,
-                                   ARRAY_TYPE(string) *extra_fields_r)
+                                   pool_t pool,
+                                   ARRAY_TYPE(string) **extra_fields_r)
 {
         struct auth_connection *conn;
+       struct auth_user_reply *reply;
+       bool debug = getenv("DEBUG") != NULL;
 
-       conn = auth_connection_new(auth_socket);
-       if (conn == NULL)
-               return EX_TEMPFAIL;
+       conn = auth_master_init(auth_socket, debug);
+       reply = i_new(struct auth_user_reply, 1);
 
-       conn->ioloop = ioloop;
-       conn->euid = euid;
-       conn->user = user;
-       conn->auth_socket = auth_socket;
-       conn->to = timeout_add(1000*AUTH_REQUEST_TIMEOUT,
-                              auth_client_timeout, conn);
-       conn->extra_fields = extra_fields_r;
+       return_value = EX_TEMPFAIL;
 
-       o_stream_send_str(conn->output,
-                         t_strconcat("VERSION\t1\t0\n"
-                                     "USER\t1\t", user, "\t"
-                                     "service=deliver\n", NULL));
+       switch (auth_master_user_lookup(conn, user, "deliver", pool, reply)) {
+       case -1:
+               break;
+       case 0:
+               return_value = EX_NOUSER;
+               break;
+       case 1:
+               set_env(reply, user, euid);
+               if (return_value == EX_OK)
+                       restrict_access_by_env(TRUE);
+               break;
+       }
+       
+       *extra_fields_r = reply->extra_fields;
+       i_free(reply);
+       auth_master_deinit(conn);
 
-       return_value = EX_TEMPFAIL;
-       io_loop_run(ioloop);
        return return_value;
 }
index a2eeeb9140dbf241387067476524996b44b089a4..2908802dd70c327b6d201c9b8e6f16993a2e6ffe 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef AUTH_CLIENT_H
 #define AUTH_CLIENT_H
 
-int auth_client_lookup_and_restrict(struct ioloop *ioloop,
-                                   const char *auth_socket,
+int auth_client_lookup_and_restrict(const char *auth_socket,
                                    const char *user, uid_t euid,
-                                   ARRAY_TYPE(string) *extra_fields_r);
+                                   pool_t pool,
+                                   ARRAY_TYPE(string) **extra_fields_r);
 
 #endif
index 201ed9acce847288589ae4c7eaab9bc76c8f81c3..26ff8ce52f15f6480a8a3968ad7111c37006d9b2 100644 (file)
@@ -789,7 +789,6 @@ static void putenv_extra_fields(ARRAY_TYPE(string) *extra_fields)
                        key = t_str_ucase(t_strdup_until(fields[i], p));
                        env_put(t_strconcat(key, p, NULL));
                }
-               i_free(fields[i]);
        }
 }
 
@@ -799,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(string) *extra_fields;
        struct mail_user *mail_user, *raw_mail_user;
        struct mail_namespace *raw_ns;
        struct mail_storage *storage;
@@ -815,6 +814,7 @@ int main(int argc, char *argv[])
        bool user_auth = FALSE;
        time_t mtime;
        int i, ret;
+       pool_t userdb_pool;
 
        i_set_failure_exit_callback(failure_exit_callback);
 
@@ -945,7 +945,8 @@ int main(int argc, char *argv[])
                                          TRUE, version);
        }
 
-       t_array_init(&extra_fields, 64);
+       userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
+
        if (user_auth) {
                auth_socket = getenv("AUTH_SOCKET_PATH");
                if (auth_socket == NULL) {
@@ -956,8 +957,9 @@ int main(int argc, char *argv[])
                                                  NULL);
                }
 
-               ret = auth_client_lookup_and_restrict(ioloop, auth_socket,
+               ret = auth_client_lookup_and_restrict(auth_socket,
                                                      user, process_euid,
+                                                     userdb_pool,
                                                      &extra_fields);
                if (ret != 0)
                        return ret;
@@ -966,7 +968,9 @@ int main(int argc, char *argv[])
                destaddr = user;
 
        expand_envs(user);
-       putenv_extra_fields(&extra_fields);
+       putenv_extra_fields(extra_fields);
+
+       pool_unref(&userdb_pool);
 
        /* Fix namespaces with empty locations */
        for (i = 1;; i++) {
index 6f3eb658d4254cd73353b40b7cd5e676df65f8d3..6965692a640054efa82ae55cdb61ce053196a60c 100644 (file)
@@ -5,11 +5,13 @@ AM_CPPFLAGS = \
 
 libauth_a_SOURCES = \
        auth-client.c \
+       auth-master.c \
        auth-server-connection.c \
        auth-server-request.c
 
 headers = \
        auth-client.h \
+       auth-master.h \
        auth-server-connection.h \
        auth-server-request.h
 
diff --git a/src/lib-auth/auth-master.c b/src/lib-auth/auth-master.c
new file mode 100644 (file)
index 0000000..96625ff
--- /dev/null
@@ -0,0 +1,233 @@
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.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 MAX_INBUF_SIZE 8192
+#define MAX_OUTBUF_SIZE 512
+
+struct auth_connection {
+       int fd;
+       struct timeout *to;
+       struct io *io;
+       struct istream *input;
+       struct ostream *output;
+
+       struct ioloop *ioloop;
+       const char *auth_socket;
+       const char *user;
+       pool_t pool;
+       struct auth_user_reply *user_reply;
+       int return_value;
+
+       unsigned int handshaked:1;
+       bool debug;
+};
+
+static void auth_input(struct auth_connection *conn);
+
+struct auth_connection *auth_master_init(const char *auth_socket, 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->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");
+
+       conn->fd = -1;
+}
+
+void auth_master_deinit(struct auth_connection *conn)
+{
+       auth_connection_close(conn);
+       i_free(conn);
+}
+
+static void auth_parse_input(struct auth_connection *conn, const char *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);
+
+       for (tmp = t_strsplit(args, "\t"); *tmp != NULL; tmp++) {
+               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);
+               }
+       }
+
+       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 void auth_input(struct auth_connection *conn)
+{
+       const char *line;
+
+       switch (i_stream_read(conn->input)) {
+       case 0:
+               return;
+       case -1:
+               /* disconnected */
+               i_error("Auth lookup disconnected unexpectedly");
+               auth_connection_close(conn);
+               return;
+       case -2:
+               /* buffer full */
+               i_error("BUG: Auth master sent us more than %d bytes",
+                       MAX_INBUF_SIZE);
+               auth_connection_close(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;
+                       }
+               }
+       }
+
+       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)
+                       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);
+               }
+               auth_connection_close(conn);
+       }
+}
+
+
+static void auth_client_timeout(struct auth_connection *conn)
+{
+       if (!conn->handshaked)
+               i_error("Connecting to dovecot-auth timed out");
+       else
+               i_error("User request from dovecot-auth timed out");
+       auth_connection_close(conn);
+}
+
+int auth_master_user_lookup(struct auth_connection *conn,
+                           const char *user,
+                           const char *service,
+                           pool_t pool,
+                           struct auth_user_reply *reply_r)
+{
+       if (conn == NULL)
+               return -1;
+
+       conn->user = user;
+       conn->return_value = -1;
+       conn->to = timeout_add(1000*AUTH_REQUEST_TIMEOUT,
+                              auth_client_timeout, conn);
+       conn->pool = pool;
+       conn->user_reply = reply_r;
+
+       o_stream_send_str(conn->output,
+                         t_strconcat("VERSION\t1\t0\n"
+                                     "USER\t1\t", user, "\t"
+                                     "service=", service, "\n",
+                                     NULL));
+
+       io_loop_run(conn->ioloop);
+       return conn->return_value;
+}
diff --git a/src/lib-auth/auth-master.h b/src/lib-auth/auth-master.h
new file mode 100644 (file)
index 0000000..c8a5ec7
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef AUTH_MASTER_H
+#define AUTH_MASTER_H
+
+struct auth_user_reply {
+       uid_t uid;
+       gid_t gid;
+       const char *home, *chroot;
+       ARRAY_TYPE(string) *extra_fields;
+};
+
+struct auth_connection *auth_master_init(const char *auth_socket, 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);
+
+#endif