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

Legend:
Removed from v.5  
changed lines
  Added in v.48

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26