xref: /openssh-portable/auth.c (revision 31d8d231)
1*31d8d231Sdjm@openbsd.org /* $OpenBSD: auth.c,v 1.152 2021/04/03 06:18:40 djm Exp $ */
2116e6dfaSDamien Miller /*
3efb4afe0SDamien Miller  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4e4340be5SDamien Miller  *
5e4340be5SDamien Miller  * Redistribution and use in source and binary forms, with or without
6e4340be5SDamien Miller  * modification, are permitted provided that the following conditions
7e4340be5SDamien Miller  * are met:
8e4340be5SDamien Miller  * 1. Redistributions of source code must retain the above copyright
9e4340be5SDamien Miller  *    notice, this list of conditions and the following disclaimer.
10e4340be5SDamien Miller  * 2. Redistributions in binary form must reproduce the above copyright
11e4340be5SDamien Miller  *    notice, this list of conditions and the following disclaimer in the
12e4340be5SDamien Miller  *    documentation and/or other materials provided with the distribution.
13e4340be5SDamien Miller  *
14e4340be5SDamien Miller  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e4340be5SDamien Miller  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e4340be5SDamien Miller  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e4340be5SDamien Miller  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e4340be5SDamien Miller  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e4340be5SDamien Miller  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e4340be5SDamien Miller  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e4340be5SDamien Miller  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e4340be5SDamien Miller  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e4340be5SDamien Miller  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24b38eff8eSDamien Miller  */
25b38eff8eSDamien Miller 
26b38eff8eSDamien Miller #include "includes.h"
27f17883e6SDamien Miller 
28f17883e6SDamien Miller #include <sys/types.h>
29f17883e6SDamien Miller #include <sys/stat.h>
3095767262Sdjm@openbsd.org #include <sys/socket.h>
3125cf9105Smarkus@openbsd.org #include <sys/wait.h>
32b38eff8eSDamien Miller 
3336cbe41cSDamien Miller #include <netinet/in.h>
3436cbe41cSDamien Miller 
35be02d7cbSdjm@openbsd.org #include <stdlib.h>
3639972493SDarren Tucker #include <errno.h>
3733c787f2SDarren Tucker #include <fcntl.h>
3803e2003aSDamien Miller #ifdef HAVE_PATHS_H
3903e2003aSDamien Miller # include <paths.h>
4003e2003aSDamien Miller #endif
419f2abc47SDamien Miller #include <pwd.h>
42d2c208a2SDamien Miller #ifdef HAVE_LOGIN_H
43d2c208a2SDamien Miller #include <login.h>
44d2c208a2SDamien Miller #endif
4515ee748fSDarren Tucker #ifdef USE_SHADOW
461f335fb8SDamien Miller #include <shadow.h>
4715ee748fSDarren Tucker #endif
485d19626aSDarren Tucker #include <stdarg.h>
49a7a73ee3SDamien Miller #include <stdio.h>
50e3476ed0SDamien Miller #include <string.h>
517acf550aSDamien Miller #include <unistd.h>
52087266ecSderaadt@openbsd.org #include <limits.h>
5395767262Sdjm@openbsd.org #include <netdb.h>
54943d0965Sdjm@openbsd.org #include <time.h>
55bfb3a0e9SBen Lindstrom 
56226cfa03SBen Lindstrom #include "xmalloc.h"
57226cfa03SBen Lindstrom #include "match.h"
58226cfa03SBen Lindstrom #include "groupaccess.h"
59226cfa03SBen Lindstrom #include "log.h"
60c7d39ac8Smarkus@openbsd.org #include "sshbuf.h"
617acefbbcSDamien Miller #include "misc.h"
62226cfa03SBen Lindstrom #include "servconf.h"
63c7d39ac8Smarkus@openbsd.org #include "sshkey.h"
64d7834353SDamien Miller #include "hostfile.h"
65efb4afe0SDamien Miller #include "auth.h"
66db65e8fdSBen Lindstrom #include "auth-options.h"
67226cfa03SBen Lindstrom #include "canohost.h"
6883647ce4SBen Lindstrom #include "uidswap.h"
69a574cda4SBen Lindstrom #include "packet.h"
7042d9dc75SDarren Tucker #include "loginrec.h"
71d7834353SDamien Miller #ifdef GSSAPI
72d7834353SDamien Miller #include "ssh-gss.h"
73d7834353SDamien Miller #endif
741aed65ebSDamien Miller #include "authfile.h"
75269a1ea1SDarren Tucker #include "monitor_wrap.h"
765e39a499Sdjm@openbsd.org #include "ssherr.h"
770acca379SDarren Tucker #include "compat.h"
787c856857Sdjm@openbsd.org #include "channels.h"
79efb4afe0SDamien Miller 
80b38eff8eSDamien Miller /* import */
81b38eff8eSDamien Miller extern ServerOptions options;
82c2bd7f74Sdjm@openbsd.org extern struct include_list includes;
837a8f5b33SDamien Miller extern int use_privsep;
84120a1ec7SDamien Miller extern struct sshbuf *loginmsg;
856433df03SDamien Miller extern struct passwd *privsep_pw;
867c856857Sdjm@openbsd.org extern struct sshauthopt *auth_opts;
87b38eff8eSDamien Miller 
88a574cda4SBen Lindstrom /* Debugging messages */
89c7d39ac8Smarkus@openbsd.org static struct sshbuf *auth_debug;
90a574cda4SBen Lindstrom 
91b38eff8eSDamien Miller /*
927b61cfa1SKevin Steves  * Check if the user is allowed to log in via ssh. If user is listed
937b61cfa1SKevin Steves  * in DenyUsers or one of user's groups is listed in DenyGroups, false
947b61cfa1SKevin Steves  * will be returned. If AllowUsers isn't empty and user isn't listed
957b61cfa1SKevin Steves  * there, or if AllowGroups isn't empty and one of user's groups isn't
967b61cfa1SKevin Steves  * listed there, false will be returned.
97b38eff8eSDamien Miller  * If the user's shell is not executable, false will be returned.
98b38eff8eSDamien Miller  * Otherwise true is returned.
99b38eff8eSDamien Miller  */
100eba71babSDamien Miller int
allowed_user(struct ssh * ssh,struct passwd * pw)1013a00a921Sdjm@openbsd.org allowed_user(struct ssh *ssh, struct passwd * pw)
102b38eff8eSDamien Miller {
103b38eff8eSDamien Miller 	struct stat st;
10443a0dc66SDarren Tucker 	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
105eccb9de7SDamien Miller 	u_int i;
106010359b3Sdjm@openbsd.org 	int r;
10715ee748fSDarren Tucker #ifdef USE_SHADOW
108e41bba58SDarren Tucker 	struct spwd *spw = NULL;
109458c6bfaSTim Rice #endif
110b38eff8eSDamien Miller 
111b38eff8eSDamien Miller 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
1127b61cfa1SKevin Steves 	if (!pw || !pw->pw_name)
113b38eff8eSDamien Miller 		return 0;
114b38eff8eSDamien Miller 
11515ee748fSDarren Tucker #ifdef USE_SHADOW
116e41bba58SDarren Tucker 	if (!options.use_pam)
117e41bba58SDarren Tucker 		spw = getspnam(pw->pw_name);
118e41bba58SDarren Tucker #ifdef HAS_SHADOW_EXPIRE
11915ee748fSDarren Tucker 	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
1201f335fb8SDamien Miller 		return 0;
121e41bba58SDarren Tucker #endif /* HAS_SHADOW_EXPIRE */
12215ee748fSDarren Tucker #endif /* USE_SHADOW */
123e41bba58SDarren Tucker 
124e41bba58SDarren Tucker 	/* grab passwd field for locked account check */
12522989f1bSDamien Miller 	passwd = pw->pw_passwd;
12615ee748fSDarren Tucker #ifdef USE_SHADOW
127e41bba58SDarren Tucker 	if (spw != NULL)
12899203ec4STim Rice #ifdef USE_LIBIAF
1292291c00aSTim Rice 		passwd = get_iaf_password(pw);
1302291c00aSTim Rice #else
131e41bba58SDarren Tucker 		passwd = spw->sp_pwdp;
13299203ec4STim Rice #endif /* USE_LIBIAF */
13348cb8aa9SDamien Miller #endif
13464004b55SDamien Miller 
135e41bba58SDarren Tucker 	/* check for locked account */
13643a0dc66SDarren Tucker 	if (!options.use_pam && passwd && *passwd) {
137e41bba58SDarren Tucker 		int locked = 0;
138e41bba58SDarren Tucker 
139e41bba58SDarren Tucker #ifdef LOCKED_PASSWD_STRING
140e41bba58SDarren Tucker 		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
141e41bba58SDarren Tucker 			 locked = 1;
142e41bba58SDarren Tucker #endif
143e41bba58SDarren Tucker #ifdef LOCKED_PASSWD_PREFIX
144e41bba58SDarren Tucker 		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
145e41bba58SDarren Tucker 		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
146e41bba58SDarren Tucker 			 locked = 1;
147e41bba58SDarren Tucker #endif
148e41bba58SDarren Tucker #ifdef LOCKED_PASSWD_SUBSTR
149e41bba58SDarren Tucker 		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
150e41bba58SDarren Tucker 			locked = 1;
151e41bba58SDarren Tucker #endif
15299203ec4STim Rice #ifdef USE_LIBIAF
153ad7d547aSTim Rice 		free((void *) passwd);
15499203ec4STim Rice #endif /* USE_LIBIAF */
155e41bba58SDarren Tucker 		if (locked) {
156e41bba58SDarren Tucker 			logit("User %.100s not allowed because account is locked",
157e41bba58SDarren Tucker 			    pw->pw_name);
158e41bba58SDarren Tucker 			return 0;
159e41bba58SDarren Tucker 		}
160e41bba58SDarren Tucker 	}
161e41bba58SDarren Tucker 
162ef7df540SDamien Miller 	/*
16347cf16b8SDamien Miller 	 * Deny if shell does not exist or is not executable unless we
16447cf16b8SDamien Miller 	 * are chrooting.
165ef7df540SDamien Miller 	 */
16647cf16b8SDamien Miller 	if (options.chroot_directory == NULL ||
16747cf16b8SDamien Miller 	    strcasecmp(options.chroot_directory, "none") == 0) {
16847cf16b8SDamien Miller 		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
16947cf16b8SDamien Miller 		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
17094881d8dSDarren Tucker 
1714d28fa78Sderaadt@openbsd.org 		if (stat(shell, &st) == -1) {
17247cf16b8SDamien Miller 			logit("User %.100s not allowed because shell %.100s "
17347cf16b8SDamien Miller 			    "does not exist", pw->pw_name, shell);
174a627d42eSDarren Tucker 			free(shell);
175b38eff8eSDamien Miller 			return 0;
1766ef9ec6bSBen Lindstrom 		}
177b61e6df9SBen Lindstrom 		if (S_ISREG(st.st_mode) == 0 ||
178b61e6df9SBen Lindstrom 		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
17947cf16b8SDamien Miller 			logit("User %.100s not allowed because shell %.100s "
18047cf16b8SDamien Miller 			    "is not executable", pw->pw_name, shell);
181a627d42eSDarren Tucker 			free(shell);
182b38eff8eSDamien Miller 			return 0;
1836ef9ec6bSBen Lindstrom 		}
184a627d42eSDarren Tucker 		free(shell);
18547cf16b8SDamien Miller 	}
186b38eff8eSDamien Miller 
187a8f553dfSDarren Tucker 	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
188a8f553dfSDarren Tucker 	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
18995767262Sdjm@openbsd.org 		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
19095767262Sdjm@openbsd.org 		ipaddr = ssh_remote_ipaddr(ssh);
1913fb5d00fSBen Lindstrom 	}
1923fb5d00fSBen Lindstrom 
193b38eff8eSDamien Miller 	/* Return false if user is listed in DenyUsers */
194b38eff8eSDamien Miller 	if (options.num_deny_users > 0) {
195fe06b68fSdtucker@openbsd.org 		for (i = 0; i < options.num_deny_users; i++) {
196010359b3Sdjm@openbsd.org 			r = match_user(pw->pw_name, hostname, ipaddr,
197010359b3Sdjm@openbsd.org 			    options.deny_users[i]);
198010359b3Sdjm@openbsd.org 			if (r < 0) {
199010359b3Sdjm@openbsd.org 				fatal("Invalid DenyUsers pattern \"%.100s\"",
200010359b3Sdjm@openbsd.org 				    options.deny_users[i]);
2011a6f9d2eSdjm@openbsd.org 			} else if (r != 0) {
202094cd0baSDarren Tucker 				logit("User %.100s from %.100s not allowed "
203094cd0baSDarren Tucker 				    "because listed in DenyUsers",
204094cd0baSDarren Tucker 				    pw->pw_name, hostname);
205b38eff8eSDamien Miller 				return 0;
206b38eff8eSDamien Miller 			}
2076ef9ec6bSBen Lindstrom 		}
208fe06b68fSdtucker@openbsd.org 	}
209b38eff8eSDamien Miller 	/* Return false if AllowUsers isn't empty and user isn't listed there */
210b38eff8eSDamien Miller 	if (options.num_allow_users > 0) {
211010359b3Sdjm@openbsd.org 		for (i = 0; i < options.num_allow_users; i++) {
212010359b3Sdjm@openbsd.org 			r = match_user(pw->pw_name, hostname, ipaddr,
213010359b3Sdjm@openbsd.org 			    options.allow_users[i]);
214010359b3Sdjm@openbsd.org 			if (r < 0) {
215010359b3Sdjm@openbsd.org 				fatal("Invalid AllowUsers pattern \"%.100s\"",
216010359b3Sdjm@openbsd.org 				    options.allow_users[i]);
217010359b3Sdjm@openbsd.org 			} else if (r == 1)
218b38eff8eSDamien Miller 				break;
219010359b3Sdjm@openbsd.org 		}
220b38eff8eSDamien Miller 		/* i < options.num_allow_users iff we break for loop */
2216ef9ec6bSBen Lindstrom 		if (i >= options.num_allow_users) {
222094cd0baSDarren Tucker 			logit("User %.100s from %.100s not allowed because "
223094cd0baSDarren Tucker 			    "not listed in AllowUsers", pw->pw_name, hostname);
224b38eff8eSDamien Miller 			return 0;
225b38eff8eSDamien Miller 		}
2266ef9ec6bSBen Lindstrom 	}
227b38eff8eSDamien Miller 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
2287b61cfa1SKevin Steves 		/* Get the user's group access list (primary and supplementary) */
2296ef9ec6bSBen Lindstrom 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
230094cd0baSDarren Tucker 			logit("User %.100s from %.100s not allowed because "
231094cd0baSDarren Tucker 			    "not in any group", pw->pw_name, hostname);
232b38eff8eSDamien Miller 			return 0;
2336ef9ec6bSBen Lindstrom 		}
234b38eff8eSDamien Miller 
2357b61cfa1SKevin Steves 		/* Return false if one of user's groups is listed in DenyGroups */
2367b61cfa1SKevin Steves 		if (options.num_deny_groups > 0)
2377b61cfa1SKevin Steves 			if (ga_match(options.deny_groups,
2387b61cfa1SKevin Steves 			    options.num_deny_groups)) {
2397b61cfa1SKevin Steves 				ga_free();
240094cd0baSDarren Tucker 				logit("User %.100s from %.100s not allowed "
241094cd0baSDarren Tucker 				    "because a group is listed in DenyGroups",
242094cd0baSDarren Tucker 				    pw->pw_name, hostname);
243b38eff8eSDamien Miller 				return 0;
244b38eff8eSDamien Miller 			}
245b38eff8eSDamien Miller 		/*
2467b61cfa1SKevin Steves 		 * Return false if AllowGroups isn't empty and one of user's groups
247b38eff8eSDamien Miller 		 * isn't listed there
248b38eff8eSDamien Miller 		 */
2497b61cfa1SKevin Steves 		if (options.num_allow_groups > 0)
2507b61cfa1SKevin Steves 			if (!ga_match(options.allow_groups,
2517b61cfa1SKevin Steves 			    options.num_allow_groups)) {
2527b61cfa1SKevin Steves 				ga_free();
253094cd0baSDarren Tucker 				logit("User %.100s from %.100s not allowed "
254094cd0baSDarren Tucker 				    "because none of user's groups are listed "
255094cd0baSDarren Tucker 				    "in AllowGroups", pw->pw_name, hostname);
256b38eff8eSDamien Miller 				return 0;
257b38eff8eSDamien Miller 			}
2587b61cfa1SKevin Steves 		ga_free();
259b38eff8eSDamien Miller 	}
260b38eff8eSDamien Miller 
2610a9d43d7SDarren Tucker #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
262a784fa8cSKevin Adler 	if (!sys_auth_allowed_user(pw, loginmsg))
263b38eff8eSDamien Miller 		return 0;
2640a9d43d7SDarren Tucker #endif
265b38eff8eSDamien Miller 
266b38eff8eSDamien Miller 	/* We found no reason not to let this user try to log on... */
267b38eff8eSDamien Miller 	return 1;
268b38eff8eSDamien Miller }
269db65e8fdSBen Lindstrom 
2708f574959Sdjm@openbsd.org /*
2718f574959Sdjm@openbsd.org  * Formats any key left in authctxt->auth_method_key for inclusion in
2728f574959Sdjm@openbsd.org  * auth_log()'s message. Also includes authxtct->auth_method_info if present.
2738f574959Sdjm@openbsd.org  */
2748f574959Sdjm@openbsd.org static char *
format_method_key(Authctxt * authctxt)2758f574959Sdjm@openbsd.org format_method_key(Authctxt *authctxt)
2760acca379SDarren Tucker {
2778f574959Sdjm@openbsd.org 	const struct sshkey *key = authctxt->auth_method_key;
2788f574959Sdjm@openbsd.org 	const char *methinfo = authctxt->auth_method_info;
27950e2687eSdjm@openbsd.org 	char *fp, *cafp, *ret = NULL;
2800acca379SDarren Tucker 
2818f574959Sdjm@openbsd.org 	if (key == NULL)
2828f574959Sdjm@openbsd.org 		return NULL;
2830acca379SDarren Tucker 
284c7d39ac8Smarkus@openbsd.org 	if (sshkey_is_cert(key)) {
28550e2687eSdjm@openbsd.org 		fp = sshkey_fingerprint(key,
2868f574959Sdjm@openbsd.org 		    options.fingerprint_hash, SSH_FP_DEFAULT);
28750e2687eSdjm@openbsd.org 		cafp = sshkey_fingerprint(key->cert->signature_key,
28850e2687eSdjm@openbsd.org 		    options.fingerprint_hash, SSH_FP_DEFAULT);
28950e2687eSdjm@openbsd.org 		xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
29050e2687eSdjm@openbsd.org 		    sshkey_type(key), fp == NULL ? "(null)" : fp,
29150e2687eSdjm@openbsd.org 		    key->cert->key_id,
2928f574959Sdjm@openbsd.org 		    (unsigned long long)key->cert->serial,
2938f574959Sdjm@openbsd.org 		    sshkey_type(key->cert->signature_key),
29450e2687eSdjm@openbsd.org 		    cafp == NULL ? "(null)" : cafp,
2958f574959Sdjm@openbsd.org 		    methinfo == NULL ? "" : ", ",
2968f574959Sdjm@openbsd.org 		    methinfo == NULL ? "" : methinfo);
2978f574959Sdjm@openbsd.org 		free(fp);
29850e2687eSdjm@openbsd.org 		free(cafp);
2998f574959Sdjm@openbsd.org 	} else {
3008f574959Sdjm@openbsd.org 		fp = sshkey_fingerprint(key, options.fingerprint_hash,
3018f574959Sdjm@openbsd.org 		    SSH_FP_DEFAULT);
3028f574959Sdjm@openbsd.org 		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
3038f574959Sdjm@openbsd.org 		    fp == NULL ? "(null)" : fp,
3048f574959Sdjm@openbsd.org 		    methinfo == NULL ? "" : ", ",
3058f574959Sdjm@openbsd.org 		    methinfo == NULL ? "" : methinfo);
3068f574959Sdjm@openbsd.org 		free(fp);
3078f574959Sdjm@openbsd.org 	}
3088f574959Sdjm@openbsd.org 	return ret;
3090acca379SDarren Tucker }
3100acca379SDarren Tucker 
3110acca379SDarren Tucker void
auth_log(struct ssh * ssh,int authenticated,int partial,const char * method,const char * submethod)3123a00a921Sdjm@openbsd.org auth_log(struct ssh *ssh, int authenticated, int partial,
3130acca379SDarren Tucker     const char *method, const char *submethod)
314db65e8fdSBen Lindstrom {
3153a00a921Sdjm@openbsd.org 	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
31650e2687eSdjm@openbsd.org 	int level = SYSLOG_LEVEL_VERBOSE;
3178f574959Sdjm@openbsd.org 	const char *authmsg;
3188f574959Sdjm@openbsd.org 	char *extra = NULL;
319db65e8fdSBen Lindstrom 
3207a8f5b33SDamien Miller 	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
3217a8f5b33SDamien Miller 		return;
3227a8f5b33SDamien Miller 
323db65e8fdSBen Lindstrom 	/* Raise logging level */
324db65e8fdSBen Lindstrom 	if (authenticated == 1 ||
325db65e8fdSBen Lindstrom 	    !authctxt->valid ||
32689413dbaSDarren Tucker 	    authctxt->failures >= options.max_authtries / 2 ||
327db65e8fdSBen Lindstrom 	    strcmp(method, "password") == 0)
32850e2687eSdjm@openbsd.org 		level = SYSLOG_LEVEL_INFO;
329db65e8fdSBen Lindstrom 
330db65e8fdSBen Lindstrom 	if (authctxt->postponed)
331db65e8fdSBen Lindstrom 		authmsg = "Postponed";
33215b05cfaSDamien Miller 	else if (partial)
33315b05cfaSDamien Miller 		authmsg = "Partial";
334db65e8fdSBen Lindstrom 	else
335db65e8fdSBen Lindstrom 		authmsg = authenticated ? "Accepted" : "Failed";
336db65e8fdSBen Lindstrom 
3378f574959Sdjm@openbsd.org 	if ((extra = format_method_key(authctxt)) == NULL) {
3388f574959Sdjm@openbsd.org 		if (authctxt->auth_method_info != NULL)
3398f574959Sdjm@openbsd.org 			extra = xstrdup(authctxt->auth_method_info);
3408f574959Sdjm@openbsd.org 	}
3418f574959Sdjm@openbsd.org 
34250e2687eSdjm@openbsd.org 	do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
343db65e8fdSBen Lindstrom 	    authmsg,
344db65e8fdSBen Lindstrom 	    method,
34515b05cfaSDamien Miller 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
3465cb30ad2SDarren Tucker 	    authctxt->valid ? "" : "invalid user ",
347f655207aSDamien Miller 	    authctxt->user,
34895767262Sdjm@openbsd.org 	    ssh_remote_ipaddr(ssh),
34995767262Sdjm@openbsd.org 	    ssh_remote_port(ssh),
3508f574959Sdjm@openbsd.org 	    extra != NULL ? ": " : "",
3518f574959Sdjm@openbsd.org 	    extra != NULL ? extra : "");
3528f574959Sdjm@openbsd.org 
3538f574959Sdjm@openbsd.org 	free(extra);
354e06eb682SBen Lindstrom 
35597363a8bSDarren Tucker #ifdef CUSTOM_FAILED_LOGIN
3562fba9930SDarren Tucker 	if (authenticated == 0 && !authctxt->postponed &&
3572fba9930SDarren Tucker 	    (strcmp(method, "password") == 0 ||
35840d9a637SDarren Tucker 	    strncmp(method, "keyboard-interactive", 20) == 0 ||
35940d9a637SDarren Tucker 	    strcmp(method, "challenge-response") == 0))
36008f66d9fSDamien Miller 		record_failed_login(ssh, authctxt->user,
361885fb2a4SDarren Tucker 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
36226d4e19cSDarren Tucker # ifdef WITH_AIXAUTHENTICATE
36326d4e19cSDarren Tucker 	if (authenticated)
36479a87d32SDarren Tucker 		sys_auth_record_login(authctxt->user,
365885fb2a4SDarren Tucker 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
366a784fa8cSKevin Adler 		    loginmsg);
36726d4e19cSDarren Tucker # endif
36897363a8bSDarren Tucker #endif
3692e0cf0dcSDarren Tucker #ifdef SSH_AUDIT_EVENTS
370f14b2aa6SDarren Tucker 	if (authenticated == 0 && !authctxt->postponed)
3719b655dc9SDamien Miller 		audit_event(ssh, audit_classify_auth(method));
372269a1ea1SDarren Tucker #endif
373db65e8fdSBen Lindstrom }
374db65e8fdSBen Lindstrom 
375686feb56SDamien Miller 
376686feb56SDamien Miller void
auth_maxtries_exceeded(struct ssh * ssh)3773a00a921Sdjm@openbsd.org auth_maxtries_exceeded(struct ssh *ssh)
378686feb56SDamien Miller {
3793a00a921Sdjm@openbsd.org 	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
38095767262Sdjm@openbsd.org 
3816f621603Sdjm@openbsd.org 	error("maximum authentication attempts exceeded for "
3826cb6dcffSmarkus@openbsd.org 	    "%s%.100s from %.200s port %d ssh2",
383686feb56SDamien Miller 	    authctxt->valid ? "" : "invalid user ",
384686feb56SDamien Miller 	    authctxt->user,
38595767262Sdjm@openbsd.org 	    ssh_remote_ipaddr(ssh),
3866cb6dcffSmarkus@openbsd.org 	    ssh_remote_port(ssh));
3873a00a921Sdjm@openbsd.org 	ssh_packet_disconnect(ssh, "Too many authentication failures");
388686feb56SDamien Miller 	/* NOTREACHED */
389686feb56SDamien Miller }
390686feb56SDamien Miller 
391db65e8fdSBen Lindstrom /*
392d8a9021fSBen Lindstrom  * Check whether root logins are disallowed.
393db65e8fdSBen Lindstrom  */
394db65e8fdSBen Lindstrom int
auth_root_allowed(struct ssh * ssh,const char * method)3957c856857Sdjm@openbsd.org auth_root_allowed(struct ssh *ssh, const char *method)
396db65e8fdSBen Lindstrom {
397d8a9021fSBen Lindstrom 	switch (options.permit_root_login) {
398d8a9021fSBen Lindstrom 	case PERMIT_YES:
399db65e8fdSBen Lindstrom 		return 1;
400d8a9021fSBen Lindstrom 	case PERMIT_NO_PASSWD:
4011dc8d93cSderaadt@openbsd.org 		if (strcmp(method, "publickey") == 0 ||
4021dc8d93cSderaadt@openbsd.org 		    strcmp(method, "hostbased") == 0 ||
40332a18198Sdjm@openbsd.org 		    strcmp(method, "gssapi-with-mic") == 0)
404d8a9021fSBen Lindstrom 			return 1;
405d8a9021fSBen Lindstrom 		break;
406d8a9021fSBen Lindstrom 	case PERMIT_FORCED_ONLY:
4077c856857Sdjm@openbsd.org 		if (auth_opts->force_command != NULL) {
408996acd24SDamien Miller 			logit("Root login accepted for forced command.");
409db65e8fdSBen Lindstrom 			return 1;
410d8a9021fSBen Lindstrom 		}
411d8a9021fSBen Lindstrom 		break;
412d8a9021fSBen Lindstrom 	}
41395767262Sdjm@openbsd.org 	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
41495767262Sdjm@openbsd.org 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
415db65e8fdSBen Lindstrom 	return 0;
416db65e8fdSBen Lindstrom }
417bfb3a0e9SBen Lindstrom 
418bfb3a0e9SBen Lindstrom 
419bfb3a0e9SBen Lindstrom /*
420bfb3a0e9SBen Lindstrom  * Given a template and a passwd structure, build a filename
421bfb3a0e9SBen Lindstrom  * by substituting % tokenised options. Currently, %% becomes '%',
422bfb3a0e9SBen Lindstrom  * %h becomes the home directory and %u the username.
423bfb3a0e9SBen Lindstrom  *
424bfb3a0e9SBen Lindstrom  * This returns a buffer allocated by xmalloc.
425bfb3a0e9SBen Lindstrom  */
426d8478b6aSDamien Miller char *
expand_authorized_keys(const char * filename,struct passwd * pw)4276476cad9SDamien Miller expand_authorized_keys(const char *filename, struct passwd *pw)
428bfb3a0e9SBen Lindstrom {
4299c935dd9Sdjm@openbsd.org 	char *file, uidstr[32], ret[PATH_MAX];
43007d86becSDamien Miller 	int i;
431bfb3a0e9SBen Lindstrom 
4329c935dd9Sdjm@openbsd.org 	snprintf(uidstr, sizeof(uidstr), "%llu",
4339c935dd9Sdjm@openbsd.org 	    (unsigned long long)pw->pw_uid);
4346476cad9SDamien Miller 	file = percent_expand(filename, "h", pw->pw_dir,
4359c935dd9Sdjm@openbsd.org 	    "u", pw->pw_name, "U", uidstr, (char *)NULL);
436bfb3a0e9SBen Lindstrom 
437bfb3a0e9SBen Lindstrom 	/*
438bfb3a0e9SBen Lindstrom 	 * Ensure that filename starts anchored. If not, be backward
439bfb3a0e9SBen Lindstrom 	 * compatible and prepend the '%h/'
440bfb3a0e9SBen Lindstrom 	 */
4412a35862eSdjm@openbsd.org 	if (path_absolute(file))
4426476cad9SDamien Miller 		return (file);
443bfb3a0e9SBen Lindstrom 
44407d86becSDamien Miller 	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
44507d86becSDamien Miller 	if (i < 0 || (size_t)i >= sizeof(ret))
4466476cad9SDamien Miller 		fatal("expand_authorized_keys: path too long");
447a627d42eSDarren Tucker 	free(file);
44807d86becSDamien Miller 	return (xstrdup(ret));
449bfb3a0e9SBen Lindstrom }
450bfb3a0e9SBen Lindstrom 
451bfb3a0e9SBen Lindstrom char *
authorized_principals_file(struct passwd * pw)45230da3447SDamien Miller authorized_principals_file(struct passwd *pw)
45330da3447SDamien Miller {
4547e8528caSdjm@openbsd.org 	if (options.authorized_principals_file == NULL)
45530da3447SDamien Miller 		return NULL;
45630da3447SDamien Miller 	return expand_authorized_keys(options.authorized_principals_file, pw);
45730da3447SDamien Miller }
45830da3447SDamien Miller 
45983647ce4SBen Lindstrom /* return ok if key exists in sysfile or userfile */
46083647ce4SBen Lindstrom HostStatus
check_key_in_hostfiles(struct passwd * pw,struct sshkey * key,const char * host,const char * sysfile,const char * userfile)46154d90aceSmarkus@openbsd.org check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
46283647ce4SBen Lindstrom     const char *sysfile, const char *userfile)
46383647ce4SBen Lindstrom {
46483647ce4SBen Lindstrom 	char *user_hostfile;
46583647ce4SBen Lindstrom 	struct stat st;
46665366a8cSBen Lindstrom 	HostStatus host_status;
467d925dcd8SDamien Miller 	struct hostkeys *hostkeys;
468d925dcd8SDamien Miller 	const struct hostkey_entry *found;
46983647ce4SBen Lindstrom 
470d925dcd8SDamien Miller 	hostkeys = init_hostkeys();
471b4c7cd11Sdjm@openbsd.org 	load_hostkeys(hostkeys, host, sysfile, 0);
472d925dcd8SDamien Miller 	if (userfile != NULL) {
47383647ce4SBen Lindstrom 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
47483647ce4SBen Lindstrom 		if (options.strict_modes &&
47583647ce4SBen Lindstrom 		    (stat(user_hostfile, &st) == 0) &&
47683647ce4SBen Lindstrom 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
47783647ce4SBen Lindstrom 		    (st.st_mode & 022) != 0)) {
478996acd24SDamien Miller 			logit("Authentication refused for %.100s: "
47983647ce4SBen Lindstrom 			    "bad owner or modes for %.200s",
48083647ce4SBen Lindstrom 			    pw->pw_name, user_hostfile);
48148147d68SDamien Miller 			auth_debug_add("Ignored %.200s: bad ownership or modes",
48248147d68SDamien Miller 			    user_hostfile);
48383647ce4SBen Lindstrom 		} else {
48483647ce4SBen Lindstrom 			temporarily_use_uid(pw);
485b4c7cd11Sdjm@openbsd.org 			load_hostkeys(hostkeys, host, user_hostfile, 0);
48683647ce4SBen Lindstrom 			restore_uid();
48783647ce4SBen Lindstrom 		}
488a627d42eSDarren Tucker 		free(user_hostfile);
48983647ce4SBen Lindstrom 	}
490d925dcd8SDamien Miller 	host_status = check_key_in_hostkeys(hostkeys, key, &found);
491d925dcd8SDamien Miller 	if (host_status == HOST_REVOKED)
492d925dcd8SDamien Miller 		error("WARNING: revoked key for %s attempted authentication",
49376ed2199Sdjm@openbsd.org 		    host);
494d925dcd8SDamien Miller 	else if (host_status == HOST_OK)
495816036f1Sdjm@openbsd.org 		debug_f("key for %s found at %s:%ld",
496d925dcd8SDamien Miller 		    found->host, found->file, found->line);
497d925dcd8SDamien Miller 	else
498816036f1Sdjm@openbsd.org 		debug_f("key for host %s not found", host);
49983647ce4SBen Lindstrom 
500d925dcd8SDamien Miller 	free_hostkeys(hostkeys);
501d925dcd8SDamien Miller 
50283647ce4SBen Lindstrom 	return host_status;
50383647ce4SBen Lindstrom }
50483647ce4SBen Lindstrom 
50530da3447SDamien Miller static FILE *
auth_openfile(const char * file,struct passwd * pw,int strict_modes,int log_missing,char * file_type)50630da3447SDamien Miller auth_openfile(const char *file, struct passwd *pw, int strict_modes,
50730da3447SDamien Miller     int log_missing, char *file_type)
50833c787f2SDarren Tucker {
50933c787f2SDarren Tucker 	char line[1024];
51033c787f2SDarren Tucker 	struct stat st;
51133c787f2SDarren Tucker 	int fd;
51233c787f2SDarren Tucker 	FILE *f;
51333c787f2SDarren Tucker 
51443551527SDarren Tucker 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
51530da3447SDamien Miller 		if (log_missing || errno != ENOENT)
51630da3447SDamien Miller 			debug("Could not open %s '%s': %s", file_type, file,
51743551527SDarren Tucker 			    strerror(errno));
51833c787f2SDarren Tucker 		return NULL;
51943551527SDarren Tucker 	}
52033c787f2SDarren Tucker 
5214d28fa78Sderaadt@openbsd.org 	if (fstat(fd, &st) == -1) {
52233c787f2SDarren Tucker 		close(fd);
52333c787f2SDarren Tucker 		return NULL;
52433c787f2SDarren Tucker 	}
52533c787f2SDarren Tucker 	if (!S_ISREG(st.st_mode)) {
52630da3447SDamien Miller 		logit("User %s %s %s is not a regular file",
52730da3447SDamien Miller 		    pw->pw_name, file_type, file);
52833c787f2SDarren Tucker 		close(fd);
52933c787f2SDarren Tucker 		return NULL;
53033c787f2SDarren Tucker 	}
53133c787f2SDarren Tucker 	unset_nonblock(fd);
53233c787f2SDarren Tucker 	if ((f = fdopen(fd, "r")) == NULL) {
53333c787f2SDarren Tucker 		close(fd);
53433c787f2SDarren Tucker 		return NULL;
53533c787f2SDarren Tucker 	}
5366a740e7bSDamien Miller 	if (strict_modes &&
537de4ae07fSdjm@openbsd.org 	    safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
53833c787f2SDarren Tucker 		fclose(f);
53933c787f2SDarren Tucker 		logit("Authentication refused: %s", line);
54048147d68SDamien Miller 		auth_debug_add("Ignored %s: %s", file_type, line);
54133c787f2SDarren Tucker 		return NULL;
54233c787f2SDarren Tucker 	}
54333c787f2SDarren Tucker 
54433c787f2SDarren Tucker 	return f;
54533c787f2SDarren Tucker }
54633c787f2SDarren Tucker 
54730da3447SDamien Miller 
54830da3447SDamien Miller FILE *
auth_openkeyfile(const char * file,struct passwd * pw,int strict_modes)549