mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Windows: use the named pipe for normal agent queries.
As in the previous commit, this means that agent_query() is now able to operate in an asynchronous mode, so that if Pageant takes time to answer a request, the GUI of the PuTTY instance making the request won't be blocked. Also as in the previous commit, we still fall back to the WM_COPYDATA protocol if the new named pipe protocol isn't available.
This commit is contained in:
parent
cf29125fb4
commit
c2b135c92a
2
Recipe
2
Recipe
@ -341,7 +341,7 @@ pageant : [G] winpgnt pageant sshrsa sshpubk sshdes ARITH sshmd5 version
|
|||||||
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
+ tree234 MISC sshaes sshsha winsecur winpgntc aqsync sshdss sshsh256
|
||||||
+ sshsh512 winutils sshecc winmisc winmiscs winhelp conf pageant.res
|
+ sshsh512 winutils sshecc winmisc winmiscs winhelp conf pageant.res
|
||||||
+ sshauxcrypt sshhmac wincapi winnps winnpc winhsock errsock winnet
|
+ sshauxcrypt sshhmac wincapi winnps winnpc winhsock errsock winnet
|
||||||
+ winhandl callback be_misc winselgui LIBS
|
+ winhandl callback be_misc winselgui winhandl LIBS
|
||||||
|
|
||||||
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes ARITH sshmd5 version
|
||||||
+ sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
|
+ sshrand winnoise sshsha winstore MISC winctrls sshrsa sshdss winmisc
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
|
#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
|
||||||
|
|
||||||
bool agent_exists(void)
|
static bool wm_copydata_agent_exists(void)
|
||||||
{
|
{
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
hwnd = FindWindow("Pageant", "Pageant");
|
hwnd = FindWindow("Pageant", "Pageant");
|
||||||
@ -26,14 +26,7 @@ bool agent_exists(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void agent_cancel_query(agent_pending_query *q)
|
static void wm_copydata_agent_query(strbuf *query, void **out, int *outlen)
|
||||||
{
|
|
||||||
unreachable("Windows agent queries are never asynchronous!");
|
|
||||||
}
|
|
||||||
|
|
||||||
agent_pending_query *agent_query(
|
|
||||||
strbuf *query, void **out, int *outlen,
|
|
||||||
void (*callback)(void *, void *, int), void *callback_ctx)
|
|
||||||
{
|
{
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
char *mapname;
|
char *mapname;
|
||||||
@ -49,11 +42,11 @@ agent_pending_query *agent_query(
|
|||||||
*outlen = 0;
|
*outlen = 0;
|
||||||
|
|
||||||
if (query->len > AGENT_MAX_MSGLEN)
|
if (query->len > AGENT_MAX_MSGLEN)
|
||||||
return NULL; /* query too large */
|
return; /* query too large */
|
||||||
|
|
||||||
hwnd = FindWindow("Pageant", "Pageant");
|
hwnd = FindWindow("Pageant", "Pageant");
|
||||||
if (!hwnd)
|
if (!hwnd)
|
||||||
return NULL; /* *out == NULL, so failure */
|
return; /* *out == NULL, so failure */
|
||||||
mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
|
mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
|
||||||
|
|
||||||
psa = NULL;
|
psa = NULL;
|
||||||
@ -94,7 +87,7 @@ agent_pending_query *agent_query(
|
|||||||
0, AGENT_MAX_MSGLEN, mapname);
|
0, AGENT_MAX_MSGLEN, mapname);
|
||||||
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
|
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
|
||||||
sfree(mapname);
|
sfree(mapname);
|
||||||
return NULL; /* *out == NULL, so failure */
|
return; /* *out == NULL, so failure */
|
||||||
}
|
}
|
||||||
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
|
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
|
||||||
strbuf_finalise_agent_query(query);
|
strbuf_finalise_agent_query(query);
|
||||||
@ -134,7 +127,6 @@ agent_pending_query *agent_query(
|
|||||||
sfree(mapname);
|
sfree(mapname);
|
||||||
if (psd)
|
if (psd)
|
||||||
LocalFree(psd);
|
LocalFree(psd);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_SECURITY
|
#ifndef NO_SECURITY
|
||||||
@ -173,6 +165,159 @@ void agent_free_connect_ctx(agent_connect_ctx *ctx)
|
|||||||
sfree(ctx);
|
sfree(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool named_pipe_agent_exists(void)
|
||||||
|
{
|
||||||
|
char *pipename = agent_named_pipe_name();
|
||||||
|
DWORD type = GetFileType(pipename);
|
||||||
|
sfree(pipename);
|
||||||
|
return type == FILE_TYPE_PIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool agent_exists(void)
|
||||||
|
{
|
||||||
|
return named_pipe_agent_exists() || wm_copydata_agent_exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct agent_pending_query {
|
||||||
|
struct handle *handle;
|
||||||
|
strbuf *response;
|
||||||
|
void (*callback)(void *, void *, int);
|
||||||
|
void *callback_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int named_pipe_agent_accumulate_response(
|
||||||
|
strbuf *sb, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
put_data(sb, data, len);
|
||||||
|
if (sb->len >= 4) {
|
||||||
|
uint32_t length_field = GET_32BIT_MSB_FIRST(sb->u);
|
||||||
|
if (length_field > AGENT_MAX_MSGLEN)
|
||||||
|
return -1; /* badly formatted message */
|
||||||
|
|
||||||
|
int overall_length = length_field + 4;
|
||||||
|
if (sb->len >= overall_length)
|
||||||
|
return overall_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* not done yet */
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t named_pipe_agent_gotdata(
|
||||||
|
struct handle *h, const void *data, size_t len, int err)
|
||||||
|
{
|
||||||
|
agent_pending_query *pq = handle_get_privdata(h);
|
||||||
|
|
||||||
|
if (err || len == 0) {
|
||||||
|
pq->callback(pq->callback_ctx, NULL, 0);
|
||||||
|
agent_cancel_query(pq);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = named_pipe_agent_accumulate_response(pq->response, data, len);
|
||||||
|
if (status == -1) {
|
||||||
|
pq->callback(pq->callback_ctx, NULL, 0);
|
||||||
|
agent_cancel_query(pq);
|
||||||
|
} else if (status > 0) {
|
||||||
|
void *response_buf = strbuf_to_str(pq->response);
|
||||||
|
pq->response = NULL;
|
||||||
|
pq->callback(pq->callback_ctx, response_buf, status);
|
||||||
|
agent_cancel_query(pq);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_pending_query *named_pipe_agent_query(
|
||||||
|
strbuf *query, void **out, int *outlen,
|
||||||
|
void (*callback)(void *, void *, int), void *callback_ctx)
|
||||||
|
{
|
||||||
|
agent_pending_query *pq = NULL;
|
||||||
|
char *err = NULL, *pipename = NULL;
|
||||||
|
strbuf *sb = NULL;
|
||||||
|
HANDLE pipehandle;
|
||||||
|
|
||||||
|
pipename = agent_named_pipe_name();
|
||||||
|
pipehandle = connect_to_named_pipe(pipename, &err);
|
||||||
|
if (pipehandle == INVALID_HANDLE_VALUE)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
strbuf_finalise_agent_query(query);
|
||||||
|
|
||||||
|
for (DWORD done = 0; done < query->len ;) {
|
||||||
|
DWORD nwritten;
|
||||||
|
bool ret = WriteFile(pipehandle, query->s + done, query->len - done,
|
||||||
|
&nwritten, NULL);
|
||||||
|
if (!ret)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
done += nwritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callback) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
sb = strbuf_new_nm();
|
||||||
|
do {
|
||||||
|
char buf[1024];
|
||||||
|
DWORD nread;
|
||||||
|
bool ret = ReadFile(pipehandle, buf, sizeof(buf), &nread, NULL);
|
||||||
|
if (!ret)
|
||||||
|
goto failure;
|
||||||
|
status = named_pipe_agent_accumulate_response(sb, buf, nread);
|
||||||
|
} while (status == 0);
|
||||||
|
|
||||||
|
if (status == -1)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
*out = strbuf_to_str(sb);
|
||||||
|
*outlen = status;
|
||||||
|
sb = NULL;
|
||||||
|
pq = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pq = snew(agent_pending_query);
|
||||||
|
pq->handle = handle_input_new(pipehandle, named_pipe_agent_gotdata, pq, 0);
|
||||||
|
pipehandle = NULL; /* prevent it being closed below */
|
||||||
|
pq->response = strbuf_new_nm();
|
||||||
|
pq->callback = callback;
|
||||||
|
pq->callback_ctx = callback_ctx;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
*out = NULL;
|
||||||
|
*outlen = 0;
|
||||||
|
pq = NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
sfree(err);
|
||||||
|
sfree(pipename);
|
||||||
|
if (pipehandle != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(pipehandle);
|
||||||
|
if (sb)
|
||||||
|
strbuf_free(sb);
|
||||||
|
return pq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void agent_cancel_query(agent_pending_query *pq)
|
||||||
|
{
|
||||||
|
handle_free(pq->handle);
|
||||||
|
if (pq->response)
|
||||||
|
strbuf_free(pq->response);
|
||||||
|
sfree(pq);
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_pending_query *agent_query(
|
||||||
|
strbuf *query, void **out, int *outlen,
|
||||||
|
void (*callback)(void *, void *, int), void *callback_ctx)
|
||||||
|
{
|
||||||
|
agent_pending_query *pq = named_pipe_agent_query(
|
||||||
|
query, out, outlen, callback, callback_ctx);
|
||||||
|
if (pq || *out)
|
||||||
|
return pq;
|
||||||
|
|
||||||
|
wm_copydata_agent_query(query, out, outlen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#else /* NO_SECURITY */
|
#else /* NO_SECURITY */
|
||||||
|
|
||||||
Socket *agent_connect(void *vctx, Plug *plug)
|
Socket *agent_connect(void *vctx, Plug *plug)
|
||||||
@ -189,4 +334,22 @@ void agent_free_connect_ctx(agent_connect_ctx *ctx)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool agent_exists(void)
|
||||||
|
{
|
||||||
|
return wm_copydata_agent_exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_pending_query *agent_query(
|
||||||
|
strbuf *query, void **out, int *outlen,
|
||||||
|
void (*callback)(void *, void *, int), void *callback_ctx)
|
||||||
|
{
|
||||||
|
wm_copydata_agent_query(query, out, outlen);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void agent_cancel_query(agent_pending_query *q)
|
||||||
|
{
|
||||||
|
unreachable("Windows agent queries are never asynchronous!");
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* NO_SECURITY */
|
#endif /* NO_SECURITY */
|
||||||
|
Loading…
Reference in New Issue
Block a user