client.c 32.9 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
/* client.c
2
 *
3
 */
4
5
6

/* lsh, an implementation of the ssh protocol
 *
7
 * Copyright (C) 1998, 1999, 2000 Niels Mller
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * 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
J.H.M. Dassen's avatar
J.H.M. Dassen committed
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
22
23
 */

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>
#include <string.h>

#include <fcntl.h>
#include <signal.h>

#if HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>

Niels Möller's avatar
Niels Möller committed
41
#include "client.h"
42

Niels Möller's avatar
Niels Möller committed
43
#include "abstract_io.h"
44
#include "channel.h"
45
#include "channel_commands.h"
46
#include "connection.h"
47
#include "environ.h"
48
49
50
#include "format.h"
#include "interact.h"
#include "io.h"
Niels Möller's avatar
Niels Möller committed
51
#include "pad.h"
52
53
#include "parse.h"
#include "ssh.h"
54
#include "suspend.h"
55
#include "tcpforward_commands.h"
Niels Möller's avatar
Niels Möller committed
56
#include "translate_signal.h"
57
58
#include "werror.h"
#include "xalloc.h"
59
#include "io.h"
Niels Möller's avatar
Niels Möller committed
60

61
62
#include "lsh_argp.h"

63
64
65
66
#define GABA_DEFINE
#include "client.h.x"
#undef GABA_DEFINE

67
68
#include "client.c.x"

69
70
#define DEFAULT_ESCAPE_CHAR '~'

71
72
73
74
75
76
static struct lsh_string *
format_service_request(int name)
{
  return ssh_format("%c%a", SSH_MSG_SERVICE_REQUEST, name);
}

77
78
/* Start a service that the server has accepted (for instance
 * ssh-userauth). */
79
/* GABA:
80
81
82
83
   (class
     (name accept_service_handler)
     (super packet_handler)
     (vars
Niels Möller's avatar
Niels Möller committed
84
       (service . int)
85
       (c object command_continuation)))
86
87
*/

Niels Möller's avatar
Niels Möller committed
88
89
90
91
static void
do_accept_service(struct packet_handler *c,
		  struct ssh_connection *connection,
		  struct lsh_string *packet)
92
{
93
  CAST(accept_service_handler, closure, c);
94
95

  struct simple_buffer buffer;
96
  unsigned msg_number;
Niels Möller's avatar
Niels Möller committed
97
  int name;
98

99
100
  simple_buffer_init(&buffer, packet->length, packet->data);
  
101
102
  if (parse_uint8(&buffer, &msg_number)
      && (msg_number == SSH_MSG_SERVICE_ACCEPT)
103
104
105
106
107
108
109
110
111
      && (
#if DATAFELLOWS_WORKAROUNDS
	  (connection->peer_flags & PEER_SERVICE_ACCEPT_KLUDGE)
#else
	  0
#endif
	  || (parse_atom(&buffer, &name)
	      && (name == closure->service)))
      && parse_eod(&buffer))
112
    {
113
      connection->dispatch[SSH_MSG_SERVICE_ACCEPT] = &connection_fail_handler;
114
      
Niels Möller's avatar
Niels Möller committed
115
      COMMAND_RETURN(closure->c, connection);
116
    }
Niels Möller's avatar
Niels Möller committed
117
  else
118
    PROTOCOL_ERROR(connection->e, "Invalid SSH_MSG_SERVICE_ACCEPT message");
119
120
}

121
struct packet_handler *
122
make_accept_service_handler(uint32_t service,
123
			    struct command_continuation *c)
124
{
125
  NEW(accept_service_handler, closure);
126

Niels Möller's avatar
Niels Möller committed
127
  closure->super.handler = do_accept_service;
128
  closure->service = service;
129
  closure->c = c;
130
  
131
132
133
  return &closure->super;
}

134
void
Niels Möller's avatar
Niels Möller committed
135
136
137
do_request_service(struct command *s,
		   struct lsh_object *x,
		   struct command_continuation *c,
138
		   struct exception_handler *e UNUSED)
139
{
140
141
  CAST(request_service, self, s);
  CAST(ssh_connection, connection, x);
142
143
144

  /* NOTE: Uses the connection's exception handler, not the one passed
   * in. */
Niels Möller's avatar
Niels Möller committed
145
  connection->dispatch[SSH_MSG_SERVICE_ACCEPT]
146
    = make_accept_service_handler(self->service, c);
Niels Möller's avatar
Niels Möller committed
147
  
Niels Möller's avatar
Niels Möller committed
148
149
  C_WRITE(connection,
	  format_service_request(self->service));
150
151
}

152
153
struct command *
make_request_service(int service)
154
{
155
  NEW(request_service, closure);
156

157
  closure->super.call = do_request_service;
158
159
160
161
162
  closure->service = service;

  return &closure->super;
}

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
/* GABA:
   (class
     (name detach_callback)
     (super lsh_callback)
     (vars 
       (channel_flag . int)
       (fd_flag . int)
       (exit_status . "int *")))
*/

/* GABA:
   (class
     (name detach_resource)
     (super resource)
     (vars
       (c object detach_callback)))
*/

