blob: 3720a7d28447e5b4d2bb27806ac6fa74ce94cd8d [file] [log] [blame]
Damien Millereba71ba2000-04-29 23:57:08 +10001/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved
4 */
5
6#include "includes.h"
Damien Millerad833b32000-08-23 10:46:23 +10007RCSID("$OpenBSD: auth1.c,v 1.3 2000/08/20 18:42:40 millert Exp $");
Damien Millereba71ba2000-04-29 23:57:08 +10008
9#include "xmalloc.h"
10#include "rsa.h"
11#include "ssh.h"
12#include "packet.h"
13#include "buffer.h"
14#include "cipher.h"
15#include "mpaux.h"
16#include "servconf.h"
17#include "compat.h"
18#include "auth.h"
19#include "session.h"
20
Damien Millerb8c656e2000-06-28 15:22:41 +100021#ifdef HAVE_OSF_SIA
22# include <sia.h>
23# include <siad.h>
24#endif
25
Damien Millerbac2d8a2000-09-05 16:13:06 +110026#ifdef HAVE_CYGWIN
27#include <windows.h>
28#define is_winnt (GetVersion() < 0x80000000)
29#endif
30
Damien Millereba71ba2000-04-29 23:57:08 +100031/* import */
32extern ServerOptions options;
33extern char *forced_command;
Damien Millerfe668e42000-07-08 10:44:13 +100034#ifdef HAVE_OSF_SIA
35extern int saved_argc;
36extern char **saved_argv;
37#endif /* HAVE_OSF_SIA */
Damien Millereba71ba2000-04-29 23:57:08 +100038
39/*
40 * convert ssh auth msg type into description
41 */
42char *
43get_authname(int type)
44{
45 static char buf[1024];
46 switch (type) {
47 case SSH_CMSG_AUTH_PASSWORD:
48 return "password";
49 case SSH_CMSG_AUTH_RSA:
50 return "rsa";
51 case SSH_CMSG_AUTH_RHOSTS_RSA:
52 return "rhosts-rsa";
53 case SSH_CMSG_AUTH_RHOSTS:
54 return "rhosts";
55#ifdef KRB4
56 case SSH_CMSG_AUTH_KERBEROS:
57 return "kerberos";
58#endif
59#ifdef SKEY
60 case SSH_CMSG_AUTH_TIS_RESPONSE:
61 return "s/key";
62#endif
63 }
64 snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
65 return buf;
66}
67
68/*
69 * The user does not exist or access is denied,
70 * but fake indication that authentication is needed.
71 */
72void
73do_fake_authloop1(char *user)
74{
75 int attempt = 0;
76
77 log("Faking authloop for illegal user %.200s from %.200s port %d",
78 user,
79 get_remote_ipaddr(),
80 get_remote_port());
81
82#ifdef WITH_AIXAUTHENTICATE
Damien Millerd2c208a2000-05-17 22:00:02 +100083 loginfailed(user,get_canonical_hostname(),"ssh");
Damien Millereba71ba2000-04-29 23:57:08 +100084#endif /* WITH_AIXAUTHENTICATE */
85
86 /* Indicate that authentication is needed. */
87 packet_start(SSH_SMSG_FAILURE);
88 packet_send();
89 packet_write_wait();
90
91 /*
92 * Keep reading packets, and always respond with a failure. This is
93 * to avoid disclosing whether such a user really exists.
94 */
95 for (attempt = 1;; attempt++) {
96 /* Read a packet. This will not return if the client disconnects. */
97 int plen;
98#ifndef SKEY
99 (void)packet_read(&plen);
100#else /* SKEY */
101 int type = packet_read(&plen);
102 unsigned int dlen;
103 char *password, *skeyinfo;
104 password = NULL;
105 /* Try to send a fake s/key challenge. */
106 if (options.skey_authentication == 1 &&
107 (skeyinfo = skey_fake_keyinfo(user)) != NULL) {
108 if (type == SSH_CMSG_AUTH_TIS) {
109 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
110 packet_put_string(skeyinfo, strlen(skeyinfo));
111 packet_send();
112 packet_write_wait();
113 continue;
114 } else if (type == SSH_CMSG_AUTH_PASSWORD &&
115 options.password_authentication &&
116 (password = packet_get_string(&dlen)) != NULL &&
117 dlen == 5 &&
118 strncasecmp(password, "s/key", 5) == 0 ) {
119 packet_send_debug(skeyinfo);
120 }
121 }
122 if (password != NULL)
123 xfree(password);
124#endif
125 if (attempt > AUTH_FAIL_MAX)
126 packet_disconnect(AUTH_FAIL_MSG, user);
127
128 /*
129 * Send failure. This should be indistinguishable from a
130 * failed authentication.
131 */
132 packet_start(SSH_SMSG_FAILURE);
133 packet_send();
134 packet_write_wait();
135 }
136 /* NOTREACHED */
137 abort();
138}
139
140/*
141 * read packets and try to authenticate local user *pw.
142 * return if authentication is successfull
143 */
144void
145do_authloop(struct passwd * pw)
146{
147 int attempt = 0;
148 unsigned int bits;
149 RSA *client_host_key;
150 BIGNUM *n;
151 char *client_user = NULL, *password = NULL;
152 char user[1024];
153 unsigned int dlen;
154 int plen, nlen, elen;
155 unsigned int ulen;
156 int type = 0;
157 void (*authlog) (const char *fmt,...) = verbose;
158
159 /* Indicate that authentication is needed. */
160 packet_start(SSH_SMSG_FAILURE);
161 packet_send();
162 packet_write_wait();
163
164 for (attempt = 1;; attempt++) {
165 int authenticated = 0;
166 strlcpy(user, "", sizeof user);
167
168 /* Get a packet from the client. */
169 type = packet_read(&plen);
170
171 /* Process the packet. */
172 switch (type) {
173#ifdef AFS
174 case SSH_CMSG_HAVE_KERBEROS_TGT:
175 if (!options.kerberos_tgt_passing) {
176 /* packet_get_all(); */
177 verbose("Kerberos tgt passing disabled.");
178 break;
179 } else {
180 /* Accept Kerberos tgt. */
181 char *tgt = packet_get_string(&dlen);
182 packet_integrity_check(plen, 4 + dlen, type);
183 if (!auth_kerberos_tgt(pw, tgt))
184 verbose("Kerberos tgt REFUSED for %s", pw->pw_name);
185 xfree(tgt);
186 }
187 continue;
188
189 case SSH_CMSG_HAVE_AFS_TOKEN:
190 if (!options.afs_token_passing || !k_hasafs()) {
191 /* packet_get_all(); */
192 verbose("AFS token passing disabled.");
193 break;
194 } else {
195 /* Accept AFS token. */
196 char *token_string = packet_get_string(&dlen);
197 packet_integrity_check(plen, 4 + dlen, type);
198 if (!auth_afs_token(pw, token_string))
199 verbose("AFS token REFUSED for %s", pw->pw_name);
200 xfree(token_string);
201 }
202 continue;
203#endif /* AFS */
204#ifdef KRB4
205 case SSH_CMSG_AUTH_KERBEROS:
206 if (!options.kerberos_authentication) {
207 /* packet_get_all(); */
208 verbose("Kerberos authentication disabled.");
209 break;
210 } else {
211 /* Try Kerberos v4 authentication. */
212 KTEXT_ST auth;
213 char *tkt_user = NULL;
214 char *kdata = packet_get_string((unsigned int *) &auth.length);
215 packet_integrity_check(plen, 4 + auth.length, type);
216
217 if (auth.length < MAX_KTXT_LEN)
218 memcpy(auth.dat, kdata, auth.length);
219 xfree(kdata);
220
221 authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);
222
223 if (authenticated) {
224 snprintf(user, sizeof user, " tktuser %s", tkt_user);
225 xfree(tkt_user);
226 }
227 }
228 break;
229#endif /* KRB4 */
230
231 case SSH_CMSG_AUTH_RHOSTS:
232 if (!options.rhosts_authentication) {
233 verbose("Rhosts authentication disabled.");
234 break;
235 }
236 /*
237 * Get client user name. Note that we just have to
238 * trust the client; this is one reason why rhosts
239 * authentication is insecure. (Another is
240 * IP-spoofing on a local network.)
241 */
242 client_user = packet_get_string(&ulen);
243 packet_integrity_check(plen, 4 + ulen, type);
244
245 /* Try to authenticate using /etc/hosts.equiv and
246 .rhosts. */
247 authenticated = auth_rhosts(pw, client_user);
248
249 snprintf(user, sizeof user, " ruser %s", client_user);
250 break;
251
252 case SSH_CMSG_AUTH_RHOSTS_RSA:
253 if (!options.rhosts_rsa_authentication) {
254 verbose("Rhosts with RSA authentication disabled.");
255 break;
256 }
257 /*
258 * Get client user name. Note that we just have to
259 * trust the client; root on the client machine can
260 * claim to be any user.
261 */
262 client_user = packet_get_string(&ulen);
263
264 /* Get the client host key. */
265 client_host_key = RSA_new();
266 if (client_host_key == NULL)
267 fatal("RSA_new failed");
268 client_host_key->e = BN_new();
269 client_host_key->n = BN_new();
270 if (client_host_key->e == NULL || client_host_key->n == NULL)
271 fatal("BN_new failed");
272 bits = packet_get_int();
273 packet_get_bignum(client_host_key->e, &elen);
274 packet_get_bignum(client_host_key->n, &nlen);
275
276 if (bits != BN_num_bits(client_host_key->n))
Damien Millerbd483e72000-04-30 10:00:53 +1000277 log("Warning: keysize mismatch for client_host_key: "
278 "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);
Damien Millereba71ba2000-04-29 23:57:08 +1000279 packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);
280
281 authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);
282 RSA_free(client_host_key);
283
284 snprintf(user, sizeof user, " ruser %s", client_user);
285 break;
286
287 case SSH_CMSG_AUTH_RSA:
288 if (!options.rsa_authentication) {
289 verbose("RSA authentication disabled.");
290 break;
291 }
292 /* RSA authentication requested. */
293 n = BN_new();
294 packet_get_bignum(n, &nlen);
295 packet_integrity_check(plen, nlen, type);
296 authenticated = auth_rsa(pw, n);
297 BN_clear_free(n);
298 break;
299
300 case SSH_CMSG_AUTH_PASSWORD:
301 if (!options.password_authentication) {
302 verbose("Password authentication disabled.");
303 break;
304 }
305 /*
306 * Read user password. It is in plain text, but was
307 * transmitted over the encrypted channel so it is
308 * not visible to an outside observer.
309 */
310 password = packet_get_string(&dlen);
311 packet_integrity_check(plen, 4 + dlen, type);
312
313#ifdef USE_PAM
314 /* Do PAM auth with password */
315 authenticated = auth_pam_password(pw, password);
Damien Millerb8c656e2000-06-28 15:22:41 +1000316#elif defined(HAVE_OSF_SIA)
317 /* Do SIA auth with password */
Damien Millerb8c656e2000-06-28 15:22:41 +1000318 if (sia_validate_user(NULL, saved_argc, saved_argv,
319 get_canonical_hostname(), pw->pw_name, NULL, 0,
320 NULL, password) == SIASUCCESS) {
321 authenticated = 1;
322 }
323#else /* !USE_PAM && !HAVE_OSF_SIA */
Damien Millereba71ba2000-04-29 23:57:08 +1000324 /* Try authentication with the password. */
325 authenticated = auth_password(pw, password);
326#endif /* USE_PAM */
327
328 memset(password, 0, strlen(password));
329 xfree(password);
330 break;
331
332#ifdef SKEY
333 case SSH_CMSG_AUTH_TIS:
334 debug("rcvd SSH_CMSG_AUTH_TIS");
335 if (options.skey_authentication == 1) {
336 char *skeyinfo = skey_keyinfo(pw->pw_name);
337 if (skeyinfo == NULL) {
338 debug("generating fake skeyinfo for %.100s.", pw->pw_name);
339 skeyinfo = skey_fake_keyinfo(pw->pw_name);
340 }
341 if (skeyinfo != NULL) {
342 /* we send our s/key- in tis-challenge messages */
343 debug("sending challenge '%s'", skeyinfo);
344 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
345 packet_put_string(skeyinfo, strlen(skeyinfo));
346 packet_send();
347 packet_write_wait();
348 continue;
349 }
350 }
351 break;
352 case SSH_CMSG_AUTH_TIS_RESPONSE:
353 debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
354 if (options.skey_authentication == 1) {
355 char *response = packet_get_string(&dlen);
356 debug("skey response == '%s'", response);
357 packet_integrity_check(plen, 4 + dlen, type);
358 authenticated = (skey_haskey(pw->pw_name) == 0 &&
359 skey_passcheck(pw->pw_name, response) != -1);
360 xfree(response);
361 }
362 break;
363#else
364 case SSH_CMSG_AUTH_TIS:
365 /* TIS Authentication is unsupported */
366 log("TIS authentication unsupported.");
367 break;
368#endif
369
370 default:
371 /*
372 * Any unknown messages will be ignored (and failure
373 * returned) during authentication.
374 */
375 log("Unknown message during authentication: type %d", type);
376 break;
377 }
378
Damien Millerbac2d8a2000-09-05 16:13:06 +1100379#ifdef HAVE_CYGWIN
380 /*
381 * The only authentication which is able to change the user
382 * context on NT systems is the password authentication. So
383 * we deny all requsts for changing the user context if another
384 * authentication method is used.
385 * This may change in future when a special openssh
386 * subauthentication package is available.
387 */
388 if (is_winnt && type != SSH_CMSG_AUTH_PASSWORD &&
389 authenticated && geteuid() != pw->pw_uid) {
390 packet_disconnect("Authentication rejected for uid %d.",
391 (int) pw->pw_uid);
392 authenticated = 0;
393 }
394#endif
395
Damien Millereba71ba2000-04-29 23:57:08 +1000396 /*
397 * Check if the user is logging in as root and root logins
398 * are disallowed.
399 * Note that root login is allowed for forced commands.
400 */
401 if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {
402 if (forced_command) {
403 log("Root login accepted for forced command.");
404 } else {
405 authenticated = 0;
406 log("ROOT LOGIN REFUSED FROM %.200s",
407 get_canonical_hostname());
408 }
409 }
410
411 /* Raise logging level */
412 if (authenticated ||
413 attempt == AUTH_FAIL_LOG ||
414 type == SSH_CMSG_AUTH_PASSWORD)
415 authlog = log;
416
417 authlog("%s %s for %.200s from %.200s port %d%s",
418 authenticated ? "Accepted" : "Failed",
419 get_authname(type),
420 pw->pw_uid == 0 ? "ROOT" : pw->pw_name,
421 get_remote_ipaddr(),
422 get_remote_port(),
423 user);
424
425#ifdef USE_PAM
426 if (authenticated) {
427 if (!do_pam_account(pw->pw_name, client_user)) {
428 if (client_user != NULL) {
429 xfree(client_user);
430 client_user = NULL;
431 }
432 do_fake_authloop1(pw->pw_name);
433 }
434 return;
435 }
436#else /* USE_PAM */
437 if (authenticated) {
438 return;
439 }
440#endif /* USE_PAM */
441
442 if (client_user != NULL) {
443 xfree(client_user);
444 client_user = NULL;
445 }
446
Damien Millerd2c208a2000-05-17 22:00:02 +1000447 if (attempt > AUTH_FAIL_MAX) {
448#ifdef WITH_AIXAUTHENTICATE
449 loginfailed(pw->pw_name,get_canonical_hostname(),"ssh");
450#endif /* WITH_AIXAUTHENTICATE */
Damien Millereba71ba2000-04-29 23:57:08 +1000451 packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);
Damien Millerd2c208a2000-05-17 22:00:02 +1000452 }
Damien Millereba71ba2000-04-29 23:57:08 +1000453
454 /* Send a message indicating that the authentication attempt failed. */
455 packet_start(SSH_SMSG_FAILURE);
456 packet_send();
457 packet_write_wait();
458 }
459}
460
461/*
462 * Performs authentication of an incoming connection. Session key has already
463 * been exchanged and encryption is enabled.
464 */
465void
466do_authentication()
467{
468 struct passwd *pw, pwcopy;
469 int plen;
470 unsigned int ulen;
471 char *user;
472#ifdef WITH_AIXAUTHENTICATE
Damien Millerd2c208a2000-05-17 22:00:02 +1000473 extern char *aixloginmsg;
Damien Millereba71ba2000-04-29 23:57:08 +1000474#endif /* WITH_AIXAUTHENTICATE */
475
476 /* Get the name of the user that we wish to log in as. */
477 packet_read_expect(&plen, SSH_CMSG_USER);
478
479 /* Get the user name. */
480 user = packet_get_string(&ulen);
481 packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);
482
483 setproctitle("%s", user);
484
485#ifdef AFS
486 /* If machine has AFS, set process authentication group. */
487 if (k_hasafs()) {
488 k_setpag();
489 k_unlog();
490 }
491#endif /* AFS */
492
493 /* Verify that the user is a valid user. */
494 pw = getpwnam(user);
495 if (!pw || !allowed_user(pw))
496 do_fake_authloop1(user);
497 xfree(user);
498
499 /* Take a copy of the returned structure. */
500 memset(&pwcopy, 0, sizeof(pwcopy));
501 pwcopy.pw_name = xstrdup(pw->pw_name);
502 pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
503 pwcopy.pw_uid = pw->pw_uid;
504 pwcopy.pw_gid = pw->pw_gid;
Damien Millerad833b32000-08-23 10:46:23 +1000505#ifdef HAVE_PW_CLASS_IN_PASSWD
506 pwcopy.pw_class = xstrdup(pw->pw_class);
507#endif
Damien Millereba71ba2000-04-29 23:57:08 +1000508 pwcopy.pw_dir = xstrdup(pw->pw_dir);
509 pwcopy.pw_shell = xstrdup(pw->pw_shell);
510 pw = &pwcopy;
511
512#ifdef USE_PAM
513 start_pam(pw);
514#endif
515
Damien Millerbac2d8a2000-09-05 16:13:06 +1100516#ifndef HAVE_CYGWIN
Damien Millereba71ba2000-04-29 23:57:08 +1000517 /*
518 * If we are not running as root, the user must have the same uid as
519 * the server.
Damien Millerbac2d8a2000-09-05 16:13:06 +1100520 * Rule not valid on Windows systems.
Damien Millereba71ba2000-04-29 23:57:08 +1000521 */
522 if (getuid() != 0 && pw->pw_uid != getuid())
523 packet_disconnect("Cannot change user when server not running as root.");
Damien Millerbac2d8a2000-09-05 16:13:06 +1100524#endif
Damien Millereba71ba2000-04-29 23:57:08 +1000525
526 debug("Attempting authentication for %.100s.", pw->pw_name);
527
528 /* If the user has no password, accept authentication immediately. */
529 if (options.password_authentication &&
530#ifdef KRB4
531 (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
532#endif /* KRB4 */
533#ifdef USE_PAM
534 auth_pam_password(pw, "")) {
Damien Millerd8cfda62000-07-01 12:56:09 +1000535#elif defined(HAVE_OSF_SIA)
536 (sia_validate_user(NULL, saved_argc, saved_argv,
537 get_canonical_hostname(), pw->pw_name, NULL, 0, NULL,
538 "") == SIASUCCESS)) {
539#else /* !HAVE_OSF_SIA && !USE_PAM */
Damien Millereba71ba2000-04-29 23:57:08 +1000540 auth_password(pw, "")) {
541#endif /* USE_PAM */
542 /* Authentication with empty password succeeded. */
543 log("Login for user %s from %.100s, accepted without authentication.",
544 pw->pw_name, get_remote_ipaddr());
545 } else {
546 /* Loop until the user has been authenticated or the
547 connection is closed, do_authloop() returns only if
548 authentication is successfull */
549 do_authloop(pw);
550 }
551
552 /* The user has been authenticated and accepted. */
553#ifdef WITH_AIXAUTHENTICATE
Damien Millerd2c208a2000-05-17 22:00:02 +1000554 /* We don't have a pty yet, so just label the line as "ssh" */
555 if (loginsuccess(user,get_canonical_hostname(),"ssh",&aixloginmsg) < 0)
556 aixloginmsg = NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000557#endif /* WITH_AIXAUTHENTICATE */
558 packet_start(SSH_SMSG_SUCCESS);
559 packet_send();
560 packet_write_wait();
561
562 /* Perform session preparation. */
563 do_authenticated(pw);
564}