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

Annotation of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Wed Oct 26 11:20:09 2005 UTC (19 years, 4 months ago) by twoaday
File size: 16407 byte(s)
2005-10-25  Timo Schulz  <twoaday@g10code.com>
                                                                                
        * wptGPGUtil.cpp (create_process): Hide window.
        * wptKeyPropsDlg.cpp (get_photo_tmpname): New.
        * wptClipSignEncDlg.cpp (clip_signenc_dlg_proc): Remove
        static var 'enable'.
        * wptKeygenDlg.cpp (keygen_dlg_proc): Likewise.
        (gpg_genkey_params): Make sure all primary keys are capable
        for signing and certification.
        * wptKeySigDlg.cpp (is_sig): If no item is selected, return 0.
        * wptGPG.cpp (gnupg_access_keyring): Check return value for
        NULL. Noted by Ralf.
        (get_gnupg_prog): Simplified.
        (check_homedir): Fixed. Return 0 when the dir is successfully created.
        * wptKeyManagerDlg.cpp (km_file_import): Use the hourglass to
        indicate a pending GPG process.
        * wptFileManager.cpp (op_begin, op_end): New. Indicate an start
        and and of an operation. For now just the cursor changes.
        (fm_parse_command_line): Remove debug output. Thanks to Ralf again.
        * WinPT.cpp (WinMain): Check if there is already an instance and
        set a variable early as possible.
        (load_gettext): If a previous instance was found, do not output
        any errors. Kudos to Ralf.


