2005-04-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / pipemode.c
blob9f2ddfdb5cd2d4e776912514fd4773bb7a350101
1 /* pipemode.c - pipemode handler
2 * Copyright (C) 1998, 1990, 2000, 2001 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
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"
40 #define CONTROL_PACKET_SPACE 30
41 #define FAKED_LITERAL_PACKET_SPACE (9+2+2)
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
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;
64 static size_t
65 make_control ( byte *buf, int code, int operation )
67 const byte *sesmark;
68 size_t sesmarklen, n=0;;
70 sesmark = get_session_marker( &sesmarklen );
71 if ( sesmarklen > 20 )
72 BUG();
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;
86 static int
87 pipemode_filter( void *opaque, int control,
88 iobuf_t a, byte *buf, size_t *ret_len)
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;
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;
103 if ( stx->block_mode ) {
104 /* reserve 2 bytes for the block length */
105 buf[n++] = 0;
106 buf[n++] = 0;
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;
123 break;
125 if ( esc ) {
126 switch (c) {
127 case '@':
128 if ( stx->state == STX_text ) {
129 buf[n++] = c;
130 break;
132 else if ( stx->state == STX_detached_signature ) {
133 esc = 0;
134 goto do_unarmor; /* not a very elegant solution */
136 else if ( stx->state == STX_detached_signature_wait_text) {
137 esc = 0;
138 break; /* just ignore it in this state */
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;
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;
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;
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 ();
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;
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;
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;
211 else {
212 log_error ("invalid state for @t\n");
213 stx->stop = 1;
214 return -1;
216 break;
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;
228 stx->block_mode = 0;
230 n += make_control ( buf+n, 3, 'B' );
232 else {
233 log_error ("invalid state for @.\n");
234 stx->stop = 1;
235 return -1;
237 stx->state = STX_wait_init;
238 goto leave;
240 default:
241 log_error ("invalid escape sequence 0x%02x in stream\n",
243 stx->stop = 1;
244 return -1;
246 esc = 0;
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;
264 else if (stx->state == STX_detached_signature_wait_text)
265 ; /* just wait */
266 else
267 buf[n++] = c;
270 leave:
271 if ( !n ) {
272 stx->stop = 1;
273 rc = -1; /* eof */
275 if ( stx->block_mode ) {
276 /* fixup the block length */
277 buf[0] = (n-2) >> 8;
278 buf[1] = (n-2);
280 leave2:
281 /*log_hexdump ("pipemode:", buf, n );*/
282 *ret_len = n;
284 else if( control == IOBUFCTRL_DESC )
285 *(char**)buf = "pipemode_filter";
286 return rc;
291 void
292 run_in_pipemode(void)
294 iobuf_t fp;
295 armor_filter_context_t afx;
296 struct pipemode_context_s stx;
297 int rc;
299 memset( &afx, 0, sizeof afx);
300 memset( &stx, 0, sizeof stx);
302 fp = iobuf_open("-");
303 iobuf_push_filter (fp, pipemode_filter, &stx );
305 do {
306 write_status (STATUS_BEGIN_STREAM);
307 rc = proc_packets( NULL, fp );
308 write_status (STATUS_END_STREAM);
309 } while ( !stx.stop );