[BACK]Return to auth.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / crypto / external / bsd / openssh / dist

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/crypto/external/bsd/openssh/dist/auth.c between version 1.5.12.2 and 1.6

version 1.5.12.2, 2017/08/15 04:40:16 version 1.6, 2012/12/12 17:42:39
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
 /* $OpenBSD: auth.c,v 1.119 2016/12/15 21:29:05 dtucker Exp $ */  /* $OpenBSD: auth.c,v 1.96 2012/05/13 01:42:32 dtucker Exp $ */
 /*  /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.   * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *   *
Line 28 
Line 28 
 __RCSID("$NetBSD$");  __RCSID("$NetBSD$");
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/socket.h>  #include <sys/param.h>
   
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
Line 40  __RCSID("$NetBSD$");
Line 40  __RCSID("$NetBSD$");
 #include <stdio.h>  #include <stdio.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
 #include <limits.h>  
 #include <netdb.h>  
   
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "match.h"  #include "match.h"
 #include "groupaccess.h"  #include "groupaccess.h"
 #include "log.h"  #include "log.h"
 #include "buffer.h"  #include "buffer.h"
 #include "misc.h"  
 #include "servconf.h"  #include "servconf.h"
 #include "key.h"  #include "key.h"
 #include "hostfile.h"  #include "hostfile.h"
Line 56  __RCSID("$NetBSD$");
Line 53  __RCSID("$NetBSD$");
 #include "auth-options.h"  #include "auth-options.h"
 #include "canohost.h"  #include "canohost.h"
 #include "uidswap.h"  #include "uidswap.h"
   #include "misc.h"
 #include "packet.h"  #include "packet.h"
 #ifdef GSSAPI  #ifdef GSSAPI
 #include "ssh-gss.h"  #include "ssh-gss.h"
 #endif  #endif
 #include "authfile.h"  #include "authfile.h"
 #include "monitor_wrap.h"  #include "monitor_wrap.h"
 #include "authfile.h"  
 #include "ssherr.h"  
 #include "compat.h"  
 #include "pfilter.h"  
   
 #ifdef HAVE_LOGIN_CAP  #ifdef HAVE_LOGIN_CAP
 #include <login_cap.h>  #include <login_cap.h>
Line 79  extern int use_privsep;
Line 73  extern int use_privsep;
 Buffer auth_debug;  Buffer auth_debug;
 int auth_debug_init;  int auth_debug_init;
   
 #ifndef HOST_ONLY  
 /*  /*
  * Check if the user is allowed to log in via ssh. If user is listed   * Check if the user is allowed to log in via ssh. If user is listed
  * in DenyUsers or one of user's groups is listed in DenyGroups, false   * in DenyUsers or one of user's groups is listed in DenyGroups, false
Line 97  allowed_user(struct passwd * pw)
Line 90  allowed_user(struct passwd * pw)
         int match_name, match_ip;          int match_name, match_ip;
         char *cap_hlist, *hp;          char *cap_hlist, *hp;
 #endif  #endif
         struct ssh *ssh = active_state; /* XXX */  
         struct stat st;          struct stat st;
         const char *hostname = NULL, *ipaddr = NULL;          const char *hostname = NULL, *ipaddr = NULL;
         int r;  
         u_int i;          u_int i;
   
         /* Shouldn't be called if pw is NULL, but better safe than sorry... */          /* Shouldn't be called if pw is NULL, but better safe than sorry... */
Line 108  allowed_user(struct passwd * pw)
Line 99  allowed_user(struct passwd * pw)
                 return 0;                  return 0;
   
 #ifdef HAVE_LOGIN_CAP  #ifdef HAVE_LOGIN_CAP
         hostname = auth_get_canonical_hostname(ssh, options.use_dns);          hostname = get_canonical_hostname(1);
         ipaddr = ssh_remote_ipaddr(ssh);          ipaddr = get_remote_ipaddr();
   
         lc = login_getclass(pw->pw_class);          lc = login_getclass(pw->pw_class);
   
