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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 222 - (show annotations)
Thu Jun 1 08:30:46 2006 UTC (18 years, 9 months ago) by twoaday
File size: 26637 byte(s)
Applied some more patches.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26