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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 442 - (show annotations)
Sat Apr 14 14:23:34 2012 UTC (12 years, 10 months ago) by twoaday
File size: 26710 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26