commands.c revision 1ee1a73bde20380ba39d572681397ad05dcdf9a1
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2009-2014 Dovecot authors, see the included COPYING file */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define ERRSTR_TEMP_MAILBOX_FAIL "451 4.3.0 <%s> Temporary internal error"
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen#define ERRSTR_TEMP_USERDB_FAIL_PREFIX "451 4.3.0 <%s> "
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen ERRSTR_TEMP_USERDB_FAIL_PREFIX "Temporary user lookup failure"
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen#define LMTP_PROXY_DEFAULT_TIMEOUT_MSECS (1000*30)
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);
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen client_send_line(client, "250-XCLIENT ADDR PORT TTL TIMEOUT");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "250-ENHANCEDSTATUSCODES");
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenstatic int parse_address(const char *str, const char **address_r,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const char **rest_r)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen /* "quoted-string"@domain */
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");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else if (strcasecmp(*argv, "BODY=8BITMIME") == 0)
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen "501 5.5.4 Unsupported options");
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen client->state.mail_from = p_strdup(client->state_pool, addr);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen p_array_init(&client->state.rcpt_to, client->state_pool, 64);
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainenclient_proxy_rcpt_parse_fields(struct lmtp_proxy_rcpt_settings *set,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *const *args, const char **address)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* changing the username */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* just ignore it */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_proxy_is_ourself(const struct client *client,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenstatic const char *
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenaddress_add_detail(struct client *client, const char *username,
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen const char *delim = client->unexpanded_lda_set->recipient_delimiter;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, NULL);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return t_strconcat(username, delim, detail, domain, NULL);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic bool client_proxy_rcpt(struct client *client, const char *address,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *args, *const *fields, *errstr, *orig_username = username;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen mail_storage_service_init_settings(storage_service, &input);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen info.service = master_service_get_name(master_service);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen pool = pool_alloconly_create("auth lookup", 1024);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen auth_conn = mail_storage_service_get_auth_conn(storage_service);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ret = auth_master_pass_lookup(auth_conn, username, &info,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen errstr = ret < 0 && fields[0] != NULL ? t_strdup(fields[0]) :
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL, address);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* user not found from passdb. try userdb also. */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* not proxying this user */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* username changed. change the address as well */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen address = address_add_detail(client, username, detail);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen } else if (client_proxy_is_ourself(client, &set)) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen i_error("Proxying to <%s> loops to itself", username);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen i_error("Proxying to <%s> appears to be looping (TTL=0)",
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen "Proxying appears to be looping (TTL=0)",
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen if (array_count(&client->state.rcpt_to) != 0) {
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen "Can't handle mixed proxy/non-proxy destinations",
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen proxy_set.dns_client_socket_path = dns_client_socket_path;
d163fac99c7ca5b2ce2edfa83a1b2922cf66aeacTimo Sirainen proxy_set.session_id = client->state.session_id;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen client->proxy = lmtp_proxy_init(&proxy_set, client->output);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen lmtp_proxy_mail_from(client->proxy, t_strdup_printf(
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (lmtp_proxy_add_rcpt(client->proxy, address, &set) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen client_send_line(client, ERRSTR_TEMP_REMOTE_FAILURE);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenstatic const char *lmtp_unescape_address(const char *name)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const char *p;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* quoted-string local-part. drop the quotes unless there's a
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen '@' character inside or there's an error. */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\0')
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '\\') {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (*p == '@')
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenstatic void rcpt_address_parse(struct client *client, const char *address,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const char **username_r, const char **detail_r)
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen const char *p, *domain;
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen if (*client->unexpanded_lda_set->recipient_delimiter == '\0')
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen p = strstr(address, client->unexpanded_lda_set->recipient_delimiter);
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen if (p != NULL && (domain == NULL || p < domain)) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* user+detail@domain */
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen *username_r = t_strconcat(*username_r, domain, NULL);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainenstatic void lmtp_address_translate(struct client *client, const char **address)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen const char *transpos = client->lmtp_set->lmtp_address_translate;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen unsigned int len;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* check that string matches up to the first '%' */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* find where the next string starts */
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainenlmtp_rcpt_to_is_over_quota(struct client *client,
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ret = mail_storage_service_next(storage_service,
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ns = mail_namespace_find_inbox(user->namespaces);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rcpt(struct client *client, const char *args)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen const char *address, *username, *detail, *prefix;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "503 5.5.1 MAIL needed first");
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen parse_address(args + 3, &address, &args) < 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen client_send_line(client, "501 5.5.4 Invalid parameters");
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen client_send_line(client, "501 5.5.4 Unsupported options");
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt_address_parse(client, address, &username, &detail);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (client_proxy_rcpt(client, address, username, detail))
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen ret = mail_storage_service_lookup(storage_service, &input,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen prefix = t_strdup_printf(ERRSTR_TEMP_USERDB_FAIL_PREFIX,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client_send_line(client, "%s%s", prefix, error);
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",
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.address = p_strdup(client->state_pool, address);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen rcpt.detail = p_strdup(client->state_pool, detail);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if ((ret = lmtp_rcpt_to_is_over_quota(client, &rcpt)) < 0) {
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen array_append(&client->state.rcpt_to, &rcpt, 1);
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));
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");
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_rset(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenint cmd_noop(struct client *client, const char *args ATTR_UNUSED)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenclient_deliver(struct client *client, const struct mail_recipient *rcpt,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail *src_mail, struct mail_deliver_session *session)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen const struct mail_storage_service_input *input;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen input = mail_storage_service_user_get_input(rcpt->service_user);
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen mail_set = mail_storage_service_user_get_mail_set(rcpt->service_user);
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen set_parser = mail_storage_service_user_get_settings_parser(rcpt->service_user);
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen mail_set->mail_max_lock_timeout > client->proxy_timeout_secs)) {
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen /* set lock timeout waits to be less than when proxy has
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen advertised that it's going to timeout the connection.
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen this avoids duplicate deliveries in case the delivery
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen succeeds after the proxy has already disconnected from us. */
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen line = t_strdup_printf("mail_max_lock_timeout=%u",
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen if (settings_parse_line(set_parser, line) < 0)
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("lmtp(%s, %s): ", my_pid, username);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (mail_storage_service_next(storage_service, rcpt->service_user,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen sets = mail_storage_service_user_get_set(rcpt->service_user);
8c30a8e508dd05b63c9b1fa7ae9c637d132dac6fTimo Sirainen settings_var_expand(&lda_setting_parser_info, lda_set, client->pool,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_user_var_expand_table(client->state.dest_user));
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dctx.src_envelope_sender = client->state.mail_from;
71564d36ea3aba6dd6a0d2560da46ffda733b679Timo Sirainen if (*dctx.set->lda_original_recipient_header != '\0') {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen dctx.dest_addr = mail_deliver_get_address(src_mail,
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen !client->lmtp_set->lmtp_save_to_detail_mailbox)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen ns = mail_namespace_find_inbox(dctx.dest_user->namespaces);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen dctx.save_dest_mail = array_count(&client->state.rcpt_to) > 1 &&
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen i_assert(client->state.first_saved_mail == NULL);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen client->state.first_saved_mail = dctx.dest_mail;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen client_send_line(client, "250 2.0.0 <%s> %s Saved",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen error = mail_storage_get_last_error(storage, &mail_error);
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen /* This shouldn't happen */
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen i_error("BUG: Saving failed to unknown storage");
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainenstatic bool client_deliver_next(struct client *client, struct mail *src_mail,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen unsigned int count;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rcpts = array_get(&client->state.rcpt_to, &count);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen ret = client_deliver(client, &rcpts[client->state.rcpt_idx],
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* failed. try the next one. */
efb0def040a3e98da05ea77c170cd6711a9c8747Timo Sirainenstatic void client_rcpt_fail_all(struct client *client)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
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 int client_open_raw_mail(struct client *client, struct istream *input)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen static const char *wanted_headers[] = {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen "From", "To", "Message-ID", "Subject", "Return-Path",
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mailbox_header_lookup_ctx *headers_ctx;
15dd1857d40544e2c356d4f1c87c42a0579c665cTimo Sirainen if (raw_mailbox_alloc_stream(client->raw_mail_user, input,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_error("Can't open delivery mail as raw: %s",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
8aa60989067046e35c4809a616b46473fce0113eTimo Sirainen client->state.raw_mail = mail_alloc(trans, 0, headers_ctx);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenclient_input_data_write_local(struct client *client, struct istream *input)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen while (client_deliver_next(client, src_mail, session)) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* use the first saved message to save it elsewhere too.
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen this might allow hard linking the files. */
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mail *mail = client->state.first_saved_mail;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen struct mailbox_transaction_context *trans = mail->transaction;
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* just in case these functions are going to write anything,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen change uid back to user's own one */
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen /* switch back to running as root, since that's what we're
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen practically doing anyway. it's also important in case we
75e789ce60fba8e9ad07f51a8fd186fa65823328Timo Sirainen lose e.g. config connection and need to reconnect to it. */
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen /* enable core dumping again. we need to chdir also to
ffaa309c211897ab875bbe0b093bc7e709bb1e5dTimo Sirainen root-owned directory to get core dumps. */
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) {
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) {
a192134d1aaf3ff73bff040c7cd9ab3e9a8fe1ddTimo Sirainen str_printfa(str, "Delivered-To: %s\r\n", rcpt_to);
fcd443a32b01c4da131f36649d5a5fa5f8452dcfTimo Sirainen str_printfa(str, "Received: from %s", client->lhlo);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "\r\n\tby %s ("PACKAGE_NAME") with LMTP id %s",
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen str_printfa(str, "; %s\r\n", message_date_create(ioloop_time));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic bool client_input_data_write(struct client *client)
fb340f9dfd8ca3a66ef6830c047333a220e8f9b3Timo Sirainen /* stop handling client input until saving/proxying is finished */
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.. */
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen i_error("unlink(%s) failed: %m", str_c(path));
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data_output = o_stream_create_fd_file(fd, 0, FALSE);
2dad3ab8045be38711f277f065b76f76bb5f63f8Timo Sirainen state->mail_data->data, state->mail_data->used);
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen if (o_stream_send(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 */
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);
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainenint cmd_xclient(struct client *client, const char *args)
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen const char *const *tmp;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen unsigned int remote_port = 0, 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) {
b015d3d3af5b1c0fd526f31d78229bf9f633db56Timo Sirainen if (str_to_uint(*tmp + 5, &remote_port) < 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 */