OpenSSH PATCH: OpenCommand and CloseCommand

Clifford Wolf clifford at clifford.at
Thu Aug 26 22:16:38 EST 2004


Hi,

the attached patch adds support for the keywords "OpenCommand" and
"CloseCommand" to ssh_config. They are commands which are executed before
the connection is established (or ProxyCommand started) and after the
connection has been closed (or ProxyCommand ended).

this is usefull for stuff like portknocking or (that's what I wrote the
patch for) talking with trapdoor2 (http://oss.linbit.com/trapdoor2/).

it would be great to see that patch applied (or compareable functionality
implemented) in one of the coming openssh releases.

yours,
 - clifford

PS: I'm not subscribed to this list, so please CC me on replies.

-- 
 ____   ___   ____ _  __  _     _ www.rocklinux.org
|  _ \ / _ \ / ___| |/ / | |   (_)_ __  _   ___  __
| |_) | | | | |   | ' /  | |   | | '_ \| | | \ \/ /
|  _ <| |_| | |___| . \  | |___| | | | | |_| |>  <         Clifford Wolf
|_| \_\\___/ \____|_|\_\ |_____|_|_| |_|\__,_/_/\_\      www.clifford.at

checking whether the linker (ld -static) supports shared libraries... yes

-------------- next part --------------
This is a patch for OpenSSH 3.8p1 by Clifford Wolf <clifford at clifford.at>
=========================================================================

This patch adds OpenCommand and CloseCommand keywords to ssh_config. This
commands are run before the connection is established and after it has been
closed. It can be used e.g. to open trapdoors or establish tunnels.


 openssh-3.8p1/readconf.c   |   20 +++++++++-
 openssh-3.8p1/readconf.h   |    2 +
 openssh-3.8p1/ssh.0        |    2 +
 openssh-3.8p1/ssh.1        |    2 +
 openssh-3.8p1/ssh.c        |   10 +++++
 openssh-3.8p1/ssh_config.0 |   13 ++++++
 openssh-3.8p1/ssh_config.5 |   18 +++++++++
 openssh-3.8p1/sshconnect.c |   87 +++++++++++++++++++++++++++++++++++++++++++++
 openssh-3.8p1/sshconnect.h |    4 ++
 9 files changed, 156 insertions(+), 2 deletions(-)


Index: ssh.1
--- openssh-3.8p1.orig/ssh.1	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/ssh.1	(revision 25)
@@ -614,6 +614,7 @@
 .It CheckHostIP
 .It Cipher
 .It Ciphers
+.It CloseCommand
 .It ClearAllForwardings
 .It Compression
 .It CompressionLevel
@@ -639,6 +640,7 @@
 .It MACs
 .It NoHostAuthenticationForLocalhost
 .It NumberOfPasswordPrompts
+.It OpenCommand
 .It PasswordAuthentication
 .It Port
 .It PreferredAuthentications

Index: sshconnect.h
--- openssh-3.8p1.orig/sshconnect.h	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/sshconnect.h	(revision 25)
@@ -34,6 +34,10 @@
 };
 
 int
+ssh_run_command(const char *type, const char *host, u_short port,
+    const char *run_command);
+
+int
 ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
     int, const char *);
 

Index: ssh.c
--- openssh-3.8p1.orig/ssh.c	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/ssh.c	(revision 25)
@@ -606,6 +606,11 @@
 	    strcmp(options.proxy_command, "none") == 0)
 		options.proxy_command = NULL;
 
