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