Postfix3.3.1
tls_proxy_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* tlsproxy_clnt 3
4 /* SUMMARY
5 /* postscreen TLS proxy support
6 /* SYNOPSIS
7 /* #include <tlsproxy_clnt.h>
8 /*
9 /* VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr,
10 /* peer_port, timeout)
11 /* const char *service;
12 /* int flags;
13 /* VSTREAM *peer_stream;
14 /* const char *peer_addr;
15 /* const char *peer_port;
16 /* int timeout;
17 /*
18 /* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream)
19 /* VSTREAM *proxy_stream;
20 /*
21 /* void tls_proxy_context_free(tls_context)
22 /* TLS_SESS_STATE *tls_context;
23 /* DESCRIPTION
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.
29 /*
30 /* After this, it is a good idea to use the CA_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.
37 /*
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.
44 /*
45 /* After this, the proxy_stream is ready for plain-text I/O.
46 /*
47 /* tls_proxy_context_free() destroys a TLS context object that
48 /* was received with tls_proxy_context_receive().
49 /*
50 /* Arguments:
51 /* .IP service
52 /* The (base) name of the tlsproxy service.
53 /* .IP flags
54 /* Bit-wise OR of:
55 /* .RS
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.
62 /* .RE
63 /* .IP peer_stream
64 /* Stream that connects the current process to a remote peer.
65 /* .IP peer_addr
66 /* Printable IP address of the remote peer_stream endpoint.
67 /* .IP peer_port
68 /* Printable TCP port of the remote peer_stream endpoint.
69 /* .IP timeout
70 /* Time limit that the tlsproxy(8) daemon should use.
71 /* .IP proxy_stream
72 /* Stream from tls_proxy_open().
73 /* .IP tls_context
74 /* TLS session object from tls_proxy_context_receive().
75 /* LICENSE
76 /* .ad
77 /* .fi
78 /* The Secure Mailer license must be distributed with this software.
79 /* AUTHOR(S)
80 /* Wietse Venema
81 /* IBM T.J. Watson Research
82 /* P.O. Box 704
83 /* Yorktown Heights, NY 10598, USA
84 /*--*/
85 
86 #ifdef USE_TLS
87 
88 /* System library. */
89 
90 #include <sys_defs.h>
91 
92 /* Utility library. */
93 
94 #include <msg.h>
95 #include <mymalloc.h>
96 #include <connect.h>
97 #include <stringops.h>
98 #include <vstring.h>
99 
100 /* Global library. */
101 
102 #include <mail_proto.h>
103 #include <mail_params.h>
104 
105 /* TLS library-specific. */
106 
107 #include <tls.h>
108 #include <tls_proxy.h>
109 
110 #define TLSPROXY_INIT_TIMEOUT 10
111 
112 /* SLMs. */
113 
114 #define STR vstring_str
115 
116 /* tls_proxy_open - open negotiations with TLS proxy */
117 
118 VSTREAM *tls_proxy_open(const char *service, int flags,
119  VSTREAM *peer_stream,
120  const char *peer_addr,
121  const char *peer_port,
122  int timeout)
123 {
124  VSTREAM *tlsproxy_stream;
125  int status;
126  int fd;
127  static VSTRING *tlsproxy_service = 0;
128  static VSTRING *remote_endpt = 0;
129 
130  /*
131  * Initialize.
132  */
133  if (tlsproxy_service == 0) {
134  tlsproxy_service = vstring_alloc(20);
135  remote_endpt = vstring_alloc(20);
136  }
137 
138  /*
139  * Connect to the tlsproxy(8) daemon.
140  */
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));
145  return (0);
146  }
147 
148  /*
149  * Initial handshake. Send the data attributes now, and send the client
150  * file descriptor in a later transaction.
151  *
152  * XXX The formatted endpoint should be a state member. Then, we can
153  * simplify all the format strings throughout the program.
154  */
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  SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
161  ATTR_TYPE_END);
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);
166  return (0);
167  }
168 
169  /*
170  * Receive the "TLS is available" indication.
171  *
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.
175  */
176  if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
178  ATTR_TYPE_END) != 1 || status == 0) {
179 
180  /*
181  * The TLS proxy reports that the TLS engine is not available (due to
182  * configuration error, or other causes).
183  */
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" :
188  "bogus role");
189  vstream_fclose(tlsproxy_stream);
190  return (0);
191  }
192 
193  /*
194  * Send the remote SMTP client file descriptor.
195  */
196  if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
197  vstream_fileno(peer_stream)) < 0) {
198 
199  /*
200  * Some error: drop the TLS proxy stream.
201  */
202  msg_warn("sending file handle to %s service: %m",
203  STR(tlsproxy_service));
204  vstream_fclose(tlsproxy_stream);
205  return (0);
206  }
207  return (tlsproxy_stream);
208 }
209 
210 /* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */
211 
212 TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream)
213 {
214  TLS_SESS_STATE *tls_context;
215 
216  tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context));
217 
218  if (attr_scan(proxy_stream, ATTR_FLAG_STRICT,
219  RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) tls_context),
220  ATTR_TYPE_END) != 1) {
221  tls_proxy_context_free(tls_context);
222  return (0);
223  } else {
224  return (tls_context);
225  }
226 }
227 
228 /* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */
229 
230 void tls_proxy_context_free(TLS_SESS_STATE *tls_context)
231 {
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_cert_fprint)
237  myfree(tls_context->peer_cert_fprint);
238  if (tls_context->protocol)
239  myfree((void *) tls_context->protocol);
240  if (tls_context->cipher_name)
241  myfree((void *) tls_context->cipher_name);
242  myfree((void *) tls_context);
243 }
244 
245 #endif
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
#define TLSPROXY_INIT_TIMEOUT
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define LOCAL_SEND_FD
Definition: sys_defs.h:1426
#define LOCAL_CONNECT
Definition: sys_defs.h:1424
#define attr_print
Definition: attr.h:109
#define MAIL_ATTR_TIMEOUT
Definition: mail_proto.h:286
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define TLS_PROXY_FLAG_ROLE_CLIENT
Definition: tls_proxy.h:29
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_REMOTE_ENDPT
Definition: mail_proto.h:282
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define TLS_PROXY_FLAG_ROLE_SERVER
Definition: tls_proxy.h:28
#define vstream_fileno(vp)
Definition: vstream.h:115
#define RECV_ATTR_FUNC(func, val)
Definition: attr.h:77
#define attr_scan
Definition: attr.h:111
#define BLOCKING
Definition: iostuff.h:48
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define ATTR_FLAG_STRICT
Definition: attr.h:103