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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 333 - (hide annotations)
Tue Oct 13 10:51:21 2009 UTC (15 years, 4 months ago) by twoaday
File size: 26971 byte(s)


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