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

Contents of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 219 - (show annotations)
Sat May 27 08:56:00 2006 UTC (18 years, 9 months ago) by twoaday
File size: 20921 byte(s)
2006-05-25  Timo Schulz  <ts@g10code.de>
                                                                                
        * wptGPGUtil.cpp (gpg_rebuild_cache): Return error code.
        * wptGPGME.cpp (winpt_get_seckey): Fix off-by-one bug.
        * wptVerifyList.cpp (verlist_build): New argument type.
        Change all callers.
        (verlist_set_info_control): New.
        (verlist_set_additional_info): New.
        * wptFileVerifyDlg.cpp (file_verify_dlg_proc): Adjust code.
        * wptClipVerifyDlg.cpp (clip_verify_dlg_proc): Likewise.
        * wptFileCBS.cpp (read_cb, write_cb): Add logging.
                                                                                


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 log_debug ("read_w32_registry (%s, %s) failed.\r\n", dir, name);
194 return NULL; /* no need for a RegClose, so return direct */
195 }
196
197 nbytes = 1;
198 if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
199 goto leave;
200 result = (char*)xcalloc (1, (n1=nbytes+1));
201 if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {
202 safe_free (result);
203 result = NULL;
204 goto leave;
205 }
206 if (type == REG_EXPAND_SZ && strchr (result, '%')) {
207 char *p = expand_path (result);
208 safe_free (result);
209 result = p;
210 }
211
212 leave:
213 RegCloseKey (key_handle);
214 return result;
215 }
216
217
218 static char*
219 read_gpg_program (void)
220 {
221 return read_w32_registry (HKEY_CURRENT_USER,
222 "Software\\GNU\\GnuPG", "gpgProgram");
223 }
224
225
226 /* Create a temp file based on the name of @name.
227 Return value: handle to the file in case of success. */
228 static HANDLE
229 create_tmpfile (const char *name)
230 {
231 HANDLE out;
232 SECURITY_ATTRIBUTES sec_attr;
233 char tmp[MAX_PATH+64];
234
235 memset (&sec_attr, 0, sizeof sec_attr);
236 sec_attr.bInheritHandle = TRUE;
237 sec_attr.lpSecurityDescriptor = NULL;
238 sec_attr.nLength = sizeof sec_attr;
239
240 get_temp_name (tmp, DIM (tmp)-1, name);
241 out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,
242 FILE_SHARE_WRITE, &sec_attr,
243 OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
244 if (out == INVALID_HANDLE_VALUE)
245 log_debug ("create_tmpfile: CreateFile failed ec=%d\r\n",
246 (int)GetLastError ());
247 return out;
248 }
249
250
251 /* Create a pipe with a readable remote end and
252 write the data from @dat to the local end.
253 Return value: read handle on success. */
254 static HANDLE
255 create_in_pipe (const char *dat)
256 {
257 HANDLE r, w;
258 SECURITY_ATTRIBUTES sec_attr;
259 DWORD n;
260
261 memset (&sec_attr, 0, sizeof sec_attr);
262 sec_attr.bInheritHandle = TRUE;
263 sec_attr.nLength = sizeof sec_attr;
264
265 if (!CreatePipe (&r, &w, &sec_attr, 4096)) {
266 log_debug ("create_in_pipe: CreatePipeFailed ec=%d\r\n",
267 (int)GetLastError ());
268 return NULL;
269 }
270
271 WriteFile (w, dat, strlen (dat), &n, NULL);
272 CloseHandle (w);
273
274 return r;
275 }
276
277
278 /* Map the contents of the file handle @out to
279 a buffer and return it. */
280 static char*
281 map_tmpfile (HANDLE out, DWORD *nread)
282 {
283 DWORD n;
284 char *p;
285
286 FlushFileBuffers (out);
287 SetFilePointer (out, 0, NULL, FILE_BEGIN);
288 n = GetFileSize (out, NULL);
289 p = (char*)xcalloc (1, n+1);
290 ReadFile (out, p, n, &n, NULL);
291 p[n] = 0;
292 if (nread)
293 *nread = n;
294 return p;
295 }
296
297
298 /* Create a process from the command line in @cmd.
299 If @out is != NULL, the output of the process will
300 be redirected to @out. If @in is != NULL the input
301 will be read from @in.
302 Return value: 0 on success. */
303 static int
304 create_process (const char *cmd, HANDLE in, HANDLE out, HANDLE err)
305 {
306 STARTUPINFO si;
307 PROCESS_INFORMATION pi;
308
309 memset (&si, 0, sizeof (si));
310 si.cb = sizeof si;
311 if (in || out || err)
312 si.dwFlags = STARTF_USESTDHANDLES;
313 if (out)
314 si.hStdOutput = out;
315 if (in)
316 si.hStdInput = in;
317 if (err)
318 si.hStdError = err;
319 si.dwFlags |= STARTF_USESHOWWINDOW;
320 si.wShowWindow = SW_HIDE;
321 if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
322 NULL, NULL, &si, &pi)) {
323 log_debug ("create_process: CreateProcess failed ec=%d\r\n",
324 (int)GetLastError ());
325 return -1;
326 }
327 WaitForSingleObject (pi.hProcess, INFINITE);
328 CloseHandle (pi.hProcess);
329 return 0;
330 }
331
332
333 /* Export a GPG secret key given by @keyid into the file @outfile.
334 Return value: 0 on success. */
335 gpgme_error_t
336 gpg_export_seckey (const char *keyid, const char *outfile)
337 {
338 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
339 struct stat st;
340 const char *fmt;
341 char *p;
342 char *cmd;
343
344 p = read_gpg_program ();
345 if (!p)
346 return gpg_error (GPG_ERR_INV_ARG);
347 fmt = "%s --armor --yes --output \"%s\" --export-secret-key %s";
348 cmd = (char*)xcalloc (1, strlen (p) + strlen (keyid)
349 + strlen (outfile) + strlen (fmt) + 2);
350 sprintf (cmd, fmt, p, outfile, keyid);
351 if (create_process (cmd, NULL, NULL, NULL))
352 err = gpg_error (GPG_ERR_INTERNAL);
353
354 if (stat (outfile, &st) == -1 || st.st_size == 0)
355 err = gpg_error (GPG_ERR_NO_DATA);
356
357 safe_free (p);
358 safe_free (cmd);
359 return err;
360 }
361
362
363 /* If @export is 1, export the ownertrust data to the
364 buffer @data. Otherwise import the ownertrust data from @data.
365 Return value: 0 on success. */
366 gpgme_error_t
367 gpg_manage_ownertrust (char **data, int do_export)
368 {
369 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
370 HANDLE out = NULL, in = NULL;
371 char *p;
372 char *cmd;
373
374 p = read_gpg_program ();
375 if (!p)
376 return gpg_error (GPG_ERR_INV_ARG);
377
378 cmd = (char*)xcalloc (1, strlen (p) + 64 + 1);
379 sprintf (cmd, "%s %s", p,
380 do_export? "--export-ownertrust" : "--import-ownertrust");
381
382 if (do_export)
383 out = create_tmpfile ("gpg_ot_out");
384 else {
385 DWORD nw;
386 in = create_tmpfile ("gpg_ot_in");
387 WriteFile (in, *data, strlen (*data), &nw, NULL);
388 FlushFileBuffers (in);
389 }
390 if (create_process (cmd, in, out, NULL))
391 err = gpg_error (GPG_ERR_INTERNAL);
392
393 safe_free (p);
394 safe_free (cmd);
395
396 if (in)
397 CloseHandle (in);
398 if (out) {
399 *data = map_tmpfile (out, NULL);
400 CloseHandle (out);
401 }
402
403 return err;
404 }
405
406
407 /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
408 gpgme_error_t
409 gpg_rebuild_cache (char **r_inf)
410 {
411 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
412 HANDLE out = NULL;
413 const char *fmt;
414 char *p;
415 char *cmd;
416
417 p = read_gpg_program ();
418 if (!p)
419 return gpg_error (GPG_ERR_INV_ARG);
420 fmt = "%s --logger-fd=1 --batch --rebuild-keydb-caches";
421 cmd = (char*)xcalloc (1, strlen (p) + strlen (fmt) + 32);
422 sprintf (cmd, fmt, p);
423
424 if (r_inf)
425 out = create_tmpfile ("gpg_rebuild_cache");
426
427 if (create_process (cmd, NULL, out, NULL))
428 err = gpg_error (GPG_ERR_INTERNAL);
429
430 if (r_inf)
431 *r_inf = map_tmpfile (out, NULL);
432 if (out)
433 CloseHandle (out);
434 safe_free (p);
435 safe_free (cmd);
436 return err;
437 }
438
439
440 /* Call gpg --version to retrieve the 'about' information. */
441 gpgme_error_t
442 gpg_get_version (char **r_inf)
443 {
444 gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
445 HANDLE out;
446 char *p, *cmd;
447
448 p = read_gpg_program ();
449 if (!p)
450 return gpg_error (GPG_ERR_INV_ARG);
451 cmd = (char*)xcalloc (1, strlen (p) + 32);
452 sprintf (cmd, "%s --version", p);
453
454 out = create_tmpfile ("gpg_out");
455 if (create_process (cmd, NULL, out, NULL))
456 err = gpg_error (GPG_ERR_INTERNAL);
457
458 safe_free (p);
459 safe_free (cmd);
460
461 *r_inf = map_tmpfile (out, NULL);
462 CloseHandle (out);
463 return err;
464 }
465
466
467 /* Return the colon file output of the given file @fname in @r_out.
468 Return value: 0 on success. */
469 gpgme_error_t
470 gpg_import_key_list (const char *fname, char **r_out)
471 {
472 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
473 const char *fmt;
474 char *cmd, *p;
475 HANDLE out;
476
477 p = read_gpg_program ();
478 if (!p)
479 return gpg_error (GPG_ERR_INV_ARG);
480
481 fmt = "%s --fixed-list-mode --with-colons \"%s\"";
482 cmd = (char*)xcalloc (1, strlen (p) + strlen (fname) + strlen (fmt) + 2);
483 sprintf (cmd, fmt, p, fname);
484
485 out = create_tmpfile ("gpg_keys");
486 if (create_process (cmd, NULL, out, NULL))
487 err = gpg_error (GPG_ERR_INTERNAL);
488
489 safe_free (p);
490 safe_free (cmd);
491
492 *r_out = map_tmpfile (out, NULL);
493 CloseHandle (out);
494 return err;
495 }
496
497
498 /* Generate a revocation certificate for the key with the keyid @keyid.
499 @inp_data contains all needed data to answer the questions of the
500 command handler. Each separate with a '\n'.
501 @r_revcert contains the revocation cert on success.
502 if @desig_revoke is 1, the designated revoker mode is used.
503 Return value: 0 on success. */
504 gpgme_error_t
505 gpg_revoke_cert (int desig_revoke, const char *inp_data,
506 const char *keyid, char **r_revcert)
507 {
508 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
509 const char *fmt, *revcmd;
510 char *rcrt;
511 char *cmd, *p;
512 HANDLE in, out;
513
514 p = read_gpg_program ();
515 if (!p)
516 return gpg_error (GPG_ERR_INV_ARG);
517
518 revcmd = desig_revoke? "--desig-revoke" : "--gen-revoke";
519 fmt = "%s --pgp7 --command-fd=0 --status-fd=2 %s %s";
520 cmd = (char*)xcalloc (1, strlen (p) + strlen (revcmd) +
521 strlen (keyid) + strlen (fmt) + 2);
522 sprintf (cmd, fmt, p, revcmd, keyid);
523
524 in = create_in_pipe (inp_data);
525 out = create_tmpfile ("gpg_revcert");
526 if (create_process (cmd, in, out, NULL)) {
527 *r_revcert = NULL;
528 err = gpg_error (GPG_ERR_INTERNAL);
529 }
530 else {
531 rcrt = map_tmpfile (out, NULL);
532 *r_revcert = rcrt;
533 if (rcrt && strlen (rcrt) == 0)
534 err = gpg_error (GPG_ERR_BAD_PASSPHRASE);
535 }
536
537 safe_free (p);
538 safe_free (cmd);
539
540 CloseHandle (in);
541 CloseHandle (out);
542 return err;
543 }
544
545
546 /* Return the raw photo-id data combined with the status-fd
547 entry in @r_data. If @keyid is set, only the data for this
548 key will be returned.
549 Return value: 0 on success. */
550 gpgme_error_t
551 gpg_get_photoid_data (const char *keyid, char **r_status_data,
552 unsigned char **r_data, unsigned long *ndata)
553 {
554 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
555 HANDLE herr, hdat;
556 const char *fmt;
557 char *p, *cmd;
558 DWORD n;
559
560 if (ndata)
561 *ndata = 0;
562 p = read_gpg_program ();
563 if (!p)
564 return gpg_error (GPG_ERR_INV_ARG);
565 fmt = "%s --attribute-fd=%d --status-fd=2 --list-keys %s";
566 n = strlen (p) + strlen (fmt) + 1;
567 if (keyid)
568 n += strlen (keyid) + 1;
569 cmd = (char*)xcalloc (1, n+1);
570 /* XXX: add --list-options show-unsuable-uid to display
571 revoked attribute IDs */
572 hdat = create_tmpfile ("gpg_uat_data");
573 herr = create_tmpfile ("gpg_uat_status");
574 sprintf (cmd, fmt, p, (int)hdat, keyid? keyid : "");
575 if (create_process (cmd, NULL, NULL, herr))
576 err = gpg_error (GPG_ERR_INTERNAL);
577
578 safe_free (p);
579 safe_free (cmd);
580
581 *r_data = (BYTE*)map_tmpfile (hdat, ndata);
582 *r_status_data = map_tmpfile (herr, NULL);
583 CloseHandle (hdat);
584 CloseHandle (herr);
585
586 return err;
587 }
588
589
590 /* Extract one or more keys from the key file @keyfile.
591 The keys to extract are give in @keys and the size of it is @nkeys.
592 @new_keyfile is a file with the extract keys.
593 Return value: 0 on success. */
594 gpgme_error_t
595 gpg_extract_keys (const char *keyfile, const char **keys, DWORD nkeys,
596 char **new_keyfile)
597 {
598 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
599 const char *fmt;
600 char *p, *cmd;
601 char tmpnam[MAX_PATH], tmpdir[MAX_PATH];
602 int i, n;
603
604 /* copy key file to temp dir. */
605 GetTempPath (MAX_PATH-1, tmpdir);
606 get_temp_name (tmpnam, MAX_PATH-1, NULL);
607 CopyFile (keyfile, tmpnam, FALSE);
608
609 /* create temp file for output. */
610 *new_keyfile = new char[MAX_PATH];
611 if (!*new_keyfile)
612 BUG (NULL);
613 get_temp_name (*new_keyfile, MAX_PATH-1, "sel_keys");
614
615 p = read_gpg_program ();
616 if (!p)
617 return gpg_error (GPG_ERR_INV_ARG);
618
619 /* Use the temp key file as a keyring and export the selected
620 keys from it. */
621 fmt = "%s --yes --output %s --no-options --homedir %s --keyring %s --export ";
622 n = strlen (fmt) + strlen (p)+1 + strlen (tmpdir)+1 + strlen (tmpnam) + 1;
623 n += strlen (*new_keyfile)+1;
624 for (i=0; i < (int)nkeys; i++)
625 n += strlen (keys[i])+1+2;
626 cmd = (char*)xcalloc (1, n+1);
627 sprintf (cmd, fmt, p, *new_keyfile, tmpdir, tmpnam);
628 for (i=0; i < (int)nkeys; i++) {
629 strcat (cmd, keys[i]);
630 strcat (cmd, " " );
631 }
632
633 if (create_process (cmd, NULL, NULL, NULL))
634 err = gpgme_error (GPG_ERR_INTERNAL);
635
636 DeleteFile (tmpnam);
637 safe_free (cmd);
638 safe_free (p);
639 return err;
640 }
641
642
643 /* Return the validity of the user attribute, informerly known
644 as photo-ID. If no uat was found, return 0 for unknown. */
645 gpgme_error_t
646 get_uat_validity (const char *keyid, gpgme_validity_t *r_valid)
647 {
648 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
649 HANDLE out;
650 const char *fmt;
651 char *p, *cmd;
652 char *uat;
653
654 *r_valid = GPGME_VALIDITY_UNKNOWN;
655 p = read_gpg_program ();
656 if (!p)
657 return gpg_error (GPG_ERR_INV_ARG);
658
659 fmt = "%s --with-colons --fixed-list-mode --list-keys \"%s\"";
660 cmd = (char*)xcalloc (1, strlen (p) + strlen (keyid) + strlen (fmt) + 2);
661 sprintf (cmd, fmt, p, keyid);
662
663 out = create_tmpfile ("gpg_keys");
664 if (create_process (cmd, NULL, out, NULL))
665 err = gpg_error (GPG_ERR_INTERNAL);
666
667 safe_free (p);
668 safe_free (cmd);
669
670 p = map_tmpfile (out, NULL);
671 if ((uat = strstr (p, "uat:"))) {
672 switch (*(uat+4)) {
673 case 'm': *r_valid = GPGME_VALIDITY_MARGINAL; break;
674 case 'f':
675 case 'u': *r_valid = GPGME_VALIDITY_FULL; break;
676 default : *r_valid = GPGME_VALIDITY_UNDEFINED; break;
677 }
678 }
679
680 safe_free (p);
681 CloseHandle (out);
682 return err;
683 }
684
685
686 static gpgme_error_t
687 clip_store_data (char *tmp_outname, DWORD outlen)
688 {
689 gpgme_data_t in;
690 gpgme_error_t err;
691
692 get_temp_name (tmp_outname, outlen-1, NULL);
693 err = gpg_data_new_from_clipboard (&in, 0);
694 if (err)
695 return err;
696 err = gpg_data_release_and_set_file (in, tmp_outname);
697 return err;
698 }
699
700
701 /* Extract all recipients from the file @file.
702 Return value: 0 on success. */
703 static gpgme_error_t
704 file_extract_recipient (const char *file, gpgme_recipient_t *r_list)
705 {
706 PACKET *pkt;
707 PKT_pubkey_enc *enc;
708 gpg_iobuf_t inp = NULL;
709 armor_filter_context_t afx;
710 gpgme_recipient_t l;
711 int rc = 0, quit=0;
712
713 if (!file || !r_list) {
714 log_debug ("do_list_packets: !r_list || !file");
715 return gpgme_error (GPG_ERR_INV_ARG);
716 }
717
718 *r_list = NULL;
719 inp = gpg_iobuf_open (file);
720 if (!inp)
721 return gpgme_err_code_from_errno (errno);
722 gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
723 if (gpg_use_armor_filter (inp)) {
724 memset (&afx, 0, sizeof (afx));
725 gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);
726 }
727 pkt = (PACKET *)xcalloc(1, sizeof *pkt);
728 gpg_init_packet (pkt);
729 while (!quit && (rc = gpg_parse_packet (inp, pkt)) != -1) {
730 switch (pkt->pkttype) {
731 case PKT_PUBKEY_ENC:
732 enc = pkt->pkt.pubkey_enc;
733 if (!enc)
734 break;
735 l = (gpgme_recipient_t)xcalloc (1, sizeof *l);
736 l->keyid = (char*)xcalloc (1, 16+1);
737 _snprintf (l->keyid, 16, "%08lX%08lX",
738 enc->keyid[0], enc->keyid[1]);
739 l->pubkey_algo = (gpgme_pubkey_algo_t)enc->pubkey_algo;
740 l->status = 0;
741 l->next = (*r_list);
742 *r_list = l;
743 break;
744
745 case PKT_ENCRYPTED:
746 case PKT_ENCRYPTED_MDC:
747 case PKT_PLAINTEXT:
748 case PKT_COMPRESSED:
749 case PKT_PUBLIC_KEY:
750 case PKT_SECRET_KEY:
751 quit = 1;
752 break;
753
754 default:
755 break;
756 }
757 gpg_free_packet (pkt);
758 gpg_init_packet (pkt);
759 }
760 gpg_iobuf_close (inp);
761 safe_free (pkt);
762 return 0;
763 }
764
765
766 /* Either extract the list of recipients from the file @file or
767 if the string is NULL, try to extract them from the clipboard.
768 Return value: 0 on success. */
769 gpgme_error_t
770 gpg_get_recipients (const char *file, gpgme_recipient_t *r_list)
771 {
772 gpgme_error_t err;
773 char tmp[MAX_PATH+1];
774
775 if (!file) {
776 clip_store_data (tmp, DIM (tmp)-2);
777 err = file_extract_recipient (tmp, r_list);
778 DeleteFile (tmp);
779 }
780 else
781 err = file_extract_recipient (file, r_list);
782 return err;
783 }
784
785
786 /* Try to find a subpacket with the given id @subpktid
787 inside the key @key.
788 Return value: 0 on success. */
789 gpgme_error_t
790 gpg_find_key_subpacket (const char *key, int subpktid, char **value)
791 {
792 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
793 const char *fmt;
794 const char *spk;
795 char *p, *cmd;
796 HANDLE out;
797
798 *value = NULL;
799 p = read_gpg_program ();
800 fmt = "%s --with-colons --no-options --list-options show-sig-subpackets=%d --list-sigs %s";
801 cmd = (char*)xcalloc (1, strlen (fmt) + strlen (p) + strlen (key) + 32 + 1);
802 sprintf (cmd, fmt, p, subpktid, key);
803
804 out = create_tmpfile ("gpg_subpackets");
805 if (create_process (cmd, NULL, out, NULL))
806 err = gpg_error (GPG_ERR_INTERNAL);
807
808 safe_free (p);
809 safe_free (cmd);
810
811 p = map_tmpfile (out, NULL);
812 if (p && (spk=strstr (p, "spk"))) {
813 char *end = strstr (spk, "\n");
814
815 if (end) {
816 *value = (char*)xcalloc (1, (end-spk)+1);
817 memcpy (*value, spk, (end-spk)-1);
818 }
819 }
820
821 safe_free (p);
822 CloseHandle (out);
823 return err;
824 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26