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

Contents of /trunk/Src/wptGPGUtil.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 15830 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

1 /* wptGPGUtil.cpp - GPG helper functions
2 * Copyright (C) 2005 g10 Code GmbH
3 *
4 * This file is part of WinPT.
5 *
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
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
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,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 */
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <windows.h>
25 #include <sys/stat.h>
26
27 #include "gpgme.h"
28
29
30 #define NROFHEXDIGITS 2
31 /* Convert two hexadecimal digits from STR to the value they
32 represent. Returns -1 if one of the characters is not a
33 hexadecimal digit. */
34 static int
35 hextobyte (const unsigned char *str)
36 {
37 int val = 0;
38 int i;
39
40 for (i = 0; i < NROFHEXDIGITS; i++) {
41 if (*str >= '0' && *str <= '9')
42 val += *str - '0';
43 else if (*str >= 'A' && *str <= 'F')
44 val += 10 + *str - 'A';
45 else if (*str >= 'a' && *str <= 'f')
46 val += 10 + *str - 'a';
47 else
48 return -1;
49 if (i < NROFHEXDIGITS - 1)
50 val *= 16;
51 str++;
52 }
53 return val;
54 }
55
56 /* Decode the C formatted string @src and store the result in the
57 buffer @destp which is @len bytes long. If @len is zero, then a
58 large enough buffer is allocated with malloc and @destp is set to
59 the result. Currently, @len is only used to specify if allocation
60 is desired or not, the caller is expected to make sure that @destp
61 is large enough if @len is not zero. */
62 gpgme_error_t
63 gpg_decode_c_string (const char *src, char **destp, size_t len)
64 {
65 char *dest;
66
67 /* Set up the destination buffer. */
68 if (len) {
69 if (len < strlen (src) + 1)
70 return gpg_error (GPG_ERR_TOO_SHORT);
71 dest = *destp;
72 }
73 else {
74 /* The converted string will never be larger than the original string. */
75 dest = (char*)malloc (strlen (src) + 1);
76 if (!dest)
77 return gpg_error (GPG_ERR_ENOMEM);
78 *destp = dest;
79 }
80
81 /* Convert the string. */
82 while (*src) {
83 if (*src != '\\') {
84 *(dest++) = *(src++);
85 continue;
86 }
87
88 switch (src[1]) {
89 #define DECODE_ONE(match,result) \
90 case match: \
91 src += 2; \
92 *(dest++) = result; \
93 break;
94
95 DECODE_ONE ('\'', '\'');
96 DECODE_ONE ('\"', '\"');
97 DECODE_ONE ('\?', '\?');
98 DECODE_ONE ('\\', '\\');
99 DECODE_ONE ('a', '\a');
100 DECODE_ONE ('b', '\b');
101 DECODE_ONE ('f', '\f');
102 DECODE_ONE ('n', '\n');
103 DECODE_ONE ('r', '\r');
104 DECODE_ONE ('t', '\t');
105 DECODE_ONE ('v', '\v');
106
107 case 'x': {
108 int val = hextobyte ((unsigned char*)&src[2]);
109 if (val == -1) { /* Should not happen. */
110 *(dest++) = *(src++);
111 *(dest++) = *(src++);
112 if (*src)
113 *(dest++) = *(src++);
114 if (*src)
115 *(dest++) = *(src++);
116 }
117 else {
118 if (!val) {
119 /* A binary zero is not representable in a C string. */
120 *(dest++) = '\\';
121 *(dest++) = '0';
122 }
123 else
124 *((unsigned char *) dest++) = val;
125 src += 4;
126 }
127 }
128
129 default: /* Should not happen. */
130 {
131 *(dest++) = *(src++);
132 *(dest++) = *(src++);
133 }
134 }
135 }
136 *(dest++) = 0;
137 return 0;
138 }
139
140 /* Replace %foo% entries with its real values.
141 Return value: expanded path or NULL on error. */
142 static char *
143 expand_path (const char *path)
144 {
145 DWORD len;
146 char *p;
147
148 len = ExpandEnvironmentStrings (path, NULL, 0);
149 if (!len)
150 return NULL;
151 len += 1;
152 p = (char*)calloc (1, len+1);
153 if (!p)
154 abort ();
155 len = ExpandEnvironmentStrings (path, p, len);
156 if (!len) {
157 free (p);
158 return NULL;
159 }
160 return p;
161 }
162
163
164 /* Read a string from the W32 registry. The directory is given
165 in @dir and the name of the value in @name, */
166 static char *
167 read_w32_registry (HKEY root_key, const char *dir, const char *name)
168 {
169 HKEY key_handle;
170 DWORD n1, nbytes;
171 DWORD type;
172 char *result = NULL;
173
174 if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
175 return NULL; /* no need for a RegClose, so return direct */
176
177 nbytes = 1;
178 if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
179 goto leave;
180 result = (char*)calloc (1, (n1=nbytes+1));
181 if (!result)
182 abort ();
183 if (RegQueryValueEx (key_handle, name, 0, &type, (BYTE*)result, &n1)) {
184 free (result);
185 result = NULL;
186 goto leave;
187 }
188 if (type == REG_EXPAND_SZ && strchr (result, '%')) {
189 char *p = expand_path (result);
190 free (result);
191 result = p;
192 }
193
194 leave:
195 RegCloseKey (key_handle);
196 return result;
197 }
198
199
200 /* Create a temp file based on the name of @name.
201 Return value: handle to the file in case of success. */
202 static HANDLE
203 create_tmpfile (const char *name)
204 {
205 HANDLE out;
206 SECURITY_ATTRIBUTES sattr;
207 char tmp[300];
208
209 memset (&sattr, 0, sizeof sattr);
210 sattr.bInheritHandle = TRUE;
211 sattr.lpSecurityDescriptor = NULL;
212 sattr.nLength = sizeof sattr;
213
214 GetTempPath (sizeof (tmp)-1 - strlen (name)-1, tmp);
215 strcat (tmp, name);
216 out = CreateFile (tmp, GENERIC_READ|GENERIC_WRITE,
217 FILE_SHARE_WRITE, &sattr,
218 OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
219 return out;
220 }
221
222
223 /* Create a pipe with a readable remote end and
224 write the data from @dat to the local end.
225 Return value: read handle on success. */
226 static HANDLE
227 create_in_pipe (const char *dat)
228 {
229 HANDLE r, w;
230 SECURITY_ATTRIBUTES sec_attr;
231 DWORD n;
232
233 memset (&sec_attr, 0, sizeof sec_attr);
234 sec_attr.bInheritHandle = TRUE;
235 sec_attr.nLength = sizeof sec_attr;
236
237 if (!CreatePipe (&r, &w, &sec_attr, 4096))
238 return NULL;
239
240 WriteFile (w, dat, strlen (dat), &n, NULL);
241 CloseHandle (w);
242
243 return r;
244 }
245
246
247 /* Map the contents of the file handle @out to
248 a buffer and return it. */
249 static char*
250 map_tmpfile (HANDLE out)
251 {
252 DWORD n;
253 char *p;
254
255 FlushFileBuffers (out);
256 SetFilePointer (out, 0, NULL, FILE_BEGIN);
257 n = GetFileSize (out, NULL);
258 p = (char*)calloc (1, n+1);
259 if (!p)
260 abort ();
261 ReadFile (out, p, n, &n, NULL);
262 p[n] = 0;
263 return p;
264 }
265
266
267 /* Create a process from the command line in @cmd.
268 If @out is != NULL, the output of the process will
269 be redirected to @out. If @in is != NULL the input
270 will be read from @in.
271 Return value: 0 on success. */
272 static int
273 create_process (const char *cmd, HANDLE in, HANDLE out)
274 {
275 STARTUPINFO si;
276 PROCESS_INFORMATION pi;
277
278 memset (&si, 0, sizeof (si));
279 si.cb = sizeof si;
280 if (in || out)
281 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
282 if (out)
283 si.hStdOutput = out;
284 if (in)
285 si.hStdInput = in;
286 si.wShowWindow = SW_HIDE;
287 if (!CreateProcess (NULL, (char*)cmd, NULL, NULL, TRUE, 0,
288 NULL, NULL, &si, &pi))
289 return -1;
290 WaitForSingleObject (pi.hProcess, INFINITE);
291 CloseHandle (pi.hProcess);
292 return 0;
293 }
294
295
296 /* Export a GPG secret key given by @keyid into the file @outfile.
297 Return value: 0 on success. */
298 gpgme_error_t
299 gpg_export_seckey (const char *keyid, const char *outfile)
300 {
301 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
302 struct stat st;
303 char *p;
304 char *cmd;
305
306 p = read_w32_registry (HKEY_CURRENT_USER,
307 "Software\\GNU\\GnuPG", "gpgProgram");
308 if (!p)
309 return gpg_error (GPG_ERR_INV_ARG);
310 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)
311 + strlen (outfile) + 64 + 2);
312 if (!cmd)
313 abort ();
314 sprintf (cmd, "%s --yes --output \"%s\" --export-secret-key %s",
315 p, outfile, keyid);
316 if (create_process (cmd, NULL, NULL))
317 err = gpg_error (GPG_ERR_INTERNAL);
318
319 if (stat (outfile, &st) == -1 || st.st_size == 0)
320 err = gpg_error (GPG_ERR_NO_DATA);
321
322 free (p);
323 free (cmd);
324 return err;
325 }
326
327
328 /* If EXPORTFLAG is 1, export the ownertrust data to the
329 buffer DATA. Otherwise import the ownertrust data from DATA.
330 Return value: 0 on success. */
331 gpgme_error_t
332 gpg_manage_ownertrust (char **data, int exportflag)
333 {
334 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
335 HANDLE out = NULL, in = NULL;
336 char *p;
337 char *cmd;
338
339 p = read_w32_registry (HKEY_CURRENT_USER,
340 "Software\\GNU\\GnuPG", "gpgProgram");
341 if (!p)
342 return gpg_error (GPG_ERR_INV_ARG);
343
344 cmd = (char*)calloc (1, strlen (p) + 64 + 1);
345 if (!cmd)
346 abort ();
347 sprintf (cmd, "%s %s", p,
348 exportflag? "--export-ownertrust" : "--import-ownertrust");
349
350 if (exportflag)
351 out = create_tmpfile ("gpg_ot_out");
352 else {
353 DWORD nw;
354 in = create_tmpfile ("gpg_ot_in");
355 WriteFile (in, *data, strlen (*data), &nw, NULL);
356 FlushFileBuffers (in);
357 /* XXX: need a rewind? */
358 }
359 if (create_process (cmd, in, out))
360 err = gpg_error (GPG_ERR_INTERNAL);
361
362 free (p);
363 free (cmd);
364
365 if (in)
366 CloseHandle (in);
367 if (out) {
368 *data = map_tmpfile (out);
369 CloseHandle (out);
370 }
371 return err;
372 }
373
374
375 /* Call gpg --rebuild-keydb-caches to speed up signature listings. */
376 gpgme_error_t
377 gpg_rebuild_cache (char **r_inf)
378 {
379 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
380 HANDLE out = NULL;
381 char *p;
382 char *cmd;
383
384 p = read_w32_registry (HKEY_CURRENT_USER,
385 "Software\\GNU\\GnuPG", "gpgProgram");
386 if (!p)
387 return gpg_error (GPG_ERR_INV_ARG);
388 cmd = (char*)calloc (1, strlen (p) + 64);
389 if (!cmd)
390 abort ();
391 sprintf (cmd, "%s --logger-fd=1 --rebuild-keydb-caches", p);
392
393 if (r_inf)
394 out = create_tmpfile ("gpg_rebuild_cache");
395
396 if (create_process (cmd, NULL, out))
397 err = gpg_error (GPG_ERR_INTERNAL);
398
399 if (r_inf)
400 *r_inf = map_tmpfile (out);
401 if (out)
402 CloseHandle (out);
403 free (p);
404 free (cmd);
405 return 0;
406 }
407
408
409 /* Call gpg --version to retrieve the 'about' information. */
410 gpgme_error_t
411 gpg_get_version (char **r_inf)
412 {
413 gpgme_error_t err= gpg_error (GPG_ERR_NO_ERROR);
414 HANDLE out;
415 char *p, *cmd;
416
417 p =read_w32_registry (HKEY_CURRENT_USER,
418 "Software\\GNU\\GnuPG", "gpgProgram");
419 if (!p)
420 return gpg_error (GPG_ERR_INV_ARG);
421 cmd = (char*)calloc (1, strlen (p) + 32);
422 if (!cmd)
423 abort ();
424 sprintf (cmd, "%s --version", p);
425
426 out = create_tmpfile ("gpg_out");
427 if (create_process (cmd, NULL, out))
428 err = gpg_error (GPG_ERR_INTERNAL);
429
430 free (p);
431 free (cmd);
432
433 *r_inf = map_tmpfile (out);
434 CloseHandle (out);
435 return err;
436 }
437
438
439 /* Return the colon file output of the given file @fname in @r_out.
440 Return value: 0 on success. */
441 gpgme_error_t
442 gpg_import_key_list (const char *fname, char **r_out)
443 {
444 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
445 char *cmd, *p;
446 HANDLE out;
447
448 p = read_w32_registry (HKEY_CURRENT_USER,
449 "Software\\GNU\\GnuPG", "gpgProgram");
450 if (!p)
451 return gpg_error (GPG_ERR_INV_ARG);
452
453 cmd = (char*)calloc (1, strlen (p) + strlen (fname) + 2+2 + 64);
454 if (!cmd)
455 abort ();
456 sprintf (cmd, "%s --fixed-list-mode --with-colons \"%s\"", p, fname);
457
458 out = create_tmpfile ("gpg_keys");
459 if (create_process (cmd, NULL, out))
460 err = gpg_error (GPG_ERR_INTERNAL);
461
462 free (p);
463 free (cmd);
464
465 *r_out = map_tmpfile (out);
466 CloseHandle (out);
467 return err;
468 }
469
470 char*
471 generate_revoc_input (int code, const char *cmt, const char *pass)
472 {
473 const char *fmt;
474 char *p;
475 size_t n;
476
477 fmt = "Y\n" /* gen_revoke.okay */
478 "%d\n" /* ask_revocation_reason.code */
479 "%s\n" /* ask_revocation_reason.text */
480 "%s" /* text != NULL '\n' otherwise '' */
481 "Y\n" /* ask_revocation_reason.okay */
482 "%s\n"; /* passphrase.enter. */
483 n = strlen (fmt) + 32;
484 if (pass)
485 n += strlen (pass) + 1;
486 if (cmt)
487 n += strlen (cmt) + 1;
488 p = (char*)calloc (1, n+1);
489 if (!p)
490 abort ();
491 sprintf (p, fmt, code, cmt? cmt : "", cmt? "\n" : "", pass? pass : "");
492 return p;
493 }
494
495
496 /* Generate a revocation certificate for the key with the keyid @keyid.
497 @inp_data contains all needed data to answer the questions of the
498 command handler. Each separate with a '\n'.
499 @r_revcert contains the revocation cert on success.
500 Return value: 0 on success. */
501 gpgme_error_t
502 gpg_revoke_key (const char *inp_data, const char *keyid, char **r_revcert)
503 {
504 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
505 char *rcrt;
506 char *cmd, *p;
507 HANDLE in, out;
508
509 p = read_w32_registry (HKEY_CURRENT_USER,
510 "Software\\GNU\\GnuPG", "gpgProgram");
511 if (!p)
512 return gpg_error (GPG_ERR_INV_ARG);
513
514 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
515 if (!cmd)
516 abort ();
517 sprintf (cmd, "%s --pgp7 --command-fd=0 --status-fd=2 --gen-revoke %s",
518 p, keyid);
519
520 in = create_in_pipe (inp_data);
521 out = create_tmpfile ("gpg_revcert");
522 if (create_process (cmd, in, out)) {
523 *r_revcert = NULL;
524 err = gpg_error (GPG_ERR_INTERNAL);
525 }
526 else {
527 rcrt = map_tmpfile (out);
528 *r_revcert = rcrt;
529 }
530
531 free (p);
532 free (cmd);
533
534 CloseHandle (in);
535 CloseHandle (out);
536 return err;
537 }
538
539
540 /* Return the validity of the user attribute, informerly known
541 as photo-ID. If no uat was found, return 0 for unknown. */
542 gpgme_error_t
543 get_uat_validity (const char *keyid, gpgme_validity_t *r_valid)
544 {
545 gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
546 HANDLE out;
547 char *p, *cmd;
548 char *uat;
549
550 *r_valid = GPGME_VALIDITY_UNKNOWN;
551 p = read_w32_registry (HKEY_CURRENT_USER,
552 "Software\\GNU\\GnuPG", "gpgProgram");
553 if (!p)
554 return gpg_error (GPG_ERR_INV_ARG);
555
556 cmd = (char*)calloc (1, strlen (p) + strlen (keyid)+1 + 128);
557 if (!cmd)
558 abort ();
559 sprintf (cmd, "%s --with-colons --fixed-list-mode --list-keys \"%s\"",
560 p, keyid);
561
562 out = create_tmpfile ("gpg_keys");
563 if (create_process (cmd, NULL, out))
564 err = gpg_error (GPG_ERR_INTERNAL);
565
566 free (p);
567 free (cmd);
568
569 p = map_tmpfile (out);
570 if ((uat = strstr (p, "uat:"))) {
571 switch (*(uat+4)) {
572 case 'm': *r_valid = GPGME_VALIDITY_MARGINAL; break;
573 case 'f':
574 case 'u': *r_valid = GPGME_VALIDITY_FULL; break;
575 default: *r_valid = GPGME_VALIDITY_UNDEFINED; break;
576 }
577 }
578
579 free (p);
580 CloseHandle (out);
581 return err;
582 }
583
584
585 #if 0
586 /* Extract all recipients from the file @file.
587 Return value: 0 on success. */
588 static int
589 do_get_recipients (const char *file, gpgme_recipient_t *r_list)
590 {
591 gpgme_recipient_t l;
592 PACKET *pkt;
593 gpg_iobuf_t inp = NULL;
594 armor_filter_context_t afx;
595 int rc = 0, quit=0;
596
597 if (!file || !r_list) {
598 log_debug ("do_list_packets: !r_list || !file");
599 return -1;
600 }
601
602 *r_list=NULL;
603 inp = gpg_iobuf_open (file);
604 if (!inp)
605 return WPTERR_FILE_OPEN;
606 gpg_iobuf_ioctl (inp, 3, 1, NULL); /* disable cache */
607 if (gpg_use_armor_filter (inp)) {
608 memset (&afx, 0, sizeof (afx));
609 gpg_iobuf_push_filter (inp, gpg_armor_filter, &afx);
610 }
611 pkt = (PACKET *)calloc(1, sizeof *pkt);
612 gpg_init_packet (pkt);
613 while (!quit && (rc = gpg_parse_packet (inp, pkt)) != -1) {
614 switch (pkt->pkttype) {
615 case PKT_PUBKEY_ENC:
616 {PKT_pubkey_enc *enc = pkt->pkt.pubkey_enc;
617 if (!enc)
618 break;
619 l = calloc (1, sizeof *l);
620 l->keyid = calloc (1, 16+1);
621 _snprintf (l->keyid, 16, "%08lX%08lX", enc->keyid[0], enc->keyid[1]);
622 l->pubkey_algo = enc->pubkey_algo;
623 l->status = 0;
624 l->next = (*r_list);
625 *r_list = l;
626 break;}
627
628 case PKT_ENCRYPTED:
629 case PKT_ENCRYPTED_MDC:
630 case PKT_COMPRESSED:
631 case PKT_PUBLIC_KEY:
632 case PKT_SECRET_KEY:
633 quit = 1;
634 break;
635 }
636 gpg_free_packet (pkt);
637 gpg_init_packet (pkt);
638 }
639 gpg_iobuf_close (inp);
640 safe_free (pkt);
641 return 0;
642 }
643 #endif

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26