aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-21 00:06:28 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2006-11-21 00:06:28 +0000
commit4ef4f06b342a621422e5314f4d724a6b472a8614 (patch)
tree20af8b0cad2a9cd2b2b18da8fbf44fabd6510bf8
parent0d01b9791d1d7ad53c4a9173298a14cf7dc0b571 (diff)
downloadbusybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.tar.gz
busybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.tar.bz2
busybox-w32-4ef4f06b342a621422e5314f4d724a6b472a8614.zip
httpd: More robust Content-length: parsing,
code reorganization (less indented) git-svn-id: svn://busybox.net/trunk/busybox@16593 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--networking/httpd.c170
1 files changed, 86 insertions, 84 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index d5cfd652c..71792862e 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -256,7 +256,9 @@ static const HttpEnumString httpResponseNames[] = {
256 256
257 257
258static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT"; 258static const char RFC1123FMT[] = "%a, %d %b %Y %H:%M:%S GMT";
259static const char Content_length[] = "Content-length:"; 259
260
261#define STRNCASECMP(a, str) strncasecmp((a), (str), sizeof(str)-1)
260 262
261 263
262static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc) 264static int scan_ip(const char **ep, unsigned int *ip, unsigned char endc)
@@ -880,7 +882,7 @@ static int sendHeaders(HttpResponseNum responseNum)
880 if (config->ContentLength != -1) { /* file */ 882 if (config->ContentLength != -1) { /* file */
881 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod)); 883 strftime(timeStr, sizeof(timeStr), RFC1123FMT, gmtime(&config->last_mod));
882 len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"\r\n", 884 len += sprintf(buf+len, "Last-Modified: %s\r\n%s %"OFF_FMT"\r\n",
883 timeStr, Content_length, (off_t) config->ContentLength); 885 timeStr, "Content-length:", (off_t) config->ContentLength);
884 } 886 }
885 strcat(buf, "\r\n"); 887 strcat(buf, "\r\n");
886 len += 2; 888 len += 2;
@@ -962,20 +964,15 @@ static int sendCgi(const char *url,
962 int outFd; 964 int outFd;
963 int firstLine = 1; 965 int firstLine = 1;
964 966
965 do { 967 if (pipe(fromCgi) != 0)
966 if (pipe(fromCgi) != 0) { 968 return 0;
967 break; 969 if (pipe(toCgi) != 0)
968 } 970 return 0;
969 if (pipe(toCgi) != 0) { 971 pid = fork();
970 break; 972 if (pid < 0)
971 } 973 return 0;
972
973 pid = fork();
974 if (pid < 0) {
975 pid = 0;
976 break;
977 }
978 974
975 do {
979 if (!pid) { 976 if (!pid) {
980 /* child process */ 977 /* child process */
981 char *script; 978 char *script;
@@ -1031,10 +1028,9 @@ static int sendCgi(const char *url,
1031 if (script != NULL) 1028 if (script != NULL)
1032 *script = '\0'; /* reduce /PATH_INFO */ 1029 *script = '\0'; /* reduce /PATH_INFO */
1033 /* SCRIPT_FILENAME required by PHP in CGI mode */ 1030 /* SCRIPT_FILENAME required by PHP in CGI mode */
1034 if (realpath(purl + 1, realpath_buff)) 1031 if (!realpath(purl + 1, realpath_buff))
1035 setenv1("SCRIPT_FILENAME", realpath_buff); 1032 goto error_execing_cgi;
1036 else 1033 setenv1("SCRIPT_FILENAME", realpath_buff);
1037 *realpath_buff = '\0';
1038 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1034 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
1039 setenv1("SCRIPT_NAME", purl); 1035 setenv1("SCRIPT_NAME", purl);
1040 setenv1("QUERY_STRING", config->query); 1036 setenv1("QUERY_STRING", config->query);
@@ -1045,9 +1041,8 @@ static int sendCgi(const char *url,
1045#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV 1041#if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV
1046 setenv_long("REMOTE_PORT", config->port); 1042 setenv_long("REMOTE_PORT", config->port);
1047#endif 1043#endif
1048 if (bodyLen) { 1044 if (bodyLen)
1049 setenv_long("CONTENT_LENGTH", bodyLen); 1045 setenv_long("CONTENT_LENGTH", bodyLen);
1050 }
1051 if (cookie) 1046 if (cookie)
1052 setenv1("HTTP_COOKIE", cookie); 1047 setenv1("HTTP_COOKIE", cookie);
1053 if (content_type) 1048 if (content_type)
@@ -1064,37 +1059,37 @@ static int sendCgi(const char *url,
1064 /* set execve argp[0] without path */ 1059 /* set execve argp[0] without path */
1065 argp[0] = strrchr(purl, '/') + 1; 1060 argp[0] = strrchr(purl, '/') + 1;
1066 /* but script argp[0] must have absolute path and chdiring to this */ 1061 /* but script argp[0] must have absolute path and chdiring to this */
1067 if (*realpath_buff) { 1062 script = strrchr(realpath_buff, '/');
1068 script = strrchr(realpath_buff, '/'); 1063 if (!script)
1069 if (script) { 1064 goto error_execing_cgi;
1070 *script = '\0'; 1065 *script = '\0';
1071 if (chdir(realpath_buff) == 0) { 1066 if (chdir(realpath_buff) == 0) {
1072 // now run the program. If it fails, 1067 // now run the program. If it fails,
1073 // use _exit() so no destructors 1068 // use _exit() so no destructors
1074 // get called and make a mess. 1069 // get called and make a mess.
1075#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1070#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1076 char *interpr = NULL; 1071 char *interpr = NULL;
1077 char *suffix = strrchr(purl, '.'); 1072 char *suffix = strrchr(purl, '.');
1078 1073
1079 if (suffix) { 1074 if (suffix) {
1080 Htaccess * cur; 1075 Htaccess *cur;
1081 for (cur = config->script_i; cur; cur = cur->next) 1076 for (cur = config->script_i; cur; cur = cur->next) {
1082 if (strcmp(cur->before_colon + 1, suffix) == 0) { 1077 if (strcmp(cur->before_colon + 1, suffix) == 0) {
1083 interpr = cur->after_colon; 1078 interpr = cur->after_colon;
1084 break; 1079 break;
1085 }
1086 } 1080 }
1081 }
1082 }
1087#endif 1083#endif
1088 *script = '/'; 1084 *script = '/';
1089#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1085#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1090 if (interpr) 1086 if (interpr)
1091 execv(interpr, argp); 1087 execv(interpr, argp);
1092 else 1088 else
1093#endif 1089#endif
1094 execv(realpath_buff, argp); 1090 execv(realpath_buff, argp);
1095 }
1096 }
1097 } 1091 }
1092 error_execing_cgi:
1098 /* send to stdout (even if we are not from inetd) */ 1093 /* send to stdout (even if we are not from inetd) */
1099 config->accepted_socket = 1; 1094 config->accepted_socket = 1;
1100 sendHeaders(HTTP_NOT_FOUND); 1095 sendHeaders(HTTP_NOT_FOUND);
@@ -1103,7 +1098,7 @@ static int sendCgi(const char *url,
1103 1098
1104 } while (0); 1099 } while (0);
1105 1100
1106 if (pid) { 1101 if (pid > 0) {
1107 /* parent process */ 1102 /* parent process */
1108 int status; 1103 int status;
1109 size_t post_readed_size = 0, post_readed_idx = 0; 1104 size_t post_readed_size = 0, post_readed_idx = 0;
@@ -1425,7 +1420,7 @@ static void handleIncoming(void)
1425 int ip_allowed; 1420 int ip_allowed;
1426#if ENABLE_FEATURE_HTTPD_CGI 1421#if ENABLE_FEATURE_HTTPD_CGI
1427 const char *prequest = request_GET; 1422 const char *prequest = request_GET;
1428 long length = 0; 1423 unsigned long length = 0;
1429 char *cookie = 0; 1424 char *cookie = 0;
1430 char *content_type = 0; 1425 char *content_type = 0;
1431#endif 1426#endif
@@ -1452,11 +1447,11 @@ static void handleIncoming(void)
1452 1447
1453 purl = strpbrk(buf, " \t"); 1448 purl = strpbrk(buf, " \t");
1454 if (purl == NULL) { 1449 if (purl == NULL) {
1455BAD_REQUEST: 1450 BAD_REQUEST:
1456 sendHeaders(HTTP_BAD_REQUEST); 1451 sendHeaders(HTTP_BAD_REQUEST);
1457 break; 1452 break;
1458 } 1453 }
1459 *purl = 0; 1454 *purl = '\0';
1460#if ENABLE_FEATURE_HTTPD_CGI 1455#if ENABLE_FEATURE_HTTPD_CGI
1461 if (strcasecmp(buf, prequest) != 0) { 1456 if (strcasecmp(buf, prequest) != 0) {
1462 prequest = "POST"; 1457 prequest = "POST";
@@ -1487,29 +1482,35 @@ BAD_REQUEST:
1487 /* extract url args if present */ 1482 /* extract url args if present */
1488 test = strchr(url, '?'); 1483 test = strchr(url, '?');
1489 if (test) { 1484 if (test) {
1490 *test++ = 0; 1485 *test++ = '\0';
1491 config->query = test; 1486 config->query = test;
1492 } 1487 }
1493 1488
1494 test = decodeString(url, 0); 1489 test = decodeString(url, 0);
1495 if (test == NULL) 1490 if (test == NULL)
1496 goto BAD_REQUEST; 1491 goto BAD_REQUEST;
1492 /* FIXME: bug? should be "url+1"? */
1497 if (test == (buf+1)) { 1493 if (test == (buf+1)) {
1498 sendHeaders(HTTP_NOT_FOUND); 1494 sendHeaders(HTTP_NOT_FOUND);
1499 break; 1495 break;
1500 } 1496 }
1497
1501 /* algorithm stolen from libbb bb_simplify_path(), 1498 /* algorithm stolen from libbb bb_simplify_path(),
1502 but don't strdup and reducing trailing slash and protect out root */ 1499 but don't strdup and reducing trailing slash and protect out root */
1503 purl = test = url; 1500 purl = test = url;
1504
1505 do { 1501 do {
1506 if (*purl == '/') { 1502 if (*purl == '/') {
1507 if (*test == '/') { /* skip duplicate (or initial) slash */ 1503 /* skip duplicate (or initial) slash */
1504 if (*test == '/') {
1508 continue; 1505 continue;
1509 } else if (*test == '.') { 1506 }
1510 if (test[1] == '/' || test[1] == 0) { /* skip extra '.' */ 1507 if (*test == '.') {
1508 /* skip extra '.' */
1509 if (test[1] == '/' || test[1] == 0) {
1511 continue; 1510 continue;
1512 } else if ((test[1] == '.') && (test[2] == '/' || test[2] == 0)) { 1511 } else
1512 /* '..': be careful */
1513 if (test[1] == '.' && (test[2] == '/' || test[2] == 0)) {
1513 ++test; 1514 ++test;
1514 if (purl == url) { 1515 if (purl == url) {
1515 /* protect out root */ 1516 /* protect out root */
@@ -1522,9 +1523,8 @@ BAD_REQUEST:
1522 } 1523 }
1523 *++purl = *test; 1524 *++purl = *test;
1524 } while (*++test); 1525 } while (*++test);
1525 1526 *++purl = '\0'; /* so keep last character */
1526 *++purl = 0; /* so keep last character */ 1527 test = purl; /* end ptr */
1527 test = purl; /* end ptr */
1528 1528
1529 /* If URL is directory, adding '/' */ 1529 /* If URL is directory, adding '/' */
1530 if (test[-1] != '/') { 1530 if (test[-1] != '/') {
@@ -1560,36 +1560,40 @@ BAD_REQUEST:
1560 1560
1561#if ENABLE_FEATURE_HTTPD_CGI 1561#if ENABLE_FEATURE_HTTPD_CGI
1562 /* try and do our best to parse more lines */ 1562 /* try and do our best to parse more lines */
1563 if ((strncasecmp(buf, Content_length, 15) == 0)) { 1563 if ((STRNCASECMP(buf, "Content-length:") == 0)) {
1564 if (prequest != request_GET) 1564 /* extra read only for POST */
1565 length = strtol(buf + 15, 0, 0); // extra read only for POST 1565 if (prequest != request_GET) {
1566 } else if ((strncasecmp(buf, "Cookie:", 7) == 0)) { 1566 test = buf + sizeof("Content-length:")-1;
1567 for (test = buf + 7; isspace(*test); test++) 1567 if (!test[0]) goto bail_out;
1568 ; 1568 errno = 0;
1569 cookie = strdup(test); 1569 /* not using strtoul: it ignores leading munis! */
1570 } else if ((strncasecmp(buf, "Content-Type:", 13) == 0)) { 1570 length = strtol(test, &test, 10);
1571 for (test = buf + 13; isspace(*test); test++) 1571 /* length is "ulong", but we need to pass it to int later */
1572 ; 1572 /* so we check for negative or too large values in one go: */
1573 content_type = strdup(test); 1573 /* (long -> ulong conv will cause negatives to be seen as > INT_MAX) */
1574 } else if ((strncasecmp(buf, "Referer:", 8) == 0)) { 1574 if (test[0] || errno || length > INT_MAX)
1575 for (test = buf + 8; isspace(*test); test++) 1575 goto bail_out;
1576 ; 1576 }
1577 config->referer = strdup(test); 1577 } else if ((STRNCASECMP(buf, "Cookie:") == 0)) {
1578 cookie = strdup(skip_whitespace(buf + sizeof("Cookie:")-1));
1579 } else if ((STRNCASECMP(buf, "Content-Type:") == 0)) {
1580 content_type = strdup(skip_whitespace(buf + sizeof("Content-Type:")-1));
1581 } else if ((STRNCASECMP(buf, "Referer:") == 0)) {
1582 config->referer = strdup(skip_whitespace(buf + sizeof("Referer:")-1));
1578 } 1583 }
1579#endif 1584#endif
1580 1585
1581#if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1586#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
1582 if (strncasecmp(buf, "Authorization:", 14) == 0) { 1587 if (STRNCASECMP(buf, "Authorization:") == 0) {
1583 /* We only allow Basic credentials. 1588 /* We only allow Basic credentials.
1584 * It shows up as "Authorization: Basic <userid:password>" where 1589 * It shows up as "Authorization: Basic <userid:password>" where
1585 * the userid:password is base64 encoded. 1590 * the userid:password is base64 encoded.
1586 */ 1591 */
1587 for (test = buf + 14; isspace(*test); test++) 1592 test = skip_whitespace(buf + sizeof("Authorization:")-1);
1588 ; 1593 if (STRNCASECMP(test, "Basic") != 0)
1589 if (strncasecmp(test, "Basic", 5) != 0)
1590 continue; 1594 continue;
1591 1595 test += sizeof("Basic")-1;
1592 test += 5; /* decodeBase64() skiping space self */ 1596 /* decodeBase64() skips whitespace itself */
1593 decodeBase64(test); 1597 decodeBase64(test);
1594 credentials = checkPerm(url, test); 1598 credentials = checkPerm(url, test);
1595 } 1599 }
@@ -1627,10 +1631,6 @@ FORBIDDEN: /* protect listing /cgi-bin */
1627 test = url + 1; /* skip first '/' */ 1631 test = url + 1; /* skip first '/' */
1628 1632
1629#if ENABLE_FEATURE_HTTPD_CGI 1633#if ENABLE_FEATURE_HTTPD_CGI
1630 /* if strange Content-Length */
1631 if (length < 0)
1632 break;
1633
1634 if (strncmp(test, "cgi-bin", 7) == 0) { 1634 if (strncmp(test, "cgi-bin", 7) == 0) {
1635 if (test[7] == '/' && test[8] == 0) 1635 if (test[7] == '/' && test[8] == 0)
1636 goto FORBIDDEN; // protect listing cgi-bin/ 1636 goto FORBIDDEN; // protect listing cgi-bin/
@@ -1654,6 +1654,8 @@ FORBIDDEN: /* protect listing /cgi-bin */
1654#endif 1654#endif
1655 } while (0); 1655 } while (0);
1656 1656
1657 bail_out:
1658
1657 if (DEBUG) 1659 if (DEBUG)
1658 fprintf(stderr, "closing socket\n\n"); 1660 fprintf(stderr, "closing socket\n\n");
1659#if ENABLE_FEATURE_HTTPD_CGI 1661#if ENABLE_FEATURE_HTTPD_CGI