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
This commit is contained in:
djm@openbsd.org 2021-07-13 23:48:36 +00:00 committed by Damien Miller
parent 7ae69f2628
commit eda8909d1b
7 changed files with 81 additions and 35 deletions

View File

@ -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 <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -118,9 +118,6 @@ extern Options options;
/* Flag indicating that stdin should be redirected from /dev/null. */ /* Flag indicating that stdin should be redirected from /dev/null. */
extern int stdin_null_flag; 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 */ /* Flag indicating that ssh should daemonise after authentication is complete */
extern int fork_after_authentication_flag; 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 * exit status to be returned. In that case, clear error code if the
* connection was deliberately terminated at this end. * 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; received_signal = 0;
exit_status = 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 * If we are in persist mode, or don't have a shell, signal that we
* should close when all active channels are closed. * 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; session_closed = 1;
setproctitle("[stopped mux]"); setproctitle("[stopped mux]");
} }

5
mux.c
View File

@ -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 <djm@openbsd.org> * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
* *
@ -73,7 +73,6 @@ extern int tty_flag;
extern Options options; extern Options options;
extern int stdin_null_flag; extern int stdin_null_flag;
extern char *host; extern char *host;
extern int subsystem_flag;
extern struct sshbuf *command; extern struct sshbuf *command;
extern volatile sig_atomic_t quit_pending; 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, tty_flag)) != 0 ||
(r = sshbuf_put_u32(m, options.forward_x11)) != 0 || (r = sshbuf_put_u32(m, options.forward_x11)) != 0 ||
(r = sshbuf_put_u32(m, options.forward_agent)) != 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_u32(m, echar)) != 0 ||
(r = sshbuf_put_cstring(m, term == NULL ? "" : term)) != 0 || (r = sshbuf_put_cstring(m, term == NULL ? "" : term)) != 0 ||
(r = sshbuf_put_stringb(m, command)) != 0) (r = sshbuf_put_stringb(m, command)) != 0)

View File

