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

Diff of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 25 by twoaday, Wed Oct 12 10:04:26 2005 UTC revision 181 by twoaday, Tue Mar 14 11:01:22 2006 UTC
# Line 1  Line 1 
1  /* wptGPGUtil.cpp - GPG helper functions  /* wptGPGUtil.cpp - GPG util functions
2   *      Copyright (C) 2005 g10 Code GmbH   *      Copyright (C) 2005, 2006 Timo Schulz
3   *   *      Copyright (C) 2005 g10 Code GmbH
4   * This file is part of WinPT.   *
5   *   * This file is part of WinPT.
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   * WinPT is free software; you can redistribute it and/or modify
8   * the Free Software Foundation; either version 2 of the License, or   * it under the terms of the GNU General Public License as published by
9   * (at your option) any later version.   * the Free Software Foundation; either version 2 of the License, or
10   *   * (at your option) any later version.
11   * WinPT is distributed in the hope that it will be useful,   *
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * WinPT is distributed in the hope that it will be useful,
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * GNU General Public License for more details.   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   *   * GNU General Public License for more details.
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,   * You should have received a copy of the GNU General Public License
18   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * along with WinPT; if not, write to the Free Software Foundation,
19   */   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  #include <windows.h>   */
21  #include <sys/stat.h>  
22    #ifdef HAVE_CONFIG_H
23  #include "gpgme.h"  #include <config.h>
24    #endif
25    
26  #define NROFHEXDIGITS 2    #include <windows.h>
27  /* Convert two hexadecimal digits from STR to the value they  #include <sys/stat.h>
28     represent.  Returns -1 if one of the characters is not a  #include <string.h>
29     hexadecimal digit.  */  #include <errno.h>
30  static int  
31  hextobyte (const unsigned char *str)  #include "gpgme.h"
32  {  #include "wptTypes.h"
33      int val = 0;    #include "wptErrors.h"
34      int i;  #include "wptW32API.h"
35    #include "wptGPG.h"
36      for (i = 0; i < NROFHEXDIGITS; i++) {  #include "openpgp.h"
37          if (*str >= '0' && *str <= '9')  
38              val += *str - '0';  
39          else if (*str >= 'A' && *str <= 'F')  #define NROFHEXDIGITS 2  
40              val += 10 + *str - 'A';  /* Convert two hexadecimal digits from STR to the value they
41          else if (*str >= 'a' && *str <= 'f')     represent.  Returns -1 if one of the characters is not a
42              val += 10 + *str - 'a';     hexadecimal digit.  */
43          else  static int
44              return -1;  hextobyte (const unsigned char *str)
45          if (i < NROFHEXDIGITS - 1)  {
46              val *= 16;      int val = 0;  
47          str++;      int i;
48      }  
49      return val;      for (i = 0; i < NROFHEXDIGITS; i++) {
50  }          if (*str >= '0' && *str <= '9')
51                val += *str - '0';
52  /* Decode the C formatted string @src and store the result in the          else if (*str >= 'A' && *str <= 'F')
53     buffer @destp which is @len bytes long.  If @len is zero, then a              val += 10 + *str - 'A';
54     large enough buffer is allocated with malloc and @destp is set to          else if (*str >= 'a' && *str <= 'f')
55     the result.  Currently, @len is only used to specify if allocation              val += 10 + *str - 'a';
56     is desired or not, the caller is expected to make sure that @destp          else
57     is large enough if @len is not zero.  */              return -1;
58  gpgme_error_t          if (i < NROFHEXDIGITS - 1)
59  gpg_decode_c_string (const char *src, char **destp, size_t len)              val *= 16;
60  {          str++;
61    char *dest;      }
62        return val;
63    /* Set up the destination buffer.  */  }
64    if (len) {  
65        if (len < strlen (src) + 1)  /* Decode the C formatted string @src and store the result in the
66            return gpg_error (GPG_ERR_TOO_SHORT);     buffer @destp which is @len bytes long.  If @len is zero, then a
67        dest = *destp;     large enough buffer is allocated with malloc and @destp is set to
68    }     the result.  Currently, @len is only used to specify if allocation
69    else {           is desired or not, the caller is expected to make sure that @destp
70    /* The converted string will never be larger than the original string.  */     is large enough if @len is not zero.  */
71        dest = (char*)malloc (strlen (src) + 1);  gpgme_error_t
72        if (!dest)  gpg_decode_c_string (const char *src, char **destp, size_t len)
73            return gpg_error (GPG_ERR_ENOMEM);  {
74        *destp = dest;    char *dest;
75    }  
76      /* Set up the destination buffer.  */
77    /* Convert the string.  */    if (len) {
78    while (*src) {            if (len < strlen (src) + 1)
79        if (*src != '\\') {            return gpg_error (GPG_ERR_TOO_SHORT);
80            *(dest++) = *(src++);        dest = *destp;
81            continue;    }
82          }    else {      
83      /* The converted string will never be larger than the original string.  */
84        switch (src[1]) {        dest = (char*)malloc (strlen (src) + 1);
85  #define DECODE_ONE(match,result)        \        if (!dest)
86        case match:                       \            return gpg_error (GPG_ERR_ENOMEM);
87            src += 2;                     \        *destp = dest;
88            *(dest++) = result;           \    }
89            break;  
90      /* Convert the string.  */
91            DECODE_ONE ('\'', '\'');    while (*src) {    
92            DECODE_ONE ('\"', '\"');        if (*src != '\\') {
93            DECODE_ONE ('\?', '\?');            *(dest++) = *(src++);
94            DECODE_ONE ('\\', '\\');            continue;
95            DECODE_ONE ('a', '\a');        }
96            DECODE_ONE ('b', '\b');  
97            DECODE_ONE ('f', '\f');        switch (src[1]) {
98            DECODE_ONE ('n', '\n');  #define DECODE_ONE(match,result)        \
99            DECODE_ONE ('r', '\r');        case match:                       \
100            DECODE_ONE ('t', '\t');            src += 2;                     \
101            DECODE_ONE ('v', '\v');            *(dest++) = result;           \
102              break;
103        case 'x': {  
104              int val = hextobyte ((unsigned char*)&src[2]);            DECODE_ONE ('\'', '\'');
105              if (val == -1) {            DECODE_ONE ('\"', '\"');
106                  /* Should not happen.  */            DECODE_ONE ('\?', '\?');
107                  *(dest++) = *(src++);            DECODE_ONE ('\\', '\\');
108                  *(dest++) = *(src++);            DECODE_ONE ('a', '\a');
109                  if (*src)            DECODE_ONE ('b', '\b');
110                    *(dest++) = *(src++);            DECODE_ONE ('f', '\f');
111                  if (*src)            DECODE_ONE ('n', '\n');
112                    *(dest++) = *(src++);            DECODE_ONE ('r', '\r');
113              }            DECODE_ONE ('t', '\t');
114              else {            DECODE_ONE ('v', '\v');
115                  if (!val) {                
116                      /* A binary zero is not representable in a C        case 'x': {
117                         string.  */              int val = hextobyte ((unsigned char*)&src[2]);
118                      *(dest++) = '\\';              if (val == -1) { /* Should not happen.  */
119                      *(dest++) = '0';                  *(dest++) = *(src++);
120                  }                  *(dest++) = *(src++);
121                  else                  if (*src)
122                      *((unsigned char *) dest++) = val;                    *(dest++) = *(src++);
123                  src += 4;                  if (*src)
124              }                    *(dest++) = *(src++);
125          }              }
126                else {
127          default:                  if (!val) {
128            {                      /* A binary zero is not representable in a C string.  */
129              /* Should not happen.  */                      *(dest++) = '\\';
130              *(dest++) = *(src++);                      *(dest++) = '0';
131              *(dest++) = *(src++);                  }
132            }                  else
133          }                      *((unsigned char *) dest++) = val;
134    }                  src += 4;
135    *(dest++) = 0;              }
136    return 0;          }
137  }  
138            default: /* Should not happen.  */
139  /* Replace %foo% entries with its real values.            {
140     Return value: expanded path or NULL on error. */              *(dest++) = *(src++);
141  static char *              *(dest++) = *(src++);
142  expand_path (const char *path)            }
143  {          }
144      DWORD len;    }
145      char *p;    *(dest++) = 0;
146      return 0;
147      len = ExpandEnvironmentStrings (path, NULL, 0);  }
148      if (!len)  
149          return NULL;  /* Replace %foo% entries with its real values.
150      len += 1;     Return value: expanded path or NULL on error. */
151      p = (char*)calloc (1, len+1);  static char *
152      if (!p)  expand_path (const char *path)
153          abort ();  {
154      len = ExpandEnvironmentStrings (path, p, len);      DWORD len;
155      if (!len) {      char *p;
156          free (p);  
157          return NULL;      len = ExpandEnvironmentStrings (path, NULL, 0);
158      }      if (!len)
159      return p;          return NULL;
160  }      len += 1;
161        p = (char*)calloc (1, len+1);
162        if (!p)
163  /* Read a string from the W32 registry. The directory is given          BUG (NULL);
164     in @dir and the name of the value in @name, */      len = ExpandEnvironmentStrings (path, p, len);
165  static char *      if (!len) {
166  read_w32_registry (HKEY root_key, const char *dir, const char *name )          free (p);
167  {          return NULL;
168      HKEY key_handle;      }
169      DWORD n1, nbytes;      return p;
170      DWORD type;  }
171      char *result = NULL;  
172        
173      if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))  /* Read a string from the W32 registry. The directory is given
174          return NULL; /* no need for a RegClose, so return direct */     in @dir and the name of the value in @name, */
175        static char *
176      nbytes = 1;  read_w32_registry (HKEY root_key, const char *dir, const char *name)
177      if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))  {
178          goto leave;      HKEY key_handle;
179      result = (char*)calloc (1, (n1=nbytes+1));      DWORD n1, nbytes;
180      if (!result)      DWORD type;
181          abort ();      char *result = NULL;
182      if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {      
183          free (result);      if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
184          result = NULL;          return NULL; /* no need for a RegClose, so return direct */
185          goto leave;      
186      }      nbytes = 1;
187      if (type == REG_EXPAND_SZ && strchr (result, '%')) {      if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
188          char *p = expand_path (result);          goto leave;
189          free (result);      result = (char*)calloc (1, (n1=nbytes+1));
190          result = p;      if (!result)
191      }          BUG (NULL);
192            if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {
193  leave:          free (result);
194      RegCloseKey (key_handle);          result = NULL;
195      return result;          goto leave;
196  }      }
197        if (type == REG_EXPAND_SZ && strchr (result, '%')) {
198            char *p = expand_path (result);
199  /* Create a temp file based on the name of @name.          free (result);
200     Return value: handle to the file in case of success. */          result = p;
201  static HANDLE      }
202  create_tmpfile (const char *name)      
203  {      leave:
204      HANDLE out;      RegCloseKey (key_handle);
205      SECURITY_ATTRIBUTES sattr;      return result;
206      char tmp[300];  }
207    
208      memset (&sattr, 0, sizeof sattr);  static char*
209      sattr.bInheritHandle = TRUE;  read_gpg_program (void)
210      sattr.lpSecurityDescriptor = NULL;  {
211      sattr.nLength = sizeof sattr;      return read_w32_registry (HKEY_CURRENT_USER,
212                                  "Software\\GNU\\GnuPG", "gpgProgram");
213      GetTempPath (300 - 64, tmp);  }
214      strcat (tmp, name);  
215      out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,  
216                        FILE_SHARE_WRITE, &sattr,  /* Create a temp file based on the name of @name.
217                        OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);     Return value: handle to the file in case of success. */
218      return out;  static HANDLE
219  }  create_tmpfile (const char *name)
220    {    
221        HANDLE out;
222  /* Create a pipe with a readable remote end and      SECURITY_ATTRIBUTES sec_attr;
223     write the data from @dat to the local end.      char tmp[300];
224     Return value: read handle on success. */  
225  static HANDLE      memset (&sec_attr, 0, sizeof sec_attr);
226  create_in_pipe (const char *dat)      sec_attr.bInheritHandle = TRUE;
227  {      sec_attr.lpSecurityDescriptor = NULL;
228      HANDLE r, w;      sec_attr.nLength = sizeof sec_attr;
229      SECURITY_ATTRIBUTES sec_attr;  
230      DWORD n;      get_temp_name (tmp, DIM (tmp)-1, name);
231        out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,
232      memset (&sec_attr, 0, sizeof sec_attr);                        FILE_SHARE_WRITE, &sec_attr,
233      sec_attr.bInheritHandle = TRUE;                        OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
234      sec_attr.nLength = sizeof sec_attr;      if (out == INVALID_HANDLE_VALUE)
235            log_debug ("create_tmpfile: CreateFile failed ec=%d\r\n",
236      if (!CreatePipe (&r, &w, &sec_attr, 4096))                     (int)GetLastError ());
237          return NULL;      return out;
238    }
239      WriteFile (w, dat, strlen (dat), &n, NULL);  
240      CloseHandle (w);  
241    /* Create a pipe with a readable remote end and
242      return r;     write the data from @dat to the local end.
243  }     Return value: read handle on success. */
244    static HANDLE
245    create_in_pipe (const char *dat)
246  /* Map the contents of the file handle @out to  {
247     a buffer and return it. */      HANDLE r, w;
248  static char*      SECURITY_ATTRIBUTES sec_attr;
249  map_tmpfile (HANDLE out)      DWORD n;
250  {  
251      DWORD n;      memset (&sec_attr, 0, sizeof sec_attr);
252      char *p;      sec_attr.bInheritHandle = TRUE;
253        sec_attr.nLength = sizeof sec_attr;
254      FlushFileBuffers (out);  
255      SetFilePointer (out, 0, NULL, FILE_BEGIN);      if (!CreatePipe (&r, &w, &sec_attr, 4096)) {
256      n = GetFileSize (out, NULL);          log_debug ("create_in_pipe: CreatePipeFailed ec=%d\r\n",
257      p = (char*)calloc (1, n+1);                     (int)GetLastError ());
258      if (!p)          return NULL;
259          abort ();      }
260      ReadFile (out, p, n, &n, NULL);  
261      p[n] = 0;      WriteFile (w, dat, strlen (dat), &n, NULL);
262      return p;      CloseHandle (w);
263  }  
264        return r;
265    }
266  /* Create a process from the command line in @cmd.  
267     If @out is != NULL, the output of the process will  
268     be redirected to @out. If @in is != NULL the input  /* Map the contents of the file handle @out to
269     will be read from @in.     a buffer and return it. */
270     Return value: 0 on success. */  static char*
271  static int  map_tmpfile (HANDLE out, DWORD *nread)
272  create_process (const char *cmd, HANDLE in, HANDLE out)  {
273  {      DWORD n;
274      STARTUPINFO si;      char *p;
275      PROCESS_INFORMATION pi;  
276        FlushFileBuffers (out);
277      memset (&si, 0, sizeof (si));      SetFilePointer (out, 0, NULL, FILE_BEGIN);
278      si.cb = sizeof si;      n = GetFileSize (out, NULL);
279      if (in || out)      p = (char*)calloc (1, n+1);
280          si.dwFlags = STARTF_USESTDHANDLES;      if (!p)
281      if (out)          BUG (NULL);
282          si.hStdOutput = out;      ReadFile (out, p, n, &n, NULL);
283      if (in)      p[n] = 0;
284          si.hStdInput = in;      if (nread)
285      if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))          *nread = n;
286          return -1;      return p;
287      WaitForSingleObject (pi.hProcess, INFINITE);  }
288      CloseHandle (pi.hProcess);  
289      return 0;  
290  }  /* Create a process from the command line in @cmd.
291       If @out is != NULL, the output of the process will
292       be redirected to @out. If @in is != NULL the input
293  /* Export a GPG secret key given by @keyid into the file @outfile.     will be read from @in.
294     Return value: 0 on success. */     Return value: 0 on success. */
295  gpgme_error_t  static int
296  gpg_export_seckey (const char *keyid, const char *outfile)  create_process (const char *cmd, HANDLE in, HANDLE out, HANDLE err)
297  {  {
298      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      STARTUPINFO si;
299      struct stat st;      PROCESS_INFORMATION pi;
300      char *p;  
301      char *cmd;      memset (&si, 0, sizeof (si));
302        si.cb = sizeof si;
303      p = read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");      if (in || out || err)
304      if (!p)          si.dwFlags = STARTF_USESTDHANDLES;
305          return gpg_error (GPG_ERR_INV_ARG);      if (out)
306      cmd = (char*)calloc (1, strlen (p) + strlen (keyid) + strlen (outfile ) + 64 + 2);          si.hStdOutput = out;
307      if (!cmd)      if (in)
308          abort ();          si.hStdInput = in;
309      sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s", p, outfile, keyid);      if (err)
310      if (create_process (cmd, NULL, NULL))          si.hStdError = err;
311          err = gpg_error (GPG_ERR_INTERNAL);      si.dwFlags |= STARTF_USESHOWWINDOW;
312        si.wShowWindow = SW_HIDE;
313      if (stat (outfile, &st) == -1 || st.st_size == 0)      if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
314          err = gpg_error (GPG_ERR_NO_DATA);                          NULL, NULL, &si, &pi)) {
315            log_debug ("create_process: CreateProcess failed ec=%d\r\n",
316      free (p);                     (int)GetLastError ());
317      free (cmd);          return -1;
318      return err;      }
319  }      WaitForSingleObject (pi.hProcess, INFINITE);
320        CloseHandle (pi.hProcess);
321        return 0;
322  /* If @export is 1, export the ownertrust data to the  }
323     buffer @data. Otherwise import the ownertrust data from @data.  
324     Return value: 0 on success. */  
325  gpgme_error_t  /* Export a GPG secret key given by @keyid into the file @outfile.
326  gpg_manage_ownertrust (char **data, int export)     Return value: 0 on success. */
327  {  gpgme_error_t
328      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);  gpg_export_seckey (const char *keyid, const char *outfile)
329      HANDLE out = NULL, in = NULL;  {
330      char *p;      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
331      char *cmd;      struct stat st;
332        char *p;
333      p = read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");      char *cmd;
334      if (!p)  
335          return gpg_error (GPG_ERR_INV_ARG);      p = read_gpg_program ();
336        if (!p)
337      cmd = (char*)calloc (1, strlen (p) + 64 + 1);          return gpg_error (GPG_ERR_INV_ARG);
338      if (!cmd)      cmd = (char*)calloc (1, strlen (p) + strlen (keyid)
339          abort ();                                + strlen (outfile) + 64 + 2);
340      sprintf (cmd, "%s %s", p, export? "--export-ownertrust" : "--import-ownertrust");      if (!cmd)
341            BUG (NULL);
342      if (export)      sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s",
343          out = create_tmpfile ("gpg_ot_out");               p, outfile, keyid);
344      else {      if (create_process (cmd, NULL, NULL, NULL))
345          DWORD nw;          err = gpg_error (GPG_ERR_INTERNAL);
346          in = create_tmpfile ("gpg_ot_in");  
347          WriteFile (in, *data, strlen (*data), &nw, NULL);      if (stat (outfile, &st) == -1 || st.st_size == 0)
348          FlushFileBuffers (in);          err = gpg_error (GPG_ERR_NO_DATA);
349          /* XXX: need a rewind? */  
350      }      free (p);
351      if (create_process (cmd, in, out))      free (cmd);
352          err = gpg_error (GPG_ERR_INTERNAL);      return err;
353    }
354      free (p);  
355      free (cmd);  
356    /* If @export is 1, export the ownertrust data to the
357      if (in)     buffer @data. Otherwise import the ownertrust data from @data.
358          CloseHandle (in);     Return value: 0 on success. */
359      if (out) {  gpgme_error_t
360          *data = map_tmpfile (out);  gpg_manage_ownertrust (char **data, int do_export)
361          CloseHandle (out);  {
362      }      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
363      return err;      HANDLE out = NULL, in = NULL;
364  }      char *p;
365        char *cmd;
366  /* Call gpg --rebuild-keydb-caches to speed up signature listings. */  
367  gpgme_error_t      p = read_gpg_program ();
368  gpg_rebuild_cache (char **r_inf)      if (!p)
369  {          return gpg_error (GPG_ERR_INV_ARG);
370      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);  
371      HANDLE out = NULL;      cmd = (char*)calloc (1, strlen (p) + 64 + 1);
372      char *p;      if (!cmd)
373      char *cmd;          BUG (NULL);
374        sprintf (cmd, "%s %s", p,
375      p = read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");               do_export? "--export-ownertrust" : "--import-ownertrust");
376      if (!p)  
377          return gpg_error (GPG_ERR_INV_ARG);      if (do_export)
378      cmd = (char*)calloc (1, strlen (p) + 64);          out = create_tmpfile ("gpg_ot_out");
379      if (!cmd)      else {
380          abort ();          DWORD nw;
381      sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);          in = create_tmpfile ("gpg_ot_in");
382            WriteFile (in, *data, strlen (*data), &nw, NULL);
383      if (r_inf)          FlushFileBuffers (in);
384          out = create_tmpfile ("gpg_rebuild_cache");          /* XXX: need a rewind? */
385        }
386      if (create_process (cmd, NULL, out))      if (create_process (cmd, in, out, NULL))
387          err = gpg_error (GPG_ERR_INTERNAL);          err = gpg_error (GPG_ERR_INTERNAL);
388    
389      if (r_inf)      free (p);
390          *r_inf = map_tmpfile (out);      free (cmd);
391      if (out)  
392          CloseHandle (out);      if (in)
393      free (p);          CloseHandle (in);
394      free (cmd);      if (out) {
395      return 0;          *data = map_tmpfile (out, NULL);
396  }          CloseHandle (out);
397        }
398  /* Call gpg --version to retrieve the 'about' information. */  
399  gpgme_error_t      return err;
400  gpg_get_version (char **r_inf)  }
401  {  
402      gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);  
403      HANDLE out;      /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
404      char *p, *cmd;  gpgme_error_t
405    gpg_rebuild_cache (char **r_inf)
406      p =read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");  {
407      if (!p)      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
408          return gpg_error (GPG_ERR_INV_ARG);      HANDLE out = NULL;
409      cmd = (char*)calloc (1, strlen (p) + 32);      char *p;
410      if (!cmd)      char *cmd;
411          abort ();  
412      sprintf (cmd, "%s --version", p);      p = read_gpg_program ();
413        if (!p)
414      out = create_tmpfile ("gpg_out");          return gpg_error (GPG_ERR_INV_ARG);
415      if (create_process (cmd, NULL, out))      cmd = (char*)calloc (1, strlen (p) + 64);
416          err = gpg_error (GPG_ERR_INTERNAL);      if (!cmd)
417            BUG (NULL);
418      free (p);      sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);
419      free (cmd);  
420        if (r_inf)
421      *r_inf = map_tmpfile (out);          out = create_tmpfile ("gpg_rebuild_cache");
422      CloseHandle (out);      
423      return err;      if (create_process (cmd, NULL, out, NULL))
424  }          err = gpg_error (GPG_ERR_INTERNAL);
425    
426  /* Return the colon file output of the given file @fname in @r_out.      if (r_inf)
427     Return value: 0 on success. */          *r_inf = map_tmpfile (out, NULL);
428  gpgme_error_t      if (out)
429  gpg_import_key_list (const char *fname, char **r_out)          CloseHandle (out);
430  {      free (p);
431      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      free (cmd);
432      char *cmd, *p;      return 0;
433      HANDLE out;  }
434    
435      p = read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");  
436      if (!p)  /* Call gpg --version to retrieve the 'about' information. */
437          return gpg_error (GPG_ERR_INV_ARG);  gpgme_error_t
438    gpg_get_version (char **r_inf)
439      cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);  {
440      if (!cmd)      gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
441          abort ();      HANDLE out;    
442      sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);      char *p, *cmd;
443    
444      out = create_tmpfile ("gpg_keys");      p = read_gpg_program ();
445      if (create_process (cmd, NULL, out))      if (!p)
446          err = gpg_error (GPG_ERR_INTERNAL);          return gpg_error (GPG_ERR_INV_ARG);
447        cmd = (char*)calloc (1, strlen (p) + 32);
448      free (p);      if (!cmd)
449      free (cmd);          BUG (NULL);
450        sprintf (cmd, "%s --version", p);
451      *r_out = map_tmpfile (out);  
452      CloseHandle (out);      out = create_tmpfile ("gpg_out");
453      return err;      if (create_process (cmd, NULL, out, NULL))
454  }          err = gpg_error (GPG_ERR_INTERNAL);
455    
456  char*      free (p);
457  generate_revoc_input (int code, const char *cmt, const char *pass)      free (cmd);
458  {  
459      const char *fmt;      *r_inf = map_tmpfile (out, NULL);
460      char *p;      CloseHandle (out);    
461      size_t n;      return err;
462    }
463      fmt = "Y\n"     /*  gen_revoke.okay */  
464            "%d\n"    /* ask_revocation_reason.code */  
465            "%s\n"    /* ask_revocation_reason.text */  /* Return the colon file output of the given file @fname in @r_out.
466            "%s"      /* text != NULL '\n' otherwise '' */     Return value: 0 on success. */
467            "Y\n"     /* ask_revocation_reason.okay */  gpgme_error_t
468            "%s\n";   /* passphrase.enter. */  gpg_import_key_list (const char *fname, char **r_out)
469      n = strlen (fmt) + 32;  {
470      if (pass)      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
471          n += strlen (pass) + 1;      char *cmd, *p;
472      if (cmt)      HANDLE out;
473          n += strlen (cmt) + 1;  
474      p = (char*)calloc (1, n+1);      p = read_gpg_program ();
475      if (!p)      if (!p)
476          abort ();          return gpg_error (GPG_ERR_INV_ARG);
477      sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");  
478      return p;      cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);
479  }      if (!cmd)
480                BUG (NULL);
481        sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);
482  /* Generate a revocation certificate for the key with the keyid @keyid.  
483     @inp_data contains all needed data to answer the questions of the      out = create_tmpfile ("gpg_keys");
484     command handler. Each separate with a '\n'.      if (create_process (cmd, NULL, out, NULL))
485     @r_revcert contains the revocation cert on success.          err = gpg_error (GPG_ERR_INTERNAL);
486     Return value: 0 on success. */  
487  gpgme_error_t      free (p);
488  gpg_revoke_key (const char *inp_data, const char *keyid, char **r_revcert)      free (cmd);
489  {  
490      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      *r_out = map_tmpfile (out, NULL);
491      char *rcrt;      CloseHandle (out);
492      char *cmd, *p;      return err;
493      HANDLE in, out;  }
494        
495      p = read_w32_registry (HKEY_CURRENT_USER, "Software\\GNU\\GnuPG", "gpgProgram");  
496      if (!p)  char*
497          return gpg_error (GPG_ERR_INV_ARG);  generate_revoke_input (int code, const char *cmt, const char *pass)
498    {
499      cmd = (char*)calloc (1, strlen (p) + 128);      const char *fmt;
500      if (!cmd)      char *p;
501          abort ();      size_t n;
502      sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s", p, keyid);  
503        fmt = "Y\n"     /*  gen_revoke.okay */
504      in = create_in_pipe (inp_data);            "%d\n"    /* ask_revocation_reason.code */
505      out = create_tmpfile ("gpg_revcert");            "%s\n"    /* ask_revocation_reason.text */
506      if (create_process (cmd, in, out)) {            "%s"      /* text != NULL '\n' otherwise '' */
507          *r_revcert = NULL;            "Y\n"     /* ask_revocation_reason.okay */
508          err = gpg_error (GPG_ERR_INTERNAL);            "%s\n";   /* passphrase.enter. */
509      }      n = strlen (fmt) + 32;
510      else {      if (pass)
511          rcrt = map_tmpfile (out);          n += strlen (pass) + 1;
512          *r_revcert = rcrt;      if (cmt)
513      }          n += strlen (cmt) + 1;
514        p = (char*)calloc (1, n+1);
515      free (p);      if (!p)
516      free (cmd);          BUG (NULL);
517        sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");
518      CloseHandle (in);      return p;
519      CloseHandle (out);  }
520      return err;      
521  }  
522    /* Generate a revocation certificate for the key with the keyid @keyid.
523       @inp_data contains all needed data to answer the questions of the
524       command handler. Each separate with a '\n'.
525       @r_revcert contains the revocation cert on success.
526       Return value: 0 on success. */
527    gpgme_error_t
528    gpg_revoke_cert (const char *inp_data, const char *keyid, char **r_revcert)
529    {
530        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
531        char *rcrt;
532        char *cmd, *p;
533        HANDLE in, out;
534        
535        p = read_gpg_program ();
536        if (!p)
537            return gpg_error (GPG_ERR_INV_ARG);
538    
539        cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
540        if (!cmd)
541            BUG (NULL);
542        sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",
543                 p, keyid);
544    
545        in = create_in_pipe (inp_data);
546        out = create_tmpfile ("gpg_revcert");
547        if (create_process (cmd, in, out, NULL)) {
548            *r_revcert = NULL;
549            err = gpg_error (GPG_ERR_INTERNAL);
550        }
551        else {
552            rcrt = map_tmpfile (out, NULL);
553            *r_revcert = rcrt;
554            if (rcrt && strlen (rcrt) == 0)
555                err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
556        }
557    
558        free (p);
559        free (cmd);
560    
561        CloseHandle (in);
562        CloseHandle (out);
563        return err;
564    }
565    
566    
567    /* Return the raw photo-id data combined with the status-fd
568       entry in @r_data. If @keyid is set, only the data for this
569       key will be returned.
570       Return value: 0 on success. */
571    gpgme_error_t
572    gpg_get_photoid_data (const char *keyid, char **r_status_data,
573                          unsigned char **r_data, unsigned long *ndata)
574    {
575        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
576        HANDLE herr, hdat;
577        char *p, *cmd;
578        DWORD n;
579    
580        if (ndata)
581            *ndata = 0;
582        p = read_gpg_program ();
583        if (!p)
584            return gpg_error (GPG_ERR_INV_ARG);
585        n = strlen (p) + 128;
586        if (keyid)
587            n += strlen (keyid) + 1;
588        cmd = (char*)calloc (1, n+1);
589        if (!cmd)
590            BUG (NULL);
591        hdat = create_tmpfile ("gpg_uat_data");
592        herr = create_tmpfile ("gpg_uat_status");
593        /* XXX: add --list-options show-unsuable-uid to display
594                revoked attribute IDs */
595        sprintf (cmd, "%s --attribute-fd=%d --status-fd=2 --list-keys %s",
596                 p, (int)hdat, keyid? keyid : "");
597        if (create_process (cmd, NULL, NULL, herr))
598            err = gpg_error (GPG_ERR_INTERNAL);
599    
600        free (p);
601        free (cmd);
602    
603        *r_data = (BYTE*)map_tmpfile (hdat, ndata);
604        *r_status_data = map_tmpfile (herr, NULL);
605        CloseHandle (hdat);
606        CloseHandle (herr);
607    
608        return err;
609    }
610    
611    
612    /* Extract one or more keys from the key file @keyfile.
613       The keys to extract are give in @keys and the size of it is @nkeys.
614       @new_keyfile is a file with the extract keys.
615       Return value: 0 on success. */
616    gpgme_error_t
617    gpg_extract_keys (const char *keyfile, const char **keys, DWORD nkeys,
618                      char **new_keyfile)
619    {
620        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
621        const char *fmt;
622        char *p, *cmd;
623        char tmpnam[MAX_PATH], tmpdir[MAX_PATH];
624        int i, n;
625    
626        /* copy key file to temp dir. */
627        GetTempPath (MAX_PATH-1, tmpdir);
628        get_temp_name (tmpnam, MAX_PATH-1, NULL);
629        CopyFile (keyfile, tmpnam, FALSE);
630    
631        /* create temp file for output. */
632        *new_keyfile = new char[MAX_PATH];
633        if (!*new_keyfile)
634            BUG (NULL);
635        get_temp_name (*new_keyfile, MAX_PATH-1, "sel_keys");
636    
637        p = read_gpg_program ();
638        if (!p)
639            return gpg_error (GPG_ERR_INV_ARG);
640    
641        /* Use the temp key file as a keyring and export the selected
642           keys from it. */
643        fmt = "%s --yes --output %s --no-options --homedir %s --keyring %s --export ";
644        n = strlen (fmt) + strlen (p)+1 + strlen (tmpdir)+1 + strlen (tmpnam) + 1;
645        n += strlen (*new_keyfile)+1;
646        for (i=0; i < (int)nkeys; i++)
647            n += strlen (keys[i])+1+2;
648        cmd = (char*)calloc (1, n+1);
649        sprintf (cmd, fmt, p, *new_keyfile, tmpdir, tmpnam);
650        for (i=0; i < (int)nkeys; i++) {
651            strcat (cmd, keys[i]);
652            strcat (cmd, " " );
653        }
654    
655        if (create_process (cmd, NULL, NULL, NULL))
656            err = gpgme_error (GPG_ERR_INTERNAL);
657    
658        DeleteFile (tmpnam);
659        safe_free (cmd);
660        safe_free (p);
661        return err;
662    }
663    
664    
665    /* Return the validity of the user attribute, informerly known
666       as photo-ID. If no uat was found, return 0 for unknown. */
667    gpgme_error_t
668    get_uat_validity (const char *keyid, gpgme_validity_t *r_valid)
669    {
670        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
671        HANDLE out;
672        char *p, *cmd;
673        char *uat;
674    
675        *r_valid = GPGME_VALIDITY_UNKNOWN;
676        p = read_gpg_program ();
677        if (!p)
678            return gpg_error (GPG_ERR_INV_ARG);
679    
680        cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
681        if (!cmd)
682            BUG (NULL);
683        sprintf (cmd, "%s --with-colons --fixed-list-mode --list-keys \"%s\"",
684                 p, keyid);
685    
686        out = create_tmpfile ("gpg_keys");
687        if (create_process (cmd, NULL, out, NULL))
688            err = gpg_error (GPG_ERR_INTERNAL);
689    
690        safe_free (p);
691        safe_free (cmd);
692        
693        p = map_tmpfile (out, NULL);
694        if ((uat = strstr (p, "uat:"))) {
695            switch (*(uat+4)) {
696            case 'm': *r_valid = GPGME_VALIDITY_MARGINAL; break;
697            case 'f':
698            case 'u': *r_valid = GPGME_VALIDITY_FULL; break;
699            default: *r_valid = GPGME_VALIDITY_UNDEFINED; break;
700            }
701        }
702    
703        free (p);    
704        CloseHandle (out);
705        return err;
706    }
707    
708    
709    static gpgme_error_t
710    clip_store_data (char *tmp_outname, DWORD outlen)
711    {
712        gpgme_data_t in;
713        gpgme_error_t err;
714    
715        get_temp_name (tmp_outname, outlen-1, NULL);
716        err = gpg_data_new_from_clipboard (&in, 0);
717        if (err)
718            return err;
719        err = gpg_data_release_and_set_file (in, tmp_outname);
720        return err;
721    }
722    
723    
724    /* Extract all recipients from the file @file.
725       Return value: 0 on success. */
726    static gpgme_error_t
727    file_extract_recipient (const char *file, gpgme_recipient_t *r_list)
728    {    
729        PACKET *pkt;
730        PKT_pubkey_enc *enc;
731        gpg_iobuf_t inp = NULL;
732        armor_filter_context_t afx;
733        gpgme_recipient_t l;
734        int rc = 0, quit=0;
735    
736        if (!file || !r_list) {
737            log_debug ("do_list_packets: !r_list || !file");
738            return gpgme_error (GPG_ERR_INV_ARG);
739        }
740    
741        *r_list=NULL;
742        inp = gpg_iobuf_open (file);
743        if (!inp)
744            return gpgme_err_code_from_errno (errno);
745        gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
746        if (gpg_use_armor_filter (inp)) {
747            memset (&afx, 0, sizeof (afx));
748            gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);
749        }
750        pkt = (PACKET *)calloc(1, sizeof *pkt);
751        gpg_init_packet (pkt);
752        while (!quit && (rc = gpg_parse_packet (inp, pkt)) != -1) {
753            switch (pkt->pkttype) {
754            case PKT_PUBKEY_ENC:
755                enc = pkt->pkt.pubkey_enc;
756                if (!enc)
757                    break;
758                l = (gpgme_recipient_t)calloc (1, sizeof *l);          
759                if (!l)
760                    BUG (NULL);
761                l->keyid = (char*)calloc (1, 16+1);
762                _snprintf (l->keyid, 16, "%08lX%08lX", enc->keyid[0], enc->keyid[1]);
763                l->pubkey_algo = (gpgme_pubkey_algo_t)enc->pubkey_algo;
764                l->status = 0;
765                l->next = (*r_list);
766                *r_list = l;
767                break;
768    
769            case PKT_ENCRYPTED:    
770            case PKT_ENCRYPTED_MDC:
771            case PKT_COMPRESSED:
772            case PKT_PUBLIC_KEY:
773            case PKT_SECRET_KEY:
774                quit = 1;
775                break;
776    
777            default:
778                break;
779            }
780            gpg_free_packet (pkt);
781            gpg_init_packet (pkt);
782        }
783        gpg_iobuf_close (inp);
784        safe_free (pkt);
785        return 0;
786    }
787    
788    
789    /* Either extract the list of recipients from the file @file or
790       if the string is NULL, try to extract them from the clipboard.
791       Return value: 0 on success. */
792    gpgme_error_t
793    gpg_get_recipients (const char *file, gpgme_recipient_t *r_list)
794    {
795        gpgme_error_t err;
796        char tmp[MAX_PATH+1];
797    
798        if (!file) {
799            clip_store_data (tmp, DIM (tmp)-2);
800            err = file_extract_recipient (tmp, r_list);
801            DeleteFile (tmp);
802        }
803        else
804            err = file_extract_recipient (file, r_list);
805        return err;
806    }
807    
808    
809    /* Try to find a subpacket with the given id @subpktid
810       inside the key @key.
811       Return value: 0 on success. */
812    gpgme_error_t
813    gpg_find_key_subpacket (const char *key, int subpktid,
814                            char **value)
815    {
816        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
817        const char *fmt;
818        const char *spk;
819        char *p, *cmd;
820        HANDLE out;
821    
822        *value = NULL;
823        p = read_gpg_program ();
824        fmt = "%s --with-colons --list-options show-sig-subpackets=%d --list-sigs %s";
825        cmd = (char*)calloc (1, strlen (fmt) + strlen (p) + strlen (key) + 32 + 1);
826        sprintf (cmd, fmt, p, subpktid, key);
827    
828        out = create_tmpfile ("gpg_subpackets");
829        if (create_process (cmd, NULL, out, NULL))
830            err = gpg_error (GPG_ERR_INTERNAL);
831    
832        free (p);
833        free (cmd);
834    
835        p = map_tmpfile (out, NULL);
836        if (p && (spk=strstr (p, "spk"))) {
837            char *end = strstr (spk, "\n");
838            if (end) {
839                *value = (char*)calloc (1, (end-spk)+1);
840                memcpy (*value, spk, (end-spk)-1);
841            }
842        }
843    
844        free (p);
845        CloseHandle (out);
846        return err;
847    }

Legend:
Removed from v.25  
changed lines
  Added in v.181

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26