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

Annotation of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Thu Oct 20 12:35:59 2005 UTC (19 years, 4 months ago) by twoaday
File size: 15873 byte(s)
Minor cleanups and prepare the translation.

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26