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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 407 - (hide annotations)
Mon Feb 6 19:26:03 2012 UTC (13 years ago) by twoaday
File size: 26784 byte(s)
2012-02-06  Timo Schulz  <twoaday@gmx.net>

        * wptNLS.cpp (gettext_free_current_domain): Replace free()
	        with safe_free():
        * WinPT.cpp: Use log_debug to improve bug tracking capabilities.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26