xref: /dflybsd-src/crypto/openssh/auth.c (revision ce74baca94b6dd2a80af6a625aba2cf14ab7fec8)
1*ce74bacaSMatthew Dillon /* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
418de8d7fSPeter Avalos  *
518de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
618de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
718de8d7fSPeter Avalos  * are met:
818de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
918de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1018de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1118de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1218de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
1318de8d7fSPeter Avalos  *
1418de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1518de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1618de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1718de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1818de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1918de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2018de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2118de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2218de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2318de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2418de8d7fSPeter Avalos  */
2518de8d7fSPeter Avalos 
2618de8d7fSPeter Avalos #include "includes.h"
2718de8d7fSPeter Avalos 
2818de8d7fSPeter Avalos #include <sys/types.h>
2918de8d7fSPeter Avalos #include <sys/stat.h>
30e9778795SPeter Avalos #include <sys/socket.h>
3118de8d7fSPeter Avalos 
3218de8d7fSPeter Avalos #include <netinet/in.h>
3318de8d7fSPeter Avalos 
3418de8d7fSPeter Avalos #include <errno.h>
3518de8d7fSPeter Avalos #include <fcntl.h>
3618de8d7fSPeter Avalos #ifdef HAVE_PATHS_H
3718de8d7fSPeter Avalos # include <paths.h>
3818de8d7fSPeter Avalos #endif
3918de8d7fSPeter Avalos #include <pwd.h>
4018de8d7fSPeter Avalos #ifdef HAVE_LOGIN_H
4118de8d7fSPeter Avalos #include <login.h>
4218de8d7fSPeter Avalos #endif
4318de8d7fSPeter Avalos #ifdef USE_SHADOW
4418de8d7fSPeter Avalos #include <shadow.h>
4518de8d7fSPeter Avalos #endif
4618de8d7fSPeter Avalos #include <stdarg.h>
4718de8d7fSPeter Avalos #include <stdio.h>
4818de8d7fSPeter Avalos #include <string.h>
4918de8d7fSPeter Avalos #include <unistd.h>
50e9778795SPeter Avalos #include <limits.h>
51e9778795SPeter Avalos #include <netdb.h>
5218de8d7fSPeter Avalos 
5318de8d7fSPeter Avalos #include "xmalloc.h"
5418de8d7fSPeter Avalos #include "match.h"
5518de8d7fSPeter Avalos #include "groupaccess.h"
5618de8d7fSPeter Avalos #include "log.h"
5718de8d7fSPeter Avalos #include "buffer.h"
5836e94dc5SPeter Avalos #include "misc.h"
5918de8d7fSPeter Avalos #include "servconf.h"
6018de8d7fSPeter Avalos #include "key.h"
6118de8d7fSPeter Avalos #include "hostfile.h"
6218de8d7fSPeter Avalos #include "auth.h"
6318de8d7fSPeter Avalos #include "auth-options.h"
6418de8d7fSPeter Avalos #include "canohost.h"
6518de8d7fSPeter Avalos #include "uidswap.h"
6618de8d7fSPeter Avalos #include "packet.h"
6718de8d7fSPeter Avalos #include "loginrec.h"
6818de8d7fSPeter Avalos #ifdef GSSAPI
6918de8d7fSPeter Avalos #include "ssh-gss.h"
7018de8d7fSPeter Avalos #endif
71856ea928SPeter Avalos #include "authfile.h"
7218de8d7fSPeter Avalos #include "monitor_wrap.h"
73e9778795SPeter Avalos #include "authfile.h"
74e9778795SPeter Avalos #include "ssherr.h"
7536e94dc5SPeter Avalos #include "compat.h"
7618de8d7fSPeter Avalos 
7718de8d7fSPeter Avalos /* import */
7818de8d7fSPeter Avalos extern ServerOptions options;
7918de8d7fSPeter Avalos extern int use_privsep;
8018de8d7fSPeter Avalos extern Buffer loginmsg;
8118de8d7fSPeter Avalos extern struct passwd *privsep_pw;
8218de8d7fSPeter Avalos 
8318de8d7fSPeter Avalos /* Debugging messages */
8418de8d7fSPeter Avalos Buffer auth_debug;
8518de8d7fSPeter Avalos int auth_debug_init;
8618de8d7fSPeter Avalos 
8718de8d7fSPeter Avalos /*
8818de8d7fSPeter Avalos  * Check if the user is allowed to log in via ssh. If user is listed
8918de8d7fSPeter Avalos  * in DenyUsers or one of user's groups is listed in DenyGroups, false
9018de8d7fSPeter Avalos  * will be returned. If AllowUsers isn't empty and user isn't listed
9118de8d7fSPeter Avalos  * there, or if AllowGroups isn't empty and one of user's groups isn't
9218de8d7fSPeter Avalos  * listed there, false will be returned.
9318de8d7fSPeter Avalos  * If the user's shell is not executable, false will be returned.
9418de8d7fSPeter Avalos  * Otherwise true is returned.
9518de8d7fSPeter Avalos  */
9618de8d7fSPeter Avalos int
9718de8d7fSPeter Avalos allowed_user(struct passwd * pw)
9818de8d7fSPeter Avalos {
99e9778795SPeter Avalos 	struct ssh *ssh = active_state; /* XXX */
10018de8d7fSPeter Avalos 	struct stat st;
10118de8d7fSPeter Avalos 	const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
10218de8d7fSPeter Avalos 	u_int i;
103*ce74bacaSMatthew Dillon 	int r;
10418de8d7fSPeter Avalos #ifdef USE_SHADOW
10518de8d7fSPeter Avalos 	struct spwd *spw = NULL;
10618de8d7fSPeter Avalos #endif
10718de8d7fSPeter Avalos 
10818de8d7fSPeter Avalos 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
10918de8d7fSPeter Avalos 	if (!pw || !pw->pw_name)
11018de8d7fSPeter Avalos 		return 0;
11118de8d7fSPeter Avalos 
11218de8d7fSPeter Avalos #ifdef USE_SHADOW
11318de8d7fSPeter Avalos 	if (!options.use_pam)
11418de8d7fSPeter Avalos 		spw = getspnam(pw->pw_name);
11518de8d7fSPeter Avalos #ifdef HAS_SHADOW_EXPIRE
11618de8d7fSPeter Avalos 	if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
11718de8d7fSPeter Avalos 		return 0;
11818de8d7fSPeter Avalos #endif /* HAS_SHADOW_EXPIRE */
11918de8d7fSPeter Avalos #endif /* USE_SHADOW */
12018de8d7fSPeter Avalos 
12118de8d7fSPeter Avalos 	/* grab passwd field for locked account check */
12218de8d7fSPeter Avalos 	passwd = pw->pw_passwd;
12318de8d7fSPeter Avalos #ifdef USE_SHADOW
12418de8d7fSPeter Avalos 	if (spw != NULL)
12518de8d7fSPeter Avalos #ifdef USE_LIBIAF
12618de8d7fSPeter Avalos 		passwd = get_iaf_password(pw);
12718de8d7fSPeter Avalos #else
12818de8d7fSPeter Avalos 		passwd = spw->sp_pwdp;
12918de8d7fSPeter Avalos #endif /* USE_LIBIAF */
13018de8d7fSPeter Avalos #endif
13118de8d7fSPeter Avalos 
13218de8d7fSPeter Avalos 	/* check for locked account */
13318de8d7fSPeter Avalos 	if (!options.use_pam && passwd && *passwd) {
13418de8d7fSPeter Avalos 		int locked = 0;
13518de8d7fSPeter Avalos 
13618de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_STRING
13718de8d7fSPeter Avalos 		if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
13818de8d7fSPeter Avalos 			 locked = 1;
13918de8d7fSPeter Avalos #endif
14018de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_PREFIX
14118de8d7fSPeter Avalos 		if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
14218de8d7fSPeter Avalos 		    strlen(LOCKED_PASSWD_PREFIX)) == 0)
14318de8d7fSPeter Avalos 			 locked = 1;
14418de8d7fSPeter Avalos #endif
14518de8d7fSPeter Avalos #ifdef LOCKED_PASSWD_SUBSTR
14618de8d7fSPeter Avalos 		if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
14718de8d7fSPeter Avalos 			locked = 1;
14818de8d7fSPeter Avalos #endif
14918de8d7fSPeter Avalos #ifdef USE_LIBIAF
150856ea928SPeter Avalos 		free((void *) passwd);
15118de8d7fSPeter Avalos #endif /* USE_LIBIAF */
15218de8d7fSPeter Avalos 		if (locked) {
15318de8d7fSPeter Avalos 			logit("User %.100s not allowed because account is locked",
15418de8d7fSPeter Avalos 			    pw->pw_name);
15518de8d7fSPeter Avalos 			return 0;
15618de8d7fSPeter Avalos 		}
15718de8d7fSPeter Avalos 	}
15818de8d7fSPeter Avalos 
15918de8d7fSPeter Avalos 	/*
160856ea928SPeter Avalos 	 * Deny if shell does not exist or is not executable unless we
161856ea928SPeter Avalos 	 * are chrooting.
16218de8d7fSPeter Avalos 	 */
163856ea928SPeter Avalos 	if (options.chroot_directory == NULL ||
164856ea928SPeter Avalos 	    strcasecmp(options.chroot_directory, "none") == 0) {
165856ea928SPeter Avalos 		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
166856ea928SPeter Avalos 		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
16718de8d7fSPeter Avalos 
16818de8d7fSPeter Avalos 		if (stat(shell, &st) != 0) {
169856ea928SPeter Avalos 			logit("User %.100s not allowed because shell %.100s "
170856ea928SPeter Avalos 			    "does not exist", pw->pw_name, shell);
17136e94dc5SPeter Avalos 			free(shell);
17218de8d7fSPeter Avalos 			return 0;
17318de8d7fSPeter Avalos 		}
17418de8d7fSPeter Avalos 		if (S_ISREG(st.st_mode) == 0 ||
17518de8d7fSPeter Avalos 		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
176856ea928SPeter Avalos 			logit("User %.100s not allowed because shell %.100s "
177856ea928SPeter Avalos 			    "is not executable", pw->pw_name, shell);
17836e94dc5SPeter Avalos 			free(shell);
17918de8d7fSPeter Avalos 			return 0;
18018de8d7fSPeter Avalos 		}
18136e94dc5SPeter Avalos 		free(shell);
182856ea928SPeter Avalos 	}
18318de8d7fSPeter Avalos 
18418de8d7fSPeter Avalos 	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
18518de8d7fSPeter Avalos 	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
186e9778795SPeter Avalos 		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
187e9778795SPeter Avalos 		ipaddr = ssh_remote_ipaddr(ssh);
18818de8d7fSPeter Avalos 	}
18918de8d7fSPeter Avalos 
19018de8d7fSPeter Avalos 	/* Return false if user is listed in DenyUsers */
19118de8d7fSPeter Avalos 	if (options.num_deny_users > 0) {
192*ce74bacaSMatthew Dillon 		for (i = 0; i < options.num_deny_users; i++) {
193*ce74bacaSMatthew Dillon 			r = match_user(pw->pw_name, hostname, ipaddr,
194*ce74bacaSMatthew Dillon 			    options.deny_users[i]);
195*ce74bacaSMatthew Dillon 			if (r < 0) {
196*ce74bacaSMatthew Dillon 				fatal("Invalid DenyUsers pattern \"%.100s\"",
197*ce74bacaSMatthew Dillon 				    options.deny_users[i]);
198*ce74bacaSMatthew Dillon 			} else if (r != 0) {
19918de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
20018de8d7fSPeter Avalos 				    "because listed in DenyUsers",
20118de8d7fSPeter Avalos 				    pw->pw_name, hostname);
20218de8d7fSPeter Avalos 				return 0;
20318de8d7fSPeter Avalos 			}
20418de8d7fSPeter Avalos 		}
205*ce74bacaSMatthew Dillon 	}
20618de8d7fSPeter Avalos 	/* Return false if AllowUsers isn't empty and user isn't listed there */
20718de8d7fSPeter Avalos 	if (options.num_allow_users > 0) {
208*ce74bacaSMatthew Dillon 		for (i = 0; i < options.num_allow_users; i++) {
209*ce74bacaSMatthew Dillon 			r = match_user(pw->pw_name, hostname, ipaddr,
210*ce74bacaSMatthew Dillon 			    options.allow_users[i]);
211*ce74bacaSMatthew Dillon 			if (r < 0) {
212*ce74bacaSMatthew Dillon 				fatal("Invalid AllowUsers pattern \"%.100s\"",
213*ce74bacaSMatthew Dillon 				    options.allow_users[i]);
214*ce74bacaSMatthew Dillon 			} else if (r == 1)
21518de8d7fSPeter Avalos 				break;
216*ce74bacaSMatthew Dillon 		}
21718de8d7fSPeter Avalos 		/* i < options.num_allow_users iff we break for loop */
21818de8d7fSPeter Avalos 		if (i >= options.num_allow_users) {
21918de8d7fSPeter Avalos 			logit("User %.100s from %.100s not allowed because "
22018de8d7fSPeter Avalos 			    "not listed in AllowUsers", pw->pw_name, hostname);
22118de8d7fSPeter Avalos 			return 0;
22218de8d7fSPeter Avalos 		}
22318de8d7fSPeter Avalos 	}
22418de8d7fSPeter Avalos 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
22518de8d7fSPeter Avalos 		/* Get the user's group access list (primary and supplementary) */
22618de8d7fSPeter Avalos 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
22718de8d7fSPeter Avalos 			logit("User %.100s from %.100s not allowed because "
22818de8d7fSPeter Avalos 			    "not in any group", pw->pw_name, hostname);
22918de8d7fSPeter Avalos 			return 0;
23018de8d7fSPeter Avalos 		}
23118de8d7fSPeter Avalos 
23218de8d7fSPeter Avalos 		/* Return false if one of user's groups is listed in DenyGroups */
23318de8d7fSPeter Avalos 		if (options.num_deny_groups > 0)
23418de8d7fSPeter Avalos 			if (ga_match(options.deny_groups,
23518de8d7fSPeter Avalos 			    options.num_deny_groups)) {
23618de8d7fSPeter Avalos 				ga_free();
23718de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
23818de8d7fSPeter Avalos 				    "because a group is listed in DenyGroups",
23918de8d7fSPeter Avalos 				    pw->pw_name, hostname);
24018de8d7fSPeter Avalos 				return 0;
24118de8d7fSPeter Avalos 			}
24218de8d7fSPeter Avalos 		/*
24318de8d7fSPeter Avalos 		 * Return false if AllowGroups isn't empty and one of user's groups
24418de8d7fSPeter Avalos 		 * isn't listed there
24518de8d7fSPeter Avalos 		 */
24618de8d7fSPeter Avalos 		if (options.num_allow_groups > 0)
24718de8d7fSPeter Avalos 			if (!ga_match(options.allow_groups,
24818de8d7fSPeter Avalos 			    options.num_allow_groups)) {
24918de8d7fSPeter Avalos 				ga_free();
25018de8d7fSPeter Avalos 				logit("User %.100s from %.100s not allowed "
25118de8d7fSPeter Avalos 				    "because none of user's groups are listed "
25218de8d7fSPeter Avalos 				    "in AllowGroups", pw->pw_name, hostname);
25318de8d7fSPeter Avalos 				return 0;
25418de8d7fSPeter Avalos 			}
25518de8d7fSPeter Avalos 		ga_free();
25618de8d7fSPeter Avalos 	}
25718de8d7fSPeter Avalos 
25818de8d7fSPeter Avalos #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
25918de8d7fSPeter Avalos 	if (!sys_auth_allowed_user(pw, &loginmsg))
26018de8d7fSPeter Avalos 		return 0;
26118de8d7fSPeter Avalos #endif
26218de8d7fSPeter Avalos 
26318de8d7fSPeter Avalos 	/* We found no reason not to let this user try to log on... */
26418de8d7fSPeter Avalos 	return 1;
26518de8d7fSPeter Avalos }
26618de8d7fSPeter Avalos 
267*ce74bacaSMatthew Dillon /*
268*ce74bacaSMatthew Dillon  * Formats any key left in authctxt->auth_method_key for inclusion in
269*ce74bacaSMatthew Dillon  * auth_log()'s message. Also includes authxtct->auth_method_info if present.
270*ce74bacaSMatthew Dillon  */
271*ce74bacaSMatthew Dillon static char *
272*ce74bacaSMatthew Dillon format_method_key(Authctxt *authctxt)
27336e94dc5SPeter Avalos {
274*ce74bacaSMatthew Dillon 	const struct sshkey *key = authctxt->auth_method_key;
275*ce74bacaSMatthew Dillon 	const char *methinfo = authctxt->auth_method_info;
276*ce74bacaSMatthew Dillon 	char *fp, *ret = NULL;
27736e94dc5SPeter Avalos 
278*ce74bacaSMatthew Dillon 	if (key == NULL)
279*ce74bacaSMatthew Dillon 		return NULL;
28036e94dc5SPeter Avalos 
281*ce74bacaSMatthew Dillon 	if (key_is_cert(key)) {
282*ce74bacaSMatthew Dillon 		fp = sshkey_fingerprint(key->cert->signature_key,
283*ce74bacaSMatthew Dillon 		    options.fingerprint_hash, SSH_FP_DEFAULT);
284*ce74bacaSMatthew Dillon 		xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
285*ce74bacaSMatthew Dillon 		    sshkey_type(key), key->cert->key_id,
286*ce74bacaSMatthew Dillon 		    (unsigned long long)key->cert->serial,
287*ce74bacaSMatthew Dillon 		    sshkey_type(key->cert->signature_key),
288*ce74bacaSMatthew Dillon 		    fp == NULL ? "(null)" : fp,
289*ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : ", ",
290*ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : methinfo);
291*ce74bacaSMatthew Dillon 		free(fp);
292*ce74bacaSMatthew Dillon 	} else {
293*ce74bacaSMatthew Dillon 		fp = sshkey_fingerprint(key, options.fingerprint_hash,
294*ce74bacaSMatthew Dillon 		    SSH_FP_DEFAULT);
295*ce74bacaSMatthew Dillon 		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
296*ce74bacaSMatthew Dillon 		    fp == NULL ? "(null)" : fp,
297*ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : ", ",
298*ce74bacaSMatthew Dillon 		    methinfo == NULL ? "" : methinfo);
299*ce74bacaSMatthew Dillon 		free(fp);
300*ce74bacaSMatthew Dillon 	}
301*ce74bacaSMatthew Dillon 	return ret;
30236e94dc5SPeter Avalos }
30336e94dc5SPeter Avalos 
30436e94dc5SPeter Avalos void
30536e94dc5SPeter Avalos auth_log(Authctxt *authctxt, int authenticated, int partial,
30636e94dc5SPeter Avalos     const char *method, const char *submethod)
30718de8d7fSPeter Avalos {
308e9778795SPeter Avalos 	struct ssh *ssh = active_state; /* XXX */
30918de8d7fSPeter Avalos 	void (*authlog) (const char *fmt,...) = verbose;
310*ce74bacaSMatthew Dillon 	const char *authmsg;
311*ce74bacaSMatthew Dillon 	char *extra = NULL;
31218de8d7fSPeter Avalos 
31318de8d7fSPeter Avalos 	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
31418de8d7fSPeter Avalos 		return;
31518de8d7fSPeter Avalos 
31618de8d7fSPeter Avalos 	/* Raise logging level */
31718de8d7fSPeter Avalos 	if (authenticated == 1 ||
31818de8d7fSPeter Avalos 	    !authctxt->valid ||
31918de8d7fSPeter Avalos 	    authctxt->failures >= options.max_authtries / 2 ||
32018de8d7fSPeter Avalos 	    strcmp(method, "password") == 0)
32118de8d7fSPeter Avalos 		authlog = logit;
32218de8d7fSPeter Avalos 
32318de8d7fSPeter Avalos 	if (authctxt->postponed)
32418de8d7fSPeter Avalos 		authmsg = "Postponed";
32536e94dc5SPeter Avalos 	else if (partial)
32636e94dc5SPeter Avalos 		authmsg = "Partial";
32718de8d7fSPeter Avalos 	else
32818de8d7fSPeter Avalos 		authmsg = authenticated ? "Accepted" : "Failed";
32918de8d7fSPeter Avalos 
330*ce74bacaSMatthew Dillon 	if ((extra = format_method_key(authctxt)) == NULL) {
331*ce74bacaSMatthew Dillon 		if (authctxt->auth_method_info != NULL)
332*ce74bacaSMatthew Dillon 			extra = xstrdup(authctxt->auth_method_info);
333*ce74bacaSMatthew Dillon 	}
334*ce74bacaSMatthew Dillon 
335*ce74bacaSMatthew Dillon 	authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
33618de8d7fSPeter Avalos 	    authmsg,
33718de8d7fSPeter Avalos 	    method,
33836e94dc5SPeter Avalos 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
33918de8d7fSPeter Avalos 	    authctxt->valid ? "" : "invalid user ",
34018de8d7fSPeter Avalos 	    authctxt->user,
341e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh),
342e9778795SPeter Avalos 	    ssh_remote_port(ssh),
343*ce74bacaSMatthew Dillon 	    extra != NULL ? ": " : "",
344*ce74bacaSMatthew Dillon 	    extra != NULL ? extra : "");
345*ce74bacaSMatthew Dillon 
346*ce74bacaSMatthew Dillon 	free(extra);
34718de8d7fSPeter Avalos 
34818de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN
34918de8d7fSPeter Avalos 	if (authenticated == 0 && !authctxt->postponed &&
35018de8d7fSPeter Avalos 	    (strcmp(method, "password") == 0 ||
35118de8d7fSPeter Avalos 	    strncmp(method, "keyboard-interactive", 20) == 0 ||
35218de8d7fSPeter Avalos 	    strcmp(method, "challenge-response") == 0))
35318de8d7fSPeter Avalos 		record_failed_login(authctxt->user,
354e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
35518de8d7fSPeter Avalos # ifdef WITH_AIXAUTHENTICATE
35618de8d7fSPeter Avalos 	if (authenticated)
35718de8d7fSPeter Avalos 		sys_auth_record_login(authctxt->user,
358e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
359e9778795SPeter Avalos 		    &loginmsg);
36018de8d7fSPeter Avalos # endif
36118de8d7fSPeter Avalos #endif
36218de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS
36318de8d7fSPeter Avalos 	if (authenticated == 0 && !authctxt->postponed)
36418de8d7fSPeter Avalos 		audit_event(audit_classify_auth(method));
36518de8d7fSPeter Avalos #endif
36618de8d7fSPeter Avalos }
36718de8d7fSPeter Avalos 
36836e94dc5SPeter Avalos 
36936e94dc5SPeter Avalos void
37036e94dc5SPeter Avalos auth_maxtries_exceeded(Authctxt *authctxt)
37136e94dc5SPeter Avalos {
372e9778795SPeter Avalos 	struct ssh *ssh = active_state; /* XXX */
373e9778795SPeter Avalos 
374e9778795SPeter Avalos 	error("maximum authentication attempts exceeded for "
375*ce74bacaSMatthew Dillon 	    "%s%.100s from %.200s port %d ssh2",
37636e94dc5SPeter Avalos 	    authctxt->valid ? "" : "invalid user ",
37736e94dc5SPeter Avalos 	    authctxt->user,
378e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh),
379*ce74bacaSMatthew Dillon 	    ssh_remote_port(ssh));
380e9778795SPeter Avalos 	packet_disconnect("Too many authentication failures");
38136e94dc5SPeter Avalos 	/* NOTREACHED */
38236e94dc5SPeter Avalos }
38336e94dc5SPeter Avalos 
38418de8d7fSPeter Avalos /*
38518de8d7fSPeter Avalos  * Check whether root logins are disallowed.
38618de8d7fSPeter Avalos  */
38718de8d7fSPeter Avalos int
38836e94dc5SPeter Avalos auth_root_allowed(const char *method)
38918de8d7fSPeter Avalos {
390e9778795SPeter Avalos 	struct ssh *ssh = active_state; /* XXX */
391e9778795SPeter Avalos 
39218de8d7fSPeter Avalos 	switch (options.permit_root_login) {
39318de8d7fSPeter Avalos 	case PERMIT_YES:
39418de8d7fSPeter Avalos 		return 1;
39518de8d7fSPeter Avalos 	case PERMIT_NO_PASSWD:
396e9778795SPeter Avalos 		if (strcmp(method, "publickey") == 0 ||
397e9778795SPeter Avalos 		    strcmp(method, "hostbased") == 0 ||
398e9778795SPeter Avalos 		    strcmp(method, "gssapi-with-mic") == 0)
39918de8d7fSPeter Avalos 			return 1;
40018de8d7fSPeter Avalos 		break;
40118de8d7fSPeter Avalos 	case PERMIT_FORCED_ONLY:
40218de8d7fSPeter Avalos 		if (forced_command) {
40318de8d7fSPeter Avalos 			logit("Root login accepted for forced command.");
40418de8d7fSPeter Avalos 			return 1;
40518de8d7fSPeter Avalos 		}
40618de8d7fSPeter Avalos 		break;
40718de8d7fSPeter Avalos 	}
408e9778795SPeter Avalos 	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
409e9778795SPeter Avalos 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
41018de8d7fSPeter Avalos 	return 0;
41118de8d7fSPeter Avalos }
41218de8d7fSPeter Avalos 
41318de8d7fSPeter Avalos 
41418de8d7fSPeter Avalos /*
41518de8d7fSPeter Avalos  * Given a template and a passwd structure, build a filename
41618de8d7fSPeter Avalos  * by substituting % tokenised options. Currently, %% becomes '%',
41718de8d7fSPeter Avalos  * %h becomes the home directory and %u the username.
41818de8d7fSPeter Avalos  *
41918de8d7fSPeter Avalos  * This returns a buffer allocated by xmalloc.
42018de8d7fSPeter Avalos  */
4211c188a7fSPeter Avalos char *
42218de8d7fSPeter Avalos expand_authorized_keys(const char *filename, struct passwd *pw)
42318de8d7fSPeter Avalos {
424e9778795SPeter Avalos 	char *file, ret[PATH_MAX];
42518de8d7fSPeter Avalos 	int i;
42618de8d7fSPeter Avalos 
42718de8d7fSPeter Avalos 	file = percent_expand(filename, "h", pw->pw_dir,
42818de8d7fSPeter Avalos 	    "u", pw->pw_name, (char *)NULL);
42918de8d7fSPeter Avalos 
43018de8d7fSPeter Avalos 	/*
43118de8d7fSPeter Avalos 	 * Ensure that filename starts anchored. If not, be backward
43218de8d7fSPeter Avalos 	 * compatible and prepend the '%h/'
43318de8d7fSPeter Avalos 	 */
43418de8d7fSPeter Avalos 	if (*file == '/')
43518de8d7fSPeter Avalos 		return (file);
43618de8d7fSPeter Avalos 
43718de8d7fSPeter Avalos 	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
43818de8d7fSPeter Avalos 	if (i < 0 || (size_t)i >= sizeof(ret))
43918de8d7fSPeter Avalos 		fatal("expand_authorized_keys: path too long");
44036e94dc5SPeter Avalos 	free(file);
44118de8d7fSPeter Avalos 	return (xstrdup(ret));
44218de8d7fSPeter Avalos }
44318de8d7fSPeter Avalos 
44418de8d7fSPeter Avalos char *
445856ea928SPeter Avalos authorized_principals_file(struct passwd *pw)
446856ea928SPeter Avalos {
447e9778795SPeter Avalos 	if (options.authorized_principals_file == NULL)
448856ea928SPeter Avalos 		return NULL;
449856ea928SPeter Avalos 	return expand_authorized_keys(options.authorized_principals_file, pw);
450856ea928SPeter Avalos }
451856ea928SPeter Avalos 
45218de8d7fSPeter Avalos /* return ok if key exists in sysfile or userfile */
45318de8d7fSPeter Avalos HostStatus
454*ce74bacaSMatthew Dillon check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
45518de8d7fSPeter Avalos     const char *sysfile, const char *userfile)
45618de8d7fSPeter Avalos {
45718de8d7fSPeter Avalos 	char *user_hostfile;
45818de8d7fSPeter Avalos 	struct stat st;
45918de8d7fSPeter Avalos 	HostStatus host_status;
4609f304aafSPeter Avalos 	struct hostkeys *hostkeys;
4619f304aafSPeter Avalos 	const struct hostkey_entry *found;
46218de8d7fSPeter Avalos 
4639f304aafSPeter Avalos 	hostkeys = init_hostkeys();
4649f304aafSPeter Avalos 	load_hostkeys(hostkeys, host, sysfile);
4659f304aafSPeter Avalos 	if (userfile != NULL) {
46618de8d7fSPeter Avalos 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
46718de8d7fSPeter Avalos 		if (options.strict_modes &&
46818de8d7fSPeter Avalos 		    (stat(user_hostfile, &st) == 0) &&
46918de8d7fSPeter Avalos 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
47018de8d7fSPeter Avalos 		    (st.st_mode & 022) != 0)) {
47118de8d7fSPeter Avalos 			logit("Authentication refused for %.100s: "
47218de8d7fSPeter Avalos 			    "bad owner or modes for %.200s",
47318de8d7fSPeter Avalos 			    pw->pw_name, user_hostfile);
474856ea928SPeter Avalos 			auth_debug_add("Ignored %.200s: bad ownership or modes",
475856ea928SPeter Avalos 			    user_hostfile);
47618de8d7fSPeter Avalos 		} else {
47718de8d7fSPeter Avalos 			temporarily_use_uid(pw);
4789f304aafSPeter Avalos 			load_hostkeys(hostkeys, host, user_hostfile);
47918de8d7fSPeter Avalos 			restore_uid();
48018de8d7fSPeter Avalos 		}
48136e94dc5SPeter Avalos 		free(user_hostfile);
48218de8d7fSPeter Avalos 	}
4839f304aafSPeter Avalos 	host_status = check_key_in_hostkeys(hostkeys, key, &found);
4849f304aafSPeter Avalos 	if (host_status == HOST_REVOKED)
4859f304aafSPeter Avalos 		error("WARNING: revoked key for %s attempted authentication",
4869f304aafSPeter Avalos 		    found->host);
4879f304aafSPeter Avalos 	else if (host_status == HOST_OK)
4889f304aafSPeter Avalos 		debug("%s: key for %s found at %s:%ld", __func__,
4899f304aafSPeter Avalos 		    found->host, found->file, found->line);
4909f304aafSPeter Avalos 	else
4919f304aafSPeter Avalos 		debug("%s: key for host %s not found", __func__, host);
49218de8d7fSPeter Avalos 
4939f304aafSPeter Avalos 	free_hostkeys(hostkeys);
4949f304aafSPeter Avalos 
49518de8d7fSPeter Avalos 	return host_status;
49618de8d7fSPeter Avalos }
49718de8d7fSPeter Avalos 
498856ea928SPeter Avalos static FILE *
499856ea928SPeter Avalos auth_openfile(const char *file, struct passwd *pw, int strict_modes,
500856ea928SPeter Avalos     int log_missing, char *file_type)
50118de8d7fSPeter Avalos {
50218de8d7fSPeter Avalos 	char line[1024];
50318de8d7fSPeter Avalos 	struct stat st;
50418de8d7fSPeter Avalos 	int fd;
50518de8d7fSPeter Avalos 	FILE *f;
50618de8d7fSPeter Avalos 
507856ea928SPeter Avalos 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
508856ea928SPeter Avalos 		if (log_missing || errno != ENOENT)
509856ea928SPeter Avalos 			debug("Could not open %s '%s': %s", file_type, file,
510856ea928SPeter Avalos 			   strerror(errno));
51118de8d7fSPeter Avalos 		return NULL;
512856ea928SPeter Avalos 	}
51318de8d7fSPeter Avalos 
51418de8d7fSPeter Avalos 	if (fstat(fd, &st) < 0) {
51518de8d7fSPeter Avalos 		close(fd);
51618de8d7fSPeter Avalos 		return NULL;
51718de8d7fSPeter Avalos 	}
51818de8d7fSPeter Avalos 	if (!S_ISREG(st.st_mode)) {
519856ea928SPeter Avalos 		logit("User %s %s %s is not a regular file",
520856ea928SPeter Avalos 		    pw->pw_name, file_type, file);
52118de8d7fSPeter Avalos 		close(fd);
52218de8d7fSPeter Avalos 		return NULL;
52318de8d7fSPeter Avalos 	}
52418de8d7fSPeter Avalos 	unset_nonblock(fd);
52518de8d7fSPeter Avalos 	if ((f = fdopen(fd, "r")) == NULL) {
52618de8d7fSPeter Avalos 		close(fd);
52718de8d7fSPeter Avalos 		return NULL;
52818de8d7fSPeter Avalos 	}
5299f304aafSPeter Avalos 	if (strict_modes &&
530*ce74bacaSMatthew Dillon 	    safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
53118de8d7fSPeter Avalos 		fclose(f);
53218de8d7fSPeter Avalos 		logit("Authentication refused: %s", line);
533856ea928SPeter Avalos 		auth_debug_add("Ignored %s: %s", file_type, line);
53418de8d7fSPeter Avalos 		return NULL;
53518de8d7fSPeter Avalos 	}
53618de8d7fSPeter Avalos 
53718de8d7fSPeter Avalos 	return f;
53818de8d7fSPeter Avalos }
53918de8d7fSPeter Avalos 
540856ea928SPeter Avalos 
541856ea928SPeter Avalos FILE *
542856ea928SPeter Avalos auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
543856ea928SPeter Avalos {
544856ea928SPeter Avalos 	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
545856ea928SPeter Avalos }
546856ea928SPeter Avalos 
547856ea928SPeter Avalos FILE *
548856ea928SPeter Avalos auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
549856ea928SPeter Avalos {
550856ea928SPeter Avalos 	return auth_openfile(file, pw, strict_modes, 0,
551856ea928SPeter Avalos 	    "authorized principals");
552856ea928SPeter Avalos }
553856ea928SPeter Avalos 
55418de8d7fSPeter Avalos struct passwd *
55518de8d7fSPeter Avalos getpwnamallow(const char *user)
55618de8d7fSPeter Avalos {
557e9778795SPeter Avalos 	struct ssh *ssh = active_state; /* XXX */
55818de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP
55918de8d7fSPeter Avalos 	extern login_cap_t *lc;
56018de8d7fSPeter Avalos #ifdef BSD_AUTH
56118de8d7fSPeter Avalos 	auth_session_t *as;
56218de8d7fSPeter Avalos #endif
56318de8d7fSPeter Avalos #endif
56418de8d7fSPeter Avalos 	struct passwd *pw;
56599e85e0dSPeter Avalos 	struct connection_info *ci = get_connection_info(1, options.use_dns);
56618de8d7fSPeter Avalos 
56799e85e0dSPeter Avalos 	ci->user = user;
56899e85e0dSPeter Avalos 	parse_server_match_config(&options, ci);
569*ce74bacaSMatthew Dillon 	log_change_level(options.log_level);
570*ce74bacaSMatthew Dillon 	process_permitopen(ssh, &options);
57118de8d7fSPeter Avalos 
572856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB)
573856ea928SPeter Avalos 	aix_setauthdb(user);
574856ea928SPeter Avalos #endif
575856ea928SPeter Avalos 
57618de8d7fSPeter Avalos 	pw = getpwnam(user);
577856ea928SPeter Avalos 
578856ea928SPeter Avalos #if defined(_AIX) && defined(HAVE_SETAUTHDB)
579856ea928SPeter Avalos 	aix_restoreauthdb();
580856ea928SPeter Avalos #endif
581856ea928SPeter Avalos #ifdef HAVE_CYGWIN
582856ea928SPeter Avalos 	/*
583856ea928SPeter Avalos 	 * Windows usernames are case-insensitive.  To avoid later problems
584856ea928SPeter Avalos 	 * when trying to match the username, the user is only allowed to
585856ea928SPeter Avalos 	 * login if the username is given in the same case as stored in the
586856ea928SPeter Avalos 	 * user database.
587856ea928SPeter Avalos 	 */
588856ea928SPeter Avalos 	if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
589856ea928SPeter Avalos 		logit("Login name %.100s does not match stored username %.100s",
590856ea928SPeter Avalos 		    user, pw->pw_name);
591856ea928SPeter Avalos 		pw = NULL;
592856ea928SPeter Avalos 	}
593856ea928SPeter Avalos #endif
59418de8d7fSPeter Avalos 	if (pw == NULL) {
595e9778795SPeter Avalos 		logit("Invalid user %.100s from %.100s port %d",
596e9778795SPeter Avalos 		    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
59718de8d7fSPeter Avalos #ifdef CUSTOM_FAILED_LOGIN
59818de8d7fSPeter Avalos 		record_failed_login(user,
599e9778795SPeter Avalos 		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
60018de8d7fSPeter Avalos #endif
60118de8d7fSPeter Avalos #ifdef SSH_AUDIT_EVENTS
60218de8d7fSPeter Avalos 		audit_event(SSH_INVALID_USER);
60318de8d7fSPeter Avalos #endif /* SSH_AUDIT_EVENTS */
60418de8d7fSPeter Avalos 		return (NULL);
60518de8d7fSPeter Avalos 	}
60618de8d7fSPeter Avalos 	if (!allowed_user(pw))
60718de8d7fSPeter Avalos 		return (NULL);
60818de8d7fSPeter Avalos #ifdef HAVE_LOGIN_CAP
60918de8d7fSPeter Avalos 	if ((lc = login_getclass(pw->pw_class)) == NULL) {
61018de8d7fSPeter Avalos 		debug("unable to get login class: %s", user);
61118de8d7fSPeter Avalos 		return (NULL);
61218de8d7fSPeter Avalos 	}
61318de8d7fSPeter Avalos #ifdef BSD_AUTH
61418de8d7fSPeter Avalos 	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
61518de8d7fSPeter Avalos 	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
61618de8d7fSPeter Avalos 		debug("Approval failure for %s", user);
61718de8d7fSPeter Avalos 		pw = NULL;
61818de8d7fSPeter Avalos 	}
61918de8d7fSPeter Avalos 	if (as != NULL)
62018de8d7fSPeter Avalos 		auth_close(as);
62118de8d7fSPeter Avalos #endif
62218de8d7fSPeter Avalos #endif
62318de8d7fSPeter Avalos 	if (pw != NULL)
62418de8d7fSPeter Avalos 		return (pwcopy(pw));
62518de8d7fSPeter Avalos 	return (NULL);
62618de8d7fSPeter Avalos }
62718de8d7fSPeter Avalos 
628856ea928SPeter Avalos /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
629856ea928SPeter Avalos int
630*ce74bacaSMatthew Dillon auth_key_is_revoked(struct sshkey *key)
631856ea928SPeter Avalos {
632e9778795SPeter Avalos 	char *fp = NULL;
633e9778795SPeter Avalos 	int r;
634856ea928SPeter Avalos 
635856ea928SPeter Avalos 	if (options.revoked_keys_file == NULL)
636856ea928SPeter Avalos 		return 0;
637e9778795SPeter Avalos 	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
638e9778795SPeter Avalos 	    SSH_FP_DEFAULT)) == NULL) {
639e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
640e9778795SPeter Avalos 		error("%s: fingerprint key: %s", __func__, ssh_err(r));
641e9778795SPeter Avalos 		goto out;
642e9778795SPeter Avalos 	}
643e9778795SPeter Avalos 
644e9778795SPeter Avalos 	r = sshkey_check_revoked(key, options.revoked_keys_file);
645e9778795SPeter Avalos 	switch (r) {
64636e94dc5SPeter Avalos 	case 0:
647e9778795SPeter Avalos 		break; /* not revoked */
648e9778795SPeter Avalos 	case SSH_ERR_KEY_REVOKED:
649e9778795SPeter Avalos 		error("Authentication key %s %s revoked by file %s",
650e9778795SPeter Avalos 		    sshkey_type(key), fp, options.revoked_keys_file);
651e9778795SPeter Avalos 		goto out;
65236e94dc5SPeter Avalos 	default:
653e9778795SPeter Avalos 		error("Error checking authentication key %s %s in "
654e9778795SPeter Avalos 		    "revoked keys file %s: %s", sshkey_type(key), fp,
655e9778795SPeter Avalos 		    options.revoked_keys_file, ssh_err(r));
656e9778795SPeter Avalos 		goto out;
65736e94dc5SPeter Avalos 	}
658e9778795SPeter Avalos 
659e9778795SPeter Avalos 	/* Success */
660e9778795SPeter Avalos 	r = 0;
661e9778795SPeter Avalos 
662e9778795SPeter Avalos  out:
663e9778795SPeter Avalos 	free(fp);
664e9778795SPeter Avalos 	return r == 0 ? 0 : 1;
665856ea928SPeter Avalos }
666856ea928SPeter Avalos 
66718de8d7fSPeter Avalos void
66818de8d7fSPeter Avalos auth_debug_add(const char *fmt,...)
66918de8d7fSPeter Avalos {
67018de8d7fSPeter Avalos 	char buf[1024];
67118de8d7fSPeter Avalos 	va_list args;
67218de8d7fSPeter Avalos 
67318de8d7fSPeter Avalos 	if (!auth_debug_init)
67418de8d7fSPeter Avalos 		return;
67518de8d7fSPeter Avalos 
67618de8d7fSPeter Avalos 	va_start(args, fmt);
67718de8d7fSPeter Avalos 	vsnprintf(buf, sizeof(buf), fmt, args);
67818de8d7fSPeter Avalos 	va_end(args);
67918de8d7fSPeter Avalos 	buffer_put_cstring(&auth_debug, buf);
68018de8d7fSPeter Avalos }
68118de8d7fSPeter Avalos 
68218de8d7fSPeter Avalos void
68318de8d7fSPeter Avalos auth_debug_send(void)
68418de8d7fSPeter Avalos {
68518de8d7fSPeter Avalos 	char *msg;
68618de8d7fSPeter Avalos 
68718de8d7fSPeter Avalos 	if (!auth_debug_init)
68818de8d7fSPeter Avalos 		return;
68918de8d7fSPeter Avalos 	while (buffer_len(&auth_debug)) {
69018de8d7fSPeter Avalos 		msg = buffer_get_string(&auth_debug, NULL);
69118de8d7fSPeter Avalos 		packet_send_debug("%s", msg);
69236e94dc5SPeter Avalos 		free(msg);
69318de8d7fSPeter Avalos 	}
69418de8d7fSPeter Avalos }
69518de8d7fSPeter Avalos 
69618de8d7fSPeter Avalos void
69718de8d7fSPeter Avalos auth_debug_reset(void)
69818de8d7fSPeter Avalos {
69918de8d7fSPeter Avalos 	if (auth_debug_init)
70018de8d7fSPeter Avalos 		buffer_clear(&auth_debug);
70118de8d7fSPeter Avalos 	else {
70218de8d7fSPeter Avalos 		buffer_init(&auth_debug);
70318de8d7fSPeter Avalos 		auth_debug_init = 1;
70418de8d7fSPeter Avalos 	}
70518de8d7fSPeter Avalos }
70618de8d7fSPeter Avalos 
70718de8d7fSPeter Avalos struct passwd *
70818de8d7fSPeter Avalos fakepw(void)
70918de8d7fSPeter Avalos {
71018de8d7fSPeter Avalos 	static struct passwd fake;
71118de8d7fSPeter Avalos 
71218de8d7fSPeter Avalos 	memset(&fake, 0, sizeof(fake));
71318de8d7fSPeter Avalos 	fake.pw_name = "NOUSER";
71418de8d7fSPeter Avalos 	fake.pw_passwd =
71518de8d7fSPeter Avalos 	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
71636e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
71718de8d7fSPeter Avalos 	fake.pw_gecos = "NOUSER";
71836e94dc5SPeter Avalos #endif
71918de8d7fSPeter Avalos 	fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
72018de8d7fSPeter Avalos 	fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
72136e94dc5SPeter Avalos #ifdef HAVE_STRUCT_PASSWD_PW_CLASS
72218de8d7fSPeter Avalos 	fake.pw_class = "";
72318de8d7fSPeter Avalos #endif
72418de8d7fSPeter Avalos 	fake.pw_dir = "/nonexist";
72518de8d7fSPeter Avalos 	fake.pw_shell = "/nonexist";
72618de8d7fSPeter Avalos 
72718de8d7fSPeter Avalos 	return (&fake);
72818de8d7fSPeter Avalos }
729e9778795SPeter Avalos 
730e9778795SPeter Avalos /*
731e9778795SPeter Avalos  * Returns the remote DNS hostname as a string. The returned string must not
732e9778795SPeter Avalos  * be freed. NB. this will usually trigger a DNS query the first time it is
733e9778795SPeter Avalos  * called.
734e9778795SPeter Avalos  * This function does additional checks on the hostname to mitigate some
735e9778795SPeter Avalos  * attacks on legacy rhosts-style authentication.
736e9778795SPeter Avalos  * XXX is RhostsRSAAuthentication vulnerable to these?
737e9778795SPeter Avalos  * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
738e9778795SPeter Avalos  */
739e9778795SPeter Avalos 
740e9778795SPeter Avalos static char *
741e9778795SPeter Avalos remote_hostname(struct ssh *ssh)
742e9778795SPeter Avalos {
743e9778795SPeter Avalos 	struct sockaddr_storage from;
744e9778795SPeter Avalos 	socklen_t fromlen;
745e9778795SPeter Avalos 	struct addrinfo hints, *ai, *aitop;
746e9778795SPeter Avalos 	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
747e9778795SPeter Avalos 	const char *ntop = ssh_remote_ipaddr(ssh);
748e9778795SPeter Avalos 
749e9778795SPeter Avalos 	/* Get IP address of client. */
750e9778795SPeter Avalos 	fromlen = sizeof(from);
751e9778795SPeter Avalos 	memset(&from, 0, sizeof(from));
752e9778795SPeter Avalos 	if (getpeername(ssh_packet_get_connection_in(ssh),
753e9778795SPeter Avalos 	    (struct sockaddr *)&from, &fromlen) < 0) {
754e9778795SPeter Avalos 		debug("getpeername failed: %.100s", strerror(errno));
755e9778795SPeter Avalos 		return strdup(ntop);
756e9778795SPeter Avalos 	}
757e9778795SPeter Avalos 
758e9778795SPeter Avalos 	ipv64_normalise_mapped(&from, &fromlen);
759e9778795SPeter Avalos 	if (from.ss_family == AF_INET6)
760e9778795SPeter Avalos 		fromlen = sizeof(struct sockaddr_in6);
761e9778795SPeter Avalos 
762e9778795SPeter Avalos 	debug3("Trying to reverse map address %.100s.", ntop);
763e9778795SPeter Avalos 	/* Map the IP address to a host name. */
764e9778795SPeter Avalos 	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
765e9778795SPeter Avalos 	    NULL, 0, NI_NAMEREQD) != 0) {
766e9778795SPeter Avalos 		/* Host name not found.  Use ip address. */
767e9778795SPeter Avalos 		return strdup(ntop);
768e9778795SPeter Avalos 	}
769e9778795SPeter Avalos 
770e9778795SPeter Avalos 	/*
771e9778795SPeter Avalos 	 * if reverse lookup result looks like a numeric hostname,
772e9778795SPeter Avalos 	 * someone is trying to trick us by PTR record like following:
773e9778795SPeter Avalos 	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
774e9778795SPeter Avalos 	 */
775e9778795SPeter Avalos 	memset(&hints, 0, sizeof(hints));
776e9778795SPeter Avalos 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
777e9778795SPeter Avalos 	hints.ai_flags = AI_NUMERICHOST;
778e9778795SPeter Avalos 	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
779e9778795SPeter Avalos 		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
780e9778795SPeter Avalos 		    name, ntop);
781e9778795SPeter Avalos 		freeaddrinfo(ai);
782e9778795SPeter Avalos 		return strdup(ntop);
783e9778795SPeter Avalos 	}
784e9778795SPeter Avalos 
785e9778795SPeter Avalos 	/* Names are stored in lowercase. */
786e9778795SPeter Avalos 	lowercase(name);
787e9778795SPeter Avalos 
788e9778795SPeter Avalos 	/*
789e9778795SPeter Avalos 	 * Map it back to an IP address and check that the given
790e9778795SPeter Avalos 	 * address actually is an address of this host.  This is
791e9778795SPeter Avalos 	 * necessary because anyone with access to a name server can
792e9778795SPeter Avalos 	 * define arbitrary names for an IP address. Mapping from
793e9778795SPeter Avalos 	 * name to IP address can be trusted better (but can still be
794e9778795SPeter Avalos 	 * fooled if the intruder has access to the name server of
795e9778795SPeter Avalos 	 * the domain).
796e9778795SPeter Avalos 	 */
797e9778795SPeter Avalos 	memset(&hints, 0, sizeof(hints));
798e9778795SPeter Avalos 	hints.ai_family = from.ss_family;
799e9778795SPeter Avalos 	hints.ai_socktype = SOCK_STREAM;
800e9778795SPeter Avalos 	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
801e9778795SPeter Avalos 		logit("reverse mapping checking getaddrinfo for %.700s "
802e9778795SPeter Avalos 		    "[%s] failed.", name, ntop);
803e9778795SPeter Avalos 		return strdup(ntop);
804e9778795SPeter Avalos 	}
805e9778795SPeter Avalos 	/* Look for the address from the list of addresses. */
806e9778795SPeter Avalos 	for (ai = aitop; ai; ai = ai->ai_next) {
807e9778795SPeter Avalos 		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
808e9778795SPeter Avalos 		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
809e9778795SPeter Avalos 		    (strcmp(ntop, ntop2) == 0))
810e9778795SPeter Avalos 				break;
811e9778795SPeter Avalos 	}
812e9778795SPeter Avalos 	freeaddrinfo(aitop);
813e9778795SPeter Avalos 	/* If we reached the end of the list, the address was not there. */
814e9778795SPeter Avalos 	if (ai == NULL) {
815e9778795SPeter Avalos 		/* Address not found for the host name. */
816e9778795SPeter Avalos 		logit("Address %.100s maps to %.600s, but this does not "
817e9778795SPeter Avalos 		    "map back to the address.", ntop, name);
818e9778795SPeter Avalos 		return strdup(ntop);
819e9778795SPeter Avalos 	}
820e9778795SPeter Avalos 	return strdup(name);
821e9778795SPeter Avalos }
822e9778795SPeter Avalos 
823e9778795SPeter Avalos /*
824e9778795SPeter Avalos  * Return the canonical name of the host in the other side of the current
825e9778795SPeter Avalos  * connection.  The host name is cached, so it is efficient to call this
826e9778795SPeter Avalos  * several times.
827e9778795SPeter Avalos  */
828e9778795SPeter Avalos 
829e9778795SPeter Avalos const char *
830e9778795SPeter Avalos auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
831e9778795SPeter Avalos {
832e9778795SPeter Avalos 	static char *dnsname;
833e9778795SPeter Avalos 
834e9778795SPeter Avalos 	if (!use_dns)
835e9778795SPeter Avalos 		return ssh_remote_ipaddr(ssh);
836e9778795SPeter Avalos 	else if (dnsname != NULL)
837e9778795SPeter Avalos 		return dnsname;
838e9778795SPeter Avalos 	else {
839e9778795SPeter Avalos 		dnsname = remote_hostname(ssh);
840e9778795SPeter Avalos 		return dnsname;
841e9778795SPeter Avalos 	}
842e9778795SPeter Avalos }
843