]> granicus.if.org Git - apache/blob - modules/ssl/ssl_engine_io.c
4ba1574ca8839cc5b9d331892a32d4541134b02d
[apache] / modules / ssl / ssl_engine_io.c
1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  ssl_engine_io.c
8 **  I/O Functions
9 */
10
11 /* ====================================================================
12  * Copyright (c) 1998-2001 Ralf S. Engelschall. All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  *
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  *
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following
23  *    disclaimer in the documentation and/or other materials
24  *    provided with the distribution.
25  *
26  * 3. All advertising materials mentioning features or use of this
27  *    software must display the following acknowledgment:
28  *    "This product includes software developed by
29  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
30  *     mod_ssl project (http://www.modssl.org/)."
31  *
32  * 4. The names "mod_ssl" must not be used to endorse or promote
33  *    products derived from this software without prior written
34  *    permission. For written permission, please contact
35  *    rse@engelschall.com.
36  *
37  * 5. Products derived from this software may not be called "mod_ssl"
38  *    nor may "mod_ssl" appear in their names without prior
39  *    written permission of Ralf S. Engelschall.
40  *
41  * 6. Redistributions of any form whatsoever must retain the following
42  *    acknowledgment:
43  *    "This product includes software developed by
44  *     Ralf S. Engelschall <rse@engelschall.com> for use in the
45  *     mod_ssl project (http://www.modssl.org/)."
46  *
47  * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
48  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR
51  * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
56  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
58  * OF THE POSSIBILITY OF SUCH DAMAGE.
59  * ====================================================================
60  */
61                              /* ``MY HACK: This universe.
62                                   Just one little problem:
63                                   core keeps dumping.''
64                                             -- Unknown    */
65 #include "mod_ssl.h"
66
67 /*  _________________________________________________________________
68 **
69 **  I/O Request Body Sucking and Re-Injection
70 **  _________________________________________________________________
71 */
72
73 #ifndef SSL_CONSERVATIVE
74
75 /*
76  * Background:
77  *
78  * 1. When the client sends a HTTP/HTTPS request, Apache's core code
79  * reads only the request line ("METHOD /path HTTP/x.y") and the
80  * attached MIME headers ("Foo: bar") up to the terminating line ("CR
81  * LF"). An attached request body (for instance the data of a POST
82  * method) is _NOT_ read. Instead it is read by mod_cgi's content
83  * handler and directly passed to the CGI script.
84  *
85  * 2. mod_ssl supports per-directory re-configuration of SSL parameters.
86  * This is implemented by performing an SSL renegotiation of the
87  * re-configured parameters after the request is read, but before the
88  * response is sent. In more detail: the renegotiation happens after the
89  * request line and MIME headers were read, but _before_ the attached
90  * request body is read. The reason simply is that in the HTTP protocol
91  * usually there is no acknowledgment step between the headers and the
92  * body (there is the 100-continue feature and the chunking facility
93  * only), so Apache has no API hook for this step.
94  *
95  * 3. the problem now occurs when the client sends a POST request for
96  * URL /foo via HTTPS the server and the server has SSL parameters
97  * re-configured on a per-URL basis for /foo. Then mod_ssl has to
98  * perform an SSL renegotiation after the request was read and before
99  * the response is sent. But the problem is the pending POST body data
100  * in the receive buffer of SSL (which Apache still has not read - it's
101  * pending until mod_cgi sucks it in). When mod_ssl now tries to perform
102  * the renegotiation the pending data leads to an I/O error.
103  *
104  * Solution Idea:
105  *
106  * There are only two solutions: Either to simply state that POST
107  * requests to URLs with SSL re-configurations are not allowed, or to
108  * renegotiate really after the _complete_ request (i.e. including
109  * the POST body) was read. Obviously the latter would be preferred,
110  * but it cannot be done easily inside Apache, because as already
111  * mentioned, there is no API step between the body reading and the body
112  * processing. And even when we mod_ssl would hook directly into the
113  * loop of mod_cgi, we wouldn't solve the problem for other handlers, of
114  * course. So the only general solution is to suck in the pending data
115  * of the request body from the OpenSSL BIO into the Apache BUFF. Then
116  * the renegotiation can be done and after this step Apache can proceed
117  * processing the request as before.
118  *
119  * Solution Implementation:
120  *
121  * We cannot simply suck in the data via an SSL_read-based loop because of
122  * HTTP chunking. Instead we _have_ to use the Apache API for this step which
123  * is aware of HTTP chunking. So the trick is to suck in the pending request
124  * data via the Apache API (which uses Apache's BUFF code and in the
125  * background mod_ssl's I/O glue code) and re-inject it later into the Apache
126  * BUFF code again. This way the data flows twice through the Apache BUFF, of
127  * course. But this way the solution doesn't depend on any Apache specifics
128  * and is fully transparent to Apache modules.
129  */
130
131 struct ssl_io_suck_st {
132     BOOL  active;
133     char *bufptr;
134     int   buflen;
135     char *pendptr;
136     int   pendlen;
137 };
138
139 /* prepare request_rec structure for input sucking */
140 static void ssl_io_suck_start(request_rec *r)
141 {
142     struct ssl_io_suck_st *ss;
143
144     ss = ap_ctx_get(r->ctx, "ssl::io::suck");
145     if (ss == NULL) {
146         ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));
147         ap_ctx_set(r->ctx, "ssl::io::suck", ss);
148         ss->buflen  = 8192;
149         ss->bufptr  = ap_palloc(r->pool, ss->buflen);
150     }
151     ss->pendptr = ss->bufptr;
152     ss->pendlen = 0;
153     ss->active = FALSE;
154     return;
155 }
156
157 /* record a sucked input chunk */
158 static void ssl_io_suck_record(request_rec *r, char *buf, int len)
159 {
160     struct ssl_io_suck_st *ss;
161     
162     if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
163         return;
164     if (((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) < len) {
165         /* "expand" buffer: actually we cannot really expand the buffer
166            here, because Apache's pool system doesn't support expanding chunks
167            of memory. Instead we have to either reuse processed data or
168            allocate a new chunk of memory in advance if we really need more
169            memory. */
170         int newlen;
171         char *newptr;
172
173         if ((  (ss->pendptr - ss->bufptr) 
174              + ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) {
175             /* make memory available by reusing already processed data */
176             memmove(ss->bufptr, ss->pendptr, ss->pendlen);
177             ss->pendptr = ss->bufptr;
178         }
179         else {
180             /* too bad, we have to allocate a new larger buffer */
181             newlen = (ss->buflen * 2) + len;
182             newptr = ap_palloc(r->pool, newlen);
183             ss->bufptr  = newptr;
184             ss->buflen  = newlen;
185             memcpy(ss->bufptr, ss->pendptr, ss->pendlen);
186             ss->pendptr = ss->bufptr;
187         }
188     }
189     memcpy(ss->pendptr+ss->pendlen, buf, len);
190     ss->pendlen += len;
191     return;
192 }
193
194 /* finish request_rec after input sucking */
195 static void ssl_io_suck_end(request_rec *r)
196 {
197     struct ssl_io_suck_st *ss;
198     
199     if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)
200         return;
201     ss->active = TRUE;
202     r->read_body    = REQUEST_NO_BODY;
203     r->read_length  = 0;
204     r->read_chunked = 0;
205     r->remaining    = 0;
206     ap_bsetflag(r->connection->client, B_CHUNK, 0);
207     return;
208 }
209
210 void ssl_io_suck(request_rec *r, SSL *ssl)
211 {
212     int rc;
213     int len;
214     char *buf;
215     int buflen;
216     char c;
217     int sucked;
218
219     if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {
220         if (ap_should_client_block(r)) {
221
222             /* read client request block through Apache API */
223             buflen = HUGE_STRING_LEN;
224             buf = ap_palloc(r->pool, buflen);
225             ap_hard_timeout("SSL I/O request body pre-sucking", r);
226             sucked = 0;
227             ssl_io_suck_start(r);
228             while ((len = ap_get_client_block(r, buf, buflen)) > 0) {
229                 ssl_io_suck_record(r, buf, len);
230                 sucked += len;
231             }
232             ssl_io_suck_end(r);
233             ap_kill_timeout(r);
234
235             /* suck trailing data (usually CR LF) which 
236                is still in the Apache BUFF layer */
237             while (ap_bpeekc(r->connection->client) != EOF) {
238                 c = ap_bgetc(r->connection->client);
239                 ssl_io_suck_record(r, &c, 1);
240                 sucked++;
241             }
242
243             ssl_log(r->server, SSL_LOG_TRACE, 
244                     "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "
245                     "for delayed injection into Apache I/O layer", sucked);
246         }
247     }
248     return;
249 }
250     
251 /* the SSL_read replacement routine which knows about the suck buffer */
252 static int ssl_io_suck_read(SSL *ssl, char *buf, int len)
253 {
254     ap_ctx *actx;
255     struct ssl_io_suck_st *ss;
256     request_rec *r = NULL;
257     int rv;
258
259     actx = (ap_ctx *)SSL_get_app_data2(ssl);
260     if (actx != NULL)
261         r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");
262
263     rv = -1;
264     if (r != NULL) {
265         ss = ap_ctx_get(r->ctx, "ssl::io::suck");
266         if (ss != NULL) {
267             if (ss->active && ss->pendlen > 0) {
268                 /* ok, there is pre-sucked data */
269                 len = (ss->pendlen > len ? len : ss->pendlen);
270                 memcpy(buf, ss->pendptr, len);
271                 ss->pendptr += len;
272                 ss->pendlen -= len;
273                 ssl_log(r->server, SSL_LOG_TRACE, 
274                         "I/O: injecting %d bytes of pre-sucked data "
275                         "into Apache I/O layer", len);
276                 rv = len;
277             }
278         }
279     }
280     if (rv == -1)
281         rv = SSL_read(ssl, buf, len);
282     return rv;
283 }
284
285 /* override SSL_read in the following code... */
286 #define SSL_read ssl_io_suck_read
287
288 #endif /* !SSL_CONSERVATIVE */
289
290 /*  _________________________________________________________________
291 **
292 **  I/O Hooks
293 **  _________________________________________________________________
294 */
295
296 #ifndef NO_WRITEV
297 #include <sys/types.h>
298 #include <sys/uio.h>
299 #endif
300
301 static int ssl_io_hook_read(BUFF *fb, char *buf, int len);
302 static int ssl_io_hook_write(BUFF *fb, char *buf, int len);
303 #ifndef NO_WRITEV
304 static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt);
305 #endif
306 #ifdef WIN32
307 static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len);
308 static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len);
309 #endif /* WIN32 */
310
311 void ssl_io_register(void)
312 {
313     ap_hook_register("ap::buff::read",   ssl_io_hook_read,  AP_HOOK_NOCTX);
314     ap_hook_register("ap::buff::write",  ssl_io_hook_write, AP_HOOK_NOCTX);
315 #ifndef NO_WRITEV
316     ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX);
317 #endif
318 #ifdef WIN32
319     ap_hook_register("ap::buff::recvwithtimeout",
320                      ssl_io_hook_recvwithtimeout, AP_HOOK_NOCTX);
321     ap_hook_register("ap::buff::sendwithtimeout",
322                      ssl_io_hook_sendwithtimeout, AP_HOOK_NOCTX);
323 #endif
324     return;
325 }
326
327 void ssl_io_unregister(void)
328 {
329     ap_hook_unregister("ap::buff::read",   ssl_io_hook_read);
330     ap_hook_unregister("ap::buff::write",  ssl_io_hook_write);
331 #ifndef NO_WRITEV
332     ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev);
333 #endif
334 #ifdef WIN32
335     ap_hook_unregister("ap::buff::recvwithtimeout", ssl_io_hook_recvwithtimeout);
336     ap_hook_unregister("ap::buff::sendwithtimeout", ssl_io_hook_sendwithtimeout);
337 #endif
338     return;
339 }
340
341 static int ssl_io_hook_read(BUFF *fb, char *buf, int len)
342 {
343     SSL *ssl;
344     conn_rec *c;
345     int rc;
346
347     if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
348         rc = SSL_read(ssl, buf, len);
349         /*
350          * Simulate an EINTR in case OpenSSL wants to read more.
351          * (This is usually the case when the client forces an SSL
352          * renegotation which is handled implicitly by OpenSSL.)
353          */
354         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ)
355             errno = EINTR;
356         /*
357          * Log SSL errors
358          */
359         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
360             c = (conn_rec *)SSL_get_app_data(ssl);
361             ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
362                     "SSL error on reading data");
363         }
364         /*
365          * read(2) returns only the generic error number -1
366          */
367         if (rc < 0)
368             rc = -1;
369     }
370     else
371         rc = read(fb->fd_in, buf, len);
372     return rc;
373 }
374
375 static int ssl_io_hook_write(BUFF *fb, char *buf, int len)
376 {
377     SSL *ssl;
378     conn_rec *c;
379     int rc;
380
381     if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
382         rc = SSL_write(ssl, buf, len);
383         /*
384          * Simulate an EINTR in case OpenSSL wants to write more.
385          */
386         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
387             errno = EINTR;
388         /*
389          * Log SSL errors
390          */
391         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
392             c = (conn_rec *)SSL_get_app_data(ssl);
393             ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
394                     "SSL error on writing data");
395         }
396         /*
397          * write(2) returns only the generic error number -1
398          */
399         if (rc < 0)
400             rc = -1;
401     }
402     else
403         rc = write(fb->fd, buf, len);
404     return rc;
405 }
406
407 #ifndef NO_WRITEV
408 /* the prototype for our own SSL_writev() */
409 static int SSL_writev(SSL *, const struct iovec *, int);
410
411 static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt)
412 {
413     SSL *ssl;
414     conn_rec *c;
415     int rc;
416
417     if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
418         rc = SSL_writev(ssl, iov, iovcnt);
419         /*
420          * Simulate an EINTR in case OpenSSL wants to write more.
421          */
422         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
423             errno = EINTR;
424         /*
425          * Log SSL errors
426          */
427         if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {
428             c = (conn_rec *)SSL_get_app_data(ssl);
429             ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
430                     "SSL error on writing data");
431         }
432         /*
433          * writev(2) returns only the generic error number -1
434          */
435         if (rc < 0)
436             rc = -1;
437     }
438     else
439         rc = writev(fb->fd, iov, iovcnt);
440     return rc;
441 }
442 #endif
443
444 #ifdef WIN32
445
446 /* these two functions are exported from buff.c under WIN32 */
447 API_EXPORT(int) sendwithtimeout(int sock, const char *buf, int len, int flags);
448 API_EXPORT(int) recvwithtimeout(int sock, char *buf, int len, int flags);
449
450 /* and the prototypes for our SSL_xxx variants */
451 static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len);
452 static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len);
453
454 static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len)
455 {
456     SSL *ssl;
457     int rc;
458
459     if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL)
460         rc = SSL_recvwithtimeout(fb, buf, len);
461     else
462         rc = recvwithtimeout(fb->fd, buf, len, 0);
463     return rc;
464 }
465
466 static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len)
467 {
468     SSL *ssl;
469     int rc;
470
471     if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL)
472         rc = SSL_sendwithtimeout(fb, buf, len);
473     else
474         rc = sendwithtimeout(fb->fd, buf, len, 0);
475     return rc;
476 }
477
478 #endif /* WIN32 */
479
480 /*  _________________________________________________________________
481 **
482 **  Special Functions for OpenSSL
483 **  _________________________________________________________________
484 */
485
486 #ifdef WIN32
487
488 static int SSL_sendwithtimeout(BUFF *fb, const char *buf, int len)
489 {
490     int iostate = 1;
491     fd_set fdset;
492     struct timeval tv;
493     int err = WSAEWOULDBLOCK;
494     int rv;
495     int retry;
496     int sock = fb->fd;
497     SSL *ssl;
498
499     ssl = ap_ctx_get(fb->ctx, "ssl");
500
501     if (!(tv.tv_sec = ap_check_alarm()))
502         return (SSL_write(ssl, (char*)buf, len));
503
504     rv = ioctlsocket(sock, FIONBIO, &iostate);
505     iostate = 0;
506     if (rv) {
507         err = WSAGetLastError();
508         ap_assert(0);
509     }
510     rv = SSL_write(ssl, (char*)buf, len);
511     if (rv <= 0) {
512         if (BIO_sock_should_retry(rv)) {
513             do {
514                 retry = 0;
515                 FD_ZERO(&fdset);
516                 FD_SET((unsigned int)sock, &fdset);
517                 tv.tv_usec = 0;
518                 rv = select(FD_SETSIZE, NULL, &fdset, NULL, &tv);
519                 if (rv == SOCKET_ERROR)
520                     err = WSAGetLastError();
521                 else if (rv == 0) {
522                     ioctlsocket(sock, FIONBIO, &iostate);
523                     if(ap_check_alarm() < 0) {
524                         WSASetLastError(EINTR); /* Simulate an alarm() */
525                         return (SOCKET_ERROR);
526                     }
527                 }
528                 else {
529                     rv = SSL_write(ssl, (char*)buf, len);
530                     if (BIO_sock_should_retry(rv)) {
531                         ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL,
532                                      "select claimed we could write, "
533                                      "but in fact we couldn't. "
534                                      "This is a bug in Windows.");
535                         retry = 1;
536                         Sleep(100);
537                     }
538                 }
539             } while(retry);
540         }
541     }
542     ioctlsocket(sock, FIONBIO, &iostate);
543     if (rv == SOCKET_ERROR)
544         WSASetLastError(err);
545     return (rv);
546 }
547
548 static int SSL_recvwithtimeout(BUFF *fb, char *buf, int len)
549 {
550     int iostate = 1;
551     fd_set fdset;
552     struct timeval tv;
553     int err = WSAEWOULDBLOCK;
554     int rv;
555     int sock = fb->fd_in;
556     SSL *ssl;
557     int retry;
558
559     ssl = ap_ctx_get(fb->ctx, "ssl");
560
561     if (!(tv.tv_sec = ap_check_alarm()))
562         return (SSL_read(ssl, buf, len));
563
564     rv = ioctlsocket(sock, FIONBIO, &iostate);
565     iostate = 0;
566     ap_assert(!rv);
567     rv = SSL_read(ssl, buf, len);
568     if (rv <= 0) {
569         if (BIO_sock_should_retry(rv)) {
570             do {
571                 retry = 0;
572                 FD_ZERO(&fdset);
573                 FD_SET((unsigned int)sock, &fdset);
574                 tv.tv_usec = 0;
575                 rv = select(FD_SETSIZE, &fdset, NULL, NULL, &tv);
576                 if (rv == SOCKET_ERROR)
577                     err = WSAGetLastError();
578                 else if (rv == 0) {
579                     ioctlsocket(sock, FIONBIO, &iostate);
580                     ap_check_alarm();
581                     WSASetLastError(WSAEWOULDBLOCK);
582                     return (SOCKET_ERROR);
583                 }
584                 else {
585                     rv = SSL_read(ssl, buf, len);
586                     if (rv == SOCKET_ERROR) {
587                         if (BIO_sock_should_retry(rv)) {
588                           ap_log_error(APLOG_MARK,APLOG_DEBUG, NULL,
589                                        "select claimed we could read, "
590                                        "but in fact we couldn't. "
591                                        "This is a bug in Windows.");
592                           retry = 1;
593                           Sleep(100);
594                         }
595                         else {
596                             err = WSAGetLastError();
597                         }
598                     }
599                 }
600             } while(retry);
601         }
602     }
603     ioctlsocket(sock, FIONBIO, &iostate);
604     if (rv == SOCKET_ERROR)
605         WSASetLastError(err);
606     return (rv);
607 }
608
609 #endif /*WIN32*/
610
611 /*
612  * There is no SSL_writev() provided by OpenSSL. The reason is mainly because
613  * OpenSSL has to fragment the data itself again for the SSL record layer, so a
614  * writev() like interface makes not much sense.  What we do is to emulate it
615  * to at least being able to use the write() like interface. But keep in mind
616  * that the network I/O performance is not write() like, of course.
617  */
618 #ifndef NO_WRITEV
619 static int SSL_writev(SSL *ssl, const struct iovec *iov, int iovcnt)
620 {
621     int i;
622     int n;
623     int rc;
624
625     rc = 0;
626     for (i = 0; i < iovcnt; i++) {
627         if ((n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len)) == -1) {
628             rc = -1;
629             break;
630         }
631         rc += n;
632     }
633     return rc;
634 }
635 #endif
636
637 /*  _________________________________________________________________
638 **
639 **  I/O Data Debugging
640 **  _________________________________________________________________
641 */
642
643 #define DUMP_WIDTH 16
644
645 static void ssl_io_data_dump(server_rec *srvr, const char *s, long len)
646 {
647     char buf[256];
648     char tmp[64];
649     int i, j, rows, trunc;
650     unsigned char ch;
651
652     trunc = 0;
653     for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--)
654         trunc++;
655     rows = (len / DUMP_WIDTH);
656     if ((rows * DUMP_WIDTH) < len)
657         rows++;
658     ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
659             "+-------------------------------------------------------------------------+");
660     for(i = 0 ; i< rows; i++) {
661         ap_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
662         ap_cpystrn(buf, tmp, sizeof(buf));
663         for (j = 0; j < DUMP_WIDTH; j++) {
664             if (((i * DUMP_WIDTH) + j) >= len)
665                 ap_cpystrn(buf+strlen(buf), "   ", sizeof(buf)-strlen(buf));
666             else {
667                 ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
668                 ap_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
669                 ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
670             }
671         }
672         ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
673         for (j = 0; j < DUMP_WIDTH; j++) {
674             if (((i * DUMP_WIDTH) + j) >= len)
675                 ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
676             else {
677                 ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
678                 ap_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
679                 ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
680             }
681         }
682         ap_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
683         ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf);
684     }
685     if (trunc > 0)
686         ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
687                 "| %04x - <SPACES/NULS>", len + trunc);
688     ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
689             "+-------------------------------------------------------------------------+");
690     return;
691 }
692
693 long ssl_io_data_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long rc)
694 {
695     SSL *ssl;
696     conn_rec *c;
697     server_rec *s;
698
699     if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
700         return rc;
701     if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
702         return rc;
703     s = c->server;
704
705     if (   cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
706         || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
707         if (rc >= 0) {
708             ssl_log(s, SSL_LOG_DEBUG,
709                     "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s",
710                     SSL_LIBRARY_NAME,
711                     (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
712                     rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
713                     bio, argp,
714                     (argp != NULL ? "(BIO dump follows)" : "(Ops, no memory buffer?)"));
715             if (argp != NULL)
716                 ssl_io_data_dump(s, argp, rc);
717         }
718         else {
719             ssl_log(s, SSL_LOG_DEBUG,
720                     "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
721                     SSL_LIBRARY_NAME, argi,
722                     (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
723                     bio, argp);
724         }
725     }
726     return rc;
727 }
728