wok-undigest view busybox/stuff/busybox-1.19-httpd.u @ rev 547

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