[PATCH] features for restricted shell environments

Tony Finch dot at dotat.at
Thu Jan 30 08:40:20 EST 2003


The patch below implements a couple of features which are useful
in an environment where users do not have a regular shell login.
It allows you to selectively disable certain features on a
system-wide level for users with a certain shell; it also allows
you to control and audit TCP forwarding in more detail.

Our system is an email server with a menu for the login shell;
we selectively allow port forwarding for users to connect to the
IMAP server etc. and prevent users from escaping via ~/.ssh/rc.
This patch may also be useful with secure CVS servers.

Tony.
-- 
f.a.n.finch  <dot at dotat.at>  http://dotat.at/
FISHER GERMAN BIGHT: NORTHWESTERLY 6 OR 7, OCCASIONALLY GALE 8 IN WEST,
VEERING NORTHEASTERLY 5 LATER. WINTRY SHOWERS. GOOD.


--- auth-options.c	28 Jan 2003 18:06:50 -0000	1.1.1.2
+++ auth-options.c	29 Jan 2003 20:39:19 -0000	1.7
@@ -133,7 +135,7 @@
 			goto next_option;
 		}
 		cp = "environment=\"";
-		if (options.permit_user_env &&
+		if (!auth_restricted(RESTRICT_ENV, pw) &&
 		    strncasecmp(opts, cp, strlen(cp)) == 0) {
 			char *s;
 			struct envstring *new_envstring;
@@ -217,8 +219,6 @@
 		}
 		cp = "permitopen=\"";
 		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			char host[256], sport[6];
-			u_short port;
 			char *patterns = xmalloc(strlen(opts) + 1);
 
 			opts += strlen(cp);
@@ -243,8 +243,7 @@
 			}
 			patterns[i] = 0;
 			opts++;
-			if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 &&
-			    sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) {
+			if (channel_add_permitted_opens(patterns) < 0) {
 				debug("%.100s, line %lu: Bad permitopen specification "
 				    "<%.100s>", file, linenum, patterns);
 				auth_debug_add("%.100s, line %lu: "
@@ -252,16 +251,6 @@
 				xfree(patterns);
 				goto bad_option;
 			}
-			if ((port = a2port(sport)) == 0) {
-				debug("%.100s, line %lu: Bad permitopen port <%.100s>",
-				    file, linenum, sport);
-				auth_debug_add("%.100s, line %lu: "
-				    "Bad permitopen port", file, linenum);
-				xfree(patterns);
-				goto bad_option;
-			}
-			if (options.allow_tcp_forwarding)
-				channel_add_permitted_opens(host, port);
 			xfree(patterns);
 			goto next_option;
 		}
--- auth-pam.c	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ auth-pam.c	29 Jan 2003 20:39:19 -0000	1.2
@@ -358,7 +360,7 @@
 		no_port_forwarding_flag &= ~2;
 		no_agent_forwarding_flag &= ~2;
 		no_x11_forwarding_flag &= ~2;
-		if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+		if (!auth_restricted(RESTRICT_TCP, auth_get_user()))
 			channel_permit_all_opens();
 #endif
 	}
--- auth.c	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ auth.c	29 Jan 2003 21:26:11 -0000	1.4
@@ -291,6 +293,31 @@
 	return 0;
 }
 
+/*
+ * Is the user subject to this restriction?
+ */
+int
+auth_restricted(int restriction, struct passwd *pw)
+{
+	debug2("user shell is %s", pw->pw_shell);
+	if ((options.restrictions & restriction) &&
+	    options.restricted_shell != NULL &&
+	    strcmp(options.restricted_shell, pw->pw_shell) == 0) {
+		debug("Restricted shell (%d)", restriction);
+		return 1;
+	} else if ((restriction & RESTRICT_AGENT) && no_agent_forwarding_flag)
+		return 1;
+	else if ((restriction & RESTRICT_ENV) && !options.permit_user_env)
+		return 1;
+	else if ((restriction & RESTRICT_TCP) &&
+	    (!options.allow_tcp_forwarding || no_port_forwarding_flag))
+		return 1;
+	else if ((restriction & RESTRICT_X11) &&
+	    (!options.x11_forwarding || no_x11_forwarding_flag))
+		return 1;
+	else
+		return 0;
+}
 
 /*
  * Given a template and a passwd structure, build a filename
--- auth.h	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ auth.h	29 Jan 2003 20:39:19 -0000	1.3
@@ -142,6 +143,7 @@
 void	auth_log(Authctxt *, int, char *, char *);
 void	userauth_finish(Authctxt *, int, char *);
 int	auth_root_allowed(char *);
+int	auth_restricted(int, struct passwd *);
 
 char	*auth2_read_banner(void);
 
--- channels.c	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ channels.c	28 Jan 2003 19:06:35 -0000	1.4
@@ -96,6 +98,10 @@
 
 /* Number of permitted host/port pairs in the array. */
 static int num_permitted_opens = 0;
