X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/06897bd7828721c71d68f28cf2df4fca57964538..4b38c5ea8b261eed4f68751cc345e9a24e392ad8:/windows/winpgnt.c diff --git a/windows/winpgnt.c b/windows/winpgnt.c index d4463155..e220d6bb 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -19,6 +19,10 @@ #ifndef NO_SECURITY #include +#ifdef DEBUG_IPC +#define _WIN32_WINNT 0x0500 /* for ConvertSidToStringSid */ +#include +#endif #endif #define IDI_MAINICON 200 @@ -113,10 +117,10 @@ static tree234 *rsakeys, *ssh2keys; static int has_security; #ifndef NO_SECURITY -typedef DWORD(WINAPI * gsi_fn_t) - (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, - PSID *, PSID *, PACL *, PACL *, PSECURITY_DESCRIPTOR *); -static gsi_fn_t getsecurityinfo; +DECL_WINDOWS_FUNCTION(extern, DWORD, GetSecurityInfo, + (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, + PSID *, PSID *, PACL *, PACL *, + PSECURITY_DESCRIPTOR *)); #endif /* @@ -155,10 +159,8 @@ struct blob { }; static int cmpkeys_ssh2_asymm(void *av, void *bv); -#define PASSPHRASE_MAXLEN 512 - struct PassphraseProcStruct { - char *passphrase; + char **passphrase; char *comment; }; @@ -172,7 +174,7 @@ static void forget_passphrases(void) { while (count234(passphrases) > 0) { char *pp = index234(passphrases, 0); - memset(pp, 0, strlen(pp)); + smemclr(pp, strlen(pp)); delpos234(passphrases, 0); free(pp); } @@ -243,7 +245,7 @@ static HWND passphrase_box; static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - static char *passphrase = NULL; + static char **passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { @@ -271,8 +273,9 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); - *passphrase = 0; - SetDlgItemText(hwnd, 102, passphrase); + burnstr(*passphrase); + *passphrase = dupstr(""); + SetDlgItemText(hwnd, 102, *passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -287,9 +290,8 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, return 0; case 102: /* edit box */ if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { - GetDlgItemText(hwnd, 102, passphrase, - PASSPHRASE_MAXLEN - 1); - passphrase[PASSPHRASE_MAXLEN - 1] = '\0'; + burnstr(*passphrase); + *passphrase = GetDlgItemText_alloc(hwnd, 102); } return 0; } @@ -351,28 +353,27 @@ static void keylist_update(void) 0, (LPARAM) listentry); } for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) { - char listentry[512], *p; - int len; + char *listentry, *p; + int fp_len; /* * Replace two spaces in the fingerprint with tabs, for * nice alignment in the box. */ p = skey->alg->fingerprint(skey->data); - strncpy(listentry, p, sizeof(listentry)); + listentry = dupprintf("%s\t%s", p, skey->comment); + fp_len = strlen(listentry); + sfree(p); + p = strchr(listentry, ' '); - if (p) + if (p && p < listentry + fp_len) *p = '\t'; p = strchr(listentry, ' '); - if (p) + if (p && p < listentry + fp_len) *p = '\t'; - len = strlen(listentry); - if (len < sizeof(listentry) - 2) { - listentry[len] = '\t'; - strncpy(listentry + len + 1, skey->comment, - sizeof(listentry) - len - 1); - } + SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); + sfree(listentry); } SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM) - 1, 0); } @@ -381,9 +382,9 @@ static void keylist_update(void) /* * This function loads a key from a file and adds it. */ -static void add_keyfile(Filename filename) +static void add_keyfile(Filename *filename) { - char passphrase[PASSPHRASE_MAXLEN]; + char *passphrase; struct RSAKey *rkey = NULL; struct ssh2_userkey *skey = NULL; int needs_pass; @@ -391,11 +392,10 @@ static void add_keyfile(Filename filename) int attempts; char *comment; const char *error = NULL; - struct PassphraseProcStruct pps; int type; int original_pass; - type = key_type(&filename); + type = key_type(filename); if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) { char *msg = dupprintf("Couldn't load this key (%s)", key_type_to_str(type)); @@ -415,7 +415,7 @@ static void add_keyfile(Filename filename) int i, nkeys, bloblen, keylistlen; if (type == SSH_KEYTYPE_SSH1) { - if (!rsakey_pubblob(&filename, &blob, &bloblen, &error)) { + if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) { char *msg = dupprintf("Couldn't load private key (%s)", error); message_box(msg, APPNAME, MB_OK | MB_ICONERROR, HELPCTXID(errors_cantloadkey)); @@ -425,7 +425,7 @@ static void add_keyfile(Filename filename) keylist = get_keylist1(&keylistlen); } else { unsigned char *blob2; - blob = ssh2_userkey_loadpub(&filename, NULL, &bloblen, + blob = ssh2_userkey_loadpub(filename, NULL, &bloblen, NULL, &error); if (!blob) { char *msg = dupprintf("Couldn't load private key (%s)", error); @@ -449,7 +449,12 @@ static void add_keyfile(Filename filename) MB_OK | MB_ICONERROR); return; } - nkeys = GET_32BIT(keylist); + nkeys = toint(GET_32BIT(keylist)); + if (nkeys < 0) { + MessageBox(NULL, "Received broken key list?!", APPNAME, + MB_OK | MB_ICONERROR); + return; + } p = keylist + 4; keylistlen -= 4; @@ -477,8 +482,8 @@ static void add_keyfile(Filename filename) MB_OK | MB_ICONERROR); return; } - n = 4 + GET_32BIT(p); - if (keylistlen < n) { + n = toint(4 + GET_32BIT(p)); + if (n < 0 || keylistlen < n) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; @@ -494,8 +499,8 @@ static void add_keyfile(Filename filename) MB_OK | MB_ICONERROR); return; } - n = 4 + GET_32BIT(p); - if (keylistlen < n) { + n = toint(4 + GET_32BIT(p)); + if (n < 0 || keylistlen < n) { MessageBox(NULL, "Received broken key list?!", APPNAME, MB_OK | MB_ICONERROR); return; @@ -513,23 +518,30 @@ static void add_keyfile(Filename filename) error = NULL; if (type == SSH_KEYTYPE_SSH1) - needs_pass = rsakey_encrypted(&filename, &comment); + needs_pass = rsakey_encrypted(filename, &comment); else - needs_pass = ssh2_userkey_encrypted(&filename, &comment); + needs_pass = ssh2_userkey_encrypted(filename, &comment); attempts = 0; if (type == SSH_KEYTYPE_SSH1) rkey = snew(struct RSAKey); - pps.passphrase = passphrase; - pps.comment = comment; + passphrase = NULL; original_pass = 0; do { + burnstr(passphrase); + passphrase = NULL; + if (needs_pass) { /* try all the remembered passphrases first */ char *pp = index234(passphrases, attempts); if(pp) { - strcpy(passphrase, pp); + passphrase = dupstr(pp); } else { int dlgret; + struct PassphraseProcStruct pps; + + pps.passphrase = &passphrase; + pps.comment = comment; + original_pass = 1; dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, (LPARAM) &pps); @@ -541,13 +553,16 @@ static void add_keyfile(Filename filename) sfree(rkey); return; /* operation cancelled */ } + + assert(passphrase != NULL); } } else - *passphrase = '\0'; + passphrase = dupstr(""); + if (type == SSH_KEYTYPE_SSH1) - ret = loadrsakey(&filename, rkey, passphrase, &error); + ret = loadrsakey(filename, rkey, passphrase, &error); else { - skey = ssh2_load_userkey(&filename, passphrase, &error); + skey = ssh2_load_userkey(filename, passphrase, &error); if (skey == SSH2_WRONG_PASSPHRASE) ret = -1; else if (!skey) @@ -558,11 +573,14 @@ static void add_keyfile(Filename filename) attempts++; } while (ret == -1); - /* if they typed in an ok passphrase, remember it */ if(original_pass && ret) { - char *pp = dupstr(passphrase); - addpos234(passphrases, pp, 0); + /* If they typed in an ok passphrase, remember it */ + addpos234(passphrases, passphrase, 0); + } else { + /* Otherwise, destroy it */ + burnstr(passphrase); } + passphrase = NULL; if (comment) sfree(comment); @@ -954,7 +972,7 @@ static void answer_msg(void *msg) MD5Init(&md5c); MD5Update(&md5c, response_source, 48); MD5Final(response_md5, &md5c); - memset(response_source, 0, 48); /* burn the evidence */ + smemclr(response_source, 48); /* burn the evidence */ freebn(response); /* and that evidence */ freebn(challenge); /* yes, and that evidence */ freebn(reqkey.exponent); /* and free some memory ... */ @@ -984,17 +1002,17 @@ static void answer_msg(void *msg) if (msgend < p+4) goto failure; - b.len = GET_32BIT(p); + b.len = toint(GET_32BIT(p)); + if (b.len < 0 || b.len > msgend - (p+4)) + goto failure; p += 4; - if (msgend < p+b.len) - goto failure; b.blob = p; p += b.len; if (msgend < p+4) goto failure; - datalen = GET_32BIT(p); + datalen = toint(GET_32BIT(p)); p += 4; - if (msgend < p+datalen) + if (datalen < 0 || datalen > msgend - p) goto failure; data = p; key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); @@ -1067,9 +1085,9 @@ static void answer_msg(void *msg) sfree(key); goto failure; } - commentlen = GET_32BIT(p); + commentlen = toint(GET_32BIT(p)); - if (msgend < p+commentlen) { + if (commentlen < 0 || commentlen > msgend - p) { freersakey(key); sfree(key); goto failure; @@ -1106,9 +1124,9 @@ static void answer_msg(void *msg) if (msgend < p+4) goto failure; - alglen = GET_32BIT(p); + alglen = toint(GET_32BIT(p)); p += 4; - if (msgend < p+alglen) + if (alglen < 0 || alglen > msgend - p) goto failure; alg = p; p += alglen; @@ -1142,10 +1160,10 @@ static void answer_msg(void *msg) sfree(key); goto failure; } - commlen = GET_32BIT(p); + commlen = toint(GET_32BIT(p)); p += 4; - if (msgend < p+commlen) { + if (commlen < 0 || commlen > msgend - p) { key->alg->freekey(key->data); sfree(key); goto failure; @@ -1209,10 +1227,10 @@ static void answer_msg(void *msg) if (msgend < p+4) goto failure; - b.len = GET_32BIT(p); + b.len = toint(GET_32BIT(p)); p += 4; - if (msgend < p+b.len) + if (b.len < 0 || b.len > msgend - p) goto failure; b.blob = p; p += b.len; @@ -1470,7 +1488,7 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, rd.right - rd.left, rd.bottom - rd.top, TRUE); } - if (help_path) + if (has_help()) SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP); @@ -1479,7 +1497,6 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, if (item) DestroyWindow(item); } - requested_help = FALSE; keylist = hwnd; { @@ -1572,29 +1589,22 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, case 103: /* help */ if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { - if (help_path) { - WinHelp(hwnd, help_path, HELP_COMMAND, - (DWORD)"JI(`',`pageant.general')"); - requested_help = TRUE; - } + launch_help(hwnd, WINHELP_CTX_pageant_general); } return 0; } return 0; case WM_HELP: - if (help_path) { + { int id = ((LPHELPINFO)lParam)->iCtrlId; char *topic = NULL; switch (id) { - case 100: topic = "pageant.keylist"; break; - case 101: topic = "pageant.addkey"; break; - case 102: topic = "pageant.remkey"; break; + case 100: topic = WINHELP_CTX_pageant_keylist; break; + case 101: topic = WINHELP_CTX_pageant_addkey; break; + case 102: topic = WINHELP_CTX_pageant_remkey; break; } if (topic) { - char *cmd = dupprintf("JI(`',`%s')", topic); - WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd); - sfree(cmd); - requested_help = TRUE; + launch_help(hwnd, topic); } else { MessageBeep(0); } @@ -1688,6 +1698,53 @@ static void update_sessions(void) } } +#ifndef NO_SECURITY +/* + * Versions of Pageant prior to 0.61 expected this SID on incoming + * communications. For backwards compatibility, and more particularly + * for compatibility with derived works of PuTTY still using the old + * Pageant client code, we accept it as an alternative to the one + * returned from get_user_sid() in winpgntc.c. + */ +PSID get_default_sid(void) +{ + HANDLE proc = NULL; + DWORD sidlen; + PSECURITY_DESCRIPTOR psd = NULL; + PSID sid = NULL, copy = NULL, ret = NULL; + + if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, + GetCurrentProcessId())) == NULL) + goto cleanup; + + if (p_GetSecurityInfo(proc, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, + &sid, NULL, NULL, NULL, &psd) != ERROR_SUCCESS) + goto cleanup; + + sidlen = GetLengthSid(sid); + + copy = (PSID)smalloc(sidlen); + + if (!CopySid(sidlen, copy, sid)) + goto cleanup; + + /* Success. Move sid into the return value slot, and null it out + * to stop the cleanup code freeing it. */ + ret = copy; + copy = NULL; + + cleanup: + if (proc != NULL) + CloseHandle(proc); + if (psd != NULL) + LocalFree(psd); + if (copy != NULL) + sfree(copy); + + return ret; +} +#endif + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1788,11 +1845,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case IDM_HELP: - if (help_path) { - WinHelp(hwnd, help_path, HELP_COMMAND, - (DWORD)"JI(`',`pageant.general')"); - requested_help = TRUE; - } + launch_help(hwnd, WINHELP_CTX_pageant_general); break; default: { @@ -1819,10 +1872,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case WM_DESTROY: - if (requested_help) { - WinHelp(hwnd, help_path, HELP_QUIT, 0); - requested_help = FALSE; - } + quit_help(hwnd); PostQuitMessage(0); return 0; case WM_COPYDATA: @@ -1832,10 +1882,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, void *p; HANDLE filemap; #ifndef NO_SECURITY - HANDLE proc; - PSID mapowner, procowner; - PSECURITY_DESCRIPTOR psd1 = NULL, psd2 = NULL; + PSID mapowner, ourself, ourself2; #endif + PSECURITY_DESCRIPTOR psd = NULL; int ret = 0; cds = (COPYDATASTRUCT *) lParam; @@ -1855,46 +1904,54 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #ifndef NO_SECURITY int rc; if (has_security) { - if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE, - GetCurrentProcessId())) == - NULL) { + if ((ourself = get_user_sid()) == NULL) { #ifdef DEBUG_IPC - debug(("couldn't get handle for process\n")); + debug(("couldn't get user SID\n")); #endif return 0; - } - if (getsecurityinfo(proc, SE_KERNEL_OBJECT, - OWNER_SECURITY_INFORMATION, - &procowner, NULL, NULL, NULL, - &psd2) != ERROR_SUCCESS) { + } + + if ((ourself2 = get_default_sid()) == NULL) { #ifdef DEBUG_IPC - debug(("couldn't get owner info for process\n")); + debug(("couldn't get default SID\n")); #endif - CloseHandle(proc); - return 0; /* unable to get security info */ - } - CloseHandle(proc); - if ((rc = getsecurityinfo(filemap, SE_KERNEL_OBJECT, - OWNER_SECURITY_INFORMATION, - &mapowner, NULL, NULL, NULL, - &psd1) != ERROR_SUCCESS)) { + 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)); + debug(("couldn't get owner info for filemap: %d\n", + rc)); #endif return 0; } #ifdef DEBUG_IPC - debug(("got security stuff\n")); + { + 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, procowner)) + if (!EqualSid(mapowner, ourself) && + !EqualSid(mapowner, ourself2)) { + CloseHandle(filemap); return 0; /* security ID mismatch! */ + } #ifdef DEBUG_IPC debug(("security stuff matched\n")); #endif - LocalFree(psd1); - LocalFree(psd2); + LocalFree(psd); + sfree(ourself); + sfree(ourself2); } else { #ifdef DEBUG_IPC debug(("security APIs not present\n")); @@ -1907,9 +1964,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, { int i; for (i = 0; i < 5; i++) - debug( - ("p[%d]=%02x\n", i, - ((unsigned char *) p)[i]));} + debug(("p[%d]=%02x\n", i, + ((unsigned char *) p)[i])); + } #endif answer_msg(p); ret = 1; @@ -1948,7 +2005,11 @@ void agent_schedule_callback(void (*callback)(void *, void *, int), assert(!"We shouldn't get here"); } -void cleanup_exit(int code) { exit(code); } +void cleanup_exit(int code) +{ + shutdown_help(); + exit(code); +} int flags = FLAG_SYNCAGENT; @@ -1983,10 +2044,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * Attempt to get the security API we need. */ - advapi = LoadLibrary("ADVAPI32.DLL"); - getsecurityinfo = - (gsi_fn_t) GetProcAddress(advapi, "GetSecurityInfo"); - if (!getsecurityinfo) { + if (!init_advapi()) { MessageBox(NULL, "Unable to access security APIs. Pageant will\n" "not run, in case it causes a security breach.", @@ -2006,22 +2064,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * See if we can find our Help file. */ - { - char b[2048], *p, *q, *r; - FILE *fp; - GetModuleFileName(NULL, b, sizeof(b) - 1); - r = b; - p = strrchr(b, '\\'); - if (p && p >= r) r = p+1; - q = strrchr(b, ':'); - if (q && q >= r) r = q+1; - strcpy(r, PUTTY_HELP_FILE); - if ( (fp = fopen(b, "r")) != NULL) { - help_path = dupstr(b); - fclose(fp); - } else - help_path = NULL; - } + init_help(); /* * Look for the PuTTY binary (we will enable the saved session @@ -2030,7 +2073,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { char b[2048], *p, *q, *r; FILE *fp; - GetModuleFileName(NULL, b, sizeof(b) - 1); + GetModuleFileName(NULL, b, sizeof(b) - 16); r = b; p = strrchr(b, '\\'); if (p && p >= r) r = p+1; @@ -2161,7 +2204,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) "&View Keys"); AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key"); AppendMenu(systray_menu, MF_SEPARATOR, 0, 0); - if (help_path) + if (has_help()) AppendMenu(systray_menu, MF_ENABLED, IDM_HELP, "&Help"); AppendMenu(systray_menu, MF_ENABLED, IDM_ABOUT, "&About"); AppendMenu(systray_menu, MF_SEPARATOR, 0, 0); @@ -2201,5 +2244,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (advapi) FreeLibrary(advapi); - return msg.wParam; + + cleanup_exit(msg.wParam); + return msg.wParam; /* just in case optimiser complains */ }