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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (show annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 26378 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 "wptGpgCmds.h"
30 #include "wptTypes.h"
31 #include "wptNLS.h"
32 #include "wptRegistry.h"
33 #include "wptErrors.h"
34 #include "wptW32API.h"
35 #include "wptCrypto.h"
36
37 #define GPG_CONF "gpg.conf"
38 #define GPG_REG_EXE "gpgProgram" /* registry name for the binary. */
39 #define GPG_REG_HOME "HomeDir" /* registry name of the home dir. */
40
41 /* Context to monitor GPG file changes. */
42 struct gpg_monitor_s {
43 FILETIME last_access; /* last write access. */
44 FILETIME access;
45 char *object; /* name of the object. */
46 char *fpath_object; /* full path to the object. */
47 int modified; /* 1 = modified. */
48 };
49 typedef struct gpg_monitor_s *gpg_monitor_t;
50
51 static const char *gpg_objs[] = {"pubring.gpg", "secring.gpg", "trustdb.gpg"};
52 static gpg_monitor_s gpg_table[3];
53 static int gpg_table_count = DIM (gpg_table);
54
55 int idea_available = 0; /* if the IDEA extension is available. */
56
57
58 static int check_keyring (char ** r_path);
59
60
61 /* Return the application data folder of the current user. */
62 char*
63 multi_gnupg_path (int strict)
64 {
65 static char buf[MAX_PATH+64];
66 BOOL ec;
67
68 /* MSDN: buf must be at least MAX_PATH=256 bytes */
69 memset (buf, 0, sizeof (buf));
70 /* XXX: ec should be NOERROR (MSDN) but NOERROR is defined as '0' !? */
71 ec = SHGetSpecialFolderPath (HWND_DESKTOP, buf, CSIDL_APPDATA, TRUE);
72 if (ec != 1) {
73 log_debug ("multi_gnupg_path: SHGetSpecialFolderPath() failed\r\n",
74 (int)GetLastError ());
75 return NULL;
76 }
77 strcat (buf, "\\gnupg");
78 if (strict && access (buf, 00))
79 return NULL;
80 return m_strdup (buf);
81 }
82
83
84 /* Return the full path to the GPG home directory. First the 'HomeDir' entry
85 from the registry is used. Then the default $APPDATA\gnupg path. */
86 char*
87 get_gnupg_path (void)
88 {
89 char *path;
90
91 path = get_reg_entry_gpg (GPG_REG_HOME);
92 if (path && dir_exist_check (path) == 0)
93 return path;
94 free_if_alloc (path);
95 return multi_gnupg_path (1);
96 }
97
98
99 /* Return the full path of the gpg config file.
100 A value of NULL indicates an error. */
101 char*
102 get_gnupg_cfgfile (void)
103 {
104 char *optfile;
105 char *path;
106
107 path = get_gnupg_path ();
108 if (!path)
109 return NULL;
110 optfile = make_filename (path, GPG_CONF, NULL);
111 free_if_alloc (path);
112
113 return optfile;
114 }
115
116
117 static char*
118 get_keyring_from_conf (const char *fname, int pub)
119 {
120 config_file_t opt;
121 conf_option_t e;
122 char *kring = NULL;
123 int rc;
124
125 rc = parse_config (fname, &opt);
126 if (rc)
127 return NULL;
128 if (pub)
129 e = conf_find_option (opt, "keyring");
130 else
131 e = conf_find_option (opt, "secret-keyring");
132 if (e != NULL)
133 kring = m_strdup (e->val);
134 release_config (opt);
135
136 return kring;
137 }
138
139
140 /* Return the full path of the keyring. If @pub is 1, the public
141 keyring is return, otherwise the secret keyring. */
142 char*
143 get_gnupg_keyring (int pub, int strict)
144 {
145 char *optfile;
146 char *path;
147 char *keyring;
148
149 path = get_gnupg_path ();
150 if (!path)
151 return NULL;
152 keyring = make_filename (path, pub? "pubring" : "secring", "gpg");
153 if (strict && !file_exist_check (keyring)) {
154 free_if_alloc (path);
155 return keyring;
156 }
157 else if (!strict) {
158 free_if_alloc (path);
159 return keyring;
160 }
161 if (file_exist_check (keyring) ||
162 (pub && get_file_size (keyring) == 0)) {
163 free_if_alloc (keyring);
164 optfile = make_filename (path, GPG_CONF, NULL);
165 keyring = get_keyring_from_conf (optfile, pub);
166 free_if_alloc (optfile);
167 }
168 free_if_alloc (path);
169
170 return keyring;
171 }
172
173
174 /* Return the full path (with the gpg exe name). First the registry is scanned
175 for the entry 'gpgProgram'. If it wasn't set, the default path is the
176 appended string 'gpg.exe' is used. */
177 char*
178 get_gnupg_prog (void)
179 {
180 char *path;
181 char *pgm;
182
183 pgm = get_reg_entry_gpg (GPG_REG_EXE);
184 if (pgm)
185 return pgm;
186 path = get_gnupg_path ();
187 if (!path)
188 return NULL;
189 pgm = make_filename (path, "gpg", "exe");
190 free_if_alloc (path);
191 return pgm;
192 }
193
194
195 /* Retrieve the first usable secret key from cache.
196 If no usable was found, @ret_no_useable is 1.
197 Return value: the keyid of the secret key. */
198 static char*
199 default_key_from_cache (int *ret_no_useable)
200 {
201 gpgme_key_t key, pk;
202 gpg_keycache_t sec, pub;
203 const char *s;
204 char *keyid = NULL;
205
206 sec = keycache_get_ctx (0);
207 pub = keycache_get_ctx (1);
208 gpg_keycache_rewind (sec);
209 while (!gpg_keycache_next_key (sec, 1, &key)) {
210 if (key_is_useable (key) && !get_pubkey (key->subkeys->keyid, &pk)) {
211 s = key->subkeys->keyid;
212 if (s)
213 keyid = m_strdup (s+8);
214 break;
215 }
216 }
217 if (!keyid)
218 *ret_no_useable = 1;
219 return keyid;
220 }
221
222
223 /* Load the gpg.conf and search for some options
224 and store the result in the global preference context.
225 Return value: 0 on success. */
226 int
227 gnupg_load_config (void)
228 {
229 config_file_t opt;
230 char *conf;
231 int rc = 0;
232
233 conf = get_gnupg_cfgfile ();
234 if (!conf)
235 return -1;
236 if (parse_config (conf, &opt)) {
237 free_if_alloc (conf);
238 return -1;
239 }
240 free_if_alloc (conf);
241 if (conf_find_option (opt, "ask-cert-level"))
242 reg_prefs.gpg.ask_cert_level = 1;
243 if (conf_find_option (opt, "ask-cert-expire"))
244 reg_prefs.gpg.ask_cert_expire = 1;
245 /* The 'textmode' option for GPG is useful for text files
246 but it breaks the output of any binary data. Thus we return
247 a warning here to inform the user that binary output is broken. */
248 if (conf_find_option (opt, "textmode"))
249 rc = -2;
250 release_config (opt);
251
252 return rc;
253 }
254
255
256 /* handle the case the user added a '!' to force a subkey. */
257 static char*
258 extract_keyid (const char *val)
259 {
260 size_t len = strlen (val);
261
262 if (len > 1 && val[len-1] == '!')
263 return substr (val, 0, len-1);
264 return m_strdup (val);
265 }
266
267
268 /* Return the default key.
269 This can be either a substring or a key ID. */
270 char*
271 get_gnupg_default_key (void)
272 {
273 config_file_t opt = NULL;
274 conf_option_t e;
275 char *keyid = NULL, *optfile = NULL;
276 int no_usable=0;
277
278 optfile = get_gnupg_cfgfile ();
279 if (!optfile)
280 return default_key_from_cache (&no_usable);
281 if (parse_config (optfile, &opt)) {
282 free_if_alloc (optfile);
283 return default_key_from_cache (&no_usable);
284 }
285 /* First we search for config entries which specify a default key. */
286 e = conf_find_option (opt, "default-key");
287 if (!e)
288 e = conf_find_option (opt, "local-user");
289 if (e)
290 keyid = extract_keyid (e->val);
291
292 free_if_alloc (optfile);
293 release_config (opt);
294
295 /* If no entry in the config has been found, we get a key
296 from the key cache. */
297 if (!keyid)
298 keyid = default_key_from_cache (&no_usable);
299 return keyid;
300 }
301
302
303 /* Check if GPG4WIN is available and if so, use the
304 install path to figure out where the gpg.exe is. */
305 char*
306 check_for_gpg4win (void)
307 {
308 return get_reg_entry_gpg4win ("gpg.exe");
309 }
310
311
312 /* Check if the gpg application (exe file) is available. */
313 int
314 check_gnupg_prog (void)
315 {
316 char *gpgexe = NULL;
317 int rc = 0;
318
319 gpgexe = get_gnupg_prog ();
320 if (!gpgexe || file_exist_check (gpgexe)) {
321 free_if_alloc (gpgexe);
322 gpgexe = check_for_gpg4win ();
323 if (!gpgexe || file_exist_check (gpgexe))
324 rc = WPTERR_GPG_EXEFILE;
325 else
326 set_reg_entry_gpg (GPG_REG_EXE, gpgexe);
327 }
328 free_if_alloc (gpgexe);
329 return rc;
330 }
331
332
333 static int
334 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
335 {
336 char *p;
337 char *tmp = m_strdup(buf);
338
339 int pos=0;
340 while ((p = strsep(&tmp, ".")) != NULL) {
341 switch (++pos) {
342 case 1: *major = atoi (p); break;
343 case 2: *minor = atoi (p); break;
344 case 3: *patch = atoi (p); break;
345 }
346 }
347 delete[] tmp;
348 if (pos != 3)
349 return -1;
350 return 0;
351 }
352
353
354 /* Check if the gnupg engine fullfills the minimum requirement
355 version given in @r_major.@r_minor.@r_patch. On success these
356 variables contain the GPG version which is installed. */
357 int
358 check_gnupg_engine (const char *need_gpg_ver,
359 int *r_major, int *r_minor, int *r_patch)
360 {
361 gpgme_engine_info_t inf;
362 char *eng = NULL;
363 int major=0, minor=0, patch=0;
364 int need_major = 0, need_minor = 0, need_patch = 0;
365 int rc = 1;
366
367 /* Convert the needed GPG version to the integer format. */
368 if (parse_version_nr (need_gpg_ver,
369 &need_major, &need_minor, &need_patch))
370 return 1;
371
372 if (gpgme_get_engine_info (&inf))
373 return -1;
374
375 /* We need to exec GPG again to find out if IDEA is available. */
376 if (gpg_get_version (&eng))
377 return -1;
378 if (strstr (eng, "IDEA"))
379 idea_available = 1;
380 safe_free (eng);
381
382 if (parse_version_nr (inf->version, &major, &minor, &patch))
383 return 1;
384
385 if (major > need_major)
386 rc = 0;
387 else if (major == need_major && minor > need_minor)
388 rc = 0;
389 else if (major == need_major && minor == need_minor &&
390 patch >= need_patch)
391 rc = 0;
392
393 /* Return the current GPG version. */
394 *r_major = major;
395 *r_minor = minor;
396 *r_patch = patch;
397 return rc;
398 }
399
400
401 /* Count the keyring entries in the gpg.conf file.
402 Return value: 0 on success. */
403 static int
404 cfgfile_count_keyrings (const char *fname, int *r_secrings, int *r_pubrings)
405 {
406 config_file_t opt;
407 conf_option_t e;
408
409 *r_secrings = 0;
410 *r_pubrings = 0;
411
412 if (parse_config (fname, &opt))
413 return WPTERR_FILE_OPEN;
414 for (e = opt->list; e; e = e->next) {
415 if (!strcmp (e->name, "secret-keyring")) {
416 if (!file_exist_check (e->val))
417 r_secrings[0]++;
418 }
419 else if (!strcmp (e->name, "keyring")) {
420 if (!file_exist_check (e->val))
421 r_pubrings[0]++;
422 }
423 }
424 release_config (opt);
425 return 0;
426 }
427
428
429 /* Usually GPG creates the pubring.gpg, secring.gpg on
430 the first start, but to make sure they always exist
431 create them empty if needed. */
432 static void
433 create_empty_keyring (int _pub)
434 {
435 char *name;
436 FILE *fp;
437
438 name = get_gnupg_keyring (_pub, 0);
439 if (name && file_exist_check (name) != 0) {
440 fp = fopen (name, "ab");
441 if (fp != NULL)
442 fclose (fp);
443 }
444 free_if_alloc (name);
445 }
446
447
448 /* Check if both keyrings are located in the gnupg home directory. */
449 int
450 gnupg_access_files (void)
451 {
452 int rc = 0;
453 int pubring_ok = 0, secring_ok = 0;
454 int secrings = 0, pubrings = 0;
455 char *optfile;
456
457 create_empty_keyring (1);
458 if (gnupg_access_keyring (1))
459 rc = WPTERR_GPG_KEYRINGS;
460 else
461 pubring_ok = 1;
462
463 create_empty_keyring (0);
464 if (gnupg_access_keyring (0))
465 rc = WPTERR_GPG_KEYRINGS;
466 else
467 secring_ok = 1;
468
469 if (!pubring_ok || !secring_ok) {
470 optfile = get_gnupg_cfgfile ();
471 if (!optfile)
472 return WPTERR_GPG_KEYRINGS;
473 rc = file_exist_check (optfile);
474 if (!rc && get_file_size (optfile) > 0) {
475 rc = cfgfile_count_keyrings (optfile, &secrings, &pubrings);
476 if (!rc && secrings > 0 && pubrings > 0) {
477 free_if_alloc (optfile);
478 return 0; /* found two keyrings in the option file */
479 }
480 else if ((!rc && pubrings && secring_ok)
481 || (!rc && secrings && pubring_ok)) {
482 free_if_alloc (optfile);
483 return 0; /* found one keyring and one entry in the options file */
484 }
485 else
486 return WPTERR_GPG_OPT_KEYRINGS;
487 }
488 free_if_alloc (optfile);
489 rc = WPTERR_GPG_KEYRINGS;
490 }
491 return rc;
492 }
493
494
495
496 /* Return the contents of the options file as a char buf. */
497 char*
498 get_gnupg_config (void)
499 {
500 FILE *fp;
501 char *p = NULL, *optfile;
502 int fsize;
503
504 optfile = get_gnupg_cfgfile ();
505 if (!optfile)
506 return NULL;
507 fsize = get_file_size (optfile);
508 if (fsize < 1 || fsize > 100000)
509 goto leave; /* too large or does not exist */
510
511 fp = fopen (optfile, "rb");
512 if (!fp)
513 goto leave;
514 p = new char[fsize+1];
515 if (!p)
516 BUG (NULL);
517 fread (p, 1, fsize, fp);
518 fclose (fp);
519 p[fsize] = '\0';
520
521 leave:
522 free_if_alloc (optfile);
523 return p;
524 }
525
526
527 /* Set the default key in the gpg.conf.
528 If @key is NULL, the entry will be deleted. */
529 int
530 set_gnupg_default_key (const char *key)
531 {
532 config_file_t opt;
533 conf_option_t e;
534 char *optfile = NULL;
535 int rc = 0;
536
537 optfile = get_gnupg_cfgfile ();
538 if (!optfile)
539 return WPTERR_FILE_OPEN;
540 rc = parse_config (optfile, &opt);
541 if (rc) {
542 free_if_alloc (optfile);
543 return WPTERR_GENERAL;
544 }
545 e = conf_find_option (opt, "default-key");
546 if (e && !key)
547 e->used = 0;
548 else if (e) {
549 free_if_alloc (e->val);
550 e->val = m_strdup (key);
551 e->used = 1;
552 }
553 else if (key)
554 conf_add_entry (opt, ENTRY_MULTI, "default-key", key);
555 rc = commit_config (optfile, opt);
556
557 free_if_alloc (optfile);
558 release_config (opt);
559 return rc;
560 }
561
562
563 /* Set the contents of the options file. */
564 int
565 set_gnupg_options (const char *buf, size_t buflen)
566 {
567 FILE *fp;
568 char *optfile;
569
570 optfile = get_gnupg_cfgfile ();
571 if (!optfile)
572 return WPTERR_FILE_CREAT;
573
574 fp = fopen (optfile, "wb");
575 if (!fp) {
576 free_if_alloc (optfile);
577 return WPTERR_FILE_CREAT;
578 }
579 fwrite (buf, 1, buflen, fp);
580 fclose (fp);
581 free_if_alloc (optfile);
582 return 0;
583 }
584
585
586 /* Check if the parameter for the option @buf is an existing file name.
587 Return value: 0 on success. */
588 static int
589 check_arg_file_exist (const char *buf)
590 {
591 const char *s = "load-extension ";
592
593 /* XXX: this is a bit of a kludge because we just
594 detect errors for 'load-extension'. */
595 if (!strncmp (buf, s, strlen (s)))
596 buf += strlen (s);
597 else
598 return 0;
599 return file_exist_check (buf);
600 }
601
602
603 /* Check if the line contains a valid GPG argument. */
604 static int
605 check_line (const char *buf)
606 {
607 int j, len;
608 int rc = 0;
609
610 if (*buf == '#' || *buf == '\r' || *buf == '\n')
611 return 1;
612 for (j = 0; valid_gpg_args[j]; j++) {
613 len = strlen (valid_gpg_args[j]);
614 if (!strncmp (valid_gpg_args[j], buf, len))
615 rc = 1;
616 }
617 return rc;
618 }
619
620
621 int
622 check_gnupg_options (const char *buf, int showerr)
623 {
624 char line[1024];
625 int nbytes = 0, lineno=0;
626 unsigned j;
627
628 for (j = 0; j < strlen (buf) && j < DIM (line); j++) {
629 line[nbytes++] = buf[j];
630 if (buf[j] == '\n' || j == (strlen (buf) - 1)) {
631 line[nbytes] = '\0';
632 lineno++;
633 if (!check_line (line)) {
634 if (showerr)
635 log_box ("GPG Config File", MB_ERR,
636 "gpg.conf:%d: invalid keyword '%s'",
637 lineno, line);
638 return 1;
639 }
640 if (check_arg_file_exist (line))
641 return WPTERR_FILE_EXIST;
642 nbytes = 0;
643 }
644 }
645 return 0;
646 }
647
648
649 /* Store the last access of the file inside the watcher @ctx. */
650 static int
651 get_last_gnupg_access (gpg_monitor_t ctx)
652 {
653 HANDLE fd;
654
655 fd = CreateFile (ctx->fpath_object, GENERIC_READ, FILE_SHARE_READ,
656 NULL, OPEN_EXISTING, 0, NULL);
657 if (fd == INVALID_HANDLE_VALUE)
658 return WPTERR_FILE_OPEN;
659 GetFileTime (fd, NULL, NULL, &ctx->access);
660 CloseHandle (fd);
661 return 0;
662 }
663
664
665 /* Check if the file inside watcher @ctx was modified. */
666 static void
667 check_last_gnupg_access (gpg_monitor_t ctx)
668 {
669 ctx->modified = 0;
670
671 if (ctx->last_access.dwHighDateTime != ctx->access.dwHighDateTime &&
672 ctx->last_access.dwLowDateTime != ctx->access.dwLowDateTime)
673 ctx->modified = 1;
674
675 if (ctx->last_access.dwLowDateTime == 0)
676 ctx->modified = 0;
677
678 ctx->last_access.dwLowDateTime = ctx->access.dwLowDateTime;
679 ctx->last_access.dwHighDateTime = ctx->access.dwHighDateTime;
680 }
681
682
683 /* Init GPG monitor table for all monitored files. */
684 void
685 init_gnupg_table (void)
686 {
687 char *path;
688 int j;
689
690 path = get_gnupg_path ();
691 for (j = 0; j < gpg_table_count; j++) {
692 gpg_table[j].object = m_strdup (gpg_objs[j]);
693 gpg_table[j].fpath_object = make_filename (path, gpg_objs[j], NULL);
694 memset (&gpg_table[j].access, 0, sizeof (FILETIME));
695 memset (&gpg_table[j].last_access, 0, sizeof (FILETIME));
696 gpg_table[j].modified = 0;
697 }
698 free_if_alloc (path);
699 }
700
701
702 /* Release the GPG monitor table. */
703 void
704 free_gnupg_table (void)
705 {
706 for (int j=0; j < gpg_table_count; j++) {
707 free_if_alloc (gpg_table[j].object);
708 free_if_alloc (gpg_table[j].fpath_object);
709 }
710 }
711
712
713 /* Return the amount of files modified since the last call. */
714 int
715 keyring_check_last_access (void)
716 {
717 int nfiles;
718
719 nfiles = 0;
720 for (int pos = 0; pos < gpg_table_count; pos++) {
721 get_last_gnupg_access (&gpg_table[pos]);
722 check_last_gnupg_access (&gpg_table[pos]);
723 if (gpg_table[pos].modified)
724 nfiles++;
725 }
726
727 return nfiles;
728 }
729
730
731 const char*
732 gnupg_check_file_ext (const char *fname, int *r_type)
733 {
734 char file_ext[5];
735
736 if (r_type)
737 *r_type = PGP_NONE;
738 if (!strchr (fname, '.' ))
739 return "UNKNOWN";
740
741 strncpy (file_ext, fname + strlen (fname) - 4, 4);
742 file_ext[4] = '\0';
743 if (!stricmp (file_ext, ".asc"))
744 return "ARMORED";
745 else if (!stricmp (file_ext, ".sig")) {
746 if (r_type)
747 *r_type = PGP_SIG;
748 return "SIGNED";
749 }
750 else if (!stricmp (file_ext, ".gpg") ||
751 !stricmp (file_ext, ".pgp")) {
752 if (r_type)
753 *r_type = PGP_MESSAGE;
754 return "ENCRYPTED";
755 }
756 return "UNKNOWN";
757 }
758
759
760 /* Check if the device where file @fname is stored on, is write-protected. */
761 static int
762 check_file_access (const char *fname, int mode)
763 {
764 HANDLE hd;
765
766 if (!mode)
767 mode = FILE_SHARE_WRITE;
768 hd = CreateFile (fname, GENERIC_WRITE, mode,
769 NULL, OPEN_EXISTING, 0, NULL);
770 if (hd == INVALID_HANDLE_VALUE)
771 return -1;
772 CloseHandle (hd);
773 return 0;
774 }
775
776
777 /* Check the device where the file @fname is stored on, is either
778 write-protected or if the file is already opened by another process
779 exclusively. And as a result, we cannot use the file for output. */
780 int
781 gpg_check_file_permissions (const char *fname, int mode)
782 {
783 int api_mode;
784
785 switch (mode) {
786 case 0: api_mode = FILE_SHARE_READ; break;
787 case 1: api_mode = FILE_SHARE_WRITE; break;
788 case 2: api_mode = FILE_SHARE_WRITE|FILE_SHARE_READ; break;
789 default: api_mode = FILE_SHARE_READ; break;
790 }
791
792 return check_file_access (fname, api_mode);
793 }
794
795
796 /* Check the file permissions of the public keyring.
797 If @showmsg is 1 output a message in case of errors.
798 Return value: 1 if read-only attribute
799 2 if file is opened by another process exclusively. */
800 int
801 gpg_check_permissions (int showmsg)
802 {
803 char *p = NULL;
804 char *name = NULL;
805 int failed = 0, ans=0, attrs=0;
806
807 p = get_gnupg_path ();
808 if (p && check_keyring (&p)) {
809 name = make_filename (p, "pubring", "gpg");
810 if ((attrs=GetFileAttributes (name)) & FILE_ATTRIBUTE_READONLY) {
811 ans = msg_box (NULL,
812 _("The selected keyring has the read-only file\n"
813 "attribute. In this state you do not have write\n"
814 "access. Do you want to remove the attribute?"),
815 _("GPG Information"), MB_YESNO);
816 if (ans == IDYES) {
817 attrs &= ~FILE_ATTRIBUTE_READONLY;
818 if (!SetFileAttributes (name, attrs)) {
819 msg_box (NULL, _("Could not reset read-only state."),
820 _("GPG Error"), MB_ERR);
821 failed = 1;
822 }
823 }
824 else if (ans == IDNO) {
825 /* All commands with write access will be disabled. */
826 failed = 1;
827 }
828 }
829 if (gpg_check_file_permissions (name, 1)) {
830 if (showmsg)
831 msg_box (NULL,
832 _("You do not have file access to modify the contents of\n"
833 "one or both of the selected keyrings.\n"
834 "\n"
835 "The keyrings are in a read-only state which is propably\n"
836 "caused by another program which already opened the files.\n"),
837 _("GPG Warning"), MB_WARN);
838 failed = 2;
839 }
840 }
841 free_if_alloc (p);
842 free_if_alloc (name);
843 return failed;
844 }
845
846
847 /* Check the GPG home dir. First try to read the 'HomeDir' registry entry,
848 then check for $APPDATA\gnupg. Create the dir if it does not exists. */
849 int
850 gnupg_check_homedir (void)
851 {
852 char *homedir;
853 int val;
854 int rc = 0;
855
856 homedir = get_reg_entry_gpg (GPG_REG_HOME);
857 if (!homedir)
858 homedir = multi_gnupg_path (0);
859 if (homedir) {
860 if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
861 val = log_box (_("Preferences"), MB_YESNO,
862 _("%s does not exit.\n"
863 "Do you want to create this directory?"), homedir);
864 if (val == IDYES) {
865 if (!CreateDirectory (homedir, NULL))
866 rc = WPTERR_DIR_CREAT;
867 }
868 else
869 rc = WPTERR_DIR_OPEN;
870 }
871 free_if_alloc (homedir);
872 }
873 return rc;
874 }
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 *cfgfile;
944 char bak[MAX_PATH+32];
945
946 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 (get_file_size (p) <= 0)
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