1 /* 2 * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* Very basic HTTP server */ 11 12 #if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) 13 /* 14 * On VMS, you need to define this to get the declaration of fileno(). The 15 * value 2 is to make sure no function defined in POSIX-2 is left undefined. 16 */ 17 # define _POSIX_C_SOURCE 2 18 #endif 19 20 #include <string.h> 21 #include <ctype.h> 22 #include "http_server.h" 23 #include "internal/sockets.h" 24 #include <openssl/err.h> 25 #include <openssl/rand.h> 26 #include "s_apps.h" 27 28 #if defined(__TANDEM) 29 # if defined(OPENSSL_TANDEM_FLOSS) 30 # include <floss.h(floss_fork)> 31 # endif 32 #endif 33 34 static int verbosity = LOG_INFO; 35 36 #define HTTP_PREFIX "HTTP/" 37 #define HTTP_VERSION_PATT "1." /* allow 1.x */ 38 #define HTTP_PREFIX_VERSION HTTP_PREFIX""HTTP_VERSION_PATT 39 #define HTTP_1_0 HTTP_PREFIX_VERSION"0" /* "HTTP/1.0" */ 40 41 #ifdef HTTP_DAEMON 42 43 int multi = 0; /* run multiple responder processes */ 44 int acfd = (int) INVALID_SOCKET; 45 46 static int print_syslog(const char *str, size_t len, void *levPtr) 47 { 48 int level = *(int *)levPtr; 49 int ilen = len > MAXERRLEN ? MAXERRLEN : len; 50 51 syslog(level, "%.*s", ilen, str); 52 53 return ilen; 54 } 55 #endif 56 57 void log_message(const char *prog, int level, const char *fmt, ...) 58 { 59 va_list ap; 60 61 if (verbosity < level) 62 return; 63 64 va_start(ap, fmt); 65 #ifdef HTTP_DAEMON 66 if (multi) { 67 char buf[1024]; 68 69 if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) 70 syslog(level, "%s", buf); 71 if (level <= LOG_ERR) 72 ERR_print_errors_cb(print_syslog, &level); 73 } else 74 #endif 75 { 76 BIO_printf(bio_err, "%s: ", prog); 77 BIO_vprintf(bio_err, fmt, ap); 78 BIO_printf(bio_err, "\n"); 79 (void)BIO_flush(bio_err); 80 } 81 va_end(ap); 82 } 83 84 #ifdef HTTP_DAEMON 85 void socket_timeout(int signum) 86 { 87 if (acfd != (int)INVALID_SOCKET) 88 (void)shutdown(acfd, SHUT_RD); 89 } 90 91 static void killall(int ret, pid_t *kidpids) 92 { 93 int i; 94 95 for (i = 0; i < multi; ++i) 96 if (kidpids[i] != 0) 97 (void)kill(kidpids[i], SIGTERM); 98 OPENSSL_free(kidpids); 99 ossl_sleep(1000); 100 exit(ret); 101 } 102 103 static int termsig = 0; 104 105 static void noteterm(int sig) 106 { 107 termsig = sig; 108 } 109 110 /* 111 * Loop spawning up to `multi` child processes, only child processes return 112 * from this function. The parent process loops until receiving a termination 113 * signal, kills extant children and exits without returning. 114 */ 115 void spawn_loop(const char *prog) 116 { 117 pid_t *kidpids = NULL; 118 int status; 119 int procs = 0; 120 int i; 121 122 openlog(prog, LOG_PID, LOG_DAEMON); 123 124 if (setpgid(0, 0)) { 125 syslog(LOG_ERR, "fatal: error detaching from parent process group: %s", 126 strerror(errno)); 127 exit(1); 128 } 129 kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array"); 130 for (i = 0; i < multi; ++i) 131 kidpids[i] = 0; 132 133 signal(SIGINT, noteterm); 134 signal(SIGTERM, noteterm); 135 136 while (termsig == 0) { 137 pid_t fpid; 138 139 /* 140 * Wait for a child to replace when we're at the limit. 141 * Slow down if a child exited abnormally or waitpid() < 0 142 */ 143 while (termsig == 0 && procs >= multi) { 144 if ((fpid = waitpid(-1, &status, 0)) > 0) { 145 for (i = 0; i < procs; ++i) { 146 if (kidpids[i] == fpid) { 147 kidpids[i] = 0; 148 --procs; 149 break; 150 } 151 } 152 if (i >= multi) { 153 syslog(LOG_ERR, "fatal: internal error: " 154 "no matching child slot for pid: %ld", 155 (long) fpid); 156 killall(1, kidpids); 157 } 158 if (status != 0) { 159 if (WIFEXITED(status)) 160 syslog(LOG_WARNING, "child process: %ld, exit status: %d", 161 (long)fpid, WEXITSTATUS(status)); 162 else if (WIFSIGNALED(status)) 163 syslog(LOG_WARNING, "child process: %ld, term signal %d%s", 164 (long)fpid, WTERMSIG(status), 165 # ifdef WCOREDUMP 166 WCOREDUMP(status) ? " (core dumped)" : 167 # endif 168 ""); 169 ossl_sleep(1000); 170 } 171 break; 172 } else if (errno != EINTR) { 173 syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno)); 174 killall(1, kidpids); 175 } 176 } 177 if (termsig) 178 break; 179 180 switch (fpid = fork()) { 181 case -1: /* error */ 182 /* System critically low on memory, pause and try again later */ 183 ossl_sleep(30000); 184 break; 185 case 0: /* child */ 186 OPENSSL_free(kidpids); 187 signal(SIGINT, SIG_DFL); 188 signal(SIGTERM, SIG_DFL); 189 if (termsig) 190 _exit(0); 191 if (RAND_poll() <= 0) { 192 syslog(LOG_ERR, "fatal: RAND_poll() failed"); 193 _exit(1); 194 } 195 return; 196 default: /* parent */ 197 for (i = 0; i < multi; ++i) { 198 if (kidpids[i] == 0) { 199 kidpids[i] = fpid; 200 procs++; 201 break; 202 } 203 } 204 if (i >= multi) { 205 syslog(LOG_ERR, "fatal: internal error: no free child slots"); 206 killall(1, kidpids); 207 } 208 break; 209 } 210 } 211 212 /* The loop above can only break on termsig */ 213 syslog(LOG_INFO, "terminating on signal: %d", termsig); 214 killall(0, kidpids); 215 } 216 #endif 217 218 #ifndef OPENSSL_NO_SOCK 219 BIO *http_server_init_bio(const char *prog, const char *port) 220 { 221 BIO *acbio = NULL, *bufbio; 222 int asock; 223 224 bufbio = BIO_new(BIO_f_buffer()); 225 if (bufbio == NULL) 226 goto err; 227 acbio = BIO_new(BIO_s_accept()); 228 if (acbio == NULL 229 || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0 230 || BIO_set_accept_port(acbio, port) < 0) { 231 log_message(prog, LOG_ERR, "Error setting up accept BIO"); 232 goto err; 233 } 234 235 BIO_set_accept_bios(acbio, bufbio); 236 bufbio = NULL; 237 if (BIO_do_accept(acbio) <= 0) { 238 log_message(prog, LOG_ERR, "Error starting accept"); 239 goto err; 240 } 241 242 /* Report back what address and port are used */ 243 BIO_get_fd(acbio, &asock); 244 if (!report_server_accept(bio_out, asock, 1, 1)) { 245 log_message(prog, LOG_ERR, "Error printing ACCEPT string"); 246 goto err; 247 } 248 249 return acbio; 250 251 err: 252 BIO_free_all(acbio); 253 BIO_free(bufbio); 254 return NULL; 255 } 256 257 /* 258 * Decode %xx URL-decoding in-place. Ignores malformed sequences. 259 */ 260 static int urldecode(char *p) 261 { 262 unsigned char *out = (unsigned char *)p; 263 unsigned char *save = out; 264 265 for (; *p; p++) { 266 if (*p != '%') { 267 *out++ = *p; 268 } else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) { 269 /* Don't check, can't fail because of ixdigit() call. */ 270 *out++ = (OPENSSL_hexchar2int(p[1]) << 4) 271 | OPENSSL_hexchar2int(p[2]); 272 p += 2; 273 } else { 274 return -1; 275 } 276 } 277 *out = '\0'; 278 return (int)(out - save); 279 } 280 281 /* if *pcbio != NULL, continue given connected session, else accept new */ 282 /* if found_keep_alive != NULL, return this way connection persistence state */ 283 int http_server_get_asn1_req(const ASN1_ITEM *it, ASN1_VALUE **preq, 284 char **ppath, BIO **pcbio, BIO *acbio, 285 int *found_keep_alive, 286 const char *prog, const char *port, 287 int accept_get, int timeout) 288 { 289 BIO *cbio = *pcbio, *getbio = NULL, *b64 = NULL; 290 int len; 291 char reqbuf[2048], inbuf[2048]; 292 char *meth, *url, *end; 293 ASN1_VALUE *req; 294 int ret = 0; 295 296 *preq = NULL; 297 if (ppath != NULL) 298 *ppath = NULL; 299 300 if (cbio == NULL) { 301 log_message(prog, LOG_DEBUG, 302 "Awaiting new connection on port %s...", port); 303 if (BIO_do_accept(acbio) <= 0) 304 /* Connection loss before accept() is routine, ignore silently */ 305 return ret; 306 307 *pcbio = cbio = BIO_pop(acbio); 308 } else { 309 log_message(prog, LOG_DEBUG, "Awaiting next request..."); 310 } 311 if (cbio == NULL) { 312 /* Cannot call http_server_send_status(cbio, ...) */ 313 ret = -1; 314 goto out; 315 } 316 317 # ifdef HTTP_DAEMON 318 if (timeout > 0) { 319 (void)BIO_get_fd(cbio, &acfd); 320 alarm(timeout); 321 } 322 # endif 323 324 /* Read the request line. */ 325 len = BIO_gets(cbio, reqbuf, sizeof(reqbuf)); 326 if (len == 0) 327 return ret; 328 ret = 1; 329 if (len < 0) { 330 log_message(prog, LOG_WARNING, "Request line read error"); 331 (void)http_server_send_status(cbio, 400, "Bad Request"); 332 goto out; 333 } 334 if ((end = strchr(reqbuf, '\r')) != NULL 335 || (end = strchr(reqbuf, '\n')) != NULL) 336 *end = '\0'; 337 log_message(prog, LOG_INFO, "Received request, 1st line: %s", reqbuf); 338 339 meth = reqbuf; 340 url = meth + 3; 341 if ((accept_get && strncmp(meth, "GET ", 4) == 0) 342 || (url++, strncmp(meth, "POST ", 5) == 0)) { 343 static const char http_version_str[] = " "HTTP_PREFIX_VERSION; 344 static const size_t http_version_str_len = sizeof(http_version_str) - 1; 345 346 /* Expecting (GET|POST) {sp} /URL {sp} HTTP/1.x */ 347 *(url++) = '\0'; 348 while (*url == ' ') 349 url++; 350 if (*url != '/') { 351 log_message(prog, LOG_WARNING, 352 "Invalid %s -- URL does not begin with '/': %s", 353 meth, url); 354 (void)http_server_send_status(cbio, 400, "Bad Request"); 355 goto out; 356 } 357 url++; 358 359 /* Splice off the HTTP version identifier. */ 360 for (end = url; *end != '\0'; end++) 361 if (*end == ' ') 362 break; 363 if (strncmp(end, http_version_str, http_version_str_len) != 0) { 364 log_message(prog, LOG_WARNING, 365 "Invalid %s -- bad HTTP/version string: %s", 366 meth, end + 1); 367 (void)http_server_send_status(cbio, 400, "Bad Request"); 368 goto out; 369 } 370 *end = '\0'; 371 /* above HTTP 1.0, connection persistence is the default */ 372 if (found_keep_alive != NULL) 373 *found_keep_alive = end[http_version_str_len] > '0'; 374 375 /*- 376 * Skip "GET / HTTP..." requests often used by load-balancers. 377 * 'url' was incremented above to point to the first byte *after* 378 * the leading slash, so in case 'GET / ' it is now an empty string. 379 */ 380 if (strlen(meth) == 3 && url[0] == '\0') { 381 (void)http_server_send_status(cbio, 200, "OK"); 382 goto out; 383 } 384 385 len = urldecode(url); 386 if (len < 0) { 387 log_message(prog, LOG_WARNING, 388 "Invalid %s request -- bad URL encoding: %s", 389 meth, url); 390 (void)http_server_send_status(cbio, 400, "Bad Request"); 391 goto out; 392 } 393 if (strlen(meth) == 3) { /* GET */ 394 if ((getbio = BIO_new_mem_buf(url, len)) == NULL 395 || (b64 = BIO_new(BIO_f_base64())) == NULL) { 396 log_message(prog, LOG_ERR, 397 "Could not allocate base64 bio with size = %d", 398 len); 399 goto fatal; 400 } 401 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 402 getbio = BIO_push(b64, getbio); 403 } 404 } else { 405 log_message(prog, LOG_WARNING, 406 "HTTP request does not begin with %sPOST: %s", 407 accept_get ? "GET or " : "", reqbuf); 408 (void)http_server_send_status(cbio, 400, "Bad Request"); 409 goto out; 410 } 411 412 /* chop any further/duplicate leading or trailing '/' */ 413 while (*url == '/') 414 url++; 415 while (end >= url + 2 && end[-2] == '/' && end[-1] == '/') 416 end--; 417 *end = '\0'; 418 419 /* Read and skip past the headers. */ 420 for (;;) { 421 char *key, *value, *line_end = NULL; 422 423 len = BIO_gets(cbio, inbuf, sizeof(inbuf)); 424 if (len <= 0) { 425 log_message(prog, LOG_WARNING, "Error reading HTTP header"); 426 (void)http_server_send_status(cbio, 400, "Bad Request"); 427 goto out; 428 } 429 430 if (inbuf[0] == '\r' || inbuf[0] == '\n') 431 break; 432 433 key = inbuf; 434 value = strchr(key, ':'); 435 if (value == NULL) { 436 log_message(prog, LOG_WARNING, 437 "Error parsing HTTP header: missing ':'"); 438 (void)http_server_send_status(cbio, 400, "Bad Request"); 439 goto out; 440 } 441 *(value++) = '\0'; 442 while (*value == ' ') 443 value++; 444 line_end = strchr(value, '\r'); 445 if (line_end == NULL) { 446 line_end = strchr(value, '\n'); 447 if (line_end == NULL) { 448 log_message(prog, LOG_WARNING, 449 "Error parsing HTTP header: missing end of line"); 450 (void)http_server_send_status(cbio, 400, "Bad Request"); 451 goto out; 452 } 453 } 454 *line_end = '\0'; 455 /* https://tools.ietf.org/html/rfc7230#section-6.3 Persistence */ 456 if (found_keep_alive != NULL 457 && OPENSSL_strcasecmp(key, "Connection") == 0) { 458 if (OPENSSL_strcasecmp(value, "keep-alive") == 0) 459 *found_keep_alive = 1; 460 else if (OPENSSL_strcasecmp(value, "close") == 0) 461 *found_keep_alive = 0; 462 } 463 } 464 465 # ifdef HTTP_DAEMON 466 /* Clear alarm before we close the client socket */ 467 alarm(0); 468 timeout = 0; 469 # endif 470 471 /* Try to read and parse request */ 472 req = ASN1_item_d2i_bio(it, getbio != NULL ? getbio : cbio, NULL); 473 if (req == NULL) { 474 log_message(prog, LOG_WARNING, 475 "Error parsing DER-encoded request content"); 476 (void)http_server_send_status(cbio, 400, "Bad Request"); 477 } else if (ppath != NULL && (*ppath = OPENSSL_strdup(url)) == NULL) { 478 log_message(prog, LOG_ERR, 479 "Out of memory allocating %zu bytes", strlen(url) + 1); 480 ASN1_item_free(req, it); 481 goto fatal; 482 } 483 484 *preq = req; 485 486 out: 487 BIO_free_all(getbio); 488 # ifdef HTTP_DAEMON 489 if (timeout > 0) 490 alarm(0); 491 acfd = (int)INVALID_SOCKET; 492 # endif 493 return ret; 494 495 fatal: 496 (void)http_server_send_status(cbio, 500, "Internal Server Error"); 497 if (ppath != NULL) { 498 OPENSSL_free(*ppath); 499 *ppath = NULL; 500 } 501 BIO_free_all(cbio); 502 *pcbio = NULL; 503 ret = -1; 504 goto out; 505 } 506 507 /* assumes that cbio does not do an encoding that changes the output length */ 508 int http_server_send_asn1_resp(BIO *cbio, int keep_alive, 509 const char *content_type, 510 const ASN1_ITEM *it, const ASN1_VALUE *resp) 511 { 512 int ret = BIO_printf(cbio, HTTP_1_0" 200 OK\r\n%s" 513 "Content-type: %s\r\n" 514 "Content-Length: %d\r\n\r\n", 515 keep_alive ? "Connection: keep-alive\r\n" : "", 516 content_type, 517 ASN1_item_i2d(resp, NULL, it)) > 0 518 && ASN1_item_i2d_bio(it, cbio, resp) > 0; 519 520 (void)BIO_flush(cbio); 521 return ret; 522 } 523 524 int http_server_send_status(BIO *cbio, int status, const char *reason) 525 { 526 int ret = BIO_printf(cbio, HTTP_1_0" %d %s\r\n\r\n", 527 /* This implicitly cancels keep-alive */ 528 status, reason) > 0; 529 530 (void)BIO_flush(cbio); 531 return ret; 532 } 533 #endif 534