static void 
do_detach_res_kill(struct resource *r)
{
  CAST(detach_resource,self,r);

  trace("client.c:do_detach_res\n");
  self->c->channel_flag = 1;

  if (self->c->channel_flag && self->c->fd_flag)
    /* If the fd_flag is set, the callback should be changed */
    io_callout(&self->c->super, 0);
}

static struct resource*
make_detach_resource(struct lsh_callback *c)
{
   NEW(detach_resource, self);
   CAST(detach_callback, cb, c);

   trace("client.c:make_detach_resource\n");
   init_resource(&self->super, do_detach_res_kill);

   self->c = cb;

   return &self->super;
}


static void 
211
do_detach_cb(struct lsh_callback *c)
212
213
214
{
  CAST(detach_callback,self,c);

215
  trace("client.c: do_detach_cb\n");
216
  
217
  if (!self->fd_flag) /* First time around? */
218
    {
219
      self->fd_flag = 1; /* Note */
220
      
221
222
223
    if (self->channel_flag && self->fd_flag)
      /* If the fd is closed already, asked to be called from the main loop */ 
      io_callout(c, 0);
224
225

    }
226
227
228
  else
    {
      int pid = fork();
229

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
      /* Ignore any errors, what can we do? */
      
      switch(pid)
	{
	case -1: /* Fork failed, this we can handle by doing nothing */
	  werror("Fork failed, not detaching.\n");
	  break;
	  
	case 0:
	  /* Detach, lsh doesn't actually use these fds but dup(2)s them */
	  
	  close(STDIN_FILENO); 
	  close(STDOUT_FILENO); 
	  close(STDERR_FILENO); 
	  
	  /* Make sure they aren't used by any file lsh opens */
	  
	  open("/dev/null", O_RDONLY);
	  open("/dev/null", O_RDONLY);
	  open("/dev/null", O_RDONLY);
	  break;
	  
	default:
	  /* It's a good idea to reset std* to blocking mode. */
	  io_set_blocking(STDIN_FILENO);
	  io_set_blocking(STDOUT_FILENO);
	  io_set_blocking(STDERR_FILENO);
	  
	  exit(*self->exit_status);
	}
    }
261
262
263
264
265
266
267
}

static struct lsh_callback* 
make_detach_callback(int *exit_status)
{
   NEW(detach_callback, self);

268
   self->super.f = do_detach_cb;
269
270
271
272
273
274
275
   self->exit_status = exit_status;
   self->fd_flag = 0;
   self->channel_flag = 0;

   return &self->super;
}

276
/* GABA:
277
278
279
280
   (class
     (name exit_handler)
     (super channel_request)
     (vars
Niels Möller's avatar
Niels Möller committed
281
       (exit_status . "int *")))
282
283
*/

Niels Möller's avatar
Niels Möller committed
284
285
286
static void
do_exit_status(struct channel_request *c,
	       struct ssh_channel *channel,
Niels Möller's avatar
Niels Möller committed
287
	       struct channel_request_info *info,
288
289
290
	       struct simple_buffer *args,
	       struct command_continuation *s,
	       struct exception_handler *e)
Niels Möller's avatar
Niels Möller committed
291
{
292
  CAST(exit_handler, closure, c);
293
  uint32_t status;
Niels Möller's avatar
Niels Möller committed
294

Niels Möller's avatar
Niels Möller committed
295
  if (!info->want_reply
Niels Möller's avatar
Niels Möller committed
296
297
298
      && parse_uint32(args, &status)
      && parse_eod(args))
    {
299
300
      verbose("client.c: Receiving exit-status %i on channel %i\n",
	      status, channel->channel_number);
Niels Möller's avatar
Niels Möller committed
301

302
      *closure->exit_status = status;
303
304
      ALIST_SET(channel->request_types, ATOM_EXIT_STATUS, NULL);
      ALIST_SET(channel->request_types, ATOM_EXIT_SIGNAL, NULL);
305
      
306
      COMMAND_RETURN(s, NULL);
Niels Möller's avatar
Niels Möller committed
307
    }
Niels Möller's avatar
Niels Möller committed
308
309
  else
    /* Invalid request */
310
    PROTOCOL_ERROR(e, "Invalid exit-status message");
Niels Möller's avatar
Niels Möller committed
311
312
}

Niels Möller's avatar
Niels Möller committed
313
314
315
static void
do_exit_signal(struct channel_request *c,
	       struct ssh_channel *channel,
Niels Möller's avatar
Niels Möller committed
316
	       struct channel_request_info *info,
317
318
319
	       struct simple_buffer *args,
	       struct command_continuation *s,
	       struct exception_handler *e)
