lsh.c 6.87 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 50 51 52 53
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>

#include "getopt.h"

54 55
#include "lsh.c.x"

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

Niels Möller's avatar
Niels Möller committed
59
void usage(void) NORETURN;
Niels Möller's avatar
Niels Möller committed
60

Niels Möller's avatar
Niels Möller committed
61
void usage(void)
Niels Möller's avatar
Niels Möller committed
62
{
63 64 65 66 67 68 69 70 71
  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
72 73 74
  exit(1);
}

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

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

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

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

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

  return &res->super;
}

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

  int lsh_exit_code;
115
  
Niels Möller's avatar
Niels Möller committed
116
  struct sockaddr_in remote;
Niels Möller's avatar
Niels Möller committed
117

Niels Möller's avatar
Niels Möller committed
118 119 120 121 122 123 124
  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;
125
  struct ssh_service *service;
126 127

  int in, out, err;
128 129 130

  NEW(io_backend, backend);

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

  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
150
  
151 152 153
  while(1)
    {
      static struct option options[] =
Niels Möller's avatar
Niels Möller committed
154
      {
155 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 215 216 217 218 219 220
	{ "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);
	    }
	    
	case '?':
	  usage();
	}
      not = (option == 'n');
    }
 options_done:
  
Niels Möller's avatar
Niels Möller committed
221 222 223 224
  if ( (argc - optind) < 1)
    usage();

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

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

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

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

  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));
268
  
269
  service = make_connection_service
270
    (make_alist(0, -1),
Niels Möller's avatar
Niels Möller committed
271
     make_alist(0, -1),
272 273 274
     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
275
			 ATOM_SHELL, ssh_format(""), &lsh_exit_code));
276 277 278 279
  
  kexinit_handler = make_kexinit_handler
    (CONNECTION_CLIENT,
     make_kexinit, algorithms,
Niels Möller's avatar
Niels Möller committed
280 281 282 283 284
     request_service(ATOM_SSH_USERAUTH, 
		     make_client_userauth(ssh_format("%lz", user),
					  ATOM_SSH_CONNECTION,
					  service)));
  
285 286
  if (!io_connect(backend, &remote, NULL,
		  make_client_callback(backend,
Niels Möller's avatar
Niels Möller committed
287
				       "lsh - a free ssh",
288
				       SSH_MAX_PACKET,
Niels Möller's avatar
Niels Möller committed
289 290
				       r, make_kexinit,
				       kexinit_handler)))
Niels Möller's avatar
Niels Möller committed
291 292 293 294 295
    {
      werror("lsh: Connection failed: %s\n", strerror(errno));
      return 1;
    }
  
Niels Möller's avatar
Niels Möller committed
296 297
  /* Exit code if no session is established */
  lsh_exit_code = 17;
Niels Möller's avatar
Niels Möller committed
298
  
299
  io_run(backend);
Niels Möller's avatar
Niels Möller committed
300

Niels Möller's avatar
Niels Möller committed
301
  return lsh_exit_code;
Niels Möller's avatar
Niels Möller committed
302 303 304
}