bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* max. length of input command line */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Stop reading input when output buffer has this many bytes. Once the buffer
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch size has dropped to half of it, start reading input again. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Disconnect client when it sends too many bad commands in a row */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Disconnect client after idling this many milliseconds */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const struct smtp_server_callbacks smtp_callbacks;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* try to proxy pipelined commands in a similarly pipelined fashion */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_cork(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_uncork(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *client_remote_id(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch addr = net_ip2addr(client->user->conn.remote_ip);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_proxy_ready_cb(const struct smtp_reply *reply,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* check proxy status */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_error("Failed to establish relay connection: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "4.4.0", "Failed to establish relay connection");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* propagate capabilities */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch caps = smtp_client_connection_get_capabilities(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch caps |= SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_CHUNKING | SMTP_CAPABILITY_BURL |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_set_capabilities(client->conn, caps);
d63fbcb367b6de01f5e39d72a825f03a832e308fStephan Bosch /* now that we know our capabilities, commence server protocol dialog */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_proxy_create(struct client *client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum smtp_client_connection_ssl_mode ssl_mode;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_init_ssl_client_settings(user, &ssl_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* make proxy connection */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.username = set->submission_relay_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.master_user = set->submission_relay_master_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.password = set->submission_relay_password;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (strcmp(set->submission_relay_ssl, "smtps") == 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch else if (strcmp(set->submission_relay_ssl, "starttls") == 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->proxy_conn = smtp_client_connection_create(smtp_client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_PROTOCOL_SMTP, set->submission_relay_host,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch set->submission_relay_port, ssl_mode, &smtp_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_connect(client->proxy_conn,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_init_urlauth(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch static const char *access_apps[] = { "submit+", NULL };
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.url_host = client->set->imap_urlauth_host;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.url_port = client->set->imap_urlauth_port;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.socket_path = t_strconcat(client->user->set->base_dir,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.access_anonymous = client->user->anonymous;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->urlauth_ctx = imap_urlauth_init(client->user, &config);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstruct client *client_create(int fd_in, int fd_out,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *session_id, struct mail_user *user,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct mail_storage_service_user *service_user,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const unsigned char *pdata, unsigned int pdata_len)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *ident;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* always use nonblocking I/O */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.login_greeting = set->login_greeting;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.max_recipients = set->submission_max_recipients;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->conn = smtp_server_connection_create(smtp_server,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port,
d63fbcb367b6de01f5e39d72a825f03a832e308fStephan Bosch smtp_server_connection_start_pending(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_set = mail_user_set_get_storage_set(user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Enable BURL capability only when urlauth dict is
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch configured correctly */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ident = mail_user_get_anvil_userip_ident(client->user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (ident != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_anvil_send(master_service, t_strconcat(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_state_reset(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid client_destroy(struct client *client, const char *prefix,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_close(&client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_anvil_send(master_service, t_strconcat(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_get_anvil_userip_ident(client->user),
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_storage_service_user_unref(&client->service_user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_client_connection_destroyed(master_service);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_transaction *trans ATTR_UNUSED)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschclient_connection_state_changed(void *context ATTR_UNUSED,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_connection_disconnect(void *context, const char *reason)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_connection *conn = client->conn;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch stats = smtp_server_connection_get_stats(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->last_state = smtp_server_connection_get_state(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_connection_destroy(void *context)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschconst char *client_state_get_name(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch state = smtp_server_connection_get_state(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *client_stats(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *trans_id = (client->conn == NULL ? "" :
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_get_transaction_id(client->conn));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct var_expand_table logout_tab[] = {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { 'i', dec2str(client->stats.input), "input" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { 'o', dec2str(client->stats.output), "output" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', dec2str(client->stats.command_count), "command_count" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', dec2str(client->stats.reply_count), "reply_count" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch t_var_expand_merge_tables(logout_tab, user_tab);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (var_expand_with_funcs(str, client->set->submission_logout_format,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_error("Failed to expand submission_logout_format=%s: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->set->submission_logout_format, error);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid client_disconnect(struct client *client, const char *enh_code,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_close(&client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_get_stats(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_info("Disconnect from %s: %s %s (state = %s)",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->last_state = smtp_server_connection_get_state(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch (enh_code == NULL ? "4.0.0" : enh_code), reason);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschbool client_proxy_is_ready(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return (smtp_client_connection_get_state(client->proxy_conn) ==
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschbool client_proxy_is_disconnected(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return (smtp_client_connection_get_state(client->proxy_conn) ==
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschuoff_t client_get_max_mail_size(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Account for the backend server's SIZE limit and calculate our own
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch relative to it. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = smtp_client_connection_get_size_capability(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (max_size == 0 || max_size <= SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = client->set->submission_max_mail_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = max_size - SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->set->submission_max_mail_size > 0 &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size > client->set->submission_max_mail_size)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = client->set->submission_max_mail_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const struct smtp_server_callbacks smtp_callbacks = {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_trans_free = client_connection_trans_free,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_state_changed = client_connection_state_changed,