]> sourceware.org Git - newlib-cygwin.git/commitdiff
* fhandler.h (class fhandler_socket): Add members and methods to
authorEgor Duda <deo@logos-m.ru>
Mon, 9 Apr 2001 07:21:32 +0000 (07:21 +0000)
committerEgor Duda <deo@logos-m.ru>
Mon, 9 Apr 2001 07:21:32 +0000 (07:21 +0000)
support secure connections on AF_UNIX sockets.
* fhandler_socket.cc (fhandler_socket::set_connect_secret): New method.
(fhandler_socket::get_connect_secret): Ditto.
(fhandler_socket::create_secret_event): Ditto.
(fhandler_socket::close_secret_event): Ditto.
(fhandler_socket::check_peer_secret_event): Ditto.
(fhandler_socket::fixup_after_fork): Duplicate secret event to child.
(fhandler_socket::dup): Copy address family.
(fhandler_socket::close): Close secret event.
* net.cc (get_inet_addr): Read secret cookie.
(cygwin_connect): Check if peer knows secret cookie value.
(cygwin_accept): Ditto. Copy address family to newly created socket.
(cygwin_bind): Generate and write secret cookie.
(wsock_init): Initialize random number generator.

winsup/cygwin/ChangeLog
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/net.cc

index 547fe23fe5a416343cedd1c26ff321937506e2d7..6bed3b02c35c4fc00c86cc02f48d1d560028656c 100644 (file)
@@ -1,3 +1,21 @@
+2001-04-09  Egor Duda  <deo@logos-m.ru>
+
+       * fhandler.h (class fhandler_socket): Add members and methods to
+       support secure connections on AF_UNIX sockets.
+       * fhandler_socket.cc (fhandler_socket::set_connect_secret): New method.
+       (fhandler_socket::get_connect_secret): Ditto.
+       (fhandler_socket::create_secret_event): Ditto.
+       (fhandler_socket::close_secret_event): Ditto.
+       (fhandler_socket::check_peer_secret_event): Ditto.
+       (fhandler_socket::fixup_after_fork): Duplicate secret event to child.
+       (fhandler_socket::dup): Copy address family.
+       (fhandler_socket::close): Close secret event.
+       * net.cc (get_inet_addr): Read secret cookie.
+       (cygwin_connect): Check if peer knows secret cookie value.
+       (cygwin_accept): Ditto. Copy address family to newly created socket.
+       (cygwin_bind): Generate and write secret cookie.
+       (wsock_init): Initialize random number generator.
+
 Sun Apr  8 20:40:58 2001  Christopher Faylor <cgf@cygnus.com>
 
        * Makefile.in: Put -lgcc last in list of libraries, since stdc++
index 6a8d11a4cd4024d081acac9bf590c8e3e7134d5d..32ccacc7591788a42e754eac098c65707e530ac7 100644 (file)
@@ -342,6 +342,8 @@ class fhandler_socket: public fhandler_base
 {
 private:
   int addr_family;
+  int connect_secret [4];
+  HANDLE secret_event;
   struct _WSAPROTOCOL_INFOA *prot_info_ptr;
 
 public:
@@ -368,6 +370,11 @@ public:
   int ready_for_read (int fd, DWORD howlong, int ignra);
   int get_addr_family () {return addr_family;}
   void set_addr_family (int af) {addr_family = af;}
+  void set_connect_secret ();
+  void get_connect_secret (char*);
+  HANDLE create_secret_event (int *secret = NULL);
+  int check_peer_secret_event (struct sockaddr_in *peer, int *secret = NULL);
+  void close_secret_event ();
 };
 
 class fhandler_pipe: public fhandler_base
index a52d2851af2c2548ba4fc7843447fe3ee72bba4b..3b3ba7bacf029cc8aff08b6e0f92775ea782f3a0 100644 (file)
@@ -16,6 +16,7 @@
 #include <errno.h>
 #include <sys/socket.h>
 
+#include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 #define USE_SYS_TYPES_FD_SET
@@ -26,6 +27,8 @@
 #include "dtable.h"
 #include "sigproc.h"
 
+#define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"
+
 /**********************************************************************/
 /* fhandler_socket */
 
@@ -44,6 +47,87 @@ fhandler_socket::~fhandler_socket ()
     cfree (prot_info_ptr);
 }
 