Niels Möller's avatar
Niels Möller committed
320
{
321
322
  CAST(exit_handler, closure, c);

323
  uint32_t signal;
Niels Möller's avatar
Niels Möller committed
324
325
  int core;

326
327
  const uint8_t *msg;
  uint32_t length;
Niels Möller's avatar
Niels Möller committed
328

329
330
  const uint8_t *language;
  uint32_t language_length;
Niels Möller's avatar
Niels Möller committed
331
  
Niels Möller's avatar
Niels Möller committed
332
  if (!info->want_reply
333
      && parse_atom(args, &signal)
Niels Möller's avatar
Niels Möller committed
334
335
336
337
338
339
340
341
342
343
      && parse_boolean(args, &core)
      && parse_string(args, &length, &msg)
      && parse_string(args, &language_length, &language)
      && parse_eod(args))
    {
      /* FIXME: What exit status should be returned when the remote
       * process dies violently? */

      *closure->exit_status = 7;

344
345
      werror("Remote process was killed by signal: %ups %z\n",
	     length, msg,
346
	     core ? "(core dumped remotely)\n": "");
347
      
348
349
      ALIST_SET(channel->request_types, ATOM_EXIT_STATUS, NULL);
      ALIST_SET(channel->request_types, ATOM_EXIT_SIGNAL, NULL);
Niels Möller's avatar
Niels Möller committed
350

351
      COMMAND_RETURN(s, NULL);
Niels Möller's avatar
Niels Möller committed
352
    }
Niels Möller's avatar
Niels Möller committed
353
354
  else
    /* Invalid request */
355
    PROTOCOL_ERROR(e, "Invalid exit-signal message");
Niels Möller's avatar
Niels Möller committed
356
357
}

358
359
struct channel_request *
make_handle_exit_status(int *exit_status)
Niels Möller's avatar
Niels Möller committed
360
{
361
  NEW(exit_handler, self);
Niels Möller's avatar
Niels Möller committed
362
363
364
365
366
367
368
369

  self->super.handler = do_exit_status;

  self->exit_status = exit_status;

  return &self->super;
}

370
371
struct channel_request *
make_handle_exit_signal(int *exit_status)
Niels Möller's avatar
Niels Möller committed
372
{
373
  NEW(exit_handler, self);
Niels Möller's avatar
Niels Möller committed
374
375
376
377
378
379
380
381

  self->super.handler = do_exit_signal;

  self->exit_status = exit_status;

  return &self->super;
}

382
383
384
385
386
387
388
/* GABA:
   (class
     (name session_open_command)
     (super channel_open_command)
     (vars
       ; This command can only be executed once,
       ; so we can allocate the session object in advance.
389
       (session object ssh_channel)))
390
391
392
393
394
*/

static struct ssh_channel *
new_session(struct channel_open_command *s,
	    struct ssh_connection *connection,
395
	    uint32_t local_channel_number,
396
397
398
399
	    struct lsh_string **request)
{
  CAST(session_open_command, self, s);
  struct ssh_channel *res;
400

401
  self->session->connection = connection;
402
  
403
404
405
  *request = format_channel_open(ATOM_SESSION,
				 local_channel_number,
				 self->session, "");
406
  
407
  res = self->session;
408
409
410
411
412
413
414

  /* Make sure this command can not be invoked again */
  self->session = NULL;

  return res;
}

415
416
struct command *
make_open_session_command(struct ssh_channel *session)
417
418
419
420
421
{
  NEW(session_open_command, self);
  self->super.super.call = do_channel_open_command;
  self->super.new_channel = new_session;
  self->session = session;
422
423

  return &self->super.super;
424
425
}

426
427
428
429
430
431
432
433

static struct lsh_string *
do_format_shell_request(struct channel_request_command *s UNUSED,
			struct ssh_channel *channel,
			struct command_continuation **c)
{
  return format_channel_request(ATOM_SHELL, channel, !!*c, "");
}
434

435
436
struct channel_request_command request_shell =
{ { STATIC_HEADER, do_channel_request_command }, do_format_shell_request };
437

438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470

/* GABA:
   (class
     (name exec_request)
     (super channel_request_command)
     (vars
       (command string)))
*/

static struct lsh_string *
do_format_exec_request(struct channel_request_command *s,
		       struct ssh_channel *channel,
		       struct command_continuation **c)
{
  CAST(exec_request, self, s);

  verbose("lsh: Requesting remote exec.\n");

  return format_channel_request(ATOM_EXEC, channel,
				!!*c, "%S", self->command);
}

struct command *
make_exec_request(struct lsh_string *command)
{
  NEW(exec_request, req);

  req->super.format_request = do_format_exec_request;
  req->super.super.call = do_channel_request_command;
  req->command = command;

  return &req->super.super;
}
471

472

473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
/* GABA:
   (class
     (name subsystem_request)
     (super channel_request_command)
     (vars
       (subsystem string)))
*/

static struct lsh_string *
do_format_subsystem_request(struct channel_request_command *s,
			    struct ssh_channel *channel,
			    struct command_continuation **c)
{
  CAST(subsystem_request, self, s);

  verbose("lsh: Requesting remote subsystem.\n");

  return format_channel_request(ATOM_SUBSYSTEM, channel,
				!!*c, "%S", self->subsystem);
}

struct command *
make_subsystem_request(struct lsh_string *subsystem)
{
  NEW(subsystem_request, req);

  req->super.format_request = do_format_subsystem_request;
  req->super.super.call = do_channel_request_command;
  req->subsystem = subsystem;

  return &req->super.super;
}


