Example #1
0
static void main_stdio_run(const char *username)
{
	struct mail_storage_service_input input;
	buffer_t *input_buf;
	const char *value, *error, *input_base64;

	memset(&input, 0, sizeof(input));
	input.module = input.service = "pop3";
	input.username = username != NULL ? username : getenv("USER");
	if (input.username == NULL && IS_STANDALONE())
		input.username = getlogin();
	if (input.username == NULL)
		i_fatal("USER environment missing");
	if ((value = getenv("IP")) != NULL)
		(void)net_addr2ip(value, &input.remote_ip);
	if ((value = getenv("LOCAL_IP")) != NULL)
		(void)net_addr2ip(value, &input.local_ip);

	input_base64 = getenv("CLIENT_INPUT");
	input_buf = input_base64 == NULL ? NULL :
		t_base64_decode_str(input_base64);

	if (client_create_from_input(&input, STDIN_FILENO, STDOUT_FILENO,
				     input_buf, &error) < 0)
		i_fatal("%s", error);
}
Example #2
0
static struct passdb_module *
vpopmail_preinit(pool_t pool, const char *args)
{
	static bool vauth_load_initialized = FALSE;
	struct vpopmail_passdb_module *module;
	const char *const *tmp;

	module = p_new(pool, struct vpopmail_passdb_module, 1);
	module->module.default_pass_scheme = VPOPMAIL_DEFAULT_PASS_SCHEME;
	module->module.blocking = TRUE;

	tmp = t_strsplit_spaces(args, " ");
	for (; *tmp != NULL; tmp++) {
		if (strncmp(*tmp, "cache_key=", 10) == 0) {
			module->module.default_cache_key =
				auth_cache_parse_key(pool, *tmp + 10);
		} else if (strncmp(*tmp, "webmail=", 8) == 0) {
			if (net_addr2ip(*tmp + 8, &module->webmail_ip) < 0)
				i_fatal("vpopmail: Invalid webmail IP address");
		} else if (strcmp(*tmp, "blocking=no") == 0) {
			module->module.blocking = FALSE;
		} else {
			i_fatal("passdb vpopmail: Unknown setting: %s", *tmp);
		}
	}
	if (!vauth_load_initialized) {
		vauth_load_initialized = TRUE;
		if (vauth_open(0) != 0)
			i_fatal("vpopmail: vauth_open() failed");
	}
	return &module->module;
}
Example #3
0
int lmtp_client_connect_tcp(struct lmtp_client *client,
			    enum lmtp_client_protocol protocol,
			    const char *host, unsigned int port)
{
	struct dns_lookup_settings dns_lookup_set;

	client->input_state = LMTP_INPUT_STATE_GREET;
	client->host = p_strdup(client->pool, host);
	client->port = port;
	client->protocol = protocol;

	if (*host == '\0') {
		i_error("lmtp client: host not given");
		return -1;
	}

	memset(&dns_lookup_set, 0, sizeof(dns_lookup_set));
	dns_lookup_set.dns_client_socket_path =
		client->set.dns_client_socket_path;
	dns_lookup_set.timeout_msecs = LMTP_CLIENT_DNS_LOOKUP_TIMEOUT_MSECS;

	if (net_addr2ip(host, &client->ip) < 0) {
		if (dns_lookup(host, &dns_lookup_set,
			       lmtp_client_dns_done, client) < 0)
			return -1;
	} else {
		if (lmtp_client_connect(client) < 0)
			return -1;
	}
	return 0;
}
Example #4
0
int mail_session_connect_parse(const char *const *args, const char **error_r)
{
	struct mail_session *session;
	const char *session_id;
	pid_t pid;
	struct ip_addr ip;
	unsigned int i;

	/* <session id> <username> <service> <pid> [key=value ..] */
	if (str_array_length(args) < 4) {
		*error_r = "CONNECT: Too few parameters";
		return -1;
	}
	session_id = args[0];
	if (str_to_pid(args[3], &pid) < 0) {
		*error_r = t_strdup_printf("CONNECT: Invalid pid %s for session ID %s",
					   args[3], session_id);
		return -1;
	}

	session = hash_table_lookup(mail_sessions_hash, session_id);
	if (session != NULL) {
		*error_r = t_strdup_printf(
			"CONNECT: Duplicate session ID %s for user %s service %s",
			session_id, args[1], args[2]);
		return -1;
	}
	session = i_malloc(sizeof(struct mail_session) + stats_alloc_size());
	session->stats = (void *)(session + 1);
	session->refcount = 1; /* unrefed at disconnect */
	session->id = i_strdup(session_id);
	session->service = str_table_ref(services, args[2]);
	session->pid = pid;
	session->last_update = ioloop_timeval;
	session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
				       mail_session_idle_timeout, session);

	session->user = mail_user_login(args[1]);
	for (i = 3; args[i] != NULL; i++) {
		if (strncmp(args[i], "rip=", 4) == 0 &&
		    net_addr2ip(args[i] + 4, &ip) == 0)
			session->ip = mail_ip_login(&ip);
	}

	hash_table_insert(mail_sessions_hash, session->id, session);
	DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
			    stable_prev, stable_next);
	DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
			    sorted_prev, sorted_next);
	DLLIST_PREPEND_FULL(&session->user->sessions, session,
			    user_prev, user_next);
	mail_user_ref(session->user);
	if (session->ip != NULL) {
		DLLIST_PREPEND_FULL(&session->ip->sessions, session,
				    ip_prev, ip_next);
		mail_ip_ref(session->ip);
	}
	global_memory_alloc(mail_session_memsize(session));
	return 0;
}
Example #5
0
static int proxy_start(struct client *client,
		       const struct client_auth_reply *reply)
{
	struct login_proxy_settings proxy_set;

	i_assert(reply->destuser != NULL);
	i_assert(!client->destroyed);

	client->v.proxy_reset(client);

	if (reply->password == NULL) {
		client_log_err(client, "proxy: password not given");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}
	if (reply->host == NULL || *reply->host == '\0') {
		client_log_err(client, "proxy: host not given");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	i_assert(client->refcount > 1);

	if (client->destroyed) {
		/* connection_queue_add() decided that we were the oldest
		   connection and killed us. */
		return -1;
	}
	if (login_proxy_is_ourself(client, reply->host, reply->port,
				   reply->destuser)) {
		client_log_err(client, "Proxying loops to itself");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	memset(&proxy_set, 0, sizeof(proxy_set));
	proxy_set.host = reply->host;
	if (reply->hostip != NULL &&
	    net_addr2ip(reply->hostip, &proxy_set.ip) < 0)
		proxy_set.ip.family = 0;
	proxy_set.port = reply->port;
	proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
	proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
	proxy_set.ssl_flags = reply->ssl_flags;

	if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	client->proxy_user = i_strdup(reply->destuser);
	client->proxy_master_user = i_strdup(reply->master_user);
	client->proxy_password = i_strdup(reply->password);

	/* disable input until authentication is finished */
	if (client->io != NULL)
		io_remove(&client->io);
	return 0;
}
Example #6
0
static void
client_update_info(struct imap_client *client,
		   const char *key, const char *value)
{
	if (strcasecmp(key, "x-originating-ip") == 0)
		(void)net_addr2ip(value, &client->common.ip);
	else if (strcasecmp(key, "x-originating-port") == 0)
		client->common.remote_port = atoi(value);
	else if (strcasecmp(key, "x-connected-ip") == 0)
		(void)net_addr2ip(value, &client->common.local_ip);
	else if (strcasecmp(key, "x-connected-port") == 0)
		client->common.local_port = atoi(value);
	else if (strcasecmp(key, "x-proxy-ttl") == 0)
		client->common.proxy_ttl = atoi(value);
	else if (strcasecmp(key, "x-session-id") == 0) {
		client->common.session_id =
			p_strdup(client->common.pool, value);
	}
}
Example #7
0
static void auth_user_info_parse(struct auth_user_info *info, const char *arg)
{
    if (strncmp(arg, "service=", 8) == 0)
        info->service = arg + 8;
    else if (strncmp(arg, "lip=", 4) == 0) {
        if (net_addr2ip(arg + 4, &info->local_ip) < 0)
            i_fatal("lip: Invalid ip");
    } else if (strncmp(arg, "rip=", 4) == 0) {
        if (net_addr2ip(arg + 4, &info->remote_ip) < 0)
            i_fatal("rip: Invalid ip");
    } else if (strncmp(arg, "lport=", 6) == 0) {
        if (net_str2port(arg + 6, &info->local_port) < 0)
            i_fatal("lport: Invalid port number");
    } else if (strncmp(arg, "rport=", 6) == 0) {
        if (net_str2port(arg + 6, &info->remote_port) < 0)
            i_fatal("rport: Invalid port number");
    } else {
        i_fatal("Unknown -x argument: %s", arg);
    }
}
Example #8
0
static void test_net_ip2addr(void)
{
	struct ip_addr ip;

	test_begin("net_ip2addr()");
	test_assert(net_addr2ip("127.0.0.1", &ip) == 0 &&
		    ip.family == AF_INET &&
		    ip.u.ip4.s_addr == (127 | (1 << 24)));
#ifdef HAVE_IPV6
	test_assert(net_addr2ip("::5", &ip) == 0 &&
		    ip.family == AF_INET6 &&
		    ip.u.ip6.s6_addr[15] == 5);
	test_assert(net_addr2ip("[::5]", &ip) == 0 &&
		    ip.family == AF_INET6 &&
		    ip.u.ip6.s6_addr[15] == 5);
	ip.family = 123;
	test_assert(net_addr2ip("abc", &ip) < 0 &&
		    ip.family == 123);
#endif
	test_end();
}
Example #9
0
int
stats_carbon_send(const char *endpoint, const char *data,
		  void (*callback)(void *), void *cb_ctx,
		  struct stats_send_ctx **ctx_r)
{
	const char *host;
	in_port_t port;
	struct ip_addr ip;

	if (net_str2hostport(endpoint, CARBON_SERVER_DEFAULT_PORT,
			     &host, &port) < 0 ||
	    net_addr2ip(host, &ip) < 0) {
		i_error("stats_submit: Cannot parse endpoint '%s'",
			endpoint);
		return -1;
	}

	pool_t pool = pool_alloconly_create("stats carbon send", 1024);
	struct stats_send_ctx *ctx = p_new(pool,
					   struct stats_send_ctx, 1);
	ctx->pool = pool;
	ctx->str = p_strdup(ctx->pool, data);

	ctx->fd = net_connect_ip(&ip, port, NULL);
	if (ctx->fd < 0) {
		i_error("connect(%s) failed: %m", endpoint);
		stats_carbon_callback(ctx);
		return -1;
	}
	ctx->io = io_add(ctx->fd, IO_WRITE,
			 stats_carbon_connected,
			 ctx);

	/* give time for almost until next update
	   this is to ensure we leave a little pause between
           attempts. Multiplier 800 gives us 20% window, and
           ensures the number stays positive. */
	ctx->to_msecs = stats_settings->carbon_interval*800;
	ctx->to = timeout_add(ctx->to_msecs,
			      stats_carbon_timeout,
			      ctx);
	if (net_ipport2str(&ip, port, &host) < 0)
		i_unreached();
	ctx->endpoint = p_strdup(ctx->pool, host);
	ctx->callback = callback;
	ctx->ctx = cb_ctx;

	*ctx_r = ctx;

	return 0;
}
Example #10
0
int login_proxy_new(struct client *client,
		    const struct login_proxy_settings *set,
		    proxy_callback_t *callback)
{
	struct login_proxy *proxy;

	i_assert(client->login_proxy == NULL);

	if (set->host == NULL || *set->host == '\0') {
		i_error("proxy(%s): host not given", client->virtual_user);
		return -1;
	}

	if (client->proxy_ttl <= 1) {
		i_error("proxy(%s): TTL reached zero - "
			"proxies appear to be looping?", client->virtual_user);
		return -1;
	}

	proxy = i_new(struct login_proxy, 1);
	proxy->client = client;
	proxy->client_fd = -1;
	proxy->server_fd = -1;
	proxy->created = ioloop_timeval;
	proxy->ip = set->ip;
	proxy->source_ip = set->source_ip;
	proxy->host = i_strdup(set->host);
	proxy->port = set->port;
	proxy->connect_timeout_msecs = set->connect_timeout_msecs;
	proxy->notify_refresh_secs = set->notify_refresh_secs;
	proxy->ssl_flags = set->ssl_flags;
	proxy->state_rec = login_proxy_state_get(proxy_state, &proxy->ip,
						 proxy->port);
	client_ref(client);

	if (set->ip.family == 0 &&
	    net_addr2ip(set->host, &proxy->ip) < 0) {
		i_error("proxy(%s): BUG: host %s is not an IP "
			"(auth should have changed it)",
			client->virtual_user, set->host);
	} else {
		if (login_proxy_connect(proxy) < 0)
			return -1;
	}

	DLLIST_PREPEND(&login_proxies_pending, proxy);

	proxy->callback = callback;
	client->login_proxy = proxy;
	return 0;
}
Example #11
0
static void test_net_is_in_network(void)
{
	static struct test_net_is_in_network_input input[] = {
		{ "1.2.3.4", "1.2.3.4", 32, TRUE },
		{ "1.2.3.4", "1.2.3.3", 32, FALSE },
		{ "1.2.3.4", "1.2.3.5", 32, FALSE },
		{ "1.2.3.4", "1.2.2.4", 32, FALSE },
		{ "1.2.3.4", "1.1.3.4", 32, FALSE },
		{ "1.2.3.4", "0.2.3.4", 32, FALSE },
		{ "1.2.3.253", "1.2.3.254", 31, FALSE },
		{ "1.2.3.254", "1.2.3.254", 31, TRUE },
		{ "1.2.3.255", "1.2.3.254", 31, TRUE },
		{ "1.2.3.255", "1.2.3.0", 24, TRUE },
		{ "1.2.255.255", "1.2.254.0", 23, TRUE },
		{ "255.255.255.255", "128.0.0.0", 1, TRUE },
		{ "255.255.255.255", "127.0.0.0", 1, FALSE }
#ifdef HAVE_IPV6
		,
		{ "1234:5678::abcf", "1234:5678::abce", 127, TRUE },
		{ "1234:5678::abcd", "1234:5678::abce", 127, FALSE },
		{ "123e::ffff", "123e::0", 15, TRUE },
		{ "123d::ffff", "123e::0", 15, FALSE }
#endif
	};
	struct ip_addr ip, net_ip;
	unsigned int i;
	bool success;

	test_begin("net_is_in_network()");
	for (i = 0; i < N_ELEMENTS(input); i++) {
		test_assert(net_addr2ip(input[i].ip, &ip) == 0);
		test_assert(net_addr2ip(input[i].net, &net_ip) == 0);
		success = net_is_in_network(&ip, &net_ip, input[i].bits) ==
			input[i].ret;
		test_out(t_strdup_printf("net_is_in_network(%u)", i), success);
	}
	test_end();
}
Example #12
0
bool login_proxy_is_ourself(const struct client *client, const char *host,
			    in_port_t port, const char *destuser)
{
	struct ip_addr ip;

	if (port != client->local_port)
		return FALSE;

	if (net_addr2ip(host, &ip) < 0)
		return FALSE;
	if (!net_ip_compare(&ip, &client->local_ip))
		return FALSE;

	return strcmp(client->virtual_user, destuser) == 0;
}
Example #13
0
static void penalty_parse_line(const char *line, struct penalty_line *line_r)
{
	const char *const *args = t_strsplit_tab(line);
	const char *ident = args[0];
	const char *penalty_str = args[1];
	const char *last_penalty_str = args[2];
	const char *last_update_str = args[3];

	memset(line_r, 0, sizeof(*line_r));

	(void)net_addr2ip(ident, &line_r->ip);
	line_r->penalty = strtoul(penalty_str, NULL, 10);
	line_r->last_penalty = strtoul(last_penalty_str, NULL, 10);
	line_r->last_update = strtoul(last_update_str, NULL, 10);
}
Example #14
0
static bool
client_proxy_is_ourself(const struct client *client,
			const struct lmtp_proxy_rcpt_settings *set)
{
	struct ip_addr ip;

	if (set->port != client->local_port)
		return FALSE;

	if (net_addr2ip(set->host, &ip) < 0)
		return FALSE;
	if (!net_ip_compare(&ip, &client->local_ip))
		return FALSE;
	return TRUE;
}
Example #15
0
static int login_proxy_connect(struct login_proxy *proxy)
{
	struct login_proxy_record *rec = proxy->state_rec;

	/* this needs to be done early, since login_proxy_free() shrinks
	   num_waiting_connections. */
	proxy->num_waiting_connections_updated = FALSE;
	rec->num_waiting_connections++;

	if (proxy->ip.family == 0 &&
	    net_addr2ip(proxy->host, &proxy->ip) < 0) {
		client_log_err(proxy->client, t_strdup_printf(
			"proxy(%s): BUG: host %s is not an IP "
			"(auth should have changed it)",
			proxy->client->virtual_user, proxy->host));
		return -1;
	}

	if (rec->last_success.tv_sec == 0) {
		/* first connect to this IP. don't start immediately failing
		   the check below. */
		rec->last_success.tv_sec = ioloop_timeval.tv_sec - 1;
	}
	if (timeval_cmp(&rec->last_failure, &rec->last_success) > 0 &&
	    rec->last_failure.tv_sec - rec->last_success.tv_sec > PROXY_IMMEDIATE_FAILURE_SECS &&
	    rec->num_waiting_connections > 1) {
		/* the server is down. fail immediately */
		client_log_err(proxy->client, t_strdup_printf(
			"proxy(%s): Host %s:%u is down",
			proxy->client->virtual_user, proxy->host, proxy->port));
		return -1;
	}

	proxy->server_fd = net_connect_ip(&proxy->ip, proxy->port,
					  proxy->source_ip.family == 0 ? NULL :
					  &proxy->source_ip);
	if (proxy->server_fd == -1) {
		proxy_log_connect_error(proxy);
		return -1;
	}
	proxy->server_io = io_add(proxy->server_fd, IO_WRITE,
				  proxy_wait_connect, proxy);
	if (proxy->connect_timeout_msecs != 0) {
		proxy->to = timeout_add(proxy->connect_timeout_msecs,
					proxy_connect_timeout, proxy);
	}
	return 0;
}
Example #16
0
int lmtp_client_connect_tcp(struct lmtp_client *client,
			    enum lmtp_client_protocol protocol,
			    const char *host, unsigned int port)
{
	struct dns_lookup_settings dns_lookup_set;
	struct ip_addr *ips;
	unsigned int ips_count;
	int ret;

	client->input_state = LMTP_INPUT_STATE_GREET;
	client->host = p_strdup(client->pool, host);
	client->port = port;
	client->protocol = protocol;

	if (*host == '\0') {
		i_error("lmtp client: host not given");
		return -1;
	}

	memset(&dns_lookup_set, 0, sizeof(dns_lookup_set));
	dns_lookup_set.dns_client_socket_path =
		client->set.dns_client_socket_path;
	dns_lookup_set.timeout_msecs = LMTP_CLIENT_DNS_LOOKUP_TIMEOUT_MSECS;

	if (net_addr2ip(host, &client->ip) == 0) {
		/* IP address */
	} else if (dns_lookup_set.dns_client_socket_path == NULL) {
		/* no dns-client, use blocking lookup */
		ret = net_gethostbyname(host, &ips, &ips_count);
		if (ret != 0) {
			i_error("lmtp client: DNS lookup of %s failed: %s",
				client->host, net_gethosterror(ret));
			return -1;
		}
		client->ip = ips[0];
	} else {
		if (dns_lookup(host, &dns_lookup_set,
			       lmtp_client_dns_done, client,
			       &client->dns_lookup) < 0)
			return -1;
		client->running = TRUE;
		return 0;
	}

	if (lmtp_client_connect(client) < 0)
		return -1;
	return 0;
}
Example #17
0
static void penalty_parse_line(const char *line, struct penalty_line *line_r)
{
	const char *const *args = t_strsplit_tab(line);
	const char *ident = args[0];
	const char *penalty_str = args[1];
	const char *last_penalty_str = args[2];
	const char *last_update_str = args[3];

	memset(line_r, 0, sizeof(*line_r));

	(void)net_addr2ip(ident, &line_r->ip);
	if (str_to_uint(penalty_str, &line_r->penalty) < 0 ||
	    str_to_time(last_penalty_str, &line_r->last_penalty) < 0 ||
	    str_to_time(last_update_str, &line_r->last_update) < 0)
		i_fatal("Read invalid penalty line: %s", line);
}
Example #18
0
static int dns_client_input_line(struct dns_client *client, const char *line)
{
	struct ip_addr *ips, ip;
	const char *name;
	unsigned int i, ips_count;
	int ret;

	if (strncmp(line, "IP\t", 3) == 0) {
		ret = net_gethostbyname(line + 3, &ips, &ips_count);
		if (ret == 0 && ips_count == 0) {
			/* shouldn't happen, but fix it anyway.. */
			ret = EAI_NONAME;
		}
		if (ret != 0) {
			o_stream_nsend_str(client->output,
				t_strdup_printf("%d\n", ret));
		} else {
			o_stream_nsend_str(client->output,
				t_strdup_printf("0 %u\n", ips_count));
			for (i = 0; i < ips_count; i++) {
				o_stream_nsend_str(client->output, t_strconcat(
					net_ip2addr(&ips[i]), "\n", NULL));
			}
		}
	} else if (strncmp(line, "NAME\t", 5) == 0) {
		if (net_addr2ip(line+5, &ip) < 0)
			o_stream_nsend_str(client->output, "-1\n");
		else if ((ret = net_gethostbyaddr(&ip, &name)) != 0) {
			o_stream_nsend_str(client->output,
				t_strdup_printf("%d\n", ret));
		} else {
			o_stream_nsend_str(client->output,
				t_strdup_printf("0 %s\n", name));
		}
	} else if (strcmp(line, "QUIT") == 0) {
		return -1;
	} else {
		o_stream_nsend_str(client->output, "Unknown command\n");
	}

	if (client->output->overflow)
		return -1;
	return 0;
}
Example #19
0
static void
login_proxy_cmd_kick_director_hash(struct ipc_cmd *cmd, const char *const *args)
{
	struct login_proxy *proxy, *next;
	struct ip_addr except_ip;
	unsigned int hash, proxy_hash, count = 0;

	if (args[0] == NULL || str_to_uint(args[0], &hash) < 0) {
		ipc_cmd_fail(&cmd, "Invalid parameters");
		return;
	}
	/* optional except_ip parameter specifies that we're not killing the
	   connections that are proxying to the except_ip backend */
	except_ip.family = 0;
	if (args[1] != NULL && args[1][0] != '\0' &&
	    net_addr2ip(args[1], &except_ip) < 0) {
		ipc_cmd_fail(&cmd, "Invalid except_ip parameter");
		return;
	}

	for (proxy = login_proxies; proxy != NULL; proxy = next) {
		next = proxy->next;

		if (director_username_hash(proxy->client, &proxy_hash) &&
		    proxy_hash == hash &&
		    !net_ip_compare(&proxy->ip, &except_ip)) {
			login_proxy_free_delayed(&proxy, KILLED_BY_DIRECTOR_REASON);
			count++;
		}
	}
	for (proxy = login_proxies_pending; proxy != NULL; proxy = next) {
		next = proxy->next;

		if (director_username_hash(proxy->client, &proxy_hash) &&
		    proxy_hash == hash &&
		    !net_ip_compare(&proxy->ip, &except_ip)) {
			client_destroy(proxy->client, "Connection kicked");
			count++;
		}
	}
	ipc_cmd_success_reply(&cmd, t_strdup_printf("%u", count));
}
Example #20
0
static int
imap_master_client_parse_input(const char *const *args, pool_t pool,
			       struct mail_storage_service_input *input_r,
			       struct imap_master_input *master_input_r,
			       const char **error_r)
{
	const char *key, *value;
	unsigned int peer_dev_major = 0, peer_dev_minor = 0;

	i_zero(input_r);
	i_zero(master_input_r);
	master_input_r->client_input = buffer_create_dynamic(pool, 64);
	master_input_r->client_output = buffer_create_dynamic(pool, 16);
	master_input_r->state = buffer_create_dynamic(pool, 512);

	input_r->module = input_r->service = "imap";
	/* we never want to do userdb lookup again when restoring the client.
	   we have the userdb_fields cached already. */
	input_r->flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;

	if (args[0] == NULL) {
		*error_r = "Missing username in input";
		return -1;
	}
	input_r->username = args[0];

	for (args++; *args != NULL; args++) {
		value = strchr(*args, '=');
		if (value != NULL)
			key = t_strdup_until(*args, value++);
		else {
			key = *args;
			value = "";
		}
		if (strcmp(key, "lip") == 0) {
			if (net_addr2ip(value, &input_r->local_ip) < 0) {
				*error_r = t_strdup_printf(
					"Invalid lip value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "rip") == 0) {
			if (net_addr2ip(value, &input_r->remote_ip) < 0) {
				*error_r = t_strdup_printf(
					"Invalid rip value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_dev_major") == 0) {
			if (str_to_uint(value, &peer_dev_major) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_dev_major value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_dev_minor") == 0) {
			if (str_to_uint(value, &peer_dev_minor) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_dev_minor value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_ino") == 0) {
			if (str_to_ino(value, &master_input_r->peer_ino) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_ino value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "session") == 0) {
			input_r->session_id = value;
		} else if (strcmp(key, "session_created") == 0) {
			if (str_to_time(value, &input_r->session_create_time) < 0) {
				*error_r = t_strdup_printf(
					"Invalid session_created value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "userdb_fields") == 0) {
			input_r->userdb_fields =
				t_strsplit_tabescaped(value);
		} else if (strcmp(key, "client_input") == 0) {
			if (base64_decode(value, strlen(value), NULL,
					  master_input_r->client_input) < 0) {
				*error_r = t_strdup_printf(
					"Invalid client_input base64 value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "client_output") == 0) {
			if (base64_decode(value, strlen(value), NULL,
					  master_input_r->client_output) < 0) {
				*error_r = t_strdup_printf(
					"Invalid client_output base64 value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "state") == 0) {
			if (base64_decode(value, strlen(value), NULL,
					  master_input_r->state) < 0) {
				*error_r = t_strdup_printf(
					"Invalid state base64 value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "tag") == 0) {
			master_input_r->tag = t_strdup(value);
		} else if (strcmp(key, "bad-done") == 0) {
			master_input_r->state_import_bad_idle_done = TRUE;
		} else if (strcmp(key, "idle-continue") == 0) {
			master_input_r->state_import_idle_continue = TRUE;
		}
	}
	if (peer_dev_major != 0 || peer_dev_minor != 0) {
		master_input_r->peer_dev =
			makedev(peer_dev_major, peer_dev_minor);
	}
	return 0;
}
int mail_session_connect_parse(const char *const *args, const char **error_r)
{
	struct mail_session *session;
	guid_128_t session_guid;
	uint8_t *guid_p;
	pid_t pid;
	struct ip_addr ip;
	unsigned int i;

	/* <session guid> <username> <service> <pid> [key=value ..] */
	if (str_array_length(args) < 4) {
		*error_r = "CONNECT: Too few parameters";
		return -1;
	}
	if (guid_128_from_string(args[0], session_guid) < 0) {
		*error_r = "CONNECT: Invalid GUID";
		return -1;
	}
	if (str_to_pid(args[3], &pid) < 0) {
		*error_r = "CONNECT: Invalid pid";
		return -1;
	}

	guid_p = session_guid;
	session = hash_table_lookup(mail_sessions_hash, guid_p);
	if (session != NULL) {
		*error_r = "CONNECT: Duplicate session GUID";
		return -1;
	}
	session = i_new(struct mail_session, 1);
	session->refcount = 1; /* unrefed at disconnect */
	session->service = i_strdup(args[2]);
	memcpy(session->guid, session_guid, sizeof(session->guid));
	session->pid = pid;
	session->last_update = ioloop_timeval;
	session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
				       mail_session_idle_timeout, session);

	session->user = mail_user_login(args[1]);
	for (i = 3; args[i] != NULL; i++) {
		if (strncmp(args[i], "rip=", 4) == 0 &&
		    net_addr2ip(args[i] + 4, &ip) == 0)
			session->ip = mail_ip_login(&ip);
	}

	guid_p = session->guid;
	hash_table_insert(mail_sessions_hash, guid_p, session);
	DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
			    stable_prev, stable_next);
	DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
			    sorted_prev, sorted_next);
	DLLIST_PREPEND_FULL(&session->user->sessions, session,
			    user_prev, user_next);
	mail_user_ref(session->user);
	if (session->ip != NULL) {
		DLLIST_PREPEND_FULL(&session->ip->sessions, session,
				    ip_prev, ip_next);
		mail_ip_ref(session->ip);
	}
	global_memory_alloc(mail_session_memsize(session));
	return 0;
}
Example #22
0
static int config_connection_request(struct config_connection *conn,
				     const char *const *args)
{
	struct config_export_context *ctx;
	struct master_service_settings_output output;
	struct config_filter filter;
	const char *path, *error, *module = "";

	/* [<args>] */
	memset(&filter, 0, sizeof(filter));
	for (; *args != NULL; args++) {
		if (strncmp(*args, "service=", 8) == 0)
			filter.service = *args + 8;
		else if (strncmp(*args, "module=", 7) == 0)
			module = *args + 7;
		else if (strncmp(*args, "lname=", 6) == 0)
			filter.local_name = *args + 6;
		else if (strncmp(*args, "lip=", 4) == 0) {
			if (net_addr2ip(*args + 4, &filter.local_net) == 0) {
				filter.local_bits =
					IPADDR_IS_V4(&filter.local_net) ?
					32 : 128;
			}
		} else if (strncmp(*args, "rip=", 4) == 0) {
			if (net_addr2ip(*args + 4, &filter.remote_net) == 0) {
				filter.remote_bits =
					IPADDR_IS_V4(&filter.remote_net) ?
					32 : 128;
			}
		}
	}

	if (strcmp(module, "master") == 0) {
		/* master reads configuration only when reloading settings */
		path = master_service_get_config_path(master_service);
		if (config_parse_file(path, TRUE, "", &error) <= 0) {
			o_stream_send_str(conn->output,
				t_strconcat("ERROR ", error, "\n", NULL));
			config_connection_destroy(conn);
			return -1;
		}
	}

	o_stream_cork(conn->output);

	ctx = config_export_init(module, CONFIG_DUMP_SCOPE_SET, 0,
				 config_request_output, conn->output);
	config_export_by_filter(ctx, &filter);
	config_export_get_output(ctx, &output);

	if (output.specific_services != NULL) {
		const char *const *s;

		for (s = output.specific_services; *s != NULL; s++) {
			o_stream_send_str(conn->output,
				t_strdup_printf("service=%s\t", *s));
		}
	}
	if (output.service_uses_local)
		o_stream_send_str(conn->output, "service-uses-local\t");
	if (output.service_uses_remote)
		o_stream_send_str(conn->output, "service-uses-remote\t");
	if (output.used_local)
		o_stream_send_str(conn->output, "used-local\t");
	if (output.used_remote)
		o_stream_send_str(conn->output, "used-remote\t");
	o_stream_send_str(conn->output, "\n");

	if (config_export_finish(&ctx) < 0) {
		config_connection_destroy(conn);
		return -1;
	}
	o_stream_send_str(conn->output, "\n");
	o_stream_uncork(conn->output);
	return 0;
}
Example #23
0
static void client_connected(struct master_service_connection *conn)
{
	enum mail_storage_service_flags flags =
		MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS;
	string_t *instr, *keys;
	const char **args, *key, *value, *error, *version_line, *data_line;
	struct mail_storage_service_ctx *service_ctx;
	struct mail_storage_service_input input;
	struct mail_storage_service_user *user;
	char buf[1024];
	unsigned int i, socket_count;
	int fd = -1;
	ssize_t ret;

	alarm(SCRIPT_LOGIN_READ_TIMEOUT_SECS);

	net_set_nonblock(conn->fd, FALSE);
	instr = t_str_new(1024);
	ret = fd_read(conn->fd, buf, sizeof(buf), &fd);
	while (ret > 0) {
		str_append_n(instr, buf, ret);
		if (buf[ret-1] == '\n' &&
		    strchr(str_c(instr), '\n')[1] != '\0') {
			str_truncate(instr, str_len(instr)-1);
			break;
		}

		ret = read(conn->fd, buf, sizeof(buf));
	}

	version_line = str_c(instr);
	data_line = strchr(version_line, '\n');
	if (data_line != NULL)
		version_line = t_strdup_until(version_line, data_line++);
	else
		version_line = NULL;

	if (ret > 0 || version_line != NULL) {
		if (version_line == NULL ||
		    !version_string_verify(version_line, "script-login",
				SCRIPT_LOGIN_PROTOCOL_VERSION_MAJOR)) {
			i_fatal("Client not compatible with this binary "
				"(connecting to wrong socket?)");
		}
	}

	if (ret <= 0) {
		if (ret < 0)
			i_fatal("read() failed: %m");
		else
			i_fatal("read() failed: disconnected");
	}
	if (fd == -1)
		i_fatal("client fd not received");

	alarm(0);

	/* put everything to environment */
	env_clean();
	keys = t_str_new(256);
	args = t_strsplit_tab(data_line);

	if (str_array_length(args) < 3)
		i_fatal("Missing input fields");

	i = 0;
	memset(&input, 0, sizeof(input));
	input.module = "mail"; /* need to get mail_uid, mail_gid */
	input.service = "script-login";
	(void)net_addr2ip(args[i++], &input.local_ip);
	(void)net_addr2ip(args[i++], &input.remote_ip);
	input.username = args[i++];
	input.userdb_fields = args + i;

	env_put(t_strconcat("LOCAL_IP=", net_ip2addr(&input.local_ip), NULL));
	env_put(t_strconcat("IP=", net_ip2addr(&input.remote_ip), NULL));
	env_put(t_strconcat("USER="******"%s ", key);
		}
	}
	env_put(t_strconcat(ENV_USERDB_KEYS"=", str_c(keys), NULL));

	master_service_init_log(master_service,
		t_strdup_printf("script-login(%s): ", input.username));

	if (drop_to_userdb_privileges) {
		service_ctx = mail_storage_service_init(master_service, NULL, flags);
		if (mail_storage_service_lookup(service_ctx, &input, &user, &error) <= 0)
			i_fatal("%s", error);
		mail_storage_service_restrict_setenv(service_ctx, user);
		/* we can't exec anything in a chroot */
		env_remove("RESTRICT_CHROOT");
		restrict_access_by_env(getenv("HOME"), TRUE);
	}

	if (dup2(fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (dup2(fd, STDOUT_FILENO) < 0)
		i_fatal("dup2() failed: %m");
	if (close(fd) < 0)
		i_fatal("close() failed: %m");
	if (conn->fd != SCRIPT_COMM_FD) {
		if (dup2(conn->fd, SCRIPT_COMM_FD) < 0)
			i_fatal("dup2() failed: %m");
		if (close(conn->fd) < 0)
			i_fatal("close() failed: %m");
	}

	/* close all listener sockets */
	socket_count = master_service_get_socket_count(master_service);
	for (i = 0; i < socket_count; i++) {
		if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
			i_error("close(listener) failed: %m");
	}
	if (close(MASTER_STATUS_FD) < 0)
		i_error("close(status) failed: %m");

	execvp_const(exec_args[0], exec_args);
}
Example #24
0
static void auth_input_line(const char *line, void *context)
{
	struct login_connection *conn = context;
	struct login_host_request *request, temp_request;
	const char *const *args, *line_params, *username = NULL, *tag = "";
	bool proxy = FALSE, host = FALSE;

	if (line == NULL) {
		/* auth connection died -> kill also this login connection */
		login_connection_deinit(&conn);
		return;
	}
	if (conn->type != LOGIN_CONNECTION_TYPE_USERDB &&
	    strncmp(line, "OK\t", 3) == 0)
		line_params = line + 3;
	else if (conn->type == LOGIN_CONNECTION_TYPE_USERDB &&
		 strncmp(line, "PASS\t", 5) == 0)
		line_params = line + 5;
	else {
		login_connection_send_line(conn, line);
		return;
	}

	/* OK <id> [<parameters>] */
	args = t_strsplit_tab(line_params);
	if (*args != NULL) {
		/* we should always get here, but in case we don't just
		   forward as-is and let login process handle the error. */
		args++;
	}

	memset(&temp_request, 0, sizeof(temp_request));
	for (; *args != NULL; args++) {
		if (strncmp(*args, "proxy", 5) == 0 &&
		    ((*args)[5] == '=' || (*args)[5] == '\0'))
			proxy = TRUE;
		else if (strncmp(*args, "host=", 5) == 0)
			host = TRUE;
		else if (strncmp(*args, "lip=", 4) == 0) {
			if (net_addr2ip((*args) + 4, &temp_request.local_ip) < 0)
				i_error("auth sent invalid lip field: %s", (*args) + 6);
		} else if (strncmp(*args, "lport=", 6) == 0) {
			if (str_to_uint((*args) + 6, &temp_request.local_port) < 0)
				i_error("auth sent invalid lport field: %s", (*args) + 6);
		} else if (strncmp(*args, "port=", 5) == 0) {
			if (str_to_uint((*args) + 5, &temp_request.dest_port) < 0)
				i_error("auth sent invalid port field: %s", (*args) + 6);
		} else if (strncmp(*args, "destuser="******"director_tag=", 13) == 0)
			tag = *args + 13;
		else if (strncmp(*args, "director_proxy_maybe", 20) == 0 &&
			 ((*args)[20] == '=' || (*args)[20] == '\0'))
			temp_request.director_proxy_maybe = TRUE;
		else if (strncmp(*args, "user=", 5) == 0) {
			if (username == NULL)
				username = *args + 5;
		}
	}
	if ((!proxy && !temp_request.director_proxy_maybe) ||
	    host || username == NULL) {
		login_connection_send_line(conn, line);
		return;
	}
	if (*conn->dir->set->master_user_separator != '\0') {
		/* with master user logins we still want to use only the
		   login username */
		username = t_strcut(username,
				    *conn->dir->set->master_user_separator);
	}

	/* we need to add the host. the lookup might be asynchronous */
	request = i_new(struct login_host_request, 1);
	*request = temp_request;
	request->conn = conn;
	request->line = i_strdup(line);
	request->username = i_strdup(username);

	conn->refcount++;
	director_request(conn->dir, username, tag, login_host_callback, request);
}
static int proxy_start(struct client *client,
		       const struct client_auth_reply *reply)
{
	struct login_proxy_settings proxy_set;
	const struct dsasl_client_mech *sasl_mech = NULL;

	i_assert(reply->destuser != NULL);
	i_assert(!client->destroyed);
	i_assert(client->proxy_sasl_client == NULL);

	client->proxy_mech = NULL;
	client->v.proxy_reset(client);

	if (reply->password == NULL) {
		client_log_err(client, "proxy: password not given");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}
	if (reply->host == NULL || *reply->host == '\0') {
		client_log_err(client, "proxy: host not given");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	if (reply->proxy_mech != NULL) {
		sasl_mech = dsasl_client_mech_find(reply->proxy_mech);
		if (sasl_mech == NULL) {
			client_log_err(client, t_strdup_printf(
				"proxy: Unsupported SASL mechanism %s",
				reply->proxy_mech));
			client_proxy_error(client, PROXY_FAILURE_MSG);
			return -1;
		}
	} else if (reply->master_user != NULL) {
		/* have to use PLAIN authentication with master user logins */
		sasl_mech = &dsasl_client_mech_plain;
	}

	i_assert(client->refcount > 1);

	if (client->destroyed) {
		/* connection_queue_add() decided that we were the oldest
		   connection and killed us. */
		return -1;
	}
	if (login_proxy_is_ourself(client, reply->host, reply->port,
				   reply->destuser)) {
		client_log_err(client, "Proxying loops to itself");
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	memset(&proxy_set, 0, sizeof(proxy_set));
	proxy_set.host = reply->host;
	if (reply->hostip != NULL &&
	    net_addr2ip(reply->hostip, &proxy_set.ip) < 0)
		proxy_set.ip.family = 0;
	proxy_set.port = reply->port;
	proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
	if (proxy_set.connect_timeout_msecs == 0)
		proxy_set.connect_timeout_msecs = PROXY_DEFAULT_TIMEOUT_MSECS;
	proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
	proxy_set.ssl_flags = reply->ssl_flags;

	if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
		client_proxy_error(client, PROXY_FAILURE_MSG);
		return -1;
	}

	client->proxy_mech = sasl_mech;
	client->proxy_user = i_strdup(reply->destuser);
	client->proxy_master_user = i_strdup(reply->master_user);
	client->proxy_password = i_strdup(reply->password);
	client->proxy_nopipelining = reply->proxy_nopipelining;

	/* disable input until authentication is finished */
	if (client->io != NULL)
		io_remove(&client->io);
	return 0;
}
static int
imap_hibernate_client_parse_input(const char *const *args, pool_t pool,
				  struct imap_client_state *state_r,
				  const char **error_r)
{
	const char *key, *value;
	unsigned int peer_dev_major = 0, peer_dev_minor = 0;

	memset(state_r, 0, sizeof(*state_r));
	if (args[0] == NULL) {
		*error_r = "Missing username in input";
		return -1;
	}
	state_r->username = args[0]; args++;
	if (args[0] == NULL) {
		*error_r = "Missing mail_log_prefix in input";
		return -1;
	}
	state_r->mail_log_prefix = args[0]; args++;

	for (; *args != NULL; args++) {
		value = strchr(*args, '=');
		if (value != NULL)
			key = t_strdup_until(*args, value++);
		else {
			key = *args;
			value = "";
		}
		if (strcmp(key, "lip") == 0) {
			if (net_addr2ip(value, &state_r->local_ip) < 0) {
				*error_r = t_strdup_printf(
					"Invalid lip value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "rip") == 0) {
			if (net_addr2ip(value, &state_r->remote_ip) < 0) {
				*error_r = t_strdup_printf(
					"Invalid rip value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_dev_major") == 0) {
			if (str_to_uint(value, &peer_dev_major) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_dev_major value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_dev_minor") == 0) {
			if (str_to_uint(value, &peer_dev_minor) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_dev_minor value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "peer_ino") == 0) {
			if (str_to_ino(value, &state_r->peer_ino) < 0) {
				*error_r = t_strdup_printf(
					"Invalid peer_ino value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "uid") == 0) {
			if (str_to_uid(value, &state_r->uid) < 0) {
				*error_r = t_strdup_printf(
					"Invalid uid value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "gid") == 0) {
			if (str_to_gid(value, &state_r->gid) < 0) {
				*error_r = t_strdup_printf(
					"Invalid gid value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "stats") == 0) {
			state_r->stats = value;
		} else if (strcmp(key, "idle-cmd") == 0) {
			state_r->idle_cmd = TRUE;
		} else if (strcmp(key, "session") == 0) {
			state_r->session_id = value;
		} else if (strcmp(key, "userdb_fields") == 0) {
			state_r->userdb_fields = value;
		} else if (strcmp(key, "notify_fd") == 0) {
			state_r->have_notify_fd = TRUE;
		} else if (strcmp(key, "idle_notify_interval") == 0) {
			if (str_to_uint(value, &state_r->imap_idle_notify_interval) < 0) {
				*error_r = t_strdup_printf(
					"Invalid idle_notify_interval value: %s", value);
				return -1;
			}
		} else if (strcmp(key, "state") == 0) {
			buffer_t *state_buf;

			state_buf = buffer_create_dynamic(pool, 1024);
			if (base64_decode(value, strlen(value), NULL,
					  state_buf) < 0) {
				*error_r = t_strdup_printf(
					"Invalid state base64 value: %s", value);
				return -1;
			}
			state_r->state = state_buf->data;
			state_r->state_size = state_buf->used;
		}
	}
	if (peer_dev_major != 0 || peer_dev_minor != 0)
		state_r->peer_dev = makedev(peer_dev_major, peer_dev_minor);
	return 0;
}