From a6099ff810747d2830edebc836202ff8dae1ead7 Mon Sep 17 00:00:00 2001
From: Corinna Vinschen <corinna@vinschen.de>
Date: Wed, 23 Mar 2005 17:27:18 +0000
Subject: 	* fhandler.h (fhandler_socket::eid_connect): Make private. 
 (fhandler_socket::set_connect_secret): Ditto. 
 (fhandler_socket::get_connect_secret): Ditto. 
 (fhandler_socket::create_secret_event): Ditto. Remove secret argument. 
 (fhandler_socket::check_peer_secret_event): Ditto. 
 (fhandler_socket::signal_secret_event): Make private. 
 (fhandler_socket::close_secret_event): Ditto. 
 (fhandler_socket::sec_event_accept): New private method. 
 (fhandler_socket::sec_event_connect): Ditto. 
 (fhandler_socket::af_local_connect): New public method. 	*
 fhandler_socket.cc: Use 'struct sockaddr' and 'struct sockaddr_in' 	rather
 than just 'sockaddr' and 'sockaddr_in' throughout. 
 (fhandler_socket::eid_connect): Drop AF_LOCAL/SOCK_STREAM test. 
 (fhandler_socket::create_secret_event): Remove secret argument. 	Always
 use connect_secret instead. 	(fhandler_socket::check_peer_secret_event):
 Ditto. 	(fhandler_socket::sec_event_connect): New method, combining
 entire 	secret event handshake on connect side. 
 (fhandler_socket::af_local_connect): New method, combining secret 	event
 handshake and eid credential transaction on connect side, to 	be called from
 select. 	(fhandler_socket::sec_event_accept): New method, combining
 entire 	secret event handshake on accept side. 
 (fhandler_socket::connect): Drop secret, use connect_secret instead. 	Move
 entire secret event handshake to sec_event_connect. 
 (fhandler_socket::accept): Move entire secret event handshake to 
 sec_event_accept. 	* select.cc (set_bits): Just call af_local_connect
 here.

---
 winsup/cygwin/ChangeLog          |  31 ++++++++
 winsup/cygwin/fhandler.h         |  13 +++-
 winsup/cygwin/fhandler_socket.cc | 152 ++++++++++++++++++++++-----------------
 winsup/cygwin/select.cc          |  15 ++--
 4 files changed, 135 insertions(+), 76 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ad38fde..f10a698 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,34 @@
+2005-03-23  Corinna Vinschen  <corinna@vinschen.de>
+
+	* fhandler.h (fhandler_socket::eid_connect): Make private.
+	(fhandler_socket::set_connect_secret): Ditto.
+	(fhandler_socket::get_connect_secret): Ditto.
+	(fhandler_socket::create_secret_event): Ditto. Remove secret argument.
+	(fhandler_socket::check_peer_secret_event): Ditto.
+	(fhandler_socket::signal_secret_event): Make private.
+	(fhandler_socket::close_secret_event): Ditto.
+	(fhandler_socket::sec_event_accept): New private method.
+	(fhandler_socket::sec_event_connect): Ditto.
+	(fhandler_socket::af_local_connect): New public method.
+	* fhandler_socket.cc: Use 'struct sockaddr' and 'struct sockaddr_in'
+	rather than just 'sockaddr' and 'sockaddr_in' throughout.
+	(fhandler_socket::eid_connect): Drop AF_LOCAL/SOCK_STREAM test.
+	(fhandler_socket::create_secret_event): Remove secret argument.
+	Always use connect_secret instead.
+	(fhandler_socket::check_peer_secret_event): Ditto.
+	(fhandler_socket::sec_event_connect): New method, combining entire
+	secret event handshake on connect side.
+	(fhandler_socket::af_local_connect): New method, combining secret
+	event handshake and eid credential transaction on connect side, to
+	be called from select.
+	(fhandler_socket::sec_event_accept): New method, combining entire
+	secret event handshake on accept side.
+	(fhandler_socket::connect): Drop secret, use connect_secret instead.
+	Move entire secret event handshake to sec_event_connect.
+	(fhandler_socket::accept): Move entire secret event handshake to
+	sec_event_accept.
+	* select.cc (set_bits): Just call af_local_connect here.
+
 2005-03-23  Christopher Faylor  <cgf@timesys.com>
 
 	* include/cygwin/version.h: Change coment for most recent API version
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 1ca95d3..2f14246 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -376,8 +376,8 @@ class fhandler_socket: public fhandler_base
   bool eid_recv (void);
   bool eid_send (void);
   void eid_accept (void);
- public:
   void eid_connect (void);
+ public:
   void set_socketpair_eids (void);
 
  private:
@@ -458,12 +458,19 @@ class fhandler_socket: public fhandler_base
   int get_socket_type () {return type;}
   void set_sun_path (const char *path);
   char *get_sun_path () {return sun_path;}
+
+ private:
   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);
