diff options
author | Pascal Bellard <pascal.bellard@ads-lu.com> | 2011-11-29 13:51:11 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-11-29 13:51:11 +0100 |
commit | 7291755439ad2f400df51a74b4e9a31a48f484b1 (patch) | |
tree | 98ab3d41aaecca3419d319e0f953818a1981e7f3 | |
parent | 901365fcffbc318395d24a05b6951288562da6af (diff) | |
download | busybox-w32-7291755439ad2f400df51a74b4e9a31a48f484b1.tar.gz busybox-w32-7291755439ad2f400df51a74b4e9a31a48f484b1.tar.bz2 busybox-w32-7291755439ad2f400df51a74b4e9a31a48f484b1.zip |
httpd: make it possible to use system passwords for auth
function old new delta
check_user_passwd 320 467 +147
httpd_main 760 757 -3
Signed-off-by: Pascal Bellard <pascal.bellard@ads-lu.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/httpd.c | 175 |
1 files changed, 147 insertions, 28 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index ecdf5b572..c66e0f66b 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -54,6 +54,8 @@ | |||
54 | * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ | 54 | * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ |
55 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ | 55 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ |
56 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | 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/ | ||
57 | * .au:audio/basic # additional mime type for audio.au files | 59 | * .au:audio/basic # additional mime type for audio.au files |
58 | * *.php:/path/php # run xxx.php through an interpreter | 60 | * *.php:/path/php # run xxx.php through an interpreter |
59 | * | 61 | * |
@@ -123,6 +125,14 @@ | |||
123 | //usage: "\n -d STRING URL decode STRING" | 125 | //usage: "\n -d STRING URL decode STRING" |
124 | 126 | ||
125 | #include "libbb.h" | 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 | ||
126 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE | 136 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE |
127 | # include <sys/sendfile.h> | 137 | # include <sys/sendfile.h> |
128 | #endif | 138 | #endif |
@@ -1658,6 +1668,56 @@ static int checkPermIP(void) | |||
1658 | } | 1668 | } |
1659 | 1669 | ||
1660 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 1670 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
1671 | |||
1672 | # if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM | ||
1673 | struct pam_userinfo { | ||
1674 | const char *name; | ||
1675 | const char *pw; | ||
1676 | }; | ||
1677 | |||
1678 | static int pam_talker(int num_msg, | ||
1679 | const struct pam_message **msg, | ||
1680 | struct pam_response **resp, | ||
1681 | void *appdata_ptr) | ||
1682 | { | ||
1683 | int i; | ||
1684 | struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; | ||
1685 | struct pam_response *response; | ||
1686 | |||
1687 | if (!resp || !msg || !userinfo) | ||
1688 | return PAM_CONV_ERR; | ||
1689 | |||
1690 | /* allocate memory to store response */ | ||
1691 | response = xzalloc(num_msg * sizeof(*response)); | ||
1692 | |||
1693 | /* copy values */ | ||
1694 | for (i = 0; i < num_msg; i++) { | ||
1695 | const char *s; | ||
1696 | |||
1697 | switch (msg[i]->msg_style) { | ||
1698 | case PAM_PROMPT_ECHO_ON: | ||
1699 | s = userinfo->name; | ||
1700 | break; | ||
1701 | case PAM_PROMPT_ECHO_OFF: | ||
1702 | s = userinfo->pw; | ||
1703 | break; | ||
1704 | case PAM_ERROR_MSG: | ||
1705 | case PAM_TEXT_INFO: | ||
1706 | s = ""; | ||
1707 | break; | ||
1708 | default: | ||
1709 | free(response); | ||
1710 | return PAM_CONV_ERR; | ||
1711 | } | ||
1712 | response[i].resp = xstrdup(s); | ||
1713 | if (PAM_SUCCESS != 0) | ||
1714 | response[i].resp_retcode = PAM_SUCCESS; | ||
1715 | } | ||
1716 | *resp = response; | ||
1717 | return PAM_SUCCESS; | ||
1718 | } | ||
1719 | # endif | ||
1720 | |||
1661 | /* | 1721 | /* |
1662 | * Config file entries are of the form "/<path>:<user>:<passwd>". | 1722 | * Config file entries are of the form "/<path>:<user>:<passwd>". |
1663 | * If config file has no prefix match for path, access is allowed. | 1723 | * If config file has no prefix match for path, access is allowed. |
@@ -1667,7 +1727,7 @@ static int checkPermIP(void) | |||
1667 | * | 1727 | * |
1668 | * Returns 1 if user_and_passwd is OK. | 1728 | * Returns 1 if user_and_passwd is OK. |
1669 | */ | 1729 | */ |
1670 | static int check_user_passwd(const char *path, const char *user_and_passwd) | 1730 | static int check_user_passwd(const char *path, char *user_and_passwd) |
1671 | { | 1731 | { |
1672 | Htaccess *cur; | 1732 | Htaccess *cur; |
1673 | const char *prev = NULL; | 1733 | const char *prev = NULL; |
@@ -1675,6 +1735,7 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) | |||
1675 | for (cur = g_auth; cur; cur = cur->next) { | 1735 | for (cur = g_auth; cur; cur = cur->next) { |
1676 | const char *dir_prefix; | 1736 | const char *dir_prefix; |
1677 | size_t len; | 1737 | size_t len; |
1738 | int r; | ||
1678 | 1739 | ||
1679 | dir_prefix = cur->before_colon; | 1740 | dir_prefix = cur->before_colon; |
1680 | 1741 | ||
@@ -1690,7 +1751,8 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) | |||
1690 | len = strlen(dir_prefix); | 1751 | len = strlen(dir_prefix); |
1691 | if (len != 1 /* dir_prefix "/" matches all, don't need to check */ | 1752 | if (len != 1 /* dir_prefix "/" matches all, don't need to check */ |
1692 | && (strncmp(dir_prefix, path, len) != 0 | 1753 | && (strncmp(dir_prefix, path, len) != 0 |
1693 | || (path[len] != '/' && path[len] != '\0')) | 1754 | || (path[len] != '/' && path[len] != '\0') |
1755 | ) | ||
1694 | ) { | 1756 | ) { |
1695 | continue; | 1757 | continue; |
1696 | } | 1758 | } |
@@ -1699,38 +1761,95 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) | |||
1699 | prev = dir_prefix; | 1761 | prev = dir_prefix; |
1700 | 1762 | ||
1701 | if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { | 1763 | if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { |
1702 | char *md5_passwd; | 1764 | char *colon_after_user; |
1703 | 1765 | const char *passwd; | |
1704 | md5_passwd = strchr(cur->after_colon, ':'); | 1766 | |
1705 | if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' | 1767 | colon_after_user = strchr(user_and_passwd, ':'); |
1706 | && md5_passwd[3] == '$' && md5_passwd[4] | 1768 | if (!colon_after_user) |
1707 | ) { | 1769 | goto bad_input; |
1708 | char *encrypted; | 1770 | passwd = strchr(cur->after_colon, ':'); |
1709 | int r, user_len_p1; | 1771 | if (!passwd) |
1710 | 1772 | goto bad_input; | |
1711 | md5_passwd++; | 1773 | passwd++; |
1712 | user_len_p1 = md5_passwd - cur->after_colon; | 1774 | if (passwd[0] == '*') { |
1713 | /* comparing "user:" */ | 1775 | # if ENABLE_PAM |
1714 | if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { | 1776 | struct pam_userinfo userinfo; |
1777 | struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; | ||
1778 | pam_handle_t *pamh; | ||
1779 | |||
1780 | /* compare "user:" */ | ||
1781 | if (cur->after_colon[0] != '*' | ||
1782 | && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 | ||
1783 | ) { | ||
1784 | continue; | ||
1785 | } | ||
1786 | /* this cfg entry is '*' or matches username from peer */ | ||
1787 | *colon_after_user = '\0'; | ||
1788 | userinfo.name = user_and_passwd; | ||
1789 | userinfo.pw = colon_after_user + 1; | ||
1790 | r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS | ||
1791 | || pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS | ||
1792 | || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS | ||
1793 | ; | ||
1794 | pam_end(pamh, PAM_SUCCESS); | ||
1795 | *colon_after_user = ':'; | ||
1796 | goto end_check_passwd; | ||
1797 | # else | ||
1798 | # if ENABLE_FEATURE_SHADOWPASSWDS | ||
1799 | /* Using _r function to avoid pulling in static buffers */ | ||
1800 | struct spwd spw; | ||
1801 | char buffer[256]; | ||
1802 | # endif | ||
1803 | struct passwd *pw; | ||
1804 | |||
1805 | *colon_after_user = '\0'; | ||
1806 | pw = getpwnam(user_and_passwd); | ||
1807 | *colon_after_user = ':'; | ||
1808 | if (!pw || !pw->pw_passwd) | ||
1715 | continue; | 1809 | continue; |
1810 | passwd = pw->pw_passwd; | ||
1811 | # if ENABLE_FEATURE_SHADOWPASSWDS | ||
1812 | if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) { | ||
1813 | /* getspnam_r may return 0 yet set result to NULL. | ||
1814 | * At least glibc 2.4 does this. Be extra paranoid here. */ | ||
1815 | struct spwd *result = NULL; | ||
1816 | r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result); | ||
1817 | if (r == 0 && result) | ||
1818 | passwd = result->sp_pwdp; | ||
1716 | } | 1819 | } |
1820 | # endif | ||
1821 | # endif /* ENABLE_PAM */ | ||
1822 | } | ||
1717 | 1823 | ||
1718 | encrypted = pw_encrypt( | 1824 | /* compare "user:" */ |
1719 | user_and_passwd + user_len_p1 /* cleartext pwd from user */, | 1825 | if (cur->after_colon[0] != '*' |
1720 | md5_passwd /*salt */, 1 /* cleanup */); | 1826 | && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 |
1721 | r = strcmp(encrypted, md5_passwd); | 1827 | ) { |
1722 | free(encrypted); | ||
1723 | if (r == 0) | ||
1724 | goto set_remoteuser_var; /* Ok */ | ||
1725 | continue; | 1828 | continue; |
1726 | } | 1829 | } |
1830 | /* this cfg entry is '*' or matches username from peer */ | ||
1831 | |||
1832 | /* encrypt pwd from peer and check match with local one */ | ||
1833 | { | ||
1834 | char *encrypted = pw_encrypt( | ||
1835 | /* pwd: */ colon_after_user + 1, | ||
1836 | /* salt: */ passwd, | ||
1837 | /* cleanup: */ 0 | ||
1838 | ); | ||
1839 | r = strcmp(encrypted, passwd); | ||
1840 | free(encrypted); | ||
1841 | goto end_check_passwd; | ||
1842 | } | ||
1843 | bad_input: ; | ||
1727 | } | 1844 | } |
1728 | 1845 | ||
1729 | /* Comparing plaintext "user:pass" in one go */ | 1846 | /* Comparing plaintext "user:pass" in one go */ |
1730 | if (strcmp(cur->after_colon, user_and_passwd) == 0) { | 1847 | r = strcmp(cur->after_colon, user_and_passwd); |
1731 | set_remoteuser_var: | 1848 | end_check_passwd: |
1849 | if (r == 0) { | ||
1732 | remoteuser = xstrndup(user_and_passwd, | 1850 | remoteuser = xstrndup(user_and_passwd, |
1733 | strchrnul(user_and_passwd, ':') - user_and_passwd); | 1851 | strchrnul(user_and_passwd, ':') - user_and_passwd |
1852 | ); | ||
1734 | return 1; /* Ok */ | 1853 | return 1; /* Ok */ |
1735 | } | 1854 | } |
1736 | } /* for */ | 1855 | } /* for */ |
@@ -2067,10 +2186,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
2067 | } | 2186 | } |
2068 | 2187 | ||
2069 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 2188 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
2070 | /* Case: no "Authorization:" was seen, but page does require passwd. | 2189 | /* Case: no "Authorization:" was seen, but page might require passwd. |
2071 | * Check that with dummy user:pass */ | 2190 | * Check that with dummy user:pass */ |
2072 | if (authorized < 0) | 2191 | if (authorized < 0) |
2073 | authorized = check_user_passwd(urlcopy, ":"); | 2192 | authorized = check_user_passwd(urlcopy, (char *) ""); |
2074 | if (!authorized) | 2193 | if (!authorized) |
2075 | send_headers_and_exit(HTTP_UNAUTHORIZED); | 2194 | send_headers_and_exit(HTTP_UNAUTHORIZED); |
2076 | #endif | 2195 | #endif |
@@ -2353,7 +2472,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2353 | salt[1] = '1'; | 2472 | salt[1] = '1'; |
2354 | salt[2] = '$'; | 2473 | salt[2] = '$'; |
2355 | crypt_make_salt(salt + 3, 4); | 2474 | crypt_make_salt(salt + 3, 4); |
2356 | puts(pw_encrypt(pass, salt, 1)); | 2475 | puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); |
2357 | return 0; | 2476 | return 0; |
2358 | } | 2477 | } |
2359 | #endif | 2478 | #endif |