Skip to content

Commit

Permalink
agent: Add support for Windows OpenSSH agent
Browse files Browse the repository at this point in the history
  • Loading branch information
yodaldevoid committed Sep 14, 2020
1 parent ecd6a74 commit b84a940
Showing 1 changed file with 159 additions and 0 deletions.
159 changes: 159 additions & 0 deletions src/agent.c
Expand Up @@ -50,6 +50,9 @@
#endif
#include "userauth.h"
#include "session.h"
#ifdef WIN32
#include <stdlib.h>
#endif

/* Requests from client to agent for protocol 1 key operations */
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
Expand Down Expand Up @@ -362,6 +365,161 @@ struct agent_ops agent_ops_pageant = {
agent_transact_pageant,
agent_disconnect_pageant
};

/* Code to talk to OpenSSH was taken from Portable OpenSSH.
*
* TODO: copyright information
*/

#define WIN32_OPENSSH_AGENT_SOCK "\\\\.\\pipe\\openssh-ssh-agent"

static HANDLE win32_openssh_socket_handle = INVALID_HANDLE_VALUE;

static int
agent_connect_openssh(LIBSSH2_AGENT *agent)
{
int ret = LIBSSH2_ERROR_NONE;
const char *path;
HANDLE h = INVALID_HANDLE_VALUE;

path = agent->identity_agent_path;
if(!path) {
path = getenv("SSH_AUTH_SOCK");
if(!path)
path = WIN32_OPENSSH_AGENT_SOCK;
}

while(1) {
h = CreateFileA(
path,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
// FILE_FLAG_OVERLAPPED |
SECURITY_SQOS_PRESENT |
SECURITY_IDENTIFICATION,
NULL
);

if(h != INVALID_HANDLE_VALUE)
break;
if(GetLastError() != ERROR_PIPE_BUSY)
break;

// Wait up to 1 second for a pipe instance to become available
if(!WaitNamedPipeA(path, 1000))
break;
}

if(h == INVALID_HANDLE_VALUE) {
ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
"unable to connect to agent pipe");
goto cleanup;
}

if(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0) == FALSE) {
ret = _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
"unable to set handle information of agent pipe");
goto cleanup;
}

win32_openssh_socket_handle = h;
h = INVALID_HANDLE_VALUE;
agent->fd = 0; /* Mark as the connection has been established */

cleanup:
if(h != INVALID_HANDLE_VALUE)
CloseHandle(h);
return ret;
}

// TODO: async operations
static int
agent_transact_openssh(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
{
unsigned char buf[4];

/* Send the length of the request */
if(transctx->state == agent_NB_state_request_created) {
_libssh2_htonu32(buf, transctx->request_len);
if(!WriteFile(win32_openssh_socket_handle, buf, 4, NULL, NULL)) {
if(ERROR_IO_PENDING == GetLastError())
return LIBSSH2_ERROR_EAGAIN;

return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
"agent send failed");
}
transctx->state = agent_NB_state_request_length_sent;
}

/* Send the request body */
if(transctx->state == agent_NB_state_request_length_sent) {
if(!WriteFile(win32_openssh_socket_handle, transctx->request,
transctx->request_len, NULL, NULL)) {
if(ERROR_IO_PENDING == GetLastError())
return LIBSSH2_ERROR_EAGAIN;

return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
"agent send failed");
}
transctx->state = agent_NB_state_request_sent;
}

/* Receive the length of the body */
if(transctx->state == agent_NB_state_request_sent) {
if(!ReadFile(win32_openssh_socket_handle, buf, 4, NULL, NULL)) {
if(ERROR_IO_PENDING == GetLastError())
return LIBSSH2_ERROR_EAGAIN;

return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
"agent recv failed");
}
transctx->response_len = _libssh2_ntohu32(buf);
transctx->response = LIBSSH2_ALLOC(agent->session,
transctx->response_len);
if(!transctx->response)
return LIBSSH2_ERROR_ALLOC;

transctx->state = agent_NB_state_response_length_received;
}

/* Receive the response body */
if(transctx->state == agent_NB_state_response_length_received) {
if(!ReadFile(win32_openssh_socket_handle, transctx->response,
transctx->response_len, NULL, NULL)) {
if(ERROR_IO_PENDING == GetLastError())
return LIBSSH2_ERROR_EAGAIN;

return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
"agent recv failed");
}
transctx->state = agent_NB_state_response_received;
}

return LIBSSH2_ERROR_NONE;
}

static int
agent_disconnect_openssh(LIBSSH2_AGENT *agent)
{
if(!CancelIo(win32_openssh_socket_handle))
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
"failed to cancel pending IO of agent pipe");
/* let queued APCs (if any) drain */
SleepEx(0, TRUE);
if(!CloseHandle(win32_openssh_socket_handle))
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
"failed to close handle to agent pipe");

return LIBSSH2_ERROR_NONE;
}

struct agent_ops agent_ops_openssh = {
agent_connect_openssh,
agent_transact_openssh,
agent_disconnect_openssh
};
#endif /* WIN32 */

static struct {
Expand All @@ -370,6 +528,7 @@ static struct {
} supported_backends[] = {
#ifdef WIN32
{"Pageant", &agent_ops_pageant},
{"OpenSSH", &agent_ops_openssh},
#endif /* WIN32 */
#ifdef PF_UNIX
{"Unix", &agent_ops_unix},
Expand Down

0 comments on commit b84a940

Please sign in to comment.