aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h4
-rw-r--r--libbb/concat_path_file.c8
-rw-r--r--networking/httpd.c143
3 files changed, 84 insertions, 71 deletions
diff --git a/include/libbb.h b/include/libbb.h
index dfcc96d5b..281152f5f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -938,6 +938,10 @@ int bb_ask_confirmation(void);
938 938
939extern int bb_parse_mode(const char* s, mode_t* theMode); 939extern int bb_parse_mode(const char* s, mode_t* theMode);
940 940
941/* Concatenate path and filename to new allocated buffer.
942 * Add "/" only as needed (no duplicate "//" are produced).
943 * If path is NULL, it is assumed to be "/".
944 * filename should not be NULL. */
941char *concat_path_file(const char *path, const char *filename); 945char *concat_path_file(const char *path, const char *filename);
942char *concat_subpath_file(const char *path, const char *filename); 946char *concat_subpath_file(const char *path, const char *filename);
943const char *bb_basename(const char *name); 947const char *bb_basename(const char *name);
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index 9aae601a4..dd6909fc2 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -8,9 +8,11 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */ 9 */
10 10
11/* concatenate path and file name to new allocation buffer, 11/* Concatenate path and filename to new allocated buffer.
12 * not adding '/' if path name already has '/' 12 * Add '/' only as needed (no duplicate // are produced).
13*/ 13 * If path is NULL, it is assumed to be "/".
14 * filename should not be NULL.
15 */
14 16
15#include "libbb.h" 17#include "libbb.h"
16 18
diff --git a/networking/httpd.c b/networking/httpd.c
index ed699df48..6fd322cb8 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -613,7 +613,12 @@ static void parse_conf(const char *path, int flag)
613 /* then error page; find matching status */ 613 /* then error page; find matching status */
614 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { 614 for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
615 if (http_response_type[i] == status) { 615 if (http_response_type[i] == status) {
616 http_error_page[i] = concat_path_file((*c == '/') ? NULL : home_httpd, c); 616 // We chdir to home_httpd, thus no need to
617 // concat_path_file(home_httpd, c)
618 //if (c[0] == '/' || home_httpd[0] != '/')
619 http_error_page[i] = xstrdup(c);
620 //else
621 // http_error_page[i] = concat_path_file(home_httpd, c);
617 break; 622 break;
618 } 623 }
619 } 624 }
@@ -1009,7 +1014,7 @@ static void send_headers(int responseNum)
1009 } 1014 }
1010 1015
1011#if ENABLE_FEATURE_HTTPD_ERROR_PAGES 1016#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
1012 if (error_page && !access(error_page, R_OK)) { 1017 if (error_page && access(error_page, R_OK) == 0) {
1013 strcat(iobuf, "\r\n"); 1018 strcat(iobuf, "\r\n");
1014 len += 2; 1019 len += 2;
1015 1020
@@ -1313,49 +1318,49 @@ static void send_cgi_and_exit(
1313{ 1318{
1314 struct fd_pair fromCgi; /* CGI -> httpd pipe */ 1319 struct fd_pair fromCgi; /* CGI -> httpd pipe */
1315 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1320 struct fd_pair toCgi; /* httpd -> CGI pipe */
1316 char *fullpath;
1317 char *script; 1321 char *script;
1318 char *purl;
1319 int pid; 1322 int pid;
1320 1323
1324 /* Make a copy. NB: caller guarantees:
1325 * url[0] == '/', url[1] != '/' */
1326 url = xstrdup(url);
1327
1321 /* 1328 /*
1322 * We are mucking with environment _first_ and then vfork/exec, 1329 * We are mucking with environment _first_ and then vfork/exec,
1323 * this allows us to use vfork safely. Parent don't care about 1330 * this allows us to use vfork safely. Parent doesn't care about
1324 * these environment changes anyway. 1331 * these environment changes anyway.
1325 */ 1332 */
1326 1333
1327 /* 1334 /* Check for [dirs/]script.cgi/PATH_INFO */
1328 * Find PATH_INFO. 1335 script = (char*)url;
1329 */
1330 purl = xstrdup(url);
1331 script = purl;
1332 while ((script = strchr(script + 1, '/')) != NULL) { 1336 while ((script = strchr(script + 1, '/')) != NULL) {
1333 /* have script.cgi/PATH_INFO or dirs/script.cgi[/PATH_INFO] */
1334 struct stat sb; 1337 struct stat sb;
1335 1338
1336 *script = '\0'; 1339 *script = '\0';
1337 if (!is_directory(purl + 1, 1, &sb)) { 1340 if (!is_directory(url + 1, 1, &sb)) {
1338 /* not directory, found script.cgi/PATH_INFO */ 1341 /* not directory, found script.cgi/PATH_INFO */
1339 *script = '/'; 1342 *script = '/';
1340 break; 1343 break;
1341 } 1344 }
1342 *script = '/'; /* is directory, find next '/' */ 1345 *script = '/'; /* is directory, find next '/' */
1343 } 1346 }
1344 setenv1("PATH_INFO", script); /* set /PATH_INFO or "" */ 1347 setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */
1345 setenv1("REQUEST_METHOD", request); 1348 setenv1("REQUEST_METHOD", request);
1346 if (g_query) { 1349 if (g_query) {
1347 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", purl, g_query)); 1350 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query));
1348 } else { 1351 } else {
1349 setenv1("REQUEST_URI", purl); 1352 setenv1("REQUEST_URI", url);
1350 } 1353 }
1351 if (script != NULL) 1354 if (script != NULL)
1352 *script = '\0'; /* cut off /PATH_INFO */ 1355 *script = '\0'; /* cut off /PATH_INFO */
1353 1356
1354 /* SCRIPT_FILENAME required by PHP in CGI mode */ 1357 /* SCRIPT_FILENAME is required by PHP in CGI mode */
1355 fullpath = concat_path_file(home_httpd, purl); 1358 if (home_httpd[0] == '/') {
1356 setenv1("SCRIPT_FILENAME", fullpath); 1359 char *fullpath = concat_path_file(home_httpd, url);
1360 setenv1("SCRIPT_FILENAME", fullpath);
1361 }
1357 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */ 1362 /* set SCRIPT_NAME as full path: /cgi-bin/dirs/script.cgi */
1358 setenv1("SCRIPT_NAME", purl); 1363 setenv1("SCRIPT_NAME", url);
1359 /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html: 1364 /* http://hoohoo.ncsa.uiuc.edu/cgi/env.html:
1360 * QUERY_STRING: The information which follows the ? in the URL 1365 * QUERY_STRING: The information which follows the ? in the URL
1361 * which referenced this script. This is the query information. 1366 * which referenced this script. This is the query information.
@@ -1413,6 +1418,8 @@ static void send_cgi_and_exit(
1413 1418
1414 if (!pid) { 1419 if (!pid) {
1415 /* Child process */ 1420 /* Child process */
1421 char *argv[3];
1422
1416 xfunc_error_retval = 242; 1423 xfunc_error_retval = 242;
1417 1424
1418 /* NB: close _first_, then move fds! */ 1425 /* NB: close _first_, then move fds! */
@@ -1424,53 +1431,54 @@ static void send_cgi_and_exit(
1424 * If CGI really wants that, it can always do dup itself. */ 1431 * If CGI really wants that, it can always do dup itself. */
1425 /* dup2(1, 2); */ 1432 /* dup2(1, 2); */
1426 1433
1427 script = strrchr(fullpath, '/'); 1434 /* Chdiring to script's dir */
1428 //fullpath is a result of concat_path_file and always has '/' 1435 script = strrchr(url, '/');
1429 //if (!script) 1436 if (script != url) { /* paranoia */
1430 // goto error_execing_cgi; 1437 *script = '\0';
1431 *script = '\0'; 1438 if (chdir(url + 1) != 0) {
1432 /* chdiring to script's dir */ 1439 bb_perror_msg("chdir %s", url + 1);
1433 if (chdir(script == fullpath ? "/" : fullpath) == 0) { 1440 goto error_execing_cgi;
1434 char *argv[3]; 1441 }
1442 // not needed: *script = '/';
1443 }
1444 script++;
1435 1445
1436 *script++ = '/'; /* repair fullpath */ 1446 /* set argv[0] to name without path */
1437 /* set argv[0] to name without path */ 1447 argv[0] = script;
1438 argv[0] = script; 1448 argv[1] = NULL;
1439 argv[1] = NULL;
1440 1449
1441#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR 1450#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
1442 { 1451 {
1443 char *suffix = strrchr(script, '.'); 1452 char *suffix = strrchr(script, '.');
1444 1453
1445 if (suffix) { 1454 if (suffix) {
1446 Htaccess *cur; 1455 Htaccess *cur;
1447 for (cur = script_i; cur; cur = cur->next) { 1456 for (cur = script_i; cur; cur = cur->next) {
1448 if (strcmp(cur->before_colon + 1, suffix) == 0) { 1457 if (strcmp(cur->before_colon + 1, suffix) == 0) {
1449 /* found interpreter name */ 1458 /* found interpreter name */
1450 fullpath = cur->after_colon; 1459 argv[0] = cur->after_colon;
1451 argv[0] = cur->after_colon; 1460 argv[1] = script;
1452 argv[1] = script; 1461 argv[2] = NULL;
1453 argv[2] = NULL; 1462 break;
1454 break;
1455 }
1456 } 1463 }
1457 } 1464 }
1458 } 1465 }
1459#endif
1460 /* restore default signal dispositions for CGI process */
1461 bb_signals(0
1462 | (1 << SIGCHLD)
1463 | (1 << SIGPIPE)
1464 | (1 << SIGHUP)
1465 , SIG_DFL);
1466
1467 execv(fullpath, argv);
1468 if (verbose)
1469 bb_perror_msg("exec %s", fullpath);
1470 } else if (verbose) {
1471 bb_perror_msg("chdir %s", fullpath);
1472 } 1466 }
1473 //error_execing_cgi: 1467#endif
1468 /* restore default signal dispositions for CGI process */
1469 bb_signals(0
1470 | (1 << SIGCHLD)
1471 | (1 << SIGPIPE)
1472 | (1 << SIGHUP)
1473 , SIG_DFL);
1474
1475 /* _NOT_ execvp. We do not search PATH. argv[0] is a filename
1476 * without any dir components and will only match a file
1477 * in the current directory */
1478 execv(argv[0], argv);
1479 if (verbose)
1480 bb_perror_msg("exec %s", argv[0]);
1481 error_execing_cgi:
1474 /* send to stdout 1482 /* send to stdout
1475 * (we are CGI here, our stdout is pumped to the net) */ 1483 * (we are CGI here, our stdout is pumped to the net) */
1476 send_headers_and_exit(HTTP_NOT_FOUND); 1484 send_headers_and_exit(HTTP_NOT_FOUND);
@@ -1889,7 +1897,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1889 1897
1890 /* Canonicalize path */ 1898 /* Canonicalize path */
1891 /* Algorithm stolen from libbb bb_simplify_path(), 1899 /* Algorithm stolen from libbb bb_simplify_path(),
1892 * but don't strdup and reducing trailing slash and protect out root */ 1900 * but don't strdup, retain trailing slash, protect root */
1893 urlp = tptr = urlcopy; 1901 urlp = tptr = urlcopy;
1894 do { 1902 do {
1895 if (*urlp == '/') { 1903 if (*urlp == '/') {
@@ -1898,11 +1906,11 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1898 continue; 1906 continue;
1899 } 1907 }
1900 if (*tptr == '.') { 1908 if (*tptr == '.') {
1901 /* skip extra '.' */ 1909 /* skip extra "/./" */
1902 if (tptr[1] == '/' || !tptr[1]) { 1910 if (tptr[1] == '/' || !tptr[1]) {
1903 continue; 1911 continue;
1904 } 1912 }
1905 /* '..': be careful */ 1913 /* "..": be careful */
1906 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { 1914 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) {
1907 ++tptr; 1915 ++tptr;
1908 if (urlp == urlcopy) /* protect root */ 1916 if (urlp == urlcopy) /* protect root */
@@ -1914,11 +1922,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
1914 } 1922 }
1915 *++urlp = *tptr; 1923 *++urlp = *tptr;
1916 } while (*++tptr); 1924 } while (*++tptr);
1917 *++urlp = '\0'; /* so keep last character */ 1925 *++urlp = '\0'; /* terminate after last character */
1918 tptr = urlp; /* end ptr */
1919 1926
1920 /* If URL is a directory, add '/' */ 1927 /* If URL is a directory, add '/' */
1921 if (tptr[-1] != '/') { 1928 if (urlp[-1] != '/') {
1922 if (is_directory(urlcopy + 1, 1, &sb)) { 1929 if (is_directory(urlcopy + 1, 1, &sb)) {
1923 found_moved_temporarily = urlcopy; 1930 found_moved_temporarily = urlcopy;
1924 } 1931 }
@@ -2310,8 +2317,8 @@ int httpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
2310 /* -v counts, -i implies -f */ 2317 /* -v counts, -i implies -f */
2311 opt_complementary = "vv:if"; 2318 opt_complementary = "vv:if";
2312 /* We do not "absolutize" path given by -h (home) opt. 2319 /* We do not "absolutize" path given by -h (home) opt.
2313 * If user gives relative path in -h, $SCRIPT_FILENAME can end up 2320 * If user gives relative path in -h,
2314 * relative too. */ 2321 * $SCRIPT_FILENAME will not be set. */
2315 opt = getopt32(argv, "c:d:h:" 2322 opt = getopt32(argv, "c:d:h:"
2316 USE_FEATURE_HTTPD_ENCODE_URL_STR("e:") 2323 USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
2317 USE_FEATURE_HTTPD_BASIC_AUTH("r:") 2324 USE_FEATURE_HTTPD_BASIC_AUTH("r:")