507
/* Handling of options and operations shared by the plain lsh client
508
 * and lshg. */
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530

/* Forward declaration */

static struct ssh_channel *
make_client_session(struct client_options *options);

/* Block size for stdout and stderr buffers */
#define BLOCK_SIZE 32768

/* Window size for the session channel
 *
 * NOTE: Large windows seem to trig a bug in sshd2. */
#define WINDOW_SIZE 10000

#define ARG_NOT 0x400

#define OPT_STDIN 0x210
#define OPT_STDOUT 0x211
#define OPT_STDERR 0x212

#define OPT_FORK_STDIO 0x213

531
#define OPT_SUBSYSTEM 0x214
532
#define OPT_DETACH 0x215
533

534
535
void
init_client_options(struct client_options *self,
536
		    struct randomness *random,
537
538
539
		    struct exception_handler *handler,
		    int *exit_code)			 
{
540
541
  self->random = random;
  
542
  self->tty = make_unix_interact();
543
544
  self->escape = -1;
  
545
546
547
548
549
  self->handler = handler;

  self->exit_code = exit_code;
  
  self->not = 0;
550
  self->port = NULL;
551
  self->target = NULL;
552

553
  self->local_user = self->user = getenv(ENV_LOGNAME);
554
555
556

  self->with_remote_peers = 0; 
  self->with_pty = -1;
557
558
  self->with_x11 = 0;
    
559
560
561
562
563
564
  self->stdin_file = NULL;
  self->stdout_file = NULL;
  self->stderr_file = NULL;

  self->stdin_fork = 0;
  self->stdout_fork = 0;
565
  self->stderr_fork = 1;
566
567
568

  self->used_stdin = 0;
  self->used_pty = 0;
569
570
  self->used_x11 = 0;
  
571
  self->detach_end = 0;
572
  self->start_shell = 1;
573
  self->remote_forward = 0;
574

575
576
  self->inhibit_actions = 0;

577
578
579
580
  object_queue_init(&self->actions);  
}

/* Host to connect to */
581
582
583
584
585
DEFINE_COMMAND(client_options2actions)
     (struct command *s UNUSED,
      struct lsh_object *a,
      struct command_continuation *c,
      struct exception_handler *e UNUSED)
586
587
588
589
590
591
{
  CAST_SUBTYPE(client_options, options, a);

  trace("client.c: client_options2actions, %i actions\n",
	options->actions.length);
  
592
  COMMAND_RETURN(c, queue_to_list(&options->actions));
593
594
595
596
597
598
599
600
601
602
603
}

static const struct argp_option
client_options[] =
{
  /* Name, key, arg-name, flags, doc, group */
  { "port", 'p', "Port", 0, "Connect to this port.", 0 },
  { "user", 'l', "User name", 0, "Login as this user.", 0 },

  { NULL, 0, NULL, 0, "Actions:", CLIENT_ARGP_ACTION_GROUP },
  { "forward-local-port", 'L', "local-port:target-host:target-port", 0, "", 0 },
604
#if 0
605
606
607
608
  { "forward-remote-port", 'R', "remote-port:target-host:target-port", 0, "", 0 },
#endif
  { "nop", 'N', NULL, 0, "No operation (suppresses the default action, "
    "which is to spawn a remote shell)", 0 },
609
  { "background", 'B', NULL, 0, "Put process into the background. Implies -N.", 0 },
610
611
  { "execute", 'E', "command", 0, "Execute a command on the remote machine", 0 },
  { "shell", 'S', "command", 0, "Spawn a remote shell", 0 },
612
  { "subsystem", OPT_SUBSYSTEM, "subsystem-name", 0,
613
#if WITH_PTY_SUPPORT 
614
    "Connect to given subsystem. Implies --no-pty.",
615
#else
616
    "Connect to given subsystem.",
617
#endif
618
    0 },
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  /* { "gateway", 'G', NULL, 0, "Setup a local gateway", 0 }, */
  { NULL, 0, NULL, 0, "Universal not:", 0 },
  { "no", 'n', NULL, 0, "Inverts the effect of the next modifier", 0 },

  { NULL, 0, NULL, 0, "Modifiers that apply to port forwarding:",
    CLIENT_ARGP_MODIFIER_GROUP - 10 },
  { "remote-peers", 'g', NULL, 0, "Allow remote access to forwarded ports", 0 },
  { "no-remote-peers", 'g' | ARG_NOT, NULL, 0, 
    "Disallow remote access to forwarded ports (default).", 0 },

  { NULL, 0, NULL, 0, "Modifiers that apply to remote execution:", 0 },
  { "stdin", OPT_STDIN, "Filename", 0, "Redirect stdin", 0},
  { "no-stdin", OPT_STDIN | ARG_NOT, NULL, 0, "Redirect stdin from /dev/null", 0}, 
  { "stdout", OPT_STDOUT, "Filename", 0, "Redirect stdout", 0},
  { "no-stdout", OPT_STDOUT | ARG_NOT, NULL, 0, "Redirect stdout to /dev/null", 0}, 
  { "stderr", OPT_STDERR, "Filename", 0, "Redirect stderr", 0},
  { "no-stderr", OPT_STDERR | ARG_NOT, NULL, 0, "Redirect stderr to /dev/null", 0}, 
636

637
  { "cvs-workaround", OPT_FORK_STDIO, "i?o?e?", OPTION_ARG_OPTIONAL,
638
639
640
641
642
643
    "Avoid setting one or more of the stdio file descriptors into "
    "non-blocking mode. If no argument is provided, the workaround is "
    "applied to all three file descriptors. By default, the workaround "
    "is applied to stderr only.", 0 },
  { "no-cvs-workaround", OPT_FORK_STDIO | ARG_NOT, NULL, 0,
    "Disable the cvs workaround.", 0 },
644
645
646
  { "detach", OPT_DETACH, NULL, 0, "Detach from terminal at session end.", 0},
  { "no-detach", OPT_DETACH | ARG_NOT, NULL, 0, "Do not detach session at end," 
    " wait for all open channels (default).", 0},
647

648
649
650
651
#if WITH_PTY_SUPPORT
  { "pty", 't', NULL, 0, "Request a remote pty (default).", 0 },
  { "no-pty", 't' | ARG_NOT, NULL, 0, "Don't request a remote pty.", 0 },
#endif /* WITH_PTY_SUPPORT */
652
653
  { "escape-char", 'e', "Character", 0, "Escape char. `none' means disable. "
    "Default is to use `~' if we have a tty, otherwise none.", 0 },
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  { NULL, 0, NULL, 0, NULL, 0 }
};