+  HANDLE create_secret_event ();
+  int check_peer_secret_event (struct sockaddr_in *peer);
   void signal_secret_event ();
   void close_secret_event ();
+  int sec_event_accept (int, struct sockaddr_in *);
+  int sec_event_connect (struct sockaddr_in *peer);
+ public:
+  int af_local_connect (void);
+
   int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
   int __stdcall fchmod (mode_t mode) __attribute__ ((regparm (1)));
   int __stdcall fchown (__uid32_t uid, __gid32_t gid) __attribute__ ((regparm (2)));
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index e7194df..d2892e2 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -65,7 +65,7 @@ get_inet_addr (const struct sockaddr *in, int inlen,
 
   if (in->sa_family == AF_INET)
     {
-      *out = * (sockaddr_in *)in;
+      *out = * (struct sockaddr_in *)in;
       *outlen = inlen;
       return 1;
     }
@@ -100,7 +100,7 @@ get_inet_addr (const struct sockaddr *in, int inlen,
       memset (buf, 0, sizeof buf);
       if (ReadFile (fh, buf, 128, &len, 0))
 	{
-	  sockaddr_in sin;
+	  struct sockaddr_in sin;
 	  sin.sin_family = AF_INET;
 	  sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",
 		  &sin.sin_port,
@@ -238,10 +238,6 @@ fhandler_socket::eid_send (void)
 void
 fhandler_socket::eid_connect (void)
 {
-  /* This test allows to keep select.cc clean from boring implementation
-     details. */
-  if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM)
-    return;
   debug_printf ("eid_connect called");
   bool orig_async_io, orig_is_nonblocking;
   eid_setblocking (orig_async_io, orig_is_nonblocking);
@@ -306,7 +302,7 @@ fhandler_socket::get_connect_secret (char* buf)
 }
 
 HANDLE
-fhandler_socket::create_secret_event (int* secret)
+fhandler_socket::create_secret_event ()
 {
   struct sockaddr_in sin;
   int sin_len = sizeof (sin);
@@ -321,7 +317,7 @@ fhandler_socket::create_secret_event (int* secret)
     }
 
   char event_name[CYG_MAX_PATH];
-  secret_event_name (event_name, sin.sin_port, secret ?: connect_secret);
+  secret_event_name (event_name, sin.sin_port, connect_secret);
   secret_event = CreateEvent (&sec_all, FALSE, FALSE, event_name);
 
   if (!secret_event)
@@ -354,12 +350,12 @@ fhandler_socket::close_secret_event ()
 }
 
 int
-fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
+fhandler_socket::check_peer_secret_event (struct sockaddr_in *peer)
 {
 
   char event_name[CYG_MAX_PATH];
 
-  secret_event_name (event_name, peer->sin_port, secret ?: connect_secret);
+  secret_event_name (event_name, peer->sin_port, connect_secret);
   HANDLE ev = CreateEvent (&sec_all_nih, FALSE, FALSE, event_name);
   if (!ev)
     debug_printf("create event %E");
@@ -377,6 +373,78 @@ fhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret)
     return 0;
 }
 
