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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 270 - (hide annotations)
Sat Oct 21 18:08:57 2006 UTC (18 years, 4 months ago) by twoaday
File size: 26184 byte(s)


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 twoaday 255 /* Context to monitor GPG file changes. */
47     struct gpg_monitor_s {
48     FILETIME last_access; /* last write access. */
49 werner 36 FILETIME access;
50 twoaday 255 char *object; /* name of the object. */
51     char *fpath_object; /* full path to the object. */
52     int modified; /* 1 = modified. */
53 werner 36 };
54 twoaday 255 typedef struct gpg_monitor_s *gpg_monitor_t;
55 werner 36
56 twoaday 255 static const char *gpg_objs[] = {"pubring.gpg", "secring.gpg", "trustdb.gpg"};
57     static gpg_monitor_s gpg_table[3];
58 werner 36 static int gpg_table_count = DIM (gpg_table);
59    
60 twoaday 255 int idea_available = 0; /* if the IDEA extension is available. */
61 werner 36
62 twoaday 255
63 werner 36 static int check_keyring (char ** r_path);
64    
65    
66     /* Return the application data folder of the current user. */
67 twoaday 128 char*
68 twoaday 73 multi_gnupg_path (int strict)
69 werner 36 {
70     static char buf[256+64];
71     BOOL ec;
72    
73     /* MSDN: buf must be at least MAX_PATH=256 bytes */
74     memset (buf, 0, sizeof (buf));
75     /* XXX: ec should be NOERROR (MSDN) but NOERROR is defined as '0' !? */
76     ec = SHGetSpecialFolderPath (HWND_DESKTOP, buf, CSIDL_APPDATA, TRUE);
77 twoaday 73 if (ec != 1) {
78     log_debug ("multi_gnupg_path: SHGetSpecialFolderPath() failed\r\n",
79     (int)GetLastError ());
80 werner 36 return NULL;
81 twoaday 73 }
82 werner 36 strcat (buf, "\\gnupg");
83 twoaday 73 if (strict && access (buf, 00))
84 werner 36 return NULL;
85     return m_strdup (buf);
86     }
87    
88    
89 twoaday 128 /* Return the full path to the GPG home directory. First the 'HomeDir' entry
90     from the registry is used. Then the default $APPDATA\gnupg path. */
91 werner 36 char*
92     get_gnupg_path (void)
93     {
94 twoaday 128 char *path;
95    
96     path = get_reg_entry_gpg (GPG_REG_HOME);
97 twoaday 248 if (path && dir_exist_check (path) == 0)
98     return path;
99     free_if_alloc (path);
100 twoaday 270 return multi_gnupg_path (1);
101 werner 36 }
102    
103    
104     /* Return the full path of the gpg config file.
105     A value of NULL indicates an error. */
106     char*
107     get_gnupg_cfgfile (void)
108 twoaday 255 {
109 twoaday 73 char *optfile = NULL;
110 twoaday 270 char *path;
111     size_t nlen;
112 werner 36
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 twoaday 270 BUG (NULL);
120 twoaday 200 _snprintf (optfile, nlen, "%s\\"GPG_CONF, path);
121    
122 werner 36 free_if_alloc (path);
123     return optfile;
124     }
125    
126    
127     /* Return the full path of the keyring. If @pub is 1, the public
128     keyring is return, otherwise the secret keyring. */
129     char*
130     get_gnupg_keyring (int pub, int strict)
131     {
132     char *optfile = NULL;
133     char *path = NULL;
134     char *keyring = NULL;
135    
136     path = get_gnupg_path ();
137     if (!path)
138     return NULL;
139     keyring = make_filename (path, pub? "pubring" : "secring", "gpg");
140 twoaday 133 if (strict && !file_exist_check (keyring)) {
141 werner 36 free_if_alloc (path);
142     return keyring;
143     }
144 twoaday 133 else if (!strict) {
145     free_if_alloc (path);
146     return keyring;
147     }
148 twoaday 66 if (file_exist_check (keyring) || pub && get_file_size (keyring) == 0) {
149 werner 36 free_if_alloc (keyring);
150     optfile = make_filename (path, GPG_CONF, NULL);
151     keyring = get_gnupg_keyring_from_options (optfile, pub);
152     }
153     free_if_alloc (path);
154     free_if_alloc (optfile);
155     return keyring;
156     }
157    
158    
159     /* Return the full path (with the gpg exe name). First the registry is scanned
160     for the entry 'gpgProgram'. If it wasn't set, the default path is the
161     appended string 'gpg.exe' is used. */
162     char*
163     get_gnupg_prog (void)
164     {
165 twoaday 248 char *path;
166     char *pgm;
167 werner 36
168 twoaday 248 pgm = get_reg_entry_gpg (GPG_REG_EXE);
169     if (pgm)
170     return pgm;
171     path = get_gnupg_path ();
172     if (!path)
173     return NULL;
174     pgm = make_filename (path, "gpg", "exe");
175 twoaday 270 free_if_alloc (path);
176 werner 36 return pgm;
177     }
178    
179    
180     /* Retrieve the first usable secret key from cache.
181     If no usable was found, @ret_no_useable is 1.
182     Return value: the keyid of the secret key. */
183 twoaday 255 static char*
184 werner 36 default_key_from_cache (int *ret_no_useable)
185 twoaday 197 {
186     gpgme_key_t key, pk;
187     gpg_keycache_t sec, pub;
188 twoaday 73 const char *s;
189     char *keyid = NULL;
190 werner 36
191 twoaday 197 sec = keycache_get_ctx (0);
192     pub = keycache_get_ctx (1);
193 werner 36 gpg_keycache_rewind (sec);
194     while (!gpg_keycache_next_key (sec, 1, &key)) {
195 twoaday 197 if (key_is_useable (key) && !get_pubkey (key->subkeys->keyid, &pk)) {
196 werner 36 s = key->subkeys->keyid;
197 twoaday 200 if (s)
198 twoaday 197 keyid = m_strdup (s+8);
199 werner 36 break;
200     }
201     }
202 twoaday 66 if (!keyid)
203 twoaday 248 *ret_no_useable = 1;
204 werner 36 return keyid;
205     }
206    
207    
208 twoaday 41 /* Load the gpg.conf and search for some options
209     and store the result in the global preference context.
210     Return value: 0 on success. */
211     int
212     gnupg_load_config (void)
213 twoaday 255 {
214 twoaday 41 gpg_optfile_t opt;
215 twoaday 200 char *conf;
216    
217     conf = get_gnupg_cfgfile ();
218 twoaday 41 if (!conf)
219     return -1;
220 twoaday 270 if (parse_config (conf, &opt)) {
221 twoaday 41 free_if_alloc (conf);
222     return -1;
223     }
224 twoaday 270 if (find_option (opt, "ask-cert-level"))
225 twoaday 41 reg_prefs.gpg.ask_cert_level = 1;
226 twoaday 270 if (find_option (opt, "ask-cert-expire"))
227 twoaday 181 reg_prefs.gpg.ask_cert_expire = 1;
228 twoaday 270 release_config (opt);
229 twoaday 41 free_if_alloc (conf);
230     return 0;
231     }
232    
233    
234 twoaday 214 /* handle the case the user added a '!' to force a subkey. */
235     static char*
236     extract_keyid (const char *val)
237     {
238     size_t len = strlen (val);
239    
240     if (len > 1 && val[len-1] == '!') {
241     char *p = new char[len+1];
242     if (!p)
243     BUG (0);
244     memset (p, 0, len+1);
245     memcpy (p, val, len-1);
246     return p;
247     }
248     return m_strdup (val);
249     }
250    
251    
252 werner 36 char*
253     get_gnupg_default_key (void)
254     {
255     gpg_optfile_t opt = NULL;
256     gpg_option_t e;
257 twoaday 197 char *keyid = NULL, *optfile = NULL;
258 twoaday 255 int no_usable=0;
259 werner 36
260     optfile = get_gnupg_cfgfile ();
261     if (!optfile)
262     return default_key_from_cache (&no_usable);
263 twoaday 270 if (parse_config (optfile, &opt)) {
264 twoaday 73 free_if_alloc (optfile);
265     return default_key_from_cache (&no_usable);
266 werner 36 }
267 twoaday 197 e = find_option (opt, "default-key");
268 twoaday 200 if (!e)
269     e = find_option (opt, "local-user");
270 twoaday 197 if (e)
271 twoaday 214 keyid = extract_keyid (e->val);
272 twoaday 200
273 twoaday 41 free_if_alloc (optfile);
274 twoaday 270 release_config (opt);
275 twoaday 41 if (!keyid)
276     keyid = default_key_from_cache (&no_usable);
277 werner 36 return keyid;
278 twoaday 197 }
279 werner 36
280    
281 twoaday 73 /* Check if GPG4WIN is available and if so, use the
282     install path to figure out where the gpg.exe is. */
283     char*
284     check_for_gpg4win (void)
285     {
286 twoaday 74 return get_reg_entry_gpg4win ("gpg.exe");
287 twoaday 73 }
288    
289    
290 werner 36 /* Check if the gpg application (exe file) is available. */
291     int
292     check_gnupg_prog (void)
293     {
294 twoaday 73 char *gpgexe = NULL;
295 werner 36 int rc = 0;
296    
297 twoaday 73 gpgexe = get_gnupg_prog ();
298     if (!gpgexe || file_exist_check (gpgexe)) {
299     free_if_alloc (gpgexe);
300     gpgexe = check_for_gpg4win ();
301     if (!gpgexe || file_exist_check (gpgexe))
302     rc = WPTERR_GPG_EXEFILE;
303     else
304     set_reg_entry_gpg (GPG_REG_EXE, gpgexe);
305     }
306     free_if_alloc (gpgexe);
307 werner 36 return rc;
308     }
309    
310    
311     static int
312 twoaday 137 parse_version_nr (const char *buf, int *major, int *minor, int *patch)
313 werner 36 {
314     char tmp[8];
315     int i;
316    
317     i=0;
318     while (buf && *buf != '.' && i < 8)
319     tmp[i++] = *buf++;
320     tmp[i] = 0; buf++;
321 twoaday 200 *major = atoi (tmp);
322 werner 36 i=0;
323     while (buf && *buf != '.' && i < 8)
324     tmp[i++] = *buf++;
325     tmp[i] = 0; buf++;
326 twoaday 200 *minor = atoi (tmp);
327 werner 36 i=0;
328 twoaday 78 while (buf && isdigit (*buf) && i < 8)
329 werner 36 tmp[i++] = *buf++;
330     tmp[i] = 0;
331 twoaday 200 *patch = atoi (tmp);
332 werner 36 return 0;
333     }
334    
335    
336     /* Check if the gnupg engine fullfills the minimum requirement
337     version given in @r_major.@r_minor.@r_patch. On success these
338     variables contain the GPG version which is installed. */
339     int
340 twoaday 137 check_gnupg_engine (const char *need_gpg_ver,
341     int *r_major, int *r_minor, int *r_patch)
342 werner 36 {
343     gpgme_ctx_t ctx;
344     gpgme_engine_info_t inf;
345 twoaday 78 char *eng = NULL;
346 werner 36 int major=0, minor=0, patch=0;
347 twoaday 137 int need_major = 0, need_minor = 0, need_patch = 0;
348 twoaday 78 int rc = 1;
349 twoaday 137
350     /* Convert the needed GPG version to the integer format. */
351 twoaday 138 if (parse_version_nr (need_gpg_ver,
352     &need_major, &need_minor, &need_patch))
353     return 1;
354 twoaday 137
355 werner 36 gpgme_new (&ctx);
356     inf = gpgme_ctx_get_engine_info (ctx);
357     if (!inf) {
358     gpgme_release (ctx);
359     return -1;
360     }
361 twoaday 78
362 werner 36 /* We need to exec GPG again to find out if IDEA is available. */
363 twoaday 248 if (gpg_get_version (&eng)) {
364     gpgme_release (ctx);
365 werner 36 return -1;
366 twoaday 248 }
367 werner 36 if (strstr (eng, "IDEA"))
368     idea_available = 1;
369 twoaday 200 safe_free (eng);
370 twoaday 138 if (parse_version_nr (inf->version, &major, &minor, &patch)) {
371 werner 36 gpgme_release (ctx);
372 twoaday 138 return 1;
373 werner 36 }
374 twoaday 200 gpgme_release (ctx);
375 twoaday 78
376 twoaday 137 if (major > need_major)
377 werner 36 rc = 0;
378 twoaday 137 else if (major == need_major && minor > need_minor)
379 twoaday 78 rc = 0;
380 twoaday 137 else if (major == need_major && minor == need_minor &&
381     patch >= need_patch)
382 twoaday 78 rc = 0;
383    
384 twoaday 137 /* Return the current GPG version. */
385 werner 36 *r_major = major;
386     *r_minor = minor;
387     *r_patch = patch;
388     return rc;
389     }
390    
391    
392 twoaday 255 /* Count the keyring entries in the gpg.conf file.
393     Return value: 0 on success. */
394     static int
395     cfgfile_count_keyrings (const char *fname, int *r_secrings, int *r_pubrings)
396 werner 36 {
397     gpg_optfile_t opt;
398     gpg_option_t e;
399    
400     *r_secrings = 0;
401     *r_pubrings = 0;
402 twoaday 248
403 twoaday 270 if (parse_config (fname, &opt))
404 werner 36 return WPTERR_FILE_OPEN;
405 twoaday 200 for (e = opt->list; e; e = e->next) {
406 twoaday 270 if (!strcmp (e->name, "secret-keyring")) {
407 twoaday 200 if (!file_exist_check (e->val))
408 werner 36 r_secrings[0]++;
409     }
410 twoaday 200 else if (!strcmp (e->name, "keyring")) {
411     if (!file_exist_check (e->val))
412 werner 36 r_pubrings[0]++;
413     }
414     }
415 twoaday 270 release_config (opt);
416 werner 36 return 0;
417 twoaday 200 }
418 werner 36
419    
420 twoaday 133 /* Usually GPG creates the pubring.gpg, secring.gpg on
421     the first start, but to make sure they always exist
422     create them empty if needed. */
423     static void
424     create_empty_keyring (int _pub)
425     {
426     char *name;
427 twoaday 200 FILE *fp;
428 twoaday 133
429     name = get_gnupg_keyring (_pub, 0);
430 twoaday 200 if (name && file_exist_check (name) != 0) {
431     fp = fopen (name, "ab");
432     if (fp != NULL)
433     fclose (fp);
434 twoaday 133 }
435     free_if_alloc (name);
436     }
437    
438    
439     /* Check if both keyrings are located in the gnupg home directory. */
440 werner 36 int
441     gnupg_access_files (void)
442     {
443     int rc = 0;
444     int pubring_ok = 0, secring_ok = 0;
445     int secrings = 0, pubrings = 0;
446     char *optfile;
447    
448 twoaday 133 create_empty_keyring (1);
449 werner 36 if (gnupg_access_keyring (1))
450     rc = WPTERR_GPG_KEYRINGS;
451     else
452     pubring_ok = 1;
453    
454 twoaday 133 create_empty_keyring (0);
455 werner 36 if (gnupg_access_keyring (0))
456     rc = WPTERR_GPG_KEYRINGS;
457     else
458     secring_ok = 1;
459 twoaday 73
460 werner 36 if (!pubring_ok || !secring_ok) {
461     optfile = get_gnupg_cfgfile ();
462     if (!optfile)
463     return WPTERR_GPG_KEYRINGS;
464     rc = file_exist_check (optfile);
465 twoaday 73 if (!rc && get_file_size (optfile) > 0) {
466 twoaday 255 rc = cfgfile_count_keyrings (optfile, &secrings, &pubrings);
467 twoaday 200 if (!rc && secrings > 0 && pubrings > 0) {
468 werner 36 free_if_alloc (optfile);
469     return 0; /* found two keyrings in the option file */
470     }
471     else if ((!rc && pubrings && secring_ok)
472     || (!rc && secrings && pubring_ok)) {
473     free_if_alloc (optfile);
474     return 0; /* found one keyring and one entry in the options file */
475     }
476     else
477     return WPTERR_GPG_OPT_KEYRINGS;
478     }
479     free_if_alloc (optfile);
480     rc = WPTERR_GPG_KEYRINGS;
481     }
482     return rc;
483 twoaday 133 }
484 werner 36
485    
486     static int
487 twoaday 255 create_gpg_conf (void)
488 werner 36 {
489     FILE *fp;
490     char *s, *optfile;
491    
492 twoaday 73 s = get_gnupg_path ();
493 twoaday 200 if (!s)
494 werner 36 return WPTERR_FILE_CREAT;
495 twoaday 73 optfile = make_filename (s, GPG_CONF, NULL);
496 twoaday 133 fp = fopen (optfile, "wb");
497 twoaday 200 if (!fp) {
498 werner 36 return WPTERR_FILE_CREAT;
499     goto fail;
500     }
501 twoaday 133 fwrite (options_skel, 1, strlen (options_skel), fp);
502     fclose (fp);
503 werner 36
504     fail:
505 twoaday 133 free_if_alloc (s);
506     free_if_alloc (optfile);
507 werner 36 return 0;
508 twoaday 200 }
509 werner 36
510    
511 twoaday 200 /* Return the contents of the options file as a char buf. */
512     char*
513 werner 36 get_gnupg_config (void)
514     {
515 twoaday 200 FILE *fp;
516     char *p = NULL, *optfile = NULL;
517 twoaday 255 int fsize;
518 werner 36
519     optfile = get_gnupg_cfgfile ();
520 twoaday 255 if (!optfile)
521 werner 36 return NULL;
522 twoaday 200 fsize = get_file_size (optfile);
523     if (!fsize) {
524 twoaday 255 if (create_gpg_conf ())
525 werner 36 return NULL;
526 twoaday 200 fsize = get_file_size (optfile);
527 werner 36 }
528 twoaday 200 if (fsize > 100000)
529 werner 36 goto leave; /* too large */
530     p = new char[fsize+1];
531 twoaday 200 if (!p)
532     BUG (NULL);
533 werner 36 fp = fopen( optfile, "rb" );
534 twoaday 200 if (!fp) {
535     free_if_alloc (p);
536 werner 36 return NULL;
537     }
538 twoaday 200 fread (p, 1, fsize, fp);
539     fclose (fp);
540 werner 36 p[fsize] = '\0';
541 twoaday 200 free_if_alloc (optfile);
542 werner 36
543     leave:
544     return p;
545 twoaday 200 }
546 werner 36
547    
548 twoaday 179 /* Set the default key in the gpg.conf.
549     If @key is NULL, the entry will be deleted. */
550 werner 36 int
551 twoaday 179 set_gnupg_default_key (const char *key)
552 werner 36 {
553     gpg_optfile_t opt;
554     gpg_option_t e;
555     char *optfile = NULL;
556     int rc = 0;
557    
558     optfile = get_gnupg_cfgfile ();
559     if (!optfile)
560 twoaday 179 return WPTERR_FILE_OPEN;
561 twoaday 270 rc = parse_config (optfile, &opt);
562 twoaday 179 if (rc) {
563 werner 36 free_if_alloc (optfile);
564 twoaday 179 return WPTERR_GENERAL;
565 werner 36 }
566     e = find_option (opt, "default-key");
567 twoaday 179 if (e && !key)
568     e->used = 0;
569     else if (e) {
570 werner 36 free_if_alloc (e->val);
571     e->val = m_strdup (key);
572     e->used = 1;
573     }
574 twoaday 197 else if (key)
575 werner 36 add_entry (opt, ENTRY_MULTI, "default-key", key);
576 twoaday 270 rc = commit_config (optfile, opt);
577 werner 36
578     free_if_alloc (optfile);
579 twoaday 270 release_config (opt);
580 werner 36 return rc;
581 twoaday 179 }
582 werner 36
583    
584 twoaday 200 /* Set the contents of the options file. */
585 werner 36 int
586 twoaday 248 set_gnupg_options (const char *buf, size_t buflen)
587 werner 36 {
588     FILE *fp;
589 twoaday 255 char *optfile;
590 werner 36
591 twoaday 248 optfile = get_gnupg_cfgfile ();
592     if (!optfile)
593 werner 36 return WPTERR_FILE_CREAT;
594    
595 twoaday 248 fp = fopen (optfile, "wb");
596     if (!fp) {
597     free_if_alloc (optfile);
598 werner 36 return WPTERR_FILE_CREAT;
599     }
600 twoaday 248 fwrite (buf, 1, buflen, fp);
601     fclose (fp);
602     free_if_alloc (optfile);
603 werner 36 return 0;
604 twoaday 248 }
605 werner 36
606 twoaday 248
607 twoaday 255 /* Check if the parameter for the option @buf is an existing file name.
608     Return value: 0 on success. */
609 werner 36 static int
610 twoaday 255 check_arg_file_exist (const char *buf)
611     {
612     const char *s = "load-extension ";
613    
614     /* XXX: this is a bit of a kludge because we just
615     detect errors for 'load-extension'. */
616     if (!strncmp (buf, s, strlen (s)))
617     buf += strlen (s);
618     else
619     return 0;
620     return file_exist_check (buf);
621     }
622    
623    
624     /* Check if the line contains a valid GPG argument. */
625     static int
626 twoaday 248 check_line (const char *buf)
627 werner 36 {
628     int j, len;
629 twoaday 255 int rc;
630 werner 36
631 twoaday 248 if (*buf == '#' || *buf == '\r' || *buf == '\n')
632 werner 36 return 1;
633     rc = 0;
634 twoaday 248 for (j = 0; valid_gpg_args[j]; j++) {
635     len = strlen (valid_gpg_args[j]);
636     if (!strncmp (valid_gpg_args[j], buf, len))
637     rc = 1;
638 werner 36 }
639     return rc;
640 twoaday 248 }
641 werner 36
642    
643     int
644 twoaday 255 check_gnupg_options (const char *buf, int showerr)
645 werner 36 {
646     char line[1024];
647 twoaday 255 int nbytes = 0, lineno=0;
648 werner 36 unsigned j;
649    
650 twoaday 255 for (j = 0; j < strlen (buf) && j < sizeof (line); j++) {
651 werner 36 line[nbytes++] = buf[j];
652 twoaday 255 if (buf[j] == '\n' || j == (strlen (buf) - 1)) {
653 werner 36 line[nbytes] = '\0';
654 twoaday 255 lineno++;
655     if (!check_line (line)) {
656     if (showerr)
657     log_box ("GPG Config File", MB_ERR,
658     "gpg.conf:%d: invalid keyword '%s'",
659     lineno, line);
660 werner 36 return 1;
661     }
662 twoaday 255 if (check_arg_file_exist (line))
663     return WPTERR_FILE_EXIST;
664 werner 36 nbytes = 0;
665 twoaday 255 }
666 werner 36 }
667     return 0;
668 twoaday 248 }
669 werner 36
670    
671     /* Store the last access of the file inside the watcher @ctx. */
672     static int
673 twoaday 255 get_last_gnupg_access (gpg_monitor_t ctx)
674 werner 36 {
675     HANDLE fd;
676    
677 twoaday 255 fd = CreateFile (ctx->fpath_object, GENERIC_READ, FILE_SHARE_READ,
678     NULL, OPEN_ALWAYS, 0, NULL);
679     if (fd == INVALID_HANDLE_VALUE)
680 werner 36 return WPTERR_FILE_OPEN;
681     GetFileTime (fd, NULL, NULL, &ctx->access);
682     CloseHandle (fd);
683     return 0;
684     }
685    
686    
687     /* Check if the file inside watcher @ctx was modified. */
688     static void
689 twoaday 255 check_last_gnupg_access (gpg_monitor_t ctx)
690 werner 36 {
691     ctx->modified = 0;
692    
693     if (ctx->last_access.dwHighDateTime != ctx->access.dwHighDateTime &&
694     ctx->last_access.dwLowDateTime != ctx->access.dwLowDateTime)
695     ctx->modified = 1;
696 twoaday 255
697 twoaday 85 if (ctx->last_access.dwLowDateTime == 0)
698     ctx->modified = 0;
699 twoaday 117
700 werner 36 ctx->last_access.dwLowDateTime = ctx->access.dwLowDateTime;
701     ctx->last_access.dwHighDateTime = ctx->access.dwHighDateTime;
702     }
703    
704    
705 twoaday 255 /* Init GPG monitor table for all monitored files. */
706 werner 36 void
707     init_gnupg_table (void)
708     {
709 twoaday 255 char *path;
710 werner 36 int j;
711    
712 twoaday 255 path = get_gnupg_path ();
713 werner 36 for (j = 0; j < gpg_table_count; j++) {
714 twoaday 255 gpg_table[j].object = m_strdup (gpg_objs[j]);
715     gpg_table[j].fpath_object = make_filename (path, gpg_objs[j], NULL);
716 werner 36 memset (&gpg_table[j].access, 0, sizeof (FILETIME));
717     memset (&gpg_table[j].last_access, 0, sizeof (FILETIME));
718     gpg_table[j].modified = 0;
719     }
720 twoaday 255 free_if_alloc (path);
721 werner 36 }
722    
723    
724 twoaday 255 /* Release the GPG monitor table. */
725 werner 36 void
726     free_gnupg_table (void)
727     {
728     int j;
729    
730 twoaday 255 for (j=0; j < gpg_table_count; j++) {
731 werner 36 free_if_alloc (gpg_table[j].object);
732 twoaday 255 free_if_alloc (gpg_table[j].fpath_object);
733     }
734 werner 36 }
735    
736    
737     /* Return the amount of files modified since the last call. */
738     int
739     keyring_check_last_access (void)
740 twoaday 255 {
741     int nfiles;
742     int pos;
743 werner 36
744 twoaday 255 nfiles = 0;
745     for (pos = 0; pos < gpg_table_count; pos++) {
746     get_last_gnupg_access (&gpg_table[pos]);
747     check_last_gnupg_access (&gpg_table[pos]);
748     if (gpg_table[pos].modified)
749     nfiles++;
750 werner 36 }
751    
752 twoaday 255 return nfiles;
753 werner 36 }
754    
755    
756     const char*
757     gnupg_check_file_ext (const char *fname, int *r_type)
758     {
759     char file_ext[5];
760    
761     if (r_type)
762     *r_type = PGP_NONE;
763     if (!strchr (fname, '.' ))
764     return "UNKNOWN";
765    
766     strncpy (file_ext, fname + strlen (fname) - 4, 4);
767     file_ext[4] = '\0';
768     if (!stricmp (file_ext, ".asc"))
769     return "ARMORED";
770     else if (!stricmp (file_ext, ".sig")) {
771     if (r_type)
772     *r_type = PGP_SIG;
773     return "SIGNED";
774     }
775 twoaday 255 else if (!stricmp (file_ext, ".gpg") ||
776     !stricmp (file_ext, ".pgp")) {
777 werner 36 if (r_type)
778     *r_type = PGP_MESSAGE;
779     return "ENCRYPTED";
780     }
781     return "UNKNOWN";
782     }
783    
784    
785     char*
786 twoaday 255 get_gnupg_keyring_from_options (const char *fname, int pub)
787 werner 36 {
788     gpg_optfile_t opt;
789     gpg_option_t e;
790 twoaday 255 char *kring = NULL;
791     int rc;
792 werner 36
793 twoaday 270 rc = parse_config (fname, &opt);
794 werner 36 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 twoaday 270 release_config (opt);
803 werner 36
804     return kring;
805     }
806    
807    
808 twoaday 255 /* Check if the device file @fname is stored on, is write-protected. */
809 werner 36 static int
810 twoaday 128 my_access (const char *fname)
811 werner 36 {
812     HANDLE hd;
813 twoaday 255
814 werner 36 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 twoaday 255 char *homedir;
880     int val;
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 twoaday 255 const char *pring, *sring;
908     char *file = NULL, *path = NULL;
909 werner 36 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 twoaday 255 char *cfgfile;
970     char bak[MAX_PATH+32];
971 werner 36
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     dst = make_filename (dstpath, dstn, "gpg");
990     rc = CopyFile (src, dst, FALSE);
991     free_if_alloc (src);
992     free_if_alloc (dst);
993 twoaday 200 if (!rc) {
994 werner 36 log_box (_("Backup"), MB_ERR, _("Backup keyring \"%s\" failed"), srcn);
995     return WPTERR_GENERAL;
996     }
997     return 0;
998 twoaday 200 }
999 werner 36
1000    
1001 twoaday 128 /* Figure out first public keyring which is not empty.
1002     Return value: 1 on success. */
1003 werner 36 static int
1004 twoaday 128 check_keyring (char **r_path)
1005 werner 36 {
1006 twoaday 128 char *p;
1007     char *opt;
1008     char *name;
1009 werner 36
1010     if (!*r_path)
1011     return 0;
1012     p = make_filename (*r_path, "pubring", "gpg");
1013 twoaday 255 if (get_file_size (p) <= 0)
1014 werner 36 return 0;
1015    
1016     opt = get_gnupg_cfgfile ();
1017     if (!opt)
1018     BUG (0);
1019     name = get_gnupg_keyring_from_options (opt, 1);
1020     free_if_alloc (opt);
1021     free_if_alloc (p);
1022     if (!name)
1023     return 0;
1024     p = strrchr (name, '\\');
1025 twoaday 128 if (!p) {
1026 werner 36 free_if_alloc (name);
1027     return 0;
1028     }
1029     free_if_alloc (*r_path);
1030     *r_path = new char [strlen (name)+1];
1031     memset (*r_path, 0, strlen (name));
1032     strncpy (*r_path, name, (p-name));
1033     free_if_alloc (name);
1034     return 1;
1035     }
1036    
1037    
1038 twoaday 128 /* Return a temp name based on the day of the week. */
1039 werner 36 static char*
1040     get_backup_name (const char *templ)
1041     {
1042     struct tm *tm;
1043     char *p;
1044 twoaday 128 time_t t;
1045 werner 36
1046 twoaday 128 t = time (NULL);
1047 werner 36 tm = localtime (&t);
1048     p = new char [strlen (templ) + 8 + 1];
1049     if (!p)
1050     BUG (0);
1051     sprintf (p, "%s-%d", templ, tm->tm_wday % 3);
1052     return p;
1053     }
1054    
1055    
1056 twoaday 222 /* Make backups of all keyrings. The public key ring is rotated like
1057     this pubring-%d.gpg.
1058     If @auto_backup is false, no action is performed.
1059     @include_secr indicated if the backup includes the secret keyring. */
1060 werner 36 void
1061 twoaday 222 gnupg_backup_keyrings (int auto_backup, int backup_mode, int include_secr)
1062 werner 36 {
1063     char *srcpath = NULL, *dstpath = NULL;
1064     char *name=NULL;
1065 twoaday 200 int rc;
1066 werner 36
1067 twoaday 200 if (!auto_backup)
1068 werner 36 return;
1069 twoaday 117 srcpath = get_gnupg_path ();
1070 werner 36 check_keyring (&srcpath);
1071 twoaday 200 if (backup_mode == 1) {
1072 twoaday 117 dstpath = multi_gnupg_path (1);
1073 werner 36 check_keyring (&dstpath);
1074     }
1075 twoaday 200 else if (backup_mode == 2) {
1076 twoaday 117 char *tmpfile;
1077     FILE *fp;
1078 werner 36
1079     dstpath = m_strdup (reg_prefs.backup.path);
1080     tmpfile = make_filename (reg_prefs.backup.path, "test", "tmp");
1081     fp = fopen (tmpfile, "wb");
1082     if (!fp)
1083     rc = log_box (_("Backup"), MB_WARN|MB_RETRYCANCEL,
1084 twoaday 248 _("The backup drive '%s' does not seems to be accessable.\n"
1085 werner 36 "Please insert/check the drive to continue."), dstpath);
1086     else {
1087     rc = 0;
1088     fclose (fp);
1089 twoaday 255 DeleteFile (tmpfile);
1090 werner 36 }
1091     free_if_alloc (tmpfile);
1092     if (!fp || rc == IDCANCEL)
1093     return;
1094     }
1095     else {
1096 twoaday 200 log_box (_("Backup"), MB_ERR, _("Invalid backup mode %d"), backup_mode);
1097 werner 36 return;
1098     }
1099     name = get_backup_name ("pubring-bak");
1100     rc = backup_one_file (srcpath, "pubring", dstpath, name);
1101 twoaday 222 if (!rc && include_secr)
1102 werner 36 rc = backup_one_file (srcpath, "secring", dstpath, "secring-bak");
1103     free_if_alloc (name);
1104     free_if_alloc (srcpath);
1105     free_if_alloc (dstpath);
1106 twoaday 117 }
1107 werner 36
1108    
1109     /* check that the requested GPG keyring exist and.
1110     Return value: 0 for success. */
1111     int
1112     gnupg_access_keyring (int _pub)
1113     {
1114     int rc = 0;
1115     char *name = get_gnupg_keyring (_pub, 1);
1116     if (!name || file_exist_check (name))
1117     rc = -1;
1118     free_if_alloc (name);
1119     return rc;
1120     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26