Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/networking/httpd.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/networking/httpd.c
r2725 r3232 21 21 * The server changes directory to the location of the script and executes it 22 22 * after setting QUERY_STRING and other environment variables. 23 * 24 * If directory URL is given, no index.html is found and CGI support is enabled, 25 * cgi-bin/index.cgi will be run. Directory to list is ../$QUERY_STRING. 26 * See httpd_indexcgi.c for an example GCI code. 23 27 * 24 28 * Doc: … … 51 55 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ 52 56 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ 57 * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/ 58 * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/ 53 59 * .au:audio/basic # additional mime type for audio.au files 54 60 * *.php:/path/php # run xxx.php through an interpreter … … 72 78 * A:* # (optional line added for clarity) 73 79 * 74 * If a sub directory contains a config fileit is parsed and merged with80 * If a sub directory contains config file, it is parsed and merged with 75 81 * any existing settings as if it was appended to the original configuration. 76 82 * … … 94 100 /* TODO: use TCP_CORK, parse_config() */ 95 101 102 //usage:#define httpd_trivial_usage 103 //usage: "[-ifv[v]]" 104 //usage: " [-c CONFFILE]" 105 //usage: " [-p [IP:]PORT]" 106 //usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") 107 //usage: IF_FEATURE_HTTPD_BASIC_AUTH(" [-r REALM]") 108 //usage: " [-h HOME]\n" 109 //usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" 110 //usage:#define httpd_full_usage "\n\n" 111 //usage: "Listen for incoming HTTP requests\n" 112 //usage: "\n -i Inetd mode" 113 //usage: "\n -f Don't daemonize" 114 //usage: "\n -v[v] Verbose" 115 //usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" 116 //usage: IF_FEATURE_HTTPD_SETUID( 117 //usage: "\n -u USER[:GRP] Set uid/gid after binding to port") 118 //usage: IF_FEATURE_HTTPD_BASIC_AUTH( 119 //usage: "\n -r REALM Authentication Realm for Basic Authentication") 120 //usage: "\n -h HOME Home directory (default .)" 121 //usage: "\n -c FILE Configuration file (default {/etc,HOME}/httpd.conf)" 122 //usage: IF_FEATURE_HTTPD_AUTH_MD5( 123 //usage: "\n -m STRING MD5 crypt STRING") 124 //usage: "\n -e STRING HTML encode STRING" 125 //usage: "\n -d STRING URL decode STRING" 126 96 127 #include "libbb.h" 128 #if ENABLE_PAM 129 /* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 130 # undef setlocale 131 /* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. 132 * Apparently they like to confuse people. */ 133 # include <security/pam_appl.h> 134 # include <security/pam_misc.h> 135 #endif 97 136 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 98 137 # include <sys/sendfile.h> … … 310 349 #else 311 350 enum { 312 range_start = 0,351 range_start = -1, 313 352 range_end = MAXINT(off_t) - 1, 314 353 range_len = MAXINT(off_t), … … 332 371 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 333 372 IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ 373 IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ 334 374 bind_addr_or_port = "80"; \ 335 375 index_page = index_html; \ … … 757 797 config_error: 758 798 bb_error_msg("config error '%s' in '%s'", buf, filename); 759 760 761 799 } /* while (fgets) */ 800 801 fclose(f); 762 802 } 763 803 … … 791 831 } 792 832 #endif 793 794 /*795 * Given a URL encoded string, convert it to plain ascii.796 * Since decoding always makes strings smaller, the decode is done in-place.797 * Thus, callers should xstrdup() the argument if they do not want the798 * argument modified. The return is the original pointer, allowing this799 * function to be easily used as arguments to other functions.800 *801 * string The first string to decode.802 * option_d 1 if called for httpd -d803 *804 * Returns a pointer to the decoded string (same as input).805 */806 static unsigned hex_to_bin(unsigned char c)807 {808 unsigned v;809 810 v = c - '0';811 if (v <= 9)812 return v;813 /* c | 0x20: letters to lower case, non-letters814 * to (potentially different) non-letters */815 v = (unsigned)(c | 0x20) - 'a';816 if (v <= 5)817 return v + 10;818 return ~0;819 /* For testing:820 void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }821 int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');822 t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }823 */824 }825 static char *decodeString(char *orig, int option_d)826 {827 /* note that decoded string is always shorter than original */828 char *string = orig;829 char *ptr = string;830 char c;831 832 while ((c = *ptr++) != '\0') {833 unsigned v;834 835 if (option_d && c == '+') {836 *string++ = ' ';837 continue;838 }839 if (c != '%') {840 *string++ = c;841 continue;842 }843 v = hex_to_bin(ptr[0]);844 if (v > 15) {845 bad_hex:846 if (!option_d)847 return NULL;848 *string++ = '%';849 continue;850 }851 v = (v * 16) | hex_to_bin(ptr[1]);852 if (v > 255)853 goto bad_hex;854 if (!option_d && (v == '/' || v == '\0')) {855 /* caller takes it as indication of invalid856 * (dangerous wrt exploits) chars */857 return orig + 1;858 }859 *string++ = v;860 ptr += 2;861 }862 *string = '\0';863 return orig;864 }865 833 866 834 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH … … 1066 1034 static void send_headers_and_exit(int responseNum) 1067 1035 { 1036 IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) 1068 1037 send_headers(responseNum); 1069 1038 log_and_exit(); … … 1298 1267 * Parameters: 1299 1268 * const char *url The requested URL (with leading /). 1269 * const char *orig_uri The original URI before rewriting (if any) 1300 1270 * int post_len Length of the POST body. 1301 1271 * const char *cookie For set HTTP_COOKIE. … … 1304 1274 static void send_cgi_and_exit( 1305 1275 const char *url, 1276 const char *orig_uri, 1306 1277 const char *request, 1307 1278 int post_len, … … 1310 1281 static void send_cgi_and_exit( 1311 1282 const char *url, 1283 const char *orig_uri, 1312 1284 const char *request, 1313 1285 int post_len, … … 1317 1289 struct fd_pair fromCgi; /* CGI -> httpd pipe */ 1318 1290 struct fd_pair toCgi; /* httpd -> CGI pipe */ 1319 char *script ;1291 char *script, *last_slash; 1320 1292 int pid; 1321 1293 … … 1331 1303 1332 1304 /* Check for [dirs/]script.cgi/PATH_INFO */ 1333 script = (char*)url;1305 last_slash = script = (char*)url; 1334 1306 while ((script = strchr(script + 1, '/')) != NULL) { 1307 int dir; 1335 1308 *script = '\0'; 1336 if (!is_directory(url + 1, 1, NULL)) { 1309 dir = is_directory(url + 1, /*followlinks:*/ 1); 1310 *script = '/'; 1311 if (!dir) { 1337 1312 /* not directory, found script.cgi/PATH_INFO */ 1338 *script = '/';1339 1313 break; 1340 1314 } 1341 *script = '/'; /* is directory, find next '/' */ 1315 /* is directory, find next '/' */ 1316 last_slash = script; 1342 1317 } 1343 1318 setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ 1344 1319 setenv1("REQUEST_METHOD", request); 1345 1320 if (g_query) { 1346 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query));1321 putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query)); 1347 1322 } else { 1348 setenv1("REQUEST_URI", url);1323 setenv1("REQUEST_URI", orig_uri); 1349 1324 } 1350 1325 if (script != NULL) … … 1420 1395 } 1421 1396 1422 if ( !pid) {1397 if (pid == 0) { 1423 1398 /* Child process */ 1424 1399 char *argv[3]; … … 1436 1411 1437 1412 /* Chdiring to script's dir */ 1438 script = strrchr(url, '/');1413 script = last_slash; 1439 1414 if (script != url) { /* paranoia */ 1440 1415 *script = '\0'; 1441 1416 if (chdir(url + 1) != 0) { 1442 bb_perror_msg("c hdir(%s)", url + 1);1417 bb_perror_msg("can't change directory to '%s'", url + 1); 1443 1418 goto error_execing_cgi; 1444 1419 } … … 1616 1591 || content_gzip /* we are sending compressed page: can't do ranges */ ///why? 1617 1592 ) { 1618 range_start = 0;1593 range_start = -1; 1619 1594 } 1620 1595 range_len = MAXINT(off_t); 1621 if (range_start ) {1622 if (!range_end ) {1596 if (range_start >= 0) { 1597 if (!range_end || range_end > file_size - 1) { 1623 1598 range_end = file_size - 1; 1624 1599 } … … 1627 1602 ) { 1628 1603 lseek(fd, 0, SEEK_SET); 1629 range_start = 0;1604 range_start = -1; 1630 1605 } else { 1631 1606 range_len = range_end - range_start + 1; … … 1650 1625 goto fin; 1651 1626 } 1652 IF_FEATURE_HTTPD_RANGES(range_len -= sz;)1627 IF_FEATURE_HTTPD_RANGES(range_len -= count;) 1653 1628 if (count == 0 || range_len == 0) 1654 1629 log_and_exit(); … … 1701 1676 1702 1677 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1678 1679 # if ENABLE_PAM 1680 struct pam_userinfo { 1681 const char *name; 1682 const char *pw; 1683 }; 1684 1685 static int pam_talker(int num_msg, 1686 const struct pam_message **msg, 1687 struct pam_response **resp, 1688 void *appdata_ptr) 1689 { 1690 int i; 1691 struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; 1692 struct pam_response *response; 1693 1694 if (!resp || !msg || !userinfo) 1695 return PAM_CONV_ERR; 1696 1697 /* allocate memory to store response */ 1698 response = xzalloc(num_msg * sizeof(*response)); 1699 1700 /* copy values */ 1701 for (i = 0; i < num_msg; i++) { 1702 const char *s; 1703 1704 switch (msg[i]->msg_style) { 1705 case PAM_PROMPT_ECHO_ON: 1706 s = userinfo->name; 1707 break; 1708 case PAM_PROMPT_ECHO_OFF: 1709 s = userinfo->pw; 1710 break; 1711 case PAM_ERROR_MSG: 1712 case PAM_TEXT_INFO: 1713 s = ""; 1714 break; 1715 default: 1716 free(response); 1717 return PAM_CONV_ERR; 1718 } 1719 response[i].resp = xstrdup(s); 1720 if (PAM_SUCCESS != 0) 1721 response[i].resp_retcode = PAM_SUCCESS; 1722 } 1723 *resp = response; 1724 return PAM_SUCCESS; 1725 } 1726 # endif 1727 1703 1728 /* 1704 1729 * Config file entries are of the form "/<path>:<user>:<passwd>". … … 1710 1735 * Returns 1 if user_and_passwd is OK. 1711 1736 */ 1712 static int check_user_passwd(const char *path, c onst char *user_and_passwd)1737 static int check_user_passwd(const char *path, char *user_and_passwd) 1713 1738 { 1714 1739 Htaccess *cur; … … 1718 1743 const char *dir_prefix; 1719 1744 size_t len; 1745 int r; 1720 1746 1721 1747 dir_prefix = cur->before_colon; … … 1733 1759 if (len != 1 /* dir_prefix "/" matches all, don't need to check */ 1734 1760 && (strncmp(dir_prefix, path, len) != 0 1735 || (path[len] != '/' && path[len] != '\0')) 1761 || (path[len] != '/' && path[len] != '\0') 1762 ) 1736 1763 ) { 1737 1764 continue; … … 1742 1769 1743 1770 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { 1744 char *md5_passwd; 1745 1746 md5_passwd = strchr(cur->after_colon, ':'); 1747 if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' 1748 && md5_passwd[3] == '$' && md5_passwd[4] 1771 char *colon_after_user; 1772 const char *passwd; 1773 # if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM 1774 char sp_buf[256]; 1775 # endif 1776 1777 colon_after_user = strchr(user_and_passwd, ':'); 1778 if (!colon_after_user) 1779 goto bad_input; 1780 1781 /* compare "user:" */ 1782 if (cur->after_colon[0] != '*' 1783 && strncmp(cur->after_colon, user_and_passwd, 1784 colon_after_user - user_and_passwd + 1) != 0 1749 1785 ) { 1786 continue; 1787 } 1788 /* this cfg entry is '*' or matches username from peer */ 1789 1790 passwd = strchr(cur->after_colon, ':'); 1791 if (!passwd) 1792 goto bad_input; 1793 passwd++; 1794 if (passwd[0] == '*') { 1795 # if ENABLE_PAM 1796 struct pam_userinfo userinfo; 1797 struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; 1798 pam_handle_t *pamh; 1799 1800 *colon_after_user = '\0'; 1801 userinfo.name = user_and_passwd; 1802 userinfo.pw = colon_after_user + 1; 1803 r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS; 1804 if (r == 0) { 1805 r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS 1806 || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS 1807 ; 1808 pam_end(pamh, PAM_SUCCESS); 1809 } 1810 *colon_after_user = ':'; 1811 goto end_check_passwd; 1812 # else 1813 # if ENABLE_FEATURE_SHADOWPASSWDS 1814 /* Using _r function to avoid pulling in static buffers */ 1815 struct spwd spw; 1816 # endif 1817 struct passwd *pw; 1818 1819 *colon_after_user = '\0'; 1820 pw = getpwnam(user_and_passwd); 1821 *colon_after_user = ':'; 1822 if (!pw || !pw->pw_passwd) 1823 continue; 1824 passwd = pw->pw_passwd; 1825 # if ENABLE_FEATURE_SHADOWPASSWDS 1826 if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) { 1827 /* getspnam_r may return 0 yet set result to NULL. 1828 * At least glibc 2.4 does this. Be extra paranoid here. */ 1829 struct spwd *result = NULL; 1830 r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result); 1831 if (r == 0 && result) 1832 passwd = result->sp_pwdp; 1833 } 1834 # endif 1835 /* In this case, passwd is ALWAYS encrypted: 1836 * it came from /etc/passwd or /etc/shadow! 1837 */ 1838 goto check_encrypted; 1839 # endif /* ENABLE_PAM */ 1840 } 1841 /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ 1842 1843 if (passwd[0] == '$' && isdigit(passwd[1])) { 1750 1844 char *encrypted; 1751 int r, user_len_p1; 1752 1753 md5_passwd++; 1754 user_len_p1 = md5_passwd - cur->after_colon; 1755 /* comparing "user:" */ 1756 if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { 1757 continue; 1758 } 1759 1845 # if !ENABLE_PAM 1846 check_encrypted: 1847 # endif 1848 /* encrypt pwd from peer and check match with local one */ 1760 1849 encrypted = pw_encrypt( 1761 user_and_passwd + user_len_p1 /* cleartext pwd from user */, 1762 md5_passwd /*salt */, 1 /* cleanup */); 1763 r = strcmp(encrypted, md5_passwd); 1850 /* pwd (from peer): */ colon_after_user + 1, 1851 /* salt: */ passwd, 1852 /* cleanup: */ 0 1853 ); 1854 r = strcmp(encrypted, passwd); 1764 1855 free(encrypted); 1765 if (r == 0) 1766 goto set_remoteuser_var; /* Ok */ 1767 continue; 1768 } 1769 } 1770 1856 } else { 1857 /* local passwd is from httpd.conf and it's plaintext */ 1858 r = strcmp(colon_after_user + 1, passwd); 1859 } 1860 goto end_check_passwd; 1861 } 1862 bad_input: 1771 1863 /* Comparing plaintext "user:pass" in one go */ 1772 if (strcmp(cur->after_colon, user_and_passwd) == 0) { 1773 set_remoteuser_var: 1864 r = strcmp(cur->after_colon, user_and_passwd); 1865 end_check_passwd: 1866 if (r == 0) { 1774 1867 remoteuser = xstrndup(user_and_passwd, 1775 strchrnul(user_and_passwd, ':') - user_and_passwd); 1868 strchrnul(user_and_passwd, ':') - user_and_passwd 1869 ); 1776 1870 return 1; /* Ok */ 1777 1871 } … … 1912 2006 1913 2007 /* Extract url args if present */ 1914 g_query = NULL;2008 /* g_query = NULL; - already is */ 1915 2009 tptr = strchr(urlcopy, '?'); 1916 2010 if (tptr) { … … 1920 2014 1921 2015 /* Decode URL escape sequences */ 1922 tptr = decodeString(urlcopy, 0);2016 tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); 1923 2017 if (tptr == NULL) 1924 2018 send_headers_and_exit(HTTP_BAD_REQUEST); … … 1932 2026 * but don't strdup, retain trailing slash, protect root */ 1933 2027 urlp = tptr = urlcopy; 1934 do{2028 for (;;) { 1935 2029 if (*urlp == '/') { 1936 2030 /* skip duplicate (or initial) slash */ 1937 2031 if (*tptr == '/') { 1938 continue;2032 goto next_char; 1939 2033 } 1940 2034 if (*tptr == '.') { 1941 /* skip extra "/./" */ 1942 if (tptr[1] == '/' || !tptr[1]) { 1943 continue; 2035 if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) { 2036 /* "..": be careful */ 2037 /* protect root */ 2038 if (urlp == urlcopy) 2039 send_headers_and_exit(HTTP_BAD_REQUEST); 2040 /* omit previous dir */ 2041 while (*--urlp != '/') 2042 continue; 2043 /* skip to "./" or ".<NUL>" */ 2044 tptr++; 1944 2045 } 1945 /* "..": be careful */ 1946 if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { 1947 ++tptr; 1948 if (urlp == urlcopy) /* protect root */ 1949 send_headers_and_exit(HTTP_BAD_REQUEST); 1950 while (*--urlp != '/') /* omit previous dir */; 1951 continue; 2046 if (tptr[1] == '/' || tptr[1] == '\0') { 2047 /* skip extra "/./" */ 2048 goto next_char; 1952 2049 } 1953 2050 } 1954 2051 } 1955 2052 *++urlp = *tptr; 1956 } while (*++tptr); 1957 *++urlp = '\0'; /* terminate after last character */ 2053 if (*urlp == '\0') 2054 break; 2055 next_char: 2056 tptr++; 2057 } 1958 2058 1959 2059 /* If URL is a directory, add '/' */ 1960 2060 if (urlp[-1] != '/') { 1961 if (is_directory(urlcopy + 1, 1, NULL)) {2061 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { 1962 2062 found_moved_temporarily = urlcopy; 1963 2063 } … … 1973 2073 /* have path1/path2 */ 1974 2074 *tptr = '\0'; 1975 if (is_directory(urlcopy + 1, 1, NULL)) {2075 if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { 1976 2076 /* may have subdir config */ 1977 2077 parse_conf(urlcopy + 1, SUBDIR_PARSE); … … 2072 2172 range_start = BB_STRTOOFF(s, &s, 10); 2073 2173 if (s[0] != '-' || range_start < 0) { 2074 range_start = 0;2174 range_start = -1; 2075 2175 } else if (s[1]) { 2076 2176 range_end = BB_STRTOOFF(s+1, NULL, 10); 2077 2177 if (errno || range_end < range_start) 2078 range_start = 0;2178 range_start = -1; 2079 2179 } 2080 2180 } … … 2110 2210 2111 2211 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 2112 /* Case: no "Authorization:" was seen, but page doesrequire passwd.2212 /* Case: no "Authorization:" was seen, but page might require passwd. 2113 2213 * Check that with dummy user:pass */ 2114 2214 if (authorized < 0) 2115 authorized = check_user_passwd(urlcopy, ":");2215 authorized = check_user_passwd(urlcopy, (char *) ""); 2116 2216 if (!authorized) 2117 2217 send_headers_and_exit(HTTP_UNAUTHORIZED); … … 2159 2259 send_headers_and_exit(HTTP_FORBIDDEN); 2160 2260 } 2161 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); 2162 } 2163 #endif 2164 2165 if (urlp[-1] == '/') 2261 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); 2262 } 2263 #endif 2264 2265 if (urlp[-1] == '/') { 2266 /* When index_page string is appended to <dir>/ URL, it overwrites 2267 * the query string. If we fall back to call /cgi-bin/index.cgi, 2268 * query string would be lost and not available to the CGI. 2269 * Work around it by making a deep copy. 2270 */ 2271 if (ENABLE_FEATURE_HTTPD_CGI) 2272 g_query = xstrdup(g_query); /* ok for NULL too */ 2166 2273 strcpy(urlp, index_page); 2274 } 2167 2275 if (stat(tptr, &sb) == 0) { 2168 2276 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR … … 2172 2280 for (cur = script_i; cur; cur = cur->next) { 2173 2281 if (strcmp(cur->before_colon + 1, suffix) == 0) { 2174 send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type);2282 send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); 2175 2283 } 2176 2284 } … … 2185 2293 * Try cgi-bin/index.cgi */ 2186 2294 if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { 2187 urlp[0] = '\0'; 2188 g_query = urlcopy; 2189 send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type); 2295 urlp[0] = '\0'; /* remove index_page */ 2296 send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type); 2190 2297 } 2191 2298 } … … 2286 2393 re_exec(argv_copy); 2287 2394 } 2395 argv_copy[0][0] &= 0x7f; 2288 2396 /* parent, or vfork failed */ 2289 2397 close(n); … … 2379 2487 ); 2380 2488 if (opt & OPT_DECODE_URL) { 2381 fputs( decodeString(url_for_decode, 1), stdout);2489 fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout); 2382 2490 return 0; 2383 2491 } … … 2394 2502 salt[1] = '1'; 2395 2503 salt[2] = '$'; 2396 crypt_make_salt(salt + 3, 4 , 0);2397 puts(pw_encrypt(pass, salt, 1));2504 crypt_make_salt(salt + 3, 4); 2505 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); 2398 2506 return 0; 2399 2507 }
Note:
See TracChangeset
for help on using the changeset viewer.