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(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 */ 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 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* 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) && defined(HAVE_SSL_CTX_SET_TMP_ECDH) 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 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* 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 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 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 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 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 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 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 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 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 */ 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