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

Diff of /trunk/Src/wptCardDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2 by twoaday, Mon Jan 31 11:02:21 2005 UTC revision 278 by twoaday, Mon Jan 15 22:02:04 2007 UTC
# Line 1  Line 1 
 /* wptCardDlg.cpp - Smart Card support  
  *      Copyright (C) 2003, 2004 Timo Schulz  
  *  
  * This file is part of WinPT.  
  *  
  * WinPT is free software; you can redistribute it and/or modify  
  * it under the terms of the GNU General Public License as published by  
  * the Free Software Foundation; either version 2 of the License, or  
  * (at your option) any later version.  
  *  
  * WinPT is distributed in the hope that it will be useful,  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  * GNU General Public License for more details.  
  *  
  * You should have received a copy of the GNU General Public License  
  * along with WinPT; if not, write to the Free Software Foundation,  
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA  
  */  
   
 #include <windows.h>  
 #include <commctrl.h>  
 #include <ctype.h>  
   
 #include "../resource.h"  
 #include "wptTypes.h"  
 #include "wptW32API.h"  
 #include "wptErrors.h"  
 #include "wptRegistry.h"  
 #include "wptVersion.h"  
 #include "wptCommonCtl.h"  
 #include "wptDlgs.h"  
 #include "wptGPG.h"  
 #include "wptUTF8.h"  
 #include "wptCard.h"  
   
 int keygen_check_date (SYSTEMTIME * st);  
   
 static const char * sex[] = {"Male", "Female", "Undefined", NULL};  
 static const char * lang[] = {"Undefined", "cs", "de", "en", "es", "fr", "hu",  
                               "it", "nl", "pt", "ro", "ru", "zh", "at",  
                               NULL};  
   
 static pin_cb_ctx_s pincb;  
   
 struct {  
     int ctlid;  
     gpgme_attr_t attr;  
     const char * err;  
 } attr_tab[] = {  
     {IDC_CEDIT_AID,    GPGME_ATTR_CARD_AID,    ""},  
     {IDC_CEDIT_VENDOR, GPGME_ATTR_CARD_VENDOR, "No Vendor"},  
     {IDC_CEDIT_VERSION,GPGME_ATTR_CARD_VER,    "No Version"},  
     {IDC_CEDIT_SERIAL, GPGME_ATTR_CARD_SERIAL, "No Serial-No"},  
     {IDC_CEDIT_NAME,   GPGME_ATTR_CARD_NAME,   "No Name"},  
     {IDC_CEDIT_NAME2,  GPGME_ATTR_CARD_NAME2,  "No Surname"},  
     {IDC_CEDIT_KEYURL, GPGME_ATTR_CARD_URL,    "No Key-URL"},  
     {IDC_CEDIT_LOGIN,  GPGME_ATTR_CARD_LOGIN,  "No Login name"},  
     {0},  
 };  
   
   
 #define card_get_string(card, what) \  
     gpgme_card_get_string_attr ((card), (what), NULL, 0)  
 #define card_get_ulong(card, what)  \  
     gpgme_card_get_ulong_attr ((card), (what), NULL, 0)  
 #define card_get_fpr(card, idx)     \  
     gpgme_card_get_string_attr ((card), GPGME_ATTR_CARD_FPR, NULL, (idx)-1)  
   
   
 static int  
 idx_from_lang( const char * _lang )  
 {  
     const char * s;  
     int i;  
   
     if (!_lang)  
         return 0;  
     for (i=0; (s = lang[i]); i++) {  
         if( !strcmp( _lang, s ) )  
             return i;  
     }  
     return 0;  
 } /* idx_from_lang */  
   
   
 int  
 show_card_status (void)  
 {  
     int rc = 0;  
     int cardstat;  
   
     cardstat = pcsc_get_card_status ();  
     if ((cardstat & CARD_STATE_UNAWARE) || (cardstat & CARD_STATE_UNAVAIL))  
         rc = WPTERR_NOREADER;  
     else if (cardstat & CARD_STATE_EMPTY)  
         rc = WPTERR_NOCARD;      
     if (rc) {  
         msg_box (NULL, winpt_strerror (rc), _("Card Manager"), MB_ERR);  
         return -1;  
     }  
     return 0;  
 } /* show_card_status */  
   
   
 gpgme_card_t  
 gpg_load_scard (void)  
 {  
     gpgme_error_t rc;  
     gpgme_card_t card = NULL;  
     gpgme_editcard_t ec;  
     gpgme_ctx_t ctx;  
     const char * s;  
     struct card_cb_s cb = {0};  
   
     rc = gpgme_new (&ctx);  
     if (!rc)  
         rc = gpgme_editcard_new (&ec);  
     if (rc)  
         BUG (0);  
     gpgme_enable_logging (ctx);  
     gpgme_editcard_set_callback (ec, card_callback, &cb);  
     gpgme_set_edit_ctx (ctx, ec, 0);  
     rc = gpgme_op_statuscard (ctx, &card);  
     if (rc) {  
         gpgme_show_error (NULL, rc, ctx, _("Card Manager"), MB_ERR);  
         goto leave;  
     }  
     s = gpgme_card_get_string_attr (card, GPGME_ATTR_CARD_AID, NULL, 0);  
     if (!s || strncmp (s, "D276000124", 10)) {  
         msg_box (NULL, winpt_strerror (WPTERR_NOPGPCARD), "WinPT", MB_ERR);  
         gpgme_card_release (card);  
         card = NULL;  
     }  
   
 leave:  
     gpgme_editcard_release (ec);  
     gpgme_release (ctx);  
     return card;  
 } /* gpg_load_scard */  
   
   
 static void  
 print_fpr (HWND dlg, int id, const char * fpr)  
 {  
     char buf[128], dig[2];      
     size_t i, c;  
   
     if (!fpr)  
         strcpy( buf, _("No Fingerprint") );  
     else {  
         memset( buf, 0, sizeof (buf) );  
         for( i=0, c=0; i < strlen( fpr ); i++ ) {  
             dig[0] = fpr[i]; dig[1] = 0;  
             strcat( buf, dig );  
             if( ++c == 4 ) {  
                 strcat( buf, " " );  
                 c=0;  
             }  
         }  
     }  
     SetDlgItemText( dlg, id, buf );  
 } /* print_fpr */  
   
   
 static int  
 card_status( HWND dlg, gpgme_card_t card )  
 {  
     static int fprbuf[] = {0, IDC_CEDIT_FPR1, IDC_CEDIT_FPR2, IDC_CEDIT_FPR3, 0};  
     const char * s;  
     int idx=0;  
     u32 t;  
   
     s = card_get_string( card, GPGME_ATTR_CARD_AID );  
     if( !s ) {  
         msg_box( dlg, _("No OpenPGP smart card detected."), "WinPT", MB_ERR );  
         return -1;  
     }  
     SetDlgItemText( dlg, IDC_CEDIT_AID, s );  
   
     t = card_get_ulong( card, GPGME_ATTR_CARD_SIGCOUNT );  
     SetDlgItemInt( dlg, IDC_CEDIT_SIGCOUNT, t, TRUE );  
   
     for( idx=1; fprbuf[idx]; idx++ ) {  
         s = card_get_fpr( card, idx );  
         print_fpr( dlg, fprbuf[idx], s );  
     }  
   
     for( idx=1; attr_tab[idx].attr; idx++ ) {  
         s = card_get_string( card, attr_tab[idx].attr );  
         SetDlgItemText( dlg, attr_tab[idx].ctlid, s && *s? s : attr_tab[idx].err );  
     }  
   
     s = card_get_string( card, GPGME_ATTR_CARD_LANG );  
     idx = idx_from_lang( s );      
     SendDlgItemMessage( dlg, IDC_CEDIT_LANG, CB_SETCURSEL, (WPARAM)idx, 0 );  
   
     t = card_get_ulong( card, GPGME_ATTR_CARD_SEX );  
     switch( t ) {  
     case 'm': idx=0; break;  
     case 'f': idx=1; break;  
     default :  
     case 'u': idx=2; break;  
     }  
     SendDlgItemMessage( dlg, IDC_CEDIT_SEX, CB_SETCURSEL, (WPARAM)idx, 0 );  
   
     return 0;  
 } /* card_status */  
   
   
 static void  
 prepare_dialog( HWND dlg )  
 {  
     const char * s;  
     int i;  
   
     for( i=0; (s = sex[i]); i++ )  
         SendDlgItemMessage( dlg, IDC_CEDIT_SEX, CB_ADDSTRING, 0, (LPARAM) s );  
     SendDlgItemMessage( dlg, IDC_CEDIT_SEX, CB_SETCURSEL, 0, 0 );  
     for( i=0; (s = lang[i]); i++ )  
         SendDlgItemMessage( dlg, IDC_CEDIT_LANG, CB_ADDSTRING, 0, (LPARAM)s );  
     SendDlgItemMessage( dlg, IDC_CEDIT_LANG, CB_SETCURSEL, 0, 0 );  
 } /* prepare_dialog */  
   
   
 static int  
 check_string( const char * str, int flags )  
 {  
     size_t i;  
     for( i=0; i < strlen( str ); i++ ) {  
         if( flags & 0x02 && !isalpha( str[i] ) )  
             return -1;  
     }  
     return 0;  
 }  
   
   
 static int  
 do_proc_card_cmds( HWND dlg, struct pin_cb_ctx_s * pincb, gpgme_card_t card )  
 {  
     static struct {  
         int id;  
         int cmd;  
         int us_ascii;  
         int changed;  
     } idctl[] = {  
         {IDC_CEDIT_NAME,  GPGME_EDITCARD_NAME,  1,  0},  
         {IDC_CEDIT_LANG2, GPGME_EDITCARD_LANG,  1,  0},  
         {IDC_CEDIT_SEX2,  GPGME_EDITCARD_SEX,   1|1,0},  
         {IDC_CEDIT_KEYURL,GPGME_EDITCARD_KEYURL,1,  0},  
         {IDC_CEDIT_LOGIN, GPGME_EDITCARD_LOGIN, 1,  0},  
         {0}  
     };  
     gpgme_editcard_t ec;  
     gpgme_ctx_t ctx;  
     gpgme_error_t rc;  
     char buf[256], tmp[128];  
     int errc=0;  
     int i, id, n=0;  
   
     /* XXX rewrite the entire function */  
     for( i=0; idctl[i].id; i++ ) /* reset */  
         idctl[i].changed = 0;  
       
     if( SendMessage( GetDlgItem( dlg, IDC_CEDIT_LANG2 ), WM_GETTEXTLENGTH, 0, 0 ) ) {  
         idctl[1].changed = 1;  
         n++;  
     }  
     if( SendMessage( GetDlgItem( dlg, IDC_CEDIT_SEX2 ), WM_GETTEXTLENGTH, 0, 0 ) ) {  
         idctl[2].changed = 1;  
         n++;  
     }  
       
     if( SendDlgItemMessage( dlg, IDC_CEDIT_NAME2, EM_GETMODIFY, 0, 0 ) ) {  
         idctl[0].changed = 1;  
         n++;  
     }  
     for( i=0; (id = idctl[i].id); i++ ) {  
         if( SendDlgItemMessage( dlg, id, EM_GETMODIFY, 0, 0 ) ) {  
             idctl[i].changed = 1;  
             n++;  
         }  
     }  
     if( !pincb || !card ) /* just return the changed elements */  
         return n;  
     if( !n )  
         return 0;  
       
     rc = gpgme_editcard_new( &ec );  
     if( !rc )  
         rc = gpgme_new( &ctx );  
     if( rc )  
         BUG( NULL );  
     gpgme_editcard_control( ec, GPGME_EDITCARD_APIN, pincb->apin );  
     gpgme_editcard_control( ec, GPGME_EDITCARD_UPIN, pincb->upin );  
     for( i=0; idctl[i].id; i++ ) {  
         if( idctl[i].changed ) {  
             GetDlgItemText( dlg, idctl[i].id, buf, sizeof (buf)-1 );  
             if (idctl[i].us_ascii && is_8bit_string (buf)) {  
                 msg_box (dlg, _("Only plain ASCII is currently allowed."),  
                          _("Card Edit"), MB_ERR);  
                 errc--; continue;  
             }  
             if( (idctl[i].us_ascii & 2) && check_string( buf, 2 ) ) {  
                 msg_box( dlg, _("Only alphabetic characters are allowed."),  
                          _("Card Edit"), MB_ERR );  
                 errc--; continue;  
             }  
             if( idctl[i].cmd == GPGME_EDITCARD_NAME ) {  
                 /* The "name" command actually needs two fields */  
                 GetDlgItemText( dlg, IDC_CEDIT_NAME2, tmp, sizeof tmp-1 );  
                 gpgme_editcard_control( ec, GPGME_EDITCARD_NAME2, tmp );  
             }  
             gpgme_editcard_control( ec, idctl[i].cmd, buf );  
             gpgme_set_edit_ctx( ctx, ec, idctl[i].cmd );  
             rc = gpgme_op_editcard( ctx );  
             if( rc ) {  
                 msg_box( dlg, _("Could not modify card attribute."),  
                          _("Card Edit"), MB_ERR );  
                 errc--;  
             }  
         }  
     }  
     if( !errc ) {  
         /* if the operation(s) succeeded, reset the modify flag for each control */  
         for( i = 0; idctl[i].id; i++ )  
             SendDlgItemMessage( dlg, idctl[i].id, EM_SETMODIFY, (WPARAM)(UINT)FALSE, 0 );  
         msg_box( dlg, _("Card attribute changed."), _("Card Edit"), MB_OK );  
         SetDlgItemText( dlg, IDC_CEDIT_LANG2, "" );  
         SetDlgItemText( dlg, IDC_CEDIT_SEX2, "" );  
     }  
     gpgme_editcard_release( ec );  
     gpgme_release( ctx );  
     return errc;  
 } /* do_proc_card_cmds */  
   
   
 void  
 free_pincb (struct pin_cb_ctx_s * ctx)  
 {  
     if (!ctx)  
         return;  
     free_if_alloc (ctx->info_text);  
     free_if_alloc (ctx->upin);  
     free_if_alloc (ctx->apin);  
 } /* free_pincb */  
   
   
 static int  
 do_askpin( HWND dlg, gpgme_edit_card_t which, gpgme_card_t card,  
            struct pin_cb_ctx_s * pincb )  
 {  
     const char * s, * fmt;  
     const char * n1, * n2, * serial;  
     char * p;  
     size_t n;  
   
     if( (which == GPGME_EDITCARD_CHAPIN && pincb->apin) ||  
         (which == GPGME_EDITCARD_CHUPIN && pincb->upin) )  
         return 0;  
       
     if( which == GPGME_EDITCARD_CHAPIN )  
         s = _("Please enter the 'Admin PIN'");  
     else if( which == GPGME_EDITCARD_CHUPIN )  
         s = _("Please enter the 'User PIN'");  
     else  
         s = _("Please enter the PIN");  
     pincb->which = which;  
     free_if_alloc( pincb->info_text );  
     if( card ) {  
         fmt = _("%s\nName: %s %s\nSerial-No: %s\n");  
         n1 = card_get_string( card, GPGME_ATTR_CARD_NAME );  
         n2 = card_get_string( card, GPGME_ATTR_CARD_NAME2 );  
         if( !n1 || !n2 ) {  
             n1 = "No"; n2 = "Name";  
         }      
         serial = card_get_string( card, GPGME_ATTR_CARD_SERIAL );  
         if( !serial )  
             serial = "No Serial";  
         n = strlen( n1 ) + strlen( n2 ) + strlen( fmt ) + strlen( serial ) + 3;  
         p = pincb->info_text = new char[strlen( s )+n+1 ];  
         if( !p )  
             BUG (0);  
         sprintf( p, fmt, s, n1, n2, serial );  
     }  
     else {  
         p = pincb->info_text = m_strdup (s);  
         if (!p)  
             BUG (0);  
     }  
     DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_PIN, dlg,  
                     pin_cb_dlg_proc, (LPARAM)pincb);  
     if( !pincb->apin && !pincb->upin) {  
         safe_free (pincb->info_text);  
         return -1;  
     }  
     return 0;  
 } /* do_askpin */  
   
   
 BOOL CALLBACK  
 card_edit_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  
 {  
     static gpgme_card_t card;      
     char tmp[128];  
     size_t n=0;  
   
     switch (msg) {  
     case WM_INITDIALOG:  
         card = (gpgme_card_t)lparam;  
         if (!card)  
             BUG (0);  
         prepare_dialog (dlg);  
         if (card_status (dlg, card ))  
             EndDialog (dlg, TRUE);  
         center_window (dlg);  
         SetForegroundWindow (dlg);  
         return TRUE;  
   
     case WM_DESTROY:  
         free_if_alloc (pincb.info_text);  
         free_if_alloc (pincb.apin);  
         free_if_alloc (pincb.upin);  
         memset (&pincb, 0, sizeof pincb);  
         break;  
   
     case WM_COMMAND:  
         switch( HIWORD( wparam ) ) {  
         case CBN_KILLFOCUS:  
         case CBN_EDITCHANGE:  
         case CBN_EDITUPDATE:  
             int ctlid = GetDlgCtrlID( (HWND)lparam );  
             int dstid = 0;  
   
             switch (ctlid) {  
             case IDC_CEDIT_LANG: dstid = IDC_CEDIT_LANG2; break;  
             case IDC_CEDIT_SEX:  dstid = IDC_CEDIT_SEX2; break;  
             }        
             GetDlgItemText (dlg, ctlid, tmp, 127);  
             SetDlgItemText (dlg, dstid, tmp);  
             break;  
         }  
         switch( LOWORD( wparam ) ) {  
         case IDC_CEDIT_CHPIN:  
             DialogBoxParam( glob_hinst, (LPCTSTR)IDD_WINPT_CARD_CHPIN, dlg,  
                             card_changepin_dlg_proc, NULL );  
             break;  
   
         case IDC_CEDIT_NEWKEYS:  
             if (item_get_text_length (dlg, IDC_CEDIT_FPR1) > 0) {  
                 int id = msg_box (dlg,  
                     _("This operation will override the keys on the card.\n"  
                       "Still proceed?"), _("Card Edit"), MB_WARN|MB_YESNO);  
                 if (id == IDNO)  
                     return FALSE;  
             }  
             DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_CARD_KEYGEN,  
                             glob_hwnd, card_keygen_dlg_proc, NULL);  
             break;  
   
         case IDOK:  
             n = do_proc_card_cmds( dlg, NULL, NULL );  
             if( n ) {  
                 if( do_askpin( dlg, GPGME_EDITCARD_CHAPIN, card, &pincb ) )  
                     EndDialog( dlg, FALSE );  
                 if( do_askpin( dlg, GPGME_EDITCARD_CHUPIN, card, &pincb ) )  
                     EndDialog( dlg, FALSE );  
             }  
             do_proc_card_cmds( dlg, &pincb, card );  
             free_pincb( &pincb );  
             if( !n )  
                 EndDialog( dlg, TRUE );  
             break;  
   
         case IDCANCEL:  
             EndDialog( dlg, FALSE );  
             break;  
         }  
         break;  
     }  
   
     return FALSE;  
 } /* card_edit_dlg_proc */  
   
   
   
 static int /* fixme: works only roughly */  
 calc_days (int y2, int m2, int d2,  
            int y1, int m1, int d1)  
   
 {  
     int n=0;  
       
     if ((y2-y1) > 0)  
         n += (y2-y1)*365;  
     if ((m2-m1) > 0)  
         n += (m2-m1)*30;  
     if ((d2-d1) > 0)  
         n += (d2-d1);  
     else if ((d2-d1) < 0)  
         n -= (d1-d2);  
     return n;  
 }  
   
   
 static void  
 keygen_fill_algbox (HWND dlg)  
 {  
     SendDlgItemMessage (dlg, IDC_CKEYGEN_ALG, CB_ADDSTRING, 0, (LPARAM)(const char*)"RSA");  
     SendDlgItemMessage (dlg, IDC_CKEYGEN_ALG, CB_SETCURSEL, 0, 0);  
 }  
   
   
 BOOL CALLBACK  
 card_keygen_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  
 {  
     static int state = 0;  
     static int pwd_state = 0;  
     gpgme_ctx_t ctx;  
     gpgme_editcard_t crd;  
     gpgme_error_t err;  
     char name[128], email[128], comment[128], expdate[64];  
     char pass[128];  
     int card_flags = GPGME_CARDFLAG_NONE;  
     int expires=0;  
     size_t n;  
   
     switch (msg) {  
     case WM_INITDIALOG:  
         state = 0;  
         pwd_state = 1;  
         center_window (dlg);  
         CheckDlgButton (dlg, IDC_CKEYGEN_REPLACE, BST_CHECKED);  
         CheckDlgButton (dlg, IDC_CKEYGEN_NEVER, BST_CHECKED);  
         CheckDlgButton (dlg, IDC_CKEYGEN_BACKUP, BST_CHECKED);  
         EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_VALID), FALSE);  
         keygen_fill_algbox (dlg);  
         SetFocus (GetDlgItem (dlg, IDC_CKEYGEN_NAME));  
         SetForegroundWindow (dlg);  
         return FALSE;  
   
     case WM_COMMAND:  
         if (HIWORD (wparam) == BN_CLICKED) {  
             switch (LOWORD (wparam)) {  
             case IDC_CKEYGEN_NEVER:          
                 state ^= 1;  
                 EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_VALID), state);  
                 break;  
   
             case IDC_CKEYGEN_BACKUP:  
                 pwd_state ^= 1;  
                 EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_PASS), pwd_state);  
                 break;  
             }  
         }  
   
         switch (LOWORD (wparam)) {  
         case IDOK:  
             n = item_get_text_length (dlg, IDC_CKEYGEN_NAME);  
             if (!n) {  
                 msg_box (dlg, _("Please enter your name."), _("Card Edit"), MB_ERR);  
                 return FALSE;  
             }  
             if (n < 5) {  
                 msg_box (dlg, _("Name must be at least 5 characters long."),  
                          _("Card Edit"), MB_INFO);  
                 return FALSE;  
             }  
             n = item_get_text_length (dlg, IDC_CKEYGEN_EMAIL);  
             if (!n) {  
                 msg_box (dlg, _("Please enter your e-mail address."),  
                          _("Card Edit"), MB_ERR);  
                 return FALSE;  
             }  
             GetDlgItemText (dlg, IDC_CKEYGEN_NAME, name, sizeof (name)-1);  
             GetDlgItemText (dlg, IDC_CKEYGEN_EMAIL, email, sizeof (email)-1);  
             if (!strchr (email, '@') || n < 3) {  
                 msg_box (dlg, _("Please enter a valid e-mail address."),  
                          _("Card Edit"), MB_ERR);  
                 return FALSE;  
             }  
             n = GetDlgItemText (dlg, IDC_CKEYGEN_PASS, pass, sizeof (pass)-1);  
             if (!n) {  
                 msg_box (dlg, _("Please enter an off-card passphrase."), _("Card Edit"), MB_ERR);  
                 return FALSE;  
             }  
             n = item_get_text_length (dlg, IDC_CKEYGEN_COMMENT);  
             if (n > 0)  
                 GetDlgItemText (dlg, IDC_CKEYGEN_COMMENT, comment, sizeof (comment)-1);  
             if (is_8bit_string (name) ||is_8bit_string (comment)) {  
                 msg_box (dlg, _("Please use plain ASCII charset for the fields."),  
                          _("Card Edit"), MB_INFO);  
                 return FALSE;  
             }  
             memset (&pincb, 0, sizeof (pincb));  
             if (do_askpin (dlg, GPGME_EDITCARD_CHAPIN, NULL, &pincb)) {  
                 free_pincb (&pincb);  
                 return FALSE;  
             }  
             if (do_askpin (dlg, GPGME_EDITCARD_CHUPIN, NULL, &pincb)) {  
                 free_pincb (&pincb);  
                 return FALSE;  
             }  
             err = gpgme_new (&ctx);  
             if (!err)  
                 err = gpgme_editcard_new (&crd);  
             if (err)  
                 BUG (0);  
             expires = !IsDlgButtonChecked (dlg, IDC_CKEYGEN_NEVER);  
             if (expires) {  
                 SYSTEMTIME st, ct;  
                 DateTime_GetSystemtime (GetDlgItem (dlg, IDC_CKEYGEN_VALID), &st);  
                 if (!keygen_check_date (&st)) {  
                     msg_box (dlg, _("The date you have chosen lies in the past."),  
                              _("Card Edit"), MB_ERR);  
                     gpgme_release (ctx);  
                     gpgme_editcard_release (crd);  
                     return FALSE;  
                 }  
                 GetSystemTime (&ct);  
                 /* XXX this is not very precise */  
                 sprintf (expdate, "%d", calc_days (st.wYear, st.wMonth, st.wDay,  
                                                    ct.wYear, ct.wMonth, ct.wDay));  
             }  
             if (IsDlgButtonChecked (dlg, IDC_CKEYGEN_REPLACE))  
                 card_flags |= GPGME_CARDFLAG_REPLACE;  
             if (IsDlgButtonChecked (dlg, IDC_CKEYGEN_BACKUP))  
                 card_flags |= GPGME_CARDFLAG_BAKENC;  
             gpgme_editcard_set_keygen_params (crd, card_flags, name, email,  
                                               n? comment : NULL,  
                                               expires? expdate : NULL);  
             gpgme_editcard_set_passwd (crd, pass);  
             gpgme_editcard_control (crd, GPGME_EDITCARD_APIN, pincb.apin);  
             gpgme_editcard_control (crd, GPGME_EDITCARD_UPIN, pincb.upin);  
             gpgme_set_edit_ctx (ctx, crd, GPGME_EDITCARD_GENKEY);  
             SetCursor( LoadCursor (NULL, IDC_WAIT));  
             err = gpgme_op_editcard (ctx);  
             SetCursor (LoadCursor (NULL, IDC_ARROW));  
             if (err == GPGME_Canceled)  
                 msg_box (dlg, _("Operation was canceled. It seems that there are "  
                                 "existing\nkeys on the cards. You need to mark the "  
                                 "'Overwrite' flag."), _("Card Edit"), MB_INFO);  
             else if (err)  
                 msg_box (dlg, "The operation does not succeed.\n"  
                               "Please make sure you entered the right PIN's."  
                               , _("Card Edit"), MB_ERR);  
             else  
                 msg_box (dlg, _("Keys successfully created."),  
                          _("Card Edit"), MB_OK);  
             memset (pass, 0, sizeof (pass));  
             free_pincb (&pincb);  
             gpgme_release (ctx);  
             gpgme_editcard_release (crd);  
             break;  
   
         case IDCANCEL:  
             EndDialog (dlg, FALSE);  
             return FALSE;  
         }  
         break;  
     }  
     return FALSE;  
 } /* card_keygen_dlg_proc */  
   
   
 static int  
 check_pin_len (int which, int flag, int pinlen)  
 {  
     if (!pinlen) {  
         if (flag)  
             msg_box (NULL, _("Please enter the old card PIN."), _("Card Edit"), MB_ERR);  
         else  
             msg_box (NULL, _("Please enter the new card PIN."), _("Card Edit"), MB_ERR);  
         return -1;  
     }  
     if (which == GPGME_EDITCARD_CHAPIN  
         && pinlen < 8) {  
         msg_box (NULL, _("PIN must be minimal 8 characters."), _("Card Edit"), MB_ERR);  
         return -1;  
     }  
     if (which == GPGME_EDITCARD_CHUPIN  
         && pinlen < 6) {  
         msg_box (NULL, _("PIN must be minimal 6 characters."), _("Card Edit"), MB_ERR);  
         return -1;  
     }  
     return 0;  
 }  
   
   
 BOOL CALLBACK  
 card_changepin_dlg_proc( HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam )  
 {      
     gpgme_ctx_t ctx;  
     gpgme_editcard_t chpin;  
     gpgme_error_t rc;  
     gpgme_edit_card_t which;  
     char pold[128], pnew[128];  
     size_t n;  
   
     switch( msg ) {  
     case WM_INITDIALOG:  
         center_window( dlg );  
         CheckDlgButton( dlg, IDC_CHPIN_ISWORK, BST_CHECKED );  
         SetForegroundWindow( dlg );  
         break;  
   
     case WM_COMMAND:  
         switch( LOWORD( wparam ) ) {  
         case IDOK:  
             if( IsDlgButtonChecked( dlg, IDC_CHPIN_ISADMIN ) )  
                 which = GPGME_EDITCARD_CHAPIN;  
             else if( IsDlgButtonChecked( dlg, IDC_CHPIN_ISWORK ) )  
                 which = GPGME_EDITCARD_CHUPIN;  
             else  
                 BUG (0);  
   
             n = item_get_text_length( dlg, IDC_CHPIN_OLDPIN );  
             if (check_pin_len (which, 1, n))  
                 return FALSE;  
             n = item_get_text_length( dlg, IDC_CHPIN_NEWPIN );  
             if (check_pin_len (which, 0, n))  
                 return FALSE;  
             GetDlgItemText( dlg, IDC_CHPIN_OLDPIN, pold, sizeof (pold)-1 );  
             GetDlgItemText( dlg, IDC_CHPIN_NEWPIN, pnew, sizeof (pnew)-1 );  
             rc = gpgme_new( &ctx );  
             if( !rc )  
                 rc = gpgme_editcard_new( &chpin );  
             if (rc)  
                 BUG (0);  
             gpgme_changepin_set( chpin, which, pold, pnew );  
             gpgme_set_edit_ctx( ctx, chpin, which );  
             rc = gpgme_op_changepin( ctx );  
             if( rc )  
                 msg_box( dlg, gpgme_strerror( rc ), _("Card Edit"), MB_ERR );  
             else {  
                 msg_box( dlg, _("PIN successfully changed."), _("Card Edit"), MB_OK );  
                 SetDlgItemText( dlg, IDC_CHPIN_NEWPIN, "" );  
                 SetDlgItemText( dlg, IDC_CHPIN_OLDPIN, "" );  
             }  
             gpgme_release( ctx );  
             gpgme_editcard_release( chpin );  
             break;  
   
         case IDCANCEL:  
             SetDlgItemText( dlg, IDC_CHPIN_NEWPIN, "" );  
             SetDlgItemText( dlg, IDC_CHPIN_OLDPIN, "" );  
             EndDialog( dlg, FALSE );  
             break;  
         }  
         break;  
     }  
   
     return FALSE;  
 } /* card_changepin_dlg_proc */  
