diff options
Diffstat (limited to 'auth1.c')
-rw-r--r-- | auth1.c | 444 |
1 files changed, 0 insertions, 444 deletions
diff --git a/auth1.c b/auth1.c deleted file mode 100644 index 5073c49bb..000000000 --- a/auth1.c +++ /dev/null | |||
@@ -1,444 +0,0 @@ | |||
1 | /* $OpenBSD: auth1.c,v 1.82 2014/07/15 15:54:14 millert Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
4 | * All rights reserved | ||
5 | * | ||
6 | * As far as I am concerned, the code I have written for this software | ||
7 | * can be used freely for any purpose. Any derived versions of this | ||
8 | * software must be clearly marked as such, and if the derived work is | ||
9 | * incompatible with the protocol description in the RFC file, it must be | ||
10 | * called by a name other than "ssh" or "Secure Shell". | ||
11 | */ | ||
12 | |||
13 | #include "includes.h" | ||
14 | |||
15 | #ifdef WITH_SSH1 | ||
16 | |||
17 | #include <sys/types.h> | ||
18 | |||
19 | #include <stdarg.h> | ||
20 | #include <stdio.h> | ||
21 | #include <string.h> | ||
22 | #include <unistd.h> | ||
23 | #include <pwd.h> | ||
24 | |||
25 | #include "openbsd-compat/sys-queue.h" | ||
26 | #include "xmalloc.h" | ||
27 | #include "rsa.h" | ||
28 | #include "ssh1.h" | ||
29 | #include "packet.h" | ||
30 | #include "buffer.h" | ||
31 | #include "log.h" | ||
32 | #include "misc.h" | ||
33 | #include "servconf.h" | ||
34 | #include "compat.h" | ||
35 | #include "key.h" | ||
36 | #include "hostfile.h" | ||
37 | #include "auth.h" | ||
38 | #include "channels.h" | ||
39 | #include "session.h" | ||
40 | #include "uidswap.h" | ||
41 | #ifdef GSSAPI | ||
42 | #include "ssh-gss.h" | ||
43 | #endif | ||
44 | #include "monitor_wrap.h" | ||
45 | #include "buffer.h" | ||
46 | |||
47 | /* import */ | ||
48 | extern ServerOptions options; | ||
49 | extern Buffer loginmsg; | ||
50 | |||
51 | static int auth1_process_password(Authctxt *); | ||
52 | static int auth1_process_rsa(Authctxt *); | ||
53 | static int auth1_process_rhosts_rsa(Authctxt *); | ||
54 | static int auth1_process_tis_challenge(Authctxt *); | ||
55 | static int auth1_process_tis_response(Authctxt *); | ||
56 | |||
57 | static char *client_user = NULL; /* Used to fill in remote user for PAM */ | ||
58 | |||
59 | struct AuthMethod1 { | ||
60 | int type; | ||
61 | char *name; | ||
62 | int *enabled; | ||
63 | int (*method)(Authctxt *); | ||
64 | }; | ||
65 | |||
66 | const struct AuthMethod1 auth1_methods[] = { | ||
67 | { | ||
68 | SSH_CMSG_AUTH_PASSWORD, "password", | ||
69 | &options.password_authentication, auth1_process_password | ||
70 | }, | ||
71 | { | ||
72 | SSH_CMSG_AUTH_RSA, "rsa", | ||
73 | &options.rsa_authentication, auth1_process_rsa | ||
74 | }, | ||
75 | { | ||
76 | SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa", | ||
77 | &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa | ||
78 | }, | ||
79 | { | ||
80 | SSH_CMSG_AUTH_TIS, "challenge-response", | ||
81 | &options.challenge_response_authentication, | ||
82 | auth1_process_tis_challenge | ||
83 | }, | ||
84 | { | ||
85 | SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response", | ||
86 | &options.challenge_response_authentication, | ||
87 | auth1_process_tis_response | ||
88 | }, | ||
89 | { -1, NULL, NULL, NULL} | ||
90 | }; | ||
91 | |||
92 | static const struct AuthMethod1 | ||
93 | *lookup_authmethod1(int type) | ||
94 | { | ||
95 | int i; | ||
96 | |||
97 | for (i = 0; auth1_methods[i].name != NULL; i++) | ||
98 | if (auth1_methods[i].type == type) | ||
99 | return (&(auth1_methods[i])); | ||
100 | |||
101 | return (NULL); | ||
102 | } | ||
103 | |||
104 | static char * | ||
105 | get_authname(int type) | ||
106 | { | ||
107 | const struct AuthMethod1 *a; | ||
108 | static char buf[64]; | ||
109 | |||
110 | if ((a = lookup_authmethod1(type)) != NULL) | ||
111 | return (a->name); | ||
112 | snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type); | ||
113 | return (buf); | ||
114 | } | ||
115 | |||
116 | /*ARGSUSED*/ | ||
117 | static int | ||
118 | auth1_process_password(Authctxt *authctxt) | ||
119 | { | ||
120 | int authenticated = 0; | ||
121 | char *password; | ||
122 | u_int dlen; | ||
123 | |||
124 | /* | ||
125 | * Read user password. It is in plain text, but was | ||
126 | * transmitted over the encrypted channel so it is | ||
127 | * not visible to an outside observer. | ||
128 | */ | ||
129 | password = packet_get_string(&dlen); | ||
130 | packet_check_eom(); | ||
131 | |||
132 | /* Try authentication with the password. */ | ||
133 | authenticated = PRIVSEP(auth_password(authctxt, password)); | ||
134 | |||
135 | explicit_bzero(password, dlen); | ||
136 | free(password); | ||
137 | |||
138 | return (authenticated); | ||
139 | } | ||
140 | |||
141 | /*ARGSUSED*/ | ||
142 | static int | ||
143 | auth1_process_rsa(Authctxt *authctxt) | ||
144 | { | ||
145 | int authenticated = 0; | ||
146 | BIGNUM *n; | ||
147 | |||
148 | /* RSA authentication requested. */ | ||
149 | if ((n = BN_new()) == NULL) | ||
150 | fatal("do_authloop: BN_new failed"); | ||
151 | packet_get_bignum(n); | ||
152 | packet_check_eom(); | ||
153 | authenticated = auth_rsa(authctxt, n); | ||
154 | BN_clear_free(n); | ||
155 | |||
156 | return (authenticated); | ||
157 | } | ||
158 | |||
159 | /*ARGSUSED*/ | ||
160 | static int | ||
161 | auth1_process_rhosts_rsa(Authctxt *authctxt) | ||
162 | { | ||
163 | int keybits, authenticated = 0; | ||
164 | u_int bits; | ||
165 | Key *client_host_key; | ||
166 | u_int ulen; | ||
167 | |||
168 | /* | ||
169 | * Get client user name. Note that we just have to | ||
170 | * trust the client; root on the client machine can | ||
171 | * claim to be any user. | ||
172 | */ | ||
173 | client_user = packet_get_cstring(&ulen); | ||
174 | |||
175 | /* Get the client host key. */ | ||
176 | client_host_key = key_new(KEY_RSA1); | ||
177 | bits = packet_get_int(); | ||
178 | packet_get_bignum(client_host_key->rsa->e); | ||
179 | packet_get_bignum(client_host_key->rsa->n); | ||
180 | |||
181 | keybits = BN_num_bits(client_host_key->rsa->n); | ||
182 | if (keybits < 0 || bits != (u_int)keybits) { | ||
183 | verbose("Warning: keysize mismatch for client_host_key: " | ||
184 | "actual %d, announced %d", | ||
185 | BN_num_bits(client_host_key->rsa->n), bits); | ||
186 | } | ||
187 | packet_check_eom(); | ||
188 | |||
189 | authenticated = auth_rhosts_rsa(authctxt, client_user, | ||
190 | client_host_key); | ||
191 | key_free(client_host_key); | ||
192 | |||
193 | auth_info(authctxt, "ruser %.100s", client_user); | ||
194 | |||
195 | return (authenticated); | ||
196 | } | ||
197 | |||
198 | /*ARGSUSED*/ | ||
199 | static int | ||
200 | auth1_process_tis_challenge(Authctxt *authctxt) | ||
201 | { | ||
202 | char *challenge; | ||
203 | |||
204 | if ((challenge = get_challenge(authctxt)) == NULL) | ||
205 | return (0); | ||
206 | |||
207 | debug("sending challenge '%s'", challenge); | ||
208 | packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); | ||
209 | packet_put_cstring(challenge); | ||
210 | free(challenge); | ||
211 | packet_send(); | ||
212 | packet_write_wait(); | ||
213 | |||
214 | return (-1); | ||
215 | } | ||
216 | |||
217 | /*ARGSUSED*/ | ||
218 | static int | ||
219 | auth1_process_tis_response(Authctxt *authctxt) | ||
220 | { | ||
221 | int authenticated = 0; | ||
222 | char *response; | ||
223 | u_int dlen; | ||
224 | |||
225 | response = packet_get_string(&dlen); | ||
226 | packet_check_eom(); | ||
227 | authenticated = verify_response(authctxt, response); | ||
228 | explicit_bzero(response, dlen); | ||
229 | free(response); | ||
230 | |||
231 | return (authenticated); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * read packets, try to authenticate the user and | ||
236 | * return only if authentication is successful | ||
237 | */ | ||
238 | static void | ||
239 | do_authloop(Authctxt *authctxt) | ||
240 | { | ||
241 | int authenticated = 0; | ||
242 | int prev = 0, type = 0; | ||
243 | const struct AuthMethod1 *meth; | ||
244 | |||
245 | debug("Attempting authentication for %s%.100s.", | ||
246 | authctxt->valid ? "" : "invalid user ", authctxt->user); | ||
247 | |||
248 | /* If the user has no password, accept authentication immediately. */ | ||
249 | if (options.permit_empty_passwd && options.password_authentication && | ||
250 | #ifdef KRB5 | ||
251 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && | ||
252 | #endif | ||
253 | PRIVSEP(auth_password(authctxt, ""))) { | ||
254 | #ifdef USE_PAM | ||
255 | if (options.use_pam && (PRIVSEP(do_pam_account()))) | ||
256 | #endif | ||
257 | { | ||
258 | auth_log(authctxt, 1, 0, "without authentication", | ||
259 | NULL); | ||
260 | return; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | /* Indicate that authentication is needed. */ | ||
265 | packet_start(SSH_SMSG_FAILURE); | ||
266 | packet_send(); | ||
267 | packet_write_wait(); | ||
268 | |||
269 | for (;;) { | ||
270 | /* default to fail */ | ||
271 | authenticated = 0; | ||
272 | |||
273 | |||
274 | /* Get a packet from the client. */ | ||
275 | prev = type; | ||
276 | type = packet_read(); | ||
277 | |||
278 | /* | ||
279 | * If we started challenge-response authentication but the | ||
280 | * next packet is not a response to our challenge, release | ||
281 | * the resources allocated by get_challenge() (which would | ||
282 | * normally have been released by verify_response() had we | ||
283 | * received such a response) | ||
284 | */ | ||
285 | if (prev == SSH_CMSG_AUTH_TIS && | ||
286 | type != SSH_CMSG_AUTH_TIS_RESPONSE) | ||
287 | abandon_challenge_response(authctxt); | ||
288 | |||
289 | if (authctxt->failures >= options.max_authtries) | ||
290 | goto skip; | ||
291 | if ((meth = lookup_authmethod1(type)) == NULL) { | ||
292 | logit("Unknown message during authentication: " | ||
293 | "type %d", type); | ||
294 | goto skip; | ||
295 | } | ||
296 | |||
297 | if (!*(meth->enabled)) { | ||
298 | verbose("%s authentication disabled.", meth->name); | ||
299 | goto skip; | ||
300 | } | ||
301 | |||
302 | authenticated = meth->method(authctxt); | ||
303 | if (authenticated == -1) | ||
304 | continue; /* "postponed" */ | ||
305 | |||
306 | #ifdef BSD_AUTH | ||
307 | if (authctxt->as) { | ||
308 | auth_close(authctxt->as); | ||
309 | authctxt->as = NULL; | ||
310 | } | ||
311 | #endif | ||
312 | if (!authctxt->valid && authenticated) | ||
313 | fatal("INTERNAL ERROR: authenticated invalid user %s", | ||
314 | authctxt->user); | ||
315 | |||
316 | #ifdef _UNICOS | ||
317 | if (authenticated && cray_access_denied(authctxt->user)) { | ||
318 | authenticated = 0; | ||
319 | fatal("Access denied for user %s.",authctxt->user); | ||
320 | } | ||
321 | #endif /* _UNICOS */ | ||
322 | |||
323 | #ifndef HAVE_CYGWIN | ||
324 | /* Special handling for root */ | ||
325 | if (authenticated && authctxt->pw->pw_uid == 0 && | ||
326 | !auth_root_allowed(meth->name)) { | ||
327 | authenticated = 0; | ||
328 | # ifdef SSH_AUDIT_EVENTS | ||
329 | PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED)); | ||
330 | # endif | ||
331 | } | ||
332 | #endif | ||
333 | |||
334 | #ifdef USE_PAM | ||
335 | if (options.use_pam && authenticated && | ||
336 | !PRIVSEP(do_pam_account())) { | ||
337 | char *msg; | ||
338 | size_t len; | ||
339 | |||
340 | error("Access denied for user %s by PAM account " | ||
341 | "configuration", authctxt->user); | ||
342 | len = buffer_len(&loginmsg); | ||
343 | buffer_append(&loginmsg, "\0", 1); | ||
344 | msg = buffer_ptr(&loginmsg); | ||
345 | /* strip trailing newlines */ | ||
346 | if (len > 0) | ||
347 | while (len > 0 && msg[--len] == '\n') | ||
348 | msg[len] = '\0'; | ||
349 | else | ||
350 | msg = "Access denied."; | ||
351 | packet_disconnect("%s", msg); | ||
352 | } | ||
353 | #endif | ||
354 | |||
355 | skip: | ||
356 | /* Log before sending the reply */ | ||
357 | auth_log(authctxt, authenticated, 0, get_authname(type), NULL); | ||
358 | |||
359 | free(client_user); | ||
360 | client_user = NULL; | ||
361 | |||
362 | if (authenticated) | ||
363 | return; | ||
364 | |||
365 | if (++authctxt->failures >= options.max_authtries) { | ||
366 | #ifdef SSH_AUDIT_EVENTS | ||
367 | PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); | ||
368 | #endif | ||
369 | auth_maxtries_exceeded(authctxt); | ||
370 | } | ||
371 | |||
372 | packet_start(SSH_SMSG_FAILURE); | ||
373 | packet_send(); | ||
374 | packet_write_wait(); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * Performs authentication of an incoming connection. Session key has already | ||
380 | * been exchanged and encryption is enabled. | ||
381 | */ | ||
382 | void | ||
383 | do_authentication(Authctxt *authctxt) | ||
384 | { | ||
385 | u_int ulen; | ||
386 | char *user, *style = NULL; | ||
387 | |||
388 | /* Get the name of the user that we wish to log in as. */ | ||
389 | packet_read_expect(SSH_CMSG_USER); | ||
390 | |||
391 | /* Get the user name. */ | ||
392 | user = packet_get_cstring(&ulen); | ||
393 | packet_check_eom(); | ||
394 | |||
395 | if ((style = strchr(user, ':')) != NULL) | ||
396 | *style++ = '\0'; | ||
397 | |||
398 | authctxt->user = user; | ||
399 | authctxt->style = style; | ||
400 | |||
401 | /* Verify that the user is a valid user. */ | ||
402 | if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) | ||
403 | authctxt->valid = 1; | ||
404 | else { | ||
405 | debug("do_authentication: invalid user %s", user); | ||
406 | authctxt->pw = fakepw(); | ||
407 | } | ||
408 | |||
409 | /* Configuration may have changed as a result of Match */ | ||
410 | if (options.num_auth_methods != 0) | ||
411 | fatal("AuthenticationMethods is not supported with SSH " | ||
412 | "protocol 1"); | ||
413 | |||
414 | setproctitle("%s%s", authctxt->valid ? user : "unknown", | ||
415 | use_privsep ? " [net]" : ""); | ||
416 | |||
417 | #ifdef USE_PAM | ||
418 | if (options.use_pam) | ||
419 | PRIVSEP(start_pam(authctxt)); | ||
420 | #endif | ||
421 | |||
422 | /* | ||
423 | * If we are not running as root, the user must have the same uid as | ||
424 | * the server. | ||
425 | */ | ||
426 | #ifndef HAVE_CYGWIN | ||
427 | if (!use_privsep && getuid() != 0 && authctxt->pw && | ||
428 | authctxt->pw->pw_uid != getuid()) | ||
429 | packet_disconnect("Cannot change user when server not running as root."); | ||
430 | #endif | ||
431 | |||
432 | /* | ||
433 | * Loop until the user has been authenticated or the connection is | ||
434 | * closed, do_authloop() returns only if authentication is successful | ||
435 | */ | ||
436 | do_authloop(authctxt); | ||
437 | |||
438 | /* The user has been authenticated and accepted. */ | ||
439 | packet_start(SSH_SMSG_SUCCESS); | ||
440 | packet_send(); | ||
441 | packet_write_wait(); | ||
442 | } | ||
443 | |||
444 | #endif /* WITH_SSH1 */ | ||