auth-master.c revision fc464e5b2b2ab4d415a5d5b90ce4475d34620a75
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen#define DEFAULT_USERDB_LOOKUP_PREFIX "userdb lookup"
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen bool (*reply_callback)(const char *cmd, const char *const *args,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char **fields;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *const *user_strings;
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_input(struct auth_master_connection *conn);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainenauth_master_init(const char *auth_socket_path, bool debug)
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainen conn = i_new(struct auth_master_connection, 1);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->auth_socket_path = i_strdup(auth_socket_path);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_connection_close(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("close(%s) failed: %m", conn->auth_socket_path);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenvoid auth_master_deinit(struct auth_master_connection **_conn)
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_request_lookup_abort(struct auth_master_connection *conn)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic void auth_parse_input(struct auth_master_user_lookup_ctx *ctx,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *const *args)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_user_reply *reply = ctx->user_reply;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen p_array_init(&reply->extra_fields, ctx->pool, 64);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen reply->chroot = p_strdup(ctx->pool, *args + 7);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *field = p_strdup(ctx->pool, *args);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen array_append(&reply->extra_fields, &field, 1);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic int auth_input_handshake(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (strcmp(tmp[1], dec2str(AUTH_PROTOCOL_MAJOR)) != 0) {
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen "Auth protocol version mismatch "
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic int parse_reply(struct auth_master_connection *conn,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic bool auth_user_reply_callback(const char *cmd, const char *const *args,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_lookup_ctx *ctx = context;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->return_value = parse_reply(ctx->conn, cmd, args, "USER");
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainenauth_handle_line(struct auth_master_connection *conn, const char *line)
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen const char *cmd, *const *args, *id, *wanted_id;
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen return conn->reply_callback(cmd, args, conn->reply_context);
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen "It should be a master socket.",
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen i_error("%s: BUG: Unexpected input: %s", conn->prefix, line);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_input(struct auth_master_connection *conn)
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* disconnected */
fc71e94957d0c2959a609450a2f303640d681858Sascha Wilde /* buffer full */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: BUG: Received more than %d bytes",
5c0ab4cc4dff573940df683eb4b23bd6077153faTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic int auth_master_connect(struct auth_master_connection *conn)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* max. 1 second wait here. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen fd = net_connect_unix(conn->auth_socket_path);
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* busy. wait for a while. */
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen i_error("userdb lookup: connect(%s) failed: %m",
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_request_timeout(struct auth_master_connection *conn)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: Connecting timed out", conn->prefix);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen i_error("%s: Request timed out", conn->prefix);
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_idle_timeout(struct auth_master_connection *conn)
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_master_set_io(struct auth_master_connection *conn)
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,
64bfe7b4a42512971db154937905dfa2bdb9cf2cTimo Sirainenstatic void auth_master_unset_io(struct auth_master_connection *conn,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *p;
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen /* make sure we're not sending any characters that have a special
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenstatic int auth_master_run_cmd(struct auth_master_connection *conn,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *cmd)
aba994a4e79a020b4748e0ceffc194e5a18e1d1aTimo Sirainen const char *str;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic unsigned int
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenauth_master_next_request_id(struct auth_master_connection *conn)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* avoid zero */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenauth_user_info_export(string_t *str, const struct auth_user_info *info)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\tlport=%d", info->local_port);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip));
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str_printfa(str, "\trport=%d", info->remote_port);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenint auth_master_user_lookup(struct auth_master_connection *conn,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *user, const struct auth_user_info *info,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!is_valid_string(user) || !is_valid_string(info->service)) {
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen /* non-allowed characters, the user can't exist */
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->reply_callback = auth_user_reply_callback;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen conn->prefix = t_strdup_printf("userdb lookup(%s)", user);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenstatic bool auth_pass_reply_callback(const char *cmd, const char *const *args,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct auth_master_pass_lookup_ctx *ctx = context;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen unsigned int i, len;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen ctx->return_value = parse_reply(ctx->conn, cmd, args, "PASS");
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 Sirainenint auth_master_pass_lookup(struct auth_master_connection *conn,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen const char *user, const struct auth_user_info *info,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (!is_valid_string(user) || !is_valid_string(info->service)) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen /* non-allowed characters, the user can't exist */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->reply_callback = auth_pass_reply_callback;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen conn->prefix = t_strdup_printf("passdb lookup(%s)", user);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenauth_user_list_reply_callback(const char *cmd, const char *const *args,
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen struct auth_master_user_list_ctx *ctx = context;
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen if (args[0] != NULL && strcmp(args[0], "fail") == 0) {
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 Sirainenauth_master_user_list_init(struct auth_master_connection *conn)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen const char *str;
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 conn->reply_callback = auth_user_list_reply_callback;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen str = t_strdup_printf("LIST\t%u\n", auth_master_next_request_id(conn));
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainen ctx->user_strings = array_get(&ctx->users, &ctx->user_count);
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenconst char *auth_master_user_list_next(struct auth_master_user_list_ctx *ctx)
69d60dcff2614c4bfc8ad59e8fdc09e39c9dd0dcTimo Sirainenunsigned int auth_master_user_list_count(struct auth_master_user_list_ctx *ctx)
4b1359bde7d32667197548652a4b4f540062e2acTimo Sirainenint auth_master_user_list_deinit(struct auth_master_user_list_ctx **_ctx)