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

Annotation of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 24 08:03:48 2005 UTC (19 years, 4 months ago) by twoaday
File size: 13609 byte(s)
2005-10-23  Timo Schulz  <twoaday@g10code.com>
 
        * wptFileManager.cpp (fm_get_file_type): Detect detached sigs.
        * wptKeyList.cpp (keylist_cmp_cb): Take care of expired/revoked keys.
        (get_ext_validity): New.
        * wptFileVerifyDlg.cpp (file_verify_dlg_proc): Several cleanups.
        * wptClipEditDlg.cpp (load_clipboard): Factored out some code into
        this function.
        (load_clipboard_from_file): Likewise.
        (save_clipboard_to_file): New.
        * wptKeyManagerDlg.cpp (keyprops_dlg_proc): Fix stack overflow.

For complete details, see the ChangeLog files.

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 32 GetTempPath (sizeof (tmp)-1 - 64, 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     si.dwFlags = STARTF_USESTDHANDLES;
278     if (out)
279     si.hStdOutput = out;
280     if (in)
281     si.hStdInput = in;
282 twoaday 32 if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
283     NULL, NULL, &si, &pi))
284 twoaday 25 return -1;
285     WaitForSingleObject (pi.hProcess, INFINITE);
286     CloseHandle (pi.hProcess);
287     return 0;
288     }
289    
290    
291     /* Export a GPG secret key given by @keyid into the file @outfile.
292     Return value: 0 on success. */
293     gpgme_error_t
294     gpg_export_seckey (const char *keyid, const char *outfile)
295     {
296     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
297     struct stat st;
298     char *p;
299     char *cmd;
300    
301 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
302     "Software\\GNU\\GnuPG", "gpgProgram");
303 twoaday 25 if (!p)
304     return gpg_error (GPG_ERR_INV_ARG);
305 twoaday 32 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)
306     + strlen (outfile) + 64 + 2);
307 twoaday 25 if (!cmd)
308     abort ();
309 twoaday 32 sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s",
310     p, outfile, keyid);
311 twoaday 25 if (create_process (cmd, NULL, NULL))
312     err = gpg_error (GPG_ERR_INTERNAL);
313    
314     if (stat (outfile, &st) == -1 || st.st_size == 0)
315     err = gpg_error (GPG_ERR_NO_DATA);
316    
317     free (p);
318     free (cmd);
319     return err;
320     }
321    
322    
323     /* If @export is 1, export the ownertrust data to the
324     buffer @data. Otherwise import the ownertrust data from @data.
325     Return value: 0 on success. */
326     gpgme_error_t
327     gpg_manage_ownertrust (char **data, int export)
328     {
329     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
330     HANDLE out = NULL, in = NULL;
331     char *p;
332     char *cmd;
333    
334 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
335     "Software\\GNU\\GnuPG", "gpgProgram");
336 twoaday 25 if (!p)
337     return gpg_error (GPG_ERR_INV_ARG);
338    
339     cmd = (char*)calloc (1, strlen (p) + 64 + 1);
340     if (!cmd)
341     abort ();
342 twoaday 32 sprintf (cmd, "%s %s", p,
343     export? "--export-ownertrust" : "--import-ownertrust");
344 twoaday 25
345     if (export)
346     out = create_tmpfile ("gpg_ot_out");
347     else {
348     DWORD nw;
349     in = create_tmpfile ("gpg_ot_in");
350     WriteFile (in, *data, strlen (*data), &nw, NULL);
351     FlushFileBuffers (in);
352     /* XXX: need a rewind? */
353     }
354     if (create_process (cmd, in, out))
355     err = gpg_error (GPG_ERR_INTERNAL);
356    
357     free (p);
358     free (cmd);
359    
360     if (in)
361     CloseHandle (in);
362     if (out) {
363     *data = map_tmpfile (out);
364     CloseHandle (out);
365     }
366     return err;
367     }
368    
369 twoaday 32
370 twoaday 25 /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
371     gpgme_error_t
372     gpg_rebuild_cache (char **r_inf)
373     {
374     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
375     HANDLE out = NULL;
376     char *p;
377     char *cmd;
378    
379 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
380     "Software\\GNU\\GnuPG", "gpgProgram");
381 twoaday 25 if (!p)
382     return gpg_error (GPG_ERR_INV_ARG);
383     cmd = (char*)calloc (1, strlen (p) + 64);
384     if (!cmd)
385     abort ();
386     sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);
387    
388     if (r_inf)
389     out = create_tmpfile ("gpg_rebuild_cache");
390    
391     if (create_process (cmd, NULL, out))
392     err = gpg_error (GPG_ERR_INTERNAL);
393    
394     if (r_inf)
395     *r_inf = map_tmpfile (out);
396     if (out)
397     CloseHandle (out);
398     free (p);
399     free (cmd);
400     return 0;
401     }
402    
403 twoaday 32
404 twoaday 25 /* Call gpg --version to retrieve the 'about' information. */
405     gpgme_error_t
406     gpg_get_version (char **r_inf)
407     {
408     gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
409     HANDLE out;
410     char *p, *cmd;
411    
412 twoaday 32 p =read_w32_registry (HKEY_CURRENT_USER,
413     "Software\\GNU\\GnuPG", "gpgProgram");
414 twoaday 25 if (!p)
415     return gpg_error (GPG_ERR_INV_ARG);
416     cmd = (char*)calloc (1, strlen (p) + 32);
417     if (!cmd)
418     abort ();
419     sprintf (cmd, "%s --version", p);
420    
421     out = create_tmpfile ("gpg_out");
422     if (create_process (cmd, NULL, out))
423     err = gpg_error (GPG_ERR_INTERNAL);
424    
425     free (p);
426     free (cmd);
427    
428     *r_inf = map_tmpfile (out);
429     CloseHandle (out);
430     return err;
431     }
432    
433 twoaday 32
434 twoaday 25 /* Return the colon file output of the given file @fname in @r_out.
435     Return value: 0 on success. */
436     gpgme_error_t
437     gpg_import_key_list (const char *fname, char **r_out)
438     {
439     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
440     char *cmd, *p;
441     HANDLE out;
442    
443 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
444     "Software\\GNU\\GnuPG", "gpgProgram");
445 twoaday 25 if (!p)
446     return gpg_error (GPG_ERR_INV_ARG);
447    
448     cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);
449     if (!cmd)
450     abort ();
451     sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);
452    
453     out = create_tmpfile ("gpg_keys");
454     if (create_process (cmd, NULL, out))
455     err = gpg_error (GPG_ERR_INTERNAL);
456    
457     free (p);
458     free (cmd);
459    
460     *r_out = map_tmpfile (out);
461     CloseHandle (out);
462     return err;
463     }
464    
465     char*
466     generate_revoc_input (int code, const char *cmt, const char *pass)
467     {
468     const char *fmt;
469     char *p;
470     size_t n;
471    
472     fmt = "Y\n" /* gen_revoke.okay */
473     "%d\n" /* ask_revocation_reason.code */
474     "%s\n" /* ask_revocation_reason.text */
475     "%s" /* text != NULL '\n' otherwise '' */
476     "Y\n" /* ask_revocation_reason.okay */
477     "%s\n"; /* passphrase.enter. */
478     n = strlen (fmt) + 32;
479     if (pass)
480     n += strlen (pass) + 1;
481     if (cmt)
482     n += strlen (cmt) + 1;
483     p = (char*)calloc (1, n+1);
484     if (!p)
485     abort ();
486     sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");
487     return p;
488     }
489    
490    
491     /* Generate a revocation certificate for the key with the keyid @keyid.
492     @inp_data contains all needed data to answer the questions of the
493     command handler. Each separate with a '\n'.
494     @r_revcert contains the revocation cert on success.
495     Return value: 0 on success. */
496     gpgme_error_t
497     gpg_revoke_key (const char *inp_data, const char *keyid, char **r_revcert)
498     {
499     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
500     char *rcrt;
501     char *cmd, *p;
502     HANDLE in, out;
503    
504 twoaday 32 p = read_w32_registry (HKEY_CURRENT_USER,
505     "Software\\GNU\\GnuPG", "gpgProgram");
506 twoaday 25 if (!p)
507     return gpg_error (GPG_ERR_INV_ARG);
508    
509     cmd = (char*)calloc (1, strlen (p) + 128);
510     if (!cmd)
511     abort ();
512 twoaday 32 sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",
513     p, keyid);
514 twoaday 25
515     in = create_in_pipe (inp_data);
516     out = create_tmpfile ("gpg_revcert");
517     if (create_process (cmd, in, out)) {
518     *r_revcert = NULL;
519     err = gpg_error (GPG_ERR_INTERNAL);
520     }
521     else {
522     rcrt = map_tmpfile (out);
523     *r_revcert = rcrt;
524     }
525    
526     free (p);
527     free (cmd);
528    
529     CloseHandle (in);
530     CloseHandle (out);
531     return err;
532     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26