~x2go/x2go/pinentry-x2go_build-main

« back to all changes in this revision

Viewing changes to w32/main.c

  • Committer: Mike Gabriel
  • Date: 2012-06-13 12:55:37 UTC
  • Revision ID: git-v1:d2060291d5cc7beb92f78168e48ececfe765d552
Strip code project down to its essentials, remove a lot of unneeded cruft. / Make code tree fully build with autotools, see README file for further info.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* main.c - Secure W32 dialog for PIN entry.
2
 
   Copyright (C) 2004, 2007 g10 Code GmbH
3
 
   
4
 
   This program is free software; you can redistribute it and/or
5
 
   modify it under the terms of the GNU General Public License as
6
 
   published by the Free Software Foundation; either version 2 of the
7
 
   License, or (at your option) any later version.
8
 
 
9
 
   This program is distributed in the hope that it will be useful, but
10
 
   WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
   General Public License for more details.
13
 
 
14
 
   You should have received a copy of the GNU General Public License
15
 
   along with this program; if not, write to the Free Software
16
 
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17
 
   02111-1307, USA  */
18
 
 
19
 
#include <config.h>
20
 
#include <stdio.h>
21
 
#include <stdlib.h>
22
 
#define WINVER 0x0403  /* Required for SendInput.  */
23
 
#include <windows.h>
24
 
 
25
 
#include "pinentry.h"
26
 
#include "memory.h"
27
 
 
28
 
#include "resource.h"
29
 
/* #include "msgcodes.h" */
30
 
 
31
 
#define PGMNAME "pinentry-w32"
32
 
 
33
 
#ifndef LSFW_LOCK
34
 
# define LSFW_LOCK 1
35
 
# define LSFW_UNLOCK 2
36
 
#endif
37
 
 
38
 
 
39
 
/* This function pointer gets initialized in main.  */
40
 
static WINUSERAPI BOOL WINAPI (*lock_set_foreground_window)(UINT);
41
 
 
42
 
 
43
 
static int w32_cmd_handler (pinentry_t pe);
44
 
static void ok_button_clicked (HWND dlg, pinentry_t pe);
45
 
 
46
 
 
47
 
/* We use global variables for the state, because there should never
48
 
   ever be a second instance.  */
49
 
static HWND dialog_handle;
50
 
static int confirm_mode;
51
 
static int passphrase_ok;
52
 
static int confirm_yes;
53
 
 
54
 
static FILE *debugfp;
55
 
 
56
 
 
57
 
/* Connect this module to the pinnetry framework.  */
58
 
pinentry_cmd_handler_t pinentry_cmd_handler = w32_cmd_handler;
59
 
 
60
 
 
61
 
 
62
 
const char *
63
 
w32_strerror (int ec)
64
 
{
65
 
  static char strerr[256];
66
 
  
67
 
  if (ec == -1)
68
 
    ec = (int)GetLastError ();
69
 
  FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec,
70
 
                 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
71
 
                 strerr, sizeof strerr - 1, NULL);
72
 
  return strerr;    
73
 
}
74
 
 
75
 
 
76
 
/* static HWND */
77
 
/* show_window_hierarchy (HWND parent, int level) */
78
 
/* { */
79
 
/*   HWND child; */
80
 
 
81
 
/*   child = GetWindow (parent, GW_CHILD); */
82
 
/*   while (child) */
83
 
/*     { */
84
 
/*       char buf[1024+1]; */
85
 
/*       char name[200]; */
86
 
/*       int nname; */
87
 
/*       char *pname; */
88
 
   
89
 
/*       memset (buf, 0, sizeof (buf)); */
90
 
/*       GetWindowText (child, buf, sizeof (buf)-1); */
91
 
/*       nname = GetClassName (child, name, sizeof (name)-1); */
92
 
/*       if (nname) */
93
 
/*         pname = name; */
94
 
/*       else */
95
 
