1323124Sdes/* $OpenBSD: auth.c,v 1.115 2016/06/15 00:40:40 dtucker 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: stable/10/crypto/openssh/auth.c 323124 2017-09-01 22:52:18Z des $");
2860573Skris
29162856Sdes#include <sys/types.h>
30162856Sdes#include <sys/stat.h>
31323124Sdes#include <sys/socket.h>
32162856Sdes
33162856Sdes#include <netinet/in.h>
34162856Sdes
35162856Sdes#include <errno.h>
36181111Sdes#include <fcntl.h>
37162856Sdes#ifdef HAVE_PATHS_H
38162856Sdes# include <paths.h>
39162856Sdes#endif
40162856Sdes#include <pwd.h>
4198941Sdes#ifdef HAVE_LOGIN_H
4298941Sdes#include <login.h>
4398941Sdes#endif
44126277Sdes#ifdef USE_SHADOW
4598941Sdes#include <shadow.h>
46126277Sdes#endif
4798941Sdes#ifdef HAVE_LIBGEN_H
4892559Sdes#include <libgen.h>
4998941Sdes#endif
50162856Sdes#include <stdarg.h>
51162856Sdes#include <stdio.h>
52162856Sdes#include <string.h>
53181111Sdes#include <unistd.h>
54295367Sdes#include <limits.h>
55323124Sdes#include <netdb.h>
5692559Sdes
5760573Skris#include "xmalloc.h"
5876262Sgreen#include "match.h"
5976262Sgreen#include "groupaccess.h"
6076262Sgreen#include "log.h"
61162856Sdes#include "buffer.h"
62295367Sdes#include "misc.h"
6360573Skris#include "servconf.h"
64162856Sdes#include "key.h"
65162856Sdes#include "hostfile.h"
6660573Skris#include "auth.h"
6776262Sgreen#include "auth-options.h"
6876262Sgreen#include "canohost.h"
6992559Sdes#include "uidswap.h"
7098684Sdes#include "packet.h"
71147005Sdes#include "loginrec.h"
72162856Sdes#ifdef GSSAPI
73162856Sdes#include "ssh-gss.h"
74162856Sdes#endif
75204917Sdes#include "authfile.h"
76147005Sdes#include "monitor_wrap.h"
77295367Sdes#include "authfile.h"
78295367Sdes#include "ssherr.h"
79255767Sdes#include "compat.h"
8060573Skris
8160573Skris/* import */
8260573Skrisextern ServerOptions options;
83162856Sdesextern int use_privsep;
84124211Sdesextern Buffer loginmsg;
85162856Sdesextern struct passwd *privsep_pw;
8660573Skris
8798684Sdes/* Debugging messages */
8898684SdesBuffer auth_debug;
8998684Sdesint auth_debug_init;
9098684Sdes
9160573Skris/*
9276262Sgreen * Check if the user is allowed to log in via ssh. If user is listed
9376262Sgreen * in DenyUsers or one of user's groups is listed in DenyGroups, false
9476262Sgreen * will be returned. If AllowUsers isn't empty and user isn't listed
9576262Sgreen * there, or if AllowGroups isn't empty and one of user's groups isn't
9676262Sgreen * listed there, false will be returned.
9760573Skris * If the user's shell is not executable, false will be returned.
9860573Skris * Otherwise true is returned.
9960573Skris */
10060573Skrisint
10160573Skrisallowed_user(struct passwd * pw)
10260573Skris{
103323124Sdes	struct ssh *ssh = active_state; /* XXX */
10460573Skris	struct stat st;
105124211Sdes	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
106149753Sdes	u_int i;
107126277Sdes#ifdef USE_SHADOW
108124211Sdes	struct spwd *spw = NULL;
109113911Sdes#endif
11060573Skris
11160573Skris	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
11276262Sgreen	if (!pw || !pw->pw_name)
11360573Skris		return 0;
11460573Skris
115126277Sdes#ifdef USE_SHADOW
116124211Sdes	if (!options.use_pam)
117124211Sdes		spw = getspnam(pw->pw_name);
118124211Sdes#ifdef HAS_SHADOW_EXPIRE
119126277Sdes	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
120126277Sdes		return 0;
121124211Sdes#endif /* HAS_SHADOW_EXPIRE */
122126277Sdes#endif /* USE_SHADOW */
123124211Sdes
124126277Sdes	/* grab passwd field for locked account check */
125181111Sdes	passwd = pw->pw_passwd;
126126277Sdes#ifdef USE_SHADOW
127124211Sdes	if (spw != NULL)
128181111Sdes#ifdef USE_LIBIAF
129149753Sdes		passwd = get_iaf_password(pw);
130149753Sdes#else
131124211Sdes		passwd = spw->sp_pwdp;
132181111Sdes#endif /* USE_LIBIAF */
13398941Sdes#endif
13498941Sdes
135126277Sdes	/* check for locked account */
136124211Sdes	if (!options.use_pam && passwd && *passwd) {
137124211Sdes		int locked = 0;
138124211Sdes
139124211Sdes#ifdef LOCKED_PASSWD_STRING
140124211Sdes		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
141124211Sdes			 locked = 1;
142124211Sdes#endif
143124211Sdes#ifdef LOCKED_PASSWD_PREFIX
144124211Sdes		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
145124211Sdes		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
146124211Sdes			 locked = 1;
147124211Sdes#endif
148124211Sdes#ifdef LOCKED_PASSWD_SUBSTR
149124211Sdes		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
150124211Sdes			locked = 1;
151124211Sdes#endif
152181111Sdes#ifdef USE_LIBIAF
153215116Sdes		free((void *) passwd);
154181111Sdes#endif /* USE_LIBIAF */
155124211Sdes		if (locked) {
156124211Sdes			logit("User %.100s not allowed because account is locked",
157124211Sdes			    pw->pw_name);
158124211Sdes			return 0;
159124211Sdes		}
160124211Sdes	}
161124211Sdes
16261212Skris	/*
163204917Sdes	 * Deny if shell does not exist or is not executable unless we
164204917Sdes	 * are chrooting.
16561212Skris	 */
166204917Sdes	if (options.chroot_directory == NULL ||
167204917Sdes	    strcasecmp(options.chroot_directory, "none") == 0) {
168204917Sdes		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
169204917Sdes		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
17061212Skris
171204917Sdes		if (stat(shell, &st) != 0) {
172204917Sdes			logit("User %.100s not allowed because shell %.100s "
173204917Sdes			    "does not exist", pw->pw_name, shell);
174255767Sdes			free(shell);
175204917Sdes			return 0;
176204917Sdes		}
177204917Sdes		if (S_ISREG(st.st_mode) == 0 ||
178204917Sdes		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
179204917Sdes			logit("User %.100s not allowed because shell %.100s "
180204917Sdes			    "is not executable", pw->pw_name, shell);
181255767Sdes			free(shell);
182204917Sdes			return 0;
183204917Sdes		}
184255767Sdes		free(shell);
18592559Sdes	}
18660573Skris
187147005Sdes	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
188147005Sdes	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
189323124Sdes		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
190323124Sdes		ipaddr = ssh_remote_ipaddr(ssh);
19192559Sdes	}
19292559Sdes
19360573Skris	/* Return false if user is listed in DenyUsers */
19460573Skris	if (options.num_deny_users > 0) {
19560573Skris		for (i = 0; i < options.num_deny_users; i++)
19698684Sdes			if (match_user(pw->pw_name, hostname, ipaddr,
19792559Sdes			    options.deny_users[i])) {
198147005Sdes				logit("User %.100s from %.100s not allowed "
199147005Sdes				    "because listed in DenyUsers",
200147005Sdes				    pw->pw_name, hostname);
20160573Skris				return 0;
20292559Sdes			}
20360573Skris	}
20460573Skris	/* Return false if AllowUsers isn't empty and user isn't listed there */
20560573Skris	if (options.num_allow_users > 0) {
20660573Skris		for (i = 0; i < options.num_allow_users; i++)
20798684Sdes			if (match_user(pw->pw_name, hostname, ipaddr,
20892559Sdes			    options.allow_users[i]))
20960573Skris				break;
21060573Skris		/* i < options.num_allow_users iff we break for loop */
21192559Sdes		if (i >= options.num_allow_users) {
212147005Sdes			logit("User %.100s from %.100s not allowed because "
213147005Sdes			    "not listed in AllowUsers", pw->pw_name, hostname);
21460573Skris			return 0;
21592559Sdes		}
21660573Skris	}
21760573Skris	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
21876262Sgreen		/* Get the user's group access list (primary and supplementary) */
21992559Sdes		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
220147005Sdes			logit("User %.100s from %.100s not allowed because "
221147005Sdes			    "not in any group", pw->pw_name, hostname);
22260573Skris			return 0;
22392559Sdes		}
22460573Skris
22576262Sgreen		/* Return false if one of user's groups is listed in DenyGroups */
22676262Sgreen		if (options.num_deny_groups > 0)
22776262Sgreen			if (ga_match(options.deny_groups,
22876262Sgreen			    options.num_deny_groups)) {
22976262Sgreen				ga_free();
230147005Sdes				logit("User %.100s from %.100s not allowed "
231147005Sdes				    "because a group is listed in DenyGroups",
232147005Sdes				    pw->pw_name, hostname);
23360573Skris				return 0;
23476262Sgreen			}
23560573Skris		/*
23676262Sgreen		 * Return false if AllowGroups isn't empty and one of user's groups
23760573Skris		 * isn't listed there
23860573Skris		 */
23976262Sgreen		if (options.num_allow_groups > 0)
24076262Sgreen			if (!ga_match(options.allow_groups,
24176262Sgreen			    options.num_allow_groups)) {
24276262Sgreen				ga_free();
243147005Sdes				logit("User %.100s from %.100s not allowed "
244147005Sdes				    "because none of user's groups are listed "
245147005Sdes				    "in AllowGroups", pw->pw_name, hostname);
24660573Skris				return 0;
24776262Sgreen			}
24876262Sgreen		ga_free();
24960573Skris	}
25098941Sdes
251137019Sdes#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
252147005Sdes	if (!sys_auth_allowed_user(pw, &loginmsg))
253137019Sdes		return 0;
254137019Sdes#endif
255113911Sdes
25660573Skris	/* We found no reason not to let this user try to log on... */
25760573Skris	return 1;
25860573Skris}
25976262Sgreen
26076262Sgreenvoid
261255767Sdesauth_info(Authctxt *authctxt, const char *fmt, ...)
262255767Sdes{
263255767Sdes	va_list ap;
264255767Sdes        int i;
265255767Sdes
266255767Sdes	free(authctxt->info);
267255767Sdes	authctxt->info = NULL;
268255767Sdes
269255767Sdes	va_start(ap, fmt);
270255767Sdes	i = vasprintf(&authctxt->info, fmt, ap);
271255767Sdes	va_end(ap);
272255767Sdes
273255767Sdes	if (i < 0 || authctxt->info == NULL)
274255767Sdes		fatal("vasprintf failed");
275255767Sdes}
276255767Sdes
277255767Sdesvoid
278248619Sdesauth_log(Authctxt *authctxt, int authenticated, int partial,
279255767Sdes    const char *method, const char *submethod)
28076262Sgreen{
281323124Sdes	struct ssh *ssh = active_state; /* XXX */
28276262Sgreen	void (*authlog) (const char *fmt,...) = verbose;
28376262Sgreen	char *authmsg;
28476262Sgreen
285162856Sdes	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
286162856Sdes		return;
287162856Sdes
28876262Sgreen	/* Raise logging level */
28976262Sgreen	if (authenticated == 1 ||
29076262Sgreen	    !authctxt->valid ||
291137019Sdes	    authctxt->failures >= options.max_authtries / 2 ||
29276262Sgreen	    strcmp(method, "password") == 0)
293124211Sdes		authlog = logit;
29476262Sgreen
29576262Sgreen	if (authctxt->postponed)
29676262Sgreen		authmsg = "Postponed";
297248619Sdes	else if (partial)
298248619Sdes		authmsg = "Partial";
29976262Sgreen	else
30076262Sgreen		authmsg = authenticated ? "Accepted" : "Failed";
30176262Sgreen
302255767Sdes	authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
30376262Sgreen	    authmsg,
30476262Sgreen	    method,
305248619Sdes	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
306137019Sdes	    authctxt->valid ? "" : "invalid user ",
30792559Sdes	    authctxt->user,
308323124Sdes	    ssh_remote_ipaddr(ssh),
309323124Sdes	    ssh_remote_port(ssh),
310255767Sdes	    compat20 ? "ssh2" : "ssh1",
311255767Sdes	    authctxt->info != NULL ? ": " : "",
312255767Sdes	    authctxt->info != NULL ? authctxt->info : "");
313255767Sdes	free(authctxt->info);
314255767Sdes	authctxt->info = NULL;
315106130Sdes
316124211Sdes#ifdef CUSTOM_FAILED_LOGIN
317147005Sdes	if (authenticated == 0 && !authctxt->postponed &&
318147005Sdes	    (strcmp(method, "password") == 0 ||
319147005Sdes	    strncmp(method, "keyboard-interactive", 20) == 0 ||
320147005Sdes	    strcmp(method, "challenge-response") == 0))
321147005Sdes		record_failed_login(authctxt->user,
322323124Sdes		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
323162856Sdes# ifdef WITH_AIXAUTHENTICATE
324162856Sdes	if (authenticated)
325162856Sdes		sys_auth_record_login(authctxt->user,
326323124Sdes		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
327323124Sdes		    &loginmsg);
328162856Sdes# endif
329124211Sdes#endif
330147005Sdes#ifdef SSH_AUDIT_EVENTS
331162856Sdes	if (authenticated == 0 && !authctxt->postponed)
332162856Sdes		audit_event(audit_classify_auth(method));
333147005Sdes#endif
33476262Sgreen}
33576262Sgreen
336295367Sdes
337295367Sdesvoid
338295367Sdesauth_maxtries_exceeded(Authctxt *authctxt)
339295367Sdes{
340323124Sdes	struct ssh *ssh = active_state; /* XXX */
341323124Sdes
342295367Sdes	error("maximum authentication attempts exceeded for "
343295367Sdes	    "%s%.100s from %.200s port %d %s",
344295367Sdes	    authctxt->valid ? "" : "invalid user ",
345295367Sdes	    authctxt->user,
346323124Sdes	    ssh_remote_ipaddr(ssh),
347323124Sdes	    ssh_remote_port(ssh),
348295367Sdes	    compat20 ? "ssh2" : "ssh1");
349295367Sdes	packet_disconnect("Too many authentication failures");
350295367Sdes	/* NOTREACHED */
351295367Sdes}
352295367Sdes
35376262Sgreen/*
35476262Sgreen * Check whether root logins are disallowed.
35576262Sgreen */
35676262Sgreenint
357248619Sdesauth_root_allowed(const char *method)
35876262Sgreen{
359323124Sdes	struct ssh *ssh = active_state; /* XXX */
360323124Sdes
36176262Sgreen	switch (options.permit_root_login) {
36276262Sgreen	case PERMIT_YES:
36376262Sgreen		return 1;
36476262Sgreen	case PERMIT_NO_PASSWD:
365295367Sdes		if (strcmp(method, "publickey") == 0 ||
366295367Sdes		    strcmp(method, "hostbased") == 0 ||
367295367Sdes		    strcmp(method, "gssapi-with-mic") == 0)
36876262Sgreen			return 1;
36976262Sgreen		break;
37076262Sgreen	case PERMIT_FORCED_ONLY:
37176262Sgreen		if (forced_command) {
372124211Sdes			logit("Root login accepted for forced command.");
37376262Sgreen			return 1;
37476262Sgreen		}
37576262Sgreen		break;
37676262Sgreen	}
377323124Sdes	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
378323124Sdes	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
37976262Sgreen	return 0;
38076262Sgreen}
38192559Sdes
38292559Sdes
38392559Sdes/*
38492559Sdes * Given a template and a passwd structure, build a filename
38592559Sdes * by substituting % tokenised options. Currently, %% becomes '%',
38692559Sdes * %h becomes the home directory and %u the username.
38792559Sdes *
38892559Sdes * This returns a buffer allocated by xmalloc.
38992559Sdes */
390226046Sdeschar *
391149753Sdesexpand_authorized_keys(const char *filename, struct passwd *pw)
39292559Sdes{
393295367Sdes	char *file, ret[PATH_MAX];
394162856Sdes	int i;
39592559Sdes
396149753Sdes	file = percent_expand(filename, "h", pw->pw_dir,
397149753Sdes	    "u", pw->pw_name, (char *)NULL);
39892559Sdes
39992559Sdes	/*
40092559Sdes	 * Ensure that filename starts anchored. If not, be backward
40192559Sdes	 * compatible and prepend the '%h/'
40292559Sdes	 */
403149753Sdes	if (*file == '/')
404149753Sdes		return (file);
40592559Sdes
406162856Sdes	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
407162856Sdes	if (i < 0 || (size_t)i >= sizeof(ret))
408149753Sdes		fatal("expand_authorized_keys: path too long");
409255767Sdes	free(file);
410162856Sdes	return (xstrdup(ret));
41192559Sdes}
41292559Sdes
41392559Sdeschar *
414215116Sdesauthorized_principals_file(struct passwd *pw)
415215116Sdes{
416295367Sdes	if (options.authorized_principals_file == NULL)
417215116Sdes		return NULL;
418215116Sdes	return expand_authorized_keys(options.authorized_principals_file, pw);
419215116Sdes}
420215116Sdes
42192559Sdes/* return ok if key exists in sysfile or userfile */
42292559SdesHostStatus
42392559Sdescheck_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
42492559Sdes    const char *sysfile, const char *userfile)
42592559Sdes{
42692559Sdes	char *user_hostfile;
42792559Sdes	struct stat st;
42892559Sdes	HostStatus host_status;
429221420Sdes	struct hostkeys *hostkeys;
430221420Sdes	const struct hostkey_entry *found;
43192559Sdes
432221420Sdes	hostkeys = init_hostkeys();
433221420Sdes	load_hostkeys(hostkeys, host, sysfile);
434221420Sdes	if (userfile != NULL) {
43592559Sdes		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
43692559Sdes		if (options.strict_modes &&
43792559Sdes		    (stat(user_hostfile, &st) == 0) &&
43892559Sdes		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
43992559Sdes		    (st.st_mode & 022) != 0)) {
440124211Sdes			logit("Authentication refused for %.100s: "
44192559Sdes			    "bad owner or modes for %.200s",
44292559Sdes			    pw->pw_name, user_hostfile);
443215116Sdes			auth_debug_add("Ignored %.200s: bad ownership or modes",
444215116Sdes			    user_hostfile);
44592559Sdes		} else {
44692559Sdes			temporarily_use_uid(pw);
447221420Sdes			load_hostkeys(hostkeys, host, user_hostfile);
44892559Sdes			restore_uid();
44992559Sdes		}
450255767Sdes		free(user_hostfile);
45192559Sdes	}
452221420Sdes	host_status = check_key_in_hostkeys(hostkeys, key, &found);
453221420Sdes	if (host_status == HOST_REVOKED)
454221420Sdes		error("WARNING: revoked key for %s attempted authentication",
455221420Sdes		    found->host);
456221420Sdes	else if (host_status == HOST_OK)
457221420Sdes		debug("%s: key for %s found at %s:%ld", __func__,
458221420Sdes		    found->host, found->file, found->line);
459221420Sdes	else
460221420Sdes		debug("%s: key for host %s not found", __func__, host);
46192559Sdes
462221420Sdes	free_hostkeys(hostkeys);
463221420Sdes
46492559Sdes	return host_status;
46592559Sdes}
46692559Sdes
46792559Sdes/*
468248619Sdes * Check a given path for security. This is defined as all components
469106130Sdes * of the path to the file must be owned by either the owner of
47092559Sdes * of the file or root and no directories must be group or world writable.
47192559Sdes *
47292559Sdes * XXX Should any specific check be done for sym links ?
47392559Sdes *
474248619Sdes * Takes a file name, its stat information (preferably from fstat() to
475248619Sdes * avoid races), the uid of the expected owner, their home directory and an
47692559Sdes * error buffer plus max size as arguments.
47792559Sdes *
47892559Sdes * Returns 0 on success and -1 on failure
47992559Sdes */
480248619Sdesint
481248619Sdesauth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
482248619Sdes    uid_t uid, char *err, size_t errlen)
48392559Sdes{
484295367Sdes	char buf[PATH_MAX], homedir[PATH_MAX];
48592559Sdes	char *cp;
486113911Sdes	int comparehome = 0;
48792559Sdes	struct stat st;
48892559Sdes
489248619Sdes	if (realpath(name, buf) == NULL) {
490248619Sdes		snprintf(err, errlen, "realpath %s failed: %s", name,
49192559Sdes		    strerror(errno));
49292559Sdes		return -1;
49392559Sdes	}
494248619Sdes	if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
495113911Sdes		comparehome = 1;
49692559Sdes
497248619Sdes	if (!S_ISREG(stp->st_mode)) {
498248619Sdes		snprintf(err, errlen, "%s is not a regular file", buf);
499248619Sdes		return -1;
500248619Sdes	}
501248619Sdes	if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
502248619Sdes	    (stp->st_mode & 022) != 0) {
50392559Sdes		snprintf(err, errlen, "bad ownership or modes for file %s",
50492559Sdes		    buf);
50592559Sdes		return -1;
50692559Sdes	}
50792559Sdes
50892559Sdes	/* for each component of the canonical path, walking upwards */
50992559Sdes	for (;;) {
51092559Sdes		if ((cp = dirname(buf)) == NULL) {
51192559Sdes			snprintf(err, errlen, "dirname() failed");
51292559Sdes			return -1;
51392559Sdes		}
51492559Sdes		strlcpy(buf, cp, sizeof(buf));
51592559Sdes
51692559Sdes		if (stat(buf, &st) < 0 ||
517248619Sdes		    (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
51892559Sdes		    (st.st_mode & 022) != 0) {
51992559Sdes			snprintf(err, errlen,
52092559Sdes			    "bad ownership or modes for directory %s", buf);
52192559Sdes			return -1;
52292559Sdes		}
52392559Sdes
524204917Sdes		/* If are past the homedir then we can stop */
525226046Sdes		if (comparehome && strcmp(homedir, buf) == 0)
52692559Sdes			break;
527226046Sdes
52892559Sdes		/*
52992559Sdes		 * dirname should always complete with a "/" path,
53092559Sdes		 * but we can be paranoid and check for "." too
53192559Sdes		 */
53292559Sdes		if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
53392559Sdes			break;
53492559Sdes	}
53592559Sdes	return 0;
53692559Sdes}
53798684Sdes
538248619Sdes/*
539248619Sdes * Version of secure_path() that accepts an open file descriptor to
540248619Sdes * avoid races.
541248619Sdes *
542248619Sdes * Returns 0 on success and -1 on failure
543248619Sdes */
544248619Sdesstatic int
545248619Sdessecure_filename(FILE *f, const char *file, struct passwd *pw,
546248619Sdes    char *err, size_t errlen)
547248619Sdes{
548248619Sdes	struct stat st;
549248619Sdes
550248619Sdes	/* check the open file to avoid races */
551248619Sdes	if (fstat(fileno(f), &st) < 0) {
552248619Sdes		snprintf(err, errlen, "cannot stat file %s: %s",
553248619Sdes		    file, strerror(errno));
554248619Sdes		return -1;
555248619Sdes	}
556248619Sdes	return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
557248619Sdes}
558248619Sdes
559215116Sdesstatic FILE *
560215116Sdesauth_openfile(const char *file, struct passwd *pw, int strict_modes,
561215116Sdes    int log_missing, char *file_type)
562181111Sdes{
563181111Sdes	char line[1024];
564181111Sdes	struct stat st;
565181111Sdes	int fd;
566181111Sdes	FILE *f;
567181111Sdes
568204917Sdes	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
569215116Sdes		if (log_missing || errno != ENOENT)
570215116Sdes			debug("Could not open %s '%s': %s", file_type, file,
571204917Sdes			   strerror(errno));
572181111Sdes		return NULL;
573204917Sdes	}
574181111Sdes
575181111Sdes	if (fstat(fd, &st) < 0) {
576181111Sdes		close(fd);
577181111Sdes		return NULL;
578181111Sdes	}
579181111Sdes	if (!S_ISREG(st.st_mode)) {
580215116Sdes		logit("User %s %s %s is not a regular file",
581215116Sdes		    pw->pw_name, file_type, file);
582181111Sdes		close(fd);
583181111Sdes		return NULL;
584181111Sdes	}
585181111Sdes	unset_nonblock(fd);
586181111Sdes	if ((f = fdopen(fd, "r")) == NULL) {
587181111Sdes		close(fd);
588181111Sdes		return NULL;
589181111Sdes	}
590221420Sdes	if (strict_modes &&
591181111Sdes	    secure_filename(f, file, pw, line, sizeof(line)) != 0) {
592181111Sdes		fclose(f);
593181111Sdes		logit("Authentication refused: %s", line);
594215116Sdes		auth_debug_add("Ignored %s: %s", file_type, line);
595181111Sdes		return NULL;
596181111Sdes	}
597181111Sdes
598181111Sdes	return f;
599181111Sdes}
600181111Sdes
601215116Sdes
602215116SdesFILE *
603215116Sdesauth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
604215116Sdes{
605215116Sdes	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
606215116Sdes}
607215116Sdes
608215116SdesFILE *
609215116Sdesauth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
610215116Sdes{
611215116Sdes	return auth_openfile(file, pw, strict_modes, 0,
612215116Sdes	    "authorized principals");
613215116Sdes}
614215116Sdes
61598684Sdesstruct passwd *
61698684Sdesgetpwnamallow(const char *user)
61798684Sdes{
618323124Sdes	struct ssh *ssh = active_state; /* XXX */
61998684Sdes#ifdef HAVE_LOGIN_CAP
62098684Sdes	extern login_cap_t *lc;
62198684Sdes#ifdef BSD_AUTH
62298684Sdes	auth_session_t *as;
62398684Sdes#endif
62498684Sdes#endif
62598684Sdes	struct passwd *pw;
626240075Sdes	struct connection_info *ci = get_connection_info(1, options.use_dns);
62798684Sdes
628240075Sdes	ci->user = user;
629240075Sdes	parse_server_match_config(&options, ci);
630162856Sdes
631204917Sdes#if defined(_AIX) && defined(HAVE_SETAUTHDB)
632204917Sdes	aix_setauthdb(user);
633204917Sdes#endif
634204917Sdes
63598684Sdes	pw = getpwnam(user);
636204917Sdes
637204917Sdes#if defined(_AIX) && defined(HAVE_SETAUTHDB)
638204917Sdes	aix_restoreauthdb();
639204917Sdes#endif
640204917Sdes#ifdef HAVE_CYGWIN
641204917Sdes	/*
642204917Sdes	 * Windows usernames are case-insensitive.  To avoid later problems
643204917Sdes	 * when trying to match the username, the user is only allowed to
644204917Sdes	 * login if the username is given in the same case as stored in the
645204917Sdes	 * user database.
646204917Sdes	 */
647204917Sdes	if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
648204917Sdes		logit("Login name %.100s does not match stored username %.100s",
649204917Sdes		    user, pw->pw_name);
650204917Sdes		pw = NULL;
651204917Sdes	}
652204917Sdes#endif
653106130Sdes	if (pw == NULL) {
654323124Sdes		logit("Invalid user %.100s from %.100s port %d",
655323124Sdes		    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
656124211Sdes#ifdef CUSTOM_FAILED_LOGIN
657147005Sdes		record_failed_login(user,
658323124Sdes		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
659113911Sdes#endif
660147005Sdes#ifdef SSH_AUDIT_EVENTS
661147005Sdes		audit_event(SSH_INVALID_USER);
662147005Sdes#endif /* SSH_AUDIT_EVENTS */
66398684Sdes		return (NULL);
664106130Sdes	}
665106130Sdes	if (!allowed_user(pw))
666106130Sdes		return (NULL);
66798684Sdes#ifdef HAVE_LOGIN_CAP
668100838Sfanf	if ((lc = login_getpwclass(pw)) == NULL) {
66998684Sdes		debug("unable to get login class: %s", user);
67098684Sdes		return (NULL);
67198684Sdes	}
67298684Sdes#ifdef BSD_AUTH
67398684Sdes	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
67498684Sdes	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
67598684Sdes		debug("Approval failure for %s", user);
67698684Sdes		pw = NULL;
67798684Sdes	}
67898684Sdes	if (as != NULL)
67998684Sdes		auth_close(as);
68098684Sdes#endif
68198684Sdes#endif
68298684Sdes	if (pw != NULL)
68398684Sdes		return (pwcopy(pw));
68498684Sdes	return (NULL);
68598684Sdes}
68698684Sdes
687204917Sdes/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
688204917Sdesint
689204917Sdesauth_key_is_revoked(Key *key)
690204917Sdes{
691295367Sdes	char *fp = NULL;
692295367Sdes	int r;
693204917Sdes
694204917Sdes	if (options.revoked_keys_file == NULL)
695204917Sdes		return 0;
696295367Sdes	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
697295367Sdes	    SSH_FP_DEFAULT)) == NULL) {
698295367Sdes		r = SSH_ERR_ALLOC_FAIL;
699295367Sdes		error("%s: fingerprint key: %s", __func__, ssh_err(r));
700295367Sdes		goto out;
701295367Sdes	}
702295367Sdes
703295367Sdes	r = sshkey_check_revoked(key, options.revoked_keys_file);
704295367Sdes	switch (r) {
705248619Sdes	case 0:
706295367Sdes		break; /* not revoked */
707295367Sdes	case SSH_ERR_KEY_REVOKED:
708295367Sdes		error("Authentication key %s %s revoked by file %s",
709295367Sdes		    sshkey_type(key), fp, options.revoked_keys_file);
710295367Sdes		goto out;
711248619Sdes	default:
712295367Sdes		error("Error checking authentication key %s %s in "
713295367Sdes		    "revoked keys file %s: %s", sshkey_type(key), fp,
714295367Sdes		    options.revoked_keys_file, ssh_err(r));
715295367Sdes		goto out;
716248619Sdes	}
717295367Sdes
718295367Sdes	/* Success */
719295367Sdes	r = 0;
720295367Sdes
721295367Sdes out:
722295367Sdes	free(fp);
723295367Sdes	return r == 0 ? 0 : 1;
724204917Sdes}
725204917Sdes
72698684Sdesvoid
72798684Sdesauth_debug_add(const char *fmt,...)
72898684Sdes{
72998684Sdes	char buf[1024];
73098684Sdes	va_list args;
73198684Sdes
73298684Sdes	if (!auth_debug_init)
73398684Sdes		return;
73498684Sdes
73598684Sdes	va_start(args, fmt);
73698684Sdes	vsnprintf(buf, sizeof(buf), fmt, args);
73798684Sdes	va_end(args);
73898684Sdes	buffer_put_cstring(&auth_debug, buf);
73998684Sdes}
74098684Sdes
74198684Sdesvoid
74298684Sdesauth_debug_send(void)
74398684Sdes{
74498684Sdes	char *msg;
74598684Sdes
74698684Sdes	if (!auth_debug_init)
74798684Sdes		return;
74898684Sdes	while (buffer_len(&auth_debug)) {
74998684Sdes		msg = buffer_get_string(&auth_debug, NULL);
75098684Sdes		packet_send_debug("%s", msg);
751255767Sdes		free(msg);
75298684Sdes	}
75398684Sdes}
75498684Sdes
75598684Sdesvoid
75698684Sdesauth_debug_reset(void)
75798684Sdes{
75898684Sdes	if (auth_debug_init)
75998684Sdes		buffer_clear(&auth_debug);
76098684Sdes	else {
76198684Sdes		buffer_init(&auth_debug);
76298684Sdes		auth_debug_init = 1;
76398684Sdes	}
76498684Sdes}
765124211Sdes
766124211Sdesstruct passwd *
767124211Sdesfakepw(void)
768124211Sdes{
769124211Sdes	static struct passwd fake;
770124211Sdes
771124211Sdes	memset(&fake, 0, sizeof(fake));
772124211Sdes	fake.pw_name = "NOUSER";
773124211Sdes	fake.pw_passwd =
774126277Sdes	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
775255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
776124211Sdes	fake.pw_gecos = "NOUSER";
777255767Sdes#endif
778181111Sdes	fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
779181111Sdes	fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
780255767Sdes#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
781124211Sdes	fake.pw_class = "";
782124211Sdes#endif
783124211Sdes	fake.pw_dir = "/nonexist";
784124211Sdes	fake.pw_shell = "/nonexist";
785124211Sdes
786124211Sdes	return (&fake);
787124211Sdes}
788323124Sdes
789323124Sdes/*
790323124Sdes * Returns the remote DNS hostname as a string. The returned string must not
791323124Sdes * be freed. NB. this will usually trigger a DNS query the first time it is
792323124Sdes * called.
793323124Sdes * This function does additional checks on the hostname to mitigate some
794323124Sdes * attacks on legacy rhosts-style authentication.
795323124Sdes * XXX is RhostsRSAAuthentication vulnerable to these?
796323124Sdes * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
797323124Sdes */
798323124Sdes
799323124Sdesstatic char *
800323124Sdesremote_hostname(struct ssh *ssh)
801323124Sdes{
802323124Sdes	struct sockaddr_storage from;
803323124Sdes	socklen_t fromlen;
804323124Sdes	struct addrinfo hints, *ai, *aitop;
805323124Sdes	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
806323124Sdes	const char *ntop = ssh_remote_ipaddr(ssh);
807323124Sdes
808323124Sdes	/* Get IP address of client. */
809323124Sdes	fromlen = sizeof(from);
810323124Sdes	memset(&from, 0, sizeof(from));
811323124Sdes	if (getpeername(ssh_packet_get_connection_in(ssh),
812323124Sdes	    (struct sockaddr *)&from, &fromlen) < 0) {
813323124Sdes		debug("getpeername failed: %.100s", strerror(errno));
814323124Sdes		return strdup(ntop);
815323124Sdes	}
816323124Sdes
817323124Sdes	ipv64_normalise_mapped(&from, &fromlen);
818323124Sdes	if (from.ss_family == AF_INET6)
819323124Sdes		fromlen = sizeof(struct sockaddr_in6);
820323124Sdes
821323124Sdes	debug3("Trying to reverse map address %.100s.", ntop);
822323124Sdes	/* Map the IP address to a host name. */
823323124Sdes	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
824323124Sdes	    NULL, 0, NI_NAMEREQD) != 0) {
825323124Sdes		/* Host name not found.  Use ip address. */
826323124Sdes		return strdup(ntop);
827323124Sdes	}
828323124Sdes
829323124Sdes	/*
830323124Sdes	 * if reverse lookup result looks like a numeric hostname,
831323124Sdes	 * someone is trying to trick us by PTR record like following:
832323124Sdes	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
833323124Sdes	 */
834323124Sdes	memset(&hints, 0, sizeof(hints));
835323124Sdes	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
836323124Sdes	hints.ai_flags = AI_NUMERICHOST;
837323124Sdes	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
838323124Sdes		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
839323124Sdes		    name, ntop);
840323124Sdes		freeaddrinfo(ai);
841323124Sdes		return strdup(ntop);
842323124Sdes	}
843323124Sdes
844323124Sdes	/* Names are stored in lowercase. */
845323124Sdes	lowercase(name);
846323124Sdes
847323124Sdes	/*
848323124Sdes	 * Map it back to an IP address and check that the given
849323124Sdes	 * address actually is an address of this host.  This is
850323124Sdes	 * necessary because anyone with access to a name server can
851323124Sdes	 * define arbitrary names for an IP address. Mapping from
852323124Sdes	 * name to IP address can be trusted better (but can still be
853323124Sdes	 * fooled if the intruder has access to the name server of
854323124Sdes	 * the domain).
855323124Sdes	 */
856323124Sdes	memset(&hints, 0, sizeof(hints));
857323124Sdes	hints.ai_family = from.ss_family;
858323124Sdes	hints.ai_socktype = SOCK_STREAM;
859323124Sdes	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
860323124Sdes		logit("reverse mapping checking getaddrinfo for %.700s "
861323124Sdes		    "[%s] failed.", name, ntop);
862323124Sdes		return strdup(ntop);
863323124Sdes	}
864323124Sdes	/* Look for the address from the list of addresses. */
865323124Sdes	for (ai = aitop; ai; ai = ai->ai_next) {
866323124Sdes		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
867323124Sdes		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
868323124Sdes		    (strcmp(ntop, ntop2) == 0))
869323124Sdes				break;
870323124Sdes	}
871323124Sdes	freeaddrinfo(aitop);
872323124Sdes	/* If we reached the end of the list, the address was not there. */
873323124Sdes	if (ai == NULL) {
874323124Sdes		/* Address not found for the host name. */
875323124Sdes		logit("Address %.100s maps to %.600s, but this does not "
876323124Sdes		    "map back to the address.", ntop, name);
877323124Sdes		return strdup(ntop);
878323124Sdes	}
879323124Sdes	return strdup(name);
880323124Sdes}
881323124Sdes
882323124Sdes/*
883323124Sdes * Return the canonical name of the host in the other side of the current
884323124Sdes * connection.  The host name is cached, so it is efficient to call this
885323124Sdes * several times.
886323124Sdes */
887323124Sdes
888323124Sdesconst char *
889323124Sdesauth_get_canonical_hostname(struct ssh *ssh, int use_dns)
890323124Sdes{
891323124Sdes	static char *dnsname;
892323124Sdes
893323124Sdes	if (!use_dns)
894323124Sdes		return ssh_remote_ipaddr(ssh);
895323124Sdes	else if (dnsname != NULL)
896323124Sdes		return dnsname;
897323124Sdes	else {
898323124Sdes		dnsname = remote_hostname(ssh);
899323124Sdes		return dnsname;
900323124Sdes	}
901323124Sdes}
902