lsh.c 6.98 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1 2 3
/* lsh.c
 *
 * client main program
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
24 25
 */

26
#include "algorithms.h"
Niels Möller's avatar
Niels Möller committed
27 28
#include "alist.h"
#include "atoms.h"
29
#include "channel.h"
30
#include "charset.h"
Niels Möller's avatar
Niels Möller committed
31
#include "client.h"
Niels Möller's avatar
Niels Möller committed
32
#include "client_keyexchange.h"
Niels Möller's avatar
Niels Möller committed
33
#include "crypto.h"
Niels Möller's avatar
Niels Möller committed
34 35 36
#include "format.h"
#include "io.h"
#include "randomness.h"
Niels Möller's avatar
Niels Möller committed
37
#include "service.h"
38
#include "ssh.h"
Niels Möller's avatar
Niels Möller committed
39
#include "userauth.h"
Niels Möller's avatar
Niels Möller committed
40
#include "werror.h"
Niels Möller's avatar
Niels Möller committed
41
#include "xalloc.h"
Niels Möller's avatar
Niels Möller committed
42
#include "compress.h"
Niels Möller's avatar
Niels Möller committed
43

44 45 46 47 48 49
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

50
#if HAVE_UNISTD_H
51
#include <unistd.h>
52
#endif
53 54 55

#include "getopt.h"

56 57
#include "lsh.c.x"

58
/* Block size for stdout and stderr buffers */
Niels Möller's avatar
Niels Möller committed
59 60
#define BLOCK_SIZE 32768

Niels Möller's avatar
Niels Möller committed
61
void usage(void) NORETURN;
Niels Möller's avatar
Niels Möller committed
62

Niels Möller's avatar
Niels Möller committed
63
void usage(void)
Niels Möller's avatar
Niels Möller committed
64
{
65 66 67 68 69 70 71 72 73
  wwrite("lsh [options] host\n"
	 " -p,  --port=PORT\n"
	 " -l,  --user=NAME\n"
	 " -c,  --crypto=ALGORITHM\n"
	 " -z,  --compression=ALGORITHM\n"
	 "      --mac=ALGORITHM\n"
	 " -q,  --quiet\n"
	 " -v,  --verbose\n"
	 "      --debug\n");
Niels Möller's avatar
Niels Möller committed
74 75 76
  exit(1);
}

77 78 79 80 81 82 83 84
/* CLASS:
   (class
     (name fake_host_db)
     (super lookup_verifier)
     (vars
       (algorithm object signature_algorithm)))
*/

Niels Möller's avatar
Niels Möller committed
85
static struct verifier *do_host_lookup(struct lookup_verifier *c,
Niels Möller's avatar
Niels Möller committed
86
				       struct lsh_string *key)
Niels Möller's avatar
Niels Möller committed
87
{
88
  CAST(fake_host_db, closure, c);
Niels Möller's avatar
Niels Möller committed
89

Niels Möller's avatar
Niels Möller committed
90 91 92 93 94
  return MAKE_VERIFIER(closure->algorithm, key->length, key->data);
}

static struct lookup_verifier *make_fake_host_db(struct signature_algorithm *a)
{
95
  NEW(fake_host_db, res);
Niels Möller's avatar
Niels Möller committed
96 97 98 99 100 101 102

  res->super.lookup = do_host_lookup;
  res->algorithm = a;

  return &res->super;
}

