* pads its data with random bytes. Since we only use rsadecrypt()
* and the signing functions, which are deterministic, this should
* never be called.
- *
+ *
* If it _is_ called, there is a _serious_ problem, because it
* won't generate true random numbers. So we must scream, panic,
* and exit immediately if that should happen.
char *comment;
};
+static tree234 *passphrases = NULL;
+
+/*
+ * After processing a list of filenames, we want to forget the
+ * passphrases.
+ */
+static void forget_passphrases(void)
+{
+ int i;
+ while (count234(passphrases) > 0) {
+ char *pp = index234(passphrases, 0);
+ memset(pp, 0, strlen(pp));
+ delpos234(passphrases, 0);
+ free(pp);
+ }
+}
+
/*
* Dialog-box function for the Licence box.
*/
}
/*
+ * Warn about the obsolescent key file format.
+ */
+void old_keyfile_warning(void)
+{
+ static const char mbtitle[] = "PuTTY Key File Warning";
+ static const char message[] =
+ "You are loading an SSH 2 private key which has an\n"
+ "old version of the file format. This means your key\n"
+ "file is not fully tamperproof. Future versions of\n"
+ "PuTTY may stop supporting this private key format,\n"
+ "so we recommend you convert your key to the new\n"
+ "format.\n"
+ "\n"
+ "You can perform this conversion by loading the key\n"
+ "into PuTTYgen and then saving it again.";
+
+ MessageBox(NULL, message, mbtitle, MB_OK);
+}
+
+/*
* Update the visible key list.
*/
static void keylist_update(void)
char *comment;
struct PassphraseProcStruct pps;
int ver;
-
+ int original_pass;
+
ver = keyfile_version(filename);
if (ver == 0) {
MessageBox(NULL, "Couldn't load private key.", APPNAME,
rkey = smalloc(sizeof(*rkey));
pps.passphrase = passphrase;
pps.comment = comment;
+ original_pass = 0;
do {
if (needs_pass) {
- int dlgret;
- dlgret = DialogBoxParam(instance, MAKEINTRESOURCE(210),
- NULL, PassphraseProc, (LPARAM) & pps);
- passphrase_box = NULL;
- if (!dlgret) {
- if (comment)
- sfree(comment);
- if (ver == 1)
- sfree(rkey);
- return; /* operation cancelled */
+ /* try all the remembered passphrases first */
+ char *pp = index234(passphrases, attempts);
+ if(pp) {
+ strcpy(passphrase, pp);
+ } else {
+ int dlgret;
+ original_pass = 1;
+ dlgret = DialogBoxParam(instance, MAKEINTRESOURCE(210),
+ NULL, PassphraseProc, (LPARAM) & pps);
+ passphrase_box = NULL;
+ if (!dlgret) {
+ if (comment)
+ sfree(comment);
+ if (ver == 1)
+ sfree(rkey);
+ return; /* operation cancelled */
+ }
}
} else
*passphrase = '\0';
}
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 (comment)
sfree(comment);
if (ret == 0) {
break;
case SSH2_AGENTC_SIGN_REQUEST:
/*
- * Reply with either SSH2_AGENT_RSA_RESPONSE or
+ * Reply with either SSH2_AGENT_SIGN_RESPONSE or
* SSH_AGENT_FAILURE, depending on whether we have that key
* or not.
*/
char *comment;
int commentlen;
key = smalloc(sizeof(struct RSAKey));
- memset(key, 0, sizeof(key));
+ memset(key, 0, sizeof(struct RSAKey));
p += makekey(p, key, NULL, 1);
p += makeprivate(p, key);
p += ssh1_read_bignum(p, &key->iqmp); /* p^-1 mod q */
/* Add further algorithm names here. */
if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
key->alg = &ssh_rsa;
+ else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7))
+ key->alg = &ssh_dss;
else {
sfree(key);
goto failure;
{
OPENFILENAME of;
char filename[FILENAME_MAX];
+ char *filelist = smalloc(8192);
+ char *filewalker;
+ int n, dirlen;
+
memset(&of, 0, sizeof(of));
#ifdef OPENFILENAME_SIZE_VERSION_400
of.lStructSize = OPENFILENAME_SIZE_VERSION_400;
of.lpstrFilter = "All Files\0*\0\0\0";
of.lpstrCustomFilter = NULL;
of.nFilterIndex = 1;
- of.lpstrFile = filename;
- *filename = '\0';
- of.nMaxFile = sizeof(filename);
+ of.lpstrFile = filelist;
+ *filelist = '\0';
+ of.nMaxFile = FILENAME_MAX;
of.lpstrFileTitle = NULL;
of.lpstrInitialDir = NULL;
of.lpstrTitle = "Select Private Key File";
- of.Flags = 0;
+ of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
if (GetOpenFileName(&of)) {
- add_keyfile(filename);
+ if(strlen(filelist) > of.nFileOffset)
+ /* Only one filename returned? */
+ add_keyfile(filelist);
+ else {
+ /* we are returned a bunch of strings, end to
+ * end. first string is the directory, the
+ * rest the filenames. terminated with an
+ * empty string.
+ */
+ filewalker = filelist;
+ dirlen = strlen(filewalker);
+ if(dirlen > FILENAME_MAX - 8) return;
+ memcpy(filename, filewalker, dirlen);
+
+ filewalker += dirlen + 1;
+ filename[dirlen++] = '\\';
+
+ /* then go over names one by one */
+ for(;;) {
+ n = strlen(filewalker) + 1;
+ /* end of the list */
+ if(n == 1)
+ break;
+ /* too big, shouldn't happen */
+ if(n + dirlen > FILENAME_MAX)
+ break;
+
+ memcpy(filename + dirlen, filewalker, n);
+ filewalker += n;
+
+ add_keyfile(filename);
+ }
+ }
+
keylist_update();
+ forget_passphrases();
}
+ sfree(filelist);
}
/*
case 102: /* remove key */
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) {
- int n = SendDlgItemMessage(hwnd, 100, LB_GETCURSEL, 0, 0);
int i;
- if (n == LB_ERR) {
+ int rCount, sCount;
+ int *selectedArray;
+
+ /* our counter within the array of selected items */
+ int itemNum;
+
+ /* get the number of items selected in the list */
+ int numSelected =
+ SendDlgItemMessage(hwnd, 100, LB_GETSELCOUNT, 0, 0);
+
+ /* none selected? that was silly */
+ if (numSelected == 0) {
MessageBeep(0);
break;
}
- for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++)
- if (n-- == 0)
- break;
- if (rkey) {
- del234(rsakeys, rkey);
- freersakey(rkey);
- sfree(rkey);
- } else {
- for (i = 0; NULL != (skey = index234(ssh2keys, i));
- i++) if (n-- == 0)
- break;
- if (skey) {
- del234(ssh2keys, skey);
- skey->alg->freekey(skey->data);
- sfree(skey);
- }
+
+ /* get item indices in an array */
+ selectedArray = smalloc(numSelected * sizeof(int));
+ SendDlgItemMessage(hwnd, 100, LB_GETSELITEMS,
+ numSelected, (WPARAM)selectedArray);
+
+ itemNum = numSelected - 1;
+ rCount = count234(rsakeys);
+ sCount = count234(ssh2keys);
+
+ /* go through the non-rsakeys until we've covered them all,
+ * and/or we're out of selected items to check. note that
+ * we go *backwards*, to avoid complications from deleting
+ * things hence altering the offset of subsequent items
+ */
+ for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) {
+ skey = index234(ssh2keys, i);
+
+ if (selectedArray[itemNum] == rCount + i) {
+ del234(ssh2keys, skey);
+ skey->alg->freekey(skey->data);
+ sfree(skey);
+ itemNum--;
+ }
+ }
+
+ /* do the same for the rsa keys */
+ for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) {
+ rkey = index234(rsakeys, i);
+
+ if(selectedArray[itemNum] == i) {
+ del234(rsakeys, rkey);
+ freersakey(rkey);
+ sfree(rkey);
+ itemNum--;
+ }
}
+
+ sfree(selectedArray);
keylist_update();
}
return 0;
return 0;
}
+/* Set up a system tray icon */
+static BOOL AddTrayIcon(HWND hwnd)
+{
+ BOOL res;
+ NOTIFYICONDATA tnid;
+ HICON hicon;
+
+#ifdef NIM_SETVERSION
+ 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);
+
+ return res;
+}
+
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int ret;
static int menuinprogress;
+ static UINT msgTaskbarCreated = 0;
switch (message) {
+ case WM_CREATE:
+ msgTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
+ break;
+ default:
+ if (message==msgTaskbarCreated) {
+ /*
+ * Explorer has been restarted, so the tray icon will
+ * have been lost.
+ */
+ AddTrayIcon(hwnd);
+ }
+ break;
+
case WM_SYSTRAY:
if (lParam == WM_RBUTTONUP) {
POINT cursorpos;
/*
* Fork and Exec the command in cmdline. [DBW]
*/
-void spawn_cmd(char *cmdline, int show)
+void spawn_cmd(char *cmdline, char * args, int show)
{
if (ShellExecute(NULL, _T("open"), cmdline,
- NULL, NULL, show) <= (HINSTANCE) 32) {
+ args, NULL, show) <= (HINSTANCE) 32) {
TCHAR sMsg[140];
sprintf(sMsg, _T("Failed to run \"%.100s\", Error: %d"), cmdline,
(int)GetLastError());
100, 100, NULL, NULL, inst, NULL);
/* Set up a system tray icon */
- {
- BOOL res;
- NOTIFYICONDATA tnid;
- HICON hicon;
+ AddTrayIcon(hwnd);
-#ifdef NIM_SETVERSION
- 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");
- }
+ 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);
}
/*
+ * Initialise storage for short-term passphrase cache.
+ */
+ passphrases = newtree234(NULL);
+
+ /*
* 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]
while (*p) {
while (*p && isspace(*p))
p++;
- if (*p && !isspace(*p)) {
+ if (*p && !isspace(*p)) {
char *q = p, *pp = p;
while (*p && (inquotes || !isspace(*p))) {
- if (*p == '"') {
+ if (*p == '"') {
inquotes = !inquotes;
p++;
continue;
}
}
- if (command)
- spawn_cmd(command, show);
+ /*
+ * Forget any passphrase that we retained while going over
+ * command line keyfiles.
+ */
+ forget_passphrases();
+
+ if (command) {
+ char *args;
+ if (command[0] == '"')
+ args = strchr(++command, '"');
+ else
+ args = strchr(command, ' ');
+ if (args) {
+ *args++ = 0;
+ while(*args && isspace(*args)) args++;
+ }
+ spawn_cmd(command, args, show);
+ }
/*
* If Pageant was already running, we leave now. If we haven't