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