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@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@540
|
12 @@ -123,6 +124,14 @@
|
pascal@540
|
13 //usage: "\n -d STRING URL decode STRING"
|
pascal@540
|
14
|
pascal@540
|
15 #include "libbb.h"
|
pascal@540
|
16 +#if ENABLE_PAM
|
pascal@540
|
17 +/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
|
pascal@540
|
18 +# undef setlocale
|
pascal@540
|
19 +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
|
pascal@540
|
20 + * Apparently they like to confuse people. */
|
pascal@540
|
21 +# include <security/pam_appl.h>
|
pascal@540
|
22 +# include <security/pam_misc.h>
|
pascal@540
|
23 +#endif
|
pascal@540
|
24 #if ENABLE_FEATURE_HTTPD_USE_SENDFILE
|
pascal@540
|
25 # include <sys/sendfile.h>
|
pascal@540
|
26 #endif
|
pascal@540
|
27 @@ -1730,6 +1739,57 @@
|
pascal@539
|
28 }
|
pascal@539
|
29
|
pascal@539
|
30 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
|
pascal@539
|
31 +
|
pascal@539
|
32 +#if ENABLE_PAM
|
pascal@539
|
33 +struct pam_userinfo {
|
pascal@539
|
34 + char *name;
|
pascal@539
|
35 + char *pw;
|
pascal@539
|
36 +};
|
pascal@539
|
37 +
|
pascal@539
|
38 +static int pam_talker(int num_msg,
|
pascal@539
|
39 + const struct pam_message ** msg,
|
pascal@539
|
40 + struct pam_response ** resp,
|
pascal@539
|
41 + void *appdata_ptr)
|
pascal@539
|
42 +{
|
pascal@539
|
43 + int i;
|
pascal@539
|
44 + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr;
|
pascal@539
|
45 + struct pam_response *response;
|
pascal@539
|
46 +
|
pascal@539
|
47 + if (!resp || !msg || !userinfo)
|
pascal@539
|
48 + return PAM_CONV_ERR;
|
pascal@539
|
49 +
|
pascal@539
|
50 + /* allocate memory to store response */
|
pascal@539
|
51 + response = malloc(num_msg * sizeof(struct pam_response));
|
pascal@539
|
52 + if (!response)
|
pascal@539
|
53 + return PAM_CONV_ERR;
|
pascal@539
|
54 +
|
pascal@539
|
55 + /* copy values */
|
pascal@539
|
56 + for (i = 0; i < num_msg; i++) {
|
pascal@539
|
57 + char *s;
|
pascal@539
|
58 +
|
pascal@539
|
59 + switch (msg[i]->msg_style) {
|
pascal@539
|
60 + case PAM_PROMPT_ECHO_ON:
|
pascal@539
|
61 + s = userinfo->name;
|
pascal@539
|
62 + break;
|
pascal@539
|
63 + case PAM_PROMPT_ECHO_OFF:
|
pascal@539
|
64 + s = userinfo->pw;
|
pascal@539
|
65 + break;
|
pascal@539
|
66 + case PAM_ERROR_MSG:
|
pascal@539
|
67 + case PAM_TEXT_INFO:
|
pascal@539
|
68 + s = "";
|
pascal@539
|
69 + break;
|
pascal@539
|
70 + default:
|
pascal@539
|
71 + free(response);
|
pascal@539
|
72 + return PAM_CONV_ERR;
|
pascal@539
|
73 + }
|
pascal@539
|
74 + response[i].resp = strdup(s);
|
pascal@539
|
75 + response[i].resp_retcode = PAM_SUCCESS;
|
pascal@539
|
76 + }
|
pascal@539
|
77 + *resp = response;
|
pascal@539
|
78 + return PAM_SUCCESS;
|
pascal@539
|
79 +}
|
pascal@539
|
80 +#endif
|
pascal@539
|
81 +
|
pascal@539
|
82 /*
|
pascal@539
|
83 * Config file entries are of the form "/<path>:<user>:<passwd>".
|
pascal@539
|
84 * If config file has no prefix match for path, access is allowed.
|
pascal@540
|
85 @@ -1745,7 +1805,7 @@
|
pascal@536
|
86 const char *prev = NULL;
|
pascal@536
|
87
|
pascal@536
|
88 for (cur = g_auth; cur; cur = cur->next) {
|
pascal@536
|
89 - const char *dir_prefix;
|
pascal@536
|
90 + const char *dir_prefix, *passwd;
|
pascal@536
|
91 size_t len;
|
pascal@536
|
92
|
pascal@536
|
93 dir_prefix = cur->before_colon;
|
pascal@540
|
94 @@ -1770,18 +1830,71 @@
|
pascal@536
|
95 /* Path match found */
|
pascal@536
|
96 prev = dir_prefix;
|
pascal@536
|
97
|
pascal@536
|
98 + remoteuser = xstrndup(user_and_passwd,
|
pascal@536
|
99 + strchrnul(user_and_passwd, ':') - user_and_passwd);
|
pascal@536
|
100 + passwd = strchr(cur->after_colon, ':');
|
pascal@536
|
101 +
|
pascal@536
|
102 + if (passwd && passwd[1] == '*' && passwd[2] == 0) {
|
pascal@539
|
103 +#if ENABLE_PAM
|
pascal@539
|
104 + int r;
|
pascal@539
|
105 + struct pam_userinfo userinfo = {NULL, NULL};
|
pascal@539
|
106 + struct pam_conv conv_info = {&pam_talker, (void *) &userinfo};
|
pascal@539
|
107 + pam_handle_t *pamh;
|
pascal@539
|
108 +
|
pascal@539
|
109 + userinfo.name = remoteuser;
|
pascal@539
|
110 + userinfo.pw = strchr(user_and_passwd, ':');
|
pascal@539
|
111 +
|
pascal@539
|
112 + r = pam_start("httpd", remoteuser, &conv_info, &pamh) == PAM_SUCCESS
|
pascal@539
|
113 + && pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) == PAM_SUCCESS
|
pascal@539
|
114 + && pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK)) == PAM_SUCCESS;
|
pascal@539
|
115 + pam_end(pamh, PAM_SUCCESS);
|
pascal@539
|
116 + if (r)
|
pascal@539
|
117 + return 1; /* Ok */
|
pascal@539
|
118 +#else
|
pascal@537
|
119 + struct passwd *pw = getpwnam(remoteuser);
|
pascal@538
|
120 + if (pw) {
|
pascal@538
|
121 +#if ENABLE_FEATURE_SHADOWPASSWDS
|
pascal@538
|
122 + /* Using _r function to avoid pulling in static buffers */
|
pascal@538
|
123 + struct spwd spw;
|
pascal@538
|
124 + char buffer[256];
|
pascal@538
|
125 +#endif
|
pascal@538
|
126 + const char *correct = pw->pw_passwd;
|
pascal@538
|
127 + char *unencrypted = strchr(user_and_passwd, ':');
|
pascal@538
|
128 + int r;
|
pascal@538
|
129 +
|
pascal@538
|
130 + /* Don't check the password if password entry is empty (!) */
|
pascal@538
|
131 + if (!correct[0])
|
pascal@538
|
132 + return 1; /* Ok */
|
pascal@538
|
133 +#if ENABLE_FEATURE_SHADOWPASSWDS
|
pascal@538
|
134 + if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) {
|
pascal@538
|
135 + /* getspnam_r may return 0 yet set result to NULL.
|
pascal@538
|
136 + * At least glibc 2.4 does this. Be extra paranoid here. */
|
pascal@538
|
137 + struct spwd *result = NULL;
|
pascal@538
|
138 + r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result);
|
pascal@538
|
139 + correct = (r || !result) ? "aa" : result->sp_pwdp;
|
pascal@538
|
140 + }
|
pascal@538
|
141 +#endif
|
pascal@538
|
142 + if (correct[0] != '!' && correct[0] != '*') {
|
pascal@538
|
143 + char *encrypted = pw_encrypt(unencrypted, correct, 1);
|
pascal@538
|
144 + r = (strcmp(encrypted, correct) == 0);
|
pascal@538
|
145 + free(encrypted);
|
pascal@538
|
146 + if (r)
|
pascal@538
|
147 + return 1; /* Ok */
|
pascal@539
|
148 + }
|
pascal@538
|
149 + }
|
pascal@539
|
150 +#endif // ENABLE_PAM
|
pascal@536
|
151 + free(remoteuser);
|
pascal@536
|
152 + continue;
|
pascal@536
|
153 + }
|
pascal@536
|
154 if (ENABLE_FEATURE_HTTPD_AUTH_MD5) {
|
pascal@536
|
155 - char *md5_passwd;
|
pascal@536
|
156 -
|
pascal@536
|
157 - md5_passwd = strchr(cur->after_colon, ':');
|
pascal@536
|
158 - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1'
|
pascal@536
|
159 - && md5_passwd[3] == '$' && md5_passwd[4]
|
pascal@536
|
160 + if (passwd && passwd[1] == '$' && passwd[2] == '1'
|
pascal@536
|
161 + && passwd[3] == '$' && passwd[4]
|
pascal@536
|
162 ) {
|
pascal@536
|
163 char *encrypted;
|
pascal@536
|
164 int r, user_len_p1;
|
pascal@536
|
165
|
pascal@536
|
166 - md5_passwd++;
|
pascal@536
|
167 - user_len_p1 = md5_passwd - cur->after_colon;
|
pascal@536
|
168 + passwd++;
|
pascal@536
|
169 + user_len_p1 = passwd - cur->after_colon;
|
pascal@536
|
170 /* comparing "user:" */
|
pascal@536
|
171 if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) {
|
pascal@536
|
172 continue;
|
pascal@540
|
173 @@ -1789,22 +1902,20 @@
|
pascal@536
|
174
|
pascal@536
|
175 encrypted = pw_encrypt(
|
pascal@536
|
176 user_and_passwd + user_len_p1 /* cleartext pwd from user */,
|
pascal@536
|
177 - md5_passwd /*salt */, 1 /* cleanup */);
|
pascal@536
|
178 - r = strcmp(encrypted, md5_passwd);
|
pascal@536
|
179 + passwd /*salt */, 1 /* cleanup */);
|
pascal@536
|
180 + r = strcmp(encrypted, passwd);
|
pascal@536
|
181 free(encrypted);
|
pascal@536
|
182 if (r == 0)
|
pascal@536
|
183 - goto set_remoteuser_var; /* Ok */
|
pascal@536
|
184 + return 1; /* Ok */
|
pascal@536
|
185 continue;
|
pascal@536
|
186 }
|
pascal@536
|
187 }
|
pascal@536
|
188
|
pascal@536
|
189 /* Comparing plaintext "user:pass" in one go */
|
pascal@536
|
190 - if (strcmp(cur->after_colon, user_and_passwd) == 0) {
|
pascal@536
|
191 - set_remoteuser_var:
|
pascal@536
|
192 - remoteuser = xstrndup(user_and_passwd,
|
pascal@536
|
193 - strchrnul(user_and_passwd, ':') - user_and_passwd);
|
pascal@536
|
194 + if (strcmp(cur->after_colon, user_and_passwd) == 0)
|
pascal@536
|
195 return 1; /* Ok */
|
pascal@536
|
196 - }
|
pascal@536
|
197 + free(remoteuser);
|
pascal@536
|
198 + remoteuser = NULL;
|
pascal@536
|
199 } /* for */
|
pascal@536
|
200
|
pascal@536
|
201 /* 0(bad) if prev is set: matches were found but passwd was wrong */
|