/[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 33 by twoaday, Tue Oct 25 07:46:20 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) { /* Should not happen.  */            DECODE_ONE ('\"', '\"');
106                  *(dest++) = *(src++);            DECODE_ONE ('\?', '\?');
107                  *(dest++) = *(src++);            DECODE_ONE ('\\', '\\');
108                  if (*src)            DECODE_ONE ('a', '\a');
109                    *(dest++) = *(src++);            DECODE_ONE ('b', '\b');
110                  if (*src)            DECODE_ONE ('f', '\f');
111                    *(dest++) = *(src++);            DECODE_ONE ('n', '\n');
112              }            DECODE_ONE ('r', '\r');
113              else {            DECODE_ONE ('t', '\t');
114                  if (!val) {            DECODE_ONE ('v', '\v');
115                      /* A binary zero is not representable in a C string.  */  
116                      *(dest++) = '\\';        case 'x': {
117                      *(dest++) = '0';              int val = hextobyte ((unsigned char*)&src[2]);
118                  }              if (val == -1) { /* Should not happen.  */
119                  else                  *(dest++) = *(src++);
120                      *((unsigned char *) dest++) = val;                  *(dest++) = *(src++);
121                  src += 4;                  if (*src)
122              }                    *(dest++) = *(src++);
123          }                  if (*src)
124                      *(dest++) = *(src++);
125          default: /* Should not happen.  */              }
126            {              else {
127              *(dest++) = *(src++);                  if (!val) {
128              *(dest++) = *(src++);                      /* A binary zero is not representable in a C string.  */
129            }                      *(dest++) = '\\';
130          }                      *(dest++) = '0';
131    }                  }
132    *(dest++) = 0;                  else
133    return 0;                      *((unsigned char *) dest++) = val;
134  }                  src += 4;
135                }
136  /* Replace %foo% entries with its real values.          }
137     Return value: expanded path or NULL on error. */  
138  static char *          default: /* Should not happen.  */
139  expand_path (const char *path)            {
140  {              *(dest++) = *(src++);
141      DWORD len;              *(dest++) = *(src++);
142      char *p;            }
143            }
144      len = ExpandEnvironmentStrings (path, NULL, 0);    }
145      if (!len)    *(dest++) = 0;
146          return NULL;    return 0;
147      len += 1;  }
148      p = (char*)calloc (1, len+1);  
149      if (!p)  /* Replace %foo% entries with its real values.
150          abort ();     Return value: expanded path or NULL on error. */
151      len = ExpandEnvironmentStrings (path, p, len);  static char *
152      if (!len) {  expand_path (const char *path)
153          free (p);  {
154          return NULL;      DWORD len;
155      }      char *p;
156      return p;  
157  }      len = ExpandEnvironmentStrings (path, NULL, 0);
158        if (!len)
159            return NULL;
160  /* Read a string from the W32 registry. The directory is given      len += 1;
161     in @dir and the name of the value in @name, */      p = (char*)calloc (1, len+1);
162  static char *      if (!p)
163  read_w32_registry (HKEY root_key, const char *dir, const char *name)          BUG (NULL);
164  {      len = ExpandEnvironmentStrings (path, p, len);
165      HKEY key_handle;      if (!len) {
166      DWORD n1, nbytes;          free (p);
167      DWORD type;          return NULL;
168      char *result = NULL;      }
169            return p;
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;  /* Read a string from the W32 registry. The directory is given
174      if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))     in @dir and the name of the value in @name, */
175          goto leave;  static char *
176      result = (char*)calloc (1, (n1=nbytes+1));  read_w32_registry (HKEY root_key, const char *dir, const char *name)
177      if (!result)  {
178          abort ();      HKEY key_handle;
179      if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {      DWORD n1, nbytes;
180          free (result);      DWORD type;
181          result = NULL;      char *result = NULL;
182          goto leave;      
183      }      if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
184      if (type == REG_EXPAND_SZ && strchr (result, '%')) {          return NULL; /* no need for a RegClose, so return direct */
185          char *p = expand_path (result);      
186          free (result);      nbytes = 1;
187          result = p;      if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
188      }          goto leave;
189            result = (char*)calloc (1, (n1=nbytes+1));
190  leave:      if (!result)
191      RegCloseKey (key_handle);          BUG (NULL);
192      return result;      if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {
193  }          free (result);
194            result = NULL;
195            goto leave;
196  /* Create a temp file based on the name of @name.      }
197     Return value: handle to the file in case of success. */      if (type == REG_EXPAND_SZ && strchr (result, '%')) {
198  static HANDLE          char *p = expand_path (result);
199  create_tmpfile (const char *name)          free (result);
200  {              result = p;
201      HANDLE out;      }
202      SECURITY_ATTRIBUTES sattr;      
203      char tmp[300];  leave:
204        RegCloseKey (key_handle);
205      memset (&sattr, 0, sizeof sattr);      return result;
206      sattr.bInheritHandle = TRUE;  }
207      sattr.lpSecurityDescriptor = NULL;  
208      sattr.nLength = sizeof sattr;  static char*
209    read_gpg_program (void)
210      GetTempPath (sizeof (tmp)-1 - strlen (name)-1, tmp);  {
211      strcat (tmp, name);      return read_w32_registry (HKEY_CURRENT_USER,
212      out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,                                "Software\\GNU\\GnuPG", "gpgProgram");
213                        FILE_SHARE_WRITE, &sattr,  }
214                        OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);  
215      return out;  
216  }  /* Create a temp file based on the name of @name.
217       Return value: handle to the file in case of success. */
218    static HANDLE
219  /* Create a pipe with a readable remote end and  create_tmpfile (const char *name)
220     write the data from @dat to the local end.  {    
221     Return value: read handle on success. */      HANDLE out;
222  static HANDLE      SECURITY_ATTRIBUTES sec_attr;
223  create_in_pipe (const char *dat)      char tmp[300];
224  {  
225      HANDLE r, w;      memset (&sec_attr, 0, sizeof sec_attr);
226      SECURITY_ATTRIBUTES sec_attr;      sec_attr.bInheritHandle = TRUE;
227      DWORD n;      sec_attr.lpSecurityDescriptor = NULL;
228        sec_attr.nLength = sizeof sec_attr;
229      memset (&sec_attr, 0, sizeof sec_attr);  
230      sec_attr.bInheritHandle = TRUE;      get_temp_name (tmp, DIM (tmp)-1, name);
231      sec_attr.nLength = sizeof sec_attr;      out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,
232                          FILE_SHARE_WRITE, &sec_attr,
233      if (!CreatePipe (&r, &w, &sec_attr, 4096))                        OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
234          return NULL;      if (out == INVALID_HANDLE_VALUE)
235            log_debug ("create_tmpfile: CreateFile failed ec=%d\r\n",
236      WriteFile (w, dat, strlen (dat), &n, NULL);                     (int)GetLastError ());
237      CloseHandle (w);      return out;
238    }
239      return r;  
240  }  
241    /* Create a pipe with a readable remote end and
242       write the data from @dat to the local end.
243  /* Map the contents of the file handle @out to     Return value: read handle on success. */
244     a buffer and return it. */  static HANDLE
245  static char*  create_in_pipe (const char *dat)
246  map_tmpfile (HANDLE out)  {
247  {      HANDLE r, w;
248      DWORD n;      SECURITY_ATTRIBUTES sec_attr;
249      char *p;      DWORD n;
250    
251      FlushFileBuffers (out);      memset (&sec_attr, 0, sizeof sec_attr);
252      SetFilePointer (out, 0, NULL, FILE_BEGIN);      sec_attr.bInheritHandle = TRUE;
253      n = GetFileSize (out, NULL);      sec_attr.nLength = sizeof sec_attr;
254      p = (char*)calloc (1, n+1);  
255      if (!p)      if (!CreatePipe (&r, &w, &sec_attr, 4096)) {
256          abort ();          log_debug ("create_in_pipe: CreatePipeFailed ec=%d\r\n",
257      ReadFile (out, p, n, &n, NULL);                     (int)GetLastError ());
258      p[n] = 0;          return NULL;
259      return p;      }
260  }  
261        WriteFile (w, dat, strlen (dat), &n, NULL);
262        CloseHandle (w);
263  /* Create a process from the command line in @cmd.  
264     If @out is != NULL, the output of the process will      return r;
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  /* Map the contents of the file handle @out to
269  create_process (const char *cmd, HANDLE in, HANDLE out)     a buffer and return it. */
270  {  static char*
271      STARTUPINFO si;  map_tmpfile (HANDLE out, DWORD *nread)
272      PROCESS_INFORMATION pi;  {
273        DWORD n;
274      memset (&si, 0, sizeof (si));      char *p;
275      si.cb = sizeof si;  
276      if (in || out)      FlushFileBuffers (out);
277          si.dwFlags = STARTF_USESTDHANDLES;      SetFilePointer (out, 0, NULL, FILE_BEGIN);
278      if (out)      n = GetFileSize (out, NULL);
279          si.hStdOutput = out;      p = (char*)calloc (1, n+1);
280      if (in)      if (!p)
281          si.hStdInput = in;          BUG (NULL);
282      if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,      ReadFile (out, p, n, &n, NULL);
283                          NULL, NULL, &si, &pi))      p[n] = 0;
284          return -1;      if (nread)
285      WaitForSingleObject (pi.hProcess, INFINITE);          *nread = n;
286      CloseHandle (pi.hProcess);      return p;
287      return 0;  }
288  }  
289    
290    /* Create a process from the command line in @cmd.
291  /* Export a GPG secret key given by @keyid into the file @outfile.     If @out is != NULL, the output of the process will
292     Return value: 0 on success. */     be redirected to @out. If @in is != NULL the input
293  gpgme_error_t     will be read from @in.
294  gpg_export_seckey (const char *keyid, const char *outfile)     Return value: 0 on success. */
295  {  static int
296      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);  create_process (const char *cmd, HANDLE in, HANDLE out, HANDLE err)
297      struct stat st;  {
298      char *p;      STARTUPINFO si;
299      char *cmd;      PROCESS_INFORMATION pi;
300    
301      p = read_w32_registry (HKEY_CURRENT_USER,      memset (&si, 0, sizeof (si));
302                             "Software\\GNU\\GnuPG", "gpgProgram");      si.cb = sizeof si;
303      if (!p)      if (in || out || err)
304          return gpg_error (GPG_ERR_INV_ARG);          si.dwFlags = STARTF_USESTDHANDLES;
305      cmd = (char*)calloc (1, strlen (p) + strlen (keyid)      if (out)
306                              + 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",      if (err)
310               p, outfile, keyid);          si.hStdError = err;
311      if (create_process (cmd, NULL, NULL))      si.dwFlags |= STARTF_USESHOWWINDOW;
312          err = gpg_error (GPG_ERR_INTERNAL);      si.wShowWindow = SW_HIDE;
313        if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
314      if (stat (outfile, &st) == -1 || st.st_size == 0)                          NULL, NULL, &si, &pi)) {
315          err = gpg_error (GPG_ERR_NO_DATA);          log_debug ("create_process: CreateProcess failed ec=%d\r\n",
316                       (int)GetLastError ());
317      free (p);          return -1;
318      free (cmd);      }
319      return err;      WaitForSingleObject (pi.hProcess, INFINITE);
320  }      CloseHandle (pi.hProcess);
321        return 0;
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. */  /* Export a GPG secret key given by @keyid into the file @outfile.
326  gpgme_error_t     Return value: 0 on success. */
327  gpg_manage_ownertrust (char **data, int export)  gpgme_error_t
328  {  gpg_export_seckey (const char *keyid, const char *outfile)
329      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);  {
330      HANDLE out = NULL, in = NULL;      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
331      char *p;      struct stat st;
332      char *cmd;      char *p;
333        char *cmd;
334      p = read_w32_registry (HKEY_CURRENT_USER,  
335                             "Software\\GNU\\GnuPG", "gpgProgram");      p = read_gpg_program ();
336      if (!p)      if (!p)
337          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
338        cmd = (char*)calloc (1, strlen (p) + strlen (keyid)
339      cmd = (char*)calloc (1, strlen (p) + 64 + 1);                              + strlen (outfile) + 64 + 2);
340      if (!cmd)      if (!cmd)
341          abort ();            BUG (NULL);
342      sprintf (cmd, "%s %s", p,      sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s",
343               export? "--export-ownertrust" : "--import-ownertrust");               p, outfile, keyid);
344        if (create_process (cmd, NULL, NULL, NULL))
345      if (export)          err = gpg_error (GPG_ERR_INTERNAL);
346          out = create_tmpfile ("gpg_ot_out");  
347      else {      if (stat (outfile, &st) == -1 || st.st_size == 0)
348          DWORD nw;          err = gpg_error (GPG_ERR_NO_DATA);
349          in = create_tmpfile ("gpg_ot_in");  
350          WriteFile (in, *data, strlen (*data), &nw, NULL);      free (p);
351          FlushFileBuffers (in);      free (cmd);
352          /* XXX: need a rewind? */      return err;
353      }  }
354      if (create_process (cmd, in, out))  
355          err = gpg_error (GPG_ERR_INTERNAL);  
356    /* If @export is 1, export the ownertrust data to the
357      free (p);     buffer @data. Otherwise import the ownertrust data from @data.
358      free (cmd);     Return value: 0 on success. */
359    gpgme_error_t
360      if (in)  gpg_manage_ownertrust (char **data, int do_export)
361          CloseHandle (in);  {
362      if (out) {      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
363          *data = map_tmpfile (out);      HANDLE out = NULL, in = NULL;
364          CloseHandle (out);      char *p;
365      }      char *cmd;
366      return err;  
367  }      p = read_gpg_program ();
368        if (!p)
369            return gpg_error (GPG_ERR_INV_ARG);
370  /* Call gpg --rebuild-keydb-caches to speed up signature listings. */  
371  gpgme_error_t      cmd = (char*)calloc (1, strlen (p) + 64 + 1);
372  gpg_rebuild_cache (char **r_inf)      if (!cmd)
373  {          BUG (NULL);
374      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      sprintf (cmd, "%s %s", p,
375      HANDLE out = NULL;               do_export? "--export-ownertrust" : "--import-ownertrust");
376      char *p;  
377      char *cmd;      if (do_export)
378            out = create_tmpfile ("gpg_ot_out");
379      p = read_w32_registry (HKEY_CURRENT_USER,      else {
380                             "Software\\GNU\\GnuPG", "gpgProgram");          DWORD nw;
381      if (!p)          in = create_tmpfile ("gpg_ot_in");
382          return gpg_error (GPG_ERR_INV_ARG);          WriteFile (in, *data, strlen (*data), &nw, NULL);
383      cmd = (char*)calloc (1, strlen (p) + 64);          FlushFileBuffers (in);
384      if (!cmd)          /* XXX: need a rewind? */
385          abort ();      }
386      sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);      if (create_process (cmd, in, out, NULL))
387            err = gpg_error (GPG_ERR_INTERNAL);
388      if (r_inf)  
389          out = create_tmpfile ("gpg_rebuild_cache");      free (p);
390        free (cmd);
391      if (create_process (cmd, NULL, out))  
392          err = gpg_error (GPG_ERR_INTERNAL);      if (in)
393            CloseHandle (in);
394      if (r_inf)      if (out) {
395          *r_inf = map_tmpfile (out);          *data = map_tmpfile (out, NULL);
396      if (out)          CloseHandle (out);
397          CloseHandle (out);      }
398      free (p);  
399      free (cmd);      return err;
400      return 0;  }
401  }  
402    
403    /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
404  /* Call gpg --version to retrieve the 'about' information. */  gpgme_error_t
405  gpgme_error_t  gpg_rebuild_cache (char **r_inf)
406  gpg_get_version (char **r_inf)  {
407  {      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
408      gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);      HANDLE out = NULL;
409      HANDLE out;          char *p;
410      char *p, *cmd;      char *cmd;
411    
412      p =read_w32_registry (HKEY_CURRENT_USER,      p = read_gpg_program ();
413                            "Software\\GNU\\GnuPG", "gpgProgram");      if (!p)
414      if (!p)          return gpg_error (GPG_ERR_INV_ARG);
415          return gpg_error (GPG_ERR_INV_ARG);      cmd = (char*)calloc (1, strlen (p) + 64);
416      cmd = (char*)calloc (1, strlen (p) + 32);      if (!cmd)
417      if (!cmd)          BUG (NULL);
418          abort ();      sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);
419      sprintf (cmd, "%s --version", p);  
420        if (r_inf)
421      out = create_tmpfile ("gpg_out");          out = create_tmpfile ("gpg_rebuild_cache");
422      if (create_process (cmd, NULL, out))  
423          err = gpg_error (GPG_ERR_INTERNAL);      if (create_process (cmd, NULL, out, NULL))
424            err = gpg_error (GPG_ERR_INTERNAL);
425      free (p);  
426      free (cmd);      if (r_inf)
427            *r_inf = map_tmpfile (out, NULL);
428      *r_inf = map_tmpfile (out);      if (out)
429      CloseHandle (out);              CloseHandle (out);
430      return err;      free (p);
431  }      free (cmd);
432        return 0;
433    }
434  /* Return the colon file output of the given file @fname in @r_out.  
435     Return value: 0 on success. */  
436  gpgme_error_t  /* Call gpg --version to retrieve the 'about' information. */
437  gpg_import_key_list (const char *fname, char **r_out)  gpgme_error_t
438  {  gpg_get_version (char **r_inf)
439      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);  {
440      char *cmd, *p;      gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
441      HANDLE out;      HANDLE out;    
442        char *p, *cmd;
443      p = read_w32_registry (HKEY_CURRENT_USER,  
444                             "Software\\GNU\\GnuPG", "gpgProgram");      p = read_gpg_program ();
445      if (!p)      if (!p)
446          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
447        cmd = (char*)calloc (1, strlen (p) + 32);
448      cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);      if (!cmd)
449      if (!cmd)          BUG (NULL);
450          abort ();      sprintf (cmd, "%s --version", p);
451      sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);  
452        out = create_tmpfile ("gpg_out");
453      out = create_tmpfile ("gpg_keys");      if (create_process (cmd, NULL, out, NULL))
454      if (create_process (cmd, NULL, out))          err = gpg_error (GPG_ERR_INTERNAL);
455          err = gpg_error (GPG_ERR_INTERNAL);  
456        free (p);
457      free (p);      free (cmd);
458      free (cmd);  
459        *r_inf = map_tmpfile (out, NULL);
460      *r_out = map_tmpfile (out);      CloseHandle (out);    
461      CloseHandle (out);      return err;
462      return err;  }
463  }  
464    
465  char*  /* Return the colon file output of the given file @fname in @r_out.
466  generate_revoc_input (int code, const char *cmt, const char *pass)     Return value: 0 on success. */
467  {  gpgme_error_t
468      const char *fmt;  gpg_import_key_list (const char *fname, char **r_out)
469      char *p;  {
470      size_t n;      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
471        char *cmd, *p;
472      fmt = "Y\n"     /*  gen_revoke.okay */      HANDLE out;
473            "%d\n"    /* ask_revocation_reason.code */  
474            "%s\n"    /* ask_revocation_reason.text */      p = read_gpg_program ();
475            "%s"      /* text != NULL '\n' otherwise '' */      if (!p)
476            "Y\n"     /* ask_revocation_reason.okay */          return gpg_error (GPG_ERR_INV_ARG);
477            "%s\n";   /* passphrase.enter. */  
478      n = strlen (fmt) + 32;      cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);
479      if (pass)      if (!cmd)
480          n += strlen (pass) + 1;          BUG (NULL);
481      if (cmt)      sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);
482          n += strlen (cmt) + 1;  
483      p = (char*)calloc (1, n+1);      out = create_tmpfile ("gpg_keys");
484      if (!p)      if (create_process (cmd, NULL, out, NULL))
485          abort ();          err = gpg_error (GPG_ERR_INTERNAL);
486      sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");  
487      return p;      free (p);
488  }      free (cmd);
489        
490        *r_out = map_tmpfile (out, NULL);
491  /* Generate a revocation certificate for the key with the keyid @keyid.      CloseHandle (out);
492     @inp_data contains all needed data to answer the questions of the      return err;
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  char*
497  gpg_revoke_key (const char *inp_data, const char *keyid, char **r_revcert)  generate_revoke_input (int code, const char *cmt, const char *pass)
498  {  {
499      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      const char *fmt;
500      char *rcrt;      char *p;
501      char *cmd, *p;      size_t n;
502      HANDLE in, out;  
503            fmt = "Y\n"     /*  gen_revoke.okay */
504      p = read_w32_registry (HKEY_CURRENT_USER,            "%d\n"    /* ask_revocation_reason.code */
505                             "Software\\GNU\\GnuPG", "gpgProgram");            "%s\n"    /* ask_revocation_reason.text */
506      if (!p)            "%s"      /* text != NULL '\n' otherwise '' */
507          return gpg_error (GPG_ERR_INV_ARG);            "Y\n"     /* ask_revocation_reason.okay */
508              "%s\n";   /* passphrase.enter. */
509      cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);      n = strlen (fmt) + 32;
510      if (!cmd)      if (pass)
511          abort ();          n += strlen (pass) + 1;
512      sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",      if (cmt)
513               p, keyid);          n += strlen (cmt) + 1;
514        p = (char*)calloc (1, n+1);
515      in = create_in_pipe (inp_data);      if (!p)
516      out = create_tmpfile ("gpg_revcert");          BUG (NULL);
517      if (create_process (cmd, in, out)) {      sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");
518          *r_revcert = NULL;      return p;
519          err = gpg_error (GPG_ERR_INTERNAL);  }
520      }      
521      else {  
522          rcrt = map_tmpfile (out);  /* Generate a revocation certificate for the key with the keyid @keyid.
523          *r_revcert = rcrt;     @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      free (p);     Return value: 0 on success. */
527      free (cmd);  gpgme_error_t
528    gpg_revoke_cert (const char *inp_data, const char *keyid, char **r_revcert)
529      CloseHandle (in);  {
530      CloseHandle (out);      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
531      return err;      char *rcrt;
532  }      char *cmd, *p;
533        HANDLE in, out;
534        
535  /* Return the validity of the user attribute, informerly known      p = read_gpg_program ();
536     as photo-ID. If no uat was found, return 0 for unknown. */      if (!p)
537  gpgme_error_t          return gpg_error (GPG_ERR_INV_ARG);
538  get_uat_validity (const char *keyid, gpgme_validity_t *r_valid)  
539  {      cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
540      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);      if (!cmd)
541      HANDLE out;          BUG (NULL);
542      char *p, *cmd;      sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",
543      char *uat;               p, keyid);
544    
545      *r_valid = GPGME_VALIDITY_UNKNOWN;      in = create_in_pipe (inp_data);
546      p = read_w32_registry (HKEY_CURRENT_USER,      out = create_tmpfile ("gpg_revcert");
547                             "Software\\GNU\\GnuPG", "gpgProgram");      if (create_process (cmd, in, out, NULL)) {
548      if (!p)          *r_revcert = NULL;
549          return gpg_error (GPG_ERR_INV_ARG);          err = gpg_error (GPG_ERR_INTERNAL);
550        }
551      cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);      else {
552      if (!cmd)          rcrt = map_tmpfile (out, NULL);
553          abort ();          *r_revcert = rcrt;
554      sprintf (cmd, "%s --with-colons --fixed-list-mode --list-keys \"%s\"",          if (rcrt && strlen (rcrt) == 0)
555               p, keyid);              err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
556        }
557      out = create_tmpfile ("gpg_keys");  
558      if (create_process (cmd, NULL, out))      free (p);
559          err = gpg_error (GPG_ERR_INTERNAL);      free (cmd);
560    
561      free (p);      CloseHandle (in);
562      free (cmd);      CloseHandle (out);
563            return err;
564      p = map_tmpfile (out);  }
565      if ((uat = strstr (p, "uat:"))) {  
566          switch (*(uat+4)) {  
567          case 'm': *r_valid = GPGME_VALIDITY_MARGINAL; break;  /* Return the raw photo-id data combined with the status-fd
568          case 'f':     entry in @r_data. If @keyid is set, only the data for this
569          case 'u': *r_valid = GPGME_VALIDITY_FULL; break;     key will be returned.
570          default: *r_valid = GPGME_VALIDITY_UNDEFINED; break;     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      free (p);      {
575      CloseHandle (out);      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
576      return err;      HANDLE herr, hdat;
577  }      char *p, *cmd;
578        DWORD n;
579    
580  #if 0      if (ndata)
581  /* Extract all recipients from the file @file.          *ndata = 0;
582     Return value: 0 on success. */      p = read_gpg_program ();
583  static int      if (!p)
584  do_get_recipients (const char *file, gpgme_recipient_t *r_list)          return gpg_error (GPG_ERR_INV_ARG);
585  {      n = strlen (p) + 128;
586      gpgme_recipient_t l;      if (keyid)
587      PACKET *pkt;          n += strlen (keyid) + 1;
588      gpg_iobuf_t inp = NULL;      cmd = (char*)calloc (1, n+1);
589      armor_filter_context_t afx;      if (!cmd)
590      int rc = 0, quit=0;          BUG (NULL);
591        hdat = create_tmpfile ("gpg_uat_data");
592      if (!file || !r_list) {      herr = create_tmpfile ("gpg_uat_status");
593          log_debug ("do_list_packets: !r_list || !file");      /* XXX: add --list-options show-unsuable-uid to display
594          return -1;              revoked attribute IDs */
595      }      sprintf (cmd, "%s --attribute-fd=%d --status-fd=2 --list-keys %s",
596                 p, (int)hdat, keyid? keyid : "");
597      *r_list=NULL;      if (create_process (cmd, NULL, NULL, herr))
598      inp = gpg_iobuf_open (file);          err = gpg_error (GPG_ERR_INTERNAL);
599      if (!inp)  
600          return WPTERR_FILE_OPEN;      free (p);
601      gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */      free (cmd);
602      if (gpg_use_armor_filter (inp)) {  
603          memset (&afx, 0, sizeof (afx));      *r_data = (BYTE*)map_tmpfile (hdat, ndata);
604          gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);      *r_status_data = map_tmpfile (herr, NULL);
605      }      CloseHandle (hdat);
606      pkt = (PACKET *)calloc(1, sizeof *pkt);      CloseHandle (herr);
607      gpg_init_packet (pkt);  
608      while (!quit && (rc = gpg_parse_packet (inp, pkt)) != -1) {      return err;
609          switch (pkt->pkttype) {  }
610          case PKT_PUBKEY_ENC:  
611              {PKT_pubkey_enc *enc = pkt->pkt.pubkey_enc;  
612              if (!enc)  /* Extract one or more keys from the key file @keyfile.
613                  break;     The keys to extract are give in @keys and the size of it is @nkeys.
614              l = calloc (1, sizeof *l);     @new_keyfile is a file with the extract keys.
615              l->keyid = calloc (1, 16+1);     Return value: 0 on success. */
616              _snprintf (l->keyid, 16, "%08lX%08lX", enc->keyid[0], enc->keyid[1]);  gpgme_error_t
617              l->pubkey_algo = enc->pubkey_algo;  gpg_extract_keys (const char *keyfile, const char **keys, DWORD nkeys,
618              l->status = 0;                    char **new_keyfile)
619              l->next = (*r_list);  {
620              *r_list = l;      gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
621              break;}      const char *fmt;
622        char *p, *cmd;
623          case PKT_ENCRYPTED:          char tmpnam[MAX_PATH], tmpdir[MAX_PATH];
624          case PKT_ENCRYPTED_MDC:      int i, n;
625          case PKT_COMPRESSED:  
626          case PKT_PUBLIC_KEY:      /* copy key file to temp dir. */
627          case PKT_SECRET_KEY:      GetTempPath (MAX_PATH-1, tmpdir);
628              quit = 1;      get_temp_name (tmpnam, MAX_PATH-1, NULL);
629              break;      CopyFile (keyfile, tmpnam, FALSE);
630          }  
631          gpg_free_packet (pkt);      /* create temp file for output. */
632          gpg_init_packet (pkt);      *new_keyfile = new char[MAX_PATH];
633      }      if (!*new_keyfile)
634      gpg_iobuf_close (inp);          BUG (NULL);
635      safe_free (pkt);      get_temp_name (*new_keyfile, MAX_PATH-1, "sel_keys");
636      return 0;  
637  }      p = read_gpg_program ();
638  #endif      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.33  
changed lines
  Added in v.181

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26