@ -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 <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -167,7 +167,8 @@ typedef enum {
oTunnel, oTunnelDevice, oTunnel, oTunnelDevice,
oLocalCommand, oPermitLocalCommand, oRemoteCommand, oLocalCommand, oPermitLocalCommand, oRemoteCommand,
oVisualHostKey, oVisualHostKey,
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType,
oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
@ -297,6 +298,7 @@ static struct {
{ "kexalgorithms", oKexAlgorithms }, { "kexalgorithms", oKexAlgorithms },
{ "ipqos", oIPQoS }, { "ipqos", oIPQoS },
{ "requesttty", oRequestTTY }, { "requesttty", oRequestTTY },
{ "sessiontype", oSessionType },
{ "proxyusefdpass", oProxyUseFdpass }, { "proxyusefdpass", oProxyUseFdpass },
{ "canonicaldomains", oCanonicalDomains }, { "canonicaldomains", oCanonicalDomains },
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
@ -872,6 +874,12 @@ static const struct multistate multistate_requesttty[] = {
{ "auto", REQUEST_TTY_AUTO }, { "auto", REQUEST_TTY_AUTO },
{ NULL, -1 } { 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[] = { static const struct multistate multistate_canonicalizehostname[] = {
{ "true", SSH_CANONICALISE_YES }, { "true", SSH_CANONICALISE_YES },
{ "false", SSH_CANONICALISE_NO }, { "false", SSH_CANONICALISE_NO },
@ -1941,6 +1949,11 @@ parse_pubkey_algos:
multistate_ptr = multistate_requesttty; multistate_ptr = multistate_requesttty;
goto parse_multistate; goto parse_multistate;
case oSessionType:
intptr = &options->session_type;
multistate_ptr = multistate_sessiontype;
goto parse_multistate;
case oIgnoreUnknown: case oIgnoreUnknown:
charptr = &options->ignored_unknown; charptr = &options->ignored_unknown;
goto parse_string; goto parse_string;
@ -2363,6 +2376,7 @@ initialize_options(Options * options)
options->ip_qos_interactive = -1; options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1; options->ip_qos_bulk = -1;
options->request_tty = -1; options->request_tty = -1;
options->session_type = -1;
options->proxy_use_fdpass = -1; options->proxy_use_fdpass = -1;
options->ignored_unknown = NULL; options->ignored_unknown = NULL;
options->num_canonical_domains = 0; options->num_canonical_domains = 0;
@ -2549,6 +2563,8 @@ fill_default_options(Options * options)
options->ip_qos_bulk = IPTOS_DSCP_CS1; options->ip_qos_bulk = IPTOS_DSCP_CS1;
if (options->request_tty == -1) if (options->request_tty == -1)
options->request_tty = REQUEST_TTY_AUTO; options->request_tty = REQUEST_TTY_AUTO;
if (options->session_type == -1)
options->session_type = SESSION_TYPE_DEFAULT;
if (options->proxy_use_fdpass == -1) if (options->proxy_use_fdpass == -1)
options->proxy_use_fdpass = 0; options->proxy_use_fdpass = 0;
if (options->canonicalize_max_dots == -1) if (options->canonicalize_max_dots == -1)
@ -3063,6 +3079,8 @@ fmt_intarg(OpCodes code, int val)
return fmt_multistate_int(val, multistate_tunnel); return fmt_multistate_int(val, multistate_tunnel);
case oRequestTTY: case oRequestTTY:
return fmt_multistate_int(val, multistate_requesttty); return fmt_multistate_int(val, multistate_requesttty);
case oSessionType:
return fmt_multistate_int(val, multistate_sessiontype);
case oCanonicalizeHostname: case oCanonicalizeHostname:
return fmt_multistate_int(val, multistate_canonicalizehostname); return fmt_multistate_int(val, multistate_canonicalizehostname);
case oAddKeysToAgent: 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(oProxyUseFdpass, o->proxy_use_fdpass);
dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication); dump_cfg_fmtint(oPubkeyAuthentication, o->pubkey_authentication);
dump_cfg_fmtint(oRequestTTY, o->request_tty); 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(oStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking); dump_cfg_fmtint(oStrictHostKeyChecking, o->strict_host_key_checking);
dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive); dump_cfg_fmtint(oTCPKeepAlive, o->tcp_keep_alive);

View File

@ -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 <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -146,6 +146,7 @@ typedef struct {
int visual_host_key; int visual_host_key;
int request_tty; int request_tty;
int session_type;
int proxy_use_fdpass; int proxy_use_fdpass;
@ -191,6 +192,10 @@ typedef struct {
#define REQUEST_TTY_YES 2 #define REQUEST_TTY_YES 2
#define REQUEST_TTY_FORCE 3 #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_CHECKPERM 1 /* check permissions on config file */
#define SSHCONF_USERCONF 2 /* user provided config file not system */ #define SSHCONF_USERCONF 2 /* user provided config file not system */
#define SSHCONF_FINAL 4 /* Final pass over config, after canon. */ #define SSHCONF_FINAL 4 /* Final pass over config, after canon. */

15
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" 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 $ .\" $OpenBSD: ssh.1,v 1.422 2021/07/13 23:48:36 djm Exp $
.Dd $Mdocdate: July 2 2021 $ .Dd $Mdocdate: July 13 2021 $
.Dt SSH 1 .Dt SSH 1
.Os .Os
.Sh NAME .Sh NAME
@ -425,6 +425,11 @@ keyword for more information.
.It Fl N .It Fl N
Do not execute a remote command. Do not execute a remote command.
This is useful for just forwarding ports. This is useful for just forwarding ports.
Refer to the description of
.Cm SessionType
in
.Xr ssh_config 5
for details.
.Pp .Pp
.It Fl n .It Fl n
Redirects stdin from Redirects stdin from
@ -546,6 +551,7 @@ For full details of the options listed below, and their possible values, see
.It SendEnv .It SendEnv
.It ServerAliveInterval .It ServerAliveInterval
.It ServerAliveCountMax .It ServerAliveCountMax
.It SessionType
.It SetEnv .It SetEnv
.It StreamLocalBindMask .It StreamLocalBindMask
.It StreamLocalBindUnlink .It StreamLocalBindUnlink
@ -703,6 +709,11 @@ Subsystems facilitate the use of SSH
as a secure transport for other applications (e.g.\& as a secure transport for other applications (e.g.\&
.Xr sftp 1 ) . .Xr sftp 1 ) .
The subsystem is specified as the remote command. The subsystem is specified as the remote command.
Refer to the description of
.Cm SessionType
in
.Xr ssh_config 5
for details.
.Pp .Pp
.It Fl T .It Fl T
Disable pseudo-terminal allocation. Disable pseudo-terminal allocation.

38
ssh.c
View File

@ -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 <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -126,9 +126,6 @@ int debug_flag = 0;
/* Flag indicating whether a tty should be requested */ /* Flag indicating whether a tty should be requested */
int tty_flag = 0; 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 * Flag indicating that nothing should be read from stdin. This can be set
* on the command line. * on the command line.
@ -142,7 +139,7 @@ int stdin_null_flag = 0;
int need_controlpersist_detach = 0; int need_controlpersist_detach = 0;
/* Copies of flags for ControlPersist foreground mux-client */ /* 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 * Flag indicating that ssh should fork after authentication. This is useful
@ -182,9 +179,6 @@ Sensitive sensitive_data;
/* command to be executed */ /* command to be executed */
struct sshbuf *command; struct sshbuf *command;
/* Should we execute a command or invoke a subsystem? */
int subsystem_flag = 0;
/* # of replies received for global requests */ /* # of replies received for global requests */
static int forward_confirms_pending = -1; static int forward_confirms_pending = -1;
@ -921,7 +915,7 @@ main(int ac, char **av)
exit(255); exit(255);
} }
options.request_tty = REQUEST_TTY_NO; options.request_tty = REQUEST_TTY_NO;
no_shell_flag = 1; options.session_type = SESSION_TYPE_NONE;
break; break;
case 'q': case 'q':
options.log_level = SYSLOG_LEVEL_QUIET; options.log_level = SYSLOG_LEVEL_QUIET;
@ -1024,7 +1018,10 @@ main(int ac, char **av)
#endif #endif
break; break;
case 'N': 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; options.request_tty = REQUEST_TTY_NO;
break; break;
case 'T': case 'T':
@ -1039,7 +1036,10 @@ main(int ac, char **av)
free(line); free(line);
break; break;
case 's': 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; break;
case 'S': case 'S':
free(options.control_path); free(options.control_path);
@ -1122,7 +1122,7 @@ main(int ac, char **av)
*/ */
if (!ac) { if (!ac) {
/* No command specified - execute shell on a tty. */ /* No command specified - execute shell on a tty. */
if (subsystem_flag) { if (options.session_type == SESSION_TYPE_SUBSYSTEM) {
fprintf(stderr, fprintf(stderr,
"You must specify a subsystem to invoke.\n"); "You must specify a subsystem to invoke.\n");
usage(); usage();
@ -1331,7 +1331,7 @@ main(int ac, char **av)
/* Cannot fork to background if no command. */ /* Cannot fork to background if no command. */
if (fork_after_authentication_flag && sshbuf_len(command) == 0 && 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 " fatal("Cannot fork into background without a command "
"to execute."); "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, if ((term = lookup_env_in_list("TERM", options.setenv,
options.num_setenv)) == NULL || *term == '\0') options.num_setenv)) == NULL || *term == '\0')
term = getenv("TERM"); 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); NULL, fileno(stdin), command, environ);
} }
@ -2097,7 +2097,7 @@ ssh_session2_open(struct ssh *ssh)
debug3_f("channel_new: %d", c->self); debug3_f("channel_new: %d", c->self);
channel_send_open(ssh, 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, channel_register_open_confirm(ssh, c->self,
ssh_session2_setup, NULL); 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) { if (options.control_persist && muxserver_sock != -1) {
ostdin_null_flag = stdin_null_flag; ostdin_null_flag = stdin_null_flag;
ono_shell_flag = no_shell_flag; osession_type = options.session_type;
orequest_tty = options.request_tty; orequest_tty = options.request_tty;
otty_flag = tty_flag; otty_flag = tty_flag;
stdin_null_flag = 1; stdin_null_flag = 1;
no_shell_flag = 1; options.session_type = SESSION_TYPE_NONE;
tty_flag = 0; tty_flag = 0;
if (!fork_after_authentication_flag && 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; need_controlpersist_detach = 1;
fork_after_authentication_flag = 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) if (options.control_persist && muxserver_sock == -1)
ssh_init_stdio_forwarding(ssh); ssh_init_stdio_forwarding(ssh);
if (!no_shell_flag) if (options.session_type != SESSION_TYPE_NONE)
id = ssh_session2_open(ssh); id = ssh_session2_open(ssh);
else { else {
ssh_packet_set_interactive(ssh, ssh_packet_set_interactive(ssh,

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" 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 $ .\" $OpenBSD: ssh_config.5,v 1.356 2021/07/13 23:48:36 djm Exp $
.Dd $Mdocdate: July 2 2021 $ .Dd $Mdocdate: July 13 2021 $
.Dt SSH_CONFIG 5 .Dt SSH_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -1263,6 +1263,21 @@ The argument to this keyword must be
or or
.Cm no .Cm no
(the default). (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 .It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up. Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer. The argument to this keyword must be an integer.