~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to g10/pipemode.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_t 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_t 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