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