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

Annotation of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 73 - (hide annotations)
Tue Nov 8 07:15:13 2005 UTC (19 years, 3 months ago) by twoaday
File size: 15953 byte(s)
2005-11-08  Timo Schulz  <ts@g10code.com>
 
        More minor changes to avoid GCC warnings.
         
        * wptGPG.cpp (check_homedir): Free memory in case of errors.
        (multi_gnupg_path): Add strict mode. If non-strict mode return
        the folder even if it does not exist.
        (check_for_gpgwin): New.
        * wptKeyserverDlg.cpp (hkp_recv_key): Make sure import_res is
        initialized.
        * wptRegistry.cpp (get_reg_entry_gpg4win): New.
        (get_reg_entry_mo): Support for gpg4win.
         
For complete changes see ChangeLogs.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26