+void
+fhandler_socket::set_connect_secret ()
+{
+  for (int i = 0; i < 4; i++)
+    connect_secret [i] = random ();
+}
+
+void
+fhandler_socket::get_connect_secret (char* buf)
+{
+  __small_sprintf (buf, "%08x-%08x-%08x-%08x",
+                  connect_secret [0], connect_secret [1],
+                  connect_secret [2], connect_secret [3]);
+}
+
+HANDLE
+fhandler_socket::create_secret_event (int* secret)
+{
+  char buf [128];
+  int* secret_ptr = (secret ? : connect_secret);
+  struct sockaddr_in sin;
+  int sin_len = sizeof (sin);
+
+  if (getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))
+    {
+      debug_printf ("error getting local socket name (%d)", WSAGetLastError ());
+      return NULL;
+    }
+
+  __small_sprintf (buf, SECRET_EVENT_NAME, sin.sin_port,
+                  secret_ptr [0], secret_ptr [1],
+                  secret_ptr [2], secret_ptr [3]);
+  secret_event = CreateEvent ( NULL, FALSE, FALSE, buf);
+  if (!secret_event && GetLastError () == ERROR_ALREADY_EXISTS)
+    secret_event = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
+
+  if (secret_event)
+    {
+      ProtectHandle (secret_event);
+      SetEvent (secret_event);
+    }
+
+  return secret_event;
+}
+
+void
+fhandler_socket::close_secret_event ()
+{
+  if (secret_event)
+    ForceCloseHandle (secret_event);
+  secret_event = NULL;
+}
+
+int
+fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
+{
+  char buf [128];
+  HANDLE ev;
+  int* secret_ptr = (secret ? : connect_secret);
+
+  __small_sprintf (buf, SECRET_EVENT_NAME, peer->sin_port,
+                  secret_ptr [0], secret_ptr [1],
+                  secret_ptr [2], secret_ptr [3]);
+  ev = CreateEvent (NULL, FALSE, FALSE, buf);
+  if (!ev && GetLastError () == ERROR_ALREADY_EXISTS)
+    {
+      debug_printf ("%s event already exist");
+      ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);
+    }
+
+  if (ev)
+    {
+      DWORD rc = WaitForSingleObject (ev, 10000);
+      debug_printf ("WFSO rc=%d", rc);
+      CloseHandle (ev);
+      return (rc == WAIT_OBJECT_0 ? 1 : 0 );
+    }
+  else
+    return 0;
+}
+
 void
 fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
 {
@@ -93,12 +177,15 @@ fhandler_socket::fixup_after_fork (HANDLE parent)
       fhandler_base::fixup_after_fork (parent);
       debug_printf ("Without Winsock 2.0");
     }
+  if (secret_event)
+    fork_fixup (parent, secret_event, "secret_event");
 }
 
 int
 fhandler_socket::dup (fhandler_base *child)
 {
   fhandler_socket *fhs = (fhandler_socket *) child;
+  fhs->addr_family = addr_family;
   fhs->set_io_handle (get_io_handle ());
   fhs->fixup_before_fork_exec (GetCurrentProcessId ());
   if (ws2_32_handle)
@@ -148,6 +235,8 @@ fhandler_socket::close ()
       res = -1;
     }
 
+  close_secret_event ();
+
   return res;
 }
 
index 5f10a68b04e26452174115a5434d0a3e6f3262d6..e089cd642155b2c50eec6277420592060e69165f 100644 (file)
@@ -18,6 +18,7 @@ details. */
 #include <sys/un.h>
 #include <iphlpapi.h>
 
+#include <stdlib.h>
 #include <unistd.h>
 #include <netdb.h>
 #include <fcntl.h>
