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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26