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

Contents of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 77 - (show annotations)
Mon Nov 14 15:01:01 2005 UTC (19 years, 3 months ago) by twoaday
File size: 15255 byte(s)
2005-11-12  Timo Schulz  <ts@g10code.com>
 
        Fix more GCC warnings.
 
2005-11-10  Timo Schulz  <ts@g10code.com>
 
        * wptClipSignDlg.cpp (one_key_proc): Use
        release_gpg_passphrase_cb() to free the context.
        * wptListView.cpp (listview_deselect_all): New.
        * wptMAPI.cpp (mapi_send_pubkey): Works again.
        * wptFileManagerDlg.cpp (file_manager_dlg_proc): Support encrypt &
        zip.
        * wptPassphraseCB.cpp (passphrase_callback_proc): Fix passphrase
        caching for signing operations.
        * wptKeyManager.cpp (km_send_to_mail_recipient): Works again.
        * wptFileManager.cpp (fm_send_file): Likewise.
        (fm_encrypt_into_zip): New.
         

1 /* wptCardEdit.cpp - OpenPGP editing interface
2 * Copyright (C) 2005 Timo Schulz
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
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <windows.h>
26 #include <time.h>
27
28 #include "gpgme.h"
29 #include "wptCard.h"
30 #include "wptCardEdit.h"
31 #include "wptGPG.h"
32 #include "wptErrors.h"
33
34 /* Create a new Smartcard context. */
35 static gpgme_error_t
36 gpg_card_new (gpg_card_t *ret_card)
37 {
38 gpg_card_t c;
39
40 if (!ret_card)
41 return gpg_error (GPG_ERR_INV_ARG);
42 *ret_card = NULL;
43 c = (gpg_card_t)calloc (1, sizeof *c);
44 if (!c)
45 return gpg_error (GPG_ERR_ENOMEM);
46 *ret_card = c;
47 return 0;
48 }
49
50
51 /* Release an existing Smartcard context. @card. */
52 void
53 gpg_card_release (gpg_card_t card)
54 {
55 int i;
56
57 if (!card)
58 return;
59 if (card->aid)
60 free (card->aid);
61 if (card->version)
62 free (card->version);
63 if (card->lang)
64 free (card->lang);
65 if (card->login)
66 free (card->login);
67 for (i=0; i < 3; i++) {
68 if (card->fpr[i])
69 free (card->fpr[i]);
70 if (card->ca_fpr[i])
71 free (card->ca_fpr[i]);
72 if (card->fpr_created_str[i])
73 free (card->fpr_created_str[i]);
74 }
75 if (card->surname)
76 free (card->surname);
77 if (card->givenname)
78 free (card->givenname);
79 if (card->serial)
80 free (card->serial);
81 if (card->vendor)
82 free (card->vendor);
83 if (card->url)
84 free (card->url);
85 if (card->card_type)
86 free (card->card_type);
87 free (card);
88
89 }
90
91
92 /* Parse the timestamp @long_ts and return a string
93 representation of it (format: YYYY-DD-MM HH:MM:SS). */
94 static char*
95 get_str_timestamp (long long_ts)
96 {
97 struct tm *tm;
98 char *p, *fmt;
99
100 tm = localtime (&long_ts);
101 fmt = "%04d-%02d-%02d %02d:%02d:%02d";
102 p = (char*)calloc (1, strlen (fmt)+32);
103 if (!p)
104 abort ();
105 sprintf (p, fmt,
106 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
107 tm->tm_hour, tm->tm_min, tm->tm_sec);
108 return p;
109 }
110
111
112 /* Colon handler for parsing the GPG card colon output. */
113 static gpgme_error_t
114 statuscard_colon_handler (gpg_card_t card, char * line)
115 {
116 enum rectype_t {
117 CARD_None = 0,
118 CARD_AID,
119 CARD_Version,
120 CARD_Vendor,
121 CARD_Serial,
122 CARD_Name,
123 CARD_Lang,
124 CARD_Sex,
125 CARD_Url,
126 CARD_Login,
127 CARD_MaxPinLen,
128 CARD_SigCount,
129 CARD_CAFpr,
130 CARD_Fpr,
131 CARD_FprTime
132 };
133 enum rectype_t rectype = (rectype_t)0;
134 char *p, *pend;
135 int field = 0;
136
137 if (!line)
138 return gpg_error (GPG_ERR_EOF);
139
140 for (p = line; p; p = pend) {
141 field++;
142 pend = strchr (p, ':');
143 if (pend)
144 *pend++ = 0;
145
146 if (field == 1) {
147 if (!strcmp (p, "AID"))
148 rectype = CARD_AID;
149 else if( !strcmp( p, "version" ) )
150 rectype = CARD_Version;
151 else if( !strcmp( p, "vendor" ) )
152 rectype = CARD_Vendor;
153 else if( !strcmp( p, "serial" ) )
154 rectype = CARD_Serial;
155 else if( !strcmp( p, "name" ) )
156 rectype = CARD_Name;
157 else if( !strcmp( p, "lang" ) )
158 rectype = CARD_Lang;
159 else if( !strcmp( p, "sex" ) )
160 rectype = CARD_Sex;
161 else if( !strcmp( p, "url" ) )
162 rectype = CARD_Url;
163 else if( !strcmp( p, "login" ) )
164 rectype = CARD_Login;
165 else if( !strcmp( p, "maxpinlen" ) )
166 rectype = CARD_MaxPinLen;
167 else if( !strcmp( p, "sigcount" ) )
168 rectype = CARD_SigCount;
169 else if (!strcmp (p, "cafpr"))
170 rectype = CARD_CAFpr;
171 else if (!strcmp (p, "fpr"))
172 rectype = CARD_Fpr;
173 else if (!strcmp (p, "fprtime"))
174 rectype = CARD_FprTime;
175 else
176 rectype = CARD_None;
177 }
178 switch (rectype) {
179 case CARD_AID:
180 if (field == 2) {
181 card->aid = strdup (p);
182 if (!card->aid)
183 return gpg_error (GPG_ERR_ENOMEM);
184 }
185 else if (field == 3) {
186 card->card_type = strdup (p);
187 if (!card->card_type)
188 return gpg_error (GPG_ERR_ENOMEM);
189 }
190 break;
191
192 case CARD_Version:
193 if (field == 2) {
194 card->version = strdup (p);
195 if (!card->version)
196 return gpg_error (GPG_ERR_ENOMEM);
197 }
198 break;
199
200 case CARD_Vendor:
201 if (field == 3) {
202 card->vendor = strdup (p);
203 if (!card->vendor)
204 return gpg_error (GPG_ERR_ENOMEM);
205 }
206 break;
207
208 case CARD_Serial:
209 if (field == 2) {
210 card->serial = strdup (p);
211 if (!card->serial)
212 return gpg_error (GPG_ERR_ENOMEM);
213 }
214 break;
215 case CARD_Name:
216 if (field == 2) {
217 card->givenname = strdup (p);
218 if (!card->givenname)
219 return gpg_error (GPG_ERR_ENOMEM);
220 }
221 else if (field == 3) {
222 card->surname = strdup (p);
223 if (!card->surname)
224 return gpg_error (GPG_ERR_ENOMEM);
225 }
226 break;
227 case CARD_Lang:
228 if( field == 2 ) {
229 card->lang = strdup (p);
230 if (!card->lang)
231 return gpg_error (GPG_ERR_ENOMEM);
232 }
233 break;
234 case CARD_Sex:
235 if( field == 2 )
236 card->sex = *p;
237 break;
238
239 case CARD_Url:
240 if( field == 2 ) {
241 if (card->url)
242 free (card->url);
243 card->url = (char*)calloc (1, strlen (p) + 1);
244 if( !card->url ) {
245 return gpg_error (GPG_ERR_ENOMEM);
246 }
247 gpg_decode_c_string (p, &card->url, strlen (p) + 1);
248 if (!card->url)
249 return gpg_error (GPG_ERR_ENOMEM);
250 }
251 break;
252
253 case CARD_Login:
254 if (field == 2) {
255 card->login = strdup (p);
256 if (!card->login)
257 return gpg_error (GPG_ERR_ENOMEM);
258 }
259 break;
260
261 case CARD_MaxPinLen:
262 break;
263
264 case CARD_SigCount:
265 if (field == 2)
266 card->sig_count = atol (p);
267 break;
268
269 case CARD_CAFpr:
270 if (!p)
271 break;
272 if (field > 4 || field == 1)
273 break;
274 card->ca_fpr[field-2] = strdup (p);
275 if (!card->ca_fpr[field-2])
276 return gpg_error (GPG_ERR_ENOMEM);
277 break;
278
279 case CARD_Fpr:
280 if (field > 4 || field == 1) /* max 3 fprs */
281 break;
282 card->fpr[field-2] = strdup (p);
283 if (!card->fpr[field-2])
284 return gpg_error (GPG_ERR_ENOMEM);
285 break;
286
287 case CARD_FprTime:
288 if (field > 4 || field == 1)
289 break;
290 card->fpr_created[field-2] = strtoul (p, NULL, 10);
291 card->fpr_created_str[field-2] = get_str_timestamp (strtoul (p, NULL, 10));
292 if (!card->fpr_created_str[field-2])
293 return gpg_error (GPG_ERR_ENOMEM);
294 break;
295
296 default:
297 break;
298 }
299 }
300 return 0;
301 }
302
303
304 /* Dummy handler to get the colon data and then quit. */
305 static gpgme_error_t
306 list_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
307 {
308 static int wait_card=0;
309 GpgCardEdit *ce = (GpgCardEdit *)opaque;
310 const char *s="";
311 DWORD n;
312
313
314 if (code == GPGME_STATUS_CARDCTRL) {
315 if (!strcmp (key, "5"))
316 ce->setResult (GPG_CARDRES_NOCARD);
317 else if (!strcmp (key, "1"))
318 wait_card = 1;
319 }
320 if (wait_card && !strcmp (key, "cardctrl.insert_card.okay")) {
321 n = MessageBox (NULL, _("Please insert the card and click OK or Cancel to abort."),
322 _("GPG Card Status"), MB_ICONQUESTION|MB_OKCANCEL);
323 if (n == IDCANCEL) {
324 ce->setResult (GPG_CARDRES_CANCEL);
325 WriteFile ((HANDLE)fd, "c\n", 2, &n, NULL);
326 wait_card = 0;
327 }
328 }
329 if (!strcmp (key, "cardedit.prompt")) {
330 s = "quit\n";
331 if (!WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL))
332 log_debug ("list_handler: WriteFile() failed ec=%d\r\n",
333 (int)GetLastError ());
334 wait_card = 0;
335 }
336 return 0;
337 }
338
339
340 /* Construct an empty object. */
341 GpgCardEdit::GpgCardEdit (void)
342 {
343 pin = NULL;
344 pin_new = NULL;
345 admin_pin = NULL;
346
347 keygen.comment = NULL;
348 keygen.email = NULL;
349 keygen.name = NULL;
350 keygen.expdate = NULL;
351 keygen.key_fpr = NULL;
352
353 type = 0;
354 cnt = 0;
355 cancel = 0;
356 result = 0;
357
358 gpgme_new (&ctx); /* XXX: check return code */
359 }
360
361 /* Release the object. */
362 GpgCardEdit::~GpgCardEdit (void)
363 {
364 if (keygen.name)
365 free (keygen.name);
366 if (keygen.comment)
367 free (keygen.comment);
368 if (keygen.email)
369 free (keygen.email);
370 if (keygen.expdate)
371 free (keygen.expdate);
372 if (keygen.key_fpr)
373 free (keygen.key_fpr);
374 gpgme_release (ctx);
375 }
376
377
378 /* Set the user PIN for the object to @pin. */
379 void
380 GpgCardEdit::setPIN (const char *_pin)
381 {
382 this->pin = _pin;
383 }
384
385 /* Set the admin PIN for the object to @admin_pin. */
386 void
387 GpgCardEdit::setAdminPIN (const char *_admin_pin)
388 {
389 this->admin_pin = _admin_pin;
390 }
391
392
393 /* Set the new user PIN for the object to @new_pin. */
394 void
395 GpgCardEdit::setNewPIN (const char *_new_pin)
396 {
397 this->pin_new = _new_pin;
398 }
399
400
401 /* Set the passphrase needed when generating a key to @pass. */
402 void
403 GpgCardEdit::setKeygenPassphrase (const char *_pass)
404 {
405 this->keygen.pass = _pass;
406 }
407
408
409 /* Set the callback to @cb and the hook value to @cb_value. */
410 void
411 GpgCardEdit::setCallback (const char* (*_cb)(int code, void *opaque),
412 void *_cb_value)
413 {
414 this->cb_value = _cb_value;
415 this->card_cb = _cb;
416 }
417
418
419 /* Read the information from the inserted card and return
420 it in form of a card context @r_card.
421 Return value: 0 on success. */
422 gpgme_error_t
423 GpgCardEdit::getCardStatus (gpg_card_t *r_card)
424 {
425 gpgme_data_t out = NULL;
426 gpgme_error_t err;
427 gpg_card_t card=NULL;
428 char buf[200];
429
430 if (!r_card)
431 return gpg_error (GPG_ERR_INV_ARG);
432
433 err = gpg_card_new (&card);
434 if (err)
435 return err;
436
437 err = gpgme_data_new (&out);
438 if (err) {
439 gpg_card_release (card);
440 return err;
441 }
442
443 err = gpgme_op_card_edit (ctx, NULL, list_handler, this, out);
444 gpgme_data_rewind (out);
445 if (err) {
446 gpgme_data_release (out);
447 gpg_card_release (card);
448 return err;
449 }
450 if (getResult () & GPG_CARDRES_NOCARD ||
451 getResult () & GPG_CARDRES_CANCEL) {
452 gpg_card_release (card);
453 gpgme_data_release (out);
454 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
455 }
456
457 *r_card = card;
458 while (gpg_data_readline (out, buf, sizeof (buf)-2) > 0) {
459 err = statuscard_colon_handler (card, buf);
460 if (err)
461 break;
462 }
463 gpgme_data_release (out);
464
465 return err;
466 }
467
468
469 /* Generate a key on a smart card with the following params:
470 @flags: user specific params.
471 @name: name of the key holder.
472 @email: email of the key holder.
473 @comment: optional comment.
474 @valid: how long is the key valid in days.
475 Return value: 0 on success. */
476 gpgme_error_t
477 GpgCardEdit::genKey (int flags, const char *name,
478 const char *email, const char *comment, long valid,
479 char **r_key_fpr)
480 {
481 gpgme_error_t err;
482
483 if (!name || !email)
484 return gpg_error (GPG_ERR_INV_ARG);
485 if (!this->keygen.pass)
486 return gpg_error (GPG_ERR_INV_OBJ);
487
488 type = GPG_EDITCARD_GENKEY;
489 this->keygen.flags = flags;
490
491 if (this->keygen.name)
492 free (this->keygen.name);
493 this->keygen.name = strdup (name);
494 if (this->keygen.email)
495 free (this->keygen.email);
496 this->keygen.email = strdup (email);
497 if (this->keygen.comment)
498 free (this->keygen.comment);
499 this->keygen.comment = comment? strdup (comment) : strdup ("");
500 if (this->keygen.expdate)
501 free (this->keygen.expdate);
502 this->keygen.expdate = (char*)calloc (1, 16);
503 if (this->keygen.expdate)
504 sprintf (this->keygen.expdate, "%lu", valid);
505
506 if (!this->keygen.name || !this->keygen.email)
507 return gpg_error (GPG_ERR_ENOMEM);
508
509 err = gpg_card_edit (ctx, this);
510 if (!err)
511 err = getResult () & GPG_CARDRES_CANCEL? gpg_error (GPG_ERR_CANCELED) : 0;
512 if (!err && r_key_fpr)
513 *r_key_fpr = strdup (keygen.key_fpr? keygen.key_fpr : "");
514 return err;
515 }
516
517
518 /* Change the pin from @pin to @pin_new.
519 Return value: 0 on success. */
520 gpgme_error_t
521 GpgCardEdit::changePIN (int _type)
522 {
523 gpgme_error_t err;
524
525 if (!this->pin_new)
526 return gpg_error (GPG_ERR_INV_ARG);
527
528 if (!_type) {
529 if (this->pin && this->pin_new)
530 this->type = GPG_EDITCARD_CHUPIN;
531 else if (this->pin && this->admin_pin)
532 this->type = GPG_EDITCARD_CHAPIN;
533 else
534 this->type = GPG_EDITCARD_UNBPIN;
535 }
536 else
537 this->type = _type;
538 /* check if the user provided the needed PIN. */
539 if ((this->type == GPG_EDITCARD_CHUPIN && !this->pin) ||
540 (this->type == GPG_EDITCARD_CHAPIN && !this->admin_pin))
541 return gpg_error (GPG_ERR_INV_ARG);
542
543 err = gpg_card_edit (ctx, this);
544 return err;
545 }
546
547
548 gpgme_error_t
549 GpgCardEdit::updateName (const char *given, const char *sur)
550 {
551 gpgme_error_t err;
552
553 if (!this->admin_pin)
554 return gpg_error (GPG_ERR_INV_OBJ);
555
556 this->type = GPG_EDITCARD_NAME;
557 this->edit.surname = sur;
558 this->edit.givenname = given;
559
560 err = gpg_card_edit (ctx, this);
561 return err;
562 }
563
564 gpgme_error_t
565 GpgCardEdit::updateURL (const char *_url)
566 {
567 gpgme_error_t err;
568
569 if (!this->admin_pin)
570 return gpg_error (GPG_ERR_INV_OBJ);
571
572 type = GPG_EDITCARD_KEYURL;
573 this->edit.keyurl = _url;
574
575 err = gpg_card_edit (ctx, this);
576 return err;
577 }
578
579
580 gpgme_error_t
581 GpgCardEdit::updateLogin (const char *login)
582 {
583 gpgme_error_t err;
584
585 if (!this->admin_pin)
586 return gpg_error (GPG_ERR_INV_OBJ);
587
588 this->type = GPG_EDITCARD_LOGIN;
589 this->edit.login = login;
590
591 err = gpg_card_edit (ctx, this);
592 return err;
593 }
594
595 gpgme_error_t
596 GpgCardEdit::updateSex (char sex)
597 {
598 gpgme_error_t err;
599
600 if (!this->admin_pin)
601 return gpg_error (GPG_ERR_INV_OBJ);
602
603 type = GPG_EDITCARD_SEX;
604 this->edit.sex = sex;
605
606 err = gpg_card_edit (ctx, this);
607 return err;
608 }
609
610 gpgme_error_t
611 GpgCardEdit::updateLanguage (const char *lang)
612 {
613 gpgme_error_t err;
614
615 if (!this->admin_pin)
616 return gpg_error (GPG_ERR_INV_OBJ);
617
618 type = GPG_EDITCARD_LANG;
619 this->edit.lang = lang;
620
621 err = gpg_card_edit (ctx, this);
622 return err;
623 }
624
625
626 /* Fetch the key specified by the url stored on the card.
627 Return value: 0 on success. */
628 gpgme_error_t
629 GpgCardEdit::fetchKey (void)
630 {
631 if (!this->pin)
632 return gpg_error (GPG_ERR_INV_OBJ);
633
634 return 0;
635 }
636
637
638 /* Dispatcher for the various commands. @cmd is the card command ID
639 and @arg1 and @arg2 the actual values for the command.
640 Return value: 0 on success. */
641 gpgme_error_t
642 GpgCardEdit:: doCmd (int cmd, const char *arg1, const char *arg2)
643 {
644 switch (cmd) {
645 case GPG_EDITCARD_NAME:
646 return updateName (arg1, arg2); /* given, surname */
647
648 case GPG_EDITCARD_LANG:
649 return updateLanguage (arg1); /* lang */
650
651 case GPG_EDITCARD_SEX:
652 return updateSex (*arg1); /* sex */
653
654 case GPG_EDITCARD_KEYURL:
655 return updateURL (arg1); /* url */
656
657 case GPG_EDITCARD_LOGIN:
658 return updateLogin (arg1); /* login */
659
660 default:
661 return gpg_error (GPG_ERR_INV_VALUE);
662 }
663
664 return 0;
665 }
666
667
668 /* Set the result for the executed operation.
669 The values will be ORed. */
670 void
671 GpgCardEdit::setResult (int res)
672 {
673 result |= res;
674 }
675
676
677 /* Return the result of the executed operation. */
678 int
679 GpgCardEdit::getResult (void)
680 {
681 return result;
682 }
683
684
685 /* Reset the object state. */
686 void
687 GpgCardEdit::reset (void)
688 {
689 cnt = 0;
690 }
691
692
693 /* Return card command type */
694 int
695 GpgCardEdit::getType (void)
696 {
697 return type;
698 }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26