5c58ad2d |
1 | /* |
2 | * Pageant client code. |
3 | */ |
4 | |
5c58ad2d |
5 | #include <stdio.h> |
6 | #include <stdlib.h> |
7 | |
c44bf5bd |
8 | #include "putty.h" |
dcbde236 |
9 | |
d70f60ae |
10 | #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ |
11 | #define AGENT_MAX_MSGLEN 8192 |
12 | |
d70f60ae |
13 | #define GET_32BIT(cp) \ |
14 | (((unsigned long)(unsigned char)(cp)[0] << 24) | \ |
15 | ((unsigned long)(unsigned char)(cp)[1] << 16) | \ |
16 | ((unsigned long)(unsigned char)(cp)[2] << 8) | \ |
17 | ((unsigned long)(unsigned char)(cp)[3])) |
18 | |
32874aea |
19 | int agent_exists(void) |
20 | { |
5c58ad2d |
21 | HWND hwnd; |
22 | hwnd = FindWindow("Pageant", "Pageant"); |
23 | if (!hwnd) |
32874aea |
24 | return FALSE; |
5c58ad2d |
25 | else |
32874aea |
26 | return TRUE; |
5c58ad2d |
27 | } |
28 | |
28f7ab3c |
29 | /* |
30 | * Unfortunately, this asynchronous agent request mechanism doesn't |
31 | * appear to work terribly well. I'm going to comment it out for |
32 | * the moment, and see if I can come up with a better one :-/ |
33 | */ |
34 | #ifdef WINDOWS_ASYNC_AGENT |
35 | |
c44bf5bd |
36 | struct agent_query_data { |
37 | COPYDATASTRUCT cds; |
38 | unsigned char *mapping; |
39 | HANDLE handle; |
40 | char *mapname; |
41 | HWND hwnd; |
42 | void (*callback)(void *, void *, int); |
43 | void *callback_ctx; |
44 | }; |
45 | |
46 | DWORD WINAPI agent_query_thread(LPVOID param) |
47 | { |
48 | struct agent_query_data *data = (struct agent_query_data *)param; |
49 | unsigned char *ret; |
50 | int id, retlen; |
51 | |
52 | id = SendMessage(data->hwnd, WM_COPYDATA, (WPARAM) NULL, |
53 | (LPARAM) &data->cds); |
54 | ret = NULL; |
55 | if (id > 0) { |
56 | retlen = 4 + GET_32BIT(data->mapping); |
57 | ret = snewn(retlen, unsigned char); |
58 | if (ret) { |
59 | memcpy(ret, data->mapping, retlen); |
60 | } |
61 | } |
62 | if (!ret) |
63 | retlen = 0; |
64 | UnmapViewOfFile(data->mapping); |
65 | CloseHandle(data->handle); |
66 | sfree(data->mapname); |
67 | |
68 | agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen); |
69 | |
70 | return 0; |
71 | } |
72 | |
28f7ab3c |
73 | #endif |
74 | |
839f10db |
75 | int agent_query(void *in, int inlen, void **out, int *outlen, |
76 | void (*callback)(void *, void *, int), void *callback_ctx) |
32874aea |
77 | { |
5c58ad2d |
78 | HWND hwnd; |
c44bf5bd |
79 | char *mapname; |
5c58ad2d |
80 | HANDLE filemap; |
d70f60ae |
81 | unsigned char *p, *ret; |
5c58ad2d |
82 | int id, retlen; |
83 | COPYDATASTRUCT cds; |
84 | |
85 | *out = NULL; |
86 | *outlen = 0; |
87 | |
88 | hwnd = FindWindow("Pageant", "Pageant"); |
5c58ad2d |
89 | if (!hwnd) |
839f10db |
90 | return 1; /* *out == NULL, so failure */ |
c44bf5bd |
91 | mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId()); |
d70f60ae |
92 | filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, |
32874aea |
93 | 0, AGENT_MAX_MSGLEN, mapname); |
d70f60ae |
94 | if (!filemap) |
839f10db |
95 | return 1; /* *out == NULL, so failure */ |
d70f60ae |
96 | p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); |
97 | memcpy(p, in, inlen); |
98 | cds.dwData = AGENT_COPYDATA_ID; |
32874aea |
99 | cds.cbData = 1 + strlen(mapname); |
d70f60ae |
100 | cds.lpData = mapname; |
28f7ab3c |
101 | #ifdef WINDOWS_ASYNC_AGENT |
c44bf5bd |
102 | if (callback != NULL && !(flags & FLAG_SYNCAGENT)) { |
103 | /* |
104 | * We need an asynchronous Pageant request. Since I know of |
105 | * no way to stop SendMessage from blocking the thread it's |
106 | * called in, I see no option but to start a fresh thread. |
107 | * When we're done we'll PostMessage the result back to our |
108 | * main window, so that the callback is done in the primary |
109 | * thread to avoid concurrency. |
110 | */ |
111 | struct agent_query_data *data = snew(struct agent_query_data); |
112 | DWORD threadid; |
113 | data->mapping = p; |
114 | data->handle = filemap; |
115 | data->mapname = mapname; |
116 | data->callback = callback; |
117 | data->callback_ctx = callback_ctx; |
118 | data->cds = cds; /* structure copy */ |
119 | data->hwnd = hwnd; |
120 | if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid)) |
121 | return 0; |
122 | sfree(data); |
123 | } |
28f7ab3c |
124 | #endif |
c44bf5bd |
125 | |
126 | /* |
127 | * The user either passed a null callback (indicating that the |
128 | * query is required to be synchronous) or CreateThread failed. |
129 | * Either way, we need a synchronous request. |
130 | */ |
32874aea |
131 | id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) & cds); |
5c58ad2d |
132 | if (id > 0) { |
32874aea |
133 | retlen = 4 + GET_32BIT(p); |
3d88e64d |
134 | ret = snewn(retlen, unsigned char); |
32874aea |
135 | if (ret) { |
136 | memcpy(ret, p, retlen); |
137 | *out = ret; |
138 | *outlen = retlen; |
139 | } |
5c58ad2d |
140 | } |
d70f60ae |
141 | UnmapViewOfFile(p); |
142 | CloseHandle(filemap); |
839f10db |
143 | return 1; |
5c58ad2d |
144 | } |