/*         pname = NULL; */
96
 
/*       fprintf (debugfp, "### %*shwnd=%p (%s) `%s'\n", level*2, "", child, */
97
 
/*                pname? pname:"", buf); */
98
 
/*       show_window_hierarchy (child, level+1); */
99
 
/*       child = GetNextWindow (child, GW_HWNDNEXT);     */
100
 
/*     } */
101
 
 
102
 
/*   return NULL; */
103
 
/* } */
104
 
 
105
 
 
106
 
 
107
 
/* Convert a wchar to UTF8.  Caller needs to release the string.
108
 
   Returns NULL on error. */
109
 
static char *
110
 
wchar_to_utf8 (const wchar_t *string, size_t len, int secure)
111
 
{
112
 
  int n;
113
 
  char *result;
114
 
 
115
 
  /* Note, that CP_UTF8 is not defined in Windows versions earlier
116
 
     than NT.  */
117
 
  n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
118
 
  if (n < 0)
119
 
    return NULL;
120
 
 
121
 
  result = secure? secmem_malloc (n+1) : malloc (n+1);
122
 
  if (!result)
123
 
    return NULL;
124
 
  n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
125
 
  if (n < 0)
126
 
    {
127
 
      if (secure)
128
 
        secmem_free (result);
129
 
      else
130
 
        free (result);
131
 
      return NULL;
132
 
    }
133
 
  return result;
134
 
}
135
 
 
136
 
 
137
 
/* Convert a UTF8 string to wchar.  Returns NULL on error. Caller
138
 
   needs to free the returned value.  */
139
 
wchar_t *
140
 
utf8_to_wchar (const char *string)
141
 
{
142
 
  int n;
143
 
  wchar_t *result;
144
 
  size_t len = strlen (string);
145
 
 
146
 
  n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
147
 
  if (n < 0)
148
 
    return NULL;
149
 
 
150
 
  result = calloc ((n+1), sizeof *result);
151
 
  if (!result)
152
 
    return NULL;
153
 
  n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
154
 
  if (n < 0)
155
 
    {
156
 
      free (result);
157
 
      return NULL;
158
 
    }
159
 
  result[n] = 0;
160
 
  return result;
161
 
}
162
 
 
163
 
 
164
 
/* Center the window CHILDWND with the desktop as its parent
165
 
   window.  STYLE is passed as second arg to SetWindowPos.*/
166
 
static void
167
 
center_window (HWND childwnd, HWND style) 
168
 
{     
169
 
  HWND parwnd;
170
 
  RECT rchild, rparent;    
171
 
  HDC hdc;
172
 
  int wchild, hchild, wparent, hparent;
173
 
  int wscreen, hscreen, xnew, ynew;
174
 
  int flags = SWP_NOSIZE | SWP_NOZORDER;
175
 
  
176
 
  parwnd = GetDesktopWindow ();
177
 
  GetWindowRect (childwnd, &rchild);     
178
 
  wchild = rchild.right - rchild.left;     
179
 
  hchild = rchild.bottom - rchild.top;
180
 
  
181
 
  GetWindowRect (parwnd, &rparent);     
182
 
  wparent = rparent.right - rparent.left;     
183
 
  hparent = rparent.bottom - rparent.top;      
184
 
  
185
 
  hdc = GetDC (childwnd);     
186
 
  wscreen = GetDeviceCaps (hdc, HORZRES);     
187
 
  hscreen = GetDeviceCaps (hdc, VERTRES);     
188
 
  ReleaseDC (childwnd, hdc);      
189
 
  xnew = rparent.left + ((wparent - wchild) / 2);     
190
 
  if (xnew < 0)
191
 
    xnew = 0;
192
 
  else if ((xnew+wchild) > wscreen) 
193
 
    xnew = wscreen - wchild;
194
 
  ynew = rparent.top  + ((hparent - hchild) / 2);
195
 
  if (ynew < 0)
196
 
    ynew = 0;
197
 
  else if ((ynew+hchild) > hscreen)
198
 
    ynew = hscreen - hchild;
199
 
  if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
200
 
    flags = SWP_NOMOVE | SWP_NOSIZE;
201
 
  SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
202
 
}
203
 
 
204
 
 
205
 
 
206
 
