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
make_control(byte * buf,int code,int operation)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
pipemode_filter(void * opaque,int control,IOBUF a,byte * buf,size_t * ret_len)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 mem2str (buf, "pipemode_filter", *ret_len);
285 return rc;
286 }
287
288
289
290 void
run_in_pipemode(void)291 run_in_pipemode(void)
292 {
293 IOBUF fp;
294 armor_filter_context_t afx;
295 struct pipemode_context_s stx;
296
297 memset( &afx, 0, sizeof afx);
298 memset( &stx, 0, sizeof stx);
299
300 fp = iobuf_open("-");
301 iobuf_push_filter (fp, pipemode_filter, &stx );
302
303 do {
304 write_status (STATUS_BEGIN_STREAM);
305 proc_packets( NULL, fp );
306 write_status (STATUS_END_STREAM);
307 } while ( !stx.stop );
308
309 }
310
311
312
313
314
315
316