auth-master.c revision ef0c36aa8114feee80aa696d9cb8106140371243
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define DEFAULT_USERDB_LOOKUP_PREFIX "userdb lookup"
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose const char *prefix;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose bool (*reply_callback)(const char *cmd, const char *const *args,
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose const char **fields;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bosestatic void auth_input(struct auth_master_connection *conn);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Boseauth_master_init(const char *auth_socket_path, enum auth_master_flags flags)
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->auth_socket_path = i_strdup(auth_socket_path);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bosestatic void auth_connection_close(struct auth_master_connection *conn)
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose i_error("close(%s) failed: %m", conn->auth_socket_path);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bosevoid auth_master_deinit(struct auth_master_connection **_conn)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Boseconst char *auth_master_get_socket_path(struct auth_master_connection *conn)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bosestatic void auth_request_lookup_abort(struct auth_master_connection *conn)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bosestatic int auth_input_handshake(struct auth_master_connection *conn)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose while ((line = i_stream_next_line(conn->input)) != NULL) {
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose if (strcmp(tmp[1], dec2str(AUTH_PROTOCOL_MAJOR)) != 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "Auth protocol version mismatch "
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic int parse_reply(const char *cmd, const char *const *args,
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek const char *expected_reply, const char *user, bool debug)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_debug("user %s: Auth %s lookup returned temporary failure: %s",
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic const char *const *args_hide_passwords(const char *const *args)
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek const char *p, *p2;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek unsigned int i;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek /* if there are any keys that contain "pass" string */
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek /* there are. replace their values with <hidden> */
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic bool auth_lookup_reply_callback(const char *cmd, const char *const *args,
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher struct auth_master_lookup_ctx *ctx = context;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher unsigned int i, len;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher bool debug = (ctx->conn->flags & AUTH_MASTER_FLAG_DEBUG) != 0;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek parse_reply(cmd, args, ctx->expected_reply, ctx->user, debug);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek ctx->fields = p_new(ctx->pool, const char *, len + 1);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek for (i = 0; i < len; i++)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose /* put the reason string into first field */
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose for (i = 0; i < len; i++) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_debug("auth input: %s", t_strarray_join(args, " "));
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherauth_handle_line(struct auth_master_connection *conn, const char *line)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher const char *cmd, *const *args, *id, *wanted_id;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher wanted_id = dec2str(conn->request_counter);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return conn->reply_callback(cmd, args, conn->reply_context);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: %s is an auth client socket. "
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "It should be a master socket.",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: BUG: Unexpected input: %s", conn->prefix, line);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_input(struct auth_master_connection *conn)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* disconnected */
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher /* buffer full */
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher i_error("%s: BUG: Received more than %d bytes",
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher while ((line = i_stream_next_line(conn->input)) != NULL) {
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagherstatic int auth_master_connect(struct auth_master_connection *conn)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* max. 1 second wait here. */
5dedd73d90f0c1f23299f0c613f384ef902c3653Stephen Gallagher fd = net_connect_unix_with_retries(conn->auth_socket_path, 1000);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("userdb lookup: connect(%s) failed: %m",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_request_timeout(struct auth_master_connection *conn)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: Connecting timed out", conn->prefix);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: Request timed out", conn->prefix);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic void auth_idle_timeout(struct auth_master_connection *conn)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_master_set_io(struct auth_master_connection *conn)
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov conn->output = o_stream_create_fd(conn->fd, MAX_OUTBUF_SIZE);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov conn->io = io_add(conn->fd, IO_READ, auth_input, conn);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose conn->to = timeout_add(1000*MASTER_AUTH_LOOKUP_TIMEOUT_SECS,
cb446b6149d28c204954ae75143b89aef14115dcSumit Bosestatic void auth_master_unset_io(struct auth_master_connection *conn)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if ((conn->flags & AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT) == 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic bool is_valid_string(const char *str)
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose const char *p;
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose /* make sure we're not sending any characters that have a special
cb446b6149d28c204954ae75143b89aef14115dcSumit Bosestatic int auth_master_run_cmd_pre(struct auth_master_connection *conn,
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher str = t_strdup_printf("VERSION\t%d\t%d\n",
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher AUTH_PROTOCOL_MAJOR, AUTH_PROTOCOL_MINOR);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagherstatic int auth_master_run_cmd_post(struct auth_master_connection *conn)
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagherstatic int auth_master_run_cmd(struct auth_master_connection *conn,
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (auth_master_run_cmd_pre(conn, cmd) < 0)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagherstatic unsigned int
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagherauth_master_next_request_id(struct auth_master_connection *conn)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher /* avoid zero */
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidekauth_user_info_export(string_t *str, const struct auth_user_info *info)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip));
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\tlport=%d", info->local_port);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip));
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\trport=%d", info->remote_port);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovint auth_master_user_lookup(struct auth_master_connection *conn,
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher const char *user, const struct auth_user_info *info,
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher const char *const **fields_r)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (!is_valid_string(user) || !is_valid_string(info->service)) {
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher /* non-allowed characters, the user can't exist */
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek conn->reply_callback = auth_lookup_reply_callback;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher conn->prefix = t_strdup_printf("userdb lookup(%s)", user);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher (void)auth_master_run_cmd(conn, str_c(str));
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (ctx.return_value <= 0 || ctx.fields[0] == NULL) {
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnikvoid auth_user_fields_parse(const char *const *fields, pool_t pool,
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik if (str_to_uid(*fields + 4, &reply_r->uid) < 0)
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik } else if (strncmp(*fields, "gid=", 4) == 0) {
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Boseint auth_master_pass_lookup(struct auth_master_connection *conn,
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose const char *user, const struct auth_user_info *info,
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose if (!is_valid_string(user) || !is_valid_string(info->service)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* non-allowed characters, the user can't exist */
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->reply_callback = auth_lookup_reply_callback;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->prefix = t_strdup_printf("passdb lookup(%s)", user);
struct auth_master_cache_ctx {
unsigned int count;
bool failed;
void *context)
return TRUE;
void *context)
return FALSE;
struct auth_master_user_list_ctx *
const char *user_mask,
return ctx;
const char *line;
return NULL;
T_BEGIN {
} T_END;
return NULL;
return ret;