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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 248 - (hide annotations)
Fri Jul 28 11:11:09 2006 UTC (18 years, 7 months ago) by twoaday
File size: 26386 byte(s)
Prepare 1.0.0pre2 release.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26