xref: /freebsd/crypto/openssh/auth2.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 
25 #include "includes.h"
26 RCSID("$OpenBSD: auth2.c,v 1.14 2000/09/07 20:27:49 deraadt Exp $");
27 RCSID("$FreeBSD$");
28 
29 #include <openssl/dsa.h>
30 #include <openssl/rsa.h>
31 #include <openssl/evp.h>
32 
33 #include "xmalloc.h"
34 #include "rsa.h"
35 #include "ssh.h"
36 #include "pty.h"
37 #include "packet.h"
38 #include "buffer.h"
39 #include "cipher.h"
40 #include "servconf.h"
41 #include "compat.h"
42 #include "channels.h"
43 #include "bufaux.h"
44 #include "ssh2.h"
45 #include "auth.h"
46 #include "session.h"
47 #include "dispatch.h"
48 #include "auth.h"
49 #include "key.h"
50 #include "kex.h"
51 
52 #include "dsa.h"
53 #include "uidswap.h"
54 #include "auth-options.h"
55 
56 #ifdef HAVE_LOGIN_CAP
57 #include <login_cap.h>
58 #endif /* HAVE_LOGIN_CAP */
59 
60 /* import */
61 extern ServerOptions options;
62 extern unsigned char *session_id2;
63 extern int session_id2_len;
64 
65 /* protocol */
66 
67 void	input_service_request(int type, int plen);
68 void	input_userauth_request(int type, int plen);
69 void	protocol_error(int type, int plen);
70 
71 /* auth */
72 int	ssh2_auth_none(struct passwd *pw);
73 int	ssh2_auth_password(struct passwd *pw);
74 int  	ssh2_auth_pubkey(struct passwd *pw, char *service);
75 
76 /* helper */
77 struct passwd*	 auth_set_user(char *u, char *s);
78 int	user_dsa_key_allowed(struct passwd *pw, Key *key);
79 
80 typedef struct Authctxt Authctxt;
81 struct Authctxt {
82 	char *user;
83 	char *service;
84 	struct passwd pw;
85 	int valid;
86 };
87 static Authctxt	*authctxt = NULL;
88 static int userauth_success = 0;
89 
90 /*
91  * loop until userauth_success == TRUE
92  */
93 
94 void
95 do_authentication2()
96 {
97 	/* turn off skey/kerberos, not supported by SSH2 */
98 #ifdef SKEY
99 	options.skey_authentication = 0;
100 #endif
101 #ifdef KRB4
102 	options.krb4_authentication = 0;
103 #endif
104 
105 	dispatch_init(&protocol_error);
106 	dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
107 	dispatch_run(DISPATCH_BLOCK, &userauth_success);
108 	do_authenticated2();
109 }
110 
111 void
112 protocol_error(int type, int plen)
113 {
114 	log("auth: protocol error: type %d plen %d", type, plen);
115 	packet_start(SSH2_MSG_UNIMPLEMENTED);
116 	packet_put_int(0);
117 	packet_send();
118 	packet_write_wait();
119 }
120 
121 void
122 input_service_request(int type, int plen)
123 {
124 	unsigned int len;
125 	int accept = 0;
126 	char *service = packet_get_string(&len);
127 	packet_done();
128 
129 	if (strcmp(service, "ssh-userauth") == 0) {
130 		if (!userauth_success) {
131 			accept = 1;
132 			/* now we can handle user-auth requests */
133 			dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
134 		}
135 	}
136 	/* XXX all other service requests are denied */
137 
138 	if (accept) {
139 		packet_start(SSH2_MSG_SERVICE_ACCEPT);
140 		packet_put_cstring(service);
141 		packet_send();
142 		packet_write_wait();
143 	} else {
144 		debug("bad service request %s", service);
145 		packet_disconnect("bad service request %s", service);
146 	}
147 	xfree(service);
148 }
149 
150 void
151 input_userauth_request(int type, int plen)
152 {
153 	static void (*authlog) (const char *fmt,...) = verbose;
154 	static int attempt = 0;
155 	unsigned int len;
156 	int authenticated = 0;
157 	char *user, *service, *method, *authmsg = NULL;
158 	struct passwd *pw;
159 #ifdef HAVE_LOGIN_CAP
160 	login_cap_t *lc;
161 #endif /* HAVE_LOGIN_CAP */
162 #if defined(HAVE_LOGIN_CAP) || defined(LOGIN_ACCESS)
163 	const char *from_host, *from_ip;
164 
165 	from_host = get_canonical_hostname();
166 	from_ip = get_remote_ipaddr();
167 #endif /* HAVE_LOGIN_CAP || LOGIN_ACCESS */
168 
169 	if (++attempt == AUTH_FAIL_MAX)
170 		packet_disconnect("too many failed userauth_requests");
171 
172 	user = packet_get_string(&len);
173 	service = packet_get_string(&len);
174 	method = packet_get_string(&len);
175 	debug("userauth-request for user %s service %s method %s", user, service, method);
176 
177 	/* XXX we only allow the ssh-connection service */
178 	pw = auth_set_user(user, service);
179 	if (pw && strcmp(service, "ssh-connection")==0) {
180 		if (strcmp(method, "none") == 0) {
181 			authenticated =	ssh2_auth_none(pw);
182 		} else if (strcmp(method, "password") == 0) {
183 			authenticated =	ssh2_auth_password(pw);
184 		} else if (strcmp(method, "publickey") == 0) {
185 			authenticated =	ssh2_auth_pubkey(pw, service);
186 		}
187 	}
188 	if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
189 		authenticated = 0;
190 		log("ROOT LOGIN REFUSED FROM %.200s",
191 		    get_canonical_hostname());
192 	}
193 
194 #ifdef HAVE_LOGIN_CAP
195 	lc = login_getpwclass(pw);
196 	if (lc == NULL)
197 		lc = login_getclassbyname(NULL, pw);
198 	if (!auth_hostok(lc, from_host, from_ip)) {
199 		log("Denied connection for %.200s from %.200s [%.200s].",
200 		    pw->pw_name, from_host, from_ip);
201 		packet_disconnect("Sorry, you are not allowed to connect.");
202 	}
203 	if (!auth_timeok(lc, time(NULL))) {
204 		log("LOGIN %.200s REFUSED (TIME) FROM %.200s",
205 		    pw->pw_name, from_host);
206 		packet_disconnect("Logins not available right now.");
207 	}
208 	login_close(lc);
209 #endif  /* HAVE_LOGIN_CAP */
210 #ifdef LOGIN_ACCESS
211 	if (!login_access(pw->pw_name, from_host)) {
212 		log("Denied connection for %.200s from %.200s [%.200s].",
213 		    pw->pw_name, from_host, from_ip);
214 		packet_disconnect("Sorry, you are not allowed to connect.");
215 	}
216 #endif /* LOGIN_ACCESS */
217 
218 	/* Raise logging level */
219 	if (authenticated == 1 ||
220 	    attempt == AUTH_FAIL_LOG ||
221 	    strcmp(method, "password") == 0)
222 		authlog = log;
223 
224 	/* Log before sending the reply */
225 	if (authenticated == 1) {
226 		authmsg = "Accepted";
227 	} else if (authenticated == 0) {
228 		authmsg = "Failed";
229 	} else {
230 		authmsg = "Postponed";
231 	}
232 	authlog("%s %s for %.200s from %.200s port %d ssh2",
233 		authmsg,
234 		method,
235 		pw && pw->pw_uid == 0 ? "ROOT" : user,
236 		get_remote_ipaddr(),
237 		get_remote_port());
238 
239 	/* XXX todo: check if multiple auth methods are needed */
240 	if (authenticated == 1) {
241 		/* turn off userauth */
242 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
243 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
244 		packet_send();
245 		packet_write_wait();
246 		/* now we can break out */
247 		userauth_success = 1;
248 	} else if (authenticated == 0) {
249 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
250 		packet_put_cstring("publickey,password");	/* XXX dynamic */
251 		packet_put_char(0);				/* XXX partial success, unused */
252 		packet_send();
253 		packet_write_wait();
254 	}
255 
256 	xfree(service);
257 	xfree(user);
258 	xfree(method);
259 }
260 
261 int
262 ssh2_auth_none(struct passwd *pw)
263 {
264 	packet_done();
265 	return auth_password(pw, "");
266 }
267 int
268 ssh2_auth_password(struct passwd *pw)
269 {
270 	char *password;
271 	int authenticated = 0;
272 	int change;
273 	unsigned int len;
274 	change = packet_get_char();
275 	if (change)
276 		log("password change not supported");
277 	password = packet_get_string(&len);
278 	packet_done();
279 	if (options.password_authentication &&
280 	    auth_password(pw, password) == 1)
281 		authenticated = 1;
282 	memset(password, 0, len);
283 	xfree(password);
284 	return authenticated;
285 }
286 int
287 ssh2_auth_pubkey(struct passwd *pw, char *service)
288 {
289 	Buffer b;
290 	Key *key;
291 	char *pkalg, *pkblob, *sig;
292 	unsigned int alen, blen, slen;
293 	int have_sig;
294 	int authenticated = 0;
295 
296 	if (options.dsa_authentication == 0) {
297 		debug("pubkey auth disabled");
298 		return 0;
299 	}
300 	have_sig = packet_get_char();
301 	pkalg = packet_get_string(&alen);
302 	if (strcmp(pkalg, KEX_DSS) != 0) {
303 		xfree(pkalg);
304 		log("bad pkalg %s", pkalg);	/*XXX*/
305 		return 0;
306 	}
307 	pkblob = packet_get_string(&blen);
308 	key = dsa_key_from_blob(pkblob, blen);
309 	if (key != NULL) {
310 		if (have_sig) {
311 			sig = packet_get_string(&slen);
312 			packet_done();
313 			buffer_init(&b);
314 			if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
315 				buffer_put_string(&b, session_id2, session_id2_len);
316 			} else {
317 				buffer_append(&b, session_id2, session_id2_len);
318 			}
319 			/* reconstruct packet */
320 			buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
321 			buffer_put_cstring(&b, pw->pw_name);
322 			buffer_put_cstring(&b,
323 			    datafellows & SSH_BUG_PUBKEYAUTH ?
324 			    "ssh-userauth" :
325 			    service);
326 			buffer_put_cstring(&b, "publickey");
327 			buffer_put_char(&b, have_sig);
328 			buffer_put_cstring(&b, KEX_DSS);
329 			buffer_put_string(&b, pkblob, blen);
330 #ifdef DEBUG_DSS
331 			buffer_dump(&b);
332 #endif
333 			/* test for correct signature */
334 			if (user_dsa_key_allowed(pw, key) &&
335 			    dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
336 				authenticated = 1;
337 			buffer_clear(&b);
338 			xfree(sig);
339 		} else {
340 			packet_done();
341 			debug("test key...");
342 			/* test whether pkalg/pkblob are acceptable */
343 			/* XXX fake reply and always send PK_OK ? */
344 			/*
345 			 * XXX this allows testing whether a user is allowed
346 			 * to login: if you happen to have a valid pubkey this
347 			 * message is sent. the message is NEVER sent at all
348 			 * if a user is not allowed to login. is this an
349 			 * issue? -markus
350 			 */
351 			if (user_dsa_key_allowed(pw, key)) {
352 				packet_start(SSH2_MSG_USERAUTH_PK_OK);
353 				packet_put_string(pkalg, alen);
354 				packet_put_string(pkblob, blen);
355 				packet_send();
356 				packet_write_wait();
357 				authenticated = -1;
358 			}
359 		}
360 		key_free(key);
361 	}
362 	xfree(pkalg);
363 	xfree(pkblob);
364 	return authenticated;
365 }
366 
367 /* set and get current user */
368 
369 struct passwd*
370 auth_get_user(void)
371 {
372 	return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
373 }
374 
375 struct passwd*
376 auth_set_user(char *u, char *s)
377 {
378 	struct passwd *pw, *copy;
379 
380 	if (authctxt == NULL) {
381 		authctxt = xmalloc(sizeof(*authctxt));
382 		authctxt->valid = 0;
383 		authctxt->user = xstrdup(u);
384 		authctxt->service = xstrdup(s);
385 		setproctitle("%s", u);
386 		pw = getpwnam(u);
387 		if (!pw || !allowed_user(pw)) {
388 			log("auth_set_user: illegal user %s", u);
389 			return NULL;
390 		}
391 		copy = &authctxt->pw;
392 		memset(copy, 0, sizeof(*copy));
393 		copy->pw_name = xstrdup(pw->pw_name);
394 		copy->pw_passwd = xstrdup(pw->pw_passwd);
395 		copy->pw_uid = pw->pw_uid;
396 		copy->pw_gid = pw->pw_gid;
397 		copy->pw_class = xstrdup(pw->pw_class);
398 		copy->pw_dir = xstrdup(pw->pw_dir);
399 		copy->pw_shell = xstrdup(pw->pw_shell);
400 		copy->pw_class = xstrdup(pw->pw_class);
401 		copy->pw_expire = pw->pw_expire;
402 		copy->pw_change = pw->pw_change;
403 		authctxt->valid = 1;
404 	} else {
405 		if (strcmp(u, authctxt->user) != 0 ||
406 		    strcmp(s, authctxt->service) != 0) {
407 			log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
408 			    u, s, authctxt->user, authctxt->service);
409 			return NULL;
410 		}
411 	}
412 	return auth_get_user();
413 }
414 
415 /* return 1 if user allows given key */
416 int
417 user_dsa_key_allowed(struct passwd *pw, Key *key)
418 {
419 	char line[8192], file[1024];
420 	int found_key = 0;
421 	unsigned int bits = -1;
422 	FILE *f;
423 	unsigned long linenum = 0;
424 	struct stat st;
425 	Key *found;
426 
427 	/* Temporarily use the user's uid. */
428 	temporarily_use_uid(pw->pw_uid);
429 
430 	/* The authorized keys. */
431 	snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
432 	    SSH_USER_PERMITTED_KEYS2);
433 
434 	/* Fail quietly if file does not exist */
435 	if (stat(file, &st) < 0) {
436 		/* Restore the privileged uid. */
437 		restore_uid();
438 		return 0;
439 	}
440 	/* Open the file containing the authorized keys. */
441 	f = fopen(file, "r");
442 	if (!f) {
443 		/* Restore the privileged uid. */
444 		restore_uid();
445 		return 0;
446 	}
447 	if (options.strict_modes) {
448 		int fail = 0;
449 		char buf[1024];
450 		/* Check open file in order to avoid open/stat races */
451 		if (fstat(fileno(f), &st) < 0 ||
452 		    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
453 		    (st.st_mode & 022) != 0) {
454 			snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
455 			    "bad ownership or modes for '%s'.", pw->pw_name, file);
456 			fail = 1;
457 		} else {
458 			/* Check path to SSH_USER_PERMITTED_KEYS */
459 			int i;
460 			static const char *check[] = {
461 				"", SSH_USER_DIR, NULL
462 			};
463 			for (i = 0; check[i]; i++) {
464 				snprintf(line, sizeof line, "%.500s/%.100s",
465 				    pw->pw_dir, check[i]);
466 				if (stat(line, &st) < 0 ||
467 				    (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
468 				    (st.st_mode & 022) != 0) {
469 					snprintf(buf, sizeof buf,
470 					    "DSA authentication refused for %.100s: "
471 					    "bad ownership or modes for '%s'.",
472 					    pw->pw_name, line);
473 					fail = 1;
474 					break;
475 				}
476 			}
477 		}
478 		if (fail) {
479 			fclose(f);
480 			log("%s",buf);
481 			restore_uid();
482 			return 0;
483 		}
484 	}
485 	found_key = 0;
486 	found = key_new(KEY_DSA);
487 
488 	while (fgets(line, sizeof(line), f)) {
489 		char *cp, *options = NULL;
490 		linenum++;
491 		/* Skip leading whitespace, empty and comment lines. */
492 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
493 			;
494 		if (!*cp || *cp == '\n' || *cp == '#')
495 			continue;
496 
497 		bits = key_read(found, &cp);
498 		if (bits == 0) {
499 			/* no key?  check if there are options for this key */
500 			int quoted = 0;
501 			options = cp;
502 			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
503 				if (*cp == '\\' && cp[1] == '"')
504 					cp++;	/* Skip both */
505 				else if (*cp == '"')
506 					quoted = !quoted;
507 			}
508 			/* Skip remaining whitespace. */
509 			for (; *cp == ' ' || *cp == '\t'; cp++)
510 				;
511 			bits = key_read(found, &cp);
512 			if (bits == 0) {
513 				/* still no key?  advance to next line*/
514 				continue;
515 			}
516 		}
517 		if (key_equal(found, key) &&
518 		    auth_parse_options(pw, options, linenum) == 1) {
519 			found_key = 1;
520 			debug("matching key found: file %s, line %ld",
521 			    file, linenum);
522 			break;
523 		}
524 	}
525 	restore_uid();
526 	fclose(f);
527 	key_free(found);
528 	return found_key;
529 }
530