$NetBSD: patch-aq,v 1.1 2000/03/20 02:25:37 itojun Exp $

--- newchannels.c.orig	Wed May 12 07:19:27 1999
+++ newchannels.c	Fri Dec 24 22:01:15 1999
@@ -274,7 +274,7 @@
 #include "authfd.h"
 #include "emulate.h"
 #include "servconf.h"
-#ifdef LIBWRAP
+#if defined(LIBWRAP) && defined(LIBWRAP_FWD)
 #include <tcpd.h>
 #include <syslog.h>
 #ifdef NEED_SYS_SYSLOG_H
@@ -922,6 +922,7 @@
           /* This is our fake X11 server socket. */
           if (FD_ISSET(ch->sock, readset))
             {
+              int on = 1;
               debug("X11 connection requested.");
               addrlen = sizeof(addr);
               newsock = accept(ch->sock, &addr, &addrlen);
@@ -930,11 +931,12 @@
                   error("accept: %.100s", strerror(errno));
                   break;
                 }
+              setsockopt(newsock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
               remote_hostname = get_remote_hostname(newsock);
               snprintf(buf, sizeof(buf), "X11 connection from %.200s port %d",
                       remote_hostname, get_peer_port(newsock));
               xfree(remote_hostname);
-#ifdef LIBWRAP
+#if defined(LIBWRAP) && defined(LIBWRAP_FWD)
               {
                 struct request_info req;
                 struct servent *serv;
@@ -986,7 +988,7 @@
                        ch->listening_port, remote_hostname,
                        get_peer_port(newsock));
               xfree(remote_hostname);
-#ifdef LIBWRAP
+#if defined(LIBWRAP) && defined(LIBWRAP_FWD)
               {
                 struct request_info req;
                 struct servent *serv;
@@ -1405,13 +1407,29 @@
                                       int host_port, int gatewayports)
 {
   int ch, sock;
-  struct sockaddr_in sin;
+  struct addrinfo hints, *ai, *aitop;
+  char ntop[ADDRSTRLEN], strport[PORTSTRLEN];
 
   if (strlen(host) > sizeof(channels[0].path) - 1)
     packet_disconnect("Forward host name too long.");
   
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = IPv4or6;
+  hints.ai_flags = gatewayports ? AI_PASSIVE : 0;
+  hints.ai_socktype = SOCK_STREAM;
+  sprintf(strport, "%d", port);
+  if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
+    packet_disconnect("getaddrinfo: fatal error");
+
+  for (ai = aitop; ai; ai = ai->ai_next)
+    {
+
+  getnameinfo(ai->ai_addr, ai->ai_addrlen,
+	      ntop, sizeof(ntop), strport, sizeof(strport),
+	      NI_NUMERICHOST|NI_NUMERICSERV);
+
   /* Create a port to listen for the host. */
-  sock = socket(AF_INET, SOCK_STREAM, 0);
+  sock = socket(ai->ai_family, SOCK_STREAM, 0);
   if (sock < 0)
     packet_disconnect("socket: %.100s", strerror(errno));
 
@@ -1421,21 +1439,10 @@
   (void)fcntl(sock, F_SETFL, O_NDELAY);
 #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
 
-  /* Initialize socket address. */
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_family = AF_INET;
-  if (gatewayports)
-    sin.sin_addr.s_addr = INADDR_ANY;
-  else
-#ifdef BROKEN_INET_ADDR
-    sin.sin_addr.s_addr = inet_network("127.0.0.1");
-#else /* BROKEN_INET_ADDR */
-    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
-#endif /* BROKEN_INET_ADDR */
-  sin.sin_port = htons(port);
-  
+  debug("Listening on %s port %s.", ntop, strport);
+
   /* Bind the socket to the address. */
-  if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+  if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0)
     packet_disconnect("bind: %.100s", strerror(errno));
       
   /* Start listening for connections on the socket. */
@@ -1448,6 +1455,9 @@
   strcpy(channels[ch].path, host); /* note: host name stored here */
   channels[ch].host_port = host_port; /* port on host to connect to */
   channels[ch].listening_port = port; /* port being listened */
+
+  } /* for (ai = aitop; ai; ai = ai->ai_next) */
+  freeaddrinfo(aitop);
 }  
 
 /* Initiate forwarding of connections to port "port" on remote host through
@@ -1636,9 +1646,10 @@
 void channel_input_port_open(void)
 {
   int remote_channel, sock, newch, host_port, i;
-  struct sockaddr_in sin;
   char *host, *originator_string;
-  struct hostent *hp;
+  struct addrinfo hints, *ai, *aitop;
+  char ntop[ADDRSTRLEN], strport[PORTSTRLEN];
+  int gaierr;
 
   /* Get remote channel number. */
   remote_channel = packet_get_int();
