Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'windows/winpgnt.c')
-rw-r--r--windows/winpgnt.c1723
1 files changed, 0 insertions, 1723 deletions
diff --git a/windows/winpgnt.c b/windows/winpgnt.c
deleted file mode 100644
index d6e960b6..00000000
--- a/windows/winpgnt.c
+++ /dev/null
@@ -1,1723 +0,0 @@
-/*
- * Pageant: the PuTTY Authentication Agent.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <ctype.h>
-#include <assert.h>
-#include <tchar.h>
-
-#include "putty.h"
-#include "ssh.h"
-#include "misc.h"
-#include "tree234.h"
-#include "winsecur.h"
-#include "wincapi.h"
-#include "pageant.h"
-#include "licence.h"
-#include "pageant-rc.h"
-
-#include <shellapi.h>
-
-#ifndef NO_SECURITY
-#include <aclapi.h>
-#ifdef DEBUG_IPC
-#define _WIN32_WINNT 0x0500 /* for ConvertSidToStringSid */
-#include <sddl.h>
-#endif
-#endif
-
-#define WM_SYSTRAY (WM_APP + 6)
-#define WM_SYSTRAY2 (WM_APP + 7)
-
-#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
-
-#define APPNAME "Pageant"
-
-/* Titles and class names for invisible windows. IPCWINTITLE and
- * IPCCLASSNAME are critical to backwards compatibility: WM_COPYDATA
- * based Pageant clients will call FindWindow with those parameters
- * and expect to find the Pageant IPC receiver. */
-#define TRAYWINTITLE "Pageant"
-#define TRAYCLASSNAME "PageantSysTray"
-#define IPCWINTITLE "Pageant"
-#define IPCCLASSNAME "Pageant"
-
-static HWND traywindow;
-static HWND keylist;
-static HWND aboutbox;
-static HMENU systray_menu, session_menu;
-static bool already_running;
-static FingerprintType fptype = SSH_FPTYPE_DEFAULT;
-
-static char *putty_path;
-static bool restrict_putty_acl = false;
-
-/* CWD for "add key" file requester. */
-static filereq *keypath = NULL;
-
-/* From MSDN: In the WM_SYSCOMMAND message, the four low-order bits of
- * wParam are used by Windows, and should be masked off, so we shouldn't
- * attempt to store information in them. Hence all these identifiers have
- * the low 4 bits clear. Also, identifiers should < 0xF000. */
-
-#define IDM_CLOSE 0x0010
-#define IDM_VIEWKEYS 0x0020
-#define IDM_ADDKEY 0x0030
-#define IDM_ADDKEY_ENCRYPTED 0x0040
-#define IDM_REMOVE_ALL 0x0050
-#define IDM_REENCRYPT_ALL 0x0060
-#define IDM_HELP 0x0070
-#define IDM_ABOUT 0x0080
-#define IDM_PUTTY 0x0090
-#define IDM_SESSIONS_BASE 0x1000
-#define IDM_SESSIONS_MAX 0x2000
-#define PUTTY_REGKEY "Software\\SimonTatham\\PuTTY\\Sessions"
-#define PUTTY_DEFAULT "Default%20Settings"
-static int initial_menuitems_count;
-
-/*
- * Print a modal (Really Bad) message box and perform a fatal exit.
- */
-void modalfatalbox(const char *fmt, ...)
-{
- va_list ap;
- char *buf;
-
- va_start(ap, fmt);
- buf = dupvprintf(fmt, ap);
- va_end(ap);
- MessageBox(traywindow, buf, "Pageant Fatal Error",
- MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
- sfree(buf);
- exit(1);
-}
-
-static bool has_security;
-
-struct PassphraseProcStruct {
- bool modal;
- const char *help_topic;
- PageantClientDialogId *dlgid;
- char *passphrase;
- const char *comment;
-};
-
-/*
- * Dialog-box function for the Licence box.
- */
-static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG:
- SetDlgItemText(hwnd, IDC_LICENCE_TEXTBOX, LICENCE_TEXT("\r\n\r\n"));
- return 1;
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- EndDialog(hwnd, 1);
- return 0;
- }
- return 0;
-}
-
-/*
- * Dialog-box function for the About box.
- */
-static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- switch (msg) {
- case WM_INITDIALOG: {
- char *buildinfo_text = buildinfo("\r\n");
- char *text = dupprintf
- ("Pageant\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s",
- ver, buildinfo_text,
- "\251 " SHORT_COPYRIGHT_DETAILS ". All rights reserved.");
- sfree(buildinfo_text);
- SetDlgItemText(hwnd, IDC_ABOUT_TEXTBOX, text);
- MakeDlgItemBorderless(hwnd, IDC_ABOUT_TEXTBOX);
- sfree(text);
- return 1;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- aboutbox = NULL;
- DestroyWindow(hwnd);
- return 0;
- case IDC_ABOUT_LICENCE:
- EnableWindow(hwnd, 0);
- DialogBox(hinst, MAKEINTRESOURCE(IDD_LICENCE), hwnd, LicenceProc);
- EnableWindow(hwnd, 1);
- SetActiveWindow(hwnd);
- return 0;
- case IDC_ABOUT_WEBSITE:
- /* Load web browser */
- ShellExecute(hwnd, "open",
- "https://www.chiark.greenend.org.uk/~sgtatham/putty/",
- 0, 0, SW_SHOWDEFAULT);
- return 0;
- }
- return 0;
- case WM_CLOSE:
- aboutbox = NULL;
- DestroyWindow(hwnd);
- return 0;
- }
- return 0;
-}
-
-static HWND modal_passphrase_hwnd = NULL;
-static HWND nonmodal_passphrase_hwnd = NULL;
-
-static void end_passphrase_dialog(HWND hwnd, INT_PTR result)
-{
- struct PassphraseProcStruct *p = (struct PassphraseProcStruct *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- if (p->modal) {
- EndDialog(hwnd, result);
- } else {
- /*
- * Destroy this passphrase dialog box before passing the
- * results back to pageant.c, to avoid re-entrancy issues.
- *
- * If we successfully got a passphrase from the user, but it
- * was _wrong_, then pageant_passphrase_request_success will
- * respond by calling back - synchronously - to our
- * ask_passphrase() implementation, which will expect the
- * previous value of nonmodal_passphrase_hwnd to have already
- * been cleaned up.
- */
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) NULL);
- DestroyWindow(hwnd);
- nonmodal_passphrase_hwnd = NULL;
-
- if (result)
- pageant_passphrase_request_success(
- p->dlgid, ptrlen_from_asciz(p->passphrase));
- else
- pageant_passphrase_request_refused(p->dlgid);
-
- burnstr(p->passphrase);
- sfree(p);
- }
-}
-
-/*
- * Dialog-box function for the passphrase box.
- */
-static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- struct PassphraseProcStruct *p;
-
- if (msg == WM_INITDIALOG) {
- p = (struct PassphraseProcStruct *) lParam;
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) p);
- } else {
- p = (struct PassphraseProcStruct *)
- GetWindowLongPtr(hwnd, GWLP_USERDATA);
- }
-
- switch (msg) {
- case WM_INITDIALOG: {
- if (p->modal)
- modal_passphrase_hwnd = hwnd;
-
- /*
- * Centre the window.
- */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
-
- SetForegroundWindow(hwnd);
- SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- if (!p->modal)
- SetActiveWindow(hwnd); /* this won't have happened automatically */
- if (p->comment)
- SetDlgItemText(hwnd, IDC_PASSPHRASE_FINGERPRINT, p->comment);
- burnstr(p->passphrase);
- p->passphrase = dupstr("");
- SetDlgItemText(hwnd, IDC_PASSPHRASE_EDITBOX, p->passphrase);
- if (!p->help_topic || !has_help()) {
- HWND item = GetDlgItem(hwnd, IDHELP);
- if (item)
- DestroyWindow(item);
- }
- return 0;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- if (p->passphrase)
- end_passphrase_dialog(hwnd, 1);
- else
- MessageBeep(0);
- return 0;
- case IDCANCEL:
- end_passphrase_dialog(hwnd, 0);
- return 0;
- case IDHELP:
- if (p->help_topic)
- launch_help(hwnd, p->help_topic);
- return 0;
- case IDC_PASSPHRASE_EDITBOX:
- if ((HIWORD(wParam) == EN_CHANGE) && p->passphrase) {
- burnstr(p->passphrase);
- p->passphrase = GetDlgItemText_alloc(
- hwnd, IDC_PASSPHRASE_EDITBOX);
- }
- return 0;
- }
- return 0;
- case WM_CLOSE:
- end_passphrase_dialog(hwnd, 0);
- return 0;
- }
- return 0;
-}
-
-/*
- * 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);
-}
-
-struct keylist_update_ctx {
- bool enable_remove_controls;
- bool enable_reencrypt_controls;
-};
-
-static void keylist_update_callback(
- void *vctx, char **fingerprints, const char *comment, uint32_t ext_flags,
- struct pageant_pubkey *key)
-{
- struct keylist_update_ctx *ctx = (struct keylist_update_ctx *)vctx;
- FingerprintType this_type = ssh2_pick_fingerprint(fingerprints, fptype);
- const char *fingerprint = fingerprints[this_type];
- strbuf *listentry = strbuf_new();
-
- /* There is at least one key, so the controls for removing keys
- * should be enabled */
- ctx->enable_remove_controls = true;
-
- switch (key->ssh_version) {
- case 1: {
- strbuf_catf(listentry, "ssh1\t%s\t%s", fingerprint, comment);
-
- /*
- * Replace the space in the fingerprint (between bit count and
- * hash) with a tab, for nice alignment in the box.
- */
- char *p = strchr(listentry->s, ' ');
- if (p)
- *p = '\t';
- break;
- }
-
- case 2: {
- /*
- * For nice alignment in the list box, we would ideally want
- * every entry to align to the tab stop settings, and have a
- * column for algorithm name, one for bit count, one for hex
- * fingerprint, and one for key comment.
- *
- * Unfortunately, some of the algorithm names are so long that
- * they overflow into the bit-count field. Fortunately, at the
- * moment, those are _precisely_ the algorithm names that
- * don't need a bit count displayed anyway (because for
- * NIST-style ECDSA the bit count is mentioned in the
- * algorithm name, and for ssh-ed25519 there is only one
- * possible value anyway). So we fudge this by simply omitting
- * the bit count field in that situation.
- *
- * This is fragile not only in the face of further key types
- * that don't follow this pattern, but also in the face of
- * font metrics changes - the Windows semantics for list box
- * tab stops is that \t aligns to the next one you haven't
- * already exceeded, so I have to guess when the key type will
- * overflow past the bit-count tab stop and leave out a tab
- * character. Urgh.
- */
- BinarySource src[1];
- BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(key->blob));
- ptrlen algname = get_string(src);
- const ssh_keyalg *alg = find_pubkey_alg_len(algname);
-
- bool include_bit_count = (alg == &ssh_dss || alg == &ssh_rsa);
-
- int wordnumber = 0;
- for (const char *p = fingerprint; *p; p++) {
- char c = *p;
- if (c == ' ') {
- if (wordnumber < 2)
- c = '\t';
- wordnumber++;
- }
- if (include_bit_count || wordnumber != 1)
- put_byte(listentry, c);
- }
-
- strbuf_catf(listentry, "\t%s", comment);
- break;
- }
- }
-
- if (ext_flags & LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY) {
- strbuf_catf(listentry, "\t(encrypted)");
- } else if (ext_flags & LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE) {
- strbuf_catf(listentry, "\t(re-encryptable)");
-
- /* At least one key can be re-encrypted */
- ctx->enable_reencrypt_controls = true;
- }
-
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_ADDSTRING, 0, (LPARAM)listentry->s);
- strbuf_free(listentry);
-}
-
-/*
- * Update the visible key list.
- */
-void keylist_update(void)
-{
- if (keylist) {
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_RESETCONTENT, 0, 0);
-
- char *errmsg;
- struct keylist_update_ctx ctx[1];
- ctx->enable_remove_controls = false;
- ctx->enable_reencrypt_controls = false;
- int status = pageant_enum_keys(keylist_update_callback, ctx, &errmsg);
- assert(status == PAGEANT_ACTION_OK);
- assert(!errmsg);
-
- SendDlgItemMessage(keylist, IDC_KEYLIST_LISTBOX,
- LB_SETCURSEL, (WPARAM) - 1, 0);
-
- EnableWindow(GetDlgItem(keylist, IDC_KEYLIST_REMOVE),
- ctx->enable_remove_controls);
- EnableWindow(GetDlgItem(keylist, IDC_KEYLIST_REENCRYPT),
- ctx->enable_reencrypt_controls);
- }
-}
-
-static void win_add_keyfile(Filename *filename, bool encrypted)
-{
- char *err;
- int ret;
-
- /*
- * Try loading the key without a passphrase. (Or rather, without a
- * _new_ passphrase; pageant_add_keyfile will take care of trying
- * all the passphrases we've already stored.)
- */
- ret = pageant_add_keyfile(filename, NULL, &err, encrypted);
- if (ret == PAGEANT_ACTION_OK) {
- goto done;
- } else if (ret == PAGEANT_ACTION_FAILURE) {
- goto error;
- }
-
- /*
- * OK, a passphrase is needed, and we've been given the key
- * comment to use in the passphrase prompt.
- */
- while (1) {
- INT_PTR dlgret;
- struct PassphraseProcStruct pps;
- pps.modal = true;
- pps.help_topic = NULL; /* this dialog has no help button */
- pps.dlgid = NULL;
- pps.passphrase = NULL;
- pps.comment = err;
- dlgret = DialogBoxParam(
- hinst, MAKEINTRESOURCE(IDD_LOAD_PASSPHRASE),
- NULL, PassphraseProc, (LPARAM) &pps);
- modal_passphrase_hwnd = NULL;
-
- if (!dlgret) {
- burnstr(pps.passphrase);
- goto done; /* operation cancelled */
- }
-
- sfree(err);
-
- assert(pps.passphrase != NULL);
-
- ret = pageant_add_keyfile(filename, pps.passphrase, &err, false);
- burnstr(pps.passphrase);
-
- if (ret == PAGEANT_ACTION_OK) {
- goto done;
- } else if (ret == PAGEANT_ACTION_FAILURE) {
- goto error;
- }
- }
-
- error:
- message_box(traywindow, err, APPNAME, MB_OK | MB_ICONERROR,
- HELPCTXID(errors_cantloadkey));
- done:
- sfree(err);
- return;
-}
-
-/*
- * Prompt for a key file to add, and add it.
- */
-static void prompt_add_keyfile(bool encrypted)
-{
- OPENFILENAME of;
- char *filelist = snewn(8192, char);
-
- if (!keypath) keypath = filereq_new();
- memset(&of, 0, sizeof(of));
- of.hwndOwner = traywindow;
- of.lpstrFilter = FILTER_KEY_FILES;
- of.lpstrCustomFilter = NULL;
- of.nFilterIndex = 1;
- of.lpstrFile = filelist;
- *filelist = '\0';
- of.nMaxFile = 8192;
- of.lpstrFileTitle = NULL;
- of.lpstrTitle = "Select Private Key File";
- of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
- if (request_file(keypath, &of, true, false)) {
- if(strlen(filelist) > of.nFileOffset) {
- /* Only one filename returned? */
- Filename *fn = filename_from_str(filelist);
- win_add_keyfile(fn, encrypted);
- filename_free(fn);
- } 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.
- */
- char *dir = filelist;
- char *filewalker = filelist + strlen(dir) + 1;
- while (*filewalker != '\0') {
- char *filename = dupcat(dir, "\\", filewalker);
- Filename *fn = filename_from_str(filename);
- win_add_keyfile(fn, encrypted);
- filename_free(fn);
- sfree(filename);
- filewalker += strlen(filewalker) + 1;
- }
- }
-
- keylist_update();
- pageant_forget_passphrases();
- }
- sfree(filelist);
-}
-
-/*
- * Dialog-box function for the key list box.
- */
-static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
-{
- static const struct {
- const char *name;
- FingerprintType value;
- } fptypes[] = {
- {"SHA256", SSH_FPTYPE_SHA256},
- {"MD5", SSH_FPTYPE_MD5},
- };
-
- switch (msg) {
- case WM_INITDIALOG: {
- /*
- * Centre the window.
- */
- RECT rs, rd;
- HWND hw;
-
- hw = GetDesktopWindow();
- if (GetWindowRect(hw, &rs) && GetWindowRect(hwnd, &rd))
- MoveWindow(hwnd,
- (rs.right + rs.left + rd.left - rd.right) / 2,
- (rs.bottom + rs.top + rd.top - rd.bottom) / 2,
- rd.right - rd.left, rd.bottom - rd.top, true);
-
- if (has_help())
- SetWindowLongPtr(hwnd, GWL_EXSTYLE,
- GetWindowLongPtr(hwnd, GWL_EXSTYLE) |
- WS_EX_CONTEXTHELP);
- else {
- HWND item = GetDlgItem(hwnd, IDC_KEYLIST_HELP);
- if (item)
- DestroyWindow(item);
- }
-
- keylist = hwnd;
- {
- static int tabs[] = { 35, 75, 300 };
- SendDlgItemMessage(hwnd, IDC_KEYLIST_LISTBOX, LB_SETTABSTOPS,
- sizeof(tabs) / sizeof(*tabs),
- (LPARAM) tabs);
- }
-
- int selection = 0;
- for (size_t i = 0; i < lenof(fptypes); i++) {
- SendDlgItemMessage(hwnd, IDC_KEYLIST_FPTYPE, CB_ADDSTRING,
- 0, (LPARAM)fptypes[i].name);
- if (fptype == fptypes[i].value)
- selection = (int)i;
- }
- SendDlgItemMessage(hwnd, IDC_KEYLIST_FPTYPE,
- CB_SETCURSEL, 0, selection);
-
- keylist_update();
- return 0;
- }
- case WM_COMMAND:
- switch (LOWORD(wParam)) {
- case IDOK:
- case IDCANCEL:
- keylist = NULL;
- DestroyWindow(hwnd);
- return 0;
- case IDC_KEYLIST_ADDKEY:
- case IDC_KEYLIST_ADDKEY_ENC:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- if (modal_passphrase_hwnd) {
- MessageBeep(MB_ICONERROR);
- SetForegroundWindow(modal_passphrase_hwnd);
- break;
- }
- prompt_add_keyfile(LOWORD(wParam) == IDC_KEYLIST_ADDKEY_ENC);
- }
- return 0;
- case IDC_KEYLIST_REMOVE:
- case IDC_KEYLIST_REENCRYPT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- int i;
- 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, IDC_KEYLIST_LISTBOX, LB_GETSELCOUNT, 0, 0);
-
- /* none selected? that was silly */
- if (numSelected == 0) {
- MessageBeep(0);
- break;
- }
-
- /* get item indices in an array */
- selectedArray = snewn(numSelected, int);
- SendDlgItemMessage(hwnd, IDC_KEYLIST_LISTBOX, LB_GETSELITEMS,
- numSelected, (WPARAM)selectedArray);
-
- itemNum = numSelected - 1;
- rCount = pageant_count_ssh1_keys();
- sCount = pageant_count_ssh2_keys();
-
- /* 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--) {
- if (selectedArray[itemNum] == rCount + i) {
- switch (LOWORD(wParam)) {
- case IDC_KEYLIST_REMOVE:
- pageant_delete_nth_ssh2_key(i);
- break;
- case IDC_KEYLIST_REENCRYPT:
- pageant_reencrypt_nth_ssh2_key(i);
- break;
- }
- itemNum--;
- }
- }
-
- /* do the same for the rsa keys */
- for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) {
- if(selectedArray[itemNum] == i) {
- switch (LOWORD(wParam)) {
- case IDC_KEYLIST_REMOVE:
- pageant_delete_nth_ssh1_key(i);
- break;
- case IDC_KEYLIST_REENCRYPT:
- /* SSH-1 keys can't be re-encrypted */
- break;
- }
- itemNum--;
- }
- }
-
- sfree(selectedArray);
- keylist_update();
- }
- return 0;
- case IDC_KEYLIST_HELP:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED) {
- launch_help(hwnd, WINHELP_CTX_pageant_general);
- }
- return 0;
- case IDC_KEYLIST_FPTYPE:
- if (HIWORD(wParam) == CBN_SELCHANGE) {
- int selection = SendDlgItemMessage(
- hwnd, IDC_KEYLIST_FPTYPE, CB_GETCURSEL, 0, 0);
- if (selection >= 0 && (size_t)selection < lenof(fptypes)) {
- fptype = fptypes[selection].value;
- keylist_update();
- }
- }
- return 0;
- }
- return 0;
- case WM_HELP: {
- int id = ((LPHELPINFO)lParam)->iCtrlId;
- const char *topic = NULL;
- switch (id) {
- case IDC_KEYLIST_LISTBOX:
- case IDC_KEYLIST_FPTYPE:
- case IDC_KEYLIST_FPTYPE_STATIC:
- topic = WINHELP_CTX_pageant_keylist; break;
- case IDC_KEYLIST_ADDKEY: topic = WINHELP_CTX_pageant_addkey; break;
- case IDC_KEYLIST_REMOVE: topic = WINHELP_CTX_pageant_remkey; break;
- case IDC_KEYLIST_ADDKEY_ENC:
- case IDC_KEYLIST_REENCRYPT:
- topic = WINHELP_CTX_pageant_deferred; break;
- }
- if (topic) {
- launch_help(hwnd, topic);
- } else {
- MessageBeep(0);
- }
- break;
- }
- case WM_CLOSE:
- keylist = NULL;
- DestroyWindow(hwnd);
- 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(hinst, MAKEINTRESOURCE(201));
- strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)");
-
- res = Shell_NotifyIcon(NIM_ADD, &tnid);
-
- if (hicon) DestroyIcon(hicon);
-
- return res;
-}
-
-/* Update the saved-sessions menu. */
-static void update_sessions(void)
-{
- int num_entries;
- HKEY hkey;
- TCHAR buf[MAX_PATH + 1];
- MENUITEMINFO mii;
- strbuf *sb;
-
- int index_key, index_menu;
-
- if (!putty_path)
- return;
-
- if(ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, PUTTY_REGKEY, &hkey))
- return;
-
- for(num_entries = GetMenuItemCount(session_menu);
- num_entries > initial_menuitems_count;
- num_entries--)
- RemoveMenu(session_menu, 0, MF_BYPOSITION);
-
- index_key = 0;
- index_menu = 0;
-
- sb = strbuf_new();
- while(ERROR_SUCCESS == RegEnumKey(hkey, index_key, buf, MAX_PATH)) {
- if(strcmp(buf, PUTTY_DEFAULT) != 0) {
- strbuf_clear(sb);
- unescape_registry_key(buf, sb);
-
- memset(&mii, 0, sizeof(mii));
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
- mii.fType = MFT_STRING;
- mii.fState = MFS_ENABLED;
- mii.wID = (index_menu * 16) + IDM_SESSIONS_BASE;
- mii.dwTypeData = sb->s;
- InsertMenuItem(session_menu, index_menu, true, &mii);
- index_menu++;
- }
- index_key++;
- }
- strbuf_free(sb);
-
- RegCloseKey(hkey);
-
- if(index_menu == 0) {
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE | MIIM_STATE;
- mii.fType = MFT_STRING;
- mii.fState = MFS_GRAYED;
- mii.dwTypeData = _T("(No sessions)");
- InsertMenuItem(session_menu, index_menu, true, &mii);
- }
-}
-
-#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
-
-struct WmCopydataTransaction {
- char *length, *body;
- size_t bodysize, bodylen;
- HANDLE ev_msg_ready, ev_reply_ready;
-} wmct;
-
-static struct PageantClient wmcpc;
-
-static void wm_copydata_got_msg(void *vctx)
-{
- pageant_handle_msg(&wmcpc, NULL, make_ptrlen(wmct.body, wmct.bodylen));
-}
-
-static void wm_copydata_got_response(
- PageantClient *pc, PageantClientRequestId *reqid, ptrlen response)
-{
- if (response.len > wmct.bodysize) {
- /* Output would overflow message buffer. Replace with a
- * failure message. */
- static const unsigned char failure[] = { SSH_AGENT_FAILURE };
- response = make_ptrlen(failure, lenof(failure));
- assert(response.len <= wmct.bodysize);
- }
-
- PUT_32BIT_MSB_FIRST(wmct.length, response.len);
- memcpy(wmct.body, response.ptr, response.len);
-
- SetEvent(wmct.ev_reply_ready);
-}
-
-static bool ask_passphrase_common(PageantClientDialogId *dlgid,
- const char *comment)
-{
- /* Pageant core should be serialising requests, so we never expect
- * a passphrase prompt to exist already at this point */
- assert(!nonmodal_passphrase_hwnd);
-
- struct PassphraseProcStruct *pps = snew(struct PassphraseProcStruct);
- pps->modal = false;
- pps->help_topic = WINHELP_CTX_pageant_deferred;
- pps->dlgid = dlgid;
- pps->passphrase = NULL;
- pps->comment = comment;
-
- nonmodal_passphrase_hwnd = CreateDialogParam(
- hinst, MAKEINTRESOURCE(IDD_ONDEMAND_PASSPHRASE),
- NULL, PassphraseProc, (LPARAM)pps);
-
- /*
- * Try to put this passphrase prompt into the foreground.
- *
- * This will probably not succeed in giving it the actual keyboard
- * focus, because Windows is quite opposed to applications being
- * able to suddenly steal the focus on their own initiative.
- *
- * That makes sense in a lot of situations, as a defensive
- * measure. If you were about to type a password or other secret
- * data into the window you already had focused, and some
- * malicious app stole the focus, it might manage to trick you
- * into typing your secrets into _it_ instead.
- *
- * In this case it's possible to regard the same defensive measure
- * as counterproductive, because the effect if we _do_ steal focus
- * is that you type something into our passphrase prompt that
- * isn't the passphrase, and we fail to decrypt the key, and no
- * harm is done. Whereas the effect of the user wrongly _assuming_
- * the new passphrase prompt has the focus is much worse: now you
- * type your highly secret passphrase into some other window you
- * didn't mean to trust with that information - such as the
- * agent-forwarded PuTTY in which you just ran an ssh command,
- * which the _whole point_ was to avoid telling your passphrase to!
- *
- * On the other hand, I'm sure _every_ application author can come
- * up with an argument for why they think _they_ should be allowed
- * to steal the focus. Probably most of them include the claim
- * that no harm is done if their application receives data
- * intended for something else, and of course that's not always
- * true!
- *
- * In any case, I don't know of anything I can do about it, or
- * anything I _should_ do about it if I could. If anyone thinks
- * they can improve on all this, patches are welcome.
- */
- SetForegroundWindow(nonmodal_passphrase_hwnd);
-
- return true;
-}
-
-static bool wm_copydata_ask_passphrase(
- PageantClient *pc, PageantClientDialogId *dlgid, const char *comment)
-{
- return ask_passphrase_common(dlgid, comment);
-}
-
-static const PageantClientVtable wmcpc_vtable = {
- .log = NULL, /* no logging in this client */
- .got_response = wm_copydata_got_response,
- .ask_passphrase = wm_copydata_ask_passphrase,
-};
-
-static char *answer_filemapping_message(const char *mapname)
-{
- HANDLE maphandle = INVALID_HANDLE_VALUE;
- void *mapaddr = NULL;
- char *err = NULL;
- size_t mapsize;
- unsigned msglen;
-
-#ifndef NO_SECURITY
- PSID mapsid = NULL;
- PSID expectedsid = NULL;
- PSID expectedsid_bc = NULL;
- PSECURITY_DESCRIPTOR psd = NULL;
-#endif
-
- wmct.length = wmct.body = NULL;
-
-#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
-
- {
- MEMORY_BASIC_INFORMATION mbi;
- size_t mbiSize = VirtualQuery(mapaddr, &mbi, sizeof(mbi));
- if (mbiSize == 0) {
- err = dupprintf("unable to query view of file mapping: %s",
- win_strerror(GetLastError()));
- goto cleanup;
- }
- if (mbiSize < (offsetof(MEMORY_BASIC_INFORMATION, RegionSize) +
- sizeof(mbi.RegionSize))) {
- err = dupstr("VirtualQuery returned too little data to get "
- "region size");
- goto cleanup;
- }
-
- mapsize = mbi.RegionSize;
- }
-#ifdef DEBUG_IPC
- debug("region size = %"SIZEu"\n", mapsize);
-#endif
- if (mapsize < 5) {
- err = dupstr("mapping smaller than smallest possible request");
- goto cleanup;
- }
-
- wmct.length = (char *)mapaddr;
- msglen = GET_32BIT_MSB_FIRST(wmct.length);
-
-#ifdef DEBUG_IPC
- debug("msg length=%08x, msg type=%02x\n",
- msglen, (unsigned)((unsigned char *) mapaddr)[4]);
-#endif
-
- wmct.body = wmct.length + 4;
- wmct.bodysize = mapsize - 4;
-
- if (msglen > wmct.bodysize) {
- /* Incoming length field is too large. Emit a failure response
- * without even trying to handle the request.
- *
- * (We know this must fit, because we checked mapsize >= 5
- * above.) */
- PUT_32BIT_MSB_FIRST(wmct.length, 1);
- *wmct.body = SSH_AGENT_FAILURE;
- } else {
- wmct.bodylen = msglen;
- SetEvent(wmct.ev_msg_ready);
- WaitForSingleObject(wmct.ev_reply_ready, INFINITE);
- }
-
- 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 void create_keylist_window(void)
-{
- if (keylist)
- return;
-
- keylist = CreateDialog(hinst, MAKEINTRESOURCE(IDD_KEYLIST),
- NULL, KeyListProc);
- ShowWindow(keylist, SW_SHOWNORMAL);
-}
-
-static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam)
-{
- static bool 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;
- GetCursorPos(&cursorpos);
- PostMessage(hwnd, WM_SYSTRAY2, cursorpos.x, cursorpos.y);
- } else if (lParam == WM_LBUTTONDBLCLK) {
- /* Run the default menu item. */
- UINT menuitem = GetMenuDefaultItem(systray_menu, false, 0);
- if (menuitem != -1)
- PostMessage(hwnd, WM_COMMAND, menuitem, 0);
- }
- break;
- case WM_SYSTRAY2:
- if (!menuinprogress) {
- menuinprogress = true;
- update_sessions();
- SetForegroundWindow(hwnd);
- TrackPopupMenu(systray_menu,
- TPM_RIGHTALIGN | TPM_BOTTOMALIGN |
- TPM_RIGHTBUTTON,
- wParam, lParam, 0, hwnd, NULL);
- menuinprogress = false;
- }
- break;
- case WM_COMMAND:
- case WM_SYSCOMMAND: {
- unsigned command = wParam & ~0xF; /* low 4 bits reserved to Windows */
- switch (command) {
- case IDM_PUTTY: {
- TCHAR cmdline[10];
- cmdline[0] = '\0';
- if (restrict_putty_acl)
- strcat(cmdline, "&R");
-
- if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, cmdline,
- _T(""), SW_SHOW) <= 32) {
- MessageBox(NULL, "Unable to execute PuTTY!",
- "Error", MB_OK | MB_ICONERROR);
- }
- break;
- }
- case IDM_CLOSE:
- if (modal_passphrase_hwnd)
- SendMessage(modal_passphrase_hwnd, WM_CLOSE, 0, 0);
- SendMessage(hwnd, WM_CLOSE, 0, 0);
- break;
- case IDM_VIEWKEYS:
- create_keylist_window();
- /*
- * Sometimes the window comes up minimised / hidden for
- * no obvious reason. Prevent this. This also brings it
- * to the front if it's already present (the user
- * selected View Keys because they wanted to _see_ the
- * thing).
- */
- SetForegroundWindow(keylist);
- SetWindowPos(keylist, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- break;
- case IDM_ADDKEY:
- case IDM_ADDKEY_ENCRYPTED:
- if (modal_passphrase_hwnd) {
- MessageBeep(MB_ICONERROR);
- SetForegroundWindow(modal_passphrase_hwnd);
- break;
- }
- prompt_add_keyfile(command == IDM_ADDKEY_ENCRYPTED);
- break;
- case IDM_REMOVE_ALL:
- pageant_delete_all();
- keylist_update();
- break;
- case IDM_REENCRYPT_ALL:
- pageant_reencrypt_all();
- keylist_update();
- break;
- case IDM_ABOUT:
- if (!aboutbox) {
- aboutbox = CreateDialog(hinst, MAKEINTRESOURCE(IDD_ABOUT),
- NULL, AboutProc);
- ShowWindow(aboutbox, SW_SHOWNORMAL);
- /*
- * Sometimes the window comes up minimised / hidden
- * for no obvious reason. Prevent this.
- */
- SetForegroundWindow(aboutbox);
- SetWindowPos(aboutbox, HWND_TOP, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
- }
- break;
- case IDM_HELP:
- launch_help(hwnd, WINHELP_CTX_pageant_general);
- break;
- default: {
- if(wParam >= IDM_SESSIONS_BASE && wParam <= IDM_SESSIONS_MAX) {
- MENUITEMINFO mii;
- TCHAR buf[MAX_PATH + 1];
- TCHAR param[MAX_PATH + 1];
- memset(&mii, 0, sizeof(mii));
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_TYPE;
- mii.cch = MAX_PATH;
- mii.dwTypeData = buf;
- GetMenuItemInfo(session_menu, wParam, false, &mii);
- param[0] = '\0';
- if (restrict_putty_acl)
- strcat(param, "&R");
- strcat(param, "@");
- strcat(param, mii.dwTypeData);
- if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, param,
- _T(""), SW_SHOW) <= 32) {
- MessageBox(NULL, "Unable to execute PuTTY!", "Error",
- MB_OK | MB_ICONERROR);
- }
- }
- break;
- }
- }
- break;
- }
- case WM_DESTROY:
- quit_help(hwnd);
- PostQuitMessage(0);
- return 0;
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-static LRESULT CALLBACK wm_copydata_WndProc(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM lParam)
-{
- switch (message) {
- case WM_COPYDATA: {
- COPYDATASTRUCT *cds;
- char *mapname, *err;
-
- cds = (COPYDATASTRUCT *) lParam;
- if (cds->dwData != AGENT_COPYDATA_ID)
- return 0; /* not our message, mate */
- 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("IPC failed: %s\n", err);
-#endif
- sfree(err);
- return 0;
- }
- return 1;
- }
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-static DWORD WINAPI wm_copydata_threadfunc(void *param)
-{
- HINSTANCE inst = *(HINSTANCE *)param;
-
- HWND ipchwnd = CreateWindow(IPCCLASSNAME, IPCWINTITLE,
- WS_OVERLAPPEDWINDOW | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100, NULL, NULL, inst, NULL);
- ShowWindow(ipchwnd, SW_HIDE);
-
- MSG msg;
- while (GetMessage(&msg, NULL, 0, 0) == 1) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- return 0;
-}
-
-/*
- * Fork and Exec the command in cmdline. [DBW]
- */
-void spawn_cmd(const char *cmdline, const char *args, int show)
-{
- if (ShellExecute(NULL, _T("open"), cmdline,
- args, NULL, show) <= (HINSTANCE) 32) {
- char *msg;
- msg = dupprintf("Failed to run \"%s\": %s", cmdline,
- win_strerror(GetLastError()));
- MessageBox(NULL, msg, APPNAME, MB_OK | MB_ICONEXCLAMATION);
- sfree(msg);
- }
-}
-
-void logevent(LogContext *logctx, const char *event)
-{
- unreachable("Pageant can't create a LogContext, so this can't be called");
-}
-
-void noise_ultralight(NoiseSourceId id, unsigned long data)
-{
- /* Pageant doesn't use random numbers, so we ignore this */
-}
-
-void cleanup_exit(int code)
-{
- shutdown_help();
- exit(code);
-}
-
-static bool winpgnt_listener_ask_passphrase(
- PageantListenerClient *plc, PageantClientDialogId *dlgid,
- const char *comment)
-{
- return ask_passphrase_common(dlgid, comment);
-}
-
-struct winpgnt_client {
- PageantListenerClient plc;
-};
-static const PageantListenerClientVtable winpgnt_vtable = {
- .log = NULL, /* no logging */
- .ask_passphrase = winpgnt_listener_ask_passphrase,
-};
-
-static struct winpgnt_client wpc[1];
-
-HINSTANCE hinst;
-
-int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
-{
- MSG msg;
- const char *command = NULL;
- bool added_keys = false;
- bool show_keylist_on_startup = false;
- int argc, i;
- char **argv, **argstart;
-
- dll_hijacking_protection();
-
- hinst = inst;
-
- /*
- * Determine whether we're an NT system (should have security
- * APIs) or a non-NT system (don't do security).
- */
- init_winver();
- has_security = (osPlatformId == VER_PLATFORM_WIN32_NT);
-
- if (has_security) {
-#ifndef NO_SECURITY
- /*
- * Attempt to get the security API we need.
- */
- if (!got_advapi()) {
- MessageBox(NULL,
- "Unable to access security APIs. Pageant will\n"
- "not run, in case it causes a security breach.",
- "Pageant Fatal Error", MB_ICONERROR | MB_OK);
- return 1;
- }
-#else
- MessageBox(NULL,
- "This program has been compiled for Win9X and will\n"
- "not run on NT, in case it causes a security breach.",
- "Pageant Fatal Error", MB_ICONERROR | MB_OK);
- return 1;
-#endif
- }
-
- /*
- * See if we can find our Help file.
- */
- init_help();
-
- /*
- * Look for the PuTTY binary (we will enable the saved session
- * submenu if we find it).
- */
- {
- char b[2048], *p, *q, *r;
- FILE *fp;
- GetModuleFileName(NULL, b, sizeof(b) - 16);
- 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.exe");
- if ( (fp = fopen(b, "r")) != NULL) {
- putty_path = dupstr(b);
- fclose(fp);
- } else
- putty_path = NULL;
- }
-
- /*
- * Find out if Pageant is already running.
- */
- already_running = agent_exists();
-
- /*
- * Initialise the cross-platform Pageant code.
- */
- if (!already_running) {
- pageant_init();
- }
-
- /*
- * Process the command line and add keys as listed on it.
- */
- split_into_argv(cmdline, &argc, &argv, &argstart);
- bool doing_opts = true;
- bool add_keys_encrypted = false;
- for (i = 0; i < argc; i++) {
- char *p = argv[i];
- if (*p == '-' && doing_opts) {
- if (!strcmp(p, "-pgpfp")) {
- pgp_fingerprints_msgbox(NULL);
- return 1;
- } else if (!strcmp(p, "-restrict-acl") ||
- !strcmp(p, "-restrict_acl") ||
- !strcmp(p, "-restrictacl")) {
- restrict_process_acl();
- } else if (!strcmp(p, "-restrict-putty-acl") ||
- !strcmp(p, "-restrict_putty_acl")) {
- restrict_putty_acl = true;
- } else if (!strcmp(p, "--no-decrypt") ||
- !strcmp(p, "-no-decrypt") ||
- !strcmp(p, "--no_decrypt") ||
- !strcmp(p, "-no_decrypt") ||
- !strcmp(p, "--nodecrypt") ||
- !strcmp(p, "-nodecrypt") ||
- !strcmp(p, "--encrypted") ||
- !strcmp(p, "-encrypted")) {
- add_keys_encrypted = true;
- } else if (!strcmp(p, "-keylist") || !strcmp(p, "--keylist")) {
- show_keylist_on_startup = true;
- } else if (!strcmp(p, "-c")) {
- /*
- * If we see `-c', then the rest of the
- * command line should be treated as a
- * command to be spawned.
- */
- if (i < argc-1)
- command = argstart[i+1];
- else
- command = "";
- break;
- } else if (!strcmp(p, "--")) {
- doing_opts = false;
- } else {
- char *msg = dupprintf("unrecognised command-line option\n"
- "'%s'", p);
- MessageBox(NULL, msg, "Pageant command-line syntax error",
- MB_ICONERROR | MB_OK);
- exit(1);
- }
- } else {
- Filename *fn = filename_from_str(p);
- win_add_keyfile(fn, add_keys_encrypted);
- filename_free(fn);
- added_keys = true;
- }
- }
-
- /*
- * Forget any passphrase that we retained while going over
- * command line keyfiles.
- */
- pageant_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
- * 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);
- }
- return 0;
- }
-
-#if !defined NO_SECURITY
-
- /*
- * Set up a named-pipe listener.
- */
- {
- Plug *pl_plug;
- wpc->plc.vt = &winpgnt_vtable;
- wpc->plc.suppress_logging = true;
- struct pageant_listen_state *pl =
- pageant_listener_new(&pl_plug, &wpc->plc);
- char *pipename = agent_named_pipe_name();
- Socket *sock = new_named_pipe_listener(pipename, pl_plug);
- if (sk_socket_error(sock)) {
- char *err = dupprintf("Unable to open named pipe at %s "
- "for SSH agent:\n%s", pipename,
- sk_socket_error(sock));
- MessageBox(NULL, err, "Pageant Error", MB_ICONERROR | MB_OK);
- return 1;
- }
- pageant_listener_got_socket(pl, sock);
- sfree(pipename);
- }
-
-#endif /* !defined NO_SECURITY */
-
- /*
- * Set up window classes for two hidden windows: one that receives
- * all the messages to do with our presence in the system tray,
- * and one that receives the WM_COPYDATA message used by the
- * old-style Pageant IPC system.
- */
-
- if (!prev) {
- WNDCLASS wndclass;
-
- memset(&wndclass, 0, sizeof(wndclass));
- wndclass.lpfnWndProc = TrayWndProc;
- wndclass.hInstance = inst;
- wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(IDI_MAINICON));
- wndclass.lpszClassName = TRAYCLASSNAME;
-
- RegisterClass(&wndclass);
-
- memset(&wndclass, 0, sizeof(wndclass));
- wndclass.lpfnWndProc = wm_copydata_WndProc;
- wndclass.hInstance = inst;
- wndclass.lpszClassName = IPCCLASSNAME;
-
- RegisterClass(&wndclass);
- }
-
- keylist = NULL;
-
- traywindow = CreateWindow(TRAYCLASSNAME, TRAYWINTITLE,
- WS_OVERLAPPEDWINDOW | WS_VSCROLL,
- CW_USEDEFAULT, CW_USEDEFAULT,
- 100, 100, NULL, NULL, inst, NULL);
- winselgui_set_hwnd(traywindow);
-
- /* Set up a system tray icon */
- AddTrayIcon(traywindow);
-
- /* Accelerators used: nsvkxa */
- systray_menu = CreatePopupMenu();
- if (putty_path) {
- session_menu = CreateMenu();
- AppendMenu(systray_menu, MF_ENABLED, IDM_PUTTY, "&New Session");
- AppendMenu(systray_menu, MF_POPUP | MF_ENABLED,
- (UINT_PTR) session_menu, "&Saved Sessions");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- }
- AppendMenu(systray_menu, MF_ENABLED, IDM_VIEWKEYS,
- "&View Keys");
- AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key");
- AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY_ENCRYPTED,
- "Add key (encrypted)");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- AppendMenu(systray_menu, MF_ENABLED, IDM_REMOVE_ALL,
- "Remove All Keys");
- AppendMenu(systray_menu, MF_ENABLED, IDM_REENCRYPT_ALL,
- "Re-encrypt All Keys");
- AppendMenu(systray_menu, MF_SEPARATOR, 0, 0);
- 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);
- AppendMenu(systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit");
- initial_menuitems_count = GetMenuItemCount(session_menu);
-
- /* Set the default menu item. */
- SetMenuDefaultItem(systray_menu, IDM_VIEWKEYS, false);
-
- ShowWindow(traywindow, SW_HIDE);
-
- wmcpc.vt = &wmcpc_vtable;
- wmcpc.suppress_logging = true;
- pageant_register_client(&wmcpc);
- DWORD wm_copydata_threadid;
- wmct.ev_msg_ready = CreateEvent(NULL, false, false, NULL);
- wmct.ev_reply_ready = CreateEvent(NULL, false, false, NULL);
- HANDLE hThread = CreateThread(NULL, 0, wm_copydata_threadfunc,
- &inst, 0, &wm_copydata_threadid);
- if (hThread)
- CloseHandle(hThread); /* we don't need the thread handle */
- handle_add_foreign_event(wmct.ev_msg_ready, wm_copydata_got_msg, NULL);
-
- if (show_keylist_on_startup)
- create_keylist_window();
-
- /*
- * Main message loop.
- */
- while (true) {
- HANDLE *handles;
- int nhandles, n;
-
- handles = handle_get_events(&nhandles);
-
- n = MsgWaitForMultipleObjects(nhandles, handles, false,
- INFINITE, QS_ALLINPUT);
-
- if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
- handle_got_event(handles[n - WAIT_OBJECT_0]);
- sfree(handles);
- } else
- sfree(handles);
-
- while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
- if (msg.message == WM_QUIT)
- goto finished; /* two-level break */
-
- if (IsWindow(keylist) && IsDialogMessage(keylist, &msg))
- continue;
- if (IsWindow(aboutbox) && IsDialogMessage(aboutbox, &msg))
- continue;
- if (IsWindow(nonmodal_passphrase_hwnd) &&
- IsDialogMessage(nonmodal_passphrase_hwnd, &msg))
- continue;
-
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- run_toplevel_callbacks();
- }
- finished:
-
- /* Clean up the system tray icon */
- {
- NOTIFYICONDATA tnid;
-
- tnid.cbSize = sizeof(NOTIFYICONDATA);
- tnid.hWnd = traywindow;
- tnid.uID = 1;
-
- Shell_NotifyIcon(NIM_DELETE, &tnid);
-
- DestroyMenu(systray_menu);
- }
-
- if (keypath) filereq_free(keypath);
-
- cleanup_exit(msg.wParam);
- return msg.wParam; /* just in case optimiser complains */
-}