commands.c revision 8a68f5bb807b5233e191641e7e7f993e707ae369
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * EHLO command
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenint cmd_lhlo(struct client *client, const char *args)
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const char *p;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "501 Missing hostname");
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* domain / address-literal */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen rfc822_parser_init(&parser, (const unsigned char *)args, strlen(args),
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-%s", client->my_domain);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (master_service_ssl_is_enabled(master_service) &&
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client_send_line(client, "250-XCLIENT ADDR PORT TTL TIMEOUT");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-ENHANCEDSTATUSCODES");
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * STARTTLS command
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen struct ostream *plain_output = client->output;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "443 5.5.1 TLS is already active.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen i_error("TLS initialization failed: %s", error);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "454 4.7.0 Internal error, TLS not available.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "220 2.0.0 Begin TLS negotiation now.\r\n");
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (ssl_iostream_handshake(client->ssl_iostream) < 0) {
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * MAIL command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_mail(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL already given");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (smtp_address_parse_path_full(pool_datastack_create(), args + 5,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid FROM: %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid FROM: "
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch "Invalid character in path");
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch /* [SP Mail-parameters] */
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch if (smtp_params_mail_parse(client->state_pool, args,
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch &client->state.mail_params, &pperror, &error) < 0) {
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "501 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "555 5.5.4 %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_clone(client->state_pool, address);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_array_init(&client->state.rcpt_to, client->state_pool, 64);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit > 0) {
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen /* connect to anvil before dropping privileges */
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen client->state.mail_from_timeval = ioloop_timeval;
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * RCPT command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch if (smtp_address_parse_path_full(pool_datastack_create(), args + 3,
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid TO: %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, "501 5.5.4 Invalid TO: "
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch "Invalid character in path");
447ae13a88887d9503c05be61a4368cfae44d96dStephan Bosch rcpt = p_new(client->state_pool, struct lmtp_recipient, 1);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch /* [SP Rcpt-parameters] */
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch if (smtp_params_rcpt_parse(client->state_pool, args,
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "501 5.5.4 %s", error);
de0971aff3009fe6906c3631e8322908658a5e93Stephan Bosch client_send_line(client, "555 5.5.4 %s", error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client->unexpanded_lda_set->recipient_delimiter,
e4161404db08e61e835b330e8e12a4d0eb321ed3Stephan Bosch if (lmtp_proxy_rcpt(client, address, username, detail, delim,
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen /* Use a unique session_id for each mail delivery. This is especially
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen important for stats process to not see duplicate sessions. */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_storage_service_lookup(storage_service, &input,
f6008a666d9c3df66fd8a437369133e8519b4e24Timo Sirainen i_error("Failed to lookup user %s: %s", username, error);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen "550 5.1.1 <%s> User doesn't exist: %s",
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen /* NOTE: if this restriction is ever removed, we'll also need
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen to send different message bodies to local and proxy
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen (with and without Return-Path: header) */
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
eb318ea05532d2e54ed3bfc89bc15dcf1adae838Timo Sirainen mail_storage_service_user_unref(&rcpt->service_user);
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch rcpt->address = smtp_address_clone(client->state_pool, address);
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen rcpt->detail = p_strdup(client->state_pool, detail);
ced943b0a9b49a5be38516302fe1631c1883debaTimo Sirainen if (client->lmtp_set->lmtp_user_concurrency_limit == 0) {
d03980c62bca1d8501d67e5cf3b6f9904d166dd4Timo Sirainen /* NOTE: username may change as the result of the userdb
d03980c62bca1d8501d67e5cf3b6f9904d166dd4Timo Sirainen lookup. Look up the new one via service_user. */
d03980c62bca1d8501d67e5cf3b6f9904d166dd4Timo Sirainen const struct mail_storage_service_input *input =
d03980c62bca1d8501d67e5cf3b6f9904d166dd4Timo Sirainen mail_storage_service_user_get_input(rcpt->service_user);
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen rcpt->anvil_query = anvil_client_query(anvil, query,
ced943b0a9b49a5be38516302fe1631c1883debaTimo Sirainen /* stop processing further commands while anvil query is
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * QUIT command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_quit(struct client *client, const char *args ATTR_UNUSED)
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen /* don't log the (state name) for successful QUITs */
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen i_info("Disconnect from %s: Successful quit", client_remote_id(client));
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * VRFY command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_vrfy(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "252 2.3.3 Try RCPT instead");
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * RSET command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rset(struct client *client, const char *args ATTR_UNUSED)
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * NOOP command
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_noop(struct client *client, const char *args ATTR_UNUSED)
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * DATA command
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic struct istream *client_get_input(struct client *client)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen inputs[0] = i_stream_create_from_data(state->added_headers,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_fd(state->mail_data_fd,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen inputs[1] = i_stream_create_from_data(state->mail_data->data,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void client_input_data_finish(struct client *client)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainenstatic const char *client_get_added_headers(struct client *client)
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen if (array_count(&client->state.rcpt_to) == 1) {
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen sets = mail_storage_service_user_get_set((*rcptp)->service_user);
1ac7b6969120bfdb15497663229f0dd168ae4ab8Timo Sirainen switch (lmtp_set->parsed_lmtp_hdr_delivery_address) {
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen /* don't set Return-Path when proxying so it won't get added twice */
7f250fe7eede5f1d17c5e177c7f2dc0dd742e224Timo Sirainen if (array_count(&client->state.rcpt_to) > 0) {
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch smtp_address_encode(client->state.mail_from));
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen str_printfa(str, "Received: from %s", client->lhlo);
0dc719a06fc1bbe11238762f9beb0c1faa4a2b75Timo Sirainen ssl_iostream_get_security_string(client->ssl_iostream));
3d7828efd92ecc0d08049f727d9be0154d1d681bStephan Bosch str_printfa(str, "for <%s>", smtp_address_encode(rcpt_to));
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "; %s\r\n", message_date_create(ioloop_time));
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenstatic void client_input_data_write(struct client *client)
fb340f9dfd8ca3a66ef6830c047333a220e8f9b3Timo Sirainen /* stop handling client input until saving/proxying is finished */
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen client->state.data_end_timeval = ioloop_timeval;
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainenstatic int client_input_add_file(struct client *client,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* continue writing to file */
b5babd4ea611616f0b3b2b9fb5917c78d1999a7bTimo Sirainen /* move everything to a temporary file. */
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen mail_user_set_get_temp_prefix(path, client->raw_mail_user->set);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen i_error("Temp file creation to %s failed: %m", str_c(path));
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* we just want the fd, unlink it */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen /* shouldn't happen.. */
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_set_name(state->mail_data_output, str_c(path));
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen state->mail_data->data, state->mail_data->used);
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_nsend(client->state.mail_data_output, data, size);
d1ba8ecbb936ace90179d2292952546708d68f71Timo Sirainen if (o_stream_flush(client->state.mail_data_output) < 0) {
61d89b0ca0300e230c7882b71e8360edf62d9cd0Timo Sirainen o_stream_get_error(client->state.mail_data_output));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_input_add(struct client *client, const unsigned char *data, size_t size)
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen buffer_append(client->state.mail_data, data, size);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen return client_input_add_file(client, data, size);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data_handle(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const unsigned char *data;
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen while ((ret = i_stream_read(client->dot_input)) > 0 || ret == -2) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen data = i_stream_get_data(client->dot_input, &size);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen if (client_input_add(client, data, size) < 0) {
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen "Temporary internal failure");
85f8811e47003717620cbe066bb05494124308faTimo Sirainen /* client probably disconnected */
3bb61142ca8dc0c71efd430fa8f805a4c7262aa8Timo Sirainen /* the ending "." line was seen. begin saving the mail. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic void client_input_data(struct client *client)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_data(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (array_count(&client->state.rcpt_to) == 0 && client->proxy == NULL) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "554 5.5.1 No valid recipients");
9deb15b8dec1a593940d72532ececc673c6b48ffTimo Sirainen p_strdup(client->state_pool, client_get_added_headers(client));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client->state.mail_data = buffer_create_dynamic(default_pool, 1024*64);
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen client->dot_input = i_stream_create_dot(client->input, TRUE);
75e2c45e2e60ba22728b7520818aa0a191f8ca3dTimo Sirainen /* send the DATA reply immediately before we start handling any data */
701c9fc6dc06415bbf15490125e001d9db8c7cbdTimo Sirainen client->io = io_add(client->fd_in, IO_READ, client_input_data, client);
ebdfdb765f3ce2176c3483b5416b51af9593aca2Stephan Bosch * XCLIENT command
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainenint cmd_xclient(struct client *client, const char *args)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen const char *const *tmp;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unsigned int ttl = UINT_MAX, timeout_secs = 0;
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client_send_line(client, "550 You are not from trusted IP");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen } else if (strncasecmp(*tmp, "PORT=", 5) == 0) {
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen } else if (strncasecmp(*tmp, "TTL=", 4) == 0) {
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen } else if (strncasecmp(*tmp, "TIMEOUT=", 8) == 0) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen client_send_line(client, "501 Invalid parameters");
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen /* args ok, set them and reset the state */