@@ -1678,36 +1689,15 @@
         }
     }
   
-  memset(&sin, 0, sizeof(sin));
-#ifdef BROKEN_INET_ADDR
-  sin.sin_addr.s_addr = inet_network(host);
-#else /* BROKEN_INET_ADDR */
-  sin.sin_addr.s_addr = inet_addr(host);
-#endif /* BROKEN_INET_ADDR */
-  if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = IPv4or6;
+  hints.ai_socktype = SOCK_STREAM;
+  sprintf(strport, "%d", host_port);
+  if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
     {
-      /* It was a valid numeric host address. */
-      sin.sin_family = AF_INET;
-    }
-  else
-    {
-      /* Look up the host address from the name servers. */
-      hp = gethostbyname(host);
-      if (!hp)
-        {
-          error("%.100s: unknown host.", host);
-          goto fail;
-        }
-      if (!hp->h_addr_list[0])
-        {
-          error("%.100s: host has no IP address.", host);
-          goto fail;
-        }
-      sin.sin_family = hp->h_addrtype;
-      memcpy(&sin.sin_addr, hp->h_addr_list[0], 
-             sizeof(sin.sin_addr));
+      error("%.100s: unknown host (%s)", host, gai_strerror(gaierr));
+      goto fail;
     }
-  sin.sin_port = htons(host_port);
   
 #ifdef F_SECURE_COMMERCIAL
 
@@ -1744,8 +1734,15 @@
 
 #endif /* F_SECURE_COMMERCIAL */
 
+  for (ai = aitop; ai; ai = ai->ai_next)
+    {
+
+  getnameinfo(ai->ai_addr, ai->ai_addrlen,
+	      ntop, sizeof(ntop), strport, sizeof(strport),
+	      NI_NUMERICHOST|NI_NUMERICSERV);
+
   /* Create the socket. */
-  sock = socket(sin.sin_family, SOCK_STREAM, 0);
+  sock = socket(ai->ai_family, SOCK_STREAM, 0);
   if (sock < 0)
     {
       error("socket: %.100s", strerror(errno));
@@ -1753,15 +1750,25 @@
     }
 
   /* Connect to the host/port. */
-  if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+  if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0)
     {
-      error("connect %.100s:%d: %.100s", host, host_port,
-            strerror(errno));
+      debug("connect %.100s port %s: %.100s", ntop, strport, strerror(errno));
       close(sock);
+      continue;	/* fail -- try next */	
+    }
+  break; /* success */
+
+  } /* for (ai = aitop; ai; ai = ai->ai_next) */
+  freeaddrinfo(aitop);
+
+  if (!ai)
+    {
+      error("connect %.100s:%d: failed.", host, host_port);
       goto fail;
     }
 
   /* Successful connection. */
+  debug("Connecting to %.200s [%.100s] port %s.", host, ntop, strport);
 
 #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
   (void)fcntl(sock, F_SETFL, O_NONBLOCK);
