From: Stephan Bosch Date: Sat, 5 Nov 2016 13:47:53 +0000 (+0100) Subject: lib-lda: Changed struct mail_deliver_context address fields to use the new struct... X-Git-Tag: 2.3.0.rc1~370 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d7828efd92ecc0d08049f727d9be0154d1d681b;p=thirdparty%2Fdovecot%2Fcore.git lib-lda: Changed struct mail_deliver_context address fields to use the new struct smtp_address type. --- diff --git a/src/lda/Makefile.am b/src/lda/Makefile.am index a066417ea4..eb1807972b 100644 --- a/src/lda/Makefile.am +++ b/src/lda/Makefile.am @@ -10,6 +10,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-master \ + -I$(top_srcdir)/src/lib-smtp \ -I$(top_srcdir)/src/lib-lda \ -I$(top_srcdir)/src/lib-storage \ -I$(top_srcdir)/src/lib-storage/index \ diff --git a/src/lda/main.c b/src/lda/main.c index ad8ab45e11..77f8924606 100644 --- a/src/lda/main.c +++ b/src/lda/main.c @@ -16,6 +16,7 @@ #include "unichar.h" #include "rfc822-parser.h" #include "message-address.h" +#include "smtp-address.h" #include "settings-parser.h" #include "master-service.h" #include "master-service-settings.h" @@ -31,7 +32,8 @@ #include #include -#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" +#define DEFAULT_ENVELOPE_SENDER \ + SMTP_ADDRESS_LITERAL("MAILER-DAEMON", NULL) /* After buffer grows larger than this, create a temporary file to /tmp where to read the mail. */ @@ -42,46 +44,6 @@ static const char *wanted_headers[] = { NULL }; -static const char *escape_local_part(const char *local_part) -{ - const char *p; - - /* if local_part isn't dot-atom-text, we need to return quoted-string - dot-atom-text = 1*atext *("." 1*atext) */ - for (p = local_part; *p != '\0'; p++) { - if (!IS_ATEXT(*p) && *p != '.') - break; - } - if (*p != '\0' || *local_part == '.' || - (p != local_part && p[-1] == '.')) - local_part = t_strdup_printf("\"%s\"", str_escape(local_part)); - return local_part; -} - -static const char *address_sanitize(const char *address) -{ - struct message_address *addr; - const char *ret, *mailbox; - pool_t pool; - - pool = pool_alloconly_create("address sanitizer", 256); - addr = message_address_parse(pool, (const unsigned char *)address, - strlen(address), 1, FALSE); - - if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL || - *addr->mailbox == '\0') - ret = DEFAULT_ENVELOPE_SENDER; - else { - mailbox = escape_local_part(addr->mailbox); - if (*addr->domain == '\0') - ret = t_strdup(mailbox); - else - ret = t_strdup_printf("%s@%s", mailbox, addr->domain); - } - pool_unref(&pool); - return ret; -} - static int seekable_fd_callback(const char **path_r, void *context) { struct mail_deliver_context *ctx = context; @@ -113,6 +75,7 @@ create_raw_stream(struct mail_deliver_context *ctx, { struct istream *input, *input2, *input_list[2]; const unsigned char *data; + const char *error; char *sender = NULL; size_t i, size; int ret, tz; @@ -143,9 +106,15 @@ create_raw_stream(struct mail_deliver_context *ctx, } if (sender != NULL && ctx->mail_from == NULL) { + struct smtp_address *mail_from = NULL; /* use the envelope sender from From_-line, but only if it hasn't been specified with -f already. */ - ctx->mail_from = p_strdup(ctx->pool, sender); + if (smtp_address_parse_mailbox(ctx->pool, + sender, 0, &mail_from, &error) < 0) { + i_warning("Failed to parse address from `From_'-line: %s", + error); + } + ctx->mail_from = mail_from; } i_free(sender); @@ -172,9 +141,9 @@ lda_raw_mail_open(struct mail_deliver_context *ctx, const char *path) struct mailbox_transaction_context *t; struct mail *mail; struct mailbox_header_lookup_ctx *headers_ctx; + const struct smtp_address *mail_from; struct istream *input; void **sets; - const char *mail_from; time_t mtime; int ret; @@ -188,11 +157,11 @@ lda_raw_mail_open(struct mail_deliver_context *ctx, const char *path) input = create_raw_stream(ctx, 0, &mtime); i_stream_set_name(input, "stdin"); ret = raw_mailbox_alloc_stream(raw_mail_user, input, mtime, - mail_from, &box); + smtp_address_encode(mail_from), &box); i_stream_unref(&input); } else { ret = raw_mailbox_alloc_path(raw_mail_user, path, (time_t)-1, - mail_from, &box); + smtp_address_encode(mail_from), &box); } if (ret < 0) { i_fatal("Can't open delivery mail as raw: %s", @@ -209,27 +178,41 @@ lda_raw_mail_open(struct mail_deliver_context *ctx, const char *path) } static void -lda_set_rcpt_orig_to(struct mail_deliver_context *ctx, const char *user, - const char *rcpt_to_source) +lda_set_rcpt_to(struct mail_deliver_context *ctx, + const struct smtp_address *rcpt_to, const char *user, + const char *rcpt_to_source) { - if (ctx->rcpt_orig_to == NULL && + const char *error; + + if (rcpt_to == NULL && *ctx->set->lda_original_recipient_header != '\0') { - ctx->rcpt_orig_to = mail_deliver_get_address(ctx->src_mail, + rcpt_to = mail_deliver_get_address(ctx->src_mail, ctx->set->lda_original_recipient_header); rcpt_to_source = t_strconcat( ctx->set->lda_original_recipient_header, " header", NULL); } - if (ctx->rcpt_orig_to == NULL) { - ctx->rcpt_orig_to = strchr(user, '@') != NULL ? user : - t_strconcat(user, "@", ctx->set->hostname, NULL); + if (rcpt_to == NULL) { + struct smtp_address *user_addr; + + if (smtp_address_parse_username(ctx->pool, user, + &user_addr, &error) < 0) { + i_fatal_status(EX_USAGE, + "Cannot obtain SMTP address from username `%s': %s", + user, error); + } + if (user_addr->domain == NULL) + user_addr->domain = ctx->set->hostname; + rcpt_to = user_addr; rcpt_to_source = "user@hostname"; } + + ctx->rcpt_orig_to = rcpt_to; if (ctx->rcpt_to == NULL) - ctx->rcpt_to = ctx->rcpt_orig_to; + ctx->rcpt_to = rcpt_to; if (ctx->rcpt_user->mail_debug) { i_debug("Destination address: %s (source: %s)", - ctx->rcpt_orig_to, rcpt_to_source); + smtp_address_encode_path(rcpt_to), rcpt_to_source); } } @@ -277,6 +260,7 @@ int main(int argc, char *argv[]) const char *user, *errstr, *path; struct lda_settings *lda_set; struct smtp_submit_settings *smtp_set; + struct smtp_address *rcpt_to, *final_rcpt_to, *mail_from; struct mail_storage_service_ctx *storage_service; struct mail_storage_service_user *service_user; struct mail_storage_service_input service_input; @@ -321,11 +305,18 @@ int main(int argc, char *argv[]) path = NULL; user = getenv("USER"); + mail_from = final_rcpt_to = rcpt_to = NULL; while ((c = master_getopt(master_service)) > 0) { switch (c) { case 'a': /* original recipient address */ - ctx.rcpt_orig_to = optarg; + if (smtp_address_parse_path(ctx.pool, optarg, + SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART | + SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL, + &rcpt_to, &errstr) < 0) { + i_fatal_status(EX_USAGE, + "Invalid -a parameter: %s", errstr); + } rcpt_to_source = "-a parameter"; break; case 'd': @@ -338,8 +329,12 @@ int main(int argc, char *argv[]) break; case 'f': /* envelope sender address */ - ctx.mail_from = - p_strdup(ctx.pool, address_sanitize(optarg)); + if (smtp_address_parse_path(ctx.pool, optarg, + SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL, + &mail_from, &errstr) < 0) { + i_fatal_status(EX_USAGE, + "Invalid -f parameter: %s", errstr); + } break; case 'm': /* destination mailbox. @@ -362,7 +357,13 @@ int main(int argc, char *argv[]) break; case 'r': /* final recipient address */ - ctx.rcpt_to = optarg; + if (smtp_address_parse_path(ctx.pool, optarg, + SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART | + SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL, + &final_rcpt_to, &errstr) < 0) { + i_fatal_status(EX_USAGE, + "Invalid -a parameter: %s", errstr); + } break; default: print_help(); @@ -453,8 +454,13 @@ int main(int argc, char *argv[]) user_source); } + if (mail_from == NULL) + mail_from = DEFAULT_ENVELOPE_SENDER; + ctx.src_mail = lda_raw_mail_open(&ctx, path); - lda_set_rcpt_orig_to(&ctx, user, rcpt_to_source); + ctx.mail_from = mail_from; + ctx.rcpt_to = final_rcpt_to; + lda_set_rcpt_to(&ctx, rcpt_to, user, rcpt_to_source); if (mail_deliver(&ctx, &storage) < 0) { if (ctx.tempfail_error != NULL) { diff --git a/src/lib-lda/Makefile.am b/src/lib-lda/Makefile.am index 0536080434..25251fc783 100644 --- a/src/lib-lda/Makefile.am +++ b/src/lib-lda/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-smtp \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-imap \ + -I$(top_srcdir)/src/lib-smtp \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-storage diff --git a/src/lib-lda/mail-deliver.c b/src/lib-lda/mail-deliver.c index 734a41403d..d864f89102 100644 --- a/src/lib-lda/mail-deliver.c +++ b/src/lib-lda/mail-deliver.c @@ -9,6 +9,7 @@ #include "unichar.h" #include "var-expand.h" #include "message-address.h" +#include "smtp-address.h" #include "lda-settings.h" #include "mail-storage.h" #include "mail-namespace.h" @@ -64,7 +65,8 @@ static MODULE_CONTEXT_DEFINE_INIT(mail_deliver_user_module, static MODULE_CONTEXT_DEFINE_INIT(mail_deliver_storage_module, &mail_storage_module_register); -const char *mail_deliver_get_address(struct mail *mail, const char *header) +const struct smtp_address * +mail_deliver_get_address(struct mail *mail, const char *header) { struct message_address *addr; const char *str; @@ -76,7 +78,7 @@ const char *mail_deliver_get_address(struct mail *mail, const char *header) strlen(str), 1, FALSE); return addr == NULL || addr->mailbox == NULL || addr->domain == NULL || *addr->mailbox == '\0' || *addr->domain == '\0' ? - NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL); + NULL : smtp_address_create_from_msg_temp(addr); } static void update_cache(pool_t pool, const char **old_str, const char *new_str) @@ -106,7 +108,7 @@ mail_deliver_log_update_cache(struct mail_deliver_cache *cache, pool_t pool, subject = str_sanitize(subject, 80); update_cache(pool, &cache->subject, subject); - from = str_sanitize(mail_deliver_get_address(mail, "From"), 80); + from = smtp_address_encode(mail_deliver_get_address(mail, "From")); update_cache(pool, &cache->from, from); if (mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE, &from_envelope) > 0) @@ -149,7 +151,7 @@ mail_deliver_ctx_get_log_var_expand_table(struct mail_deliver_context *ctx, { 'w', dec2str(ctx->cache->vsize), "vsize" }, { '\0', dec2str(delivery_time_msecs), "delivery_time" }, { '\0', dec2str(ctx->session_time_msecs), "session_time" }, - { '\0', ctx->rcpt_orig_to, "to_envelope" }, + { '\0', smtp_address_encode(ctx->rcpt_orig_to), "to_envelope" }, { '\0', ctx->cache->storage_id, "storage_id" }, { '\0', NULL, NULL } }; @@ -346,8 +348,10 @@ int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, kw = str_array_length(keywords) == 0 ? NULL : mailbox_keywords_create_valid(box, keywords); save_ctx = mailbox_save_alloc(t); - if (ctx->mail_from != NULL) - mailbox_save_set_from_envelope(save_ctx, ctx->mail_from); + if (ctx->mail_from != NULL) { + mailbox_save_set_from_envelope(save_ctx, + smtp_address_encode(ctx->mail_from)); + } mailbox_save_set_flags(save_ctx, flags, kw); headers_ctx = mailbox_header_lookup_init(box, lda_log_wanted_headers); @@ -398,12 +402,32 @@ int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, return ret; } -const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx) +const struct smtp_address * +mail_deliver_get_return_address(struct mail_deliver_context *ctx) { + struct smtp_address *address; + const char *path, *error; + int ret; + if (ctx->mail_from != NULL) return ctx->mail_from; - return mail_deliver_get_address(ctx->src_mail, "Return-Path"); + if ((ret=mail_get_first_header(ctx->src_mail, + "Return-Path", &path)) <= 0) { + if (ret < 0) { + struct mailbox *box = ctx->src_mail->box; + i_warning("Failed read return-path header: %s", + mailbox_get_last_internal_error(box, NULL)); + } + return NULL; + } + if (smtp_address_parse_path(ctx->pool, path, + SMTP_ADDRESS_PARSE_FLAG_BRACKETS_OPTIONAL, + &address, &error) < 0) { + i_warning("Failed to parse return-path header: %s", error); + return NULL; + } + return address; } const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx) diff --git a/src/lib-lda/mail-deliver.h b/src/lib-lda/mail-deliver.h index 299b3aea43..ddb4f04ba8 100644 --- a/src/lib-lda/mail-deliver.h +++ b/src/lib-lda/mail-deliver.h @@ -7,6 +7,7 @@ #include +struct smtp_address; struct mail_storage; struct mail_save_context; struct mailbox; @@ -35,12 +36,12 @@ struct mail_deliver_context { struct mail *src_mail; /* Envelope sender, if known. */ - const char *mail_from; + const struct smtp_address *mail_from; /* Envelope recipient (final recipient) */ - const char *rcpt_to; + const struct smtp_address *rcpt_to; /* Envelope recipient (original recipient) */ - const char *rcpt_orig_to; + const struct smtp_address *rcpt_orig_to; /* Destination user */ struct mail_user *rcpt_user; /* Mailbox where mail should be saved, unless e.g. Sieve does @@ -85,8 +86,10 @@ mail_deliver_ctx_get_log_var_expand_table(struct mail_deliver_context *ctx, void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) ATTR_FORMAT(2, 3); -const char *mail_deliver_get_address(struct mail *mail, const char *header); -const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx); +const struct smtp_address * +mail_deliver_get_address(struct mail *mail, const char *header); +const struct smtp_address * +mail_deliver_get_return_address(struct mail_deliver_context *ctx); const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx); struct mail_deliver_session *mail_deliver_session_init(void); diff --git a/src/lib-lda/mail-send.c b/src/lib-lda/mail-send.c index 9cd427db45..e53e8718e3 100644 --- a/src/lib-lda/mail-send.c +++ b/src/lib-lda/mail-send.c @@ -16,6 +16,7 @@ #include "mail-storage-settings.h" #include "lda-settings.h" #include "mail-deliver.h" +#include "smtp-address.h" #include "smtp-submit.h" #include "mail-send.h" @@ -53,8 +54,8 @@ int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, struct istream *input; struct smtp_submit *smtp_submit; struct ostream *output; - const char *return_addr, *hdr; - const char *value, *msgid, *orig_msgid, *boundary, *error; + const struct smtp_address *return_addr; + const char *hdr, *value, *msgid, *orig_msgid, *boundary, *error; const struct var_expand_table *vtable; string_t *str; int ret; @@ -71,7 +72,7 @@ int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, } return_addr = mail_deliver_get_return_address(ctx); - if (return_addr == NULL) { + if (smtp_address_isnull(return_addr)) { i_info("msgid=%s: Return-Path missing, rejection reason: %s", orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80), str_sanitize(reason, 512)); @@ -80,13 +81,14 @@ int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, if (mailbox_get_settings(mail->box)->mail_debug) { i_debug("Sending a rejection to %s: %s", - return_addr, str_sanitize(reason, 512)); + smtp_address_encode(return_addr), + str_sanitize(reason, 512)); } vtable = get_var_expand_table(mail, reason, recipient); smtp_submit = smtp_submit_init_simple(ctx->smtp_set, NULL); - smtp_submit_add_rcpt(smtp_submit, return_addr); + smtp_submit_add_rcpt(smtp_submit, smtp_address_encode(return_addr)); output = smtp_submit_send(smtp_submit); msgid = mail_deliver_get_new_message_id(ctx); @@ -98,7 +100,7 @@ int mail_send_rejection(struct mail_deliver_context *ctx, const char *recipient, str_append(str, "From: "); message_address_write(str, mail_set->parsed_postmaster_address); str_append(str, "\r\n"); - str_printfa(str, "To: <%s>\r\n", return_addr); + str_printfa(str, "To: <%s>\r\n", smtp_address_encode(return_addr)); str_append(str, "MIME-Version: 1.0\r\n"); str_printfa(str, "Content-Type: " "multipart/report; report-type=%s;\r\n" diff --git a/src/lmtp/client.h b/src/lmtp/client.h index 856a7d468c..dac1aa59d7 100644 --- a/src/lmtp/client.h +++ b/src/lmtp/client.h @@ -10,7 +10,7 @@ struct mail_recipient { struct client *client; const char *session_id; - const char *address; + struct smtp_address *address; const char *detail; /* +detail part is also in address */ struct lmtp_recipient_params params; @@ -22,7 +22,7 @@ struct mail_recipient { struct client_state { const char *name; const char *session_id; - const char *mail_from; + struct smtp_address *mail_from; ARRAY(struct mail_recipient *) rcpt_to; unsigned int rcpt_idx; diff --git a/src/lmtp/commands.c b/src/lmtp/commands.c index 4f14605428..ef7d8706a4 100644 --- a/src/lmtp/commands.c +++ b/src/lmtp/commands.c @@ -21,7 +21,9 @@ #include "master-service-ssl.h" #include "iostream-ssl.h" #include "rfc822-parser.h" +#include "smtp-address.h" #include "message-date.h" +#include "message-address.h" #include "auth-master.h" #include "mail-storage-service.h" #include "index/raw/raw-storage.h" @@ -119,40 +121,6 @@ int cmd_starttls(struct client *client) return 0; } -static int parse_address(const char *str, const char **address_r, - const char **rest_r) -{ - const char *start; - - if (*str++ != '<') - return -1; - start = str; - if (*str == '"') { - /* "quoted-string"@domain */ - for (str++; *str != '"'; str++) { - if (*str == '\\') - str++; - if (*str == '\0') - return -1; - } - str++; - } - for (; *str != '>'; str++) { - if (*str == '\0' || *str == ' ') - return -1; - } - *address_r = t_strdup_until(start, str); - if (*str++ != '>') - return -1; - - if (*str == ' ') - str++; - else if (*str != '\0') - return -1; - *rest_r = str; - return 0; -} - static const char * parse_xtext(struct client *client, const char *value) { @@ -190,18 +158,32 @@ static void lmtp_anvil_init(void) int cmd_mail(struct client *client, const char *args) { - const char *addr, *const *argv; + struct smtp_address *address; + const char *const *argv; + const char *error; if (client->state.mail_from != NULL) { client_send_line(client, "503 5.5.1 MAIL already given"); return 0; } - if (strncasecmp(args, "FROM:", 5) != 0 || - parse_address(args + 5, &addr, &args) < 0) { + if (strncasecmp(args, "FROM:", 5) != 0) { client_send_line(client, "501 5.5.4 Invalid parameters"); return 0; } + if (smtp_address_parse_path_full(pool_datastack_create(), args + 5, + SMTP_ADDRESS_PARSE_FLAG_ALLOW_EMPTY, + &address, &error, &args) < 0) { + client_send_line(client, "501 5.5.4 Invalid FROM: %s", error); + return 0; + } + if (*args == ' ') + args++; + else if (*args != '\0') { + client_send_line(client, "501 5.5.4 Invalid FROM: " + "Invalid character in path"); + return 0; + } argv = t_strsplit(args, " "); for (; *argv != NULL; argv++) { @@ -216,10 +198,12 @@ int cmd_mail(struct client *client, const char *args) } } - client->state.mail_from = p_strdup(client->state_pool, addr); + client->state.mail_from = + smtp_address_clone(client->state_pool, address); p_array_init(&client->state.rcpt_to, client->state_pool, 64); client_send_line(client, "250 2.1.0 OK"); - client_state_set(client, "MAIL FROM", client->state.mail_from); + client_state_set(client, "MAIL FROM", + smtp_address_encode(address)); if (client->lmtp_set->lmtp_user_concurrency_limit > 0) { /* connect to anvil before dropping privileges */ @@ -316,23 +300,8 @@ client_proxy_is_ourself(const struct client *client, return TRUE; } -static const char * -address_add_detail(const char *username, char delim_c, - const char *detail) -{ - const char *domain; - const char delim[] = {delim_c, '\0'}; - - domain = strchr(username, '@'); - if (domain == NULL) - return t_strconcat(username, delim, detail, NULL); - else { - username = t_strdup_until(username, domain); - return t_strconcat(username, delim, detail, domain, NULL); - } -} - -static bool client_proxy_rcpt(struct client *client, const char *address, +static bool client_proxy_rcpt(struct client *client, + struct smtp_address *address, const char *username, const char *detail, char delim, const struct lmtp_recipient_params *params) { @@ -341,6 +310,7 @@ static bool client_proxy_rcpt(struct client *client, const char *address, struct auth_user_info info; struct mail_storage_service_input input; const char *args, *const *fields, *errstr, *orig_username = username; + struct smtp_address *user; pool_t pool; int ret; @@ -361,7 +331,8 @@ static bool client_proxy_rcpt(struct client *client, const char *address, pool, &fields); if (ret <= 0) { errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) : - t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address); + t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, + smtp_address_encode(address)); pool_unref(&pool); if (ret < 0) { client_send_line(client, "%s", errstr); @@ -384,15 +355,27 @@ static bool client_proxy_rcpt(struct client *client, const char *address, return FALSE; } if (strcmp(username, orig_username) != 0) { + if (smtp_address_parse_username(pool_datastack_create(), + username, &user, &errstr) < 0) { + i_error("%s: Username `%s' returned by passdb lookup is not a valid SMTP address", + orig_username, username); + client_send_line(client, "550 5.3.5 <%s> " + "Internal user lookup failure", + smtp_address_encode(address)); + pool_unref(&pool); + return FALSE; + } /* username changed. change the address as well */ - if (*detail == '\0') - address = username; - else - address = address_add_detail(username, delim, detail); + if (*detail == '\0') { + address = user; + } else { + address = smtp_address_add_detail_temp(user, detail, delim); + } } 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); + "Proxying loops to itself", + smtp_address_encode(address)); pool_unref(&pool); return TRUE; } @@ -409,7 +392,7 @@ static bool client_proxy_rcpt(struct client *client, const char *address, 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); + smtp_address_encode(address)); pool_unref(&pool); return TRUE; } @@ -431,10 +414,12 @@ static bool client_proxy_rcpt(struct client *client, const char *address, args = " BODY=7BIT"; else args = ""; - lmtp_proxy_mail_from(client->proxy, t_strdup_printf( - "<%s>%s", client->state.mail_from, args)); + lmtp_proxy_mail_from(client->proxy, + t_strdup_printf("<%s>%s", + smtp_address_encode(client->state.mail_from), args)); } - if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0) + if (lmtp_proxy_add_rcpt(client->proxy, + smtp_address_encode(address), &set) < 0) client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE); else client_send_line(client, "250 2.1.5 OK"); @@ -442,39 +427,6 @@ static bool client_proxy_rcpt(struct client *client, const char *address, return TRUE; } -static const char *lmtp_unescape_address(const char *name) -{ - string_t *str; - const char *p; - - if (*name != '"') - return name; - - /* quoted-string local-part. drop the quotes unless there's a - '@' character inside or there's an error. */ - str = t_str_new(128); - for (p = name+1; *p != '"'; p++) { - if (*p == '\0') - return name; - if (*p == '\\') { - if (p[1] == '\0') { - /* error */ - return name; - } - p++; - } - if (*p == '@') - return name; - str_append_c(str, *p); - } - p++; - if (*p != '@' && *p != '\0') - return name; - - str_append(str, p); - return str_c(str); -} - static void client_send_line_overquota(struct client *client, const struct mail_recipient *rcpt, const char *error) @@ -482,8 +434,9 @@ client_send_line_overquota(struct client *client, struct lda_settings *lda_set = mail_storage_service_user_get_set(rcpt->service_user)[2]; - client_send_line(client, "%s <%s> %s", lda_set->quota_full_tempfail ? - "452 4.2.2" : "552 5.2.2", rcpt->address, error); + client_send_line(client, "%s <%s> %s", + lda_set->quota_full_tempfail ? "452 4.2.2" : "552 5.2.2", + smtp_address_encode(rcpt->address), error); } static int @@ -514,7 +467,8 @@ lmtp_rcpt_to_is_over_quota(struct client *client, &user, &errstr); if (ret < 0) { - i_error("Failed to initialize user %s: %s", rcpt->address, errstr); + i_error("Failed to initialize user %s: %s", + smtp_address_encode(rcpt->address), errstr); return -1; } @@ -546,7 +500,7 @@ static bool cmd_rcpt_finish(struct client *client, struct mail_recipient *rcpt) if ((ret = lmtp_rcpt_to_is_over_quota(client, rcpt)) != 0) { if (ret < 0) { client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - rcpt->address); + smtp_address_encode(rcpt->address)); } mail_storage_service_user_unref(&rcpt->service_user); return FALSE; @@ -573,7 +527,7 @@ static void rcpt_anvil_lookup_callback(const char *reply, void *context) if (parallel_count >= client->lmtp_set->lmtp_user_concurrency_limit) { client_send_line(client, ERRSTR_TEMP_USERDB_FAIL_PREFIX "Too many concurrent deliveries for user", - rcpt->address); + smtp_address_encode(rcpt->address)); mail_storage_service_user_unref(&rcpt->service_user); } else if (cmd_rcpt_finish(client, rcpt)) { rcpt->anvil_connect_sent = TRUE; @@ -591,7 +545,8 @@ 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; + struct smtp_address *address; + const char *username, *detail; const char *const *argv; const char *error = NULL; char delim = '\0'; @@ -602,17 +557,28 @@ int cmd_rcpt(struct client *client, const char *args) return 0; } - if (strncasecmp(args, "TO:", 3) != 0 || - parse_address(args + 3, &address, ¶ms) < 0) { + if (strncasecmp(args, "TO:", 3) != 0) { client_send_line(client, "501 5.5.4 Invalid parameters"); return 0; } + if (smtp_address_parse_path_full(pool_datastack_create(), args + 3, + SMTP_ADDRESS_PARSE_FLAG_ALLOW_LOCALPART, + &address, &error, &args) < 0) { + client_send_line(client, "501 5.5.4 Invalid TO: %s", error); + return 0; + } + if (*args == ' ') + args++; + else if (*args != '\0') { + client_send_line(client, "501 5.5.4 Invalid TO: " + "Invalid character in path"); + return 0; + } rcpt = p_new(client->state_pool, struct mail_recipient, 1); rcpt->client = client; - address = lmtp_unescape_address(address); - argv = t_strsplit(params, " "); + argv = t_strsplit(args, " "); for (; *argv != NULL; argv++) { if (strncasecmp(*argv, "ORCPT=", 6) == 0) { rcpt->params.dsn_orcpt = parse_xtext(client, *argv + 6); @@ -621,10 +587,13 @@ int cmd_rcpt(struct client *client, const char *args) return 0; } } - message_detail_address_parse(client->unexpanded_lda_set->recipient_delimiter, - address, &username, &delim, &detail); - client_state_set(client, "RCPT TO", address); + smtp_address_detail_parse_temp( + client->unexpanded_lda_set->recipient_delimiter, + address, &username, &delim, &detail); + + client_state_set(client, "RCPT TO", + smtp_address_encode(address)); if (client->lmtp_set->lmtp_proxy) { if (client_proxy_rcpt(client, address, username, detail, delim, @@ -657,13 +626,14 @@ int cmd_rcpt(struct client *client, const char *args) if (ret < 0) { i_error("Failed to lookup user %s: %s", username, error); - client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, address); + client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, + smtp_address_encode(address)); return 0; } if (ret == 0) { client_send_line(client, "550 5.1.1 <%s> User doesn't exist: %s", - address, username); + smtp_address_encode(address), username); return 0; } if (client->proxy != NULL) { @@ -672,12 +642,12 @@ int cmd_rcpt(struct client *client, const char *args) (with and without Return-Path: header) */ client_send_line(client, "451 4.3.0 <%s> " "Can't handle mixed proxy/non-proxy destinations", - address); + smtp_address_encode(address)); mail_storage_service_user_unref(&rcpt->service_user); return 0; } - rcpt->address = p_strdup(client->state_pool, address); + rcpt->address = smtp_address_clone(client->state_pool, address); rcpt->detail = p_strdup(client->state_pool, detail); if (client->lmtp_set->lmtp_user_concurrency_limit == 0) { @@ -729,12 +699,20 @@ int cmd_noop(struct client *client, const char *args ATTR_UNUSED) return 0; } -static bool orcpt_get_valid_rfc822(const char *orcpt, const char **addr_r) +static bool orcpt_get_valid_rfc822(const char *orcpt, + const struct smtp_address **addr_r) { + struct message_address *rfc822_addr; + if (orcpt == NULL || strncasecmp(orcpt, "rfc822;", 7) != 0) return FALSE; - /* FIXME: we should verify the address further */ - *addr_r = orcpt + 7; + + rfc822_addr = message_address_parse(pool_datastack_create(), + (const unsigned char *)orcpt+7, strlen(orcpt+7), 2, FALSE); + if (rfc822_addr == NULL || rfc822_addr->invalid_syntax || + rfc822_addr->next != NULL) + return FALSE; + *addr_r = smtp_address_create_temp(rfc822_addr->mailbox, rfc822_addr->domain); return TRUE; } @@ -788,7 +766,7 @@ client_deliver(struct client *client, const struct mail_recipient *rcpt, &dest_user, &error) < 0) { i_error("Failed to initialize user: %s", error); client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - rcpt->address); + smtp_address_encode(rcpt->address)); return -1; } client->state.dest_user = dest_user; @@ -810,7 +788,7 @@ client_deliver(struct client *client, const struct mail_recipient *rcpt, if (ret <= 0) { i_error("Failed to expand settings: %s", error); client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - rcpt->address); + smtp_address_encode(rcpt->address)); return -1; } @@ -821,7 +799,7 @@ client_deliver(struct client *client, const struct mail_recipient *rcpt, i_error("Failed to expand mail_log_prefix=%s: %s", dest_user->set->mail_log_prefix, error); client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - rcpt->address); + smtp_address_encode(rcpt->address)); return -1; } i_set_failure_prefix("%s", str_c(str)); @@ -867,11 +845,13 @@ client_deliver(struct client *client, const struct mail_recipient *rcpt, client->state.first_saved_mail = dctx.dest_mail; } client_send_line(client, "250 2.0.0 <%s> %s Saved", - rcpt->address, rcpt->session_id); + smtp_address_encode(rcpt->address), + rcpt->session_id); ret = 0; } else if (dctx.tempfail_error != NULL) { client_send_line(client, "451 4.2.0 <%s> %s", - rcpt->address, dctx.tempfail_error); + smtp_address_encode(rcpt->address), + dctx.tempfail_error); ret = -1; } else if (storage != NULL) { error = mail_storage_get_last_error(storage, &mail_error); @@ -879,14 +859,14 @@ client_deliver(struct client *client, const struct mail_recipient *rcpt, client_send_line_overquota(client, rcpt, error); } else { client_send_line(client, "451 4.2.0 <%s> %s", - rcpt->address, error); + smtp_address_encode(rcpt->address), error); } ret = -1; } else { /* This shouldn't happen */ i_error("BUG: Saving failed to unknown storage"); client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - rcpt->address); + smtp_address_encode(rcpt->address)); ret = -1; } return ret; @@ -946,7 +926,7 @@ static void client_rcpt_fail_all(struct client *client) array_foreach(&client->state.rcpt_to, rcptp) { client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, - (*rcptp)->address); + smtp_address_encode((*rcptp)->address)); } } @@ -989,7 +969,7 @@ static int client_open_raw_mail(struct client *client, struct istream *input) enum mail_error error; if (raw_mailbox_alloc_stream(client->raw_mail_user, input, - (time_t)-1, client->state.mail_from, + (time_t)-1, smtp_address_encode(client->state.mail_from), &box) < 0) { i_error("Can't open delivery mail as raw: %s", mailbox_get_last_internal_error(box, &error)); @@ -1078,7 +1058,8 @@ static const char *client_get_added_headers(struct client *client) string_t *str = t_str_new(200); void **sets; const struct lmtp_settings *lmtp_set; - const char *host, *rcpt_to = NULL; + const struct smtp_address *rcpt_to = NULL; + const char *host; if (array_count(&client->state.rcpt_to) == 1) { struct mail_recipient *const *rcptp = @@ -1104,9 +1085,11 @@ static const char *client_get_added_headers(struct client *client) /* don't set Return-Path when proxying so it won't get added twice */ if (array_count(&client->state.rcpt_to) > 0) { str_printfa(str, "Return-Path: <%s>\r\n", - client->state.mail_from); - if (rcpt_to != NULL) - str_printfa(str, "Delivered-To: %s\r\n", rcpt_to); + smtp_address_encode(client->state.mail_from)); + if (rcpt_to != NULL) { + str_printfa(str, "Delivered-To: %s\r\n", + smtp_address_encode(rcpt_to)); + } } str_printfa(str, "Received: from %s", client->lhlo); @@ -1123,7 +1106,7 @@ static const char *client_get_added_headers(struct client *client) str_append(str, "\r\n\t"); if (rcpt_to != NULL) - str_printfa(str, "for <%s>", rcpt_to); + str_printfa(str, "for <%s>", smtp_address_encode(rcpt_to)); str_printfa(str, "; %s\r\n", message_date_create(ioloop_time)); return str_c(str); }