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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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