auth1.c revision 126277
1/* 2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * All rights reserved 4 * 5 * As far as I am concerned, the code I have written for this software 6 * can be used freely for any purpose. Any derived versions of this 7 * software must be clearly marked as such, and if the derived work is 8 * incompatible with the protocol description in the RFC file, it must be 9 * called by a name other than "ssh" or "Secure Shell". 10 */ 11 12#include "includes.h" 13RCSID("$OpenBSD: auth1.c,v 1.55 2003/11/08 16:02:40 jakob Exp $"); 14RCSID("$FreeBSD: head/crypto/openssh/auth1.c 126277 2004-02-26 10:52:33Z des $"); 15 16#include "xmalloc.h" 17#include "rsa.h" 18#include "ssh1.h" 19#include "packet.h" 20#include "buffer.h" 21#include "mpaux.h" 22#include "log.h" 23#include "servconf.h" 24#include "compat.h" 25#include "auth.h" 26#include "channels.h" 27#include "session.h" 28#include "uidswap.h" 29#include "monitor_wrap.h" 30 31/* import */ 32extern ServerOptions options; 33 34/* 35 * convert ssh auth msg type into description 36 */ 37static char * 38get_authname(int type) 39{ 40 static char buf[1024]; 41 switch (type) { 42 case SSH_CMSG_AUTH_PASSWORD: 43 return "password"; 44 case SSH_CMSG_AUTH_RSA: 45 return "rsa"; 46 case SSH_CMSG_AUTH_RHOSTS_RSA: 47 return "rhosts-rsa"; 48 case SSH_CMSG_AUTH_RHOSTS: 49 return "rhosts"; 50 case SSH_CMSG_AUTH_TIS: 51 case SSH_CMSG_AUTH_TIS_RESPONSE: 52 return "challenge-response"; 53 } 54 snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); 55 return buf; 56} 57 58/* 59 * read packets, try to authenticate the user and 60 * return only if authentication is successful 61 */ 62static void 63do_authloop(Authctxt *authctxt) 64{ 65 int authenticated = 0; 66 u_int bits; 67 Key *client_host_key; 68 BIGNUM *n; 69 char *client_user, *password; 70 char info[1024]; 71 u_int dlen; 72 u_int ulen; 73 int prev, type = 0; 74 struct passwd *pw = authctxt->pw; 75 76 debug("Attempting authentication for %s%.100s.", 77 authctxt->valid ? "" : "illegal user ", authctxt->user); 78 79 /* If the user has no password, accept authentication immediately. */ 80 if (options.password_authentication && 81#ifdef KRB5 82 (!options.kerberos_authentication || options.kerberos_or_local_passwd) && 83#endif 84 PRIVSEP(auth_password(authctxt, ""))) { 85 auth_log(authctxt, 1, "without authentication", ""); 86 return; 87 } 88 89 /* Indicate that authentication is needed. */ 90 packet_start(SSH_SMSG_FAILURE); 91 packet_send(); 92 packet_write_wait(); 93 94 client_user = NULL; 95 96 for (;;) { 97 /* default to fail */ 98 authenticated = 0; 99 100 info[0] = '\0'; 101 102 /* Get a packet from the client. */ 103 prev = type; 104 type = packet_read(); 105 106 /* 107 * If we started challenge-response authentication but the 108 * next packet is not a response to our challenge, release 109 * the resources allocated by get_challenge() (which would 110 * normally have been released by verify_response() had we 111 * received such a response) 112 */ 113 if (prev == SSH_CMSG_AUTH_TIS && 114 type != SSH_CMSG_AUTH_TIS_RESPONSE) 115 abandon_challenge_response(authctxt); 116 117 /* Process the packet. */ 118 switch (type) { 119 case SSH_CMSG_AUTH_RHOSTS_RSA: 120 if (!options.rhosts_rsa_authentication) { 121 verbose("Rhosts with RSA authentication disabled."); 122 break; 123 } 124 /* 125 * Get client user name. Note that we just have to 126 * trust the client; root on the client machine can 127 * claim to be any user. 128 */ 129 client_user = packet_get_string(&ulen); 130 131 /* Get the client host key. */ 132 client_host_key = key_new(KEY_RSA1); 133 bits = packet_get_int(); 134 packet_get_bignum(client_host_key->rsa->e); 135 packet_get_bignum(client_host_key->rsa->n); 136 137 if (bits != BN_num_bits(client_host_key->rsa->n)) 138 verbose("Warning: keysize mismatch for client_host_key: " 139 "actual %d, announced %d", 140 BN_num_bits(client_host_key->rsa->n), bits); 141 packet_check_eom(); 142 143 authenticated = auth_rhosts_rsa(authctxt, client_user, 144 client_host_key); 145 key_free(client_host_key); 146 147 snprintf(info, sizeof info, " ruser %.100s", client_user); 148 break; 149 150 case SSH_CMSG_AUTH_RSA: 151 if (!options.rsa_authentication) { 152 verbose("RSA authentication disabled."); 153 break; 154 } 155 /* RSA authentication requested. */ 156 if ((n = BN_new()) == NULL) 157 fatal("do_authloop: BN_new failed"); 158 packet_get_bignum(n); 159 packet_check_eom(); 160 authenticated = auth_rsa(authctxt, n); 161 BN_clear_free(n); 162 break; 163 164 case SSH_CMSG_AUTH_PASSWORD: 165 if (!options.password_authentication) { 166 verbose("Password authentication disabled."); 167 break; 168 } 169 /* 170 * Read user password. It is in plain text, but was 171 * transmitted over the encrypted channel so it is 172 * not visible to an outside observer. 173 */ 174 password = packet_get_string(&dlen); 175 packet_check_eom(); 176 177 /* Try authentication with the password. */ 178 authenticated = PRIVSEP(auth_password(authctxt, password)); 179 180 memset(password, 0, strlen(password)); 181 xfree(password); 182 break; 183 184 case SSH_CMSG_AUTH_TIS: 185 debug("rcvd SSH_CMSG_AUTH_TIS"); 186 if (options.challenge_response_authentication == 1) { 187 char *challenge = get_challenge(authctxt); 188 if (challenge != NULL) { 189 debug("sending challenge '%s'", challenge); 190 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); 191 packet_put_cstring(challenge); 192 xfree(challenge); 193 packet_send(); 194 packet_write_wait(); 195 continue; 196 } 197 } 198 break; 199 case SSH_CMSG_AUTH_TIS_RESPONSE: 200 debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); 201 if (options.challenge_response_authentication == 1) { 202 char *response = packet_get_string(&dlen); 203 packet_check_eom(); 204 authenticated = verify_response(authctxt, response); 205 memset(response, 'r', dlen); 206 xfree(response); 207 } 208 break; 209 210 default: 211 /* 212 * Any unknown messages will be ignored (and failure 213 * returned) during authentication. 214 */ 215 logit("Unknown message during authentication: type %d", type); 216 break; 217 } 218#ifdef BSD_AUTH 219 if (authctxt->as) { 220 auth_close(authctxt->as); 221 authctxt->as = NULL; 222 } 223#endif 224 if (!authctxt->valid && authenticated) 225 fatal("INTERNAL ERROR: authenticated invalid user %s", 226 authctxt->user); 227 228#ifdef _UNICOS 229 if (authenticated && cray_access_denied(authctxt->user)) { 230 authenticated = 0; 231 fatal("Access denied for user %s.",authctxt->user); 232 } 233#endif /* _UNICOS */ 234 235#ifdef HAVE_CYGWIN 236 if (authenticated && 237 !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) { 238 packet_disconnect("Authentication rejected for uid %d.", 239 pw == NULL ? -1 : pw->pw_uid); 240 authenticated = 0; 241 } 242#else 243 /* Special handling for root */ 244 if (authenticated && authctxt->pw->pw_uid == 0 && 245 !auth_root_allowed(get_authname(type))) 246 authenticated = 0; 247#endif 248 249#ifdef USE_PAM 250 if (options.use_pam && authenticated && 251 !PRIVSEP(do_pam_account())) 252 authenticated = 0; 253#endif 254 255 /* Log before sending the reply */ 256 auth_log(authctxt, authenticated, get_authname(type), info); 257 258 if (client_user != NULL) { 259 xfree(client_user); 260 client_user = NULL; 261 } 262 263 if (authenticated) 264 return; 265 266 if (authctxt->failures++ > AUTH_FAIL_MAX) 267 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 268 269 packet_start(SSH_SMSG_FAILURE); 270 packet_send(); 271 packet_write_wait(); 272 } 273} 274 275/* 276 * Performs authentication of an incoming connection. Session key has already 277 * been exchanged and encryption is enabled. 278 */ 279void 280do_authentication(Authctxt *authctxt) 281{ 282 u_int ulen; 283 char *user, *style = NULL; 284 285 /* Get the name of the user that we wish to log in as. */ 286 packet_read_expect(SSH_CMSG_USER); 287 288 /* Get the user name. */ 289 user = packet_get_string(&ulen); 290 packet_check_eom(); 291 292 if ((style = strchr(user, ':')) != NULL) 293 *style++ = '\0'; 294 295 authctxt->user = user; 296 authctxt->style = style; 297 298 /* Verify that the user is a valid user. */ 299 if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) 300 authctxt->valid = 1; 301 else { 302 debug("do_authentication: illegal user %s", user); 303 authctxt->pw = fakepw(); 304 } 305 306 setproctitle("%s%s", authctxt->pw ? user : "unknown", 307 use_privsep ? " [net]" : ""); 308 309#ifdef USE_PAM 310 if (options.use_pam) 311 PRIVSEP(start_pam(user)); 312#endif 313 314 /* 315 * If we are not running as root, the user must have the same uid as 316 * the server. (Unless you are running Windows) 317 */ 318#ifndef HAVE_CYGWIN 319 if (!use_privsep && getuid() != 0 && authctxt->pw && 320 authctxt->pw->pw_uid != getuid()) 321 packet_disconnect("Cannot change user when server not running as root."); 322#endif 323 324 /* 325 * Loop until the user has been authenticated or the connection is 326 * closed, do_authloop() returns only if authentication is successful 327 */ 328 do_authloop(authctxt); 329 330 /* The user has been authenticated and accepted. */ 331 packet_start(SSH_SMSG_SUCCESS); 332 packet_send(); 333 packet_write_wait(); 334} 335