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

Contents of /trunk/Src/WinPT.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 337 - (show annotations)
Sun Nov 27 12:38:43 2011 UTC (13 years, 3 months ago) by twoaday
File size: 18121 byte(s)
2011-11-25  Timo Schulz  <twoaday@gmx.net>

        * WinPT.cpp (check_os_version): New. Separated
        function to check the OS verson.
        Removed emulate utf8 bug legacy code.
			

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26