Line 120  allowed_user(struct passwd * pw)
Line 111  allowed_user(struct passwd * pw)
         if (cap_hlist != NULL) {          if (cap_hlist != NULL) {
                 hp = strtok(cap_hlist, ",");                  hp = strtok(cap_hlist, ",");
                 while (hp != NULL) {                  while (hp != NULL) {
                         match_name = match_hostname(hostname, hp);                          match_name = match_hostname(hostname,
                         match_ip = match_hostname(ipaddr, hp);                              hp, strlen(hp));
                           match_ip = match_hostname(ipaddr,
                               hp, strlen(hp));
                         /*                          /*
                          * Only a positive match here causes a "deny".                           * Only a positive match here causes a "deny".
                          */                           */
Line 149  allowed_user(struct passwd * pw)
Line 142  allowed_user(struct passwd * pw)
                         return 0;                          return 0;
                 }                  }
                 while (hp != NULL) {                  while (hp != NULL) {
                         match_name = match_hostname(hostname, hp);                          match_name = match_hostname(hostname,
                         match_ip = match_hostname(ipaddr, hp);                              hp, strlen(hp));
                           match_ip = match_hostname(ipaddr,
                               hp, strlen(hp));
                         /*                          /*
                          * Negative match causes an immediate "deny".                           * Negative match causes an immediate "deny".
                          * Positive match causes us to break out                           * Positive match causes us to break out
Line 228  allowed_user(struct passwd * pw)
Line 223  allowed_user(struct passwd * pw)
                 if (stat(shell, &st) != 0) {                  if (stat(shell, &st) != 0) {
                         logit("User %.100s not allowed because shell %.100s "                          logit("User %.100s not allowed because shell %.100s "
                             "does not exist", pw->pw_name, shell);                              "does not exist", pw->pw_name, shell);
                         free(shell);                          xfree(shell);
                         return 0;                          return 0;
                 }                  }
                 if (S_ISREG(st.st_mode) == 0 ||                  if (S_ISREG(st.st_mode) == 0 ||
                     (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {                      (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
                         logit("User %.100s not allowed because shell %.100s "                          logit("User %.100s not allowed because shell %.100s "
                             "is not executable", pw->pw_name, shell);                              "is not executable", pw->pw_name, shell);
                         free(shell);                          xfree(shell);
                         return 0;                          return 0;
                 }                  }
                 free(shell);                  xfree(shell);
         }          }
         /*          /*
          * XXX Consider nuking {Allow,Deny}{Users,Groups}.  We have the           * XXX Consider nuking {Allow,Deny}{Users,Groups}.  We have the
Line 248  allowed_user(struct passwd * pw)
Line 243  allowed_user(struct passwd * pw)
   
         if (options.num_deny_users > 0 || options.num_allow_users > 0 ||          if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
             options.num_deny_groups > 0 || options.num_allow_groups > 0) {              options.num_deny_groups > 0 || options.num_allow_groups > 0) {
                 hostname = auth_get_canonical_hostname(ssh, options.use_dns);                  hostname = get_canonical_hostname(options.use_dns);
                 ipaddr = ssh_remote_ipaddr(ssh);                  ipaddr = get_remote_ipaddr();
         }          }
   
         /* Return false if user is listed in DenyUsers */          /* Return false if user is listed in DenyUsers */
         if (options.num_deny_users > 0) {          if (options.num_deny_users > 0) {
                 for (i = 0; i < options.num_deny_users; i++) {                  for (i = 0; i < options.num_deny_users; i++)
                         r = match_user(pw->pw_name, hostname, ipaddr,                          if (match_user(pw->pw_name, hostname, ipaddr,
                             options.deny_users[i]);                              options.deny_users[i])) {
                         if (r < 0) {  
                                 fatal("Invalid DenyUsers pattern \"%.100s\"",  
                                     options.deny_users[i]);  
                         } else if (r != 0) {  
                                 logit("User %.100s from %.100s not allowed "                                  logit("User %.100s from %.100s not allowed "
                                     "because listed in DenyUsers",                                      "because listed in DenyUsers",
                                     pw->pw_name, hostname);                                      pw->pw_name, hostname);
                                 return 0;                                  return 0;
                         }                          }
                 }  
         }          }
         /* Return false if AllowUsers isn't empty and user isn't listed there */          /* Return false if AllowUsers isn't empty and user isn't listed there */
         if (options.num_allow_users > 0) {          if (options.num_allow_users > 0) {
                 for (i = 0; i < options.num_allow_users; i++) {                  for (i = 0; i < options.num_allow_users; i++)
                         r = match_user(pw->pw_name, hostname, ipaddr,                          if (match_user(pw->pw_name, hostname, ipaddr,
                             options.allow_users[i]);                              options.allow_users[i]))
                         if (r < 0) {  
                                 fatal("Invalid AllowUsers pattern \"%.100s\"",  
                                     options.allow_users[i]);  
                         } else if (r == 1)  
                                 break;                                  break;
                 }  
                 /* i < options.num_allow_users iff we break for loop */                  /* i < options.num_allow_users iff we break for loop */
                 if (i >= options.num_allow_users) {                  if (i >= options.num_allow_users) {
                         logit("User %.100s from %.100s not allowed because "                          logit("User %.100s from %.100s not allowed because "
Line 324  allowed_user(struct passwd * pw)
Line 309  allowed_user(struct passwd * pw)
 }  }
   
 void  void
 auth_info(Authctxt *authctxt, const char *fmt, ...)  auth_log(Authctxt *authctxt, int authenticated, const char *method,
       const char *info)
 {  {
         va_list ap;  
         int i;  
   
         free(authctxt->info);  
         authctxt->info = NULL;  
   
         va_start(ap, fmt);  
         i = vasprintf(&authctxt->info, fmt, ap);  
         va_end(ap);  
   
         if (i < 0 || authctxt->info == NULL)  
                 fatal("vasprintf failed");  
 }  
   
 void  
 auth_log(Authctxt *authctxt, int authenticated, int partial,  
     const char *method, const char *submethod)  
 {  
         struct ssh *ssh = active_state; /* XXX */  
         void (*authlog) (const char *fmt,...) = verbose;          void (*authlog) (const char *fmt,...) = verbose;
         const char *authmsg;          const char *authmsg;
   
Line 360  auth_log(Authctxt *authctxt, int authent
Line 327  auth_log(Authctxt *authctxt, int authent
   
         if (authctxt->postponed)          if (authctxt->postponed)
                 authmsg = "Postponed";                  authmsg = "Postponed";
         else if (partial)  
                 authmsg = "Partial";  
         else          else
                 authmsg = authenticated ? "Accepted" : "Failed";                  authmsg = authenticated ? "Accepted" : "Failed";
   
         authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",          authlog("%s %s for %s%.100s from %.200s port %d%s",
             authmsg,              authmsg,
             method,              method,
             submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,  
             authctxt->valid ? "" : "invalid user ",  
             authctxt->user,  
             ssh_remote_ipaddr(ssh),  
             ssh_remote_port(ssh),  
             authctxt->info != NULL ? ": " : "",  
             authctxt->info != NULL ? authctxt->info : "");  
         if (!authctxt->postponed)  
                 pfilter_notify(!authenticated);  
         free(authctxt->info);  
         authctxt->info = NULL;  
 }  
   
 void  
 auth_maxtries_exceeded(Authctxt *authctxt)  
 {  
         struct ssh *ssh = active_state; /* XXX */  
   
         error("maximum authentication attempts exceeded for "  
             "%s%.100s from %.200s port %d ssh2",  
             authctxt->valid ? "" : "invalid user ",              authctxt->valid ? "" : "invalid user ",
             authctxt->user,              authctxt->user,
             ssh_remote_ipaddr(ssh),              get_remote_ipaddr(),
             ssh_remote_port(ssh));              get_remote_port(),
         packet_disconnect("Too many authentication failures");              info);
         /* NOTREACHED */  
 }  }
   
 /*  /*
Line 402  auth_maxtries_exceeded(Authctxt *authctx
Line 346  auth_maxtries_exceeded(Authctxt *authctx
 int  int
 auth_root_allowed(const char *method)  auth_root_allowed(const char *method)
 {  {
         struct ssh *ssh = active_state; /* XXX */  
   
         switch (options.permit_root_login) {          switch (options.permit_root_login) {
         case PERMIT_YES:          case PERMIT_YES:
                 return 1;                  return 1;
         case PERMIT_NO_PASSWD:          case PERMIT_NO_PASSWD:
                 if (strcmp(method, "publickey") == 0 ||                  if (strcmp(method, "password") != 0)
                     strcmp(method, "hostbased") == 0 ||  
                     strcmp(method, "gssapi-with-mic") == 0)  
                         return 1;                          return 1;
                 break;                  break;
         case PERMIT_FORCED_ONLY:          case PERMIT_FORCED_ONLY:
Line 420  auth_root_allowed(const char *method)
Line 360  auth_root_allowed(const char *method)
                 }                  }
                 break;                  break;
         }          }
         logit("ROOT LOGIN REFUSED FROM %.200s port %d",          logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
             ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));  
         return 0;          return 0;
 }  }
   
Line 436  auth_root_allowed(const char *method)
Line 375  auth_root_allowed(const char *method)
 char *  char *
 expand_authorized_keys(const char *filename, struct passwd *pw)  expand_authorized_keys(const char *filename, struct passwd *pw)
 {  {
         char *file, ret[PATH_MAX];          char *file, ret[MAXPATHLEN];
         int i;          int i;
   
         file = percent_expand(filename, "h", pw->pw_dir,          file = percent_expand(filename, "h", pw->pw_dir,
Line 452  expand_authorized_keys(const char *filen
Line 391  expand_authorized_keys(const char *filen
         i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);          i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
         if (i < 0 || (size_t)i >= sizeof(ret))          if (i < 0 || (size_t)i >= sizeof(ret))
                 fatal("expand_authorized_keys: path too long");                  fatal("expand_authorized_keys: path too long");
         free(file);          xfree(file);
         return (xstrdup(ret));          return (xstrdup(ret));
 }  }
   
 char *  char *
 authorized_principals_file(struct passwd *pw)  authorized_principals_file(struct passwd *pw)
 {  {
         if (options.authorized_principals_file == NULL)          if (options.authorized_principals_file == NULL ||
               strcasecmp(options.authorized_principals_file, "none") == 0)
                 return NULL;                  return NULL;
         return expand_authorized_keys(options.authorized_principals_file, pw);          return expand_authorized_keys(options.authorized_principals_file, pw);
 }  }
Line 493  check_key_in_hostfiles(struct passwd *pw
Line 433  check_key_in_hostfiles(struct passwd *pw
                         load_hostkeys(hostkeys, host, user_hostfile);                          load_hostkeys(hostkeys, host, user_hostfile);
                         restore_uid();                          restore_uid();
                 }                  }
                 free(user_hostfile);                  xfree(user_hostfile);
         }          }
         host_status = check_key_in_hostkeys(hostkeys, key, &found);          host_status = check_key_in_hostkeys(hostkeys, key, &found);
         if (host_status == HOST_REVOKED)          if (host_status == HOST_REVOKED)
Line 510  check_key_in_hostfiles(struct passwd *pw
Line 450  check_key_in_hostfiles(struct passwd *pw
         return host_status;          return host_status;
 }  }
   
   
 /*  /*
  * Check a given path for security. This is defined as all components   * Check a given file for security. This is defined as all components
  * of the path to the file must be owned by either the owner of   * of the path to the file must be owned by either the owner of
  * of the file or root and no directories must be group or world writable.   * of the file or root and no directories must be group or world writable.
  *   *
  * XXX Should any specific check be done for sym links ?   * XXX Should any specific check be done for sym links ?
  *   *
  * Takes a file name, its stat information (preferably from fstat() to   * Takes an open file descriptor, the file name, a uid and and
  * avoid races), the uid of the expected owner, their home directory and an  
  * error buffer plus max size as arguments.   * error buffer plus max size as arguments.
  *   *
  * Returns 0 on success and -1 on failure   * Returns 0 on success and -1 on failure
  */   */
 int  static int
 auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,  secure_filename(FILE *f, const char *file, struct passwd *pw,
     uid_t uid, char *err, size_t errlen)      char *err, size_t errlen)
 {  {
         char buf[PATH_MAX], homedir[PATH_MAX];          uid_t uid = pw->pw_uid;
           char buf[MAXPATHLEN], homedir[MAXPATHLEN];
         char *cp;          char *cp;
         int comparehome = 0;          int comparehome = 0;
         struct stat st;          struct stat st;
   
         if (realpath(name, buf) == NULL) {          if (realpath(file, buf) == NULL) {
                 snprintf(err, errlen, "realpath %s failed: %s", name,                  snprintf(err, errlen, "realpath %s failed: %s", file,
                     strerror(errno));                      strerror(errno));
                 return -1;                  return -1;
         }          }
         if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)          if (realpath(pw->pw_dir, homedir) != NULL)
                 comparehome = 1;                  comparehome = 1;
   
         if (!S_ISREG(stp->st_mode)) {          /* check the open file to avoid races */
                 snprintf(err, errlen, "%s is not a regular file", buf);          if (fstat(fileno(f), &st) < 0 ||
                 return -1;              (st.st_uid != 0 && st.st_uid != uid) ||
         }              (st.st_mode & 022) != 0) {
         if ((stp->st_uid != 0 && stp->st_uid != uid) ||  
             (stp->st_mode & 022) != 0) {  
                 snprintf(err, errlen, "bad ownership or modes for file %s",                  snprintf(err, errlen, "bad ownership or modes for file %s",
                     buf);                      buf);
                 return -1;                  return -1;
Line 581  auth_secure_path(const char *name, struc
Line 520  auth_secure_path(const char *name, struc
         return 0;          return 0;
 }  }
   
 /*  
  * Version of secure_path() that accepts an open file descriptor to  
  * avoid races.  
  *  
  * Returns 0 on success and -1 on failure  
  */  
 static int  
 secure_filename(FILE *f, const char *file, struct passwd *pw,  
     char *err, size_t errlen)  
 {  
         struct stat st;  
   
         /* check the open file to avoid races */  
         if (fstat(fileno(f), &st) < 0) {  
                 snprintf(err, errlen, "cannot stat file %s: %s",  
                     file, strerror(errno));  
                 return -1;  
         }  
         return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);  
 }  
   
 static FILE *  static FILE *
 auth_openfile(const char *file, struct passwd *pw, int strict_modes,  auth_openfile(const char *file, struct passwd *pw, int strict_modes,
     int log_missing, const char *file_type)      int log_missing, const char *file_type)
Line 667  getpwnamallow(const char *user)
Line 585  getpwnamallow(const char *user)
         auth_session_t *as;          auth_session_t *as;
 #endif  #endif
 #endif  #endif
         struct ssh *ssh = active_state; /* XXX */  
         struct passwd *pw;          struct passwd *pw;
         struct connection_info *ci = get_connection_info(1, options.use_dns);          struct connection_info *ci = get_connection_info(1, options.use_dns);
   
Line 676  getpwnamallow(const char *user)
Line 593  getpwnamallow(const char *user)
   
         pw = getpwnam(user);          pw = getpwnam(user);
         if (pw == NULL) {          if (pw == NULL) {
                 pfilter_notify(1);                  logit("Invalid user %.100s from %.100s",
                 logit("Invalid user %.100s from %.100s port %d",                      user, get_remote_ipaddr());
                     user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));  
                 return (NULL);                  return (NULL);
         }          }
         if (!allowed_user(pw))          if (!allowed_user(pw))
Line 707  getpwnamallow(const char *user)
Line 623  getpwnamallow(const char *user)
 int  int
 auth_key_is_revoked(Key *key)  auth_key_is_revoked(Key *key)
 {  {
         char *fp = NULL;          char *key_fp;
         int r;  
   
         if (options.revoked_keys_file == NULL)          if (options.revoked_keys_file == NULL)
                 return 0;                  return 0;
         if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,  
             SSH_FP_DEFAULT)) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 error("%s: fingerprint key: %s", __func__, ssh_err(r));  
                 goto out;  
         }  
   
         r = sshkey_check_revoked(key, options.revoked_keys_file);          switch (key_in_file(key, options.revoked_keys_file, 0)) {
         switch (r) {  
         case 0:          case 0:
                 break; /* not revoked */                  /* key not revoked */
         case SSH_ERR_KEY_REVOKED:                  return 0;
                 error("Authentication key %s %s revoked by file %s",          case -1:
                     sshkey_type(key), fp, options.revoked_keys_file);                  /* Error opening revoked_keys_file: refuse all keys */
                 goto out;                  error("Revoked keys file is unreadable: refusing public key "
         default:                      "authentication");
                 error("Error checking authentication key %s %s in "                  return 1;
                     "revoked keys file %s: %s", sshkey_type(key), fp,          case 1:
                     options.revoked_keys_file, ssh_err(r));                  /* Key revoked */
                 goto out;                  key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
         }                  error("WARNING: authentication attempt with a revoked "
                       "%s key %s ", key_type(key), key_fp);
         /* Success */                  xfree(key_fp);
         r = 0;                  return 1;
           }
  out:          fatal("key_in_file returned junk");
         free(fp);  
         return r == 0 ? 0 : 1;  
 }  }
   
 void  void
Line 767  auth_debug_send(void)
Line 673  auth_debug_send(void)
         while (buffer_len(&auth_debug)) {          while (buffer_len(&auth_debug)) {
                 msg = buffer_get_string(&auth_debug, NULL);                  msg = buffer_get_string(&auth_debug, NULL);
                 packet_send_debug("%s", msg);                  packet_send_debug("%s", msg);
                 free(msg);                  xfree(msg);
         }          }
 }  }
   