+int
+fhandler_socket::sec_event_connect (struct sockaddr_in *peer)
+{
+  bool secret_check_failed = false;
+  struct sockaddr_in sin;
+  int siz = sizeof sin;
+
+  debug_printf ("sec_event_connect called");
+  if (!peer)
+    {
+      if (::getpeername (get_socket (), (struct sockaddr *) &sin, &siz))
+        goto err;
+      peer = &sin;
+    }
+  if (!create_secret_event ())
+    secret_check_failed = true;
+  if (!secret_check_failed && !check_peer_secret_event (peer))
+    {
+      debug_printf ("accept from unauthorized server");
+      secret_check_failed = true;
+    }
+  if (!secret_check_failed)
+    return 0;
+
+err:
+  close_secret_event ();
+  closesocket (get_socket ());
+  WSASetLastError (WSAECONNREFUSED);
+  set_winsock_errno ();
+  return -1;
+}
+
+/* Called from select().  It combines the secret event handshake and
+   the eid credential transaction into one call.  This keeps implementation
+   details from select. */
+int
+fhandler_socket::af_local_connect (void)
+{
+  if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM)
+    return 0;
+  int ret = sec_event_connect (NULL);
+  if (!ret)
+    eid_connect ();
+  return ret;
+}
+
+int
+fhandler_socket::sec_event_accept (int sock, struct sockaddr_in *peer)
+{
+  bool secret_check_failed = false;
+
+  debug_printf ("sec_event_accept called");
+
+  if (!create_secret_event ())
+    secret_check_failed = true;
+
+  if (!secret_check_failed
+      && !check_peer_secret_event (peer))
+    {
+      debug_printf ("connect from unauthorized client");
+      secret_check_failed = true;
+    }
+  if (secret_check_failed)
+    {
+      close_secret_event ();
+      closesocket (sock);
+      set_errno (ECONNABORTED);
+      return -1;
+    }
+  return sock;
+}
+
 void
 fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
 {
@@ -687,16 +755,14 @@ int
 fhandler_socket::connect (const struct sockaddr *name, int namelen)
 {
   int res = -1;
-  bool secret_check_failed = false;
   bool in_progress = false;
-  sockaddr_in sin;
-  int secret [4];
+  struct sockaddr_in sin;
   DWORD err;
 
-  if (!get_inet_addr (name, namelen, &sin, &namelen, secret))
+  if (!get_inet_addr (name, namelen, &sin, &namelen, connect_secret))
     return -1;
 
-  res = ::connect (get_socket (), (sockaddr *) &sin, namelen);
+  res = ::connect (get_socket (), (struct sockaddr *) &sin, namelen);
 
   if (!res)
     err = 0;
@@ -723,34 +789,6 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
 
   if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
     {
-      if (!res || in_progress)
-	{
-	  if (!create_secret_event (secret))
-	    {
-	      secret_check_failed = true;
-	    }
-	  else if (in_progress)
-	    signal_secret_event ();
-	}
-
-      if (!secret_check_failed && !res)
-	{
-	  if (!check_peer_secret_event (&sin, secret))
-	    {
-	      debug_printf ("accept from unauthorized server");
-	      secret_check_failed = true;
-	    }
-       }
-
-      if (secret_check_failed)
-	{
-	  close_secret_event ();
-	  if (res)
-	    closesocket (res);
-	  set_errno (ECONNREFUSED);
-	  res = -1;
-	}
-
       /* Prepare eid credential transaction. */
       sec_pid = getpid ();
       sec_uid = geteuid32 ();
@@ -760,6 +798,9 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
       sec_peer_gid = (__gid32_t) -1;
 
       if (!res)
+	res = sec_event_connect (&sin);
+
+      if (!res)
         {
 	  /* eid credential transaction.  If connect is in progress,
 	    we're deferring the eid transaction to the successful select,
@@ -803,7 +844,6 @@ int
 fhandler_socket::accept (struct sockaddr *peer, int *len)
 {
   int res = -1;
-  bool secret_check_failed = false;
 
   /* Allows NULL peer and len parameters. */
   struct sockaddr_in peer_dummy;
@@ -827,27 +867,7 @@ fhandler_socket::accept (struct sockaddr *peer, int *len)
 
   if ((SOCKET) res != INVALID_SOCKET && get_addr_family () == AF_LOCAL
       && get_socket_type () == SOCK_STREAM)
-    {
-	if (!create_secret_event ())
-	  secret_check_failed = true;
-
-      if (!secret_check_failed)
-	{
-	  if (!check_peer_secret_event ((struct sockaddr_in*) peer))
-	    {
-	      debug_printf ("connect from unauthorized client");
-	      secret_check_failed = true;
-	    }
-	}
-
-      if (secret_check_failed)
-	{
-	  close_secret_event ();
-	  closesocket (res);
-	  set_errno (ECONNABORTED);
-	  return -1;
-	}
-    }
+    res = sec_event_accept (res, (struct sockaddr_in *) peer);
 
   if ((SOCKET) res == INVALID_SOCKET)
     set_winsock_errno ();
@@ -1256,7 +1276,7 @@ int
 fhandler_socket::sendto (const void *ptr, size_t len, int flags,
 			 const struct sockaddr *to, int tolen)
 {
-  sockaddr_in sin;
+  struct sockaddr_in sin;
 
   if (to && !get_inet_addr (to, tolen, &sin, &tolen))
     return SOCKET_ERROR;
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 8b77d2a..a884ea1 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -338,11 +338,10 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
       UNIX_FD_SET (me->fd, writefds);
       if (me->except_on_write && (sock = me->fh->is_socket ()))
 	{
-	  /* eid credential transaction on successful non-blocking connect.
-	     Since the read bit indicates an error, don't start transaction
-	     if it's set. */
-	  if (!me->read_ready && sock->connect_state () == connect_pending)
-	    sock->eid_connect ();
+	  /* Special AF_LOCAL handling. */
+	  if (!me->read_ready && sock->connect_state () == connect_pending
+	      && sock->af_local_connect () && me->read_selected)
+	    UNIX_FD_SET (me->fd, readfds);
 	  sock->connect_state (connected);
 	}
       ready++;
@@ -354,8 +353,10 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
 	  UNIX_FD_SET (me->fd, writefds);
 	  if ((sock = me->fh->is_socket ()))
 	    {
-	      if (!me->read_ready && sock->connect_state () == connect_pending)
-	        sock->eid_connect ();
+	      /* Special AF_LOCAL handling. */
+	      if (!me->read_ready && sock->connect_state () == connect_pending
+		  && sock->af_local_connect () && me->read_selected)
+		UNIX_FD_SET (me->fd, readfds);
 	      sock->connect_state (connected);
 	    }
 	}
-- 
cgit v1.1