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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26