1 twoaday 25 /* wptGPGUtil.cpp - GPG helper functions
2     * Copyright (C) 2005 g10 Code GmbH
3     *
4     * This file is part of WinPT.
5     *
6     * WinPT is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (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
14     * GNU 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     #include <windows.h>
21     #include <sys/stat.h>
22    
23     #include "gpgme.h"
24    
25    
26     #define NROFHEXDIGITS 2
27     /* Convert two hexadecimal digits from STR to the value they
28     represent. Returns -1 if one of the characters is not a
29     hexadecimal digit. */
30     static int
31     hextobyte (const unsigned char *str)
32     {
33     int val = 0;
34     int i;
35    
36     for (i = 0; i < NROFHEXDIGITS; i++) {
37     if (*str >= '0' && *str <= '9')
38     val += *str - '0';
39     else if (*str >= 'A' && *str <= 'F')
40     val += 10 + *str - 'A';
41     else if (*str >= 'a' && *str <= 'f')
42     val += 10 + *str - 'a';
43     else
44     return -1;
45     if (i < NROFHEXDIGITS - 1)
46     val *= 16;
47     str++;
48     }
49     return val;
50     }
51    
52     /* Decode the C formatted string @src and store the result in the
53     buffer @destp which is @len bytes long. If @len is zero, then a
54     large enough buffer is allocated with malloc and @destp is set to
55     the result. Currently, @len is only used to specify if allocation
56     is desired or not, the caller is expected to make sure that @destp
57     is large enough if @len is not zero. */
58     gpgme_error_t
59     gpg_decode_c_string (const char *src, char **destp, size_t len)
60     {
61     char *dest;
62    
63     /* Set up the destination buffer. */
64     if (len) {
65     if (len < strlen (src) + 1)
66     return gpg_error (GPG_ERR_TOO_SHORT);
67     dest = *destp;
68     }
69     else {
70     /* The converted string will never be larger than the original string. */
71     dest = (char*)malloc (strlen (src) + 1);
72     if (!dest)
73     return gpg_error (GPG_ERR_ENOMEM);
74     *destp = dest;
75     }
76    
77     /* Convert the string. */
78     while (*src) {
79     if (*src != '\\') {
80     *(dest++) = *(src++);
81     continue;
82 twoaday 32 }
83 twoaday 25
84     switch (src[1]) {
85     #define DECODE_ONE(match,result) \
86     case match: \
87     src += 2; \
88     *(dest++) = result; \
89     break;
90    
91     DECODE_ONE ('\'', '\'');
92     DECODE_ONE ('\"', '\"');
93     DECODE_ONE ('\?', '\?');
94     DECODE_ONE ('\\', '\\');
95     DECODE_ONE ('a', '\a');
96     DECODE_ONE ('b', '\b');
97     DECODE_ONE ('f', '\f');
98     DECODE_ONE ('n', '\n');
99     DECODE_ONE ('r', '\r');
100     DECODE_ONE ('t', '\t');
101     DECODE_ONE ('v', '\v');
102    
103     case 'x': {
104     int val = hextobyte ((unsigned char*)&src[2]);
105 twoaday 32 if (val == -1) { /* Should not happen. */
106 twoaday 25 *(dest++) = *(src++);
107     *(dest++) = *(src++);
108     if (*src)
109     *(dest++) = *(src++);
110     if (*src)
111     *(dest++) = *(src++);
112     }
113     else {
114 twoaday 32 if (!val) {
115     /* A binary zero is not representable in a C string. */
116 twoaday 25 *(dest++) = '\\';
117     *(dest++) = '0';
118     }
119     else
120     *((unsigned char *) dest++) = val;
121     src += 4;
122     }
123     }
124    
125 twoaday 32 default: /* Should not happen. */
126 twoaday 25 {
127     *(dest++) = *(src++);
128     *(dest++) = *(src++);
129     }
130     }
131     }
132     *(dest++) = 0;
133     return 0;
134     }
135    
136     /* Replace %foo% entries with its real values.
137     Return value: expanded path or NULL on error. */
138     static char *
139     expand_path (const char *path)
140     {
141     DWORD len;
142     char *p;
143    
144     len = ExpandEnvironmentStrings (path, NULL, 0);
145     if (!len)
146     return NULL;
147     len += 1;
148     p = (char*)calloc (1, len+1);
149     if (!p)
150     abort ();
151     len = ExpandEnvironmentStrings (path, p, len);
152     if (!len) {
153     free (p);
154     return NULL;
155     }
156     return p;
157     }
158    
159    
160     /* Read a string from the W32 registry. The directory is given
161     in @dir and the name of the value in @name, */
162     static char *
163 twoaday 32 read_w32_registry (HKEY root_key, const char *dir, const char *name)
164 twoaday 25 {
165     HKEY key_handle;
166     DWORD n1, nbytes;
167     DWORD type;
168     char *result = NULL;
169    
170     if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
171     return NULL; /* no need for a RegClose, so return direct */
172    
173     nbytes = 1;
174     if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
175     goto leave;
176     result = (char*)calloc (1, (n1=nbytes+1));
177     if (!result)
178     abort ();
179     if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {
180     free (result);
181     result = NULL;
182     goto leave;
183     }
184     if (type == REG_EXPAND_SZ && strchr (result, '%')) {
185     char *p = expand_path (result);
186     free (result);
187     result = p;
188     }
189    
190     leave:
191     RegCloseKey (key_handle);
192     return result;
193     }
194    
195    
196     /* Create a temp file based on the name of @name.
197     Return value: handle to the file in case of success. */
198     static HANDLE
199     create_tmpfile (const char *name)
200     {
201     HANDLE out;
202     SECURITY_ATTRIBUTES sattr;
203     char tmp[300];
204    
205     memset (&sattr, 0, sizeof sattr);
206     sattr.bInheritHandle = TRUE;
207     sattr.lpSecurityDescriptor = NULL;
208     sattr.nLength = sizeof sattr;
209    
210 twoaday 33 GetTempPath (sizeof (tmp)-1 - strlen (name)-1, tmp);
211 twoaday 25 strcat (tmp, name);
212     out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,
213     FILE_SHARE_WRITE, &sattr,
214     OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
215     return out;
216     }
217    
218    
219     /* Create a pipe with a readable remote end and
220     write the data from @dat to the local end.
221     Return value: read handle on success. */
222     static HANDLE
223     create_in_pipe (const char *dat)
224     {
225     HANDLE r, w;
226     SECURITY_ATTRIBUTES sec_attr;
227     DWORD n;
228    
229     memset (&sec_attr, 0, sizeof sec_attr);
230     sec_attr.bInheritHandle = TRUE;
231     sec_attr.nLength = sizeof sec_attr;
232    
233     if (!CreatePipe (&r, &w, &sec_attr, 4096))
234     return NULL;
235    
236     WriteFile (w, dat, strlen (dat), &n, NULL);
237     CloseHandle (w);
238    
239     return r;
240     }
241    
242    
243     /* Map the contents of the file handle @out to
244     a buffer and return it. */
245     static char*
246     map_tmpfile (HANDLE out)
247     {
248     DWORD n;
249     char *p;
250    
251     FlushFileBuffers (out);
252     SetFilePointer (out, 0, NULL, FILE_BEGIN);
253     n = GetFileSize (out, NULL);
254     p = (char*)calloc (1, n+1);
255     if (!p)
256     abort ();
257     ReadFile (out, p, n, &n, NULL);
258     p[n] = 0;
259     return p;
260     }
261    
262    
263     /* Create a process from the command line in @cmd.
264     If @out is != NULL, the output of the process will
265     be redirected to @out. If @in is != NULL the input
266     will be read from @in.
267     Return value: 0 on success. */
268     static int
269     create_process (const char *cmd, HANDLE in, HANDLE out)
270     {
271     STARTUPINFO si;
272     PROCESS_INFORMATION pi;
273    
274     memset (&si, 0, sizeof (si));
275     si.cb = sizeof si;
276     if (in || out)
277 twoaday 34 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
278 twoaday 25 if (out)
279     si.hStdOutput = out;
280     if (in)
281     si.hStdInput = in;
282 twoaday 34 si.wShowWindow = SW_HIDE;
283 twoaday 32 if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
284     NULL, NULL, &si, &pi))
285 twoaday 25 return -1;
286     WaitForSingleObject (pi.hProcess, INFINITE);
287     CloseHandle (pi.hProcess);
288     return 0;
289     }
290    
291    
292     /* Export a GPG secret key given by @keyid into the file @outfile.
293     Return value: 0 on success. */
294     gpgme_error_t
295     gpg_export_seckey (const char *keyid, const char *outfile)
296     {
297     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
298     struct stat st;
299     char *p;
300     char *cmd;
301    
302 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
303     "Software\\GNU\\GnuPG", "gpgProgram");
304 twoaday 25 if (!p)
305     return gpg_error (GPG_ERR_INV_ARG);
306 twoaday 32 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)
307     + strlen (outfile) + 64 + 2);
308 twoaday 25 if (!cmd)
309     abort ();
310 twoaday 32 sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s",
311     p, outfile, keyid);
312 twoaday 25 if (create_process (cmd, NULL, NULL))
313     err = gpg_error (GPG_ERR_INTERNAL);
314    
315     if (stat (outfile, &st) == -1 || st.st_size == 0)
316     err = gpg_error (GPG_ERR_NO_DATA);
317    
318     free (p);
319     free (cmd);
320     return err;
321     }
322    
323    
324     /* If @export is 1, export the ownertrust data to the
325     buffer @data. Otherwise import the ownertrust data from @data.
326     Return value: 0 on success. */
327     gpgme_error_t
328     gpg_manage_ownertrust (char **data, int export)
329     {
330     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
331     HANDLE out = NULL, in = NULL;
332     char *p;
333     char *cmd;
334    
335 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
336     "Software\\GNU\\GnuPG", "gpgProgram");
337 twoaday 25 if (!p)
338     return gpg_error (GPG_ERR_INV_ARG);
339    
340     cmd = (char*)calloc (1, strlen (p) + 64 + 1);
341     if (!cmd)
342     abort ();
343 twoaday 32 sprintf (cmd, "%s %s", p,
344     export? "--export-ownertrust" : "--import-ownertrust");
345 twoaday 25
346     if (export)
347     out = create_tmpfile ("gpg_ot_out");
348     else {
349     DWORD nw;
350     in = create_tmpfile ("gpg_ot_in");
351     WriteFile (in, *data, strlen (*data), &nw, NULL);
352     FlushFileBuffers (in);
353     /* XXX: need a rewind? */
354     }
355     if (create_process (cmd, in, out))
356     err = gpg_error (GPG_ERR_INTERNAL);
357    
358     free (p);
359     free (cmd);
360    
361     if (in)
362     CloseHandle (in);
363     if (out) {
364     *data = map_tmpfile (out);
365     CloseHandle (out);
366     }
367     return err;
368     }
369    
370 twoaday 32
371 twoaday 25 /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
372     gpgme_error_t
373     gpg_rebuild_cache (char **r_inf)
374     {
375     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
376     HANDLE out = NULL;
377     char *p;
378     char *cmd;
379    
380 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
381     "Software\\GNU\\GnuPG", "gpgProgram");
382 twoaday 25 if (!p)
383     return gpg_error (GPG_ERR_INV_ARG);
384     cmd = (char*)calloc (1, strlen (p) + 64);
385     if (!cmd)
386     abort ();
387     sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);
388    
389     if (r_inf)
390     out = create_tmpfile ("gpg_rebuild_cache");
391    
392     if (create_process (cmd, NULL, out))
393     err = gpg_error (GPG_ERR_INTERNAL);
394    
395     if (r_inf)
396     *r_inf = map_tmpfile (out);
397     if (out)
398     CloseHandle (out);
399     free (p);
400     free (cmd);
401     return 0;
402     }
403    
404 twoaday 32
405 twoaday 25 /* Call gpg --version to retrieve the 'about' information. */
406     gpgme_error_t
407     gpg_get_version (char **r_inf)
408     {
409     gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
410     HANDLE out;
411     char *p, *cmd;
412    
413 twoaday 32 p =read_w32_registry (HKEY_CURRENT_USER,
414     "Software\\GNU\\GnuPG", "gpgProgram");
415 twoaday 25 if (!p)
416     return gpg_error (GPG_ERR_INV_ARG);
417     cmd = (char*)calloc (1, strlen (p) + 32);
418     if (!cmd)
419     abort ();
420     sprintf (cmd, "%s --version", p);
421    
422     out = create_tmpfile ("gpg_out");
423     if (create_process (cmd, NULL, out))
424     err = gpg_error (GPG_ERR_INTERNAL);
425    
426     free (p);
427     free (cmd);
428    
429     *r_inf = map_tmpfile (out);
430     CloseHandle (out);
431     return err;
432     }
433    
434 twoaday 32
435 twoaday 25 /* Return the colon file output of the given file @fname in @r_out.
436     Return value: 0 on success. */
437     gpgme_error_t
438     gpg_import_key_list (const char *fname, char **r_out)
439     {
440     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
441     char *cmd, *p;
442     HANDLE out;
443    
444 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
445     "Software\\GNU\\GnuPG", "gpgProgram");
446 twoaday 25 if (!p)
447     return gpg_error (GPG_ERR_INV_ARG);
448    
449     cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);
450     if (!cmd)
451     abort ();
452     sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);
453    
454     out = create_tmpfile ("gpg_keys");
455     if (create_process (cmd, NULL, out))
456     err = gpg_error (GPG_ERR_INTERNAL);
457    
458     free (p);
459     free (cmd);
460    
461     *r_out = map_tmpfile (out);
462     CloseHandle (out);
463     return err;
464     }
465    
466     char*
467     generate_revoc_input (int code, const char *cmt, const char *pass)
468     {
469     const char *fmt;
470     char *p;
471     size_t n;
472    
473     fmt = "Y\n" /* gen_revoke.okay */
474     "%d\n" /* ask_revocation_reason.code */
475     "%s\n" /* ask_revocation_reason.text */
476     "%s" /* text != NULL '\n' otherwise '' */
477     "Y\n" /* ask_revocation_reason.okay */
478     "%s\n"; /* passphrase.enter. */
479     n = strlen (fmt) + 32;
480     if (pass)
481     n += strlen (pass) + 1;
482     if (cmt)
483     n += strlen (cmt) + 1;
484     p = (char*)calloc (1, n+1);
485     if (!p)
486     abort ();
487     sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");
488     return p;
489     }
490    
491    
492     /* Generate a revocation certificate for the key with the keyid @keyid.
493     @inp_data contains all needed data to answer the questions of the
494     command handler. Each separate with a '\n'.
495     @r_revcert contains the revocation cert on success.
496     Return value: 0 on success. */
497     gpgme_error_t
498     gpg_revoke_key (const char *inp_data, const char *keyid, char **r_revcert)
499     {
500     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
501     char *rcrt;
502     char *cmd, *p;
503     HANDLE in, out;
504    
505 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
506     "Software\\GNU\\GnuPG", "gpgProgram");
507 twoaday 25 if (!p)
508     return gpg_error (GPG_ERR_INV_ARG);
509    
510 twoaday 33 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
511 twoaday 25 if (!cmd)
512     abort ();
513 twoaday 32 sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",
514     p, keyid);
515 twoaday 25
516     in = create_in_pipe (inp_data);
517     out = create_tmpfile ("gpg_revcert");
518     if (create_process (cmd, in, out)) {
519     *r_revcert = NULL;
520     err = gpg_error (GPG_ERR_INTERNAL);
521     }
522     else {
523     rcrt = map_tmpfile (out);
524     *r_revcert = rcrt;
525     }
526    
527     free (p);
528     free (cmd);
529    
530     CloseHandle (in);
531     CloseHandle (out);
532     return err;
533     }
534 twoaday 33
535    
536     /* Return the validity of the user attribute, informerly known
537     as photo-ID. If no uat was found, return 0 for unknown. */
538     gpgme_error_t
539     get_uat_validity (const char *keyid, gpgme_validity_t *r_valid)
540     {
541     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
542     HANDLE out;
543     char *p, *cmd;
544     char *uat;
545    
546     *r_valid = GPGME_VALIDITY_UNKNOWN;
547     p = read_w32_registry (HKEY_CURRENT_USER,
548     "Software\\GNU\\GnuPG", "gpgProgram");
549     if (!p)
550     return gpg_error (GPG_ERR_INV_ARG);
551    
552     cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
553     if (!cmd)
554     abort ();
555     sprintf (cmd, "%s --with-colons --fixed-list-mode --list-keys \"%s\"",
556     p, keyid);
557    
558     out = create_tmpfile ("gpg_keys");
559     if (create_process (cmd, NULL, out))
560     err = gpg_error (GPG_ERR_INTERNAL);
561    
562     free (p);
563     free (cmd);
564    
565     p = map_tmpfile (out);
566     if ((uat = strstr (p, "uat:"))) {
567     switch (*(uat+4)) {
568     case 'm': *r_valid = GPGME_VALIDITY_MARGINAL; break;
569     case 'f':
570     case 'u': *r_valid = GPGME_VALIDITY_FULL; break;
571     default: *r_valid = GPGME_VALIDITY_UNDEFINED; break;
572     }
573     }
574    
575     free (p);
576     CloseHandle (out);
577     return err;
578     }
579    
580    
581     #if 0
582     /* Extract all recipients from the file @file.
583     Return value: 0 on success. */
584     static int
585     do_get_recipients (const char *file, gpgme_recipient_t *r_list)
586     {
587     gpgme_recipient_t l;
588     PACKET *pkt;
589     gpg_iobuf_t inp = NULL;
590     armor_filter_context_t afx;
591     int rc = 0, quit=0;
592    
593     if (!file || !r_list) {
594     log_debug ("do_list_packets: !r_list || !file");
595     return -1;
596     }
597    
598     *r_list=NULL;
599     inp = gpg_iobuf_open (file);
600     if (!inp)
601     return WPTERR_FILE_OPEN;
602     gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
603     if (gpg_use_armor_filter (inp)) {
604     memset (&afx, 0, sizeof (afx));
605     gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);
606     }
607     pkt = (PACKET *)calloc(1, sizeof *pkt);
608     gpg_init_packet (pkt);
609     while (!quit && (rc = gpg_parse_packet (inp, pkt)) != -1) {
610     switch (pkt->pkttype) {
611     case PKT_PUBKEY_ENC:
612     {PKT_pubkey_enc *enc = pkt->pkt.pubkey_enc;
613     if (!enc)
614     break;
615     l = calloc (1, sizeof *l);
616     l->keyid = calloc (1, 16+1);
617     _snprintf (l->keyid, 16, "%08lX%08lX", enc->keyid[0], enc->keyid[1]);
618     l->pubkey_algo = enc->pubkey_algo;
619     l->status = 0;
620     l->next = (*r_list);
621     *r_list = l;
622     break;}
623    
624     case PKT_ENCRYPTED:
625     case PKT_ENCRYPTED_MDC:
626     case PKT_COMPRESSED:
627     case PKT_PUBLIC_KEY:
628     case PKT_SECRET_KEY:
629     quit = 1;
630     break;
631     }
632     gpg_free_packet (pkt);
633     gpg_init_packet (pkt);
634     }
635     gpg_iobuf_close (inp);
636     safe_free (pkt);
637     return 0;
638     }
639     #endif

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26