/* GABA:
   (expr
     (name make_start_session)
     (params
       (open_session object command)
       (requests object object_list))
     (expr (lambda (connection)
       ((progn requests)
         ; Create a "session" channel
         (open_session connection)))))
*/
669

670
671
672
673
674
675
676
677
678
/* Requests a shell or command, and connects the channel to our stdio. */
/* GABA:
   (expr
     (name client_start_session)
     (params
       (request object command))
     (expr
       (lambda (session)
          (client_start_io (request session)))))
679
680
*/

681
682
683
684
685
686
687
static struct command *
make_client_start_session(struct command *request)
{
  CAST_SUBTYPE(command, r, client_start_session(request));
  return r;
}

688
689
static void
client_maybe_pty(struct client_options *options,
690
		 int default_pty,
691
		 struct object_queue *q)
692
693
{
#if WITH_PTY_SUPPORT
694
695
696
697
698
  int with_pty = options->with_pty;
  if (with_pty < 0)
    with_pty = default_pty;
  
  if (with_pty && !options->used_pty)
699
700
701
702
703
    {
      options->used_pty = 1;
      
      if (options->tty && INTERACT_IS_TTY(options->tty))
	{
704
705
706
707
708
709
710
711
712
713
714
	  struct command *get_pty = make_pty_request(options->tty);

	  if (get_pty)
	    object_queue_add_tail(q,
				  /* Ignore EXC_CHANNEL_REQUEST for the pty allocation call. */
				  &make_catch_apply
				  (make_catch_handler_info(EXC_ALL, EXC_CHANNEL_REQUEST,
							   0, NULL),
				   get_pty)->super);
	  else
	    werror("lsh: Can't use tty (probably getattr or atexit failed).\n");
715
716
	}
      else
717
718
719
720
721
722
723
724
725
726
727
	werror("lsh: No tty available.\n");
    }
#endif
}

static void
client_maybe_x11(struct client_options *options,
		 struct object_queue *q)
{
  if (options->with_x11)
    {
728
      char *display = getenv(ENV_DISPLAY);
729
730
      struct command *request = NULL;
      
731
      assert(options->random);
732
      if (display)
733
	request = make_forward_x11(display, options->random);
734
	  
735
736
737
738
      if (request)
	{
	  object_queue_add_tail(q, &request->super);
	  options->used_x11 = 1;
739
	}
740
741
      else
	werror("Can't find any local X11 display to forward.\n");
742
    }
743
}
744

745
746
747
748
749
/* Create an interactive session */
static struct command *
client_shell_session(struct client_options *options)
{
  struct ssh_channel *session = make_client_session(options);
750
  
751
752
753
  if (session)
    {
      struct object_queue session_requests;
754

755
      object_queue_init(&session_requests);
756

757
      client_maybe_pty(options, 1, &session_requests);
758
759
760
761
762
763
764
765
766
767
768
769
770
      client_maybe_x11(options, &session_requests);
  
      object_queue_add_tail(&session_requests,
			    &make_client_start_session(&request_shell.super)->super);
  
      {
	CAST_SUBTYPE(command, r,
		     make_start_session
		     (make_open_session_command(session),
		      queue_to_list_and_kill(&session_requests)));
	return r;
      }
    }
771
  else
772
    return NULL;
773
774
}

775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
/* Create a session for a subsystem */
static struct command *
client_subsystem_session(struct client_options *options,
		       struct lsh_string *subsystem)
{
  struct ssh_channel *session = make_client_session(options);
  
  if (session)
    {
      CAST_SUBTYPE(command, r,
		   make_start_session
		   (make_open_session_command(session),
		    make_object_list(1,
				     make_client_start_session
				     (make_subsystem_request(subsystem)),
				     -1)));
      return r;
    }
  
