wok-stable diff busybox/stuff/busybox-1.18-httpd.u @ rev 11352
busybox/httpd: add support for system passwords
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Tue Nov 29 18:11:22 2011 +0100 (2011-11-29) |
parents | |
children | c2af9b1a616f |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/busybox/stuff/busybox-1.18-httpd.u Tue Nov 29 18:11:22 2011 +0100 1.3 @@ -0,0 +1,218 @@ 1.4 +Add support for system passwords 1.5 +--- busybox-1.18.2/networking/httpd.c 1.6 ++++ busybox-1.18.2/networking/httpd.c 1.7 +@@ -53,6 +53,8 @@ 1.8 + * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ 1.9 + * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ 1.10 + * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ 1.11 ++ * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/ 1.12 ++ * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/ 1.13 + * .au:audio/basic # additional mime type for audio.au files 1.14 + * *.php:/path/php # running cgi.php scripts through an interpreter 1.15 + * 1.16 +@@ -96,6 +98,14 @@ 1.17 + */ 1.18 + 1.19 + #include "libbb.h" 1.20 ++#if ENABLE_PAM 1.21 ++/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */ 1.22 ++# undef setlocale 1.23 ++/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. 1.24 ++ * Apparently they like to confuse people. */ 1.25 ++# include <security/pam_appl.h> 1.26 ++# include <security/pam_misc.h> 1.27 ++#endif 1.28 + #if ENABLE_FEATURE_HTTPD_USE_SENDFILE 1.29 + #include <sys/sendfile.h> 1.30 + #endif 1.31 +@@ -1663,6 +1673,56 @@ 1.32 + } 1.33 + 1.34 + #if ENABLE_FEATURE_HTTPD_BASIC_AUTH 1.35 ++ 1.36 ++# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM 1.37 ++struct pam_userinfo { 1.38 ++ const char *name; 1.39 ++ const char *pw; 1.40 ++}; 1.41 ++ 1.42 ++static int pam_talker(int num_msg, 1.43 ++ const struct pam_message **msg, 1.44 ++ struct pam_response **resp, 1.45 ++ void *appdata_ptr) 1.46 ++{ 1.47 ++ int i; 1.48 ++ struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; 1.49 ++ struct pam_response *response; 1.50 ++ 1.51 ++ if (!resp || !msg || !userinfo) 1.52 ++ return PAM_CONV_ERR; 1.53 ++ 1.54 ++ /* allocate memory to store response */ 1.55 ++ response = xzalloc(num_msg * sizeof(*response)); 1.56 ++ 1.57 ++ /* copy values */ 1.58 ++ for (i = 0; i < num_msg; i++) { 1.59 ++ const char *s; 1.60 ++ 1.61 ++ switch (msg[i]->msg_style) { 1.62 ++ case PAM_PROMPT_ECHO_ON: 1.63 ++ s = userinfo->name; 1.64 ++ break; 1.65 ++ case PAM_PROMPT_ECHO_OFF: 1.66 ++ s = userinfo->pw; 1.67 ++ break; 1.68 ++ case PAM_ERROR_MSG: 1.69 ++ case PAM_TEXT_INFO: 1.70 ++ s = ""; 1.71 ++ break; 1.72 ++ default: 1.73 ++ free(response); 1.74 ++ return PAM_CONV_ERR; 1.75 ++ } 1.76 ++ response[i].resp = xstrdup(s); 1.77 ++ if (PAM_SUCCESS != 0) 1.78 ++ response[i].resp_retcode = PAM_SUCCESS; 1.79 ++ } 1.80 ++ *resp = response; 1.81 ++ return PAM_SUCCESS; 1.82 ++} 1.83 ++# endif 1.84 ++ 1.85 + /* 1.86 + * Config file entries are of the form "/<path>:<user>:<passwd>". 1.87 + * If config file has no prefix match for path, access is allowed. 1.88 +@@ -1672,7 +1732,7 @@ 1.89 + * 1.90 + * Returns 1 if user_and_passwd is OK. 1.91 + */ 1.92 +-static int check_user_passwd(const char *path, const char *user_and_passwd) 1.93 ++static int check_user_passwd(const char *path, char *user_and_passwd) 1.94 + { 1.95 + Htaccess *cur; 1.96 + const char *prev = NULL; 1.97 +@@ -1680,6 +1740,7 @@ 1.98 + for (cur = g_auth; cur; cur = cur->next) { 1.99 + const char *dir_prefix; 1.100 + size_t len; 1.101 ++ int r; 1.102 + 1.103 + dir_prefix = cur->before_colon; 1.104 + 1.105 +@@ -1704,36 +1765,96 @@ 1.106 + prev = dir_prefix; 1.107 + 1.108 + if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { 1.109 +- char *md5_passwd; 1.110 ++ char *colon_after_user; 1.111 ++ const char *passwd; 1.112 ++# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM 1.113 ++ char buffer[256]; /* will store passwd */ 1.114 ++# endif 1.115 + 1.116 +- md5_passwd = strchr(cur->after_colon, ':'); 1.117 +- if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' 1.118 +- && md5_passwd[3] == '$' && md5_passwd[4] 1.119 +- ) { 1.120 +- char *encrypted; 1.121 +- int r, user_len_p1; 1.122 ++ colon_after_user = strchr(user_and_passwd, ':'); 1.123 ++ if (!colon_after_user) 1.124 ++ goto bad_input; 1.125 ++ passwd = strchr(cur->after_colon, ':'); 1.126 ++ if (!passwd) 1.127 ++ goto bad_input; 1.128 ++ passwd++; 1.129 ++ if (passwd[0] == '*') { 1.130 ++# if ENABLE_PAM 1.131 ++ struct pam_userinfo userinfo; 1.132 ++ struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; 1.133 ++ pam_handle_t *pamh; 1.134 + 1.135 +- md5_passwd++; 1.136 +- user_len_p1 = md5_passwd - cur->after_colon; 1.137 +- /* comparing "user:" */ 1.138 +- if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { 1.139 ++ /* compare "user:" */ 1.140 ++ if (cur->after_colon[0] != '*' 1.141 ++ && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 1.142 ++ ) { 1.143 + continue; 1.144 + } 1.145 ++ /* this cfg entry is '*' or matches username from peer */ 1.146 ++ *colon_after_user = '\0'; 1.147 ++ userinfo.name = user_and_passwd; 1.148 ++ userinfo.pw = colon_after_user + 1; 1.149 ++ r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS; 1.150 ++ if (r == 0) { 1.151 ++ r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS 1.152 ++ || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS 1.153 ++ ; 1.154 ++ pam_end(pamh, PAM_SUCCESS); 1.155 ++ } 1.156 ++ *colon_after_user = ':'; 1.157 ++ goto end_check_passwd; 1.158 ++# else 1.159 ++# if ENABLE_FEATURE_SHADOWPASSWDS 1.160 ++ /* Using _r function to avoid pulling in static buffers */ 1.161 ++ struct spwd spw; 1.162 ++# endif 1.163 ++ struct passwd *pw; 1.164 + 1.165 +- encrypted = pw_encrypt( 1.166 +- user_and_passwd + user_len_p1 /* cleartext pwd from user */, 1.167 +- md5_passwd /*salt */, 1 /* cleanup */); 1.168 +- r = strcmp(encrypted, md5_passwd); 1.169 +- free(encrypted); 1.170 +- if (r == 0) 1.171 +- goto set_remoteuser_var; /* Ok */ 1.172 ++ *colon_after_user = '\0'; 1.173 ++ pw = getpwnam(user_and_passwd); 1.174 ++ *colon_after_user = ':'; 1.175 ++ if (!pw || !pw->pw_passwd) 1.176 ++ continue; 1.177 ++ passwd = pw->pw_passwd; 1.178 ++# if ENABLE_FEATURE_SHADOWPASSWDS 1.179 ++ if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) { 1.180 ++ /* getspnam_r may return 0 yet set result to NULL. 1.181 ++ * At least glibc 2.4 does this. Be extra paranoid here. */ 1.182 ++ struct spwd *result = NULL; 1.183 ++ r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result); 1.184 ++ if (r == 0 && result) 1.185 ++ passwd = result->sp_pwdp; /* note: passwd is located into buffer ! */ 1.186 ++ } 1.187 ++# endif 1.188 ++# endif /* ENABLE_PAM */ 1.189 ++ } 1.190 ++ 1.191 ++ /* compare "user:" */ 1.192 ++ if (cur->after_colon[0] != '*' 1.193 ++ && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0 1.194 ++ ) { 1.195 + continue; 1.196 + } 1.197 ++ /* this cfg entry is '*' or matches username from peer */ 1.198 ++ 1.199 ++ /* encrypt pwd from peer and check match with local one */ 1.200 ++ { 1.201 ++ char *encrypted = pw_encrypt( 1.202 ++ /* pwd: */ colon_after_user + 1, 1.203 ++ /* salt: */ passwd, 1.204 ++ /* cleanup: */ 0 1.205 ++ ); 1.206 ++ r = strcmp(encrypted, passwd); 1.207 ++ free(encrypted); 1.208 ++ goto end_check_passwd; 1.209 ++ } 1.210 ++ bad_input: ; 1.211 + } 1.212 + 1.213 + /* Comparing plaintext "user:pass" in one go */ 1.214 +- if (strcmp(cur->after_colon, user_and_passwd) == 0) { 1.215 +- set_remoteuser_var: 1.216 ++ end_check_passwd: 1.217 ++ r = strcmp(cur->after_colon, user_and_passwd); 1.218 ++ if (r == 0) { 1.219 + remoteuser = xstrndup(user_and_passwd, 1.220 + strchrnul(user_and_passwd, ':') - user_and_passwd); 1.221 + return 1; /* Ok */