static void
207
 
move_mouse_and_click (HWND hwnd)
208
 
{
209
 
  RECT rect;
210
 
  HDC hdc;
211
 
  int wscreen, hscreen, x, y, normx, normy;
212
 
  INPUT inp[3];
213
 
  int idx;
214
 
  
215
 
  hdc = GetDC (hwnd);     
216
 
  wscreen = GetDeviceCaps (hdc, HORZRES);     
217
 
  hscreen = GetDeviceCaps (hdc, VERTRES);     
218
 
  ReleaseDC (hwnd, hdc);      
219
 
  if (wscreen < 10 || hscreen < 10)
220
 
    return;
221
 
  
222
 
  GetWindowRect (hwnd, &rect);
223
 
  x = rect.left;
224
 
  y = rect.bottom;
225
 
 
226
 
  normx = x * (65535 / wscreen);
227
 
  if (normx < 0 || normx > 65535)
228
 
    return;
229
 
  normy = y * (65535 / hscreen);
230
 
  if (normy < 0 || normy > 65535)
231
 
    return;
232
 
 
233
 
  for (idx=0; idx < 3; idx++)
234
 
    memset (&inp[idx], 0, sizeof inp[idx]);
235
 
 
236
 
  idx=0;
237
 
  inp[idx].type = INPUT_MOUSE;
238
 
  inp[idx].mi.dx = normx;
239
 
  inp[idx].mi.dy = normy;
240
 
  inp[idx].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
241
 
  idx++;
242
 
 
243
 
  inp[idx].type = INPUT_MOUSE;
244
 
  inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
245
 
  idx++;
246
 
 
247
 
  inp[idx].type = INPUT_MOUSE;
248
 
  inp[idx].mi.dwFlags = MOUSEEVENTF_LEFTUP;
249
 
  idx++;
250
 
 
251
 
  if ( SendInput (idx, inp, sizeof (INPUT)) != idx && debugfp )
252
 
    fprintf (debugfp, "SendInput failed: %s\n", w32_strerror (-1));
253
 
}
254
 
 
255
 
 
256
 
 
257
 
/* Resize the button so that STRING fits into it.   */
258
 
static void
259
 
resize_button (HWND hwnd, const char *string)
260
 
{
261
 
  if (!hwnd)
262
 
    return;
263
 
 
264
 
  /* FIXME: Need to figure out how to convert dialog coorddnates to
265
 
     screen coordinates and how buttons should be placed.  */
266
 
/*   SetWindowPos (hbutton, NULL, */
267
 
/*                 10, 180,  */
268
 
/*                 strlen (string+2), 14, */
269
 
/*                 (SWP_NOZORDER)); */
270
 
}
271
 
 
272
 
 
273
 
 
274
 
 
275
 
 
276
 
/* Call SetDlgItemTextW with an UTF8 string.  */
277
 
static void
278
 
set_dlg_item_text (HWND dlg, int item, const char *string)
279
 
{
280
 
  if (!string || !*string)
281
 
    SetDlgItemText (dlg, item, "");
282
 
  else
283
 
    {
284
 
      wchar_t *wbuf;
285
 
      
286
 
      wbuf = utf8_to_wchar (string);
287
 
      if (!wbuf)
288
 
        SetDlgItemText (dlg, item, "[out of core]");
289
 
      else
290
 
        {
291
 
          SetDlgItemTextW (dlg, item, wbuf);
292
 
          free (wbuf);
293
 
        }
294
 
    }
295
 
}
296
 
 
297
 
 
298
 
/* Dialog processing loop.  */
299
 