1    /* wptCardDlg.cpp - Smart Card support
2     *      Copyright (C) 2003-2006 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 modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (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
15     * GNU General Public License for more details.
16     */
17    
18    #ifdef HAVE_CONFIG_H
19    #include <config.h>
20    #endif
21    
22    #include <windows.h>
23    #include <commctrl.h>
24    #include <ctype.h>
25    
26    #include "resource.h"
27    #include "gpgme.h"
28    #include "wptTypes.h"
29    #include "wptW32API.h"
30    #include "wptErrors.h"
31    #include "wptRegistry.h"
32    #include "wptVersion.h"
33    #include "wptCommonCtl.h"
34    #include "wptDlgs.h"
35    #include "wptGPG.h"
36    #include "wptUTF8.h"
37    #include "wptCardEdit.h"
38    #include "wptCard.h"
39    #include "wptContext.h"
40    #include "StringBuffer.h"
41    
42    int keygen_check_date (SYSTEMTIME * st);
43    
44    
45    #define OPENPGP_APPID "D276000124"
46    
47    /* Possible values for the sex field. */
48    static const char *sex[] = {"Male", "Female", "Undefined", NULL};
49    
50    /* Predefined languages. */
51    static const char *lang[] = {"Undefined", "cs", "de", "en", "es", "fr", "hu",
52                                  "it", "nl", "pt", "ro", "ru", "zh", "at",
53                                  NULL};
54    
55    /* PIN callback context. */
56    static pin_cb_ctx_s pincb;
57    
58    /* Attribute table. */
59    struct {
60        int ctlid;
61        const char *err;
62    } attr_tab[] = {
63        {IDC_CEDIT_AID,    ""},
64        {IDC_CEDIT_VENDOR, "No Vendor"},
65        {IDC_CEDIT_VERSION,"No Version"},
66        {IDC_CEDIT_SERIAL, "No Serial-No"},
67        {IDC_CEDIT_NAME,   "No Name"},
68        {IDC_CEDIT_NAME2,  "No Surname"},
69        {IDC_CEDIT_KEYURL, "No Key-URL"},
70        {IDC_CEDIT_LOGIN,  "No Login name"},    
71        {0},
72    };
73    
74    
75    
76    /* Return all card attributes from @card. @n contains
77       the number of items which were returned. */
78    char**
79    card_get_items (gpg_card_t card, int *n)
80    {
81        static char printver[16];
82        char **p;
83    
84        *n= 8;
85        p = (char **)calloc (*n+1, sizeof (char*));
86        if (!p)
87            BUG (0);
88        _snprintf (printver, sizeof (printver)-1, "%d.%d",
89                    card->ver[0], card->ver[1]);
90        p[0] = card->aid;
91        p[1] = card->vendor;
92        p[2] = printver;
93        p[3] = card->serial;
94        p[4] = card->givenname;
95        p[5] = card->surname;
96        p[6] = card->url;
97        p[7] = card->login;
98        return p;
99    }
100    
101    
102    static int
103    idx_from_lang (const char *_lang)
104    {
105        const char *s;
106        int i;
107    
108        if (!_lang)
109            return 0;
110        for (i=0; (s = lang[i]); i++) {
111            if (!strcmp (_lang, s))
112                return i;
113        }
114        return 0;
115    }
116    
117    
118    static GpgCardEdit*
119    create_GpgCardEdit (void)
120    {
121        GpgCardEdit *ce;
122    
123        ce = new GpgCardEdit ();
124        if (!ce)
125            BUG (0);
126        return ce;
127    }
128    
129    
130    /* Check if there is a card in the reader and analyze the
131       returned information.
132       Return value: card context or NULL on error. */
133    gpg_card_t
134    gpg_card_load (void)
135    {
136        gpgme_error_t err;
137        GpgCardEdit *ce;
138        gpg_card_t card = NULL;
139        struct card_cb_s cb = {0};
140        
141        ce = create_GpgCardEdit ();
142        memset (&cb, 0, sizeof (cb));
143        ce->setCallback (card_callback, &cb);
144        err = ce->getCardStatus (&card);
145        if (err) {
146            msg_box (NULL, gpgme_strerror (err), _("Card Manager"), MB_ERR);
147            goto leave;
148        }
149    
150        if (!card->aid ||
151            strncmp (card->aid, OPENPGP_APPID, strlen (OPENPGP_APPID))) {
152            msg_box (NULL, winpt_strerror (WPTERR_NOPGPCARD), "WinPT", MB_ERR);
153            gpg_card_release (card);
154            card = NULL;
155        }
156        else {
157            struct winpt_key_s key;
158    
159            memset (&key, 0, sizeof (key));
160            winpt_get_pubkey (card->fpr[1]+32, &key);
161            if (key.ext) {
162                key.ext->card_type = m_strdup (card->card_type);
163                /* memory will be released in gpg_keycache_release (). */
164            }
165        }
166    
167    leave:
168        delete ce;
169        return card;
170    }
171    
172    
173    /* Print human friendly fingerprint to control @id in the
174       dialog @dlg. @fpr contains the raw fingerprint. */
175    static void
176    print_fpr (HWND dlg, int id, const char * fpr)
177    {
178        char buf[128], dig[2];    
179        size_t i, c;
180    
181        if (!fpr)
182            strcpy (buf, _("No Fingerprint"));
183        else {
184            memset (buf, 0, sizeof (buf));
185            for (i=0, c=0; i < strlen (fpr); i++) {
186                dig[0] = fpr[i]; dig[1] = 0;
187                strcat (buf, dig);
188                if (++c == 4) {
189                    strcat (buf, " ");
190                    c=0;
191                }
192            }
193        }
194        SetDlgItemText (dlg, id, buf);
195    }
196    
197    
198    /* Fill in all card information from @card. into the corresponding
199       dialog item fields in the dialog @dlg.
200       Return value: 0 on success. */
201    static int
202    card_status (HWND dlg, gpg_card_t card)
203    {
204        static int fprbuf[] = {IDC_CEDIT_FPR1, IDC_CEDIT_FPR2, IDC_CEDIT_FPR3, 0};
205        static int fprtime[] = {IDC_CEDIT_SIG_FPRTIME, IDC_CEDIT_DEC_FPRTIME,
206                                IDC_CEDIT_AUTH_FPRTIME, 0};
207        const char *s;
208        char **attrs;
209        char cardinf[128];
210        int idx=0, n=0;
211    
212        if (!card->aid) {
213            msg_box (dlg, _("No OpenPGP smart card detected."), "WinPT", MB_ERR);
214            return -1;
215        }
216        SetDlgItemText (dlg, IDC_CEDIT_AID, card->aid);
217        SetDlgItemInt (dlg, IDC_CEDIT_SIGCOUNT, card->sig_count, TRUE);
218    
219        for (idx=0; fprbuf[idx]; idx++) {
220            print_fpr (dlg, fprbuf[idx], card->fpr[idx]);
221            s = card->fpr_created_str[idx];
222            if (!s) /* no keys on the card. */
223                s = "";
224            SetDlgItemText (dlg, fprtime[idx], s);
225        }
226    
227        attrs = card_get_items (card, &n);
228        for (idx=1; attr_tab[idx].ctlid; idx++) {
229            s = attrs[idx];
230            SetDlgItemText (dlg, attr_tab[idx].ctlid,
231                            s && *s? s : attr_tab[idx].err);
232        }
233        safe_free (attrs);
234    
235        idx = idx_from_lang (card->lang);    
236        SendDlgItemMessage (dlg, IDC_CEDIT_LANG, CB_SETCURSEL, (WPARAM)idx, 0);
237    
238        switch (card->sex) {
239        case 'm': idx=0; break;
240        case 'f': idx=1; break;
241        default :
242        case 'u': idx=2; break;
243        }
244        SendDlgItemMessage (dlg, IDC_CEDIT_SEX, CB_SETCURSEL, (WPARAM)idx, 0);
245    
246        s = card->serial;
247        while (s && *s == '0') s++;
248        _snprintf (cardinf, sizeof (cardinf)-1,
249                   "Card Edit - %s serial no. %s version %d.%d",
250                   card->card_type, s, card->ver[0], card->ver[1]);
251        SetWindowText (dlg, cardinf);
252    
253        return 0;
254    }
255    
256    
257    /* Initialize the enum combox boxes in dialog @dlg. */
258    static void
259    prepare_dialog (HWND dlg)
260    {
261        const char * s;
262        int i;
263    
264        for (i=0; (s = sex[i]); i++)
265            SendDlgItemMessage (dlg, IDC_CEDIT_SEX, CB_ADDSTRING, 0, (LPARAM) s);
266        SendDlgItemMessage (dlg, IDC_CEDIT_SEX, CB_SETCURSEL, 0, 0);
267        for (i=0; (s = lang[i]); i++)
268            SendDlgItemMessage (dlg, IDC_CEDIT_LANG, CB_ADDSTRING, 0, (LPARAM)s);
269        SendDlgItemMessage (dlg, IDC_CEDIT_LANG, CB_SETCURSEL, 0, 0);
270    }
271    
272    
273    /* Return 0 if the given string @str has the proper format. */
274    static int
275    check_string (const char *str, int flags)
276    {
277        size_t i;
278    
279        for (i=0; i < strlen (str); i++) {
280            if (flags & 0x02 && !isalpha (str[i]))
281                return -1;
282        }
283        return 0;
284    }
285    
286    
287    static int
288    do_proc_card_cmds (HWND dlg, struct pin_cb_ctx_s *cb, gpg_card_t card)
289    {
290        static struct {
291            int id;
292            int cmd;
293            int us_ascii;
294            int changed;
295        } idctl[] = {
296            {IDC_CEDIT_NAME,  GPG_EDITCARD_NAME,  1,  0},
297            {IDC_CEDIT_LANG2, GPG_EDITCARD_LANG,  1,  0},
298            {IDC_CEDIT_SEX2,  GPG_EDITCARD_SEX,   1|1,0},
299            {IDC_CEDIT_KEYURL,GPG_EDITCARD_KEYURL,1|4,0},
300            {IDC_CEDIT_LOGIN, GPG_EDITCARD_LOGIN, 1,  0},
301            {0}
302        };    
303        gpgme_error_t err;
304        GpgCardEdit *ce;
305        char buf[256], tmp[128];
306        int errc=0, use_arg2 = 0;
307        int i, id, n=0;
308    
309        /* XXX rewrite the entire function */
310        for( i=0; idctl[i].id; i++ ) /* reset */
311            idctl[i].changed = 0;
312        
313        if( SendMessage( GetDlgItem( dlg, IDC_CEDIT_LANG2 ), WM_GETTEXTLENGTH, 0, 0 ) ) {
314            idctl[1].changed = 1;
315            n++;
316        }
317        if( SendMessage( GetDlgItem( dlg, IDC_CEDIT_SEX2 ), WM_GETTEXTLENGTH, 0, 0 ) ) {
318            idctl[2].changed = 1;
319            n++;
320        }
321        
322        if( SendDlgItemMessage( dlg, IDC_CEDIT_NAME2, EM_GETMODIFY, 0, 0 ) ) {
323            idctl[0].changed = 1;
324            n++;
325        }
326        for( i=0; (id = idctl[i].id); i++ ) {
327            if( SendDlgItemMessage( dlg, id, EM_GETMODIFY, 0, 0 ) ) {
328                idctl[i].changed = 1;
329                n++;
330            }
331        }
332        if (!cb || !card) /* just return the changed elements */
333            return n;
334        if (!n)
335            return 0;
336        if (!cb->apin) {
337            msg_box (dlg, _("No PINs found."), _("Card Edit"), MB_ERR);
338            return 0;
339        }
340        
341        ce = create_GpgCardEdit ();
342        ce->setAdminPIN (cb->apin);
343        for( i=0; idctl[i].id; i++ ) {
344            if( idctl[i].changed ) {
345                GetDlgItemText( dlg, idctl[i].id, buf, sizeof (buf)-1 );
346                if (idctl[i].us_ascii && is_8bit_string (buf)) {
347                    msg_box (dlg, _("Only plain ASCII is currently allowed."),
348                             _("Card Edit"), MB_ERR);
349                    errc--; continue;
350                }
351                if( (idctl[i].us_ascii & 2) && check_string( buf, 2 ) ) {
352                    msg_box( dlg, _("Only alphabetic characters are allowed."),
353                             _("Card Edit"), MB_ERR );
354                    errc--; continue;
355                }
356                if ((idctl[i].us_ascii & 4) &&
357                    (!strchr (buf, ':') || !strstr (buf, "//"))) {
358                    /* XXX: better URL check. */
359                    msg_box (dlg, _("Invalid URL."), _("Card Edit"), MB_ERR);
360                    errc--; continue;
361                }
362                if( idctl[i].cmd == GPG_EDITCARD_NAME ) {
363                    /* The "name" command actually needs two fields */
364                    GetDlgItemText( dlg, IDC_CEDIT_NAME2, tmp, sizeof tmp-1 );
365                    use_arg2 = 1;
366                }
367                else
368                    use_arg2 = 0;
369                err = ce->doCmd (idctl[i].cmd, buf, use_arg2? tmp : NULL);
370                if (err) {
371                    log_box (_("Card Edit"), MB_ERR,
372                             _("Could not modify card attribute: %s"),
373                             gpgme_strerror (err));
374                    errc--;
375                    /* If no card is inserted, we leave the loop. */
376                    if (gpgme_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
377                        break;
378                }
379            }
380        }
381        if (!errc) {
382            /* if the operation(s) succeeded, reset the modify flag for each control */
383            for( i = 0; idctl[i].id; i++ )
384                SendDlgItemMessage( dlg, idctl[i].id, EM_SETMODIFY, (WPARAM)(UINT)FALSE, 0 );
385            msg_box( dlg, _("Card attribute changed."), _("Card Edit"), MB_OK );
386            SetDlgItemText( dlg, IDC_CEDIT_LANG2, "" );
387            SetDlgItemText( dlg, IDC_CEDIT_SEX2, "" );
388        }
389        delete ce;
390        return errc;
391    }
392    
393    
394    /* Cleanup pin callback @ctx. */
395    void
396    free_pincb (struct pin_cb_ctx_s *ctx)
397    {
398        if (!ctx)
399            return;
400        free_if_alloc (ctx->info_text);
401        sfree_if_alloc (ctx->upin);
402        sfree_if_alloc (ctx->apin);
403    }
404    
405    
406    /* Request a PIN from the user. @which decided if the
407       normal PIN or the admin PIN will be requested.
408       @card is used to show some information to the user.
409       @pincb is the actuall callback context.
410       Return value: 0 on success. */
411    static int
412    do_askpin (HWND dlg, int which, gpg_card_t card,
413               struct pin_cb_ctx_s *cb)
414    {
415        const char *s;
416        char *p;
417    
418        if( (which == CARD_ADMIN_PIN && cb->apin) ||
419            (which == CARD_USER_PIN && cb->upin) )
420            return 0;
421        
422        if (which == CARD_ADMIN_PIN)
423            s = _("Please enter the 'Admin PIN'");
424        else if (which == CARD_USER_PIN)
425            s = _("Please enter the 'User PIN'");
426        else
427            s = _("Please enter the PIN");
428        cb->which = which;
429        free_if_alloc (cb->info_text);
430        if (card) {
431            StringBuffer buf;
432    
433            buf = s;
434            buf = buf + "\nName: " + (card->givenname?card->givenname: "No");
435            buf = buf + " " + (card->surname?card->surname : "Name");
436            buf = buf + "\nSerial-No:" + card->serial;
437            p = buf.getBufferCopy ();
438        }
439        else
440            p = cb->info_text = m_strdup (s);
441        DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_PIN, dlg,
442                        pin_cb_dlg_proc, (LPARAM)cb);
443        if (!cb->apin && !cb->upin) {
444            safe_free (cb->info_text);
445            return -1;
446        }
447        return 0;
448    }
449    
450    
451    /* Dialog box procedure for card edit. */
452    BOOL CALLBACK
453    card_edit_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
454    {
455        static gpg_card_t card;    
456        char tmp[128];
457        size_t n=0;
458    
459        switch (msg) {
460        case WM_INITDIALOG:
461            card = (gpg_card_t)lparam;
462            if (!card)
463                BUG (0);
464            prepare_dialog (dlg);
465            if (card_status (dlg, card ))
466                EndDialog (dlg, TRUE);
467            SetDlgItemText (dlg, IDC_CEDIT_NAMEINF, _("&Name"));
468            SetDlgItemText (dlg, IDC_CEDIT_LANGINF, _("&Language"));
469            SetDlgItemText (dlg, IDC_CEDIT_KURLINF, _("&Key-URL"));
470            SetDlgItemText (dlg, IDC_CEDIT_LOGINF, _("&Login"));
471            SetDlgItemText (dlg, IDC_CEDIT_SEXINF, _("&Sex"));
472            SetDlgItemText (dlg, IDOK, _("&OK"));
473            SetDlgItemText (dlg, IDCANCEL, _("&Exit"));
474            SetDlgItemText (dlg, IDC_CEDIT_NEWKEYS, _("&New keys"));
475            SetDlgItemText (dlg, IDC_CEDIT_CHPIN, _("Change &PIN"));
476            center_window (dlg, NULL);
477            SetForegroundWindow (dlg);
478            return TRUE;
479    
480        case WM_DESTROY:
481            free_pincb (&pincb);
482            memset (&pincb, 0, sizeof pincb);
483            break;
484    
485        case WM_COMMAND:
486            switch (HIWORD (wparam)) {
487            case CBN_KILLFOCUS:
488            case CBN_EDITCHANGE:
489            case CBN_EDITUPDATE:
490                int ctlid = GetDlgCtrlID ((HWND)lparam);
491                int dstid = 0;
492    
493                switch (ctlid) {
494                case IDC_CEDIT_LANG: dstid = IDC_CEDIT_LANG2; break;
495                case IDC_CEDIT_SEX:  dstid = IDC_CEDIT_SEX2; break;
496                }      
497                GetDlgItemText (dlg, ctlid, tmp, sizeof (tmp)-1);
498                SetDlgItemText (dlg, dstid, tmp);
499                break;
500            }
501            switch (LOWORD (wparam)) {
502            case IDC_CEDIT_CHPIN:
503                DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_CARD_CHPIN, dlg,
504                                card_changepin_dlg_proc, 0);
505                break;
506    
507            case IDC_CEDIT_NEWKEYS:
508                if (item_get_text_length (dlg, IDC_CEDIT_FPR1) > 0) {
509                    int id = msg_box (dlg,
510                        _("This operation will override the keys on the card.\n"
511                          "Continue?"), _("Card Edit"), MB_WARN|MB_YESNO);
512                    if (id == IDNO)
513                        return TRUE;
514                }
515                DialogBoxParam (glob_hinst, (LPCTSTR)IDD_WINPT_CARD_KEYGEN,
516                                dlg, card_keygen_dlg_proc, 0);
517                break;
518    
519            case IDOK:
520                n = do_proc_card_cmds (dlg, NULL, NULL);
521                if (n) {
522                    if (do_askpin (dlg, CARD_ADMIN_PIN, card, &pincb))
523                        EndDialog (dlg, FALSE);
524                }
525                do_proc_card_cmds (dlg, &pincb, card);
526                free_pincb (&pincb);
527                if (!n)
528                    EndDialog (dlg, TRUE);
529                break;
530    
531            case IDCANCEL:
532                EndDialog (dlg, FALSE);
533                break;
534            }
535            break;
536        }
537    
538        return FALSE;
539    }
540    
541    
542    static int /* fixme: works only roughly */
543    calc_days (int y2, int m2, int d2,
544               int y1, int m1, int d1)
545    
546    {
547        int n=0;
548        
549        if ((y2-y1) > 0)
550            n += (y2-y1)*365;
551        if ((m2-m1) > 0)
552            n += (m2-m1)*30;
553        if ((d2-d1) > 0)
554            n += (d2-d1);
555        else if ((d2-d1) < 0)
556            n -= (d1-d2);
557        return n;
558    }
559    
560    
561    /* Dialog box procedure for the key generation on cards. */
562    BOOL CALLBACK
563    card_keygen_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
564    {
565        gpgme_error_t err;
566        GpgCardEdit *ce;
567        char name[128], email[128], comment[128];
568        char pass[128];
569        int card_flags = GPG_CARDFLAG_NONE;
570        int expires=0, valid=0;
571        DWORD n;
572    
573        switch (msg) {
574        case WM_INITDIALOG:
575            CheckDlgButton (dlg, IDC_CKEYGEN_REPLACE, BST_CHECKED);
576            CheckDlgButton (dlg, IDC_CKEYGEN_NEVER, BST_CHECKED);
577            CheckDlgButton (dlg, IDC_CKEYGEN_BACKUP, BST_CHECKED);
578            EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_VALID), FALSE);
579            SendDlgItemMessage (dlg, IDC_CKEYGEN_ALG, CB_ADDSTRING, 0,
580                                (LPARAM)(const char*)"RSA");
581            SendDlgItemMessage (dlg, IDC_CKEYGEN_ALG, CB_SETCURSEL, 0, 0);
582            SetDlgItemText (dlg, IDC_CKEYGEN_PKINF, _("Pubkey algorithm"));
583            SetDlgItemText (dlg, IDC_CKEYGEN_NAMEINF, _("&Name"));
584            SetDlgItemText (dlg, IDC_CKEYGEN_CMTINF, _("&Comment (optional)"));
585            SetDlgItemText (dlg, IDC_CKEYGEN_EXPDATEINF, _("&Expire date"));
586            SetDlgItemText (dlg, IDC_CKEYGEN_PWDINF, _("Off-card passphrase"));
587            SetDlgItemText (dlg, IDC_CKEYGEN_NEVER, _("&Never"));
588            SetDlgItemText (dlg, IDC_CKEYGEN_MAILINF, _("Email &address"));
589            SetDlgItemText (dlg, IDC_CKEYGEN_REPLACE, _("Overwrite old keys on the card"));
590            SetDlgItemText (dlg, IDC_CKEYGEN_BACKUP, _("Make off-card backup of encryption key"));
591            SetWindowText (dlg, _("Card Key Generation"));
592            center_window (dlg, NULL);
593            SetForegroundWindow (dlg);
594            SetFocus (GetDlgItem (dlg, IDC_CKEYGEN_NAME));
595            return FALSE;
596    
597        case WM_COMMAND:
598            if (HIWORD (wparam) == BN_CLICKED &&
599                (LOWORD (wparam) == IDC_CKEYGEN_BACKUP) ||
600                 LOWORD (wparam) == IDC_CKEYGEN_NEVER) {
601                EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_VALID),
602                              IsDlgButtonChecked (dlg, IDC_CKEYGEN_NEVER)? 0: 1);
603                EnableWindow (GetDlgItem (dlg, IDC_CKEYGEN_PASS),
604                              IsDlgButtonChecked (dlg, IDC_CKEYGEN_BACKUP)? 1 : 0);
605                return TRUE;
606            }      
607    
608            switch (LOWORD (wparam)) {
609            case IDOK:
610                n = item_get_text_length (dlg, IDC_CKEYGEN_NAME);
611                if (!n) {
612                    msg_box (dlg, _("Please enter your name."), _("Card Edit"), MB_ERR);
613                    return TRUE;
614                }
615                if (n < 5) {
616                    msg_box (dlg, _("Name must be at least 5 characters long."),
617                             _("Card Edit"), MB_INFO);
618                    return TRUE;
619                }
620                n = item_get_text_length (dlg, IDC_CKEYGEN_EMAIL);
621                if (!n) {
622                    msg_box (dlg, _("Please enter your e-mail address."),
623                             _("Card Edit"), MB_ERR);
624                    return TRUE;
625                }
626                GetDlgItemText (dlg, IDC_CKEYGEN_NAME, name, sizeof (name)-1);
627                GetDlgItemText (dlg, IDC_CKEYGEN_EMAIL, email, sizeof (email)-1);
628                if (check_email_address (email) || n < 3) {
629                    msg_box (dlg, _("Please enter a valid e-mail address."),
630                             _("Card Edit"), MB_ERR);
631                    return TRUE;
632                }
633                n = GetDlgItemText (dlg, IDC_CKEYGEN_PASS, pass, sizeof (pass)-1);
634                if (!n && IsDlgButtonChecked (dlg, IDC_CKEYGEN_BACKUP)) {
635                    msg_box (dlg, _("Please enter an off-card passphrase."),
636                             _("Card Edit"), MB_ERR);
637                    return TRUE;
638                }
639                n = item_get_text_length (dlg, IDC_CKEYGEN_COMMENT);
640                if (n > 0)
641                    GetDlgItemText (dlg, IDC_CKEYGEN_COMMENT, comment, sizeof (comment)-1);
642                if (is_8bit_string (name) || n > 0 && is_8bit_string (comment)) {
643                    msg_box (dlg, _("Please use plain ASCII charset for the fields."),
644                             _("Card Edit"), MB_INFO);
645                    return TRUE;
646                }
647                memset (&pincb, 0, sizeof (pincb));
648                if (do_askpin (dlg, CARD_ADMIN_PIN, NULL, &pincb)) {
649                    free_pincb (&pincb);
650                    return TRUE;
651                }
652                if (do_askpin (dlg, CARD_USER_PIN, NULL, &pincb)) {
653                    free_pincb (&pincb);
654                    return TRUE;
655                }
656                ce = create_GpgCardEdit ();
657    
658                expires = !IsDlgButtonChecked (dlg, IDC_CKEYGEN_NEVER);
659                if (expires) {
660                    SYSTEMTIME st, ct;
661    
662                    DateTime_GetSystemtime (GetDlgItem (dlg, IDC_CKEYGEN_VALID), &st);
663                    if (!keygen_check_date (&st)) {
664                        msg_box (dlg, _("The date you have chosen has already passed."),
665                                 _("Card Edit"), MB_ERR);
666                        free_pincb (&pincb);
667                        delete ce;
668                        return TRUE;
669                    }
670                    GetSystemTime (&ct);
671                    /* XXX this is not very precise */
672                    valid = calc_days (st.wYear, st.wMonth, st.wDay,
673                                       ct.wYear, ct.wMonth, ct.wDay);
674                }
675                if (IsDlgButtonChecked (dlg, IDC_CKEYGEN_REPLACE))
676                    card_flags |= GPG_CARDFLAG_REPLACE;
677                if (IsDlgButtonChecked (dlg, IDC_CKEYGEN_BACKUP))
678                    card_flags |= GPG_CARDFLAG_BAKENC;
679                ce->setKeygenPassphrase (pass);
680                ce->setPIN (pincb.upin);
681                ce->setAdminPIN (pincb.apin);
682                
683                SetCursor (LoadCursor (NULL, IDC_WAIT));
684                err = ce->genKey (card_flags, name, email, n? comment: NULL,
685                                  expires? valid : 0, NULL);
686                SetCursor (LoadCursor (NULL, IDC_ARROW));
687                
688                if (gpgme_err_code (err) == GPG_ERR_CANCELED)
689                    msg_box (dlg, _("Operation was canceled. It seems that there are "
690                                    "existing\nkeys on the cards. You need to mark the "
691                                    "'Overwrite' flag."), _("Card Edit"), MB_INFO);
692                else
693                if (err)
694                    msg_box (dlg, "The operation does not succeed.\n"
695                                  "Please make sure you entered the right PIN's."
696                                  , _("Card Edit"), MB_ERR);
697                else
698                    msg_box (dlg, _("Keys successfully created."),
699                             _("Card Edit"), MB_OK);
700                wipememory (pass, sizeof (pass));
701                free_pincb (&pincb);
702                delete ce;
703                EndDialog (dlg, TRUE);
704                return TRUE;
705    
706            case IDCANCEL:
707                EndDialog (dlg, FALSE);
708                return TRUE;
709            }
710            break;
711        }
712        return FALSE;
713    }
714    
715    
716    /* Check if the given pinlen is valid.
717       @which decided what PIN will be used.
718       @pinlen is the pin length entered by the user.
719       Return value: 0 on success. */
720    static int
721    check_pin_len (int which, int flag, int pinlen)
722    {
723        if (!pinlen) {
724            if (flag)
725                msg_box (NULL, _("Please enter the old card PIN."), _("Card Edit"), MB_ERR);
726            else
727                msg_box (NULL, _("Please enter the new card PIN."), _("Card Edit"), MB_ERR);
728            return -1;
729        }
730        if (which == CARD_ADMIN_PIN
731            && pinlen < 8) {
732            msg_box (NULL, _("Admin PIN must be at least 8 characters."), _("Card Edit"), MB_ERR);
733            return -1;
734        }
735        if (which == CARD_USER_PIN
736            && pinlen < 6) {
737            msg_box (NULL, _("PIN must be at least 6 characters."), _("Card Edit"), MB_ERR);
738            return -1;
739        }
740        return 0;
741    }
742    
743    /* Dialog box procedure to change the PIN. */
744    BOOL CALLBACK
745    card_changepin_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
746    {    
747        static int hide = 1;
748        gpgme_error_t err;
749        GpgCardEdit *ce;    
750        char pold[128], pnew[128], pnew2[128];
751        int which = 0;
752        DWORD n;
753    
754        switch( msg ) {
755        case WM_INITDIALOG:
756            hide = 1;
757            CheckDlgButton (dlg, IDC_CHPIN_HIDE, BST_CHECKED);
758            center_window (dlg, NULL);
759            CheckDlgButton (dlg, IDC_CHPIN_ISWORK, BST_CHECKED);
760            SetWindowText (dlg, _("Change Card PIN"));
761            SetForegroundWindow (dlg);
762            break;
763    
764        case WM_COMMAND:
765            if (HIWORD (wparam) == BN_CLICKED && LOWORD (wparam) == IDC_CHPIN_HIDE) {          
766                HWND hwnd;
767                hide ^= 1;
768                hwnd = GetDlgItem (dlg, IDC_CHPIN_OLDPIN);
769                SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
770                SetFocus (hwnd);
771                hwnd = GetDlgItem (dlg, IDC_CHPIN_NEWPIN);
772                SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
773                SetFocus (hwnd);
774                hwnd = GetDlgItem (dlg, IDC_CHPIN_NEWPIN2);
775                SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
776                SetFocus (hwnd);
777            }
778            switch (LOWORD (wparam)) {
779            case IDOK:
780                if (IsDlgButtonChecked (dlg, IDC_CHPIN_ISADMIN))
781                    which = CARD_ADMIN_PIN;
782                else if (IsDlgButtonChecked (dlg, IDC_CHPIN_ISWORK))
783                    which = CARD_USER_PIN;
784    
785                n = item_get_text_length (dlg, IDC_CHPIN_OLDPIN);
786                if (check_pin_len (which, 1, n))
787                    return TRUE;
788                n = item_get_text_length (dlg, IDC_CHPIN_NEWPIN);
789                if (check_pin_len (which, 0, n))
790                    return TRUE;
791                n = item_get_text_length (dlg, IDC_CHPIN_NEWPIN2);
792                if (check_pin_len (which, 0, n))
793                    return TRUE;
794                GetDlgItemText (dlg, IDC_CHPIN_OLDPIN, pold, sizeof (pold)-1);
795                GetDlgItemText (dlg, IDC_CHPIN_NEWPIN, pnew, sizeof (pnew)-1);
796                GetDlgItemText (dlg, IDC_CHPIN_NEWPIN2, pnew2, sizeof (pnew2)-1);
797                if (strcmp (pnew, pnew2)) {
798                    wipememory (pnew2, sizeof (pnew2));
799                    wipememory (pnew, sizeof (pnew));
800                    msg_box (dlg, _("Passphrases do not match. Please try again."),
801                             _("Card Edit"), MB_ERR);
802                    return TRUE;
803                }
804    
805                ce = create_GpgCardEdit ();
806                if (which == CARD_ADMIN_PIN)
807                    ce->setAdminPIN (pold);
808                else
809                    ce->setPIN (pold);
810                ce->setNewPIN (pnew);
811                err = ce->changePIN (which == CARD_ADMIN_PIN? GPG_EDITCARD_CHAPIN :
812                                     GPG_EDITCARD_CHUPIN);
813                if (err)
814                    msg_box (dlg, gpgme_strerror (err), _("Card Edit"), MB_ERR);
815                else {
816                    msg_box (dlg, _("PIN successfully changed."),
817                             _("Card Edit"), MB_OK);
818                    SetDlgItemText (dlg, IDC_CHPIN_NEWPIN, "");
819                    SetDlgItemText (dlg, IDC_CHPIN_OLDPIN, "");
820                    SetDlgItemText (dlg, IDC_CHPIN_NEWPIN2, "");
821                }
822                wipememory (pold, sizeof (pold));
823                wipememory (pnew, sizeof (pnew));
824                wipememory (pnew2, sizeof (pnew2));
825                delete ce;
826                break;
827    
828            case IDCANCEL:
829                SetDlgItemText (dlg, IDC_CHPIN_NEWPIN, "");
830                SetDlgItemText (dlg, IDC_CHPIN_OLDPIN, "");
831                SetDlgItemText (dlg, IDC_CHPIN_NEWPIN2, "");
832                EndDialog (dlg, FALSE);
833                break;
834            }
835            break;
836        }
837    
838        return FALSE;
839    }

Legend:
Removed from v.2  
changed lines
  Added in v.278

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26