auth-master.c revision 31a574fda352ef4f71dbff9c30e15e4744e132c0
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2005-2012 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"
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen#include "eacces-error.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "network.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "istream.h"
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde#include "ostream.h"
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen#include "str.h"
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen#include "master-interface.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_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;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen enum auth_master_flags flags;
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 sent_handshake:1;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde unsigned int handshaked:1;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen unsigned int aborted:1;
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde};
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenstruct auth_master_lookup_ctx {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct auth_master_connection *conn;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *user;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen const char *expected_reply;
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 *
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainenauth_master_init(const char *auth_socket_path, enum auth_master_flags flags)
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;
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen conn->flags = flags;
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
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) {
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen tmp = t_strsplit_tab(line);
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
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic int parse_reply(const char *cmd, const char *const *args,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *expected_reply, const char *user, bool debug)
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) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (*args == NULL) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen i_error("user %s: Auth %s lookup failed",
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen user, expected_reply);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen } else if (debug) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen i_debug("user %s: Auth %s lookup returned temporary failure: %s",
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen user, expected_reply, *args);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_error("Unknown reply: %s", cmd);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return -1;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainenstatic const char *const *args_hide_passwords(const char *const *args)
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen{
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen ARRAY_TYPE(const_string) new_args;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen const char *p, *p2;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen unsigned int i;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* if there are any keys that contain "pass" string */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen for (i = 0; args[i] != NULL; i++) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen p = strstr(args[i], "pass");
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (p != NULL && p < strchr(args[i], '='))
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen break;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (args[i] == NULL)
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return args;
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen /* there are. replace their values with <hidden> */
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen t_array_init(&new_args, i + 16);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen array_append(&new_args, args, i);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen for (; args[i] != NULL; i++) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen p = strstr(args[i], "pass");
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen p2 = strchr(args[i], '=');
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (p != NULL && p < p2) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen p = t_strconcat(t_strdup_until(args[i], p2),
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen "=<hidden>", NULL);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen array_append(&new_args, &p, 1);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen } else {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen array_append(&new_args, &args[i], 1);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&new_args);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen return array_idx(&new_args, 0);
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen}
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenstatic bool auth_lookup_reply_callback(const char *cmd, const char *const *args,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen void *context)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct auth_master_lookup_ctx *ctx = context;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen unsigned int i, len;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen bool debug = (ctx->conn->flags & AUTH_MASTER_FLAG_DEBUG) != 0;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen io_loop_stop(ctx->conn->ioloop);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->return_value =
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen parse_reply(cmd, args, ctx->expected_reply, ctx->user, debug);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen len = str_array_length(args);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (ctx->return_value >= 0) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->fields = p_new(ctx->pool, const char *, len + 1);
2ba63f475f74b2aa87f9fd9e28a6c5738deb0878Timo Sirainen for (i = 0; i < len; i++)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx->fields[i] = p_strdup(ctx->pool, args[i]);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen } else {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* put the reason string into first field */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->fields = p_new(ctx->pool, const char *, 2);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen for (i = 0; i < len; i++) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (strncmp(args[i], "reason=", 7) == 0) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx->fields[0] =
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen p_strdup(ctx->pool, args[i] + 7);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen break;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen if (debug) {
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen args = args_hide_passwords(args);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen i_debug("auth input: %s", t_strarray_join(args, " "));
61767c7537efe3eb51f80d37cda12d69c67f3c05Timo Sirainen }
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
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen args = t_strsplit_tab(line);
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{
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen int fd;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_assert(conn->fd == -1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* max. 1 second wait here. */
21c1655dbc5fe861a152dc9a8a388d0d64f5ae20Timo Sirainen fd = net_connect_unix_with_retries(conn->auth_socket_path, 1000);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fd == -1) {
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen if (errno == EACCES) {
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen i_error("userdb lookup: %s",
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen eacces_error_get("connect",
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen conn->auth_socket_path));
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen } else {
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen i_error("userdb lookup: connect(%s) failed: %m",
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen conn->auth_socket_path);
9bb91f1dbf7cf8cfbd2df7784101df98d59fb46dTimo Sirainen }
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);
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen conn->to = timeout_add(1000*MASTER_AUTH_LOOKUP_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{
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen if (prev_ioloop != NULL) {
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen io_loop_set_current(prev_ioloop);
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen lib_signals_reset_ioloop();
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen }
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
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen if ((conn->flags & AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT) == 0) {
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen if (prev_ioloop == NULL)
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen auth_connection_close(conn);
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen else {
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen auth_idle_timeout, conn);
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo Sirainen }
c5a6a6565be93224fc26522eda855b0990f256e8Timo Sirainen }
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);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, str);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->sent_handshake = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend_str(conn->output, cmd);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen o_stream_uncork(conn->output);
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (o_stream_nfinish(conn->output) < 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("write(auth socket) failed: %m");
7cdf66ecb4957ab2789a4fe39ee01e01b3c2e76cTimo Sirainen conn->aborted = TRUE;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen } else {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen io_loop_run(conn->ioloop);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen }
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen
9d2a30e39c0662498db3368dbb010e36df54b7e8Timo 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{
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen if (info->service != NULL) {
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_append(str, "\tservice=");
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_append(str, info->service);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen }
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,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen pool_t pool, const char **username_r,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen const char *const **fields_r)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct auth_master_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 */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen *username_r = NULL;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen *fields_r = NULL;
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;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx.expected_reply = "USER";
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx.user = user;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen conn->reply_callback = auth_lookup_reply_callback;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_context = &ctx;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_str_new(128);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_printfa(str, "USER\t%u\t%s",
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
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ctx.return_value <= 0 || ctx.fields[0] == NULL) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen *username_r = NULL;
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen *fields_r = ctx.fields != NULL ? ctx.fields :
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen p_new(pool, const char *, 1);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen if (ctx.return_value > 0) {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen i_error("Userdb lookup didn't return username");
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx.return_value = -1;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen } else {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen *username_r = ctx.fields[0];
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen *fields_r = ctx.fields + 1;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen return ctx.return_value;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen}
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainenvoid auth_user_fields_parse(const char *const *fields, pool_t pool,
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct auth_user_reply *reply_r)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen memset(reply_r, 0, sizeof(*reply_r));
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen reply_r->uid = (uid_t)-1;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen reply_r->gid = (gid_t)-1;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen p_array_init(&reply_r->extra_fields, pool, 64);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen for (; *fields != NULL; fields++) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (strncmp(*fields, "uid=", 4) == 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_uid(*fields + 4, &reply_r->uid) < 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("Invalid uid in reply");
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen } else if (strncmp(*fields, "gid=", 4) == 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_gid(*fields + 4, &reply_r->gid) < 0)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("Invalid gid in reply");
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen } else if (strncmp(*fields, "home=", 5) == 0)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen reply_r->home = p_strdup(pool, *fields + 5);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen else if (strncmp(*fields, "chroot=", 7) == 0)
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen reply_r->chroot = p_strdup(pool, *fields + 7);
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch else if (strcmp(*fields, "anonymous") == 0)
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch reply_r->anonymous = TRUE;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen else {
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen const char *field = p_strdup(pool, *fields);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen array_append(&reply_r->extra_fields, &field, 1);
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen }
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen }
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{
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen struct auth_master_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 */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen *fields_r = NULL;
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;
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen ctx.expected_reply = "PASS";
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ctx.user = user;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen conn->reply_callback = auth_lookup_reply_callback;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->reply_context = &ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_str_new(128);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_printfa(str, "PASS\t%u\t%s",
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
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen *fields_r = ctx.fields != NULL ? ctx.fields :
a3f5bd60d81b456b7e4b79b26a825b71b836a537Timo Sirainen p_new(pool, const char *, 1);
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
36bf6cd88b1c71055ef12b07253f5223d981e43dTimo Sirainen timeout_reset(ctx->conn->to);
36bf6cd88b1c71055ef12b07253f5223d981e43dTimo 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 *
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainenauth_master_user_list_init(struct auth_master_connection *conn,
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen const char *user_mask,
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen const struct auth_user_info *info)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen{
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_list_ctx *ctx;
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen string_t *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
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str = t_str_new(128);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_printfa(str, "LIST\t%u",
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen auth_master_next_request_id(conn));
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen if (*user_mask != '\0')
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_printfa(str, "\tuser=%s", user_mask);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen if (info != NULL)
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen auth_user_info_export(str, info);
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen str_append_c(str, '\n');
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = "userdb list";
665e9d14c005b65d95eae0baaa471c51e5caca73Timo Sirainen if (auth_master_run_cmd(conn, str_c(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}