diff --git a/tty/pinentry-tty.c b/tty/pinentry-tty.c index 3951bc8..a66241b 100644 --- a/tty/pinentry-tty.c +++ b/tty/pinentry-tty.c @@ -1,611 +1,611 @@ /* pinentry-tty.c - A minimalist dumb terminal mechanism for PIN entry * Copyright (C) 2014 Serge Voilokov * Copyright (C) 2015 Daniel Kahn Gillmor * Copyright (C) 2015 g10 Code GmbH * * This file is part of PINENTRY. * * PINENTRY is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * PINENTRY is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_UTIME_H #include #endif /*HAVE_UTIME_H*/ #include #include #include #include #include "pinentry.h" #ifndef HAVE_DOSISH_SYSTEM static int timed_out; #endif static struct termios n_term; static struct termios o_term; static int terminal_save (int fd) { if ((tcgetattr (fd, &o_term)) == -1) return -1; return 0; } static void terminal_restore (int fd) { tcsetattr (fd, TCSANOW, &o_term); } static int terminal_setup (int fd, int line_edit) { n_term = o_term; if (line_edit) n_term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); else { n_term.c_lflag &= ~(ECHO|ICANON); n_term.c_lflag |= ISIG; n_term.c_cc[VMIN] = 1; n_term.c_cc[VTIME]= 0; } if ((tcsetattr(fd, TCSAFLUSH, &n_term)) == -1) return -1; return 1; } #define UNDERLINE_START "\033[4m" /* Bold, red. */ #define ALERT_START "\033[1;31m" #define NORMAL_RESTORE "\033[0m" static void fputs_highlighted (char *text, char *highlight, FILE *ttyfo) { for (; *text; text ++) { /* Skip accelerator prefix. */ if (*text == '_') { text ++; if (! *text) break; } if (text == highlight) fputs (UNDERLINE_START, ttyfo); fputc (*text, ttyfo); if (text == highlight) fputs (NORMAL_RESTORE, ttyfo); } } static char button (char *text, char *default_text, FILE *ttyfo) { char *highlight; int use_default = 0; if (! text) return 0; /* Skip any leading white space. */ while (*text == ' ') text ++; highlight = text; while ((highlight = strchr (highlight, '_'))) { highlight = highlight + 1; if (*highlight == '_') { /* Escaped underscore. Skip both characters. */ highlight++; continue; } - if (!isalnum (*highlight)) + if (!isalnum (*(unsigned char*)highlight)) /* Unusable accelerator. */ continue; break; } if (! highlight) /* Not accelerator. Take the first alpha-numeric character. */ { highlight = text; - while (*highlight && !isalnum (*highlight)) + while (*highlight && !isalnum (*(unsigned char*)highlight)) highlight ++; } if (! *highlight) /* Hmm, no alpha-numeric characters. */ { if (! default_text) return 0; highlight = default_text; use_default = 1; } fputs (" ", ttyfo); fputs_highlighted (text, highlight, ttyfo); if (use_default) { fputs (" (", ttyfo); fputs_highlighted (default_text, highlight, ttyfo); fputc (')', ttyfo); } fputc ('\n', ttyfo); return tolower (*highlight); } static void dump_error_text (FILE *ttyfo, const char *text) { int lines = 0; if (! text || ! *text) return; for (;;) { const char *eol = strchr (text, '\n'); if (! eol) eol = text + strlen (text); lines ++; fwrite ("\n *** ", 6, 1, ttyfo); fputs (ALERT_START, ttyfo); fwrite (text, (size_t) (eol - text), 1, ttyfo); fputs (NORMAL_RESTORE, ttyfo); if (! *eol) break; text = eol + 1; } if (lines > 1) fputc ('\n', ttyfo); else fwrite (" ***\n", 5, 1, ttyfo); fputc ('\n', ttyfo); } static int confirm (pinentry_t pinentry, FILE *ttyfi, FILE *ttyfo) { char *msg; char *msgbuffer = NULL; char ok = 0; char notok = 0; char cancel = 0; int ret; dump_error_text (ttyfo, pinentry->error); msg = pinentry->description; if (! msg) { /* If there is no description, fallback to the title. */ msg = msgbuffer = pinentry_get_title (pinentry); } if (! msg) msg = "Confirm:"; if (msg) { fputs (msg, ttyfo); fputc ('\n', ttyfo); } free (msgbuffer); fflush (ttyfo); if (pinentry->ok) ok = button (pinentry->ok, "OK", ttyfo); else if (pinentry->default_ok) ok = button (pinentry->default_ok, "OK", ttyfo); else ok = button ("OK", NULL, ttyfo); if (! pinentry->one_button) { if (pinentry->cancel) cancel = button (pinentry->cancel, "Cancel", ttyfo); else if (pinentry->default_cancel) cancel = button (pinentry->default_cancel, "Cancel", ttyfo); if (pinentry->notok) notok = button (pinentry->notok, "No", ttyfo); } while (1) { int input; if (pinentry->one_button) fprintf (ttyfo, "Press any key to continue."); else { fputc ('[', ttyfo); if (ok) fputc (ok, ttyfo); if (cancel) fputc (cancel, ttyfo); if (notok) fputc (notok, ttyfo); fputs("]? ", ttyfo); } fflush (ttyfo); input = fgetc (ttyfi); if (input == EOF) { pinentry->close_button = 1; pinentry->canceled = 1; #ifndef HAVE_DOSISH_SYSTEM if (!timed_out && errno == EINTR) pinentry->specific_err = gpg_error (GPG_ERR_FULLY_CANCELED); #endif ret = 0; break; } else { fprintf (ttyfo, "%c\n", input); input = tolower (input); } if (pinentry->one_button) { ret = 1; break; } if (cancel && input == cancel) { pinentry->canceled = 1; ret = 0; break; } else if (notok && input == notok) { ret = 0; break; } else if (ok && input == ok) { ret = 1; break; } else { fprintf (ttyfo, "Invalid selection.\n"); } } #ifndef HAVE_DOSISH_SYSTEM if (timed_out) pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT); #endif return ret; } static char * read_password (pinentry_t pinentry, FILE *ttyfi, FILE *ttyfo) { int done = 0; int len = 128; int count = 0; char *buffer; (void) ttyfo; buffer = secmem_malloc (len); if (! buffer) return NULL; while (!done) { int c; if (count == len - 1) /* Double the buffer's size. Note: we check if count is len - 1 and not len so that we always have space for the NUL character. */ { int new_len = 2 * len; char *tmp = secmem_realloc (buffer, new_len); if (! tmp) { secmem_free (tmp); return NULL; } buffer = tmp; len = new_len; } c = fgetc (ttyfi); switch (c) { case EOF: done = -1; #ifndef HAVE_DOSISH_SYSTEM if (!timed_out && errno == EINTR) pinentry->specific_err = gpg_error (GPG_ERR_FULLY_CANCELED); #endif break; case '\n': done = 1; break; default: buffer[count ++] = c; break; } } buffer[count] = '\0'; if (done == -1) { secmem_free (buffer); return NULL; } return buffer; } static int password (pinentry_t pinentry, FILE *ttyfi, FILE *ttyfo) { char *msg; char *msgbuffer = NULL; int done = 0; msg = pinentry->description; if (! msg) msg = msgbuffer = pinentry_get_title (pinentry); if (! msg) msg = "Enter your passphrase."; dump_error_text (ttyfo, pinentry->error); fprintf (ttyfo, "%s\n", msg); free (msgbuffer); while (! done) { char *passphrase; char *prompt = pinentry->prompt; if (! prompt || !*prompt) prompt = "PIN"; fprintf (ttyfo, "%s%s ", prompt, /* Make sure the prompt ends in a : or a question mark. */ (prompt[strlen(prompt) - 1] == ':' || prompt[strlen(prompt) - 1] == '?') ? "" : ":"); fflush (ttyfo); passphrase = read_password (pinentry, ttyfi, ttyfo); fputc ('\n', ttyfo); if (! passphrase) { done = -1; break; } if (! pinentry->repeat_passphrase) done = 1; else { char *passphrase2; prompt = pinentry->repeat_passphrase; fprintf (ttyfo, "%s%s ", prompt, /* Make sure the prompt ends in a : or a question mark. */ (prompt[strlen(prompt) - 1] == ':' || prompt[strlen(prompt) - 1] == '?') ? "" : ":"); fflush (ttyfo); passphrase2 = read_password (pinentry, ttyfi, ttyfo); fputc ('\n', ttyfo); if (! passphrase2) { done = -1; break; } if (strcmp (passphrase, passphrase2) == 0) { pinentry->repeat_okay = 1; done = 1; } else dump_error_text (ttyfo, pinentry->repeat_error_string ?: "Passphrases don't match."); secmem_free (passphrase2); } if (done == 1) pinentry_setbuffer_use (pinentry, passphrase, 0); else secmem_free (passphrase); } #ifndef HAVE_DOSISH_SYSTEM if (timed_out) pinentry->specific_err = gpg_error (GPG_ERR_TIMEOUT); #endif return done; } /* If a touch has been registered, touch that file. */ static void do_touch_file(pinentry_t pinentry) { #ifdef HAVE_UTIME_H struct stat st; time_t tim; if (!pinentry->touch_file || !*pinentry->touch_file) return; if (stat(pinentry->touch_file, &st)) return; /* Oops. */ /* Make sure that we actually update the mtime. */ while ((tim = time(NULL)) == st.st_mtime) sleep(1); /* Update but ignore errors as we can't do anything in that case. Printing error messages may even clubber the display further. */ utime (pinentry->touch_file, NULL); #endif /*HAVE_UTIME_H*/ } #ifndef HAVE_DOSISH_SYSTEM static void catchsig (int sig) { if (sig == SIGALRM) timed_out = 1; } #endif int tty_cmd_handler (pinentry_t pinentry) { int rc = 0; FILE *ttyfi = stdin; FILE *ttyfo = stdout; int saved_errno = 0; #ifndef HAVE_DOSISH_SYSTEM timed_out = 0; if (pinentry->timeout) { struct sigaction sa; memset (&sa, 0, sizeof(sa)); sa.sa_handler = catchsig; sigaction (SIGALRM, &sa, NULL); sigaction (SIGINT, &sa, NULL); alarm (pinentry->timeout); } #endif if (pinentry->ttyname) { ttyfi = fopen (pinentry->ttyname, "r"); if (!ttyfi) return -1; ttyfo = fopen (pinentry->ttyname, "w"); if (!ttyfo) { saved_errno = errno; fclose (ttyfi); errno = saved_errno; return -1; } } if (terminal_save (fileno (ttyfi)) < 0) rc = -1; else { if (terminal_setup (fileno (ttyfi), !!pinentry->pin) == -1) { saved_errno = errno; fprintf (stderr, "terminal_setup failure, exiting\n"); rc = -1; } else { if (pinentry->pin) rc = password (pinentry, ttyfi, ttyfo); else rc = confirm (pinentry, ttyfi, ttyfo); terminal_restore (fileno (ttyfi)); do_touch_file (pinentry); } } if (pinentry->ttyname) { fclose (ttyfi); fclose (ttyfo); } if (saved_errno) errno = saved_errno; return rc; } pinentry_cmd_handler_t pinentry_cmd_handler = tty_cmd_handler; int main (int argc, char *argv[]) { pinentry_init ("pinentry-tty"); /* Consumes all arguments. */ pinentry_parse_opts(argc, argv); if (pinentry_loop ()) return 1; return 0; } diff --git a/w32/main.c b/w32/main.c index bb41363..922e9c4 100644 --- a/w32/main.c +++ b/w32/main.c @@ -1,718 +1,480 @@ /* main.c - Secure W32 dialog for PIN entry. * Copyright (C) 2004, 2007 g10 Code GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include +#include #if WINVER < 0x0403 # define WINVER 0x0403 /* Required for SendInput. */ #endif #include -#ifdef HAVE_W32CE_SYSTEM -# include -# include -#endif #include "pinentry.h" #include "resource.h" /* #include "msgcodes.h" */ #define PGMNAME "pinentry-w32" -#ifndef LSFW_LOCK -# define LSFW_LOCK 1 -# define LSFW_UNLOCK 2 -#endif - #ifndef debugfp #define debugfp stderr #endif -/* This function pointer gets initialized in main. */ -#ifndef HAVE_W32CE_SYSTEM -static BOOL WINAPI (*lock_set_foreground_window)(UINT); -#endif - static int w32_cmd_handler (pinentry_t pe); static void ok_button_clicked (HWND dlg, pinentry_t pe); /* We use global variables for the state, because there should never ever be a second instance. */ static HWND dialog_handle; static int confirm_mode; static int passphrase_ok; static int confirm_yes; /* The file descriptors for the loop. */ static int w32_infd; static int w32_outfd; /* Connect this module to the pinentry framework. */ pinentry_cmd_handler_t pinentry_cmd_handler = w32_cmd_handler; const char * w32_strerror (int ec) { static char strerr[256]; if (ec == -1) ec = (int)GetLastError (); #ifdef HAVE_W32CE_SYSTEM /* There is only a wchar_t FormatMessage. It does not make much sense to play the conversion game; we print only the code. */ snprintf (strerr, sizeof strerr, "ec=%d", ec); #else FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), strerr, sizeof strerr - 1, NULL); #endif return strerr; } -#ifdef HAVE_W32CE_SYSTEM -/* Create a pipe. WRITE_END shall have the opposite value of the one - pssed to _assuan_w32ce_prepare_pipe; see there for more - details. */ -#define GPGCEDEV_IOCTL_MAKE_PIPE \ - CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS) -static HANDLE -w32ce_finish_pipe (int rvid, int write_end) -{ - HANDLE hd; - - hd = CreateFile (L"GPG1:", write_end? GENERIC_WRITE : GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL); - if (hd != INVALID_HANDLE_VALUE) - { - if (!DeviceIoControl (hd, GPGCEDEV_IOCTL_MAKE_PIPE, - &rvid, sizeof rvid, NULL, 0, NULL, NULL)) - { - DWORD lastrc = GetLastError (); - CloseHandle (hd); - hd = INVALID_HANDLE_VALUE; - SetLastError (lastrc); - } - } - - return hd; -} -#endif /*HAVE_W32CE_SYSTEM*/ - - /* static HWND */ /* show_window_hierarchy (HWND parent, int level) */ /* { */ /* HWND child; */ /* child = GetWindow (parent, GW_CHILD); */ /* while (child) */ /* { */ /* char buf[1024+1]; */ /* char name[200]; */ /* int nname; */ /* char *pname; */ /* memset (buf, 0, sizeof (buf)); */ /* GetWindowText (child, buf, sizeof (buf)-1); */ /* nname = GetClassName (child, name, sizeof (name)-1); */ /* if (nname) */ /* pname = name; */ /* else */ /* pname = NULL; */ /* fprintf (debugfp, "### %*shwnd=%p (%s) `%s'\n", level*2, "", child, */ /* pname? pname:"", buf); */ /* show_window_hierarchy (child, level+1); */ /* child = GetNextWindow (child, GW_HWNDNEXT); */ /* } */ /* return NULL; */ /* } */ /* Convert a wchar to UTF8. Caller needs to release the string. Returns NULL on error. */ static char * wchar_to_utf8 (const wchar_t *string, size_t len, int secure) { int n; char *result; /* Note, that CP_UTF8 is not defined in Windows versions earlier than NT. */ n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL); if (n < 0) return NULL; result = secure? secmem_malloc (n+1) : malloc (n+1); if (!result) return NULL; n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL); if (n < 0) { if (secure) secmem_free (result); else free (result); return NULL; } return result; } /* Convert a UTF8 string to wchar. Returns NULL on error. Caller needs to free the returned value. */ wchar_t * utf8_to_wchar (const char *string) { int n; wchar_t *result; size_t len = strlen (string); n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0); if (n < 0) return NULL; result = calloc ((n+1), sizeof *result); if (!result) return NULL; n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n); if (n < 0) { free (result); return NULL; } result[n] = 0; return result; } -/* Raise the software input panel. */ -static void -raise_sip (HWND dlg) -{ -#ifdef HAVE_W32CE_SYSTEM - SIPINFO si; - - SetForegroundWindow (dlg); - - memset (&si, 0, sizeof si); - si.cbSize = sizeof si; - - if (SipGetInfo (&si)) - { - si.fdwFlags |= SIPF_ON; - SipSetInfo (&si); - } -#else - (void)dlg; -#endif -} - /* Center the window CHILDWND with the desktop as its parent window. STYLE is passed as second arg to SetWindowPos.*/ static void center_window (HWND childwnd, HWND style) { -#ifndef HAVE_W32CE_SYSTEM HWND parwnd; RECT rchild, rparent; HDC hdc; int wchild, hchild, wparent, hparent; int wscreen, hscreen, xnew, ynew; int flags = SWP_NOSIZE | SWP_NOZORDER; parwnd = GetDesktopWindow (); GetWindowRect (childwnd, &rchild); wchild = rchild.right - rchild.left; hchild = rchild.bottom - rchild.top; GetWindowRect (parwnd, &rparent); wparent = rparent.right - rparent.left; hparent = rparent.bottom - rparent.top; hdc = GetDC (childwnd); wscreen = GetDeviceCaps (hdc, HORZRES); hscreen = GetDeviceCaps (hdc, VERTRES); ReleaseDC (childwnd, hdc); xnew = rparent.left + ((wparent - wchild) / 2); if (xnew < 0) xnew = 0; else if ((xnew+wchild) > wscreen) xnew = wscreen - wchild; ynew = rparent.top + ((hparent - hchild) / 2); if (ynew < 0) ynew = 0; else if ((ynew+hchild) > hscreen) ynew = hscreen - hchild; if (style == HWND_TOPMOST || style == HWND_NOTOPMOST) flags = SWP_NOMOVE | SWP_NOSIZE; SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags); -#endif -} - - - -static void -move_mouse_and_click (HWND hwnd) -{ -#ifndef HAVE_W32CE_SYSTEM - RECT rect; - HDC hdc; - int wscreen, hscreen, x, y, normx, normy; - INPUT inp[3]; - int idx; - - hdc = GetDC (hwnd); - wscreen = GetDeviceCaps (hdc, HORZRES); - hscreen = GetDeviceCaps (hdc, VERTRES); - ReleaseDC (hwnd, hdc); - if (wscreen < 10 || hscreen < 10) - return; - - GetWindowRect (hwnd, &rect); - x = rect.left; - y = rect.bottom; - - normx = x * (65535 / wscreen); - if (normx < 0 || normx > 65535) - return; - normy = y * (65535 / hscreen); - if (normy < 0 || normy > 65535) - return; - - for (idx=0; idx < 3; idx++) - memset (&inp[idx], 0, sizeof inp[idx]); - - idx=0; - inp[idx].type = INPUT_MOUSE; - inp[idx].mi.dx = normx; - inp[idx].mi.dy = normy; - inp[idx].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; - idx++; - - inp[idx].type = INPUT_MOUSE; - inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; - idx++; - - inp[idx].type = INPUT_MOUSE; - inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTUP; - idx++; - - if ( (SendInput (idx, inp, sizeof (INPUT)) != idx) && debugfp) - fprintf (debugfp, "SendInput failed: %s\n", w32_strerror (-1)); -#endif } /* Resize the button so that STRING fits into it. */ static void resize_button (HWND hwnd, const char *string) { if (!hwnd) return; - /* FIXME: Need to figure out how to convert dialog coorddnates to + (void)string; + + /* FIXME: Need to figure out how to convert dialog coordinates to screen coordinates and how buttons should be placed. */ /* SetWindowPos (hbutton, NULL, */ /* 10, 180, */ /* strlen (string+2), 14, */ /* (SWP_NOZORDER)); */ } /* Call SetDlgItemTextW with an UTF8 string. */ static void set_dlg_item_text (HWND dlg, int item, const char *string) { if (!string || !*string) SetDlgItemTextW (dlg, item, L""); else { wchar_t *wbuf; wbuf = utf8_to_wchar (string); if (!wbuf) SetDlgItemTextW (dlg, item, L"[out of core]"); else { SetDlgItemTextW (dlg, item, wbuf); free (wbuf); } } } /* Load our butmapped icon from the resource and display it. */ static void set_bitmap (HWND dlg, int item) { HWND hwnd; HBITMAP bitmap; RECT rect; int resid; hwnd = GetDlgItem (dlg, item); if (!hwnd) return; rect.left = 0; rect.top = 0; rect.right = 32; rect.bottom = 32; if (!MapDialogRect (dlg, &rect)) { fprintf (stderr, "MapDialogRect failed: %s\n", w32_strerror (-1)); return; } /* fprintf (stderr, "MapDialogRect: %d/%d\n", rect.right, rect.bottom); */ switch (rect.right) { case 32: resid = IDB_ICON_32; break; case 48: resid = IDB_ICON_48; break; case 64: resid = IDB_ICON_64; break; case 96: resid = IDB_ICON_96; break; default: resid = IDB_ICON_128;break; } bitmap = LoadImage (GetModuleHandle (NULL), MAKEINTRESOURCE (resid), IMAGE_BITMAP, rect.right, rect.bottom, (LR_SHARED | LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS)); if (!bitmap) { fprintf (stderr, "LoadImage failed: %s\n", w32_strerror (-1)); return; } SendMessage(hwnd, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)bitmap); } /* Dialog processing loop. */ -static BOOL CALLBACK +static INT_PTR CALLBACK dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam) { static pinentry_t pe; /* static int item; */ /* { */ /* int idx; */ /* for (idx=0; msgcodes[idx].string; idx++) */ /* if (msg == msgcodes[idx].msg) */ /* break; */ /* if (msgcodes[idx].string) */ /* fprintf (debugfp, "received %s\n", msgcodes[idx].string); */ /* else */ /* fprintf (debugfp, "received WM_%u\n", msg); */ /* } */ switch (msg) { case WM_INITDIALOG: dialog_handle = dlg; pe = (pinentry_t)lparam; if (!pe) abort (); set_dlg_item_text (dlg, IDC_PINENT_PROMPT, pe->prompt); set_dlg_item_text (dlg, IDC_PINENT_DESC, pe->description); set_dlg_item_text (dlg, IDC_PINENT_TEXT, ""); set_bitmap (dlg, IDC_PINENT_ICON); if (pe->ok) { set_dlg_item_text (dlg, IDOK, pe->ok); resize_button (GetDlgItem (dlg, IDOK), pe->ok); } if (pe->cancel) { set_dlg_item_text (dlg, IDCANCEL, pe->cancel); resize_button (GetDlgItem (dlg, IDCANCEL), pe->cancel); } if (pe->error) set_dlg_item_text (dlg, IDC_PINENT_ERR, pe->error); if (confirm_mode) { EnableWindow (GetDlgItem (dlg, IDC_PINENT_TEXT), FALSE); SetWindowPos (GetDlgItem (dlg, IDC_PINENT_TEXT), NULL, 0, 0, 0, 0, (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW)); /* item = IDOK; */ } /* else */ /* item = IDC_PINENT_TEXT; */ center_window (dlg, HWND_TOP); - /* Unfortunately we can't use SetForegroundWindow because there - is no easy eay to have all the calling processes do an - AllowSetForegroundWindow. What we do instead is to bad hack - by simulating a click to the Window. */ -/* if (SetForegroundWindow (dlg) && lock_set_foreground_window) */ -/* { */ -/* lock_set_foreground_window (LSFW_LOCK); */ -/* } */ - -/* show_window_hierarchy (GetDesktopWindow (), 0); */ - ShowWindow (dlg, SW_SHOW); - move_mouse_and_click ( GetDlgItem (dlg, IDC_PINENT_PROMPT) ); - raise_sip (dlg); + break; case WM_COMMAND: switch (LOWORD (wparam)) { case IDOK: if (confirm_mode) confirm_yes = 1; else ok_button_clicked (dlg, pe); EndDialog (dlg, TRUE); break; case IDCANCEL: pe->result = -1; EndDialog (dlg, FALSE); break; } break; case WM_KEYDOWN: if (wparam == VK_RETURN) { if (confirm_mode) confirm_yes = 1; else ok_button_clicked (dlg, pe); EndDialog (dlg, TRUE); } break; case WM_CTLCOLORSTATIC: if ((HWND)lparam == GetDlgItem (dlg, IDC_PINENT_ERR)) { /* Display the error prompt in red. */ SetTextColor ((HDC)wparam, RGB (255, 0, 0)); SetBkMode ((HDC)wparam, TRANSPARENT); return (BOOL)GetStockObject (NULL_BRUSH); } break; } return FALSE; } /* The okay button has been clicked or the enter enter key in the text field. */ static void ok_button_clicked (HWND dlg, pinentry_t pe) { char *s_utf8; wchar_t *w_buffer; size_t w_buffer_size = 255; unsigned int nchar; pe->locale_err = 1; w_buffer = secmem_malloc ((w_buffer_size + 1) * sizeof *w_buffer); if (!w_buffer) return; nchar = GetDlgItemTextW (dlg, IDC_PINENT_TEXT, w_buffer, w_buffer_size); s_utf8 = wchar_to_utf8 (w_buffer, nchar, 1); secmem_free (w_buffer); if (s_utf8) { passphrase_ok = 1; pinentry_setbufferlen (pe, strlen (s_utf8) + 1); if (pe->pin) strcpy (pe->pin, s_utf8); secmem_free (s_utf8); pe->locale_err = 0; pe->result = pe->pin? strlen (pe->pin) : 0; } } static int w32_cmd_handler (pinentry_t pe) { -/* HWND lastwindow = GetForegroundWindow (); */ - confirm_mode = !pe->pin; passphrase_ok = confirm_yes = 0; dialog_handle = NULL; DialogBoxParam (GetModuleHandle (NULL), MAKEINTRESOURCE (IDD_PINENT), GetDesktopWindow (), dlg_proc, (LPARAM)pe); - if (dialog_handle) - { -/* if (lock_set_foreground_window) */ -/* lock_set_foreground_window (LSFW_UNLOCK); */ -/* if (lastwindow) */ -/* SetForegroundWindow (lastwindow); */ - } - else + if (!dialog_handle) return -1; if (confirm_mode) return confirm_yes; else if (passphrase_ok && pe->pin) return strlen (pe->pin); else return -1; } -/* WindowsCE uses a very strange way of handling the standard streams. - There is a function SetStdioPath to associate a standard stream - with a file or a device but what we really want is to use pipes as - standard streams. Despite that we implement pipes using a device, - we would have some limitations on the number of open pipes due to - the 3 character limit of device file name. Thus we don't take this - path. Another option would be to install a file system driver with - support for pipes; this would allow us to get rid of the device - name length limitation. However, with GnuPG we can get away be - redefining the standard streams and passing the handles to be used - on the command line. This has also the advantage that it makes - creating a process much easier and does not require the - SetStdioPath set and restore game. The caller needs to pass the - rendezvous ids using up to three options: - - -&S0= -&S1= -&S2= - - They are all optional but they must be the first arguments on the - command line. Parsing stops as soon as an invalid option is found. - These rendezvous ids are then used to finish the pipe creation.*/ -#ifdef HAVE_W32CE_SYSTEM -static void -parse_std_file_handles (int *argcp, char ***argvp) -{ - int argc = *argcp; - char **argv = *argvp; - const char *s; - int fd; - int i; - int fixup = 0; - - if (!argc) - return; - - for (argc--, argv++; argc; argc--, argv++) - { - s = *argv; - if (*s == '-' && s[1] == '&' && s[2] == 'S' - && (s[3] == '0' || s[3] == '1' || s[3] == '2') - && s[4] == '=' - && (strchr ("-01234567890", s[5]) || !strcmp (s+5, "null"))) - { - if (s[5] == 'n') - fd = (int)(-1); - else - fd = (int)w32ce_finish_pipe (atoi (s+5), s[3] != '0'); - if (s[3] == '0' && fd != -1) - w32_infd = fd; - else if (s[3] == '1' && fd != -1) - w32_outfd = fd; - fixup++; - } - else - break; - } - - if (fixup) - { - argc = *argcp; - argc -= fixup; - *argcp = argc; - - argv = *argvp; - for (i=1; i < argc; i++) - argv[i] = argv[i + fixup]; - for (; i < argc + fixup; i++) - argv[i] = NULL; - } - - -} -#endif /*HAVE_W32CE_SYSTEM*/ - int main (int argc, char **argv) { -#ifndef HAVE_W32CE_SYSTEM - void *handle; -#endif - w32_infd = STDIN_FILENO; w32_outfd = STDOUT_FILENO; -#ifdef HAVE_W32CE_SYSTEM - parse_std_file_handles (&argc, &argv); -#endif - pinentry_init (PGMNAME); pinentry_parse_opts (argc, argv); /* debugfp = fopen ("pinentry.log", "w"); */ /* if (!debugfp) */ /* debugfp = stderr; */ - /* We need to load a function because that one is only available - since W2000 but not in older NTs. */ -#ifndef HAVE_W32CE_SYSTEM - handle = LoadLibrary ("user32.dll"); - if (handle) - { - void *foo; - foo = GetProcAddress (handle, "LockSetForegroundWindow"); - if (foo) - lock_set_foreground_window = foo; - else - CloseHandle (handle); - } -#endif if (pinentry_loop2 (w32_infd, w32_outfd)) return 1; -#ifdef HAVE_W32CE_SYSTEM - Sleep (400); -#endif return 0; } diff --git a/w32/pinentry-w32.rc b/w32/pinentry-w32.rc index bc3dacb..28a2de0 100755 --- a/w32/pinentry-w32.rc +++ b/w32/pinentry-w32.rc @@ -1,74 +1,74 @@ /* dialog.rc - Resource definitions -*- c -*- * Copyright (C) 2004, 2010 g10 Code GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include "resource.h" /* * Main dialog */ #ifdef HAVE_W32CE_SYSTEM IDD_PINENT DIALOG DISCARDABLE 0, 0, 150, 100 STYLE DS_MODALFRAME | DS_SYSMODAL | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pinentry" FONT 8, "MS Shell Dlg" BEGIN LTEXT "", IDC_PINENT_DESC, 2, 2, 140, 24 LTEXT "", IDC_PINENT_ERR, 2, 30, 140, 12 LTEXT "", IDC_PINENT_PROMPT, 2, 56, 20, 12 EDITTEXT IDC_PINENT_TEXT, 30, 56, 100, 12, ES_PASSWORD | ES_AUTOHSCROLL DEFPUSHBUTTON "O&K", IDOK, 2, 70, 50, 14 PUSHBUTTON "&Cancel", IDCANCEL, 60, 70, 50, 14 END #else /* Standard Windows. */ IDB_ICON_32 BITMAP DISCARDABLE "logo-32.bmp" IDB_ICON_48 BITMAP DISCARDABLE "logo-48.bmp" IDB_ICON_64 BITMAP DISCARDABLE "logo-64.bmp" IDB_ICON_96 BITMAP DISCARDABLE "logo-96.bmp" IDB_ICON_128 BITMAP DISCARDABLE "logo-128.bmp" -IDD_PINENT DIALOG DISCARDABLE 0, 0, 186, 116 +IDD_PINENT DIALOG DISCARDABLE 0, 0, 230, 125 STYLE DS_MODALFRAME | DS_SYSMODAL | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Pinentry" FONT 10, "MS Sans Serif" BEGIN CONTROL "", IDC_PINENT_ICON, "Static", SS_BITMAP|SS_CENTERIMAGE, - 4, 6, 32, 32 - LTEXT "", IDC_PINENT_DESC, 40, 6, 140, 50 - RTEXT "", IDC_PINENT_PROMPT, 6, 60, 60, 12 - EDITTEXT IDC_PINENT_TEXT, 70, 59, 110, 12, ES_PASSWORD | ES_AUTOHSCROLL - CTEXT "", IDC_PINENT_ERR, 6, 76, 174, 12 - DEFPUSHBUTTON "O&K", IDOK, 74, 96, 50, 14 - PUSHBUTTON "&Cancel", IDCANCEL, 130, 96, 50, 14 + 5, 5, 32, 32 + LTEXT "", IDC_PINENT_DESC, 45, 5, 180, 65 + RTEXT "", IDC_PINENT_PROMPT, 5, 75, 60, 12 + EDITTEXT IDC_PINENT_TEXT, 70, 75, 155, 12, ES_PASSWORD | ES_AUTOHSCROLL + CTEXT "", IDC_PINENT_ERR, 5, 90, 220, 12 + DEFPUSHBUTTON "O&K", IDOK, 50, 105, 85, 14 + PUSHBUTTON "&Cancel", IDCANCEL, 140, 105, 85, 14 END #endif /* Standard Windows. */