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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 304 - (show annotations)
Wed Mar 21 10:59:31 2007 UTC (17 years, 11 months ago) by twoaday
File size: 27225 byte(s)


1 /* wptGPG.cpp - GnuPG configuration
2 * Copyright (C) 2001-2007 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <windows.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <shlobj.h>
24 #include <ctype.h>
25 #include <io.h>
26 #include <time.h>
27
28 #include "wptGPG.h"
29 #include "wptGpgCmds.h"
30 #include "wptGPGOptSkel.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 tmp[8];
338 int i;
339
340 i=0;
341 while (buf && *buf != '.' && i < 8)
342 tmp[i++] = *buf++;
343 tmp[i] = 0; buf++;
344 *major = atoi (tmp);
345 i=0;
346 while (buf && *buf != '.' && i < 8)
347 tmp[i++] = *buf++;
348 tmp[i] = 0; buf++;
349 *minor = atoi (tmp);
350 i=0;
351 while (buf && isdigit (*buf) && i < 8)
352 tmp[i++] = *buf++;
353 tmp[i] = 0;
354 *patch = atoi (tmp);
355 return 0;
356 }
357
358
359 /* Check if the gnupg engine fullfills the minimum requirement
360 version given in @r_major.@r_minor.@r_patch. On success these
361 variables contain the GPG version which is installed. */
362 int
363 check_gnupg_engine (const char *need_gpg_ver,
364 int *r_major, int *r_minor, int *r_patch)
365 {
366 gpgme_ctx_t ctx;
367 gpgme_engine_info_t inf;
368 char *eng = NULL;
369 int major=0, minor=0, patch=0;
370 int need_major = 0, need_minor = 0, need_patch = 0;
371 int rc = 1;
372
373 /* Convert the needed GPG version to the integer format. */
374 if (parse_version_nr (need_gpg_ver,
375 &need_major, &need_minor, &need_patch))
376 return 1;
377
378 gpgme_new (&ctx);
379 inf = gpgme_ctx_get_engine_info (ctx);
380 if (!inf) {
381 gpgme_release (ctx);
382 return -1;
383 }
384
385 /* We need to exec GPG again to find out if IDEA is available. */
386 if (gpg_get_version (&eng)) {
387 gpgme_release (ctx);
388 return -1;
389 }
390 if (strstr (eng, "IDEA"))
391 idea_available = 1;
392 safe_free (eng);
393 if (parse_version_nr (inf->version, &major, &minor, &patch)) {
394 gpgme_release (ctx);
395 return 1;
396 }
397 gpgme_release (ctx);
398
399 if (major > need_major)
400 rc = 0;
401 else if (major == need_major && minor > need_minor)
402 rc = 0;
403 else if (major == need_major && minor == need_minor &&
404 patch >= need_patch)
405 rc = 0;
406
407 /* Return the current GPG version. */
408 *r_major = major;
409 *r_minor = minor;
410 *r_patch = patch;
411 return rc;
412 }
413
414
415 /* Count the keyring entries in the gpg.conf file.
416 Return value: 0 on success. */
417 static int
418 cfgfile_count_keyrings (const char *fname, int *r_secrings, int *r_pubrings)
419 {
420 config_file_t opt;
421 conf_option_t e;
422
423 *r_secrings = 0;
424 *r_pubrings = 0;
425
426 if (parse_config (fname, &opt))
427 return WPTERR_FILE_OPEN;
428 for (e = opt->list; e; e = e->next) {
429 if (!strcmp (e->name, "secret-keyring")) {
430 if (!file_exist_check (e->val))
431 r_secrings[0]++;
432 }
433 else if (!strcmp (e->name, "keyring")) {
434 if (!file_exist_check (e->val))
435 r_pubrings[0]++;
436 }
437 }
438 release_config (opt);
439 return 0;
440 }
441
442
443 /* Usually GPG creates the pubring.gpg, secring.gpg on
444 the first start, but to make sure they always exist
445 create them empty if needed. */
446 static void
447 create_empty_keyring (int _pub)
448 {
449 char *name;
450 FILE *fp;
451
452 name = get_gnupg_keyring (_pub, 0);
453 if (name && file_exist_check (name) != 0) {
454 fp = fopen (name, "ab");
455 if (fp != NULL)
456 fclose (fp);
457 }
458 free_if_alloc (name);
459 }
460
461
462 /* Check if both keyrings are located in the gnupg home directory. */
463 int
464 gnupg_access_files (void)
465 {
466 int rc = 0;
467 int pubring_ok = 0, secring_ok = 0;
468 int secrings = 0, pubrings = 0;
469 char *optfile;
470
471 create_empty_keyring (1);
472 if (gnupg_access_keyring (1))
473 rc = WPTERR_GPG_KEYRINGS;
474 else
475 pubring_ok = 1;
476
477 create_empty_keyring (0);
478 if (gnupg_access_keyring (0))
479 rc = WPTERR_GPG_KEYRINGS;
480 else
481 secring_ok = 1;
482
483 if (!pubring_ok || !secring_ok) {
484 optfile = get_gnupg_cfgfile ();
485 if (!optfile)
486 return WPTERR_GPG_KEYRINGS;
487 rc = file_exist_check (optfile);
488 if (!rc && get_file_size (optfile) > 0) {
489 rc = cfgfile_count_keyrings (optfile, &secrings, &pubrings);
490 if (!rc && secrings > 0 && pubrings > 0) {
491 free_if_alloc (optfile);
492 return 0; /* found two keyrings in the option file */
493 }
494 else if ((!rc && pubrings && secring_ok)
495 || (!rc && secrings && pubring_ok)) {
496 free_if_alloc (optfile);
497 return 0; /* found one keyring and one entry in the options file */
498 }
499 else
500 return WPTERR_GPG_OPT_KEYRINGS;
501 }
502 free_if_alloc (optfile);
503 rc = WPTERR_GPG_KEYRINGS;
504 }
505 return rc;
506 }
507
508
509 static int
510 create_gpg_conf (void)
511 {
512 FILE *fp;
513 char *s, *optfile;
514
515 s = get_gnupg_path ();
516 if (!s)
517 return WPTERR_FILE_CREAT;
518 optfile = make_filename (s, GPG_CONF, NULL);
519 fp = fopen (optfile, "wb");
520 if (!fp) {
521 return WPTERR_FILE_CREAT;
522 goto fail;
523 }
524 fwrite (options_skel, 1, strlen (options_skel), fp);
525 fclose (fp);
526
527 fail:
528 free_if_alloc (s);
529 free_if_alloc (optfile);
530 return 0;
531 }
532
533
534 /* Return the contents of the options file as a char buf. */
535 char*
536 get_gnupg_config (void)
537 {
538 FILE *fp;
539 char *p = NULL, *optfile = NULL;
540 int fsize;
541
542 optfile = get_gnupg_cfgfile ();
543 if (!optfile)
544 return NULL;
545 fsize = get_file_size (optfile);
546 if (!fsize) {
547 if (create_gpg_conf ())
548 return NULL;
549 fsize = get_file_size (optfile);
550 }
551 if (fsize > 100000)
552 goto leave; /* too large */
553 p = new char[fsize+1];
554 if (!p)
555 BUG (NULL);
556 fp = fopen( optfile, "rb" );
557 if (!fp) {
558 free_if_alloc (p);
559 return NULL;
560 }
561 fread (p, 1, fsize, fp);
562 fclose (fp);
563 p[fsize] = '\0';
564 free_if_alloc (optfile);
565
566 leave:
567 return p;
568 }
569
570
571 /* Set the default key in the gpg.conf.
572 If @key is NULL, the entry will be deleted. */
573 int
574 set_gnupg_default_key (const char *key)
575 {
576 config_file_t opt;
577 conf_option_t e;
578 char *optfile = NULL;
579 int rc = 0;
580
581 optfile = get_gnupg_cfgfile ();
582 if (!optfile)
583 return WPTERR_FILE_OPEN;
584 rc = parse_config (optfile, &opt);
585 if (rc) {
586 free_if_alloc (optfile);
587 return WPTERR_GENERAL;
588 }
589 e = conf_find_option (opt, "default-key");
590 if (e && !key)
591 e->used = 0;
592 else if (e) {
593 free_if_alloc (e->val);
594 e->val = m_strdup (key);
595 e->used = 1;
596 }
597 else if (key)
598 conf_add_entry (opt, ENTRY_MULTI, "default-key", key);
599 rc = commit_config (optfile, opt);
600
601 free_if_alloc (optfile);
602 release_config (opt);
603 return rc;
604 }
605
606
607 /* Set the contents of the options file. */
608 int
609 set_gnupg_options (const char *buf, size_t buflen)
610 {
611 FILE *fp;
612 char *optfile;
613
614 optfile = get_gnupg_cfgfile ();
615 if (!optfile)
616 return WPTERR_FILE_CREAT;
617
618 fp = fopen (optfile, "wb");
619 if (!fp) {
620 free_if_alloc (optfile);
621 return WPTERR_FILE_CREAT;
622 }
623 fwrite (buf, 1, buflen, fp);
624 fclose (fp);
625 free_if_alloc (optfile);
626 return 0;
627 }
628
629
630 /* Check if the parameter for the option @buf is an existing file name.
631 Return value: 0 on success. */
632 static int
633 check_arg_file_exist (const char *buf)
634 {
635 const char *s = "load-extension ";
636
637 /* XXX: this is a bit of a kludge because we just
638 detect errors for 'load-extension'. */
639 if (!strncmp (buf, s, strlen (s)))
640 buf += strlen (s);
641 else
642 return 0;
643 return file_exist_check (buf);
644 }
645
646
647 /* Check if the line contains a valid GPG argument. */
648 static int
649 check_line (const char *buf)
650 {
651 int j, len;
652 int rc = 0;
653
654 if (*buf == '#' || *buf == '\r' || *buf == '\n')
655 return 1;
656 for (j = 0; valid_gpg_args[j]; j++) {
657 len = strlen (valid_gpg_args[j]);
658 if (!strncmp (valid_gpg_args[j], buf, len))
659 rc = 1;
660 }
661 return rc;
662 }
663
664
665 int
666 check_gnupg_options (const char *buf, int showerr)
667 {
668 char line[1024];
669 int nbytes = 0, lineno=0;
670 unsigned j;
671
672 for (j = 0; j < strlen (buf) && j < DIM (line); j++) {
673 line[nbytes++] = buf[j];
674 if (buf[j] == '\n' || j == (strlen (buf) - 1)) {
675 line[nbytes] = '\0';
676 lineno++;
677 if (!check_line (line)) {
678 if (showerr)
679 log_box ("GPG Config File", MB_ERR,
680 "gpg.conf:%d: invalid keyword '%s'",
681 lineno, line);
682 return 1;
683 }
684 if (check_arg_file_exist (line))
685 return WPTERR_FILE_EXIST;
686 nbytes = 0;
687 }
688 }
689 return 0;
690 }
691
692
693 /* Store the last access of the file inside the watcher @ctx. */
694 static int
695 get_last_gnupg_access (gpg_monitor_t ctx)
696 {
697 HANDLE fd;
698
699 fd = CreateFile (ctx->fpath_object, GENERIC_READ, FILE_SHARE_READ,
700 NULL, OPEN_EXISTING, 0, NULL);
701 if (fd == INVALID_HANDLE_VALUE)
702 return WPTERR_FILE_OPEN;
703 GetFileTime (fd, NULL, NULL, &ctx->access);
704 CloseHandle (fd);
705 return 0;
706 }
707
708
709 /* Check if the file inside watcher @ctx was modified. */
710 static void
711 check_last_gnupg_access (gpg_monitor_t ctx)
712 {
713 ctx->modified = 0;
714
715 if (ctx->last_access.dwHighDateTime != ctx->access.dwHighDateTime &&
716 ctx->last_access.dwLowDateTime != ctx->access.dwLowDateTime)
717 ctx->modified = 1;
718
719 if (ctx->last_access.dwLowDateTime == 0)
720 ctx->modified = 0;
721
722 ctx->last_access.dwLowDateTime = ctx->access.dwLowDateTime;
723 ctx->last_access.dwHighDateTime = ctx->access.dwHighDateTime;
724 }
725
726
727 /* Init GPG monitor table for all monitored files. */
728 void
729 init_gnupg_table (void)
730 {
731 char *path;
732 int j;
733
734 path = get_gnupg_path ();
735 for (j = 0; j < gpg_table_count; j++) {
736 gpg_table[j].object = m_strdup (gpg_objs[j]);
737 gpg_table[j].fpath_object = make_filename (path, gpg_objs[j], NULL);
738 memset (&gpg_table[j].access, 0, sizeof (FILETIME));
739 memset (&gpg_table[j].last_access, 0, sizeof (FILETIME));
740 gpg_table[j].modified = 0;
741 }
742 free_if_alloc (path);
743 }
744
745
746 /* Release the GPG monitor table. */
747 void
748 free_gnupg_table (void)
749 {
750 int j;
751
752 for (j=0; j < gpg_table_count; j++) {
753 free_if_alloc (gpg_table[j].object);
754 free_if_alloc (gpg_table[j].fpath_object);
755 }
756 }
757
758
759 /* Return the amount of files modified since the last call. */
760 int
761 keyring_check_last_access (void)
762 {
763 int nfiles;
764 int pos;
765
766 nfiles = 0;
767 for (pos = 0; pos < gpg_table_count; pos++) {
768 get_last_gnupg_access (&gpg_table[pos]);
769 check_last_gnupg_access (&gpg_table[pos]);
770 if (gpg_table[pos].modified)
771 nfiles++;
772 }
773
774 return nfiles;
775 }
776
777
778 const char*
779 gnupg_check_file_ext (const char *fname, int *r_type)
780 {
781 char file_ext[5];
782
783 if (r_type)
784 *r_type = PGP_NONE;
785 if (!strchr (fname, '.' ))
786 return "UNKNOWN";
787
788 strncpy (file_ext, fname + strlen (fname) - 4, 4);
789 file_ext[4] = '\0';
790 if (!stricmp (file_ext, ".asc"))
791 return "ARMORED";
792 else if (!stricmp (file_ext, ".sig")) {
793 if (r_type)
794 *r_type = PGP_SIG;
795 return "SIGNED";
796 }
797 else if (!stricmp (file_ext, ".gpg") ||
798 !stricmp (file_ext, ".pgp")) {
799 if (r_type)
800 *r_type = PGP_MESSAGE;
801 return "ENCRYPTED";
802 }
803 return "UNKNOWN";
804 }
805
806
807 /* Check if the device where file @fname is stored on, is write-protected. */
808 static int
809 check_file_access (const char *fname, int mode)
810 {
811 HANDLE hd;
812
813 if (!mode)
814 mode = FILE_SHARE_WRITE;
815 hd = CreateFile (fname, GENERIC_WRITE, mode,
816 NULL, OPEN_EXISTING, 0, NULL);
817 if (hd == INVALID_HANDLE_VALUE)
818 return -1;
819 CloseHandle (hd);
820 return 0;
821 }
822
823
824 /* Check the device where the file @fname is stored on, is either
825 write-protected or if the file is already opened by another process
826 exclusively. And as a result, we cannot use the file for output. */
827 int
828 gpg_check_file_permissions (const char *fname, int mode)
829 {
830 int api_mode;
831
832 switch (mode) {
833 case 0: api_mode = FILE_SHARE_READ; break;
834 case 1: api_mode = FILE_SHARE_WRITE; break;
835 case 2: api_mode = FILE_SHARE_WRITE|FILE_SHARE_READ; break;
836 default: api_mode = FILE_SHARE_READ; break;
837 }
838
839 return check_file_access (fname, api_mode);
840 }
841
842
843 /* Check the file permissions of the public keyring.
844 If @showmsg is 1 output a message in case of errors.
845 Return value: 1 if read-only attribute
846 2 if file is opened by another process exclusively. */
847 int
848 gpg_check_permissions (int showmsg)
849 {
850 char *p = NULL;
851 char *name = NULL;
852 int failed = 0, ans=0, attrs=0;
853
854 p = get_gnupg_path ();
855 if (p && check_keyring (&p)) {
856 name = make_filename (p, "pubring", "gpg");
857 if ((attrs=GetFileAttributes (name)) & FILE_ATTRIBUTE_READONLY) {
858 ans = msg_box (NULL,
859 _("The selected keyring has the read-only file\n"
860 "attribute. In this state you do not have write\n"
861 "access. Do you want to remove the attribute?"),
862 _("GPG Information"), MB_YESNO);
863 if (ans == IDYES) {
864 attrs &= ~FILE_ATTRIBUTE_READONLY;
865 if (!SetFileAttributes (name, attrs)) {
866 msg_box (NULL, _("Could not reset read-only state."),
867 _("GPG Error"), MB_ERR);
868 failed = 1;
869 }
870 }
871 else if (ans == IDNO) {
872 /* All commands with write access will be disabled. */
873 failed = 1;
874 }
875 }
876 if (gpg_check_file_permissions (name, 1)) {
877 if (showmsg)
878 msg_box (NULL,
879 _("You do not have file access to modify the contents of\n"
880 "one or both of the selected keyrings.\n"
881 "\n"
882 "The keyrings are in a read-only state which is propably\n"
883 "caused by another program which already opened the files.\n"),
884 _("GPG Warning"), MB_WARN);
885 failed = 2;
886 }
887 }
888 free_if_alloc (p);
889 free_if_alloc (name);
890 return failed;
891 }
892
893
894 /* Check the GPG home dir. First try to read the 'HomeDir' registry entry,
895 then check for $APPDATA\gnupg. Create the dir if it does not exists. */
896 int
897 gnupg_check_homedir (void)
898 {
899 char *homedir;
900 int val;
901 int rc = 0;
902
903 #ifdef WINPT_MOBILE
904 return 0;
905 #endif
906
907 homedir = get_reg_entry_gpg (GPG_REG_HOME);
908 if (!homedir)
909 homedir = multi_gnupg_path (0);
910 if (homedir) {
911 if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
912 val = log_box (_("Preferences"), MB_YESNO,
913 _("%s does not exit.\n"
914 "Do you want to create this directory?"), homedir);
915 if (val == IDYES) {
916 if (!CreateDirectory (homedir, NULL))
917 rc = WPTERR_DIR_CREAT;
918 }
919 else
920 rc = WPTERR_DIR_OPEN;
921 }
922 free_if_alloc (homedir);
923 }
924 return rc;
925 }
926
927
928 int
929 gnupg_copy_keyrings (void)
930 {
931 const char *pring, *sring;
932 char *file = NULL, *path = NULL;
933 int id = 0, rc = 0;
934 HWND hwnd;
935
936 path = get_gnupg_path ();
937 if (!path)
938 return WPTERR_GENERAL;
939 hwnd = GetDesktopWindow ();
940
941 pring = get_fileopen_dlg (hwnd, _("Please choose your Public Keyring"),
942 "GPG Keyrings (*.gpg)\0*.gpg\0\0",NULL);
943 if (!pring) {
944 msg_box (hwnd, _("No keyring was chosen. Exit."),
945 _("WinPT Error"), MB_ERR);
946 free_if_alloc (path);
947 return WPTERR_GENERAL;
948 }
949 file = make_filename (path, "pubring", "gpg");
950 if (file_exist_check (file) == 0) {
951 id = msg_box (hwnd, _("Overwrite old public keyring?"),
952 "WinPT", MB_INFO|MB_YESNO);
953 if (id == IDNO)
954 goto fail;
955 }
956 if (!CopyFile (pring, file, FALSE)) {
957 msg_box (hwnd, _("Could not copy file."), _("WinPT Error"), MB_ERR);
958 rc = WPTERR_FILE_READ;
959 goto fail;
960 }
961 free_if_alloc (file);
962
963 sring = get_fileopen_dlg (hwnd, _("Please choose your Secret Keyring"),
964 "GPG Keyrings (*.gpg)\0*.gpg\0\0", NULL);
965 if (!sring) {
966 msg_box (NULL, _("No keyring was chosen. Exit."),
967 _("WinPT Error"), MB_ERR);
968 return WPTERR_GENERAL;
969 }
970 file = make_filename (path, "secring", "gpg");
971 if (file_exist_check (file) == 0) {
972 id = msg_box (hwnd, _("Overwrite old secret keyring?"),
973 "WinPT", MB_INFO|MB_YESNO);
974 if (id == IDNO)
975 goto fail;
976 }
977 if (!CopyFile (sring, file, FALSE)) {
978 msg_box (NULL, _("Could not copy file."), _("WinPT Error"), MB_ERR);
979 rc = WPTERR_FILE_READ;
980 }
981
982 fail:
983 free_if_alloc (file);
984 free_if_alloc (path);
985 return rc;
986 }
987
988
989 /* Backup the gpg.conf file. */
990 void
991 gnupg_backup_options (void)
992 {
993 char *cfgfile;
994 char bak[MAX_PATH+32];
995
996 cfgfile = get_gnupg_cfgfile ();
997 if (!cfgfile)
998 return;
999 _snprintf (bak, DIM (bak)-1, "%s.bak", cfgfile);
1000 CopyFile (cfgfile, bak, FALSE);
1001 free_if_alloc (cfgfile);
1002 }
1003
1004
1005 static int
1006 backup_one_file (const char *srcpath, const char *srcn,
1007 const char *dstpath, const char *dstn)
1008 {
1009 char *src, *dst;
1010 BOOL rc;
1011
1012 src = make_filename (srcpath, srcn, "gpg");
1013 dst = make_filename (dstpath, dstn, "gpg");
1014 rc = CopyFile (src, dst, FALSE);
1015 free_if_alloc (src);
1016 free_if_alloc (dst);
1017 if (!rc) {
1018 log_box (_("Backup"), MB_ERR, _("Backup keyring \"%s\" failed"), srcn);
1019 return WPTERR_GENERAL;
1020 }
1021 return 0;
1022 }
1023
1024
1025 /* Figure out first public keyring which is not empty.
1026 Return value: 1 on success. */
1027 static int
1028 check_keyring (char **r_path)
1029 {
1030 char *p;
1031 char *opt;
1032 char *name;
1033
1034 if (!*r_path)
1035 return 0;
1036 p = make_filename (*r_path, "pubring", "gpg");
1037 if (get_file_size (p) <= 0)
1038 return 0;
1039
1040 opt = get_gnupg_cfgfile ();
1041 if (!opt)
1042 BUG (0);
1043 name = get_keyring_from_conf (opt, 1);
1044 free_if_alloc (opt);
1045 free_if_alloc (p);
1046 if (!name)
1047 return 0;
1048 p = strrchr (name, '\\');
1049 if (!p) {
1050 free_if_alloc (name);
1051 return 0;
1052 }
1053 free_if_alloc (*r_path);
1054 *r_path = new char [strlen (name)+1];
1055 memset (*r_path, 0, strlen (name));
1056 strncpy (*r_path, name, (p-name));
1057 free_if_alloc (name);
1058 return 1;
1059 }
1060
1061
1062 /* Return a temp name based on the day of the week. */
1063 static char*
1064 get_backup_name (const char *templ)
1065 {
1066 struct tm *tm;
1067 const char *fmt;
1068 char *p;
1069 time_t t;
1070
1071 t = time (NULL);
1072 tm = localtime (&t);
1073 fmt = "%s-%d";
1074 p = new char [strlen (templ) + strlen (fmt) + 8 + 1];
1075 if (!p)
1076 BUG (0);
1077 sprintf (p, fmt, templ, tm->tm_wday % 3);
1078 return p;
1079 }
1080
1081
1082 /* Make backups of all keyrings. The public key ring is rotated like
1083 this pubring-%d.gpg.
1084 If @auto_backup is false, no action is performed.
1085 @include_secr indicated if the backup includes the secret keyring. */
1086 void
1087 gnupg_backup_keyrings (int auto_backup, int backup_mode, int include_secr)
1088 {
1089 char *srcpath, *dstpath;
1090 char *name;
1091 int rc;
1092
1093 if (!auto_backup)
1094 return;
1095 srcpath = get_gnupg_path ();
1096 check_keyring (&srcpath);
1097 if (backup_mode == 1) {
1098 /* If the backup mode uses the home directory the source
1099 and destination folder will be the same. */
1100 dstpath = get_gnupg_path ();
1101 check_keyring (&dstpath);
1102 }
1103 else if (backup_mode == 2) {
1104 char *tmpfile;
1105 FILE *fp;
1106
1107 dstpath = m_strdup (reg_prefs.backup.path);
1108 tmpfile = make_filename (reg_prefs.backup.path, "test", "tmp");
1109 fp = fopen (tmpfile, "wb");
1110 if (!fp)
1111 rc = log_box (_("Backup"), MB_WARN|MB_RETRYCANCEL,
1112 _("The backup drive '%s' does not seems to be accessable.\n"
1113 "Please insert/check the drive to continue."), dstpath);
1114 else {
1115 rc = 0;
1116 fclose (fp);
1117 DeleteFile (tmpfile);
1118 }
1119 free_if_alloc (tmpfile);
1120 if (!fp || rc == IDCANCEL) {
1121 free_if_alloc (dstpath);
1122 free_if_alloc (srcpath);
1123 return;
1124 }
1125 }
1126 else {
1127 log_box (_("Backup"), MB_ERR, _("Invalid backup mode %d"), backup_mode);
1128 free_if_alloc (srcpath);
1129 return;
1130 }
1131 name = get_backup_name ("pubring-bak");
1132 rc = backup_one_file (srcpath, "pubring", dstpath, name);
1133 if (!rc && include_secr)
1134 rc = backup_one_file (srcpath, "secring", dstpath, "secring-bak");
1135 free_if_alloc (name);
1136 free_if_alloc (srcpath);
1137 free_if_alloc (dstpath);
1138 }
1139
1140
1141 /* check that the requested GPG keyring exist and.
1142 Return value: 0 for success. */
1143 int
1144 gnupg_access_keyring (int _pub)
1145 {
1146 int rc = 0;
1147 char *name = get_gnupg_keyring (_pub, 1);
1148 if (!name || file_exist_check (name))
1149 rc = -1;
1150 free_if_alloc (name);
1151 return rc;
1152 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26