  return NULL;
}

797
798
799
800
/* Create a session executing a command line */
static struct command *
client_command_session(struct client_options *options,
		       struct lsh_string *command)
801
{
802
  struct ssh_channel *session = make_client_session(options);
803
  
804
805
  if (session)
    {
806
807
808
809
      struct object_queue session_requests;
    
      object_queue_init(&session_requests);
  
810
811
      /* NOTE: Doesn't ask for a pty by default. That's traditional
       * behaviour, although perhaps not the Right Thing. */
812
      
813
      client_maybe_pty(options, 0, &session_requests);
814
815
816
817
818
819
820
821
822
823
824
      client_maybe_x11(options, &session_requests);

      object_queue_add_tail(&session_requests,
			    &make_client_start_session(make_exec_request(command))->super);
      {
	CAST_SUBTYPE(command, r,
		     make_start_session
		     (make_open_session_command(session),
		      queue_to_list_and_kill(&session_requests)));
	return r;
      }
825
826
    }
  
827
828
829
  return NULL;
}

830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
struct command *
client_add_action(struct client_options *options,
		  struct command *action)
{
  if (action)
    object_queue_add_tail(&options->actions, &action->super);

  return action;
}

/* NOTE: Some of the original quoting is lost here. */
static struct lsh_string *
rebuild_command_line(unsigned argc, char **argv)
{
  unsigned length;
  unsigned i;
  unsigned pos;
  struct lsh_string *r;
  unsigned *alengths = alloca(sizeof(unsigned) * argc);
  
  assert (argc);
  length = argc - 1; /* Number of separating spaces. */

  for (i = 0; i<argc; i++)
    {
      alengths[i] = strlen(argv[i]);
      length += alengths[i];
    }

  r = lsh_string_alloc(length);
  memcpy(r->data, argv[0], alengths[0]);
  pos = alengths[0];
  for (i = 1; i<argc; i++)
    {
      r->data[pos++] = ' ';
      memcpy(r->data + pos, argv[i], alengths[i]);
      pos += alengths[i];
    }

  assert(pos == r->length);

  return r;
}

static int
fork_input(int in)
{
  /* pipe[0] for reading, pipe[1] for writing. */
  int pipe[2];

  if (!lsh_make_pipe(pipe))
    return -1;

  switch (fork())
    {
    case -1:
      /* Error */
      return -1;
    case 0:
      close(pipe[0]);
      if (lsh_copy_file(in, pipe[1]))
	_exit(EXIT_SUCCESS);
      else
	_exit(EXIT_FAILURE);
    default:
      /* Parent */
      close(pipe[1]);
      return pipe[0];
    }
}

static int
fork_output(int out)
{
  /* pipe[0] for reading, pipe[1] for writing. */
  int pipe[2];

  if (!lsh_make_pipe(pipe))
    return -1;

  switch (fork())
    {
    case -1:
      /* Error */
      return -1;
    case 0:
      close(pipe[1]);
      if (lsh_copy_file(pipe[0], out))
	_exit(EXIT_SUCCESS);
      else
	_exit(EXIT_FAILURE);
    default:
      /* Parent */
      close(pipe[0]);
      return pipe[1];
    }
}

928
/* A callback that exits the process immediately. */
929
DEFINE_ESCAPE(exit_callback, "Exit.")
930
931
932
933
{
  exit(EXIT_SUCCESS);
}

934
DEFINE_ESCAPE(verbose_callback, "Toggle verbose messages.")
935
936
937
938
939
940
{
  verbose_flag = !verbose_flag;
  if (verbose_flag)
    verbose("Enabling verbose messages\n");
}

941
DEFINE_ESCAPE(debug_callback, "Toggle debug messages.")
942
943
944
945
946
947
{
  debug_flag = !debug_flag;
  if (debug_flag)
    debug("Enabling debug messages\n");
}

948
DEFINE_ESCAPE(quiet_callback, "Toggle warning messages.")
949
950
951
952
953
{
  quiet_flag = !quiet_flag;
  if (!quiet_flag)
    werror("Enabling warning messages\n");
}
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970

DEFINE_COMMAND(background_process)
     (struct command *s UNUSED,
      struct lsh_object *a,
      struct command_continuation *c,
      struct exception_handler *e UNUSED)
{
  switch (fork())
    {
    case 0:
      /* Child */
      /* FIXME: Should we create a new process group, close our tty
       * and stdio, etc? */
      COMMAND_RETURN(c, a);
      break;
    case -1:
      /* Error */
971
      werror("background_process: fork failed %e\n", errno);
972
973
974
975
976
977
978
      COMMAND_RETURN(c, a);
      break;
    default:
      /* Parent */
      _exit(EXIT_SUCCESS);
    }
}
979

980
981
982
983
984
/* Create a session object. stdout and stderr are shared (although
 * with independent lsh_fd objects). stdin can be used by only one
 * session (until something "session-control"/"job-control" is added).
 * */