Line 802  fakepw(void)
Line 708  fakepw(void)
   
         return (&fake);          return (&fake);
 }  }
 #endif  
   
 /*  
  * Returns the remote DNS hostname as a string. The returned string must not  
  * be freed. NB. this will usually trigger a DNS query the first time it is  
  * called.  
  * This function does additional checks on the hostname to mitigate some  
  * attacks on legacy rhosts-style authentication.  
  * XXX is RhostsRSAAuthentication vulnerable to these?  
  * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?)  
  */  
   
 static char *  
 remote_hostname(struct ssh *ssh)  
 {  
         struct sockaddr_storage from;  
         socklen_t fromlen;  
         struct addrinfo hints, *ai, *aitop;  
         char name[NI_MAXHOST], ntop2[NI_MAXHOST];  
         const char *ntop = ssh_remote_ipaddr(ssh);  
   
         /* Get IP address of client. */  
         fromlen = sizeof(from);  
         memset(&from, 0, sizeof(from));  
         if (getpeername(ssh_packet_get_connection_in(ssh),  
             (struct sockaddr *)&from, &fromlen) < 0) {  
                 debug("getpeername failed: %.100s", strerror(errno));  
                 return strdup(ntop);  
         }  
   
         debug3("Trying to reverse map address %.100s.", ntop);  
         /* Map the IP address to a host name. */  
         if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),  
             NULL, 0, NI_NAMEREQD) != 0) {  
                 /* Host name not found.  Use ip address. */  
                 return strdup(ntop);  
         }  
   
         /*  
          * if reverse lookup result looks like a numeric hostname,  
          * someone is trying to trick us by PTR record like following:  
          *      1.1.1.10.in-addr.arpa.  IN PTR  2.3.4.5  
          */  
         memset(&hints, 0, sizeof(hints));  
         hints.ai_socktype = SOCK_DGRAM; /*dummy*/  
         hints.ai_flags = AI_NUMERICHOST;  
         if (getaddrinfo(name, NULL, &hints, &ai) == 0) {  
                 logit("Nasty PTR record \"%s\" is set up for %s, ignoring",  
                     name, ntop);  
                 freeaddrinfo(ai);  
                 return strdup(ntop);  
         }  
   
         /* Names are stored in lowercase. */  
         lowercase(name);  
   
         /*  
          * Map it back to an IP address and check that the given  
          * address actually is an address of this host.  This is  
          * necessary because anyone with access to a name server can  
          * define arbitrary names for an IP address. Mapping from  
          * name to IP address can be trusted better (but can still be  
          * fooled if the intruder has access to the name server of  
          * the domain).  
          */  
         memset(&hints, 0, sizeof(hints));  
         hints.ai_family = from.ss_family;  
         hints.ai_socktype = SOCK_STREAM;  
         if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {  
                 logit("reverse mapping checking getaddrinfo for %.700s "  
                     "[%s] failed.", name, ntop);  
                 return strdup(ntop);  
         }  
         /* Look for the address from the list of addresses. */  
         for (ai = aitop; ai; ai = ai->ai_next) {  
                 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,  
                     sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&  
                     (strcmp(ntop, ntop2) == 0))  
                                 break;  
         }  
         freeaddrinfo(aitop);  
         /* If we reached the end of the list, the address was not there. */  
         if (ai == NULL) {  
                 /* Address not found for the host name. */  
                 logit("Address %.100s maps to %.600s, but this does not "  
                     "map back to the address.", ntop, name);  
                 return strdup(ntop);  
         }  
         return strdup(name);  
 }  
   
 /*  
  * Return the canonical name of the host in the other side of the current  
  * connection.  The host name is cached, so it is efficient to call this  
  * several times.  
  */  
   
 const char *  
 auth_get_canonical_hostname(struct ssh *ssh, int use_dns)  
 {  
         static char *dnsname;  
   
         if (!use_dns)  
                 return ssh_remote_ipaddr(ssh);  
         else if (dnsname != NULL)  
                 return dnsname;  
         else {  
                 dnsname = remote_hostname(ssh);  
                 return dnsname;  
         }  
 }  

Legend:
Removed from v.1.5.12.2  
changed lines
  Added in v.1.6

CVSweb <webmaster@jp.NetBSD.org>