]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - windows/winpgntc.c
Move the dynamic loading of advapi into its own module.
[PuTTY.git] / windows / winpgntc.c
1 /*
2  * Pageant client code.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "putty.h"
9
10 #ifndef NO_SECURITY
11 #include "winsecur.h"
12 #endif
13
14 #define AGENT_COPYDATA_ID 0x804e50ba   /* random goop */
15 #define AGENT_MAX_MSGLEN  8192
16
17 int agent_exists(void)
18 {
19     HWND hwnd;
20     hwnd = FindWindow("Pageant", "Pageant");
21     if (!hwnd)
22         return FALSE;
23     else
24         return TRUE;
25 }
26
27 /*
28  * Unfortunately, this asynchronous agent request mechanism doesn't
29  * appear to work terribly well. I'm going to comment it out for
30  * the moment, and see if I can come up with a better one :-/
31  */
32 #ifdef WINDOWS_ASYNC_AGENT
33
34 struct agent_query_data {
35     COPYDATASTRUCT cds;
36     unsigned char *mapping;
37     HANDLE handle;
38     char *mapname;
39     HWND hwnd;
40     void (*callback)(void *, void *, int);
41     void *callback_ctx;
42 };
43
44 DWORD WINAPI agent_query_thread(LPVOID param)
45 {
46     struct agent_query_data *data = (struct agent_query_data *)param;
47     unsigned char *ret;
48     int id, retlen;
49
50     id = SendMessage(data->hwnd, WM_COPYDATA, (WPARAM) NULL,
51                      (LPARAM) &data->cds);
52     ret = NULL;
53     if (id > 0) {
54         retlen = 4 + GET_32BIT(data->mapping);
55         ret = snewn(retlen, unsigned char);
56         if (ret) {
57             memcpy(ret, data->mapping, retlen);
58         }
59     }
60     if (!ret)
61         retlen = 0;
62     UnmapViewOfFile(data->mapping);
63     CloseHandle(data->handle);
64     sfree(data->mapname);
65
66     agent_schedule_callback(data->callback, data->callback_ctx, ret, retlen);
67
68     return 0;
69 }
70
71 #endif
72
73 int agent_query(void *in, int inlen, void **out, int *outlen,
74                 void (*callback)(void *, void *, int), void *callback_ctx)
75 {
76     HWND hwnd;
77     char *mapname;
78     HANDLE filemap;
79     unsigned char *p, *ret;
80     int id, retlen;
81     COPYDATASTRUCT cds;
82     SECURITY_ATTRIBUTES sa, *psa;
83     PSECURITY_DESCRIPTOR psd = NULL;
84     PSID usersid = NULL;
85
86     *out = NULL;
87     *outlen = 0;
88
89     hwnd = FindWindow("Pageant", "Pageant");
90     if (!hwnd)
91         return 1;                      /* *out == NULL, so failure */
92     mapname = dupprintf("PageantRequest%08x", (unsigned)GetCurrentThreadId());
93
94     psa = NULL;
95 #ifndef NO_SECURITY
96     if (got_advapi()) {
97         /*
98          * Make the file mapping we create for communication with
99          * Pageant owned by the user SID rather than the default. This
100          * should make communication between processes with slightly
101          * different contexts more reliable: in particular, command
102          * prompts launched as administrator should still be able to
103          * run PSFTPs which refer back to the owning user's
104          * unprivileged Pageant.
105          */
106         usersid = get_user_sid();
107
108         if (usersid) {
109             psd = (PSECURITY_DESCRIPTOR)
110                 LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
111             if (psd) {
112                 if (p_InitializeSecurityDescriptor
113                     (psd, SECURITY_DESCRIPTOR_REVISION) &&
114                     p_SetSecurityDescriptorOwner(psd, usersid, FALSE)) {
115                     sa.nLength = sizeof(sa);
116                     sa.bInheritHandle = TRUE;
117                     sa.lpSecurityDescriptor = psd;
118                     psa = &sa;
119                 } else {
120                     LocalFree(psd);
121                     psd = NULL;
122                 }
123             }
124         }
125     }
126 #endif /* NO_SECURITY */
127
128     filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE,
129                                 0, AGENT_MAX_MSGLEN, mapname);
130     if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
131         sfree(mapname);
132         return 1;                      /* *out == NULL, so failure */
133     }
134     p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
135     memcpy(p, in, inlen);
136     cds.dwData = AGENT_COPYDATA_ID;
137     cds.cbData = 1 + strlen(mapname);
138     cds.lpData = mapname;
139 #ifdef WINDOWS_ASYNC_AGENT
140     if (callback != NULL && !(flags & FLAG_SYNCAGENT)) {
141         /*
142          * We need an asynchronous Pageant request. Since I know of
143          * no way to stop SendMessage from blocking the thread it's
144          * called in, I see no option but to start a fresh thread.
145          * When we're done we'll PostMessage the result back to our
146          * main window, so that the callback is done in the primary
147          * thread to avoid concurrency.
148          */
149         struct agent_query_data *data = snew(struct agent_query_data);
150         DWORD threadid;
151         data->mapping = p;
152         data->handle = filemap;
153         data->mapname = mapname;
154         data->callback = callback;
155         data->callback_ctx = callback_ctx;
156         data->cds = cds;               /* structure copy */
157         data->hwnd = hwnd;
158         if (CreateThread(NULL, 0, agent_query_thread, data, 0, &threadid))
159             return 0;
160         sfree(mapname);
161         sfree(data);
162     }
163 #endif
164
165     /*
166      * The user either passed a null callback (indicating that the
167      * query is required to be synchronous) or CreateThread failed.
168      * Either way, we need a synchronous request.
169      */
170     id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
171     if (id > 0) {
172         retlen = 4 + GET_32BIT(p);
173         ret = snewn(retlen, unsigned char);
174         if (ret) {
175             memcpy(ret, p, retlen);
176             *out = ret;
177             *outlen = retlen;
178         }
179     }
180     UnmapViewOfFile(p);
181     CloseHandle(filemap);
182     sfree(mapname);
183     if (psd)
184         LocalFree(psd);
185     sfree(usersid);
186     return 1;
187 }