/[winpt]/trunk/Src/WinPT.cpp
ViewVC logotype

Contents of /trunk/Src/WinPT.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 333 - (show annotations)
Tue Oct 13 10:51:21 2009 UTC (15 years, 4 months ago) by twoaday
File size: 18234 byte(s)


1 /* WinPT.cpp - Windows Privacy Tray (WinPT)
2 * Copyright (C) 2000-2009 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <windows.h>
21 #include <shlobj.h>
22
23 #include "resource.h"
24 #include "wptTypes.h"
25 #include "wptW32API.h"
26 #include "wptVersion.h"
27 #include "wptErrors.h"
28 #include "wptGPG.h"
29 #include "wptRegistry.h"
30 #include "wptCommonCtl.h"
31 #include "wptDlgs.h"
32 #include "wptNLS.h"
33 #include "wptKeyserver.h"
34 #include "wptCard.h"
35 #include "wptFileManager.h"
36 #include "wptContext.h"
37 #include "wptCardEdit.h"
38 #include "wptCrypto.h"
39 #include "wptUTF8.h"
40
41 void remove_crit_file_attrs (const char *fname, int force);
42
43 /* Global variables. */
44 HINSTANCE glob_hinst; /* global instance for the dialogs */
45 HWND glob_hwnd; /* global window handle for the dialogs */
46 int scard_support = 0;
47 int debug = 0;
48 int gpg_read_only = 0;
49 int emulate_utf8_bug = 0;
50 char gpgver[3];
51 /* End */
52
53
54 /* Load the key cache and rebuild the signature cache. */
55 int
56 update_keycache (HWND hwnd)
57 {
58 int err;
59 refresh_cache_s rcs;
60
61 /* no need to rebuild the sig cache each time. */
62 memset (&rcs, 0, sizeof (rcs));
63 rcs.kring_update = 1;
64 err = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_KEYCACHE, hwnd,
65 keycache_dlg_proc, (LPARAM)&rcs);
66 if (err) {
67 char *cfgf = get_gnupg_config ();
68 if (cfgf && check_gnupg_options (cfgf, 0) == WPTERR_FILE_EXIST)
69 msg_box (GetDesktopWindow (),
70 _("The gpg.conf contains at least one argument which points to a non-existing file."), "WinPT", MB_ERR);
71 free_if_alloc (cfgf);
72 return -1;
73 }
74 return 0;
75 }
76
77
78 /* Set GPGME debug mode. If @val is 0, the debug mode is disabled. */
79 void
80 gpg_set_debug_mode (int val)
81 {
82 static char buf[MAX_PATH+1];
83 char tmp[128];
84
85 /* XXX: no gpgme.dbg is created. */
86 if (val > 0) {
87 GetTempPath (DIM (tmp)-1, tmp);
88 _snprintf (buf, DIM (buf)-1, "GPGME_DEBUG=5:%sgpgme.dbg", tmp);
89 putenv (buf);
90 }
91 else
92 putenv ("GPGME_DEBUG=");
93 }
94
95
96 /* Return true if the GPG environment is useable. */
97 static bool
98 gpg_prefs_ok (void)
99 {
100 char *p = get_reg_entry_gpg4win ("gpg.exe");
101 if (!p || file_exist_check (p) != 0) {
102 free_if_alloc (p);
103 p = get_reg_entry_gpg ("gpgProgram");
104 if (!p || file_exist_check (p) != 0) {
105 free_if_alloc (p);
106 log_debug ("gpg_prefs_ok: could not locate gpg.exe");
107 return false;
108 }
109 }
110 free_if_alloc (p);
111 p = get_reg_entry_gpg4win (NULL);
112 if (!p || dir_exist_check (p) != 0) {
113 free_if_alloc (p);
114 p = get_reg_entry_gpg ("HomeDir");
115 if (!p || dir_exist_check (p) != 0) {
116 free_if_alloc (p);
117 log_debug ("gpg_prefs_ok: could not determine home directory");
118 return false;
119 }
120 }
121 free_if_alloc (p);
122 return true;
123 }
124
125
126 /* Check gpg files if they are read-only and ask the user
127 if this should be corrected. */
128 static void
129 check_readonly_attr (const char *homedir)
130 {
131 const char *files[] = {"pubring.gpg", "secring.gpg", "trustdb.gpg", NULL};
132
133 for (int i=0; files[i] != NULL; i++) {
134 char *file = make_filename (homedir, files[i], NULL);
135 remove_crit_file_attrs (file, 0);
136 free_if_alloc (file);
137 }
138 }
139
140
141 /* Load the GPG environment. On the first start, some
142 checks are performed to find out in what state GPG is.
143 Return value: 0 everything OK.
144 >0 fatal error.
145 -1 public keyring is empty or does not exist. */
146 static int
147 load_gpg_env (void)
148 {
149 SECURITY_ATTRIBUTES sec_attr;
150 char *p;
151 char *pkr;
152 int err = 0;
153
154 p = get_reg_entry_gpg4win ("gpg.exe");
155 if (!p)
156 return (1);
157 if (file_exist_check (p)) {
158 free_if_alloc (p);
159 return (1);
160 }
161 free_if_alloc (p);
162
163 p = get_reg_entry_gpg ("HomeDir");
164 if (!p || dir_exist_check (p) != 0) {
165 free_if_alloc (p);
166 p = multi_gnupg_path (0);
167 }
168 if (p && dir_exist_check (p)) {
169 memset (&sec_attr, 0, sizeof (sec_attr));
170 sec_attr.nLength = sizeof (sec_attr);
171 if (!CreateDirectory (p, &sec_attr)) {
172 msg_box (GetDesktopWindow (),
173 _("Could not create GPG home directory"),
174 _("WinPT Error"), MB_ERR);
175 free_if_alloc (p);
176 return (2);
177 }
178 }
179 check_readonly_attr (p);
180 pkr = make_filename (p, "pubring", "gpg");
181 free_if_alloc (p);
182 if (get_file_size (pkr) == 0)
183 err = -1;
184 free_if_alloc (pkr);
185 return err;
186 }
187
188
189 /* check if the default key from the gpg.conf file is available in the
190 keyring. if not, bail out because encryption won't work properly then. */
191 static int
192 check_default_key (void)
193 {
194 gpgme_key_t key;
195 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
196 gpg_keycache_t kc;
197 char *defkey;
198
199 kc = keycache_get_ctx (0);
200 defkey = get_gnupg_default_key ();
201 if (defkey != NULL) {
202 err = gpg_keycache_find_key (kc, defkey, 0, &key);
203 if (err) {
204 free_if_alloc (defkey);
205 return -1;
206 }
207 }
208 else {
209 /* Actually this is just a warning but we still continue. */
210 msg_box (GetDesktopWindow (), _("No useable secret key found."),
211 _("WinPT Warning"), MB_WARN);
212 return 0;
213 }
214
215 /* Because the secret key listing has no information
216 about the validity/status, we need to check the public key. */
217 kc = keycache_get_ctx (1);
218 if (!gpg_keycache_find_key (kc, defkey, 0, &key) &&
219 (key->revoked || key->expired)) {
220 msg_box (GetDesktopWindow (), _("Default secret key is unuseable"),
221 _("WinPT Warning"), MB_ERR);
222 free_if_alloc (defkey);
223 return -1;
224 }
225 free_if_alloc (defkey);
226 return 0;
227 }
228
229
230 /* Check that the underlying crypto engine fullfills the minimal
231 requirements so all commands work properly. */
232 static bool
233 check_crypto_engine (void)
234 {
235 int ma = 0, mi = 0, pa = 0;
236 int rc;
237
238 rc = check_gnupg_engine (NEED_GPG_VERSION, &ma, &mi, &pa);
239 if (rc == -1) {
240 msg_box (GetDesktopWindow (), _("Could not read GnuPG version."),
241 _("WinPT Error"), MB_ERR);
242 return false;
243 }
244 else if (rc) {
245 log_box (_("WinPT Error"), MB_ERR,
246 _("A newer GPG version is needed.\n"
247 "Current GPG version %d.%d.%d, required "NEED_GPG_VERSION),
248 ma, mi, pa);
249 return false;
250 }
251
252 // TODO: smart card support needs to be revamped
253 // and adjusted according to newer OpenPGP cards.
254 /*
255 if ((ma > 1 || pa >= 4) && pcsc_available ())
256 scard_support = 1;
257 */
258 scard_support = 0;
259
260 gpgver[0] = ma;
261 gpgver[1] = mi;
262 gpgver[2] = pa;
263 return true;
264 }
265
266
267
268 /* Check if both keyrings are empty. This indicates that
269 WinPT should offer to generate a key pair. */
270 static bool
271 check_for_empty_keyrings (bool pub_only)
272 {
273 char *p;
274 int n;
275
276 n=0;
277 p = get_gnupg_keyring (1, 0);
278 if (file_exist_check (p) == 0 && get_file_size (p) == 0)
279 n++;
280 free_if_alloc (p);
281 if (pub_only)
282 return n == 1? true : false;
283 p = get_gnupg_keyring (0, 0);
284 if (file_exist_check (p) == 0 && get_file_size (p) == 0)
285 n++;
286 free_if_alloc (p);
287 return n==2? true : false;
288 }
289
290
291
292 /* Display info message that WinPT is now in debug mode. */
293 void
294 winpt_debug_msg (void)
295 {
296 char output[512];
297 char temp[MAX_PATH+1];
298
299 GetTempPath (DIM (temp) -1, temp);
300 _snprintf (output, DIM (output)-1,
301 "The GPGME output file is %sgpgme.dbg\n"
302 "The WinPT output file is %swinpt.log\n", temp, temp);
303 MessageBox (NULL, output, "WinPT now runs in DEBUG MODE", MB_INFO);
304 }
305
306
307 /* Search for insecure ElGamal keys and return the
308 number of founded keys. */
309 static int
310 count_insecure_elgkeys (void)
311 {
312 gpg_keycache_t pc;
313 gpgme_key_t key;
314 int n;
315
316 n=0;
317 pc = keycache_get_ctx (1);
318 while (!gpg_keycache_next_key (pc, 0, &key)) {
319 if (key->subkeys->pubkey_algo == GPGME_PK_ELG)
320 n++;
321 }
322 gpg_keycache_rewind (pc);
323 return n;
324 }
325
326
327 /* Main entry point. */
328 int WINAPI
329 WinMain (HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int showcmd)
330 {
331 WNDCLASS wc = {0, winpt_main_proc, 0, 0, hinst, 0, 0, 0, 0, PGM_NAME};
332 HACCEL accel_tab;
333 MSG msg;
334 HWND hwnd = NULL;
335 WORD ver[3], ptdver[4];
336 OSVERSIONINFOA osver;
337 const char *s;
338 int rc, ec, created = 0;
339 int first_start = 0, start_gpgprefs = 0;
340 int winpt_inst_found = 0;
341 int start_manager = 0;
342
343 memset (&osver, 0, sizeof (osver));
344 osver.dwOSVersionInfoSize = sizeof (osver);
345 if (!GetVersionEx (&osver)) {
346 MessageBox (NULL, _("Could not read the OS version."),
347 _("WinPT Error"), MB_ERR);
348 return 0;
349 }
350 /*
351 if (osver.dwMajorVersion < 5) {
352 MessageBox (NULL, _("WinPT requires Windows XP or higher."),
353 _("WinPT Warning"), MB_INFO);
354 return 0;
355 }*/
356
357 glob_hinst = hinst;
358 if (cmdline && stristr (cmdline, "--stop")) {
359 hwnd = FindWindow ("WinPT", "WinPT");
360 if (hwnd != NULL)
361 PostMessage (hwnd, WM_DESTROY, 0, 0);
362 return 0;
363 }
364
365 get_file_version ("winpt.exe", &ver[0], &ver[1], &ver[2], &ver[3]);
366 ec = get_file_version ("PTD.dll", &ptdver[0], &ptdver[1],
367 &ptdver[2], &ptdver[3]);
368
369 if (!ec && (ptdver[0] != ver[0] ||
370 ptdver[1] != ver[1] ||
371 ptdver[2] != ver[2])) {
372 log_box (_("WinPT Error"), MB_ERR,
373 _("The PTD.dll file has a different version than WinPT.exe\n"
374 "Please update the PTD.dll to version %d.%d.%d"),
375 ver[0], ver[1], ver[2]);
376 return 0;
377 }
378
379 if (gpg_md_selftest ()) {
380 msg_box (GetDesktopWindow (), _("Cryptographic selftest failed."),
381 _("WinPT Error"), MB_ERR);
382 return 0;
383 }
384
385 s = gpgme_check_version (NEED_GPGME_VERSION);
386 if (!s || !*s) {
387 msg_box (GetDesktopWindow (),
388 _("A newer GPGME version is needed; at least "NEED_GPGME_VERSION),
389 _("WinPT Error"), MB_ERR);
390 return 0;
391 }
392
393 CreateMutex (NULL, TRUE, PGM_NAME);
394 if (GetLastError () == ERROR_ALREADY_EXISTS)
395 winpt_inst_found = 1;
396
397 gettext_set_user_domain ();
398
399 regist_inst_gnupg (1);
400 regist_inst_winpt (1, &created);
401
402 if (!created) {
403 memset (&reg_prefs, 0, sizeof (reg_prefs));
404 get_reg_winpt_prefs (&reg_prefs);
405 reg_prefs.fm.progress = 0; /* TODO: fix the bug and enable it again */
406 if (gnupg_load_config () == -2)
407 msg_box (GetDesktopWindow (),
408 _("The gpg.conf file contains the 'textmode' option\n"
409 "which leads to broken binary output during decryption.\n"
410 "If this is on purpose, just continue otherwise the option should be disabled."),
411 _("WinPT Error"), MB_ERR);
412 }
413
414 if (is_gpg4win_installed ())
415 load_gpg_env (); /* TODO: check return code. */
416
417 rc = gnupg_check_homedir ();
418 if (rc) {
419 char *p;
420
421 log_box (_("WinPT Error"), MB_ERR,
422 _("GPG home directory is not set correctly.\n"
423 "Please check the GPG registry settings:\n%s."),
424 winpt_strerror (rc));
425 s = get_fileopen_dlg (GetActiveWindow (),
426 _("Select GPG Public Keyring"),
427 "GPG Keyrings (*.gpg)\0*.gpg\0\0",
428 NULL);
429 if (s != NULL && (p=strrchr (s, '\\'))) {
430 char *path = substr (s, 0, (p-s));
431
432 set_reg_entry_gpg ("HomeDir", path);
433 free_if_alloc (path);
434 }
435 else {
436 msg_box (GetDesktopWindow (),
437 _("GPG home directory could not be determined."),
438 _("WinPT Error"), MB_ERR);
439 goto start;
440 }
441 }
442
443 rc = check_gnupg_prog ();
444 if (rc) {
445 if (msg_box (GetDesktopWindow (),
446 _("Could not find the GPG binary (gpg.exe).\n"
447 "Do you want to start the GPG preferences to "
448 "correct this problem?"), _("WinPT Error"),
449 MB_INFO|MB_YESNO) == IDYES)
450 start_gpgprefs = 1;
451 else {
452 msg_box (GetDesktopWindow (),
453 winpt_strerror (rc), _("WinPT Error"), MB_ERR);
454 return 0;
455 }
456 }
457
458 rc = gnupg_access_files ();
459 if (!start_gpgprefs && rc) {
460 if (rc == WPTERR_GPG_KEYRINGS || rc == WPTERR_GPG_OPT_KEYRINGS) {
461 ec = msg_box (GetDesktopWindow (),
462 _("Could not access and/or find the public and secret keyring.\n"
463 "If this is an accident, quit the program and fix it.\n\n"
464 "Continue if you want WinPT to offer you more choices.\n"),
465 "WinPT", MB_INFO|MB_YESNO);
466 if (ec == IDYES)
467 first_start = 1;
468 }
469 if (!first_start) {
470 msg_box (GetDesktopWindow (), winpt_strerror (rc), _("WinPT Error"), MB_ERR);
471 return 0;
472 }
473 }
474 if (check_for_empty_keyrings (false))
475 first_start = 1;
476
477 if (!first_start) {
478 rc = gpg_check_permissions (1);
479 if (rc && rc == 2) /* 2 means read-only mode. */
480 gpg_read_only = 1;
481 else if (rc)
482 return 0;
483 }
484
485 init_gnupg_table ();
486
487 if (fm_parse_command_line (cmdline) > 0) {
488 free_gnupg_table ();
489 return 0;
490 }
491
492 rc = kserver_load_conf ();
493 if (rc)
494 msg_box (GetDesktopWindow (), winpt_strerror (rc),
495 _("Keyserver"), MB_ERR);
496
497 if (cmdline && (stristr (cmdline, "--keymanager")
498 || stristr (cmdline, "--cardmanager"))) {
499 /* If an instance of WinPT is running, just send the command
500 to open the key manager. Otherwise start a new instance. */
501 HWND tray = FindWindow ("WinPT", "WinPT");
502 if (stristr (cmdline, "keymanager"))
503 start_manager = ID_WINPT_KEY;
504 else
505 start_manager = ID_WINPT_CARD;
506 if (tray != NULL) {
507 PostMessage (tray, WM_COMMAND, start_manager, 0);
508 free_gnupg_table ();
509 return 0;
510 }
511 }
512
513 /* If we found another WinPT instance, just quit to avoid it
514 will be executed twice. */
515 if (winpt_inst_found) {
516 log_debug ("%s", "WinMain: WinPT is already running.");
517 free_gnupg_table ();
518 return 0;
519 }
520
521 if (cmdline && (stristr (cmdline, "--enable-debug") ||
522 stristr (cmdline, "--debug"))) {
523 gpg_set_debug_mode (1);
524 winpt_debug_msg ();
525 debug = 1;
526 }
527
528 wc.hIcon = LoadIcon (glob_hinst, MAKEINTRESOURCE (IDI_WINPT));
529 rc = RegisterClass (&wc);
530 if (rc == FALSE) {
531 msg_box (GetDesktopWindow (),
532 _("Could not register window class"),
533 _("WinPT Error"), MB_ERR);
534 free_gnupg_table ();
535 return 0;
536 }
537
538 hwnd = CreateWindow (PGM_NAME,
539 PGM_NAME,
540 0, 0, 0, 0, 0,
541 NULL,
542 NULL,
543 hinst,
544 NULL);
545 if (hwnd == NULL) {
546 msg_box (GetDesktopWindow (),
547 _("Could not create window"),
548 _("WinPT Error"), MB_ERR);
549 free_gnupg_table ();
550 return 0;
551 }
552 glob_hwnd = hwnd;
553 UpdateWindow (hwnd);
554
555 if (!first_start && !start_gpgprefs) {
556 gnupg_backup_options ();
557 if (!check_crypto_engine ()) {
558 DestroyWindow (hwnd);
559 free_gnupg_table ();
560 return 0;
561 }
562 }
563
564 if (start_gpgprefs) {
565 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_GPGPREFS, hwnd,
566 gpgprefs_dlg_proc, 0);
567 if (check_for_empty_keyrings (true))
568 first_start = 1; /* The public keyring is empty. */
569 }
570
571 if (first_start) {
572 struct genkey_s c;
573 int choice;
574 HWND h;
575 start:
576 h = GetDesktopWindow ();
577 if (!gpg_prefs_ok ())
578 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_GPGPREFS, h,
579 gpgprefs_dlg_proc, 0);
580 choice = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_FIRST, h,
581 first_run_dlg_proc, 0);
582 switch (choice) {
583 case SETUP_KEYGEN:
584 c.interactive = 1;
585 c.first_start = 1;
586 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_KEYWIZARD,
587 h, keygen_wizard_dlg_proc, (LPARAM)&c);
588 if (!rc)
589 goto start;
590 break;
591
592 case SETUP_IMPORT:
593 rc = gnupg_copy_keyrings ();
594 if (rc) {
595 msg_box (hwnd, winpt_strerror (rc), _("WinPT Error"), MB_ERR);
596 goto start;
597 }
598 break;
599
600 case SETUP_EXISTING:
601 rc = gnupg_import_keypair ();
602 if (rc) {
603 msg_box (hwnd, winpt_strerror (rc), _("WinPT Error"), MB_ERR);
604 goto start;
605 }
606 break;
607
608 case SETUP_CARDGEN:
609 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_CARD_KEYGEN,
610 h, card_keygen_dlg_proc, 0);
611 if (!rc)
612 goto start;
613 break;
614
615 case 0: /* Cancel/Abort. */
616 default:
617 DestroyWindow (hwnd);
618 free_gnupg_table ();
619 return 0;
620 }
621 update_keycache (hwnd);
622 if (!check_crypto_engine ()) {
623 DestroyWindow (hwnd);
624 free_gnupg_table ();
625 keycache_release (1);
626 return 0;
627 }
628 }
629 else {
630 gpg_keycache_t c;
631 if (update_keycache (hwnd)) {
632 DestroyWindow (hwnd);
633 free_gnupg_table ();
634 keycache_release (1);
635 return 0;
636 }
637 /* XXX: rewrite this part. */
638 c = keycache_get_ctx (1);
639 if (!gpg_keycache_get_size (c)) {
640 msg_box (hwnd, _("The keycache was not initialized or is empty.\n"
641 "Please check your GPG config (keyrings, pathes...)"),
642 _("WinPT Error"), MB_ERR);
643 ec = msg_box (GetDesktopWindow (),
644 _("It seems that GPG is not configured properly.\n"
645 "Do you want to start the GPG preferences dialog?"),
646 "WinPT", MB_INFO|MB_YESNO);
647 if (ec == IDYES) {
648 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_GPGPREFS, hwnd,
649 gpgprefs_dlg_proc, 0);
650 update_keycache (hwnd);
651 }
652 else {
653 DestroyWindow (hwnd);
654 free_gnupg_table ();
655 keycache_release (1);
656 return 0;
657 }
658 }
659 if (check_default_key ()) {
660 char *p = get_gnupg_default_key ();
661 log_box (_("WinPT Error"), MB_ERR,
662 _("Default key (from the GPG config file) could not be found or is unuseable.\n"
663 "The default key will be resetted and can be set later in the Key Manager again.\n\n"
664 "%s: secret key not found."), p? p : "?");
665 set_gnupg_default_key (NULL);
666 free_if_alloc (p);
667 }
668 if (count_insecure_elgkeys ())
669 DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_ELGWARN, glob_hwnd,
670 elgamal_warn_dlg_proc, 0);
671 }
672
673 if (strstr (cmdline, "--emulate-utf8-bug")) {
674 MessageBox (NULL, "Please use this mode only for resetting your passphrase to a non-utf8 form.",
675 "WinPT Warning", MB_WARN);
676 emulate_utf8_bug = 1;
677 }
678 if (start_manager)
679 PostMessage (hwnd, WM_COMMAND, start_manager, 0);
680
681 accel_tab = LoadAccelerators (glob_hinst, (LPCTSTR)IDR_WINPT_ACCELERATOR);
682 keyring_check_last_access (); /* init */
683 while (GetMessage (&msg, hwnd, 0, 0)) {
684 if (!TranslateAccelerator (msg.hwnd, accel_tab, &msg)) {
685 TranslateMessage (&msg);
686 DispatchMessage (&msg);
687 }
688 }
689
690 return 0;
691 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26