winpgntc.c 5.2 KB

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