diff --git a/contrib/win32/openssh/win32iocompat.vcxproj b/contrib/win32/openssh/win32iocompat.vcxproj
index 5573140daa29..58af537555ce 100644
--- a/contrib/win32/openssh/win32iocompat.vcxproj
+++ b/contrib/win32/openssh/win32iocompat.vcxproj
@@ -328,6 +328,7 @@
+
diff --git a/contrib/win32/openssh/win32iocompat.vcxproj.filters b/contrib/win32/openssh/win32iocompat.vcxproj.filters
index c727e636bca0..c9ec6cd264ba 100644
--- a/contrib/win32/openssh/win32iocompat.vcxproj.filters
+++ b/contrib/win32/openssh/win32iocompat.vcxproj.filters
@@ -24,6 +24,7 @@
+
diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c
index 2f62fa855478..84b1ec9eb220 100644
--- a/contrib/win32/win32compat/fileio.c
+++ b/contrib/win32/win32compat/fileio.c
@@ -106,6 +106,77 @@ errno_from_Win32Error(int win32_error)
}
}
+/* return 1 if the file is native a unix socket, 0 otherwise
+ detail = 1: AF_UNIX
+ detail = 2: PIPE - this may fail, so treat any value other than 1 and 3 as PIPE
+ detail = 3: FILE
+ */
+int fileio_is_afunix_socket(const char* name, int* detail)
+{
+ wchar_t* name_w = utf8_to_utf16(name);
+ int ret = 0;
+ int type;
+ HANDLE h;
+ FILE_ATTRIBUTE_TAG_INFO info;
+
+ if (name_w == NULL)
+ return 0;
+
+ if (detail != NULL)
+ *detail = 0;
+
+ h = CreateFileW(name_w,
+ 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ ret = 0;
+ debug("fileio_is_afunix_socket - ERROR: CreateFileW failed, error: 0x%08x", GetLastError());
+ goto clean;
+ }
+
+ if (GetFileInformationByHandleEx(h, FileAttributeTagInfo, &info, sizeof(info)) != FALSE) {
+ if (info.ReparseTag == IO_REPARSE_TAG_AF_UNIX) {
+ ret = 1;
+ if (detail != NULL)
+ *detail = 1;
+ goto clean;
+ }
+ }else{
+ ret = 0;
+ debug("fileio_is_afunix_socket - ERROR: GetFileInformationByHandleEx failed, error: 0x%08x", GetLastError());
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ type = GetFileType(h);
+ if(GetLastError() != ERROR_SUCCESS) {
+ ret = 0;
+ debug("fileio_is_afunix_socket - ERROR: GetFileType failed, error: 0x%08x", GetLastError());
+ goto clean;
+ }
+
+ if (type == FILE_TYPE_PIPE) {
+ ret = 0;
+ if (detail != NULL)
+ *detail = 2;
+ goto clean;
+ } else if (type == FILE_TYPE_DISK) {
+ ret = 0;
+ if (detail != NULL)
+ *detail = 3;
+ goto clean;
+ }
+
+clean:
+ if (name_w)
+ free(name_w);
+ if (h != INVALID_HANDLE_VALUE)
+ CloseHandle(h);
+ return ret;
+}
+
struct w32_io*
fileio_afunix_socket()
{
diff --git a/contrib/win32/win32compat/lxss.c b/contrib/win32/win32compat/lxss.c
new file mode 100644
index 000000000000..02071ed94b28
--- /dev/null
+++ b/contrib/win32/win32compat/lxss.c
@@ -0,0 +1,92 @@
+
+#include "w32fd.h"
+#include "inc\utf.h"
+#include "misc_internal.h"
+#include "debug.h"
+
+#include
+#include
+#include
+
+
+static const NTSTATUS STATUS_SUCCESS = 0;
+
+#define MAX_EA_INFO_SIZE 64
+
+#pragma pack(push, 1)
+typedef struct _FILE_FULL_EA_INFORMATION {
+ ULONG NextEntryOffset;
+ BYTE Flags;
+ BYTE EaNameLength;
+ USHORT EaValueLength;
+ CHAR EaName[1];
+} FILE_FULL_EA_INFORMATION, * PFILE_FULL_EA_INFORMATION;
+
+#pragma pack(pop)
+
+typedef
+NTSTATUS
+(NTAPI* NtSetEaFileFn)(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PVOID EaBuffer,
+ IN ULONG EaBufferSize);
+
+struct ea_keyvalue {
+ const char* name;
+ const char* value;
+ ULONG value_len;
+};
+
+static void lxss_set_ea_info(wchar_t* path, char* buffer, ULONG length, int reparse){
+ IO_STATUS_BLOCK ioStatus;
+ NTSTATUS r;
+ HMODULE hmod = GetModuleHandleW(L"ntdll.dll");
+ if (hmod == NULL)
+ return;
+ NtSetEaFileFn NtSetEaFile = (NtSetEaFileFn)GetProcAddress(hmod, "NtSetEaFile");
+ if (NtSetEaFile == NULL)
+ return;
+ HANDLE file = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | (reparse ? FILE_FLAG_OPEN_REPARSE_POINT : 0), NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ return;
+
+ r = NtSetEaFile(file, &ioStatus, buffer, length);
+ if (r != STATUS_SUCCESS)
+ return;
+ CloseHandle(file);
+}
+
+void lxss_set_perm(wchar_t* path, int reparse, ULONG uid, ULONG gid, ULONG mode){
+ struct ea_keyvalue** p;
+ struct ea_keyvalue* ea[4]; // **
+ int count = 0;
+ struct ea_keyvalue uid_ea = {"$LXUID", (char*)&uid, sizeof(uid)};
+ struct ea_keyvalue gid_ea = {"$LXGID", (char*)&gid, sizeof(gid)};
+ struct ea_keyvalue mode_ea = {"$LXMOD", (char*)&mode, sizeof(mode)};
+ FILE_FULL_EA_INFORMATION* ea_info = NULL;
+ ea[0] = &uid_ea;
+ ea[1] = &gid_ea;
+ ea[2] = &mode_ea;
+ ea[3] = NULL;
+ __declspec(align(16)) char buffer[MAX_EA_INFO_SIZE * sizeof(ea) / sizeof(ea[0])];
+ char *pb = buffer;
+
+ for (p = ea; *p != NULL; p++) {
+ ea_info = (FILE_FULL_EA_INFORMATION*)pb;
+ ea_info->NextEntryOffset = MAX_EA_INFO_SIZE;
+ ea_info->Flags = 0;
+ ea_info->EaNameLength = (BYTE)strlen((*p)->name);
+ ea_info->EaValueLength = (USHORT)(*p)->value_len;
+ memcpy(ea_info->EaName, (*p)->name, ea_info->EaNameLength);
+ memcpy(ea_info->EaName + ea_info->EaNameLength, (*p)->value, (*p)->value_len);
+ pb += MAX_EA_INFO_SIZE;
+ ++count;
+ }
+ // mark last info
+ if (ea_info)
+ ea_info->NextEntryOffset = 0;
+ lxss_set_ea_info(path, buffer, count * MAX_EA_INFO_SIZE, reparse);
+}
diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c
index 861ee2d585e4..2743f0a04bdd 100644
--- a/contrib/win32/win32compat/misc.c
+++ b/contrib/win32/win32compat/misc.c
@@ -955,6 +955,8 @@ realpath(const char *inputpath, char * resolved)
{
wchar_t* temppath_utf16 = NULL;
wchar_t* resolved_utf16 = NULL;
+ DWORD temppath_len = 0;
+ char* temppath_utf8 = NULL;
char path[PATH_MAX] = { 0, }, tempPath[PATH_MAX] = { 0, }, *ret = NULL;
int is_win_path = 1;
@@ -972,6 +974,25 @@ realpath(const char *inputpath, char * resolved)
if (is_bash_test_env() && bash_to_win_path(inputpath, path, _countof(path)))
is_win_path = 0;
+ if (_strnicmp(inputpath, TMP_DIR, strlen(TMP_DIR)) == 0) {
+ /* if input path is TMP_DIR, replace TMP_DIR with GetTempPath() */
+ temppath_utf16 = malloc(sizeof(wchar_t) * MAX_PATH + 1);
+ temppath_len = GetTempPathW(MAX_PATH, temppath_utf16);
+ if (temppath_len > 0 && temppath_len < MAX_PATH)
+ {
+ temppath_utf8 = utf16_to_utf8(temppath_utf16);
+ if (temppath_utf8 != NULL)
+ {
+ strcpy_s(path, PATH_MAX, temppath_utf8);
+ strcat_s(path, PATH_MAX, &inputpath[strlen(TMP_DIR)]);
+ is_win_path = 0;
+ free(temppath_utf8);
+ }
+ }
+ free(temppath_utf16);
+ temppath_utf16 = NULL;
+ }
+
if (is_win_path) {
if (_strnicmp(inputpath, PROGRAM_DATA, strlen(PROGRAM_DATA)) == 0) {
strcpy_s(path, PATH_MAX, __progdata);
diff --git a/contrib/win32/win32compat/misc_internal.h b/contrib/win32/win32compat/misc_internal.h
index 5a43a992e820..a27d01b96aa3 100644
--- a/contrib/win32/win32compat/misc_internal.h
+++ b/contrib/win32/win32compat/misc_internal.h
@@ -12,6 +12,8 @@
#define NULL_DEVICE "/dev/null"
#define NULL_DEVICE_WIN "NUL"
+#define TMP_DIR "/tmp/"
+
#define IsWin7OrLess() (!IsWindows8OrGreater())
#define IS_INVALID_HANDLE(h) ( ((NULL == h) || (INVALID_HANDLE_VALUE == h)) ? 1 : 0 )
diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c
index c4eceaea8f71..f49a584ff52a 100644
--- a/contrib/win32/win32compat/socketio.c
+++ b/contrib/win32/win32compat/socketio.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include "w32fd.h"
#include "inc\utf.h"
#include "misc_internal.h"
@@ -43,6 +44,17 @@
#define INTERNAL_RECV_BUFFER_SIZE 70*1024 //70KB
#define errno_from_WSALastError() errno_from_WSAError(WSAGetLastError())
+#define CHECK_NAMEDPIPE(pio, retv) do { \
+ errno = 0; \
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) { \
+ errno = ENOTSUP; \
+ debug(__FILE__ ":%d: Named pipes are not supported", __LINE__); \
+ return retv; \
+ } \
+} while (0)
+
+void lxss_set_perm(wchar_t* path, int reparse, ULONG uid, ULONG gid, ULONG mode);
+
/* state info that needs to be persisted for an inprocess acceptEx call*/
struct acceptEx_context {
char lpOutputBuf[1024];
@@ -83,6 +95,70 @@ errno_from_WSAError(int wsaerrno)
}
}
+static int
+socketio_parse_assuan(const char* path, struct sockaddr_in* addr, char* nonce)
+{
+ int port;
+ FILE* fp = fopen(path, "rb");
+ if (fp == NULL) {
+ errno = EINVAL;
+ error("connect: assuan - ERROR: fopen failed:%d", errno);
+ return -1;
+ }
+ fscanf(fp, "%d", &port);
+ fgetc(fp); // skip \n
+ if (fread(nonce, 1, 16, fp) != 16) {
+ errno = EINVAL;
+ error("connect: assuan - ERROR: invalid nonce");
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ debug("connect: assuan - parsed: port:%d, nonce:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ port, (unsigned char)nonce[0], (unsigned char)nonce[1], (unsigned char)nonce[2],
+ (unsigned char)nonce[3], (unsigned char)nonce[4], (unsigned char)nonce[5],
+ (unsigned char)nonce[6], (unsigned char)nonce[7], (unsigned char)nonce[8],
+ (unsigned char)nonce[9], (unsigned char)nonce[10], (unsigned char)nonce[11],
+ (unsigned char)nonce[12], (unsigned char)nonce[13], (unsigned char)nonce[14],
+ (unsigned char)nonce[15]);
+ return 0;
+}
+
+static void
+socketio_fixup_sun_addr(const struct sockaddr_un* orig, struct sockaddr_un* out)
+{
+ memcpy(out, orig, sizeof(struct sockaddr_un));
+ char* resolved;
+ size_t resolved_len;
+ if (strncmp(orig->sun_path, "/nt:", 4) == 0) {
+ /* this is a special windows path used in forward spec
+ strip this prefix */
+ memcpy(out->sun_path, orig->sun_path + 4, sizeof(out->sun_path) - 4);
+ memset(out->sun_path + sizeof(out->sun_path) - 4, 0, 4);
+ } else if (strncmp(orig->sun_path, "\\\\?\\", 4 ) == 0 ||
+ strncmp(orig->sun_path, "\\\\.\\", 4) == 0) {
+ /* if it starts with \\.\ or \\?\,
+ leave it as-is (default agent NamedPipe path) */
+ return;
+ } else {
+ /* resolve the path */
+ resolved = resolved_path_utf8(orig->sun_path);
+ if (resolved)
+ {
+ resolved_len = strlen(resolved);
+ if (resolved_len < sizeof(out->sun_path))
+ {
+ /* replace out->sun_path */
+ strcpy_s(out->sun_path, sizeof(out->sun_path), resolved);
+ }
+ free(resolved);
+ }
+ }
+}
+
/* called before any other calls to socketio_ functions */
int
socketio_initialize()
@@ -118,7 +194,7 @@ socketio_acceptEx(struct w32_io* pio)
}
/* create accepting socket */
- context->accept_socket = socket(addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+ context->accept_socket = socket(addr.ss_family, SOCK_STREAM, addr.ss_family == AF_UNIX ? 0 : IPPROTO_TCP);
if (context->accept_socket == INVALID_SOCKET) {
errno = errno_from_WSALastError();
debug3("acceptEx - socket() ERROR:%d, io:%p", WSAGetLastError(), pio);
@@ -257,6 +333,7 @@ socketio_socket(int domain, int type, int protocol)
int
socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optval, int optlen)
{
+ CHECK_NAMEDPIPE(pio, -1);
if ((optname == SO_KEEPALIVE) || (optname == SO_REUSEADDR) ||
(optname == TCP_NODELAY) || (optname == IPV6_V6ONLY))
SET_ERRNO_ON_ERROR(setsockopt(pio->sock, level, optname, optval, optlen));
@@ -271,6 +348,7 @@ socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optv
int
socketio_getsockopt(struct w32_io* pio, int level, int optname, char* optval, int* optlen)
{
+ CHECK_NAMEDPIPE(pio, -1);
SET_ERRNO_ON_ERROR(getsockopt(pio->sock, level, optname, optval, optlen));
}
@@ -278,6 +356,7 @@ socketio_getsockopt(struct w32_io* pio, int level, int optname, char* optval, in
int
socketio_getsockname(struct w32_io* pio, struct sockaddr* name, int* namelen)
{
+ CHECK_NAMEDPIPE(pio, -1);
SET_ERRNO_ON_ERROR(getsockname(pio->sock, name, namelen));
}
@@ -285,6 +364,7 @@ socketio_getsockname(struct w32_io* pio, struct sockaddr* name, int* namelen)
int
socketio_getpeername(struct w32_io* pio, struct sockaddr* name, int* namelen)
{
+ CHECK_NAMEDPIPE(pio, -1);
SET_ERRNO_ON_ERROR(getpeername(pio->sock, name, namelen));
}
@@ -294,6 +374,10 @@ socketio_listen(struct w32_io* pio, int backlog)
{
struct acceptEx_context* context;
+ if (pio->internal.subtype == SOCKET_SUBTYPE_UNKNOWN)
+ pio->internal.subtype = SOCKET_SUBTYPE_GENERIC;
+ CHECK_NAMEDPIPE(pio, -1);
+
if (SOCKET_ERROR == listen(pio->sock, backlog)) {
errno = errno_from_WSALastError();
debug3("listen - listen() ERROR:%d io:%p", WSAGetLastError(), pio);
@@ -355,6 +439,26 @@ socketio_listen(struct w32_io* pio, int backlog)
int
socketio_bind(struct w32_io* pio, const struct sockaddr *name, int namelen)
{
+ struct sockaddr_un sun_addr;
+ wchar_t *w_path;
+ if (pio->internal.subtype == SOCKET_SUBTYPE_UNKNOWN)
+ pio->internal.subtype = SOCKET_SUBTYPE_GENERIC;
+ CHECK_NAMEDPIPE(pio, -1);
+
+ if (name->sa_family == AF_UNIX) {
+ socketio_fixup_sun_addr((const struct sockaddr_un*)name, &sun_addr);
+ name = (struct sockaddr*)&sun_addr;
+ namelen = sizeof(struct sockaddr_un);
+
+ w_path = utf8_to_utf16(sun_addr.sun_path);
+ if (w_path) {
+ // set Lxss Permission Info
+ // uid(1000), gid(1000), mode(0700)
+ lxss_set_perm(w_path, TRUE, 1000, 1000, 0700);
+ free(w_path);
+ }
+ }
+
SET_ERRNO_ON_ERROR(bind(pio->sock, name, namelen));
}
@@ -378,6 +482,10 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags)
return -1;
}
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) {
+ return fileio_read(pio->internal.proxy_io, buf, len);
+ }
+
/* TODO - ensure socket is in accepted or connected state */
/* /io is initiated and pending */
if (pio->read_details.pending) {
@@ -533,6 +641,10 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags)
return -1;
}
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) {
+ return fileio_write_wrapper(pio->internal.proxy_io, buf, len);
+ }
+
/* TODO - ensure socket is in accepted or connected state */
/* if io is already pending */
if (pio->write_details.pending) {
@@ -623,6 +735,8 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags)
int
socketio_shutdown(struct w32_io* pio, int how)
{
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE)
+ return 0; /* named pipe does not support it */
SET_ERRNO_ON_ERROR(shutdown(pio->sock, how));
}
@@ -631,6 +745,9 @@ int
socketio_close(struct w32_io* pio)
{
debug4("close - io:%p", pio);
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) {
+ fileio_close(pio->internal.proxy_io);
+ }
closesocket(pio->sock);
/* wait for pending io to abort */
SleepEx(0, TRUE);
@@ -675,6 +792,8 @@ socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen)
int local_address_len, remote_address_len;
errno_t r = 0;
+ CHECK_NAMEDPIPE(pio, NULL);
+
debug5("accept - io:%p", pio);
/* start io if not already started */
if (pio->read_details.pending == FALSE) {
@@ -759,6 +878,7 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen)
struct sockaddr_in tmp_addr4;
struct sockaddr_in6 tmp_addr6;
+ struct sockaddr_un tmp_un;
SOCKADDR* tmp_addr;
size_t tmp_addr_len;
DWORD tmp_bytes;
@@ -778,6 +898,11 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen)
tmp_addr4.sin_port = 0;
tmp_addr = (SOCKADDR*)&tmp_addr4;
tmp_addr_len = sizeof(tmp_addr4);
+ } else if (name->sa_family == AF_UNIX) {
+ ZeroMemory(&tmp_un, sizeof(tmp_un));
+ tmp_un.sun_family = AF_UNIX;
+ tmp_addr = (SOCKADDR*)&tmp_un;
+ tmp_addr_len = sizeof(tmp_un);
} else {
errno = ENOTSUP;
debug3("connectex - ERROR: unsuppored address family:%d, io:%p", name->sa_family, pio);
@@ -832,10 +957,71 @@ socketio_connectex(struct w32_io* pio, const struct sockaddr* name, int namelen)
return 0;
}
+
/* connect implementation */
int
socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namelen)
{
+ int detail = 0;
+ struct sockaddr_in synth_addr;
+ struct sockaddr_un sun_addr;
+
+ if (pio->internal.subtype == SOCKET_SUBTYPE_UNKNOWN)
+ {
+ if (name->sa_family == AF_UNIX)
+ {
+ if (namelen < sizeof(struct sockaddr_un))
+ {
+ errno = EINVAL;
+ debug("connect - ERROR: invalid sockaddr_un, io:%p", pio);
+ return -1;
+ }
+
+ const struct sockaddr_un* sun = (const struct sockaddr_un*)name;
+ socketio_fixup_sun_addr(sun, &sun_addr);
+ name = (const struct sockaddr*)&sun_addr;
+ namelen = sizeof(sun_addr);
+ sun = (const struct sockaddr_un*)&sun_addr;
+
+ if (fileio_is_afunix_socket(sun->sun_path, &detail)) {
+ pio->internal.subtype = SOCKET_SUBTYPE_GENERIC;
+ debug("connect - AF_UNIX socket, path:%s", sun->sun_path);
+ } else {
+ if (detail == 3) {
+ // parse assuan file
+ debug("connect - AF_UNIX assuan file, path:%s", sun->sun_path);
+ if (-1 == socketio_parse_assuan(sun->sun_path, &synth_addr, pio->internal.assuan_nonce)) {
+ errno = EINVAL;
+ debug("connect: assuan - ERROR: parse assuan file failed:%d, io:%p", errno, pio);
+ return -1;
+ }
+ pio->internal.subtype = SOCKET_SUBTYPE_ASSUAN;
+ // replace socket
+ closesocket(pio->sock);
+ pio->sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (pio->sock == INVALID_SOCKET) {
+ errno = WSAGetLastError();
+ debug("connect - ERROR: socket failed:%d, io:%p", WSAGetLastError(), pio);
+ return -1;
+ }
+ name = (const struct sockaddr*)&synth_addr;
+ namelen = sizeof(synth_addr);
+ } else {
+ debug("connect - AF_UNIX named pipe, path:%s", sun->sun_path);
+ pio->internal.subtype = SOCKET_SUBTYPE_NAMEDPIPE;
+ pio->internal.proxy_io = fileio_afunix_socket();
+ if (pio->internal.proxy_io == NULL) {
+ errno = ENOMEM;
+ debug("connect - ERROR: out of memory for named pipe, io:%p", pio);
+ return -1;
+ }
+ return fileio_connect(pio->internal.proxy_io, sun->sun_path);
+ }
+ }
+ } else {
+ pio->internal.subtype = SOCKET_SUBTYPE_GENERIC;
+ }
+ }
debug5("connect - io:%p", pio);
if (pio->write_details.pending == FALSE) {
@@ -892,6 +1078,19 @@ socketio_finish_connect(struct w32_io* pio)
ZeroMemory(&pio->write_details, sizeof(pio->write_details));
pio->internal.state = SOCK_READY;
+
+ if (!wsa_error) {
+ // connected
+ if (pio->internal.subtype == SOCKET_SUBTYPE_ASSUAN) {
+ // send assuan nonce
+ if (-1 == socketio_send(pio, pio->internal.assuan_nonce, sizeof(pio->internal.assuan_nonce), 0)) {
+ wsa_error = WSAGetLastError();
+ debug3("finish_connect - ERROR: send assuan nonce failed:%d, io:%p", wsa_error, pio);
+ goto done;
+ }
+ }
+ }
+
return (wsa_error? -1 : 0);
}
@@ -899,6 +1098,10 @@ socketio_finish_connect(struct w32_io* pio)
BOOL
socketio_is_io_available(struct w32_io* pio, BOOL rd)
{
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE && pio->internal.proxy_io) {
+ return fileio_is_io_available(pio->internal.proxy_io, rd);
+ }
+
if ((pio->internal.state == SOCK_LISTENING) ||
(pio->internal.state == SOCK_CONNECTING)) {
DWORD numBytes = 0;
@@ -943,6 +1146,12 @@ void
socketio_on_select(struct w32_io* pio, BOOL rd)
{
enum w32_io_sock_state sock_state = pio->internal.state;
+
+ if (pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) {
+ fileio_on_select(pio->internal.proxy_io, rd);
+ return;
+ }
+
debug4("on_select - io:%p type:%d rd:%d", pio, pio->type, rd);
/* nothing to do for writes (that includes connect) */
diff --git a/contrib/win32/win32compat/w32fd.c b/contrib/win32/win32compat/w32fd.c
index b4c436864dc4..b341bf099499 100644
--- a/contrib/win32/win32compat/w32fd.c
+++ b/contrib/win32/win32compat/w32fd.c
@@ -316,17 +316,11 @@ w32_socket(int domain, int type, int protocol)
if (min_index == -1)
return -1;
- if (domain == AF_UNIX && type == SOCK_STREAM) {
- pio = fileio_afunix_socket();
- if (pio == NULL)
- return -1;
- pio->type = NONSOCK_FD;
- } else {
- pio = socketio_socket(domain, type, protocol);
- if (pio == NULL)
- return -1;
- pio->type = SOCK_FD;
- }
+ pio = socketio_socket(domain, type, protocol);
+ if (pio == NULL)
+ return -1;
+ pio->type = SOCK_FD;
+ pio->internal.subtype = SOCKET_SUBTYPE_UNKNOWN;
fd_table_set(pio, min_index);
debug4("socket:%d, socktype:%d, io:%p, fd:%d ", pio->sock, type, pio, min_index);
@@ -344,12 +338,6 @@ w32_accept(int fd, struct sockaddr* addr, int* addrlen)
if (min_index == -1)
return -1;
- if (fd_table.w32_ios[fd]->type == NONSOCK_FD) {
- errno = ENOTSUP;
- verbose("Unix domain server sockets are not supported");
- return -1;
- }
-
pio = socketio_accept(fd_table.w32_ios[fd], addr, addrlen);
if (!pio)
return -1;
@@ -410,12 +398,6 @@ int
w32_bind(int fd, const struct sockaddr *name, int namelen)
{
CHECK_FD(fd);
- if (fd_table.w32_ios[fd]->type == NONSOCK_FD) {
- errno = ENOTSUP;
- verbose("Unix domain server sockets are not supported");
- return -1;
- }
-
CHECK_SOCK_IO(fd_table.w32_ios[fd]);
return socketio_bind(fd_table.w32_ios[fd], name, namelen);
}
@@ -424,12 +406,6 @@ int
w32_connect(int fd, const struct sockaddr* name, int namelen)
{
CHECK_FD(fd);
-
- if (fd_table.w32_ios[fd]->type == NONSOCK_FD) {
- struct sockaddr_un* addr = (struct sockaddr_un*)name;
- return fileio_connect(fd_table.w32_ios[fd], addr->sun_path);
- }
-
CHECK_SOCK_IO(fd_table.w32_ios[fd]);
return socketio_connect(fd_table.w32_ios[fd], name, namelen);
}
@@ -438,7 +414,6 @@ int
w32_recv(int fd, void *buf, size_t len, int flags)
{
CHECK_FD(fd);
-
CHECK_SOCK_IO(fd_table.w32_ios[fd]);
return socketio_recv(fd_table.w32_ios[fd], buf, len, flags);
}
@@ -688,6 +663,9 @@ w32_io_process_fd_flags(struct w32_io* pio, int flags)
}
pio->fd_flags = flags;
+ if (pio->type == SOCK_FD && pio->internal.subtype == SOCKET_SUBTYPE_NAMEDPIPE) {
+ return w32_io_process_fd_flags(pio->internal.proxy_io, flags);
+ }
return 0;
}
diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h
index 0f1ee3a08f62..4244c85e0063 100644
--- a/contrib/win32/win32compat/w32fd.h
+++ b/contrib/win32/win32compat/w32fd.h
@@ -65,10 +65,18 @@ enum w32_io_sock_state {
SOCK_READY = 3 /*recv and send can be done*/
};
+enum w32_io_sock_subtype {
+ SOCKET_SUBTYPE_UNKNOWN = 0,
+ SOCKET_SUBTYPE_GENERIC = 1,
+ SOCKET_SUBTYPE_NAMEDPIPE = 2,
+ SOCKET_SUBTYPE_ASSUAN = 3
+};
+
/*
* This structure encapsulates the I/O state info needed to map a File Descriptor
* to Win32 Handle
*/
+struct w32_io;
struct w32_io {
OVERLAPPED read_overlapped;
OVERLAPPED write_overlapped;
@@ -118,6 +126,11 @@ struct w32_io {
struct {
enum w32_io_sock_state state;
void* context;
+
+ enum w32_io_sock_subtype subtype;
+ struct w32_io* proxy_io;
+ char assuan_nonce[16];
+ int assuan_nonce_sent;
}internal;
};
@@ -167,4 +180,5 @@ long fileio_lseek(struct w32_io* pio, unsigned __int64 offset, int origin);
FILE* fileio_fdopen(struct w32_io* pio, const char *mode);
ssize_t fileio_readlink(const char *path, char *buf, size_t bufsiz);
int fileio_symlink(const char *target, const char *linkpath);
-int fileio_link(const char *oldpath, const char *newpath);
\ No newline at end of file
+int fileio_link(const char *oldpath, const char *newpath);
+int fileio_is_afunix_socket(const char* name, int* detail);