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