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

Contents of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (show annotations)
Mon Apr 17 09:12:50 2006 UTC (18 years, 10 months ago) by twoaday
File size: 26142 byte(s)
2006-04-16  Timo Schulz  <ts@g10code.de>
 
        * wptHTTP.cpp (getErrorCode): New.
        (connect): Store winsock error code.
        * wptGPGMEData.cpp (is_armor_header): New.
        * wptGPG.cpp (check_gnupg_engine): Free context.
        (gnupg_backup_keyrings): Do not use global vars.
        * wptGPGUtil.cpp (gpg_export_seckey): Export in ascii format.
         
2006-04-15  Timo Schulz  <ts@g10code.de>
 
        * wptKeyManager.cpp (km_get_key): New.
        (km_key_show_revoc_info): New.
        * wptKeyRevokeDlg.cpp (key_revoke_dlg): Cleanups.
        (on_init_dialog): New.
        * wptKeyManagerDlg.cpp (key_manager_dlg_proc): Factour
        out some common code and use km_get_key() instead.
        * wptKeyEditDlgs.cpp (do_init_keylist): Change second
        param type. Change all callers.
        * wptKeyEdit.cpp (addNotation): New.
        * wptKeyEditCB.cpp (editkey_command_handler): Remove 'step'
        param everywhere. Change all callers.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26