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 */