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

Annotation of /trunk/Src/wptGPG.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (hide annotations)
Mon Apr 17 09:12:50 2006 UTC (18 years, 10 months ago) by twoaday
File size: 26142 byte(s)
2006-04-16  Timo Schulz  <ts@g10code.de>
 
        * wptHTTP.cpp (getErrorCode): New.
        (connect): Store winsock error code.
        * wptGPGMEData.cpp (is_armor_header): New.
        * wptGPG.cpp (check_gnupg_engine): Free context.
        (gnupg_backup_keyrings): Do not use global vars.
        * wptGPGUtil.cpp (gpg_export_seckey): Export in ascii format.
         
2006-04-15  Timo Schulz  <ts@g10code.de>
 
        * wptKeyManager.cpp (km_get_key): New.
        (km_key_show_revoc_info): New.
        * wptKeyRevokeDlg.cpp (key_revoke_dlg): Cleanups.
        (on_init_dialog): New.
        * wptKeyManagerDlg.cpp (key_manager_dlg_proc): Factour
        out some common code and use km_get_key() instead.
        * wptKeyEditDlgs.cpp (do_init_keylist): Change second
        param type. Change all callers.
        * wptKeyEdit.cpp (addNotation): New.
        * wptKeyEditCB.cpp (editkey_command_handler): Remove 'step'
        param everywhere. Change all callers.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26