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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 197 - (show annotations)
Mon Apr 10 07:38:06 2006 UTC (18 years, 10 months ago) by twoaday
File size: 26635 byte(s)
2006-04-09  Timo Schulz  <ts@g10code.de>
 
        * wptGPGPrefsDlg.cpp (gpgprefs_dlg_proc): Only return true
        if the homedir value was changed.
        * wptGPG.cpp (default_key_from_cache): Only return secret key
        if public part is available.
        (set_gnupg_default_key): Fix NULL problem.
        * wptKeyEditDlgs.cpp (do_editkey_clean): Set update flag.
        * wptFileCBS.cpp (write_cb, read_cb): Better error handling.
        * wptFileManagerDlg.cpp (file_manager_dlg_proc): Handle
        'always-on-top' correctly.
        * wptKeylist.cpp (keylist_get_recipients): Allocate enough
        mem to hold all possible keys.
        (keylist_enum_keys): Likewise.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26