|
|
/* 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 <https://www.gnu.org/licenses/>.
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
*/
|
|
|
|
|
|
#include <config.h>
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#if WINVER < 0x0403
|
|
|
# define WINVER 0x0403 /* Required for SendInput. */
|
|
|
#endif
|
|
|
#include <windows.h>
|
|
|
#ifdef HAVE_W32CE_SYSTEM
|
|
|
# include <winioctl.h>
|
|
|
# include <sipapi.h>
|
|
|
#endif
|
|
|
|
|
|
#include "pinentry.h"
|
|
|
#include "memory.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);
|
|
|
strerr[sizeof strerr -1] = 0;
|
|
|
#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
|
|
|
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
|
|
|
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
|
|
|
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=<rvid> -&S1=<rvid> -&S2=<rvid>
|
|
|
|
|
|
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;
|
|
|
}
|