From eda8909d1b0a85b9c3804a04d03ec6738fd9dc7f Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 13 Jul 2021 23:48:36 +0000 Subject: [PATCH] upstream: 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@ OpenBSD-Commit-ID: 726ee931dd4c5cc7f1d7a187b26f41257f9a2d12 --- clientloop.c | 9 +++------ mux.c | 5 ++--- readconf.c | 23 +++++++++++++++++++++-- readconf.h | 7 ++++++- ssh.1 | 15 +++++++++++++-- ssh.c | 38 +++++++++++++++++++------------------- ssh_config.5 | 19 +++++++++++++++++-- 7 files changed, 81 insertions(+), 35 deletions(-) diff --git a/clientloop.c b/clientloop.c index 2692fecc4..fbca1a45d 100644 --- a/clientloop.c +++ b/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 @@ -118,9 +118,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; @@ -1410,7 +1407,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; } @@ -2585,7 +2582,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/mux.c b/mux.c index e15207afb..267412022 100644 --- a/mux.c +++ b/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 * @@ -73,7 +73,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; @@ -1899,7 +1898,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/readconf.c b/readconf.c index 3bec3a9fb..4b1cda2ee 100644 --- a/readconf.c +++ b/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 @@ -167,7 +167,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, @@ -297,6 +298,7 @@ static struct { { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, + { "sessiontype", oSessionType }, { "proxyusefdpass", oProxyUseFdpass }, { "canonicaldomains", oCanonicalDomains }, { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, @@ -872,6 +874,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 }, @@ -1941,6 +1949,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; @@ -2363,6 +2376,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; @@ -2549,6 +2563,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) @@ -3063,6 +3079,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: @@ -3224,6 +3242,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/readconf.h b/readconf.h index f3d02fb38..e4ebc6fb8 100644 --- a/readconf.h +++ b/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/ssh.1 b/ssh.1 index e59716b9c..6d0839761 100644 --- a/ssh.1 +++ b/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/ssh.c b/ssh.c index 0343cba32..710c4e9a7 100644 --- a/ssh.c +++ b/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 @@ -126,9 +126,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. @@ -142,7 +139,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 @@ -182,9 +179,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; @@ -921,7 +915,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; @@ -1024,7 +1018,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': @@ -1039,7 +1036,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); @@ -1122,7 +1122,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(); @@ -1331,7 +1331,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."); @@ -2061,7 +2061,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); } @@ -2097,7 +2097,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); @@ -2142,14 +2142,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; } @@ -2160,7 +2160,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/ssh_config.5 b/ssh_config.5 index aaa331a16..ee06aacdb 100644 --- a/ssh_config.5 +++ b/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 @@ -1263,6 +1263,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.