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

Annotation of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 121 - (hide annotations)
Mon Dec 12 11:19:56 2005 UTC (19 years, 2 months ago) by twoaday
File size: 16277 byte(s)
2005-12-11  Timo Schulz  <ts@g10code.com>
 
        * wptW32API.cpp (get_file_version): New.
        * wptGPGUtil.cpp (create_process): Always hide window.
        * wptClipEditDlg.cpp (clipedit_dlg_proc): Use 'Close'
        instead of 'Exit'.
        * wptKeyManager.cpp (km_http_import): New filename
        generation code.
        (km_send_to_mail_recipient): Cleanups.
        * wptKeyEditDlg.cpp (showpref_dlg_proc): Localize dialog.
        * wptKeyManagerDlg.cpp (update_ui_items): Handle the case
        when multiple keys are selected.
        (popup_multiple): New.
        * WinPT.cpp (WinMain): Check that the PTD.dll and WinPT.exe
        file versions are equal. Rewrote --keymanager code.
         
Removed temporary w32gpgme dirctory, all code is now in Src.
Changed configure files.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26