+
+/* Don't allow any more to be added. */
+static int fix_permitted_opens = 0;
+
 /*
  * If this is true, all opens are permitted.  This is the case on the server
  * on which we have to trust the client anyway, and the user could do
@@ -1972,7 +1978,7 @@
 }
 
 void
-channel_input_port_open(int type, u_int32_t seq, void *ctxt)
+channel_input_port_open(int type, u_int32_t seq, void *ctxt, int loud)
 {
 	Channel *c = NULL;
 	u_short host_port;
@@ -1989,6 +1995,8 @@
 		originator_string = xstrdup("unknown (remote did not supply name)");
 	}
 	packet_check_eom();
+	if (loud)
+		log("TCP forwarding connection to %s port %d", host, host_port);
 	sock = channel_connect_to(host, host_port);
 	if (sock != -1) {
 		c = channel_new("connected socket",
@@ -2004,6 +2012,18 @@
 	xfree(host);
 }
 
+void
+channel_input_port_open_quiet(int type, u_int32_t seq, void *ctxt)
+{
+	channel_input_port_open(type, seq, ctxt, 0);
+}
+
+void
+channel_input_port_open_loud(int type, u_int32_t seq, void *ctxt)
+{
+	channel_input_port_open(type, seq, ctxt, 1);
+}
+
 
 /* -- tcp forwarding */
 
@@ -2209,6 +2229,8 @@
 				  port);
 #endif
 	/* Initiate forwarding */
+	log("TCP forwarding listening on port %d %s", port,
+	    gateway_ports ? "open" : "private");
 	channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports);
 
 	/* Free the argument string. */
@@ -2227,10 +2249,31 @@
 		all_opens_permitted = 1;
 }
 
+/*
+ * If the server-wide configuration specifies some permitted_opens
+ * then don't allow users to add to them.
+ */
 void
-channel_add_permitted_opens(char *host, int port)
+channel_fix_permitted_opens(void)
 {
-	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+	if (num_permitted_opens != 0)
+		fix_permitted_opens = 1;
+}
+
+int
+channel_add_permitted_opens(char *hostport)
+{
+	char host[256], sport[6];
+	u_short port;
+
+	if (sscanf(hostport, "%255[^:]:%5[0-9]", host, sport) != 2 &&
+	    sscanf(hostport, "%255[^/]/%5[0-9]", host, sport) != 2)
+		return -1;
+	if ((port = a2port(sport)) == 0)
+		return -1;
+
+	if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION ||
+	    fix_permitted_opens)
 		fatal("channel_request_remote_forwarding: too many forwards");
 	debug("allow port forwarding to host %s port %d", host, port);
 
@@ -2239,6 +2282,7 @@
 	num_permitted_opens++;
 
 	all_opens_permitted = 0;
+	return 0;
 }
 
 void
@@ -2246,6 +2290,8 @@
 {
 	int i;
 
+	if (fix_permitted_opens)
+		return;
 	for (i = 0; i < num_permitted_opens; i++)
 		xfree(permitted_opens[i].host_to_connect);
 	num_permitted_opens = 0;
@@ -2448,6 +2494,7 @@
 		    0, xstrdup("X11 inet listener"), 1);
 		nc->single_connection = single_connection;
 	}
+	log("X11 forwarding listening on port %d", 6000+display_number);
 
 	/* Return the display number for the DISPLAY environment variable. */
 	*display_numberp = display_number;
--- channels.h	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ channels.h	28 Jan 2003 19:06:35 -0000	1.4
@@ -176,7 +177,9 @@
 void	 channel_input_oclose(int, u_int32_t, void *);
 void	 channel_input_open_confirmation(int, u_int32_t, void *);
 void	 channel_input_open_failure(int, u_int32_t, void *);
-void	 channel_input_port_open(int, u_int32_t, void *);
+void	 channel_input_port_open(int, u_int32_t, void *, int);
+void	 channel_input_port_open_loud(int, u_int32_t, void *);
+void	 channel_input_port_open_quiet(int, u_int32_t, void *);
 void	 channel_input_window_adjust(int, u_int32_t, void *);
 
 /* file descriptor handling (read/write) */
