int cmd_mail(struct client *client, const char *args) { const char *addr, *const *argv; 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) { client_send_line(client, "501 5.5.4 Invalid parameters"); return 0; } argv = t_strsplit(args, " "); for (; *argv != NULL; argv++) { if (strcasecmp(*argv, "BODY=7BIT") == 0) client->state.mail_body_7bit = TRUE; else if (strcasecmp(*argv, "BODY=8BITMIME") == 0) client->state.mail_body_8bitmime = TRUE; else { client_send_line(client, "501 5.5.4 Unsupported options"); return 0; } } client->state.mail_from = p_strdup(client->state_pool, addr); 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"); return 0; }
int cmd_lhlo(struct client *client, const char *args) { struct rfc822_parser_context parser; string_t *domain = t_str_new(128); const char *p; int ret = 0; if (*args == '\0') { client_send_line(client, "501 Missing hostname"); return 0; } /* domain / address-literal */ rfc822_parser_init(&parser, (const unsigned char *)args, strlen(args), NULL); if (*args != '[') ret = rfc822_parse_dot_atom(&parser, domain); else { for (p = args+1; *p != ']'; p++) { if (*p == '\\' || *p == '[') break; } if (strcmp(p, "]") != 0) ret = -1; } if (ret < 0) { str_truncate(domain, 0); str_append(domain, "invalid"); } client_state_reset(client, "LHLO"); client_send_line(client, "250-%s", client->my_domain); if (master_service_ssl_is_enabled(master_service) && client->ssl_iostream == NULL) client_send_line(client, "250-STARTTLS"); if (client_is_trusted(client)) client_send_line(client, "250-XCLIENT ADDR PORT TTL TIMEOUT"); client_send_line(client, "250-8BITMIME"); client_send_line(client, "250-ENHANCEDSTATUSCODES"); client_send_line(client, "250 PIPELINING"); i_free(client->lhlo); client->lhlo = i_strdup(str_c(domain)); client_state_set(client, "LHLO", ""); return 0; }
int cmd_rcpt(struct client *client, const char *args) { struct mail_recipient rcpt; struct mail_storage_service_input input; const char *address, *username, *detail, *prefix; const char *error = NULL; int ret = 0; client_state_set(client, "RCPT TO"); 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, &args) < 0) { client_send_line(client, "501 5.5.4 Invalid parameters"); return 0; } memset(&rcpt, 0, sizeof(rcpt)); address = lmtp_unescape_address(address); if (*args != '\0') { client_send_line(client, "501 5.5.4 Unsupported options"); return 0; } rcpt_address_parse(client, address, &username, &detail); if (client->lmtp_set->lmtp_proxy) { if (client_proxy_rcpt(client, address, username, detail)) return 0; } 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; 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); 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) { client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, rcpt.address); return 0; } if (ret == 0) { array_append(&client->state.rcpt_to, &rcpt, 1); client_send_line(client, "250 2.1.5 OK"); } return 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, ¶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; }