Skip to content

libassuan socket emulation file support #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ ssh-agent-adapter.VC.db
int
bin
.vs
*.vcxproj.user
.vscode
30 changes: 24 additions & 6 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ static void con_activity_done(connection* con) {
CloseHandle(con->np2uds_th);
CloseHandle(con->uds2np_th);
free(con);
log("connection closed");
}
}

Expand All @@ -33,25 +34,33 @@ DWORD WINAPI uds2np_thread(LPVOID param) {
ZeroMemory(&ol, sizeof(OVERLAPPED));
// read from pipe
if (!ReadFileEx(con->pipe, buf, BUFSIZE, &ol, apc_callback)) {
log("couldn't start read from pipe");
goto done;
}

SleepEx(INFINITE, TRUE);
bytes_read = 0;
if (con->abort_io || !GetOverlappedResult(con->pipe, &ol, &bytes_read, FALSE))
if (con->abort_io || !GetOverlappedResult(con->pipe, &ol, &bytes_read, FALSE)) {
log("couldn't get bytes from pipe, or read aborted");
goto done;
}
log("read %d bytes from pipe", bytes_read);

//now write to sock
bytes_written = 0;
while (bytes_written < bytes_read) {
int written = send(con->sock, buf + bytes_written, bytes_read - bytes_written, 0);
if (written == SOCKET_ERROR)
if (written == SOCKET_ERROR) {
log("error when writing to socket");
goto done;
}
bytes_written += written;
log("wrote %d (%d) of %d bytes to socket", written, bytes_written, bytes_read);
}
}

