xref: /freebsd/crypto/openssh/auth.c (revision d429ea332342fcb98d27a350d0c4944bf9aec3f9)
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: auth.c,v 1.58 2005/03/14 11:44:42 dtucker Exp $");
27 RCSID("$FreeBSD$");
28 
29 #ifdef HAVE_LOGIN_H
30 #include <login.h>
31 #endif
32 #ifdef USE_SHADOW
33 #include <shadow.h>
34 #endif
35 
36 #ifdef HAVE_LIBGEN_H
37 #include <libgen.h>
38 #endif
39 
40 #include "xmalloc.h"
41 #include "match.h"
42 #include "groupaccess.h"
43 #include "log.h"
44 #include "servconf.h"
45 #include "auth.h"
46 #include "auth-options.h"
47 #include "canohost.h"
48 #include "buffer.h"
49 #include "bufaux.h"
50 #include "uidswap.h"
51 #include "misc.h"
52 #include "bufaux.h"
53 #include "packet.h"
54 #include "loginrec.h"
55 #include "monitor_wrap.h"
56 
57 /* import */
58 extern ServerOptions options;
59 extern Buffer loginmsg;
60 
61 /* Debugging messages */
62 Buffer auth_debug;
63 int auth_debug_init;
64 
65 /*
66  * Check if the user is allowed to log in via ssh. If user is listed
67  * in DenyUsers or one of user's groups is listed in DenyGroups, false
68  * will be returned. If AllowUsers isn't empty and user isn't listed
69  * there, or if AllowGroups isn't empty and one of user's groups isn't
70  * listed there, false will be returned.
71  * If the user's shell is not executable, false will be returned.
72  * Otherwise true is returned.
73  */
74 int
75 allowed_user(struct passwd * pw)
76 {
77 	struct stat st;
78 	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
79 	char *shell;
80 	int i;
81 #ifdef USE_SHADOW
82 	struct spwd *spw = NULL;
83 #endif
84 
85 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
86 	if (!pw || !pw->pw_name)
87 		return 0;
88 
89 #ifdef USE_SHADOW
90 	if (!options.use_pam)
91 		spw = getspnam(pw->pw_name);
92 #ifdef HAS_SHADOW_EXPIRE
93 	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
94 		return 0;
95 #endif /* HAS_SHADOW_EXPIRE */
96 #endif /* USE_SHADOW */
97 
98 	/* grab passwd field for locked account check */
99 #ifdef USE_SHADOW
100 	if (spw != NULL)
101 		passwd = spw->sp_pwdp;
102 #else
103 	passwd = pw->pw_passwd;
104 #endif
105 
106 	/* check for locked account */
107 	if (!options.use_pam && passwd && *passwd) {
108 		int locked = 0;
109 
110 #ifdef LOCKED_PASSWD_STRING
111 		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
112 			 locked = 1;
113 #endif
114 #ifdef LOCKED_PASSWD_PREFIX
115 		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
116 		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
117 			 locked = 1;
118 #endif
119 #ifdef LOCKED_PASSWD_SUBSTR
120 		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
121 			locked = 1;
122 #endif
123 		if (locked) {
124 			logit("User %.100s not allowed because account is locked",
125 			    pw->pw_name);
126 			return 0;
127 		}
128 	}
129 
130 	/*
131 	 * Get the shell from the password data.  An empty shell field is
132 	 * legal, and means /bin/sh.
133 	 */
134 	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
135 
136 	/* deny if shell does not exists or is not executable */
137 	if (stat(shell, &st) != 0) {
138 		logit("User %.100s not allowed because shell %.100s does not exist",
139 		    pw->pw_name, shell);
140 		return 0;
141 	}
142 	if (S_ISREG(st.st_mode) == 0 ||
143 	    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
144 		logit("User %.100s not allowed because shell %.100s is not executable",
145 		    pw->pw_name, shell);
146 		return 0;
147 	}
148 
149 	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
150 	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
151 		hostname = get_canonical_hostname(options.use_dns);
152 		ipaddr = get_remote_ipaddr();
153 	}
154 
155 	/* Return false if user is listed in DenyUsers */
156 	if (options.num_deny_users > 0) {
157 		for (i = 0; i < options.num_deny_users; i++)
158 			if (match_user(pw->pw_name, hostname, ipaddr,
159 			    options.deny_users[i])) {
160 				logit("User %.100s from %.100s not allowed "
161 				    "because listed in DenyUsers",
162 				    pw->pw_name, hostname);
163 				return 0;
164 			}
165 	}
166 	/* Return false if AllowUsers isn't empty and user isn't listed there */
167 	if (options.num_allow_users > 0) {
168 		for (i = 0; i < options.num_allow_users; i++)
169 			if (match_user(pw->pw_name, hostname, ipaddr,
170 			    options.allow_users[i]))
171 				break;
172 		/* i < options.num_allow_users iff we break for loop */
173 		if (i >= options.num_allow_users) {
174 			logit("User %.100s from %.100s not allowed because "
175 			    "not listed in AllowUsers", pw->pw_name, hostname);
176 			return 0;
177 		}
178 	}
179 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
180 		/* Get the user's group access list (primary and supplementary) */
181 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
182 			logit("User %.100s from %.100s not allowed because "
183 			    "not in any group", pw->pw_name, hostname);
184 			return 0;
185 		}
186 
187 		/* Return false if one of user's groups is listed in DenyGroups */
188 		if (options.num_deny_groups > 0)
189 			if (ga_match(options.deny_groups,
190 			    options.num_deny_groups)) {
191 				ga_free();
192 				logit("User %.100s from %.100s not allowed "
193 				    "because a group is listed in DenyGroups",
194 				    pw->pw_name, hostname);
195 				return 0;
196 			}
197 		/*
198 		 * Return false if AllowGroups isn't empty and one of user's groups
199 		 * isn't listed there
200 		 */
201 		if (options.num_allow_groups > 0)
202 			if (!ga_match(options.allow_groups,
203 			    options.num_allow_groups)) {
204 				ga_free();
205 				logit("User %.100s from %.100s not allowed "
206 				    "because none of user's groups are listed "
207 				    "in AllowGroups", pw->pw_name, hostname);
208 				return 0;
209 			}
210 		ga_free();
211 	}
212 
213 #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
214 	if (!sys_auth_allowed_user(pw, &loginmsg))
215 		return 0;
216 #endif
217 
218 	/* We found no reason not to let this user try to log on... */
219 	return 1;
220 }
221 
222 void
223 auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
224 {
225 	void (*authlog) (const char *fmt,...) = verbose;
226 	char *authmsg;
227 
228 	/* Raise logging level */
229 	if (authenticated == 1 ||
230 	    !authctxt->valid ||
231 	    authctxt->failures >= options.max_authtries / 2 ||
232 	    strcmp(method, "password") == 0)
233 		authlog = logit;
234 
235 	if (authctxt->postponed)
236 		authmsg = "Postponed";
237 	else
238 		authmsg = authenticated ? "Accepted" : "Failed";
239 
240 	authlog("%s %s for %s%.100s from %.200s port %d%s",
241 	    authmsg,
242 	    method,
243 	    authctxt->valid ? "" : "invalid user ",
244 	    authctxt->user,
245 	    get_remote_ipaddr(),
246 	    get_remote_port(),
247 	    info);
248 
249 #ifdef CUSTOM_FAILED_LOGIN
250 	if (authenticated == 0 && !authctxt->postponed &&
251 	    (strcmp(method, "password") == 0 ||
252 	    strncmp(method, "keyboard-interactive", 20) == 0 ||
253 	    strcmp(method, "challenge-response") == 0))
254 		record_failed_login(authctxt->user,
255 		    get_canonical_hostname(options.use_dns), "ssh");
256 #endif
257 #ifdef SSH_AUDIT_EVENTS
258 	if (authenticated == 0 && !authctxt->postponed) {
259 		ssh_audit_event_t event;
260 
261 		debug3("audit failed auth attempt, method %s euid %d",
262 		    method, (int)geteuid());
263 		/*
264 		 * Because the auth loop is used in both monitor and slave,
265 		 * we must be careful to send each event only once and with
266 		 * enough privs to write the event.
267 		 */
268 		event = audit_classify_auth(method);
269 		switch(event) {
270 		case SSH_AUTH_FAIL_NONE:
271 		case SSH_AUTH_FAIL_PASSWD:
272 		case SSH_AUTH_FAIL_KBDINT:
273 			if (geteuid() == 0)
274 				audit_event(event);
275 			break;
276 		case SSH_AUTH_FAIL_PUBKEY:
277 		case SSH_AUTH_FAIL_HOSTBASED:
278 		case SSH_AUTH_FAIL_GSSAPI:
279 			/*
280 			 * This is required to handle the case where privsep
281 			 * is enabled but it's root logging in, since
282 			 * use_privsep won't be cleared until after a
283 			 * successful login.
284 			 */
285 			if (geteuid() == 0)
286 				audit_event(event);
287 			else
288 				PRIVSEP(audit_event(event));
289 			break;
290 		default:
291 			error("unknown authentication audit event %d", event);
292 		}
293 	}
294 #endif
295 }
296 
297 /*
298  * Check whether root logins are disallowed.
299  */
300 int
301 auth_root_allowed(char *method)
302 {
303 	switch (options.permit_root_login) {
304 	case PERMIT_YES:
305 		return 1;
306 		break;
307 	case PERMIT_NO_PASSWD:
308 		if (strcmp(method, "password") != 0)
309 			return 1;
310 		break;
311 	case PERMIT_FORCED_ONLY:
312 		if (forced_command) {
313 			logit("Root login accepted for forced command.");
314 			return 1;
315 		}
316 		break;
317 	}
318 	logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
319 	return 0;
320 }
321 
322 
323 /*
324  * Given a template and a passwd structure, build a filename
325  * by substituting % tokenised options. Currently, %% becomes '%',
326  * %h becomes the home directory and %u the username.
327  *
328  * This returns a buffer allocated by xmalloc.
329  */
330 char *
331 expand_filename(const char *filename, struct passwd *pw)
332 {
333 	Buffer buffer;
334 	char *file;
335 	const char *cp;
336 
337 	/*
338 	 * Build the filename string in the buffer by making the appropriate
339 	 * substitutions to the given file name.
340 	 */
341 	buffer_init(&buffer);
342 	for (cp = filename; *cp; cp++) {
343 		if (cp[0] == '%' && cp[1] == '%') {
344 			buffer_append(&buffer, "%", 1);
345 			cp++;
346 			continue;
347 		}
348 		if (cp[0] == '%' && cp[1] == 'h') {
349 			buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir));
350 			cp++;
351 			continue;
352 		}
353 		if (cp[0] == '%' && cp[1] == 'u') {
354 			buffer_append(&buffer, pw->pw_name,
355 			    strlen(pw->pw_name));
356 			cp++;
357 			continue;
358 		}
359 		buffer_append(&buffer, cp, 1);
360 	}
361 	buffer_append(&buffer, "\0", 1);
362 
363 	/*
364 	 * Ensure that filename starts anchored. If not, be backward
365 	 * compatible and prepend the '%h/'
366 	 */
367 	file = xmalloc(MAXPATHLEN);
368 	cp = buffer_ptr(&buffer);
369 	if (*cp != '/')
370 		snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp);
371 	else
372 		strlcpy(file, cp, MAXPATHLEN);
373 
374 	buffer_free(&buffer);
375 	return file;
376 }
377 
378 char *
379 authorized_keys_file(struct passwd *pw)
380 {
381 	return expand_filename(options.authorized_keys_file, pw);
382 }
383 
384 char *
385 authorized_keys_file2(struct passwd *pw)
386 {
387 	return expand_filename(options.authorized_keys_file2, pw);
388 }
389 
390 /* return ok if key exists in sysfile or userfile */
391 HostStatus
392 check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
393     const char *sysfile, const char *userfile)
394 {
395 	Key *found;
396 	char *user_hostfile;
397 	struct stat st;
398 	HostStatus host_status;
399 
400 	/* Check if we know the host and its host key. */
401 	found = key_new(key->type);
402 	host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
403 
404 	if (host_status != HOST_OK && userfile != NULL) {
405 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
406 		if (options.strict_modes &&
407 		    (stat(user_hostfile, &st) == 0) &&
408 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
409 		    (st.st_mode & 022) != 0)) {
410 			logit("Authentication refused for %.100s: "
411 			    "bad owner or modes for %.200s",
412 			    pw->pw_name, user_hostfile);
413 		} else {
414 			temporarily_use_uid(pw);
415 			host_status = check_host_in_hostfile(user_hostfile,
416 			    host, key, found, NULL);
417 			restore_uid();
418 		}
419 		xfree(user_hostfile);
420 	}
421 	key_free(found);
422 
423 	debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
424 	    "ok" : "not found", host);
425 	return host_status;
426 }
427 
428 
429 /*
430  * Check a given file for security. This is defined as all components
431  * of the path to the file must be owned by either the owner of
432  * of the file or root and no directories must be group or world writable.
433  *
434  * XXX Should any specific check be done for sym links ?
435  *
436  * Takes an open file descriptor, the file name, a uid and and
437  * error buffer plus max size as arguments.
438  *
439  * Returns 0 on success and -1 on failure
440  */
441 int
442 secure_filename(FILE *f, const char *file, struct passwd *pw,
443     char *err, size_t errlen)
444 {
445 	uid_t uid = pw->pw_uid;
446 	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
447 	char *cp;
448 	int comparehome = 0;
449 	struct stat st;
450 
451 	if (realpath(file, buf) == NULL) {
452 		snprintf(err, errlen, "realpath %s failed: %s", file,
453 		    strerror(errno));
454 		return -1;
455 	}
456 	if (realpath(pw->pw_dir, homedir) != NULL)
457 		comparehome = 1;
458 
459 	/* check the open file to avoid races */
460 	if (fstat(fileno(f), &st) < 0 ||
461 	    (st.st_uid != 0 && st.st_uid != uid) ||
462 	    (st.st_mode & 022) != 0) {
463 		snprintf(err, errlen, "bad ownership or modes for file %s",
464 		    buf);
465 		return -1;
466 	}
467 
468 	/* for each component of the canonical path, walking upwards */
469 	for (;;) {
470 		if ((cp = dirname(buf)) == NULL) {
471 			snprintf(err, errlen, "dirname() failed");
472 			return -1;
473 		}
474 		strlcpy(buf, cp, sizeof(buf));
475 
476 		debug3("secure_filename: checking '%s'", buf);
477 		if (stat(buf, &st) < 0 ||
478 		    (st.st_uid != 0 && st.st_uid != uid) ||
479 		    (st.st_mode & 022) != 0) {
480 			snprintf(err, errlen,
481 			    "bad ownership or modes for directory %s", buf);
482 			return -1;
483 		}
484 
485 		/* If are passed the homedir then we can stop */
486 		if (comparehome && strcmp(homedir, buf) == 0) {
487 			debug3("secure_filename: terminating check at '%s'",
488 			    buf);
489 			break;
490 		}
491 		/*
492 		 * dirname should always complete with a "/" path,
493 		 * but we can be paranoid and check for "." too
494 		 */
495 		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
496 			break;
497 	}
498 	return 0;
499 }
500 
501 struct passwd *
502 getpwnamallow(const char *user)
503 {
504 #ifdef HAVE_LOGIN_CAP
505 	extern login_cap_t *lc;
506 #ifdef BSD_AUTH
507 	auth_session_t *as;
508 #endif
509 #endif
510 	struct passwd *pw;
511 
512 	pw = getpwnam(user);
513 	if (pw == NULL) {
514 		logit("Invalid user %.100s from %.100s",
515 		    user, get_remote_ipaddr());
516 #ifdef CUSTOM_FAILED_LOGIN
517 		record_failed_login(user,
518 		    get_canonical_hostname(options.use_dns), "ssh");
519 #endif
520 #ifdef SSH_AUDIT_EVENTS
521 		audit_event(SSH_INVALID_USER);
522 #endif /* SSH_AUDIT_EVENTS */
523 		return (NULL);
524 	}
525 	if (!allowed_user(pw))
526 		return (NULL);
527 #ifdef HAVE_LOGIN_CAP
528 	if ((lc = login_getpwclass(pw)) == NULL) {
529 		debug("unable to get login class: %s", user);
530 		return (NULL);
531 	}
532 #ifdef BSD_AUTH
533 	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
534 	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
535 		debug("Approval failure for %s", user);
536 		pw = NULL;
537 	}
538 	if (as != NULL)
539 		auth_close(as);
540 #endif
541 #endif
542 	if (pw != NULL)
543 		return (pwcopy(pw));
544 	return (NULL);
545 }
546 
547 void
548 auth_debug_add(const char *fmt,...)
549 {
550 	char buf[1024];
551 	va_list args;
552 
553 	if (!auth_debug_init)
554 		return;
555 
556 	va_start(args, fmt);
557 	vsnprintf(buf, sizeof(buf), fmt, args);
558 	va_end(args);
559 	buffer_put_cstring(&auth_debug, buf);
560 }
561 
562 void
563 auth_debug_send(void)
564 {
565 	char *msg;
566 
567 	if (!auth_debug_init)
568 		return;
569 	while (buffer_len(&auth_debug)) {
570 		msg = buffer_get_string(&auth_debug, NULL);
571 		packet_send_debug("%s", msg);
572 		xfree(msg);
573 	}
574 }
575 
576 void
577 auth_debug_reset(void)
578 {
579 	if (auth_debug_init)
580 		buffer_clear(&auth_debug);
581 	else {
582 		buffer_init(&auth_debug);
583 		auth_debug_init = 1;
584 	}
585 }
586 
587 struct passwd *
588 fakepw(void)
589 {
590 	static struct passwd fake;
591 
592 	memset(&fake, 0, sizeof(fake));
593 	fake.pw_name = "NOUSER";
594 	fake.pw_passwd =
595 	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
596 	fake.pw_gecos = "NOUSER";
597 	fake.pw_uid = (uid_t)-1;
598 	fake.pw_gid = (gid_t)-1;
599 #ifdef HAVE_PW_CLASS_IN_PASSWD
600 	fake.pw_class = "";
601 #endif
602 	fake.pw_dir = "/nonexist";
603 	fake.pw_shell = "/nonexist";
604 
605 	return (&fake);
606 }
607