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