diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-05-07 12:18:48 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-05-07 12:18:48 +0000 |
| commit | 6bf05cf1ff3debbab2bcc482dffb821aa458177b (patch) | |
| tree | 62e5266ba56c91dc6973f7badfdcfde8e81c2a4a | |
| parent | b153ace939f7ab2857605fe10c6ae3ebd903288a (diff) | |
| download | busybox-w32-6bf05cf1ff3debbab2bcc482dffb821aa458177b.tar.gz busybox-w32-6bf05cf1ff3debbab2bcc482dffb821aa458177b.tar.bz2 busybox-w32-6bf05cf1ff3debbab2bcc482dffb821aa458177b.zip | |
httpd: fix several bugs triggering by realtive path in -h DIR.
function old new delta
handle_incoming_and_exit 2657 2659 +2
send_cgi_and_exit 869 862 -7
parse_conf 1647 1626 -21
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 2/-28) Total: -26 bytes
| -rw-r--r-- | include/libbb.h | 4 | ||||
| -rw-r--r-- | libbb/concat_path_file.c | 8 | ||||
| -rw-r--r-- | networking/httpd.c | 143 |
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 | ||
| 939 | extern int bb_parse_mode(const char* s, mode_t* theMode); | 939 | extern 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. */ | ||
| 941 | char *concat_path_file(const char *path, const char *filename); | 945 | char *concat_path_file(const char *path, const char *filename); |
| 942 | char *concat_subpath_file(const char *path, const char *filename); | 946 | char *concat_subpath_file(const char *path, const char *filename); |
| 943 | const char *bb_basename(const char *name); | 947 | const 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:") |
