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

Contents of /trunk/Src/wptImportList.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 328 - (show annotations)
Fri Sep 25 16:07:38 2009 UTC (15 years, 5 months ago) by twoaday
File size: 10819 byte(s)


1 /* wptImportList.cpp - Key import list
2 * Copyright (C) 2001-2007 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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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 GNU
15 * General Public License for more details.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #include <windows.h>
22 #include <sys/types.h>
23 #include <ctype.h>
24
25 #include "resource.h"
26 #include "wptTypes.h"
27 #include "wptGPG.h"
28 #include "wptCommonCtl.h"
29 #include "wptKeylist.h"
30 #include "wptNLS.h"
31 #include "wptErrors.h"
32 #include "wptUTF8.h"
33 #include "wptW32API.h"
34 #include "wptRegistry.h"
35 #include "wptVersion.h"
36 #include "StringBuffer.h"
37 #include "openpgp.h"
38
39
40 /* Symbolic column ids */
41 enum impl_col_t {
42 IMPL_COL_UID = 0,
43 IMPL_COL_SIZE = 1,
44 IMPL_COL_KEYID = 2,
45 IMPL_COL_CREATION = 3,
46 IMPL_COL_KTYPE = 4
47 };
48
49 /* context to hold information about a key. */
50 struct import_key_s {
51 /* primary userid */
52 char *uid;
53
54 /* 1 = secret key is available. */
55 int secret;
56
57 /* flags */
58 unsigned int disabled:1;
59 unsigned int expired:1;
60 unsigned int revoked:1;
61
62 /* primary key attributes */
63 char keyid[16+1];
64 gpgme_pubkey_algo_t pubkey_algo;
65 size_t length;
66 time_t timestamp;
67
68 /* secondary key attributes */
69 char subkey_keyid[16+1];
70 gpgme_pubkey_algo_t subkey_algo;
71 size_t subkey_length;
72 time_t subkey_timestamp;
73 };
74 typedef struct import_key_s *import_key_t;
75
76
77 /* Release the key in @c. */
78 static void
79 import_key_release (import_key_t c)
80 {
81 if (!c)
82 return;
83 safe_free (c->uid);
84 safe_free (c);
85 }
86
87
88 /* Decode the %-encoded userid in @pend and store it as the first
89 userid in the key @c. */
90 static void
91 decode_userid (char *pend, import_key_t c)
92 {
93 char *uid;
94
95 uid = (char*)calloc (1, strlen (pend) + 1);
96 if (!uid)
97 BUG (NULL);
98 gpg_decode_c_string (pend, &uid, strlen (pend) + 1);
99 uid[strlen (uid) -3] = '\0';
100 c->uid = utf8_to_native (uid);
101 safe_free (uid);
102 }
103
104
105 /* Parse the output of 'gpg --with-colons <data'. */
106 static void
107 parse_colon_key (char *buf, import_key_t c)
108 {
109 const char * s;
110 char *p, *pend;
111 int field = 0, rectype = 0;
112 enum key_t {
113 KEY_none = 0,
114 KEY_primary = 1,
115 KEY_secondary = 2,
116 };
117
118 if (!buf)
119 return; /* EOF */
120
121 if( !strncmp (buf, "pub", 3) || !strncmp (buf, "sec", 3)) {
122 rectype = KEY_primary;
123 if (*buf == 's')
124 c->secret = 1;
125 }
126 else if (!strncmp (buf, "sub", 3) || !strncmp (buf, "ssb", 3))
127 rectype = KEY_secondary;
128 else if (!strncmp (buf, "uid", 3)) {
129 if (!c->uid) {
130 const char *uid = buf+3;
131 while (uid && *uid == ':')
132 uid++;
133 decode_userid ((char *)uid, c);
134 }
135 return;
136 }
137 else
138 return;
139
140 for (p = buf; p; p = pend) {
141 field++;
142 pend = strchr (p, ':');
143 if (pend)
144 *pend++ = 0;
145
146 switch (field) {
147 case 1:
148 if (rectype != KEY_primary)
149 break;
150 for (s = pend; *s && !isdigit (*s); s++) {
151 switch (*s) {
152 case 'd': c->disabled = 1;break;
153 case 'e': c->expired = 1; break;
154 case 'r': c->revoked = 1; break;
155 }
156 }
157 break;
158
159 case 2:
160 if (rectype == KEY_primary)
161 c->length = atoi (pend);
162 else if (rectype == KEY_secondary)
163 c->subkey_length = atoi (pend);
164 break;
165
166 case 3:
167 if (rectype == KEY_primary)
168 c->pubkey_algo = (gpgme_pubkey_algo_t)atoi (pend);
169 else if (rectype == KEY_secondary)
170 c->subkey_algo = (gpgme_pubkey_algo_t)atoi (pend);
171 break;
172
173 case 4:
174 if (rectype == KEY_primary) {
175 strncpy (c->keyid, pend, 16);
176 c->keyid[16] = 0;
177 }
178 else if (rectype == KEY_secondary) {
179 strncpy (c->subkey_keyid, pend, 16);
180 c->subkey_keyid[16] = 0;
181 }
182 break;
183
184 case 5:
185 if (rectype == KEY_primary)
186 c->timestamp = strtoul (pend, NULL, 10);
187 else if (rectype == KEY_secondary)
188 c->subkey_timestamp = strtoul (pend, NULL, 10);
189 break;
190
191 case 9:
192 if (rectype == KEY_primary && !c->uid && strlen (pend) > 2) {
193 if (!strchr (pend, '[') && !strchr (pend, ']'))
194 decode_userid (pend, c);
195 }
196 break;
197 }
198 }
199 }
200
201 /* Read the next key from data stream @out. The result is stored in @r_key.
202 Return value: 0 on success. */
203 gpgme_error_t
204 gpg_import_next_key (gpgme_data_t out, char **pending_line,
205 import_key_t *r_key)
206 {
207 import_key_t key;
208 int in_cert, got_block = 0;
209 char buf[384];
210 int n;
211
212 if (!r_key)
213 return gpg_error (GPG_ERR_INV_ARG);
214
215 key = (import_key_t) calloc (1, sizeof *key);
216 if (!key)
217 BUG (0);
218
219 if (*pending_line) {
220 parse_colon_key (*pending_line, key);
221 safe_free (*pending_line);
222 *pending_line = NULL;
223 in_cert = 1;
224 }
225 else
226 in_cert = 0;
227
228 while ((n=gpg_data_readline (out, buf, DIM (buf)-1)) > 0) {
229 if (!strncmp (buf, "pub", 3) || !strncmp (buf, "sec", 3)) {
230 if (in_cert) {
231 *pending_line = strdup (buf);
232 goto ready;
233 }
234 in_cert = 1;
235 got_block = 1;
236 parse_colon_key (buf, key);
237 }
238 else if (in_cert) {
239 parse_colon_key (buf, key);
240 got_block = 1;
241 }
242 }
243 ready:
244 *r_key = key;
245 if (got_block && n == 0)
246 return 0;
247 return n == 0? gpg_error (GPG_ERR_EOF) : 0;
248 }
249
250
251 /* Return a humand readable key description of @key. */
252 static char*
253 key_description (import_key_t key)
254 {
255 gpgme_pubkey_algo_t subalgo = (gpgme_pubkey_algo_t)0;
256 StringBuffer p;
257 const char *state;
258 char *desc;
259
260 if (key->subkey_algo)
261 subalgo = key->subkey_algo;
262 if (key->revoked)
263 state = _("Revoked");
264 else if (key->expired)
265 state = _("Expired");
266 else
267 state = " ";
268 p = state;
269 p = p + " " + get_key_pubalgo (key->pubkey_algo) + " ";
270 if (subalgo != 0)
271 p = p + "/" + get_key_pubalgo (subalgo) + " ";
272 p = p + (key->secret? _("secret key") : _("public key")) ;
273 desc = p.getBufferCopy ();
274 return desc;
275 }
276
277
278 /* Add the key @key to the list view control @lv at position @pos. */
279 static int
280 implist_add_key (listview_ctrl_t lv, int pos, import_key_t key)
281 {
282 char buf[64], *desc;
283 const char *t;
284 u32 tt, tt2=0;
285
286 if (listview_add_item_image (lv, " ", key->secret? 1 : 0))
287 return WPTERR_GENERAL;
288 t = key->uid;
289 if (!t || strlen (t) < 5)
290 t = _("Invalid user ID");
291 listview_add_sub_item (lv, pos, IMPL_COL_UID, t);
292
293 tt = key->length;
294 if (key->subkey_length > 0)
295 tt2 = key->subkey_length;
296 if (tt > 0 && tt2 > 0)
297 _snprintf (buf, DIM (buf) - 1, "%d/%d", tt, tt2);
298 else
299 _snprintf (buf, DIM (buf)-1, "%d", tt);
300 listview_add_sub_item (lv, pos, IMPL_COL_SIZE, buf);
301
302 t = key->keyid;
303 if (!t || strlen (t) < 8)
304 t = "????????????????";
305 _snprintf (buf, DIM (buf) -1, "0x%s", t+8);
306 listview_add_sub_item (lv, pos, IMPL_COL_KEYID, buf);
307
308 t = get_key_created (key->timestamp);
309 if (!t)
310 t = "????" "-??" "-??";
311 listview_add_sub_item (lv, pos, IMPL_COL_CREATION, (char *)t);
312
313 desc = key_description (key);
314 listview_add_sub_item (lv, pos, IMPL_COL_KTYPE, desc);
315 free_if_alloc (desc);
316
317 return 0;
318 }
319
320
321 /* Create a list view for list keys. */
322 void
323 implist_build (listview_ctrl_t *lv, HWND ctrl)
324 {
325 HICON ico[2];
326 struct listview_ctrl_s *c;
327 struct listview_column_s implist[] = {
328 {0, 190, (char *)_("User ID")},
329 {1, 66, (char *)_("Size")},
330 {2, 80, (char *)_("Key ID")},
331 {3, 72, (char *)_("Creation")},
332 {4, 132, (char *)_("Type")},
333 {0, 0, NULL}
334 };
335 int i;
336
337 listview_new (&c, ctrl);
338 for (i = 0; implist[i].fieldname != NULL; i++)
339 listview_add_column (c, &implist[i]);
340 listview_set_ext_style (c);
341 listview_set_grid_style (c);
342 ico[0] = LoadIcon (glob_hinst, (LPCTSTR)IDI_PUBKEY);
343 ico[1] = LoadIcon (glob_hinst, (LPCTSTR)IDI_KEYPAIR);
344 listview_set_image_list (c, 22, 14, ico, 2);
345 *lv = c;
346 }
347
348
349 /* Check to verify that the file can be access and
350 set @r_revcert to '1' in case of an revocation cert. */
351 static int
352 check_import_data (const char *fname, int *r_revcert)
353 {
354 FILE *fp;
355 char buf[512];
356 int n;
357
358 fp = fopen (fname, "rb");
359 if (!fp)
360 return -1;
361
362 *r_revcert = 0;
363 n = fread (buf, 1, DIM (buf)-1, fp);
364 fclose (fp);
365 if (!n)
366 return 0;
367 buf[n] = 0;
368 if (strstr (buf, "A revocation certificate should follow"))
369 *r_revcert = 1;
370 return 0;
371 }
372
373
374 /* Load the list view @lv with the contents of the file @file.
375 @r_revcerts contains the number of revocation certs and
376 @r_seckeys the number of imported secret keys. */
377 int
378 implist_load (listview_ctrl_t lv, const char *file,
379 int *r_revcerts, int *r_seckeys)
380 {
381 gpgme_data_t list;
382 gpgme_error_t err;
383 import_key_t key;
384 char *pending_line = NULL;
385 char fname[MAX_PATH+32+1], *out;
386 int rc = 0, is_tmp=0;
387
388 if (!file) {
389 err = gpg_data_new_from_clipboard (&list, 0);
390 if (err) {
391 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
392 return WPTERR_CLIP_OPEN;
393 }
394 get_temp_name (fname, DIM (fname)-1, "tmp_in_gpg_keys");
395 err = gpg_data_release_and_set_file (list, fname);
396 if (err) {
397 gpgme_data_release (list);
398 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
399 return WPTERR_FILE_CREAT;
400 }
401 file = fname;
402 is_tmp = 1;
403 }
404
405 if (check_import_data (file, r_revcerts)) {
406 msg_box (NULL, _("It is possible that the ASCII-Armor is damaged\n"
407 "and thus causing a CRC error."),
408 _("Import"), MB_ERR);
409 if (is_tmp)
410 DeleteFile (file);
411 return WPTERR_GENERAL;
412 }
413
414 err = gpg_import_key_list (file, &out);
415 if (err) {
416 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
417 if (is_tmp)
418 DeleteFile (file);
419 return WPTERR_GENERAL;
420 }
421
422 err = gpgme_data_new_from_mem (&list, out, strlen (out), 1);
423 safe_free (out);
424 if (err) {
425 msg_box (NULL, gpgme_strerror (err), _("Import"), MB_ERR);
426 if (is_tmp)
427 DeleteFile (file);
428 return WPTERR_GENERAL;
429 }
430
431 if (r_seckeys)
432 *r_seckeys = 0;
433 while (!rc) {
434 /* XXX if the key has a direct key signature, the user-id field
435 in the --with-colons mode is empty! */
436 rc = gpg_import_next_key (list, &pending_line, &key);
437 if (!rc)
438 rc = implist_add_key (lv, 0, key);
439 if (key->secret)
440 (*r_seckeys)++;
441 import_key_release (key);
442 }
443
444 gpgme_data_release (list);
445 if (is_tmp)
446 DeleteFile (file);
447 return rc;
448 }
449
450
451 /* Release the list view @lv. */
452 void
453 implist_delete (listview_ctrl_t lv)
454 {
455 if (lv) {
456 listview_release (lv);
457 }
458 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26