Пример #1
0
struct mail_user *mail_user_alloc(const char *username,
				  const struct setting_parser_info *set_info,
				  const struct mail_user_settings *set)
{
	struct mail_user *user;
	const char *error;
	pool_t pool;

	i_assert(username != NULL);
	i_assert(*username != '\0');

	pool = pool_alloconly_create(MEMPOOL_GROWING"mail user", 16*1024);
	user = p_new(pool, struct mail_user, 1);
	user->pool = pool;
	user->refcount = 1;
	user->username = p_strdup(pool, username);
	user->set_info = set_info;
	user->unexpanded_set = settings_dup(set_info, set, pool);
	user->set = settings_dup(set_info, set, pool);
	user->service = master_service_get_name(master_service);
	user->default_normalizer = uni_utf8_to_decomposed_titlecase;

	/* check settings so that the duplicated structure will again
	   contain the parsed fields */
	if (!settings_check(set_info, pool, user->set, &error))
		i_panic("Settings check unexpectedly failed: %s", error);

	user->v.deinit = mail_user_deinit_base;
	user->v.stats_fill = mail_user_stats_fill_base;
	p_array_init(&user->module_contexts, user->pool, 5);
	return user;
}
Пример #2
0
static int
mail_storage_service_load_modules(struct mail_storage_service_ctx *ctx,
				  const struct setting_parser_info *user_info,
				  const struct mail_user_settings *user_set,
				  const char **error_r)
{
	struct module_dir_load_settings mod_set;

	if (*user_set->mail_plugins == '\0')
		return 0;
	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_PLUGINS) != 0)
		return 0;

	memset(&mod_set, 0, sizeof(mod_set));
	mod_set.abi_version = DOVECOT_ABI_VERSION;
	mod_set.binary_name = master_service_get_name(ctx->service);
	mod_set.setting_name = "mail_plugins";
	mod_set.require_init_funcs = TRUE;
	mod_set.debug = mail_user_set_get_mail_debug(user_info, user_set);

	return module_dir_try_load_missing(&mail_storage_service_modules,
					   user_set->mail_plugin_dir,
					   user_set->mail_plugins,
					   &mod_set, error_r);
}
Пример #3
0
int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
				const struct mail_storage_service_input *input,
				struct mail_storage_service_user **user_r,
				const char **error_r)
{
	char *old_log_prefix = i_strdup(i_get_failure_prefix());
	bool update_log_prefix;
	int ret;

	if (io_loop_get_current_context(current_ioloop) == NULL) {
		/* no user yet. log prefix should be just "imap:" or something
		   equally unhelpful. we don't know the proper log format yet,
		   but initialize it to something better until we know it. */
		const char *session_id =
			input->session_id != NULL ? input->session_id :
			(input->session_id_prefix != NULL ?
			 input->session_id_prefix : NULL);
		i_set_failure_prefix("%s(%s%s,%s)",
			master_service_get_name(ctx->service), input->username,
			session_id == NULL ? "" : t_strdup_printf(",%s", session_id),
			input->remote_ip.family == 0 ? "" :
				t_strdup_printf(",%s", net_ip2addr(&input->remote_ip)));
		update_log_prefix = TRUE;
	} else {
		/* we might be here because we're doing a user lookup for a
		   shared user. the log prefix is likely already usable, so
		   just append our own without replacing the whole thing. */
		i_set_failure_prefix("%suser-lookup(%s)",
				     old_log_prefix, input->username);
		update_log_prefix = FALSE;
	}

	ret = mail_storage_service_lookup_real(ctx, input, update_log_prefix,
					       user_r, error_r);
	i_set_failure_prefix("%s", old_log_prefix);
	i_free(old_log_prefix);
	return ret;
}
Пример #4
0
static bool client_proxy_rcpt(struct client *client, const char *address,
			      const char *username, const char *detail)
{
	struct auth_master_connection *auth_conn;
	struct lmtp_proxy_rcpt_settings set;
	struct auth_user_info info;
	struct mail_storage_service_input input;
	const char *args, *const *fields, *errstr, *orig_username = username;
	pool_t pool;
	int ret;

	memset(&input, 0, sizeof(input));
	input.module = input.service = "lmtp";
	mail_storage_service_init_settings(storage_service, &input);

	memset(&info, 0, sizeof(info));
	info.service = master_service_get_name(master_service);
	info.local_ip = client->local_ip;
	info.remote_ip = client->remote_ip;
	info.local_port = client->local_port;
	info.remote_port = client->remote_port;

	pool = pool_alloconly_create("auth lookup", 1024);
	auth_conn = mail_storage_service_get_auth_conn(storage_service);
	ret = auth_master_pass_lookup(auth_conn, username, &info,
				      pool, &fields);
	if (ret <= 0) {
		errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
			t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address);
		pool_unref(&pool);
		if (ret < 0) {
			client_send_line(client, "%s", errstr);
			return TRUE;
		} else {
			/* user not found from passdb. try userdb also. */
			return FALSE;
		}
	}

	memset(&set, 0, sizeof(set));
	set.port = client->local_port;
	set.protocol = LMTP_CLIENT_PROTOCOL_LMTP;
	set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;

	if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
		/* not proxying this user */
		pool_unref(&pool);
		return FALSE;
	}
	if (strcmp(username, orig_username) != 0) {
		/* username changed. change the address as well */
		if (*detail == '\0')
			address = username;
		else
			address = address_add_detail(client, username, detail);
	} else if (client_proxy_is_ourself(client, &set)) {
		i_error("Proxying to <%s> loops to itself", username);
		client_send_line(client, "554 5.4.6 <%s> "
				 "Proxying loops to itself", address);
		pool_unref(&pool);
		return TRUE;
	}

	if (client->proxy_ttl <= 1) {
		i_error("Proxying to <%s> appears to be looping (TTL=0)",
			username);
		client_send_line(client, "554 5.4.6 <%s> "
				 "Proxying appears to be looping (TTL=0)",
				 username);
		pool_unref(&pool);
		return TRUE;
	}
	if (array_count(&client->state.rcpt_to) != 0) {
		client_send_line(client, "451 4.3.0 <%s> "
			"Can't handle mixed proxy/non-proxy destinations",
			address);
		pool_unref(&pool);
		return TRUE;
	}
	if (client->proxy == NULL) {
		struct lmtp_proxy_settings proxy_set;

		memset(&proxy_set, 0, sizeof(proxy_set));
		proxy_set.my_hostname = client->my_domain;
		proxy_set.dns_client_socket_path = dns_client_socket_path;
		proxy_set.session_id = client->state.session_id;
		proxy_set.source_ip = client->remote_ip;
		proxy_set.source_port = client->remote_port;
		proxy_set.proxy_ttl = client->proxy_ttl-1;

		client->proxy = lmtp_proxy_init(&proxy_set, client->output);
		if (client->state.mail_body_8bitmime)
			args = " BODY=8BITMIME";
		else if (client->state.mail_body_7bit)
			args = " BODY=7BIT";
		else
			args = "";
		lmtp_proxy_mail_from(client->proxy, t_strdup_printf(
			"<%s>%s", client->state.mail_from, args));
	}
	if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
		client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
	else
		client_send_line(client, "250 2.1.5 OK");
	pool_unref(&pool);
	return TRUE;
}
Пример #5
0
int cmd_rcpt(struct client *client, const char *args)
{
	struct mail_recipient *rcpt;
	struct mail_storage_service_input input;
	const char *params, *address, *username, *detail, *prefix;
	const char *const *argv;
	const char *error = NULL;
	char delim = '\0';
	int ret = 0;

	if (client->state.mail_from == NULL) {
		client_send_line(client, "503 5.5.1 MAIL needed first");
		return 0;
	}

	if (strncasecmp(args, "TO:", 3) != 0 ||
	    parse_address(args + 3, &address, &params) < 0) {
		client_send_line(client, "501 5.5.4 Invalid parameters");
		return 0;
	}

	rcpt = p_new(client->state_pool, struct mail_recipient, 1);
	rcpt->client = client;
	address = lmtp_unescape_address(address);

	argv = t_strsplit(params, " ");
	for (; *argv != NULL; argv++) {
		if (strncasecmp(*argv, "ORCPT=", 6) == 0) {
			rcpt->params.dsn_orcpt = parse_xtext(client, *argv + 6);
		} else {
			client_send_line(client, "501 5.5.4 Unsupported options");
			return 0;
		}
	}
	rcpt_address_parse(client, address, &username, &delim, &detail);

	client_state_set(client, "RCPT TO", address);

	if (client->lmtp_set->lmtp_proxy) {
		if (client_proxy_rcpt(client, address, username, detail, delim,
				      &rcpt->params))
			return 0;
	}

	/* Use a unique session_id for each mail delivery. This is especially
	   important for stats process to not see duplicate sessions. */
	if (array_count(&client->state.rcpt_to) == 0)
		rcpt->session_id = client->state.session_id;
	else {
		rcpt->session_id =
			p_strdup_printf(client->state_pool, "%s:%u",
					client->state.session_id,
					array_count(&client->state.rcpt_to)+1);
	}

	memset(&input, 0, sizeof(input));
	input.module = input.service = "lmtp";
	input.username = username;
	input.local_ip = client->local_ip;
	input.remote_ip = client->remote_ip;
	input.local_port = client->local_port;
	input.remote_port = client->remote_port;
	input.session_id = rcpt->session_id;

	ret = mail_storage_service_lookup(storage_service, &input,
					  &rcpt->service_user, &error);

	if (ret < 0) {
		prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
					 username);
		client_send_line(client, "%s%s", prefix, error);
		return 0;
	}
	if (ret == 0) {
		client_send_line(client,
				 "550 5.1.1 <%s> User doesn't exist: %s",
				 address, username);
		return 0;
	}
	if (client->proxy != NULL) {
		/* NOTE: if this restriction is ever removed, we'll also need
		   to send different message bodies to local and proxy
		   (with and without Return-Path: header) */
		client_send_line(client, "451 4.3.0 <%s> "
			"Can't handle mixed proxy/non-proxy destinations",
			address);
		mail_storage_service_user_free(&rcpt->service_user);
		return 0;
	}

	lmtp_address_translate(client, &address);

	rcpt->address = p_strdup(client->state_pool, address);
	rcpt->detail = p_strdup(client->state_pool, detail);
	if ((ret = lmtp_rcpt_to_is_over_quota(client, rcpt)) != 0) {
		if (ret < 0) {
			client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
					 rcpt->address);
		}
		mail_storage_service_user_free(&rcpt->service_user);
		return 0;
	}
	array_append(&client->state.rcpt_to, &rcpt, 1);
	client_send_line(client, "250 2.1.5 OK");

	if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
		const char *query = t_strconcat("LOOKUP\t",
			master_service_get_name(master_service),
			"/", str_tabescape(username), NULL);
		client->state.anvil_queries++;
		rcpt->anvil_query = anvil_client_query(anvil, query,
					rcpt_anvil_lookup_callback, rcpt);
	}
	return 0;
}