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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 197 - (hide 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 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 twoaday 197 {
204     gpgme_key_t key, pk;
205     gpg_keycache_t sec, pub;
206 twoaday 73 const char *s;
207     char *keyid = NULL;
208 werner 36
209 twoaday 197 sec = keycache_get_ctx (0);
210 werner 36 if (!sec)
211     BUG (0);
212 twoaday 197 pub = keycache_get_ctx (1);
213 werner 36 gpg_keycache_rewind (sec);
214     while (!gpg_keycache_next_key (sec, 1, &key)) {
215 twoaday 197 if (key_is_useable (key) && !get_pubkey (key->subkeys->keyid, &pk)) {
216 werner 36 s = key->subkeys->keyid;
217     if (s)
218 twoaday 197 keyid = m_strdup (s+8);
219 werner 36 break;
220     }
221     }
222 twoaday 66 if (!keyid)
223 twoaday 197 *ret_no_useable = 1;
224 werner 36 return keyid;
225     }
226    
227    
228 twoaday 41 /* 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 twoaday 181 o = find_option (opt, "ask-cert-expire");
249     if (o)
250     reg_prefs.gpg.ask_cert_expire = 1;
251 twoaday 41 release_gpg_options (opt);
252     free_if_alloc (conf);
253     return 0;
254     }
255    
256    
257 werner 36 char*
258     get_gnupg_default_key (void)
259     {
260     gpg_optfile_t opt = NULL;
261     gpg_option_t e;
262 twoaday 197 char *keyid = NULL, *optfile = NULL;
263 werner 36 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 twoaday 73 free_if_alloc (optfile);
271     return default_key_from_cache (&no_usable);
272 werner 36 }
273 twoaday 197 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 werner 36 }
281 twoaday 197 if (!e) {
282     e = find_option (opt, "encrypt-to");
283     if (e)
284     keyid = m_strdup (e->val);
285 werner 36 }
286 twoaday 41 free_if_alloc (optfile);
287 twoaday 197 release_gpg_options (opt);
288 werner 36
289 twoaday 41 if (!keyid)
290     keyid = default_key_from_cache (&no_usable);
291 werner 36 return keyid;
292 twoaday 197 }
293 werner 36
294    
295 twoaday 73 /* 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 twoaday 74 return get_reg_entry_gpg4win ("gpg.exe");
301 twoaday 73 }
302    
303    
304 werner 36 /* Check if the gpg application (exe file) is available. */
305     int
306     check_gnupg_prog (void)
307     {
308 twoaday 73 char *gpgexe = NULL;
309 werner 36 int rc = 0;
310    
311 twoaday 73 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 werner 36 return rc;
322     }
323    
324    
325     static int
326 twoaday 137 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
327 werner 36 {
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 twoaday 78 while (buf && isdigit (*buf) && i < 8)
343 werner 36 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 twoaday 137 check_gnupg_engine (const char *need_gpg_ver,
355     int *r_major, int *r_minor, int *r_patch)
356 werner 36 {
357     gpgme_ctx_t ctx;
358     gpgme_engine_info_t inf;
359 twoaday 78 char *eng = NULL;
360 werner 36 int major=0, minor=0, patch=0;
361 twoaday 137 int need_major = 0, need_minor = 0, need_patch = 0;
362 twoaday 78 int rc = 1;
363 twoaday 137
364     /* Convert the needed GPG version to the integer format. */
365 twoaday 138 if (parse_version_nr (need_gpg_ver,
366     &need_major, &need_minor, &need_patch))
367     return 1;
368 twoaday 137
369 werner 36 gpgme_new (&ctx);
370     inf = gpgme_ctx_get_engine_info (ctx);
371     if (!inf) {
372     gpgme_release (ctx);
373     return -1;
374     }
375 twoaday 78
376 werner 36 /* 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 twoaday 138 if (parse_version_nr (inf->version, &major, &minor, &patch)) {
383 werner 36 gpgme_release (ctx);
384 twoaday 138 return 1;
385 werner 36 }
386 twoaday 78
387 twoaday 137 if (major > need_major)
388 werner 36 rc = 0;
389 twoaday 137 else if (major == need_major && minor > need_minor)
390 twoaday 78 rc = 0;
391 twoaday 137 else if (major == need_major && minor == need_minor &&
392     patch >= need_patch)
393 twoaday 78 rc = 0;
394    
395 twoaday 137 /* Return the current GPG version. */
396 werner 36 *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 twoaday 133 /* 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 werner 36 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 twoaday 133 create_empty_keyring (1);
460 werner 36 if (gnupg_access_keyring (1))
461     rc = WPTERR_GPG_KEYRINGS;
462     else
463     pubring_ok = 1;
464    
465 twoaday 133 create_empty_keyring (0);
466 werner 36 if (gnupg_access_keyring (0))
467     rc = WPTERR_GPG_KEYRINGS;
468     else
469     secring_ok = 1;
470 twoaday 73
471 werner 36 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 twoaday 73 if (!rc && get_file_size (optfile) > 0) {
477 werner 36 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 twoaday 133 }
495 werner 36
496    
497     static int
498     create_gpg_options (void)
499     {
500     FILE *fp;
501     char *s, *optfile;
502    
503 twoaday 73 s = get_gnupg_path ();
504 werner 36 if( s == NULL )
505     return WPTERR_FILE_CREAT;
506 twoaday 73 optfile = make_filename (s, GPG_CONF, NULL);
507 twoaday 133 fp = fopen (optfile, "wb");
508     if (fp == NULL) {
509 werner 36 return WPTERR_FILE_CREAT;
510     goto fail;
511     }
512 twoaday 133 fwrite (options_skel, 1, strlen (options_skel), fp);
513     fclose (fp);
514 werner 36
515     fail:
516 twoaday 133 free_if_alloc (s);
517     free_if_alloc (optfile);
518 werner 36 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 twoaday 179 /* Set the default key in the gpg.conf.
563     If @key is NULL, the entry will be deleted. */
564 werner 36 int
565 twoaday 179 set_gnupg_default_key (const char *key)
566 werner 36 {
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 twoaday 179 return WPTERR_FILE_OPEN;
575 werner 36 rc = parse_gpg_options (optfile, &opt);
576 twoaday 179 if (rc) {
577 werner 36 free_if_alloc (optfile);
578 twoaday 179 return WPTERR_GENERAL;
579 werner 36 }
580     e = find_option (opt, "default-key");
581 twoaday 179 if (e && !key)
582     e->used = 0;
583     else if (e) {
584 werner 36 free_if_alloc (e->val);
585     e->val = m_strdup (key);
586     e->used = 1;
587     }
588 twoaday 197 else if (key)
589 werner 36 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 twoaday 179 }
597 werner 36
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 twoaday 85
702     /* XXX: find a better way. without it, winpt --keymanager loads
703 twoaday 117 the key cache twice. */
704 twoaday 85 if (ctx->last_access.dwLowDateTime == 0)
705     ctx->modified = 0;
706 twoaday 117
707 werner 36 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 twoaday 128 my_access (const char *fname)
813 werner 36 {
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 twoaday 78 /* 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 werner 36 int
829     gpg_check_permissions (int showmsg)
830     {
831 twoaday 128 char *p = NULL;
832     char *name = NULL;
833 werner 36 int failed = 0, ans=0, attrs=0;
834    
835     p = get_gnupg_path ();
836 twoaday 128 if (check_keyring (&p) && p) {
837 werner 36 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 twoaday 78 /* All commands with write access will be disabled. */
854 werner 36 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 twoaday 128 free_if_alloc (p);
870 werner 36 free_if_alloc (name);
871     return failed;
872 twoaday 78 }
873 werner 36
874    
875 twoaday 128 /* 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 werner 36 {
880     char *homedir = NULL;
881 twoaday 128 int val = 0;
882 twoaday 73 int rc = 0;
883 werner 36
884 twoaday 73 homedir = get_reg_entry_gpg (GPG_REG_HOME);
885 twoaday 128 if (!homedir)
886 twoaday 73 homedir = multi_gnupg_path (0);
887 werner 36 if (homedir) {
888     if (GetFileAttributes (homedir) == 0xFFFFFFFF) {
889 twoaday 128 val = log_box (_("Preferences"), MB_YESNO,
890 werner 36 _("%s does not exit.\n"
891     "Do you want to create this directory?"), homedir);
892 twoaday 128 if (val == IDYES) {
893 twoaday 73 if (!CreateDirectory (homedir, NULL))
894     rc = WPTERR_DIR_CREAT;
895 werner 36 }
896 twoaday 73 else
897     rc = WPTERR_DIR_OPEN;
898 werner 36 }
899     free_if_alloc (homedir);
900     }
901 twoaday 73 return rc;
902 werner 36 }
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 twoaday 77 pring = get_fileopen_dlg (hwnd, _("Please choose your public keyring"),
919 twoaday 167 "GPG Keyrings (*.gpg)\0*.gpg\0\0",NULL);
920 werner 36 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 twoaday 77 sring = get_fileopen_dlg (hwnd, _("Please choose your secret keyring"),
939 twoaday 167 "GPG Keyrings (*.gpg)\0*.gpg\0\0", NULL);
940 werner 36 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 twoaday 128 /* Backup the gpg.conf file. */
963 werner 36 void
964     gnupg_backup_options (void)
965     {
966     char *cfgfile = NULL;
967     char bak[512];
968    
969     cfgfile = get_gnupg_cfgfile ();
970 twoaday 128 if (!cfgfile)
971 werner 36 return;
972     _snprintf (bak, DIM (bak)-1, "%s.bak", cfgfile);
973     CopyFile (cfgfile, bak, FALSE);
974     free_if_alloc (cfgfile);
975 twoaday 128 }
976 werner 36
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 twoaday 128 /* Figure out first public keyring which is not empty.
1004     Return value: 1 on success. */
1005 werner 36 static int
1006 twoaday 128 check_keyring (char **r_path)
1007 werner 36 {
1008 twoaday 128 char *p;
1009     char *opt;
1010     char *name;
1011 werner 36
1012     if (!*r_path)
1013     return 0;
1014     p = make_filename (*r_path, "pubring", "gpg");
1015 twoaday 128 if (!p || get_file_size (p) <= 0)
1016 werner 36 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 twoaday 128 if (!p) {
1028 werner 36 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 twoaday 128 /* Return a temp name based on the day of the week. */
1041 werner 36 static char*
1042     get_backup_name (const char *templ)
1043     {
1044     struct tm *tm;
1045     char *p;
1046 twoaday 128 time_t t;
1047 werner 36
1048 twoaday 128 t = time (NULL);
1049 werner 36 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 twoaday 117 /* Make backups of all keyrings. The public key ring is
1059     rotated like this pubring-%d.gpg. */
1060 werner 36 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 twoaday 117 srcpath = get_gnupg_path ();
1071 werner 36 check_keyring (&srcpath);
1072     if (bakmode == 1) {
1073 twoaday 117 dstpath = multi_gnupg_path (1);
1074 werner 36 check_keyring (&dstpath);
1075     }
1076     else if (bakmode == 2) {
1077 twoaday 117 char *tmpfile;
1078     FILE *fp;
1079 werner 36
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 twoaday 73 remove (tmpfile);
1093 werner 36 }
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 twoaday 117 }
1110 werner 36
1111    
1112     /* Display GPG error from file if possible. */
1113     void
1114     gnupg_display_error (void)
1115     {
1116 twoaday 175 char tmpath[512], *errstr;
1117 werner 36 size_t size = 0;
1118 twoaday 175 FILE *fp;
1119 werner 36
1120 twoaday 175 get_temp_name (tmpath, sizeof (tmpath), "gpg_stderr");
1121 werner 36 size = get_file_size (tmpath);
1122     if (file_exist_check (tmpath) || size <= 0)
1123     return;
1124     fp = fopen( tmpath, "rb" );
1125     if (!fp) {
1126 twoaday 128 msg_box (NULL, _("No GPG error description available."),
1127     _("GPG Error"), MB_INFO);
1128 werner 36 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