xref: /openbsd-src/usr.bin/ssh/auth.c (revision f763167468dba5339ed4b14b7ecaca2a397ab0f6)
1 /* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm 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 <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/socket.h>
29 
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <login_cap.h>
33 #include <paths.h>
34 #include <pwd.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <netdb.h>
41 
42 #include "xmalloc.h"
43 #include "match.h"
44 #include "groupaccess.h"
45 #include "log.h"
46 #include "buffer.h"
47 #include "misc.h"
48 #include "servconf.h"
49 #include "key.h"
50 #include "hostfile.h"
51 #include "auth.h"
52 #include "auth-options.h"
53 #include "canohost.h"
54 #include "uidswap.h"
55 #include "packet.h"
56 #ifdef GSSAPI
57 #include "ssh-gss.h"
58 #endif
59 #include "authfile.h"
60 #include "monitor_wrap.h"
61 #include "authfile.h"
62 #include "ssherr.h"
63 #include "compat.h"
64 
65 /* import */
66 extern ServerOptions options;
67 extern int use_privsep;
68 
69 /* Debugging messages */
70 Buffer auth_debug;
71 int auth_debug_init;
72 
73 /*
74  * Check if the user is allowed to log in via ssh. If user is listed
75  * in DenyUsers or one of user's groups is listed in DenyGroups, false
76  * will be returned. If AllowUsers isn't empty and user isn't listed
77  * there, or if AllowGroups isn't empty and one of user's groups isn't
78  * listed there, false will be returned.
79  * If the user's shell is not executable, false will be returned.
80  * Otherwise true is returned.
81  */
82 int
83 allowed_user(struct passwd * pw)
84 {
85 	struct ssh *ssh = active_state; /* XXX */
86 	struct stat st;
87 	const char *hostname = NULL, *ipaddr = NULL;
88 	int r;
89 	u_int i;
90 
91 	/* Shouldn't be called if pw is NULL, but better safe than sorry... */
92 	if (!pw || !pw->pw_name)
93 		return 0;
94 
95 	/*
96 	 * Deny if shell does not exist or is not executable unless we
97 	 * are chrooting.
98 	 */
99 	if (options.chroot_directory == NULL ||
100 	    strcasecmp(options.chroot_directory, "none") == 0) {
101 		char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
102 		    _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
103 
104 		if (stat(shell, &st) != 0) {
105 			logit("User %.100s not allowed because shell %.100s "
106 			    "does not exist", pw->pw_name, shell);
107 			free(shell);
108 			return 0;
109 		}
110 		if (S_ISREG(st.st_mode) == 0 ||
111 		    (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
112 			logit("User %.100s not allowed because shell %.100s "
113 			    "is not executable", pw->pw_name, shell);
114 			free(shell);
115 			return 0;
116 		}
117 		free(shell);
118 	}
119 
120 	if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
121 	    options.num_deny_groups > 0 || options.num_allow_groups > 0) {
122 		hostname = auth_get_canonical_hostname(ssh, options.use_dns);
123 		ipaddr = ssh_remote_ipaddr(ssh);
124 	}
125 
126 	/* Return false if user is listed in DenyUsers */
127 	if (options.num_deny_users > 0) {
128 		for (i = 0; i < options.num_deny_users; i++) {
129 			r = match_user(pw->pw_name, hostname, ipaddr,
130 			    options.deny_users[i]);
131 			if (r < 0) {
132 				fatal("Invalid DenyUsers pattern \"%.100s\"",
133 				    options.deny_users[i]);
134 			} else if (r != 0) {
135 				logit("User %.100s from %.100s not allowed "
136 				    "because listed in DenyUsers",
137 				    pw->pw_name, hostname);
138 				return 0;
139 			}
140 		}
141 	}
142 	/* Return false if AllowUsers isn't empty and user isn't listed there */
143 	if (options.num_allow_users > 0) {
144 		for (i = 0; i < options.num_allow_users; i++) {
145 			r = match_user(pw->pw_name, hostname, ipaddr,
146 			    options.allow_users[i]);
147 			if (r < 0) {
148 				fatal("Invalid AllowUsers pattern \"%.100s\"",
149 				    options.allow_users[i]);
150 			} else if (r == 1)
151 				break;
152 		}
153 		/* i < options.num_allow_users iff we break for loop */
154 		if (i >= options.num_allow_users) {
155 			logit("User %.100s from %.100s not allowed because "
156 			    "not listed in AllowUsers", pw->pw_name, hostname);
157 			return 0;
158 		}
159 	}
160 	if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
161 		/* Get the user's group access list (primary and supplementary) */
162 		if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
163 			logit("User %.100s from %.100s not allowed because "
164 			    "not in any group", pw->pw_name, hostname);
165 			return 0;
166 		}
167 
168 		/* Return false if one of user's groups is listed in DenyGroups */
169 		if (options.num_deny_groups > 0)
170 			if (ga_match(options.deny_groups,
171 			    options.num_deny_groups)) {
172 				ga_free();
173 				logit("User %.100s from %.100s not allowed "
174 				    "because a group is listed in DenyGroups",
175 				    pw->pw_name, hostname);
176 				return 0;
177 			}
178 		/*
179 		 * Return false if AllowGroups isn't empty and one of user's groups
180 		 * isn't listed there
181 		 */
182 		if (options.num_allow_groups > 0)
183 			if (!ga_match(options.allow_groups,
184 			    options.num_allow_groups)) {
185 				ga_free();
186 				logit("User %.100s from %.100s not allowed "
187 				    "because none of user's groups are listed "
188 				    "in AllowGroups", pw->pw_name, hostname);
189 				return 0;
190 			}
191 		ga_free();
192 	}
193 	/* We found no reason not to let this user try to log on... */
194 	return 1;
195 }
196 
197 /*
198  * Formats any key left in authctxt->auth_method_key for inclusion in
199  * auth_log()'s message. Also includes authxtct->auth_method_info if present.
200  */
201 static char *
202 format_method_key(Authctxt *authctxt)
203 {
204 	const struct sshkey *key = authctxt->auth_method_key;
205 	const char *methinfo = authctxt->auth_method_info;
206 	char *fp, *ret = NULL;
207 
208 	if (key == NULL)
209 		return NULL;
210 
211 	if (key_is_cert(key)) {
212 		fp = sshkey_fingerprint(key->cert->signature_key,
213 		    options.fingerprint_hash, SSH_FP_DEFAULT);
214 		xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
215 		    sshkey_type(key), key->cert->key_id,
216 		    (unsigned long long)key->cert->serial,
217 		    sshkey_type(key->cert->signature_key),
218 		    fp == NULL ? "(null)" : fp,
219 		    methinfo == NULL ? "" : ", ",
220 		    methinfo == NULL ? "" : methinfo);
221 		free(fp);
222 	} else {
223 		fp = sshkey_fingerprint(key, options.fingerprint_hash,
224 		    SSH_FP_DEFAULT);
225 		xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
226 		    fp == NULL ? "(null)" : fp,
227 		    methinfo == NULL ? "" : ", ",
228 		    methinfo == NULL ? "" : methinfo);
229 		free(fp);
230 	}
231 	return ret;
232 }
233 
234 void
235 auth_log(Authctxt *authctxt, int authenticated, int partial,
236     const char *method, const char *submethod)
237 {
238 	struct ssh *ssh = active_state; /* XXX */
239 	void (*authlog) (const char *fmt,...) = verbose;
240 	const char *authmsg;
241 	char *extra = NULL;
242 
243 	if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
244 		return;
245 
246 	/* Raise logging level */
247 	if (authenticated == 1 ||
248 	    !authctxt->valid ||
249 	    authctxt->failures >= options.max_authtries / 2 ||
250 	    strcmp(method, "password") == 0)
251 		authlog = logit;
252 
253 	if (authctxt->postponed)
254 		authmsg = "Postponed";
255 	else if (partial)
256 		authmsg = "Partial";
257 	else
258 		authmsg = authenticated ? "Accepted" : "Failed";
259 
260 	if ((extra = format_method_key(authctxt)) == NULL) {
261 		if (authctxt->auth_method_info != NULL)
262 			extra = xstrdup(authctxt->auth_method_info);
263 	}
264 
265 	authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
266 	    authmsg,
267 	    method,
268 	    submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
269 	    authctxt->valid ? "" : "invalid user ",
270 	    authctxt->user,
271 	    ssh_remote_ipaddr(ssh),
272 	    ssh_remote_port(ssh),
273 	    extra != NULL ? ": " : "",
274 	    extra != NULL ? extra : "");
275 
276 	free(extra);
277 }
278 
279 void
280 auth_maxtries_exceeded(Authctxt *authctxt)
281 {
282 	struct ssh *ssh = active_state; /* XXX */
283 
284 	error("maximum authentication attempts exceeded for "
285 	    "%s%.100s from %.200s port %d ssh2",
286 	    authctxt->valid ? "" : "invalid user ",
287 	    authctxt->user,
288 	    ssh_remote_ipaddr(ssh),
289 	    ssh_remote_port(ssh));
290 	packet_disconnect("Too many authentication failures");
291 	/* NOTREACHED */
292 }
293 
294 /*
295  * Check whether root logins are disallowed.
296  */
297 int
298 auth_root_allowed(const char *method)
299 {
300 	struct ssh *ssh = active_state; /* XXX */
301 
302 	switch (options.permit_root_login) {
303 	case PERMIT_YES:
304 		return 1;
305 	case PERMIT_NO_PASSWD:
306 		if (strcmp(method, "publickey") == 0 ||
307 		    strcmp(method, "hostbased") == 0 ||
308 		    strcmp(method, "gssapi-with-mic") == 0)
309 			return 1;
310 		break;
311 	case PERMIT_FORCED_ONLY:
312 		if (forced_command) {
313 			logit("Root login accepted for forced command.");
314 			return 1;
315 		}
316 		break;
317 	}
318 	logit("ROOT LOGIN REFUSED FROM %.200s port %d",
319 	    ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
320 	return 0;
321 }
322 
323 
324 /*
325  * Given a template and a passwd structure, build a filename
326  * by substituting % tokenised options. Currently, %% becomes '%',
327  * %h becomes the home directory and %u the username.
328  *
329  * This returns a buffer allocated by xmalloc.
330  */
331 char *
332 expand_authorized_keys(const char *filename, struct passwd *pw)
333 {
334 	char *file, ret[PATH_MAX];
335 	int i;
336 
337 	file = percent_expand(filename, "h", pw->pw_dir,
338 	    "u", pw->pw_name, (char *)NULL);
339 
340 	/*
341 	 * Ensure that filename starts anchored. If not, be backward
342 	 * compatible and prepend the '%h/'
343 	 */
344 	if (*file == '/')
345 		return (file);
346 
347 	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
348 	if (i < 0 || (size_t)i >= sizeof(ret))
349 		fatal("expand_authorized_keys: path too long");
350 	free(file);
351 	return (xstrdup(ret));
352 }
353 
354 char *
355 authorized_principals_file(struct passwd *pw)
356 {
357 	if (options.authorized_principals_file == NULL)
358 		return NULL;
359 	return expand_authorized_keys(options.authorized_principals_file, pw);
360 }
361 
362 /* return ok if key exists in sysfile or userfile */
363 HostStatus
364 check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
365     const char *sysfile, const char *userfile)
366 {
367 	char *user_hostfile;
368 	struct stat st;
369 	HostStatus host_status;
370 	struct hostkeys *hostkeys;
371 	const struct hostkey_entry *found;
372 
373 	hostkeys = init_hostkeys();
374 	load_hostkeys(hostkeys, host, sysfile);
375 	if (userfile != NULL) {
376 		user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
377 		if (options.strict_modes &&
378 		    (stat(user_hostfile, &st) == 0) &&
379 		    ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
380 		    (st.st_mode & 022) != 0)) {
381 			logit("Authentication refused for %.100s: "
382 			    "bad owner or modes for %.200s",
383 			    pw->pw_name, user_hostfile);
384 			auth_debug_add("Ignored %.200s: bad ownership or modes",
385 			    user_hostfile);
386 		} else {
387 			temporarily_use_uid(pw);
388 			load_hostkeys(hostkeys, host, user_hostfile);
389 			restore_uid();
390 		}
391 		free(user_hostfile);
392 	}
393 	host_status = check_key_in_hostkeys(hostkeys, key, &found);
394 	if (host_status == HOST_REVOKED)
395 		error("WARNING: revoked key for %s attempted authentication",
396 		    found->host);
397 	else if (host_status == HOST_OK)
398 		debug("%s: key for %s found at %s:%ld", __func__,
399 		    found->host, found->file, found->line);
400 	else
401 		debug("%s: key for host %s not found", __func__, host);
402 
403 	free_hostkeys(hostkeys);
404 
405 	return host_status;
406 }
407 
408 static FILE *
409 auth_openfile(const char *file, struct passwd *pw, int strict_modes,
410     int log_missing, char *file_type)
411 {
412 	char line[1024];
413 	struct stat st;
414 	int fd;
415 	FILE *f;
416 
417 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
418 		if (log_missing || errno != ENOENT)
419 			debug("Could not open %s '%s': %s", file_type, file,
420 			   strerror(errno));
421 		return NULL;
422 	}
423 
424 	if (fstat(fd, &st) < 0) {
425 		close(fd);
426 		return NULL;
427 	}
428 	if (!S_ISREG(st.st_mode)) {
429 		logit("User %s %s %s is not a regular file",
430 		    pw->pw_name, file_type, file);
431 		close(fd);
432 		return NULL;
433 	}
434 	unset_nonblock(fd);
435 	if ((f = fdopen(fd, "r")) == NULL) {
436 		close(fd);
437 		return NULL;
438 	}
439 	if (strict_modes &&
440 	    safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
441 		fclose(f);
442 		logit("Authentication refused: %s", line);
443 		auth_debug_add("Ignored %s: %s", file_type, line);
444 		return NULL;
445 	}
446 
447 	return f;
448 }
449 
450 
451 FILE *
452 auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
453 {
454 	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
455 }
456 
457 FILE *
458 auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
459 {
460 	return auth_openfile(file, pw, strict_modes, 0,
461 	    "authorized principals");
462 }
463 
464 struct passwd *
465 getpwnamallow(const char *user)
466 {
467 	struct ssh *ssh = active_state; /* XXX */
468 	extern login_cap_t *lc;
469 	auth_session_t *as;
470 	struct passwd *pw;
471 	struct connection_info *ci = get_connection_info(1, options.use_dns);
472 
473 	ci->user = user;
474 	parse_server_match_config(&options, ci);
475 	log_change_level(options.log_level);
476 	process_permitopen(ssh, &options);
477 
478 	pw = getpwnam(user);
479 	if (pw == NULL) {
480 		logit("Invalid user %.100s from %.100s port %d",
481 		    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
482 		return (NULL);
483 	}
484 	if (!allowed_user(pw))
485 		return (NULL);
486 	if ((lc = login_getclass(pw->pw_class)) == NULL) {
487 		debug("unable to get login class: %s", user);
488 		return (NULL);
489 	}
490 	if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
491 	    auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
492 		debug("Approval failure for %s", user);
493 		pw = NULL;
494 	}
495 	if (as != NULL)
496 		auth_close(as);
497 	if (pw != NULL)
498 		return (pwcopy(pw));
499 	return (NULL);
500 }
501 
502 /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
503 int
504 auth_key_is_revoked(struct sshkey *key)
505 {
506 	char *fp = NULL;
507 	int r;
508 
509 	if (options.revoked_keys_file == NULL)
510 		return 0;
511 	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
512 	    SSH_FP_DEFAULT)) == NULL) {
513 		r = SSH_ERR_ALLOC_FAIL;
514 		error("%s: fingerprint key: %s", __func__, ssh_err(r));
515 		goto out;
516 	}
517 
518 	r = sshkey_check_revoked(key, options.revoked_keys_file);
519 	switch (r) {
520 	case 0:
521 		break; /* not revoked */
522 	case SSH_ERR_KEY_REVOKED:
523 		error("Authentication key %s %s revoked by file %s",
524 		    sshkey_type(key), fp, options.revoked_keys_file);
525 		goto out;
526 	default:
527 		error("Error checking authentication key %s %s in "
528 		    "revoked keys file %s: %s", sshkey_type(key), fp,
529 		    options.revoked_keys_file, ssh_err(r));
530 		goto out;
531 	}
532 
533 	/* Success */
534 	r = 0;
535 
536  out:
537 	free(fp);
538 	return r == 0 ? 0 : 1;
539 }
540 
541 void
542 auth_debug_add(const char *fmt,...)
543 {
544 	char buf[1024];
545 	va_list args;
546 
547 	if (!auth_debug_init)
548 		return;
549 
550 	va_start(args, fmt);
551 	vsnprintf(buf, sizeof(buf), fmt, args);
552 	va_end(args);
553 	buffer_put_cstring(&auth_debug, buf);
554 }
555 
556 void
557 auth_debug_send(void)
558 {
559 	char *msg;
560 
561 	if (!auth_debug_init)
562 		return;
563 	while (buffer_len(&auth_debug)) {
564 		msg = buffer_get_string(&auth_debug, NULL);
565 		packet_send_debug("%s", msg);
566 		free(msg);
567 	}
568 }
569 
570 void
571 auth_debug_reset(void)
572 {
573 	if (auth_debug_init)
574 		buffer_clear(&auth_debug);
575 	else {
576 		buffer_init(&auth_debug);
577 		auth_debug_init = 1;
578 	}
579 }
580 
581 struct passwd *
582 fakepw(void)
583 {
584 	static struct passwd fake;
585 
586 	memset(&fake, 0, sizeof(fake));
587 	fake.pw_name = "NOUSER";
588 	fake.pw_passwd =
589 	    "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
590 	fake.pw_gecos = "NOUSER";
591 	fake.pw_uid = (uid_t)-1;
592 	fake.pw_gid = (gid_t)-1;
593 	fake.pw_class = "";
594 	fake.pw_dir = "/nonexist";
595 	fake.pw_shell = "/nonexist";
596 
597 	return (&fake);
598 }
599 
600 /*
601  * Returns the remote DNS hostname as a string. The returned string must not
602  * be freed. NB. this will usually trigger a DNS query the first time it is
603  * called.
604  * This function does additional checks on the hostname to mitigate some
605  * attacks on legacy rhosts-style authentication.
606  * XXX is RhostsRSAAuthentication vulnerable to these?
607  * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)
608  */
609 
610 static char *
611 remote_hostname(struct ssh *ssh)
612 {
613 	struct sockaddr_storage from;
614 	socklen_t fromlen;
615 	struct addrinfo hints, *ai, *aitop;
616 	char name[NI_MAXHOST], ntop2[NI_MAXHOST];
617 	const char *ntop = ssh_remote_ipaddr(ssh);
618 
619 	/* Get IP address of client. */
620 	fromlen = sizeof(from);
621 	memset(&from, 0, sizeof(from));
622 	if (getpeername(ssh_packet_get_connection_in(ssh),
623 	    (struct sockaddr *)&from, &fromlen) < 0) {
624 		debug("getpeername failed: %.100s", strerror(errno));
625 		return strdup(ntop);
626 	}
627 
628 	debug3("Trying to reverse map address %.100s.", ntop);
629 	/* Map the IP address to a host name. */
630 	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
631 	    NULL, 0, NI_NAMEREQD) != 0) {
632 		/* Host name not found.  Use ip address. */
633 		return strdup(ntop);
634 	}
635 
636 	/*
637 	 * if reverse lookup result looks like a numeric hostname,
638 	 * someone is trying to trick us by PTR record like following:
639 	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
640 	 */
641 	memset(&hints, 0, sizeof(hints));
642 	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
643 	hints.ai_flags = AI_NUMERICHOST;
644 	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
645 		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
646 		    name, ntop);
647 		freeaddrinfo(ai);
648 		return strdup(ntop);
649 	}
650 
651 	/* Names are stored in lowercase. */
652 	lowercase(name);
653 
654 	/*
655 	 * Map it back to an IP address and check that the given
656 	 * address actually is an address of this host.  This is
657 	 * necessary because anyone with access to a name server can
658 	 * define arbitrary names for an IP address. Mapping from
659 	 * name to IP address can be trusted better (but can still be
660 	 * fooled if the intruder has access to the name server of
661 	 * the domain).
662 	 */
663 	memset(&hints, 0, sizeof(hints));
664 	hints.ai_family = from.ss_family;
665 	hints.ai_socktype = SOCK_STREAM;
666 	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
667 		logit("reverse mapping checking getaddrinfo for %.700s "
668 		    "[%s] failed.", name, ntop);
669 		return strdup(ntop);
670 	}
671 	/* Look for the address from the list of addresses. */
672 	for (ai = aitop; ai; ai = ai->ai_next) {
673 		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
674 		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
675 		    (strcmp(ntop, ntop2) == 0))
676 				break;
677 	}
678 	freeaddrinfo(aitop);
679 	/* If we reached the end of the list, the address was not there. */
680 	if (ai == NULL) {
681 		/* Address not found for the host name. */
682 		logit("Address %.100s maps to %.600s, but this does not "
683 		    "map back to the address.", ntop, name);
684 		return strdup(ntop);
685 	}
686 	return strdup(name);
687 }
688 
689 /*
690  * Return the canonical name of the host in the other side of the current
691  * connection.  The host name is cached, so it is efficient to call this
692  * several times.
693  */
694 
695 const char *
696 auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
697 {
698 	static char *dnsname;
699 
700 	if (!use_dns)
701 		return ssh_remote_ipaddr(ssh);
702 	else if (dnsname != NULL)
703 		return dnsname;
704 	else {
705 		dnsname = remote_hostname(ssh);
706 		return dnsname;
707 	}
708 }
709