Fix bug 894.
[gnupg.git] / g10 / passphrase.c
index b156d8f..8703580 100644 (file)
@@ -1,12 +1,12 @@
 /* passphrase.c -  Get a passphrase
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005, 2006 Free Software Foundation, Inc.
+ *               2005, 2006, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG 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
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -88,12 +86,12 @@ hash_passphrase ( DEK *dek, char *pw, STRING2KEY *s2k, int create )
             {
               gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM);
               if ( s2k->mode == 3 )
-                s2k->count = 96; /* 65536 iterations. */
+                s2k->count = opt.s2k_count;
            }
 
           if ( s2k->mode == 3 )
             {
-              count = (16ul + (s2k->count & 15)) << ((s2k->count >> 4) + 6);
+              count = S2K_DECODE_COUNT(s2k->count);
               if ( count < len2 )
                 count = len2;
            }
@@ -259,7 +257,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid,
   PKT_public_key *pk = xmalloc_clear( sizeof *pk );
   byte fpr[MAX_FINGERPRINT_LEN];
   int have_fpr = 0;
-  char *orig_codeset = NULL;
+  char *orig_codeset;
   char *my_prompt;
   char hexfprbuf[20*2+1];
   const char *my_cacheid;
@@ -279,20 +277,7 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid,
       pk = NULL; /* oops: no key for some reason */
     }
   
-#ifdef ENABLE_NLS
-  /* The Assuan agent protocol requires us to transmit utf-8 strings */
-  orig_codeset = bind_textdomain_codeset (PACKAGE, NULL);
-#ifdef HAVE_LANGINFO_CODESET
-  if (!orig_codeset)
-    orig_codeset = nl_langinfo (CODESET);
-#endif
-  if (orig_codeset)
-    { /* We only switch when we are able to restore the codeset later. */
-      orig_codeset = xstrdup (orig_codeset);
-      if (!bind_textdomain_codeset (PACKAGE, "utf-8"))
-        orig_codeset = NULL; 
-    }
-#endif
+  orig_codeset = i18n_switchto_utf8 ();
 
   if (custom_description)
     atext = native_to_utf8 (custom_description);
@@ -321,10 +306,11 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid,
 
 #undef KEYIDSTRING
 
-#define PROMPTSTRING _("You need a passphrase to unlock the secret" \
-                      " key for user:\n" \
+#define PROMPTSTRING _("Please enter the passphrase to unlock the" \
+                      " secret key for the OpenPGP certificate:\n" \
                       "\"%.*s\"\n" \
-                      "%u-bit %s key, ID %s, created %s%s\n" )
+                      "%u-bit %s key, ID %s,\n" \
+                       "created %s%s.\n" )
 
       atext = xmalloc ( 100 + strlen (PROMPTSTRING)  
                         + uidlen + 15 + strlen(algo_name) + keystrlen()
@@ -368,6 +354,9 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid,
   xfree (my_prompt);
   xfree (atext); atext = NULL;
 
+  i18n_switchback (orig_codeset);
+
+
   if (!rc)
     ;
   else if ( gpg_err_code (rc) == GPG_ERR_CANCELED )
@@ -377,15 +366,19 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid,
         *canceled = 1;
     }
   else 
-    log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
-      
-#ifdef ENABLE_NLS
-  if (orig_codeset)
     {
-      bind_textdomain_codeset (PACKAGE, orig_codeset);
-      xfree (orig_codeset);
+      log_error (_("problem with the agent: %s\n"), gpg_strerror (rc));
+      /* Due to limitations in the API of the upper layers they
+         consider an error as no passphrase entered.  This works in
+         most cases but not during key creation where this should
+         definitely not happen and let it continue without requiring a
+         passphrase.  Given that now all the upper layers handle a
+         cancel correctly, we simply set the cancel flag now for all
+         errors from the agent.  */ 
+      if (canceled)
+        *canceled = 1;
     }
-#endif
+
   if (pk)
     free_public_key( pk );
   if (rc)
@@ -456,7 +449,8 @@ ask_passphrase (const char *description,
     {
       if (strchr (description, '%'))
         {
-          char *tmp = unescape_percent_string (description);
+          char *tmp = unescape_percent_string
+            ((const unsigned char*)description);
           tty_printf ("\n%s\n", tmp);
           xfree (tmp);
         }
@@ -482,7 +476,9 @@ ask_passphrase (const char *description,
 
 
 /* Return a new DEK object Using the string-to-key sepcifier S2K.  Use
- * KEYID and PUBKEY_ALGO to prompt the user.
+   KEYID and PUBKEY_ALGO to prompt the user.  Returns NULL is the user
+   selected to cancel the passphrase entry and if CANCELED is not
+   NULL, sets it to true.
 
    MODE 0:  Allow cached passphrase
         1:  Ignore cached passphrase 
@@ -496,9 +492,11 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
   char *pw = NULL;
   DEK *dek;
   STRING2KEY help_s2k;
-  
-  if (canceled)
-    *canceled = 0;
+  int dummy_canceled;
+
+  if (!canceled)
+    canceled = &dummy_canceled;
+  *canceled = 0;
   
   if ( !s2k )
     {
@@ -600,7 +598,7 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
     }
   else if ( have_static_passphrase () ) 
     {
-      /* Return the passphrase we have store in FD_PASSWD. */
+      /* Return the passphrase we have stored in FD_PASSWD. */
       pw = xmalloc_secure ( strlen(fd_passwd)+1 );
       strcpy ( pw, fd_passwd );
     }
@@ -609,21 +607,38 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
       /* Divert to the gpg-agent. */
       pw = passphrase_get ( keyid, mode == 2? 1: 0, NULL,
                             tryagain_text, NULL, NULL, canceled );
+      if (*canceled)
+        {
+          xfree (pw);
+         write_status( STATUS_MISSING_PASSPHRASE );
+          return NULL;
+        }
       if (!pw)
         pw = xstrdup ("");
       if ( *pw && mode == 2 )
         {
-          char *pw2 = passphrase_get ( keyid, 2, NULL, NULL, NULL,
-                                       NULL, canceled );
-          if (!pw2)
-            pw2 = xstrdup ("");
-          if ( strcmp(pw, pw2) )
-            {
-              xfree(pw2);
-              xfree(pw);
-              return NULL;
-            }
-          xfree(pw2);
+         int i;
+         for(i=0;i<opt.passwd_repeat;i++)
+           {
+             char *pw2 = passphrase_get ( keyid, 2, NULL, NULL, NULL,
+                                          NULL, canceled );
+              if (*canceled)
+                {
+                  xfree (pw);
+                  xfree (pw2);
+                 write_status( STATUS_MISSING_PASSPHRASE );
+                  return NULL;
+                }
+             if (!pw2)
+               pw2 = xstrdup ("");
+             if ( strcmp(pw, pw2) )
+               {
+                 xfree(pw2);
+                 xfree(pw);
+                 return NULL;
+               }
+             xfree(pw2);
+           }
        }
     }