1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
1 |
/*
|
2 |
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
|
3 |
*
|
|
4 |
* Redistribution and use in source and binary forms, with or without
|
|
5 |
* modification, are permitted provided that the following conditions
|
|
6 |
* are met:
|
|
7 |
* 1. Redistributions of source code must retain the above copyright
|
|
8 |
* notice, this list of conditions and the following disclaimer.
|
|
9 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
10 |
* notice, this list of conditions and the following disclaimer in the
|
|
11 |
* documentation and/or other materials provided with the distribution.
|
|
12 |
*
|
|
13 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
14 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
15 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
16 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
17 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
18 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
19 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
20 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
21 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
22 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23 |
*/
|
|
24 |
||
25 |
#include "includes.h" |
|
1.1.1
by Colin Watson
Import upstream version 3.9p1 |
26 |
RCSID("$OpenBSD: auth2.c,v 1.107 2004/07/28 09:40:29 markus Exp $"); |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
27 |
|
28 |
#include "ssh2.h" |
|
29 |
#include "xmalloc.h" |
|
30 |
#include "packet.h" |
|
31 |
#include "log.h" |
|
32 |
#include "servconf.h" |
|
33 |
#include "compat.h" |
|
34 |
#include "auth.h" |
|
35 |
#include "dispatch.h" |
|
36 |
#include "pathnames.h" |
|
37 |
#include "monitor_wrap.h" |
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
38 |
#include "buffer.h" |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
39 |
|
40 |
#ifdef GSSAPI
|
|
41 |
#include "ssh-gss.h" |
|
42 |
#endif
|
|
43 |
||
44 |
/* import */
|
|
45 |
extern ServerOptions options; |
|
46 |
extern u_char *session_id2; |
|
47 |
extern u_int session_id2_len; |
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
48 |
extern Buffer loginmsg; |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
49 |
|
50 |
/* methods */
|
|
51 |
||
52 |
extern Authmethod method_none; |
|
53 |
extern Authmethod method_pubkey; |
|
54 |
extern Authmethod method_passwd; |
|
55 |
extern Authmethod method_kbdint; |
|
56 |
extern Authmethod method_hostbased; |
|
57 |
#ifdef GSSAPI
|
|
5
by Colin Watson
Resynchronise with Debian. |
58 |
extern Authmethod method_gsskeyex; |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
59 |
extern Authmethod method_gssapi; |
60 |
#endif
|
|
61 |
||
62 |
Authmethod *authmethods[] = { |
|
63 |
&method_none, |
|
64 |
&method_pubkey, |
|
65 |
#ifdef GSSAPI
|
|
5
by Colin Watson
Resynchronise with Debian. |
66 |
&method_gsskeyex, |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
67 |
&method_gssapi, |
68 |
#endif
|
|
69 |
&method_passwd, |
|
70 |
&method_kbdint, |
|
71 |
&method_hostbased, |
|
72 |
NULL
|
|
73 |
};
|
|
74 |
||
75 |
/* protocol */
|
|
76 |
||
77 |
static void input_service_request(int, u_int32_t, void *); |
|
78 |
static void input_userauth_request(int, u_int32_t, void *); |
|
79 |
||
80 |
/* helper */
|
|
81 |
static Authmethod *authmethod_lookup(const char *); |
|
82 |
static char *authmethods_get(void); |
|
83 |
int user_key_allowed(struct passwd *, Key *); |
|
84 |
||
85 |
/*
|
|
86 |
* loop until authctxt->success == TRUE
|
|
87 |
*/
|
|
88 |
||
89 |
void
|
|
90 |
do_authentication2(Authctxt *authctxt) |
|
91 |
{
|
|
92 |
/* challenge-response is implemented via keyboard interactive */
|
|
93 |
if (options.challenge_response_authentication) |
|
94 |
options.kbd_interactive_authentication = 1; |
|
95 |
||
96 |
dispatch_init(&dispatch_protocol_error); |
|
97 |
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); |
|
98 |
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); |
|
99 |
}
|
|
100 |
||
101 |
static void |
|
102 |
input_service_request(int type, u_int32_t seq, void *ctxt) |
|
103 |
{
|
|
104 |
Authctxt *authctxt = ctxt; |
|
105 |
u_int len; |
|
106 |
int acceptit = 0; |
|
107 |
char *service = packet_get_string(&len); |
|
108 |
packet_check_eom(); |
|
109 |
||
110 |
if (authctxt == NULL) |
|
111 |
fatal("input_service_request: no authctxt"); |
|
112 |
||
113 |
if (strcmp(service, "ssh-userauth") == 0) { |
|
114 |
if (!authctxt->success) { |
|
115 |
acceptit = 1; |
|
116 |
/* now we can handle user-auth requests */
|
|
117 |
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); |
|
118 |
}
|
|
119 |
}
|
|
120 |
/* XXX all other service requests are denied */
|
|
121 |
||
122 |
if (acceptit) { |
|
123 |
packet_start(SSH2_MSG_SERVICE_ACCEPT); |
|
124 |
packet_put_cstring(service); |
|
125 |
packet_send(); |
|
126 |
packet_write_wait(); |
|
127 |
} else { |
|
128 |
debug("bad service request %s", service); |
|
129 |
packet_disconnect("bad service request %s", service); |
|
130 |
}
|
|
131 |
xfree(service); |
|
132 |
}
|
|
133 |
||
134 |
static void |
|
135 |
input_userauth_request(int type, u_int32_t seq, void *ctxt) |
|
136 |
{
|
|
137 |
Authctxt *authctxt = ctxt; |
|
138 |
Authmethod *m = NULL; |
|
4
by Colin Watson
* Add /usr/games to the default $PATH for non-privileged users. |
139 |
char *user, *service, *method, *style = NULL, *role = NULL; |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
140 |
int authenticated = 0; |
141 |
||
142 |
if (authctxt == NULL) |
|
143 |
fatal("input_userauth_request: no authctxt"); |
|
144 |
||
145 |
user = packet_get_string(NULL); |
|
146 |
service = packet_get_string(NULL); |
|
147 |
method = packet_get_string(NULL); |
|
148 |
debug("userauth-request for user %s service %s method %s", user, service, method); |
|
149 |
debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); |
|
150 |
||
4
by Colin Watson
* Add /usr/games to the default $PATH for non-privileged users. |
151 |
if ((role = strchr(user, '/')) != NULL) |
152 |
*role++ = 0; |
|
153 |
||
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
154 |
if ((style = strchr(user, ':')) != NULL) |
155 |
*style++ = 0; |
|
4
by Colin Watson
* Add /usr/games to the default $PATH for non-privileged users. |
156 |
else if (role && (style = strchr(role, ':')) != NULL) |
157 |
*style++ = '\0'; |
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
158 |
|
159 |
if (authctxt->attempt++ == 0) { |
|
160 |
/* setup auth context */
|
|
161 |
authctxt->pw = PRIVSEP(getpwnamallow(user)); |
|
162 |
authctxt->user = xstrdup(user); |
|
163 |
if (authctxt->pw && strcmp(service, "ssh-connection")==0) { |
|
164 |
authctxt->valid = 1; |
|
165 |
debug2("input_userauth_request: setting up authctxt for %s", user); |
|
166 |
#ifdef USE_PAM
|
|
167 |
if (options.use_pam) |
|
168 |
PRIVSEP(start_pam(authctxt)); |
|
169 |
#endif
|
|
170 |
} else { |
|
1.1.1
by Colin Watson
Import upstream version 3.9p1 |
171 |
logit("input_userauth_request: invalid user %s", user); |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
172 |
authctxt->pw = fakepw(); |
173 |
#ifdef USE_PAM
|
|
174 |
if (options.use_pam) |
|
175 |
PRIVSEP(start_pam(authctxt)); |
|
176 |
#endif
|
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
177 |
#ifdef SSH_AUDIT_EVENTS
|
178 |
PRIVSEP(audit_event(SSH_INVALID_USER)); |
|
179 |
#endif
|
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
180 |
}
|
1.1.1
by Colin Watson
Import upstream version 3.9p1 |
181 |
setproctitle("%s%s", authctxt->valid ? user : "unknown", |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
182 |
use_privsep ? " [net]" : ""); |
183 |
authctxt->service = xstrdup(service); |
|
184 |
authctxt->style = style ? xstrdup(style) : NULL; |
|
4
by Colin Watson
* Add /usr/games to the default $PATH for non-privileged users. |
185 |
authctxt->role = role ? xstrdup(role) : NULL; |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
186 |
if (use_privsep) |
4
by Colin Watson
* Add /usr/games to the default $PATH for non-privileged users. |
187 |
mm_inform_authserv(service, style, role); |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
188 |
} else if (strcmp(user, authctxt->user) != 0 || |
189 |
strcmp(service, authctxt->service) != 0) { |
|
190 |
packet_disconnect("Change of username or service not allowed: " |
|
191 |
"(%s,%s) -> (%s,%s)", |
|
192 |
authctxt->user, authctxt->service, user, service); |
|
193 |
}
|
|
194 |
/* reset state */
|
|
195 |
auth2_challenge_stop(authctxt); |
|
196 |
||
197 |
#ifdef GSSAPI
|
|
198 |
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); |
|
199 |
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); |
|
200 |
#endif
|
|
201 |
||
202 |
authctxt->postponed = 0; |
|
203 |
||
204 |
/* try to authenticate user */
|
|
205 |
m = authmethod_lookup(method); |
|
206 |
if (m != NULL) { |
|
207 |
debug2("input_userauth_request: try method %s", method); |
|
208 |
authenticated = m->userauth(authctxt); |
|
209 |
}
|
|
210 |
userauth_finish(authctxt, authenticated, method); |
|
211 |
||
212 |
xfree(service); |
|
213 |
xfree(user); |
|
214 |
xfree(method); |
|
215 |
}
|
|
216 |
||
217 |
void
|
|
218 |
userauth_finish(Authctxt *authctxt, int authenticated, char *method) |
|
219 |
{
|
|
220 |
char *methods; |
|
221 |
||
222 |
if (!authctxt->valid && authenticated) |
|
223 |
fatal("INTERNAL ERROR: authenticated invalid user %s", |
|
224 |
authctxt->user); |
|
225 |
||
226 |
/* Special handling for root */
|
|
227 |
if (authenticated && authctxt->pw->pw_uid == 0 && |
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
228 |
!auth_root_allowed(method)) { |
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
229 |
authenticated = 0; |
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
230 |
#ifdef SSH_AUDIT_EVENTS
|
231 |
PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); |
|
232 |
#endif
|
|
233 |
}
|
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
234 |
|
235 |
#ifdef USE_PAM
|
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
236 |
if (options.use_pam && authenticated) { |
237 |
if (!PRIVSEP(do_pam_account())) { |
|
238 |
/* if PAM returned a message, send it to the user */
|
|
239 |
if (buffer_len(&loginmsg) > 0) { |
|
240 |
buffer_append(&loginmsg, "\0", 1); |
|
241 |
userauth_send_banner(buffer_ptr(&loginmsg)); |
|
242 |
packet_write_wait(); |
|
243 |
}
|
|
244 |
fatal("Access denied for user %s by PAM account " |
|
1.1.3
by Colin Watson
Import upstream version 4.2p1 |
245 |
"configuration", authctxt->user); |
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
246 |
}
|
247 |
}
|
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
248 |
#endif
|
249 |
||
250 |
#ifdef _UNICOS
|
|
251 |
if (authenticated && cray_access_denied(authctxt->user)) { |
|
252 |
authenticated = 0; |
|
253 |
fatal("Access denied for user %s.",authctxt->user); |
|
254 |
}
|
|
255 |
#endif /* _UNICOS */ |
|
256 |
||
257 |
/* Log before sending the reply */
|
|
258 |
auth_log(authctxt, authenticated, method, " ssh2"); |
|
259 |
||
260 |
if (authctxt->postponed) |
|
261 |
return; |
|
262 |
||
263 |
/* XXX todo: check if multiple auth methods are needed */
|
|
264 |
if (authenticated == 1) { |
|
265 |
/* turn off userauth */
|
|
266 |
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); |
|
267 |
packet_start(SSH2_MSG_USERAUTH_SUCCESS); |
|
268 |
packet_send(); |
|
269 |
packet_write_wait(); |
|
270 |
/* now we can break out */
|
|
271 |
authctxt->success = 1; |
|
272 |
} else { |
|
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
273 |
if (authctxt->failures++ > options.max_authtries) { |
274 |
#ifdef SSH_AUDIT_EVENTS
|
|
275 |
PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); |
|
276 |
#endif
|
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
277 |
packet_disconnect(AUTH_FAIL_MSG, authctxt->user); |
1.1.2
by Colin Watson
Import upstream version 4.1p1 |
278 |
}
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
279 |
methods = authmethods_get(); |
280 |
packet_start(SSH2_MSG_USERAUTH_FAILURE); |
|
281 |
packet_put_cstring(methods); |
|
282 |
packet_put_char(0); /* XXX partial success, unused */ |
|
283 |
packet_send(); |
|
284 |
packet_write_wait(); |
|
285 |
xfree(methods); |
|
286 |
}
|
|
287 |
}
|
|
288 |
||
289 |
#define DELIM ","
|
|
290 |
||
291 |
static char * |
|
292 |
authmethods_get(void) |
|
293 |
{
|
|
294 |
Buffer b; |
|
295 |
char *list; |
|
296 |
int i; |
|
297 |
||
298 |
buffer_init(&b); |
|
299 |
for (i = 0; authmethods[i] != NULL; i++) { |
|
300 |
if (strcmp(authmethods[i]->name, "none") == 0) |
|
301 |
continue; |
|
302 |
if (authmethods[i]->enabled != NULL && |
|
303 |
*(authmethods[i]->enabled) != 0) { |
|
304 |
if (buffer_len(&b) > 0) |
|
305 |
buffer_append(&b, ",", 1); |
|
306 |
buffer_append(&b, authmethods[i]->name, |
|
307 |
strlen(authmethods[i]->name)); |
|
308 |
}
|
|
309 |
}
|
|
310 |
buffer_append(&b, "\0", 1); |
|
311 |
list = xstrdup(buffer_ptr(&b)); |
|
312 |
buffer_free(&b); |
|
313 |
return list; |
|
314 |
}
|
|
315 |
||
316 |
static Authmethod * |
|
317 |
authmethod_lookup(const char *name) |
|
318 |
{
|
|
319 |
int i; |
|
320 |
||
321 |
if (name != NULL) |
|
322 |
for (i = 0; authmethods[i] != NULL; i++) |
|
323 |
if (authmethods[i]->enabled != NULL && |
|
324 |
*(authmethods[i]->enabled) != 0 && |
|
325 |
strcmp(name, authmethods[i]->name) == 0) |
|
326 |
return authmethods[i]; |
|
327 |
debug2("Unrecognized authentication method name: %s", |
|
328 |
name ? name : "NULL"); |
|
329 |
return NULL; |
|
330 |
}
|