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:") |