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