diff options
author | Damien Miller <djm@mindrot.org> | 2004-06-15 10:34:08 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2004-06-15 10:34:08 +1000 |
commit | 0e220dbfbcc9fe252e8f1f4890dbfa415aad35db (patch) | |
tree | b78bab0c628cd5bdb0ec95340f533a1be2fae75f | |
parent | 05202ffe214115afa24bf6e7a6d8c8457e6759bb (diff) |
- 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@
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | channels.c | 76 | ||||
-rw-r--r-- | channels.h | 7 | ||||
-rw-r--r-- | clientloop.c | 327 | ||||
-rw-r--r-- | clientloop.h | 4 | ||||
-rw-r--r-- | defines.h | 5 | ||||
-rw-r--r-- | includes.h | 3 | ||||
-rw-r--r-- | readconf.c | 18 | ||||
-rw-r--r-- | readconf.h | 5 | ||||
-rw-r--r-- | scp.1 | 4 | ||||
-rw-r--r-- | sftp.1 | 4 | ||||
-rw-r--r-- | ssh-rand-helper.c | 6 | ||||
-rw-r--r-- | ssh.1 | 26 | ||||
-rw-r--r-- | ssh.c | 276 | ||||
-rw-r--r-- | ssh_config.5 | 24 |
15 files changed, 650 insertions, 142 deletions
@@ -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 $ @@ -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 */ diff --git a/clientloop.c b/clientloop.c index 31e60418..6401588a 100644 --- a/clientloop.c +++ b/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 @@ -500,6 +512,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) { void (*handler)(int); @@ -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); } diff --git a/clientloop.h b/clientloop.h index 56af06bc..f1e13ac3 100644 --- a/clientloop.h +++ b/clientloop.h @@ -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 */ @@ -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; @@ -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 @@ -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 diff --git a/ssh-rand-helper.c b/ssh-rand-helper.c index 8a320a71..471e7295 100644 --- a/ssh-rand-helper.c +++ b/ssh-rand-helper.c @@ -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 @@ -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 |