Permalink
Browse files

Set the security info for the file mapping to the same as

Pageant's process, to make sure Pageant's SID check will pass.
Fixes the problem that required running Pageant with cygstart
in order for charade to work.
  • Loading branch information...
1 parent 997e284 commit 0308855269db7da9441af980239b8da31773aa5d @russelldavis russelldavis committed Feb 14, 2011
Showing with 111 additions and 1 deletion.
  1. +82 −1 pageant.c
  2. +29 −0 pageant.h
View
@@ -39,11 +39,60 @@
#include "eprintf.h"
#include "pageant.h"
+#ifndef NO_SECURITY
+#include <aclapi.h>
+#endif
+
// TODO: is there actually something magical about this number?
#define AGENT_COPYDATA_ID 0x804e50ba
#define AGENT_MAX_MSGLEN 8192
+/*
+ * Dynamically load advapi32.dll for SID manipulation. In its absence,
+ * we degrade gracefully.
+ */
+#ifndef NO_SECURITY
+int advapi_initialised = FALSE;
+static HMODULE advapi;
+DECL_WINDOWS_FUNCTION(static, BOOL, OpenProcessToken,
+ (HANDLE, DWORD, PHANDLE));
+DECL_WINDOWS_FUNCTION(static, BOOL, GetTokenInformation,
+ (HANDLE, TOKEN_INFORMATION_CLASS,
+ LPVOID, DWORD, PDWORD));
+DECL_WINDOWS_FUNCTION(static, BOOL, InitializeSecurityDescriptor,
+ (PSECURITY_DESCRIPTOR, DWORD));
+DECL_WINDOWS_FUNCTION(static, BOOL, SetSecurityDescriptorOwner,
+ (PSECURITY_DESCRIPTOR, PSID, BOOL));
+static int init_advapi(void)
+{
+ advapi = load_system32_dll("advapi32.dll");
+ return advapi &&
+ GET_WINDOWS_FUNCTION(advapi, OpenProcessToken) &&
+ GET_WINDOWS_FUNCTION(advapi, GetTokenInformation) &&
+ GET_WINDOWS_FUNCTION(advapi, InitializeSecurityDescriptor) &&
+ GET_WINDOWS_FUNCTION(advapi, SetSecurityDescriptorOwner);
+}
+#endif
+
+HMODULE load_system32_dll(const char *libname)
+{
+ /*
+ * Wrapper function to load a DLL out of c:\windows\system32
+ * without going through the full DLL search path. (Hence no
+ * attack is possible by placing a substitute DLL earlier on that
+ * path.)
+ */
+ static char path[MAX_PATH * 2] = {0};
+ unsigned int len = GetSystemDirectory(path, MAX_PATH);
+ if (len == 0 || len > MAX_PATH) return NULL;
+
+ strcat(path, "\\");
+ strcat(path, libname);
+ HMODULE ret = LoadLibrary(path);
+ return ret;
+}
+
void
print_buf(int level, byte *buf, int numbytes)
{
@@ -109,7 +158,35 @@ send_request_to_pageant(byte *inbuf, int inbytes, byte *outbuf, int outbuflen)
char mapname[512];
sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
- HANDLE filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
+ PSECURITY_ATTRIBUTES psa = NULL;
+#ifndef NO_SECURITY
+ SECURITY_ATTRIBUTES sa = {0};
+ if (advapi_initialised || init_advapi()) {
+ /*
+ * Set the security info for the file mapping to the same as Pageant's
+ * process, to make sure Pageant's SID check will pass.
+ */
+
+ DWORD dwProcId = 0;
+ GetWindowThreadProcessId(hwnd, &dwProcId);
+ HANDLE proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcId);
+ if (proc != NULL) {
+ sa.nLength = sizeof(sa);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+ GetSecurityInfo(proc, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
+ NULL, NULL, NULL, NULL, (PSECURITY_DESCRIPTOR*)&sa.lpSecurityDescriptor);
+ if (sa.lpSecurityDescriptor) {
+ psa = &sa;
+ }
+ }
+ CloseHandle(proc);
+ } else {
+ EPRINTF(0, "Couldn't initialize advapi.\n");
+ }
+#endif /* NO_SECURITY */
+
+ HANDLE filemap = CreateFileMapping(INVALID_HANDLE_VALUE, psa,
PAGE_READWRITE, 0,
AGENT_MAX_MSGLEN, mapname);
if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) {
@@ -147,6 +224,10 @@ send_request_to_pageant(byte *inbuf, int inbytes, byte *outbuf, int outbuflen)
UnmapViewOfFile(shmem);
CloseHandle(filemap);
+#ifndef NO_SECURITY
+ if (sa.lpSecurityDescriptor)
+ LocalFree(sa.lpSecurityDescriptor);
+#endif
EPRINTF(3, "Got %d bytes back from pageant.\n", retlen);
View
@@ -44,6 +44,35 @@
#define GET_32BIT(cp) GET_32BIT_MSB_FIRST(cp)
+/*
+ * Dynamically linked functions. These come in two flavours:
+ *
+ * - GET_WINDOWS_FUNCTION does not expose "name" to the preprocessor,
+ * so will always dynamically link against exactly what is specified
+ * in "name". If you're not sure, use this one.
+ *
+ * - GET_WINDOWS_FUNCTION_PP allows "name" to be redirected via
+ * preprocessor definitions like "#define foo bar"; this is principally
+ * intended for the ANSI/Unicode DoSomething/DoSomethingA/DoSomethingW.
+ * If your function has an argument of type "LPTSTR" or similar, this
+ * is the variant to use.
+ * (However, it can't always be used, as it trips over more complicated
+ * macro trickery such as the WspiapiGetAddrInfo wrapper for getaddrinfo.)
+ *
+ * (DECL_WINDOWS_FUNCTION works with both these variants.)
+ */
+#define DECL_WINDOWS_FUNCTION(linkage, rettype, name, params) \
+ typedef rettype (WINAPI *t_##name) params; \
+ linkage t_##name p_##name
+#define STR1(x) #x
+#define STR(x) STR1(x)
+#define GET_WINDOWS_FUNCTION_PP(module, name) \
+ (p_##name = module ? (t_##name) GetProcAddress(module, STR(name)) : NULL)
+#define GET_WINDOWS_FUNCTION(module, name) \
+ (p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL)
+
+HMODULE load_system32_dll(const char *libname);
+
// Send a numbytes-sized message to pageant, synchronously.
// Up to outbuflen bytes of response will be written into outbuf.
// If the returned message would overflow buf, or if any other

0 comments on commit 0308855

Please sign in to comment.