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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 138 - (show annotations)
Mon Jan 9 14:20:00 2006 UTC (19 years, 1 month ago) by twoaday
File size: 26562 byte(s)
Do not overwrite default return value.


1 /* wptGPG.cpp - GnuPG configuration
2 * Copyright (C) 2001-2005 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 p = get_reg_entry_gpg ("OptFile");
119 if (p && !strcmp (p, "")) {
120 nlen = strlen (path) + 64;
121 optfile = new char[nlen + 1];
122 if (!optfile)
123 BUG (0);
124 _snprintf (optfile, nlen, "%s\\"GPG_CONF, path);
125 }
126 else if (p) {
127 nlen = strlen( p ) + 4;
128 optfile = new char[nlen + 1];
129 if (!optfile)
130 BUG (NULL);
131 _snprintf (optfile, nlen, "%s", p);
132 }
133 else {
134 nlen = strlen (path) + 64;
135 optfile = new char[nlen + 1];
136 if( !optfile)
137 BUG (NULL);
138 _snprintf (optfile, nlen, "%s\\"GPG_CONF, path);
139 }
140 free_if_alloc (path);
141 free_if_alloc (p);
142 return optfile;
143 }
144
145
146 /* Return the full path of the keyring. If @pub is 1, the public
147 keyring is return, otherwise the secret keyring. */
148 char*
149 get_gnupg_keyring (int pub, int strict)
150 {
151 char *optfile = NULL;
152 char *path = NULL;
153 char *keyring = NULL;
154
155 path = get_gnupg_path ();
156 if (!path)
157 return NULL;
158 keyring = make_filename (path, pub? "pubring" : "secring", "gpg");
159 if (strict && !file_exist_check (keyring)) {
160 free_if_alloc (path);
161 return keyring;
162 }
163 else if (!strict) {
164 free_if_alloc (path);
165 return keyring;
166 }
167 if (file_exist_check (keyring) || pub && get_file_size (keyring) == 0) {
168 free_if_alloc (keyring);
169 optfile = make_filename (path, GPG_CONF, NULL);
170 keyring = get_gnupg_keyring_from_options (optfile, pub);
171 }
172 free_if_alloc (path);
173 free_if_alloc (optfile);
174 return keyring;
175 }
176
177
178 /* Return the full path (with the gpg exe name). First the registry is scanned
179 for the entry 'gpgProgram'. If it wasn't set, the default path is the
180 appended string 'gpg.exe' is used. */
181
182 /* FIXME: Use gpgme's engine info here. */
183 char*
184 get_gnupg_prog (void)
185 {
186 char *p;
187 char *pgm = NULL;
188
189 p = get_reg_entry_gpg (GPG_REG_EXE);
190 if (!p) {
191 char *path = get_gnupg_path ();
192 if (!path)
193 return NULL;
194 pgm = make_filename (path, "gpg", "exe");
195 free_if_alloc (path);
196 }
197 else {
198 pgm = m_strdup (p);
199 free_if_alloc (p);
200 }
201 return pgm;
202 }
203
204
205 /* Retrieve the first usable secret key from cache.
206 If no usable was found, @ret_no_useable is 1.
207 Return value: the keyid of the secret key. */
208 static char *
209 default_key_from_cache (int *ret_no_useable)
210 {
211 const char *s;
212 char *keyid = NULL;
213 gpgme_key_t key;
214 gpg_keycache_t sec = keycache_get_ctx (0);
215
216 if (!sec)
217 BUG (0);
218 gpg_keycache_rewind (sec);
219 while (!gpg_keycache_next_key (sec, 1, &key)) {
220 if (key_is_useable (key)) {
221 s = key->subkeys->keyid;
222 if (s)
223 keyid = m_strdup (s+8);
224 break;
225 }
226 }
227 if (!keyid)
228 *ret_no_useable = 1;
229 return keyid;
230 }
231
232
233 /* Load the gpg.conf and search for some options
234 and store the result in the global preference context.
235 Return value: 0 on success. */
236 int
237 gnupg_load_config (void)
238 {
239 int rc;
240 gpg_optfile_t opt;
241 gpg_option_t o;
242 char *conf = get_gnupg_cfgfile ();
243 if (!conf)
244 return -1;
245 rc = parse_gpg_options (conf, &opt);
246 if (rc) {
247 free_if_alloc (conf);
248 return -1;
249 }
250 o = find_option (opt, "ask-cert-level");
251 if (o)
252 reg_prefs.gpg.ask_cert_level = 1;
253 release_gpg_options (opt);
254 free_if_alloc (conf);
255 return 0;
256 }
257
258
259 char*
260 get_gnupg_default_key (void)
261 {
262 gpg_optfile_t opt = NULL;
263 gpg_option_t e;
264 char * keyid = NULL, * optfile = NULL;
265 int no_usable=0, rc = 0;
266
267 optfile = get_gnupg_cfgfile ();
268 if (!optfile)
269 return default_key_from_cache (&no_usable);
270 rc = parse_gpg_options (optfile, &opt);
271 if (rc) {
272 free_if_alloc (optfile);
273 return default_key_from_cache (&no_usable);
274 }
275 e = find_option( opt, "default-key" );
276 if ( e )
277 keyid = m_strdup( e->val );
278 if( !e ) {
279 e = find_option( opt, "local-user" );
280 if( e )
281 keyid = m_strdup( e->val );
282 }
283 if( !e ) {
284 e = find_option( opt, "encrypt-to" );
285 if( e )
286 keyid = m_strdup( e->val );
287 }
288 free_if_alloc (optfile);
289 release_gpg_options (opt);
290
291 if (!keyid)
292 keyid = default_key_from_cache (&no_usable);
293 return keyid;
294 } /* get_gnupg_default_key */
295
296
297 /* Check if GPG4WIN is available and if so, use the
298 install path to figure out where the gpg.exe is. */
299 char*
300 check_for_gpg4win (void)
301 {
302 return get_reg_entry_gpg4win ("gpg.exe");
303 }
304
305
306 /* Check if the gpg application (exe file) is available. */
307 int
308 check_gnupg_prog (void)
309 {
310 char *gpgexe = NULL;
311 int rc = 0;
312
313 gpgexe = get_gnupg_prog ();
314 if (!gpgexe || file_exist_check (gpgexe)) {
315 free_if_alloc (gpgexe);
316 gpgexe = check_for_gpg4win ();
317 if (!gpgexe || file_exist_check (gpgexe))
318 rc = WPTERR_GPG_EXEFILE;
319 else
320 set_reg_entry_gpg (GPG_REG_EXE, gpgexe);
321 }
322 free_if_alloc (gpgexe);
323 return rc;
324 }
325
326
327 static int
328 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
329 {
330 char tmp[8];
331 int i;
332
333 i=0;
334 while (buf && *buf != '.' && i < 8)
335 tmp[i++] = *buf++;
336 tmp[i] = 0; buf++;
337 *major = atol( tmp );
338 i=0;
339 while (buf && *buf != '.' && i < 8)
340 tmp[i++] = *buf++;
341 tmp[i] = 0; buf++;
342 *minor = atol (tmp);
343 i=0;
344 while (buf && isdigit (*buf) && i < 8)
345 tmp[i++] = *buf++;
346 tmp[i] = 0;
347 *patch = atol (tmp);
348 return 0;
349 }
350
351
352 /* Check if the gnupg engine fullfills the minimum requirement
353 version given in @r_major.@r_minor.@r_patch. On success these
354 variables contain the GPG version which is installed. */
355 int
356 check_gnupg_engine (const char *need_gpg_ver,
357 int *r_major, int *r_minor, int *r_patch)
358 {
359 gpgme_ctx_t ctx;
360 gpgme_engine_info_t inf;
361 char *eng = NULL;
362 int major=0, minor=0, patch=0;
363 int need_major = 0, need_minor = 0, need_patch = 0;
364 int rc = 1;
365
366 /* Convert the needed GPG version to the integer format. */
367 if (parse_version_nr (need_gpg_ver,
368 &need_major, &need_minor, &need_patch))
369 return 1;
370
371 gpgme_new (&ctx);
372 inf = gpgme_ctx_get_engine_info (ctx);
373 if (!inf) {
374 gpgme_release (ctx);
375 return -1;
376 }
377
378 /* We need to exec GPG again to find out if IDEA is available. */
379 if (gpg_get_version (&eng))
380 return -1;
381 if (strstr (eng, "IDEA"))
382 idea_available = 1;
383 free (eng);
384 if (parse_version_nr (inf->version, &major, &minor, &patch)) {
385 gpgme_release (ctx);
386 return 1;
387 }
388
389 if (major > need_major)
390 rc = 0;
391 else if (major == need_major && minor > need_minor)
392 rc = 0;
393 else if (major == need_major && minor == need_minor &&
394 patch >= need_patch)
395 rc = 0;
396
397 /* Return the current GPG version. */
398 *r_major = major;
399 *r_minor = minor;
400 *r_patch = patch;
401 return rc;
402 }
403
404
405 int
406 check_gnupg_cfgfile (const char *fname, int *r_secrings, int *r_pubrings)
407 {
408 gpg_optfile_t opt;
409 gpg_option_t e;
410 int rc = 0;
411
412 *r_secrings = 0;
413 *r_pubrings = 0;
414 rc = parse_gpg_options( fname, &opt );
415 if( rc )
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 } /* check_gnupg_cfgfile */
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 *f;
441
442 name = get_gnupg_keyring (_pub, 0);
443 if (file_exist_check (name) != 0) {
444 f = fopen (name, "ab");
445 if (f != NULL)
446 fclose (f);
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 && pubrings) {
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 == NULL )
507 return WPTERR_FILE_CREAT;
508 optfile = make_filename (s, GPG_CONF, NULL);
509 fp = fopen (optfile, "wb");
510 if (fp == NULL) {
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 } /* create_gpg_options */
522
523
524 /*
525 * Return the contents of the options file as a char buf.
526 */
527 char *
528 get_gnupg_config (void)
529 {
530 FILE * fp;
531 char * p = NULL, * optfile = NULL;
532 int fsize, rc = 0;
533
534 optfile = get_gnupg_cfgfile ();
535 if( optfile == NULL )
536 return NULL;
537 fsize = get_file_size( optfile );
538 if( !fsize ) {
539 rc = create_gpg_options( );
540 if ( rc )
541 return NULL;
542 fsize = get_file_size( optfile );
543 }
544 if( fsize > 100000 )
545 goto leave; /* too large */
546 p = new char[fsize+1];
547 if( p == NULL )
548 BUG( NULL );
549 fp = fopen( optfile, "rb" );
550 if( fp == NULL ) {
551 free_if_alloc( p );
552 return NULL;
553 }
554 fread( p, 1, fsize, fp );
555 fclose( fp );
556 p[fsize] = '\0';
557 free_if_alloc( optfile );
558
559 leave:
560 return p;
561 } /* get_gnupg_config */
562
563
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 -1;
575 rc = parse_gpg_options (optfile, &opt);
576 if( rc ) {
577 free_if_alloc (optfile);
578 return -1;
579 }
580 e = find_option (opt, "default-key");
581 if (e) {
582 free_if_alloc (e->val);
583 e->val = m_strdup (key);
584 e->used = 1;
585 }
586 else
587 add_entry (opt, ENTRY_MULTI, "default-key", key);
588 rc = commit_gpg_options (optfile, opt);
589
590 free_if_alloc (optfile);
591 release_gpg_options (opt);
592
593 return rc;
594 } /* set_gnupg_default_key */
595
596
597 /*
598 * Set the contents of the options file.
599 */
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, OPEN_ALWAYS, 0, NULL);
677 if (fd == INVALID_HANDLE_VALUE) {
678 free_if_alloc (path);
679 free_if_alloc (file);
680 return WPTERR_FILE_OPEN;
681 }
682 GetFileTime (fd, NULL, NULL, &ctx->access);
683 CloseHandle (fd);
684 free_if_alloc (path);
685 free_if_alloc (file);
686 return 0;
687 }
688
689
690 /* Check if the file inside watcher @ctx was modified. */
691 static void
692 check_last_gnupg_access (gpg_watcher_s *ctx)
693 {
694 ctx->modified = 0;
695
696 if (ctx->last_access.dwHighDateTime != ctx->access.dwHighDateTime &&
697 ctx->last_access.dwLowDateTime != ctx->access.dwLowDateTime)
698 ctx->modified = 1;
699
700 /* XXX: find a better way. without it, winpt --keymanager loads
701 the key cache twice. */
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 watcher table for all monitored files. */
711 void
712 init_gnupg_table (void)
713 {
714 char *p;
715 int j;
716
717 for (j = 0; j < gpg_table_count; j++) {
718 p = gpg_table[j].object = m_strdup (gpg_objs[j]);
719 if (!p)
720 BUG (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 }
726
727
728 void
729 free_gnupg_table (void)
730 {
731 int j;
732
733 for (j=0; j < gpg_table_count; j++)
734 free_if_alloc (gpg_table[j].object);
735 }
736
737
738 /* Return the amount of files modified since the last call. */
739 int
740 keyring_check_last_access (void)
741 {
742 int rc, j;
743
744 rc = 0;
745 for (j = 0; j < gpg_table_count; j++) {
746 get_last_gnupg_access (&gpg_table[j]);
747 check_last_gnupg_access (&gpg_table[j]);
748 if (gpg_table[j].modified)
749 rc++;
750 }
751
752 return rc;
753 }
754
755
756 const char*
757 gnupg_check_file_ext (const char *fname, int *r_type)
758 {
759 char file_ext[5];
760
761 if (r_type)
762 *r_type = PGP_NONE;
763 if (!strchr (fname, '.' ))
764 return "UNKNOWN";
765
766 strncpy (file_ext, fname + strlen (fname) - 4, 4);
767 file_ext[4] = '\0';
768 if (!stricmp (file_ext, ".asc"))
769 return "ARMORED";
770 else if (!stricmp (file_ext, ".sig")) {
771 if (r_type)
772 *r_type = PGP_SIG;
773 return "SIGNED";
774 }
775 else if (!stricmp (file_ext, ".gpg") || !stricmp (file_ext, ".pgp")) {
776 if (r_type)
777 *r_type = PGP_MESSAGE;
778 return "ENCRYPTED";
779 }
780 return "UNKNOWN";
781 }
782
783
784 char*
785 get_gnupg_keyring_from_options (const char * fname, int pub)
786 {
787 gpg_optfile_t opt;
788 gpg_option_t e;
789 char * kring = NULL;
790 int rc = 0;
791
792 rc = parse_gpg_options (fname, &opt);
793 if (rc)
794 return NULL;
795 if (pub)
796 e = find_option (opt, "keyring");
797 else
798 e = find_option (opt, "secret-keyring");
799 if (e)
800 kring = m_strdup (e->val);
801 release_gpg_options (opt);
802
803 return kring;
804 }
805
806
807
808 /* XXX: does not work with write-protected floppies */
809 static int
810 my_access (const char *fname)
811 {
812 HANDLE hd;
813 hd = CreateFile (fname, GENERIC_WRITE, FILE_SHARE_WRITE,
814 NULL, OPEN_EXISTING, 0, NULL);
815 if (hd == INVALID_HANDLE_VALUE)
816 return -1;
817 CloseHandle (hd);
818 return 0;
819 }
820
821
822 /* Check the file permissions of the public keyring.
823 If @showmsg is 1 output a message in case of errors.
824 Return value: 1 if read-only attribute
825 2 if file is opened by another process exclusively. */
826 int
827 gpg_check_permissions (int showmsg)
828 {
829 char *p = NULL;
830 char *name = NULL;
831 int failed = 0, ans=0, attrs=0;
832
833 p = get_gnupg_path ();
834 if (check_keyring (&p) && p) {
835 name = make_filename (p, "pubring", "gpg");
836 if ((attrs=GetFileAttributes (name)) & FILE_ATTRIBUTE_READONLY) {
837 ans = msg_box (NULL,
838 _("The selected keyring has the read-only file\n"
839 "attribute. In this state you do not have write\n"
840 "access. Do you want to remove the attribute?"),
841 _("GPG Information"), MB_YESNO);
842 if (ans == IDYES) {
843 attrs &= ~FILE_ATTRIBUTE_READONLY;
844 if (!SetFileAttributes (name, attrs)) {
845 msg_box (NULL, _("Could not reset read-only state."),
846 _("GPG Error"), MB_ERR);
847 failed = 1;
848 }
849 }
850 else if (ans == IDNO) {
851 /* All commands with write access will be disabled. */
852 failed = 1;
853 }
854 }
855 if (my_access (name)) {
856 if (showmsg)
857 msg_box (NULL,
858 _("You do not have file access to modify the contents of\n"
859 "one or both of the selected keyrings.\n"
860 "\n"
861 "The keyrings are in a read-only state which is propably\n"
862 "caused by another program which already opened the files.\n"),
863 _("GPG Warning"), MB_WARN);
864 failed = 2;
865 }
866 }
867 free_if_alloc (p);
868 free_if_alloc (name);
869 return failed;
870 }
871
872
873 /* Check the GPG home dir. First try to read the 'HomeDir' registry entry,
874 then check for $APPDATA\gnupg. Create the dir if it does not exists. */
875 int
876 gnupg_check_homedir (void)
877 {
878 char *homedir = NULL;
879 int val = 0;
880 int rc = 0;
881
882 homedir = get_reg_entry_gpg (GPG_REG_HOME);
883 if (!homedir)
884 homedir = multi_gnupg_path (0);
885 if (homedir) {
886 if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
887 val = log_box (_("Preferences"), MB_YESNO,
888 _("%s does not exit.\n"
889 "Do you want to create this directory?"), homedir);
890 if (val == IDYES) {
891 if (!CreateDirectory (homedir, NULL))
892 rc = WPTERR_DIR_CREAT;
893 }
894 else
895 rc = WPTERR_DIR_OPEN;
896 }
897 free_if_alloc (homedir);
898 }
899 return rc;
900 }
901
902
903 int
904 gnupg_copy_keyrings (void)
905 {
906 const char * pring, * sring;
907 char * file = NULL, * path = NULL;
908 int id = 0, rc = 0;
909 HWND hwnd;
910
911 path = get_gnupg_path ();
912 if (!path)
913 return WPTERR_GENERAL;
914 hwnd = GetDesktopWindow ();
915
916 pring = get_fileopen_dlg (hwnd, _("Please choose your public keyring"),
917 _("GPG Keyrings (*.gpg)\0*.gpg\0\0"),NULL);
918 if (!pring) {
919 msg_box (hwnd, _("No keyring was chosen. Exit."), _("WinPT Error"), MB_ERR);
920 free_if_alloc (path);
921 return WPTERR_GENERAL;
922 }
923 file = make_filename (path, "pubring", "gpg");
924 if (file_exist_check (file) == 0) {
925 id = msg_box (hwnd, _("Overwrite old public keyring?"), "WinPT", MB_INFO|MB_YESNO);
926 if (id == IDNO)
927 goto fail;
928 }
929 if (!CopyFile (pring, file, FALSE)) {
930 msg_box (hwnd, _("Could not copy file."), _("WinPT Error"), MB_ERR);
931 rc = WPTERR_FILE_READ;
932 goto fail;
933 }
934 free_if_alloc (file);
935
936 sring = get_fileopen_dlg (hwnd, _("Please choose your secret keyring"),
937 _("GPG Keyrings (*.gpg)\0*.gpg\0\0"), NULL);
938 if (!sring) {
939 msg_box( NULL, _("No keyring was chosen. Exit."), _("WinPT Error"), MB_ERR );
940 return WPTERR_GENERAL;
941 }
942 file = make_filename (path, "secring", "gpg");
943 if (file_exist_check (file) == 0) {
944 id = msg_box (hwnd, _("Overwrite old secret keyring?"), "WinPT", MB_INFO|MB_YESNO);
945 if( id == IDNO )
946 goto fail;
947 }
948 if (!CopyFile (sring, file, FALSE)) {
949 msg_box( NULL, _("Could not copy file."), _("WinPT Error"), MB_ERR);
950 rc = WPTERR_FILE_READ;
951 }
952
953 fail:
954 free_if_alloc (file);
955 free_if_alloc (path);
956 return rc;
957 } /* gnupg_import_keyrings */
958
959
960 /* Backup the gpg.conf file. */
961 void
962 gnupg_backup_options (void)
963 {
964 char *cfgfile = NULL;
965 char bak[512];
966
967 cfgfile = get_gnupg_cfgfile ();
968 if (!cfgfile)
969 return;
970 _snprintf (bak, DIM (bak)-1, "%s.bak", cfgfile);
971 CopyFile (cfgfile, bak, FALSE);
972 free_if_alloc (cfgfile);
973 }
974
975
976 static int
977 backup_one_file (const char *srcpath, const char *srcn,
978 const char *dstpath, const char *dstn)
979 {
980 char * src, * dst;
981 BOOL rc;
982
983 src = make_filename (srcpath, srcn, "gpg");
984 if (!src)
985 BUG (NULL);
986 dst = make_filename (dstpath, dstn, "gpg");
987 if (!dst)
988 BUG (NULL);
989 rc = CopyFile (src, dst, FALSE);
990 free_if_alloc (src);
991 free_if_alloc (dst);
992 if (!rc)
993 {
994 log_box (_("Backup"), MB_ERR, _("Backup keyring \"%s\" failed"), srcn);
995 return WPTERR_GENERAL;
996 }
997 return 0;
998 } /* backup_one_file */
999
1000
1001 /* Figure out first public keyring which is not empty.
1002 Return value: 1 on success. */
1003 static int
1004 check_keyring (char **r_path)
1005 {
1006 char *p;
1007 char *opt;
1008 char *name;
1009
1010 if (!*r_path)
1011 return 0;
1012 p = make_filename (*r_path, "pubring", "gpg");
1013 if (!p || get_file_size (p) <= 0)
1014 return 0;
1015
1016 opt = get_gnupg_cfgfile ();
1017 if (!opt)
1018 BUG (0);
1019 name = get_gnupg_keyring_from_options (opt, 1);
1020 free_if_alloc (opt);
1021 free_if_alloc (p);
1022 if (!name)
1023 return 0;
1024 p = strrchr (name, '\\');
1025 if (!p) {
1026 free_if_alloc (name);
1027 return 0;
1028 }
1029 free_if_alloc (*r_path);
1030 *r_path = new char [strlen (name)+1];
1031 memset (*r_path, 0, strlen (name));
1032 strncpy (*r_path, name, (p-name));
1033 free_if_alloc (name);
1034 return 1;
1035 }
1036
1037
1038 /* Return a temp name based on the day of the week. */
1039 static char*
1040 get_backup_name (const char *templ)
1041 {
1042 struct tm *tm;
1043 char *p;
1044 time_t t;
1045
1046 t = time (NULL);
1047 tm = localtime (&t);
1048 p = new char [strlen (templ) + 8 + 1];
1049 if (!p)
1050 BUG (0);
1051 sprintf (p, "%s-%d", templ, tm->tm_wday % 3);
1052 return p;
1053 }
1054
1055
1056 /* Make backups of all keyrings. The public key ring is
1057 rotated like this pubring-%d.gpg. */
1058 void
1059 gnupg_backup_keyrings (void)
1060 {
1061 char *srcpath = NULL, *dstpath = NULL;
1062 char *name=NULL;
1063 int rc, bakmode=0;
1064
1065 if (!reg_prefs.auto_backup)
1066 return;
1067 bakmode = reg_prefs.backup.mode;
1068 srcpath = get_gnupg_path ();
1069 check_keyring (&srcpath);
1070 if (bakmode == 1) {
1071 dstpath = multi_gnupg_path (1);
1072 check_keyring (&dstpath);
1073 }
1074 else if (bakmode == 2) {
1075 char *tmpfile;
1076 FILE *fp;
1077
1078 dstpath = m_strdup (reg_prefs.backup.path);
1079 if (!dstpath)
1080 BUG (0);
1081 tmpfile = make_filename (reg_prefs.backup.path, "test", "tmp");
1082 fp = fopen (tmpfile, "wb");
1083 if (!fp)
1084 rc = log_box (_("Backup"), MB_WARN|MB_RETRYCANCEL,
1085 _("The backup drive '%s' does not seems to accessable.\n"
1086 "Please insert/check the drive to continue."), dstpath);
1087 else {
1088 rc = 0;
1089 fclose (fp);
1090 remove (tmpfile);
1091 }
1092 free_if_alloc (tmpfile);
1093 if (!fp || rc == IDCANCEL)
1094 return;
1095 }
1096 else {
1097 log_box (_("Backup"), MB_ERR, _("Invalid backup mode %d"), bakmode);
1098 return;
1099 }
1100 name = get_backup_name ("pubring-bak");
1101 rc = backup_one_file (srcpath, "pubring", dstpath, name);
1102 if (!rc)
1103 rc = backup_one_file (srcpath, "secring", dstpath, "secring-bak");
1104 free_if_alloc (name);
1105 free_if_alloc (srcpath);
1106 free_if_alloc (dstpath);
1107 }
1108
1109
1110 /* Display GPG error from file if possible. */
1111 void
1112 gnupg_display_error (void)
1113 {
1114 char tmpath[512], * errstr;
1115 size_t size = 0;
1116 FILE * fp;
1117
1118 GetTempPath (sizeof tmpath - 32, (tmpath));
1119 strcat (tmpath, "gpg_stderr");
1120 size = get_file_size (tmpath);
1121 if (file_exist_check (tmpath) || size <= 0)
1122 return;
1123 fp = fopen( tmpath, "rb" );
1124 if (!fp) {
1125 msg_box (NULL, _("No GPG error description available."),
1126 _("GPG Error"), MB_INFO);
1127 return;
1128 }
1129 errstr = new char[size+1];
1130 if (!errstr)
1131 BUG (0);
1132 fread (errstr, 1, size, fp);
1133 errstr[size] = '\0';
1134 fclose (fp);
1135 msg_box (NULL, errstr, _("GPG Error"), MB_INFO);
1136 free_if_alloc (errstr);
1137 }
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