]>
Commit | Line | Data |
---|---|---|
89c4ed63 A |
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 | |
73 | usage() | |
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 */ | |
91 | static void print_exit(const char* str) {printf("error %s\n", str); exit(1);} | |
92 | /** print errno */ | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | return 1; | |
225 | if(!process_one_header(buf, file, flen, host, hlen, vs)) | |
226 | return 0; | |
227 | } | |
228 | return 0; | |
229 | } | |
230 | ||
231 | /** setup SSL context */ | |
232 | static SSL_CTX* | |
233 | setup_ctx(char* key, char* cert) | |
234 | { | |
235 | SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); | |
236 | if(!ctx) print_exit("out of memory"); | |
89c4ed63 A |
237 | if(!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) |
238 | print_exit("cannot read cert"); | |
239 | if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) | |
240 | print_exit("cannot read key"); | |
241 | if(!SSL_CTX_check_private_key(ctx)) | |
242 | print_exit("private key is not correct"); | |
243 | if(!SSL_CTX_load_verify_locations(ctx, cert, NULL)) | |
244 | print_exit("cannot load cert verify locations"); | |
245 | return ctx; | |
246 | } | |
247 | ||
248 | /** setup listening TCP */ | |
249 | static int | |
250 | setup_fd(char* addr, int port) | |
251 | { | |
252 | struct sockaddr_storage ad; | |
253 | socklen_t len; | |
254 | int fd; | |
255 | int c = 1; | |
256 | int fam = parse_ip_addr(addr, port, &ad, &len); | |
257 | fd = socket(fam, SOCK_STREAM, 0); | |
258 | if(fd == -1) { | |
259 | log_errno("socket"); | |
260 | return -1; | |
261 | } | |
262 | if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, | |
263 | (void*)&c, (socklen_t) sizeof(int)) < 0) { | |
264 | log_errno("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); | |
265 | } | |
266 | if(bind(fd, (struct sockaddr*)&ad, len) == -1) { | |
267 | log_errno("bind"); | |
268 | fd_close(fd); | |
269 | return -1; | |
270 | } | |
271 | if(listen(fd, 5) == -1) { | |
272 | log_errno("listen"); | |
273 | fd_close(fd); | |
274 | return -1; | |
275 | } | |
276 | return fd; | |
277 | } | |
278 | ||
279 | /** setup SSL connection to the client */ | |
280 | static SSL* | |
281 | setup_ssl(int s, SSL_CTX* ctx) | |
282 | { | |
283 | SSL* ssl = SSL_new(ctx); | |
284 | if(!ssl) return NULL; | |
285 | SSL_set_accept_state(ssl); | |
286 | (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); | |
287 | if(!SSL_set_fd(ssl, s)) { | |
288 | SSL_free(ssl); | |
289 | return NULL; | |
290 | } | |
291 | return ssl; | |
292 | } | |
293 | ||
294 | /** check a file name for safety */ | |
295 | static int | |
296 | file_name_is_safe(char* s) | |
297 | { | |
298 | size_t l = strlen(s); | |
299 | if(s[0] != '/') | |
300 | return 0; /* must start with / */ | |
301 | if(strstr(s, "/../")) | |
302 | return 0; /* no updirs in URL */ | |
303 | if(l>=3 && s[l-1]=='.' && s[l-2]=='.' && s[l-3]=='/') | |
304 | return 0; /* ends with /.. */ | |
305 | return 1; | |
306 | } | |
307 | ||
308 | /** adjust host and filename */ | |
309 | static void | |
310 | adjust_host_file(char* host, char* file) | |
311 | { | |
312 | size_t i, len; | |
313 | /* remove a port number if present */ | |
314 | if(strrchr(host, ':')) | |
315 | *strrchr(host, ':') = 0; | |
316 | /* lowercase */ | |
317 | len = strlen(host); | |
318 | for(i=0; i<len; i++) | |
319 | host[i] = tolower((unsigned char)host[i]); | |
320 | len = strlen(file); | |
321 | for(i=0; i<len; i++) | |
322 | file[i] = tolower((unsigned char)file[i]); | |
323 | } | |
324 | ||
325 | /** check a host name for safety */ | |
326 | static int | |
327 | host_name_is_safe(char* s) | |
328 | { | |
329 | if(strchr(s, '/')) | |
330 | return 0; | |
331 | if(strcmp(s, "..") == 0) | |
332 | return 0; | |
333 | if(strcmp(s, ".") == 0) | |
334 | return 0; | |
335 | return 1; | |
336 | } | |
337 | ||
338 | /** provide file in whole transfer */ | |
339 | static void | |
340 | provide_file_10(SSL* ssl, char* fname) | |
341 | { | |
342 | char* buf, *at; | |
343 | size_t len, avail, header_reserve=1024; | |
344 | FILE* in = fopen(fname, | |
345 | #ifndef USE_WINSOCK | |
346 | "r" | |
347 | #else | |
348 | "rb" | |
349 | #endif | |
350 | ); | |
351 | size_t r; | |
352 | const char* rcode = "200 OK"; | |
353 | if(!in) { | |
354 | char hdr[1024]; | |
355 | rcode = "404 File not found"; | |
356 | snprintf(hdr, sizeof(hdr), "HTTP/1.1 %s\r\n\r\n", rcode); | |
357 | r = strlen(hdr); | |
358 | if(SSL_write(ssl, hdr, (int)r) <= 0) { | |
359 | /* write failure */ | |
360 | } | |
361 | return; | |
362 | } | |
363 | fseek(in, 0, SEEK_END); | |
364 | len = (size_t)ftell(in); | |
365 | fseek(in, 0, SEEK_SET); | |
366 | /* plus some space for the header */ | |
367 | buf = (char*)malloc(len+header_reserve); | |
368 | if(!buf) { | |
369 | fclose(in); | |
370 | return; | |
371 | } | |
372 | avail = len+header_reserve; | |
373 | at = buf; | |
374 | snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode); | |
375 | r = strlen(at); | |
376 | at += r; | |
377 | avail -= r; | |
378 | snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION); | |
379 | r = strlen(at); | |
380 | at += r; | |
381 | avail -= r; | |
382 | snprintf(at, avail, "Content-Length: %u\r\n", (unsigned)len); | |
383 | r = strlen(at); | |
384 | at += r; | |
385 | avail -= r; | |
386 | snprintf(at, avail, "\r\n"); | |
387 | r = strlen(at); | |
388 | at += r; | |
389 | avail -= r; | |
390 | if(avail < len) { /* robust */ | |
391 | free(buf); | |
392 | fclose(in); | |
393 | return; | |
394 | } | |
395 | if(fread(at, 1, len, in) != len) { | |
396 | free(buf); | |
397 | fclose(in); | |
398 | return; | |
399 | } | |
400 | fclose(in); | |
401 | at += len; | |
402 | avail -= len; | |
403 | if(SSL_write(ssl, buf, at-buf) <= 0) { | |
404 | /* write failure */ | |
405 | } | |
406 | free(buf); | |
407 | } | |
408 | ||
409 | /** provide file over SSL, chunked encoding */ | |
410 | static void | |
411 | provide_file_chunked(SSL* ssl, char* fname) | |
412 | { | |
413 | char buf[16384]; | |
414 | char* at = buf; | |
415 | size_t avail = sizeof(buf); | |
416 | size_t r; | |
417 | FILE* in = fopen(fname, | |
418 | #ifndef USE_WINSOCK | |
419 | "r" | |
420 | #else | |
421 | "rb" | |
422 | #endif | |
423 | ); | |
424 | const char* rcode = "200 OK"; | |
425 | if(!in) { | |
426 | rcode = "404 File not found"; | |
427 | } | |
428 | ||
429 | /* print headers */ | |
430 | snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode); | |
431 | r = strlen(at); | |
432 | at += r; | |
433 | avail -= r; | |
434 | snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION); | |
435 | r = strlen(at); | |
436 | at += r; | |
437 | avail -= r; | |
438 | snprintf(at, avail, "Transfer-Encoding: chunked\r\n"); | |
439 | r = strlen(at); | |
440 | at += r; | |
441 | avail -= r; | |
442 | snprintf(at, avail, "Connection: close\r\n"); | |
443 | r = strlen(at); | |
444 | at += r; | |
445 | avail -= r; | |
446 | snprintf(at, avail, "\r\n"); | |
447 | r = strlen(at); | |
448 | at += r; | |
449 | avail -= r; | |
450 | if(avail < 16) { /* robust */ | |
451 | if(in) fclose(in); | |
452 | return; | |
453 | } | |
454 | ||
455 | do { | |
456 | char tmpbuf[sizeof(buf)]; | |
457 | /* read chunk; space-16 for xxxxCRLF..CRLF0CRLFCRLF (3 spare)*/ | |
458 | size_t red = in?fread(tmpbuf, 1, avail-16, in):0; | |
459 | /* prepare chunk */ | |
460 | snprintf(at, avail, "%x\r\n", (unsigned)red); | |
461 | r = strlen(at); | |
462 | if(verb >= 3) | |
463 | {printf("chunk len %x\n", (unsigned)red); fflush(stdout);} | |
464 | at += r; | |
465 | avail -= r; | |
466 | if(red != 0) { | |
467 | if(red > avail) break; /* robust */ | |
468 | memmove(at, tmpbuf, red); | |
469 | at += red; | |
470 | avail -= red; | |
471 | snprintf(at, avail, "\r\n"); | |
472 | r = strlen(at); | |
473 | at += r; | |
474 | avail -= r; | |
475 | } | |
476 | if(in && feof(in) && red != 0) { | |
477 | snprintf(at, avail, "0\r\n"); | |
478 | r = strlen(at); | |
479 | at += r; | |
480 | avail -= r; | |
481 | } | |
482 | if(!in || feof(in)) { | |
483 | snprintf(at, avail, "\r\n"); | |
484 | r = strlen(at); | |
485 | at += r; | |
486 | avail -= r; | |
487 | } | |
488 | /* send chunk */ | |
489 | if(SSL_write(ssl, buf, at-buf) <= 0) { | |
490 | /* SSL error */ | |
491 | break; | |
492 | } | |
493 | ||
494 | /* setup for next chunk */ | |
495 | at = buf; | |
496 | avail = sizeof(buf); | |
497 | } while(in && !feof(in) && !ferror(in)); | |
498 | ||
499 | if(in) fclose(in); | |
500 | } | |
501 | ||
502 | /** provide service to the ssl descriptor */ | |
503 | static void | |
504 | service_ssl(SSL* ssl, struct sockaddr_storage* from, socklen_t falen) | |
505 | { | |
506 | char file[1024]; | |
507 | char host[1024]; | |
508 | char combined[2048]; | |
509 | int vs = 11; | |
510 | if(!read_http_headers(ssl, file, sizeof(file), host, sizeof(host), | |
511 | &vs)) | |
512 | return; | |
513 | adjust_host_file(host, file); | |
514 | if(host[0] == 0 || !host_name_is_safe(host)) | |
515 | (void)strlcpy(host, "default", sizeof(host)); | |
516 | if(!file_name_is_safe(file)) { | |
517 | return; | |
518 | } | |
519 | snprintf(combined, sizeof(combined), "%s%s", host, file); | |
520 | if(verb) { | |
521 | char out[100]; | |
522 | void* a = &((struct sockaddr_in*)from)->sin_addr; | |
523 | if(falen != (socklen_t)sizeof(struct sockaddr_in)) | |
524 | a = &((struct sockaddr_in6*)from)->sin6_addr; | |
525 | out[0]=0; | |
526 | (void)inet_ntop((int)((struct sockaddr_in*)from)->sin_family, | |
527 | a, out, (socklen_t)sizeof(out)); | |
528 | printf("%s requests %s\n", out, combined); | |
529 | fflush(stdout); | |
530 | } | |
531 | if(vs == 10) | |
532 | provide_file_10(ssl, combined); | |
533 | else provide_file_chunked(ssl, combined); | |
534 | } | |
535 | ||
536 | /** provide ssl service */ | |
537 | static void | |
538 | do_service(char* addr, int port, char* key, char* cert) | |
539 | { | |
540 | SSL_CTX* sslctx = setup_ctx(key, cert); | |
541 | int fd = setup_fd(addr, port); | |
542 | int go = 1; | |
543 | if(fd == -1) print_exit("could not setup sockets"); | |
544 | if(verb) {printf("petal start\n"); fflush(stdout);} | |
545 | while(go) { | |
546 | struct sockaddr_storage from; | |
547 | socklen_t flen = (socklen_t)sizeof(from); | |
548 | int s = accept(fd, (struct sockaddr*)&from, &flen); | |
549 | if(verb) fflush(stdout); | |
550 | if(s != -1) { | |
551 | SSL* ssl = setup_ssl(s, sslctx); | |
552 | if(verb) fflush(stdout); | |
553 | if(ssl) { | |
554 | service_ssl(ssl, &from, flen); | |
555 | if(verb) fflush(stdout); | |
556 | SSL_shutdown(ssl); | |
557 | SSL_free(ssl); | |
558 | } | |
559 | fd_close(s); | |
560 | } else if (verb >=2) log_errno("accept"); | |
561 | if(verb) fflush(stdout); | |
562 | } | |
563 | /* if we get a kill signal, the process dies and the OS reaps us */ | |
564 | if(verb) printf("petal end\n"); | |
565 | fd_close(fd); | |
566 | SSL_CTX_free(sslctx); | |
567 | } | |
568 | ||
569 | /** getopt global, in case header files fail to declare it. */ | |
570 | extern int optind; | |
571 | /** getopt global, in case header files fail to declare it. */ | |
572 | extern char* optarg; | |
573 | ||
574 | /** Main routine for petal */ | |
575 | int main(int argc, char* argv[]) | |
576 | { | |
577 | int c; | |
578 | int port = 443; | |
579 | char* addr = "127.0.0.1", *key = "petal.key", *cert = "petal.pem"; | |
580 | #ifdef USE_WINSOCK | |
581 | WSADATA wsa_data; | |
582 | if((c=WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) | |
583 | { printf("WSAStartup failed\n"); exit(1); } | |
584 | atexit((void (*)(void))WSACleanup); | |
585 | #endif | |
586 | ||
587 | /* parse the options */ | |
588 | while( (c=getopt(argc, argv, "a:c:k:hp:v")) != -1) { | |
589 | switch(c) { | |
590 | case 'a': | |
591 | addr = optarg; | |
592 | break; | |
593 | case 'c': | |
594 | cert = optarg; | |
595 | break; | |
596 | case 'k': | |
597 | key = optarg; | |
598 | break; | |
599 | case 'p': | |
600 | port = atoi(optarg); | |
601 | break; | |
602 | case 'v': | |
603 | verb++; | |
604 | break; | |
605 | case '?': | |
606 | case 'h': | |
607 | default: | |
608 | usage(); | |
609 | } | |
610 | } | |
611 | argc -= optind; | |
612 | argv += optind; | |
613 | if(argc != 0) | |
614 | usage(); | |
615 | ||
616 | #ifdef SIGPIPE | |
617 | (void)signal(SIGPIPE, SIG_IGN); | |
618 | #endif | |
619 | ERR_load_crypto_strings(); | |
620 | ERR_load_SSL_strings(); | |
621 | OpenSSL_add_all_algorithms(); | |
622 | (void)SSL_library_init(); | |
623 | ||
624 | do_service(addr, port, key, cert); | |
625 | ||
626 | CRYPTO_cleanup_all_ex_data(); | |
627 | ERR_remove_state(0); | |
628 | ERR_free_strings(); | |
629 | RAND_cleanup(); | |
630 | return 0; | |
631 | } |