From 619f7fa0324c0eecdb7d32c5721c46b7d9a7f80b Mon Sep 17 00:00:00 2001 From: Egor Duda Date: Mon, 9 Apr 2001 07:21:32 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 18 ++++++ winsup/cygwin/fhandler.h | 7 +++ winsup/cygwin/fhandler_socket.cc | 89 ++++++++++++++++++++++++++++++ winsup/cygwin/net.cc | 95 +++++++++++++++++++++++++++++--- 4 files changed, 200 insertions(+), 9 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 547fe23fe..6bed3b02c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,21 @@ +2001-04-09 Egor Duda + + * 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 * Makefile.in: Put -lgcc last in list of libraries, since stdc++ diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 6a8d11a4c..32ccacc75 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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 diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index a52d2851a..3b3ba7bac 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #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; } diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 5f10a68b0..e089cd642 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -18,6 +18,7 @@ details. */ #include #include +#include #include #include #include @@ -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 ()); }