1295367Sdes/* $OpenBSD: auth.c,v 1.113 2015/08/21 03:42:19 djm Exp $ */
260573Skris/*
376262Sgreen * Copyright (c) 2000 Markus Friedl.  All rights reserved.
465674Skris *
565674Skris * Redistribution and use in source and binary forms, with or without
665674Skris * modification, are permitted provided that the following conditions
765674Skris * are met:
865674Skris * 1. Redistributions of source code must retain the above copyright
965674Skris *    notice, this list of conditions and the following disclaimer.
1065674Skris * 2. Redistributions in binary form must reproduce the above copyright
1165674Skris *    notice, this list of conditions and the following disclaimer in the
1265674Skris *    documentation and/or other materials provided with the distribution.
1365674Skris *
1465674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1565674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1665674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1765674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1865674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1965674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2065674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2165674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2265674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2365674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2460573Skris */
2560573Skris
2660573Skris#include "includes.h"
27162856Sdes__RCSID("$FreeBSD: releng/10.3/crypto/openssh/auth.c 295367 2016-02-07 11:38:54Z des $");
2860573Skris
29162856Sdes#include <sys/types.h>
30162856Sdes#include <sys/stat.h>
31162856Sdes
32162856Sdes#include <netinet/in.h>
33162856Sdes
34162856Sdes#include <errno.h>
35181111Sdes#include <fcntl.h>
36162856Sdes#ifdef HAVE_PATHS_H
37162856Sdes# include <paths.h>
38162856Sdes#endif
39162856Sdes#include <pwd.h>
4098941Sdes#ifdef HAVE_LOGIN_H
4198941Sdes#include <login.h>
4298941Sdes#endif
43126277Sdes#ifdef USE_SHADOW
4498941Sdes#include <shadow.h>
45126277Sdes#endif
4698941Sdes#ifdef HAVE_LIBGEN_H
4792559Sdes#include <libgen.h>
4898941Sdes#endif
49162856Sdes#include <stdarg.h>
50162856Sdes#include <stdio.h>
51162856Sdes#include <string.h>
52181111Sdes#include <unistd.h>
53295367Sdes#include <limits.h>
5492559Sdes
5560573Skris#include "xmalloc.h"
5676262Sgreen#include "match.h"
5776262Sgreen#include "groupaccess.h"
5876262Sgreen#include "log.h"
59162856Sdes#include "buffer.h"
60295367Sdes#include "misc.h"
6160573Skris#include "servconf.h"
62162856Sdes#include "key.h"
63162856Sdes#include "hostfile.h"
6460573Skris#include "auth.h"
6576262Sgreen#include "auth-options.h"
6676262Sgreen#include "canohost.h"
6792559Sdes#include "uidswap.h"
6898684Sdes#include "packet.h"
69147005Sdes#include "loginrec.h"
70162856Sdes#ifdef GSSAPI
71162856Sdes#include "ssh-gss.h"
72162856Sdes#endif
73204917Sdes#include "authfile.h"
74147005Sdes#include "monitor_wrap.h"
75295367Sdes#include "authfile.h"
76295367Sdes#include "ssherr.h"
77255767Sdes#include "compat.h"
7860573Skris
7960573Skris/* import */
8060573Skrisextern ServerOptions options;
81162856Sdesextern int use_privsep;
82124211Sdesextern Buffer loginmsg;
83162856Sdesextern struct passwd *privsep_pw;
8460573Skris
8598684Sdes/* Debugging messages */
8698684SdesBuffer auth_debug;
8798684Sdesint auth_debug_init;
8898684Sdes
8960573Skris/*
9076262Sgreen * Check if the user is allowed to log in via ssh. If user is listed
9176262Sgreen * in DenyUsers or one of user's groups is listed in DenyGroups, false
9276262Sgreen * will be returned. If AllowUsers isn't empty and user isn't listed
9376262Sgreen * there, or if AllowGroups isn't empty and one of user's groups isn't
9476262Sgreen * listed there, false will be returned.
9560573Skris * If the user's shell is not executable, false will be returned.
9660573Skris * Otherwise true is returned.
9760573Skris */
9860573Skrisint
9960573Skrisallowed_user(struct passwd * pw)
10060573Skris{
10160573Skris	struct stat st;
102124211Sdes	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
103149753Sdes	u_int i;
104126277Sdes#ifdef USE_SHADOW
105124211Sdes	struct spwd *spw = NULL;
106113911Sdes#endif
10760573Skris
10860573Skris	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
10976262Sgreen	if (!pw || !pw->pw_name)
11060573Skris		return 0;
11160573Skris
112126277Sdes#ifdef USE_SHADOW
113124211Sdes	if (!options.use_pam)
114124211Sdes		spw = getspnam(pw->pw_name);
115124211Sdes#ifdef HAS_SHADOW_EXPIRE
116126277Sdes	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
117126277Sdes		return 0;
118124211Sdes#endif /* HAS_SHADOW_EXPIRE */
119126277Sdes#endif /* USE_SHADOW */
120124211Sdes
121126277Sdes	/* grab passwd field for locked account check */
122181111Sdes	passwd = pw->pw_passwd;
123126277Sdes#ifdef USE_SHADOW
124124211Sdes	if (spw != NULL)
125181111Sdes#ifdef USE_LIBIAF
126149753Sdes		passwd = get_iaf_password(pw);
127149753Sdes#else
128124211Sdes		passwd = spw->sp_pwdp;
129181111Sdes#endif /* USE_LIBIAF */
13098941Sdes#endif
13198941Sdes
132126277Sdes	/* check for locked account */
133124211Sdes	if (!options.use_pam && passwd && *passwd) {
134124211Sdes		int locked = 0;
135124211Sdes
136124211Sdes#ifdef LOCKED_PASSWD_STRING
137124211Sdes		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
138124211Sdes			 locked = 1;
139124211Sdes#endif
140124211Sdes#ifdef LOCKED_PASSWD_PREFIX
141124211Sdes		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
142124211Sdes		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
143124211Sdes			 locked = 1;
144124211Sdes#endif
145124211Sdes#ifdef LOCKED_PASSWD_SUBSTR
146124211Sdes		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
147124211Sdes			locked = 1;
148124211Sdes#endif
149181111Sdes#ifdef USE_LIBIAF
150215116Sdes		free((void *) passwd);
151181111Sdes#endif /* USE_LIBIAF */
152124211Sdes		if (locked) {
153124211Sdes			logit("User %.100s not allowed because account is locked",
154124211Sdes			    pw->pw_name);
155124211Sdes			return 0;
156124211Sdes		}
157124211Sdes	}
158124211Sdes
15961212Skris	/*
160204917Sdes	 * Deny if shell does not exist or is not executable unless we
161204917Sdes	 * are chrooting.
16261212Skris	 */
163204917Sdes	if (options.chroot_directory == NULL ||
164204917Sdes	    strcasecmp(options.chroot_directory, "none") == 0) {
165204917Sdes		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
166204917Sdes		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
16761212Skris
168204917Sdes		if (stat(shell, &st) != 0) {
169204917Sdes			logit("User %.100s not allowed because shell %.100s "
170204917Sdes			    "does not exist", pw->pw_name, shell);
171255767Sdes			free(shell);
172204917Sdes			return 0;
173204917Sdes		}
174204917Sdes		if (S_ISREG(st.st_mode) == 0 ||
175204917Sdes		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
176204917Sdes			logit("User %.100s not allowed because shell %.100s "
177204917Sdes			    "is not executable", pw->pw_name, shell);
178255767Sdes			free(shell);
179204917Sdes			return 0;
180204917Sdes		}
181255767Sdes		free(shell);
18292559Sdes	}
18360573Skris
184147005Sdes	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
185147005Sdes	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
186124211Sdes		hostname = get_canonical_hostname(options.use_dns);
18792559Sdes		ipaddr = get_remote_ipaddr();
18892559Sdes	}
18992559Sdes
19060573Skris	/* Return false if user is listed in DenyUsers */
19160573Skris	if (options.num_deny_users > 0) {
19260573Skris		for (i = 0; i < options.num_deny_users; i++)
19398684Sdes			if (match_user(pw->pw_name, hostname, ipaddr,
19492559Sdes			    options.deny_users[i])) {
195147005Sdes				logit("User %.100s from %.100s not allowed "
196147005Sdes				    "because listed in DenyUsers",
197147005Sdes				    pw->pw_name, hostname);
19860573Skris				return 0;
19992559Sdes			}
20060573Skris	}
20160573Skris	/* Return false if AllowUsers isn't empty and user isn't listed there */
20260573Skris	if (options.num_allow_users > 0) {
20360573Skris		for (i = 0; i < options.num_allow_users; i++)
20498684Sdes			if (match_user(pw->pw_name, hostname, ipaddr,
20592559Sdes			    options.allow_users[i]))
20660573Skris				break;
20760573Skris		/* i < options.num_allow_users iff we break for loop */
20892559Sdes		if (i >= options.num_allow_users) {
209147005Sdes			logit("User %.100s from %.100s not allowed because "
210147005Sdes			    "not listed in AllowUsers", pw->pw_name, hostname);
21160573Skris			return 0;
21292559Sdes		}
21360573Skris	}
21460573Skris	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
21576262Sgreen		/* Get the user's group access list (primary and supplementary) */
21692559Sdes		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
217147005Sdes			logit("User %.100s from %.100s not allowed because "
218147005Sdes			    "not in any group", pw->pw_name, hostname);
21960573Skris			return 0;
22092559Sdes		}
22160573Skris
22276262Sgreen		/* Return false if one of user's groups is listed in DenyGroups */
22376262Sgreen		if (options.num_deny_groups > 0)
22476262Sgreen			if (ga_match(options.deny_groups,
22576262Sgreen			    options.num_deny_groups)) {
22676262Sgreen				ga_free();
227147005Sdes				logit("User %.100s from %.100s not allowed "
228147005Sdes				    "because a group is listed in DenyGroups",
229147005Sdes				    pw->pw_name, hostname);
23060573Skris				return 0;
23176262Sgreen			}
23260573Skris		/*
23376262Sgreen		 * Return false if AllowGroups isn't empty and one of user's groups
23460573Skris		 * isn't listed there
23560573Skris		 */
23676262Sgreen		if (options.num_allow_groups > 0)
23776262Sgreen			if (!ga_match(options.allow_groups,
23876262Sgreen			    options.num_allow_groups)) {
23976262Sgreen				ga_free();
240147005Sdes				logit("User %.100s from %.100s not allowed "
241147005Sdes				    "because none of user's groups are listed "
242147005Sdes				    "in AllowGroups", pw->pw_name, hostname);
24360573Skris				return 0;
24476262Sgreen			}
24576262Sgreen		ga_free();
24660573Skris	}
24798941Sdes
248137019Sdes#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
249147005Sdes	if (!sys_auth_allowed_user(pw, &loginmsg))
250137019Sdes		return 0;
251137019Sdes#endif
252113911Sdes
25360573Skris	/* We found no reason not to let this user try to log on... */
25460573Skris	return 1;
25560573Skris}
25676262Sgreen
25776262Sgreenvoid
258255767Sdesauth_info(Authctxt *authctxt, const char *fmt, ...)
259255767Sdes{
260255767Sdes	va_list ap;
261255767Sdes        int i;
262255767Sdes
263255767Sdes	free(authctxt->info);
264255767Sdes	authctxt->info = NULL;
265255767Sdes
266255767Sdes	va_start(ap, fmt);
267255767Sdes	i = vasprintf(&authctxt->info, fmt, ap);
268255767Sdes	va_end(ap);
269255767Sdes
270255767Sdes	if (i < 0 || authctxt->info == NULL)
271255767Sdes		fatal("vasprintf failed");
272255767Sdes}
273255767Sdes
274255767Sdesvoid
275248619Sdesauth_log(Authctxt *authctxt, int authenticated, int partial,
276255767Sdes    const char *method, const char *submethod)
27776262Sgreen{
27876262Sgreen	void (*authlog) (const char *fmt,...) = verbose;
27976262Sgreen	char *authmsg;
28076262Sgreen
281162856Sdes	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
282162856Sdes		return;
283162856Sdes
28476262Sgreen	/* Raise logging level */
28576262Sgreen	if (authenticated == 1 ||
28676262Sgreen	    !authctxt->valid ||
287137019Sdes	    authctxt->failures >= options.max_authtries / 2 ||
28876262Sgreen	    strcmp(method, "password") == 0)
289124211Sdes		authlog = logit;
29076262Sgreen
29176262Sgreen	if (authctxt->postponed)
29276262Sgreen		authmsg = "Postponed";
293248619Sdes	else if (partial)
294248619Sdes		authmsg = "Partial";
29576262Sgreen	else
29676262Sgreen		authmsg = authenticated ? "Accepted" : "Failed";
29776262Sgreen
298255767Sdes	authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
29976262Sgreen	    authmsg,
30076262Sgreen	    method,
301248619Sdes	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
302137019Sdes	    authctxt->valid ? "" : "invalid user ",
30392559Sdes	    authctxt->user,
30476262Sgreen	    get_remote_ipaddr(),
30576262Sgreen	    get_remote_port(),
306255767Sdes	    compat20 ? "ssh2" : "ssh1",
307255767Sdes	    authctxt->info != NULL ? ": " : "",
308255767Sdes	    authctxt->info != NULL ? authctxt->info : "");
309255767Sdes	free(authctxt->info);
310255767Sdes	authctxt->info = NULL;
311106130Sdes
312124211Sdes#ifdef CUSTOM_FAILED_LOGIN
313147005Sdes	if (authenticated == 0 && !authctxt->postponed &&
314147005Sdes	    (strcmp(method, "password") == 0 ||
315147005Sdes	    strncmp(method, "keyboard-interactive", 20) == 0 ||
316147005Sdes	    strcmp(method, "challenge-response") == 0))
317147005Sdes		record_failed_login(authctxt->user,
318147005Sdes		    get_canonical_hostname(options.use_dns), "ssh");
319162856Sdes# ifdef WITH_AIXAUTHENTICATE
320162856Sdes	if (authenticated)
321162856Sdes		sys_auth_record_login(authctxt->user,
322162856Sdes		    get_canonical_hostname(options.use_dns), "ssh", &loginmsg);
323162856Sdes# endif
324124211Sdes#endif
325147005Sdes#ifdef SSH_AUDIT_EVENTS
326162856Sdes	if (authenticated == 0 && !authctxt->postponed)
327162856Sdes		audit_event(audit_classify_auth(method));
328147005Sdes#endif
32976262Sgreen}
33076262Sgreen
331295367Sdes
332295367Sdesvoid
333295367Sdesauth_maxtries_exceeded(Authctxt *authctxt)
334295367Sdes{
335295367Sdes	error("maximum authentication attempts exceeded for "
336295367Sdes	    "%s%.100s from %.200s port %d %s",
337295367Sdes	    authctxt->valid ? "" : "invalid user ",
338295367Sdes	    authctxt->user,
339295367Sdes	    get_remote_ipaddr(),
340295367Sdes	    get_remote_port(),
341295367Sdes	    compat20 ? "ssh2" : "ssh1");
342295367Sdes	packet_disconnect("Too many authentication failures");
343295367Sdes	/* NOTREACHED */
344295367Sdes}
345295367Sdes
34676262Sgreen/*
34776262Sgreen * Check whether root logins are disallowed.
34876262Sgreen */
34976262Sgreenint
350248619Sdesauth_root_allowed(const char *method)
35176262Sgreen{
35276262Sgreen	switch (options.permit_root_login) {
35376262Sgreen	case PERMIT_YES:
35476262Sgreen		return 1;
35576262Sgreen	case PERMIT_NO_PASSWD:
356295367Sdes		if (strcmp(method, "publickey") == 0 ||
357295367Sdes		    strcmp(method, "hostbased") == 0 ||
358295367Sdes		    strcmp(method, "gssapi-with-mic") == 0)
35976262Sgreen			return 1;
36076262Sgreen		break;
36176262Sgreen	case PERMIT_FORCED_ONLY:
36276262Sgreen		if (forced_command) {
363124211Sdes			logit("Root login accepted for forced command.");
36476262Sgreen			return 1;
36576262Sgreen		}
36676262Sgreen		break;
36776262Sgreen	}
368124211Sdes	logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
36976262Sgreen	return 0;
37076262Sgreen}
37192559Sdes
37292559Sdes
37392559Sdes/*
37492559Sdes * Given a template and a passwd structure, build a filename
37592559Sdes * by substituting % tokenised options. Currently, %% becomes '%',
37692559Sdes * %h becomes the home directory and %u the username.
37792559Sdes *
37892559Sdes * This returns a buffer allocated by xmalloc.
37992559Sdes */
380226046Sdeschar *
381149753Sdesexpand_authorized_keys(const char *filename, struct passwd *pw)
38292559Sdes{
383295367Sdes	char *file, ret[PATH_MAX];
384162856Sdes	int i;
38592559Sdes
386149753Sdes	file = percent_expand(filename, "h", pw->pw_dir,
387149753Sdes	    "u", pw->pw_name, (char *)NULL);
38892559Sdes
38992559Sdes	/*
39092559Sdes	 * Ensure that filename starts anchored. If not, be backward
39192559Sdes	 * compatible and prepend the '%h/'
39292559Sdes	 */
393149753Sdes	if (*file == '/')
394149753Sdes		return (file);
39592559Sdes
396162856Sdes	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
397162856Sdes	if (i < 0 || (size_t)i >= sizeof(ret))
398149753Sdes		fatal("expand_authorized_keys: path too long");
399255767Sdes	free(file);
400162856Sdes	return (xstrdup(ret));
40192559Sdes}
40292559Sdes
40392559Sdeschar *
404215116Sdesauthorized_principals_file(struct passwd *pw)
405215116Sdes{
406295367Sdes	if (options.authorized_principals_file == NULL)
407215116Sdes		return NULL;
408215116Sdes	return expand_authorized_keys(options.authorized_principals_file, pw);
409215116Sdes}
410215116Sdes
41192559Sdes/* return ok if key exists in sysfile or userfile */
41292559SdesHostStatus
41392559Sdescheck_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
41492559Sdes    const char *sysfile, const char *userfile)
41592559Sdes{
41692559Sdes	char *user_hostfile;
41792559Sdes	struct stat st;
41892559Sdes	HostStatus host_status;
419221420Sdes	struct hostkeys *hostkeys;
420221420Sdes	const struct hostkey_entry *found;
42192559Sdes
422221420Sdes	hostkeys = init_hostkeys();
423221420Sdes	load_hostkeys(hostkeys, host, sysfile);
424221420Sdes	if (userfile != NULL) {
42592559Sdes		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
42692559Sdes		if (options.strict_modes &&
42792559Sdes		    (stat(user_hostfile, &st) == 0) &&
42892559Sdes		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
42992559Sdes		    (st.st_mode & 022) != 0)) {
430124211Sdes			logit("Authentication refused for %.100s: "
43192559Sdes			    "bad owner or modes for %.200s",
43292559Sdes			    pw->pw_name, user_hostfile);
433215116Sdes			auth_debug_add("Ignored %.200s: bad ownership or modes",
434215116Sdes			    user_hostfile);
43592559Sdes		} else {
43692559Sdes			temporarily_use_uid(pw);
437221420Sdes			load_hostkeys(hostkeys, host, user_hostfile);
43892559Sdes			restore_uid();
43992559Sdes		}
440255767Sdes		free(user_hostfile);
44192559Sdes	}
442221420Sdes	host_status = check_key_in_hostkeys(hostkeys, key, &found);
443221420Sdes	if (host_status == HOST_REVOKED)
444221420Sdes		error("WARNING: revoked key for %s attempted authentication",
445221420Sdes		    found->host);
446221420Sdes	else if (host_status == HOST_OK)
447221420Sdes		debug("%s: key for %s found at %s:%ld", __func__,
448221420Sdes		    found->host, found->file, found->line);
449221420Sdes	else
450221420Sdes		debug("%s: key for host %s not found", __func__, host);
45192559Sdes
452221420Sdes	free_hostkeys(hostkeys);
453221420Sdes
45492559Sdes	return host_status;
45592559Sdes}
45692559Sdes
45792559Sdes/*
458248619Sdes * Check a given path for security. This is defined as all components
459106130Sdes * of the path to the file must be owned by either the owner of
46092559Sdes * of the file or root and no directories must be group or world writable.
46192559Sdes *
46292559Sdes * XXX Should any specific check be done for sym links ?
46392559Sdes *
464248619Sdes * Takes a file name, its stat information (preferably from fstat() to
465248619Sdes * avoid races), the uid of the expected owner, their home directory and an
46692559Sdes * error buffer plus max size as arguments.
46792559Sdes *
46892559Sdes * Returns 0 on success and -1 on failure
46992559Sdes */
470248619Sdesint
471248619Sdesauth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
472248619Sdes    uid_t uid, char *err, size_t errlen)
47392559Sdes{
474295367Sdes	char buf[PATH_MAX], homedir[PATH_MAX];
47592559Sdes	char *cp;
476113911Sdes	int comparehome = 0;
47792559Sdes	struct stat st;
47892559Sdes
479248619Sdes	if (realpath(name, buf) == NULL) {
480248619Sdes		snprintf(err, errlen, "realpath %s failed: %s", name,
48192559Sdes		    strerror(errno));
48292559Sdes		return -1;
48392559Sdes	}
484248619Sdes	if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
485113911Sdes		comparehome = 1;
48692559Sdes
487248619Sdes	if (!S_ISREG(stp->st_mode)) {
488248619Sdes		snprintf(err, errlen, "%s is not a regular file", buf);
489248619Sdes		return -1;
490248619Sdes	}
491248619Sdes	if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
492248619Sdes	    (stp->st_mode & 022) != 0) {
49392559Sdes		snprintf(err, errlen, "bad ownership or modes for file %s",
49492559Sdes		    buf);
49592559Sdes		return -1;
49692559Sdes	}
49792559Sdes
49892559Sdes	/* for each component of the canonical path, walking upwards */
49992559Sdes	for (;;) {
50092559Sdes		if ((cp = dirname(buf)) == NULL) {
50192559Sdes			snprintf(err, errlen, "dirname() failed");
50292559Sdes			return -1;
50392559Sdes		}
50492559Sdes		strlcpy(buf, cp, sizeof(buf));
50592559Sdes
50692559Sdes		if (stat(buf, &st) < 0 ||
507248619Sdes		    (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
50892559Sdes		    (st.st_mode & 022) != 0) {
50992559Sdes			snprintf(err, errlen,
51092559Sdes			    "bad ownership or modes for directory %s", buf);
51192559Sdes			return -1;
51292559Sdes		}
51392559Sdes
514204917Sdes		/* If are past the homedir then we can stop */
515226046Sdes		if (comparehome && strcmp(homedir, buf) == 0)
51692559Sdes			break;
517226046Sdes
51892559Sdes		/*
51992559Sdes		 * dirname should always complete with a "/" path,
52092559Sdes		 * but we can be paranoid and check for "." too
52192559Sdes		 */
52292559Sdes		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
52392559Sdes			break;
52492559Sdes	}
52592559Sdes	return 0;
52692559Sdes}
52798684Sdes
528248619Sdes/*
529248619Sdes * Version of secure_path() that accepts an open file descriptor to
530248619Sdes * avoid races.
531248619Sdes *
532248619Sdes * Returns 0 on success and -1 on failure
533248619Sdes */
534248619Sdesstatic int
535248619Sdessecure_filename(FILE *f, const char *file, struct passwd *pw,
536248619Sdes    char *err, size_t errlen)
537248619Sdes{
538248619Sdes	struct stat st;
539248619Sdes
540248619Sdes	/* check the open file to avoid races */
541248619Sdes	if (fstat(fileno(f), &st) < 0) {
542248619Sdes		snprintf(err, errlen, "cannot stat file %s: %s",
543248619Sdes		    file, strerror(errno));
544248619Sdes		return -1;
545248619Sdes	}
546248619Sdes	return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
547248619Sdes}
548248619Sdes
549215116Sdesstatic FILE *
550215116Sdesauth_openfile(const char *file, struct passwd *pw, int strict_modes,
551215116Sdes    int log_missing, char *file_type)
552181111Sdes{
553181111Sdes	char line[1024];
554181111Sdes	struct stat st;
555181111Sdes	int fd;
556181111Sdes	FILE *f;
557181111Sdes
558204917Sdes	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
559215116Sdes		if (log_missing || errno != ENOENT)
560215116Sdes			debug("Could not open %s '%s': %s", file_type, file,
561204917Sdes			   strerror(errno));
562181111Sdes		return NULL;
563204917Sdes	}
564181111Sdes
565181111Sdes	if (fstat(fd, &st) < 0) {
566181111Sdes		close(fd);
567181111Sdes		return NULL;
568181111Sdes	}
569181111Sdes	if (!S_ISREG(st.st_mode)) {
570215116Sdes		logit("User %s %s %s is not a regular file",
571215116Sdes		    pw->pw_name, file_type, file);
572181111Sdes		close(fd);
573181111Sdes		return NULL;
574181111Sdes	}
575181111Sdes	unset_nonblock(fd);
576181111Sdes	if ((f = fdopen(fd, "r")) == NULL) {
577181111Sdes		close(fd);
578181111Sdes		return NULL;
579181111Sdes	}
580221420Sdes	if (strict_modes &&
581181111Sdes	    secure_filename(f, file, pw, line, sizeof(line)) != 0) {
582181111Sdes		fclose(f);
583181111Sdes		logit("Authentication refused: %s", line);
584215116Sdes		auth_debug_add("Ignored %s: %s", file_type, line);
585181111Sdes		return NULL;
586181111Sdes	}
587181111Sdes
588181111Sdes	return f;
589181111Sdes}
590181111Sdes
591215116Sdes
592215116SdesFILE *
593215116Sdesauth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
594215116Sdes{
595215116Sdes	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
596215116Sdes}
597215116Sdes
598215116SdesFILE *
599215116Sdesauth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
600215116Sdes{
601215116Sdes	return auth_openfile(file, pw, strict_modes, 0,
602215116Sdes	    "authorized principals");
603215116Sdes}
604215116Sdes
60598684Sdesstruct passwd *
60698684Sdesgetpwnamallow(const char *user)
60798684Sdes{
60898684Sdes#ifdef HAVE_LOGIN_CAP
60998684Sdes	extern login_cap_t *lc;
61098684Sdes#ifdef BSD_AUTH
61198684Sdes	auth_session_t *as;
61298684Sdes#endif
61398684Sdes#endif
61498684Sdes	struct passwd *pw;
615240075Sdes	struct connection_info *ci = get_connection_info(1, options.use_dns);
61698684Sdes
617240075Sdes	ci->user = user;
618240075Sdes	parse_server_match_config(&options, ci);
619162856Sdes
620204917Sdes#if defined(_AIX) && defined(HAVE_SETAUTHDB)
621204917Sdes	aix_setauthdb(user);
622204917Sdes#endif
623204917Sdes
62498684Sdes	pw = getpwnam(user);
625204917Sdes
626204917Sdes#if defined(_AIX) && defined(HAVE_SETAUTHDB)
627204917Sdes	aix_restoreauthdb();
628204917Sdes#endif
629204917Sdes#ifdef HAVE_CYGWIN
630204917Sdes	/*
631204917Sdes	 * Windows usernames are case-insensitive.  To avoid later problems
632204917Sdes	 * when trying to match the username, the user is only allowed to
633204917Sdes	 * login if the username is given in the same case as stored in the
634204917Sdes	 * user database.
635204917Sdes	 */
636204917Sdes	if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
637204917Sdes		logit("Login name %.100s does not match stored username %.100s",
638204917Sdes		    user, pw->pw_name);
639204917Sdes		pw = NULL;
640204917Sdes	}
641204917Sdes#endif
642106130Sdes	if (pw == NULL) {
643137019Sdes		logit("Invalid user %.100s from %.100s",
644106130Sdes		    user, get_remote_ipaddr());
645124211Sdes#ifdef CUSTOM_FAILED_LOGIN
646147005Sdes		record_failed_login(user,
647147005Sdes		    get_canonical_hostname(options.use_dns), "ssh");
648113911Sdes#endif
649147005Sdes#ifdef SSH_AUDIT_EVENTS
650147005Sdes		audit_event(SSH_INVALID_USER);
651147005Sdes#endif /* SSH_AUDIT_EVENTS */
65298684Sdes		return (NULL);
653106130Sdes	}
654106130Sdes	if (!allowed_user(pw))
655106130Sdes		return (NULL);
65698684Sdes#ifdef HAVE_LOGIN_CAP
657100838Sfanf	if ((lc = login_getpwclass(pw)) == NULL) {
65898684Sdes		debug("unable to get login class: %s", user);
65998684Sdes		return (NULL);
66098684Sdes	}
66198684Sdes#ifdef BSD_AUTH
66298684Sdes	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
66398684Sdes	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
66498684Sdes		debug("Approval failure for %s", user);
66598684Sdes		pw = NULL;
66698684Sdes	}
66798684Sdes	if (as != NULL)
66898684Sdes		auth_close(as);
66998684Sdes#endif
67098684Sdes#endif
67198684Sdes	if (pw != NULL)
67298684Sdes		return (pwcopy(pw));
67398684Sdes	return (NULL);
67498684Sdes}
67598684Sdes
676204917Sdes/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
677204917Sdesint
678204917Sdesauth_key_is_revoked(Key *key)
679204917Sdes{
680295367Sdes	char *fp = NULL;
681295367Sdes	int r;
682204917Sdes
683204917Sdes	if (options.revoked_keys_file == NULL)
684204917Sdes		return 0;
685295367Sdes	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
686295367Sdes	    SSH_FP_DEFAULT)) == NULL) {
687295367Sdes		r = SSH_ERR_ALLOC_FAIL;
688295367Sdes		error("%s: fingerprint key: %s", __func__, ssh_err(r));
689295367Sdes		goto out;
690295367Sdes	}
691295367Sdes
692295367Sdes	r = sshkey_check_revoked(key, options.revoked_keys_file);
693295367Sdes	switch (r) {
694248619Sdes	case 0:
695295367Sdes		break; /* not revoked */
696295367Sdes	case SSH_ERR_KEY_REVOKED:
697295367Sdes		error("Authentication key %s %s revoked by file %s",
698295367Sdes		    sshkey_type(key), fp, options.revoked_keys_file);
699295367Sdes		goto out;
700248619Sdes	default:
701295367Sdes		error("Error checking authentication key %s %s in "
702295367Sdes		    "revoked keys file %s: %s", sshkey_type(key), fp,
703295367Sdes		    options.revoked_keys_file, ssh_err(r));
704295367Sdes		goto out;
705248619Sdes	}
706295367Sdes
707295367Sdes	/* Success */
708295367Sdes	r = 0;
709295367Sdes
710295367Sdes out:
711295367Sdes	free(fp);
712295367Sdes	return r == 0 ? 0 : 1;
713204917Sdes}
714204917Sdes
71598684Sdesvoid
71698684Sdesauth_debug_add(const char *fmt,...)
71798684Sdes{
71898684Sdes	char buf[1024];
71998684Sdes	va_list args;
72098684Sdes
72198684Sdes	if (!auth_debug_init)
72298684Sdes		return;
72398684Sdes
72498684Sdes	va_start(args, fmt);
72598684Sdes	vsnprintf(buf, sizeof(buf), fmt, args);
72698684Sdes	va_end(args);
72798684Sdes	buffer_put_cstring(&auth_debug, buf);
72898684Sdes}
72998684Sdes
73098684Sdesvoid
73198684Sdesauth_debug_send(void)
73298684Sdes{
73398684Sdes	char *msg;
73498684Sdes
73598684Sdes	if (!auth_debug_init)
73698684Sdes		return;
73798684Sdes	while (buffer_len(&auth_debug)) {
73898684Sdes		msg = buffer_get_string(&auth_debug, NULL);
73998684Sdes		packet_send_debug("%s", msg);
740255767Sdes		free(msg);
74198684Sdes	}
74298684Sdes}
74398684Sdes
74498684Sdesvoid
74598684Sdesauth_debug_reset(void)
74698684Sdes{
74798684Sdes	if (auth_debug_init)
74898684Sdes		buffer_clear(&auth_debug);
74998684Sdes	else {
75098684Sdes		buffer_init(&auth_debug);
75198684Sdes		auth_debug_init = 1;
75298684Sdes	}
75398684Sdes}
754124211Sdes
755124211Sdesstruct passwd *
756124211Sdesfakepw(void)
757124211Sdes{
758124211Sdes	static struct passwd fake;
759124211Sdes
760124211Sdes	memset(&fake, 0, sizeof(fake));
761124211Sdes	fake.pw_name = "NOUSER";
762124211Sdes	fake.pw_passwd =
763126277Sdes	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
764255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
765124211Sdes	fake.pw_gecos = "NOUSER";
766255767Sdes#endif
767181111Sdes	fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
768181111Sdes	fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
769255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
770124211Sdes	fake.pw_class = "";
771124211Sdes#endif
772124211Sdes	fake.pw_dir = "/nonexist";
773124211Sdes	fake.pw_shell = "/nonexist";
774124211Sdes
775124211Sdes	return (&fake);
776124211Sdes}
777