Postfix3.3.1
postscreen_starttls.c
[詳解]
1 /*++
2 /* NAME
3 /* postscreen_starttls 3
4 /* SUMMARY
5 /* postscreen TLS proxy support
6 /* SYNOPSIS
7 /* #include <postscreen.h>
8 /*
9 /* int psc_starttls_open(state, resume_event)
10 /* PSC_STATE *state;
11 /* void (*resume_event)(int unused_event, char *context);
12 /* DESCRIPTION
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
17 /* application.
18 /*
19 /* Before calling psc_starttls_open() the caller must turn off
20 /* all pending timer and I/O event requests on the SMTP client
21 /* stream.
22 /*
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.
26 /*
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.
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /* The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /* Wietse Venema
37 /* IBM T.J. Watson Research
38 /* P.O. Box 704
39 /* Yorktown Heights, NY 10598, USA
40 /*--*/
41 
42 /* System library. */
43 
44 #include <sys_defs.h>
45 
46 /* Utility library. */
47 
48 #include <msg.h>
49 #include <mymalloc.h>
50 #include <connect.h>
51 #include <stringops.h> /* concatenate() */
52 #include <vstring.h>
53 
54 /* Global library. */
55 
56 #include <mail_params.h>
57 #include <mail_proto.h>
58 
59 /* TLS library. */
60 
61 #include <tls_proxy.h>
62 
63 /* Application-specific. */
64 
65 #include <postscreen.h>
66 
67  /*
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).
71  */
72 
73  /*
74  * Transient state for the portscreen(8)-to-tlsproxy(8) hand-off protocol.
75  */
76 typedef struct {
77  VSTREAM *tlsproxy_stream; /* hand-off negotiation */
78  EVENT_NOTIFY_FN resume_event; /* call-back handler */
79  PSC_STATE *smtp_state; /* SMTP session state */
80 } PSC_STARTTLS;
81 
82 #define TLSPROXY_INIT_TIMEOUT 10
83 
84 static char *psc_tlsp_service = 0;
85 
86 /* psc_starttls_finish - complete negotiation with TLS proxy */
87 
88 static void psc_starttls_finish(int event, void *context)
89 {
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;
94  int status;
95 
96  if (msg_verbose)
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));
103 
104  /*
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.
108  */
109  if (event != EVENT_TIME)
110  event_cancel_timer(psc_starttls_finish, (void *) starttls_state);
111 
112  /*
113  * Receive the "TLS is available" indication.
114  *
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.
118  */
119  if (event != EVENT_READ
120  || attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
122  ATTR_TYPE_END) != 1 || status == 0) {
123 
124  /*
125  * The TLS proxy reports that the TLS engine is not available (due to
126  * configuration error, or other causes).
127  */
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");
132  }
133 
134  /*
135  * Send the remote SMTP client file descriptor.
136  */
137  else if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
138  vstream_fileno(smtp_state->smtp_client_stream)) < 0) {
139 
140  /*
141  * Some error: drop the TLS proxy stream.
142  */
143  msg_warn("%s sending file handle to %s service",
144  event == EVENT_TIME ? "timeout" : "problem",
145  psc_tlsp_service);
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");
150  }
151 
152  /*
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.
156  */
157  else {
158  PSC_SEND_REPLY(smtp_state, "220 2.0.0 Ready to start TLS\r\n");
159 
160  /*
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).
164  *
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.
167  */
170  CA_VSTREAM_CTL_SWAP_FD(tlsproxy_stream),
172  vstream_fclose(tlsproxy_stream); /* direct-to-client stream! */
173  smtp_state->flags |= PSC_STATE_FLAG_USING_TLS;
174  }
175 
176  /*
177  * Resume the postscreen(8) dummy SMTP engine and clean up.
178  */
179  starttls_state->resume_event(event, (void *) smtp_state);
180  myfree((void *) starttls_state);
181 }
182 
183 /* psc_starttls_open - open negotiations with TLS proxy */
184 
185 void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
186 {
187  const char *myname = "psc_starttls_open";
188  PSC_STARTTLS *starttls_state;
189  VSTREAM *tlsproxy_stream;
190  int fd;
191  static VSTRING *remote_endpt = 0;
192 
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);
197  }
198 
199  /*
200  * Connect to the tlsproxy(8) daemon. We report all errors
201  * asynchronously, to avoid having to maintain multiple delivery paths.
202  */
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, (void *) smtp_state, 0);
208  return;
209  }
210  if (msg_verbose)
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));
216 
217  /*
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.
221  *
222  * XXX The formatted endpoint should be a state member. Then, we can
223  * simplify all the format strings throughout the program.
224  */
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  SEND_ATTR_STR(MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt)),
233  ATTR_TYPE_END);
234  if (vstream_fflush(tlsproxy_stream) != 0) {
235  msg_warn("error sending request to %s service: %m", psc_tlsp_service);
236  vstream_fclose(tlsproxy_stream);
237  PSC_SEND_REPLY(smtp_state,
238  "454 4.7.0 TLS not available due to local problem\r\n");
239  event_request_timer(resume_event, (void *) smtp_state, 0);
240  return;
241  }
242 
243  /*
244  * Set up a read event for the next phase of the TLS proxy handshake.
245  */
246  starttls_state = (PSC_STARTTLS *) mymalloc(sizeof(*starttls_state));
247  starttls_state->tlsproxy_stream = tlsproxy_stream;
248  starttls_state->resume_event = resume_event;
249  starttls_state->smtp_state = smtp_state;
250  PSC_READ_EVENT_REQUEST(vstream_fileno(tlsproxy_stream), psc_starttls_finish,
251  (void *) starttls_state, TLSPROXY_INIT_TIMEOUT);
252 }
int msg_verbose
Definition: msg.c:177
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
char * smtp_client_port
Definition: postscreen.h:75
#define TLSPROXY_INIT_TIMEOUT
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
int flags
Definition: postscreen.h:70
#define LOCAL_SEND_FD
Definition: sys_defs.h:1426
EVENT_NOTIFY_FN resume_event
#define LOCAL_CONNECT
Definition: sys_defs.h:1424
#define attr_print
Definition: attr.h:109
#define MAIL_ATTR_TIMEOUT
Definition: mail_proto.h:286
#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout)
Definition: postscreen.h:325
char * var_tlsproxy_service
Definition: postscreen.c:509
char * smtp_client_addr
Definition: postscreen.h:74
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define STR(x)
Definition: anvil.c:518
#define VSTREAM_PURGE_BOTH
Definition: vstream.h:90
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 EVENT_READ
Definition: events.h:40
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
void(* EVENT_NOTIFY_FN)(int, void *)
Definition: events.h:22
#define MAIL_ATTR_SERVER_ID
Definition: mail_proto.h:296
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define EVENT_TIME
Definition: events.h:43
#define NON_BLOCKING
Definition: iostuff.h:49
#define TLS_PROXY_FLAG_ROLE_SERVER
Definition: tls_proxy.h:28
#define PSC_STATE_FLAG_USING_TLS
Definition: postscreen.h:113
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define vstream_fileno(vp)
Definition: vstream.h:115
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
void psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
#define MAIL_SERVICE_SMTPD
Definition: mail_proto.h:50
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
void event_disable_readwrite(int fd)
Definition: events.c:839
#define attr_scan
Definition: attr.h:111
#define PSC_SEND_REPLY
Definition: postscreen.h:542
int psc_normal_cmd_time_limit
Definition: postscreen.c:542
int vstream_fpurge(VSTREAM *stream, int direction)
Definition: vstream.c:1041
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
VSTREAM * tlsproxy_stream
#define CA_VSTREAM_CTL_SWAP_FD(v)
Definition: vstream.h:170
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
PSC_STATE * smtp_state
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
const char * psc_print_state_flags(int, const char *)
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
VSTREAM * smtp_client_stream
Definition: postscreen.h:72
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
void msg_info(const char *fmt,...)
Definition: msg.c:199