Switched to GPLv3.
[gnupg.git] / g10 / pipemode.c
1 /* pipemode.c - pipemode handler
2  * Copyright (C) 1998, 1990, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26
27 #include "options.h"
28 #include "packet.h"
29 #include "errors.h"
30 #include "iobuf.h"
31 #include "keydb.h"
32 #include "memory.h"
33 #include "util.h"
34 #include "main.h"
35 #include "status.h"
36 #include "filter.h"
37
38
39 #define CONTROL_PACKET_SPACE 30 
40 #define FAKED_LITERAL_PACKET_SPACE (9+2+2)
41
42
43 enum pipemode_state_e {
44     STX_init = 0,
45     STX_wait_operation,
46     STX_begin,
47     STX_text,
48     STX_detached_signature,
49     STX_detached_signature_wait_text,
50     STX_signed_data,
51     STX_wait_init
52 };
53
54 struct pipemode_context_s {
55     enum pipemode_state_e state;
56     int operation;
57     int stop;
58     int block_mode;
59     UnarmorPump unarmor_ctx;
60 };
61
62
63 static size_t
64 make_control ( byte *buf, int code, int operation )
65 {
66     const byte *sesmark;
67     size_t sesmarklen, n=0;;
68
69     sesmark = get_session_marker( &sesmarklen );
70     if ( sesmarklen > 20 )
71         BUG();
72
73     buf[n++] = 0xff; /* new format, type 63, 1 length byte */
74     n++;   /* length will fixed below */
75     memcpy(buf+n, sesmark, sesmarklen ); n+= sesmarklen;
76     buf[n++] = CTRLPKT_PIPEMODE;    
77     buf[n++] = code;
78     buf[n++] = operation;
79     buf[1] = n-2;
80     return n;
81 }
82
83
84
85 static int
86 pipemode_filter( void *opaque, int control,
87                  IOBUF a, byte *buf, size_t *ret_len)
88
89     size_t size = *ret_len;
90     struct pipemode_context_s *stx = opaque;
91     int rc=0;
92     size_t n = 0;
93     int esc = 0;
94
95     if( control == IOBUFCTRL_UNDERFLOW ) {
96         *ret_len = 0;
97         /* reserve some space for one control packet */
98         if ( size <= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE )
99             BUG();
100         size -= CONTROL_PACKET_SPACE+FAKED_LITERAL_PACKET_SPACE;
101
102         if ( stx->block_mode ) {
103             /* reserve 2 bytes for the block length */
104             buf[n++] = 0;
105             buf[n++] = 0;
106         }
107             
108
109         while ( n < size ) {
110             /* FIXME: we have to make sure that we have a large enough
111              * buffer for a control packet even after we already read 
112              * something. The easest way to do this is probably by ungetting
113              * the control sequence and returning the buffer we have
114              * already assembled */
115             int c = iobuf_get (a);
116             if (c == -1) {
117                 if ( stx->state != STX_init ) {
118                     log_error ("EOF encountered at wrong state\n");
119                     stx->stop = 1;
120                     return -1;
121                 }
122                 break;
123             }
124             if ( esc ) {
125                 switch (c) {
126                   case '@':  
127                     if ( stx->state == STX_text ) {
128                         buf[n++] = c;
129                         break;
130                     }
131                     else if ( stx->state == STX_detached_signature ) {
132                         esc = 0;
133                         goto do_unarmor; /* not a very elegant solution */
134                     }
135                     else if ( stx->state == STX_detached_signature_wait_text) {
136                         esc = 0;
137                         break; /* just ignore it in this state */
138                     }
139                     log_error ("@@ not allowed in current state\n");
140                     return -1;
141                   case '<': /* begin of stream part */
142                     if ( stx->state != STX_init ) {
143                         log_error ("nested begin of stream\n");
144                         stx->stop = 1;
145                         return -1;
146                     }
147                     stx->state = STX_wait_operation;
148                     stx->block_mode = 0;
149                     unarmor_pump_release (stx->unarmor_ctx);
150                     stx->unarmor_ctx = NULL;
151                     break;
152                    case '>': /* end of stream part */
153                      if ( stx->state != STX_wait_init ) {
154                         log_error ("invalid state for @>\n");
155                         stx->stop = 1;
156                         return -1;
157                     }
158                     stx->state = STX_init;
159                     break;
160                   case 'V': /* operation = verify */
161                   case 'E': /* operation = encrypt */
162                   case 'S': /* operation = sign */
163                   case 'B': /* operation = detach sign */
164                   case 'C': /* operation = clearsign */
165                   case 'D': /* operation = decrypt */
166                     if ( stx->state != STX_wait_operation ) {
167                         log_error ("invalid state for operation code\n");
168                         stx->stop = 1;
169                         return -1;
170                     }
171                     stx->operation = c;
172                     if ( stx->operation == 'B') {
173                         stx->state = STX_detached_signature;
174                         if ( !opt.no_armor )
175                             stx->unarmor_ctx = unarmor_pump_new ();
176                     }
177                     else
178                         stx->state = STX_begin;
179                     n += make_control ( buf+n, 1, stx->operation );
180                     /* must leave after a control packet */
181                     goto leave;
182
183                   case 't': /* plaintext text follows */
184                     if ( stx->state == STX_detached_signature_wait_text ) 
185                         stx->state = STX_detached_signature;
186                     if ( stx->state == STX_detached_signature ) {
187                         if ( stx->operation != 'B' ) {
188                             log_error ("invalid operation for this state\n");
189                             stx->stop = 1;
190                             return -1;
191                         }
192                         stx->state = STX_signed_data;
193                         n += make_control ( buf+n, 2, 'B' );
194                         /* and now we fake a literal data packet much the same
195                          * as in armor.c */
196                         buf[n++] = 0xaf; /* old packet format, type 11,
197                                             var length */
198                         buf[n++] = 0;    /* set the length header */
199                         buf[n++] = 6;
200                         buf[n++] = 'b';  /* we ignore it anyway */
201                         buf[n++] = 0;    /* namelength */
202                         memset(buf+n, 0, 4); /* timestamp */
203                         n += 4;
204                         /* and return now so that we are sure to have
205                          * more space in the bufer for the next control
206                          * packet */
207                         stx->block_mode = 1;
208                         goto leave2;
209                     }
210                     else {
211                         log_error ("invalid state for @t\n");
212                         stx->stop = 1;
213                         return -1;
214                     }
215                     break;
216
217                   case '.': /* ready */
218                     if ( stx->state == STX_signed_data ) { 
219                         if (stx->block_mode) {
220                             buf[0] = (n-2) >> 8;
221                             buf[1] = (n-2);
222                             if ( buf[0] || buf[1] ) {
223                                 /* end of blocks marker */
224                                 buf[n++] = 0;
225                                 buf[n++] = 0;
226                             }
227                             stx->block_mode = 0;
228                         }
229                         n += make_control ( buf+n, 3, 'B' );
230                     }
231                     else {
232                         log_error ("invalid state for @.\n");
233                         stx->stop = 1;
234                         return -1;
235                     }
236                     stx->state = STX_wait_init;
237                     goto leave;
238
239                  default:      
240                     log_error ("invalid escape sequence 0x%02x in stream\n",
241                                c);
242                     stx->stop = 1;
243                     return -1;
244                 }
245                 esc = 0;
246             }
247             else if (c == '@') 
248                 esc = 1;
249             else if (stx->unarmor_ctx) {
250           do_unarmor: /* used to handle a @@ */
251                 c = unarmor_pump (stx->unarmor_ctx, c);
252                 if ( !(c & ~255) )
253                     buf[n++] = c;
254                 else if ( c < 0 ) {
255                     /* end of armor or error - we don't care becuase
256                       the armor can be modified anyway.  The unarmored
257                       stuff should stand for itself. */ 
258                     unarmor_pump_release (stx->unarmor_ctx);
259                     stx->unarmor_ctx = NULL;
260                     stx->state = STX_detached_signature_wait_text;
261                 }
262             }
263             else if (stx->state == STX_detached_signature_wait_text)
264                 ; /* just wait */
265             else
266                 buf[n++] = c; 
267         }
268
269       leave:      
270         if ( !n ) {
271             stx->stop = 1;
272             rc = -1; /* eof */
273         }
274         if ( stx->block_mode ) {
275             /* fixup the block length */
276             buf[0] = (n-2) >> 8;
277             buf[1] = (n-2);
278         }
279       leave2:
280         /*log_hexdump ("pipemode:", buf, n );*/
281         *ret_len = n;
282     }
283     else if( control == IOBUFCTRL_DESC )
284         *(char**)buf = "pipemode_filter";
285     return rc;
286 }
287
288
289
290 void
291 run_in_pipemode(void)
292 {
293     IOBUF fp;
294     armor_filter_context_t afx;
295     struct pipemode_context_s stx;
296     int rc;
297
298     memset( &afx, 0, sizeof afx);
299     memset( &stx, 0, sizeof stx);
300
301     fp = iobuf_open("-");
302     iobuf_push_filter (fp, pipemode_filter, &stx );
303
304     do {
305         write_status (STATUS_BEGIN_STREAM);
306         rc = proc_packets( NULL, fp );
307         write_status (STATUS_END_STREAM);
308     } while ( !stx.stop );
309   
310 }
311
312
313
314
315
316