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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 295 - (hide annotations)
Tue Mar 13 18:53:40 2007 UTC (17 years, 11 months ago) by twoaday
File size: 27383 byte(s)


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26