@@ -377,8 +378,11 @@ done:
 /* cygwin internal: map sockaddr into internet domain address */
 
 static int get_inet_addr (const struct sockaddr *in, int inlen,
-                          struct sockaddr_in *out, int *outlen)
+                          struct sockaddr_in *out, int *outlen, int* secret = 0)
 {
+  int secret_buf [4];
+  int* secret_ptr = (secret ? : secret_buf);
+
   if (in->sa_family == AF_INET)
     {
       *out = * (sockaddr_in *)in;
@@ -392,13 +396,15 @@ static int get_inet_addr (const struct sockaddr *in, int inlen,
        return 0;
 
       int ret = 0;
-      char buf[32];
+      char buf[128];
       memset (buf, 0, sizeof buf);
       if (read (fd, buf, sizeof buf) != -1)
         {
          sockaddr_in sin;
          sin.sin_family = AF_INET;
-         sscanf (buf + strlen (SOCKET_COOKIE), "%hu", &sin.sin_port);
+         sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
+                 &sin.sin_port,
+                 secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);
          sin.sin_port = htons (sin.sin_port);
          sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
          *out = sin;
@@ -615,11 +621,13 @@ cygwin_connect (int fd,
                  int namelen)
 {
   int res;
+  BOOL secret_check_failed = FALSE;
   fhandler_socket *sock = get (fd);
   sockaddr_in sin;
+  int secret [4];
   sigframe thisframe (mainthread);
 
-  if (get_inet_addr (name, namelen, &sin, &namelen) == 0)
+  if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0)
     return -1;
 
   if (!sock)
@@ -638,6 +646,34 @@ cygwin_connect (int fd,
 
          set_winsock_errno ();
         }
+      if (sock->get_addr_family () == AF_UNIX)
+        {
+          if (!res || errno == EINPROGRESS)
+            {
+              if (!sock->create_secret_event (secret))
+                {   
+                 secret_check_failed = TRUE;
+               }
+            }
+
+          if (!secret_check_failed && !res)
+            {
+             if (!sock->check_peer_secret_event (&sin, secret))
+               {
+                 debug_printf ( "accept from unauthorized server" );
+                 secret_check_failed = TRUE;
+               }
+           }
+
+          if (secret_check_failed)
+            {
+             sock->close_secret_event ();
+              if (res)
+                closesocket (res);
+             set_errno (ECONNREFUSED);
+             res = -1;
+            }
+        }
     }
   return res;
 }
@@ -733,6 +769,7 @@ extern "C" int
 cygwin_accept (int fd, struct sockaddr *peer, int *len)
 {
   int res = -1;
+  BOOL secret_check_failed = FALSE;
   sigframe thisframe (mainthread);
 
   fhandler_socket *sock = get (fd);
@@ -747,6 +784,38 @@ cygwin_accept (int fd, struct sockaddr *peer, int *len)
 
       res = accept (sock->get_socket (), peer, len);  // can't use a blocking call inside a lock
 
+      if (sock->get_addr_family () == AF_UNIX)
+        {
+          if (((SOCKET) res != (SOCKET) INVALID_SOCKET ||
+               WSAGetLastError () == WSAEWOULDBLOCK))
+            {
+              if (!sock->create_secret_event ())
+               {
+                 secret_check_failed = TRUE;
+                }
+            }
+
+          if (!secret_check_failed &&
+              (SOCKET) res != (SOCKET) INVALID_SOCKET)
+            {
+             if (!sock->check_peer_secret_event ((struct sockaddr_in*) peer))
+               {
+                 debug_printf ("connect from unauthorized client");
+                 secret_check_failed = TRUE;
+                }
+            }
+
+          if (secret_check_failed)
+            {
+              sock->close_secret_event ();
+              if ((SOCKET) res != (SOCKET) INVALID_SOCKET)
+                closesocket (res);
+             set_errno (ECONNABORTED);
+              res = -1;
+              goto done;
+            }
+        }
+
       SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
 
       int res_fd = fdtab.find_unused_handle ();
@@ -754,19 +823,21 @@ cygwin_accept (int fd, struct sockaddr *peer, int *len)
        {
          /* FIXME: what is correct errno? */
          set_errno (EMFILE);
-         goto done;
+         goto lock_done;
        }
       if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
        set_winsock_errno ();
       else
        {
-         fdsock (res_fd, sock->get_name (), res);
+         fhandler_socket* res_fh = fdsock (res_fd, sock->get_name (), res);
+         res_fh->set_addr_family (sock->get_addr_family ());
          res = res_fd;
        }
     }
+lock_done:
+  ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
 done:
   syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
-  ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
   return res;
 }
 
@@ -822,8 +893,11 @@ cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen)
              goto out;
            }
 
-         char buf[sizeof (SOCKET_COOKIE) + 10];
-         __small_sprintf (buf, "%s%u", SOCKET_COOKIE, sin.sin_port);
+          sock->set_connect_secret ();
+
+         char buf[sizeof (SOCKET_COOKIE) + 80];
+         __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);
+          sock->get_connect_secret (strchr (buf, '\0'));
          len = strlen (buf) + 1;
 
          /* Note that the terminating nul is written.  */
@@ -1866,5 +1940,8 @@ wsock_init ()
 
   if (FIONBIO  != REAL_FIONBIO)
     debug_printf ("****************  FIONBIO  != REAL_FIONBIO");
+
+  /* FIXME: will resulting random sequence be unpredictable enough? */
+  srandom (GetTickCount ());
 }
 
This page took 0.043185 seconds and 5 git commands to generate.