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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 295 - (show annotations)
Tue Mar 13 18:53:40 2007 UTC (17 years, 11 months ago) by twoaday
File size: 27383 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26