Niels Möller's avatar
Niels Möller committed
103 104 105
int main(int argc, char **argv)
{
  char *host = NULL;
106
  char *user = NULL;
Niels Möller's avatar
Niels Möller committed
107
  char *port = "ssh";
108 109 110 111 112 113
  int preferred_crypto = 0;
  int preferred_compression = 0;
  int preferred_mac = 0;
  
  int not;
  
Niels Möller's avatar
Niels Möller committed
114
  int option;
Niels Möller's avatar
Niels Möller committed
115 116

  int lsh_exit_code;
117
  
Niels Möller's avatar
Niels Möller committed
118
  struct sockaddr_in remote;
Niels Möller's avatar
Niels Möller committed
119

Niels Möller's avatar
Niels Möller committed
120 121 122 123 124 125 126
  struct randomness *r;
  struct diffie_hellman_method *dh;
  struct keyexchange_algorithm *kex;
  struct alist *algorithms;
  struct make_kexinit *make_kexinit;
  struct packet_handler *kexinit_handler;
  struct lookup_verifier *lookup;
127
  struct ssh_service *service;
128 129

  int in, out, err;
130 131 132

  NEW(io_backend, backend);

Niels Möller's avatar
Niels Möller committed
133 134 135
  /* For filtering messages. Could perhaps also be used when converting
   * strings to and from UTF8. */
  setlocale(LC_CTYPE, "");
136 137
  /* FIXME: Choose character set depending on the locale */
  set_local_charset(CHARSET_LATIN1);
138 139 140 141 142 143 144 145 146 147 148 149 150 151

  r = make_reasonably_random();
  dh = make_dh1(r);

  /* No randomness is needed for verifying signatures */
  lookup = make_fake_host_db(make_dss_algorithm(NULL)); 

  kex = make_dh_client(dh, lookup);
  algorithms = many_algorithms(2, 
			       ATOM_DIFFIE_HELLMAN_GROUP1_SHA1, kex,
			       ATOM_SSH_DSS, make_dss_algorithm(r),
			       -1);

  not = 0;
Niels Möller's avatar
Niels Möller committed
152
  
153 154 155
  while(1)
    {
      static struct option options[] =
Niels Möller's avatar
Niels Möller committed
156
      {
157 158 159 160 161 162 163 164 165 166 167 168 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
	{ "verbose", no_argument, NULL, 'v' },
	{ "quiet", no_argument, NULL, 'q' },
	{ "debug", no_argument, &debug_flag, 1},
	{ "port", required_argument, NULL, 'p' },
	{ "user", required_argument, NULL, 'l' },
	{ "crypto", required_argument, NULL, 'c' },
	{ "compression", optional_argument, NULL, 'z'},
	{ "mac", required_argument, NULL, 'm' },
	{ NULL }
      };
      
      option = getopt_long(argc, argv, "+c:l:np:qvz::", options, NULL);
      switch(option)
	{
	case -1:
	  goto options_done;
	case 0:
	case 'n':
	  break;
	case 'p':
	  port = optarg;
	  break;
	case 'l':
	  user = optarg;
	  break;
	case 'q':
	  quiet_flag = 1;
	  break;
	case 'v':
	  verbose_flag = 1;
	  break;
	case 'c':
	  preferred_crypto = lookup_crypto(algorithms, optarg);
	  if (!preferred_crypto)
	    {
	      werror("lsh: Unknown crypto algorithm '%s'.\n", optarg);
	      exit(1);
	    }
	  break;
	case 'z':
	  if (!optarg)
	    optarg = "zlib";
	
	  preferred_compression = lookup_compression(algorithms, optarg);
	  if (!preferred_compression)
	    {
	      werror("lsh: Unknown compression algorithm '%s'.\n", optarg);
	      exit(1);
	    }
	  break;
	case 'm':
	  preferred_mac = lookup_mac(algorithms, optarg);
	  if (!preferred_mac)
	    {
	      werror("lsh: Unknown message authentication algorithm '%s'.\n",
		      optarg);
	      exit(1);
	    }
215
	  break;
216 217 218 219 220 221 222
	case '?':
	  usage();
	}
      not = (option == 'n');
    }
 options_done:
  
Niels Möller's avatar
Niels Möller committed
223 224 225 226
  if ( (argc - optind) < 1)
    usage();

  host = argv[optind];
227
  if (!user)
228
    user = getenv("LOGNAME");
229 230 231

  if (!user)
    {
232
      wwrite("lsh: No user name.\n"
233 234 235 236 237 238
	     "Please use the -l option, or set LOGNAME in the environment\n");
      exit(EXIT_FAILURE);
    }

  if (!get_inaddr(&remote, host, port, "tcp"))
    {
239
      wwrite("No such host or service\n");
240 241
      exit(1);
    }
Niels Möller's avatar
Niels Möller committed
242

243 244
  in = STDIN_FILENO;
  out = STDOUT_FILENO;
Niels Möller's avatar
Niels Möller committed
245
  
Niels Möller's avatar
Niels Möller committed
246
  if ( (err = dup(STDERR_FILENO)) < 0)
247 248 249 250
    {
      werror("Can't dup stderr: %s\n", strerror(errno));
      return EXIT_FAILURE;
    }
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

  init_backend(backend);
  
  set_error_stream(STDERR_FILENO, 1);
  
  make_kexinit
    = make_simple_kexinit(r,
			  make_int_list(1, ATOM_DIFFIE_HELLMAN_GROUP1_SHA1, -1),
			  make_int_list(1, ATOM_SSH_DSS, -1),
			  (preferred_crypto
			   ? make_int_list(1, preferred_crypto, -1)
			   : default_crypto_algorithms()),
			  (preferred_mac
			   ? make_int_list(1, preferred_mac, -1)
			   : default_mac_algorithms()),
			  (preferred_compression
			   ? make_int_list(1, preferred_compression, -1)
			   : default_compression_algorithms()),
			  make_int_list(0, -1));
270
  
271
  service = make_connection_service
272
    (make_alist(0, -1),
Niels Möller's avatar
Niels Möller committed
273
     make_alist(0, -1),
274 275 276
     make_client_startup(io_read(backend, in, NULL, NULL),
			 io_write(backend, out, BLOCK_SIZE, NULL),
			 io_write(backend, err, BLOCK_SIZE, NULL),
Niels Möller's avatar
Niels Möller committed
277
			 ATOM_SHELL, ssh_format(""), &lsh_exit_code));
278 279 280 281
  
  kexinit_handler = make_kexinit_handler
    (CONNECTION_CLIENT,
     make_kexinit, algorithms,
Niels Möller's avatar
Niels Möller committed
282 283 284 285 286
     request_service(ATOM_SSH_USERAUTH, 
		     make_client_userauth(ssh_format("%lz", user),
					  ATOM_SSH_CONNECTION,
					  service)));
  
287 288
  if (!io_connect(backend, &remote, NULL,
		  make_client_callback(backend,
Niels Möller's avatar
Niels Möller committed
289
				       "lsh - a free ssh",
290
				       SSH_MAX_PACKET,
Niels Möller's avatar
Niels Möller committed
291 292
				       r, make_kexinit,
				       kexinit_handler)))
Niels Möller's avatar
Niels Möller committed
293 294 295 296
    {
      werror("lsh: Connection failed: %s\n", strerror(errno));
      return 1;
    }
Niels Möller's avatar
Niels Möller committed
297

Niels Möller's avatar
Niels Möller committed
298 299
  /* Exit code if no session is established */
  lsh_exit_code = 17;
Niels Möller's avatar
Niels Möller committed
300
  
301
  io_run(backend);
Niels Möller's avatar
Niels Möller committed
302

Niels Möller's avatar
Niels Möller committed
303 304 305
  /* FIXME: Perhaps we have to reset the stdio file descriptors to
   * blocking mode? */

Niels Möller's avatar
Niels Möller committed
306
  return lsh_exit_code;
Niels Möller's avatar
Niels Möller committed
307 308 309
}