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

Contents of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (show annotations)
Mon Apr 17 09:12:50 2006 UTC (18 years, 10 months ago) by twoaday
File size: 21295 byte(s)
2006-04-16  Timo Schulz  <ts@g10code.de>
 
        * wptHTTP.cpp (getErrorCode): New.
        (connect): Store winsock error code.
        * wptGPGMEData.cpp (is_armor_header): New.
        * wptGPG.cpp (check_gnupg_engine): Free context.
        (gnupg_backup_keyrings): Do not use global vars.
        * wptGPGUtil.cpp (gpg_export_seckey): Export in ascii format.
         
2006-04-15  Timo Schulz  <ts@g10code.de>
 
        * wptKeyManager.cpp (km_get_key): New.
        (km_key_show_revoc_info): New.
        * wptKeyRevokeDlg.cpp (key_revoke_dlg): Cleanups.
        (on_init_dialog): New.
        * wptKeyManagerDlg.cpp (key_manager_dlg_proc): Factour
        out some common code and use km_get_key() instead.
        * wptKeyEditDlgs.cpp (do_init_keylist): Change second
        param type. Change all callers.
        * wptKeyEdit.cpp (addNotation): New.
        * wptKeyEditCB.cpp (editkey_command_handler): Remove 'step'
        param everywhere. Change all callers.


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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26