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

Annotation of /trunk/Src/wptCardEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (hide annotations)
Sat Nov 5 12:28:12 2005 UTC (19 years, 3 months ago) by twoaday
File size: 15251 byte(s)
More minor fixes...

1 werner 36 /* 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 twoaday 69 enum rectype_t rectype = (rectype_t)0;
134 werner 36 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 twoaday 69
296     default:
297     break;
298 werner 36 }
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 twoaday 69 GpgCardEdit::setPIN (const char *_pin)
381 werner 36 {
382 twoaday 69 this->pin = _pin;
383 werner 36 }
384    
385     /* Set the admin PIN for the object to @admin_pin. */
386     void
387 twoaday 69 GpgCardEdit::setAdminPIN (const char *_admin_pin)
388 werner 36 {
389 twoaday 69 this->admin_pin = _admin_pin;
390 werner 36 }
391    
392    
393     /* Set the new user PIN for the object to @new_pin. */
394     void
395 twoaday 69 GpgCardEdit::setNewPIN (const char *_new_pin)
396 werner 36 {
397 twoaday 69 this->pin_new = _new_pin;
398 werner 36 }
399    
400    
401     /* Set the passphrase needed when generating a key to @pass. */
402     void
403 twoaday 69 GpgCardEdit::setKeygenPassphrase (const char *_pass)
404 werner 36 {
405 twoaday 69 this->keygen.pass = _pass;
406 werner 36 }
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, "%d", 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 twoaday 69 GpgCardEdit::changePIN (int _type)
522 werner 36 {
523     gpgme_error_t err;
524    
525     if (!this->pin_new)
526     return gpg_error (GPG_ERR_INV_ARG);
527    
528 twoaday 69 if (!_type) {
529 werner 36 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 twoaday 69 this->type = _type;
538 werner 36 /* 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 twoaday 69 GpgCardEdit::updateURL (const char *_url)
566 werner 36 {
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 twoaday 69 this->edit.keyurl = _url;
574 werner 36
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