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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 271 - (show annotations)
Sun Nov 5 08:57:45 2006 UTC (18 years, 3 months ago) by twoaday
File size: 26504 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26