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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 179 - (show annotations)
Fri Feb 24 13:12:26 2006 UTC (19 years ago) by twoaday
File size: 26472 byte(s)
Prepare 0.11.8


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26