#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
-#include "putty.h" // FIXME
+#include <tchar.h>
+
#include "ssh.h"
#include "tree234.h"
static HWND keylist;
static HWND aboutbox;
static HMENU systray_menu;
+static int already_running;
static tree234 *rsakeys, *ssh2keys;
#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
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
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;
/*
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 */
+ }
}
}
}
* 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);
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);
* 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);
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;
*/
{
struct RSAKey *rkey;
- enum234 e;
- while ( (rkey = first234(rsakeys, &e)) != NULL ) {
+ while ( (rkey = index234(rsakeys, 0)) != NULL ) {
del234(rsakeys, rkey);
freersakey(rkey);
sfree(rkey);
*/
{
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);
/*
* 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.
*/
static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) {
- enum234 e;
struct RSAKey *rkey;
struct ssh2_userkey *skey;
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) {
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) {
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
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");
} 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++;
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.
*/