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

busybox/httpd: check system passwords (with pam support)
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Nov 05 16:11:27 2011 +0100 (2011-11-05)
parents 2686f33e3494
children 7996e985a518
rev   line source
pascal@536 1 Check system passwords
pascal@536 2 --- busybox-1.19.0/networking/httpd.c
pascal@536 3 +++ busybox-1.19.0/networking/httpd.c
pascal@536 4 @@ -54,6 +54,7 @@
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@536 9 * .au:audio/basic # additional mime type for audio.au files
pascal@536 10 * *.php:/path/php # run xxx.php through an interpreter
pascal@536 11 *
pascal@539 12 @@ -1730,6 +1731,57 @@
pascal@539 13 }
pascal@539 14
pascal@539 15 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
pascal@539 16 +
pascal@539 17 +#if ENABLE_PAM
pascal@539 18 +struct pam_userinfo {
pascal@539 19 + char *name;
pascal@539 20 + char *pw;
pascal@539 21 +};
pascal@539 22 +
pascal@539 23 +static int pam_talker(int num_msg,
pascal@539 24 + const struct pam_message ** msg,
pascal@539 25 + struct pam_response ** resp,
pascal@539 26 + void *appdata_ptr)
pascal@539 27 +{
pascal@539 28 + int i;
pascal@539 29 + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
pascal@539 30 + struct pam_response *response;
pascal@539 31 +
pascal@539 32 + if (!resp || !msg || !userinfo)
pascal@539 33 + return PAM_CONV_ERR;
pascal@539 34 +
pascal@539 35 + /* allocate memory to store response */
pascal@539 36 + response = malloc(num_msg * sizeof(struct pam_response));
pascal@539 37 + if (!response)
pascal@539 38 + return PAM_CONV_ERR;
pascal@539 39 +
pascal@539 40 + /* copy values */
pascal@539 41 + for (i = 0; i < num_msg; i++) {
pascal@539 42 + char *s;
pascal@539 43 +
pascal@539 44 + switch (msg[i]->msg_style) {
pascal@539 45 + case PAM_PROMPT_ECHO_ON:
pascal@539 46 + s = userinfo->name;
pascal@539 47 + break;
pascal@539 48 + case PAM_PROMPT_ECHO_OFF:
pascal@539 49 + s = userinfo->pw;
pascal@539 50 + break;
pascal@539 51 + case PAM_ERROR_MSG:
pascal@539 52 + case PAM_TEXT_INFO:
pascal@539 53 + s = "";
pascal@539 54 + break;
pascal@539 55 + default:
pascal@539 56 + free(response);
pascal@539 57 + return PAM_CONV_ERR;
pascal@539 58 + }
pascal@539 59 + response[i].resp = strdup(s);
pascal@539 60 + response[i].resp_retcode = PAM_SUCCESS;
pascal@539 61 + }
pascal@539 62 + *resp = response;
pascal@539 63 + return PAM_SUCCESS;
pascal@539 64 +}
pascal@539 65 +#endif
pascal@539 66 +
pascal@539 67 /*
pascal@539 68 * Config file entries are of the form "/<path>:<user>:<passwd>".
pascal@539 69 * If config file has no prefix match for path, access is allowed.
pascal@539 70 @@ -1745,7 +1797,7 @@
pascal@536 71 const char *prev = NULL;
pascal@536 72
pascal@536 73 for (cur = g_auth; cur; cur = cur->next) {
pascal@536 74 - const char *dir_prefix;
pascal@536 75 + const char *dir_prefix, *passwd;
pascal@536 76 size_t len;
pascal@536 77
pascal@536 78 dir_prefix = cur->before_colon;
pascal@539 79 @@ -1770,18 +1822,71 @@
pascal@536 80 /* Path match found */
pascal@536 81 prev = dir_prefix;
pascal@536 82
pascal@536 83 + remoteuser = xstrndup(user_and_passwd,
pascal@536 84 + strchrnul(user_and_passwd, ':') - user_and_passwd);
pascal@536 85 + passwd = strchr(cur->after_colon, ':');
pascal@536 86 +
pascal@536 87 + if (passwd && passwd[1] == '*' && passwd[2] == 0) {
pascal@539 88 +#if ENABLE_PAM
pascal@539 89 + int r;
pascal@539 90 + struct pam_userinfo userinfo = {NULL, NULL};
pascal@539 91 + struct pam_conv conv_info = {&pam_talker, (void *) &userinfo};
pascal@539 92 + pam_handle_t *pamh;
pascal@539 93 +
pascal@539 94 + userinfo.name = remoteuser;
pascal@539 95 + userinfo.pw = strchr(user_and_passwd, ':');
pascal@539 96 +
pascal@539 97 + r = pam_start("httpd", remoteuser, &conv_info, &pamh) == PAM_SUCCESS
pascal@539 98 + && pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) == PAM_SUCCESS
pascal@539 99 + && pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) == PAM_SUCCESS;
pascal@539 100 + pam_end(pamh, PAM_SUCCESS);
pascal@539 101 + if (r)
pascal@539 102 + return 1; /* Ok */
pascal@539 103 +#else
pascal@537 104 + struct passwd *pw = getpwnam(remoteuser);
pascal@538 105 + if (pw) {
pascal@538 106 +#if ENABLE_FEATURE_SHADOWPASSWDS
pascal@538 107 + /* Using _r function to avoid pulling in static buffers */
pascal@538 108 + struct spwd spw;
pascal@538 109 + char buffer[256];
pascal@538 110 +#endif
pascal@538 111 + const char *correct = pw->pw_passwd;
pascal@538 112 + char *unencrypted = strchr(user_and_passwd, ':');
pascal@538 113 + int r;
pascal@538 114 +
pascal@538 115 + /* Don't check the password if password entry is empty (!) */
pascal@538 116 + if (!correct[0])
pascal@538 117 + return 1; /* Ok */
pascal@538 118 +#if ENABLE_FEATURE_SHADOWPASSWDS
pascal@538 119 + if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
pascal@538 120 + /* getspnam_r may return 0 yet set result to NULL.
pascal@538 121 + * At least glibc 2.4 does this. Be extra paranoid here. */
pascal@538 122 + struct spwd *result = NULL;
pascal@538 123 + r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
pascal@538 124 + correct = (r || !result) ? "aa" : result->sp_pwdp;
pascal@538 125 + }
pascal@538 126 +#endif
pascal@538 127 + if (correct[0] != '!' && correct[0] != '*') {
pascal@538 128 + char *encrypted = pw_encrypt(unencrypted, correct, 1);
pascal@538 129 + r = (strcmp(encrypted, correct) == 0);
pascal@538 130 + free(encrypted);
pascal@538 131 + if (r)
pascal@538 132 + return 1; /* Ok */
pascal@539 133 + }
pascal@538 134 + }
pascal@539 135 +#endif // ENABLE_PAM
pascal@536 136 + free(remoteuser);
pascal@536 137 + continue;
pascal@536 138 + }
pascal@536 139 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
pascal@536 140 - char *md5_passwd;
pascal@536 141 -
pascal@536 142 - md5_passwd = strchr(cur->after_colon, ':');
pascal@536 143 - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
pascal@536 144 - && md5_passwd[3] == '$' && md5_passwd[4]
pascal@536 145 + if (passwd && passwd[1] == '$' && passwd[2] == '1'
pascal@536 146 + && passwd[3] == '$' && passwd[4]
pascal@536 147 ) {
pascal@536 148 char *encrypted;
pascal@536 149 int r, user_len_p1;
pascal@536 150
pascal@536 151 - md5_passwd++;
pascal@536 152 - user_len_p1 = md5_passwd - cur->after_colon;
pascal@536 153 + passwd++;
pascal@536 154 + user_len_p1 = passwd - cur->after_colon;
pascal@536 155 /* comparing "user:" */
pascal@536 156 if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
pascal@536 157 continue;
pascal@539 158 @@ -1789,22 +1894,20 @@
pascal@536 159
pascal@536 160 encrypted = pw_encrypt(
pascal@536 161 user_and_passwd + user_len_p1 /* cleartext pwd from user */,
pascal@536 162 - md5_passwd /*salt */, 1 /* cleanup */);
pascal@536 163 - r = strcmp(encrypted, md5_passwd);
pascal@536 164 + passwd /*salt */, 1 /* cleanup */);
pascal@536 165 + r = strcmp(encrypted, passwd);
pascal@536 166 free(encrypted);
pascal@536 167 if (r == 0)
pascal@536 168 - goto set_remoteuser_var; /* Ok */
pascal@536 169 + return 1; /* Ok */
pascal@536 170 continue;
pascal@536 171 }
pascal@536 172 }
pascal@536 173
pascal@536 174 /* Comparing plaintext "user:pass" in one go */
pascal@536 175 - if (strcmp(cur->after_colon, user_and_passwd) == 0) {
pascal@536 176 - set_remoteuser_var:
pascal@536 177 - remoteuser = xstrndup(user_and_passwd,
pascal@536 178 - strchrnul(user_and_passwd, ':') - user_and_passwd);
pascal@536 179 + if (strcmp(cur->after_colon, user_and_passwd) == 0)
pascal@536 180 return 1; /* Ok */
pascal@536 181 - }
pascal@536 182 + free(remoteuser);
pascal@536 183 + remoteuser = NULL;
pascal@536 184 } /* for */
pascal@536 185
pascal@536 186 /* 0(bad) if prev is set: matches were found but passwd was wrong */