1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Windows Pageant: initial work on deferred decryption.

This fills in the missing piece of Windows Pageant's story on deferred
decryption: we now actually know how to put up a dialog box asking for
the passphrase, when a not-yet-decrypted key is used.

This is quite a rough implementation so far, but it's a start. Known
issues:

 - these new non-modal dialog boxes are serialised with respect to
   each other by the Pageant core, but they can run in parallel with a
   passphrase prompt popping up from the ordinary GUI 'Add Key'
   operation. That may be too confusing; perhaps I should fix it.

 - I'm not confident that the passphrase dialog box gets the keyboard
   focus in all situations where I'd like it to (or what I can do
   about it if not).

 - the text in the non-modal box has two copies of the instruction
   'enter passphrase for key'.
This commit is contained in:
Simon Tatham 2020-03-21 15:59:51 +00:00
parent 9fc8320fc3
commit 26930236ae

View File

@ -97,8 +97,10 @@ void modalfatalbox(const char *fmt, ...)
static bool has_security;
struct PassphraseProcStruct {
char **passphrase;
char *comment;
bool modal;
PageantClientDialogId *dlgid;
char *passphrase;
const char *comment;
};
/*
@ -173,7 +175,30 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
return 0;
}
static HWND passphrase_box;
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 {
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);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) NULL);
DestroyWindow(hwnd);
nonmodal_passphrase_hwnd = NULL;
}
}
/*
* Dialog-box function for the passphrase box.
@ -181,12 +206,21 @@ static HWND passphrase_box;
static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
static char **passphrase = NULL;
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: {
passphrase_box = hwnd;
if (p->modal)
modal_passphrase_hwnd = hwnd;
/*
* Centre the window.
*/
@ -203,36 +237,36 @@ static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
SetForegroundWindow(hwnd);
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
p = (struct PassphraseProcStruct *) lParam;
passphrase = p->passphrase;
if (!p->modal)
SetActiveWindow(hwnd); /* this won't have happened automatically */
if (p->comment)
SetDlgItemText(hwnd, 101, p->comment);
burnstr(*passphrase);
*passphrase = dupstr("");
SetDlgItemText(hwnd, 102, *passphrase);
burnstr(p->passphrase);
p->passphrase = dupstr("");
SetDlgItemText(hwnd, 102, p->passphrase);
return 0;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (*passphrase)
EndDialog(hwnd, 1);
if (p->passphrase)
end_passphrase_dialog(hwnd, 1);
else
MessageBeep(0);
return 0;
case IDCANCEL:
EndDialog(hwnd, 0);
end_passphrase_dialog(hwnd, 0);
return 0;
case 102: /* edit box */
if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
burnstr(*passphrase);
*passphrase = GetDlgItemText_alloc(hwnd, 102);
if ((HIWORD(wParam) == EN_CHANGE) && p->passphrase) {
burnstr(p->passphrase);
p->passphrase = GetDlgItemText_alloc(hwnd, 102);
}
return 0;
}
return 0;
case WM_CLOSE:
EndDialog(hwnd, 0);
end_passphrase_dialog(hwnd, 0);
return 0;
}
return 0;
@ -364,7 +398,6 @@ static void win_add_keyfile(Filename *filename)
{
char *err;
int ret;
char *passphrase = NULL;
/*
* Try loading the key without a passphrase. (Or rather, without a
@ -385,40 +418,37 @@ static void win_add_keyfile(Filename *filename)
while (1) {
INT_PTR dlgret;
struct PassphraseProcStruct pps;
pps.passphrase = &passphrase;
pps.modal = true;
pps.dlgid = NULL;
pps.passphrase = NULL;
pps.comment = err;
dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210),
NULL, PassphraseProc, (LPARAM) &pps);
passphrase_box = NULL;
modal_passphrase_hwnd = NULL;
if (!dlgret)
if (!dlgret) {
burnstr(pps.passphrase);
goto done; /* operation cancelled */
}
sfree(err);
assert(passphrase != NULL);
assert(pps.passphrase != NULL);
ret = pageant_add_keyfile(filename, pps.passphrase, &err, false);
burnstr(pps.passphrase);
ret = pageant_add_keyfile(filename, passphrase, &err, false);
if (ret == PAGEANT_ACTION_OK) {
goto done;
} else if (ret == PAGEANT_ACTION_FAILURE) {
goto error;
}
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
passphrase = NULL;
}
error:
message_box(traywindow, err, APPNAME, MB_OK | MB_ICONERROR,
HELPCTXID(errors_cantloadkey));
done:
if (passphrase) {
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
}
sfree(err);
return;
}
@ -527,9 +557,9 @@ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg,
case 101: /* add key */
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) {
if (passphrase_box) {
if (modal_passphrase_hwnd) {
MessageBeep(MB_ICONERROR);
SetForegroundWindow(passphrase_box);
SetForegroundWindow(modal_passphrase_hwnd);
break;
}
prompt_add_keyfile();
@ -788,11 +818,29 @@ static void wm_copydata_got_response(
SetEvent(wmct.ev_reply_ready);
}
static bool ask_passphrase_common(PageantClientDialogId *dlgid,
const char *msg)
{
/* 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->dlgid = dlgid;
pps->passphrase = NULL;
pps->comment = msg;
nonmodal_passphrase_hwnd = CreateDialogParam(
hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, (LPARAM)pps);
return true;
}
static bool wm_copydata_ask_passphrase(
PageantClient *pc, PageantClientDialogId *dlgid, const char *msg)
{
/* FIXME: we don't yet support dialog boxes */
return false;
return ask_passphrase_common(dlgid, msg);
}
static const PageantClientVtable wmcpc_vtable = {
@ -1017,8 +1065,8 @@ static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
break;
}
case IDM_CLOSE:
if (passphrase_box)
SendMessage(passphrase_box, WM_CLOSE, 0, 0);
if (modal_passphrase_hwnd)
SendMessage(modal_passphrase_hwnd, WM_CLOSE, 0, 0);
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
case IDM_VIEWKEYS:
@ -1039,9 +1087,9 @@ static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
break;
case IDM_ADDKEY:
if (passphrase_box) {
if (modal_passphrase_hwnd) {
MessageBeep(MB_ICONERROR);
SetForegroundWindow(passphrase_box);
SetForegroundWindow(modal_passphrase_hwnd);
break;
}
prompt_add_keyfile();
@ -1180,8 +1228,7 @@ void cleanup_exit(int code)
static bool winpgnt_listener_ask_passphrase(
PageantListenerClient *plc, PageantClientDialogId *dlgid, const char *msg)
{
/* FIXME: we don't yet support dialog boxes */
return false;
return ask_passphrase_common(dlgid, msg);
}
struct winpgnt_client {
@ -1464,6 +1511,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
continue;
if (IsWindow(aboutbox) && IsDialogMessage(aboutbox, &msg))
continue;
if (IsWindow(nonmodal_passphrase_hwnd) &&
IsDialogMessage(nonmodal_passphrase_hwnd, &msg))
continue;
TranslateMessage(&msg);
DispatchMessage(&msg);