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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 222 - (hide annotations)
Thu Jun 1 08:30:46 2006 UTC (18 years, 9 months ago) by twoaday
File size: 26637 byte(s)
Applied some more patches.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26