From e7245a2de177994aba9aea0f29b730b1e3797246 Mon Sep 17 00:00:00 2001 From: djm Date: Tue, 13 Jul 2021 23:48:36 +0000 Subject: [PATCH] add a SessionType directive to ssh_config, allowing the configuration file to offer equivalent control to the -N (no session) and -s (subsystem) command-line flags. Part of GHPR#231 by Volker Diels-Grabsch with some minor tweaks; feedback and ok dtucker@ --- usr.bin/ssh/clientloop.c | 9 +++------ usr.bin/ssh/mux.c | 5 ++--- usr.bin/ssh/readconf.c | 23 +++++++++++++++++++++-- usr.bin/ssh/readconf.h | 7 ++++++- usr.bin/ssh/ssh.1 | 15 +++++++++++++-- usr.bin/ssh/ssh.c | 38 +++++++++++++++++++------------------- usr.bin/ssh/ssh_config.5 | 19 +++++++++++++++++-- 7 files changed, 81 insertions(+), 35 deletions(-) diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 39ecbe5c0bf..83efcef25d1 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.365 2021/07/05 01:21:07 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.366 2021/07/13 23:48:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -111,9 +111,6 @@ extern Options options; /* Flag indicating that stdin should be redirected from /dev/null. */ extern int stdin_null_flag; -/* Flag indicating that no shell has been requested */ -extern int no_shell_flag; - /* Flag indicating that ssh should daemonise after authentication is complete */ extern int fork_after_authentication_flag; @@ -1402,7 +1399,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, * exit status to be returned. In that case, clear error code if the * connection was deliberately terminated at this end. */ - if (no_shell_flag && received_signal == SIGTERM) { + if (options.session_type == SESSION_TYPE_NONE && received_signal == SIGTERM) { received_signal = 0; exit_status = 0; } @@ -2571,7 +2568,7 @@ client_stop_mux(void) * If we are in persist mode, or don't have a shell, signal that we * should close when all active channels are closed. */ - if (options.control_persist || no_shell_flag) { + if (options.control_persist || options.session_type == SESSION_TYPE_NONE) { session_closed = 1; setproctitle("[stopped mux]"); } diff --git a/usr.bin/ssh/mux.c b/usr.bin/ssh/mux.c index fbb346ef3ef..78dd4fe8f15 100644 --- a/usr.bin/ssh/mux.c +++ b/usr.bin/ssh/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.89 2021/06/04 05:02:40 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.90 2021/07/13 23:48:36 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -60,7 +60,6 @@ extern int tty_flag; extern Options options; extern int stdin_null_flag; extern char *host; -extern int subsystem_flag; extern struct sshbuf *command; extern volatile sig_atomic_t quit_pending; @@ -1880,7 +1879,7 @@ mux_client_request_session(int fd) (r = sshbuf_put_u32(m, tty_flag)) != 0 || (r = sshbuf_put_u32(m, options.forward_x11)) != 0 || (r = sshbuf_put_u32(m, options.forward_agent)) != 0 || - (r = sshbuf_put_u32(m, subsystem_flag)) != 0 || + (r = sshbuf_put_u32(m, options.session_type == SESSION_TYPE_SUBSYSTEM)) != 0 || (r = sshbuf_put_u32(m, echar)) != 0 || (r = sshbuf_put_cstring(m, term == NULL ? "" : term)) != 0 || (r = sshbuf_put_stringb(m, command)) != 0) diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index 0ba8eb48067..761ca67f9d6 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.358 2021/07/02 05:11:21 dtucker Exp $ */ +/* $OpenBSD: readconf.c,v 1.359 2021/07/13 23:48:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -153,7 +153,8 @@ typedef enum { oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oRemoteCommand, oVisualHostKey, - oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, + oIgnoreUnknown, oProxyUseFdpass, oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, @@ -283,6 +284,7 @@ static struct { { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, + { "sessiontype", oSessionType }, { "proxyusefdpass", oProxyUseFdpass }, { "canonicaldomains", oCanonicalDomains }, { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, @@ -858,6 +860,12 @@ static const struct multistate multistate_requesttty[] = { { "auto", REQUEST_TTY_AUTO }, { NULL, -1 } }; +static const struct multistate multistate_sessiontype[] = { + { "none", SESSION_TYPE_NONE }, + { "subsystem", SESSION_TYPE_SUBSYSTEM }, + { "default", SESSION_TYPE_DEFAULT }, + { NULL, -1 } +}; static const struct multistate multistate_canonicalizehostname[] = { { "true", SSH_CANONICALISE_YES }, { "false", SSH_CANONICALISE_NO }, @@ -1927,6 +1935,11 @@ parse_pubkey_algos: multistate_ptr = multistate_requesttty; goto parse_multistate; + case oSessionType: + intptr = &options->session_type; + multistate_ptr = multistate_sessiontype; + goto parse_multistate; + case oIgnoreUnknown: charptr = &options->ignored_unknown; goto parse_string; @@ -2349,6 +2362,7 @@ initialize_options(Options * options) options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->request_tty = -1; + options->session_type = -1; options->proxy_use_fdpass = -1; options->ignored_unknown = NULL; options->num_canonical_domains = 0; @@ -2533,6 +2547,8 @@ fill_default_options(Options * options) options->ip_qos_bulk = IPTOS_DSCP_CS1; if (options->request_tty == -1) options->request_tty = REQUEST_TTY_AUTO; + if (options->session_type == -1) + options->session_type = SESSION_TYPE_DEFAULT; if (options->proxy_use_fdpass == -1) options->proxy_use_fdpass = 0; if (options->canonicalize_max_dots == -1) @@ -3042,6 +3058,8 @@ fmt_intarg(OpCodes code, int val) return fmt_multistate_int(val, multistate_tunnel); case oRequestTTY: return fmt_multistate_int(val, multistate_requesttty); + case oSessionType: + return fmt_multistate_int(val, multistate_sessiontype); case oCanonicalizeHostname: return fmt_multistate_int(val, multistate_canonicalizehostname); case oAddKeysToAgent: @@ -3203,6 +3221,7 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oProxyUseFdpass, o->proxy_use_fdpass); dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); dump_cfg_fmtint(oRequestTTY, o->request_tty); + dump_cfg_fmtint(oSessionType, o->session_type); dump_cfg_fmtint(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index f3d02fb388d..e4ebc6fb80e 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.141 2021/07/02 05:11:21 dtucker Exp $ */ +/* $OpenBSD: readconf.h,v 1.142 2021/07/13 23:48:36 djm Exp $ */ /* * Author: Tatu Ylonen @@ -146,6 +146,7 @@ typedef struct { int visual_host_key; int request_tty; + int session_type; int proxy_use_fdpass; @@ -191,6 +192,10 @@ typedef struct { #define REQUEST_TTY_YES 2 #define REQUEST_TTY_FORCE 3 +#define SESSION_TYPE_NONE 0 +#define SESSION_TYPE_SUBSYSTEM 1 +#define SESSION_TYPE_DEFAULT 2 + #define SSHCONF_CHECKPERM 1 /* check permissions on config file */ #define SSHCONF_USERCONF 2 /* user provided config file not system */ #define SSHCONF_FINAL 4 /* Final pass over config, after canon. */ diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 index e59716b9c53..6d0839761d4 100644 --- a/usr.bin/ssh/ssh.1 +++ b/usr.bin/ssh/ssh.1 @@ -33,8 +33,8 @@ .\" (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.421 2021/07/02 05:11:21 dtucker Exp $ -.Dd $Mdocdate: July 2 2021 $ +.\" $OpenBSD: ssh.1,v 1.422 2021/07/13 23:48:36 djm Exp $ +.Dd $Mdocdate: July 13 2021 $ .Dt SSH 1 .Os .Sh NAME @@ -425,6 +425,11 @@ keyword for more information. .It Fl N Do not execute a remote command. This is useful for just forwarding ports. +Refer to the description of +.Cm SessionType +in +.Xr ssh_config 5 +for details. .Pp .It Fl n Redirects stdin from @@ -546,6 +551,7 @@ For full details of the options listed below, and their possible values, see .It SendEnv .It ServerAliveInterval .It ServerAliveCountMax +.It SessionType .It SetEnv .It StreamLocalBindMask .It StreamLocalBindUnlink @@ -703,6 +709,11 @@ Subsystems facilitate the use of SSH as a secure transport for other applications (e.g.\& .Xr sftp 1 ) . The subsystem is specified as the remote command. +Refer to the description of +.Cm SessionType +in +.Xr ssh_config 5 +for details. .Pp .It Fl T Disable pseudo-terminal allocation. diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index 47044355343..8e021648226 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.559 2021/06/08 07:07:15 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.560 2021/07/13 23:48:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -110,9 +110,6 @@ int debug_flag = 0; /* Flag indicating whether a tty should be requested */ int tty_flag = 0; -/* don't exec a shell */ -int no_shell_flag = 0; - /* * Flag indicating that nothing should be read from stdin. This can be set * on the command line. @@ -126,7 +123,7 @@ int stdin_null_flag = 0; int need_controlpersist_detach = 0; /* Copies of flags for ControlPersist foreground mux-client */ -int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty; +int ostdin_null_flag, osession_type, otty_flag, orequest_tty; /* * Flag indicating that ssh should fork after authentication. This is useful @@ -166,9 +163,6 @@ Sensitive sensitive_data; /* command to be executed */ struct sshbuf *command; -/* Should we execute a command or invoke a subsystem? */ -int subsystem_flag = 0; - /* # of replies received for global requests */ static int forward_confirms_pending = -1; @@ -895,7 +889,7 @@ main(int ac, char **av) exit(255); } options.request_tty = REQUEST_TTY_NO; - no_shell_flag = 1; + options.session_type = SESSION_TYPE_NONE; break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; @@ -998,7 +992,10 @@ main(int ac, char **av) #endif break; case 'N': - no_shell_flag = 1; + if (options.session_type != -1 && + options.session_type != SESSION_TYPE_NONE) + fatal("Cannot specify -N with -s/SessionType"); + options.session_type = SESSION_TYPE_NONE; options.request_tty = REQUEST_TTY_NO; break; case 'T': @@ -1013,7 +1010,10 @@ main(int ac, char **av) free(line); break; case 's': - subsystem_flag = 1; + if (options.session_type != -1 && + options.session_type != SESSION_TYPE_SUBSYSTEM) + fatal("Cannot specify -s with -N/SessionType"); + options.session_type = SESSION_TYPE_SUBSYSTEM; break; case 'S': free(options.control_path); @@ -1101,7 +1101,7 @@ main(int ac, char **av) */ if (!ac) { /* No command specified - execute shell on a tty. */ - if (subsystem_flag) { + if (options.session_type == SESSION_TYPE_SUBSYSTEM) { fprintf(stderr, "You must specify a subsystem to invoke.\n"); usage(); @@ -1310,7 +1310,7 @@ main(int ac, char **av) /* Cannot fork to background if no command. */ if (fork_after_authentication_flag && sshbuf_len(command) == 0 && - options.remote_command == NULL && !no_shell_flag) + options.remote_command == NULL && options.session_type != SESSION_TYPE_NONE) fatal("Cannot fork into background without a command " "to execute."); @@ -2040,7 +2040,7 @@ ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg) if ((term = lookup_env_in_list("TERM", options.setenv, options.num_setenv)) == NULL || *term == '\0') term = getenv("TERM"); - client_session2_setup(ssh, id, tty_flag, subsystem_flag, term, + client_session2_setup(ssh, id, tty_flag, options.session_type == SESSION_TYPE_SUBSYSTEM, term, NULL, fileno(stdin), command, environ); } @@ -2076,7 +2076,7 @@ ssh_session2_open(struct ssh *ssh) debug3_f("channel_new: %d", c->self); channel_send_open(ssh, c->self); - if (!no_shell_flag) + if (options.session_type != SESSION_TYPE_NONE) channel_register_open_confirm(ssh, c->self, ssh_session2_setup, NULL); @@ -2121,14 +2121,14 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) */ if (options.control_persist && muxserver_sock != -1) { ostdin_null_flag = stdin_null_flag; - ono_shell_flag = no_shell_flag; + osession_type = options.session_type; orequest_tty = options.request_tty; otty_flag = tty_flag; stdin_null_flag = 1; - no_shell_flag = 1; + options.session_type = SESSION_TYPE_NONE; tty_flag = 0; if (!fork_after_authentication_flag && - (!ono_shell_flag || options.stdio_forward_host != NULL)) + (osession_type != SESSION_TYPE_NONE || options.stdio_forward_host != NULL)) need_controlpersist_detach = 1; fork_after_authentication_flag = 1; } @@ -2139,7 +2139,7 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) if (options.control_persist && muxserver_sock == -1) ssh_init_stdio_forwarding(ssh); - if (!no_shell_flag) + if (options.session_type != SESSION_TYPE_NONE) id = ssh_session2_open(ssh); else { ssh_packet_set_interactive(ssh, diff --git a/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5 index a34d2a0d1d9..179a65f3e94 100644 --- a/usr.bin/ssh/ssh_config.5 +++ b/usr.bin/ssh/ssh_config.5 @@ -33,8 +33,8 @@ .\" (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.355 2021/07/02 05:11:21 dtucker Exp $ -.Dd $Mdocdate: July 2 2021 $ +.\" $OpenBSD: ssh_config.5,v 1.356 2021/07/13 23:48:36 djm Exp $ +.Dd $Mdocdate: July 13 2021 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1264,6 +1264,21 @@ The argument to this keyword must be or .Cm no (the default). +.It Cm SessionType +May be used to either request invocation of a subsystem on the remote system, +or to prevent the execution of a remote command at all. +The latter is useful for just forwarding ports. +The argument to this keyword must be +.Cm none +(same as the +.Fl N +option), +.Cm subsystem +(same as the +.Fl s +option) or +.Cm default +(shell or command execution). .It Cm NumberOfPasswordPrompts Specifies the number of password prompts before giving up. The argument to this keyword must be an integer. -- 2.20.1