postscreen_starttls.c [plain text]
#include <sys_defs.h>
#include <msg.h>
#include <mymalloc.h>
#include <connect.h>
#include <stringops.h>
#include <vstring.h>
#include <mail_params.h>
#include <mail_proto.h>
#include <tls_proxy.h>
#include <postscreen.h>
typedef struct {
VSTREAM *tlsproxy_stream;
EVENT_NOTIFY_FN resume_event;
PSC_STATE *smtp_state;
} PSC_STARTTLS;
#define TLSPROXY_INIT_TIMEOUT 10
static char *psc_tlsp_service = 0;
static void psc_starttls_finish(int event, char *context)
{
const char *myname = "psc_starttls_finish";
PSC_STARTTLS *starttls_state = (PSC_STARTTLS *) context;
PSC_STATE *smtp_state = starttls_state->smtp_state;
VSTREAM *tlsproxy_stream = starttls_state->tlsproxy_stream;
int status;
if (msg_verbose)
msg_info("%s: send client handle on proxy socket %d"
" for smtp socket %d from [%s]:%s flags=%s",
myname, vstream_fileno(tlsproxy_stream),
vstream_fileno(smtp_state->smtp_client_stream),
smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
psc_print_state_flags(smtp_state->flags, myname));
if (event != EVENT_TIME)
event_cancel_timer(psc_starttls_finish, (char *) starttls_state);
if (event != EVENT_READ
|| attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
ATTR_TYPE_END) != 1 || status == 0) {
event_disable_readwrite(vstream_fileno(tlsproxy_stream));
vstream_fclose(tlsproxy_stream);
PSC_SEND_REPLY(smtp_state,
"454 4.7.0 TLS not available due to local problem\r\n");
}
else if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
vstream_fileno(smtp_state->smtp_client_stream)) < 0) {
msg_warn("%s sending file handle to %s service",
event == EVENT_TIME ? "timeout" : "problem",
psc_tlsp_service);
event_disable_readwrite(vstream_fileno(tlsproxy_stream));
vstream_fclose(tlsproxy_stream);
PSC_SEND_REPLY(smtp_state,
"454 4.7.0 TLS not available due to local problem\r\n");
}
else {
PSC_SEND_REPLY(smtp_state, "220 2.0.0 Ready to start TLS\r\n");
vstream_fpurge(smtp_state->smtp_client_stream, VSTREAM_PURGE_BOTH);
vstream_control(smtp_state->smtp_client_stream,
VSTREAM_CTL_SWAP_FD, tlsproxy_stream,
VSTREAM_CTL_END);
vstream_fclose(tlsproxy_stream);
smtp_state->flags |= PSC_STATE_FLAG_USING_TLS;
}
starttls_state->resume_event(event, (char *) smtp_state);
myfree((char *) starttls_state);
}
void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
{
const char *myname = "psc_starttls_open";
PSC_STARTTLS *starttls_state;
VSTREAM *tlsproxy_stream;
int fd;
static VSTRING *remote_endpt = 0;
if (psc_tlsp_service == 0) {
psc_tlsp_service = concatenate(MAIL_CLASS_PRIVATE "/",
var_tlsproxy_service, (char *) 0);
remote_endpt = vstring_alloc(20);
}
if ((fd = LOCAL_CONNECT(psc_tlsp_service, NON_BLOCKING, 1)) < 0) {
msg_warn("connect to %s service: %m", psc_tlsp_service);
PSC_SEND_REPLY(smtp_state,
"454 4.7.0 TLS not available due to local problem\r\n");
event_request_timer(resume_event, (char *) smtp_state, 0);
return;
}
if (msg_verbose)
msg_info("%s: send client name/address on proxy socket %d"
" for smtp socket %d from [%s]:%s flags=%s",
myname, fd, vstream_fileno(smtp_state->smtp_client_stream),
smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
psc_print_state_flags(smtp_state->flags, myname));
tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
vstring_sprintf(remote_endpt, "[%s]:%s", smtp_state->smtp_client_addr,
smtp_state->smtp_client_port);
attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt),
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER,
ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit,
ATTR_TYPE_STR, MAIL_ATTR_SERVER_ID, MAIL_SERVICE_SMTPD,
ATTR_TYPE_END);
if (vstream_fflush(tlsproxy_stream) != 0) {
msg_warn("error sending request to %s service: %m", psc_tlsp_service);
vstream_fclose(tlsproxy_stream);
PSC_SEND_REPLY(smtp_state,
"454 4.7.0 TLS not available due to local problem\r\n");
event_request_timer(resume_event, (char *) smtp_state, 0);
return;
}
starttls_state = (PSC_STARTTLS *) mymalloc(sizeof(*starttls_state));
starttls_state->tlsproxy_stream = tlsproxy_stream;
starttls_state->resume_event = resume_event;
starttls_state->smtp_state = smtp_state;
PSC_READ_EVENT_REQUEST(vstream_fileno(tlsproxy_stream), psc_starttls_finish,
(char *) starttls_state, TLSPROXY_INIT_TIMEOUT);
}