diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b2a20b735..a33ff3337 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,75 @@ +2005-03-23 Corinna Vinschen + + * fhandler.h (fhandler_socket::secret_event): Remove. + (fhandler_socket::af_local_set_secret): New function combining former + set_connect_secret and get_connect_secret into one function. + (fhandler_socket::af_local_setblocking): Rename from eid_setblocking. + (fhandler_socket::af_local_unsetblocking): Rename from + eid_unsetblocking. + (fhandler_socket::af_local_set_cred): New method. + (fhandler_socket::af_local_copy): New method. + (fhandler_socket::af_local_recv_secret): New method. + (fhandler_socket::af_local_send_secret): New method. + (fhandler_socket::af_local_recv_cred): Rename from eid_recv. + (fhandler_socket::af_local_send_cred): Rename from eid_send. + (fhandler_socket::af_local_accept): New method. + (fhandler_socket::af_local_set_sockpair_cred): Rename from + set_socketpair_eids. + (fhandler_socket::eid_accept): Remove. + (fhandler_socket::eid_connect): Remove. + (fhandler_socket::set_connect_secret): Remove. + (fhandler_socket::get_connect_secret): Remove. + (fhandler_socket::create_secret_event): Remove. + (fhandler_socket::check_peer_secret_event): Remove. + (fhandler_socket::signal_secret_event): Remove. + (fhandler_socket::close_secret_event): Remove. + (fhandler_socket::sec_event_accept): Remove. + (fhandler_socket::sec_event_connect): Remove. + * fhandler_socket.cc (secret_event_name): Remove. + (fhandler_socket::af_local_set_sockpair_cred): Rename from + set_socketpair_eids. + (fhandler_socket::af_local_setblocking): Rename from eid_setblocking. + (fhandler_socket::af_local_unsetblocking): Rename from + eid_unsetblocking. + (fhandler_socket::af_local_recv_secret): New function to receive + AF_LOCAL connect secret over socket itself. + (fhandler_socket::af_local_send_secret): New function to send AF_LOCAL + connect secret over socket itself. + (fhandler_socket::af_local_recv_cred): Rename from eid_recv. + (fhandler_socket::af_local_send_cred): Rename from eid_send. + (fhandler_socket::eid_connect): Remove. + (fhandler_socket::af_local_connect): Take over connect side handling + of AF_LOCAL secret and credential handshake. + (fhandler_socket::eid_accept): Remove. + (fhandler_socket::af_local_accept): New method, take over accept side + handling of AF_LOCAL secret and credential handshake. + (fhandler_socket::af_local_set_cred): New method, set eid credentials + to start values. + (fhandler_socket::af_local_copy): New method, copy secret and + credentials to another socket. + (fhandler_socket::af_local_set_secret): New function combining former + set_connect_secret and get_connect_secret into one function. + (fhandler_socket::create_secret_event): Remove. + (fhandler_socket::signal_secret_event): Remove. + (fhandler_socket::close_secret_event): Remove. + (fhandler_socket::check_peer_secret_event): Remove. + (fhandler_socket::sec_event_connect): Remove. + (fhandler_socket::sec_event_accept): Remove. + (fhandler_socket::fixup_after_fork): Drop secret_event handling. + (fhandler_socket::bind): Call af_local_set_secret. + (fhandler_socket::connect): Call af_local_set_cred and af_local_connect. + (fhandler_socket::listen): Call af_local_set_cred. + (fhandler_socket::accept): Call af_local_copy and af_local_accept on + accepted socket. + (fhandler_socket::close): Don't call close_secret_event. + (fhandler_socket::set_close_on_exec): Don't set secret_event + inheritance. + * net.cc (cygwin_getsockopt): Add debug output. + (socketpair): Call af_local_set_sockpair_cred instead of + set_socketpair_eids. + * select.cc (set_bits): Drop AF_LOCAL special handling in case + of except bit set. + 2005-03-23 Christopher Faylor * include/ctype.h: Always define macros when inside cygwin. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 2f1424681..ee86fd497 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -362,8 +362,7 @@ class fhandler_socket: public fhandler_base private: int addr_family; int type; - int connect_secret [4]; - HANDLE secret_event; + int connect_secret[4]; pid_t sec_pid; __uid32_t sec_uid; @@ -371,14 +370,19 @@ class fhandler_socket: public fhandler_base pid_t sec_peer_pid; __uid32_t sec_peer_uid; __gid32_t sec_peer_gid; - void eid_setblocking (bool &, bool &); - void eid_unsetblocking (bool, bool); - bool eid_recv (void); - bool eid_send (void); - void eid_accept (void); - void eid_connect (void); + void af_local_set_secret (char *); + void af_local_setblocking (bool &, bool &); + void af_local_unsetblocking (bool, bool); + void af_local_set_cred (void); + void af_local_copy (fhandler_socket *); + bool af_local_recv_secret (void); + bool af_local_send_secret (void); + bool af_local_recv_cred (void); + bool af_local_send_cred (void); + int af_local_accept (void); public: - void set_socketpair_eids (void); + int af_local_connect (void); + void af_local_set_sockpair_cred (void); private: struct _WSAPROTOCOL_INFOA *prot_info_ptr; @@ -459,18 +463,6 @@ class fhandler_socket: public fhandler_base 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 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 d2892e2df..8e7443e1d 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -45,16 +45,6 @@ int sscanf (const char *, const char *, ...); fhandler_dev_random* entropy_source; -static void -secret_event_name (char *buf, short port, int *secret_ptr) -{ - __small_sprintf (buf, "%scygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x", - wincap.has_terminal_services () ? "Global\\" : "", - port, - secret_ptr [0], secret_ptr [1], - secret_ptr [2], secret_ptr [3]); -} - /* cygwin internal: map sockaddr into internet domain address */ static int get_inet_addr (const struct sockaddr *in, int inlen, @@ -150,8 +140,22 @@ fhandler_socket::~fhandler_socket () cfree (sun_path); } +char * +fhandler_socket::get_proc_fd_name (char *buf) +{ + __small_sprintf (buf, "socket:[%d]", get_socket ()); + return buf; +} + +int +fhandler_socket::open (int flags, mode_t mode) +{ + set_errno (ENXIO); + return 0; +} + void -fhandler_socket::set_socketpair_eids (void) +fhandler_socket::af_local_set_sockpair_cred (void) { sec_pid = sec_peer_pid = getpid (); sec_uid = sec_peer_uid = geteuid32 (); @@ -159,7 +163,7 @@ fhandler_socket::set_socketpair_eids (void) } void -fhandler_socket::eid_setblocking (bool &async, bool &nonblocking) +fhandler_socket::af_local_setblocking (bool &async, bool &nonblocking) { async = async_io (); nonblocking = is_nonblocking (); @@ -172,7 +176,7 @@ fhandler_socket::eid_setblocking (bool &async, bool &nonblocking) } void -fhandler_socket::eid_unsetblocking (bool async, bool nonblocking) +fhandler_socket::af_local_unsetblocking (bool async, bool nonblocking) { if (nonblocking) { @@ -188,7 +192,55 @@ fhandler_socket::eid_unsetblocking (bool async, bool nonblocking) } bool -fhandler_socket::eid_recv (void) +fhandler_socket::af_local_recv_secret (void) +{ + int out[4] = { 0, 0, 0, 0 }; + int rest = sizeof out; + char *ptr = (char *) out; + while (rest > 0) + { + int ret = recvfrom (ptr, rest, 0, NULL, NULL); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + if (rest == 0) + { + debug_printf ("Received af_local secret: %08x-%08x-%08x-%08x", + out[0], out[1], out[2], out[3]); + if (out[0] != connect_secret[0] || out[1] != connect_secret[1] + || out[2] != connect_secret[2] || out[3] != connect_secret[3]) + { + debug_printf ("Receiving af_local secret mismatch"); + return false; + } + } + else + debug_printf ("Receiving af_local secret failed"); + return rest == 0; +} + +bool +fhandler_socket::af_local_send_secret (void) +{ + int rest = sizeof connect_secret; + char *ptr = (char *) connect_secret; + while (rest > 0) + { + int ret = sendto (ptr, rest, 0, NULL, 0); + if (ret <= 0) + break; + rest -= ret; + ptr += ret; + } + debug_printf ("Sending af_local secret %s", rest == 0 ? "succeeded" + : "failed"); + return rest == 0; +} + +bool +fhandler_socket::af_local_recv_cred (void) { struct ucred out = { (pid_t) 0, (__uid32_t) -1, (__gid32_t) -1 }; int rest = sizeof out; @@ -215,7 +267,7 @@ fhandler_socket::eid_recv (void) } bool -fhandler_socket::eid_send (void) +fhandler_socket::af_local_send_cred (void) { struct ucred in = { sec_pid, sec_uid, sec_gid }; int rest = sizeof in; @@ -235,42 +287,75 @@ fhandler_socket::eid_send (void) return rest == 0; } -void -fhandler_socket::eid_connect (void) +int +fhandler_socket::af_local_connect (void) { - debug_printf ("eid_connect called"); - bool orig_async_io, orig_is_nonblocking; - eid_setblocking (orig_async_io, orig_is_nonblocking); - eid_send () && eid_recv (); - eid_unsetblocking (orig_async_io, orig_is_nonblocking); -} + /* This keeps the test out of select. */ + if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) + return 0; -void -fhandler_socket::eid_accept (void) -{ - debug_printf ("eid_accept called"); + debug_printf ("af_local_connect called"); bool orig_async_io, orig_is_nonblocking; - eid_setblocking (orig_async_io, orig_is_nonblocking); - eid_recv () && eid_send (); - eid_unsetblocking (orig_async_io, orig_is_nonblocking); -} - -char * -fhandler_socket::get_proc_fd_name (char *buf) -{ - __small_sprintf (buf, "socket:[%d]", get_socket ()); - return buf; + af_local_setblocking (orig_async_io, orig_is_nonblocking); + if (!af_local_send_secret () || !af_local_recv_secret () + || !af_local_send_cred () || !af_local_recv_cred ()) + { + debug_printf ("accept from unauthorized server"); + ::shutdown (get_socket (), SD_BOTH); + WSASetLastError (WSAECONNREFUSED); + return -1; + } + af_local_unsetblocking (orig_async_io, orig_is_nonblocking); + return 0; } int -fhandler_socket::open (int flags, mode_t mode) +fhandler_socket::af_local_accept (void) { - set_errno (ENXIO); + debug_printf ("af_local_accept called"); + bool orig_async_io, orig_is_nonblocking; + af_local_setblocking (orig_async_io, orig_is_nonblocking); + if (!af_local_recv_secret () || !af_local_send_secret () + || !af_local_recv_cred () || !af_local_send_cred ()) + { + debug_printf ("connect from unauthorized client"); + ::shutdown (get_socket (), SD_BOTH); + ::closesocket (get_socket ()); + WSASetLastError (WSAECONNABORTED); + return -1; + } + af_local_unsetblocking (orig_async_io, orig_is_nonblocking); return 0; } void -fhandler_socket::set_connect_secret () +fhandler_socket::af_local_set_cred (void) +{ + sec_pid = getpid (); + sec_uid = geteuid32 (); + sec_gid = getegid32 (); + sec_peer_pid = (pid_t) 0; + sec_peer_uid = (__uid32_t) -1; + sec_peer_gid = (__gid32_t) -1; +} + +void +fhandler_socket::af_local_copy (fhandler_socket *sock) +{ + sock->connect_secret[0] = connect_secret[0]; + sock->connect_secret[1] = connect_secret[1]; + sock->connect_secret[2] = connect_secret[2]; + sock->connect_secret[3] = connect_secret[3]; + sock->sec_pid = sec_pid; + sock->sec_uid = sec_uid; + sock->sec_gid = sec_gid; + sock->sec_peer_pid = sec_peer_pid; + sock->sec_peer_uid = sec_peer_uid; + sock->sec_peer_gid = sec_peer_gid; +} + +void +fhandler_socket::af_local_set_secret (char *buf) { if (!entropy_source) { @@ -291,160 +376,11 @@ fhandler_socket::set_connect_secret () if (len != sizeof (connect_secret)) bzero ((char*) connect_secret, sizeof (connect_secret)); } -} - -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 () -{ - struct sockaddr_in sin; - int sin_len = sizeof (sin); - - if (secret_event) - return secret_event; - - if (::getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len)) - { - debug_printf ("error getting local socket name (%d)", WSAGetLastError ()); - return NULL; - } - - char event_name[CYG_MAX_PATH]; - secret_event_name (event_name, sin.sin_port, connect_secret); - secret_event = CreateEvent (&sec_all, FALSE, FALSE, event_name); - - if (!secret_event) - debug_printf("create event %E"); - else if (close_on_exec ()) - /* Event allows inheritance, but handle will not be inherited */ - set_no_inheritance (secret_event, 1); - - return secret_event; -} - -void -fhandler_socket::signal_secret_event () -{ - if (!secret_event) - debug_printf ("no secret event?"); - else - { - SetEvent (secret_event); - debug_printf ("signaled secret_event"); - } -} - -void -fhandler_socket::close_secret_event () -{ - if (secret_event) - CloseHandle (secret_event); - secret_event = NULL; -} - -int -fhandler_socket::check_peer_secret_event (struct sockaddr_in *peer) -{ - - char event_name[CYG_MAX_PATH]; - - 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"); - - signal_secret_event (); - - 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; -} - -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) { @@ -493,9 +429,6 @@ fhandler_socket::fixup_after_fork (HANDLE parent) debug_printf ("WSASocket went fine new_sock %p, old_sock %p", new_sock, get_io_handle ()); set_io_handle ((HANDLE) new_sock); } - - if (secret_event) - fork_fixup (parent, secret_event, "secret_event"); } void @@ -722,11 +655,9 @@ fhandler_socket::bind (const struct sockaddr *name, int namelen) __seterrno (); } - set_connect_secret (); - char buf[sizeof (SOCKET_COOKIE) + 80]; __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port); - get_connect_secret (strchr (buf, '\0')); + af_local_set_secret (strchr (buf, '\0')); DWORD blen = strlen (buf) + 1; if (!WriteFile (fh, buf, blen, &blen, 0)) { @@ -789,23 +720,13 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen) if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) { - /* Prepare eid credential transaction. */ - sec_pid = getpid (); - sec_uid = geteuid32 (); - sec_gid = getegid32 (); - sec_peer_pid = (pid_t) 0; - 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, - we're deferring the eid transaction to the successful select, - see select.cc, function set_bits(). */ - eid_connect (); + af_local_set_cred (); /* Don't move into af_local_connect since + af_local_connect is called from select, + possibly running under another identity. */ + if (!res && af_local_connect ()) + { + set_winsock_errno (); + return -1; } } @@ -826,15 +747,7 @@ fhandler_socket::listen (int backlog) else { if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM) - { - /* Prepare eid credential transaction. */ - sec_pid = getpid (); - sec_uid = geteuid32 (); - sec_gid = getegid32 (); - sec_peer_pid = (pid_t) 0; - sec_peer_uid = (__uid32_t) -1; - sec_peer_gid = (__gid32_t) -1; - } + af_local_set_cred (); connect_state (connected); } return res; @@ -865,11 +778,7 @@ fhandler_socket::accept (struct sockaddr *peer, int *len) res = ::accept (get_socket (), peer, len); - if ((SOCKET) res != INVALID_SOCKET && get_addr_family () == AF_LOCAL - && get_socket_type () == SOCK_STREAM) - res = sec_event_accept (res, (struct sockaddr_in *) peer); - - if ((SOCKET) res == INVALID_SOCKET) + if (res == (int) INVALID_SOCKET) set_winsock_errno (); else { @@ -889,13 +798,14 @@ fhandler_socket::accept (struct sockaddr *peer, int *len) /* Don't forget to copy credentials from accepting socket to accepted socket and start transaction on accepted socket! */ - sock->sec_pid = sec_pid; - sock->sec_uid = sec_uid; - sock->sec_gid = sec_gid; - sock->sec_peer_pid = sec_peer_pid; - sock->sec_peer_uid = sec_peer_uid; - sock->sec_peer_gid = sec_peer_gid; - sock->eid_accept (); + af_local_copy (sock); + res = sock->af_local_accept (); + if (res == -1) + { + res_fd.release (); + set_winsock_errno (); + goto out; + } } } sock->connect_state (connected); @@ -908,6 +818,7 @@ fhandler_socket::accept (struct sockaddr *peer, int *len) } } +out: debug_printf ("res %d", res); return res; } @@ -1524,8 +1435,6 @@ fhandler_socket::close () WSASetLastError (0); } - close_secret_event (); - debug_printf ("%d = fhandler_socket::close()", res); return res; } @@ -1709,8 +1618,6 @@ fhandler_socket::fcntl (int cmd, void *arg) void fhandler_socket::set_close_on_exec (bool val) { - if (secret_event) - set_no_inheritance (secret_event, val); if (!winsock2_active) /* < Winsock 2.0 */ set_no_inheritance (get_handle (), val); close_on_exec (val); diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 46455285d..7f542594d 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -790,6 +790,7 @@ cygwin_getsockopt (int fd, int level, int optname, void *optval, int *optlen) { int *e = (int *) optval; + debug_printf ("WinSock SO_ERROR = %d", *e); *e = find_winsock_errno (*e); } @@ -2162,7 +2163,7 @@ socketpair (int family, int type, int protocol, int *sb) ((fhandler_socket *) sb0)->set_socket_type (type); ((fhandler_socket *) sb0)->connect_state (connected); if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb0)->set_socketpair_eids (); + ((fhandler_socket *) sb0)->af_local_set_sockpair_cred (); cygheap_fdnew sb1 (sb0, false); @@ -2173,7 +2174,7 @@ socketpair (int family, int type, int protocol, int *sb) ((fhandler_socket *) sb1)->set_socket_type (type); ((fhandler_socket *) sb1)->connect_state (connected); if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb1)->set_socketpair_eids (); + ((fhandler_socket *) sb1)->af_local_set_sockpair_cred (); sb[0] = sb0; sb[1] = sb1; diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index a884ea14a..1c469cf63 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -352,13 +352,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds, { UNIX_FD_SET (me->fd, writefds); if ((sock = me->fh->is_socket ())) - { - /* 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); - } + sock->connect_state (connected); } if (me->except_selected) UNIX_FD_SET (me->fd, exceptfds);