1 /*
2 * petal.c - https daemon that is small and beautiful.
3 *
4 * Copyright (c) 2010, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /**
37 * \file
38 *
39 * HTTP1.1/SSL server.
40 */
41
42 #include "config.h"
43 #ifdef HAVE_GETOPT_H
44 #include <getopt.h>
45 #endif
46 #ifdef HAVE_OPENSSL_SSL_H
47 #include <openssl/ssl.h>
48 #endif
49 #ifdef HAVE_OPENSSL_ERR_H
50 #include <openssl/err.h>
51 #endif
52 #ifdef HAVE_OPENSSL_RAND_H
53 #include <openssl/rand.h>
54 #endif
55 #include <openssl/x509.h>
56 #include <openssl/pem.h>
57 #include <ctype.h>
58 #include <signal.h>
59 #if defined(UNBOUND_ALLOC_LITE) || defined(UNBOUND_ALLOC_STATS)
60 #ifdef malloc
61 #undef malloc
62 #endif
63 #ifdef free
64 #undef free
65 #endif
66 #endif /* alloc lite or alloc stats */
67
68 /** verbosity for this application */
69 static int verb = 0;
70
71 /** Give petal usage, and exit (1). */
72 static void
usage(void)73 usage(void)
74 {
75 printf("Usage: petal [opts]\n");
76 printf(" https daemon serves files from ./'host'/filename\n");
77 printf(" (no hostname: from the 'default' directory)\n");
78 printf("-a addr bind to this address, 127.0.0.1\n");
79 printf("-p port port number, default 443\n");
80 printf("-k keyfile SSL private key file (PEM), petal.key\n");
81 printf("-c certfile SSL certificate file (PEM), petal.pem\n");
82 printf("-v more verbose\n");
83 printf("-h show this usage help\n");
84 printf("Version %s\n", PACKAGE_VERSION);
85 printf("BSD licensed, see LICENSE in source package for details.\n");
86 printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
87 exit(1);
88 }
89
90 /** fatal exit */
print_exit(const char * str)91 static void print_exit(const char* str) {printf("error %s\n", str); exit(1);}
92 /** print errno */
log_errno(const char * str)93 static void log_errno(const char* str)
94 {printf("error %s: %s\n", str, strerror(errno));}
95
96 /** parse a text IP address into a sockaddr */
97 static int
parse_ip_addr(char * str,int port,struct sockaddr_storage * ret,socklen_t * l)98 parse_ip_addr(char* str, int port, struct sockaddr_storage* ret, socklen_t* l)
99 {
100 socklen_t len = 0;
101 struct sockaddr_storage* addr = NULL;
102 struct sockaddr_in6 a6;
103 struct sockaddr_in a;
104 uint16_t p = (uint16_t)port;
105 int fam = 0;
106 memset(&a6, 0, sizeof(a6));
107 memset(&a, 0, sizeof(a));
108
109 if(inet_pton(AF_INET6, str, &a6.sin6_addr) > 0) {
110 /* it is an IPv6 */
111 fam = AF_INET6;
112 a6.sin6_family = AF_INET6;
113 a6.sin6_port = (in_port_t)htons(p);
114 addr = (struct sockaddr_storage*)&a6;
115 len = (socklen_t)sizeof(struct sockaddr_in6);
116 }
117 if(inet_pton(AF_INET, str, &a.sin_addr) > 0) {
118 /* it is an IPv4 */
119 fam = AF_INET;
120 a.sin_family = AF_INET;
121 a.sin_port = (in_port_t)htons(p);
122 addr = (struct sockaddr_storage*)&a;
123 len = (socklen_t)sizeof(struct sockaddr_in);
124 }
125 if(!len) print_exit("cannot parse addr");
126 *l = len;
127 memmove(ret, addr, len);
128 return fam;
129 }
130
131 /** close the fd */
132 static void
fd_close(int fd)133 fd_close(int fd)
134 {
135 #ifndef USE_WINSOCK
136 close(fd);
137 #else
138 closesocket(fd);
139 #endif
140 }
141
142 /**
143 * Read one line from SSL
144 * zero terminates.
145 * skips "\r\n" (but not copied to buf).
146 * @param ssl: the SSL connection to read from (blocking).
147 * @param buf: buffer to return line in.
148 * @param len: size of the buffer.
149 * @return 0 on error, 1 on success.
150 */
151 static int
read_ssl_line(SSL * ssl,char * buf,size_t len)152 read_ssl_line(SSL* ssl, char* buf, size_t len)
153 {
154 size_t n = 0;
155 int r;
156 int endnl = 0;
157 while(1) {
158 if(n >= len) {
159 if(verb) printf("line too long\n");
160 return 0;
161 }
162 if((r = SSL_read(ssl, buf+n, 1)) <= 0) {
163 if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
164 /* EOF */
165 break;
166 }
167 if(verb) printf("could not SSL_read\n");
168 return 0;
169 }
170 if(endnl && buf[n] == '\n') {
171 break;
172 } else if(endnl) {
173 /* bad data */
174 if(verb) printf("error: stray linefeeds\n");
175 return 0;
176 } else if(buf[n] == '\r') {
177 /* skip \r, and also \n on the wire */
178 endnl = 1;
179 continue;
180 } else if(buf[n] == '\n') {
181 /* skip the \n, we are done */
182 break;
183 } else n++;
184 }
185 buf[n] = 0;
186 return 1;
187 }
188
189 /** process one http header */
190 static int
process_one_header(char * buf,char * file,size_t flen,char * host,size_t hlen,int * vs)191 process_one_header(char* buf, char* file, size_t flen, char* host, size_t hlen,
192 int* vs)
193 {
194 if(strncasecmp(buf, "GET ", 4) == 0) {
195 char* e = strstr(buf, " HTTP/1.1");
196 if(!e) e = strstr(buf, " http/1.1");
197 if(!e) {
198 e = strstr(buf, " HTTP/1.0");
199 if(!e) e = strstr(buf, " http/1.0");
200 if(!e) e = strrchr(buf, ' ');
201 if(!e) e = strrchr(buf, '\t');
202 if(e) *vs = 10;
203 }
204 if(e) *e = 0;
205 if(strlen(buf) < 4) return 0;
206 (void)strlcpy(file, buf+4, flen);
207 } else if(strncasecmp(buf, "Host: ", 6) == 0) {
208 (void)strlcpy(host, buf+6, hlen);
209 }
210 return 1;
211 }
212
213 /** read http headers and process them */
214 static int
read_http_headers(SSL * ssl,char * file,size_t flen,char * host,size_t hlen,int * vs)215 read_http_headers(SSL* ssl, char* file, size_t flen, char* host, size_t hlen,
216 int* vs)
217 {
218 char buf[1024];
219 file[0] = 0;
220 host[0] = 0;
221 while(read_ssl_line(ssl, buf, sizeof(buf))) {
222 if(verb>=2) printf("read: %s\n", buf);
223 if(buf[0] == 0) {
224 int e = ERR_peek_error();
225 printf("error string: %s\n", ERR_reason_error_string(e));
226 return 1;
227 }
228 if(!process_one_header(buf, file, flen, host, hlen, vs))
229 return 0;
230 }
231 return 0;
232 }
233
234 /** setup SSL context */
235 static SSL_CTX*
setup_ctx(char * key,char * cert)236 setup_ctx(char* key, char* cert)
237 {
238 SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
239 if(!ctx) print_exit("out of memory");
240 #if SSL_OP_NO_SSLv2 != 0
241 (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
242 #endif
243 (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
244 #ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
245 SSL_CTX_set_security_level(ctx, 0); /* for keys in tests */
246 #endif
247 if(!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
248 int e = ERR_peek_error();
249 printf("error string: %s\n", ERR_reason_error_string(e));
250 print_exit("cannot read cert");
251 }
252 if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM))
253 print_exit("cannot read key");
254 if(!SSL_CTX_check_private_key(ctx))
255 print_exit("private key is not correct");
256 #if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO
257 if (!SSL_CTX_set_ecdh_auto(ctx,1))
258 if(verb>=1) printf("failed to set_ecdh_auto, not enabling ECDHE\n");
259 #elif defined(USE_ECDSA)
260 if(1) {
261 EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
262 if (!ecdh) {
263 if(verb>=1) printf("could not find p256, not enabling ECDHE\n");
264 } else {
265 if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) {
266 if(verb>=1) printf("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE\n");
267 }
268 EC_KEY_free(ecdh);
269 }
270 }
271 #endif
272 if(!SSL_CTX_load_verify_locations(ctx, cert, NULL))
273 print_exit("cannot load cert verify locations");
274 return ctx;
275 }
276
277 /** setup listening TCP */
278 static int
setup_fd(char * addr,int port)279 setup_fd(char* addr, int port)
280 {
281 struct sockaddr_storage ad;
282 socklen_t len;
283 int fd;
284 int c = 1;
285 int fam = parse_ip_addr(addr, port, &ad, &len);
286 fd = socket(fam, SOCK_STREAM, 0);
287 if(fd == -1) {
288 log_errno("socket");
289 return -1;
290 }
291 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
292 (void*)&c, (socklen_t) sizeof(int)) < 0) {
293 log_errno("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
294 }
295 if(bind(fd, (struct sockaddr*)&ad, len) == -1) {
296 log_errno("bind");
297 fd_close(fd);
298 return -1;
299 }
300 if(listen(fd, 5) == -1) {
301 log_errno("listen");
302 fd_close(fd);
303 return -1;
304 }
305 return fd;
306 }
307
308 /** setup SSL connection to the client */
309 static SSL*
setup_ssl(int s,SSL_CTX * ctx)310 setup_ssl(int s, SSL_CTX* ctx)
311 {
312 SSL* ssl = SSL_new(ctx);
313 if(!ssl) return NULL;
314 SSL_set_accept_state(ssl);
315 (void)SSL_set_mode(ssl, (long)SSL_MODE_AUTO_RETRY);
316 if(!SSL_set_fd(ssl, s)) {
317 SSL_free(ssl);
318 return NULL;
319 }
320 return ssl;
321 }
322
323 /** check a file name for safety */
324 static int
file_name_is_safe(char * s)325 file_name_is_safe(char* s)
326 {
327 size_t l = strlen(s);
328 if(s[0] != '/')
329 return 0; /* must start with / */
330 if(strstr(s, "/../"))
331 return 0; /* no updirs in URL */
332 if(l>=3 && s[l-1]=='.' && s[l-2]=='.' && s[l-3]=='/')
333 return 0; /* ends with /.. */
334 return 1;
335 }
336
337 /** adjust host */
338 static void
adjust_host(char * host)339 adjust_host(char* host)
340 {
341 size_t i, len;
342 /* remove a port number if present */
343 if(strrchr(host, ':'))
344 *strrchr(host, ':') = 0;
345 /* lowercase */
346 len = strlen(host);
347 for(i=0; i<len; i++)
348 host[i] = tolower((unsigned char)host[i]);
349 }
350
351 /** adjust filename */
352 static void
adjust_file(char * file)353 adjust_file(char* file)
354 {
355 size_t i, len;
356 len = strlen(file);
357 for(i=0; i<len; i++)
358 file[i] = tolower((unsigned char)file[i]);
359 }
360
361 /** check a host name for safety */
362 static int
host_name_is_safe(char * s)363 host_name_is_safe(char* s)
364 {
365 if(strchr(s, '/'))
366 return 0;
367 if(strcmp(s, "..") == 0)
368 return 0;
369 if(strcmp(s, ".") == 0)
370 return 0;
371 return 1;
372 }
373
374 /** provide file in whole transfer */
375 static void
provide_file_10(SSL * ssl,char * fname)376 provide_file_10(SSL* ssl, char* fname)
377 {
378 char* buf, *at;
379 size_t len, avail, header_reserve=1024;
380 FILE* in = fopen(fname,
381 #ifndef USE_WINSOCK
382 "r"
383 #else
384 "rb"
385 #endif
386 );
387 size_t r;
388 const char* rcode = "200 OK";
389 if(!in) {
390 char hdr[1024];
391 rcode = "404 File not found";
392 snprintf(hdr, sizeof(hdr), "HTTP/1.1 %s\r\n\r\n", rcode);
393 r = strlen(hdr);
394 if(SSL_write(ssl, hdr, (int)r) <= 0) {
395 /* write failure */
396 }
397 return;
398 }
399 fseek(in, 0, SEEK_END);
400 len = (size_t)ftell(in);
401 fseek(in, 0, SEEK_SET);
402 /* plus some space for the header */
403 buf = (char*)malloc(len+header_reserve);
404 if(!buf) {
405 fclose(in);
406 return;
407 }
408 avail = len+header_reserve;
409 at = buf;
410 snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode);
411 r = strlen(at);
412 at += r;
413 avail -= r;
414 snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION);
415 r = strlen(at);
416 at += r;
417 avail -= r;
418 snprintf(at, avail, "Content-Length: %u\r\n", (unsigned)len);
419 r = strlen(at);
420 at += r;
421 avail -= r;
422 snprintf(at, avail, "\r\n");
423 r = strlen(at);
424 at += r;
425 avail -= r;
426 if(avail < len) { /* robust */
427 free(buf);
428 fclose(in);
429 return;
430 }
431 if(fread(at, 1, len, in) != len) {
432 free(buf);
433 fclose(in);
434 return;
435 }
436 fclose(in);
437 at += len;
438 /* avail -= len; unused */
439 if(SSL_write(ssl, buf, at-buf) <= 0) {
440 /* write failure */
441 }
442 free(buf);
443 }
444
445 /** provide file over SSL, chunked encoding */
446 static void
provide_file_chunked(SSL * ssl,char * fname)447 provide_file_chunked(SSL* ssl, char* fname)
448 {
449 char buf[16384];
450 char* tmpbuf = NULL;
451 char* at = buf;
452 size_t avail = sizeof(buf);
453 size_t r;
454 FILE* in = fopen(fname,
455 #ifndef USE_WINSOCK
456 "r"
457 #else
458 "rb"
459 #endif
460 );
461 const char* rcode = "200 OK";
462 if(!in) {
463 rcode = "404 File not found";
464 }
465
466 /* print headers */
467 snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode);
468 r = strlen(at);
469 at += r;
470 avail -= r;
471 snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION);
472 r = strlen(at);
473 at += r;
474 avail -= r;
475 snprintf(at, avail, "Transfer-Encoding: chunked\r\n");
476 r = strlen(at);
477 at += r;
478 avail -= r;
479 snprintf(at, avail, "Connection: close\r\n");
480 r = strlen(at);
481 at += r;
482 avail -= r;
483 snprintf(at, avail, "\r\n");
484 r = strlen(at);
485 at += r;
486 avail -= r;
487 if(avail < 16) { /* robust */
488 if(in) fclose(in);
489 return;
490 }
491
492 do {
493 size_t red;
494 free(tmpbuf);
495 tmpbuf = malloc(avail-16);
496 if(!tmpbuf)
497 break;
498 /* read chunk; space-16 for xxxxCRLF..CRLF0CRLFCRLF (3 spare)*/
499 red = in?fread(tmpbuf, 1, avail-16, in):0;
500 /* prepare chunk */
501 snprintf(at, avail, "%x\r\n", (unsigned)red);
502 r = strlen(at);
503 if(verb >= 3)
504 {printf("chunk len %x\n", (unsigned)red); fflush(stdout);}
505 at += r;
506 avail -= r;
507 if(red != 0) {
508 if(red > avail) break; /* robust */
509 memmove(at, tmpbuf, red);
510 at += red;
511 avail -= red;
512 snprintf(at, avail, "\r\n");
513 r = strlen(at);
514 at += r;
515 avail -= r;
516 }
517 if(in && feof(in) && red != 0) {
518 snprintf(at, avail, "0\r\n");
519 r = strlen(at);
520 at += r;
521 avail -= r;
522 }
523 if(!in || feof(in)) {
524 snprintf(at, avail, "\r\n");
525 r = strlen(at);
526 at += r;
527 /* avail -= r; unused */
528 }
529 /* send chunk */
530 if(SSL_write(ssl, buf, at-buf) <= 0) {
531 /* SSL error */
532 break;
533 }
534
535 /* setup for next chunk */
536 at = buf;
537 avail = sizeof(buf);
538 } while(in && !feof(in) && !ferror(in));
539
540 free(tmpbuf);
541 if(in) fclose(in);
542 }
543
544 /** provide service to the ssl descriptor */
545 static void
service_ssl(SSL * ssl,struct sockaddr_storage * from,socklen_t falen)546 service_ssl(SSL* ssl, struct sockaddr_storage* from, socklen_t falen)
547 {
548 char file[1024];
549 char host[1024];
550 char combined[2048];
551 int vs = 11;
552 if(!read_http_headers(ssl, file, sizeof(file), host, sizeof(host),
553 &vs))
554 return;
555 if(host[0] != 0) adjust_host(host);
556 if(file[0] != 0) adjust_file(file);
557 if(host[0] == 0 || !host_name_is_safe(host))
558 (void)strlcpy(host, "default", sizeof(host));
559 if(!file_name_is_safe(file)) {
560 return;
561 }
562 snprintf(combined, sizeof(combined), "%s%s", host, file);
563 if(verb) {
564 char out[100];
565 void* a = &((struct sockaddr_in*)from)->sin_addr;
566 if(falen != (socklen_t)sizeof(struct sockaddr_in))
567 a = &((struct sockaddr_in6*)from)->sin6_addr;
568 out[0]=0;
569 (void)inet_ntop((int)((struct sockaddr_in*)from)->sin_family,
570 a, out, (socklen_t)sizeof(out));
571 printf("%s requests %s\n", out, combined);
572 fflush(stdout);
573 }
574 if(vs == 10)
575 provide_file_10(ssl, combined);
576 else provide_file_chunked(ssl, combined);
577 }
578
579 /** provide ssl service */
580 static void
do_service(char * addr,int port,char * key,char * cert)581 do_service(char* addr, int port, char* key, char* cert)
582 {
583 SSL_CTX* sslctx = setup_ctx(key, cert);
584 int fd = setup_fd(addr, port);
585 if(fd == -1) print_exit("could not setup sockets");
586 if(verb) {printf("petal start\n"); fflush(stdout);}
587 while(1) {
588 struct sockaddr_storage from;
589 socklen_t flen = (socklen_t)sizeof(from);
590 int s;
591 memset(&from, 0, sizeof(from));
592 s = accept(fd, (struct sockaddr*)&from, &flen);
593 if(verb) fflush(stdout);
594 if(s != -1) {
595 SSL* ssl = setup_ssl(s, sslctx);
596 if(verb) fflush(stdout);
597 if(ssl) {
598 service_ssl(ssl, &from, flen);
599 if(verb) fflush(stdout);
600 SSL_shutdown(ssl);
601 SSL_free(ssl);
602 }
603 fd_close(s);
604 } else if (verb >=2) log_errno("accept");
605 if(verb) fflush(stdout);
606 }
607 /* if we get a kill signal, the process dies and the OS reaps us */
608 if(verb) printf("petal end\n");
609 fd_close(fd);
610 SSL_CTX_free(sslctx);
611 }
612
613 /** getopt global, in case header files fail to declare it. */
614 extern int optind;
615 /** getopt global, in case header files fail to declare it. */
616 extern char* optarg;
617
618 /** Main routine for petal */
main(int argc,char * argv[])619 int main(int argc, char* argv[])
620 {
621 int c;
622 int port = 443;
623 char* addr = "127.0.0.1", *key = "petal.key", *cert = "petal.pem";
624 #ifdef USE_WINSOCK
625 WSADATA wsa_data;
626 if((c=WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0)
627 { printf("WSAStartup failed\n"); exit(1); }
628 atexit((void (*)(void))WSACleanup);
629 #endif
630
631 /* parse the options */
632 while( (c=getopt(argc, argv, "a:c:k:hp:v")) != -1) {
633 switch(c) {
634 case 'a':
635 addr = optarg;
636 break;
637 case 'c':
638 cert = optarg;
639 break;
640 case 'k':
641 key = optarg;
642 break;
643 case 'p':
644 port = atoi(optarg);
645 break;
646 case 'v':
647 verb++;
648 break;
649 case '?':
650 case 'h':
651 default:
652 usage();
653 }
654 }
655 argc -= optind;
656 /* argv += optind; not using further arguments */
657 if(argc != 0)
658 usage();
659
660 #ifdef SIGPIPE
661 (void)signal(SIGPIPE, SIG_IGN);
662 #endif
663 #ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS
664 ERR_load_crypto_strings();
665 #endif
666 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
667 ERR_load_SSL_strings();
668 #endif
669 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
670 # ifndef S_SPLINT_S
671 OpenSSL_add_all_algorithms();
672 # endif
673 #else
674 OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
675 | OPENSSL_INIT_ADD_ALL_DIGESTS
676 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
677 #endif
678 #if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
679 (void)SSL_library_init();
680 #else
681 (void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
682 #endif
683
684 do_service(addr, port, key, cert);
685
686 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
687 CRYPTO_cleanup_all_ex_data();
688 #endif
689 #ifdef HAVE_ERR_FREE_STRINGS
690 ERR_free_strings();
691 #endif
692 return 0;
693 }
694