sexp_conv.c 6.5 KB
Newer Older
1
/* sexp_conv.c
Niels Möller's avatar
Niels Möller committed
2
3
4
5
6
7
8
 *
 * Reads a sexp in given form from, and writes it in given form.
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
9
 * Copyright (C) 1999 Balzs Scheidler, Niels Mller
Niels Möller's avatar
Niels Möller committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

26
27
28
29
#include "algorithms.h"
#include "alist.h"
#include "atoms.h"
#include "crypto.h"
Niels Möller's avatar
Niels Möller committed
30
31
#include "io.h"
#include "lsh.h"
32
#include "lsh_argp.h"
Niels Möller's avatar
Niels Möller committed
33
#include "sexp_commands.h"
34
#include "spki.h"
Niels Möller's avatar
Niels Möller committed
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "werror.h"
#include "xalloc.h"

#include <string.h>
#include <unistd.h>

#include "sexp_conv.c.x"

/* Global, for simplicity */
int exit_code = EXIT_SUCCESS;

/* GABA:
   (expr
     (name make_sexp_conv)
     (params
       (read object command)
51
52
53
       (transform object command)
       (print object command)
       (dest object abstract_write))
Niels Möller's avatar
Niels Möller committed
54
55
     (expr
       (lambda (in)
56
         (print dest (transform (read in))))))
Niels Möller's avatar
Niels Möller committed
57
58
59
60
*/


static void
61
do_exc_sexp_conv_handler(struct exception_handler *self,
Niels Möller's avatar
Niels Möller committed
62
63
			 const struct exception *x)
{
64
  /* CAST(exc_sexp_conv_handler, self, s); */
Niels Möller's avatar
Niels Möller committed
65
66
67
68
69
70
  
  switch (x->type)
    {
    case EXC_SEXP_SYNTAX:
      werror("Invalid SEXP input.\n");
      exit_code = EXIT_FAILURE;
71
      /* Fall through */
Niels Möller's avatar
Niels Möller committed
72
73
    case EXC_SEXP_EOF:
      /* Normal termination */
74
      EXCEPTION_RAISE(self->parent, &finish_read_exception);
Niels Möller's avatar
Niels Möller committed
75
      break;
76
77
78
79
80
81
82
83
    case EXC_IO_WRITE:
    case EXC_IO_READ:
      {
	CAST(io_exception, e, x);
	exit_code = EXIT_FAILURE;
	werror("sexp_conv: %z, (errno = %i)\n", x->msg, e->error);
	break;
      }
Niels Möller's avatar
Niels Möller committed
84
85
    default:
      exit_code = EXIT_FAILURE;
86
      EXCEPTION_RAISE(self->parent, x);
Niels Möller's avatar
Niels Möller committed
87
88
89
90
      return;
    }
}

91
92
/* Option parsing */

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#define OPT_HASH 0x200
#define OPT_SPKI_HASH 0x201
#define OPT_RAW_HASH 0x202
#define OPT_ONCE 0x203

static const struct argp_option
main_options[] =
{
  /* Name, key, arg-name, flags, doc, group */
  { "spki-hash", OPT_SPKI_HASH, NULL, 0, "Output an SPKI hash for the object.", 0 },
  { "raw-hash", OPT_RAW_HASH, NULL, 0, "Output the hash for the canonical "
    "representation of the object, in hexadecimal.", 0 },
  { "hash", OPT_HASH, "Algorithm", 0, "Hash algorithm (default sha1).", 0 },
  { "once", OPT_ONCE, NULL, 0, "Process at most one s-expression.", 0 },
  { NULL, 0, NULL, 0, NULL, 0 }
};

#define MODE_VANILLA 0
#define MODE_RAW_HASH 1
#define MODE_SPKI_HASH 2

/* GABA:
(class
  (name sexp_conv_options)
  (vars
    (input . sexp_argp_state)
    (output . sexp_argp_state)
    (once . int)
    (mode . int)
    (algorithms object alist)
    (hash . int)
    (transform object command)
    (print object command)
))
*/

static struct sexp_conv_options *make_options(void)
{
  NEW(sexp_conv_options, self);
  self->input = SEXP_TRANSPORT;
  self->output = SEXP_ADVANCED;
  self->once = 0;
  self->mode = MODE_VANILLA;
  self->transform = &command_I.super;
  self->algorithms = make_alist(2,
				ATOM_MD5, &md5_algorithm,
				ATOM_SHA1, &sha1_algorithm,
				-1);
  self->hash = ATOM_SHA1;

  return self;
}