+	/* Execute open command, if set */
+	if (options.open_command != NULL &&
+	    strcmp(options.open_command, "none") != 0)
+		ssh_run_command("open", host, options.port, options.open_command);
+
 	/* Open a connection to the remote host. */
 	if (ssh_connect(host, &hostaddr, options.port,
 	    options.address_family, options.connection_attempts,
@@ -725,6 +730,11 @@
 	if (proxy_command_pid > 1)
 		kill(proxy_command_pid, SIGHUP);
 
+	/* Execute close command, if set */
+	if (options.close_command != NULL &&
+	    strcmp(options.close_command, "none") != 0)
+		ssh_run_command("close", host, options.port, options.close_command);
+
 	return exit_status;
 }
 

Index: ssh.0
--- openssh-3.8p1.orig/ssh.0	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/ssh.0	(revision 25)
@@ -354,6 +354,7 @@
                    CheckHostIP
                    Cipher
                    Ciphers
+                   CloseCommand
                    ClearAllForwardings
                    Compression
                    CompressionLevel
@@ -379,6 +380,7 @@
                    MACs
                    NoHostAuthenticationForLocalhost
                    NumberOfPasswordPrompts
+                   OpenCommand
                    PasswordAuthentication
                    Port
                    PreferredAuthentications

Index: readconf.h
--- openssh-3.8p1.orig/readconf.h	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/readconf.h	(revision 25)
@@ -72,6 +72,8 @@
 	char   *hostname;	/* Real host to connect. */
 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
 	char   *proxy_command;	/* Proxy command for connecting the host. */
+	char   *open_command;	/* Open command for before connecting the host. */
+	char   *close_command;	/* Close command for after connecting the host. */
 	char   *user;		/* User to log in as. */
 	int     escape_char;	/* Escape character; -2 = none */
 

Index: readconf.c
--- openssh-3.8p1.orig/readconf.c	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/readconf.c	(revision 25)
@@ -93,7 +93,8 @@
 	oPasswordAuthentication, oRSAAuthentication,
 	oChallengeResponseAuthentication, oXAuthLocation,
 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
-	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
+	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication,
+	oOpenCommand, oCloseCommand, oProxyCommand,
 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
 	oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
@@ -149,6 +150,8 @@
 	{ "identityfile2", oIdentityFile },			/* alias */
 	{ "hostname", oHostName },
 	{ "hostkeyalias", oHostKeyAlias },
+	{ "opencommand", oOpenCommand },
+	{ "closecommand", oCloseCommand },
 	{ "proxycommand", oProxyCommand },
 	{ "port", oPort },
 	{ "cipher", oCipher },
@@ -537,10 +540,21 @@
 		charptr = &options->smartcard_device;
 		goto parse_string;
 
+	case oOpenCommand:
+	case oCloseCommand:
 	case oProxyCommand:
 		if (s == NULL)
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
-		charptr = &options->proxy_command;
+		switch (opcode) {
+		case oOpenCommand:
+			charptr = &options->open_command;
+			break;
+		case oCloseCommand:
+			charptr = &options->close_command;
+			break;
+		default:
+			charptr = &options->proxy_command;
+		}
 		len = strspn(s, WHITESPACE "=");
 		if (*activep && *charptr == NULL)
 			*charptr = xstrdup(s + len);
@@ -853,6 +867,8 @@
 	options->num_identity_files = 0;
 	options->hostname = NULL;
 	options->host_key_alias = NULL;
+	options->open_command = NULL;
+	options->close_command = NULL;
 	options->proxy_command = NULL;
 	options->user = NULL;
 	options->escape_char = -1;

Index: sshconnect.c
--- openssh-3.8p1.orig/sshconnect.c	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/sshconnect.c	(revision 25)
@@ -55,6 +55,93 @@
 static void warn_changed_key(Key *);
 
 /*
+ * Run the given command
+ */
+int
+ssh_run_command(const char *type, const char *host, u_short port, const char *run_command)
+{
+	Buffer command;
+	const char *cp;
+	char *command_string;
+	pid_t pid;
+	char strport[NI_MAXSERV];
+	int status;
+
+	/* Convert the port number into a string. */
+	snprintf(strport, sizeof strport, "%hu", port);
+
+	/*
+	 * Build the final command string in the buffer by making the
+	 * appropriate substitutions to the given proxy command.
+	 *
+	 * Use "exec" to avoid "sh -c" processes on some platforms
+	 * (e.g. Solaris)
+	 */
+	buffer_init(&command);
+	buffer_append(&command, "exec ", 5);
+
+	for (cp = run_command; *cp; cp++) {
+		if (cp[0] == '%' && cp[1] == '%') {
+			buffer_append(&command, "%", 1);
+			cp++;
+			continue;
+		}
+		if (cp[0] == '%' && cp[1] == 'h') {
+			buffer_append(&command, host, strlen(host));
+			cp++;
+			continue;
+		}
+		if (cp[0] == '%' && cp[1] == 'p') {
+			buffer_append(&command, strport, strlen(strport));
+			cp++;
+			continue;
+		}
+		buffer_append(&command, cp, 1);
+	}
+	buffer_append(&command, "\0", 1);
+
+	/* Get the final command string. */
+	command_string = buffer_ptr(&command);
+
+	debug("Executing %s command: %.500s", type, command_string);
+
+	/* Fork and execute the proxy command. */
+	if ((pid = fork()) == 0) {
+		char *argv[10];
+
+		/* Child.  Permanently give up superuser privileges. */
+		seteuid(original_real_uid);
+		setuid(original_real_uid);
+
+		argv[0] = _PATH_BSHELL;
+		argv[1] = "-c";
+		argv[2] = command_string;
+		argv[3] = NULL;
+
+		execv(argv[0], argv);
+		perror(argv[0]);
+		exit(1);
+	}
+	/* Parent. */
+	if (pid < 0)
+		fatal("fork failed: %.100s", strerror(errno));
+	else {
+		waitpid(pid, &status, 0);
+		if ( WIFSIGNALED(status) )
+			fatal("%s command '%.500s' failed: cought signal %d",
+					type, command_string, WTERMSIG(status));
+		if ( WEXITSTATUS(status) )
+			fatal("%s command '%.500s' failed: returned %d",
+					type, command_string, WEXITSTATUS(status));
+	}
+
+	/* Free the command name. */
+	buffer_free(&command);
+
+	/* Indicate OK return */
+	return 0;
+}
+/*
  * Connect to the given ssh server using a proxy command.
  */
 static int

Index: ssh_config.0
--- openssh-3.8p1.orig/ssh_config.0	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/ssh_config.0	(revision 25)
@@ -100,6 +100,13 @@
              Specifies whether to use compression.  The argument must be
              ``yes'' or ``no''.  The default is ``no''.
 
+     CloseCommand
+             Specifies the command to run after the connection to the server
+             has been closed.  The command string extends to the end of the
+             line, and is executed with /bin/sh.  In the command string, `%h'
+             will be substituted by the host name to connect and `%p' by the
+             port.
+
      CompressionLevel
              Specifies the compression level to use if compression is enabled.
              The argument must be an integer from 1 (fast) to 9 (slow, best).
@@ -273,6 +280,12 @@
              Specifies the number of password prompts before giving up.  The
              argument to this keyword must be an integer.  Default is 3.
 
+     OpenCommand
+             Specifies the command to run before the connection to the server
+             is opened.  The command string extends to the end of the line,
+             and is executed with /bin/sh.  In the command string, `%h' will
+             be substituted by the host name to connect and `%p' by the port.
+
      PasswordAuthentication
              Specifies whether to use password authentication.  The argument
              to this keyword must be ``yes'' or ``no''.  The default is

Index: ssh_config.5
--- openssh-3.8p1.orig/ssh_config.5	(.../.transvn:beginning)	(revision 25)
+++ openssh-3.8p1/ssh_config.5	(revision 25)
@@ -215,6 +215,15 @@
 .Dq no .
 The default is
 .Dq no .
+.It Cm CloseCommand
+Specifies the command to run after the connection to the server has been closed.
+The command string extends to the end of the line, and is executed with
+.Pa /bin/sh .
+In the command string,
+.Ql %h
+will be substituted by the host name to connect and
+.Ql %p
+by the port.
 .It Cm CompressionLevel
 Specifies the compression level to use if compression is enabled.
 The argument must be an integer from 1 (fast) to 9 (slow, best).
@@ -446,6 +455,15 @@
 Specifies the number of password prompts before giving up.
 The argument to this keyword must be an integer.
 Default is 3.
+.It Cm OpenCommand
+Specifies the command to run before the connection to the server is opened.
+The command string extends to the end of the line, and is executed with
+.Pa /bin/sh .
+In the command string,
+.Ql %h
+will be substituted by the host name to connect and
+.Ql %p
+by the port.
 .It Cm PasswordAuthentication
 Specifies whether to use password authentication.
 The argument to this keyword must be



Generated by Transvn 0.15.


More information about the openssh-unix-dev mailing list