static BOOL CALLBACK
300
 
dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
301
 
{
302
 
  static pinentry_t pe;
303
 
  static int item;
304
 
 
305
 
 
306
 
/*   { */
307
 
/*     int idx; */
308
 
 
309
 
/*     for (idx=0; msgcodes[idx].string; idx++) */
310
 
/*       if (msg == msgcodes[idx].msg) */
311
 
/*         break; */
312
 
/*     if (msgcodes[idx].string) */
313
 
/*       fprintf (debugfp, "received %s\n", msgcodes[idx].string); */
314
 
/*     else */
315
 
/*       fprintf (debugfp, "received WM_%u\n", msg); */
316
 
/*   } */
317
 
 
318
 
  switch (msg)
319
 
    {
320
 
    case WM_INITDIALOG:
321
 
      dialog_handle = dlg;
322
 
      pe = (pinentry_t)lparam;
323
 
      if (!pe)
324
 
        abort ();
325
 
      set_dlg_item_text (dlg, IDC_PINENT_PROMPT, pe->prompt);
326
 
      set_dlg_item_text (dlg, IDC_PINENT_DESC, pe->description);
327
 
      set_dlg_item_text (dlg, IDC_PINENT_TEXT, "");
328
 
      if (pe->ok)
329
 
        {
330
 
          set_dlg_item_text (dlg, IDOK, pe->ok);
331
 
          resize_button (GetDlgItem (dlg, IDOK), pe->ok);
332
 
        }
333
 
      if (pe->cancel)
334
 
        {
335
 
          set_dlg_item_text (dlg, IDCANCEL, pe->cancel);
336
 
          resize_button (GetDlgItem (dlg, IDCANCEL), pe->cancel);
337
 
        }
338
 
      if (pe->error)
339
 
        set_dlg_item_text (dlg, IDC_PINENT_ERR, pe->error);
340
 
 
341
 
      if (confirm_mode)
342
 
        {
343
 
          EnableWindow (GetDlgItem (dlg, IDC_PINENT_TEXT), FALSE);
344
 
          SetWindowPos (GetDlgItem (dlg, IDC_PINENT_TEXT), NULL, 0, 0, 0, 0,
345
 
                        (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_HIDEWINDOW));
346
 
          
347
 
          item = IDOK;
348
 
        }
349
 
      else
350
 
        item = IDC_PINENT_TEXT;
351
 
 
352
 
      center_window (dlg, HWND_TOP);
353
 
 
354
 
      /* Unfortunately we can't use SetForegroundWindow because there
355
 
         is no easy eay to have all the calling processes do an
356
 
         AllowSetForegroundWindow.  What we do instead is to bad hack
357
 
         by simulating a click to the Window. */
358
 
/*       if (SetForegroundWindow (dlg) && lock_set_foreground_window) */
359
 
/*         { */
360
 
/*           lock_set_foreground_window (LSFW_LOCK); */
361
 
/*         } */
362
 
 
363
 
/*       show_window_hierarchy (GetDesktopWindow (), 0); */
364
 
 
365
 
      ShowWindow (dlg, SW_SHOW);
366
 
      move_mouse_and_click ( GetDlgItem (dlg, IDC_PINENT_PROMPT) );
367
 
 
368
 
      break;
369
 
 
370
 
    case WM_COMMAND:
371
 
      switch (LOWORD (wparam))
372
 
        {
373
 
        case IDOK:
374
 
          if (confirm_mode)
375
 
            confirm_yes = 1;
376
 
          else
377
 
            ok_button_clicked (dlg, pe);
378
 
          EndDialog (dlg, TRUE);
379
 
          break;
380
 
 
381
 
        case IDCANCEL:
382
 
          pe->result = -1;
383
 
          EndDialog (dlg, FALSE);
384
 
          break;
385
 
        }
386
 
      break;
387
 
    }
388
 
  return FALSE;
389
 
}
390
 
 
391
 
 
392
 
