From 95c30ebc9c19cfe91f69e3cdc80c4d82acbcdbcf Mon Sep 17 00:00:00 2001 From: KingToolbox Date: Sun, 18 Oct 2020 15:39:32 +0800 Subject: [PATCH] Add support for pageant in libssh. --- src/libssh/include/libssh/agent.h | 4 +- src/libssh/include/libssh/legacy.h | 2 - src/libssh/include/libssh/libssh.h | 4 +- src/libssh/src/agent.c | 107 +++++++++++++++++++++++++++-- src/libssh/src/pki.c | 2 - src/libssh/src/session.c | 6 -- 6 files changed, 105 insertions(+), 20 deletions(-) diff --git a/src/libssh/include/libssh/agent.h b/src/libssh/include/libssh/agent.h index d4eefbb..39342be 100644 --- a/src/libssh/include/libssh/agent.h +++ b/src/libssh/include/libssh/agent.h @@ -71,13 +71,14 @@ #define SSH_AGENT_RSA_SHA2_512 0x04 struct ssh_agent_struct { +#ifndef _WIN32 struct ssh_socket_struct *sock; +#endif ssh_buffer ident; unsigned int count; ssh_channel channel; }; -#ifndef _WIN32 /* agent.c */ /** * @brief Create a new ssh agent structure. @@ -115,6 +116,5 @@ ssh_key ssh_agent_get_first_ident(struct ssh_session_struct *session, ssh_string ssh_agent_sign_data(ssh_session session, const ssh_key pubkey, struct ssh_buffer_struct *data); -#endif #endif /* __AGENT_H */ diff --git a/src/libssh/include/libssh/legacy.h b/src/libssh/include/libssh/legacy.h index 911173e..5c15134 100644 --- a/src/libssh/include/libssh/legacy.h +++ b/src/libssh/include/libssh/legacy.h @@ -34,10 +34,8 @@ typedef struct ssh_public_key_struct* ssh_public_key; LIBSSH_API int ssh_auth_list(ssh_session session); LIBSSH_API int ssh_userauth_offer_pubkey(ssh_session session, const char *username, int type, ssh_string publickey); LIBSSH_API int ssh_userauth_pubkey(ssh_session session, const char *username, ssh_string publickey, ssh_private_key privatekey); -#ifndef _WIN32 LIBSSH_API int ssh_userauth_agent_pubkey(ssh_session session, const char *username, ssh_public_key publickey); -#endif LIBSSH_API int ssh_userauth_autopubkey(ssh_session session, const char *passphrase); LIBSSH_API int ssh_userauth_privatekey_file(ssh_session session, const char *username, const char *filename, const char *passphrase); diff --git a/src/libssh/include/libssh/libssh.h b/src/libssh/include/libssh/libssh.h index d077668..5b9ad50 100644 --- a/src/libssh/include/libssh/libssh.h +++ b/src/libssh/include/libssh/libssh.h @@ -730,7 +730,9 @@ LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socke fd_set *readfds, struct timeval *timeout); LIBSSH_API int ssh_service_request(ssh_session session, const char *service); LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel); +#ifndef _WIN32 LIBSSH_API int ssh_set_agent_socket(ssh_session session, socket_t fd); +#endif LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking); LIBSSH_API void ssh_set_counters(ssh_session session, ssh_counter scounter, ssh_counter rcounter); @@ -749,10 +751,8 @@ LIBSSH_API int ssh_userauth_try_publickey(ssh_session session, LIBSSH_API int ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey); -#ifndef _WIN32 LIBSSH_API int ssh_userauth_agent(ssh_session session, const char *username); -#endif LIBSSH_API int ssh_userauth_publickey_auto(ssh_session session, const char *username, const char *passphrase); diff --git a/src/libssh/src/agent.c b/src/libssh/src/agent.c index 62b0093..76c1b82 100644 --- a/src/libssh/src/agent.c +++ b/src/libssh/src/agent.c @@ -33,7 +33,6 @@ * the agent returns the signed data */ -#ifndef _WIN32 #include "config.h" @@ -46,9 +45,6 @@ #include #endif -#include -#include - #include "libssh/agent.h" #include "libssh/priv.h" #include "libssh/socket.h" @@ -58,11 +54,21 @@ #include "libssh/pki.h" #include "libssh/bytearray.h" +#ifndef _WIN32 +#include +#include +#else +#include +#endif + +#define AGENT_MSG_MAXLEN 256 * 1024 + /* macro to check for "agent failure" message */ #define agent_failed(x) \ (((x) == SSH_AGENT_FAILURE) || ((x) == SSH_COM_AGENT2_FAILURE) || \ ((x) == SSH2_AGENT_FAILURE)) +#ifndef _WIN32 static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int do_read) { char *b = buf; size_t pos = 0; @@ -122,6 +128,7 @@ static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int return pos; } } +#endif ssh_agent ssh_agent_new(struct ssh_session_struct *session) { ssh_agent agent = NULL; @@ -133,12 +140,16 @@ ssh_agent ssh_agent_new(struct ssh_session_struct *session) { ZERO_STRUCTP(agent); agent->count = 0; + +#ifndef _WIN32 agent->sock = ssh_socket_new(session); if (agent->sock == NULL) { SAFE_FREE(agent); return NULL; } agent->channel = NULL; +#endif + return agent; } @@ -165,6 +176,7 @@ int ssh_set_agent_channel(ssh_session session, ssh_channel channel){ return SSH_OK; } +#ifndef _WIN32 /** @brief sets the SSH agent socket. * The SSH agent will be used to authenticate this client using * the given socket to communicate with the ssh-agent. The caller @@ -192,20 +204,24 @@ void ssh_agent_close(struct ssh_agent_struct *agent) { ssh_socket_close(agent->sock); } +#endif void ssh_agent_free(ssh_agent agent) { if (agent) { if (agent->ident) { SSH_BUFFER_FREE(agent->ident); } +#ifndef _WIN32 if (agent->sock) { ssh_agent_close(agent); ssh_socket_free(agent->sock); } +#endif SAFE_FREE(agent); } } +#ifndef _WIN32 static int agent_connect(ssh_session session) { const char *auth_sock = NULL; @@ -227,6 +243,7 @@ static int agent_connect(ssh_session session) { return -1; } +#endif #if 0 static int agent_decode_reply(struct ssh_session_struct *session, int type) { @@ -248,6 +265,8 @@ static int agent_decode_reply(struct ssh_session_struct *session, int type) { } #endif +#ifndef _WIN32 + static int agent_talk(struct ssh_session_struct *session, struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) { uint32_t len = 0; @@ -280,7 +299,7 @@ static int agent_talk(struct ssh_session_struct *session, } len = PULL_BE_U32(payload, 0); - if (len > 256 * 1024) { + if (len > AGENT_MSG_MAXLEN) { ssh_set_error(session, SSH_FATAL, "Authentication response too long: %u", len); return -1; @@ -307,6 +326,78 @@ static int agent_talk(struct ssh_session_struct *session, return 0; } +#else + +#define AGENT_COPYDATA_ID 0x804e50ba; + +static int agent_talk(struct ssh_session_struct *session, + struct ssh_buffer_struct *request, struct ssh_buffer_struct *reply) { + HWND hwnd = FindWindow("Pageant", "Pageant"); + if (hwnd == NULL) { + ssh_set_error(session, SSH_FATAL, + "Pageant message window not found: %u", GetLastError()); + return -1; + } + + char map_name[39]; + sprintf(map_name, "libssh_agent_%08x_%016zx", + GetCurrentProcessId(), (size_t)session->agent); + + HANDLE hmap = CreateFileMapping(NULL, NULL, PAGE_READWRITE, + 0, AGENT_MSG_MAXLEN + sizeof(uint32_t), map_name); + if (hmap == NULL) { + ssh_set_error(session, SSH_FATAL, + "Failed to create file mapping: %u", GetLastError()); + return -1; + } + + char *buf = MapViewOfFile(hmap, FILE_MAP_ALL_ACCESS, 0, 0, 0); + if (buf == NULL) { + ssh_set_error(session, SSH_FATAL, + "Failed to map the file mapping into memory: %u", GetLastError()); + CloseHandle(hmap); + return -1; + } + + uint32_t len = ssh_buffer_get_len(request); + SSH_LOG(SSH_LOG_TRACE, "Request length: %u", len); + PUSH_BE_U32(buf, 0, len); + memcpy(buf + sizeof(uint32_t), ssh_buffer_get(request), len); + + COPYDATASTRUCT data; + data.dwData = AGENT_COPYDATA_ID; + data.cbData = strlen(map_name) + 1; + data.lpData = map_name; + if (SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)&data) < 0) { + ssh_set_error(session, SSH_FATAL, "Pageant returned an error"); + UnmapViewOfFile(buf); + CloseHandle(hmap); + return -1; + } + + len = PULL_BE_U32(buf, 0); + if (len > AGENT_MSG_MAXLEN) { + ssh_set_error(session, SSH_FATAL, + "Authentication response too long: %u", len); + UnmapViewOfFile(buf); + CloseHandle(hmap); + return -1; + } + SSH_LOG(SSH_LOG_TRACE, "Response length: %u", len); + + int rc = ssh_buffer_add_data(reply, buf + sizeof(uint32_t), len); + UnmapViewOfFile(buf); + CloseHandle(hmap); + if (rc < 0) { + SSH_LOG(SSH_LOG_WARN, "Not enough space"); + return -1; + } + + return 0; +} + +#endif /* _WIN32 */ + uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session) { ssh_buffer request = NULL; @@ -459,6 +550,7 @@ int ssh_agent_is_running(ssh_session session) { return 0; } +#ifndef _WIN32 if (ssh_socket_is_open(session->agent->sock)) { return 1; } else { @@ -470,6 +562,10 @@ int ssh_agent_is_running(ssh_session session) { } return 0; +#else + HWND hwnd = FindWindow("Pageant", "Pageant"); + return hwnd != NULL; +#endif } ssh_string ssh_agent_sign_data(ssh_session session, @@ -591,4 +687,3 @@ ssh_string ssh_agent_sign_data(ssh_session session, return sig_blob; } -#endif /* _WIN32 */ diff --git a/src/libssh/src/pki.c b/src/libssh/src/pki.c index 6dcb120..8739ed9 100644 --- a/src/libssh/src/pki.c +++ b/src/libssh/src/pki.c @@ -2372,7 +2372,6 @@ end: return sig_blob; } -#ifndef _WIN32 ssh_string ssh_pki_do_sign_agent(ssh_session session, struct ssh_buffer_struct *buf, const ssh_key pubkey) @@ -2422,7 +2421,6 @@ ssh_string ssh_pki_do_sign_agent(ssh_session session, return sig_blob; } -#endif /* _WIN32 */ #ifdef WITH_SERVER ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session, diff --git a/src/libssh/src/session.c b/src/libssh/src/session.c index 3199096..05f81f2 100644 --- a/src/libssh/src/session.c +++ b/src/libssh/src/session.c @@ -97,12 +97,10 @@ ssh_session ssh_new(void) ssh_set_blocking(session, 1); session->maxchannel = FIRST_CHANNEL; -#ifndef _WIN32 session->agent = ssh_agent_new(session); if (session->agent == NULL) { goto err; } -#endif /* _WIN32 */ /* OPTIONS */ session->opts.StrictHostKeyChecking = 1; @@ -242,9 +240,7 @@ void ssh_free(ssh_session session) crypto_free(session->current_crypto); crypto_free(session->next_crypto); -#ifndef _WIN32 ssh_agent_free(session->agent); -#endif /* _WIN32 */ ssh_key_free(session->srv.dsa_key); session->srv.dsa_key = NULL; @@ -292,9 +288,7 @@ void ssh_free(ssh_session session) } ssh_list_free(session->out_queue); -#ifndef _WIN32 ssh_agent_state_free (session->agent_state); -#endif session->agent_state = NULL; SAFE_FREE(session->auth.auto_state);