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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 248 - (show annotations)
Fri Jul 28 11:11:09 2006 UTC (18 years, 7 months ago) by twoaday
File size: 26386 byte(s)
Prepare 1.0.0pre2 release.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26