/* The okay button has been clicked or the enter enter key in the text
393
 
   field.  */
394
 
static void
395
 
ok_button_clicked (HWND dlg, pinentry_t pe)
396
 
{
397
 
  char *s_utf8;
398
 
  wchar_t *w_buffer;
399
 
  size_t w_buffer_size = 255;
400
 
  unsigned int nchar;
401
 
  
402
 
  pe->locale_err = 1;
403
 
  w_buffer = secmem_malloc ((w_buffer_size + 1) * sizeof *w_buffer);
404
 
  if (!w_buffer)
405
 
    return;
406
 
 
407
 
  nchar = GetDlgItemTextW (dlg, IDC_PINENT_TEXT, w_buffer, w_buffer_size);
408
 
  s_utf8 = wchar_to_utf8 (w_buffer, nchar, 1);
409
 
  secmem_free (w_buffer);
410
 
  if (s_utf8)
411
 
    {
412
 
      passphrase_ok = 1;
413
 
      pinentry_setbufferlen (pe, strlen (s_utf8) + 1);
414
 
      if (pe->pin)
415
 
        strcpy (pe->pin, s_utf8);
416
 
      secmem_free (s_utf8);
417
 
      pe->locale_err = 0;
418
 
      pe->result = pe->pin? strlen (pe->pin) : 0;
419
 
    }
420
 
}
421
 
 
422
 
 
423
 
static int
424
 
w32_cmd_handler (pinentry_t pe)
425
 
{
426
 
/*   HWND lastwindow = GetForegroundWindow (); */
427
 
 
428
 
  confirm_mode = !pe->pin;
429
 
 
430
 
  passphrase_ok = confirm_yes = 0;
431
 
 
432
 
  dialog_handle = NULL;
433
 
  DialogBoxParam (GetModuleHandle (NULL), MAKEINTRESOURCE (IDD_PINENT),
434
 
                  GetDesktopWindow (), dlg_proc, (LPARAM)pe);
435
 
  if (dialog_handle)
436
 
    {
437
 
/*       if (lock_set_foreground_window) */
438
 
/*         lock_set_foreground_window (LSFW_UNLOCK); */
439
 
/*       if (lastwindow) */
440
 
/*         SetForegroundWindow (lastwindow); */
441
 
    }
442
 
  else
443
 
    return -1;
444
 
 
445
 
  if (confirm_mode)
446
 
    return confirm_yes;
447
 
  else if (passphrase_ok && pe->pin)
448
 
    return strlen (pe->pin);
449
 
  else
450
 
    return -1;
451
 
}
452
 
 
453
 
 
454
 
int
455
 
main (int argc, char **argv)
456
 
{
457
 
  void *handle;
458
 
 
459
 
  pinentry_init (PGMNAME);
460
 
 
461
 
  /* Consumes all arguments.  */
462
 
  if (pinentry_parse_opts (argc, argv))
463
 
    {
464
 
      printf ("pinentry-w32 (pinentry) " VERSION "\n");
465
 
      exit (EXIT_SUCCESS);
466
 
    }
467
 
 
468
 
/*   debugfp = fopen ("pinentry.log", "w"); */
469
 
/*   if (!debugfp) */
470
 
/*     debugfp = stderr; */
471
 
 
472
 
  /* We need to load a function because that one is only available
473
 
     since W2000 but not in older NTs.  */
474
 
  handle = LoadLibrary ("user32.dll");
475
 
  if (handle)
476
 
    {
477
 
      void *foo;
478
 
      foo = GetProcAddress (handle, "LockSetForegroundWindow");
479
 
      if (foo)
480
 
        lock_set_foreground_window = foo;
481
 
      else
482
 
        CloseHandle (handle);
483
 
    }
484
 
 
485
 
  if (pinentry_loop ())
486
 
    return 1;
487
 
 
488
 
  return 0;
489
 
}