/[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 32 by twoaday, Mon Oct 24 08:03:48 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 - 64, 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) + 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        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.32  
changed lines
  Added in v.181

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26