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