auth-master.c revision ef0c36aa8114feee80aa696d9cb8106140371243
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "lib.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "lib-signals.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "array.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "ioloop.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "eacces-error.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "net.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "istream.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "ostream.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "str.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "strescape.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "master-interface.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include "auth-master.h"
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#include <unistd.h>
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define AUTH_PROTOCOL_MAJOR 1
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define AUTH_PROTOCOL_MINOR 0
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define AUTH_MASTER_IDLE_SECS 60
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define MAX_INBUF_SIZE 8192
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define MAX_OUTBUF_SIZE 1024
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher#define DEFAULT_USERDB_LOOKUP_PREFIX "userdb lookup"
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstruct auth_master_connection {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose char *auth_socket_path;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose enum auth_master_flags flags;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose int fd;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct ioloop *ioloop, *prev_ioloop;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct io *io;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose struct istream *input;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose struct ostream *output;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct timeout *to;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose const char *prefix;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose unsigned int request_counter;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose bool (*reply_callback)(const char *cmd, const char *const *args,
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose void *context);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose void *reply_context;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov bool sent_handshake:1;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose bool handshaked:1;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose bool aborted:1;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose};
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bosestruct auth_master_lookup_ctx {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct auth_master_connection *conn;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov const char *user;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose const char *expected_reply;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose int return_value;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose pool_t pool;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose const char **fields;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov};
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovstruct auth_master_user_list_ctx {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct auth_master_connection *conn;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose string_t *username;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose bool finished;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose bool failed;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose};
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bosestatic void auth_input(struct auth_master_connection *conn);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bosestruct auth_master_connection *
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Boseauth_master_init(const char *auth_socket_path, enum auth_master_flags flags)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose{
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct auth_master_connection *conn;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn = i_new(struct auth_master_connection, 1);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->auth_socket_path = i_strdup(auth_socket_path);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->fd = -1;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->flags = flags;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose return conn;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose}
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bosestatic void auth_connection_close(struct auth_master_connection *conn)
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose{
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose if (conn->to != NULL)
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose timeout_remove(&conn->to);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose if (conn->fd != -1) {
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose if (close(conn->fd) < 0)
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose i_error("close(%s) failed: %m", conn->auth_socket_path);
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->fd = -1;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->sent_handshake = FALSE;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose conn->handshaked = FALSE;
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose}
3d9bafcbb5c0fbf23351004ded4dea6aa13127fcSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bosevoid auth_master_deinit(struct auth_master_connection **_conn)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose{
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose struct auth_master_connection *conn = *_conn;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose *_conn = NULL;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov auth_connection_close(conn);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_free(conn->auth_socket_path);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose i_free(conn);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose}
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Boseconst char *auth_master_get_socket_path(struct auth_master_connection *conn)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose{
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose return conn->auth_socket_path;
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose}
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bosestatic void auth_request_lookup_abort(struct auth_master_connection *conn)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose{
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose io_loop_stop(conn->ioloop);
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose conn->aborted = TRUE;
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose}
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bosestatic int auth_input_handshake(struct auth_master_connection *conn)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose{
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose const char *line, *const *tmp;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose while ((line = i_stream_next_line(conn->input)) != NULL) {
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose tmp = t_strsplit_tab(line);
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose if (strcmp(tmp[0], "VERSION") == 0 &&
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose tmp[1] != NULL && tmp[2] != NULL) {
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose if (strcmp(tmp[1], dec2str(AUTH_PROTOCOL_MAJOR)) != 0) {
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose i_error("userdb lookup: "
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "Auth protocol version mismatch "
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "(%s vs %d)", tmp[1],
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher AUTH_PROTOCOL_MAJOR);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_request_lookup_abort(conn);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return -1;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher } else if (strcmp(tmp[0], "SPID") == 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->handshaked = TRUE;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher break;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return 0;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic int parse_reply(const char *cmd, const char *const *args,
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek const char *expected_reply, const char *user, bool debug)
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (strcmp(cmd, expected_reply) == 0)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return 1;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (strcmp(cmd, "NOTFOUND") == 0)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return 0;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (strcmp(cmd, "FAIL") == 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (*args == NULL) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("user %s: Auth %s lookup failed",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher user, expected_reply);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher } else if (debug) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_debug("user %s: Auth %s lookup returned temporary failure: %s",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher user, expected_reply, *args);
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return -2;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek }
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek i_error("Unknown reply: %s", cmd);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek return -1;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek}
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic const char *const *args_hide_passwords(const char *const *args)
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek{
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek ARRAY_TYPE(const_string) new_args;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek const char *p, *p2;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek unsigned int i;
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek /* if there are any keys that contain "pass" string */
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek for (i = 0; args[i] != NULL; i++) {
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek p = strstr(args[i], "pass");
bfdb2eeed95bde6cd065a9a47a7cb1773990ccfbOndrej Kos if (p != NULL && p < strchr(args[i], '='))
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov break;
af58b15fa7f20e33736d79c6a4b3becb568517caLukas Slebodnik }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (args[i] == NULL)
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek return args;
bfdb2eeed95bde6cd065a9a47a7cb1773990ccfbOndrej Kos
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek /* there are. replace their values with <hidden> */
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek t_array_init(&new_args, i + 16);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek array_append(&new_args, args, i);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek for (; args[i] != NULL; i++) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov p = strstr(args[i], "pass");
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov p2 = strchr(args[i], '=');
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek if (p != NULL && p < p2) {
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek p = t_strconcat(t_strdup_until(args[i], p2),
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "=<hidden>", NULL);
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina array_append(&new_args, &p, 1);
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina } else {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher array_append(&new_args, &args[i], 1);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov array_append_zero(&new_args);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return array_idx(&new_args, 0);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic bool auth_lookup_reply_callback(const char *cmd, const char *const *args,
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher void *context)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher{
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
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek io_loop_stop(ctx->conn->ioloop);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek ctx->return_value =
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek parse_reply(cmd, args, ctx->expected_reply, ctx->user, debug);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov len = str_array_length(args);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek if (ctx->return_value >= 0) {
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek ctx->fields = p_new(ctx->pool, const char *, len + 1);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek for (i = 0; i < len; i++)
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose ctx->fields[i] = p_strdup(ctx->pool, args[i]);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose } else {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose /* put the reason string into first field */
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose ctx->fields = p_new(ctx->pool, const char *, 2);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose for (i = 0; i < len; i++) {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose if (strncmp(args[i], "reason=", 7) == 0) {
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose ctx->fields[0] =
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov p_strdup(ctx->pool, args[i] + 7);
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose break;
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose }
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose }
949fbc93defad394648b2651b43a7bbfa5bff42bSumit Bose }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (debug) {
7d056853e4a5fe6daa5743e38d21b4493f4fca27Jakub Hrozek args = args_hide_passwords(args);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_debug("auth input: %s", t_strarray_join(args, " "));
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov return TRUE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic bool
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherauth_handle_line(struct auth_master_connection *conn, const char *line)
a5b55bdfcda8bfce8cb2ced981773998093d7857Pavel Reichl{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher const char *cmd, *const *args, *id, *wanted_id;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher args = t_strsplit_tabescaped(line);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher cmd = *args; args++;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (*args == NULL)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher id = "";
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher else {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher id = *args;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher args++;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher wanted_id = dec2str(conn->request_counter);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (strcmp(id, wanted_id) == 0)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return conn->reply_callback(cmd, args, conn->reply_context);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (strcmp(cmd, "CUID") == 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: %s is an auth client socket. "
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher "It should be a master socket.",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->prefix, conn->auth_socket_path);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher } else {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: BUG: Unexpected input: %s", conn->prefix, line);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_request_lookup_abort(conn);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return FALSE;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_input(struct auth_master_connection *conn)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher const char *line;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher bool ret;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher switch (i_stream_read(conn->input)) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher case 0:
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher case -1:
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* disconnected */
af58b15fa7f20e33736d79c6a4b3becb568517caLukas Slebodnik i_error("%s: Disconnected unexpectedly",
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov conn->prefix);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_request_lookup_abort(conn);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher case -2:
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher /* buffer full */
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher i_error("%s: BUG: Received more than %d bytes",
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher conn->prefix, MAX_INBUF_SIZE);
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher auth_request_lookup_abort(conn);
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher return;
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher }
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher if (!conn->handshaked) {
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher if (auth_input_handshake(conn) < 0)
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher return;
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher }
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher while ((line = i_stream_next_line(conn->input)) != NULL) {
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher T_BEGIN {
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher io_loop_set_current(conn->prev_ioloop);
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher ret = auth_handle_line(conn, line);
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher io_loop_set_current(conn->ioloop);
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher } T_END;
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher if (!ret)
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher return;
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagherstatic int auth_master_connect(struct auth_master_connection *conn)
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher{
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher int fd;
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher i_assert(conn->fd == -1);
5dedd73d90f0c1f23299f0c613f384ef902c3653Stephen Gallagher
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* max. 1 second wait here. */
5dedd73d90f0c1f23299f0c613f384ef902c3653Stephen Gallagher fd = net_connect_unix_with_retries(conn->auth_socket_path, 1000);
5dedd73d90f0c1f23299f0c613f384ef902c3653Stephen Gallagher if (fd == -1) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (errno == EACCES) {
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher i_error("userdb lookup: %s",
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher eacces_error_get("connect",
4f3fd1fb264a7eaf3a9d062d49e071b0d17e4debStephen Gallagher conn->auth_socket_path));
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher } else {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("userdb lookup: connect(%s) failed: %m",
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->auth_socket_path);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return -1;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->fd = fd;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher return 0;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_request_timeout(struct auth_master_connection *conn)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (!conn->handshaked)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: Connecting timed out", conn->prefix);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher else
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher i_error("%s: Request timed out", conn->prefix);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_request_lookup_abort(conn);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidekstatic void auth_idle_timeout(struct auth_master_connection *conn)
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_connection_close(conn);
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek}
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic void auth_master_set_io(struct auth_master_connection *conn)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov{
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek if (conn->ioloop != NULL)
46222e5191473f9a46aec581273eb2eef22e23beMichal Zidek return;
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (conn->to != NULL)
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose timeout_remove(&conn->to);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose conn->prev_ioloop = current_ioloop;
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose conn->ioloop = io_loop_create();
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 Bose auth_request_timeout, conn);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose lib_signals_reset_ioloop();
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
cb446b6149d28c204954ae75143b89aef14115dcSumit Bosestatic void auth_master_unset_io(struct auth_master_connection *conn)
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose{
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose if (conn->prev_ioloop != NULL) {
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose io_loop_set_current(conn->prev_ioloop);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov lib_signals_reset_ioloop();
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose if (conn->ioloop != NULL) {
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose io_loop_set_current(conn->ioloop);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose timeout_remove(&conn->to);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose io_remove(&conn->io);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose i_stream_unref(&conn->input);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose o_stream_unref(&conn->output);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov io_loop_destroy(&conn->ioloop);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose }
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if ((conn->flags & AUTH_MASTER_FLAG_NO_IDLE_TIMEOUT) == 0) {
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher if (conn->prev_ioloop == NULL)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_connection_close(conn);
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose else {
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose i_assert(conn->to == NULL);
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher conn->to = timeout_add(1000*AUTH_MASTER_IDLE_SECS,
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher auth_idle_timeout, conn);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher}
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagherstatic bool is_valid_string(const char *str)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher{
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose const char *p;
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose /* make sure we're not sending any characters that have a special
7d056853e4a5fe6daa5743e38d21b4493f4fca27Jakub Hrozek meaning. */
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose for (p = str; *p != '\0'; p++) {
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose if (*p == '\t' || *p == '\n' || *p == '\r')
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose return FALSE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose return TRUE;
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose}
cb446b6149d28c204954ae75143b89aef14115dcSumit Bose
cb446b6149d28c204954ae75143b89aef14115dcSumit Bosestatic int auth_master_run_cmd_pre(struct auth_master_connection *conn,
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher const char *cmd)
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher{
505e75ba28b42bb3de7a6d55de825091b70cc2b2Stephen Gallagher const char *str;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (conn->fd == -1) {
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (auth_master_connect(conn) < 0)
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return -1;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher }
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher auth_master_set_io(conn);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher o_stream_cork(conn->output);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (!conn->sent_handshake) {
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher str = t_strdup_printf("VERSION\t%d\t%d\n",
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher AUTH_PROTOCOL_MAJOR, AUTH_PROTOCOL_MINOR);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher o_stream_nsend_str(conn->output, str);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher conn->sent_handshake = TRUE;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher }
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher o_stream_nsend_str(conn->output, cmd);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher o_stream_uncork(conn->output);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (o_stream_nfinish(conn->output) < 0) {
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher i_error("write(auth socket) failed: %s",
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher o_stream_get_error(conn->output));
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher auth_master_unset_io(conn);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher auth_connection_close(conn);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return -1;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher }
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return 0;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher}
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagherstatic int auth_master_run_cmd_post(struct auth_master_connection *conn)
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher{
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher auth_master_unset_io(conn);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (conn->aborted) {
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher conn->aborted = FALSE;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher auth_connection_close(conn);
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return -1;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher }
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return 0;
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher}
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagherstatic int auth_master_run_cmd(struct auth_master_connection *conn,
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher const char *cmd)
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher{
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher if (auth_master_run_cmd_pre(conn, cmd) < 0)
45f75fc8e98092fa48faa3d180fd42f7efd51486Stephen Gallagher return -1;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher io_loop_run(conn->ioloop);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher return auth_master_run_cmd_post(conn);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher}
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagherstatic unsigned int
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagherauth_master_next_request_id(struct auth_master_connection *conn)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher{
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (++conn->request_counter == 0) {
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher /* avoid zero */
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher conn->request_counter++;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher }
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher return conn->request_counter;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher}
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidekstatic void
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidekauth_user_info_export(string_t *str, const struct auth_user_info *info)
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek{
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek if (info->service != NULL) {
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_append(str, "\tservice=");
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_append(str, info->service);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher }
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (info->local_ip.family != 0)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\tlip=%s", net_ip2addr(&info->local_ip));
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (info->local_port != 0)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\tlport=%d", info->local_port);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (info->remote_ip.family != 0)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov str_printfa(str, "\trip=%s", net_ip2addr(&info->remote_ip));
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (info->remote_port != 0)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_printfa(str, "\trport=%d", info->remote_port);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (info->debug)
bfb40893be20b45279a40188cf16ef0eec1f9423Sumit Bose str_append(str, "\tdebug");
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher}
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovint auth_master_user_lookup(struct auth_master_connection *conn,
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher const char *user, const struct auth_user_info *info,
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher pool_t pool, const char **username_r,
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher const char *const **fields_r)
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher{
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher struct auth_master_lookup_ctx ctx;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher string_t *str;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (!is_valid_string(user) || !is_valid_string(info->service)) {
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher /* non-allowed characters, the user can't exist */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov *username_r = NULL;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov *fields_r = NULL;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher return 0;
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher }
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek memset(&ctx, 0, sizeof(ctx));
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek ctx.conn = conn;
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek ctx.return_value = -1;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ctx.pool = pool;
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek ctx.expected_reply = "USER";
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek ctx.user = user;
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek conn->reply_callback = auth_lookup_reply_callback;
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek conn->reply_context = &ctx;
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov str = t_str_new(128);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov str_printfa(str, "USER\t%u\t%s",
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek auth_master_next_request_id(conn), user);
d6f283302268520c1506fb3da4f2a22f5a741be5Michal Zidek auth_user_info_export(str, info);
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher str_append_c(str, '\n');
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher
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
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher if (ctx.return_value <= 0 || ctx.fields[0] == NULL) {
8be5e4497e5008f7807178acdfcbf97365ec4e73Stephen Gallagher *username_r = NULL;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose *fields_r = ctx.fields != NULL ? ctx.fields :
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose p_new(pool, const char *, 1);
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose if (ctx.return_value > 0) {
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose i_error("Userdb lookup didn't return username");
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose ctx.return_value = -2;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose }
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose } else {
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose *username_r = ctx.fields[0];
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose *fields_r = ctx.fields + 1;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose }
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->reply_context = NULL;
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnik return ctx.return_value;
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnik}
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnik
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnikvoid auth_user_fields_parse(const char *const *fields, pool_t pool,
1e4a582e29c119e2c0e58a02dcb41b829e6b5e39Lukas Slebodnik struct auth_user_reply *reply_r)
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose{
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose memset(reply_r, 0, sizeof(*reply_r));
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik reply_r->uid = (uid_t)-1;
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik reply_r->gid = (gid_t)-1;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose p_array_init(&reply_r->extra_fields, pool, 64);
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik for (; *fields != NULL; fields++) {
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik if (strncmp(*fields, "uid=", 4) == 0) {
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik if (str_to_uid(*fields + 4, &reply_r->uid) < 0)
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik i_error("Invalid uid in reply");
cdcca90249aadb72bf2978a63c202c5b68642224Lukas Slebodnik } else if (strncmp(*fields, "gid=", 4) == 0) {
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose if (str_to_gid(*fields + 4, &reply_r->gid) < 0)
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose i_error("Invalid gid in reply");
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose } else if (strncmp(*fields, "home=", 5) == 0)
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose reply_r->home = p_strdup(pool, *fields + 5);
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose else if (strncmp(*fields, "chroot=", 7) == 0)
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose reply_r->chroot = p_strdup(pool, *fields + 7);
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose else if (strcmp(*fields, "anonymous") == 0)
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose reply_r->anonymous = TRUE;
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose else {
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose const char *field = p_strdup(pool, *fields);
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose array_append(&reply_r->extra_fields, &field, 1);
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose }
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose }
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose}
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Boseint auth_master_pass_lookup(struct auth_master_connection *conn,
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose const char *user, const struct auth_user_info *info,
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose pool_t pool, const char *const **fields_r)
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose{
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose struct auth_master_lookup_ctx ctx;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose string_t *str;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose if (!is_valid_string(user) || !is_valid_string(info->service)) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* non-allowed characters, the user can't exist */
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose *fields_r = NULL;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose return 0;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose }
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose memset(&ctx, 0, sizeof(ctx));
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose ctx.conn = conn;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose ctx.return_value = -1;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov ctx.pool = pool;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose ctx.expected_reply = "PASS";
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose ctx.user = user;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->reply_callback = auth_lookup_reply_callback;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->reply_context = &ctx;
fdda4b659fa3be3027df91a2b053835186ec2c59Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose str = t_str_new(128);
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose str_printfa(str, "PASS\t%u\t%s",
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose auth_master_next_request_id(conn), user);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov auth_user_info_export(str, info);
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose str_append_c(str, '\n');
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->prefix = t_strdup_printf("passdb lookup(%s)", user);
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose (void)auth_master_run_cmd(conn, str_c(str));
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose *fields_r = ctx.fields != NULL ? ctx.fields :
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose p_new(pool, const char *, 1);
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose conn->reply_context = NULL;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose return ctx.return_value;
b2c7b6fe7a6b9ef3af8d4d3037fe83d6e9bfd6a5Sumit Bose}
struct auth_master_cache_ctx {
struct auth_master_connection *conn;
unsigned int count;
bool failed;
};
static bool
auth_cache_flush_reply_callback(const char *cmd, const char *const *args,
void *context)
{
struct auth_master_cache_ctx *ctx = context;
if (strcmp(cmd, "OK") != 0)
ctx->failed = TRUE;
else if (args[0] == NULL || str_to_uint(args[0], &ctx->count) < 0)
ctx->failed = TRUE;
io_loop_stop(ctx->conn->ioloop);
return TRUE;
}
int auth_master_cache_flush(struct auth_master_connection *conn,
const char *const *users, unsigned int *count_r)
{
struct auth_master_cache_ctx ctx;
string_t *str;
memset(&ctx, 0, sizeof(ctx));
ctx.conn = conn;
conn->reply_callback = auth_cache_flush_reply_callback;
conn->reply_context = &ctx;
str = t_str_new(128);
str_printfa(str, "CACHE-FLUSH\t%u", auth_master_next_request_id(conn));
if (users != NULL) {
for (; *users != NULL; users++) {
str_append_c(str, '\t');
str_append_tabescaped(str, *users);
}
}
str_append_c(str, '\n');
conn->prefix = "auth cache flush";
(void)auth_master_run_cmd(conn, str_c(str));
conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
conn->reply_context = NULL;
*count_r = ctx.count;
return ctx.failed ? -1 : 0;
}
static bool
auth_user_list_reply_callback(const char *cmd, const char *const *args,
void *context)
{
struct auth_master_user_list_ctx *ctx = context;
timeout_reset(ctx->conn->to);
str_truncate(ctx->username, 0);
io_loop_stop(ctx->conn->ioloop);
if (strcmp(cmd, "DONE") == 0) {
if (args[0] != NULL && strcmp(args[0], "fail") == 0) {
i_error("User listing returned failure");
ctx->failed = TRUE;
}
ctx->finished = TRUE;
} else if (strcmp(cmd, "LIST") == 0 && args[0] != NULL) {
/* we'll just read all the users into memory. otherwise we'd
have to use a separate connection for listing and there's
a higher chance of a failure since the connection could be
open to dovecot-auth for a long time. */
str_append(ctx->username, args[0]);
} else {
i_error("User listing returned invalid input");
ctx->failed = TRUE;
}
return FALSE;
}
struct auth_master_user_list_ctx *
auth_master_user_list_init(struct auth_master_connection *conn,
const char *user_mask,
const struct auth_user_info *info)
{
struct auth_master_user_list_ctx *ctx;
string_t *str;
ctx = i_new(struct auth_master_user_list_ctx, 1);
ctx->conn = conn;
ctx->username = str_new(default_pool, 128);
conn->reply_callback = auth_user_list_reply_callback;
conn->reply_context = ctx;
str = t_str_new(128);
str_printfa(str, "LIST\t%u",
auth_master_next_request_id(conn));
if (*user_mask != '\0')
str_printfa(str, "\tuser=%s", user_mask);
if (info != NULL)
auth_user_info_export(str, info);
str_append_c(str, '\n');
conn->prefix = "userdb list";
if (auth_master_run_cmd_pre(conn, str_c(str)) < 0)
ctx->failed = TRUE;
if (conn->prev_ioloop != NULL)
io_loop_set_current(conn->prev_ioloop);
conn->prefix = DEFAULT_USERDB_LOOKUP_PREFIX;
return ctx;
}
const char *auth_master_user_list_next(struct auth_master_user_list_ctx *ctx)
{
const char *line;
if (ctx->conn->input == NULL)
return NULL;
/* try to read already buffered input */
line = i_stream_next_line(ctx->conn->input);
if (line != NULL) {
T_BEGIN {
auth_handle_line(ctx->conn, line);
} T_END;
} else {
/* wait for more data */
io_loop_set_current(ctx->conn->ioloop);
io_loop_run(ctx->conn->ioloop);
io_loop_set_current(ctx->conn->prev_ioloop);
}
if (ctx->finished || ctx->failed || ctx->conn->aborted)
return NULL;
return str_c(ctx->username);
}
int auth_master_user_list_deinit(struct auth_master_user_list_ctx **_ctx)
{
struct auth_master_user_list_ctx *ctx = *_ctx;
int ret = ctx->failed ? -1 : 0;
*_ctx = NULL;
auth_master_run_cmd_post(ctx->conn);
str_free(&ctx->username);
i_free(ctx);
return ret;
}