bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "lib.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "net.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "str.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "hash.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "array.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "ioloop.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "istream.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "ostream.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "connection.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "dns-lookup.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "iostream-rawlog.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "iostream-ssl.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#include "smtp-client-private.h"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#define SMTP_DEFAULT_PORT 80
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch#define SSMTP_DEFAULT_PORT 465
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch/*
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch * Client
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstruct smtp_client *smtp_client_init(const struct smtp_client_settings *set)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch{
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client *client;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch pool_t pool;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch pool = pool_alloconly_create("smtp client", 1024);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client = p_new(pool, struct smtp_client, 1);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->pool = pool;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch client->set.my_ip = set->my_ip;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.my_hostname = p_strdup(pool, set->my_hostname);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.dns_client = set->dns_client;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.dns_client_socket_path =
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch p_strdup(pool, set->dns_client_socket_path);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->ssl != NULL) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.ssl =
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ssl_iostream_settings_dup(client->pool, set->ssl);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch }
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.master_user = p_strdup_empty(pool, set->master_user);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.username = p_strdup_empty(pool, set->username);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.sasl_mech = set->sasl_mech;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->sasl_mech == NULL) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.sasl_mechanisms =
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch p_strdup(pool, set->sasl_mechanisms);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch }
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.connect_timeout_msecs = set->connect_timeout_msecs != 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch set->connect_timeout_msecs :
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_DEFAULT_CONNECT_TIMEOUT_MSECS;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.command_timeout_msecs = set->command_timeout_msecs != 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch set->command_timeout_msecs :
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_DEFAULT_COMMAND_TIMEOUT_MSECS;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.max_reply_size = set->max_reply_size != 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch set->max_reply_size : SMTP_DEFAULT_MAX_REPLY_SIZE;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.max_data_chunk_size = set->max_data_chunk_size != 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch set->max_data_chunk_size : SMTP_DEFAULT_MAX_DATA_CHUNK_SIZE;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.max_data_chunk_pipeline = set->max_data_chunk_pipeline != 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch set->max_data_chunk_pipeline : SMTP_DEFAULT_MAX_DATA_CHUNK_PIPELINE;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.socket_send_buffer_size = set->socket_send_buffer_size;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.socket_recv_buffer_size = set->socket_recv_buffer_size;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.debug = set->debug;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.source_ip = set->proxy_data.source_ip;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.source_port = set->proxy_data.source_port;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.ttl_plus_1 = set->proxy_data.ttl_plus_1;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.timeout_secs = set->proxy_data.timeout_secs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.helo = p_strdup_empty(pool, set->proxy_data.helo);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->set.proxy_data.login = p_strdup_empty(pool, set->proxy_data.login);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch client->conn_list = smtp_client_connection_list_init();
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return client;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch}
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_deinit(struct smtp_client **_client)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch{
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client *client = *_client;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch connection_list_deinit(&client->conn_list);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (client->ssl_ctx != NULL)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ssl_iostream_context_unref(&client->ssl_ctx);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch pool_unref(&client->pool);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch *_client = NULL;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch}
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_switch_ioloop(struct smtp_client *client)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch{
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct connection *_conn = client->conn_list->connections;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* move connections */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch for (; _conn != NULL; _conn = _conn->next) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client_connection *conn =
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (struct smtp_client_connection *)_conn;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_switch_ioloop(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch }
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch}
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschint smtp_client_init_ssl_ctx(struct smtp_client *client, const char **error_r)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch{
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char *error;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (client->ssl_ctx != NULL)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return 0;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (client->set.ssl == NULL) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch *error_r = "Requested SSL connection, but no SSL settings given";
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return -1;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch }
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ssl_iostream_client_context_cache_get(client->set.ssl,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch &client->ssl_ctx, &error) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch *error_r = t_strdup_printf("Couldn't initialize SSL context: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return -1;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch }
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return 0;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch}
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch// FIXME: Implement smtp_client_run()