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; }
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); }
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; }
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; }
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, ¶ms) < 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; }