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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26