wok-undigest annotate busybox/stuff/busybox-1.19-httpd.u @ rev 544

busybox/httpd: fix shadow password
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Nov 06 09:41:04 2011 +0100 (2011-11-06)
parents dc1bc7aa6aa8
children ab59654d633d
rev   line source
pascal@540 1 Check system passwords for *
pascal@536 2 --- busybox-1.19.0/networking/httpd.c
pascal@536 3 +++ busybox-1.19.0/networking/httpd.c
pascal@543 4 @@ -54,6 +54,8 @@
pascal@536 5 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
pascal@536 6 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/
pascal@536 7 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
pascal@536 8 + * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/
pascal@543 9 + * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/
pascal@536 10 * .au:audio/basic # additional mime type for audio.au files
pascal@536 11 * *.php:/path/php # run xxx.php through an interpreter
pascal@536 12 *
pascal@543 13 @@ -123,6 +125,14 @@
pascal@540 14 //usage: "\n -d STRING URL decode STRING"
pascal@540 15
pascal@540 16 #include "libbb.h"
pascal@540 17 +#if ENABLE_PAM
pascal@540 18 +/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
pascal@540 19 +# undef setlocale
pascal@540 20 +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
pascal@540 21 + * Apparently they like to confuse people. */
pascal@540 22 +# include <security/pam_appl.h>
pascal@540 23 +# include <security/pam_misc.h>
pascal@540 24 +#endif
pascal@540 25 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
pascal@540 26 # include <sys/sendfile.h>
pascal@540 27 #endif
pascal@543 28 @@ -1730,6 +1740,57 @@
pascal@539 29 }
pascal@539 30
pascal@539 31 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
pascal@539 32 +
pascal@543 33 +#if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
pascal@539 34 +struct pam_userinfo {
pascal@544 35 + const char *name;
pascal@544 36 + const char *pw;
pascal@539 37 +};
pascal@539 38 +
pascal@539 39 +static int pam_talker(int num_msg,
pascal@539 40 + const struct pam_message ** msg,
pascal@539 41 + struct pam_response ** resp,
pascal@539 42 + void *appdata_ptr)
pascal@539 43 +{
pascal@539 44 + int i;
pascal@539 45 + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
pascal@539 46 + struct pam_response *response;
pascal@539 47 +
pascal@539 48 + if (!resp || !msg || !userinfo)
pascal@539 49 + return PAM_CONV_ERR;
pascal@539 50 +
pascal@539 51 + /* allocate memory to store response */
pascal@539 52 + response = malloc(num_msg * sizeof(struct pam_response));
pascal@539 53 + if (!response)
pascal@539 54 + return PAM_CONV_ERR;
pascal@539 55 +
pascal@539 56 + /* copy values */
pascal@539 57 + for (i = 0; i < num_msg; i++) {
pascal@544 58 + const char *s;
pascal@539 59 +
pascal@539 60 + switch (msg[i]->msg_style) {
pascal@539 61 + case PAM_PROMPT_ECHO_ON:
pascal@539 62 + s = userinfo->name;
pascal@539 63 + break;
pascal@539 64 + case PAM_PROMPT_ECHO_OFF:
pascal@539 65 + s = userinfo->pw;
pascal@539 66 + break;
pascal@539 67 + case PAM_ERROR_MSG:
pascal@539 68 + case PAM_TEXT_INFO:
pascal@539 69 + s = "";
pascal@539 70 + break;
pascal@539 71 + default:
pascal@539 72 + free(response);
pascal@539 73 + return PAM_CONV_ERR;
pascal@539 74 + }
pascal@539 75 + response[i].resp = strdup(s);
pascal@539 76 + response[i].resp_retcode = PAM_SUCCESS;
pascal@539 77 + }
pascal@539 78 + *resp = response;
pascal@539 79 + return PAM_SUCCESS;
pascal@539 80 +}
pascal@539 81 +#endif
pascal@539 82 +
pascal@539 83 /*
pascal@539 84 * Config file entries are of the form "/<path>:<user>:<passwd>".
pascal@539 85 * If config file has no prefix match for path, access is allowed.
pascal@543 86 @@ -1747,6 +1808,7 @@
pascal@536 87 for (cur = g_auth; cur; cur = cur->next) {
pascal@543 88 const char *dir_prefix;
pascal@536 89 size_t len;
pascal@543 90 + int r;
pascal@536 91
pascal@536 92 dir_prefix = cur->before_colon;
pascal@543 93
pascal@543 94 @@ -1771,36 +1833,78 @@
pascal@536 95 prev = dir_prefix;
pascal@536 96
pascal@543 97 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
pascal@543 98 - char *md5_passwd;
pascal@543 99 + const char *unencrypted = strchr(user_and_passwd, ':') + 1;
pascal@543 100 + const char *passwd = strchr(cur->after_colon, ':');
pascal@543 101 + int user_len_p1 = unencrypted - user_and_passwd;
pascal@543 102 + char username[256];
pascal@536 103 +
pascal@543 104 + strncpy(username, user_and_passwd, user_len_p1);
pascal@543 105 + username[user_len_p1 - 1] = 0;
pascal@544 106 + if (passwd && passwd[1] == '*') {
pascal@539 107 +#if ENABLE_PAM
pascal@543 108 + struct pam_userinfo userinfo;
pascal@543 109 + struct pam_conv conv_info = {&pam_talker, (void *) &userinfo};
pascal@543 110 + pam_handle_t *pamh;
pascal@539 111 +
pascal@543 112 + userinfo.name = username;
pascal@543 113 + userinfo.pw = unencrypted;
pascal@543 114
pascal@543 115 - md5_passwd = strchr(cur->after_colon, ':');
pascal@543 116 - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
pascal@543 117 - && md5_passwd[3] == '$' && md5_passwd[4]
pascal@543 118 + if (cur->after_colon[0] != '*' &&
pascal@543 119 + strncmp(username,cur->after_colon,user_len_p1 - 1) != 0)
pascal@543 120 + continue;
pascal@543 121 + r = pam_start("httpd", username, &conv_info, &pamh) != PAM_SUCCESS
pascal@543 122 + || pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
pascal@543 123 + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS;
pascal@543 124 + pam_end(pamh, PAM_SUCCESS);
pascal@543 125 + goto end_check_passwd;
pascal@539 126 +#else
pascal@538 127 +#if ENABLE_FEATURE_SHADOWPASSWDS
pascal@538 128 + /* Using _r function to avoid pulling in static buffers */
pascal@538 129 + struct spwd spw;
pascal@538 130 + char buffer[256];
pascal@538 131 +#endif
pascal@543 132 + struct passwd *pw = getpwnam(username);
pascal@543 133 + if (!pw || !pw->pw_passwd)
pascal@543 134 + continue;
pascal@543 135 + passwd = pw->pw_passwd;
pascal@538 136 +#if ENABLE_FEATURE_SHADOWPASSWDS
pascal@543 137 + if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) {
pascal@538 138 + /* getspnam_r may return 0 yet set result to NULL.
pascal@538 139 + * At least glibc 2.4 does this. Be extra paranoid here. */
pascal@538 140 + struct spwd *result = NULL;
pascal@538 141 + r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
pascal@544 142 + if (!r && result)
pascal@543 143 + passwd = result->sp_pwdp;
pascal@538 144 + }
pascal@538 145 +#endif
pascal@543 146 + passwd--;
pascal@543 147 +#endif // ENABLE_PAM
pascal@538 148 + }
pascal@536 149 + if (passwd && passwd[1] == '$' && passwd[2] == '1'
pascal@536 150 + && passwd[3] == '$' && passwd[4]
pascal@536 151 ) {
pascal@536 152 char *encrypted;
pascal@543 153 - int r, user_len_p1;
pascal@543 154 -
pascal@536 155 - md5_passwd++;
pascal@536 156 - user_len_p1 = md5_passwd - cur->after_colon;
pascal@543 157 +
pascal@536 158 + passwd++;
pascal@536 159 /* comparing "user:" */
pascal@543 160 - if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
pascal@543 161 + if (cur->after_colon[0] != '*' &&
pascal@543 162 + strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
pascal@536 163 continue;
pascal@543 164 }
pascal@536 165
pascal@536 166 encrypted = pw_encrypt(
pascal@543 167 - user_and_passwd + user_len_p1 /* cleartext pwd from user */,
pascal@536 168 - md5_passwd /*salt */, 1 /* cleanup */);
pascal@536 169 - r = strcmp(encrypted, md5_passwd);
pascal@543 170 + unencrypted /* cleartext pwd from user */,
pascal@536 171 + passwd /*salt */, 1 /* cleanup */);
pascal@536 172 + r = strcmp(encrypted, passwd);
pascal@536 173 free(encrypted);
pascal@543 174 - if (r == 0)
pascal@536 175 - goto set_remoteuser_var; /* Ok */
pascal@543 176 - continue;
pascal@543 177 + goto end_check_passwd;
pascal@536 178 }
pascal@536 179 }
pascal@536 180
pascal@536 181 /* Comparing plaintext "user:pass" in one go */
pascal@536 182 - if (strcmp(cur->after_colon, user_and_passwd) == 0) {
pascal@536 183 - set_remoteuser_var:
pascal@543 184 + r = strcmp(cur->after_colon, user_and_passwd);
pascal@543 185 +end_check_passwd:
pascal@543 186 + if (r == 0) {
pascal@543 187 remoteuser = xstrndup(user_and_passwd,
pascal@543 188 strchrnul(user_and_passwd, ':') - user_and_passwd);
pascal@536 189 return 1; /* Ok */