3
/* postscreen_starttls 3
5
/* postscreen TLS proxy support
7
/* #include <postscreen.h>
9
/* int psc_starttls_open(state, resume_event)
11
/* void (*resume_event)(int unused_event, char *context);
13
/* This module inserts the tlsproxy(8) proxy between the
14
/* postscreen(8) server and the remote SMTP client. The entire
15
/* process happens in the background, including notification
16
/* of completion to the remote SMTP client and to the calling
19
/* Before calling psc_starttls_open() the caller must turn off
20
/* all pending timer and I/O event requests on the SMTP client
23
/* psc_starttls_open() starts the first transaction in the
24
/* tlsproxy(8) hand-off protocol, and sets up event handlers
25
/* for the successive protocol stages.
27
/* Upon completion, the event handlers call resume_event()
28
/* which must reset the SMTP helo/sender/etc. state when the
29
/* PSC_STATE_FLAG_USING_TLS is set, and set up timer and read
30
/* event requests to receive the next SMTP command.
34
/* The Secure Mailer license must be distributed with this software.
37
/* IBM T.J. Watson Research
39
/* Yorktown Heights, NY 10598, USA
46
/* Utility library. */
51
#include <stringops.h> /* concatenate() */
56
#include <mail_params.h>
57
#include <mail_proto.h>
61
#include <tls_proxy.h>
63
/* Application-specific. */
65
#include <postscreen.h>
68
* For now, this code is built into the postscreen(8) daemon. In the future
69
* it may be abstracted into a reusable library module for use by other
70
* event-driven programs (perhaps smtp-source and smtp-sink).
74
* Transient state for the portscreen(8)-to-tlsproxy(8) hand-off protocol.
77
VSTREAM *tlsproxy_stream; /* hand-off negotiation */
78
EVENT_NOTIFY_FN resume_event; /* call-back handler */
79
PSC_STATE *smtp_state; /* SMTP session state */
82
#define TLSPROXY_INIT_TIMEOUT 10
84
static char *psc_tlsp_service = 0;
86
/* psc_starttls_finish - complete negotiation with TLS proxy */
88
static void psc_starttls_finish(int event, char *context)
90
const char *myname = "psc_starttls_finish";
91
PSC_STARTTLS *starttls_state = (PSC_STARTTLS *) context;
92
PSC_STATE *smtp_state = starttls_state->smtp_state;
93
VSTREAM *tlsproxy_stream = starttls_state->tlsproxy_stream;
97
msg_info("%s: send client handle on proxy socket %d"
98
" for smtp socket %d from [%s]:%s flags=%s",
99
myname, vstream_fileno(tlsproxy_stream),
100
vstream_fileno(smtp_state->smtp_client_stream),
101
smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
102
psc_print_state_flags(smtp_state->flags, myname));
105
* We leave read-event notification enabled on the postscreen to TLS
106
* proxy stream, to avoid two kqueue/epoll/etc. system calls: one here,
107
* and one when resuming the dummy SMTP engine.
109
if (event != EVENT_TIME)
110
event_cancel_timer(psc_starttls_finish, (char *) starttls_state);
113
* Receive the "TLS is available" indication.
115
* This may seem out of order, but we must have a read transaction between
116
* sending the request attributes and sending the SMTP client file
117
* descriptor. We can't assume UNIX-domain socket semantics here.
119
if (event != EVENT_READ
120
|| attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
121
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
122
ATTR_TYPE_END) != 1 || status == 0) {
125
* The TLS proxy reports that the TLS engine is not available (due to
126
* configuration error, or other causes).
128
event_disable_readwrite(vstream_fileno(tlsproxy_stream));
129
vstream_fclose(tlsproxy_stream);
130
PSC_SEND_REPLY(smtp_state,
131
"454 4.7.0 TLS not available due to local problem\r\n");
135
* Send the remote SMTP client file descriptor.
137
else if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
138
vstream_fileno(smtp_state->smtp_client_stream)) < 0) {
141
* Some error: drop the TLS proxy stream.
143
msg_warn("%s sending file handle to %s service",
144
event == EVENT_TIME ? "timeout" : "problem",
146
event_disable_readwrite(vstream_fileno(tlsproxy_stream));
147
vstream_fclose(tlsproxy_stream);
148
PSC_SEND_REPLY(smtp_state,
149
"454 4.7.0 TLS not available due to local problem\r\n");
153
* After we send the plaintext 220 greeting, the client-side TLS engine
154
* is supposed to talk first, then the server-side TLS engine. However,
155
* postscreen(8) will not participate in that conversation.
158
PSC_SEND_REPLY(smtp_state, "220 2.0.0 Ready to start TLS\r\n");
161
* Replace our SMTP client stream by the TLS proxy stream. Once the
162
* TLS handshake is done, the TLS proxy will deliver plaintext SMTP
163
* commands to postscreen(8).
165
* Swap the file descriptors from under the VSTREAM so that we don't
166
* have to worry about loss of user-configurable VSTREAM attributes.
168
vstream_fpurge(smtp_state->smtp_client_stream, VSTREAM_PURGE_BOTH);
169
vstream_control(smtp_state->smtp_client_stream,
170
VSTREAM_CTL_SWAP_FD, tlsproxy_stream,
172
vstream_fclose(tlsproxy_stream); /* direct-to-client stream! */
173
smtp_state->flags |= PSC_STATE_FLAG_USING_TLS;
177
* Resume the postscreen(8) dummy SMTP engine and clean up.
179
starttls_state->resume_event(event, (char *) smtp_state);
180
myfree((char *) starttls_state);
183
/* psc_starttls_open - open negotiations with TLS proxy */
185
void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
187
const char *myname = "psc_starttls_open";
188
PSC_STARTTLS *starttls_state;
189
VSTREAM *tlsproxy_stream;
191
static VSTRING *remote_endpt = 0;
193
if (psc_tlsp_service == 0) {
194
psc_tlsp_service = concatenate(MAIL_CLASS_PRIVATE "/",
195
var_tlsproxy_service, (char *) 0);
196
remote_endpt = vstring_alloc(20);
200
* Connect to the tlsproxy(8) daemon. We report all errors
201
* asynchronously, to avoid having to maintain multiple delivery paths.
203
if ((fd = LOCAL_CONNECT(psc_tlsp_service, NON_BLOCKING, 1)) < 0) {
204
msg_warn("connect to %s service: %m", psc_tlsp_service);
205
PSC_SEND_REPLY(smtp_state,
206
"454 4.7.0 TLS not available due to local problem\r\n");
207
event_request_timer(resume_event, (char *) smtp_state, 0);
211
msg_info("%s: send client name/address on proxy socket %d"
212
" for smtp socket %d from [%s]:%s flags=%s",
213
myname, fd, vstream_fileno(smtp_state->smtp_client_stream),
214
smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
215
psc_print_state_flags(smtp_state->flags, myname));
218
* Initial handshake. Send the data attributes now, and send the client
219
* file descriptor in a later transaction. We report all errors
220
* asynchronously, to avoid having to maintain multiple delivery paths.
222
* XXX The formatted endpoint should be a state member. Then, we can
223
* simplify all the format strings throughout the program.
225
tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
226
vstring_sprintf(remote_endpt, "[%s]:%s", smtp_state->smtp_client_addr,
227
smtp_state->smtp_client_port);
228
attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
229
ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt),
230
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER,
231
ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit,
233
if (vstream_fflush(tlsproxy_stream) != 0) {
234
msg_warn("error sending request to %s service: %m", psc_tlsp_service);
235
vstream_fclose(tlsproxy_stream);
236
PSC_SEND_REPLY(smtp_state,
237
"454 4.7.0 TLS not available due to local problem\r\n");
238
event_request_timer(resume_event, (char *) smtp_state, 0);
243
* Set up a read event for the next phase of the TLS proxy handshake.
245
starttls_state = (PSC_STARTTLS *) mymalloc(sizeof(*starttls_state));
246
starttls_state->tlsproxy_stream = tlsproxy_stream;
247
starttls_state->resume_event = resume_event;
248
starttls_state->smtp_state = smtp_state;
249
PSC_READ_EVENT_REQUEST(vstream_fileno(tlsproxy_stream), psc_starttls_finish,
250
(char *) starttls_state, TLSPROXY_INIT_TIMEOUT);