]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/uxnet.c
Merge branch 'pre-0.67'
[PuTTY.git] / unix / uxnet.c
index c3002e4388ebc8bd50d58da45db53fbd599bf412..730f1fa7d5024d3e0dd6d0e28a064005cd045ac4 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"
  * Access to sockaddr types without breaking C strict aliasing rules.
  */
 union sockaddr_union {
-#ifdef NO_IPV6
-    struct sockaddr_in storage;
-#else
     struct sockaddr_storage storage;
-    struct sockaddr_in6 sin6;
-#endif
     struct sockaddr sa;
     struct sockaddr_in sin;
+#ifndef NO_IPV6
+    struct sockaddr_in6 sin6;
+#endif
     struct sockaddr_un su;
 };
 
@@ -485,6 +485,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 = {
@@ -495,7 +496,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)
@@ -776,11 +778,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;
@@ -926,6 +929,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);
@@ -1413,6 +1422,52 @@ 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;
+    union sockaddr_union addr;
+    socklen_t addrlen = sizeof(addr);
+#ifndef NO_IPV6
+    char buf[INET6_ADDRSTRLEN];
+#endif
+
+    if (getpeername(s->s, &addr.sa, &addrlen) < 0)
+        return NULL;
+    if (addr.storage.ss_family == AF_INET) {
+        return dupprintf
+            ("%s:%d",
+             inet_ntoa(addr.sin.sin_addr),
+             (int)ntohs(addr.sin.sin_port));
+#ifndef NO_IPV6
+    } else if (addr.storage.ss_family == AF_INET6) {
+        return dupprintf
+            ("[%s]:%d",
+             inet_ntop(AF_INET6, &addr.sin6.sin6_addr, buf, sizeof(buf)),
+             (int)ntohs(addr.sin6.sin6_port));
+#endif
+    } else if (addr.storage.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;