* 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.
This commit is contained in:
parent
c08e6c4430
commit
619f7fa032
@ -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>
|
Sun Apr 8 20:40:58 2001 Christopher Faylor <cgf@cygnus.com>
|
||||||
|
|
||||||
* Makefile.in: Put -lgcc last in list of libraries, since stdc++
|
* Makefile.in: Put -lgcc last in list of libraries, since stdc++
|
||||||
|
@ -342,6 +342,8 @@ class fhandler_socket: public fhandler_base
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int addr_family;
|
int addr_family;
|
||||||
|
int connect_secret [4];
|
||||||
|
HANDLE secret_event;
|
||||||
struct _WSAPROTOCOL_INFOA *prot_info_ptr;
|
struct _WSAPROTOCOL_INFOA *prot_info_ptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -368,6 +370,11 @@ public:
|
|||||||
int ready_for_read (int fd, DWORD howlong, int ignra);
|
int ready_for_read (int fd, DWORD howlong, int ignra);
|
||||||
int get_addr_family () {return addr_family;}
|
int get_addr_family () {return addr_family;}
|
||||||
void set_addr_family (int af) {addr_family = af;}
|
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
|
class fhandler_pipe: public fhandler_base
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#define USE_SYS_TYPES_FD_SET
|
#define USE_SYS_TYPES_FD_SET
|
||||||
@ -26,6 +27,8 @@
|
|||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "sigproc.h"
|
#include "sigproc.h"
|
||||||
|
|
||||||
|
#define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* fhandler_socket */
|
/* fhandler_socket */
|
||||||
|
|
||||||
@ -44,6 +47,87 @@ fhandler_socket::~fhandler_socket ()
|
|||||||
cfree (prot_info_ptr);
|
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
|
void
|
||||||
fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
|
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);
|
fhandler_base::fixup_after_fork (parent);
|
||||||
debug_printf ("Without Winsock 2.0");
|
debug_printf ("Without Winsock 2.0");
|
||||||
}
|
}
|
||||||
|
if (secret_event)
|
||||||
|
fork_fixup (parent, secret_event, "secret_event");
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_socket::dup (fhandler_base *child)
|
fhandler_socket::dup (fhandler_base *child)
|
||||||
{
|
{
|
||||||
fhandler_socket *fhs = (fhandler_socket *) child;
|
fhandler_socket *fhs = (fhandler_socket *) child;
|
||||||
|
fhs->addr_family = addr_family;
|
||||||
fhs->set_io_handle (get_io_handle ());
|
fhs->set_io_handle (get_io_handle ());
|
||||||
fhs->fixup_before_fork_exec (GetCurrentProcessId ());
|
fhs->fixup_before_fork_exec (GetCurrentProcessId ());
|
||||||
if (ws2_32_handle)
|
if (ws2_32_handle)
|
||||||
@ -148,6 +235,8 @@ fhandler_socket::close ()
|
|||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close_secret_event ();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ details. */
|
|||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -377,8 +378,11 @@ done:
|
|||||||
/* cygwin internal: map sockaddr into internet domain address */
|
/* cygwin internal: map sockaddr into internet domain address */
|
||||||
|
|
||||||
static int get_inet_addr (const struct sockaddr *in, int inlen,
|
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)
|
if (in->sa_family == AF_INET)
|
||||||
{
|
{
|
||||||
*out = * (sockaddr_in *)in;
|
*out = * (sockaddr_in *)in;
|
||||||
@ -392,13 +396,15 @@ static int get_inet_addr (const struct sockaddr *in, int inlen,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char buf[32];
|
char buf[128];
|
||||||
memset (buf, 0, sizeof buf);
|
memset (buf, 0, sizeof buf);
|
||||||
if (read (fd, buf, sizeof buf) != -1)
|
if (read (fd, buf, sizeof buf) != -1)
|
||||||
{
|
{
|
||||||
sockaddr_in sin;
|
sockaddr_in sin;
|
||||||
sin.sin_family = AF_INET;
|
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_port = htons (sin.sin_port);
|
||||||
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||||
*out = sin;
|
*out = sin;
|
||||||
@ -615,11 +621,13 @@ cygwin_connect (int fd,
|
|||||||
int namelen)
|
int namelen)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
BOOL secret_check_failed = FALSE;
|
||||||
fhandler_socket *sock = get (fd);
|
fhandler_socket *sock = get (fd);
|
||||||
sockaddr_in sin;
|
sockaddr_in sin;
|
||||||
|
int secret [4];
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
|
|
||||||
if (get_inet_addr (name, namelen, &sin, &namelen) == 0)
|
if (get_inet_addr (name, namelen, &sin, &namelen, secret) == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (!sock)
|
if (!sock)
|
||||||
@ -638,6 +646,34 @@ cygwin_connect (int fd,
|
|||||||
|
|
||||||
set_winsock_errno ();
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
@ -733,6 +769,7 @@ extern "C" int
|
|||||||
cygwin_accept (int fd, struct sockaddr *peer, int *len)
|
cygwin_accept (int fd, struct sockaddr *peer, int *len)
|
||||||
{
|
{
|
||||||
int res = -1;
|
int res = -1;
|
||||||
|
BOOL secret_check_failed = FALSE;
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
|
|
||||||
fhandler_socket *sock = get (fd);
|
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
|
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");
|
SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
|
||||||
|
|
||||||
int res_fd = fdtab.find_unused_handle ();
|
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? */
|
/* FIXME: what is correct errno? */
|
||||||
set_errno (EMFILE);
|
set_errno (EMFILE);
|
||||||
goto done;
|
goto lock_done;
|
||||||
}
|
}
|
||||||
if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
|
if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
|
||||||
set_winsock_errno ();
|
set_winsock_errno ();
|
||||||
else
|
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;
|
res = res_fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock_done:
|
||||||
|
ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
|
||||||
done:
|
done:
|
||||||
syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
|
syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
|
||||||
ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, "accept");
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,8 +893,11 @@ cygwin_bind (int fd, const struct sockaddr *my_addr, int addrlen)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[sizeof (SOCKET_COOKIE) + 10];
|
sock->set_connect_secret ();
|
||||||
__small_sprintf (buf, "%s%u", SOCKET_COOKIE, sin.sin_port);
|
|
||||||
|
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;
|
len = strlen (buf) + 1;
|
||||||
|
|
||||||
/* Note that the terminating nul is written. */
|
/* Note that the terminating nul is written. */
|
||||||
@ -1866,5 +1940,8 @@ wsock_init ()
|
|||||||
|
|
||||||
if (FIONBIO != REAL_FIONBIO)
|
if (FIONBIO != REAL_FIONBIO)
|
||||||
debug_printf ("**************** FIONBIO != REAL_FIONBIO");
|
debug_printf ("**************** FIONBIO != REAL_FIONBIO");
|
||||||
|
|
||||||
|
/* FIXME: will resulting random sequence be unpredictable enough? */
|
||||||
|
srandom (GetTickCount ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user