From a6099ff810747d2830edebc836202ff8dae1ead7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 23 Mar 2005 17:27:18 +0000 Subject: [PATCH] * 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 ad38fde8a..f10a698c1 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,34 @@ +2005-03-23 Corinna Vinschen + + * 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 * include/cygwin/version.h: Change coment for most recent API version diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 1ca95d35f..2f1424681 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 e7194dfe5..d2892e2df 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 (); @@ -759,6 +797,9 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) sec_peer_uid = (__uid32_t) -1; sec_peer_gid = (__gid32_t) -1; + if (!res) + res = sec_event_connect (&sin); + if (!res) { /* eid credential transaction. If connect is in progress, @@ -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 8b77d2a70..a884ea14a 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); } }