Ask for the keysize when generating a new card key.
[gnupg.git] / g10 / plaintext.c
index 92187a5..027fe99 100644 (file)
@@ -1,12 +1,12 @@
 /* plaintext.c -  process plaintext packets
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 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>
@@ -31,8 +29,8 @@
 #include <fcntl.h> /* for setmode() */
 #endif
 
+#include "gpg.h"
 #include "util.h"
-#include "memory.h"
 #include "options.h"
 #include "packet.h"
 #include "ttyio.h"
@@ -69,6 +67,12 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
       {
        char status[50];
 
+        /* Better make sure that stdout has been flushed in case the
+           output will be written to it.  This is to make sure that no
+           not-yet-flushed stuff will be written after the plaintext
+           status message.  */
+        fflush (stdout);
+
        sprintf(status,"%X %lu ",(byte)pt->mode,(ulong)pt->timestamp);
        write_status_text_and_buffer(STATUS_PLAINTEXT,
                                     status,pt->name,pt->namelen,0);
@@ -91,18 +95,17 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
        log_info(_("data not saved; use option \"--output\" to save it\n"));
        nooutput = 1;
     }
-    else if( !opt.use_embedded_filename ) {
+    else if( !opt.flags.use_embedded_filename ) {
        fname = make_outfile_name( iobuf_get_real_fname(pt->buf) );
        if( !fname )
            fname = ask_outfile_name( pt->name, pt->namelen );
        if( !fname ) {
-           rc = G10ERR_CREATE_FILE;
-           goto leave;
+             rc = gpg_error (GPG_ERR_GENERAL); /* Can't create file. */
+             goto leave;
        }
     }
-    else {
-       fname = make_printable_string( pt->name, pt->namelen, 0 );
-    }
+    else
+      fname=utf8_to_native(pt->name,pt->namelen,0);
 
     if( nooutput )
        ;
@@ -119,7 +122,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
             char *tmp = ask_outfile_name (NULL, 0);
             if ( !tmp || !*tmp ) {
                 xfree (tmp);
-                rc = G10ERR_CREATE_FILE;
+                rc = gpg_error (GPG_ERR_GENERAL); /* G10ERR_CREATE_FILE*/
                 goto leave;
             }
             xfree (fname);
@@ -133,13 +136,13 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
     else if (is_secured_filename (fname))
       {
         errno = EPERM;
+       rc = gpg_error_from_syserror ();
        log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
-       rc = G10ERR_CREATE_FILE;
        goto leave;
       }
     else if( !(fp = fopen(fname,"wb")) ) {
+       rc = gpg_error_from_syserror ();
        log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
-       rc = G10ERR_CREATE_FILE;
        goto leave;
     }
 #else /* __riscos__ */
@@ -188,13 +191,13 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
        if( convert ) { /* text mode */
            for( ; pt->len; pt->len-- ) {
                if( (c = iobuf_get(pt->buf)) == -1 ) {
-                   log_error("Problem reading source (%u bytes remaining)\n",
-                             (unsigned)pt->len);
-                   rc = G10ERR_READ_FILE;
-                   goto leave;
+                    rc = gpg_error_from_syserror ();
+                   log_error ("problem reading source (%u bytes remaining)\n",
+                               (unsigned)pt->len);
+                    goto leave;
                }
                if( mfx->md )
-                   md_putc(mfx->md, c );
+                   gcry_md_putc (mfx->md, c );
 #ifndef HAVE_DOSISH_SYSTEM
                if( c == '\r' )  /* convert to native line ending */
                    continue;    /* fixme: this hack might be too simple */
@@ -203,16 +206,19 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                  {
                    if(opt.max_output && (++count)>opt.max_output)
                      {
-                       log_error("Error writing to `%s': %s\n",
-                                 fname,"exceeded --max-output limit\n");
-                       rc = G10ERR_WRITE_FILE;
+                       log_error ("error writing to `%s': %s\n",
+                                   fname,"exceeded --max-output limit\n");
+                       rc = gpg_error (GPG_ERR_TOO_LARGE);
                        goto leave;
                      }
                    else if( putc( c, fp ) == EOF )
                      {
-                       log_error("Error writing to `%s': %s\n",
-                                 fname, strerror(errno) );
-                       rc = G10ERR_WRITE_FILE;
+                        if (ferror (fp))
+                          rc = gpg_error_from_syserror ();
+                        else
+                          rc = gpg_error (GPG_ERR_EOF);
+                       log_error ("error writing to `%s': %s\n",
+                                   fname, strerror(errno) );
                        goto leave;
                      }
                  }
@@ -224,29 +230,29 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                int len = pt->len > 32768 ? 32768 : pt->len;
                len = iobuf_read( pt->buf, buffer, len );
                if( len == -1 ) {
-                   log_error("Problem reading source (%u bytes remaining)\n",
-                             (unsigned)pt->len);
-                   rc = G10ERR_READ_FILE;
+                    rc = gpg_error_from_syserror ();
+                   log_error ("problem reading source (%u bytes remaining)\n",
+                               (unsigned)pt->len);
                    xfree( buffer );
                    goto leave;
                }
                if( mfx->md )
-                   md_write( mfx->md, buffer, len );
+                   gcry_md_write ( mfx->md, buffer, len );
                if( fp )
                  {
                    if(opt.max_output && (count+=len)>opt.max_output)
                      {
-                       log_error("Error writing to `%s': %s\n",
-                                 fname,"exceeded --max-output limit\n");
-                       rc = G10ERR_WRITE_FILE;
+                       log_error ("error writing to `%s': %s\n",
+                                   fname,"exceeded --max-output limit\n");
+                       rc = gpg_error (GPG_ERR_TOO_LARGE);
                        xfree( buffer );
                        goto leave;
                      }
                    else if( fwrite( buffer, 1, len, fp ) != len )
                      {
-                       log_error("Error writing to `%s': %s\n",
-                                 fname, strerror(errno) );
-                       rc = G10ERR_WRITE_FILE;
+                        rc = gpg_error_from_syserror ();
+                       log_error ("error writing to `%s': %s\n",
+                                   fname, strerror(errno) );
                        xfree( buffer );
                        goto leave;
                      }
@@ -260,7 +266,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
        if( convert ) { /* text mode */
            while( (c = iobuf_get(pt->buf)) != -1 ) {
                if( mfx->md )
-                   md_putc(mfx->md, c );
+                   gcry_md_putc (mfx->md, c );
 #ifndef HAVE_DOSISH_SYSTEM
                if( convert && c == '\r' )
                    continue; /* fixme: this hack might be too simple */
@@ -271,14 +277,17 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                      {
                        log_error("Error writing to `%s': %s\n",
                                  fname,"exceeded --max-output limit\n");
-                       rc = G10ERR_WRITE_FILE;
+                       rc = gpg_error (GPG_ERR_TOO_LARGE);
                        goto leave;
                      }
                    else if( putc( c, fp ) == EOF )
                      {
-                       log_error("Error writing to `%s': %s\n",
+                        if ( ferror (fp ) )
+                          rc = gpg_error_from_syserror ();
+                        else
+                          rc = gpg_error (GPG_ERR_EOF);
+                       log_error("error writing to `%s': %s\n",
                                  fname, strerror(errno) );
-                       rc = G10ERR_WRITE_FILE;
                        goto leave;
                      }
                  }
@@ -286,8 +295,9 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
        }
        else { /* binary mode */
            byte *buffer = xmalloc( 32768 );
-           int eof;
-           for( eof=0; !eof; ) {
+           int eof_seen = 0;
+
+           while ( !eof_seen ) {
                /* Why do we check for len < 32768:
                 * If we won't, we would practically read 2 EOFs but
                 * the first one has already popped the block_filter
@@ -298,23 +308,24 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                if( len == -1 )
                    break;
                if( len < 32768 )
-                   eof = 1;
+                   eof_seen = 1;
                if( mfx->md )
-                   md_write( mfx->md, buffer, len );
+                   gcry_md_write ( mfx->md, buffer, len );
                if( fp )
                  {
                    if(opt.max_output && (count+=len)>opt.max_output)
                      {
-                       log_error("Error writing to `%s': %s\n",
+                       log_error("error writing to `%s': %s\n",
                                  fname,"exceeded --max-output limit\n");
-                       rc = G10ERR_WRITE_FILE;
+                       rc = gpg_error (GPG_ERR_TOO_LARGE);
                        xfree( buffer );
                        goto leave;
                      }
                    else if( fwrite( buffer, 1, len, fp ) != len ) {
-                     log_error("Error writing to `%s': %s\n",
+                     rc = (errno? gpg_error_from_syserror ()
+                            : gpg_error (GPG_ERR_INTERNAL));
+                     log_error ("error writing to `%s': %s\n",
                                fname, strerror(errno) );
-                     rc = G10ERR_WRITE_FILE;
                      xfree( buffer );
                      goto leave;
                    }
@@ -332,24 +343,25 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
              {
                if(opt.max_output && (++count)>opt.max_output)
                  {
-                   log_error("Error writing to `%s': %s\n",
+                   log_error ("error writing to `%s': %s\n",
                              fname,"exceeded --max-output limit\n");
-                   rc = G10ERR_WRITE_FILE;
+                    rc = gpg_error (GPG_ERR_TOO_LARGE);
                    goto leave;
                  }
                else if( putc( c, fp ) == EOF )
                  {
-                   log_error("Error writing to `%s': %s\n",
+                    rc = (errno? gpg_error_from_syserror ()
+                          : gpg_error (GPG_ERR_INTERNAL));
+                   log_error ("error writing to `%s': %s\n",
                              fname, strerror(errno) );
-                   rc = G10ERR_WRITE_FILE;
                    goto leave;
                  }
              }
            if( !mfx->md )
                continue;
            if( state == 2 ) {
-               md_putc(mfx->md, '\r' );
-               md_putc(mfx->md, '\n' );
+               gcry_md_putc (mfx->md, '\r' );
+               gcry_md_putc (mfx->md, '\n' );
                state = 0;
            }
            if( !state ) {
@@ -358,18 +370,18 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                else if( c == '\n'  )
                    state = 2;
                else
-                   md_putc(mfx->md, c );
+                   gcry_md_putc(mfx->md, c );
            }
            else if( state == 1 ) {
                if( c == '\n'  )
                    state = 2;
                else {
-                   md_putc(mfx->md, '\r' );
+                   gcry_md_putc(mfx->md, '\r' );
                    if( c == '\r'  )
                        state = 1;
                    else {
                        state = 0;
-                       md_putc(mfx->md, c );
+                       gcry_md_putc(mfx->md, c );
                    }
                }
            }
@@ -378,22 +390,28 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
     }
 
     if( fp && fp != stdout && fclose(fp) ) {
-       log_error("Error closing `%s': %s\n", fname, strerror(errno) );
+        rc = (errno? gpg_error_from_syserror ()
+              : gpg_error (GPG_ERR_INTERNAL));
+       log_error ("error closing `%s': %s\n", fname, strerror(errno) );
        fp = NULL;
-       rc = G10ERR_WRITE_FILE;
        goto leave;
     }
     fp = NULL;
 
   leave:
+    /* Make sure that stdout gets flushed after the plaintext has
+       been handled.  This is for extra security as we do a
+       flush anyway before checking the signature.  */
+    fflush (stdout);
+
     if( fp && fp != stdout )
-       fclose(fp);
+      fclose (fp);
     xfree(fname);
     return rc;
 }
 
 static void
-do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
+do_hash( gcry_md_hd_t md, gcry_md_hd_t md2, IOBUF fp, int textmode )
 {
     text_filter_context_t tfx;
     int c;
@@ -407,27 +425,27 @@ do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
        int lc = -1;
        while( (c = iobuf_get(fp)) != -1 ) {
            if( c == '\n' && lc == '\r' )
-               md_putc(md2, c);
+               gcry_md_putc (md2, c);
            else if( c == '\n' ) {
-               md_putc(md2, '\r');
-               md_putc(md2, c);
+               gcry_md_putc (md2, '\r');
+               gcry_md_putc (md2, c);
            }
            else if( c != '\n' && lc == '\r' ) {
-               md_putc(md2, '\n');
-               md_putc(md2, c);
+               gcry_md_putc (md2, '\n');
+               gcry_md_putc (md2, c);
            }
            else
-               md_putc(md2, c);
+               gcry_md_putc (md2, c);
 
            if( md )
-               md_putc(md, c );
+               gcry_md_putc (md, c );
            lc = c;
        }
     }
     else {
        while( (c = iobuf_get(fp)) != -1 ) {
            if( md )
-               md_putc(md, c );
+               gcry_md_putc (md, c );
        }
     }
 }
@@ -438,21 +456,23 @@ do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
  * INFILE is the name of the input file.
  */
 int
-ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
+ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2,
                           const char *inname, int textmode )
 {
-    progress_filter_context_t pfx;
+    progress_filter_context_t *pfx;
     char *answer = NULL;
     IOBUF fp;
     int rc = 0;
 
-    fp = open_sigfile( inname, &pfx ); /* open default file */
+    pfx = new_progress_context ();
+    fp = open_sigfile ( inname, pfx ); /* Open default file. */
 
     if( !fp && !opt.batch ) {
        int any=0;
        tty_printf(_("Detached signature.\n"));
        do {
            char *name;
+
            xfree(answer);
            tty_enable_completion(NULL);
            name = cpr_get("detached_signature.filename",
@@ -463,7 +483,7 @@ ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
            xfree(name);
 
            if( any && !*answer ) {
-               rc = G10ERR_READ_FILE;
+                rc = gpg_error (GPG_ERR_GENERAL); /*G10ERR_READ_FILE*/
                goto leave;
            }
            fp = iobuf_open(answer);
@@ -479,8 +499,8 @@ ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
            }
            else if( !fp )
              {
+                rc = gpg_error_from_syserror ();
                log_error(_("can't open `%s': %s\n"), answer, strerror(errno));
-               rc = G10ERR_READ_FILE;
                goto leave;
              }
        } while( !fp );
@@ -497,6 +517,7 @@ ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
 
   leave:
     xfree(answer);
+    release_progress_context (pfx);
     return rc;
 }
 
@@ -507,23 +528,27 @@ ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
  * If FILES is NULL, hash stdin.
  */
 int
-hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
+hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files,
                const char *sigfilename, int textmode )
 {
-    progress_filter_context_t pfx;
+    progress_filter_context_t *pfx;
     IOBUF fp;
-    STRLIST sl;
+    strlist_t sl;
+
+    pfx = new_progress_context ();
 
     if( !files ) {
        /* check whether we can open the signed material */
-       fp = open_sigfile( sigfilename, &pfx );
+       fp = open_sigfile( sigfilename, pfx );
        if( fp ) {
            do_hash( md, md2, fp, textmode );
            iobuf_close(fp);
+            release_progress_context (pfx);
            return 0;
        }
         log_error (_("no signed data\n"));
-        return G10ERR_OPEN_FILE;
+        release_progress_context (pfx);
+        return gpg_error (GPG_ERR_NO_DATA);
     }
 
 
@@ -536,14 +561,94 @@ hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
             errno = EPERM;
           }
        if( !fp ) {
+            int rc = gpg_error_from_syserror ();
            log_error(_("can't open signed data `%s'\n"),
                                                print_fname_stdin(sl->d));
-           return G10ERR_OPEN_FILE;
+            release_progress_context (pfx);
+           return rc;
        }
-        handle_progress (&pfx, fp, sl->d);
+        handle_progress (pfx, fp, sl->d);
        do_hash( md, md2, fp, textmode );
        iobuf_close(fp);
     }
 
+    release_progress_context (pfx);
     return 0;
 }
+
+
+/* Hash the data from file descriptor DATA_FD and append the hash to hash
+   contexts MD and MD2.  */
+int
+hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd,
+                      int textmode )
+{
+  progress_filter_context_t *pfx = new_progress_context ();
+  iobuf_t fp;
+
+  fp = iobuf_fdopen (data_fd, "rb");
+  if (fp && is_secured_file (data_fd))
+    {
+      iobuf_close (fp);
+      fp = NULL;
+      errno = EPERM;
+    }
+  if ( !fp )
+    {
+      int rc = gpg_error_from_syserror ();
+      log_error ( _("can't open signed data fd=%d: %s\n"),
+                  data_fd, strerror (errno));
+      release_progress_context (pfx);
+      return rc;
+    }
+
+  handle_progress (pfx, fp, NULL);
+
+  do_hash ( md, md2, fp, textmode);
+
+  iobuf_close(fp);
+  
+  release_progress_context (pfx);
+  return 0;
+}
+
+
+/* Set up a plaintext packet with the appropriate filename.  If there
+   is a --set-filename, use it (it's already UTF8).  If there is a
+   regular filename, UTF8-ize it if necessary.  If there is no
+   filenames at all, set the field empty. */
+
+PKT_plaintext *
+setup_plaintext_name(const char *filename,IOBUF iobuf)
+{
+  PKT_plaintext *pt;
+
+  if(filename || opt.set_filename)
+    {
+      char *s;
+
+      if(opt.set_filename)
+       s=make_basename(opt.set_filename,iobuf_get_real_fname(iobuf));
+      else if(filename && !opt.flags.utf8_filename)
+       {
+         char *tmp=native_to_utf8(filename);
+         s=make_basename(tmp,iobuf_get_real_fname(iobuf));
+         xfree(tmp);
+       }
+      else
+       s=make_basename(filename,iobuf_get_real_fname(iobuf));
+
+      pt = xmalloc (sizeof *pt + strlen(s) - 1);
+      pt->namelen = strlen (s);
+      memcpy (pt->name, s, pt->namelen);
+      xfree (s);
+    }
+  else
+    {
+      /* no filename */
+      pt = xmalloc (sizeof *pt - 1);
+      pt->namelen = 0;
+    }
+
+  return pt;
+}