@@ -194,7 +197,8 @@
 /* tcp forwarding */
 void	 channel_set_af(int af);
 void     channel_permit_all_opens(void);
-void	 channel_add_permitted_opens(char *, int);
+void     channel_fix_permitted_opens(void);
+int	 channel_add_permitted_opens(char *);
 void	 channel_clear_permitted_opens(void);
 void     channel_input_port_forward_request(int, int);
 int	 channel_connect_to(const char *, u_short);
--- clientloop.c	28 Jan 2003 18:06:51 -0000	1.1.1.2
+++ clientloop.c	28 Jan 2003 19:06:35 -0000	1.3
@@ -1342,7 +1344,7 @@
 	dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
-	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open_quiet);
 	dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
 	dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
 	dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
--- servconf.c	28 Jan 2003 18:06:52 -0000	1.1.1.2
+++ servconf.c	29 Jan 2003 21:26:11 -0000	1.8
@@ -39,6 +41,7 @@
 #include "cipher.h"
 #include "kex.h"
 #include "mac.h"
+#include "channels.h"
 
 static void add_listen_addr(ServerOptions *, char *, u_short);
 static void add_one_listen_addr(ServerOptions *, char *, u_short);
@@ -102,6 +105,9 @@
 	options->challenge_response_authentication = -1;
 	options->permit_empty_passwd = -1;
 	options->permit_user_env = -1;
+	options->permit_tcp_listen = -1;
+	options->restricted_shell = NULL;
+	options->restrictions = -1;
 	options->use_login = -1;
 	options->compression = -1;
 	options->allow_tcp_forwarding = -1;
@@ -226,6 +232,10 @@
 		options->permit_empty_passwd = 0;
 	if (options->permit_user_env == -1)
 		options->permit_user_env = 0;
+	if (options->permit_tcp_listen == -1)
+		options->permit_tcp_listen = 1;
+	if (options->restrictions == -1)
+		options->restrictions = 0;
 	if (options->use_login == -1)
 		options->use_login = 0;
 	if (options->compression == -1)
@@ -234,6 +244,7 @@
 		options->allow_tcp_forwarding = 1;
 	if (options->gateway_ports == -1)
 		options->gateway_ports = 0;
+	channel_fix_permitted_opens();
 	if (options->max_startups == -1)
 		options->max_startups = 10;
 	if (options->max_startups_rate == -1)
@@ -294,6 +305,7 @@
 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
 	sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
 	sStrictModes, sEmptyPasswd, sKeepAlives,
+	sPermitTcpConnect, sPermitTcpListen, sRestrictedShell,
 	sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
 	sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
 	sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
@@ -355,6 +367,7 @@
 	{ "x11displayoffset", sX11DisplayOffset },
 	{ "x11uselocalhost", sX11UseLocalhost },
 	{ "xauthlocation", sXAuthLocation },
+	{ "restrictedshell", sRestrictedShell },
 	{ "strictmodes", sStrictModes },
 	{ "permitemptypasswords", sEmptyPasswd },
 	{ "permituserenvironment", sPermitUserEnvironment },
@@ -362,6 +375,8 @@
 	{ "compression", sCompression },
 	{ "keepalive", sKeepAlives },
 	{ "allowtcpforwarding", sAllowTcpForwarding },
+	{ "permittcpconnect", sPermitTcpConnect },
+	{ "permittcplisten", sPermitTcpListen },
 	{ "allowusers", sAllowUsers },
 	{ "denyusers", sDenyUsers },
 	{ "allowgroups", sAllowGroups },
@@ -705,6 +720,30 @@
 		charptr = &options->xauth_location;
 		goto parse_filename;
 
+	case sRestrictedShell:
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing restrictions.",
+			    filename, linenum);
+		options->restrictions = 0;
+		while ((p = strsep(&arg, ",")) != NULL) {
+			if (strcasecmp(p, "agent") == 0)
+				options->restrictions |= RESTRICT_AGENT;
+			else if (strcasecmp(p, "env") == 0)
+				options->restrictions |= RESTRICT_ENV;
+			else if (strcasecmp(p, "rc") == 0)
+				options->restrictions |= RESTRICT_RC;
+			else if (strcasecmp(p, "tcp") == 0)
+				options->restrictions |= RESTRICT_TCP;
+			else if (strcasecmp(p, "x11") == 0)
+				options->restrictions |= RESTRICT_X11;
+			else
+				fatal("%s line %d: unknown restriction %s.",
+				    filename, linenum, p);
+		}
+		charptr = &options->restricted_shell;
+		goto parse_filename;
+
 	case sStrictModes:
 		intptr = &options->strict_modes;
 		goto parse_flag;
