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