Postfix3.3.1
tls_bio_ops.c
[詳解]
1 /*++
2 /* NAME
3 /* tls_bio_ops 3
4 /* SUMMARY
5 /* TLS network basic I/O management
6 /* SYNOPSIS
7 /* #define TLS_INTERNAL
8 /* #include <tls.h>
9 /*
10 /* int tls_bio_connect(fd, timeout, context)
11 /* int fd;
12 /* int timeout;
13 /* TLS_SESS_STATE *context;
14 /*
15 /* int tls_bio_accept(fd, timeout, context)
16 /* int fd;
17 /* int timeout;
18 /* TLS_SESS_STATE *context;
19 /*
20 /* int tls_bio_shutdown(fd, timeout, context)
21 /* int fd;
22 /* int timeout;
23 /* TLS_SESS_STATE *context;
24 /*
25 /* int tls_bio_read(fd, buf, len, timeout, context)
26 /* int fd;
27 /* void *buf;
28 /* int len;
29 /* int timeout;
30 /* TLS_SESS_STATE *context;
31 /*
32 /* int tls_bio_write(fd, buf, len, timeout, context)
33 /* int fd;
34 /* void *buf;
35 /* int len;
36 /* int timeout;
37 /* TLS_SESS_STATE *context;
38 /* DESCRIPTION
39 /* This module enforces VSTREAM-style timeouts on non-blocking
40 /* I/O while performing TLS handshake or input/output operations.
41 /*
42 /* The Postfix VSTREAM read/write routines invoke the
43 /* tls_bio_read/write routines to send and receive plain-text
44 /* data. In addition, this module provides tls_bio_connect/accept
45 /* routines that trigger the initial TLS handshake. The
46 /* tls_bio_xxx routines invoke the corresponding SSL routines
47 /* that translate the requests into TLS protocol messages.
48 /*
49 /* Whenever an SSL operation indicates that network input (or
50 /* output) needs to happen, the tls_bio_xxx routines wait for
51 /* the network to become readable (or writable) within the
52 /* timeout limit, then retry the SSL operation. This works
53 /* because the network socket is in non-blocking mode.
54 /*
55 /* tls_bio_connect() performs the SSL_connect() operation.
56 /*
57 /* tls_bio_accept() performs the SSL_accept() operation.
58 /*
59 /* tls_bio_shutdown() performs the SSL_shutdown() operation.
60 /*
61 /* tls_bio_read() performs the SSL_read() operation.
62 /*
63 /* tls_bio_write() performs the SSL_write() operation.
64 /*
65 /* Arguments:
66 /* .IP fd
67 /* Network socket.
68 /* .IP buf
69 /* Read/write buffer.
70 /* .IP len
71 /* Read/write request size.
72 /* .IP timeout
73 /* Read/write timeout.
74 /* .IP TLScontext
75 /* TLS session state.
76 /* DIAGNOSTICS
77 /* A result value > 0 means successful completion.
78 /*
79 /* A result value < 0 means that the requested operation did
80 /* not complete due to TLS protocol failure, system call
81 /* failure, or for any reason described under "in addition"
82 /* below.
83 /*
84 /* A result value of 0 from tls_bio_shutdown() means that the
85 /* operation is in progress. A result value of 0 from other
86 /* tls_bio_ops(3) operations means that the remote party either
87 /* closed the network connection or that it sent a TLS shutdown
88 /* request.
89 /*
90 /* Upon return from the tls_bio_ops(3) routines the global
91 /* errno value is non-zero when the requested operation did not
92 /* complete due to system call failure.
93 /*
94 /* In addition, the result value is set to -1, and the global
95 /* errno value is set to ETIMEDOUT, when some network read/write
96 /* operation did not complete within the time limit.
97 /* LICENSE
98 /* .ad
99 /* .fi
100 /* This software is free. You can do with it whatever you want.
101 /* The original author kindly requests that you acknowledge
102 /* the use of his software.
103 /* AUTHOR(S)
104 /* Originally written by:
105 /* Lutz Jaenicke
106 /* BTU Cottbus
107 /* Allgemeine Elektrotechnik
108 /* Universitaetsplatz 3-4
109 /* D-03044 Cottbus, Germany
110 /*
111 /* Updated by:
112 /* Wietse Venema
113 /* IBM T.J. Watson Research
114 /* P.O. Box 704
115 /* Yorktown Heights, NY 10598, USA
116 /*
117 /* Victor Duchovni
118 /* Morgan Stanley
119 /*--*/
120 
121 /* System library. */
122 
123 #include <sys_defs.h>
124 #include <sys/time.h>
125 
126 #ifndef timersub
127 /* res = a - b */
128 #define timersub(a, b, res) do { \
129  (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
130  (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
131  if ((res)->tv_usec < 0) { \
132  (res)->tv_sec--; \
133  (res)->tv_usec += 1000000; \
134  } \
135  } while (0)
136 #endif
137 
138 #ifdef USE_TLS
139 
140 /* Utility library. */
141 
142 #include <msg.h>
143 #include <iostuff.h>
144 
145 /* TLS library. */
146 
147 #define TLS_INTERNAL
148 #include <tls.h>
149 
150 /* tls_bio - perform SSL input/output operation with extreme prejudice */
151 
152 int tls_bio(int fd, int timeout, TLS_SESS_STATE *TLScontext,
153  int (*hsfunc) (SSL *),
154  int (*rfunc) (SSL *, void *, int),
155  int (*wfunc) (SSL *, const void *, int),
156  void *buf, int num)
157 {
158  const char *myname = "tls_bio";
159  int status;
160  int err;
161  int enable_deadline;
162  struct timeval time_left; /* amount of time left */
163  struct timeval time_deadline; /* time of deadline */
164  struct timeval time_now; /* time after SSL_mumble() call */
165 
166  /*
167  * Compensation for interface mis-match: With VSTREAMs, timeout <= 0
168  * means wait forever; with the read/write_wait() calls below, we need to
169  * specify timeout < 0 instead.
170  *
171  * Safety: no time limit means no deadline.
172  */
173  if (timeout <= 0) {
174  timeout = -1;
175  enable_deadline = 0;
176  }
177 
178  /*
179  * Deadline management is simpler than with VSTREAMs, because we don't
180  * need to decrement a per-stream time limit. We just work within the
181  * budget that is available for this tls_bio() call.
182  */
183  else {
184  enable_deadline =
185  vstream_fstat(TLScontext->stream, VSTREAM_FLAG_DEADLINE);
186  if (enable_deadline) {
187  GETTIMEOFDAY(&time_deadline);
188  time_deadline.tv_sec += timeout;
189  }
190  }
191 
192  /*
193  * If necessary, retry the SSL handshake or read/write operation after
194  * handling any pending network I/O.
195  */
196  for (;;) {
197  if (hsfunc)
198  status = hsfunc(TLScontext->con);
199  else if (rfunc)
200  status = rfunc(TLScontext->con, buf, num);
201  else if (wfunc)
202  status = wfunc(TLScontext->con, buf, num);
203  else
204  msg_panic("%s: nothing to do here", myname);
205  err = SSL_get_error(TLScontext->con, status);
206 
207  /*
208  * Correspondence between SSL_ERROR_* error codes and tls_bio_(read,
209  * write, accept, connect, shutdown) return values (for brevity:
210  * retval).
211  *
212  * SSL_ERROR_NONE corresponds with retval > 0. With SSL_(read, write)
213  * this is the number of plaintext bytes sent or received. With
214  * SSL_(accept, connect, shutdown) this means that the operation was
215  * completed successfully.
216  *
217  * SSL_ERROR_WANT_(WRITE, READ) start a new loop iteration, or force
218  * (retval = -1, errno = ETIMEDOUT) when the time limit is exceeded.
219  *
220  * All other SSL_ERROR_* cases correspond with retval <= 0. With
221  * SSL_(read, write, accept, connect) retval == 0 means that the
222  * remote party either closed the network connection or that it
223  * requested TLS shutdown; with SSL_shutdown() retval == 0 means that
224  * our own shutdown request is in progress. With all operations
225  * retval < 0 means that there was an error. In the latter case,
226  * SSL_ERROR_SYSCALL means that error details are returned via the
227  * errno value.
228  *
229  * Find out if we must retry the operation and/or if there is pending
230  * network I/O.
231  *
232  * XXX If we're the first to invoke SSL_shutdown(), then the operation
233  * isn't really complete when the call returns. We could hide that
234  * anomaly here and repeat the call.
235  */
236  switch (err) {
237  case SSL_ERROR_WANT_WRITE:
238  case SSL_ERROR_WANT_READ:
239  if (enable_deadline) {
240  GETTIMEOFDAY(&time_now);
241  timersub(&time_deadline, &time_now, &time_left);
242  timeout = time_left.tv_sec + (time_left.tv_usec > 0);
243  if (timeout <= 0) {
244  errno = ETIMEDOUT;
245  return (-1);
246  }
247  }
248  if (err == SSL_ERROR_WANT_WRITE) {
249  if (write_wait(fd, timeout) < 0)
250  return (-1); /* timeout error */
251  } else {
252  if (read_wait(fd, timeout) < 0)
253  return (-1); /* timeout error */
254  }
255  break;
256 
257  /*
258  * Unhandled cases: SSL_ERROR_WANT_(ACCEPT, CONNECT, X509_LOOKUP)
259  * etc. Historically, Postfix silently treated these as ordinary
260  * I/O errors so we don't really know how common they are. For
261  * now, we just log a warning.
262  */
263  default:
264  msg_warn("%s: unexpected SSL_ERROR code %d", myname, err);
265  /* FALLTHROUGH */
266 
267  /*
268  * With tls_timed_read() and tls_timed_write() the caller is the
269  * VSTREAM library module which is unaware of TLS, so we log the
270  * TLS error stack here. In a better world, each VSTREAM I/O
271  * object would provide an error reporting method in addition to
272  * the timed_read and timed_write methods, so that we would not
273  * need to have ad-hoc code like this.
274  */
275  case SSL_ERROR_SSL:
276  if (rfunc || wfunc)
277  tls_print_errors();
278  /* FALLTHROUGH */
279  case SSL_ERROR_ZERO_RETURN:
280  case SSL_ERROR_NONE:
281  errno = 0; /* avoid bogus warnings */
282  /* FALLTHROUGH */
283  case SSL_ERROR_SYSCALL:
284  return (status);
285  }
286  }
287 }
288 
289 #endif
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define write_wait(fd, timeout)
Definition: iostuff.h:40
#define read_wait(fd, timeout)
Definition: iostuff.h:39
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define VSTREAM_FLAG_DEADLINE
Definition: vstream.h:86
#define timersub(a, b, res)
Definition: tls_bio_ops.c:128
#define vstream_fstat(vp, fl)
Definition: vstream.h:130