static struct ssh_channel *
985
make_client_session(struct client_options *options)
986
987
988
989
{
  int in;
  int out;
  int err;
990
  int is_tty = 0;
991
  struct ssh_channel *session;
992
  
993
  struct escape_info *escape = NULL;
994
  struct lsh_callback *detach_cb = NULL;
995
  
996
997
998
999
  debug("lsh.c: Setting up stdin\n");

  if (options->stdin_file)
    in = open(options->stdin_file, O_RDONLY);
1000
1001
  else
    {
1002
      if (options->used_stdin)
1003
	in = open("/dev/null", O_RDONLY);
1004
      else 
1005
	{
1006
	  in = (options->stdin_fork ? fork_input : dup)(STDIN_FILENO);
1007
1008
	  is_tty = isatty(STDIN_FILENO);
	  
1009
	  options->used_stdin = 1;
1010
1011
	}
    }
1012

1013
1014
  if (in < 0)
    {
1015
      werror("lsh: Can't dup/open stdin %e\n", errno);
1016
1017
1018
      return NULL;
    }

1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
  /* Attach the escape char handler, if appropriate. */
  if (options->escape > 0)
    {
      verbose("Enabling explicit escape character `%pc'\n",
	      options->escape);
      escape = make_escape_info(options->escape);
    }
  else if ( (options->escape < 0) && is_tty)
    {
      verbose("Enabling default escape character `%pc'\n",
	      DEFAULT_ESCAPE_CHAR);
      escape = make_escape_info(DEFAULT_ESCAPE_CHAR);
    }
1032

1033
  /* Bind ^Z to suspend. */
1034
  if (escape)
1035
1036
1037
1038
    {
      /* Bind ^Z to suspend. */
      escape->dispatch[26] = &suspend_callback;
      escape->dispatch['.'] = &exit_callback;
1039
1040
1041
1042
1043

      /* Toggle the verbosity flags */
      escape->dispatch['d'] = &debug_callback;
      escape->dispatch['v'] = &verbose_callback;
      escape->dispatch['q'] = &quiet_callback;      
1044
    }
1045
  
1046
1047
1048
1049
1050
1051
1052
1053
1054
  debug("lsh.c: Setting up stdout\n");

  if (options->stdout_file)
    out = open(options->stdout_file, O_WRONLY | O_CREAT, 0666);
  else if (options->stdout_fork)
    out = fork_output(STDOUT_FILENO);
  else
    out = dup(STDOUT_FILENO);

1055
1056
  if (out < 0)
    {
1057
      werror("lsh: Can't dup/open stdout %e\n", errno);
1058
1059
1060
1061
      close(in);
      return NULL;
    }

1062
1063
1064
1065
1066
1067
  debug("lsh.c: Setting up stderr\n");
  
  if (options->stderr_file)
    err = open(options->stderr_file, O_WRONLY | O_CREAT, 0666);
  else if (options->stderr_fork)
    err = fork_output(STDERR_FILENO);
1068
1069
1070
  else
    {
      err = dup(STDERR_FILENO);
1071
      set_error_nonblocking(STDERR_FILENO);
1072
1073
1074
1075
    }

  if (err < 0) 
    {
1076
      werror("lsh: Can't dup/open stderr!\n");
1077
1078
1079
1080
1081
      close(in);
      close(out);
      return NULL;
    }

1082
1083
1084
  if (options->detach_end) /* Detach? */
    detach_cb = make_detach_callback(options->exit_code);  

1085
  /* Clear options */
1086
  options->stdin_file = options->stdout_file = options->stderr_file = NULL;
1087
1088

  session = make_client_session_channel
1089
    (io_read(make_lsh_fd(in, "client stdin", options->handler),
1090
	     NULL, NULL),
1091
     io_write(make_lsh_fd(out, "client stdout", options->handler),
1092
1093
1094
	      BLOCK_SIZE, 
	      detach_cb
	      ),
1095
     io_write(make_lsh_fd(err, "client stderr", options->handler),
1096
	      BLOCK_SIZE, NULL),
1097
     escape,
1098
     WINDOW_SIZE,
1099
     options->exit_code);
1100
1101
1102
1103
1104
1105
  
  if (options->detach_end)
    {
      remember_resource(session->resources, make_detach_resource(detach_cb));
      options->detach_end = 0;
    }
1106
1107
1108
1109
1110
1111
1112

  /* The channel won't get registered in any other resource_list
   * until later, so we must register it here to avoid a "garbage
   * collecting a live resource!" crashes if the connection fails
   * early. */
  gc_global(&session->resources->super);
  return session;
1113
1114
}

1115

1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
/* Treat environment variables as sources for options */

