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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26