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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 181 - (hide annotations)
Tue Mar 14 11:01:22 2006 UTC (18 years, 11 months ago) by twoaday
File size: 26565 byte(s)
2006-03-12  Timo Schulz  <ts@g10code.de>
 
        * wptGPG.cpp (gnupg_load_config): Search for 'ask-cert-expire'.
        * wptKeyPropsDlg.cpp (display_key_info): Automatically update
        sym algorithm preferences if needed.
        * wptKeysignDlg.cpp (date_is_today): New.
        (keysign_dlg_proc): Only allow to set cert expire date if
        the option was found.
        * wptGPGPrefsDlg.cpp (gpgprefs_dlg_proc): Allow to set
        'ask-cert-expire'.
         


1 werner 36 /* wptGPG.cpp - GnuPG configuration
2 twoaday 41 * Copyright (C) 2001-2005 Timo Schulz
3 werner 36 *
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 werner 42 #ifdef HAVE_CONFIG_H
21     #include <config.h>
22     #endif
23    
24 twoaday 41 #include <windows.h>
25 werner 36 #include <string.h>
26     #include <stdio.h>
27     #include <shlobj.h>
28     #include <ctype.h>
29     #include <io.h>
30 twoaday 41 #include <time.h>
31 werner 36
32     #include "wptGPG.h"
33 werner 48 #include "wptGpgCmds.h"
34 werner 36 #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 twoaday 73 #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 werner 36
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 twoaday 128 char*
66 twoaday 73 multi_gnupg_path (int strict)
67 werner 36 {
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 twoaday 73 if (ec != 1) {
76     log_debug ("multi_gnupg_path: SHGetSpecialFolderPath() failed\r\n",
77     (int)GetLastError ());
78 werner 36 return NULL;
79 twoaday 73 }
80 werner 36 strcat (buf, "\\gnupg");
81 twoaday 73 if (strict && access (buf, 00))
82 werner 36 return NULL;
83     return m_strdup (buf);
84     }
85    
86    
87 twoaday 128 /* 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 werner 36 char*
90     get_gnupg_path (void)
91     {
92 twoaday 128 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 werner 36 }
100 twoaday 128 path = multi_gnupg_path (1);
101     return path;
102 werner 36 }
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 twoaday 73 char *p = NULL;
111     char *optfile = NULL;
112     char *path = NULL;
113 werner 36 size_t nlen = 0;
114    
115     path = get_gnupg_path ();
116     if (!path)
117     return NULL;
118     p = get_reg_entry_gpg ("OptFile");
119 twoaday 167 if (p) {
120     nlen = strlen (p) + 4;
121 werner 36 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 twoaday 133 if (strict && !file_exist_check (keyring)) {
153 werner 36 free_if_alloc (path);
154     return keyring;
155     }
156 twoaday 133 else if (!strict) {
157     free_if_alloc (path);
158     return keyring;
159     }
160 twoaday 66 if (file_exist_check (keyring) || pub && get_file_size (keyring) == 0) {
161 werner 36 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 werner 58
175     /* FIXME: Use gpgme's engine info here. */
176 werner 36 char*
177     get_gnupg_prog (void)
178     {
179     char *p;
180     char *pgm = NULL;
181    
182 twoaday 73 p = get_reg_entry_gpg (GPG_REG_EXE);
183 werner 36 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 twoaday 73 const char *s;
205     char *keyid = NULL;
206 werner 36 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 twoaday 66 if (!keyid)
221 werner 36 *ret_no_useable = 1;
222     return keyid;
223     }
224    
225    
226 twoaday 41 /* 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 twoaday 181 o = find_option (opt, "ask-cert-expire");
247     if (o)
248     reg_prefs.gpg.ask_cert_expire = 1;
249 twoaday 41 release_gpg_options (opt);
250     free_if_alloc (conf);
251     return 0;
252     }
253    
254    
255 werner 36 char*
256     get_gnupg_default_key (void)
257     {
258     gpg_optfile_t opt = NULL;
259     gpg_option_t e;
260     char * keyid = NULL, * optfile = NULL;
261     int no_usable=0, rc = 0;
262    
263     optfile = get_gnupg_cfgfile ();
264     if (!optfile)
265     return default_key_from_cache (&no_usable);
266     rc = parse_gpg_options (optfile, &opt);
267     if (rc) {
268 twoaday 73 free_if_alloc (optfile);
269     return default_key_from_cache (&no_usable);
270 werner 36 }
271     e = find_option( opt, "default-key" );
272     if ( e )
273     keyid = m_strdup( e->val );
274     if( !e ) {
275     e = find_option( opt, "local-user" );
276     if( e )
277     keyid = m_strdup( e->val );
278     }
279     if( !e ) {
280     e = find_option( opt, "encrypt-to" );
281     if( e )
282     keyid = m_strdup( e->val );
283     }
284 twoaday 41 free_if_alloc (optfile);
285     release_gpg_options (opt);
286 werner 36
287 twoaday 41 if (!keyid)
288     keyid = default_key_from_cache (&no_usable);
289 werner 36 return keyid;
290     } /* get_gnupg_default_key */
291    
292    
293 twoaday 73 /* Check if GPG4WIN is available and if so, use the
294     install path to figure out where the gpg.exe is. */
295     char*
296     check_for_gpg4win (void)
297     {
298 twoaday 74 return get_reg_entry_gpg4win ("gpg.exe");
299 twoaday 73 }
300    
301    
302 werner 36 /* Check if the gpg application (exe file) is available. */
303     int
304     check_gnupg_prog (void)
305     {
306 twoaday 73 char *gpgexe = NULL;
307 werner 36 int rc = 0;
308    
309 twoaday 73 gpgexe = get_gnupg_prog ();
310     if (!gpgexe || file_exist_check (gpgexe)) {
311     free_if_alloc (gpgexe);
312     gpgexe = check_for_gpg4win ();
313     if (!gpgexe || file_exist_check (gpgexe))
314     rc = WPTERR_GPG_EXEFILE;
315     else
316     set_reg_entry_gpg (GPG_REG_EXE, gpgexe);
317     }
318     free_if_alloc (gpgexe);
319 werner 36 return rc;
320     }
321    
322    
323     static int
324 twoaday 137 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
325 werner 36 {
326     char tmp[8];
327     int i;
328    
329     i=0;
330     while (buf && *buf != '.' && i < 8)
331     tmp[i++] = *buf++;
332     tmp[i] = 0; buf++;
333     *major = atol( tmp );
334     i=0;
335     while (buf && *buf != '.' && i < 8)
336     tmp[i++] = *buf++;
337     tmp[i] = 0; buf++;
338     *minor = atol (tmp);
339     i=0;
340 twoaday 78 while (buf && isdigit (*buf) && i < 8)
341 werner 36 tmp[i++] = *buf++;
342     tmp[i] = 0;
343     *patch = atol (tmp);
344     return 0;
345     }
346    
347    
348     /* Check if the gnupg engine fullfills the minimum requirement
349     version given in @r_major.@r_minor.@r_patch. On success these
350     variables contain the GPG version which is installed. */
351     int
352 twoaday 137 check_gnupg_engine (const char *need_gpg_ver,
353     int *r_major, int *r_minor, int *r_patch)
354 werner 36 {
355     gpgme_ctx_t ctx;
356     gpgme_engine_info_t inf;
357 twoaday 78 char *eng = NULL;
358 werner 36 int major=0, minor=0, patch=0;
359 twoaday 137 int need_major = 0, need_minor = 0, need_patch = 0;
360 twoaday 78 int rc = 1;
361 twoaday 137
362     /* Convert the needed GPG version to the integer format. */
363 twoaday 138 if (parse_version_nr (need_gpg_ver,
364     &need_major, &need_minor, &need_patch))
365     return 1;
366 twoaday 137
367 werner 36 gpgme_new (&ctx);
368     inf = gpgme_ctx_get_engine_info (ctx);
369     if (!inf) {
370     gpgme_release (ctx);
371     return -1;
372     }
373 twoaday 78
374 werner 36 /* We need to exec GPG again to find out if IDEA is available. */
375     if (gpg_get_version (&eng))
376     return -1;
377     if (strstr (eng, "IDEA"))
378     idea_available = 1;
379     free (eng);
380 twoaday 138 if (parse_version_nr (inf->version, &major, &minor, &patch)) {
381 werner 36 gpgme_release (ctx);
382 twoaday 138 return 1;
383 werner 36 }
384 twoaday 78
385 twoaday 137 if (major > need_major)
386 werner 36 rc = 0;
387 twoaday 137 else if (major == need_major && minor > need_minor)
388 twoaday 78 rc = 0;
389 twoaday 137 else if (major == need_major && minor == need_minor &&
390     patch >= need_patch)
391 twoaday 78 rc = 0;
392    
393 twoaday 137 /* Return the current GPG version. */
394 werner 36 *r_major = major;
395     *r_minor = minor;
396     *r_patch = patch;
397     return rc;
398     }
399    
400    
401     int
402     check_gnupg_cfgfile (const char *fname, int *r_secrings, int *r_pubrings)
403     {
404     gpg_optfile_t opt;
405     gpg_option_t e;
406     int rc = 0;
407    
408     *r_secrings = 0;
409     *r_pubrings = 0;
410     rc = parse_gpg_options( fname, &opt );
411     if( rc )
412     return WPTERR_FILE_OPEN;
413    
414     for( e = opt->list; e; e = e->next ) {
415     if( !strcmp( e->name, "secret-keyring" ) ) {
416     if( !file_exist_check( e->val ) )
417     r_secrings[0]++;
418     }
419     else if( !strcmp( e->name, "keyring" ) ) {
420     if( !file_exist_check( e->val ) )
421     r_pubrings[0]++;
422     }
423     }
424     release_gpg_options( opt );
425     return 0;
426     } /* check_gnupg_cfgfile */
427    
428    
429 twoaday 133 /* Usually GPG creates the pubring.gpg, secring.gpg on
430     the first start, but to make sure they always exist
431     create them empty if needed. */
432     static void
433     create_empty_keyring (int _pub)
434     {
435     char *name;
436     FILE *f;
437    
438     name = get_gnupg_keyring (_pub, 0);
439     if (file_exist_check (name) != 0) {
440     f = fopen (name, "ab");
441     if (f != NULL)
442     fclose (f);
443     }
444     free_if_alloc (name);
445     }
446    
447    
448     /* Check if both keyrings are located in the gnupg home directory. */
449 werner 36 int
450     gnupg_access_files (void)
451     {
452     int rc = 0;
453     int pubring_ok = 0, secring_ok = 0;
454     int secrings = 0, pubrings = 0;
455     char *optfile;
456    
457 twoaday 133 create_empty_keyring (1);
458 werner 36 if (gnupg_access_keyring (1))
459     rc = WPTERR_GPG_KEYRINGS;
460     else
461     pubring_ok = 1;
462    
463 twoaday 133 create_empty_keyring (0);
464 werner 36 if (gnupg_access_keyring (0))
465     rc = WPTERR_GPG_KEYRINGS;
466     else
467     secring_ok = 1;
468 twoaday 73
469 werner 36 if (!pubring_ok || !secring_ok) {
470     optfile = get_gnupg_cfgfile ();
471     if (!optfile)
472     return WPTERR_GPG_KEYRINGS;
473     rc = file_exist_check (optfile);
474 twoaday 73 if (!rc && get_file_size (optfile) > 0) {
475 werner 36 rc = check_gnupg_cfgfile (optfile, &secrings, &pubrings);
476     if (!rc && secrings && pubrings) {
477     free_if_alloc (optfile);
478     return 0; /* found two keyrings in the option file */
479     }
480     else if ((!rc && pubrings && secring_ok)
481     || (!rc && secrings && pubring_ok)) {
482     free_if_alloc (optfile);
483     return 0; /* found one keyring and one entry in the options file */
484     }
485     else
486     return WPTERR_GPG_OPT_KEYRINGS;
487     }
488     free_if_alloc (optfile);
489     rc = WPTERR_GPG_KEYRINGS;
490     }
491     return rc;
492 twoaday 133 }
493 werner 36
494    
495     static int
496     create_gpg_options (void)
497     {
498     FILE *fp;
499     char *s, *optfile;
500    
501 twoaday 73 s = get_gnupg_path ();
502 werner 36 if( s == NULL )
503     return WPTERR_FILE_CREAT;
504 twoaday 73 optfile = make_filename (s, GPG_CONF, NULL);
505 twoaday 133 fp = fopen (optfile, "wb");
506     if (fp == NULL) {
507 werner 36 return WPTERR_FILE_CREAT;
508     goto fail;
509     }
510 twoaday 133 fwrite (options_skel, 1, strlen (options_skel), fp);
511     fclose (fp);
512 werner 36
513     fail:
514 twoaday 133 free_if_alloc (s);
515     free_if_alloc (optfile);
516 werner 36 return 0;
517     } /* create_gpg_options */
518    
519    
520     /*
521     * Return the contents of the options file as a char buf.
522     */
523     char *
524     get_gnupg_config (void)
525     {
526     FILE * fp;
527     char * p = NULL, * optfile = NULL;
528     int fsize, rc = 0;
529    
530     optfile = get_gnupg_cfgfile ();
531     if( optfile == NULL )
532     return NULL;
533     fsize = get_file_size( optfile );
534     if( !fsize ) {
535     rc = create_gpg_options( );
536     if ( rc )
537     return NULL;
538     fsize = get_file_size( optfile );
539     }
540     if( fsize > 100000 )
541     goto leave; /* too large */
542     p = new char[fsize+1];
543     if( p == NULL )
544     BUG( NULL );
545     fp = fopen( optfile, "rb" );
546     if( fp == NULL ) {
547     free_if_alloc( p );
548     return NULL;
549     }
550     fread( p, 1, fsize, fp );
551     fclose( fp );
552     p[fsize] = '\0';
553     free_if_alloc( optfile );
554    
555     leave:
556     return p;
557     } /* get_gnupg_config */
558    
559    
560 twoaday 179 /* Set the default key in the gpg.conf.
561     If @key is NULL, the entry will be deleted. */
562 werner 36 int
563 twoaday 179 set_gnupg_default_key (const char *key)
564 werner 36 {
565     gpg_optfile_t opt;
566     gpg_option_t e;
567     char *optfile = NULL;
568     int rc = 0;
569    
570     optfile = get_gnupg_cfgfile ();
571     if (!optfile)
572 twoaday 179 return WPTERR_FILE_OPEN;
573 werner 36 rc = parse_gpg_options (optfile, &opt);
574 twoaday 179 if (rc) {
575 werner 36 free_if_alloc (optfile);
576 twoaday 179 return WPTERR_GENERAL;
577 werner 36 }
578     e = find_option (opt, "default-key");
579 twoaday 179 if (e && !key)
580     e->used = 0;
581     else if (e) {
582 werner 36 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 twoaday 179 }
595 werner 36
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 twoaday 85
700     /* XXX: find a better way. without it, winpt --keymanager loads
701 twoaday 117 the key cache twice. */
702 twoaday 85 if (ctx->last_access.dwLowDateTime == 0)
703     ctx->modified = 0;
704 twoaday 117
705 werner 36 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 twoaday 128 my_access (const char *fname)
811 werner 36 {
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 twoaday 78 /* 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 werner 36 int
827     gpg_check_permissions (int showmsg)
828     {
829 twoaday 128 char *p = NULL;
830     char *name = NULL;
831 werner 36 int failed = 0, ans=0, attrs=0;
832    
833     p = get_gnupg_path ();
834 twoaday 128 if (check_keyring (&p) && p) {
835 werner 36 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 twoaday 78 /* All commands with write access will be disabled. */
852 werner 36 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 twoaday 128 free_if_alloc (p);
868 werner 36 free_if_alloc (name);
869     return failed;
870 twoaday 78 }
871 werner 36
872    
873 twoaday 128 /* 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 werner 36 {
878     char *homedir = NULL;
879 twoaday 128 int val = 0;
880 twoaday 73 int rc = 0;
881 werner 36
882 twoaday 73 homedir = get_reg_entry_gpg (GPG_REG_HOME);
883 twoaday 128 if (!homedir)
884 twoaday 73 homedir = multi_gnupg_path (0);
885 werner 36 if (homedir) {
886     if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
887 twoaday 128 val = log_box (_("Preferences"), MB_YESNO,
888 werner 36 _("%s does not exit.\n"
889     "Do you want to create this directory?"), homedir);
890 twoaday 128 if (val == IDYES) {
891 twoaday 73 if (!CreateDirectory (homedir, NULL))
892     rc = WPTERR_DIR_CREAT;
893 werner 36 }
894 twoaday 73 else
895     rc = WPTERR_DIR_OPEN;
896 werner 36 }
897     free_if_alloc (homedir);
898     }
899 twoaday 73 return rc;
900 werner 36 }
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 twoaday 77 pring = get_fileopen_dlg (hwnd, _("Please choose your public keyring"),
917 twoaday 167 "GPG Keyrings (*.gpg)\0*.gpg\0\0",NULL);
918 werner 36 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 twoaday 77 sring = get_fileopen_dlg (hwnd, _("Please choose your secret keyring"),
937 twoaday 167 "GPG Keyrings (*.gpg)\0*.gpg\0\0", NULL);
938 werner 36 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 twoaday 128 /* Backup the gpg.conf file. */
961 werner 36 void
962     gnupg_backup_options (void)
963     {
964     char *cfgfile = NULL;
965     char bak[512];
966    
967     cfgfile = get_gnupg_cfgfile ();
968 twoaday 128 if (!cfgfile)
969 werner 36 return;
970     _snprintf (bak, DIM (bak)-1, "%s.bak", cfgfile);
971     CopyFile (cfgfile, bak, FALSE);
972     free_if_alloc (cfgfile);
973 twoaday 128 }
974 werner 36
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 twoaday 128 /* Figure out first public keyring which is not empty.
1002     Return value: 1 on success. */
1003 werner 36 static int
1004 twoaday 128 check_keyring (char **r_path)
1005 werner 36 {
1006 twoaday 128 char *p;
1007     char *opt;
1008     char *name;
1009 werner 36
1010     if (!*r_path)
1011     return 0;
1012     p = make_filename (*r_path, "pubring", "gpg");
1013 twoaday 128 if (!p || get_file_size (p) <= 0)
1014 werner 36 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 twoaday 128 if (!p) {
1026 werner 36 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 twoaday 128 /* Return a temp name based on the day of the week. */
1039 werner 36 static char*
1040     get_backup_name (const char *templ)
1041     {
1042     struct tm *tm;
1043     char *p;
1044 twoaday 128 time_t t;
1045 werner 36
1046 twoaday 128 t = time (NULL);
1047 werner 36 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 twoaday 117 /* Make backups of all keyrings. The public key ring is
1057     rotated like this pubring-%d.gpg. */
1058 werner 36 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 twoaday 117 srcpath = get_gnupg_path ();
1069 werner 36 check_keyring (&srcpath);
1070     if (bakmode == 1) {
1071 twoaday 117 dstpath = multi_gnupg_path (1);
1072 werner 36 check_keyring (&dstpath);
1073     }
1074     else if (bakmode == 2) {
1075 twoaday 117 char *tmpfile;
1076     FILE *fp;
1077 werner 36
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 twoaday 73 remove (tmpfile);
1091 werner 36 }
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 twoaday 117 }
1108 werner 36
1109    
1110     /* Display GPG error from file if possible. */
1111     void
1112     gnupg_display_error (void)
1113     {
1114 twoaday 175 char tmpath[512], *errstr;
1115 werner 36 size_t size = 0;
1116 twoaday 175 FILE *fp;
1117 werner 36
1118 twoaday 175 get_temp_name (tmpath, sizeof (tmpath), "gpg_stderr");
1119 werner 36 size = get_file_size (tmpath);
1120     if (file_exist_check (tmpath) || size <= 0)
1121     return;
1122     fp = fopen( tmpath, "rb" );
1123     if (!fp) {
1124 twoaday 128 msg_box (NULL, _("No GPG error description available."),
1125     _("GPG Error"), MB_INFO);
1126 werner 36 return;
1127     }
1128     errstr = new char[size+1];
1129     if (!errstr)
1130     BUG (0);
1131     fread (errstr, 1, size, fp);
1132     errstr[size] = '\0';
1133     fclose (fp);
1134     msg_box (NULL, errstr, _("GPG Error"), MB_INFO);
1135     free_if_alloc (errstr);
1136     }
1137    
1138    
1139    
1140     /* check that the requested GPG keyring exist and.
1141     Return value: 0 for success. */
1142     int
1143     gnupg_access_keyring (int _pub)
1144     {
1145     int rc = 0;
1146     char *name = get_gnupg_keyring (_pub, 1);
1147     if (!name || file_exist_check (name))
1148     rc = -1;
1149     free_if_alloc (name);
1150     return rc;
1151     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26