wok 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 05ee700100bf
children c2af9b1a616f
files busybox/receipt busybox/stuff/busybox-1.18-httpd.u
line diff
     1.1 --- a/busybox/receipt	Tue Nov 29 11:53:47 2011 +0000
     1.2 +++ b/busybox/receipt	Tue Nov 29 18:11:22 2011 +0100
     1.3 @@ -28,6 +28,7 @@
     1.4  printable.u
     1.5  cmdline.u
     1.6  conspy.u
     1.7 +httpd.u
     1.8  EOT
     1.9      cp $stuff/$PACKAGE-${VERSION%.*}.config .config
    1.10  }
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/busybox/stuff/busybox-1.18-httpd.u	Tue Nov 29 18:11:22 2011 +0100
     2.3 @@ -0,0 +1,218 @@
     2.4 +Add support for system passwords
     2.5 +--- busybox-1.18.2/networking/httpd.c
     2.6 ++++ busybox-1.18.2/networking/httpd.c
     2.7 +@@ -53,6 +53,8 @@
     2.8 +  * /cgi-bin:foo:bar  # Require user foo, pwd bar on urls starting with /cgi-bin/
     2.9 +  * /adm:admin:setup  # Require user admin, pwd setup on urls starting with /adm/
    2.10 +  * /adm:toor:PaSsWd  # or user toor, pwd PaSsWd on urls starting with /adm/
    2.11 ++ * /adm:root:*       # or user root, pwd from /etc/passwd on urls starting with /adm/
    2.12 ++ * /wiki:*:*         # or any user from /etc/passwd with according pwd on urls starting with /wiki/
    2.13 +  * .au:audio/basic   # additional mime type for audio.au files
    2.14 +  * *.php:/path/php   # running cgi.php scripts through an interpreter
    2.15 +  *
    2.16 +@@ -96,6 +98,14 @@
    2.17 +  */
    2.18 + 
    2.19 + #include "libbb.h"
    2.20 ++#if ENABLE_PAM
    2.21 ++/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
    2.22 ++# undef setlocale
    2.23 ++/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
    2.24 ++ * Apparently they like to confuse people. */
    2.25 ++# include <security/pam_appl.h>
    2.26 ++# include <security/pam_misc.h>
    2.27 ++#endif
    2.28 + #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
    2.29 + #include <sys/sendfile.h>
    2.30 + #endif
    2.31 +@@ -1663,6 +1673,56 @@
    2.32 + }
    2.33 + 
    2.34 + #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
    2.35 ++
    2.36 ++# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
    2.37 ++struct pam_userinfo {
    2.38 ++	const char *name;
    2.39 ++	const char *pw;
    2.40 ++};
    2.41 ++
    2.42 ++static int pam_talker(int num_msg,
    2.43 ++		const struct pam_message **msg,
    2.44 ++		struct pam_response **resp,
    2.45 ++		void *appdata_ptr)
    2.46 ++{
    2.47 ++	int i;
    2.48 ++	struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
    2.49 ++	struct pam_response *response;
    2.50 ++
    2.51 ++	if (!resp || !msg || !userinfo)
    2.52 ++		return PAM_CONV_ERR;
    2.53 ++
    2.54 ++	/* allocate memory to store response */
    2.55 ++	response = xzalloc(num_msg * sizeof(*response));
    2.56 ++
    2.57 ++	/* copy values */
    2.58 ++	for (i = 0; i < num_msg; i++) {
    2.59 ++		const char *s;
    2.60 ++
    2.61 ++		switch (msg[i]->msg_style) {
    2.62 ++		case PAM_PROMPT_ECHO_ON:
    2.63 ++			s = userinfo->name;
    2.64 ++			break;
    2.65 ++		case PAM_PROMPT_ECHO_OFF:
    2.66 ++			s = userinfo->pw;
    2.67 ++			break;
    2.68 ++	        case PAM_ERROR_MSG:
    2.69 ++        	case PAM_TEXT_INFO:
    2.70 ++        		s = "";
    2.71 ++			break;
    2.72 ++		default:
    2.73 ++			free(response);
    2.74 ++			return PAM_CONV_ERR;
    2.75 ++		}
    2.76 ++		response[i].resp = xstrdup(s);
    2.77 ++		if (PAM_SUCCESS != 0)
    2.78 ++			response[i].resp_retcode = PAM_SUCCESS;
    2.79 ++	}
    2.80 ++	*resp = response;
    2.81 ++	return PAM_SUCCESS;
    2.82 ++}
    2.83 ++# endif
    2.84 ++
    2.85 + /*
    2.86 +  * Config file entries are of the form "/<path>:<user>:<passwd>".
    2.87 +  * If config file has no prefix match for path, access is allowed.
    2.88 +@@ -1672,7 +1732,7 @@
    2.89 +  *
    2.90 +  * Returns 1 if user_and_passwd is OK.
    2.91 +  */
    2.92 +-static int check_user_passwd(const char *path, const char *user_and_passwd)
    2.93 ++static int check_user_passwd(const char *path, char *user_and_passwd)
    2.94 + {
    2.95 + 	Htaccess *cur;
    2.96 + 	const char *prev = NULL;
    2.97 +@@ -1680,6 +1740,7 @@
    2.98 + 	for (cur = g_auth; cur; cur = cur->next) {
    2.99 + 		const char *dir_prefix;
   2.100 + 		size_t len;
   2.101 ++		int r;
   2.102 + 
   2.103 + 		dir_prefix = cur->before_colon;
   2.104 + 
   2.105 +@@ -1704,36 +1765,96 @@
   2.106 + 		prev = dir_prefix;
   2.107 + 
   2.108 + 		if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
   2.109 +-			char *md5_passwd;
   2.110 ++			char *colon_after_user;
   2.111 ++			const char *passwd;
   2.112 ++# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM
   2.113 ++			char buffer[256];	/* will store passwd */
   2.114 ++# endif
   2.115 + 
   2.116 +-			md5_passwd = strchr(cur->after_colon, ':');
   2.117 +-			if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
   2.118 +-			 && md5_passwd[3] == '$' && md5_passwd[4]
   2.119 +-			) {
   2.120 +-				char *encrypted;
   2.121 +-				int r, user_len_p1;
   2.122 ++			colon_after_user = strchr(user_and_passwd, ':');
   2.123 ++			if (!colon_after_user)
   2.124 ++				goto bad_input;
   2.125 ++			passwd = strchr(cur->after_colon, ':');
   2.126 ++			if (!passwd)
   2.127 ++				goto bad_input;
   2.128 ++			passwd++;
   2.129 ++			if (passwd[0] == '*') {
   2.130 ++# if ENABLE_PAM
   2.131 ++				struct pam_userinfo userinfo;
   2.132 ++				struct pam_conv conv_info = { &pam_talker, (void *) &userinfo };
   2.133 ++				pam_handle_t *pamh;
   2.134 + 
   2.135 +-				md5_passwd++;
   2.136 +-				user_len_p1 = md5_passwd - cur->after_colon;
   2.137 +-				/* comparing "user:" */
   2.138 +-				if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
   2.139 ++				/* compare "user:" */
   2.140 ++				if (cur->after_colon[0] != '*'
   2.141 ++				 && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
   2.142 ++				) {
   2.143 + 					continue;
   2.144 + 				}
   2.145 ++				/* this cfg entry is '*' or matches username from peer */
   2.146 ++				*colon_after_user = '\0';
   2.147 ++				userinfo.name = user_and_passwd;
   2.148 ++				userinfo.pw = colon_after_user + 1;
   2.149 ++				r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS;
   2.150 ++				if (r == 0) {
   2.151 ++					r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
   2.152 ++					 || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)    != PAM_SUCCESS
   2.153 ++					;
   2.154 ++					pam_end(pamh, PAM_SUCCESS);
   2.155 ++				}
   2.156 ++				*colon_after_user = ':';
   2.157 ++				goto end_check_passwd;
   2.158 ++# else
   2.159 ++#  if ENABLE_FEATURE_SHADOWPASSWDS
   2.160 ++				/* Using _r function to avoid pulling in static buffers */
   2.161 ++				struct spwd spw;
   2.162 ++#  endif
   2.163 ++				struct passwd *pw;
   2.164 + 
   2.165 +-				encrypted = pw_encrypt(
   2.166 +-					user_and_passwd + user_len_p1 /* cleartext pwd from user */,
   2.167 +-					md5_passwd /*salt */, 1 /* cleanup */);
   2.168 +-				r = strcmp(encrypted, md5_passwd);
   2.169 +-				free(encrypted);
   2.170 +-				if (r == 0)
   2.171 +-					goto set_remoteuser_var; /* Ok */
   2.172 ++				*colon_after_user = '\0';
   2.173 ++				pw = getpwnam(user_and_passwd);
   2.174 ++				*colon_after_user = ':';
   2.175 ++				if (!pw || !pw->pw_passwd)
   2.176 ++					continue;
   2.177 ++				passwd = pw->pw_passwd;
   2.178 ++#  if ENABLE_FEATURE_SHADOWPASSWDS
   2.179 ++				if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) {
   2.180 ++					/* getspnam_r may return 0 yet set result to NULL.
   2.181 ++					 * At least glibc 2.4 does this. Be extra paranoid here. */
   2.182 ++					struct spwd *result = NULL;
   2.183 ++					r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
   2.184 ++					if (r == 0 && result)
   2.185 ++						passwd = result->sp_pwdp; /* note: passwd is located into buffer ! */
   2.186 ++				}
   2.187 ++#  endif
   2.188 ++# endif /* ENABLE_PAM */
   2.189 ++			}
   2.190 ++
   2.191 ++			/* compare "user:" */
   2.192 ++			if (cur->after_colon[0] != '*'
   2.193 ++			 && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
   2.194 ++			) {
   2.195 + 				continue;
   2.196 + 			}
   2.197 ++			/* this cfg entry is '*' or matches username from peer */
   2.198 ++
   2.199 ++			/* encrypt pwd from peer and check match with local one */
   2.200 ++			{
   2.201 ++				char *encrypted = pw_encrypt(
   2.202 ++					/* pwd: */  colon_after_user + 1,
   2.203 ++					/* salt: */ passwd,
   2.204 ++					/* cleanup: */ 0
   2.205 ++				);
   2.206 ++				r = strcmp(encrypted, passwd);
   2.207 ++				free(encrypted);
   2.208 ++				goto end_check_passwd;
   2.209 ++			}
   2.210 ++ bad_input: ;
   2.211 + 		}
   2.212 + 
   2.213 + 		/* Comparing plaintext "user:pass" in one go */
   2.214 +-		if (strcmp(cur->after_colon, user_and_passwd) == 0) {
   2.215 +- set_remoteuser_var:
   2.216 ++ end_check_passwd:
   2.217 ++		r = strcmp(cur->after_colon, user_and_passwd);
   2.218 ++		if (r == 0) {
   2.219 + 			remoteuser = xstrndup(user_and_passwd,
   2.220 + 					strchrnul(user_and_passwd, ':') - user_and_passwd);
   2.221 + 			return 1; /* Ok */