146
static const struct argp_child
Niels Möller's avatar
Niels Möller committed
147
main_argp_children[] =
148
{
149
150
  { &sexp_input_argp, 0, NULL, 0 },
  { &sexp_output_argp, 0, NULL, 0 },
151
152
153
154
155
  { &werror_argp, 0, "", 0 },
  { NULL, 0, NULL, 0}
};

static error_t
156
main_argp_parser(int key, char *arg, struct argp_state *state)
157
{
158
  CAST(sexp_conv_options, self, state->input);
159
  
160
161
162
163
164
  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;
    case ARGP_KEY_INIT:
165
166
      state->child_inputs[0] = &self->input;
      state->child_inputs[1] = &self->output;
167
      state->child_inputs[2] = NULL;
168
      break;
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    case ARGP_KEY_END:
      {
	switch(self->mode)
	  {
	  default:
	    fatal("Internal error!");
	  case MODE_VANILLA:
	    self->transform = &command_I.super;
	    self->print = &make_sexp_print_command(self->output)->super;
	    break;
	  case MODE_SPKI_HASH:
	    {
	      CAST_SUBTYPE(hash_algorithm, a,
			   ALIST_GET(self->algorithms, self->hash));
	      self->transform = make_spki_hash(self->hash, a);
	      self->print = &make_sexp_print_command(self->output)->super;
	      break;
	    }
	  case MODE_RAW_HASH:
	    {
	      CAST_SUBTYPE(hash_algorithm, a,
			   ALIST_GET(self->algorithms, self->hash));
	      self->transform = &command_I.super;
	      self->print = make_sexp_print_raw_hash(a);
	      break;
	    }
	  }
	break;
      }
    case OPT_HASH:
      {
	int hash = lookup_hash(self->algorithms, arg, 0);
	if (hash)
	  self->hash = hash;
	else
	  argp_error(state, "Unknown hash algorithm '%s'.", arg);
	break;
      }
    case OPT_SPKI_HASH:
      self->mode = MODE_SPKI_HASH;
      break;
    case OPT_RAW_HASH:
      self->mode = MODE_RAW_HASH;
      break;
    case OPT_ONCE:
      self->once = 1;
      break;
216
    }
217
  
218
219
220
221
222
  return 0;
}

static const struct argp
main_argp =
223
{ main_options, main_argp_parser, NULL,
224
225
226
  "Reads an s-expression on stdin, and outputs the same "
  "s-expression on stdout, possibly using a different "
  "encoding. By default, output uses the advanced encoding. ",
Niels Möller's avatar
Niels Möller committed
227
  main_argp_children,
228
  NULL, NULL
229
230
};
  
Niels Möller's avatar
Niels Möller committed
231
232
233
234
235

#define SEXP_BUFFER_SIZE 1024

int main(int argc, char **argv)
{
236
  struct sexp_conv_options *options = make_options();
237
  struct exception_handler *e;
Niels Möller's avatar
Niels Möller committed
238
  NEW(io_backend, backend);
239
240
  
  argp_parse(&main_argp, argc, argv, 0, NULL, options);
Niels Möller's avatar
Niels Möller committed
241
242
243

  init_backend(backend);

244
  /* Patch the parent pointer later */
245
246
  e = make_exception_handler(do_exc_sexp_conv_handler,
			     NULL, HANDLER_CONTEXT);
247
  
Niels Möller's avatar
Niels Möller committed
248
249
250
  {
    CAST_SUBTYPE(command, work,
		 make_sexp_conv(
251
252
253
		   make_read_sexp_command(options->input, !options->once),
		   options->transform,
		   options->print,
Niels Möller's avatar
Niels Möller committed
254
		   &(io_write(make_lsh_fd(backend,
255
256
257
258
259
					 STDOUT_FILENO,
					 e),
			      SEXP_BUFFER_SIZE,
			      NULL)
		     ->write_buffer->super)));
Niels Möller's avatar
Niels Möller committed
260

Niels Möller's avatar
Niels Möller committed
261
    struct lsh_fd *in = make_lsh_fd(backend, STDIN_FILENO, e);
262
263

    /* Fixing the exception handler creates a circularity */
Niels Möller's avatar
Niels Möller committed
264
    e->parent = make_exc_finish_read_handler(in,
265
266
					     &default_exception_handler,
					     HANDLER_CONTEXT);
267
    
Niels Möller's avatar
Niels Möller committed
268
    COMMAND_CALL(work, in,
269
		 &discard_continuation, e);
Niels Möller's avatar
Niels Möller committed
270
271
272
273
274
  }
  io_run(backend);

  return exit_code;
}