auth-master.c revision fc464e5b2b2ab4d415a5d5b90ce4475d34620a75
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "lib.h"
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#include "lib-signals.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "array.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "ioloop.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "network.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "istream.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "ostream.h"
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen#include "str.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "auth-master.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include <stdlib.h>
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include <unistd.h>
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define AUTH_PROTOCOL_MAJOR 1
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define AUTH_PROTOCOL_MINOR 0
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define AUTH_REQUEST_TIMEOUT_SECS 30
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define AUTH_MASTER_IDLE_SECS 60
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#define MAX_INBUF_SIZE 8192
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen#define MAX_OUTBUF_SIZE 1024
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen#define DEFAULT_USERDB_LOOKUP_PREFIX "userdb lookup"
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstruct auth_master_connection {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen char *auth_socket_path;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde int fd;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct ioloop *ioloop;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct io *io;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct istream *input;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde struct ostream *output;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct timeout *to;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *prefix;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int request_counter;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen bool (*reply_callback)(const char *cmd, const char *const *args,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen void *context);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen void *reply_context;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int debug:1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int sent_handshake:1;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde unsigned int handshaked:1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int aborted:1;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde};
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstruct auth_master_user_lookup_ctx {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_connection *conn;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool_t pool;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_user_reply *user_reply;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen int return_value;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen};
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstruct auth_master_pass_lookup_ctx {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct auth_master_connection *conn;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen int return_value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen pool_t pool;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char **fields;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen};
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstruct auth_master_user_list_ctx {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_connection *conn;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool_t pool;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ARRAY_TYPE(const_string) users;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *const *user_strings;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen unsigned int idx, user_count;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen bool failed;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen};
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_input(struct auth_master_connection *conn);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstruct auth_master_connection *
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenauth_master_init(const char *auth_socket_path, bool debug)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen struct auth_master_connection *conn;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen conn = i_new(struct auth_master_connection, 1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->auth_socket_path = i_strdup(auth_socket_path);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->fd = -1;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde conn->debug = debug;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return conn;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_connection_close(struct auth_master_connection *conn)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (conn->to != NULL)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde timeout_remove(&conn->to);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (conn->fd != -1) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (close(conn->fd) < 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("close(%s) failed: %m", conn->auth_socket_path);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->fd = -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->sent_handshake = FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->handshaked = FALSE;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenvoid auth_master_deinit(struct auth_master_connection **_conn)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen struct auth_master_connection *conn = *_conn;
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen
1c6dd898551d7d4d61970b24a8372438f6b72f97Timo Sirainen *_conn = NULL;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde auth_connection_close(conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_free(conn->auth_socket_path);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde i_free(conn);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_request_lookup_abort(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_stop(conn->ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->aborted = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic void auth_parse_input(struct auth_master_user_lookup_ctx *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *const *args)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_user_reply *reply = ctx->user_reply;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen memset(reply, 0, sizeof(*reply));
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen reply->uid = (uid_t)-1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen reply->gid = (gid_t)-1;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen p_array_init(&reply->extra_fields, ctx->pool, 64);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen reply->user = p_strdup(ctx->pool, *args);
52d058e5234181fca90048d5904a151a1ccc8a6bTimo Sirainen for (args++; *args != NULL; args++) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (ctx->conn->debug)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_info("auth input: %s", *args);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (strncmp(*args, "uid=", 4) == 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen reply->uid = strtoul(*args + 4, NULL, 10);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen else if (strncmp(*args, "gid=", 4) == 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen reply->gid = strtoul(*args + 4, NULL, 10);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen else if (strncmp(*args, "home=", 5) == 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen reply->home = p_strdup(ctx->pool, *args + 5);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen else if (strncmp(*args, "chroot=", 7) == 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen reply->chroot = p_strdup(ctx->pool, *args + 7);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen else {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *field = p_strdup(ctx->pool, *args);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen array_append(&reply->extra_fields, &field, 1);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic int auth_input_handshake(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *line, *const *tmp;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen tmp = t_strsplit(line, "\t");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (strcmp(tmp[0], "VERSION") == 0 &&
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen tmp[1] != NULL && tmp[2] != NULL) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (strcmp(tmp[1], dec2str(AUTH_PROTOCOL_MAJOR)) != 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("userdb lookup: "
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen "Auth protocol version mismatch "
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen "(%s vs %d)", tmp[1],
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen AUTH_PROTOCOL_MAJOR);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_request_lookup_abort(conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen } else if (strcmp(tmp[0], "SPID") == 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->handshaked = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen break;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return 0;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic int parse_reply(struct auth_master_connection *conn,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *cmd, const char *const *args,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *expected_reply)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen io_loop_stop(conn->ioloop);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (strcmp(cmd, expected_reply) == 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return 1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (strcmp(cmd, "NOTFOUND") == 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return 0;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (strcmp(cmd, "FAIL") == 0) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_error("Lookup failed: %s",
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen *args != NULL ? *args : "Internal failure");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_error("Unknown reply: %s", cmd);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic bool auth_user_reply_callback(const char *cmd, const char *const *args,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen void *context)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_lookup_ctx *ctx = context;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->return_value = parse_reply(ctx->conn, cmd, args, "USER");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (ctx->return_value > 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen auth_parse_input(ctx, args);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainenstatic bool
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainenauth_handle_line(struct auth_master_connection *conn, const char *line)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen{
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen const char *cmd, *const *args, *id, *wanted_id;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen args = t_strsplit(line, "\t");
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen cmd = *args; args++;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (*args == NULL)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen id = "";
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen else {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen id = *args;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen args++;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen wanted_id = dec2str(conn->request_counter);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (strcmp(id, wanted_id) == 0)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return conn->reply_callback(cmd, args, conn->reply_context);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (strcmp(cmd, "CUID") == 0) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen i_error("%s: %s is an auth client socket. "
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen "It should be a master socket.",
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen conn->prefix, conn->auth_socket_path);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen } else {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen i_error("%s: BUG: Unexpected input: %s", conn->prefix, line);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen }
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen auth_request_lookup_abort(conn);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return FALSE;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen}
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_input(struct auth_master_connection *conn)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen const char *line;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen bool ret;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde switch (i_stream_read(conn->input)) {
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde case 0:
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde case -1:
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* disconnected */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: Disconnected unexpectedly",
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_request_lookup_abort(conn);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde case -2:
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* buffer full */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: BUG: Received more than %d bytes",
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix, MAX_INBUF_SIZE);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_request_lookup_abort(conn);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde return;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (!conn->handshaked) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (auth_input_handshake(conn) < 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen T_BEGIN {
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen ret = auth_handle_line(conn, line);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen } T_END;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen if (!ret)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic int auth_master_connect(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen int fd, try;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_assert(conn->fd == -1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* max. 1 second wait here. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen for (try = 0; try < 10; try++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen fd = net_connect_unix(conn->auth_socket_path);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen break;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* busy. wait for a while. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen usleep(((rand() % 10) + 1) * 10000);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fd == -1) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("userdb lookup: connect(%s) failed: %m",
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->auth_socket_path);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->fd = fd;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return 0;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_request_timeout(struct auth_master_connection *conn)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde if (!conn->handshaked)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: Connecting timed out", conn->prefix);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde else
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: Request timed out", conn->prefix);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_request_lookup_abort(conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_idle_timeout(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde auth_connection_close(conn);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_master_set_io(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (conn->to != NULL)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen timeout_remove(&conn->to);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->ioloop = io_loop_create();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE, FALSE);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->io = io_add(conn->fd, IO_READ, auth_input, conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->to = timeout_add(1000*AUTH_REQUEST_TIMEOUT_SECS,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_request_timeout, conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen lib_signals_reset_ioloop();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_master_unset_io(struct auth_master_connection *conn,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct ioloop *prev_ioloop)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_set_current(prev_ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen lib_signals_reset_ioloop();
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_set_current(conn->ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen timeout_remove(&conn->to);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_remove(&conn->io);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_stream_unref(&conn->input);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen o_stream_unref(&conn->output);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_destroy(&conn->ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_idle_timeout, conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenstatic bool is_valid_string(const char *str)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *p;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* make sure we're not sending any characters that have a special
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen meaning. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen for (p = str; *p != '\0'; p++) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (*p == '\t' || *p == '\n' || *p == '\r')
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen}
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic int auth_master_run_cmd(struct auth_master_connection *conn,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *cmd)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde{
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen struct ioloop *prev_ioloop;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *str;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (conn->fd == -1) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (auth_master_connect(conn) < 0)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen prev_ioloop = current_ioloop;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_master_set_io(conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen o_stream_cork(conn->output);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (!conn->sent_handshake) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen str = t_strdup_printf("VERSION\t%d\t%d\n",
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen AUTH_PROTOCOL_MAJOR, AUTH_PROTOCOL_MINOR);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen o_stream_send_str(conn->output, str);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->sent_handshake = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen o_stream_send_str(conn->output, cmd);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen o_stream_uncork(conn->output);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (conn->output->stream_errno != 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen errno = conn->output->stream_errno;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("write(auth socket) failed: %m");
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen } else {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_run(conn->ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_master_unset_io(conn, prev_ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (conn->aborted) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->aborted = FALSE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen auth_connection_close(conn);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return -1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return 0;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic unsigned int
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenauth_master_next_request_id(struct auth_master_connection *conn)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (++conn->request_counter == 0) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* avoid zero */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->request_counter++;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return conn->request_counter;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic void
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenauth_user_info_export(string_t *str, const struct auth_user_info *info)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append(str, "service=");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append(str, info->service);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (info->local_ip.family != 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (info->local_port != 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\tlport=%d", info->local_port);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (info->remote_ip.family != 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (info->remote_port != 0)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\trport=%d", info->remote_port);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenint auth_master_user_lookup(struct auth_master_connection *conn,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *user, const struct auth_user_info *info,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool_t pool, struct auth_user_reply *reply_r)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_lookup_ctx ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen string_t *str;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!is_valid_string(user) || !is_valid_string(info->service)) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* non-allowed characters, the user can't exist */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return 0;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen memset(&ctx, 0, sizeof(ctx));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx.conn = conn;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx.return_value = -1;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx.pool = pool;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx.user_reply = reply_r;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_callback = auth_user_reply_callback;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_context = &ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_str_new(128);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "USER\t%u\t%s\t",
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen auth_master_next_request_id(conn), user);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen auth_user_info_export(str, info);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append_c(str, '\n');
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = t_strdup_printf("userdb lookup(%s)", user);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen (void)auth_master_run_cmd(conn, str_c(str));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return ctx.return_value;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic bool auth_pass_reply_callback(const char *cmd, const char *const *args,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen void *context)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct auth_master_pass_lookup_ctx *ctx = context;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen unsigned int i, len;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->return_value = parse_reply(ctx->conn, cmd, args, "PASS");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (ctx->return_value > 0) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen len = str_array_length(args);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->fields = p_new(ctx->pool, const char *, len + 1);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen for (i = 0; i < len; i++)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->fields[i] = p_strdup(ctx->pool, args[i]);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenint auth_master_pass_lookup(struct auth_master_connection *conn,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *user, const struct auth_user_info *info,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen pool_t pool, const char *const **fields_r)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct auth_master_pass_lookup_ctx ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen string_t *str;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!is_valid_string(user) || !is_valid_string(info->service)) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* non-allowed characters, the user can't exist */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return 0;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen memset(&ctx, 0, sizeof(ctx));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx.conn = conn;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx.return_value = -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx.pool = pool;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->reply_callback = auth_pass_reply_callback;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->reply_context = &ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_str_new(128);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "PASS\t%u\t%s\t",
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen auth_master_next_request_id(conn), user);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen auth_user_info_export(str, info);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_append_c(str, '\n');
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->prefix = t_strdup_printf("passdb lookup(%s)", user);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen (void)auth_master_run_cmd(conn, str_c(str));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen *fields_r = ctx.fields;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return ctx.return_value;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic bool
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenauth_user_list_reply_callback(const char *cmd, const char *const *args,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen void *context)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_list_ctx *ctx = context;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *user;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (strcmp(cmd, "DONE") == 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen io_loop_stop(ctx->conn->ioloop);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (args[0] != NULL && strcmp(args[0], "fail") == 0) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("User listing returned failure");
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->failed = TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (strcmp(cmd, "LIST") == 0 && args[0] != NULL) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* we'll just read all the users into memory. otherwise we'd
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen have to use a separate connection for listing and there's
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen a higher chance of a failure since the connection could be
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen open to dovecot-auth for a long time. */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen user = p_strdup(ctx->pool, args[0]);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen array_append(&ctx->users, &user, 1);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return FALSE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstruct auth_master_user_list_ctx *
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenauth_master_user_list_init(struct auth_master_connection *conn)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_list_ctx *ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *str;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool_t pool;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool = pool_alloconly_create("auth master user list", 10240);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx = p_new(pool, struct auth_master_user_list_ctx, 1);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->pool = pool;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->conn = conn;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_array_init(&ctx->users, 128);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_callback = auth_user_list_reply_callback;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_context = ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_strdup_printf("LIST\t%u\n", auth_master_next_request_id(conn));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = "userdb list";
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (auth_master_run_cmd(conn, str) < 0)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->failed = TRUE;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->user_strings = array_get(&ctx->users, &ctx->user_count);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenconst char *auth_master_user_list_next(struct auth_master_user_list_ctx *ctx)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (ctx->idx == ctx->user_count)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return NULL;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return ctx->user_strings[ctx->idx++];
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainenunsigned int auth_master_user_list_count(struct auth_master_user_list_ctx *ctx)
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen{
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen return ctx->user_count;
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen}
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenint auth_master_user_list_deinit(struct auth_master_user_list_ctx **_ctx)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_list_ctx *ctx = *_ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen int ret = ctx->failed ? -1 : 0;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen *_ctx = NULL;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen array_free(&ctx->users);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen pool_unref(&ctx->pool);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return ret;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde}