This is a workaround for this problem which blocks ITP postfix: https://cygwin.com/ml/cygwin/2014-08/msg00420.html
With the patch, this disables the secret+cred handshakes of the AF_UNIX emulation:
int sd = socket(AF_UNIX, SOCK_STREAM, 0); setsockopt(sd, SOL_SOCKET, SO_PEERCRED, NULL, 0); Postfix works if socket() calls are replaced by the above. Calls of getsockopt(..., SO_PEERCRED, ...) and getpeereid() would fail with ENOTSUP then. These are not used by postfix. Christian
2014-09-25 Christian Franke <fra...@computer.org> Add setsockopt(sd, SOL_SOCKET, SO_PEERCRED, NULL, 0) to disable initial handshake on AF_LOCAL sockets. * fhandler.h (fhandler_socket::no_getpeereid): New variable. (fhandler_socket::af_local_set_no_getpeereid): New prototype. * fhandler_socket.cc (fhandler_socket::fhandler_socket): Initialize no_getpeereid. (fhandler_socket::af_local_connect): Skip handshake if no_getpeereid is set. Add debug output. (fhandler_socket::af_local_accept): Likewise. (fhandler_socket::af_local_set_no_getpeereid): New function. (fhandler_socket::af_local_copy): Copy no_getpeereid. (fhandler_socket::getpeereid): Fail if no_getpeereid is set. * net.cc (cygwin_setsockop): Add SO_PEERCRED. * select.cc (set_bits): Set socket connected state also if read bit is requested. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index cf4de07..6c2c3d4 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -492,6 +492,7 @@ class fhandler_socket: public fhandler_base pid_t sec_peer_pid; uid_t sec_peer_uid; gid_t sec_peer_gid; + bool no_getpeereid; void af_local_set_secret (char *); void af_local_setblocking (bool &, bool &); void af_local_unsetblocking (bool, bool); @@ -504,6 +505,7 @@ class fhandler_socket: public fhandler_base int af_local_accept (); public: int af_local_connect (); + int af_local_set_no_getpeereid (); void af_local_set_sockpair_cred (); private: diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 0354ee2..256ac67 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -231,6 +231,7 @@ fhandler_socket::fhandler_socket () : wsock_events (NULL), wsock_mtx (NULL), wsock_evt (NULL), + no_getpeereid(false), prot_info_ptr (NULL), sun_path (NULL), peer_sun_path (NULL), @@ -402,7 +403,10 @@ fhandler_socket::af_local_connect () if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) return 0; - debug_printf ("af_local_connect called"); + debug_printf ("af_local_connect called, no_getpeereid=%d", no_getpeereid); + if (no_getpeereid) + return 0; + connect_state (connect_credxchg); af_local_setblocking (orig_async_io, orig_is_nonblocking); if (!af_local_send_secret () || !af_local_recv_secret () @@ -422,7 +426,10 @@ fhandler_socket::af_local_accept () { bool orig_async_io, orig_is_nonblocking; - debug_printf ("af_local_accept called"); + debug_printf ("af_local_accept called, no_getpeereid=%d", no_getpeereid); + if (no_getpeereid) + return 0; + connect_state (connect_credxchg); af_local_setblocking (orig_async_io, orig_is_nonblocking); if (!af_local_recv_secret () || !af_local_send_secret () @@ -438,6 +445,25 @@ fhandler_socket::af_local_accept () return 0; } +int +fhandler_socket::af_local_set_no_getpeereid () +{ + if (get_addr_family () != AF_LOCAL || get_socket_type () != SOCK_STREAM) + { + set_errno (EINVAL); + return -1; + } + if (connect_state () != unconnected) + { + set_errno (EALREADY); + return -1; + } + + debug_printf ("no_getpeereid set"); + no_getpeereid = true; + return 0; +} + void fhandler_socket::af_local_set_cred () { @@ -462,6 +488,7 @@ fhandler_socket::af_local_copy (fhandler_socket *sock) sock->sec_peer_pid = sec_peer_pid; sock->sec_peer_uid = sec_peer_uid; sock->sec_peer_gid = sec_peer_gid; + sock->no_getpeereid = no_getpeereid; } void @@ -2287,6 +2314,11 @@ fhandler_socket::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid) set_errno (EINVAL); return -1; } + if (no_getpeereid) + { + set_errno (ENOTSUP); + return -1; + } if (connect_state () != connected) { set_errno (ENOTCONN); diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index b6c0f72..c5ca15e 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -810,6 +810,16 @@ cygwin_setsockopt (int fd, int level, int optname, const void *optval, fhandler_socket *fh = get (fd); if (!fh) __leave; + + if (optname == SO_PEERCRED && level == SOL_SOCKET) + { + if (optval || optlen) + set_errno (EINVAL); + else + res = fh->af_local_set_no_getpeereid (); + __leave; + } + /* Old applications still use the old WinSock1 IPPROTO_IP values. */ if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) optname = convert_ws1_ip_optname (optname); diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 6a39685..75eb726 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -473,6 +473,9 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds, if (me->read_selected && me->read_ready) { UNIX_FD_SET (me->fd, readfds); + /* Special AF_LOCAL handling. */ + if ((sock = me->fh->is_socket ()) && sock->connect_state () == connect_pending) + sock->connect_state (connected); ready++; } if (me->write_selected && me->write_ready)