* plaintext.c (handle_plaintext): Don't try and create a zero-length
[gnupg.git] / g10 / plaintext.c
1 /* plaintext.c -  process plaintext packets
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG 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  * GnuPG 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 this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <sys/types.h>
29 #ifdef HAVE_DOSISH_SYSTEM
30 #include <fcntl.h> /* for setmode() */
31 #endif
32
33 #include "util.h"
34 #include "memory.h"
35 #include "options.h"
36 #include "packet.h"
37 #include "ttyio.h"
38 #include "filter.h"
39 #include "main.h"
40 #include "status.h"
41 #include "i18n.h"
42
43
44 /****************
45  * Handle a plaintext packet.  If MFX is not NULL, update the MDs
46  * Note: we should use the filter stuff here, but we have to add some
47  *       easy mimic to set a read limit, so we calculate only the
48  *       bytes from the plaintext.
49  */
50 int
51 handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
52                   int nooutput, int clearsig )
53 {
54     char *fname = NULL;
55     FILE *fp = NULL;
56     static off_t count=0;
57     int rc = 0;
58     int c;
59     int convert = (pt->mode == 't' || pt->mode == 'u');
60 #ifdef __riscos__
61     int filetype = 0xfff;
62 #endif
63
64     /* Let people know what the plaintext info is. This allows the
65        receiving program to try and do something different based on
66        the format code (say, recode UTF-8 to local). */
67     if(!nooutput && is_status_enabled())
68       {
69         char status[50];
70
71         sprintf(status,"%X %lu ",(byte)pt->mode,(ulong)pt->timestamp);
72         write_status_text_and_buffer(STATUS_PLAINTEXT,
73                                      status,pt->name,pt->namelen,0);
74
75         if(!pt->is_partial)
76           {
77             sprintf(status,"%lu",(ulong)pt->len);
78             write_status_text(STATUS_PLAINTEXT_LENGTH,status);
79           }
80       }
81
82     /* create the filename as C string */
83     if( nooutput )
84         ;
85     else if( opt.outfile ) {
86         fname = m_alloc( strlen( opt.outfile ) + 1);
87         strcpy(fname, opt.outfile );
88     }
89     else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
90         log_info(_("data not saved; use option \"--output\" to save it\n"));
91         nooutput = 1;
92     }
93     else if( !opt.use_embedded_filename ) {
94         fname = make_outfile_name( iobuf_get_real_fname(pt->buf) );
95         if( !fname )
96             fname = ask_outfile_name( pt->name, pt->namelen );
97         if( !fname ) {
98             rc = G10ERR_CREATE_FILE;
99             goto leave;
100         }
101     }
102     else {
103         fname = make_printable_string( pt->name, pt->namelen, 0 );
104     }
105
106     if( nooutput )
107         ;
108     else if ( iobuf_is_pipe_filename (fname) || !*fname)
109       {
110         /* No filename or "-" given; write to stdout. */
111         fp = stdout;
112 #ifdef HAVE_DOSISH_SYSTEM
113         setmode ( fileno(fp) , O_BINARY );
114 #endif
115       }
116     else {
117         while( !overwrite_filep (fname) ) {
118             char *tmp = ask_outfile_name (NULL, 0);
119             if ( !tmp || !*tmp ) {
120                 m_free (tmp);
121                 rc = G10ERR_CREATE_FILE;
122                 goto leave;
123             }
124             m_free (fname);
125             fname = tmp;
126         }
127     }
128
129 #ifndef __riscos__
130     if( fp || nooutput )
131         ;
132     else if (is_secured_filename (fname))
133       {
134         errno = EPERM;
135         log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
136         rc = G10ERR_CREATE_FILE;
137         goto leave;
138       }
139     else if( !(fp = fopen(fname,"wb")) ) {
140         log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
141         rc = G10ERR_CREATE_FILE;
142         goto leave;
143     }
144 #else /* __riscos__ */
145     /* If no output filename was given, i.e. we constructed it,
146        convert all '.' in fname to '/' but not vice versa as
147        we don't create directories! */
148     if( !opt.outfile )
149         for( c=0; fname[c]; ++c )
150             if( fname[c] == '.' )
151                 fname[c] = '/';
152
153     if( fp || nooutput )
154         ;
155     else {
156         fp = fopen(fname,"wb");
157         if( !fp ) {
158             log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
159             rc = G10ERR_CREATE_FILE;
160             if (errno == 106)
161                 log_info("Do output file and input file have the same name?\n");
162             goto leave;
163         }
164
165         /* If there's a ,xxx extension in the embedded filename,
166            use that, else check whether the user input (in fname)
167            has a ,xxx appended, then use that in preference */
168         if( (c = riscos_get_filetype_from_string( pt->name,
169                                                   pt->namelen )) != -1 )
170             filetype = c;
171         if( (c = riscos_get_filetype_from_string( fname,
172                                                   strlen(fname) )) != -1 )
173             filetype = c;
174         riscos_set_filetype_by_number(fname, filetype);
175     }
176 #endif /* __riscos__ */
177
178     if( !pt->is_partial ) {
179         /* we have an actual length (which might be zero). */
180         assert( !clearsig );
181         if( convert ) { /* text mode */
182             for( ; pt->len; pt->len-- ) {
183                 if( (c = iobuf_get(pt->buf)) == -1 ) {
184                     log_error("Problem reading source (%u bytes remaining)\n",
185                               (unsigned)pt->len);
186                     rc = G10ERR_READ_FILE;
187                     goto leave;
188                 }
189                 if( mfx->md )
190                     md_putc(mfx->md, c );
191 #ifndef HAVE_DOSISH_SYSTEM
192                 if( c == '\r' )  /* convert to native line ending */
193                     continue;    /* fixme: this hack might be too simple */
194 #endif
195                 if( fp )
196                   {
197                     if(opt.max_output && (++count)>opt.max_output)
198                       {
199                         log_error("Error writing to `%s': %s\n",
200                                   fname,"exceeded --max-output limit\n");
201                         rc = G10ERR_WRITE_FILE;
202                         goto leave;
203                       }
204                     else if( putc( c, fp ) == EOF )
205                       {
206                         log_error("Error writing to `%s': %s\n",
207                                   fname, strerror(errno) );
208                         rc = G10ERR_WRITE_FILE;
209                         goto leave;
210                       }
211                   }
212             }
213         }
214         else { /* binary mode */
215             byte *buffer = m_alloc( 32768 );
216             while( pt->len ) {
217                 int len = pt->len > 32768 ? 32768 : pt->len;
218                 len = iobuf_read( pt->buf, buffer, len );
219                 if( len == -1 ) {
220                     log_error("Problem reading source (%u bytes remaining)\n",
221                               (unsigned)pt->len);
222                     rc = G10ERR_READ_FILE;
223                     m_free( buffer );
224                     goto leave;
225                 }
226                 if( mfx->md )
227                     md_write( mfx->md, buffer, len );
228                 if( fp )
229                   {
230                     if(opt.max_output && (count+=len)>opt.max_output)
231                       {
232                         log_error("Error writing to `%s': %s\n",
233                                   fname,"exceeded --max-output limit\n");
234                         rc = G10ERR_WRITE_FILE;
235                         m_free( buffer );
236                         goto leave;
237                       }
238                     else if( fwrite( buffer, 1, len, fp ) != len )
239                       {
240                         log_error("Error writing to `%s': %s\n",
241                                   fname, strerror(errno) );
242                         rc = G10ERR_WRITE_FILE;
243                         m_free( buffer );
244                         goto leave;
245                       }
246                   }
247                 pt->len -= len;
248             }
249             m_free( buffer );
250         }
251     }
252     else if( !clearsig ) {
253         if( convert ) { /* text mode */
254             while( (c = iobuf_get(pt->buf)) != -1 ) {
255                 if( mfx->md )
256                     md_putc(mfx->md, c );
257 #ifndef HAVE_DOSISH_SYSTEM
258                 if( convert && c == '\r' )
259                     continue; /* fixme: this hack might be too simple */
260 #endif
261                 if( fp )
262                   {
263                     if(opt.max_output && (++count)>opt.max_output)
264                       {
265                         log_error("Error writing to `%s': %s\n",
266                                   fname,"exceeded --max-output limit\n");
267                         rc = G10ERR_WRITE_FILE;
268                         goto leave;
269                       }
270                     else if( putc( c, fp ) == EOF )
271                       {
272                         log_error("Error writing to `%s': %s\n",
273                                   fname, strerror(errno) );
274                         rc = G10ERR_WRITE_FILE;
275                         goto leave;
276                       }
277                   }
278             }
279         }
280         else { /* binary mode */
281             byte *buffer = m_alloc( 32768 );
282             int eof;
283             for( eof=0; !eof; ) {
284                 /* Why do we check for len < 32768:
285                  * If we won't, we would practically read 2 EOFs but
286                  * the first one has already popped the block_filter
287                  * off and therefore we don't catch the boundary.
288                  * So, always assume EOF if iobuf_read returns less bytes
289                  * then requested */
290                 int len = iobuf_read( pt->buf, buffer, 32768 );
291                 if( len == -1 )
292                     break;
293                 if( len < 32768 )
294                     eof = 1;
295                 if( mfx->md )
296                     md_write( mfx->md, buffer, len );
297                 if( fp )
298                   {
299                     if(opt.max_output && (count+=len)>opt.max_output)
300                       {
301                         log_error("Error writing to `%s': %s\n",
302                                   fname,"exceeded --max-output limit\n");
303                         rc = G10ERR_WRITE_FILE;
304                         m_free( buffer );
305                         goto leave;
306                       }
307                     else if( fwrite( buffer, 1, len, fp ) != len ) {
308                       log_error("Error writing to `%s': %s\n",
309                                 fname, strerror(errno) );
310                       rc = G10ERR_WRITE_FILE;
311                       m_free( buffer );
312                       goto leave;
313                     }
314                   }
315             }
316             m_free( buffer );
317         }
318         pt->buf = NULL;
319     }
320     else {  /* clear text signature - don't hash the last cr,lf  */
321         int state = 0;
322
323         while( (c = iobuf_get(pt->buf)) != -1 ) {
324             if( fp )
325               {
326                 if(opt.max_output && (++count)>opt.max_output)
327                   {
328                     log_error("Error writing to `%s': %s\n",
329                               fname,"exceeded --max-output limit\n");
330                     rc = G10ERR_WRITE_FILE;
331                     goto leave;
332                   }
333                 else if( putc( c, fp ) == EOF )
334                   {
335                     log_error("Error writing to `%s': %s\n",
336                               fname, strerror(errno) );
337                     rc = G10ERR_WRITE_FILE;
338                     goto leave;
339                   }
340               }
341             if( !mfx->md )
342                 continue;
343             if( state == 2 ) {
344                 md_putc(mfx->md, '\r' );
345                 md_putc(mfx->md, '\n' );
346                 state = 0;
347             }
348             if( !state ) {
349                 if( c == '\r'  )
350                     state = 1;
351                 else if( c == '\n'  )
352                     state = 2;
353                 else
354                     md_putc(mfx->md, c );
355             }
356             else if( state == 1 ) {
357                 if( c == '\n'  )
358                     state = 2;
359                 else {
360                     md_putc(mfx->md, '\r' );
361                     if( c == '\r'  )
362                         state = 1;
363                     else {
364                         state = 0;
365                         md_putc(mfx->md, c );
366                     }
367                 }
368             }
369         }
370         pt->buf = NULL;
371     }
372
373     if( fp && fp != stdout && fclose(fp) ) {
374         log_error("Error closing `%s': %s\n", fname, strerror(errno) );
375         fp = NULL;
376         rc = G10ERR_WRITE_FILE;
377         goto leave;
378     }
379     fp = NULL;
380
381   leave:
382     if( fp && fp != stdout )
383         fclose(fp);
384     m_free(fname);
385     return rc;
386 }
387
388 static void
389 do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
390 {
391     text_filter_context_t tfx;
392     int c;
393
394     if( textmode ) {
395         memset( &tfx, 0, sizeof tfx);
396         iobuf_push_filter( fp, text_filter, &tfx );
397     }
398     if( md2 ) { /* work around a strange behaviour in pgp2 */
399         /* It seems that at least PGP5 converts a single CR to a CR,LF too */
400         int lc = -1;
401         while( (c = iobuf_get(fp)) != -1 ) {
402             if( c == '\n' && lc == '\r' )
403                 md_putc(md2, c);
404             else if( c == '\n' ) {
405                 md_putc(md2, '\r');
406                 md_putc(md2, c);
407             }
408             else if( c != '\n' && lc == '\r' ) {
409                 md_putc(md2, '\n');
410                 md_putc(md2, c);
411             }
412             else
413                 md_putc(md2, c);
414
415             if( md )
416                 md_putc(md, c );
417             lc = c;
418         }
419     }
420     else {
421         while( (c = iobuf_get(fp)) != -1 ) {
422             if( md )
423                 md_putc(md, c );
424         }
425     }
426 }
427
428
429 /****************
430  * Ask for the detached datafile and calculate the digest from it.
431  * INFILE is the name of the input file.
432  */
433 int
434 ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
435                            const char *inname, int textmode )
436 {
437     progress_filter_context_t pfx;
438     char *answer = NULL;
439     IOBUF fp;
440     int rc = 0;
441
442     fp = open_sigfile( inname, &pfx ); /* open default file */
443
444     if( !fp && !opt.batch ) {
445         int any=0;
446         tty_printf(_("Detached signature.\n"));
447         do {
448             m_free(answer);
449             answer = cpr_get("detached_signature.filename",
450                            _("Please enter name of data file: "));
451             cpr_kill_prompt();
452             if( any && !*answer ) {
453                 rc = G10ERR_READ_FILE;
454                 goto leave;
455             }
456             fp = iobuf_open(answer);
457             if (fp && is_secured_file (iobuf_get_fd (fp)))
458               {
459                 iobuf_close (fp);
460                 fp = NULL;
461                 errno = EPERM;
462               }
463             if( !fp && errno == ENOENT ) {
464                 tty_printf("No such file, try again or hit enter to quit.\n");
465                 any++;
466             }
467             else if( !fp )
468               {
469                 log_error(_("can't open `%s': %s\n"), answer, strerror(errno));
470                 rc = G10ERR_READ_FILE;
471                 goto leave;
472               }
473         } while( !fp );
474     }
475
476     if( !fp ) {
477         if( opt.verbose )
478             log_info(_("reading stdin ...\n"));
479         fp = iobuf_open( NULL );
480         assert(fp);
481     }
482     do_hash( md, md2, fp, textmode );
483     iobuf_close(fp);
484
485   leave:
486     m_free(answer);
487     return rc;
488 }
489
490
491
492 /****************
493  * Hash the given files and append the hash to hash context md.
494  * If FILES is NULL, hash stdin.
495  */
496 int
497 hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
498                 const char *sigfilename, int textmode )
499 {
500     progress_filter_context_t pfx;
501     IOBUF fp;
502     STRLIST sl;
503
504     if( !files ) {
505         /* check whether we can open the signed material */
506         fp = open_sigfile( sigfilename, &pfx );
507         if( fp ) {
508             do_hash( md, md2, fp, textmode );
509             iobuf_close(fp);
510             return 0;
511         }
512         log_error (_("no signed data\n"));
513         return G10ERR_OPEN_FILE;
514     }
515
516
517     for (sl=files; sl; sl = sl->next ) {
518         fp = iobuf_open( sl->d );
519         if (fp && is_secured_file (iobuf_get_fd (fp)))
520           {
521             iobuf_close (fp);
522             fp = NULL;
523             errno = EPERM;
524           }
525         if( !fp ) {
526             log_error(_("can't open signed data `%s'\n"),
527                                                 print_fname_stdin(sl->d));
528             return G10ERR_OPEN_FILE;
529         }
530         handle_progress (&pfx, fp, sl->d);
531         do_hash( md, md2, fp, textmode );
532         iobuf_close(fp);
533     }
534
535     return 0;
536 }