5
/* postscreen TLS proxy support
7
/* #include <tlsproxy_clnt.h>
9
/* VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr,
10
/* peer_port, timeout)
11
/* const char *service;
13
/* VSTREAM *peer_stream;
14
/* const char *peer_addr;
15
/* const char *peer_port;
18
/* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream)
19
/* VSTREAM *proxy_stream;
21
/* void tls_proxy_context_free(tls_context)
22
/* TLS_SESS_STATE *tls_context;
24
/* tls_proxy_open() prepares for inserting the tlsproxy(8)
25
/* daemon between the current process and a remote peer (the
26
/* actual insert operation is described in the next paragraph).
27
/* The result value is a null pointer on failure. The peer_stream
28
/* is not closed. The resulting proxy stream is single-buffered.
30
/* After this, it is a good idea to use the VSTREAM_CTL_SWAP_FD
31
/* request to swap the file descriptors between the plaintext
32
/* peer_stream and the proxy stream from tls_proxy_open().
33
/* This avoids the loss of application-configurable VSTREAM
34
/* attributes on the plaintext peer_stream (such as longjmp
35
/* buffer, timeout, etc.). Once the file descriptors are
36
/* swapped, the proxy stream should be closed.
38
/* tls_proxy_context_receive() receives the TLS context object
39
/* for the named proxy stream. This function must be called
40
/* only if the TLS_PROXY_SEND_CONTEXT flag was specified in
41
/* the tls_proxy_open() call. Note that this TLS context object
42
/* is not compatible with tls_session_free(). It must be given
43
/* to tls_proxy_context_free() instead.
45
/* After this, the proxy_stream is ready for plain-text I/O.
47
/* tls_proxy_context_free() destroys a TLS context object that
48
/* was received with tls_proxy_context_receive().
52
/* The (base) name of the tlsproxy service.
56
/* .IP TLS_PROXY_FLAG_ROLE_SERVER
57
/* Request the TLS server proxy role.
58
/* .IP TLS_PROXY_FLAG_ROLE_CLIENT
59
/* Request the TLS client proxy role.
60
/* .IP TLS_PROXY_FLAG_SEND_CONTEXT
61
/* Send the TLS context object.
64
/* Stream that connects the current process to a remote peer.
66
/* Printable IP address of the remote peer_stream endpoint.
68
/* Printable TCP port of the remote peer_stream endpoint.
70
/* Time limit that the tlsproxy(8) daemon should use.
72
/* Stream from tls_proxy_open().
74
/* TLS session object from tls_proxy_context_receive().
78
/* The Secure Mailer license must be distributed with this software.
81
/* IBM T.J. Watson Research
83
/* Yorktown Heights, NY 10598, USA
92
/* Utility library. */
97
#include <stringops.h>
100
/* Global library. */
102
#include <mail_proto.h>
103
#include <mail_params.h>
105
/* TLS library-specific. */
108
#include <tls_proxy.h>
110
#define TLSPROXY_INIT_TIMEOUT 10
114
#define STR vstring_str
116
/* tls_proxy_open - open negotiations with TLS proxy */
118
VSTREAM *tls_proxy_open(const char *service, int flags,
119
VSTREAM *peer_stream,
120
const char *peer_addr,
121
const char *peer_port,
124
VSTREAM *tlsproxy_stream;
127
static VSTRING *tlsproxy_service = 0;
128
static VSTRING *remote_endpt = 0;
133
if (tlsproxy_service == 0) {
134
tlsproxy_service = vstring_alloc(20);
135
remote_endpt = vstring_alloc(20);
139
* Connect to the tlsproxy(8) daemon.
141
vstring_sprintf(tlsproxy_service, "%s/%s", MAIL_CLASS_PRIVATE, service);
142
if ((fd = LOCAL_CONNECT(STR(tlsproxy_service), BLOCKING,
143
TLSPROXY_INIT_TIMEOUT)) < 0) {
144
msg_warn("connect to %s service: %m", STR(tlsproxy_service));
149
* Initial handshake. Send the data attributes now, and send the client
150
* file descriptor in a later transaction.
152
* XXX The formatted endpoint should be a state member. Then, we can
153
* simplify all the format strings throughout the program.
155
tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
156
vstring_sprintf(remote_endpt, "[%s]:%s", peer_addr, peer_port);
157
attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
158
ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt),
159
ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
160
ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, timeout,
162
if (vstream_fflush(tlsproxy_stream) != 0) {
163
msg_warn("error sending request to %s service: %m",
164
STR(tlsproxy_service));
165
vstream_fclose(tlsproxy_stream);
170
* Receive the "TLS is available" indication.
172
* This may seem out of order, but we must have a read transaction between
173
* sending the request attributes and sending the SMTP client file
174
* descriptor. We can't assume UNIX-domain socket semantics here.
176
if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
177
ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
178
ATTR_TYPE_END) != 1 || status == 0) {
181
* The TLS proxy reports that the TLS engine is not available (due to
182
* configuration error, or other causes).
184
msg_warn("%s service role \"%s\" is not available",
185
STR(tlsproxy_service),
186
(flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "server" :
187
(flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "client" :
189
vstream_fclose(tlsproxy_stream);
194
* Send the remote SMTP client file descriptor.
196
if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
197
vstream_fileno(peer_stream)) < 0) {
200
* Some error: drop the TLS proxy stream.
202
msg_warn("sending file handle to %s service: %m",
203
STR(tlsproxy_service));
204
vstream_fclose(tlsproxy_stream);
207
return (tlsproxy_stream);
210
/* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */
212
TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream)
214
TLS_SESS_STATE *tls_context;
216
tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context));
218
if (attr_scan(proxy_stream, ATTR_FLAG_STRICT,
219
ATTR_TYPE_FUNC, tls_proxy_context_scan, (char *) tls_context,
220
ATTR_TYPE_END) != 1) {
221
tls_proxy_context_free(tls_context);
224
return (tls_context);
228
/* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */
230
void tls_proxy_context_free(TLS_SESS_STATE *tls_context)
232
if (tls_context->peer_CN)
233
myfree(tls_context->peer_CN);
234
if (tls_context->issuer_CN)
235
myfree(tls_context->issuer_CN);
236
if (tls_context->peer_fingerprint)
237
myfree(tls_context->peer_fingerprint);
238
if (tls_context->protocol)
239
myfree((char *) tls_context->protocol);
240
if (tls_context->cipher_name)
241
myfree((char *) tls_context->cipher_name);
242
myfree((char *) tls_context);