xref: /dflybsd-src/crypto/openssh/auth.c (revision 664f47636b7e6e9e2c54a4799ca4884a9c628df5)
1*664f4763Szrj /* $OpenBSD: auth.c,v 1.138 2019/01/19 21:41:18 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
418de8d7fSPeter Avalos  *
518de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
618de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
718de8d7fSPeter Avalos  * are met:
818de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
918de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1018de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1118de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1218de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1318de8d7fSPeter Avalos  *
1418de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1518de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1618de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1718de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1818de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1918de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2018de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2118de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2218de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2318de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2418de8d7fSPeter Avalos  */
2518de8d7fSPeter Avalos 
2618de8d7fSPeter Avalos #include "includes.h"
2718de8d7fSPeter Avalos 
2818de8d7fSPeter Avalos #include <sys/types.h>
2918de8d7fSPeter Avalos #include <sys/stat.h>
30e9778795SPeter Avalos #include <sys/socket.h>
31*664f4763Szrj #include <sys/wait.h>
3218de8d7fSPeter Avalos 
3318de8d7fSPeter Avalos #include <netinet/in.h>
3418de8d7fSPeter Avalos 
3518de8d7fSPeter Avalos #include <errno.h>
3618de8d7fSPeter Avalos #include <fcntl.h>
3718de8d7fSPeter Avalos #ifdef HAVE_PATHS_H
3818de8d7fSPeter Avalos # include <paths.h>
3918de8d7fSPeter Avalos #endif
4018de8d7fSPeter Avalos #include <pwd.h>
4118de8d7fSPeter Avalos #ifdef HAVE_LOGIN_H
4218de8d7fSPeter Avalos #include <login.h>
4318de8d7fSPeter Avalos #endif
4418de8d7fSPeter Avalos #ifdef USE_SHADOW
4518de8d7fSPeter Avalos #include <shadow.h>
4618de8d7fSPeter Avalos #endif
4718de8d7fSPeter Avalos #include <stdarg.h>
4818de8d7fSPeter Avalos #include <stdio.h>
4918de8d7fSPeter Avalos #include <string.h>
5018de8d7fSPeter Avalos #include <unistd.h>
51e9778795SPeter Avalos #include <limits.h>
52e9778795SPeter Avalos #include <netdb.h>
53*664f4763Szrj #include <time.h>
5418de8d7fSPeter Avalos 
5518de8d7fSPeter Avalos #include "xmalloc.h"
5618de8d7fSPeter Avalos #include "match.h"
5718de8d7fSPeter Avalos #include "groupaccess.h"
5818de8d7fSPeter Avalos #include "log.h"
59*664f4763Szrj #include "sshbuf.h"
6036e94dc5SPeter Avalos #include "misc.h"
6118de8d7fSPeter Avalos #include "servconf.h"
62*664f4763Szrj #include "sshkey.h"
6318de8d7fSPeter Avalos #include "hostfile.h"
6418de8d7fSPeter Avalos #include "auth.h"
6518de8d7fSPeter Avalos #include "auth-options.h"
6618de8d7fSPeter Avalos #include "canohost.h"
6718de8d7fSPeter Avalos #include "uidswap.h"
6818de8d7fSPeter Avalos #include "packet.h"
6918de8d7fSPeter Avalos #include "loginrec.h"
7018de8d7fSPeter Avalos #ifdef GSSAPI
7118de8d7fSPeter Avalos #include "ssh-gss.h"
7218de8d7fSPeter Avalos #endif
73856ea928SPeter Avalos #include "authfile.h"
7418de8d7fSPeter Avalos #include "monitor_wrap.h"
75e9778795SPeter Avalos #include "authfile.h"
76e9778795SPeter Avalos #include "ssherr.h"
7736e94dc5SPeter Avalos #include "compat.h"
78*664f4763Szrj #include "channels.h"
7918de8d7fSPeter Avalos 
8018de8d7fSPeter Avalos /* import */
8118de8d7fSPeter Avalos extern ServerOptions options;
8218de8d7fSPeter Avalos extern int use_privsep;
83*664f4763Szrj extern struct sshbuf *loginmsg;
8418de8d7fSPeter Avalos extern struct passwd *privsep_pw;
85*664f4763Szrj extern struct sshauthopt *auth_opts;
8618de8d7fSPeter Avalos 
8718de8d7fSPeter Avalos /* Debugging messages */
88*664f4763Szrj static struct sshbuf *auth_debug;
8918de8d7fSPeter Avalos 
9018de8d7fSPeter Avalos /*
9118de8d7fSPeter Avalos  * Check if the user is allowed to log in via ssh. If user is listed
9218de8d7fSPeter Avalos  * in DenyUsers or one of user's groups is listed in DenyGroups, false
9318de8d7fSPeter Avalos  * will be returned. If AllowUsers isn't empty and user isn't listed
9418de8d7fSPeter Avalos  * there, or if AllowGroups isn't empty and one of user's groups isn't
9518de8d7fSPeter Avalos  * listed there, false will be returned.
9618de8d7fSPeter Avalos  * If the user's shell is not executable, false will be returned.
9718de8d7fSPeter Avalos  * Otherwise true is returned.
9818de8d7fSPeter Avalos  */
9918de8d7fSPeter Avalos int
100*664f4763Szrj allowed_user(struct ssh *ssh, struct passwd * pw)
10118de8d7fSPeter Avalos {
10218de8d7fSPeter Avalos 	struct stat st;
10318de8d7fSPeter Avalos 	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
10418de8d7fSPeter Avalos 	u_int i;
105ce74bacaSMatthew Dillon 	int r;
10618de8d7fSPeter Avalos #ifdef USE_SHADOW
10718de8d7fSPeter Avalos 	struct spwd *spw = NULL;
10818de8d7fSPeter Avalos #endif
10918de8d7fSPeter Avalos 
11018de8d7fSPeter Avalos 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
11118de8d7fSPeter Avalos 	if (!pw || !pw->pw_name)
11218de8d7fSPeter Avalos 		return 0;
11318de8d7fSPeter Avalos 
11418de8d7fSPeter Avalos #ifdef USE_SHADOW
11518de8d7fSPeter Avalos 	if (!options.use_pam)
11618de8d7fSPeter Avalos 		spw = getspnam(pw->pw_name);
11718de8d7fSPeter Avalos #ifdef HAS_SHADOW_EXPIRE
11818de8d7fSPeter Avalos 	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
11918de8d7fSPeter Avalos 		return 0;
12018de8d7fSPeter Avalos #endif /* HAS_SHADOW_EXPIRE */
12118de8d7fSPeter Avalos #endif /* USE_SHADOW */
12218de8d7fSPeter Avalos 
12318de8d7fSPeter Avalos 	/* grab passwd field for locked account check */
12418de8d7fSPeter Avalos 	passwd = pw->pw_passwd;
12518de8d7fSPeter Avalos #ifdef USE_SHADOW
12618de8d7fSPeter Avalos 	if (spw != NULL)
12718de8d7fSPeter Avalos #ifdef USE_LIBIAF
12818de8d7fSPeter Avalos 		passwd = get_iaf_password(pw);
12918de8d7fSPeter Avalos #else
13018de8d7fSPeter Avalos 		passwd = spw->sp_pwdp;
13118de8d7fSPeter Avalos #endif /* USE_LIBIAF */
13218de8d7fSPeter Avalos #endif
13318de8d7fSPeter Avalos 
13418de8d7fSPeter Avalos 	/* check for locked account */
13518de8d7fSPeter Avalos 	if (!options.use_pam && passwd && *passwd) {
13618de8d7fSPeter Avalos 		int locked = 0;
13718de8d7fSPeter Avalos 
13818de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_STRING
13918de8d7fSPeter Avalos 		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
14018de8d7fSPeter Avalos 			 locked = 1;
14118de8d7fSPeter Avalos #endif
14218de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_PREFIX
14318de8d7fSPeter Avalos 		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
14418de8d7fSPeter Avalos 		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
14518de8d7fSPeter Avalos 			 locked = 1;
14618de8d7fSPeter Avalos #endif
14718de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_SUBSTR
14818de8d7fSPeter Avalos 		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
14918de8d7fSPeter Avalos 			locked = 1;
15018de8d7fSPeter Avalos #endif
15118de8d7fSPeter Avalos #ifdef USE_LIBIAF
152856ea928SPeter Avalos 		free((void *) passwd);
15318de8d7fSPeter Avalos #endif /* USE_LIBIAF */
15418de8d7fSPeter Avalos 		if (locked) {
15518de8d7fSPeter Avalos 			logit("User %.100s not allowed because account is locked",
15618de8d7fSPeter Avalos 			    pw->pw_name);
15718de8d7fSPeter Avalos 			return 0;
15818de8d7fSPeter Avalos 		}
15918de8d7fSPeter Avalos 	}
16018de8d7fSPeter Avalos 
16118de8d7fSPeter Avalos 	/*
162856ea928SPeter Avalos 	 * Deny if shell does not exist or is not executable unless we
163856ea928SPeter Avalos 	 * are chrooting.
16418de8d7fSPeter Avalos 	 */
165856ea928SPeter Avalos 	if (options.chroot_directory == NULL ||
166856ea928SPeter Avalos 	    strcasecmp(options.chroot_directory, "none") == 0) {
167856ea928SPeter Avalos 		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
168856ea928SPeter Avalos 		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
16918de8d7fSPeter Avalos 
17018de8d7fSPeter Avalos 		if (stat(shell, &st) != 0) {
171856ea928SPeter Avalos 			logit("User %.100s not allowed because shell %.100s "
172856ea928SPeter Avalos 			    "does not exist", pw->pw_name, shell);
17336e94dc5SPeter Avalos 			free(shell);
17418de8d7fSPeter Avalos 			return 0;
17518de8d7fSPeter Avalos 		}
17618de8d7fSPeter Avalos 		if (S_ISREG(st.st_mode) == 0 ||
17718de8d7fSPeter Avalos 		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
178856ea928SPeter Avalos 			logit("User %.100s not allowed because shell %.100s "
179856ea928SPeter Avalos 			    "is not executable", pw->pw_name, shell);
18036e94dc5SPeter Avalos 			free(shell);
18118de8d7fSPeter Avalos 			return 0;
18218de8d7fSPeter Avalos 		}
18336e94dc5SPeter Avalos 		free(shell);
184856ea928SPeter Avalos 	}
18518de8d7fSPeter Avalos 
18618de8d7fSPeter Avalos 	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
18718de8d7fSPeter Avalos 	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
188e9778795SPeter Avalos 		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
189e9778795SPeter Avalos 		ipaddr = ssh_remote_ipaddr(ssh);
19018de8d7fSPeter Avalos 	}
19118de8d7fSPeter Avalos 
19218de8d7fSPeter Avalos 	/* Return false if user is listed in DenyUsers */
19318de8d7fSPeter Avalos 	if (options.num_deny_users > 0) {
194ce74bacaSMatthew Dillon 		for (i = 0; i < options.num_deny_users; i++) {
195ce74bacaSMatthew Dillon 			r = match_user(pw->pw_name, hostname, ipaddr,
196ce74bacaSMatthew Dillon 			    options.deny_users[i]);
197ce74bacaSMatthew Dillon 			if (r < 0) {
198ce74bacaSMatthew Dillon 				fatal("Invalid DenyUsers pattern \"%.100s\"",
199ce74bacaSMatthew Dillon 				    options.deny_users[i]);
200ce74bacaSMatthew Dillon 			} else if (r != 0) {
20118de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
20218de8d7fSPeter Avalos 				    "because listed in DenyUsers",
20318de8d7fSPeter Avalos 				    pw->pw_name, hostname);
20418de8d7fSPeter Avalos 				return 0;
20518de8d7fSPeter Avalos 			}
20618de8d7fSPeter Avalos 		}
207ce74bacaSMatthew Dillon 	}
20818de8d7fSPeter Avalos 	/* Return false if AllowUsers isn't empty and user isn't listed there */
20918de8d7fSPeter Avalos 	if (options.num_allow_users > 0) {
210ce74bacaSMatthew Dillon 		for (i = 0; i < options.num_allow_users; i++) {
211ce74bacaSMatthew Dillon 			r = match_user(pw->pw_name, hostname, ipaddr,
212ce74bacaSMatthew Dillon 			    options.allow_users[i]);
213ce74bacaSMatthew Dillon 			if (r < 0) {
214ce74bacaSMatthew Dillon 				fatal("Invalid AllowUsers pattern \"%.100s\"",
215ce74bacaSMatthew Dillon 				    options.allow_users[i]);
216ce74bacaSMatthew Dillon 			} else if (r == 1)
21718de8d7fSPeter Avalos 				break;
218ce74bacaSMatthew Dillon 		}
21918de8d7fSPeter Avalos 		/* i < options.num_allow_users iff we break for loop */
22018de8d7fSPeter Avalos 		if (i >= options.num_allow_users) {
22118de8d7fSPeter Avalos 			logit("User %.100s from %.100s not allowed because "
22218de8d7fSPeter Avalos 			    "not listed in AllowUsers", pw->pw_name, hostname);
22318de8d7fSPeter Avalos 			return 0;
22418de8d7fSPeter Avalos 		}
22518de8d7fSPeter Avalos 	}
22618de8d7fSPeter Avalos 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
22718de8d7fSPeter Avalos 		/* Get the user's group access list (primary and supplementary) */
22818de8d7fSPeter Avalos 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
22918de8d7fSPeter Avalos 			logit("User %.100s from %.100s not allowed because "
23018de8d7fSPeter Avalos 			    "not in any group", pw->pw_name, hostname);
23118de8d7fSPeter Avalos 			return 0;
23218de8d7fSPeter Avalos 		}
23318de8d7fSPeter Avalos 
23418de8d7fSPeter Avalos 		/* Return false if one of user's groups is listed in DenyGroups */
23518de8d7fSPeter Avalos 		if (options.num_deny_groups > 0)
23618de8d7fSPeter Avalos 			if (ga_match(options.deny_groups,
23718de8d7fSPeter Avalos 			    options.num_deny_groups)) {
23818de8d7fSPeter Avalos 				ga_free();
23918de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
24018de8d7fSPeter Avalos 				    "because a group is listed in DenyGroups",
24118de8d7fSPeter Avalos 				    pw->pw_name, hostname);
24218de8d7fSPeter Avalos 				return 0;
24318de8d7fSPeter Avalos 			}
24418de8d7fSPeter Avalos 		/*
24518de8d7fSPeter Avalos 		 * Return false if AllowGroups isn't empty and one of user's groups
24618de8d7fSPeter Avalos 		 * isn't listed there
24718de8d7fSPeter Avalos 		 */
24818de8d7fSPeter Avalos 		if (options.num_allow_groups > 0)
24918de8d7fSPeter Avalos 			if (!ga_match(options.allow_groups,
25018de8d7fSPeter Avalos 			    options.num_allow_groups)) {
25118de8d7fSPeter Avalos 				ga_free();
25218de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
25318de8d7fSPeter Avalos 				    "because none of user's groups are listed "
25418de8d7fSPeter Avalos 				    "in AllowGroups", pw->pw_name, hostname);
25518de8d7fSPeter Avalos 				return 0;
25618de8d7fSPeter Avalos 			}
25718de8d7fSPeter Avalos 		ga_free();
25818de8d7fSPeter Avalos 	}
25918de8d7fSPeter Avalos 
26018de8d7fSPeter Avalos #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
261*664f4763Szrj 	if (!sys_auth_allowed_user(pw, loginmsg))
26218de8d7fSPeter Avalos 		return 0;
26318de8d7fSPeter Avalos #endif
26418de8d7fSPeter Avalos 
26518de8d7fSPeter Avalos 	/* We found no reason not to let this user try to log on... */
26618de8d7fSPeter Avalos 	return 1;
26718de8d7fSPeter Avalos }
26818de8d7fSPeter Avalos 
269ce74bacaSMatthew Dillon /*
270ce74bacaSMatthew Dillon  * Formats any key left in authctxt->auth_method_key for inclusion in
271ce74bacaSMatthew Dillon  * auth_log()'s message. Also includes authxtct->auth_method_info if present.
272ce74bacaSMatthew Dillon  */
273ce74bacaSMatthew Dillon static char *
274ce74bacaSMatthew Dillon format_method_key(Authctxt *authctxt)
27536e94dc5SPeter Avalos {
276ce74bacaSMatthew Dillon 	const struct sshkey *key = authctxt->auth_method_key;
277ce74bacaSMatthew Dillon 	const char *methinfo = authctxt->auth_method_info;
278*664f4763Szrj 	char *fp, *cafp, *ret = NULL;
27936e94dc5SPeter Avalos 
280ce74bacaSMatthew Dillon 	if (key == NULL)
281ce74bacaSMatthew Dillon 		return NULL;
28236e94dc5SPeter Avalos 
283*664f4763Szrj 	if (sshkey_is_cert(key)) {
284*664f4763Szrj 		fp = sshkey_fingerprint(key,
285ce74bacaSMatthew Dillon 		    options.fingerprint_hash, SSH_FP_DEFAULT);
286*664f4763Szrj 		cafp = sshkey_fingerprint(key->cert->signature_key,
287*664f4763Szrj 		    options.fingerprint_hash, SSH_FP_DEFAULT);
288*664f4763Szrj 		xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
289*664f4763Szrj 		    sshkey_type(key), fp == NULL ? "(null)" : fp,
290*664f4763Szrj 		    key->cert->key_id,
291ce74bacaSMatthew Dillon 		    (unsigned long long)key->cert->serial,
292ce74bacaSMatthew Dillon 		    sshkey_type(key->cert->signature_key),
293*664f4763Szrj 		    cafp == NULL ? "(null)" : cafp,
294ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : ", ",
295ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : methinfo);
296ce74bacaSMatthew Dillon 		free(fp);
297*664f4763Szrj 		free(cafp);
298ce74bacaSMatthew Dillon 	} else {
299ce74bacaSMatthew Dillon 		fp = sshkey_fingerprint(key, options.fingerprint_hash,
300ce74bacaSMatthew Dillon 		    SSH_FP_DEFAULT);
301ce74bacaSMatthew Dillon 		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
302ce74bacaSMatthew Dillon 		    fp == NULL ? "(null)" : fp,
303ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : ", ",
304ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : methinfo);
305ce74bacaSMatthew Dillon 		free(fp);
306ce74bacaSMatthew Dillon 	}
307ce74bacaSMatthew Dillon 	return ret;
30836e94dc5SPeter Avalos }
30936e94dc5SPeter Avalos 
31036e94dc5SPeter Avalos void
311*664f4763Szrj auth_log(struct ssh *ssh, int authenticated, int partial,
31236e94dc5SPeter Avalos     const char *method, const char *submethod)
31318de8d7fSPeter Avalos {
314*664f4763Szrj 	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
315*664f4763Szrj 	int level = SYSLOG_LEVEL_VERBOSE;
316ce74bacaSMatthew Dillon 	const char *authmsg;
317ce74bacaSMatthew Dillon 	char *extra = NULL;
31818de8d7fSPeter Avalos 
31918de8d7fSPeter Avalos 	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
32018de8d7fSPeter Avalos 		return;
32118de8d7fSPeter Avalos 
32218de8d7fSPeter Avalos 	/* Raise logging level */
32318de8d7fSPeter Avalos 	if (authenticated == 1 ||
32418de8d7fSPeter Avalos 	    !authctxt->valid ||
32518de8d7fSPeter Avalos 	    authctxt->failures >= options.max_authtries / 2 ||
32618de8d7fSPeter Avalos 	    strcmp(method, "password") == 0)
327*664f4763Szrj 		level = SYSLOG_LEVEL_INFO;
32818de8d7fSPeter Avalos 
32918de8d7fSPeter Avalos 	if (authctxt->postponed)
33018de8d7fSPeter Avalos 		authmsg = "Postponed";
33136e94dc5SPeter Avalos 	else if (partial)
33236e94dc5SPeter Avalos 		authmsg = "Partial";
33318de8d7fSPeter Avalos 	else
33418de8d7fSPeter Avalos 		authmsg = authenticated ? "Accepted" : "Failed";
33518de8d7fSPeter Avalos 
336ce74bacaSMatthew Dillon 	if ((extra = format_method_key(authctxt)) == NULL) {
337ce74bacaSMatthew Dillon 		if (authctxt->auth_method_info != NULL)
338ce74bacaSMatthew Dillon 			extra = xstrdup(authctxt->auth_method_info);
339ce74bacaSMatthew Dillon 	}
340ce74bacaSMatthew Dillon 
341*664f4763Szrj 	do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
34218de8d7fSPeter Avalos 	    authmsg,
34318de8d7fSPeter Avalos 	    method,
34436e94dc5SPeter Avalos 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
34518de8d7fSPeter Avalos 	    authctxt->valid ? "" : "invalid user ",
34618de8d7fSPeter Avalos 	    authctxt->user,
347e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh),
348e9778795SPeter Avalos 	    ssh_remote_port(ssh),
349ce74bacaSMatthew Dillon 	    extra != NULL ? ": " : "",
350ce74bacaSMatthew Dillon 	    extra != NULL ? extra : "");
351ce74bacaSMatthew Dillon 
352ce74bacaSMatthew Dillon 	free(extra);
35318de8d7fSPeter Avalos 
35418de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN
35518de8d7fSPeter Avalos 	if (authenticated == 0 && !authctxt->postponed &&
35618de8d7fSPeter Avalos 	    (strcmp(method, "password") == 0 ||
35718de8d7fSPeter Avalos 	    strncmp(method, "keyboard-interactive", 20) == 0 ||
35818de8d7fSPeter Avalos 	    strcmp(method, "challenge-response") == 0))
359*664f4763Szrj 		record_failed_login(ssh, authctxt->user,
360e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
36118de8d7fSPeter Avalos # ifdef WITH_AIXAUTHENTICATE
36218de8d7fSPeter Avalos 	if (authenticated)
36318de8d7fSPeter Avalos 		sys_auth_record_login(authctxt->user,
364e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
365*664f4763Szrj 		    loginmsg);
36618de8d7fSPeter Avalos # endif
36718de8d7fSPeter Avalos #endif
36818de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS
36918de8d7fSPeter Avalos 	if (authenticated == 0 && !authctxt->postponed)
370*664f4763Szrj 		audit_event(ssh, audit_classify_auth(method));
37118de8d7fSPeter Avalos #endif
37218de8d7fSPeter Avalos }
37318de8d7fSPeter Avalos 
37436e94dc5SPeter Avalos 
37536e94dc5SPeter Avalos void
376*664f4763Szrj auth_maxtries_exceeded(struct ssh *ssh)
37736e94dc5SPeter Avalos {
378*664f4763Szrj 	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
379e9778795SPeter Avalos 
380e9778795SPeter Avalos 	error("maximum authentication attempts exceeded for "
381ce74bacaSMatthew Dillon 	    "%s%.100s from %.200s port %d ssh2",
38236e94dc5SPeter Avalos 	    authctxt->valid ? "" : "invalid user ",
38336e94dc5SPeter Avalos 	    authctxt->user,
384e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh),
385ce74bacaSMatthew Dillon 	    ssh_remote_port(ssh));
386*664f4763Szrj 	ssh_packet_disconnect(ssh, "Too many authentication failures");
38736e94dc5SPeter Avalos 	/* NOTREACHED */
38836e94dc5SPeter Avalos }
38936e94dc5SPeter Avalos 
39018de8d7fSPeter Avalos /*
39118de8d7fSPeter Avalos  * Check whether root logins are disallowed.
39218de8d7fSPeter Avalos  */
39318de8d7fSPeter Avalos int
394*664f4763Szrj auth_root_allowed(struct ssh *ssh, const char *method)
39518de8d7fSPeter Avalos {
39618de8d7fSPeter Avalos 	switch (options.permit_root_login) {
39718de8d7fSPeter Avalos 	case PERMIT_YES:
39818de8d7fSPeter Avalos 		return 1;
39918de8d7fSPeter Avalos 	case PERMIT_NO_PASSWD:
400e9778795SPeter Avalos 		if (strcmp(method, "publickey") == 0 ||
401e9778795SPeter Avalos 		    strcmp(method, "hostbased") == 0 ||
402e9778795SPeter Avalos 		    strcmp(method, "gssapi-with-mic") == 0)
40318de8d7fSPeter Avalos 			return 1;
40418de8d7fSPeter Avalos 		break;
40518de8d7fSPeter Avalos 	case PERMIT_FORCED_ONLY:
406*664f4763Szrj 		if (auth_opts->force_command != NULL) {
40718de8d7fSPeter Avalos 			logit("Root login accepted for forced command.");
40818de8d7fSPeter Avalos 			return 1;
40918de8d7fSPeter Avalos 		}
41018de8d7fSPeter Avalos 		break;
41118de8d7fSPeter Avalos 	}
412e9778795SPeter Avalos 	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
413e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
41418de8d7fSPeter Avalos 	return 0;
41518de8d7fSPeter Avalos }
41618de8d7fSPeter Avalos 
41718de8d7fSPeter Avalos 
41818de8d7fSPeter Avalos /*
41918de8d7fSPeter Avalos  * Given a template and a passwd structure, build a filename
42018de8d7fSPeter Avalos  * by substituting % tokenised options. Currently, %% becomes '%',
42118de8d7fSPeter Avalos  * %h becomes the home directory and %u the username.
42218de8d7fSPeter Avalos  *
42318de8d7fSPeter Avalos  * This returns a buffer allocated by xmalloc.
42418de8d7fSPeter Avalos  */
4251c188a7fSPeter Avalos char *
42618de8d7fSPeter Avalos expand_authorized_keys(const char *filename, struct passwd *pw)
42718de8d7fSPeter Avalos {
428*664f4763Szrj 	char *file, uidstr[32], ret[PATH_MAX];
42918de8d7fSPeter Avalos 	int i;
43018de8d7fSPeter Avalos 
431*664f4763Szrj 	snprintf(uidstr, sizeof(uidstr), "%llu",
432*664f4763Szrj 	    (unsigned long long)pw->pw_uid);
43318de8d7fSPeter Avalos 	file = percent_expand(filename, "h", pw->pw_dir,
434*664f4763Szrj 	    "u", pw->pw_name, "U", uidstr, (char *)NULL);
43518de8d7fSPeter Avalos 
43618de8d7fSPeter Avalos 	/*
43718de8d7fSPeter Avalos 	 * Ensure that filename starts anchored. If not, be backward
43818de8d7fSPeter Avalos 	 * compatible and prepend the '%h/'
43918de8d7fSPeter Avalos 	 */
440*664f4763Szrj 	if (path_absolute(file))
44118de8d7fSPeter Avalos 		return (file);
44218de8d7fSPeter Avalos 
44318de8d7fSPeter Avalos 	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
44418de8d7fSPeter Avalos 	if (i < 0 || (size_t)i >= sizeof(ret))
44518de8d7fSPeter Avalos 		fatal("expand_authorized_keys: path too long");
44636e94dc5SPeter Avalos 	free(file);
44718de8d7fSPeter Avalos 	return (xstrdup(ret));
44818de8d7fSPeter Avalos }
44918de8d7fSPeter Avalos 
45018de8d7fSPeter Avalos char *
451856ea928SPeter Avalos authorized_principals_file(struct passwd *pw)
452856ea928SPeter Avalos {
453e9778795SPeter Avalos 	if (options.authorized_principals_file == NULL)
454856ea928SPeter Avalos 		return NULL;
455856ea928SPeter Avalos 	return expand_authorized_keys(options.authorized_principals_file, pw);
456856ea928SPeter Avalos }
457856ea928SPeter Avalos 
45818de8d7fSPeter Avalos /* return ok if key exists in sysfile or userfile */
45918de8d7fSPeter Avalos HostStatus
460ce74bacaSMatthew Dillon check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
46118de8d7fSPeter Avalos     const char *sysfile, const char *userfile)
46218de8d7fSPeter Avalos {
46318de8d7fSPeter Avalos 	char *user_hostfile;
46418de8d7fSPeter Avalos 	struct stat st;
46518de8d7fSPeter Avalos 	HostStatus host_status;
4669f304aafSPeter Avalos 	struct hostkeys *hostkeys;
4679f304aafSPeter Avalos 	const struct hostkey_entry *found;
46818de8d7fSPeter Avalos 
4699f304aafSPeter Avalos 	hostkeys = init_hostkeys();
4709f304aafSPeter Avalos 	load_hostkeys(hostkeys, host, sysfile);
4719f304aafSPeter Avalos 	if (userfile != NULL) {
47218de8d7fSPeter Avalos 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
47318de8d7fSPeter Avalos 		if (options.strict_modes &&
47418de8d7fSPeter Avalos 		    (stat(user_hostfile, &st) == 0) &&
47518de8d7fSPeter Avalos 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
47618de8d7fSPeter Avalos 		    (st.st_mode & 022) != 0)) {
47718de8d7fSPeter Avalos 			logit("Authentication refused for %.100s: "
47818de8d7fSPeter Avalos 			    "bad owner or modes for %.200s",
47918de8d7fSPeter Avalos 			    pw->pw_name, user_hostfile);
480856ea928SPeter Avalos 			auth_debug_add("Ignored %.200s: bad ownership or modes",
481856ea928SPeter Avalos 			    user_hostfile);
48218de8d7fSPeter Avalos 		} else {
48318de8d7fSPeter Avalos 			temporarily_use_uid(pw);
4849f304aafSPeter Avalos 			load_hostkeys(hostkeys, host, user_hostfile);
48518de8d7fSPeter Avalos 			restore_uid();
48618de8d7fSPeter Avalos 		}
48736e94dc5SPeter Avalos 		free(user_hostfile);
48818de8d7fSPeter Avalos 	}
4899f304aafSPeter Avalos 	host_status = check_key_in_hostkeys(hostkeys, key, &found);
4909f304aafSPeter Avalos 	if (host_status == HOST_REVOKED)
4919f304aafSPeter Avalos 		error("WARNING: revoked key for %s attempted authentication",
4929f304aafSPeter Avalos 		    found->host);
4939f304aafSPeter Avalos 	else if (host_status == HOST_OK)
4949f304aafSPeter Avalos 		debug("%s: key for %s found at %s:%ld", __func__,
4959f304aafSPeter Avalos 		    found->host, found->file, found->line);
4969f304aafSPeter Avalos 	else
4979f304aafSPeter Avalos 		debug("%s: key for host %s not found", __func__, host);
49818de8d7fSPeter Avalos 
4999f304aafSPeter Avalos 	free_hostkeys(hostkeys);
5009f304aafSPeter Avalos 
50118de8d7fSPeter Avalos 	return host_status;
50218de8d7fSPeter Avalos }
50318de8d7fSPeter Avalos 
504856ea928SPeter Avalos static FILE *
505856ea928SPeter Avalos auth_openfile(const char *file, struct passwd *pw, int strict_modes,
506856ea928SPeter Avalos     int log_missing, char *file_type)
50718de8d7fSPeter Avalos {
50818de8d7fSPeter Avalos 	char line[1024];
50918de8d7fSPeter Avalos 	struct stat st;
51018de8d7fSPeter Avalos 	int fd;
51118de8d7fSPeter Avalos 	FILE *f;
51218de8d7fSPeter Avalos 
513856ea928SPeter Avalos 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
514856ea928SPeter Avalos 		if (log_missing || errno != ENOENT)
515856ea928SPeter Avalos 			debug("Could not open %s '%s': %s", file_type, file,
516856ea928SPeter Avalos 			   strerror(errno));
51718de8d7fSPeter Avalos 		return NULL;
518856ea928SPeter Avalos 	}
51918de8d7fSPeter Avalos 
52018de8d7fSPeter Avalos 	if (fstat(fd, &st) < 0) {
52118de8d7fSPeter Avalos 		close(fd);
52218de8d7fSPeter Avalos 		return NULL;
52318de8d7fSPeter Avalos 	}
52418de8d7fSPeter Avalos 	if (!S_ISREG(st.st_mode)) {
525856ea928SPeter Avalos 		logit("User %s %s %s is not a regular file",
526856ea928SPeter Avalos 		    pw->pw_name, file_type, file);
52718de8d7fSPeter Avalos 		close(fd);
52818de8d7fSPeter Avalos 		return NULL;
52918de8d7fSPeter Avalos 	}
53018de8d7fSPeter Avalos 	unset_nonblock(fd);
53118de8d7fSPeter Avalos 	if ((f = fdopen(fd, "r")) == NULL) {
53218de8d7fSPeter Avalos 		close(fd);
53318de8d7fSPeter Avalos 		return NULL;
53418de8d7fSPeter Avalos 	}
5359f304aafSPeter Avalos 	if (strict_modes &&
536ce74bacaSMatthew Dillon 	    safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
53718de8d7fSPeter Avalos 		fclose(f);
53818de8d7fSPeter Avalos 		logit("Authentication refused: %s", line);
539856ea928SPeter Avalos 		auth_debug_add("Ignored %s: %s", file_type, line);
54018de8d7fSPeter Avalos 		return NULL;
54118de8d7fSPeter Avalos 	}
54218de8d7fSPeter Avalos 
54318de8d7fSPeter Avalos 	return f;
54418de8d7fSPeter Avalos }
54518de8d7fSPeter Avalos 
546856ea928SPeter Avalos 
547856ea928SPeter Avalos FILE *
548856ea928SPeter Avalos auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
549856ea928SPeter Avalos {
550856ea928SPeter Avalos 	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
551856ea928SPeter Avalos }
552856ea928SPeter Avalos 
553856ea928SPeter Avalos FILE *
554856ea928SPeter Avalos auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
555856ea928SPeter Avalos {
556856ea928SPeter Avalos 	return auth_openfile(file, pw, strict_modes, 0,
557856ea928SPeter Avalos 	    "authorized principals");
558856ea928SPeter Avalos }
559856ea928SPeter Avalos 
56018de8d7fSPeter Avalos struct passwd *
561*664f4763Szrj getpwnamallow(struct ssh *ssh, const char *user)
56218de8d7fSPeter Avalos {
56318de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP
56418de8d7fSPeter Avalos 	extern login_cap_t *lc;
56518de8d7fSPeter Avalos #ifdef BSD_AUTH
56618de8d7fSPeter Avalos 	auth_session_t *as;
56718de8d7fSPeter Avalos #endif
56818de8d7fSPeter Avalos #endif
56918de8d7fSPeter Avalos 	struct passwd *pw;
570*664f4763Szrj 	struct connection_info *ci;
57118de8d7fSPeter Avalos 
572*664f4763Szrj 	ci = get_connection_info(ssh, 1, options.use_dns);
57399e85e0dSPeter Avalos 	ci->user = user;
57499e85e0dSPeter Avalos 	parse_server_match_config(&options, ci);
575ce74bacaSMatthew Dillon 	log_change_level(options.log_level);
576ce74bacaSMatthew Dillon 	process_permitopen(ssh, &options);
57718de8d7fSPeter Avalos 
578856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB)
579856ea928SPeter Avalos 	aix_setauthdb(user);
580856ea928SPeter Avalos #endif
581856ea928SPeter Avalos 
58218de8d7fSPeter Avalos 	pw = getpwnam(user);
583856ea928SPeter Avalos 
584856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB)
585856ea928SPeter Avalos 	aix_restoreauthdb();
586856ea928SPeter Avalos #endif
58718de8d7fSPeter Avalos 	if (pw == NULL) {
588e9778795SPeter Avalos 		logit("Invalid user %.100s from %.100s port %d",
589e9778795SPeter Avalos 		    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
59018de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN
591*664f4763Szrj 		record_failed_login(ssh, user,
592e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
59318de8d7fSPeter Avalos #endif
59418de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS
595*664f4763Szrj 		audit_event(ssh, SSH_INVALID_USER);
59618de8d7fSPeter Avalos #endif /* SSH_AUDIT_EVENTS */
59718de8d7fSPeter Avalos 		return (NULL);
59818de8d7fSPeter Avalos 	}
599*664f4763Szrj 	if (!allowed_user(ssh, pw))
60018de8d7fSPeter Avalos 		return (NULL);
60118de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP
60218de8d7fSPeter Avalos 	if ((lc = login_getclass(pw->pw_class)) == NULL) {
60318de8d7fSPeter Avalos 		debug("unable to get login class: %s", user);
60418de8d7fSPeter Avalos 		return (NULL);
60518de8d7fSPeter Avalos 	}
60618de8d7fSPeter Avalos #ifdef BSD_AUTH
60718de8d7fSPeter Avalos 	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
60818de8d7fSPeter Avalos 	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
60918de8d7fSPeter Avalos 		debug("Approval failure for %s", user);
61018de8d7fSPeter Avalos 		pw = NULL;
61118de8d7fSPeter Avalos 	}
61218de8d7fSPeter Avalos 	if (as != NULL)
61318de8d7fSPeter Avalos 		auth_close(as);
61418de8d7fSPeter Avalos #endif
61518de8d7fSPeter Avalos #endif
61618de8d7fSPeter Avalos 	if (pw != NULL)
61718de8d7fSPeter Avalos 		return (pwcopy(pw));
61818de8d7fSPeter Avalos 	return (NULL);
61918de8d7fSPeter Avalos }
62018de8d7fSPeter Avalos 
621856ea928SPeter Avalos /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
622856ea928SPeter Avalos int
623ce74bacaSMatthew Dillon auth_key_is_revoked(struct sshkey *key)
624856ea928SPeter Avalos {
625e9778795SPeter Avalos 	char *fp = NULL;
626e9778795SPeter Avalos 	int r;
627856ea928SPeter Avalos 
628856ea928SPeter Avalos 	if (options.revoked_keys_file == NULL)
629856ea928SPeter Avalos 		return 0;
630e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
631e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL) {
632e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
633e9778795SPeter Avalos 		error("%s: fingerprint key: %s", __func__, ssh_err(r));
634e9778795SPeter Avalos 		goto out;
635e9778795SPeter Avalos 	}
636e9778795SPeter Avalos 
637e9778795SPeter Avalos 	r = sshkey_check_revoked(key, options.revoked_keys_file);
638e9778795SPeter Avalos 	switch (r) {
63936e94dc5SPeter Avalos 	case 0:
640e9778795SPeter Avalos 		break; /* not revoked */
641e9778795SPeter Avalos 	case SSH_ERR_KEY_REVOKED:
642e9778795SPeter Avalos 		error("Authentication key %s %s revoked by file %s",
643e9778795SPeter Avalos 		    sshkey_type(key), fp, options.revoked_keys_file);
644e9778795SPeter Avalos 		goto out;
64536e94dc5SPeter Avalos 	default:
646e9778795SPeter Avalos 		error("Error checking authentication key %s %s in "
647e9778795SPeter Avalos 		    "revoked keys file %s: %s", sshkey_type(key), fp,
648e9778795SPeter Avalos 		    options.revoked_keys_file, ssh_err(r));
649e9778795SPeter Avalos 		goto out;
65036e94dc5SPeter Avalos 	}
651e9778795SPeter Avalos 
652e9778795SPeter Avalos 	/* Success */
653e9778795SPeter Avalos 	r = 0;
654e9778795SPeter Avalos 
655e9778795SPeter Avalos  out:
656e9778795SPeter Avalos 	free(fp);
657e9778795SPeter Avalos 	return r == 0 ? 0 : 1;
658856ea928SPeter Avalos }
659856ea928SPeter Avalos 
66018de8d7fSPeter Avalos void
66118de8d7fSPeter Avalos auth_debug_add(const char *fmt,...)
66218de8d7fSPeter Avalos {
66318de8d7fSPeter Avalos 	char buf[1024];
66418de8d7fSPeter Avalos 	va_list args;
665*664f4763Szrj 	int r;
66618de8d7fSPeter Avalos 
667*664f4763Szrj 	if (auth_debug == NULL)
66818de8d7fSPeter Avalos 		return;
66918de8d7fSPeter Avalos 
67018de8d7fSPeter Avalos 	va_start(args, fmt);
67118de8d7fSPeter Avalos 	vsnprintf(buf, sizeof(buf), fmt, args);
67218de8d7fSPeter Avalos 	va_end(args);
673*664f4763Szrj 	if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0)
674*664f4763Szrj 		fatal("%s: sshbuf_put_cstring: %s", __func__, ssh_err(r));
67518de8d7fSPeter Avalos }
67618de8d7fSPeter Avalos 
67718de8d7fSPeter Avalos void
678*664f4763Szrj auth_debug_send(struct ssh *ssh)
67918de8d7fSPeter Avalos {
68018de8d7fSPeter Avalos 	char *msg;
681*664f4763Szrj 	int r;
68218de8d7fSPeter Avalos 
683*664f4763Szrj 	if (auth_debug == NULL)
68418de8d7fSPeter Avalos 		return;
685*664f4763Szrj 	while (sshbuf_len(auth_debug) != 0) {
686*664f4763Szrj 		if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0)
687*664f4763Szrj 			fatal("%s: sshbuf_get_cstring: %s",
688*664f4763Szrj 			    __func__, ssh_err(r));
689*664f4763Szrj 		ssh_packet_send_debug(ssh, "%s", msg);
69036e94dc5SPeter Avalos 		free(msg);
69118de8d7fSPeter Avalos 	}
69218de8d7fSPeter Avalos }
69318de8d7fSPeter Avalos 
69418de8d7fSPeter Avalos void
69518de8d7fSPeter Avalos auth_debug_reset(void)
69618de8d7fSPeter Avalos {
697*664f4763Szrj 	if (auth_debug != NULL)
698*664f4763Szrj 		sshbuf_reset(auth_debug);
699*664f4763Szrj 	else if ((auth_debug = sshbuf_new()) == NULL)
700*664f4763Szrj 		fatal("%s: sshbuf_new failed", __func__);
70118de8d7fSPeter Avalos }
70218de8d7fSPeter Avalos 
70318de8d7fSPeter Avalos struct passwd *
70418de8d7fSPeter Avalos fakepw(void)
70518de8d7fSPeter Avalos {
70618de8d7fSPeter Avalos 	static struct passwd fake;
70718de8d7fSPeter Avalos 
70818de8d7fSPeter Avalos 	memset(&fake, 0, sizeof(fake));
70918de8d7fSPeter Avalos 	fake.pw_name = "NOUSER";
71018de8d7fSPeter Avalos 	fake.pw_passwd =
71118de8d7fSPeter Avalos 	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
71236e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
71318de8d7fSPeter Avalos 	fake.pw_gecos = "NOUSER";
71436e94dc5SPeter Avalos #endif
71518de8d7fSPeter Avalos 	fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
71618de8d7fSPeter Avalos 	fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
71736e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
71818de8d7fSPeter Avalos 	fake.pw_class = "";
71918de8d7fSPeter Avalos #endif
72018de8d7fSPeter Avalos 	fake.pw_dir = "/nonexist";
72118de8d7fSPeter Avalos 	fake.pw_shell = "/nonexist";
72218de8d7fSPeter Avalos 
72318de8d7fSPeter Avalos 	return (&fake);
72418de8d7fSPeter Avalos }
725e9778795SPeter Avalos 
726e9778795SPeter Avalos /*
727e9778795SPeter Avalos  * Returns the remote DNS hostname as a string. The returned string must not
728e9778795SPeter Avalos  * be freed. NB. this will usually trigger a DNS query the first time it is
729e9778795SPeter Avalos  * called.
730e9778795SPeter Avalos  * This function does additional checks on the hostname to mitigate some
731e9778795SPeter Avalos  * attacks on legacy rhosts-style authentication.
732e9778795SPeter Avalos  * XXX is RhostsRSAAuthentication vulnerable to these?
733e9778795SPeter Avalos  * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
734e9778795SPeter Avalos  */
735e9778795SPeter Avalos 
736e9778795SPeter Avalos static char *
737e9778795SPeter Avalos remote_hostname(struct ssh *ssh)
738e9778795SPeter Avalos {
739e9778795SPeter Avalos 	struct sockaddr_storage from;
740e9778795SPeter Avalos 	socklen_t fromlen;
741e9778795SPeter Avalos 	struct addrinfo hints, *ai, *aitop;
742e9778795SPeter Avalos 	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
743e9778795SPeter Avalos 	const char *ntop = ssh_remote_ipaddr(ssh);
744e9778795SPeter Avalos 
745e9778795SPeter Avalos 	/* Get IP address of client. */
746e9778795SPeter Avalos 	fromlen = sizeof(from);
747e9778795SPeter Avalos 	memset(&from, 0, sizeof(from));
748e9778795SPeter Avalos 	if (getpeername(ssh_packet_get_connection_in(ssh),
749e9778795SPeter Avalos 	    (struct sockaddr *)&from, &fromlen) < 0) {
750e9778795SPeter Avalos 		debug("getpeername failed: %.100s", strerror(errno));
751e9778795SPeter Avalos 		return strdup(ntop);
752e9778795SPeter Avalos 	}
753e9778795SPeter Avalos 
754e9778795SPeter Avalos 	ipv64_normalise_mapped(&from, &fromlen);
755e9778795SPeter Avalos 	if (from.ss_family == AF_INET6)
756e9778795SPeter Avalos 		fromlen = sizeof(struct sockaddr_in6);
757e9778795SPeter Avalos 
758e9778795SPeter Avalos 	debug3("Trying to reverse map address %.100s.", ntop);
759e9778795SPeter Avalos 	/* Map the IP address to a host name. */
760e9778795SPeter Avalos 	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
761e9778795SPeter Avalos 	    NULL, 0, NI_NAMEREQD) != 0) {
762e9778795SPeter Avalos 		/* Host name not found.  Use ip address. */
763e9778795SPeter Avalos 		return strdup(ntop);
764e9778795SPeter Avalos 	}
765e9778795SPeter Avalos 
766e9778795SPeter Avalos 	/*
767e9778795SPeter Avalos 	 * if reverse lookup result looks like a numeric hostname,
768e9778795SPeter Avalos 	 * someone is trying to trick us by PTR record like following:
769e9778795SPeter Avalos 	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
770e9778795SPeter Avalos 	 */
771e9778795SPeter Avalos 	memset(&hints, 0, sizeof(hints));
772e9778795SPeter Avalos 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
773e9778795SPeter Avalos 	hints.ai_flags = AI_NUMERICHOST;
774e9778795SPeter Avalos 	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
775e9778795SPeter Avalos 		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
776e9778795SPeter Avalos 		    name, ntop);
777e9778795SPeter Avalos 		freeaddrinfo(ai);
778e9778795SPeter Avalos 		return strdup(ntop);
779e9778795SPeter Avalos 	}
780e9778795SPeter Avalos 
781e9778795SPeter Avalos 	/* Names are stored in lowercase. */
782e9778795SPeter Avalos 	lowercase(name);
783e9778795SPeter Avalos 
784e9778795SPeter Avalos 	/*
785e9778795SPeter Avalos 	 * Map it back to an IP address and check that the given
786e9778795SPeter Avalos 	 * address actually is an address of this host.  This is
787e9778795SPeter Avalos 	 * necessary because anyone with access to a name server can
788e9778795SPeter Avalos 	 * define arbitrary names for an IP address. Mapping from
789e9778795SPeter Avalos 	 * name to IP address can be trusted better (but can still be
790e9778795SPeter Avalos 	 * fooled if the intruder has access to the name server of
791e9778795SPeter Avalos 	 * the domain).
792e9778795SPeter Avalos 	 */
793e9778795SPeter Avalos 	memset(&hints, 0, sizeof(hints));
794e9778795SPeter Avalos 	hints.ai_family = from.ss_family;
795e9778795SPeter Avalos 	hints.ai_socktype = SOCK_STREAM;
796e9778795SPeter Avalos 	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
797e9778795SPeter Avalos 		logit("reverse mapping checking getaddrinfo for %.700s "
798e9778795SPeter Avalos 		    "[%s] failed.", name, ntop);
799e9778795SPeter Avalos 		return strdup(ntop);
800e9778795SPeter Avalos 	}
801e9778795SPeter Avalos 	/* Look for the address from the list of addresses. */
802e9778795SPeter Avalos 	for (ai = aitop; ai; ai = ai->ai_next) {
803e9778795SPeter Avalos 		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
804e9778795SPeter Avalos 		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
805e9778795SPeter Avalos 		    (strcmp(ntop, ntop2) == 0))
806e9778795SPeter Avalos 				break;
807e9778795SPeter Avalos 	}
808e9778795SPeter Avalos 	freeaddrinfo(aitop);
809e9778795SPeter Avalos 	/* If we reached the end of the list, the address was not there. */
810e9778795SPeter Avalos 	if (ai == NULL) {
811e9778795SPeter Avalos 		/* Address not found for the host name. */
812e9778795SPeter Avalos 		logit("Address %.100s maps to %.600s, but this does not "
813e9778795SPeter Avalos 		    "map back to the address.", ntop, name);
814e9778795SPeter Avalos 		return strdup(ntop);
815e9778795SPeter Avalos 	}
816e9778795SPeter Avalos 	return strdup(name);
817e9778795SPeter Avalos }
818e9778795SPeter Avalos 
819e9778795SPeter Avalos /*
820e9778795SPeter Avalos  * Return the canonical name of the host in the other side of the current
821e9778795SPeter Avalos  * connection.  The host name is cached, so it is efficient to call this
822e9778795SPeter Avalos  * several times.
823e9778795SPeter Avalos  */
824e9778795SPeter Avalos 
825e9778795SPeter Avalos const char *
826e9778795SPeter Avalos auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
827e9778795SPeter Avalos {
828e9778795SPeter Avalos 	static char *dnsname;
829e9778795SPeter Avalos 
830e9778795SPeter Avalos 	if (!use_dns)
831e9778795SPeter Avalos 		return ssh_remote_ipaddr(ssh);
832e9778795SPeter Avalos 	else if (dnsname != NULL)
833e9778795SPeter Avalos 		return dnsname;
834e9778795SPeter Avalos 	else {
835e9778795SPeter Avalos 		dnsname = remote_hostname(ssh);
836e9778795SPeter Avalos 		return dnsname;
837e9778795SPeter Avalos 	}
838e9778795SPeter Avalos }
839*664f4763Szrj 
840*664f4763Szrj /*
841*664f4763Szrj  * Runs command in a subprocess with a minimal environment.
842*664f4763Szrj  * Returns pid on success, 0 on failure.
843*664f4763Szrj  * The child stdout and stderr maybe captured, left attached or sent to
844*664f4763Szrj  * /dev/null depending on the contents of flags.
845*664f4763Szrj  * "tag" is prepended to log messages.
846*664f4763Szrj  * NB. "command" is only used for logging; the actual command executed is
847*664f4763Szrj  * av[0].
848*664f4763Szrj  */
849*664f4763Szrj pid_t
850*664f4763Szrj subprocess(const char *tag, struct passwd *pw, const char *command,
851*664f4763Szrj     int ac, char **av, FILE **child, u_int flags)
852*664f4763Szrj {
853*664f4763Szrj 	FILE *f = NULL;
854*664f4763Szrj 	struct stat st;
855*664f4763Szrj 	int fd, devnull, p[2], i;
856*664f4763Szrj 	pid_t pid;
857*664f4763Szrj 	char *cp, errmsg[512];
858*664f4763Szrj 	u_int envsize;
859*664f4763Szrj 	char **child_env;
860*664f4763Szrj 
861*664f4763Szrj 	if (child != NULL)
862*664f4763Szrj 		*child = NULL;
863*664f4763Szrj 
864*664f4763Szrj 	debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__,
865*664f4763Szrj 	    tag, command, pw->pw_name, flags);
866*664f4763Szrj 
867*664f4763Szrj 	/* Check consistency */
868*664f4763Szrj 	if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
869*664f4763Szrj 	    (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
870*664f4763Szrj 		error("%s: inconsistent flags", __func__);
871*664f4763Szrj 		return 0;
872*664f4763Szrj 	}
873*664f4763Szrj 	if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
874*664f4763Szrj 		error("%s: inconsistent flags/output", __func__);
875*664f4763Szrj 		return 0;
876*664f4763Szrj 	}
877*664f4763Szrj 
878*664f4763Szrj 	/*
879*664f4763Szrj 	 * If executing an explicit binary, then verify the it exists
880*664f4763Szrj 	 * and appears safe-ish to execute
881*664f4763Szrj 	 */
882*664f4763Szrj 	if (!path_absolute(av[0])) {
883*664f4763Szrj 		error("%s path is not absolute", tag);
884*664f4763Szrj 		return 0;
885*664f4763Szrj 	}
886*664f4763Szrj 	temporarily_use_uid(pw);
887*664f4763Szrj 	if (stat(av[0], &st) < 0) {
888*664f4763Szrj 		error("Could not stat %s \"%s\": %s", tag,
889*664f4763Szrj 		    av[0], strerror(errno));
890*664f4763Szrj 		restore_uid();
891*664f4763Szrj 		return 0;
892*664f4763Szrj 	}
893*664f4763Szrj 	if (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
894*664f4763Szrj 		error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
895*664f4763Szrj 		restore_uid();
896*664f4763Szrj 		return 0;
897*664f4763Szrj 	}
898*664f4763Szrj 	/* Prepare to keep the child's stdout if requested */
899*664f4763Szrj 	if (pipe(p) != 0) {
900*664f4763Szrj 		error("%s: pipe: %s", tag, strerror(errno));
901*664f4763Szrj 		restore_uid();
902*664f4763Szrj 		return 0;
903*664f4763Szrj 	}
904*664f4763Szrj 	restore_uid();
905*664f4763Szrj 
906*664f4763Szrj 	switch ((pid = fork())) {
907*664f4763Szrj 	case -1: /* error */
908*664f4763Szrj 		error("%s: fork: %s", tag, strerror(errno));
909*664f4763Szrj 		close(p[0]);
910*664f4763Szrj 		close(p[1]);
911*664f4763Szrj 		return 0;
912*664f4763Szrj 	case 0: /* child */
913*664f4763Szrj 		/* Prepare a minimal environment for the child. */
914*664f4763Szrj 		envsize = 5;
915*664f4763Szrj 		child_env = xcalloc(sizeof(*child_env), envsize);
916*664f4763Szrj 		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
917*664f4763Szrj 		child_set_env(&child_env, &envsize, "USER", pw->pw_name);
918*664f4763Szrj 		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
919*664f4763Szrj 		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
920*664f4763Szrj 		if ((cp = getenv("LANG")) != NULL)
921*664f4763Szrj 			child_set_env(&child_env, &envsize, "LANG", cp);
922*664f4763Szrj 
923*664f4763Szrj 		for (i = 0; i < NSIG; i++)
924*664f4763Szrj 			signal(i, SIG_DFL);
925*664f4763Szrj 
926*664f4763Szrj 		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
927*664f4763Szrj 			error("%s: open %s: %s", tag, _PATH_DEVNULL,
928*664f4763Szrj 			    strerror(errno));
929*664f4763Szrj 			_exit(1);
930*664f4763Szrj 		}
931*664f4763Szrj 		if (dup2(devnull, STDIN_FILENO) == -1) {
932*664f4763Szrj 			error("%s: dup2: %s", tag, strerror(errno));
933*664f4763Szrj 			_exit(1);
934*664f4763Szrj 		}
935*664f4763Szrj 
936*664f4763Szrj 		/* Set up stdout as requested; leave stderr in place for now. */
937*664f4763Szrj 		fd = -1;
938*664f4763Szrj 		if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
939*664f4763Szrj 			fd = p[1];
940*664f4763Szrj 		else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
941*664f4763Szrj 			fd = devnull;
942*664f4763Szrj 		if (fd != -1 && dup2(fd, STDOUT_FILENO) == -1) {
943*664f4763Szrj 			error("%s: dup2: %s", tag, strerror(errno));
944*664f4763Szrj 			_exit(1);
945*664f4763Szrj 		}
946*664f4763Szrj 		closefrom(STDERR_FILENO + 1);
947*664f4763Szrj 
948*664f4763Szrj 		/* Don't use permanently_set_uid() here to avoid fatal() */
949*664f4763Szrj 		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
950*664f4763Szrj 			error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
951*664f4763Szrj 			    strerror(errno));
952*664f4763Szrj 			_exit(1);
953*664f4763Szrj 		}
954*664f4763Szrj 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
955*664f4763Szrj 			error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
956*664f4763Szrj 			    strerror(errno));
957*664f4763Szrj 			_exit(1);
958*664f4763Szrj 		}
959*664f4763Szrj 		/* stdin is pointed to /dev/null at this point */
960*664f4763Szrj 		if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
961*664f4763Szrj 		    dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
962*664f4763Szrj 			error("%s: dup2: %s", tag, strerror(errno));
963*664f4763Szrj 			_exit(1);
964*664f4763Szrj 		}
965*664f4763Szrj 
966*664f4763Szrj 		execve(av[0], av, child_env);
967*664f4763Szrj 		error("%s exec \"%s\": %s", tag, command, strerror(errno));
968*664f4763Szrj 		_exit(127);
969*664f4763Szrj 	default: /* parent */
970*664f4763Szrj 		break;
971*664f4763Szrj 	}
972*664f4763Szrj 
973*664f4763Szrj 	close(p[1]);
974*664f4763Szrj 	if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
975*664f4763Szrj 		close(p[0]);
976*664f4763Szrj 	else if ((f = fdopen(p[0], "r")) == NULL) {
977*664f4763Szrj 		error("%s: fdopen: %s", tag, strerror(errno));
978*664f4763Szrj 		close(p[0]);
979*664f4763Szrj 		/* Don't leave zombie child */
980*664f4763Szrj 		kill(pid, SIGTERM);
981*664f4763Szrj 		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
982*664f4763Szrj 			;
983*664f4763Szrj 		return 0;
984*664f4763Szrj 	}
985*664f4763Szrj 	/* Success */
986*664f4763Szrj 	debug3("%s: %s pid %ld", __func__, tag, (long)pid);
987*664f4763Szrj 	if (child != NULL)
988*664f4763Szrj 		*child = f;
989*664f4763Szrj 	return pid;
990*664f4763Szrj }
991*664f4763Szrj 
992*664f4763Szrj /* These functions link key/cert options to the auth framework */
993*664f4763Szrj 
994*664f4763Szrj /* Log sshauthopt options locally and (optionally) for remote transmission */
995*664f4763Szrj void
996*664f4763Szrj auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
997*664f4763Szrj {
998*664f4763Szrj 	int do_env = options.permit_user_env && opts->nenv > 0;
999*664f4763Szrj 	int do_permitopen = opts->npermitopen > 0 &&
1000*664f4763Szrj 	    (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
1001*664f4763Szrj 	int do_permitlisten = opts->npermitlisten > 0 &&
1002*664f4763Szrj 	    (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
1003*664f4763Szrj 	size_t i;
1004*664f4763Szrj 	char msg[1024], buf[64];
1005*664f4763Szrj 
1006*664f4763Szrj 	snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
1007*664f4763Szrj 	/* Try to keep this alphabetically sorted */
1008*664f4763Szrj 	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s",
1009*664f4763Szrj 	    opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
1010*664f4763Szrj 	    opts->force_command == NULL ? "" : " command",
1011*664f4763Szrj 	    do_env ?  " environment" : "",
1012*664f4763Szrj 	    opts->valid_before == 0 ? "" : "expires",
1013*664f4763Szrj 	    do_permitopen ?  " permitopen" : "",
1014*664f4763Szrj 	    do_permitlisten ?  " permitlisten" : "",
1015*664f4763Szrj 	    opts->permit_port_forwarding_flag ? " port-forwarding" : "",
1016*664f4763Szrj 	    opts->cert_principals == NULL ? "" : " principals",
1017*664f4763Szrj 	    opts->permit_pty_flag ? " pty" : "",
1018*664f4763Szrj 	    opts->force_tun_device == -1 ? "" : " tun=",
1019*664f4763Szrj 	    opts->force_tun_device == -1 ? "" : buf,
1020*664f4763Szrj 	    opts->permit_user_rc ? " user-rc" : "",
1021*664f4763Szrj 	    opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
1022*664f4763Szrj 
1023*664f4763Szrj 	debug("%s: %s", loc, msg);
1024*664f4763Szrj 	if (do_remote)
1025*664f4763Szrj 		auth_debug_add("%s: %s", loc, msg);
1026*664f4763Szrj 
1027*664f4763Szrj 	if (options.permit_user_env) {
1028*664f4763Szrj 		for (i = 0; i < opts->nenv; i++) {
1029*664f4763Szrj 			debug("%s: environment: %s", loc, opts->env[i]);
1030*664f4763Szrj 			if (do_remote) {
1031*664f4763Szrj 				auth_debug_add("%s: environment: %s",
1032*664f4763Szrj 				    loc, opts->env[i]);
1033*664f4763Szrj 			}
1034*664f4763Szrj 		}
1035*664f4763Szrj 	}
1036*664f4763Szrj 
1037*664f4763Szrj 	/* Go into a little more details for the local logs. */
1038*664f4763Szrj 	if (opts->valid_before != 0) {
1039*664f4763Szrj 		format_absolute_time(opts->valid_before, buf, sizeof(buf));
1040*664f4763Szrj 		debug("%s: expires at %s", loc, buf);
1041*664f4763Szrj 	}
1042*664f4763Szrj 	if (opts->cert_principals != NULL) {
1043*664f4763Szrj 		debug("%s: authorized principals: \"%s\"",
1044*664f4763Szrj 		    loc, opts->cert_principals);
1045*664f4763Szrj 	}
1046*664f4763Szrj 	if (opts->force_command != NULL)
1047*664f4763Szrj 		debug("%s: forced command: \"%s\"", loc, opts->force_command);
1048*664f4763Szrj 	if (do_permitopen) {
1049*664f4763Szrj 		for (i = 0; i < opts->npermitopen; i++) {
1050*664f4763Szrj 			debug("%s: permitted open: %s",
1051*664f4763Szrj 			    loc, opts->permitopen[i]);
1052*664f4763Szrj 		}
1053*664f4763Szrj 	}
1054*664f4763Szrj 	if (do_permitlisten) {
1055*664f4763Szrj 		for (i = 0; i < opts->npermitlisten; i++) {
1056*664f4763Szrj 			debug("%s: permitted listen: %s",
1057*664f4763Szrj 			    loc, opts->permitlisten[i]);
1058*664f4763Szrj 		}
1059*664f4763Szrj 	}
1060*664f4763Szrj }
1061*664f4763Szrj 
1062*664f4763Szrj /* Activate a new set of key/cert options; merging with what is there. */
1063*664f4763Szrj int
1064*664f4763Szrj auth_activate_options(struct ssh *ssh, struct sshauthopt *opts)
1065*664f4763Szrj {
1066*664f4763Szrj 	struct sshauthopt *old = auth_opts;
1067*664f4763Szrj 	const char *emsg = NULL;
1068*664f4763Szrj 
1069*664f4763Szrj 	debug("%s: setting new authentication options", __func__);
1070*664f4763Szrj 	if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) {
1071*664f4763Szrj 		error("Inconsistent authentication options: %s", emsg);
1072*664f4763Szrj 		return -1;
1073*664f4763Szrj 	}
1074*664f4763Szrj 	return 0;
1075*664f4763Szrj }
1076*664f4763Szrj 
1077*664f4763Szrj /* Disable forwarding, etc for the session */
1078*664f4763Szrj void
1079*664f4763Szrj auth_restrict_session(struct ssh *ssh)
1080*664f4763Szrj {
1081*664f4763Szrj 	struct sshauthopt *restricted;
1082*664f4763Szrj 
1083*664f4763Szrj 	debug("%s: restricting session", __func__);
1084*664f4763Szrj 
1085*664f4763Szrj 	/* A blank sshauthopt defaults to permitting nothing */
1086*664f4763Szrj 	restricted = sshauthopt_new();
1087*664f4763Szrj 	restricted->permit_pty_flag = 1;
1088*664f4763Szrj 	restricted->restricted = 1;
1089*664f4763Szrj 
1090*664f4763Szrj 	if (auth_activate_options(ssh, restricted) != 0)
1091*664f4763Szrj 		fatal("%s: failed to restrict session", __func__);
1092*664f4763Szrj 	sshauthopt_free(restricted);
1093*664f4763Szrj }
1094*664f4763Szrj 
1095*664f4763Szrj int
1096*664f4763Szrj auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw,
1097*664f4763Szrj     struct sshauthopt *opts, int allow_cert_authority, const char *loc)
1098*664f4763Szrj {
1099*664f4763Szrj 	const char *remote_ip = ssh_remote_ipaddr(ssh);
1100*664f4763Szrj 	const char *remote_host = auth_get_canonical_hostname(ssh,
1101*664f4763Szrj 	    options.use_dns);
1102*664f4763Szrj 	time_t now = time(NULL);
1103*664f4763Szrj 	char buf[64];
1104*664f4763Szrj 
1105*664f4763Szrj 	/*
1106*664f4763Szrj 	 * Check keys/principals file expiry time.
1107*664f4763Szrj 	 * NB. validity interval in certificate is handled elsewhere.
1108*664f4763Szrj 	 */
1109*664f4763Szrj 	if (opts->valid_before && now > 0 &&
1110*664f4763Szrj 	    opts->valid_before < (uint64_t)now) {
1111*664f4763Szrj 		format_absolute_time(opts->valid_before, buf, sizeof(buf));
1112*664f4763Szrj 		debug("%s: entry expired at %s", loc, buf);
1113*664f4763Szrj 		auth_debug_add("%s: entry expired at %s", loc, buf);
1114*664f4763Szrj 		return -1;
1115*664f4763Szrj 	}
1116*664f4763Szrj 	/* Consistency checks */
1117*664f4763Szrj 	if (opts->cert_principals != NULL && !opts->cert_authority) {
1118*664f4763Szrj 		debug("%s: principals on non-CA key", loc);
1119*664f4763Szrj 		auth_debug_add("%s: principals on non-CA key", loc);
1120*664f4763Szrj 		/* deny access */
1121*664f4763Szrj 		return -1;
1122*664f4763Szrj 	}
1123*664f4763Szrj 	/* cert-authority flag isn't valid in authorized_principals files */
1124*664f4763Szrj 	if (!allow_cert_authority && opts->cert_authority) {
1125*664f4763Szrj 		debug("%s: cert-authority flag invalid here", loc);
1126*664f4763Szrj 		auth_debug_add("%s: cert-authority flag invalid here", loc);
1127*664f4763Szrj 		/* deny access */
1128*664f4763Szrj 		return -1;
1129*664f4763Szrj 	}
1130*664f4763Szrj 
1131*664f4763Szrj 	/* Perform from= checks */
1132*664f4763Szrj 	if (opts->required_from_host_keys != NULL) {
1133*664f4763Szrj 		switch (match_host_and_ip(remote_host, remote_ip,
1134*664f4763Szrj 		    opts->required_from_host_keys )) {
1135*664f4763Szrj 		case 1:
1136*664f4763Szrj 			/* Host name matches. */
1137*664f4763Szrj 			break;
1138*664f4763Szrj 		case -1:
1139*664f4763Szrj 		default:
1140*664f4763Szrj 			debug("%s: invalid from criteria", loc);
1141*664f4763Szrj 			auth_debug_add("%s: invalid from criteria", loc);
1142*664f4763Szrj 			/* FALLTHROUGH */
1143*664f4763Szrj 		case 0:
1144*664f4763Szrj 			logit("%s: Authentication tried for %.100s with "
1145*664f4763Szrj 			    "correct key but not from a permitted "
1146*664f4763Szrj 			    "host (host=%.200s, ip=%.200s, required=%.200s).",
1147*664f4763Szrj 			    loc, pw->pw_name, remote_host, remote_ip,
1148*664f4763Szrj 			    opts->required_from_host_keys);
1149*664f4763Szrj 			auth_debug_add("%s: Your host '%.200s' is not "
1150*664f4763Szrj 			    "permitted to use this key for login.",
1151*664f4763Szrj 			    loc, remote_host);
1152*664f4763Szrj 			/* deny access */
1153*664f4763Szrj 			return -1;
1154*664f4763Szrj 		}
1155*664f4763Szrj 	}
1156*664f4763Szrj 	/* Check source-address restriction from certificate */
1157*664f4763Szrj 	if (opts->required_from_host_cert != NULL) {
1158*664f4763Szrj 		switch (addr_match_cidr_list(remote_ip,
1159*664f4763Szrj 		    opts->required_from_host_cert)) {
1160*664f4763Szrj 		case 1:
1161*664f4763Szrj 			/* accepted */
1162*664f4763Szrj 			break;
1163*664f4763Szrj 		case -1:
1164*664f4763Szrj 		default:
1165*664f4763Szrj 			/* invalid */
1166*664f4763Szrj 			error("%s: Certificate source-address invalid",
1167*664f4763Szrj 			    loc);
1168*664f4763Szrj 			/* FALLTHROUGH */
1169*664f4763Szrj 		case 0:
1170*664f4763Szrj 			logit("%s: Authentication tried for %.100s with valid "
1171*664f4763Szrj 			    "certificate but not from a permitted source "
1172*664f4763Szrj 			    "address (%.200s).", loc, pw->pw_name, remote_ip);
1173*664f4763Szrj 			auth_debug_add("%s: Your address '%.200s' is not "
1174*664f4763Szrj 			    "permitted to use this certificate for login.",
1175*664f4763Szrj 			    loc, remote_ip);
1176*664f4763Szrj 			return -1;
1177*664f4763Szrj 		}
1178*664f4763Szrj 	}
1179*664f4763Szrj 	/*
1180*664f4763Szrj 	 *
1181*664f4763Szrj 	 * XXX this is spammy. We should report remotely only for keys
1182*664f4763Szrj 	 *     that are successful in actual auth attempts, and not PK_OK
1183*664f4763Szrj 	 *     tests.
1184*664f4763Szrj 	 */
1185*664f4763Szrj 	auth_log_authopts(loc, opts, 1);
1186*664f4763Szrj 
1187*664f4763Szrj 	return 0;
1188*664f4763Szrj }
1189