aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPascal Bellard <pascal.bellard@ads-lu.com>2011-11-29 13:51:11 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2011-11-29 13:51:11 +0100
commit7291755439ad2f400df51a74b4e9a31a48f484b1 (patch)
tree98ab3d41aaecca3419d319e0f953818a1981e7f3
parent901365fcffbc318395d24a05b6951288562da6af (diff)
downloadbusybox-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.c175
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
1673struct pam_userinfo {
1674 const char *name;
1675 const char *pw;
1676};
1677
1678static 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 */
1670static int check_user_passwd(const char *path, const char *user_and_passwd) 1730static 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