1/* $OpenBSD: auth.c,v 1.160 2023/03/05 05:34:09 dtucker Exp $ */
2/*
3 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/socket.h>
31#include <sys/wait.h>
32
33#include <netinet/in.h>
34
35#include <stdlib.h>
36#include <errno.h>
37#include <fcntl.h>
38#ifdef HAVE_PATHS_H
39# include <paths.h>
40#endif
41#include <pwd.h>
42#ifdef HAVE_LOGIN_H
43#include <login.h>
44#endif
45#ifdef USE_SHADOW
46#include <shadow.h>
47#endif
48#include <stdarg.h>
49#include <stdio.h>
50#include <string.h>
51#include <unistd.h>
52#include <limits.h>
53#include <netdb.h>
54#include <time.h>
55
56#include "xmalloc.h"
57#include "match.h"
58#include "groupaccess.h"
59#include "log.h"
60#include "sshbuf.h"
61#include "misc.h"
62#include "servconf.h"
63#include "sshkey.h"
64#include "hostfile.h"
65#include "auth.h"
66#include "auth-options.h"
67#include "canohost.h"
68#include "uidswap.h"
69#include "packet.h"
70#include "loginrec.h"
71#ifdef GSSAPI
72#include "ssh-gss.h"
73#endif
74#include "authfile.h"
75#include "monitor_wrap.h"
76#include "ssherr.h"
77#include "channels.h"
78#include "blacklist_client.h"
79
80/* import */
81extern ServerOptions options;
82extern struct include_list includes;
83extern int use_privsep;
84extern struct sshbuf *loginmsg;
85extern struct passwd *privsep_pw;
86extern struct sshauthopt *auth_opts;
87
88/* Debugging messages */
89static struct sshbuf *auth_debug;
90
91/*
92 * Check if the user is allowed to log in via ssh. If user is listed
93 * in DenyUsers or one of user's groups is listed in DenyGroups, false
94 * will be returned. If AllowUsers isn't empty and user isn't listed
95 * there, or if AllowGroups isn't empty and one of user's groups isn't
96 * listed there, false will be returned.
97 * If the user's shell is not executable, false will be returned.
98 * Otherwise true is returned.
99 */
100int
101allowed_user(struct ssh *ssh, struct passwd * pw)
102{
103	struct stat st;
104	const char *hostname = NULL, *ipaddr = NULL;
105	u_int i;
106	int r;
107
108	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
109	if (!pw || !pw->pw_name)
110		return 0;
111
112	if (!options.use_pam && platform_locked_account(pw)) {
113		logit("User %.100s not allowed because account is locked",
114		    pw->pw_name);
115		return 0;
116	}
117
118	/*
119	 * Deny if shell does not exist or is not executable unless we
120	 * are chrooting.
121	 */
122	if (options.chroot_directory == NULL ||
123	    strcasecmp(options.chroot_directory, "none") == 0) {
124		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
125		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
126
127		if (stat(shell, &st) == -1) {
128			logit("User %.100s not allowed because shell %.100s "
129			    "does not exist", pw->pw_name, shell);
130			free(shell);
131			return 0;
132		}
133		if (S_ISREG(st.st_mode) == 0 ||
134		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
135			logit("User %.100s not allowed because shell %.100s "
136			    "is not executable", pw->pw_name, shell);
137			free(shell);
138			return 0;
139		}
140		free(shell);
141	}
142
143	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
144	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
145		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
146		ipaddr = ssh_remote_ipaddr(ssh);
147	}
148
149	/* Return false if user is listed in DenyUsers */
150	if (options.num_deny_users > 0) {
151		for (i = 0; i < options.num_deny_users; i++) {
152			r = match_user(pw->pw_name, hostname, ipaddr,
153			    options.deny_users[i]);
154			if (r < 0) {
155				fatal("Invalid DenyUsers pattern \"%.100s\"",
156				    options.deny_users[i]);
157			} else if (r != 0) {
158				logit("User %.100s from %.100s not allowed "
159				    "because listed in DenyUsers",
160				    pw->pw_name, hostname);
161				return 0;
162			}
163		}
164	}
165	/* Return false if AllowUsers isn't empty and user isn't listed there */
166	if (options.num_allow_users > 0) {
167		for (i = 0; i < options.num_allow_users; i++) {
168			r = match_user(pw->pw_name, hostname, ipaddr,
169			    options.allow_users[i]);
170			if (r < 0) {
171				fatal("Invalid AllowUsers pattern \"%.100s\"",
172				    options.allow_users[i]);
173			} else if (r == 1)
174				break;
175		}
176		/* i < options.num_allow_users iff we break for loop */
177		if (i >= options.num_allow_users) {
178			logit("User %.100s from %.100s not allowed because "
179			    "not listed in AllowUsers", pw->pw_name, hostname);
180			return 0;
181		}
182	}
183	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
184		/* Get the user's group access list (primary and supplementary) */
185		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
186			logit("User %.100s from %.100s not allowed because "
187			    "not in any group", pw->pw_name, hostname);
188			return 0;
189		}
190
191		/* Return false if one of user's groups is listed in DenyGroups */
192		if (options.num_deny_groups > 0)
193			if (ga_match(options.deny_groups,
194			    options.num_deny_groups)) {
195				ga_free();
196				logit("User %.100s from %.100s not allowed "
197				    "because a group is listed in DenyGroups",
198				    pw->pw_name, hostname);
199				return 0;
200			}
201		/*
202		 * Return false if AllowGroups isn't empty and one of user's groups
203		 * isn't listed there
204		 */
205		if (options.num_allow_groups > 0)
206			if (!ga_match(options.allow_groups,
207			    options.num_allow_groups)) {
208				ga_free();
209				logit("User %.100s from %.100s not allowed "
210				    "because none of user's groups are listed "
211				    "in AllowGroups", pw->pw_name, hostname);
212				return 0;
213			}
214		ga_free();
215	}
216
217#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
218	if (!sys_auth_allowed_user(pw, loginmsg))
219		return 0;
220#endif
221
222	/* We found no reason not to let this user try to log on... */
223	return 1;
224}
225
226/*
227 * Formats any key left in authctxt->auth_method_key for inclusion in
228 * auth_log()'s message. Also includes authxtct->auth_method_info if present.
229 */
230static char *
231format_method_key(Authctxt *authctxt)
232{
233	const struct sshkey *key = authctxt->auth_method_key;
234	const char *methinfo = authctxt->auth_method_info;
235	char *fp, *cafp, *ret = NULL;
236
237	if (key == NULL)
238		return NULL;
239
240	if (sshkey_is_cert(key)) {
241		fp = sshkey_fingerprint(key,
242		    options.fingerprint_hash, SSH_FP_DEFAULT);
243		cafp = sshkey_fingerprint(key->cert->signature_key,
244		    options.fingerprint_hash, SSH_FP_DEFAULT);
245		xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
246		    sshkey_type(key), fp == NULL ? "(null)" : fp,
247		    key->cert->key_id,
248		    (unsigned long long)key->cert->serial,
249		    sshkey_type(key->cert->signature_key),
250		    cafp == NULL ? "(null)" : cafp,
251		    methinfo == NULL ? "" : ", ",
252		    methinfo == NULL ? "" : methinfo);
253		free(fp);
254		free(cafp);
255	} else {
256		fp = sshkey_fingerprint(key, options.fingerprint_hash,
257		    SSH_FP_DEFAULT);
258		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
259		    fp == NULL ? "(null)" : fp,
260		    methinfo == NULL ? "" : ", ",
261		    methinfo == NULL ? "" : methinfo);
262		free(fp);
263	}
264	return ret;
265}
266
267void
268auth_log(struct ssh *ssh, int authenticated, int partial,
269    const char *method, const char *submethod)
270{
271	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
272	int level = SYSLOG_LEVEL_VERBOSE;
273	const char *authmsg;
274	char *extra = NULL;
275
276	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
277		return;
278
279	/* Raise logging level */
280	if (authenticated == 1 ||
281	    !authctxt->valid ||
282	    authctxt->failures >= options.max_authtries / 2 ||
283	    strcmp(method, "password") == 0)
284		level = SYSLOG_LEVEL_INFO;
285
286	if (authctxt->postponed)
287		authmsg = "Postponed";
288	else if (partial)
289		authmsg = "Partial";
290	else {
291		authmsg = authenticated ? "Accepted" : "Failed";
292		if (authenticated)
293			BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_OK, "ssh");
294	}
295
296	if ((extra = format_method_key(authctxt)) == NULL) {
297		if (authctxt->auth_method_info != NULL)
298			extra = xstrdup(authctxt->auth_method_info);
299	}
300
301	do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
302	    authmsg,
303	    method,
304	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
305	    authctxt->valid ? "" : "invalid user ",
306	    authctxt->user,
307	    ssh_remote_ipaddr(ssh),
308	    ssh_remote_port(ssh),
309	    extra != NULL ? ": " : "",
310	    extra != NULL ? extra : "");
311
312	free(extra);
313
314#if defined(CUSTOM_FAILED_LOGIN) || defined(SSH_AUDIT_EVENTS)
315	if (authenticated == 0 && !(authctxt->postponed || partial)) {
316		/* Log failed login attempt */
317# ifdef CUSTOM_FAILED_LOGIN
318		if (strcmp(method, "password") == 0 ||
319		    strncmp(method, "keyboard-interactive", 20) == 0 ||
320		    strcmp(method, "challenge-response") == 0)
321			record_failed_login(ssh, authctxt->user,
322			    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
323# endif
324# ifdef SSH_AUDIT_EVENTS
325		audit_event(ssh, audit_classify_auth(method));
326# endif
327	}
328#endif
329#if defined(CUSTOM_FAILED_LOGIN) && defined(WITH_AIXAUTHENTICATE)
330	if (authenticated)
331		sys_auth_record_login(authctxt->user,
332		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
333		    loginmsg);
334#endif
335}
336
337void
338auth_maxtries_exceeded(struct ssh *ssh)
339{
340	Authctxt *authctxt = (Authctxt *)ssh->authctxt;
341
342	error("maximum authentication attempts exceeded for "
343	    "%s%.100s from %.200s port %d ssh2",
344	    authctxt->valid ? "" : "invalid user ",
345	    authctxt->user,
346	    ssh_remote_ipaddr(ssh),
347	    ssh_remote_port(ssh));
348	ssh_packet_disconnect(ssh, "Too many authentication failures");
349	/* NOTREACHED */
350}
351
352/*
353 * Check whether root logins are disallowed.
354 */
355int
356auth_root_allowed(struct ssh *ssh, const char *method)
357{
358	switch (options.permit_root_login) {
359	case PERMIT_YES:
360		return 1;
361	case PERMIT_NO_PASSWD:
362		if (strcmp(method, "publickey") == 0 ||
363		    strcmp(method, "hostbased") == 0 ||
364		    strcmp(method, "gssapi-with-mic") == 0)
365			return 1;
366		break;
367	case PERMIT_FORCED_ONLY:
368		if (auth_opts->force_command != NULL) {
369			logit("Root login accepted for forced command.");
370			return 1;
371		}
372		break;
373	}
374	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
375	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
376	return 0;
377}
378
379
380/*
381 * Given a template and a passwd structure, build a filename
382 * by substituting % tokenised options. Currently, %% becomes '%',
383 * %h becomes the home directory and %u the username.
384 *
385 * This returns a buffer allocated by xmalloc.
386 */
387char *
388expand_authorized_keys(const char *filename, struct passwd *pw)
389{
390	char *file, uidstr[32], ret[PATH_MAX];
391	int i;
392
393	snprintf(uidstr, sizeof(uidstr), "%llu",
394	    (unsigned long long)pw->pw_uid);
395	file = percent_expand(filename, "h", pw->pw_dir,
396	    "u", pw->pw_name, "U", uidstr, (char *)NULL);
397
398	/*
399	 * Ensure that filename starts anchored. If not, be backward
400	 * compatible and prepend the '%h/'
401	 */
402	if (path_absolute(file))
403		return (file);
404
405	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
406	if (i < 0 || (size_t)i >= sizeof(ret))
407		fatal("expand_authorized_keys: path too long");
408	free(file);
409	return (xstrdup(ret));
410}
411
412char *
413authorized_principals_file(struct passwd *pw)
414{
415	if (options.authorized_principals_file == NULL)
416		return NULL;
417	return expand_authorized_keys(options.authorized_principals_file, pw);
418}
419
420/* return ok if key exists in sysfile or userfile */
421HostStatus
422check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
423    const char *sysfile, const char *userfile)
424{
425	char *user_hostfile;
426	struct stat st;
427	HostStatus host_status;
428	struct hostkeys *hostkeys;
429	const struct hostkey_entry *found;
430
431	hostkeys = init_hostkeys();
432	load_hostkeys(hostkeys, host, sysfile, 0);
433	if (userfile != NULL) {
434		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
435		if (options.strict_modes &&
436		    (stat(user_hostfile, &st) == 0) &&
437		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
438		    (st.st_mode & 022) != 0)) {
439			logit("Authentication refused for %.100s: "
440			    "bad owner or modes for %.200s",
441			    pw->pw_name, user_hostfile);
442			auth_debug_add("Ignored %.200s: bad ownership or modes",
443			    user_hostfile);
444		} else {
445			temporarily_use_uid(pw);
446			load_hostkeys(hostkeys, host, user_hostfile, 0);
447			restore_uid();
448		}
449		free(user_hostfile);
450	}
451	host_status = check_key_in_hostkeys(hostkeys, key, &found);
452	if (host_status == HOST_REVOKED)
453		error("WARNING: revoked key for %s attempted authentication",
454		    host);
455	else if (host_status == HOST_OK)
456		debug_f("key for %s found at %s:%ld",
457		    found->host, found->file, found->line);
458	else
459		debug_f("key for host %s not found", host);
460
461	free_hostkeys(hostkeys);
462
463	return host_status;
464}
465
466struct passwd *
467getpwnamallow(struct ssh *ssh, const char *user)
468{
469#ifdef HAVE_LOGIN_CAP
470	extern login_cap_t *lc;
471#ifdef HAVE_AUTH_HOSTOK
472	const char *from_host, *from_ip;
473#endif
474#ifdef BSD_AUTH
475	auth_session_t *as;
476#endif
477#endif
478	struct passwd *pw;
479	struct connection_info *ci;
480	u_int i;
481
482	ci = get_connection_info(ssh, 1, options.use_dns);
483	ci->user = user;
484	parse_server_match_config(&options, &includes, ci);
485	log_change_level(options.log_level);
486	log_verbose_reset();
487	for (i = 0; i < options.num_log_verbose; i++)
488		log_verbose_add(options.log_verbose[i]);
489	process_permitopen(ssh, &options);
490
491#if defined(_AIX) && defined(HAVE_SETAUTHDB)
492	aix_setauthdb(user);
493#endif
494
495	pw = getpwnam(user);
496
497#if defined(_AIX) && defined(HAVE_SETAUTHDB)
498	aix_restoreauthdb();
499#endif
500	if (pw == NULL) {
501		BLACKLIST_NOTIFY(ssh, BLACKLIST_BAD_USER, user);
502		logit("Invalid user %.100s from %.100s port %d",
503		    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
504#ifdef CUSTOM_FAILED_LOGIN
505		record_failed_login(ssh, user,
506		    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
507#endif
508#ifdef SSH_AUDIT_EVENTS
509		audit_event(ssh, SSH_INVALID_USER);
510#endif /* SSH_AUDIT_EVENTS */
511		return (NULL);
512	}
513	if (!allowed_user(ssh, pw))
514		return (NULL);
515#ifdef HAVE_LOGIN_CAP
516	if ((lc = login_getpwclass(pw)) == NULL) {
517		debug("unable to get login class: %s", user);
518		return (NULL);
519	}
520#ifdef HAVE_AUTH_HOSTOK
521	from_host = auth_get_canonical_hostname(ssh, options.use_dns);
522	from_ip = ssh_remote_ipaddr(ssh);
523	if (!auth_hostok(lc, from_host, from_ip)) {
524		debug("Denied connection for %.200s from %.200s [%.200s].",
525		    pw->pw_name, from_host, from_ip);
526		return (NULL);
527	}
528#endif /* HAVE_AUTH_HOSTOK */
529#ifdef HAVE_AUTH_TIMEOK
530	if (!auth_timeok(lc, time(NULL))) {
531		debug("LOGIN %.200s REFUSED (TIME)", pw->pw_name);
532		return (NULL);
533	}
534#endif /* HAVE_AUTH_TIMEOK */
535#ifdef BSD_AUTH
536	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
537	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
538		debug("Approval failure for %s", user);
539		pw = NULL;
540	}
541	if (as != NULL)
542		auth_close(as);
543#endif
544#endif
545	if (pw != NULL)
546		return (pwcopy(pw));
547	return (NULL);
548}
549
550/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
551int
552auth_key_is_revoked(struct sshkey *key)
553{
554	char *fp = NULL;
555	int r;
556
557	if (options.revoked_keys_file == NULL)
558		return 0;
559	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
560	    SSH_FP_DEFAULT)) == NULL) {
561		r = SSH_ERR_ALLOC_FAIL;
562		error_fr(r, "fingerprint key");
563		goto out;
564	}
565
566	r = sshkey_check_revoked(key, options.revoked_keys_file);
567	switch (r) {
568	case 0:
569		break; /* not revoked */
570	case SSH_ERR_KEY_REVOKED:
571		error("Authentication key %s %s revoked by file %s",
572		    sshkey_type(key), fp, options.revoked_keys_file);
573		goto out;
574	default:
575		error_r(r, "Error checking authentication key %s %s in "
576		    "revoked keys file %s", sshkey_type(key), fp,
577		    options.revoked_keys_file);
578		goto out;
579	}
580
581	/* Success */
582	r = 0;
583
584 out:
585	free(fp);
586	return r == 0 ? 0 : 1;
587}
588
589void
590auth_debug_add(const char *fmt,...)
591{
592	char buf[1024];
593	va_list args;
594	int r;
595
596	va_start(args, fmt);
597	vsnprintf(buf, sizeof(buf), fmt, args);
598	va_end(args);
599	debug3("%s", buf);
600	if (auth_debug != NULL)
601		if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0)
602			fatal_fr(r, "sshbuf_put_cstring");
603}
604
605void
606auth_debug_send(struct ssh *ssh)
607{
608	char *msg;
609	int r;
610
611	if (auth_debug == NULL)
612		return;
613	while (sshbuf_len(auth_debug) != 0) {
614		if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0)
615			fatal_fr(r, "sshbuf_get_cstring");
616		ssh_packet_send_debug(ssh, "%s", msg);
617		free(msg);
618	}
619}
620
621void
622auth_debug_reset(void)
623{
624	if (auth_debug != NULL)
625		sshbuf_reset(auth_debug);
626	else if ((auth_debug = sshbuf_new()) == NULL)
627		fatal_f("sshbuf_new failed");
628}
629
630struct passwd *
631fakepw(void)
632{
633	static int done = 0;
634	static struct passwd fake;
635	const char hashchars[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZ"
636	    "abcdefghijklmnopqrstuvwxyz0123456789"; /* from bcrypt.c */
637	char *cp;
638
639	if (done)
640		return (&fake);
641
642	memset(&fake, 0, sizeof(fake));
643	fake.pw_name = "NOUSER";
644	fake.pw_passwd = xstrdup("$2a$10$"
645	    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
646	for (cp = fake.pw_passwd + 7; *cp != '\0'; cp++)
647		*cp = hashchars[arc4random_uniform(sizeof(hashchars) - 1)];
648#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
649	fake.pw_gecos = "NOUSER";
650#endif
651	fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
652	fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
653#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
654	fake.pw_class = "";
655#endif
656	fake.pw_dir = "/nonexist";
657	fake.pw_shell = "/nonexist";
658	done = 1;
659
660	return (&fake);
661}
662
663/*
664 * Returns the remote DNS hostname as a string. The returned string must not
665 * be freed. NB. this will usually trigger a DNS query the first time it is
666 * called.
667 * This function does additional checks on the hostname to mitigate some
668 * attacks on based on conflation of hostnames and IP addresses.
669 */
670
671static char *
672remote_hostname(struct ssh *ssh)
673{
674	struct sockaddr_storage from;
675	socklen_t fromlen;
676	struct addrinfo hints, *ai, *aitop;
677	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
678	const char *ntop = ssh_remote_ipaddr(ssh);
679
680	/* Get IP address of client. */
681	fromlen = sizeof(from);
682	memset(&from, 0, sizeof(from));
683	if (getpeername(ssh_packet_get_connection_in(ssh),
684	    (struct sockaddr *)&from, &fromlen) == -1) {
685		debug("getpeername failed: %.100s", strerror(errno));
686		return xstrdup(ntop);
687	}
688
689	ipv64_normalise_mapped(&from, &fromlen);
690	if (from.ss_family == AF_INET6)
691		fromlen = sizeof(struct sockaddr_in6);
692
693	debug3("Trying to reverse map address %.100s.", ntop);
694	/* Map the IP address to a host name. */
695	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
696	    NULL, 0, NI_NAMEREQD) != 0) {
697		/* Host name not found.  Use ip address. */
698		return xstrdup(ntop);
699	}
700
701	/*
702	 * if reverse lookup result looks like a numeric hostname,
703	 * someone is trying to trick us by PTR record like following:
704	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
705	 */
706	memset(&hints, 0, sizeof(hints));
707	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
708	hints.ai_flags = AI_NUMERICHOST;
709	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
710		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
711		    name, ntop);
712		freeaddrinfo(ai);
713		return xstrdup(ntop);
714	}
715
716	/* Names are stored in lowercase. */
717	lowercase(name);
718
719	/*
720	 * Map it back to an IP address and check that the given
721	 * address actually is an address of this host.  This is
722	 * necessary because anyone with access to a name server can
723	 * define arbitrary names for an IP address. Mapping from
724	 * name to IP address can be trusted better (but can still be
725	 * fooled if the intruder has access to the name server of
726	 * the domain).
727	 */
728	memset(&hints, 0, sizeof(hints));
729	hints.ai_family = from.ss_family;
730	hints.ai_socktype = SOCK_STREAM;
731	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
732		logit("reverse mapping checking getaddrinfo for %.700s "
733		    "[%s] failed.", name, ntop);
734		return xstrdup(ntop);
735	}
736	/* Look for the address from the list of addresses. */
737	for (ai = aitop; ai; ai = ai->ai_next) {
738		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
739		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
740		    (strcmp(ntop, ntop2) == 0))
741				break;
742	}
743	freeaddrinfo(aitop);
744	/* If we reached the end of the list, the address was not there. */
745	if (ai == NULL) {
746		/* Address not found for the host name. */
747		logit("Address %.100s maps to %.600s, but this does not "
748		    "map back to the address.", ntop, name);
749		return xstrdup(ntop);
750	}
751	return xstrdup(name);
752}
753
754/*
755 * Return the canonical name of the host in the other side of the current
756 * connection.  The host name is cached, so it is efficient to call this
757 * several times.
758 */
759
760const char *
761auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
762{
763	static char *dnsname;
764
765	if (!use_dns)
766		return ssh_remote_ipaddr(ssh);
767	else if (dnsname != NULL)
768		return dnsname;
769	else {
770		dnsname = remote_hostname(ssh);
771		return dnsname;
772	}
773}
774
775/* These functions link key/cert options to the auth framework */
776
777/* Log sshauthopt options locally and (optionally) for remote transmission */
778void
779auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
780{
781	int do_env = options.permit_user_env && opts->nenv > 0;
782	int do_permitopen = opts->npermitopen > 0 &&
783	    (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
784	int do_permitlisten = opts->npermitlisten > 0 &&
785	    (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
786	size_t i;
787	char msg[1024], buf[64];
788
789	snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
790	/* Try to keep this alphabetically sorted */
791	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
792	    opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
793	    opts->force_command == NULL ? "" : " command",
794	    do_env ?  " environment" : "",
795	    opts->valid_before == 0 ? "" : "expires",
796	    opts->no_require_user_presence ? " no-touch-required" : "",
797	    do_permitopen ?  " permitopen" : "",
798	    do_permitlisten ?  " permitlisten" : "",
799	    opts->permit_port_forwarding_flag ? " port-forwarding" : "",
800	    opts->cert_principals == NULL ? "" : " principals",
801	    opts->permit_pty_flag ? " pty" : "",
802	    opts->require_verify ? " uv" : "",
803	    opts->force_tun_device == -1 ? "" : " tun=",
804	    opts->force_tun_device == -1 ? "" : buf,
805	    opts->permit_user_rc ? " user-rc" : "",
806	    opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
807
808	debug("%s: %s", loc, msg);
809	if (do_remote)
810		auth_debug_add("%s: %s", loc, msg);
811
812	if (options.permit_user_env) {
813		for (i = 0; i < opts->nenv; i++) {
814			debug("%s: environment: %s", loc, opts->env[i]);
815			if (do_remote) {
816				auth_debug_add("%s: environment: %s",
817				    loc, opts->env[i]);
818			}
819		}
820	}
821
822	/* Go into a little more details for the local logs. */
823	if (opts->valid_before != 0) {
824		format_absolute_time(opts->valid_before, buf, sizeof(buf));
825		debug("%s: expires at %s", loc, buf);
826	}
827	if (opts->cert_principals != NULL) {
828		debug("%s: authorized principals: \"%s\"",
829		    loc, opts->cert_principals);
830	}
831	if (opts->force_command != NULL)
832		debug("%s: forced command: \"%s\"", loc, opts->force_command);
833	if (do_permitopen) {
834		for (i = 0; i < opts->npermitopen; i++) {
835			debug("%s: permitted open: %s",
836			    loc, opts->permitopen[i]);
837		}
838	}
839	if (do_permitlisten) {
840		for (i = 0; i < opts->npermitlisten; i++) {
841			debug("%s: permitted listen: %s",
842			    loc, opts->permitlisten[i]);
843		}
844	}
845}
846
847/* Activate a new set of key/cert options; merging with what is there. */
848int
849auth_activate_options(struct ssh *ssh, struct sshauthopt *opts)
850{
851	struct sshauthopt *old = auth_opts;
852	const char *emsg = NULL;
853
854	debug_f("setting new authentication options");
855	if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) {
856		error("Inconsistent authentication options: %s", emsg);
857		return -1;
858	}
859	return 0;
860}
861
862/* Disable forwarding, etc for the session */
863void
864auth_restrict_session(struct ssh *ssh)
865{
866	struct sshauthopt *restricted;
867
868	debug_f("restricting session");
869
870	/* A blank sshauthopt defaults to permitting nothing */
871	if ((restricted = sshauthopt_new()) == NULL)
872		fatal_f("sshauthopt_new failed");
873	restricted->permit_pty_flag = 1;
874	restricted->restricted = 1;
875
876	if (auth_activate_options(ssh, restricted) != 0)
877		fatal_f("failed to restrict session");
878	sshauthopt_free(restricted);
879}
880