wok-undigest rev 587

busybox/httpd: add support for system passwords (again)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Thu Dec 01 22:35:18 2011 +0100 (2011-12-01)
parents 74db54588f46
children 21d5de8c62e6
files busybox/stuff/busybox-1.19-httpd.u
line diff
     1.1 --- a/busybox/stuff/busybox-1.19-httpd.u	Thu Dec 01 12:33:10 2011 +0100
     1.2 +++ b/busybox/stuff/busybox-1.19-httpd.u	Thu Dec 01 22:35:18 2011 +0100
     1.3 @@ -25,12 +25,12 @@
     1.4   #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
     1.5   # include <sys/sendfile.h>
     1.6   #endif
     1.7 -@@ -1730,6 +1740,57 @@
     1.8 +@@ -1730,6 +1740,56 @@
     1.9   }
    1.10   
    1.11   #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    1.12  +
    1.13 -+#if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
    1.14 ++# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
    1.15  +struct pam_userinfo {
    1.16  +	const char *name;
    1.17  +	const char *pw;
    1.18 @@ -49,9 +49,7 @@
    1.19  +		return PAM_CONV_ERR;
    1.20  +
    1.21  +	/* allocate memory to store response */
    1.22 -+	response = malloc(num_msg * sizeof(struct pam_response));
    1.23 -+	if (!response)
    1.24 -+		return PAM_CONV_ERR;
    1.25 ++	response = xzalloc(num_msg * sizeof(*response));
    1.26  +
    1.27  +	/* copy values */
    1.28  +	for (i = 0; i < num_msg; i++) {
    1.29 @@ -72,18 +70,28 @@
    1.30  +			free(response);
    1.31  +			return PAM_CONV_ERR;
    1.32  +		}
    1.33 -+		response[i].resp = strdup(s);
    1.34 -+		response[i].resp_retcode = PAM_SUCCESS;
    1.35 ++		response[i].resp = xstrdup(s);
    1.36 ++		if (PAM_SUCCESS != 0)
    1.37 ++			response[i].resp_retcode = PAM_SUCCESS;
    1.38  +	}
    1.39  +	*resp = response;
    1.40  +	return PAM_SUCCESS;
    1.41  +}
    1.42 -+#endif
    1.43 ++# endif
    1.44  +
    1.45   /*
    1.46    * Config file entries are of the form "/<path>:<user>:<passwd>".
    1.47    * If config file has no prefix match for path, access is allowed.
    1.48 -@@ -1747,6 +1808,7 @@
    1.49 +@@ -1739,7 +1799,7 @@
    1.50 +  *
    1.51 +  * Returns 1 if user_and_passwd is OK.
    1.52 +  */
    1.53 +-static int check_user_passwd(const char *path, const char *user_and_passwd)
    1.54 ++static int check_user_passwd(const char *path, char *user_and_passwd)
    1.55 + {
    1.56 + 	Htaccess *cur;
    1.57 + 	const char *prev = NULL;
    1.58 +@@ -1747,6 +1807,7 @@
    1.59   	for (cur = g_auth; cur; cur = cur->next) {
    1.60   		const char *dir_prefix;
    1.61   		size_t len;
    1.62 @@ -91,101 +99,129 @@
    1.63   
    1.64   		dir_prefix = cur->before_colon;
    1.65   
    1.66 -@@ -1771,36 +1833,80 @@
    1.67 +@@ -1771,36 +1832,96 @@
    1.68   		prev = dir_prefix;
    1.69   
    1.70   		if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
    1.71  -			char *md5_passwd;
    1.72 -+#if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM
    1.73 -+			/* Using _r function to avoid pulling in static buffers */
    1.74 -+			struct spwd spw;
    1.75 -+			char buffer[256];
    1.76 -+#endif
    1.77 -+			const char *unencrypted = strchr(user_and_passwd, ':') + 1;
    1.78 -+			const char *passwd = strchr(cur->after_colon, ':');
    1.79 -+			int user_len_p1 = unencrypted - user_and_passwd;
    1.80 -+			char username[256];
    1.81 -+
    1.82 -+			strncpy(username, user_and_passwd, user_len_p1);
    1.83 -+			username[user_len_p1 - 1] = 0;
    1.84 -+			if (passwd && passwd[1] == '*') {
    1.85 -+#if ENABLE_PAM
    1.86 -+				struct pam_userinfo userinfo;
    1.87 -+				struct pam_conv conv_info = {&pam_talker, (void *) &userinfo};
    1.88 -+				pam_handle_t *pamh;
    1.89 -+
    1.90 -+				userinfo.name = username;
    1.91 -+				userinfo.pw = unencrypted;
    1.92 ++			char *colon_after_user;
    1.93 ++			const char *passwd;
    1.94 ++# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM
    1.95 ++			char sp_buf[256];
    1.96 ++# endif
    1.97   
    1.98  -			md5_passwd = strchr(cur->after_colon, ':');
    1.99  -			if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
   1.100  -			 && md5_passwd[3] == '$' && md5_passwd[4]
   1.101 -+				if (cur->after_colon[0] != '*' && 
   1.102 -+				    strncmp(username,cur->after_colon,user_len_p1 - 1) != 0)
   1.103 -+					continue;
   1.104 -+				r = pam_start("httpd", username, &conv_info, &pamh) != PAM_SUCCESS;
   1.105 +-			) {
   1.106 +-				char *encrypted;
   1.107 +-				int r, user_len_p1;
   1.108 ++			colon_after_user = strchr(user_and_passwd, ':');
   1.109 ++			if (!colon_after_user)
   1.110 ++				goto bad_input;
   1.111 ++			passwd = strchr(cur->after_colon, ':');
   1.112 ++			if (!passwd)
   1.113 ++				goto bad_input;
   1.114 ++			passwd++;
   1.115 ++			if (passwd[0] == '*') {
   1.116 ++# if ENABLE_PAM
   1.117 ++				struct pam_userinfo userinfo;
   1.118 ++				struct pam_conv conv_info = { &pam_talker, (void *) &userinfo };
   1.119 ++				pam_handle_t *pamh;
   1.120 + 
   1.121 +-				md5_passwd++;
   1.122 +-				user_len_p1 = md5_passwd - cur->after_colon;
   1.123 +-				/* comparing "user:" */
   1.124 +-				if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
   1.125 ++				/* compare "user:" */
   1.126 ++				if (cur->after_colon[0] != '*'
   1.127 ++				 && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
   1.128 ++				) {
   1.129 + 					continue;
   1.130 + 				}
   1.131 ++				/* this cfg entry is '*' or matches username from peer */
   1.132 ++				*colon_after_user = '\0';
   1.133 ++				userinfo.name = user_and_passwd;
   1.134 ++				userinfo.pw = colon_after_user + 1;
   1.135 ++				r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS;
   1.136  +				if (r == 0) {
   1.137  +					r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
   1.138 -+					 || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)    != PAM_SUCCESS;
   1.139 ++					 || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)    != PAM_SUCCESS
   1.140 ++					;
   1.141  +					pam_end(pamh, PAM_SUCCESS);
   1.142  +				}
   1.143 ++				*colon_after_user = ':';
   1.144  +				goto end_check_passwd;
   1.145 -+#else
   1.146 -+				struct passwd *pw = getpwnam(username);
   1.147 ++# else
   1.148 ++#  if ENABLE_FEATURE_SHADOWPASSWDS
   1.149 ++				/* Using _r function to avoid pulling in static buffers */
   1.150 ++				struct spwd spw;
   1.151 ++#  endif
   1.152 ++				struct passwd *pw;
   1.153 + 
   1.154 +-				encrypted = pw_encrypt(
   1.155 +-					user_and_passwd + user_len_p1 /* cleartext pwd from user */,
   1.156 +-					md5_passwd /*salt */, 1 /* cleanup */);
   1.157 +-				r = strcmp(encrypted, md5_passwd);
   1.158 +-				free(encrypted);
   1.159 +-				if (r == 0)
   1.160 +-					goto set_remoteuser_var; /* Ok */
   1.161 ++				*colon_after_user = '\0';
   1.162 ++				pw = getpwnam(user_and_passwd);
   1.163 ++				*colon_after_user = ':';
   1.164  +				if (!pw || !pw->pw_passwd)
   1.165  +					continue;
   1.166  +				passwd = pw->pw_passwd;
   1.167 -+#if ENABLE_FEATURE_SHADOWPASSWDS
   1.168 ++#  if ENABLE_FEATURE_SHADOWPASSWDS
   1.169  +				if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) {
   1.170  +					/* getspnam_r may return 0 yet set result to NULL.
   1.171  +					 * At least glibc 2.4 does this. Be extra paranoid here. */
   1.172  +					struct spwd *result = NULL;
   1.173 -+					r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
   1.174 -+					if (!r && result)
   1.175 ++					r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result);
   1.176 ++					if (r == 0 && result)
   1.177  +						passwd = result->sp_pwdp;
   1.178  +				}
   1.179 -+#endif
   1.180 -+				passwd--;
   1.181 -+#endif // ENABLE_PAM
   1.182 ++#  endif
   1.183 ++# endif /* ENABLE_PAM */
   1.184  +			}
   1.185 -+			if (passwd && passwd[1] == '$' && passwd[2] == '1'
   1.186 -+			 && passwd[3] == '$' && passwd[4]
   1.187 - 			) {
   1.188 - 				char *encrypted;
   1.189 --				int r, user_len_p1;
   1.190 --
   1.191 --				md5_passwd++;
   1.192 --				user_len_p1 = md5_passwd - cur->after_colon;
   1.193 -+				
   1.194 -+				passwd++;
   1.195 - 				/* comparing "user:" */
   1.196 --				if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
   1.197 -+				if (cur->after_colon[0] != '*' && 
   1.198 -+				    strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
   1.199 - 					continue;
   1.200 - 				}
   1.201 - 
   1.202 - 				encrypted = pw_encrypt(
   1.203 --					user_and_passwd + user_len_p1 /* cleartext pwd from user */,
   1.204 --					md5_passwd /*salt */, 1 /* cleanup */);
   1.205 --				r = strcmp(encrypted, md5_passwd);
   1.206 -+					unencrypted /* cleartext pwd from user */,
   1.207 -+					passwd /*salt */, 1 /* cleanup */);
   1.208 ++
   1.209 ++			/* compare "user:" */
   1.210 ++			if (cur->after_colon[0] != '*'
   1.211 ++			 && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
   1.212 ++			) {
   1.213 + 				continue;
   1.214 + 			}
   1.215 ++			/* this cfg entry is '*' or matches username from peer */
   1.216 ++
   1.217 ++			/* encrypt pwd from peer and check match with local one */
   1.218 ++			{
   1.219 ++				char *encrypted = pw_encrypt(
   1.220 ++					/* pwd: */  colon_after_user + 1,
   1.221 ++					/* salt: */ passwd,
   1.222 ++					/* cleanup: */ 0
   1.223 ++				);
   1.224  +				r = strcmp(encrypted, passwd);
   1.225 - 				free(encrypted);
   1.226 --				if (r == 0)
   1.227 --					goto set_remoteuser_var; /* Ok */
   1.228 --				continue;
   1.229 ++				free(encrypted);
   1.230  +				goto end_check_passwd;
   1.231 - 			}
   1.232 ++			}
   1.233 ++ bad_input: ;
   1.234   		}
   1.235   
   1.236   		/* Comparing plaintext "user:pass" in one go */
   1.237  -		if (strcmp(cur->after_colon, user_and_passwd) == 0) {
   1.238  - set_remoteuser_var:
   1.239  +		r = strcmp(cur->after_colon, user_and_passwd);
   1.240 -+end_check_passwd:
   1.241 ++ end_check_passwd:
   1.242  +		if (r == 0) {
   1.243   			remoteuser = xstrndup(user_and_passwd,
   1.244   					strchrnul(user_and_passwd, ':') - user_and_passwd);
   1.245   			return 1; /* Ok */
   1.246 +@@ -2142,7 +2263,7 @@
   1.247 + 	/* Case: no "Authorization:" was seen, but page does require passwd.
   1.248 + 	 * Check that with dummy user:pass */
   1.249 + 	if (authorized < 0)
   1.250 +-		authorized = check_user_passwd(urlcopy, ":");
   1.251 ++		authorized = check_user_passwd(urlcopy, (char *) "");
   1.252 + 	if (!authorized)
   1.253 + 		send_headers_and_exit(HTTP_UNAUTHORIZED);
   1.254 + #endif