@@ -761,6 +800,22 @@
 
 	case sAllowTcpForwarding:
 		intptr = &options->allow_tcp_forwarding;
+		goto parse_flag;
+
+	case sPermitTcpConnect:
+		arg = strdelim(&cp);
+		p = NULL;
+		if (!arg || *arg == '\0')
+			p = "missing";
+		if (channel_add_permitted_opens(arg) < 0)
+			p = "bad";
+		if (p != NULL)
+			fatal("%.200s, line %d: %s inet addr:port.",
+			    filename, linenum, p);
+		break;
+
+	case sPermitTcpListen:
+		intptr = &options->permit_tcp_listen;
 		goto parse_flag;
 
 	case sUsePrivilegeSeparation:
--- servconf.h	28 Jan 2003 18:06:52 -0000	1.1.1.2
+++ servconf.h	29 Jan 2003 21:26:12 -0000	1.7
@@ -32,6 +33,13 @@
 #define	PERMIT_NO_PASSWD	2
 #define	PERMIT_YES		3
 
+/* restrictions */
+#define	RESTRICT_AGENT		1
+#define	RESTRICT_ENV		2
+#define	RESTRICT_RC		4
+#define	RESTRICT_TCP		8
+#define	RESTRICT_X11		16
+
 
 typedef struct {
 	u_int num_ports;
@@ -98,6 +106,9 @@
 	int     permit_empty_passwd;	/* If false, do not permit empty
 					 * passwords. */
 	int     permit_user_env;	/* If true, read ~/.ssh/environment */
+	int     permit_tcp_listen;	/* If true allow -R forwarding */
+	char   *restricted_shell;	/* Restrict users with this shell */
+	int     restrictions;		/* How they are restricted */
 	int     use_login;	/* If true, login(1) is used */
 	int     compression;	/* If true, compression is allowed */
 	int	allow_tcp_forwarding;
--- serverloop.c	28 Jan 2003 18:06:52 -0000	1.1.1.2
+++ serverloop.c	29 Jan 2003 21:26:12 -0000	1.5
@@ -863,8 +865,7 @@
 	originator_port = packet_get_int();
 	packet_check_eom();
 
-	debug("server_request_direct_tcpip: originator %s port %d, target %s port %d",
-	   originator, originator_port, target, target_port);
+	log("TCP forwarding connection to %s port %d", target, target_port);
 
 	/* XXX check permission */
 	sock = channel_connect_to(target, target_port);
@@ -973,12 +974,10 @@
 			fatal("server_input_global_request: no user");
 		listen_address = packet_get_string(NULL); /* XXX currently ignored */
 		listen_port = (u_short)packet_get_int();
-		debug("server_input_global_request: tcpip-forward listen %s port %d",
-		    listen_address, listen_port);
 
 		/* check permissions */
-		if (!options.allow_tcp_forwarding ||
-		    no_port_forwarding_flag
+		if (!options.permit_tcp_listen ||
+		    auth_restricted(RESTRICT_TCP, pw)
 #ifndef NO_IPPORT_RESERVED_CONCEPT
 		    || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0)
 #endif
@@ -987,6 +986,8 @@
 			packet_send_debug("Server has disabled port forwarding.");
 		} else {
 			/* Start listening on the port */
+			log("TCP forwarding listening on %s port %d",
+			    listen_address, listen_port);
 			success = channel_setup_remote_fwd_listener(
 			    listen_address, listen_port, options.gateway_ports);
 		}
@@ -1061,7 +1062,7 @@
 	dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
-	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open_loud);
 }
 static void
 server_init_dispatch_15(void)
--- session.c	28 Jan 2003 18:06:52 -0000	1.1.1.2
+++ session.c	29 Jan 2003 20:39:20 -0000	1.7
@@ -212,7 +214,7 @@
 	}
 
 	/* setup the channel layer */
-	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+	if (!auth_restricted(RESTRICT_TCP, authctxt->pw))
 		channel_permit_all_opens();
 
 	if (compat20)
@@ -312,7 +314,7 @@
 			break;
 
 		case SSH_CMSG_AGENT_REQUEST_FORWARDING:
