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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 427 - (show annotations)
Sat Apr 7 11:50:43 2012 UTC (12 years, 10 months ago) by twoaday
File size: 26747 byte(s)
2012-04-07  Timo Schulz  <twoaday@gmx.net>

        * wptFileManager.cpp (fm_add_dir_files): Limited scope of
	local vars.
	* wptImageList.cpp (km_imagelist_load): Use
	ICON16 and a larger icon size.
	

1 /* wptGPG.cpp - GnuPG configuration
2 * Copyright (C) 2001-2009 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (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 GNU
14 * 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 <string.h>
22 #include <stdio.h>
23 #include <shlobj.h>
24 #include <ctype.h>
25 #include <io.h>
26 #include <time.h>
27
28 #include "wptGPG.h"
29 #include "wptGPGME.h"
30 #include "wptGPGCmds.h"
31 #include "wptTypes.h"
32 #include "wptNLS.h"
33 #include "wptRegistry.h"
34 #include "wptErrors.h"
35 #include "wptW32API.h"
36 #include "wptCrypto.h"
37
38 #define GPG_CONF "gpg.conf"
39 #define GPG_REG_EXE "gpgProgram" /* registry name for the binary. */
40 #define GPG_REG_HOME "HomeDir" /* registry name of the home dir. */
41
42 /* Context to monitor GPG file changes. */
43 struct gpg_monitor_s {
44 FILETIME last_access; /* last write access. */
45 FILETIME access;
46 char *object; /* name of the object. */
47 char *fpath_object; /* full path to the object. */
48 int modified; /* 1 = modified. */
49 };
50 typedef struct gpg_monitor_s *gpg_monitor_t;
51
52 static const char *gpg_objs[] = {"pubring.gpg", "secring.gpg", "trustdb.gpg"};
53 static gpg_monitor_s gpg_table[3];
54 static int gpg_table_count = DIM (gpg_table);
55
56 int idea_available = 0; /* if the IDEA extension is available. */
57
58
59 static int check_keyring (char ** r_path);
60
61
62 /* Return the application data folder of the current user. */
63 char*
64 multi_gnupg_path (int strict)
65 {
66 static char buf[MAX_PATH+64];
67
68 /* MSDN: buf must be at least MAX_PATH=256 bytes */
69 memset (buf, 0, sizeof (buf));
70 if (!SHGetSpecialFolderPath (HWND_DESKTOP, buf, CSIDL_APPDATA, TRUE)) {
71 log_debug ("multi_gnupg_path: SHGetSpecialFolderPath() failed with: %d\r\n",
72 (int)GetLastError ());
73 return NULL;
74 }
75 strcat (buf, "\\gnupg");
76 if (strict && access (buf, 00))
77 return NULL;
78 return m_strdup (buf);
79 }
80
81
82 /* Return the full path to the GPG home directory. First the 'HomeDir' entry
83 from the registry is used. Then the default $APPDATA\gnupg path. */
84 char*
85 get_gnupg_path (void)
86 {
87 char *path = get_reg_entry_gpg (GPG_REG_HOME);
88 if (path && dir_exist_check (path) == 0)
89 return path;
90 free_if_alloc (path);
91 return multi_gnupg_path (1);
92 }
93
94
95 /* Return the full path of the gpg config file.
96 A value of NULL indicates an error. */
97 char*
98 get_gnupg_cfgfile (void)
99 {
100 char *path = get_gnupg_path ();
101 if (!path)
102 return NULL;
103 char *optfile = make_filename (path, GPG_CONF, NULL);
104 free_if_alloc (path);
105
106 return optfile;
107 }
108
109
110 static char*
111 get_keyring_from_conf (const char *fname, int pub)
112 {
113 config_file_t opt;
114 conf_option_t e;
115 char *kring = NULL;
116
117 if (parse_config (fname, &opt))
118 return NULL;
119 if (pub)
120 e = conf_find_option (opt, "keyring");
121 else
122 e = conf_find_option (opt, "secret-keyring");
123 if (e != NULL)
124 kring = m_strdup (e->val);
125 release_config (opt);
126
127 return kring;
128 }
129
130
131 /* Return the full path of the keyring. If @pub is 1, the public
132 keyring is return, otherwise the secret keyring. */
133 char*
134 get_gnupg_keyring (int pub, int strict)
135 {
136 char *optfile;
137 char *path;
138 char *keyring;
139
140 path = get_gnupg_path ();
141 if (!path)
142 return NULL;
143 keyring = make_filename (path, pub? "pubring" : "secring", "gpg");
144 if (strict && !file_exist_check (keyring)) {
145 free_if_alloc (path);
146 return keyring;
147 }
148 else if (!strict) {
149 free_if_alloc (path);
150 return keyring;
151 }
152 if (file_exist_check (keyring) ||
153 (pub && get_file_size (keyring) == 0)) {
154 free_if_alloc (keyring);
155 optfile = make_filename (path, GPG_CONF, NULL);
156 keyring = get_keyring_from_conf (optfile, pub);
157 free_if_alloc (optfile);
158 }
159 free_if_alloc (path);
160
161 return keyring;
162 }
163
164
165 /* Return the full path (with the gpg exe name). First the registry is scanned
166 for the entry 'gpgProgram'. If it wasn't set, the default path is the
167 appended string 'gpg.exe' is used. */
168 char*
169 get_gnupg_prog (void)
170 {
171 char *path;
172 char *pgm;
173
174 pgm = get_reg_entry_gpg (GPG_REG_EXE);
175 if (pgm)
176 return pgm;
177 path = get_gnupg_path ();
178 if (!path)
179 return NULL;
180 pgm = make_filename (path, "gpg", "exe");
181 free_if_alloc (path);
182 return pgm;
183 }
184
185
186 /* Retrieve the first usable secret key from cache.
187 If no usable was found, @ret_no_useable is 1.
188 Return value: the keyid of the secret key. */
189 static char*
190 default_key_from_cache (int *ret_no_useable)
191 {
192 gpgme_key_t key, pk;
193 gpg_keycache_t sec, pub;
194 const char *s;
195 char *keyid = NULL;
196
197 sec = keycache_get_ctx (0);
198 pub = keycache_get_ctx (1);
199 gpg_keycache_rewind (sec);
200 while (!gpg_keycache_next_key (sec, 1, &key)) {
201 if (key_is_useable (key) && !get_pubkey (key->subkeys->keyid, &pk)) {
202 s = key->subkeys->keyid;
203 if (s)
204 keyid = m_strdup (s+8);
205 break;
206 }
207 }
208 if (!keyid)
209 *ret_no_useable = 1;
210 return keyid;
211 }
212
213
214 /* Load the gpg.conf and search for some options
215 and store the result in the global preference context.
216 Return value: 0 on success. */
217 int
218 gnupg_load_config (void)
219 {
220 config_file_t opt;
221 char *conf;
222 int rc = 0;
223
224 conf = get_gnupg_cfgfile ();
225 if (!conf)
226 return -1;
227 if (parse_config (conf, &opt)) {
228 free_if_alloc (conf);
229 return -1;
230 }
231 free_if_alloc (conf);
232 if (conf_find_option (opt, "ask-cert-level"))
233 reg_prefs.gpg.ask_cert_level = 1;
234 if (conf_find_option (opt, "ask-cert-expire"))
235 reg_prefs.gpg.ask_cert_expire = 1;
236 /* The 'textmode' option for GPG is useful for text files
237 but it breaks the output of any binary data. Thus we return
238 a warning here to inform the user that binary output is broken. */
239 if (conf_find_option (opt, "textmode"))
240 rc = -2;
241 release_config (opt);
242
243 return rc;
244 }
245
246
247 /* handle the case the user added a '!' to force a subkey. */
248 static char*
249 extract_keyid (const char *val)
250 {
251 size_t len = strlen (val);
252
253 if (len > 1 && val[len-1] == '!')
254 return substr (val, 0, len-1);
255 return m_strdup (val);
256 }
257
258
259 /* Return the default key.
260 This can be either a substring or a key ID. */
261 char*
262 get_gnupg_default_key (void)
263 {
264 config_file_t opt = NULL;
265 conf_option_t e;
266 char *keyid = NULL, *optfile = NULL;
267 int no_usable=0;
268
269 optfile = get_gnupg_cfgfile ();
270 if (!optfile)
271 return default_key_from_cache (&no_usable);
272 if (parse_config (optfile, &opt)) {
273 free_if_alloc (optfile);
274 return default_key_from_cache (&no_usable);
275 }
276 /* First we search for config entries which specify a default key. */
277 e = conf_find_option (opt, "default-key");
278 if (!e)
279 e = conf_find_option (opt, "local-user");
280 if (e)
281 keyid = extract_keyid (e->val);
282
283 free_if_alloc (optfile);
284 release_config (opt);
285
286 /* If no entry in the config has been found, we get a key
287 from the key cache. */
288 if (!keyid)
289 keyid = default_key_from_cache (&no_usable);
290 return keyid;
291 }
292
293
294 /* Check if GPG4WIN is available and if so, use the
295 install path to figure out where the gpg.exe is. */
296 char*
297 check_for_gpg4win (void)
298 {
299 return get_reg_entry_gpg4win ("gpg.exe");
300 }
301
302
303 /* Check if the gpg application (exe file) is available. */
304 int
305 check_gnupg_prog (void)
306 {
307 char *gpgexe = NULL;
308 int rc = 0;
309
310 gpgexe = get_gnupg_prog ();
311 if (!gpgexe || file_exist_check (gpgexe)) {
312 free_if_alloc (gpgexe);
313 gpgexe = check_for_gpg4win ();
314 if (!gpgexe || file_exist_check (gpgexe))
315 rc = WPTERR_GPG_EXEFILE;
316 else
317 set_reg_entry_gpg (GPG_REG_EXE, gpgexe);
318 }
319 free_if_alloc (gpgexe);
320 return rc;
321 }
322
323
324 static int
325 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
326 {
327 char *p;
328 char *tmp = m_strdup(buf);
329
330 int pos = 0;
331 while ((p = strsep(&tmp, ".")) != NULL) {
332 switch (++pos) {
333 case 1: *major = atoi (p); break;
334 case 2: *minor = atoi (p); break;
335 case 3: *patch = atoi (p); break;
336 }
337 }
338 delete[] tmp;
339 if (pos != 3)
340 return -1;
341 return 0;
342 }
343
344
345 /* Check if the gnupg engine fullfills the minimum requirement
346 version given in @r_major.@r_minor.@r_patch. On success these
347 variables contain the GPG version which is installed. */
348 int
349 check_gnupg_engine (const char *need_gpg_ver,
350 int *r_major, int *r_minor, int *r_patch)
351 {
352 gpgme_engine_info_t inf;
353 char *eng = NULL;
354 int major=0, minor=0, patch=0;
355 int need_major = 0, need_minor = 0, need_patch = 0;
356 int rc = 1;
357
358 /* Convert the needed GPG version to the integer format. */
359 if (parse_version_nr (need_gpg_ver,
360 &need_major, &need_minor, &need_patch))
361 return 1;
362
363 if (gpgme_get_engine_info (&inf))
364 return -1;
365
366 /* We need to exec GPG again to find out if IDEA is available. */
367 if (gpg_get_version (&eng))
368 return -1;
369 if (strstr (eng, "IDEA"))
370 idea_available = 1;
371 safe_free (eng);
372
373 if (parse_version_nr (inf->version, &major, &minor, &patch))
374 return 1;
375
376 if (major > need_major)
377 rc = 0;
378 else if (major == need_major && minor > need_minor)
379 rc = 0;
380 else if (major == need_major && minor == need_minor &&
381 patch >= need_patch)
382 rc = 0;
383
384 /* Return the current GPG version. */
385 *r_major = major;
386 *r_minor = minor;
387 *r_patch = patch;
388 return rc;
389 }
390
391
392 /* Count the keyring entries in the gpg.conf file.
393 Return value: 0 on success. */
394 static int
395 cfgfile_count_keyrings (const char *fname, int *r_secrings, int *r_pubrings)
396 {
397 config_file_t opt;
398 conf_option_t e;
399
400 *r_secrings = 0;
401 *r_pubrings = 0;
402
403 if (parse_config (fname, &opt))
404 return WPTERR_FILE_OPEN;
405 for (e = opt->list; e; e = e->next) {
406 if (!strcmp (e->name, "secret-keyring")) {
407 if (!file_exist_check (e->val))
408 r_secrings[0]++;
409 }
410 else if (!strcmp (e->name, "keyring")) {
411 if (!file_exist_check (e->val))
412 r_pubrings[0]++;
413 }
414 }
415 release_config (opt);
416 return 0;
417 }
418
419
420 /* Usually GPG creates the pubring.gpg, secring.gpg on
421 the first start, but to make sure they always exist
422 create them empty if needed. */
423 static void
424 create_empty_keyring (int _pub)
425 {
426 char *name = get_gnupg_keyring (_pub, 0);
427 if (name && file_exist_check (name) != 0) {
428 FILE *fp = fopen (name, "ab");
429 if (fp != NULL)
430 fclose (fp);
431 }
432 free_if_alloc (name);
433 }
434
435
436 /* Check if both keyrings are located in the gnupg home directory. */
437 int
438 gnupg_access_files (void)
439 {
440 int rc = 0;
441 int pubring_ok = 0, secring_ok = 0;
442 int secrings = 0, pubrings = 0;
443 char *optfile;
444
445 create_empty_keyring (1);
446 if (gnupg_access_keyring (1))
447 rc = WPTERR_GPG_KEYRINGS;
448 else
449 pubring_ok = 1;
450
451 create_empty_keyring (0);
452 if (gnupg_access_keyring (0))
453 rc = WPTERR_GPG_KEYRINGS;
454 else
455 secring_ok = 1;
456
457 if (!pubring_ok || !secring_ok) {
458 optfile = get_gnupg_cfgfile ();
459 if (!optfile)
460 return WPTERR_GPG_KEYRINGS;
461 rc = file_exist_check (optfile);
462 if (!rc && get_file_size (optfile) > 0) {
463 rc = cfgfile_count_keyrings (optfile, &secrings, &pubrings);
464 if (!rc && secrings > 0 && pubrings > 0) {
465 free_if_alloc (optfile);
466 return 0; /* found two keyrings in the option file */
467 }
468 else if ((!rc && pubrings && secring_ok)
469 || (!rc && secrings && pubring_ok)) {
470 free_if_alloc (optfile);
471 return 0; /* found one keyring and one entry in the options file */
472 }
473 else
474 return WPTERR_GPG_OPT_KEYRINGS;
475 }
476 free_if_alloc (optfile);
477 rc = WPTERR_GPG_KEYRINGS;
478 }
479 return rc;
480 }
481
482
483
484 /* Return the contents of the options file as a char buf. */
485 char*
486 get_gnupg_config (void)
487 {
488 FILE *fp;
489 char *p = NULL, *optfile;
490 int fsize;
491
492 optfile = get_gnupg_cfgfile ();
493 if (!optfile)
494 return NULL;
495 fsize = get_file_size (optfile);
496 if (fsize < 1 || fsize > 100000)
497 goto leave; /* too large or does not exist */
498
499 fp = fopen (optfile, "rb");
500 if (!fp)
501 goto leave;
502 p = new char[fsize+1];
503 if (!p)
504 BUG (NULL);
505 fread (p, 1, fsize, fp);
506 fclose (fp);
507 p[fsize] = '\0';
508
509 leave:
510 free_if_alloc (optfile);
511 return p;
512 }
513
514
515 /* Set the default key in the gpg.conf.
516 If @key is NULL, the entry will be deleted. */
517 int
518 set_gnupg_default_key (const char *key)
519 {
520 config_file_t opt;
521 conf_option_t e;
522 char *optfile = NULL;
523 int rc = 0;
524
525 optfile = get_gnupg_cfgfile ();
526 if (!optfile)
527 return WPTERR_FILE_OPEN;
528 rc = parse_config (optfile, &opt);
529 if (rc) {
530 free_if_alloc (optfile);
531 return WPTERR_GENERAL;
532 }
533 e = conf_find_option (opt, "default-key");
534 if (e && !key)
535 e->used = 0;
536 else if (e) {
537 free_if_alloc (e->val);
538 e->val = m_strdup (key);
539 e->used = 1;
540 }
541 else if (key)
542 conf_add_entry (opt, ENTRY_MULTI, "default-key", key);
543 rc = commit_config (optfile, opt);
544
545 free_if_alloc (optfile);
546 release_config (opt);
547 return rc;
548 }
549
550
551 /* Set the contents of the options file. */
552 int
553 set_gnupg_options (const char *buf, size_t buflen)
554 {
555 FILE *fp;
556 char *optfile;
557
558 optfile = get_gnupg_cfgfile ();
559 if (!optfile)
560 return WPTERR_FILE_CREAT;
561
562 fp = fopen (optfile, "wb");
563 if (!fp) {
564 free_if_alloc (optfile);
565 return WPTERR_FILE_CREAT;
566 }
567 fwrite (buf, 1, buflen, fp);
568 fclose (fp);
569 free_if_alloc (optfile);
570 return 0;
571 }
572
573
574 /* Check if the parameter for the option @buf is an existing file name.
575 Return value: 0 on success. */
576 static int
577 check_arg_file_exist (const char *buf)
578 {
579 const char *s = "load-extension ";
580
581 /* XXX: this is a bit of a kludge because we just
582 detect errors for 'load-extension'. */
583 if (!strncmp (buf, s, strlen (s)))
584 buf += strlen (s);
585 else
586 return 0;
587 return file_exist_check (buf);
588 }
589
590
591 /* Check if the line contains a valid GPG argument. */
592 static int
593 check_line (const char *buf)
594 {
595 int j, len;
596 int rc = 0;
597
598 if (*buf == '#' || *buf == '\r' || *buf == '\n')
599 return 1;
600 for (j = 0; valid_gpg_args[j]; j++) {
601 len = strlen (valid_gpg_args[j]);
602 if (!strncmp (valid_gpg_args[j], buf, len))
603 rc = 1;
604 }
605 return rc;
606 }
607
608
609 int
610 check_gnupg_options (const char *buf, int showerr)
611 {
612 char line[1024];
613 int nbytes = 0, lineno=0;
614 unsigned j;
615
616 for (j = 0; j < strlen (buf) && j < DIM (line); j++) {
617 line[nbytes++] = buf[j];
618 if (buf[j] == '\n' || j == (strlen (buf) - 1)) {
619 line[nbytes] = '\0';
620 lineno++;
621 if (!check_line (line)) {
622 if (showerr)
623 log_box ("GPG Config File", MB_ERR,
624 "gpg.conf:%d: invalid keyword '%s'",
625 lineno, line);
626 return 1;
627 }
628 if (check_arg_file_exist (line))
629 return WPTERR_FILE_EXIST;
630 nbytes = 0;
631 }
632 }
633 return 0;
634 }
635
636
637 /* Store the last access of the file inside the watcher @ctx. */
638 static int
639 get_last_gnupg_access (gpg_monitor_t ctx)
640 {
641 HANDLE fd = CreateFile (ctx->fpath_object, GENERIC_READ, FILE_SHARE_READ,
642 NULL, OPEN_EXISTING, 0, NULL);
643 if (fd == INVALID_HANDLE_VALUE)
644 return WPTERR_FILE_OPEN;
645 GetFileTime (fd, NULL, NULL, &ctx->access);
646 CloseHandle (fd);
647 return 0;
648 }
649
650
651 /* Check if the file inside watcher @ctx was modified. */
652 static void
653 check_last_gnupg_access (gpg_monitor_t ctx)
654 {
655 ctx->modified = 0;
656
657 if (ctx->last_access.dwHighDateTime != ctx->access.dwHighDateTime &&
658 ctx->last_access.dwLowDateTime != ctx->access.dwLowDateTime)
659 ctx->modified = 1;
660
661 if (ctx->last_access.dwLowDateTime == 0)
662 ctx->modified = 0;
663
664 ctx->last_access.dwLowDateTime = ctx->access.dwLowDateTime;
665 ctx->last_access.dwHighDateTime = ctx->access.dwHighDateTime;
666 }
667
668
669 /* Init GPG monitor table for all monitored files. */
670 void
671 init_gnupg_table (void)
672 {
673 char *path = get_gnupg_path ();
674 for (int j = 0; j < gpg_table_count; j++) {
675 gpg_table[j].object = m_strdup (gpg_objs[j]);
676 gpg_table[j].fpath_object = make_filename (path, gpg_objs[j], NULL);
677 memset (&gpg_table[j].access, 0, sizeof (FILETIME));
678 memset (&gpg_table[j].last_access, 0, sizeof (FILETIME));
679 gpg_table[j].modified = 0;
680 }
681 free_if_alloc (path);
682 }
683
684
685 /* Release the GPG monitor table. */
686 void
687 free_gnupg_table (void)
688 {
689 for (int j = 0; j < gpg_table_count; j++) {
690 free_if_alloc (gpg_table[j].object);
691 free_if_alloc (gpg_table[j].fpath_object);
692 }
693 }
694
695
696 /* Return the amount of files modified since the last call. */
697 int
698 keyring_check_last_access (void)
699 {
700 int nfiles = 0;
701 for (int pos = 0; pos < gpg_table_count; pos++) {
702 get_last_gnupg_access (&gpg_table[pos]);
703 check_last_gnupg_access (&gpg_table[pos]);
704 if (gpg_table[pos].modified)
705 nfiles++;
706 }
707
708 return nfiles;
709 }
710
711
712 const char*
713 gnupg_check_file_ext (const char *fname, int *r_type)
714 {
715 char file_ext[5];
716
717 if (r_type)
718 *r_type = PGP_NONE;
719 if (!strchr (fname, '.' ))
720 return "UNKNOWN";
721
722 strncpy (file_ext, fname + strlen (fname) - 4, 4);
723 file_ext[4] = '\0';
724 if (!stricmp (file_ext, ".asc"))
725 return "ARMORED";
726 else if (!stricmp (file_ext, ".sig")) {
727 if (r_type)
728 *r_type = PGP_SIG;
729 return "SIGNED";
730 }
731 else if (!stricmp (file_ext, ".gpg") ||
732 !stricmp (file_ext, ".pgp")) {
733 if (r_type)
734 *r_type = PGP_MESSAGE;
735 return "ENCRYPTED";
736 }
737 return "UNKNOWN";
738 }
739
740
741 /* Check if the device where file @fname is stored on, is write-protected. */
742 static int
743 check_file_access (const char *fname, int mode)
744 {
745 if (!mode)
746 mode = FILE_SHARE_WRITE;
747 HANDLE hd = CreateFile (fname, GENERIC_WRITE, mode,
748 NULL, OPEN_EXISTING, 0, NULL);
749 if (hd == INVALID_HANDLE_VALUE)
750 return -1;
751 CloseHandle (hd);
752 return 0;
753 }
754
755
756 /* Check the device where the file @fname is stored on, is either
757 write-protected or if the file is already opened by another process
758 exclusively. And as a result, we cannot use the file for output. */
759 int
760 gpg_check_file_permissions (const char *fname, int mode)
761 {
762 int api_mode;
763
764 switch (mode) {
765 case 0: api_mode = FILE_SHARE_READ; break;
766 case 1: api_mode = FILE_SHARE_WRITE; break;
767 case 2: api_mode = FILE_SHARE_WRITE|FILE_SHARE_READ; break;
768 default: api_mode = FILE_SHARE_READ; break;
769 }
770
771 return check_file_access (fname, api_mode);
772 }
773
774
775 /* Check the file permissions of the public keyring.
776 If @showmsg is 1 output a message in case of errors.
777 Return value: 1 if read-only attribute
778 2 if file is opened by another process exclusively. */
779 int
780 gpg_check_permissions (int showmsg)
781 {
782 char *p = NULL;
783 char *name = NULL;
784 int failed = 0, ans=0, attrs=0;
785
786 p = get_gnupg_path ();
787 if (p && check_keyring (&p)) {
788 name = make_filename (p, "pubring", "gpg");
789 if ((attrs=GetFileAttributes (name)) & FILE_ATTRIBUTE_READONLY) {
790 ans = msg_box (NULL,
791 _("The selected keyring has the read-only file\n"
792 "attribute. In this state you do not have write\n"
793 "access. Do you want to remove the attribute?"),
794 _("GPG Information"), MB_YESNO);
795 if (ans == IDYES) {
796 attrs &= ~FILE_ATTRIBUTE_READONLY;
797 if (!SetFileAttributes (name, attrs)) {
798 msg_box (NULL, _("Could not reset read-only state."),
799 _("GPG Error"), MB_ERR);
800 failed = 1;
801 }
802 }
803 else if (ans == IDNO) {
804 /* All commands with write access will be disabled. */
805 failed = 1;
806 }
807 }
808 if (gpg_check_file_permissions (name, 1)) {
809 if (showmsg)
810 msg_box (NULL,
811 _("You do not have file access to modify the contents of\n"
812 "one or both of the selected keyrings.\n"
813 "\n"
814 "The keyrings are in a read-only state which is propably\n"
815 "caused by another program which already opened the files.\n"),
816 _("GPG Warning"), MB_WARN);
817 failed = 2;
818 }
819 }
820 free_if_alloc (p);
821 free_if_alloc (name);
822 return failed;
823 }
824
825
826 /* Check the GPG home dir. First try to read the 'HomeDir' registry entry,
827 then check for $APPDATA\gnupg. Create the dir if it does not exists. */
828 int
829 gnupg_check_homedir (void)
830 {
831 char *homedir;
832 int val;
833 int rc = 0;
834
835 homedir = get_reg_entry_gpg (GPG_REG_HOME);
836 if (!homedir)
837 homedir = multi_gnupg_path (0);
838 if (homedir) {
839 if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
840 val = log_box (_("Preferences"), MB_YESNO,
841 _("%s does not exit.\n"
842 "Do you want to create this directory?"), homedir);
843 if (val == IDYES) {
844 if (!CreateDirectory (homedir, NULL))
845 rc = WPTERR_DIR_CREAT;
846 }
847 else
848 rc = WPTERR_DIR_OPEN;
849 }
850 free_if_alloc (homedir);
851 }
852 return rc;
853 }
854
855
856 int
857 gnupg_import_keypair (void)
858 {
859 const char *file;
860 gpgme_error_t err;
861 GPGME gpgme;
862 HWND hwnd = GetDesktopWindow ();
863
864 file = get_fileopen_dlg (hwnd, _("Please choose your Key Pair"),
865 "GPG Key File (*.gpg)\0*.gpg\0"
866 "GPG Armored Key File (*.asc)\0*.asc\0\0",
867 NULL);
868 if (file == NULL)
869 return WPTERR_FILE_OPEN;
870 err = gpgme.importFromFile (file);
871 if (err)
872 msg_box (hwnd, gpgme_strerror (err), _("WinPT Error"), MB_ERR);
873 else
874 msg_box (hwnd, _("Key pair successfully imported."), "WinPT", MB_OK);
875 return 0;
876 }
877
878 int
879 gnupg_copy_keyrings (void)
880 {
881 const char *pring, *sring;
882 char *file = NULL, *path;
883 int id, rc = 0;
884 HWND hwnd;
885
886 path = get_gnupg_path ();
887 if (!path)
888 return WPTERR_GENERAL;
889 hwnd = GetDesktopWindow ();
890
891 pring = get_fileopen_dlg (hwnd, _("Please choose your Public Keyring"),
892 "GPG Keyrings (*.gpg)\0*.gpg\0\0", NULL);
893 if (!pring) {
894 msg_box (hwnd, _("No keyring was chosen. Exit."),
895 _("WinPT Error"), MB_ERR);
896 free_if_alloc (path);
897 return WPTERR_GENERAL;
898 }
899 file = make_filename (path, "pubring", "gpg");
900 if (file_exist_check (file) == 0) {
901 id = msg_box (hwnd, _("Overwrite old public keyring?"),
902 "WinPT", MB_INFO|MB_YESNO);
903 if (id == IDNO)
904 goto fail;
905 }
906 if (!CopyFile (pring, file, FALSE)) {
907 msg_box (hwnd, _("Could not copy public keyring."),
908 _("WinPT Error"), MB_ERR);
909 rc = WPTERR_FILE_READ;
910 goto fail;
911 }
912 free_if_alloc (file);
913
914 sring = get_fileopen_dlg (hwnd, _("Please choose your Secret Keyring"),
915 "GPG Keyrings (*.gpg)\0*.gpg\0\0", NULL);
916 if (!sring) {
917 msg_box (NULL, _("No keyring was chosen. Exit."),
918 _("WinPT Error"), MB_ERR);
919 return WPTERR_GENERAL;
920 }
921 file = make_filename (path, "secring", "gpg");
922 if (file_exist_check (file) == 0) {
923 id = msg_box (hwnd, _("Overwrite old secret keyring?"),
924 "WinPT", MB_INFO|MB_YESNO);
925 if (id == IDNO)
926 goto fail;
927 }
928 if (!CopyFile (sring, file, FALSE)) {
929 msg_box (NULL, _("Could not copy secret keyring."), _("WinPT Error"), MB_ERR);
930 rc = WPTERR_FILE_READ;
931 }
932
933 fail:
934 free_if_alloc (file);
935 free_if_alloc (path);
936 return rc;
937 }
938
939
940 /* Backup the gpg.conf file. */
941 void
942 gnupg_backup_options (void)
943 {
944 char bak[MAX_PATH + 32];
945
946 char *cfgfile = get_gnupg_cfgfile ();
947 if (!cfgfile)
948 return;
949 _snprintf (bak, DIM (bak)-1, "%s.bak", cfgfile);
950 CopyFile (cfgfile, bak, FALSE);
951 free_if_alloc (cfgfile);
952 }
953
954
955 static int
956 backup_one_file (const char *srcpath, const char *srcn,
957 const char *dstpath, const char *dstn)
958 {
959 char *src, *dst;
960 BOOL rc;
961
962 src = make_filename (srcpath, srcn, "gpg");
963 dst = make_filename (dstpath, dstn, "gpg");
964 rc = CopyFile (src, dst, FALSE);
965 free_if_alloc (src);
966 free_if_alloc (dst);
967 if (!rc) {
968 log_box (_("Backup"), MB_ERR, _("Backup keyring \"%s\" failed"), srcn);
969 return WPTERR_GENERAL;
970 }
971 return 0;
972 }
973
974
975 /* Figure out first public keyring which is not empty.
976 Return value: 1 on success. */
977 static int
978 check_keyring (char **r_path)
979 {
980 char *p;
981 char *opt;
982 char *name;
983
984 if (!*r_path)
985 return 0;
986 p = make_filename (*r_path, "pubring", "gpg");
987 if (!p || get_file_size (p) < 1)
988 return 0;
989
990 opt = get_gnupg_cfgfile ();
991 if (!opt)
992 BUG (0);
993 name = get_keyring_from_conf (opt, 1);
994 free_if_alloc (opt);
995 free_if_alloc (p);
996 if (!name)
997 return 0;
998 p = strrchr (name, '\\');
999 if (!p) {
1000 free_if_alloc (name);
1001 return 0;
1002 }
1003 free_if_alloc (*r_path);
1004 *r_path = new char [strlen (name)+1];
1005 memset (*r_path, 0, strlen (name));
1006 strncpy (*r_path, name, (p-name));
1007 free_if_alloc (name);
1008 return 1;
1009 }
1010
1011
1012 /* Return a temp name based on the day of the week. */
1013 static char*
1014 get_backup_name (const char *templ)
1015 {
1016 struct tm *tm;
1017 const char *fmt;
1018 char *p;
1019 time_t t;
1020
1021 t = time (NULL);
1022 tm = localtime (&t);
1023 fmt = "%s-%d";
1024 p = new char [strlen (templ) + strlen (fmt) + 8 + 1];
1025 if (!p)
1026 BUG (0);
1027 sprintf (p, fmt, templ, tm->tm_wday % 3);
1028 return p;
1029 }
1030
1031
1032 /* Make backups of all keyrings. The public key ring is rotated like
1033 this pubring-%d.gpg.
1034 If @auto_backup is false, no action is performed.
1035 @include_secr indicated if the backup includes the secret keyring. */
1036 void
1037 gnupg_backup_keyrings (int auto_backup, int backup_mode, int include_secr)
1038 {
1039 char *srcpath, *dstpath;
1040 char *name;
1041 int rc;
1042
1043 if (!auto_backup)
1044 return;
1045 srcpath = get_gnupg_path ();
1046 check_keyring (&srcpath);
1047 if (backup_mode == 1) {
1048 /* If the backup mode uses the home directory the source
1049 and destination folder will be the same. */
1050 dstpath = get_gnupg_path ();
1051 check_keyring (&dstpath);
1052 }
1053 else if (backup_mode == 2) {
1054 char *tmpfile;
1055 FILE *fp;
1056
1057 dstpath = m_strdup (reg_prefs.backup.path);
1058 tmpfile = make_filename (reg_prefs.backup.path, "test", "tmp");
1059 fp = fopen (tmpfile, "wb");
1060 if (!fp)
1061 rc = log_box (_("Backup"), MB_WARN|MB_RETRYCANCEL,
1062 _("The backup drive '%s' does not seems to be accessable.\n"
1063 "Please insert/check the drive to continue."), dstpath);
1064 else {
1065 rc = 0;
1066 fclose (fp);
1067 DeleteFile (tmpfile);
1068 }
1069 free_if_alloc (tmpfile);
1070 if (!fp || rc == IDCANCEL) {
1071 free_if_alloc (dstpath);
1072 free_if_alloc (srcpath);
1073 return;
1074 }
1075 }
1076 else {
1077 log_box (_("Backup"), MB_ERR, _("Invalid backup mode %d"), backup_mode);
1078 free_if_alloc (srcpath);
1079 return;
1080 }
1081 name = get_backup_name ("pubring-bak");
1082 rc = backup_one_file (srcpath, "pubring", dstpath, name);
1083 if (!rc && include_secr)
1084 rc = backup_one_file (srcpath, "secring", dstpath, "secring-bak");
1085 free_if_alloc (name);
1086 free_if_alloc (srcpath);
1087 free_if_alloc (dstpath);
1088 }
1089
1090
1091 /* check that the requested GPG keyring exist and.
1092 Return value: 0 for success. */
1093 int
1094 gnupg_access_keyring (int _pub)
1095 {
1096 int rc = 0;
1097 char *name = get_gnupg_keyring (_pub, 1);
1098 if (!name || file_exist_check (name))
1099 rc = -1;
1100 free_if_alloc (name);
1101 return rc;
1102 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26