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

Annotation of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (hide annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 15830 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26