1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-05-03 10:42:10 -05:00

winpgnt.c: put all file-mapping code in one function.

Previously, the code to recover and memory-map the file-mapping object
Pageant uses for its IPC, and the code to convey its contents to and
from the cross-platform agent code, were widely separated, with the
former living in the WM_COPYDATA handler in the window procedure, and
the latter in answer_msg.

Now all of that code lives in answer_filemapping_message; WndProc only
handles the _window message_ contents - i.e. ensures the WM_COPYDATA
message has the right dwData id and that its lpData contains an ASCIZ
string - and answer_filemapping_message goes all the way from that
file-mapping object name to calling pageant_handle_msg.

While I'm here, I've also tidied up the code so that it uses the 'goto
cleanup' idiom rather than nesting everything inconveniently deeply,
and arranged that if anything goes wrong then we at least _construct_
an error message (although as yet we don't use that for anything
unless we're compiled with DEBUG_IPC enabled).
This commit is contained in:
Simon Tatham 2018-07-08 15:29:41 +01:00
parent 20e8fdece3
commit fecd42858c

View File

@ -380,59 +380,6 @@ void keylist_update(void)
}
}
struct PageantReply {
char buf[AGENT_MAX_MSGLEN - 4];
int len, overflowed;
BinarySink_IMPLEMENTATION;
};
static void pageant_reply_BinarySink_write(
BinarySink *bs, const void *data, size_t len)
{
struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply);
if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) {
memcpy(rep->buf + rep->len, data, len);
rep->len += len;
} else {
rep->overflowed = TRUE;
}
}
static void answer_msg(void *msgv)
{
unsigned char *msg = (unsigned char *)msgv;
unsigned msglen;
struct PageantReply reply;
reply.len = 0;
reply.overflowed = FALSE;
BinarySink_INIT(&reply, pageant_reply_BinarySink_write);
msglen = GET_32BIT(msg);
if (msglen > AGENT_MAX_MSGLEN) {
pageant_failure_msg(BinarySink_UPCAST(&reply),
"incoming length field too large", NULL, NULL);
} else {
pageant_handle_msg(BinarySink_UPCAST(&reply),
msg + 4, msglen, NULL, NULL);
if (reply.len > AGENT_MAX_MSGLEN) {
reply.len = 0;
reply.overflowed = FALSE;
pageant_failure_msg(BinarySink_UPCAST(&reply),
"output would exceed max msglen", NULL, NULL);
}
}
/*
* Windows Pageant answers messages in place, by overwriting the
* input message buffer.
*/
assert(4 + reply.len <= AGENT_MAX_MSGLEN);
PUT_32BIT(msg, reply.len);
memcpy(msg + 4, reply.buf, reply.len);
smemclr(reply.buf, sizeof(reply.buf));
}
static void win_add_keyfile(Filename *filename)
{
char *err;
@ -829,6 +776,168 @@ PSID get_default_sid(void)
}
#endif
struct PageantReply {
char buf[AGENT_MAX_MSGLEN - 4];
int len, overflowed;
BinarySink_IMPLEMENTATION;
};
static void pageant_reply_BinarySink_write(
BinarySink *bs, const void *data, size_t len)
{
struct PageantReply *rep = BinarySink_DOWNCAST(bs, struct PageantReply);
if (!rep->overflowed && len <= sizeof(rep->buf) - rep->len) {
memcpy(rep->buf + rep->len, data, len);
rep->len += len;
} else {
rep->overflowed = TRUE;
}
}
static char *answer_filemapping_message(const char *mapname)
{
HANDLE maphandle = INVALID_HANDLE_VALUE;
void *mapaddr = NULL;
char *err = NULL;
unsigned char *msg;
unsigned msglen;
struct PageantReply reply;
#ifndef NO_SECURITY
PSID mapsid = NULL;
PSID expectedsid = NULL;
PSID expectedsid_bc = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
#endif
#ifdef DEBUG_IPC
debug(("mapname = \"%s\"\n", mapname));
#endif
maphandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname);
if (maphandle == NULL || maphandle == INVALID_HANDLE_VALUE) {
err = dupprintf("OpenFileMapping(\"%s\"): %s",
mapname, win_strerror(GetLastError()));
goto cleanup;
}
#ifdef DEBUG_IPC
debug(("maphandle = %p\n", maphandle));
#endif
#ifndef NO_SECURITY
if (has_security) {
DWORD retd;
if ((expectedsid = get_user_sid()) == NULL) {
err = dupstr("unable to get user SID");
goto cleanup;
}
if ((expectedsid_bc = get_default_sid()) == NULL) {
err = dupstr("unable to get default SID");
goto cleanup;
}
if ((retd = p_GetSecurityInfo(
maphandle, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION,
&mapsid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS)) {
err = dupprintf("unable to get owner of file mapping: "
"GetSecurityInfo returned: %s",
win_strerror(retd));
goto cleanup;
}
#ifdef DEBUG_IPC
{
LPTSTR ours, ours2, theirs;
ConvertSidToStringSid(mapsid, &theirs);
ConvertSidToStringSid(expectedsid, &ours);
ConvertSidToStringSid(expectedsid_bc, &ours2);
debug(("got sids:\n oursnew=%s\n oursold=%s\n"
" theirs=%s\n", ours, ours2, theirs));
LocalFree(ours);
LocalFree(ours2);
LocalFree(theirs);
}
#endif
if (!EqualSid(mapsid, expectedsid) &&
!EqualSid(mapsid, expectedsid_bc)) {
err = dupstr("wrong owning SID of file mapping");
goto cleanup;
}
} else
#endif /* NO_SECURITY */
{
#ifdef DEBUG_IPC
debug(("security APIs not present\n"));
#endif
}
mapaddr = MapViewOfFile(maphandle, FILE_MAP_WRITE, 0, 0, 0);
if (!mapaddr) {
err = dupprintf("unable to obtain view of file mapping: %s",
win_strerror(GetLastError()));
goto cleanup;
}
#ifdef DEBUG_IPC
debug(("mapped address = %p\n", mapaddr));
#endif
msglen = GET_32BIT((unsigned char *)mapaddr);
#ifdef DEBUG_IPC
debug(("msg length=%08x, msg type=%02x\n",
msglen, (unsigned)((unsigned char *) mapaddr)[4]));
#endif
reply.len = 0;
reply.overflowed = FALSE;
BinarySink_INIT(&reply, pageant_reply_BinarySink_write);
if (msglen > AGENT_MAX_MSGLEN - 4) {
pageant_failure_msg(BinarySink_UPCAST(&reply),
"incoming length field too large", NULL, NULL);
} else {
pageant_handle_msg(BinarySink_UPCAST(&reply),
msg + 4, msglen, NULL, NULL);
if (reply.overflowed || reply.len > AGENT_MAX_MSGLEN - 4) {
reply.len = 0;
reply.overflowed = FALSE;
pageant_failure_msg(BinarySink_UPCAST(&reply),
"output would overflow message buffer",
NULL, NULL);
}
}
if (reply.len > AGENT_MAX_MSGLEN - 4) {
err = dupstr("even error-message output overflows buffer");
goto cleanup;
}
/*
* Windows Pageant answers messages in place, by overwriting the
* input message buffer.
*/
assert(4 + reply.len <= AGENT_MAX_MSGLEN);
PUT_32BIT(msg, reply.len);
memcpy(msg + 4, reply.buf, reply.len);
smemclr(reply.buf, sizeof(reply.buf));
cleanup:
/* expectedsid has the lifetime of the program, so we don't free it */
sfree(expectedsid_bc);
if (psd)
LocalFree(psd);
if (mapaddr)
UnmapViewOfFile(mapaddr);
if (maphandle != NULL && maphandle != INVALID_HANDLE_VALUE)
CloseHandle(maphandle);
return err;
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
@ -971,14 +1080,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
case WM_COPYDATA:
{
COPYDATASTRUCT *cds;
char *mapname;
void *p;
HANDLE filemap;
#ifndef NO_SECURITY
PSID mapowner, ourself, ourself2;
#endif
PSECURITY_DESCRIPTOR psd = NULL;
int ret = 0;
char *mapname, *err;
cds = (COPYDATASTRUCT *) lParam;
if (cds->dwData != AGENT_COPYDATA_ID)
@ -986,92 +1088,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
mapname = (char *) cds->lpData;
if (mapname[cds->cbData - 1] != '\0')
return 0; /* failure to be ASCIZ! */
err = answer_filemapping_message(mapname);
if (err) {
#ifdef DEBUG_IPC
debug(("mapname is :%s:\n", mapname));
debug(("IPC failed: %s\n", err));
#endif
filemap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, mapname);
#ifdef DEBUG_IPC
debug(("filemap is %p\n", filemap));
#endif
if (filemap != NULL && filemap != INVALID_HANDLE_VALUE) {
#ifndef NO_SECURITY
int rc;
if (has_security) {
if ((ourself = get_user_sid()) == NULL) {
#ifdef DEBUG_IPC
debug(("couldn't get user SID\n"));
#endif
CloseHandle(filemap);
return 0;
}
if ((ourself2 = get_default_sid()) == NULL) {
#ifdef DEBUG_IPC
debug(("couldn't get default SID\n"));
#endif
CloseHandle(filemap);
return 0;
}
if ((rc = p_GetSecurityInfo(filemap, SE_KERNEL_OBJECT,
OWNER_SECURITY_INFORMATION,
&mapowner, NULL, NULL, NULL,
&psd) != ERROR_SUCCESS)) {
#ifdef DEBUG_IPC
debug(("couldn't get owner info for filemap: %d\n",
rc));
#endif
CloseHandle(filemap);
sfree(ourself2);
return 0;
}
#ifdef DEBUG_IPC
{
LPTSTR ours, ours2, theirs;
ConvertSidToStringSid(mapowner, &theirs);
ConvertSidToStringSid(ourself, &ours);
ConvertSidToStringSid(ourself2, &ours2);
debug(("got sids:\n oursnew=%s\n oursold=%s\n"
" theirs=%s\n", ours, ours2, theirs));
LocalFree(ours);
LocalFree(ours2);
LocalFree(theirs);
}
#endif
if (!EqualSid(mapowner, ourself) &&
!EqualSid(mapowner, ourself2)) {
CloseHandle(filemap);
LocalFree(psd);
sfree(ourself2);
return 0; /* security ID mismatch! */
}
#ifdef DEBUG_IPC
debug(("security stuff matched\n"));
#endif
LocalFree(psd);
sfree(ourself2);
} else {
#ifdef DEBUG_IPC
debug(("security APIs not present\n"));
#endif
}
#endif
p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
#ifdef DEBUG_IPC
debug(("p is %p\n", p));
{
int i;
for (i = 0; i < 5; i++)
debug(("p[%d]=%02x\n", i,
((unsigned char *) p)[i]));
}
#endif
answer_msg(p);
ret = 1;
UnmapViewOfFile(p);
}
CloseHandle(filemap);
return ret;
sfree(err);
return 0;
}
return 1;
}
}