wok annotate busybox/stuff/busybox-1.18-httpd.u @ rev 12024

pcmanfm2: new icon (Thanks moulefrite)
author Christophe Lincoln <pankso@slitaz.org>
date Tue Mar 06 20:38:45 2012 +0100 (2012-03-06)
parents 8acb23611799
children
rev   line source
pascal@11352 1 Add support for system passwords
pascal@11352 2 --- busybox-1.18.2/networking/httpd.c
pascal@11352 3 +++ busybox-1.18.2/networking/httpd.c
pascal@11353 4 @@ -50,6 +50,8 @@
pascal@11352 5 * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/
pascal@11352 6 * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/
pascal@11352 7 * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/
pascal@11352 8 + * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/
pascal@11352 9 + * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/
pascal@11352 10 * .au:audio/basic # additional mime type for audio.au files
pascal@11353 11 * *.php:/path/php # run xxx.php through an interpreter
pascal@11352 12 *
pascal@11353 13 @@ -94,6 +96,14 @@
pascal@11353 14 /* TODO: use TCP_CORK, parse_config() */
pascal@11352 15
pascal@11352 16 #include "libbb.h"
pascal@11352 17 +#if ENABLE_PAM
pascal@11352 18 +/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
pascal@11352 19 +# undef setlocale
pascal@11352 20 +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
pascal@11352 21 + * Apparently they like to confuse people. */
pascal@11352 22 +# include <security/pam_appl.h>
pascal@11352 23 +# include <security/pam_misc.h>
pascal@11352 24 +#endif
pascal@11352 25 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
pascal@11353 26 # include <sys/sendfile.h>
pascal@11352 27 #endif
pascal@11353 28 @@ -1700,6 +1710,56 @@
pascal@11352 29 }
pascal@11352 30
pascal@11352 31 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
pascal@11352 32 +
pascal@11352 33 +# if ENABLE_FEATURE_HTTPD_AUTH_MD5 && ENABLE_PAM
pascal@11352 34 +struct pam_userinfo {
pascal@11352 35 + const char *name;
pascal@11352 36 + const char *pw;
pascal@11352 37 +};
pascal@11352 38 +
pascal@11352 39 +static int pam_talker(int num_msg,
pascal@11352 40 + const struct pam_message **msg,
pascal@11352 41 + struct pam_response **resp,
pascal@11352 42 + void *appdata_ptr)
pascal@11352 43 +{
pascal@11352 44 + int i;
pascal@11352 45 + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
pascal@11352 46 + struct pam_response *response;
pascal@11352 47 +
pascal@11352 48 + if (!resp || !msg || !userinfo)
pascal@11352 49 + return PAM_CONV_ERR;
pascal@11352 50 +
pascal@11352 51 + /* allocate memory to store response */
pascal@11352 52 + response = xzalloc(num_msg * sizeof(*response));
pascal@11352 53 +
pascal@11352 54 + /* copy values */
pascal@11352 55 + for (i = 0; i < num_msg; i++) {
pascal@11352 56 + const char *s;
pascal@11352 57 +
pascal@11352 58 + switch (msg[i]->msg_style) {
pascal@11352 59 + case PAM_PROMPT_ECHO_ON:
pascal@11352 60 + s = userinfo->name;
pascal@11352 61 + break;
pascal@11352 62 + case PAM_PROMPT_ECHO_OFF:
pascal@11352 63 + s = userinfo->pw;
pascal@11352 64 + break;
pascal@11352 65 + case PAM_ERROR_MSG:
pascal@11352 66 + case PAM_TEXT_INFO:
pascal@11352 67 + s = "";
pascal@11352 68 + break;
pascal@11352 69 + default:
pascal@11352 70 + free(response);
pascal@11352 71 + return PAM_CONV_ERR;
pascal@11352 72 + }
pascal@11352 73 + response[i].resp = xstrdup(s);
pascal@11352 74 + if (PAM_SUCCESS != 0)
pascal@11352 75 + response[i].resp_retcode = PAM_SUCCESS;
pascal@11352 76 + }
pascal@11352 77 + *resp = response;
pascal@11352 78 + return PAM_SUCCESS;
pascal@11352 79 +}
pascal@11352 80 +# endif
pascal@11352 81 +
pascal@11352 82 /*
pascal@11352 83 * Config file entries are of the form "/<path>:<user>:<passwd>".
pascal@11352 84 * If config file has no prefix match for path, access is allowed.
pascal@11353 85 @@ -1709,7 +1769,7 @@
pascal@11352 86 *
pascal@11352 87 * Returns 1 if user_and_passwd is OK.
pascal@11352 88 */
pascal@11352 89 -static int check_user_passwd(const char *path, const char *user_and_passwd)
pascal@11352 90 +static int check_user_passwd(const char *path, char *user_and_passwd)
pascal@11352 91 {
pascal@11352 92 Htaccess *cur;
pascal@11352 93 const char *prev = NULL;
pascal@11353 94 @@ -1717,6 +1777,7 @@
pascal@11352 95 for (cur = g_auth; cur; cur = cur->next) {
pascal@11352 96 const char *dir_prefix;
pascal@11352 97 size_t len;
pascal@11352 98 + int r;
pascal@11352 99
pascal@11352 100 dir_prefix = cur->before_colon;
pascal@11352 101
pascal@11353 102 @@ -1741,36 +1802,96 @@
pascal@11352 103 prev = dir_prefix;
pascal@11352 104
pascal@11352 105 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
pascal@11352 106 - char *md5_passwd;
pascal@11352 107 + char *colon_after_user;
pascal@11352 108 + const char *passwd;
pascal@11352 109 +# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM
pascal@11356 110 + char sp_buf[256];
pascal@11352 111 +# endif
pascal@11352 112
pascal@11352 113 - md5_passwd = strchr(cur->after_colon, ':');
pascal@11352 114 - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
pascal@11352 115 - && md5_passwd[3] == '$' && md5_passwd[4]
pascal@11352 116 - ) {
pascal@11352 117 - char *encrypted;
pascal@11352 118 - int r, user_len_p1;
pascal@11352 119 + colon_after_user = strchr(user_and_passwd, ':');
pascal@11352 120 + if (!colon_after_user)
pascal@11352 121 + goto bad_input;
pascal@11352 122 + passwd = strchr(cur->after_colon, ':');
pascal@11352 123 + if (!passwd)
pascal@11352 124 + goto bad_input;
pascal@11352 125 + passwd++;
pascal@11352 126 + if (passwd[0] == '*') {
pascal@11352 127 +# if ENABLE_PAM
pascal@11352 128 + struct pam_userinfo userinfo;
pascal@11352 129 + struct pam_conv conv_info = { &pam_talker, (void *) &userinfo };
pascal@11352 130 + pam_handle_t *pamh;
pascal@11352 131
pascal@11352 132 - md5_passwd++;
pascal@11352 133 - user_len_p1 = md5_passwd - cur->after_colon;
pascal@11352 134 - /* comparing "user:" */
pascal@11352 135 - if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
pascal@11352 136 + /* compare "user:" */
pascal@11352 137 + if (cur->after_colon[0] != '*'
pascal@11352 138 + && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
pascal@11352 139 + ) {
pascal@11352 140 continue;
pascal@11352 141 }
pascal@11352 142 + /* this cfg entry is '*' or matches username from peer */
pascal@11352 143 + *colon_after_user = '\0';
pascal@11352 144 + userinfo.name = user_and_passwd;
pascal@11352 145 + userinfo.pw = colon_after_user + 1;
pascal@11352 146 + r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS;
pascal@11352 147 + if (r == 0) {
pascal@11352 148 + r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
pascal@11352 149 + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS
pascal@11352 150 + ;
pascal@11352 151 + pam_end(pamh, PAM_SUCCESS);
pascal@11352 152 + }
pascal@11352 153 + *colon_after_user = ':';
pascal@11352 154 + goto end_check_passwd;
pascal@11352 155 +# else
pascal@11352 156 +# if ENABLE_FEATURE_SHADOWPASSWDS
pascal@11352 157 + /* Using _r function to avoid pulling in static buffers */
pascal@11352 158 + struct spwd spw;
pascal@11352 159 +# endif
pascal@11352 160 + struct passwd *pw;
pascal@11352 161
pascal@11352 162 - encrypted = pw_encrypt(
pascal@11352 163 - user_and_passwd + user_len_p1 /* cleartext pwd from user */,
pascal@11352 164 - md5_passwd /*salt */, 1 /* cleanup */);
pascal@11352 165 - r = strcmp(encrypted, md5_passwd);
pascal@11352 166 - free(encrypted);
pascal@11352 167 - if (r == 0)
pascal@11352 168 - goto set_remoteuser_var; /* Ok */
pascal@11352 169 + *colon_after_user = '\0';
pascal@11352 170 + pw = getpwnam(user_and_passwd);
pascal@11352 171 + *colon_after_user = ':';
pascal@11352 172 + if (!pw || !pw->pw_passwd)
pascal@11352 173 + continue;
pascal@11352 174 + passwd = pw->pw_passwd;
pascal@11352 175 +# if ENABLE_FEATURE_SHADOWPASSWDS
pascal@11352 176 + if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) {
pascal@11352 177 + /* getspnam_r may return 0 yet set result to NULL.
pascal@11352 178 + * At least glibc 2.4 does this. Be extra paranoid here. */
pascal@11352 179 + struct spwd *result = NULL;
pascal@11356 180 + r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result);
pascal@11352 181 + if (r == 0 && result)
pascal@11356 182 + passwd = result->sp_pwdp;
pascal@11352 183 + }
pascal@11352 184 +# endif
pascal@11352 185 +# endif /* ENABLE_PAM */
pascal@11352 186 + }
pascal@11352 187 +
pascal@11352 188 + /* compare "user:" */
pascal@11352 189 + if (cur->after_colon[0] != '*'
pascal@11352 190 + && strncmp(cur->after_colon, user_and_passwd, colon_after_user - user_and_passwd + 1) != 0
pascal@11352 191 + ) {
pascal@11352 192 continue;
pascal@11352 193 }
pascal@11352 194 + /* this cfg entry is '*' or matches username from peer */
pascal@11352 195 +
pascal@11352 196 + /* encrypt pwd from peer and check match with local one */
pascal@11602 197 + if (passwd[0] == '$' && passwd[1] == '1' && passwd[2] == '$') {
pascal@11352 198 + char *encrypted = pw_encrypt(
pascal@11352 199 + /* pwd: */ colon_after_user + 1,
pascal@11352 200 + /* salt: */ passwd,
pascal@11352 201 + /* cleanup: */ 0
pascal@11352 202 + );
pascal@11352 203 + r = strcmp(encrypted, passwd);
pascal@11352 204 + free(encrypted);
pascal@11352 205 + goto end_check_passwd;
pascal@11352 206 + }
pascal@11352 207 + bad_input: ;
pascal@11352 208 }
pascal@11352 209
pascal@11352 210 /* Comparing plaintext "user:pass" in one go */
pascal@11352 211 - if (strcmp(cur->after_colon, user_and_passwd) == 0) {
pascal@11352 212 - set_remoteuser_var:
pascal@11356 213 + r = strcmp(cur->after_colon, user_and_passwd);
pascal@11352 214 + end_check_passwd:
pascal@11352 215 + if (r == 0) {
pascal@11352 216 remoteuser = xstrndup(user_and_passwd,
pascal@11352 217 strchrnul(user_and_passwd, ':') - user_and_passwd);
pascal@11352 218 return 1; /* Ok */
pascal@11356 219 @@ -2112,7 +2233,7 @@
pascal@11356 220 /* Case: no "Authorization:" was seen, but page does require passwd.
pascal@11356 221 * Check that with dummy user:pass */
pascal@11356 222 if (authorized < 0)
pascal@11356 223 - authorized = check_user_passwd(urlcopy, ":");
pascal@11356 224 + authorized = check_user_passwd(urlcopy, (char *) "");
pascal@11356 225 if (!authorized)
pascal@11356 226 send_headers_and_exit(HTTP_UNAUTHORIZED);
pascal@11356 227 #endif