void
envp_parse(const struct argp *argp,
	   const char** envp,
	   const char* name,
	   unsigned flags, 
	   void *input)
{
  CAST_SUBTYPE(client_options, options, input);
  int nlen = strlen(name);

  while (*envp)
    {
      if (!strncmp(*envp, name, nlen)) 	  /* Matching environment entry */
	{
	  char** sim_argv;
	  char* entry;

	  /* Make a copy we can modify */
	  
	  entry = strdup(*envp+nlen); 	  /* Skip variable name */

	  if (entry)
	    {
	      /* Extra space doesn't hurt */
	      sim_argv = malloc(sizeof(char*) * (strlen(entry)+2));

	      if (sim_argv)
		{
		  int sim_argc = 1;
		  char *token = strtok(entry, " \n\t");
		  
		  sim_argv[0] = "";

		  while (token) /* For all tokens in variable */
		    {
		      sim_argv[sim_argc++] = token;
		      token = strtok( NULL, " \n\t");
		    }

		  sim_argv[sim_argc] = NULL;
	
		  options->inhibit_actions = 1; /* Disable nnormal actions performed at end */
1160
		  argp_parse(argp, sim_argc, sim_argv, flags | ARGP_NO_ERRS | ARGP_NO_EXIT, NULL, input);
1161
1162
1163
1164
1165
1166
1167
1168
1169
		  options->inhibit_actions = 0; /* Reenable */
		}
	    }
	}

      envp++; 
   }
}

1170
1171
1172
/* Parse the argument for -R and -L */
int
client_parse_forward_arg(char *arg,
1173
			 uint32_t *listen_port,
1174
			 struct address_info **target)
1175
{
1176
1177
1178
1179
  char *first;
  char *second;
  char *end;
  long port;
1180
  
1181
1182
1183
  first = strchr(arg, ':');
  if (!first)
    return 0;
1184

1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
  second = strchr(first + 1, ':');
  if (!second || (second == first + 1))
    return 0;

  if (strchr(second + 1, ':'))
    return 0;

  port = strtol(arg, &end, 0);
  if ( (end == arg)  || (end != first)
       || (port < 0) || (port > 0xffff) )
    return 0;

  *listen_port = port;

  port = strtol(second + 1, &end, 0);
  if ( (end == second + 1) || (*end != '\0')
       || (port < 0) || (port > 0xffff) )
    return 0;

  *target = make_address_info(ssh_format("%ls", second - first - 1, first + 1), port);
1205
  
1206
1207
  return 1;
}
1208

1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
#define CASE_ARG(opt, attr, none)		\
  case opt:					\
    if (options->not)				\
      {						\
        options->not = 0;			\
						\
      case opt | ARG_NOT:			\
        options->attr = none;			\
        break;					\
      }						\
      						\
    options->attr = arg;			\
    break

#define CASE_FLAG(opt, flag)			\
  case opt:					\
    if (options->not)				\
      {						\
        options->not = 0;			\
						\
      case opt | ARG_NOT:			\
        options->flag = 0;			\
        break;					\
      }						\
      						\
    options->flag = 1;				\
    break

static error_t
client_argp_parser(int key, char *arg, struct argp_state *state)
{
  CAST_SUBTYPE(client_options, options, state->input);

  switch(key)
    {
    default:
      return ARGP_ERR_UNKNOWN;
    case ARGP_KEY_NO_ARGS:
      argp_usage(state);
      break;
    case ARGP_KEY_ARG:
      if (!state->arg_num)
1251
1252
	options->target = arg;
      
1253
      else
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
	/* Let the next case parse it.  */
	return ARGP_ERR_UNKNOWN;

      break;
    case ARGP_KEY_ARGS:
      client_add_action
	(options,
	 client_command_session
	 (options, rebuild_command_line(state->argc - state->next,
				     state->argv + state->next)));
      options->start_shell = 0;
      break;

    case ARGP_KEY_END:
1268
1269
1270
      if (options->inhibit_actions)
	break;

1271
      if (!options->user)
1272
	{
1273
1274
1275
	  argp_error(state, "No user name given. Use the -l option, or set LOGNAME in the environment.");
	  break;
	}
1276
1277
1278
1279
1280
1281
1282

#if WITH_TCP_FORWARD
      if (options->remote_forward)
	client_add_action(options,
			  make_install_fix_channel_open_handler
			  (ATOM_FORWARDED_TCPIP, &channel_open_forwarded_tcpip));
#endif /* WITH_TCP_FORWARD */
1283

1284
1285
1286
1287
      /* Add shell action */
      if (options->start_shell)
	client_add_action(options, client_shell_session(options));

1288
1289
1290
1291
      if (options->used_x11)
	client_add_action(options,
			  make_install_fix_channel_open_handler
			  (ATOM_X11,
1292
			   &channel_open_x11));
1293
      
1294
1295
      /* Install suspend-handler */
      suspend_install_handler();
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
      break;

    case 'p':
      options->port = arg;
      break;

    case 'l':
      options->user = arg;
      break;

1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
    case 'e':
      if (arg[0] && !arg[1])
	/* A single char argument */
	options->escape = arg[0];
      else if (!strcasecmp(arg, "none"))
	options->escape = 0;
      else
	argp_error(state, "Invalid escape char: `%s'. "
		   "You must use a single character or `none'.", arg);
      break;
1316
    case 'E':
1317
1318
1319
      client_add_action(options,
			client_command_session(options,
					       ssh_format("%lz", arg)));
1320
1321
1322
1323
1324
1325
      break;

    case 'S':
      client_add_action(options, client_shell_session(options));
      break;

1326
    case OPT_SUBSYSTEM: