From: Ally Sommers dropbear.sh@gmail.com
This commit additionally modifies wineserver's sock_ioctl to handle the provided pathname by changing directories and then returning after the native call. This is NOT threadsafe, but wineserver is not multithreaded. --- dlls/ws2_32/socket.c | 49 +++++++++++++++++++++++--- dlls/ws2_32/ws2_32_private.h | 14 ++++++++ server/sock.c | 66 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 5 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 5eb926a408b..026bb029328 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -226,6 +226,11 @@ const char *debugstr_sockaddr( const struct sockaddr *a ) addr, ((const SOCKADDR_IRDA *)a)->irdaServiceName); } + case AF_UNIX: + { + return wine_dbg_sprintf("{ family AF_UNIX, path %s }", + ((const SOCKADDR_UN *)a)->sun_path); + } default: return wine_dbg_sprintf("{ family %d }", a->sa_family); } @@ -1106,6 +1111,9 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) HANDLE sync_event; NTSTATUS status;
+ char *unix_path = NULL; + int unix_path_len = 0; + TRACE( "socket %#Ix, addr %s\n", s, debugstr_sockaddr(addr) );
if (!addr) @@ -1148,6 +1156,14 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) } break;
+ case AF_UNIX: + if (len < sizeof(struct sockaddr_un)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; + default: FIXME( "unknown protocol %u\n", addr->sa_family ); SetLastError( WSAEAFNOSUPPORT ); @@ -1156,8 +1172,16 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len )
if (!(sync_event = get_sync_event())) return -1;
- params = malloc( sizeof(int) + len ); - ret_addr = malloc( len ); + if (addr->sa_family == AF_UNIX && *addr->sa_data) + { + WCHAR *sun_pathW = strdupAtoW(addr->sa_data); + unix_path = wine_get_unix_file_name(sun_pathW); + unix_path_len = strlen(unix_path) + 1; + free(sun_pathW); + } + + params = malloc( sizeof(int) + len + unix_path_len ); + ret_addr = malloc( len + unix_path_len ); if (!params || !ret_addr) { free( params ); @@ -1167,9 +1191,11 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) } params->unknown = 0; memcpy( ¶ms->addr, addr, len ); + if (unix_path) + memcpy( params + 1, unix_path, unix_path_len );
status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_BIND, - params, sizeof(int) + len, ret_addr, len ); + params, sizeof(int) + len + unix_path_len, ret_addr, len + unix_path_len ); if (status == STATUS_PENDING) { if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) @@ -1222,11 +1248,22 @@ int WINAPI connect( SOCKET s, const struct sockaddr *addr, int len ) HANDLE sync_event; NTSTATUS status;
+ char *unix_path = NULL; + int unix_path_len = 0; + TRACE( "socket %#Ix, addr %s, len %d\n", s, debugstr_sockaddr(addr), len );
if (!(sync_event = get_sync_event())) return -1;
- if (!(params = malloc( sizeof(*params) + len ))) + if (addr->sa_family == AF_UNIX && *addr->sa_data) + { + WCHAR *sun_pathW = strdupAtoW(addr->sa_data); + unix_path = wine_get_unix_file_name(sun_pathW); + unix_path_len = strlen(unix_path) + 1; + free(sun_pathW); + } + + if (!(params = malloc( sizeof(*params) + len + unix_path_len ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return -1; @@ -1234,9 +1271,11 @@ int WINAPI connect( SOCKET s, const struct sockaddr *addr, int len ) params->addr_len = len; params->synchronous = TRUE; memcpy( params + 1, addr, len ); + if (unix_path_len) + memcpy( (char *)(params + 1) + len, unix_path, unix_path_len );
status = NtDeviceIoControlFile( (HANDLE)s, sync_event, NULL, NULL, &io, IOCTL_AFD_WINE_CONNECT, - params, sizeof(*params) + len, NULL, 0 ); + params, sizeof(*params) + len + unix_path_len, NULL, 0 ); free( params ); if (status == STATUS_PENDING) { diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 41d9e512488..0ded6a87efb 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -46,6 +46,7 @@ #include "mstcpip.h" #include "af_irda.h" #include "winnt.h" +#include "afunix.h" #define USE_WC_PREFIX /* For CMSG_DATA */ #include "iphlpapi.h" #include "ip2string.h" @@ -73,6 +74,19 @@ static inline char *strdupWtoA( const WCHAR *str ) return ret; }
+static inline WCHAR *strdupAtoW( const char *str ) +{ + WCHAR *ret = NULL; + if (str) + { + DWORD len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, NULL, 0); + if ((ret = malloc( len ))) + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, ret, len); + } + return ret; +} + + static const char magic_loopback_addr[] = {127, 12, 34, 56};
const char *debugstr_sockaddr( const struct sockaddr *addr ) DECLSPEC_HIDDEN; diff --git a/server/sock.c b/server/sock.c index 088e6d63079..25e72b003c1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -53,6 +53,7 @@ #include <time.h> #include <unistd.h> #include <limits.h> +#include <libgen.h> #ifdef HAVE_LINUX_FILTER_H # include <linux/filter.h> #endif @@ -83,6 +84,8 @@ # define HAS_IRDA #endif
+#include <sys/un.h> + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -93,6 +96,7 @@ #include "ws2tcpip.h" #include "wsipx.h" #include "af_irda.h" +#include "afunix.h" #include "wine/afd.h" #include "wine/rbtree.h"
@@ -116,6 +120,7 @@ union win_sockaddr struct WS_sockaddr_in6 in6; struct WS_sockaddr_ipx ipx; SOCKADDR_IRDA irda; + struct WS_sockaddr_un un; };
union unix_sockaddr @@ -129,6 +134,7 @@ union unix_sockaddr #ifdef HAS_IRDA struct sockaddr_irda irda; #endif + struct sockaddr_un un; };
static struct list poll_list = LIST_INIT( poll_list ); @@ -546,6 +552,17 @@ static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_socka } #endif
+ case AF_UNIX: + { + struct WS_sockaddr_un win = {0}; + + if (wsaddrlen < sizeof(win)) return -1; + win.sun_family = WS_AF_UNIX; + memcpy( win.sun_path, uaddr->un.sun_path, sizeof(win.sun_path) ); + memcpy( wsaddr, &win, sizeof(win) ); + return sizeof(win); + } + case AF_UNSPEC: return 0;
@@ -646,6 +663,17 @@ static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrl return sizeof(uaddr->in6); }
+ case WS_AF_UNIX: + { + struct WS_sockaddr_un win = {0}; + + if (wsaddrlen < sizeof(win)) return 0; + memcpy( &win, wsaddr, sizeof(win) ); + uaddr->un.sun_family = AF_UNIX; + memcpy( uaddr->un.sun_path, win.sun_path, sizeof(win.sun_path) ); + return sizeof(uaddr->un); + } + default: return 0; } @@ -672,6 +700,9 @@ static socklen_t get_unix_sockaddr_any( union unix_sockaddr *uaddr, int ws_famil uaddr->irda.sir_family = AF_IRDA; return sizeof(uaddr->irda); #endif + case WS_AF_UNIX: + uaddr->un.sun_family = AF_UNIX; + return sizeof(uaddr->un); default: return 0; } @@ -1757,6 +1788,7 @@ static int get_unix_family( int family ) #ifdef AF_IRDA case WS_AF_IRDA: return AF_IRDA; #endif + case WS_AF_UNIX: return AF_UNIX; case WS_AF_UNSPEC: return AF_UNSPEC; default: return -1; } @@ -2607,6 +2639,19 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (unix_addr.addr.sa_family == AF_INET && !memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 )) unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
+ if (sock->family == WS_AF_UNIX && *((char *)(params + 1) + params->addr_len)) + { + char *unix_path = (char *)(params + 1) + params->addr_len; + char unix_path_copy[PATH_MAX]; + strcpy(unix_path_copy, unix_path); + if (chdir( dirname( unix_path_copy ) ) == -1) + { + set_error( sock_get_ntstatus( errno ) ); + return; + } + memcpy( unix_addr.un.sun_path, basename( unix_path ), sizeof(unix_addr.un.sun_path) ); + } + ret = connect( unix_fd, &unix_addr.addr, unix_len ); if (ret < 0 && errno == ECONNABORTED) { @@ -2619,6 +2664,9 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ret = connect( unix_fd, &unix_addr.addr, unix_len ); }
+ if (sock->family == WS_AF_UNIX && *((char *)(params + 1) + params->addr_len)) + fchdir(server_dir_fd); + if (ret < 0 && errno != EINPROGRESS) { set_error( sock_get_ntstatus( errno ) ); @@ -2943,12 +2991,27 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (check_addr_usage( sock, &bind_addr, v6only )) return;
+ if (sock->family == WS_AF_UNIX && *(char *)(params + 1)) + { + char *unix_path = (char *)(params + 1); + char unix_path_copy[PATH_MAX]; + strcpy(unix_path_copy, unix_path); + if (chdir( dirname( unix_path_copy ) ) == -1) + { + set_error( sock_get_ntstatus( errno ) ); + return; + } + memcpy( unix_addr.un.sun_path, basename( unix_path ), sizeof(unix_addr.un.sun_path) ); + } + if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) { if (errno == EADDRINUSE && sock->reuseaddr) errno = EACCES;
set_error( sock_get_ntstatus( errno ) ); + if (sock->family == WS_AF_UNIX && *(char *)(params + 1)) + fchdir(server_dir_fd); return; }
@@ -2968,6 +3031,9 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
if (get_reply_max_size() >= sock->addr_len) set_reply_data( &sock->addr, sock->addr_len ); + + if (sock->family == WS_AF_UNIX && *(char *)(params + 1)) + fchdir(server_dir_fd); return; }