-			if (no_agent_forwarding_flag || compat13) {
+			if (auth_restricted(RESTRICT_AGENT, s->pw) || compat13) {
 				debug("Authentication agent forwarding not permitted for this authentication.");
 				break;
 			}
@@ -321,11 +323,7 @@
 			break;
 
 		case SSH_CMSG_PORT_FORWARD_REQUEST:
-			if (no_port_forwarding_flag) {
-				debug("Port forwarding not permitted for this authentication.");
-				break;
-			}
-			if (!options.allow_tcp_forwarding) {
+			if (auth_restricted(RESTRICT_TCP, s->pw)) {
 				debug("Port forwarding not permitted.");
 				break;
 			}
@@ -1085,7 +1083,7 @@
 		    auth_sock_name);
 
 	/* read $HOME/.ssh/environment. */
-	if (options.permit_user_env && !options.use_login) {
+	if (!options.use_login && !auth_restricted(RESTRICT_ENV, pw)) {
 		snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
 		    strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
 		read_environment_file(&env, &envsize, buf);
@@ -1102,6 +1100,10 @@
 /*
  * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
  * first in this order).
+ *
+ * A properly-implemented restricted shell doesn't need the
+ * restriction tests, but they're useful for reducing the
+ * amount of noise in the process accounting logs.
  */
 static void
 do_rc_files(Session *s, const char *shell)
@@ -1111,11 +1113,12 @@
 	int do_xauth;
 	struct stat st;
 
-	do_xauth =
+	do_xauth = !auth_restricted(RESTRICT_X11, s->pw) &&
 	    s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
 
 	/* ignore _PATH_SSH_USER_RC for subsystems */
-	if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
+	if (!s->is_subsystem && !auth_restricted(RESTRICT_RC, s->pw) &&
+	    (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
 		snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
 		    shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
 		if (debug_flag)
@@ -1723,8 +1726,8 @@
 {
 	static int called = 0;
 	packet_check_eom();
-	if (no_agent_forwarding_flag) {
-		debug("session_auth_agent_req: no_agent_forwarding_flag");
+	if (auth_restricted(RESTRICT_AGENT, s->pw)) {
+		debug("session_auth_agent_req: agent forwarding disabled");
 		return 0;
 	}
 	if (called) {
@@ -2019,12 +2022,8 @@
 	char display[512], auth_display[512];
 	char hostname[MAXHOSTNAMELEN];
 
-	if (no_x11_forwarding_flag) {
-		packet_send_debug("X11 forwarding disabled in user configuration file.");
-		return 0;
-	}
-	if (!options.x11_forwarding) {
-		debug("X11 forwarding disabled in server configuration file.");
+	if (auth_restricted(RESTRICT_X11, s->pw)) {
+		packet_send_debug("X11 forwarding disabled.");
 		return 0;
 	}
 	if (!options.xauth_location ||
--- sshd_config.5	28 Jan 2003 18:06:53 -0000	1.1.1.2
+++ sshd_config.5	29 Jan 2003 21:26:12 -0000	1.8
@@ -465,6 +466,35 @@
 If this option is set to
 .Dq no
 root is not allowed to login.
+.It Cm PermitTcpConnect
+Restricts TCP forwarding from the client so that
+only certain connection destinations are permitted.
+In the absence of any
+.Cm PermitTcpConnect
+options, any outgoing connection is permitted
+(although per-key restrictions may be imposed by
+.Cm permitopen=""
+options in
+.Pa authorized_keys
+files).
+If
+.Cm PermitTcpConnect
+options are present then
+.Nm sshd
+will only allow connections to the
+.Ar host Ns : Ns Ar port
+pairs that are specified.
+Multiple permitted destinations may be specified using multiple
+.Cm PermitTcpConnect
+options.
+IPv6 addresses may be specified using the syntax
+.Ar host Ns / Ns Ar port
+for the argument instead of
+.Ar host Ns : Ns Ar port .
+.It Cm PermitTcpListen
+Specifies whether TCP forwarding to the client is allowed.
+The default is
+.Dq yes .
 .It Cm PermitUserEnvironment
 Specifies whether
 .Pa ~/.ssh/environment
@@ -533,6 +563,29 @@
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
+.It Cm RestrictedShell
+This option selectively turns off various features
+for users with the shell specified in the second argument.
+The first argument is a comma-separated list, as follows.
+If
+.Dq agent
+is specified then agent forwarding is disabled.
+If
+.Dq env
+is specified then
+.Cm PermitUserEnvironment
+is turned off.
+If
+.Dq rc
+is specified then
+.Pa ~/.ssh/rc
+is not run.
+If
+.Dq tcp
+is specified then TCP port forwarding is disabled.
+If
+.Dq x11
+is specified then X11 fowarding is disabled.
 .It Cm RhostsAuthentication
 Specifies whether authentication using rhosts or /etc/hosts.equiv
 files is sufficient.




More information about the openssh-unix-dev mailing list