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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 304 - (hide annotations)
Wed Mar 21 10:59:31 2007 UTC (17 years, 11 months ago) by twoaday
File size: 27225 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26