Home | History | Annotate | Download | only in openssh
      1 /* $OpenBSD: auth1.c,v 1.75 2010/08/31 09:58:37 djm Exp $ */
      2 /*
      3  * Copyright (c) 1995 Tatu Ylonen <ylo (at) 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 #include <sys/types.h>
     16 
     17 #include <stdarg.h>
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include <unistd.h>
     21 #include <pwd.h>
     22 
     23 #include "openbsd-compat/sys-queue.h"
     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 */
     45 extern ServerOptions options;
     46 extern Buffer loginmsg;
     47 
     48 static int auth1_process_password(Authctxt *, char *, size_t);
     49 static int auth1_process_rsa(Authctxt *, char *, size_t);
     50 static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
     51 static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
     52 static int auth1_process_tis_response(Authctxt *, char *, size_t);
     53 
     54 static char *client_user = NULL;    /* Used to fill in remote user for PAM */
     55 
     56 struct AuthMethod1 {
     57 	int type;
     58 	char *name;
     59 	int *enabled;
     60 	int (*method)(Authctxt *, char *, size_t);
     61 };
     62 
     63 const 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 
     89 static 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 
    101 static char *
    102 get_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*/
    114 static int
    115 auth1_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 #ifndef ANDROID
    131 	authenticated = PRIVSEP(auth_password(authctxt, password));
    132 
    133 #else
    134 	/* no password authentication in android */
    135 	authenticated = 0;
    136 #endif
    137 
    138 	memset(password, 0, dlen);
    139 	xfree(password);
    140 
    141 	return (authenticated);
    142 }
    143 
    144 /*ARGSUSED*/
    145 static int
    146 auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
    147 {
    148 	int authenticated = 0;
    149 	BIGNUM *n;
    150 
    151 	/* RSA authentication requested. */
    152 	if ((n = BN_new()) == NULL)
    153 		fatal("do_authloop: BN_new failed");
    154 	packet_get_bignum(n);
    155 	packet_check_eom();
    156 	authenticated = auth_rsa(authctxt, n);
    157 	BN_clear_free(n);
    158 
    159 	return (authenticated);
    160 }
    161 
    162 /*ARGSUSED*/
    163 static int
    164 auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
    165 {
    166 	int keybits, authenticated = 0;
    167 	u_int bits;
    168 	Key *client_host_key;
    169 	u_int ulen;
    170 
    171 	/*
    172 	 * Get client user name.  Note that we just have to
    173 	 * trust the client; root on the client machine can
    174 	 * claim to be any user.
    175 	 */
    176 	client_user = packet_get_cstring(&ulen);
    177 
    178 	/* Get the client host key. */
    179 	client_host_key = key_new(KEY_RSA1);
    180 	bits = packet_get_int();
    181 	packet_get_bignum(client_host_key->rsa->e);
    182 	packet_get_bignum(client_host_key->rsa->n);
    183 
    184 	keybits = BN_num_bits(client_host_key->rsa->n);
    185 	if (keybits < 0 || bits != (u_int)keybits) {
    186 		verbose("Warning: keysize mismatch for client_host_key: "
    187 		    "actual %d, announced %d",
    188 		    BN_num_bits(client_host_key->rsa->n), bits);
    189 	}
    190 	packet_check_eom();
    191 
    192 	authenticated = auth_rhosts_rsa(authctxt, client_user,
    193 	    client_host_key);
    194 	key_free(client_host_key);
    195 
    196 	snprintf(info, infolen, " ruser %.100s", client_user);
    197 
    198 	return (authenticated);
    199 }
    200 
    201 /*ARGSUSED*/
    202 static int
    203 auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
    204 {
    205 	char *challenge;
    206 
    207 	if ((challenge = get_challenge(authctxt)) == NULL)
    208 		return (0);
    209 
    210 	debug("sending challenge '%s'", challenge);
    211 	packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
    212 	packet_put_cstring(challenge);
    213 	xfree(challenge);
    214 	packet_send();
    215 	packet_write_wait();
    216 
    217 	return (-1);
    218 }
    219 
    220 /*ARGSUSED*/
    221 static int
    222 auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
    223 {
    224 	int authenticated = 0;
    225 	char *response;
    226 	u_int dlen;
    227 
    228 	response = packet_get_string(&dlen);
    229 	packet_check_eom();
    230 	authenticated = verify_response(authctxt, response);
    231 	memset(response, 'r', dlen);
    232 	xfree(response);
    233 
    234 	return (authenticated);
    235 }
    236 
    237 /*
    238  * read packets, try to authenticate the user and
    239  * return only if authentication is successful
    240  */
    241 static void
    242 do_authloop(Authctxt *authctxt)
    243 {
    244 	int authenticated = 0;
    245 	char info[1024];
    246 	int prev = 0, type = 0;
    247 	const struct AuthMethod1 *meth;
    248 
    249 	debug("Attempting authentication for %s%.100s.",
    250 	    authctxt->valid ? "" : "invalid user ", authctxt->user);
    251 
    252 	/* no password authentication in android */
    253 #ifndef ANDROID
    254 	/* If the user has no password, accept authentication immediately. */
    255 	if (options.permit_empty_passwd && options.password_authentication &&
    256 #ifdef KRB5
    257 	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
    258 #endif
    259 	    PRIVSEP(auth_password(authctxt, "")))
    260 #endif
    261 	    {
    262 #ifdef USE_PAM
    263 		if (options.use_pam && (PRIVSEP(do_pam_account())))
    264 #endif
    265 		{
    266 			auth_log(authctxt, 1, "without authentication", "");
    267 			return;
    268 		}
    269 	}
    270 
    271 	/* Indicate that authentication is needed. */
    272 	packet_start(SSH_SMSG_FAILURE);
    273 	packet_send();
    274 	packet_write_wait();
    275 
    276 	for (;;) {
    277 		/* default to fail */
    278 		authenticated = 0;
    279 
    280 		info[0] = '\0';
    281 
    282 		/* Get a packet from the client. */
    283 		prev = type;
    284 		type = packet_read();
    285 
    286 		/*
    287 		 * If we started challenge-response authentication but the
    288 		 * next packet is not a response to our challenge, release
    289 		 * the resources allocated by get_challenge() (which would
    290 		 * normally have been released by verify_response() had we
    291 		 * received such a response)
    292 		 */
    293 		if (prev == SSH_CMSG_AUTH_TIS &&
    294 		    type != SSH_CMSG_AUTH_TIS_RESPONSE)
    295 			abandon_challenge_response(authctxt);
    296 
    297 		if (authctxt->failures >= options.max_authtries)
    298 			goto skip;
    299 		if ((meth = lookup_authmethod1(type)) == NULL) {
    300 			logit("Unknown message during authentication: "
    301 			    "type %d", type);
    302 			goto skip;
    303 		}
    304 
    305 		if (!*(meth->enabled)) {
    306 			verbose("%s authentication disabled.", meth->name);
    307 			goto skip;
    308 		}
    309 
    310 		authenticated = meth->method(authctxt, info, sizeof(info));
    311 		if (authenticated == -1)
    312 			continue; /* "postponed" */
    313 
    314 #ifdef BSD_AUTH
    315 		if (authctxt->as) {
    316 			auth_close(authctxt->as);
    317 			authctxt->as = NULL;
    318 		}
    319 #endif
    320 		if (!authctxt->valid && authenticated)
    321 			fatal("INTERNAL ERROR: authenticated invalid user %s",
    322 			    authctxt->user);
    323 
    324 #ifdef _UNICOS
    325 		if (authenticated && cray_access_denied(authctxt->user)) {
    326 			authenticated = 0;
    327 			fatal("Access denied for user %s.",authctxt->user);
    328 		}
    329 #endif /* _UNICOS */
    330 
    331 #ifndef HAVE_CYGWIN
    332 		/* Special handling for root */
    333 		if (authenticated && authctxt->pw->pw_uid == 0 &&
    334 		    !auth_root_allowed(meth->name)) {
    335  			authenticated = 0;
    336 # ifdef SSH_AUDIT_EVENTS
    337 			PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
    338 # endif
    339 		}
    340 #endif
    341 
    342 #ifdef USE_PAM
    343 		if (options.use_pam && authenticated &&
    344 		    !PRIVSEP(do_pam_account())) {
    345 			char *msg;
    346 			size_t len;
    347 
    348 			error("Access denied for user %s by PAM account "
    349 			    "configuration", authctxt->user);
    350 			len = buffer_len(&loginmsg);
    351 			buffer_append(&loginmsg, "\0", 1);
    352 			msg = buffer_ptr(&loginmsg);
    353 			/* strip trailing newlines */
    354 			if (len > 0)
    355 				while (len > 0 && msg[--len] == '\n')
    356 					msg[len] = '\0';
    357 			else
    358 				msg = "Access denied.";
    359 			packet_disconnect("%s", msg);
    360 		}
    361 #endif
    362 
    363  skip:
    364 		/* Log before sending the reply */
    365 		auth_log(authctxt, authenticated, get_authname(type), info);
    366 
    367 		if (client_user != NULL) {
    368 			xfree(client_user);
    369 			client_user = NULL;
    370 		}
    371 
    372 		if (authenticated)
    373 			return;
    374 
    375 		if (++authctxt->failures >= options.max_authtries) {
    376 #ifdef SSH_AUDIT_EVENTS
    377 			PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
    378 #endif
    379 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
    380 		}
    381 
    382 		packet_start(SSH_SMSG_FAILURE);
    383 		packet_send();
    384 		packet_write_wait();
    385 	}
    386 }
    387 
    388 /*
    389  * Performs authentication of an incoming connection.  Session key has already
    390  * been exchanged and encryption is enabled.
    391  */
    392 void
    393 do_authentication(Authctxt *authctxt)
    394 {
    395 	u_int ulen;
    396 	char *user, *style = NULL;
    397 
    398 	/* Get the name of the user that we wish to log in as. */
    399 	packet_read_expect(SSH_CMSG_USER);
    400 
    401 	/* Get the user name. */
    402 	user = packet_get_cstring(&ulen);
    403 	packet_check_eom();
    404 
    405 	if ((style = strchr(user, ':')) != NULL)
    406 		*style++ = '\0';
    407 
    408 	authctxt->user = user;
    409 	authctxt->style = style;
    410 
    411 	/* Verify that the user is a valid user. */
    412 	if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
    413 		authctxt->valid = 1;
    414 	else {
    415 		debug("do_authentication: invalid user %s", user);
    416 		authctxt->pw = fakepw();
    417 	}
    418 
    419 	setproctitle("%s%s", authctxt->valid ? user : "unknown",
    420 	    use_privsep ? " [net]" : "");
    421 
    422 #ifdef USE_PAM
    423 	if (options.use_pam)
    424 		PRIVSEP(start_pam(authctxt));
    425 #endif
    426 
    427 	/*
    428 	 * If we are not running as root, the user must have the same uid as
    429 	 * the server.
    430 	 */
    431 #ifndef HAVE_CYGWIN
    432 	if (!use_privsep && getuid() != 0 && authctxt->pw &&
    433 	    authctxt->pw->pw_uid != getuid())
    434 		packet_disconnect("Cannot change user when server not running as root.");
    435 #endif
    436 
    437 	/*
    438 	 * Loop until the user has been authenticated or the connection is
    439 	 * closed, do_authloop() returns only if authentication is successful
    440 	 */
    441 	do_authloop(authctxt);
    442 
    443 	/* The user has been authenticated and accepted. */
    444 	packet_start(SSH_SMSG_SUCCESS);
    445 	packet_send();
    446 	packet_write_wait();
    447 }
    448