X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/02237972725a2ee327ff5684bd09742d8c1b15e9..ff89646a8828ce862d53b96a19ee6469dabce71a:/pageant.c diff --git a/pageant.c b/pageant.c index 370c099a..2d0b15ee 100644 --- a/pageant.c +++ b/pageant.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ssh.h" #include "tree234.h" @@ -41,6 +42,7 @@ static HWND hwnd; static HWND keylist; static HWND aboutbox; static HMENU systray_menu; +static int already_running; static tree234 *rsakeys, *ssh2keys; @@ -54,6 +56,12 @@ static gsi_fn_t getsecurityinfo; #endif /* + * Exports from pageantc.c + */ +void agent_query(void *in, int inlen, void **out, int *outlen); +int agent_exists(void); + +/* * We need this to link with the RSA code, because rsaencrypt() * pads its data with random bytes. Since we only use rsadecrypt() * and the signing functions, which are deterministic, this should @@ -162,7 +170,7 @@ static int CALLBACK AboutProc (HWND hwnd, UINT msg, */ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - static char *passphrase; + static char *passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { @@ -189,6 +197,7 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, if (p->comment) SetDlgItemText(hwnd, 101, p->comment); *passphrase = 0; + SetDlgItemText (hwnd, 102, passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -202,7 +211,7 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, EndDialog (hwnd, 0); return 0; case 102: /* edit box */ - if (HIWORD(wParam) == EN_CHANGE) { + if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { GetDlgItemText (hwnd, 102, passphrase, PASSPHRASE_MAXLEN-1); passphrase[PASSPHRASE_MAXLEN-1] = '\0'; } @@ -222,11 +231,11 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, static void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; - enum234 e; + int i; if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); - for (rkey = first234(rsakeys, &e); rkey; rkey = next234(&e)) { + for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for @@ -240,7 +249,7 @@ static void keylist_update(void) { SendDlgItemMessage (keylist, 100, LB_ADDSTRING, 0, (LPARAM)listentry); } - for (skey = first234(ssh2keys, &e); skey; skey = next234(&e)) { + for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) { char listentry[512], *p; int len; /* @@ -329,12 +338,89 @@ static void add_keyfile(char *filename) { return; } if (ver == 1) { - if (add234(rsakeys, rkey) != rkey) - sfree(rkey); /* already present, don't waste RAM */ + if (already_running) { + unsigned char *request, *response; + int reqlen, clen, resplen; + + clen = strlen(rkey->comment); + + reqlen = 4 + 1 + /* length, message type */ + 4 + /* bit count */ + ssh1_bignum_length(rkey->modulus) + + ssh1_bignum_length(rkey->exponent) + + ssh1_bignum_length(rkey->private_exponent) + + ssh1_bignum_length(rkey->iqmp) + + ssh1_bignum_length(rkey->p) + + ssh1_bignum_length(rkey->q) + + 4 + clen /* comment */ + ; + + request = smalloc(reqlen); + + request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY; + reqlen = 5; + PUT_32BIT(request+reqlen, bignum_bitcount(rkey->modulus)); + reqlen += 4; + reqlen += ssh1_write_bignum(request+reqlen, rkey->modulus); + reqlen += ssh1_write_bignum(request+reqlen, rkey->exponent); + reqlen += ssh1_write_bignum(request+reqlen, rkey->private_exponent); + reqlen += ssh1_write_bignum(request+reqlen, rkey->iqmp); + reqlen += ssh1_write_bignum(request+reqlen, rkey->p); + reqlen += ssh1_write_bignum(request+reqlen, rkey->q); + PUT_32BIT(request+reqlen, clen); + memcpy(request+reqlen+4, rkey->comment, clen); + reqlen += 4+clen; + PUT_32BIT(request, reqlen-4); + + agent_query(request, reqlen, &response, &resplen); + if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) + MessageBox(NULL, "The already running Pageant " + "refused to add the key.", APPNAME, + MB_OK | MB_ICONERROR); + } else { + if (add234(rsakeys, rkey) != rkey) + sfree(rkey); /* already present, don't waste RAM */ + } } else { - if (add234(ssh2keys, skey) != skey) { - skey->alg->freekey(skey->data); - sfree(skey); /* already present, don't waste RAM */ + if (already_running) { + unsigned char *request, *response; + int reqlen, alglen, clen, keybloblen, resplen; + alglen = strlen(skey->alg->name); + clen = strlen(skey->comment); + + keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0); + + reqlen = 4 + 1 + /* length, message type */ + 4 + alglen + /* algorithm name */ + keybloblen + /* key data */ + 4 + clen /* comment */ + ; + + request = smalloc(reqlen); + + request[4] = SSH2_AGENTC_ADD_IDENTITY; + reqlen = 5; + PUT_32BIT(request+reqlen, alglen); + reqlen += 4; + memcpy(request+reqlen, skey->alg->name, alglen); + reqlen += alglen; + reqlen += skey->alg->openssh_fmtkey(skey->data, + request+reqlen, keybloblen); + PUT_32BIT(request+reqlen, clen); + memcpy(request+reqlen+4, skey->comment, clen); + PUT_32BIT(request, reqlen-4); + reqlen += clen+4; + + agent_query(request, reqlen, &response, &resplen); + if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) + MessageBox(NULL, "The already running Pageant" + "refused to add the key.", APPNAME, + MB_OK | MB_ICONERROR); + } else { + if (add234(ssh2keys, skey) != skey) { + skey->alg->freekey(skey->data); + sfree(skey); /* already present, don't waste RAM */ + } } } } @@ -359,15 +445,15 @@ static void answer_msg(void *msg) { * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER. */ { - enum234 e; struct RSAKey *key; int len, nkeys; + int i; /* * Count up the number and length of keys we hold. */ len = nkeys = 0; - for (key = first234(rsakeys, &e); key; key = next234(&e)) { + for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { nkeys++; len += 4; /* length field */ len += ssh1_bignum_length(key->exponent); @@ -386,8 +472,8 @@ static void answer_msg(void *msg) { ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER; PUT_32BIT(ret+5, nkeys); p = ret + 5 + 4; - for (key = first234(rsakeys, &e); key; key = next234(&e)) { - PUT_32BIT(p, ssh1_bignum_bitcount(key->modulus)); + for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { + PUT_32BIT(p, bignum_bitcount(key->modulus)); p += 4; p += ssh1_write_bignum(p, key->exponent); p += ssh1_write_bignum(p, key->modulus); @@ -402,17 +488,17 @@ static void answer_msg(void *msg) { * Reply with SSH2_AGENT_IDENTITIES_ANSWER. */ { - enum234 e; struct ssh2_userkey *key; int len, nkeys; unsigned char *blob; int bloblen; + int i; /* * Count up the number and length of keys we hold. */ len = nkeys = 0; - for (key = first234(ssh2keys, &e); key; key = next234(&e)) { + for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { nkeys++; len += 4; /* length field */ blob = key->alg->public_blob(key->data, &bloblen); @@ -432,7 +518,7 @@ static void answer_msg(void *msg) { ret[4] = SSH2_AGENT_IDENTITIES_ANSWER; PUT_32BIT(ret+5, nkeys); p = ret + 5 + 4; - for (key = first234(ssh2keys, &e); key; key = next234(&e)) { + for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { blob = key->alg->public_blob(key->data, &bloblen); PUT_32BIT(p, bloblen); p += 4; @@ -664,9 +750,8 @@ static void answer_msg(void *msg) { */ { struct RSAKey *rkey; - enum234 e; - while ( (rkey = first234(rsakeys, &e)) != NULL ) { + while ( (rkey = index234(rsakeys, 0)) != NULL ) { del234(rsakeys, rkey); freersakey(rkey); sfree(rkey); @@ -683,9 +768,8 @@ static void answer_msg(void *msg) { */ { struct ssh2_userkey *skey; - enum234 e; - while ( (skey = first234(ssh2keys, &e)) != NULL ) { + while ( (skey = index234(ssh2keys, 0)) != NULL ) { del234(ssh2keys, skey); skey->alg->freekey(skey->data); sfree(skey); @@ -721,8 +805,8 @@ static int cmpkeys_rsa(void *av, void *bv) { /* * Compare by length of moduli. */ - alen = ssh1_bignum_bitcount(am); - blen = ssh1_bignum_bitcount(bm); + alen = bignum_bitcount(am); + blen = bignum_bitcount(bm); if (alen > blen) return +1; else if (alen < blen) return -1; /* * Now compare by moduli themselves. @@ -846,7 +930,6 @@ static void prompt_add_keyfile(void) { */ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - enum234 e; struct RSAKey *rkey; struct ssh2_userkey *skey; @@ -891,11 +974,12 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, if (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DOUBLECLICKED) { int n = SendDlgItemMessage (hwnd, 100, LB_GETCURSEL, 0, 0); + int i; if (n == LB_ERR) { MessageBeep(0); break; } - for (rkey = first234(rsakeys, &e); rkey; rkey = next234(&e)) + for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) if (n-- == 0) break; if (rkey) { @@ -903,7 +987,7 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, freersakey(rkey); sfree(rkey); } else { - for (skey = first234(ssh2keys, &e); skey; skey = next234(&e)) + for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) if (n-- == 0) break; if (skey) { @@ -1081,11 +1165,26 @@ static LRESULT CALLBACK WndProc (HWND hwnd, UINT message, return DefWindowProc (hwnd, message, wParam, lParam); } +/* + * Fork and Exec the command in cmdline. [DBW] + */ +void spawn_cmd(char *cmdline, int show) { + if (ShellExecute(NULL, _T("open"), cmdline, + NULL, NULL, show) <= (HINSTANCE) 32) { + TCHAR sMsg[140]; + sprintf(sMsg, _T("Failed to run \"%.100s\", Error: %d"), cmdline, + GetLastError()); + MessageBox(NULL, sMsg, APPNAME, MB_OK | MB_ICONEXCLAMATION); + } +} + int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; OSVERSIONINFO osi; HMODULE advapi; + char *command = NULL; + int added_keys = 0; /* * Determine whether we're an NT system (should have security @@ -1101,7 +1200,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { if (has_security) { #ifndef NO_SECURITY /* - * Attempt to ge the security API we need. + * Attempt to get the security API we need. */ advapi = LoadLibrary("ADVAPI32.DLL"); getsecurityinfo = (gsi_fn_t)GetProcAddress(advapi, "GetSecurityInfo"); @@ -1122,87 +1221,90 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { } else advapi = NULL; - /* - * First bomb out totally if we are already running. - */ - if (FindWindow("Pageant", "Pageant")) { - MessageBox(NULL, "Pageant is already running", "Pageant Error", - MB_ICONERROR | MB_OK); - if (advapi) FreeLibrary(advapi); - return 0; - } - instance = inst; - if (!prev) { - wndclass.style = 0; - wndclass.lpfnWndProc = WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = inst; - wndclass.hIcon = LoadIcon (inst, - MAKEINTRESOURCE(IDI_MAINICON)); - wndclass.hCursor = LoadCursor (NULL, IDC_IBEAM); - wndclass.hbrBackground = GetStockObject (BLACK_BRUSH); - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = APPNAME; - - RegisterClass (&wndclass); - } + /* + * Find out if Pageant is already running. + */ + already_running = FALSE; + if (agent_exists()) + already_running = TRUE; + else { + + if (!prev) { + wndclass.style = 0; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = inst; + wndclass.hIcon = LoadIcon (inst, + MAKEINTRESOURCE(IDI_MAINICON)); + wndclass.hCursor = LoadCursor (NULL, IDC_IBEAM); + wndclass.hbrBackground = GetStockObject (BLACK_BRUSH); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = APPNAME; + + RegisterClass (&wndclass); + } - hwnd = keylist = NULL; + hwnd = keylist = NULL; - hwnd = CreateWindow (APPNAME, APPNAME, - WS_OVERLAPPEDWINDOW | WS_VSCROLL, - CW_USEDEFAULT, CW_USEDEFAULT, - 100, 100, NULL, NULL, inst, NULL); + hwnd = CreateWindow (APPNAME, APPNAME, + WS_OVERLAPPEDWINDOW | WS_VSCROLL, + CW_USEDEFAULT, CW_USEDEFAULT, + 100, 100, NULL, NULL, inst, NULL); - /* Set up a system tray icon */ - { - BOOL res; - NOTIFYICONDATA tnid; - HICON hicon; + /* Set up a system tray icon */ + { + BOOL res; + NOTIFYICONDATA tnid; + HICON hicon; #ifdef NIM_SETVERSION - tnid.uVersion = 0; - res = Shell_NotifyIcon(NIM_SETVERSION, &tnid); + tnid.uVersion = 0; + res = Shell_NotifyIcon(NIM_SETVERSION, &tnid); #endif - tnid.cbSize = sizeof(NOTIFYICONDATA); - tnid.hWnd = hwnd; - tnid.uID = 1; /* unique within this systray use */ - tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; - tnid.uCallbackMessage = WM_SYSTRAY; - tnid.hIcon = hicon = LoadIcon (instance, MAKEINTRESOURCE(201)); - strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)"); - - res = Shell_NotifyIcon(NIM_ADD, &tnid); - - if (hicon) - DestroyIcon(hicon); - - systray_menu = CreatePopupMenu(); - /* accelerators used: vkxa */ - AppendMenu (systray_menu, MF_ENABLED, IDM_VIEWKEYS, "&View Keys"); - AppendMenu (systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key"); - AppendMenu (systray_menu, MF_ENABLED, IDM_ABOUT, "&About"); - AppendMenu (systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit"); - } + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hwnd; + tnid.uID = 1; /* unique within this systray use */ + tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + tnid.uCallbackMessage = WM_SYSTRAY; + tnid.hIcon = hicon = LoadIcon (instance, MAKEINTRESOURCE(201)); + strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)"); + + res = Shell_NotifyIcon(NIM_ADD, &tnid); + + if (hicon) + DestroyIcon(hicon); + + systray_menu = CreatePopupMenu(); + /* accelerators used: vkxa */ + AppendMenu (systray_menu, MF_ENABLED, IDM_VIEWKEYS, "&View Keys"); + AppendMenu (systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key"); + AppendMenu (systray_menu, MF_ENABLED, IDM_ABOUT, "&About"); + AppendMenu (systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit"); + } - ShowWindow (hwnd, SW_HIDE); + ShowWindow (hwnd, SW_HIDE); - /* - * Initialise storage for RSA keys. - */ - rsakeys = newtree234(cmpkeys_rsa); - ssh2keys = newtree234(cmpkeys_ssh2); + /* + * Initialise storage for RSA keys. + */ + rsakeys = newtree234(cmpkeys_rsa); + ssh2keys = newtree234(cmpkeys_ssh2); + + } /* * Process the command line and add keys as listed on it. + * If we already determined that we need to spawn a program from above we + * need to ignore the first two arguments. [DBW] */ { char *p; int inquotes = 0; + int ignorearg = 0; p = cmdline; while (*p) { while (*p && isspace(*p)) p++; @@ -1221,11 +1323,39 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { if (*p) p++; *pp++ = '\0'; } - add_keyfile(q); + if (!strcmp(q, "-c")) { + /* + * If we see `-c', then the rest of the + * command line should be treated as a + * command to be spawned. + */ + while (*p && isspace(*p)) p++; + command = p; + break; + } else { + add_keyfile(q); + added_keys = TRUE; + } } } } + if (command) spawn_cmd (command, show); + + /* + * If Pageant was already running, we leave now. If we haven't + * even taken any auxiliary action (spawned a command or added + * keys), complain. + */ + if (already_running) { + if (!command && !added_keys) { + MessageBox(NULL, "Pageant is already running", "Pageant Error", + MB_ICONERROR | MB_OK); + } + if (advapi) FreeLibrary(advapi); + return 0; + } + /* * Main message loop. */