]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/uxnet.c
Merge tag '0.66'
[PuTTY.git] / unix / uxnet.c
index 3ceb985854f177e940ec58ce683c64dca2675b96..760d0a5719b036596feb896a1b760683dc7563a1 100644 (file)
@@ -16,6 +16,8 @@
 #include <netinet/tcp.h>
 #include <netdb.h>
 #include <sys/un.h>
+#include <pwd.h>
+#include <grp.h>
 
 #define DEFINE_PLUG_METHOD_MACROS
 #include "putty.h"
@@ -126,9 +128,12 @@ struct SockAddr_tag {
      (addr)->superfamily == UNIX ? AF_UNIX : \
      (step).ai ? (step).ai->ai_family : AF_INET)
 #else
+/* Here we gratuitously reference 'step' to avoid gcc warnings about
+ * 'set but not used' when compiling -DNO_IPV6 */
 #define SOCKADDR_FAMILY(addr, step) \
     ((addr)->superfamily == UNRESOLVED ? AF_UNSPEC : \
-     (addr)->superfamily == UNIX ? AF_UNIX : AF_INET)
+     (addr)->superfamily == UNIX ? AF_UNIX : \
+     (step).curraddr ? AF_INET : AF_INET)
 #endif
 
 /*
@@ -221,7 +226,11 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, int address_famil
     hints.ai_addr = NULL;
     hints.ai_canonname = NULL;
     hints.ai_next = NULL;
-    err = getaddrinfo(host, NULL, &hints, &ret->ais);
+    {
+        char *trimmed_host = host_strduptrim(host); /* strip [] on literals */
+        err = getaddrinfo(trimmed_host, NULL, &hints, &ret->ais);
+        sfree(trimmed_host);
+    }
     if (err != 0) {
        ret->error = gai_strerror(err);
        return ret;
@@ -337,6 +346,15 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen)
     }
 }
 
+int sk_addr_needs_port(SockAddr addr)
+{
+    if (addr->superfamily == UNRESOLVED || addr->superfamily == UNIX) {
+        return FALSE;
+    } else {
+        return TRUE;
+    }
+}
+
 int sk_hostname_is_local(const char *name)
 {
     return !strcmp(name, "localhost") ||
@@ -469,6 +487,7 @@ static int sk_tcp_write(Socket s, const char *data, int len);
 static int sk_tcp_write_oob(Socket s, const char *data, int len);
 static void sk_tcp_write_eof(Socket s);
 static void sk_tcp_set_frozen(Socket s, int is_frozen);
+static char *sk_tcp_peer_info(Socket s);
 static const char *sk_tcp_socket_error(Socket s);
 
 static struct socket_function_table tcp_fn_table = {
@@ -479,7 +498,8 @@ static struct socket_function_table tcp_fn_table = {
     sk_tcp_write_eof,
     sk_tcp_flush,
     sk_tcp_set_frozen,
-    sk_tcp_socket_error
+    sk_tcp_socket_error,
+    sk_tcp_peer_info,
 };
 
 static Socket sk_tcp_accept(accept_ctx_t ctx, Plug plug)
@@ -760,11 +780,12 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     return (Socket) ret;
 }
 
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int orig_address_family)
+Socket sk_newlistener(const char *srcaddr, int port, Plug plug,
+                      int local_host_only, int orig_address_family)
 {
     int s;
 #ifndef NO_IPV6
-    struct addrinfo hints, *ai;
+    struct addrinfo hints, *ai = NULL;
     char portstr[6];
 #endif
     union sockaddr_union u;
@@ -859,7 +880,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
         hints.ai_next = NULL;
        assert(port >= 0 && port <= 99999);
         sprintf(portstr, "%d", port);
-        retcode = getaddrinfo(srcaddr, portstr, &hints, &ai);
+        {
+            char *trimmed_addr = host_strduptrim(srcaddr);
+            retcode = getaddrinfo(trimmed_addr, portstr, &hints, &ai);
+            sfree(trimmed_addr);
+        }
        if (retcode == 0) {
            addr = (union sockaddr_union *)ai->ai_addr;
            addrlen = ai->ai_addrlen;
@@ -906,6 +931,12 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
     }
 
     retcode = bind(s, &addr->sa, addrlen);
+
+#ifndef NO_IPV6
+    if (ai)
+        freeaddrinfo(ai);
+#endif
+
     if (retcode < 0) {
         close(s);
        ret->error = strerror(errno);
@@ -1393,6 +1424,51 @@ static void sk_tcp_set_frozen(Socket sock, int is_frozen)
     uxsel_tell(s);
 }
 
+static char *sk_tcp_peer_info(Socket sock)
+{
+    Actual_Socket s = (Actual_Socket) sock;
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(addr);
+    char buf[INET6_ADDRSTRLEN];
+
+    if (getpeername(s->s, (struct sockaddr *)&addr, &addrlen) < 0)
+        return NULL;
+    if (addr.ss_family == AF_INET) {
+        return dupprintf
+            ("%s:%d",
+             inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr),
+             (int)ntohs(((struct sockaddr_in *)&addr)->sin_port));
+#ifndef NO_IPV6
+    } else if (addr.ss_family == AF_INET6) {
+        return dupprintf
+            ("[%s]:%d",
+             inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
+                       buf, sizeof(buf)),
+             (int)ntohs(((struct sockaddr_in6 *)&addr)->sin6_port));
+#endif
+    } else if (addr.ss_family == AF_UNIX) {
+        /*
+         * For Unix sockets, the source address is unlikely to be
+         * helpful. Instead, we try SO_PEERCRED and try to get the
+         * source pid.
+         */
+        int pid, uid, gid;
+        if (so_peercred(s->s, &pid, &uid, &gid)) {
+            char uidbuf[64], gidbuf[64];
+            sprintf(uidbuf, "%d", uid);
+            sprintf(gidbuf, "%d", gid);
+            struct passwd *pw = getpwuid(uid);
+            struct group *gr = getgrgid(gid);
+            return dupprintf("pid %d (%s:%s)", pid,
+                             pw ? pw->pw_name : uidbuf,
+                             gr ? gr->gr_name : gidbuf);
+        }
+        return NULL;
+    } else {
+        return NULL;
+    }
+}
+
 static void uxsel_tell(Actual_Socket s)
 {
     int rwx = 0;