done:
log("shutting down socket");
shutdown(con->sock, SD_SEND);
con_activity_done(con);
return 0;
Expand All @@ -68,21 +77,30 @@ DWORD WINAPI np2uds_thread(LPVOID param) {
while (1) {
// read from sock
bytes_read = recv(con->sock, buf, BUFSIZE, 0);
if (bytes_read <= 0)
if (bytes_read <= 0) {
log("nothing to read from socket");
goto done;
}
log("read %d bytes from socket", bytes_read);

// now write to pipe
bytes_written = 0;
ZeroMemory(&ol, sizeof(OVERLAPPED));
if (!WriteFileEx(con->pipe, buf, bytes_read, &ol, apc_callback))
if (!WriteFileEx(con->pipe, buf, bytes_read, &ol, apc_callback)) {
log("can't start write to pipe");
goto done;

}

SleepEx(INFINITE, TRUE);
if (!GetOverlappedResult(con->pipe, &ol, &bytes_written, FALSE))
if (!GetOverlappedResult(con->pipe, &ol, &bytes_written, FALSE)) {
log("couldn't write to pipe");
goto done;
}
log("wrote %d of %d bytes to pipe", bytes_written, bytes_read);
}

done:
log("shutting down pipe");
QueueUserAPC(apc_abortio, con->uds2np_th, (ULONG_PTR)con);
con_activity_done(con);
return 0;
Expand Down
2 changes: 1 addition & 1 deletion common.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#define DEFAULT_BUFLEN 512

extern int debug_mode;
#define log(...) {if (debug_mode) { printf(__VA_ARGS__); printf("\n");} }
#define log(...) {if (debug_mode!=0) { printf(__VA_ARGS__); printf("\n");} }

typedef struct _connection {
HANDLE pipe;
Expand Down
127 changes: 103 additions & 24 deletions uds-2-np.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,68 @@
#include <assert.h>
#include "common.h"

#define LIBASSUAN_COOKIE_LEN 16

int uds_agent_port = 47010;
char* cookie = NULL;
int cookie_len = 0;

errno_t process_sock_file(wchar_t* filename) {
#define SHORT_BUFLEN 64

errno_t err;
FILE* sock_file;
size_t read_count, i, clen = 0;
char buf[SHORT_BUFLEN], *new_cookie = NULL;
int port;

err = _wfopen_s(&sock_file, filename, L"rb");
if (err != 0) {
return err;
}
read_count = fread_s(buf, SHORT_BUFLEN, sizeof(char), SHORT_BUFLEN/sizeof(char), sock_file);
fclose(sock_file);

port = atoi(buf);
if (port < 1 || port > 65535) {
err = errno;
return (err != 0) ? err : EINVAL;
}
uds_agent_port = (UINT)port;
log("gpg-agent is listening on port %d", uds_agent_port);

for (i = read_count; i && buf[i] != '\n'; i--, clen++) {
// loop until we hit newline character
}
i++; clen--; // cookie starts at buf[i] and goes for clen characters
log("cookie starts at charpos %d, length %d", i, read_count - i);
assert(clen == LIBASSUAN_COOKIE_LEN && read_count - i == LIBASSUAN_COOKIE_LEN);

new_cookie = malloc(clen);
if (new_cookie == NULL) {
return errno;
}
err = memcpy_s(new_cookie, clen, &buf[i], clen);
if (err != 0) {
free(new_cookie); new_cookie = NULL;
return errno;
}
assert(new_cookie[clen - 1] == buf[read_count - 1]);

if (cookie != NULL) {
free(cookie); cookie = NULL;
}
cookie = new_cookie;
cookie_len = clen;
return 0;

#undef SHORT_BUFLEN
}

void process_pipe_connection(connection* con) {
WSADATA wsaData;
struct sockaddr_in serv_addr;
int sc, err;

WSAStartup(MAKEWORD(2, 2), &wsaData);
con->sock = socket(AF_INET, SOCK_STREAM, 0);
Expand All @@ -17,7 +73,18 @@ void process_pipe_connection(connection* con) {

connect(con->sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

//TODO - write cookie
// write cookie
sc = send(con->sock, cookie, (int)cookie_len, 0);
if (sc == SOCKET_ERROR) {
err = WSAGetLastError();
printf("Cookie send failed: %d\n", err);
exit(1);
}
else if (sc != (int)cookie_len) {
printf("Cookie is %d bytes but %d bytes sent!\n", cookie_len, sc);
exit(1);
}
log("sent cookie to socket (length=%d)", sc);

//start threads
con->activity_count = 2;
Expand All @@ -27,24 +94,28 @@ void process_pipe_connection(connection* con) {

int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
wchar_t pipe_name[MAX_PATH];
#define MINIBUFLEN 16

wchar_t pipe_name[MAX_PATH], sock_name[MAX_PATH], errstr[MINIBUFLEN];
size_t sock_name_len;
errno_t err;
OVERLAPPED ol;
DWORD client_pid;

//spawn a child and give back control to cmd
if (argc == 1) {
wchar_t cmdline[MAX_PATH];
STARTUPINFOW si;
STARTUPINFOW si;
PROCESS_INFORMATION pi;

cmdline[0] = L'\0';
wcscat(cmdline, argv[0]);
wcscat(cmdline, L" -z");
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(STARTUPINFOW);
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(STARTUPINFOW);
ZeroMemory(&pi, sizeof(pi));
CreateProcessW(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
swprintf_s(pipe_name, MAX_PATH, L"SSH_AUTH_SOCK=\\\\.\\pipe\\usd-2-np-%d", pi.dwProcessId);
swprintf_s(pipe_name, MAX_PATH, L"SSH_AUTH_SOCK=\\\\.\\pipe\\uds-2-np-%d", pi.dwProcessId);
_wputenv(pipe_name);
printf("set %ls", pipe_name);
return 0;
Expand Down Expand Up @@ -74,35 +145,43 @@ int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
}
}

if ((err =_wgetenv_s(&sock_name_len, &sock_name, MAX_PATH, L"SSH_AUTH_SOCK")) != 0 || sock_name[0] == 0) {
printf("couldn't get original socket path\n");
exit(err);
}
if ((err = process_sock_file(&sock_name)) != 0) {
_wcserror_s(errstr, MINIBUFLEN, err);
printf("couldn't access socket %ls: %ls\n", sock_name, errstr);
exit(err);
}

//TODO - parse contents of file pointed by SSH_AUTH_SOCK env variable
// and read port and cookie info

swprintf_s(pipe_name, MAX_PATH, L"\\\\.\\pipe\\usd-2-np-%d", GetCurrentProcessId());
swprintf_s(pipe_name, MAX_PATH, L"\\\\.\\pipe\\uds-2-np-%d", GetCurrentProcessId());
ZeroMemory(&ol, sizeof(ol));
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
log("incomig connections to pipe: %ls", pipe_name);
log("incoming connections to pipe: %ls", pipe_name);
log("will be routed to 127.0.0.1:%d", uds_agent_port);
while (1) {
connection *con = (connection*)malloc(sizeof(connection));
ZeroMemory(con, sizeof(connection));
con->pipe = CreateNamedPipeW(
pipe_name, // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // message type pipe
PIPE_READMODE_BYTE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
while (1) {
connection *con = (connection*)malloc(sizeof(connection));
ZeroMemory(con, sizeof(connection));
con->pipe = CreateNamedPipeW(
pipe_name, // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // message type pipe
PIPE_READMODE_BYTE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL);

ConnectNamedPipe(con->pipe, &ol);
WaitForSingleObject(ol.hEvent, INFINITE);
GetNamedPipeClientProcessId(con->pipe, &client_pid);
log("connection accepted from pid:%d", client_pid);
process_pipe_connection(con);

#undef MINIBUFLEN
}

return 0;
Expand Down