@@ -1803,7 +1810,10 @@
 {
   extern ServerOptions options;
   int display_number, port, sock;
-  struct sockaddr_in sin;
+  struct addrinfo hints, *ai, *aitop;
+  char strport[PORTSTRLEN];
+#define	NUM_SOCKS	10
+  int gaierr, n, nn, num_socks = 0, socks[NUM_SOCKS];
   char buf[512];
 #ifdef HAVE_GETHOSTNAME
   char hostname[257];
@@ -1817,12 +1827,21 @@
   for (display_number = options.x11_display_offset; display_number < MAX_DISPLAYS; display_number++)
     {
       port = 6000 + display_number;
-      memset(&sin, 0, sizeof(sin));
-      sin.sin_family = AF_INET;
-      sin.sin_addr.s_addr = INADDR_ANY;
-      sin.sin_port = htons(port);
+      memset(&hints, 0, sizeof(hints));
+      hints.ai_family = IPv4or6;
+      hints.ai_flags = AI_PASSIVE;
+      hints.ai_socktype = SOCK_STREAM;
+      sprintf(strport, "%d", port);
+      if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0)
+	{
+	  error("getaddrinfo: %.100s", gai_strerror(gaierr));
+	  return NULL;
+	}
+
+      for (ai = aitop; ai; ai = ai->ai_next)
+	{
       
-      sock = socket(AF_INET, SOCK_STREAM, 0);
+      sock = socket(ai->ai_family, SOCK_STREAM, 0);
       if (sock < 0)
         {
           error("socket: %.100s", strerror(errno));
@@ -1835,13 +1854,26 @@
       (void)fcntl(sock, F_SETFL, O_NDELAY);
 #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
       
-      if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+      if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0)
         {
           debug("bind port %d: %.100s", port, strerror(errno));
           shutdown(sock, 2);
           close(sock);
-          continue;
+	  for (n = 0; n < num_socks; n++)
+	    {
+	      shutdown(socks[n], 2);
+	      close(socks[n]);
+	    }
+	  num_socks = 0;
+	  break;
         }
+
+      socks[num_socks++] = sock;
+      if (num_socks == NUM_SOCKS)
+	break;
+      } /* for (ai = aitop; ai; ai = ai->ai_next) */
+
+      if (num_socks > 0)
       break;
     }
   if (display_number >= MAX_DISPLAYS)
@@ -1851,13 +1883,22 @@
     }
 
   /* Start listening for connections on the socket. */
+  for (n = 0; n < num_socks; n++)
+    {
+  sock = socks[n];
   if (listen(sock, 5) < 0)
     {
       error("listen: %.100s", strerror(errno));
       shutdown(sock, 2);
       close(sock);
+      for (nn = 0; nn < n; nn++)
+	{
+	  shutdown(socks[nn], 2);
+	  close(socks[nn]);
+	}
       return NULL;
     }
+  } /* for (n = 0; n < num_socks; n++) */
 
   /* Set up a suitable value for the DISPLAY variable. */
 #ifdef NONSTANDARD_IP_ADDRESS_X11_KLUDGE
@@ -1868,10 +1909,11 @@
   if (gethostname(hostname, sizeof(hostname)) < 0)
     fatal("gethostname: %.100s", strerror(errno));
   {
-    struct hostent *hp;
-    struct in_addr addr;
-    hp = gethostbyname(hostname);
-    if (hp == NULL || !hp->h_addr_list[0])
+    struct addrinfo hints, *ai;
+    char ntop[ADDRSTRLEN];
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = IPv4or6;
+    if (getaddrinfo(hostname, NULL, &hints, &ai) != 0 || !ai)
       {
         error("Could not get server IP address for %.200s.", hostname);
         packet_send_debug("Could not get server IP address for %.200s.", 
@@ -1880,9 +1922,10 @@
         close(sock);
         return NULL;
       }
-    memcpy(&addr, hp->h_addr_list[0], sizeof(addr));
+    getnameinfo(ai->ai_addr, ai->ai_addrlen,
+		ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST);
     snprintf(buf, sizeof(buf),
-             "%.100s:%d.%d", inet_ntoa(addr), display_number, 
+             "%.100s:%d.%d", ntop, display_number, 
              screen_number);
   }
 #else /* NONSTANDARD_IP_ADDRESS_X11_KLUDGE */
@@ -1900,8 +1943,12 @@
 #endif /* NONSTANDARD_IP_ADDRESS_X11_KLUDGE */
             
   /* Allocate a channel for the socket. */
+  for (n = 0; n < num_socks; n++)
+    {
+  sock = socks[n];
   (void)channel_allocate(SSH_CHANNEL_X11_LISTENER, sock,
                          xstrdup("X11 inet listener"));
+  } /* for (n = 0; n < num_socks; n++) */
 
   /* Return a suitable value for the DISPLAY environment variable. */
   return xstrdup(buf);
@@ -1916,9 +1963,10 @@
   int remote_channel, display_number, sock, newch;
   const char *display;
   struct sockaddr_un ssun;
-  struct sockaddr_in sin;
   char buf[255], *cp, *remote_host;
-  struct hostent *hp;
+  struct addrinfo hints, *ai, *aitop;
+  char strport[PORTSTRLEN];
+  int gaierr;
 
   /* Get remote channel number. */
   remote_channel = packet_get_int();
@@ -2058,59 +2106,54 @@
       goto fail;
     }
   
-  /* Try to parse the host name as a numeric IP address. */
-  memset(&sin, 0, sizeof(sin));
-#ifdef BROKEN_INET_ADDR
-  sin.sin_addr.s_addr = inet_network(buf);
-#else /* BROKEN_INET_ADDR */
-  sin.sin_addr.s_addr = inet_addr(buf);
-#endif /* BROKEN_INET_ADDR */
-  if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff)
+  /* Look up the host address */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = IPv4or6;
+  hints.ai_socktype = SOCK_STREAM;
+  sprintf(strport, "%d", 6000 + display_number);
+  if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0)
     {
-      /* It was a valid numeric host address. */
-      sin.sin_family = AF_INET;
+      error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr));
+      goto fail;
     }
-  else
+
+  for (ai = aitop; ai; ai = ai->ai_next)
     {
-      /* Not a numeric IP address. */
-      /* Look up the host address from the name servers. */
-      hp = gethostbyname(buf);
-      if (!hp)
-        {
-          error("%.100s: unknown host.", buf);
-          goto fail;
-        }
-      if (!hp->h_addr_list[0])
-        {
-          error("%.100s: host has no IP address.", buf);
-          goto fail;
-        }
-      sin.sin_family = hp->h_addrtype;
-      memcpy(&sin.sin_addr, hp->h_addr_list[0], 
-             sizeof(sin.sin_addr));
-    }
-  /* Set port number. */
-  sin.sin_port = htons(6000 + display_number);
 
   /* Create a socket. */
-  sock = socket(sin.sin_family, SOCK_STREAM, 0);
+  sock = socket(ai->ai_family, SOCK_STREAM, 0);
   if (sock < 0)
     {
-      error("socket: %.100s", strerror(errno));
-      goto fail;
+      debug("socket: %.100s", strerror(errno));
+      continue;
     }
   /* Connect it to the display. */
-  if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+  if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0)
     {
-      error("connect %.100s:%d: %.100s", buf, 6000 + display_number, 
+      debug("connect %.100s:%d: %.100s", buf, 6000 + display_number, 
             strerror(errno));
       close(sock);
+      continue;
+    }
+  /* Success */
+  break;
+
+  } /* (ai = aitop, ai; ai = ai->ai_next) */
+  freeaddrinfo(aitop);
+  if (!ai)
+    {
+      error("connect %.100s:%d: %.100s", buf, 6000 + display_number, 
+	    strerror(errno));
       goto fail;
     }
 
  success:
   /* We have successfully obtained a connection to the real X display. */
-
+  {
+    int on = 1;
+    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+  }
+  
 #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
       (void)fcntl(sock, F_SETFL, O_NONBLOCK);
 #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
@@ -2412,6 +2455,10 @@
      ssh-agent connections on your system */
   old_umask = umask(S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
   
+  /* Make sure the socket doesn't already exist, left over from a system
+     crash perhaps. */
+  unlink(channel_forwarded_auth_socket_name);
+
   if (bind(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0)
     packet_disconnect("Agent socket bind failed: %.100s", strerror(errno));