mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-04-08 18:35:05 +02:00
- djm@cvs.openbsd.org 2004/06/13 15:03:02
[channels.c channels.h clientloop.c clientloop.h includes.h readconf.c] [readconf.h scp.1 sftp.1 ssh.1 ssh.c ssh_config.5] implement session multiplexing in the client (the server has supported this since 2.0); ok markus@
This commit is contained in:
parent
05202ffe21
commit
0e220dbfbc
@ -24,6 +24,11 @@
|
||||
[ssh.1 ssh_config.5 sshd_config.5]
|
||||
List supported ciphers in man pages, tidy up ssh -c;
|
||||
"looks fine" jmc@, ok markus@
|
||||
- djm@cvs.openbsd.org 2004/06/13 15:03:02
|
||||
[channels.c channels.h clientloop.c clientloop.h includes.h readconf.c]
|
||||
[readconf.h scp.1 sftp.1 ssh.1 ssh.c ssh_config.5]
|
||||
implement session multiplexing in the client (the server has supported
|
||||
this since 2.0); ok markus@
|
||||
|
||||
20040603
|
||||
- (dtucker) [auth-pam.c] Don't use pam_* namespace for sshd's PAM functions.
|
||||
@ -1208,4 +1213,4 @@
|
||||
- (djm) Trim deprecated options from INSTALL. Mention UsePAM
|
||||
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
|
||||
|
||||
$Id: ChangeLog,v 1.3381 2004/06/15 00:30:39 djm Exp $
|
||||
$Id: ChangeLog,v 1.3382 2004/06/15 00:34:08 djm Exp $
|
||||
|
76
channels.c
76
channels.c
@ -39,7 +39,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: channels.c,v 1.203 2004/05/26 23:02:39 markus Exp $");
|
||||
RCSID("$OpenBSD: channels.c,v 1.204 2004/06/13 15:03:02 djm Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "ssh1.h"
|
||||
@ -172,6 +172,7 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
|
||||
c->rfd = rfd;
|
||||
c->wfd = wfd;
|
||||
c->sock = (rfd == wfd) ? rfd : -1;
|
||||
c->ctl_fd = -1; /* XXX: set elsewhere */
|
||||
c->efd = efd;
|
||||
c->extended_usage = extusage;
|
||||
|
||||
@ -263,6 +264,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
|
||||
c->single_connection = 0;
|
||||
c->detach_user = NULL;
|
||||
c->confirm = NULL;
|
||||
c->confirm_ctx = NULL;
|
||||
c->input_filter = NULL;
|
||||
debug("channel %d: new [%s]", found, remote_name);
|
||||
return c;
|
||||
@ -304,10 +306,11 @@ channel_close_fd(int *fdp)
|
||||
static void
|
||||
channel_close_fds(Channel *c)
|
||||
{
|
||||
debug3("channel %d: close_fds r %d w %d e %d",
|
||||
c->self, c->rfd, c->wfd, c->efd);
|
||||
debug3("channel %d: close_fds r %d w %d e %d c %d",
|
||||
c->self, c->rfd, c->wfd, c->efd, c->ctl_fd);
|
||||
|
||||
channel_close_fd(&c->sock);
|
||||
channel_close_fd(&c->ctl_fd);
|
||||
channel_close_fd(&c->rfd);
|
||||
channel_close_fd(&c->wfd);
|
||||
channel_close_fd(&c->efd);
|
||||
@ -333,6 +336,8 @@ channel_free(Channel *c)
|
||||
|
||||
if (c->sock != -1)
|
||||
shutdown(c->sock, SHUT_RDWR);
|
||||
if (c->ctl_fd != -1)
|
||||
shutdown(c->ctl_fd, SHUT_RDWR);
|
||||
channel_close_fds(c);
|
||||
buffer_free(&c->input);
|
||||
buffer_free(&c->output);
|
||||
@ -550,12 +555,13 @@ channel_open_message(void)
|
||||
case SSH_CHANNEL_X11_OPEN:
|
||||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n",
|
||||
snprintf(buf, sizeof buf,
|
||||
" #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n",
|
||||
c->self, c->remote_name,
|
||||
c->type, c->remote_id,
|
||||
c->istate, buffer_len(&c->input),
|
||||
c->ostate, buffer_len(&c->output),
|
||||
c->rfd, c->wfd);
|
||||
c->rfd, c->wfd, c->ctl_fd);
|
||||
buffer_append(&buffer, buf, strlen(buf));
|
||||
continue;
|
||||
default:
|
||||
@ -596,14 +602,14 @@ channel_request_start(int id, char *service, int wantconfirm)
|
||||
logit("channel_request_start: %d: unknown channel id", id);
|
||||
return;
|
||||
}
|
||||
debug2("channel %d: request %s", id, service) ;
|
||||
debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
|
||||
packet_start(SSH2_MSG_CHANNEL_REQUEST);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_cstring(service);
|
||||
packet_put_char(wantconfirm);
|
||||
}
|
||||
void
|
||||
channel_register_confirm(int id, channel_callback_fn *fn)
|
||||
channel_register_confirm(int id, channel_callback_fn *fn, void *ctx)
|
||||
{
|
||||
Channel *c = channel_lookup(id);
|
||||
|
||||
@ -612,6 +618,7 @@ channel_register_confirm(int id, channel_callback_fn *fn)
|
||||
return;
|
||||
}
|
||||
c->confirm = fn;
|
||||
c->confirm_ctx = ctx;
|
||||
}
|
||||
void
|
||||
channel_register_cleanup(int id, channel_callback_fn *fn)
|
||||
@ -729,6 +736,10 @@ channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset)
|
||||
buffer_len(&c->extended) < c->remote_window)
|
||||
FD_SET(c->efd, readset);
|
||||
}
|
||||
/* XXX: What about efd? races? */
|
||||
if (compat20 && c->ctl_fd != -1 &&
|
||||
c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN)
|
||||
FD_SET(c->ctl_fd, readset);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1482,6 +1493,33 @@ channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
|
||||
return 1;
|
||||
}
|
||||
static int
|
||||
channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset)
|
||||
{
|
||||
char buf[16];
|
||||
int len;
|
||||
|
||||
/* Monitor control fd to detect if the slave client exits */
|
||||
if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
|
||||
len = read(c->ctl_fd, buf, sizeof(buf));
|
||||
if (len < 0 && (errno == EINTR || errno == EAGAIN))
|
||||
return 1;
|
||||
if (len <= 0) {
|
||||
debug2("channel %d: ctl read<=0", c->self);
|
||||
if (c->type != SSH_CHANNEL_OPEN) {
|
||||
debug2("channel %d: not open", c->self);
|
||||
chan_mark_dead(c);
|
||||
return -1;
|
||||
} else {
|
||||
chan_read_failed(c);
|
||||
chan_write_failed(c);
|
||||
}
|
||||
return -1;
|
||||
} else
|
||||
fatal("%s: unexpected data on ctl fd", __func__);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static int
|
||||
channel_check_window(Channel *c)
|
||||
{
|
||||
if (c->type == SSH_CHANNEL_OPEN &&
|
||||
@ -1511,6 +1549,7 @@ channel_post_open(Channel *c, fd_set * readset, fd_set * writeset)
|
||||
if (!compat20)
|
||||
return;
|
||||
channel_handle_efd(c, readset, writeset);
|
||||
channel_handle_ctl(c, readset, writeset);
|
||||
channel_check_window(c);
|
||||
}
|
||||
|
||||
@ -2011,7 +2050,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
|
||||
c->remote_maxpacket = packet_get_int();
|
||||
if (c->confirm) {
|
||||
debug2("callback start");
|
||||
c->confirm(c->self, NULL);
|
||||
c->confirm(c->self, c->confirm_ctx);
|
||||
debug2("callback done");
|
||||
}
|
||||
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
|
||||
@ -2531,6 +2570,27 @@ channel_connect_to(const char *host, u_short port)
|
||||
return connect_to(host, port);
|
||||
}
|
||||
|
||||
void
|
||||
channel_send_window_changes(void)
|
||||
{
|
||||
int i;
|
||||
struct winsize ws;
|
||||
|
||||
for (i = 0; i < channels_alloc; i++) {
|
||||
if (channels[i] == NULL ||
|
||||
channels[i]->type != SSH_CHANNEL_OPEN)
|
||||
continue;
|
||||
if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
|
||||
continue;
|
||||
channel_request_start(i, "window-change", 0);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
|
||||
/* -- X11 forwarding */
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.h,v 1.72 2004/05/21 11:33:11 djm Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.73 2004/06/13 15:03:02 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -76,6 +76,7 @@ struct Channel {
|
||||
int wfd; /* write fd */
|
||||
int efd; /* extended fd */
|
||||
int sock; /* sock fd */
|
||||
int ctl_fd; /* control fd (client sharing) */
|
||||
int isatty; /* rfd is a tty */
|
||||
int wfd_isatty; /* wfd is a tty */
|
||||
int force_drain; /* force close on iEOF */
|
||||
@ -105,6 +106,7 @@ struct Channel {
|
||||
/* callback */
|
||||
channel_callback_fn *confirm;
|
||||
channel_callback_fn *detach_user;
|
||||
void *confirm_ctx;
|
||||
|
||||
/* filter */
|
||||
channel_filter_fn *input_filter;
|
||||
@ -161,10 +163,11 @@ void channel_stop_listening(void);
|
||||
void channel_send_open(int);
|
||||
void channel_request_start(int, char *, int);
|
||||
void channel_register_cleanup(int, channel_callback_fn *);
|
||||
void channel_register_confirm(int, channel_callback_fn *);
|
||||
void channel_register_confirm(int, channel_callback_fn *, void *);
|
||||
void channel_register_filter(int, channel_filter_fn *);
|
||||
void channel_cancel_cleanup(int);
|
||||
int channel_close_fd(int *);
|
||||
void channel_send_window_changes(void);
|
||||
|
||||
/* protocol handler */
|
||||
|
||||
|
327
clientloop.c
327
clientloop.c
@ -59,7 +59,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: clientloop.c,v 1.122 2004/05/22 06:32:12 djm Exp $");
|
||||
RCSID("$OpenBSD: clientloop.c,v 1.123 2004/06/13 15:03:02 djm Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "ssh1.h"
|
||||
@ -81,6 +81,9 @@ RCSID("$OpenBSD: clientloop.c,v 1.122 2004/05/22 06:32:12 djm Exp $");
|
||||
#include "atomicio.h"
|
||||
#include "sshpty.h"
|
||||
#include "misc.h"
|
||||
#include "monitor_fdpass.h"
|
||||
#include "match.h"
|
||||
#include "msg.h"
|
||||
|
||||
/* import options */
|
||||
extern Options options;
|
||||
@ -91,6 +94,9 @@ extern int stdin_null_flag;
|
||||
/* Flag indicating that no shell has been requested */
|
||||
extern int no_shell_flag;
|
||||
|
||||
/* Control socket */
|
||||
extern int control_fd;
|
||||
|
||||
/*
|
||||
* Name of the host we are connecting to. This is the name given on the
|
||||
* command line, or the HostName specified for the user-supplied name in a
|
||||
@ -131,9 +137,19 @@ static int server_alive_timeouts = 0;
|
||||
static void client_init_dispatch(void);
|
||||
int session_ident = -1;
|
||||
|
||||
struct confirm_ctx {
|
||||
int want_tty;
|
||||
int want_subsys;
|
||||
Buffer cmd;
|
||||
char *term;
|
||||
struct termios tio;
|
||||
};
|
||||
|
||||
/*XXX*/
|
||||
extern Kex *xxx_kex;
|
||||
|
||||
void ssh_process_session2_setup(int, int, int, Buffer *);
|
||||
|
||||
/* Restores stdin to blocking mode. */
|
||||
|
||||
static void
|
||||
@ -291,19 +307,13 @@ client_check_window_change(void)
|
||||
/** XXX race */
|
||||
received_window_change_signal = 0;
|
||||
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
return;
|
||||
|
||||
debug2("client_check_window_change: changed");
|
||||
|
||||
if (compat20) {
|
||||
channel_request_start(session_ident, "window-change", 0);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
packet_send();
|
||||
channel_send_window_changes();
|
||||
} else {
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
return;
|
||||
packet_start(SSH_CMSG_WINDOW_SIZE);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_col);
|
||||
@ -335,7 +345,6 @@ server_alive_check(void)
|
||||
* Waits until the client can do something (some data becomes available on
|
||||
* one of the file descriptors).
|
||||
*/
|
||||
|
||||
static void
|
||||
client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||
int *maxfdp, int *nallocp, int rekeying)
|
||||
@ -381,6 +390,9 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||
if (packet_have_data_to_write())
|
||||
FD_SET(connection_out, *writesetp);
|
||||
|
||||
if (control_fd != -1)
|
||||
FD_SET(control_fd, *readsetp);
|
||||
|
||||
/*
|
||||
* Wait for something to happen. This will suspend the process until
|
||||
* some selected descriptor can be read, written, or has some other
|
||||
@ -499,6 +511,176 @@ client_process_net_input(fd_set * readset)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
int id;
|
||||
Channel *c;
|
||||
|
||||
id = packet_get_int();
|
||||
packet_check_eom();
|
||||
|
||||
if ((c = channel_lookup(id)) == NULL) {
|
||||
error("%s: no channel for id %d", __func__, id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == SSH2_MSG_CHANNEL_SUCCESS)
|
||||
debug2("Request suceeded on channel %d", id);
|
||||
else if (type == SSH2_MSG_CHANNEL_FAILURE) {
|
||||
error("Request failed on channel %d", id);
|
||||
channel_free(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_extra_session2_setup(int id, void *arg)
|
||||
{
|
||||
struct confirm_ctx *cctx = arg;
|
||||
Channel *c;
|
||||
|
||||
if (cctx == NULL)
|
||||
fatal("%s: cctx == NULL", __func__);
|
||||
if ((c = channel_lookup(id)) == NULL)
|
||||
fatal("%s: no channel for id %d", __func__, id);
|
||||
|
||||
client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
|
||||
cctx->term, &cctx->tio, c->rfd, &cctx->cmd,
|
||||
client_subsystem_reply);
|
||||
|
||||
c->confirm_ctx = NULL;
|
||||
buffer_free(&cctx->cmd);
|
||||
free(cctx->term);
|
||||
free(cctx);
|
||||
}
|
||||
|
||||
static void
|
||||
client_process_control(fd_set * readset)
|
||||
{
|
||||
Buffer m;
|
||||
Channel *c;
|
||||
int client_fd, new_fd[3], ver;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_storage addr;
|
||||
struct confirm_ctx *cctx;
|
||||
char *cmd;
|
||||
u_int len;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
|
||||
/*
|
||||
* Accept connection on control socket
|
||||
*/
|
||||
if (control_fd == -1 || !FD_ISSET(control_fd, readset))
|
||||
return;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addrlen = sizeof(addr);
|
||||
if ((client_fd = accept(control_fd,
|
||||
(struct sockaddr*)&addr, &addrlen)) == -1) {
|
||||
error("%s accept: %s", __func__, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (getpeereid(client_fd, &euid, &egid) < 0) {
|
||||
error("%s getpeereid failed: %s", __func__, strerror(errno));
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
if ((euid != 0) && (getuid() != euid)) {
|
||||
error("control mode uid mismatch: peer euid %u != uid %u",
|
||||
(u_int) euid, (u_int) getuid());
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
/* XXX: implement use of ssh-askpass to confirm additional channels */
|
||||
|
||||
unset_nonblock(client_fd);
|
||||
|
||||
buffer_init(&m);
|
||||
|
||||
buffer_put_int(&m, getpid());
|
||||
if (ssh_msg_send(client_fd, /* version */0, &m) == -1) {
|
||||
error("%s: client msg_send failed", __func__);
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
buffer_clear(&m);
|
||||
|
||||
if (ssh_msg_recv(client_fd, &m) == -1) {
|
||||
error("%s: client msg_recv failed", __func__);
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ver = buffer_get_char(&m)) != 0) {
|
||||
error("%s: wrong client version %d", __func__, ver);
|
||||
buffer_free(&m);
|
||||
close(client_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
cctx = xmalloc(sizeof(*cctx));
|
||||
memset(cctx, 0, sizeof(*cctx));
|
||||
|
||||
cctx->want_tty = buffer_get_int(&m);
|
||||
cctx->want_subsys = buffer_get_int(&m);
|
||||
cctx->term = buffer_get_string(&m, &len);
|
||||
|
||||
cmd = buffer_get_string(&m, &len);
|
||||
buffer_init(&cctx->cmd);
|
||||
buffer_append(&cctx->cmd, cmd, strlen(cmd));
|
||||
|
||||
debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
|
||||
cctx->want_tty, cctx->want_subsys, cmd);
|
||||
|
||||
/* Gather fds from client */
|
||||
new_fd[0] = mm_receive_fd(client_fd);
|
||||
new_fd[1] = mm_receive_fd(client_fd);
|
||||
new_fd[2] = mm_receive_fd(client_fd);
|
||||
|
||||
debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
|
||||
new_fd[0], new_fd[1], new_fd[2]);
|
||||
|
||||
/* Try to pick up ttymodes from client before it goes raw */
|
||||
if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
|
||||
error("%s: tcgetattr: %s", __func__, strerror(errno));
|
||||
|
||||
buffer_clear(&m);
|
||||
if (ssh_msg_send(client_fd, /* version */0, &m) == -1) {
|
||||
error("%s: client msg_send failed", __func__);
|
||||
close(client_fd);
|
||||
close(new_fd[0]);
|
||||
close(new_fd[1]);
|
||||
close(new_fd[2]);
|
||||
return;
|
||||
}
|
||||
buffer_free(&m);
|
||||
|
||||
/* enable nonblocking unless tty */
|
||||
if (!isatty(new_fd[0]))
|
||||
set_nonblock(new_fd[0]);
|
||||
if (!isatty(new_fd[1]))
|
||||
set_nonblock(new_fd[1]);
|
||||
if (!isatty(new_fd[2]))
|
||||
set_nonblock(new_fd[2]);
|
||||
|
||||
set_nonblock(client_fd);
|
||||
|
||||
c = channel_new("session", SSH_CHANNEL_OPENING,
|
||||
new_fd[0], new_fd[1], new_fd[2],
|
||||
CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT,
|
||||
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
|
||||
|
||||
/* XXX */
|
||||
c->ctl_fd = client_fd;
|
||||
|
||||
debug3("%s: channel_new: %d", __func__, c->self);
|
||||
|
||||
channel_send_open(c->self);
|
||||
channel_register_confirm(c->self, client_extra_session2_setup, cctx);
|
||||
}
|
||||
|
||||
static void
|
||||
process_cmdline(void)
|
||||
{
|
||||
@ -901,9 +1083,6 @@ simple_escape_filter(Channel *c, char *buf, int len)
|
||||
static void
|
||||
client_channel_closed(int id, void *arg)
|
||||
{
|
||||
if (id != session_ident)
|
||||
error("client_channel_closed: id %d != session_ident %d",
|
||||
id, session_ident);
|
||||
channel_cancel_cleanup(id);
|
||||
session_closed = 1;
|
||||
leave_raw_mode();
|
||||
@ -937,6 +1116,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
connection_in = packet_get_connection_in();
|
||||
connection_out = packet_get_connection_out();
|
||||
max_fd = MAX(connection_in, connection_out);
|
||||
if (control_fd != -1)
|
||||
max_fd = MAX(max_fd, control_fd);
|
||||
|
||||
if (!compat20) {
|
||||
/* enable nonblocking unless tty */
|
||||
@ -1054,6 +1235,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
/* Buffer input from the connection. */
|
||||
client_process_net_input(readset);
|
||||
|
||||
/* Accept control connections. */
|
||||
client_process_control(readset);
|
||||
|
||||
if (quit_pending)
|
||||
break;
|
||||
|
||||
@ -1385,7 +1569,7 @@ static void
|
||||
client_input_channel_req(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
int id, reply, success = 0;
|
||||
int exitval, id, reply, success = 0;
|
||||
char *rtype;
|
||||
|
||||
id = packet_get_int();
|
||||
@ -1395,18 +1579,21 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
|
||||
debug("client_input_channel_req: channel %d rtype %s reply %d",
|
||||
id, rtype, reply);
|
||||
|
||||
if (session_ident == -1) {
|
||||
error("client_input_channel_req: no channel %d", session_ident);
|
||||
} else if (id != session_ident) {
|
||||
error("client_input_channel_req: channel %d: wrong channel: %d",
|
||||
session_ident, id);
|
||||
}
|
||||
c = channel_lookup(id);
|
||||
if (c == NULL) {
|
||||
error("client_input_channel_req: channel %d: unknown channel", id);
|
||||
} else if (strcmp(rtype, "exit-status") == 0) {
|
||||
success = 1;
|
||||
exit_status = packet_get_int();
|
||||
exitval = packet_get_int();
|
||||
if (id == session_ident) {
|
||||
success = 1;
|
||||
exit_status = exitval;
|
||||
} else if (c->ctl_fd == -1) {
|
||||
error("client_input_channel_req: unexpected channel %d",
|
||||
session_ident);
|
||||
} else {
|
||||
atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval));
|
||||
success = 1;
|
||||
}
|
||||
packet_check_eom();
|
||||
}
|
||||
if (reply) {
|
||||
@ -1437,6 +1624,98 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt)
|
||||
xfree(rtype);
|
||||
}
|
||||
|
||||
void
|
||||
client_session2_setup(int id, int want_tty, int want_subsystem,
|
||||
const char *term, struct termios *tiop, int in_fd, Buffer *cmd,
|
||||
dispatch_fn *subsys_repl)
|
||||
{
|
||||
int len;
|
||||
|
||||
debug2("%s: id %d", __func__, id);
|
||||
|
||||
if (want_tty) {
|
||||
struct winsize ws;
|
||||
struct termios tio;
|
||||
|
||||
/* Store window size in the packet. */
|
||||
if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
|
||||
channel_request_start(id, "pty-req", 0);
|
||||
packet_put_cstring(term != NULL ? term : "");
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
tio = get_saved_tio();
|
||||
tty_make_modes(-1, tiop != NULL ? tiop : &tio);
|
||||
packet_send();
|
||||
/* XXX wait for reply */
|
||||
}
|
||||
|
||||
/* Transfer any environment variables from client to server */
|
||||
if (options.num_send_env != 0) {
|
||||
int i, j, matched;
|
||||
extern char **environ;
|
||||
char *name, *val;
|
||||
|
||||
debug("Sending environment.");
|
||||
for (i = 0; environ && environ[i] != NULL; i++) {
|
||||
/* Split */
|
||||
name = xstrdup(environ[i]);
|
||||
if ((val = strchr(name, '=')) == NULL) {
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
*val++ = '\0';
|
||||
|
||||
matched = 0;
|
||||
for (j = 0; j < options.num_send_env; j++) {
|
||||
if (match_pattern(name, options.send_env[j])) {
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
debug3("Ignored env %s", name);
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Sending env %s = %s", name, val);
|
||||
channel_request_start(id, "env", 0);
|
||||
packet_put_cstring(name);
|
||||
packet_put_cstring(val);
|
||||
packet_send();
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
len = buffer_len(cmd);
|
||||
if (len > 0) {
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
if (want_subsystem) {
|
||||
debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd));
|
||||
channel_request_start(id, "subsystem", subsys_repl != NULL);
|
||||
if (subsys_repl != NULL) {
|
||||
/* register callback for reply */
|
||||
/* XXX we assume that client_loop has already been called */
|
||||
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl);
|
||||
}
|
||||
} else {
|
||||
debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd));
|
||||
channel_request_start(id, "exec", 0);
|
||||
}
|
||||
packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
|
||||
packet_send();
|
||||
} else {
|
||||
channel_request_start(id, "shell", 0);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_init_dispatch_20(void)
|
||||
{
|
||||
@ -1503,5 +1782,7 @@ cleanup_exit(int i)
|
||||
{
|
||||
leave_raw_mode();
|
||||
leave_non_blocking();
|
||||
if (options.control_path != NULL && control_fd != -1)
|
||||
unlink(options.control_path);
|
||||
_exit(i);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: clientloop.h,v 1.8 2003/12/16 15:49:51 markus Exp $ */
|
||||
/* $OpenBSD: clientloop.h,v 1.9 2004/06/13 15:03:02 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -38,3 +38,5 @@
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int, int, int);
|
||||
void client_global_request_reply_fwd(int, u_int32_t, void *);
|
||||
void client_session2_setup(int, int, int, const char *, struct termios *,
|
||||
int, Buffer *, dispatch_fn *);
|
||||
|
@ -25,7 +25,7 @@
|
||||
#ifndef _DEFINES_H
|
||||
#define _DEFINES_H
|
||||
|
||||
/* $Id: defines.h,v 1.115 2004/04/14 07:24:30 dtucker Exp $ */
|
||||
/* $Id: defines.h,v 1.116 2004/06/15 00:34:08 djm Exp $ */
|
||||
|
||||
|
||||
/* Constants */
|
||||
@ -462,6 +462,9 @@ struct winsize {
|
||||
(struct cmsghdr *)NULL)
|
||||
#endif /* CMSG_FIRSTHDR */
|
||||
|
||||
#ifndef offsetof
|
||||
# define offsetof(type, member) ((size_t) &((type *)0)->member)
|
||||
#endif
|
||||
|
||||
/* Function replacement / compatibility hacks */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: includes.h,v 1.17 2002/01/26 16:44:22 stevesk Exp $ */
|
||||
/* $OpenBSD: includes.h,v 1.18 2004/06/13 15:03:02 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -33,6 +33,7 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
|
||||
#include <grp.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h> /* For PATH_MAX */
|
||||
|
18
readconf.c
18
readconf.c
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: readconf.c,v 1.131 2004/05/27 00:50:13 dtucker Exp $");
|
||||
RCSID("$OpenBSD: readconf.c,v 1.132 2004/06/13 15:03:02 djm Exp $");
|
||||
|
||||
#include "ssh.h"
|
||||
#include "xmalloc.h"
|
||||
@ -106,7 +106,7 @@ typedef enum {
|
||||
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
|
||||
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
|
||||
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
|
||||
oSendEnv,
|
||||
oSendEnv, oControlPath, oControlMaster,
|
||||
oDeprecated, oUnsupported
|
||||
} OpCodes;
|
||||
|
||||
@ -195,6 +195,8 @@ static struct {
|
||||
{ "serveraliveinterval", oServerAliveInterval },
|
||||
{ "serveralivecountmax", oServerAliveCountMax },
|
||||
{ "sendenv", oSendEnv },
|
||||
{ "controlpath", oControlPath },
|
||||
{ "controlmaster", oControlMaster },
|
||||
{ NULL, oBadOption }
|
||||
};
|
||||
|
||||
@ -764,6 +766,14 @@ parse_int:
|
||||
}
|
||||
break;
|
||||
|
||||
case oControlPath:
|
||||
charptr = &options->control_path;
|
||||
goto parse_string;
|
||||
|
||||
case oControlMaster:
|
||||
intptr = &options->control_master;
|
||||
goto parse_flag;
|
||||
|
||||
case oDeprecated:
|
||||
debug("%s line %d: Deprecated option \"%s\"",
|
||||
filename, linenum, keyword);
|
||||
@ -905,6 +915,8 @@ initialize_options(Options * options)
|
||||
options->server_alive_interval = -1;
|
||||
options->server_alive_count_max = -1;
|
||||
options->num_send_env = 0;
|
||||
options->control_path = NULL;
|
||||
options->control_master = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1025,6 +1037,8 @@ fill_default_options(Options * options)
|
||||
options->server_alive_interval = 0;
|
||||
if (options->server_alive_count_max == -1)
|
||||
options->server_alive_count_max = 3;
|
||||
if (options->control_master == -1)
|
||||
options->control_master = 0;
|
||||
/* options->proxy_command should not be set by default */
|
||||
/* options->user will be set in the main program if appropriate */
|
||||
/* options->hostname will be set in the main program if appropriate */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: readconf.h,v 1.62 2004/04/27 09:46:37 djm Exp $ */
|
||||
/* $OpenBSD: readconf.h,v 1.63 2004/06/13 15:03:02 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -108,6 +108,9 @@ typedef struct {
|
||||
|
||||
int num_send_env;
|
||||
char *send_env[MAX_SEND_ENV];
|
||||
|
||||
char *control_path;
|
||||
int control_master;
|
||||
} Options;
|
||||
|
||||
|
||||
|
4
scp.1
4
scp.1
@ -9,7 +9,7 @@
|
||||
.\"
|
||||
.\" Created: Sun May 7 00:14:37 1995 ylo
|
||||
.\"
|
||||
.\" $OpenBSD: scp.1,v 1.35 2004/05/04 18:36:07 jmc Exp $
|
||||
.\" $OpenBSD: scp.1,v 1.36 2004/06/13 15:03:02 djm Exp $
|
||||
.\"
|
||||
.Dd September 25, 1999
|
||||
.Dt SCP 1
|
||||
@ -128,6 +128,8 @@ For full details of the options listed below, and their possible values, see
|
||||
.It CompressionLevel
|
||||
.It ConnectionAttempts
|
||||
.It ConnectTimeout
|
||||
.It ControlMaster
|
||||
.It ControlPath
|
||||
.It GlobalKnownHostsFile
|
||||
.It GSSAPIAuthentication
|
||||
.It GSSAPIDelegateCredentials
|
||||
|
4
sftp.1
4
sftp.1
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: sftp.1,v 1.54 2004/05/02 23:02:17 dtucker Exp $
|
||||
.\" $OpenBSD: sftp.1,v 1.55 2004/06/13 15:03:02 djm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
|
||||
.\"
|
||||
@ -154,6 +154,8 @@ For full details of the options listed below, and their possible values, see
|
||||
.It CompressionLevel
|
||||
.It ConnectionAttempts
|
||||
.It ConnectTimeout
|
||||
.It ControlMaster
|
||||
.It ControlPath
|
||||
.It GlobalKnownHostsFile
|
||||
.It GSSAPIAuthentication
|
||||
.It GSSAPIDelegateCredentials
|
||||
|
@ -39,7 +39,7 @@
|
||||
#include "pathnames.h"
|
||||
#include "log.h"
|
||||
|
||||
RCSID("$Id: ssh-rand-helper.c,v 1.16 2003/11/21 12:56:47 djm Exp $");
|
||||
RCSID("$Id: ssh-rand-helper.c,v 1.17 2004/06/15 00:34:08 djm Exp $");
|
||||
|
||||
/* Number of bytes we write out */
|
||||
#define OUTPUT_SEED_SIZE 48
|
||||
@ -69,10 +69,6 @@ extern char *__progname;
|
||||
char *__progname;
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
# define offsetof(type, member) ((size_t) &((type *)0)->member)
|
||||
#endif
|
||||
|
||||
#define WHITESPACE " \t\n"
|
||||
|
||||
#ifndef RUSAGE_SELF
|
||||
|
26
ssh.1
26
ssh.1
@ -34,7 +34,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh.1,v 1.189 2004/06/13 14:01:42 dtucker Exp $
|
||||
.\" $OpenBSD: ssh.1,v 1.190 2004/06/13 15:03:02 djm Exp $
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH 1
|
||||
.Os
|
||||
@ -43,7 +43,7 @@
|
||||
.Nd OpenSSH SSH client (remote login program)
|
||||
.Sh SYNOPSIS
|
||||
.Nm ssh
|
||||
.Op Fl 1246AaCfgkNnqsTtVvXxY
|
||||
.Op Fl 1246AaCfgkMNnqSsTtVvXxY
|
||||
.Op Fl b Ar bind_address
|
||||
.Op Fl c Ar cipher_spec
|
||||
.Op Fl D Ar port
|
||||
@ -605,6 +605,17 @@ be specified in order of preference.
|
||||
See the
|
||||
.Cm MACs
|
||||
keyword for more information.
|
||||
.It Fl M
|
||||
Places the
|
||||
.Nm
|
||||
client into
|
||||
.Dq master
|
||||
mode for connection sharing.
|
||||
Refer to the description of
|
||||
.Cm ControlMaster
|
||||
in
|
||||
.Xr ssh_config 5
|
||||
for details.
|
||||
.It Fl N
|
||||
Do not execute a remote command.
|
||||
This is useful for just forwarding ports
|
||||
@ -649,6 +660,8 @@ For full details of the options listed below, and their possible values, see
|
||||
.It CompressionLevel
|
||||
.It ConnectionAttempts
|
||||
.It ConnectTimeout
|
||||
.It ControlMaster
|
||||
.It ControlPath
|
||||
.It DynamicForward
|
||||
.It EscapeChar
|
||||
.It ForwardAgent
|
||||
@ -724,6 +737,15 @@ IPv6 addresses can be specified with an alternative syntax:
|
||||
.Ar hostport .
|
||||
.Xc
|
||||
.Sm on
|
||||
.It Fl S
|
||||
Places the
|
||||
.Nm
|
||||
client into slave mode for connection sharing.
|
||||
Refer to the description of
|
||||
.Cm ControlMaster
|
||||
in
|
||||
.Xr ssh_config 5
|
||||
for details.
|
||||
.It Fl s
|
||||
May be used to request invocation of a subsystem on the remote system.
|
||||
Subsystems are a feature of the SSH2 protocol which facilitate the use
|
||||
|
280
ssh.c
280
ssh.c
@ -40,7 +40,7 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $");
|
||||
RCSID("$OpenBSD: ssh.c,v 1.214 2004/06/13 15:03:02 djm Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
@ -53,21 +53,24 @@ RCSID("$OpenBSD: ssh.c,v 1.213 2004/05/08 00:01:37 deraadt Exp $");
|
||||
#include "xmalloc.h"
|
||||
#include "packet.h"
|
||||
#include "buffer.h"
|
||||
#include "bufaux.h"
|
||||
#include "channels.h"
|
||||
#include "key.h"
|
||||
#include "authfd.h"
|
||||
#include "authfile.h"
|
||||
#include "pathnames.h"
|
||||
#include "dispatch.h"
|
||||
#include "clientloop.h"
|
||||
#include "log.h"
|
||||
#include "readconf.h"
|
||||
#include "sshconnect.h"
|
||||
#include "dispatch.h"
|
||||
#include "misc.h"
|
||||
#include "kex.h"
|
||||
#include "mac.h"
|
||||
#include "sshpty.h"
|
||||
#include "match.h"
|
||||
#include "msg.h"
|
||||
#include "monitor_fdpass.h"
|
||||
|
||||
#ifdef SMARTCARD
|
||||
#include "scard.h"
|
||||
@ -141,6 +144,13 @@ static int client_global_request_id = 0;
|
||||
/* pid of proxycommand child process */
|
||||
pid_t proxy_command_pid = 0;
|
||||
|
||||
/* fd to control socket */
|
||||
int control_fd = -1;
|
||||
|
||||
/* Only used in control client mode */
|
||||
volatile sig_atomic_t control_client_terminate = 0;
|
||||
u_int control_server_pid = 0;
|
||||
|
||||
/* Prints a help message to the user. This function never returns. */
|
||||
|
||||
static void
|
||||
@ -158,6 +168,7 @@ usage(void)
|
||||
static int ssh_session(void);
|
||||
static int ssh_session2(void);
|
||||
static void load_public_identity_files(void);
|
||||
static void control_client(const char *path);
|
||||
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
@ -228,7 +239,7 @@ main(int ac, char **av)
|
||||
|
||||
again:
|
||||
while ((opt = getopt(ac, av,
|
||||
"1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVXY")) != -1) {
|
||||
"1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) {
|
||||
switch (opt) {
|
||||
case '1':
|
||||
options.protocol = SSH_PROTO_1;
|
||||
@ -364,6 +375,9 @@ again:
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
options.control_master = 1;
|
||||
break;
|
||||
case 'p':
|
||||
options.port = a2port(optarg);
|
||||
if (options.port == 0) {
|
||||
@ -432,6 +446,13 @@ again:
|
||||
case 's':
|
||||
subsystem_flag = 1;
|
||||
break;
|
||||
case 'S':
|
||||
if (options.control_path != NULL)
|
||||
free(options.control_path);
|
||||
options.control_path = xstrdup(optarg);
|
||||
if (options.control_master == -1)
|
||||
options.control_master = 0;
|
||||
break;
|
||||
case 'b':
|
||||
options.bind_address = optarg;
|
||||
break;
|
||||
@ -566,6 +587,13 @@ again:
|
||||
strcmp(options.proxy_command, "none") == 0)
|
||||
options.proxy_command = NULL;
|
||||
|
||||
if (options.control_path != NULL) {
|
||||
options.control_path = tilde_expand_filename(
|
||||
options.control_path, original_real_uid);
|
||||
}
|
||||
if (options.control_path != NULL && options.control_master == 0)
|
||||
control_client(options.control_path); /* This doesn't return */
|
||||
|
||||
/* Open a connection to the remote host. */
|
||||
if (ssh_connect(host, &hostaddr, options.port,
|
||||
options.address_family, options.connection_attempts,
|
||||
@ -678,6 +706,9 @@ again:
|
||||
exit_status = compat20 ? ssh_session2() : ssh_session();
|
||||
packet_close();
|
||||
|
||||
if (options.control_path != NULL && control_fd != -1)
|
||||
unlink(options.control_path);
|
||||
|
||||
/*
|
||||
* Send SIGHUP to proxy command if used. We don't wait() in
|
||||
* case it hangs and instead rely on init to reap the child
|
||||
@ -974,7 +1005,7 @@ ssh_session(void)
|
||||
}
|
||||
|
||||
static void
|
||||
client_subsystem_reply(int type, u_int32_t seq, void *ctxt)
|
||||
ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
int id, len;
|
||||
|
||||
@ -1006,40 +1037,50 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt)
|
||||
options.remote_forwards[i].port);
|
||||
}
|
||||
|
||||
static void
|
||||
ssh_control_listener(void)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
mode_t old_umask;
|
||||
|
||||
if (options.control_path == NULL || options.control_master != 1)
|
||||
return;
|
||||
|
||||
memset(&addr, '\0', sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
|
||||
strlen(options.control_path) + 1;
|
||||
|
||||
if (strlcpy(addr.sun_path, options.control_path,
|
||||
sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
|
||||
fatal("ControlPath too long");
|
||||
|
||||
if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
fatal("%s socket(): %s\n", __func__, strerror(errno));
|
||||
|
||||
old_umask = umask(0177);
|
||||
if (bind(control_fd, (struct sockaddr*)&addr, addr.sun_len) == -1) {
|
||||
control_fd = -1;
|
||||
if (errno == EINVAL)
|
||||
fatal("ControlSocket %s already exists",
|
||||
options.control_path);
|
||||
else
|
||||
fatal("%s bind(): %s\n", __func__, strerror(errno));
|
||||
}
|
||||
umask(old_umask);
|
||||
|
||||
if (listen(control_fd, 64) == -1)
|
||||
fatal("%s listen(): %s\n", __func__, strerror(errno));
|
||||
|
||||
set_nonblock(control_fd);
|
||||
}
|
||||
|
||||
/* request pty/x11/agent/tcpfwd/shell for channel */
|
||||
static void
|
||||
ssh_session2_setup(int id, void *arg)
|
||||
{
|
||||
int len;
|
||||
int interactive = 0;
|
||||
struct termios tio;
|
||||
|
||||
debug2("ssh_session2_setup: id %d", id);
|
||||
|
||||
if (tty_flag) {
|
||||
struct winsize ws;
|
||||
char *cp;
|
||||
cp = getenv("TERM");
|
||||
if (!cp)
|
||||
cp = "";
|
||||
/* Store window size in the packet. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
|
||||
channel_request_start(id, "pty-req", 0);
|
||||
packet_put_cstring(cp);
|
||||
packet_put_int(ws.ws_col);
|
||||
packet_put_int(ws.ws_row);
|
||||
packet_put_int(ws.ws_xpixel);
|
||||
packet_put_int(ws.ws_ypixel);
|
||||
tio = get_saved_tio();
|
||||
tty_make_modes(/*ignored*/ 0, &tio);
|
||||
packet_send();
|
||||
interactive = 1;
|
||||
/* XXX wait for reply */
|
||||
}
|
||||
if (options.forward_x11 &&
|
||||
getenv("DISPLAY") != NULL) {
|
||||
int interactive = tty_flag;
|
||||
if (options.forward_x11 && getenv("DISPLAY") != NULL) {
|
||||
char *proto, *data;
|
||||
/* Get reasonable local authentication information. */
|
||||
x11_get_proto(&proto, &data);
|
||||
@ -1057,65 +1098,8 @@ ssh_session2_setup(int id, void *arg)
|
||||
packet_send();
|
||||
}
|
||||
|
||||
/* Transfer any environment variables from client to server */
|
||||
if (options.num_send_env != 0) {
|
||||
int i, j, matched;
|
||||
extern char **environ;
|
||||
char *name, *val;
|
||||
|
||||
debug("Sending environment.");
|
||||
for (i = 0; environ && environ[i] != NULL; i++) {
|
||||
/* Split */
|
||||
name = xstrdup(environ[i]);
|
||||
if ((val = strchr(name, '=')) == NULL) {
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
*val++ = '\0';
|
||||
|
||||
matched = 0;
|
||||
for (j = 0; j < options.num_send_env; j++) {
|
||||
if (match_pattern(name, options.send_env[j])) {
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
debug3("Ignored env %s", name);
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Sending env %s = %s", name, val);
|
||||
channel_request_start(id, "env", 0);
|
||||
packet_put_cstring(name);
|
||||
packet_put_cstring(val);
|
||||
packet_send();
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
len = buffer_len(&command);
|
||||
if (len > 0) {
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
if (subsystem_flag) {
|
||||
debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command));
|
||||
channel_request_start(id, "subsystem", /*want reply*/ 1);
|
||||
/* register callback for reply */
|
||||
/* XXX we assume that client_loop has already been called */
|
||||
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply);
|
||||
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply);
|
||||
} else {
|
||||
debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));
|
||||
channel_request_start(id, "exec", 0);
|
||||
}
|
||||
packet_put_string(buffer_ptr(&command), buffer_len(&command));
|
||||
packet_send();
|
||||
} else {
|
||||
channel_request_start(id, "shell", 0);
|
||||
packet_send();
|
||||
}
|
||||
client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
|
||||
NULL, fileno(stdin), &command, &ssh_subsystem_reply);
|
||||
|
||||
packet_set_interactive(interactive);
|
||||
}
|
||||
@ -1161,7 +1145,7 @@ ssh_session2_open(void)
|
||||
|
||||
channel_send_open(c->self);
|
||||
if (!no_shell_flag)
|
||||
channel_register_confirm(c->self, ssh_session2_setup);
|
||||
channel_register_confirm(c->self, ssh_session2_setup, NULL);
|
||||
|
||||
return c->self;
|
||||
}
|
||||
@ -1173,6 +1157,7 @@ ssh_session2(void)
|
||||
|
||||
/* XXX should be pre-session */
|
||||
ssh_init_forwarding();
|
||||
ssh_control_listener();
|
||||
|
||||
if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
|
||||
id = ssh_session2_open();
|
||||
@ -1226,3 +1211,110 @@ load_public_identity_files(void)
|
||||
options.identity_keys[i] = public;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
control_client_sighandler(int signo)
|
||||
{
|
||||
control_client_terminate = signo;
|
||||
}
|
||||
|
||||
static void
|
||||
control_client_sigrelay(int signo)
|
||||
{
|
||||
if (control_server_pid > 1)
|
||||
kill(control_server_pid, signo);
|
||||
}
|
||||
|
||||
static void
|
||||
control_client(const char *path)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int r, sock, exitval;
|
||||
Buffer m;
|
||||
char *cp;
|
||||
|
||||
memset(&addr, '\0', sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
addr.sun_len = offsetof(struct sockaddr_un, sun_path) +
|
||||
strlen(path) + 1;
|
||||
|
||||
if (strlcpy(addr.sun_path, path,
|
||||
sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
|
||||
fatal("ControlPath too long");
|
||||
|
||||
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
fatal("%s socket(): %s", __func__, strerror(errno));
|
||||
|
||||
if (connect(sock, (struct sockaddr*)&addr, addr.sun_len) == -1)
|
||||
fatal("Couldn't connect to %s: %s", path, strerror(errno));
|
||||
|
||||
if ((cp = getenv("TERM")) == NULL)
|
||||
cp = "";
|
||||
|
||||
signal(SIGINT, control_client_sighandler);
|
||||
signal(SIGTERM, control_client_sighandler);
|
||||
signal(SIGWINCH, control_client_sigrelay);
|
||||
|
||||
buffer_init(&m);
|
||||
|
||||
/* Get PID of controlee */
|
||||
if (ssh_msg_recv(sock, &m) == -1)
|
||||
fatal("%s: msg_recv", __func__);
|
||||
if (buffer_get_char(&m) != 0)
|
||||
fatal("%s: wrong version", __func__);
|
||||
control_server_pid = buffer_get_int(&m);
|
||||
|
||||
/* XXX: env passing */
|
||||
|
||||
buffer_clear(&m);
|
||||
buffer_put_int(&m, tty_flag);
|
||||
buffer_put_int(&m, subsystem_flag);
|
||||
buffer_put_cstring(&m, cp);
|
||||
|
||||
buffer_append(&command, "\0", 1);
|
||||
buffer_put_cstring(&m, buffer_ptr(&command));
|
||||
|
||||
if (ssh_msg_send(sock, /* version */0, &m) == -1)
|
||||
fatal("%s: msg_send", __func__);
|
||||
|
||||
mm_send_fd(sock, STDIN_FILENO);
|
||||
mm_send_fd(sock, STDOUT_FILENO);
|
||||
mm_send_fd(sock, STDERR_FILENO);
|
||||
|
||||
/* Wait for reply, so master has a chance to gather ttymodes */
|
||||
buffer_clear(&m);
|
||||
if (ssh_msg_recv(sock, &m) == -1)
|
||||
fatal("%s: msg_recv", __func__);
|
||||
if (buffer_get_char(&m) != 0)
|
||||
fatal("%s: master returned error", __func__);
|
||||
buffer_free(&m);
|
||||
|
||||
if (tty_flag)
|
||||
enter_raw_mode();
|
||||
|
||||
/* Stick around until the controlee closes the client_fd */
|
||||
exitval = 0;
|
||||
for (;!control_client_terminate;) {
|
||||
r = read(sock, &exitval, sizeof(exitval));
|
||||
if (r == 0) {
|
||||
debug2("Received EOF from master");
|
||||
break;
|
||||
}
|
||||
if (r > 0)
|
||||
debug2("Received exit status from master %d", exitval);
|
||||
if (r == -1 && errno != EINTR)
|
||||
fatal("%s: read %s", __func__, strerror(errno));
|
||||
}
|
||||
|
||||
if (control_client_terminate)
|
||||
debug2("Exiting on signal %d", control_client_terminate);
|
||||
|
||||
close(sock);
|
||||
|
||||
leave_raw_mode();
|
||||
|
||||
if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
|
||||
fprintf(stderr, "Connection to master closed.\r\n");
|
||||
|
||||
exit(exitval);
|
||||
}
|
||||
|
24
ssh_config.5
24
ssh_config.5
@ -34,7 +34,7 @@
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh_config.5,v 1.35 2004/06/13 14:01:42 dtucker Exp $
|
||||
.\" $OpenBSD: ssh_config.5,v 1.36 2004/06/13 15:03:02 djm Exp $
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH_CONFIG 5
|
||||
.Os
|
||||
@ -256,6 +256,28 @@ will act as a SOCKS server.
|
||||
Multiple forwardings may be specified, and
|
||||
additional forwardings can be given on the command line.
|
||||
Only the superuser can forward privileged ports.
|
||||
.It Cm ControlMaster
|
||||
Enables the sharing of multiple sessions over a single network connection.
|
||||
When set to
|
||||
.Dq yes
|
||||
.Nm ssh
|
||||
will listen for connections on a control socket specified using the
|
||||
.Cm ControlPath
|
||||
argument.
|
||||
Additional sessions can connect to this socket using the same
|
||||
.Cm ControlPath
|
||||
with
|
||||
.Cm ControlMaster
|
||||
set to
|
||||
.Dq no
|
||||
(the default.)
|
||||
These sessions will reuse the master instance's network connection rather
|
||||
than initiating new ones.
|
||||
.It Cm ControlPath
|
||||
Specify a the path to the control socket used for connection sharing.
|
||||
See
|
||||
.Cm ControlMaster
|
||||
above.
|
||||
.It Cm EnableSSHKeysign
|
||||
Setting this option to
|
||||
.Dq yes
|
||||
|
Loading…
x
Reference in New Issue
Block a user