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

Contents of /trunk/Src/wptCardEdit.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: 15228 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 /* 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;
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 }
297 }
298 return 0;
299 }
300
301
302 /* Dummy handler to get the colon data and then quit. */
303 static gpgme_error_t
304 list_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
305 {
306 static int wait_card=0;
307 GpgCardEdit *ce = (GpgCardEdit *)opaque;
308 const char *s="";
309 DWORD n;
310
311
312 if (code == GPGME_STATUS_CARDCTRL) {
313 if (!strcmp (key, "5"))
314 ce->setResult (GPG_CARDRES_NOCARD);
315 else if (!strcmp (key, "1"))
316 wait_card = 1;
317 }
318 if (wait_card && !strcmp (key, "cardctrl.insert_card.okay")) {
319 n = MessageBox (NULL, _("Please insert the card and click OK or Cancel to abort."),
320 _("GPG Card Status"), MB_ICONQUESTION|MB_OKCANCEL);
321 if (n == IDCANCEL) {
322 ce->setResult (GPG_CARDRES_CANCEL);
323 WriteFile ((HANDLE)fd, "c\n", 2, &n, NULL);
324 wait_card = 0;
325 }
326 }
327 if (!strcmp (key, "cardedit.prompt")) {
328 s = "quit\n";
329 if (!WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL))
330 log_debug ("list_handler: WriteFile() failed ec=%d\r\n",
331 (int)GetLastError ());
332 wait_card = 0;
333 }
334 return 0;
335 }
336
337
338 /* Construct an empty object. */
339 GpgCardEdit::GpgCardEdit (void)
340 {
341 pin = NULL;
342 pin_new = NULL;
343 admin_pin = NULL;
344
345 keygen.comment = NULL;
346 keygen.email = NULL;
347 keygen.name = NULL;
348 keygen.expdate = NULL;
349 keygen.key_fpr = NULL;
350
351 type = 0;
352 cnt = 0;
353 cancel = 0;
354 result = 0;
355
356 gpgme_new (&ctx); /* XXX: check return code */
357 }
358
359 /* Release the object. */
360 GpgCardEdit::~GpgCardEdit (void)
361 {
362 if (keygen.name)
363 free (keygen.name);
364 if (keygen.comment)
365 free (keygen.comment);
366 if (keygen.email)
367 free (keygen.email);
368 if (keygen.expdate)
369 free (keygen.expdate);
370 if (keygen.key_fpr)
371 free (keygen.key_fpr);
372 gpgme_release (ctx);
373 }
374
375
376 /* Set the user PIN for the object to @pin. */
377 void
378 GpgCardEdit::setPIN (const char *pin)
379 {
380 this->pin = pin;
381 }
382
383 /* Set the admin PIN for the object to @admin_pin. */
384 void
385 GpgCardEdit::setAdminPIN (const char *admin_pin)
386 {
387 this->admin_pin = admin_pin;
388 }
389
390
391 /* Set the new user PIN for the object to @new_pin. */
392 void
393 GpgCardEdit::setNewPIN (const char *new_pin)
394 {
395 this->pin_new = new_pin;
396 }
397
398
399 /* Set the passphrase needed when generating a key to @pass. */
400 void
401 GpgCardEdit::setKeygenPassphrase (const char *pass)
402 {
403 this->keygen.pass = pass;
404 }
405
406
407 /* Set the callback to @cb and the hook value to @cb_value. */
408 void
409 GpgCardEdit::setCallback (const char* (*cb)(int code, void *opaque),
410 void *cb_value)
411 {
412 this->cb_value = cb_value;
413 this->card_cb = cb;
414 }
415
416
417 /* Read the information from the inserted card and return
418 it in form of a card context @r_card.
419 Return value: 0 on success. */
420 gpgme_error_t
421 GpgCardEdit::getCardStatus (gpg_card_t *r_card)
422 {
423 gpgme_data_t out = NULL;
424 gpgme_error_t err;
425 gpg_card_t card=NULL;
426 char buf[200];
427
428 if (!r_card)
429 return gpg_error (GPG_ERR_INV_ARG);
430
431 err = gpg_card_new (&card);
432 if (err)
433 return err;
434
435 err = gpgme_data_new (&out);
436 if (err) {
437 gpg_card_release (card);
438 return err;
439 }
440
441 err = gpgme_op_card_edit (ctx, NULL, list_handler, this, out);
442 gpgme_data_rewind (out);
443 if (err) {
444 gpgme_data_release (out);
445 gpg_card_release (card);
446 return err;
447 }
448 if (getResult () & GPG_CARDRES_NOCARD ||
449 getResult () & GPG_CARDRES_CANCEL) {
450 gpg_card_release (card);
451 gpgme_data_release (out);
452 return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
453 }
454
455 *r_card = card;
456 while (gpg_data_readline (out, buf, sizeof (buf)-2) > 0) {
457 err = statuscard_colon_handler (card, buf);
458 if (err)
459 break;
460 }
461 gpgme_data_release (out);
462
463 return err;
464 }
465
466
467 /* Generate a key on a smart card with the following params:
468 @flags: user specific params.
469 @name: name of the key holder.
470 @email: email of the key holder.
471 @comment: optional comment.
472 @valid: how long is the key valid in days.
473 Return value: 0 on success. */
474 gpgme_error_t
475 GpgCardEdit::genKey (int flags, const char *name,
476 const char *email, const char *comment, long valid,
477 char **r_key_fpr)
478 {
479 gpgme_error_t err;
480
481 if (!name || !email)
482 return gpg_error (GPG_ERR_INV_ARG);
483 if (!this->keygen.pass)
484 return gpg_error (GPG_ERR_INV_OBJ);
485
486 type = GPG_EDITCARD_GENKEY;
487 this->keygen.flags = flags;
488
489 if (this->keygen.name)
490 free (this->keygen.name);
491 this->keygen.name = strdup (name);
492 if (this->keygen.email)
493 free (this->keygen.email);
494 this->keygen.email = strdup (email);
495 if (this->keygen.comment)
496 free (this->keygen.comment);
497 this->keygen.comment = comment? strdup (comment) : strdup ("");
498 if (this->keygen.expdate)
499 free (this->keygen.expdate);
500 this->keygen.expdate = (char*)calloc (1, 16);
501 if (this->keygen.expdate)
502 sprintf (this->keygen.expdate, "%d", valid);
503
504 if (!this->keygen.name || !this->keygen.email)
505 return gpg_error (GPG_ERR_ENOMEM);
506
507 err = gpg_card_edit (ctx, this);
508 if (!err)
509 err = getResult () & GPG_CARDRES_CANCEL? gpg_error (GPG_ERR_CANCELED) : 0;
510 if (!err && r_key_fpr)
511 *r_key_fpr = strdup (keygen.key_fpr? keygen.key_fpr : "");
512 return err;
513 }
514
515
516 /* Change the pin from @pin to @pin_new.
517 Return value: 0 on success. */
518 gpgme_error_t
519 GpgCardEdit::changePIN (int type)
520 {
521 gpgme_error_t err;
522
523 if (!this->pin_new)
524 return gpg_error (GPG_ERR_INV_ARG);
525
526 if (!type) {
527 if (this->pin && this->pin_new)
528 this->type = GPG_EDITCARD_CHUPIN;
529 else if (this->pin && this->admin_pin)
530 this->type = GPG_EDITCARD_CHAPIN;
531 else
532 this->type = GPG_EDITCARD_UNBPIN;
533 }
534 else
535 this->type = type;
536 /* check if the user provided the needed PIN. */
537 if ((this->type == GPG_EDITCARD_CHUPIN && !this->pin) ||
538 (this->type == GPG_EDITCARD_CHAPIN && !this->admin_pin))
539 return gpg_error (GPG_ERR_INV_ARG);
540
541 err = gpg_card_edit (ctx, this);
542 return err;
543 }
544
545
546 gpgme_error_t
547 GpgCardEdit::updateName (const char *given, const char *sur)
548 {
549 gpgme_error_t err;
550
551 if (!this->admin_pin)
552 return gpg_error (GPG_ERR_INV_OBJ);
553
554 this->type = GPG_EDITCARD_NAME;
555 this->edit.surname = sur;
556 this->edit.givenname = given;
557
558 err = gpg_card_edit (ctx, this);
559 return err;
560 }
561
562 gpgme_error_t
563 GpgCardEdit::updateURL (const char *url)
564 {
565 gpgme_error_t err;
566
567 if (!this->admin_pin)
568 return gpg_error (GPG_ERR_INV_OBJ);
569
570 type = GPG_EDITCARD_KEYURL;
571 this->edit.keyurl = url;
572
573 err = gpg_card_edit (ctx, this);
574 return err;
575 }
576
577
578 gpgme_error_t
579 GpgCardEdit::updateLogin (const char *login)
580 {
581 gpgme_error_t err;
582
583 if (!this->admin_pin)
584 return gpg_error (GPG_ERR_INV_OBJ);
585
586 this->type = GPG_EDITCARD_LOGIN;
587 this->edit.login = login;
588
589 err = gpg_card_edit (ctx, this);
590 return err;
591 }
592
593 gpgme_error_t
594 GpgCardEdit::updateSex (char sex)
595 {
596 gpgme_error_t err;
597
598 if (!this->admin_pin)
599 return gpg_error (GPG_ERR_INV_OBJ);
600
601 type = GPG_EDITCARD_SEX;
602 this->edit.sex = sex;
603
604 err = gpg_card_edit (ctx, this);
605 return err;
606 }
607
608 gpgme_error_t
609 GpgCardEdit::updateLanguage (const char *lang)
610 {
611 gpgme_error_t err;
612
613 if (!this->admin_pin)
614 return gpg_error (GPG_ERR_INV_OBJ);
615
616 type = GPG_EDITCARD_LANG;
617 this->edit.lang = lang;
618
619 err = gpg_card_edit (ctx, this);
620 return err;
621 }
622
623
624 /* Fetch the key specified by the url stored on the card.
625 Return value: 0 on success. */
626 gpgme_error_t
627 GpgCardEdit::fetchKey (void)
628 {
629 gpgme_error_t err = 0;
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