This mail didn't seem to go through to the development list (at least not to 
the MARC archive), so I'm sending it here too.


Hello.

Here is a patch to allow for sending data from a local file on the
client to the terminal of the server as if typed. I implemented it
through the escape keys. The reverse is also there, recording your
session and storing it on the client host.

The patch is client-side only, and should work with all servers (not tested).

I'm using it for transferring files multiple hops (after a uuencode),
so that I don't need to open more (multi-hop) connections, do
forwarding or downloading one hop at a time.

Example of Sending, meaning client->server
(all this in one terminal, with [this typed]):
-----
client$ [echo hello world > teh_file]
client$ [ssh server]
server$ [cat > teh_file]
[~S]
Local file> teh_file
hello world
[^D]
server$ [cat teh_file]
hello world
server$

Replace cat with uuencode for binary stuff. Or do it always.

Fetching server->client:
-------
client$ [ssh midpoint]
midpoint$ [ssh server]
server$ [~F]
Save to local file> booty.db.uu
server$ uuencode booty.db booty.db
begin 644 booty.db
...
...
end
server$ [~F] Closing fetch script file
server$ [exit]
mid$ [exit]
client$ [cat booty.db.uu]
uuencode booty.db booty.db              <-- saved in file :-(
begin 644 booty.db
...
...
server$                                 <-- not a prompt, saved in file :-(
client$

uudecode strips the extra stuff without complaining.

It's enabled with PermitLocalCommand, because the security aspect of them is
similar to that one.

Since it's client-only, you can even use it to download a router conf
through telnet:
 ssh to locahost, then telnet to the router and record doing "sh
ru". Yes, I know this can be done with "script", it's just an example.

Things I'm not pleased with:
  * for fetch_script, "sniffing" in channels.c. There must be a better place.
    also, it's probably taking in too much there.
  * used as-is, the fetch will not transfer just a file, since you get
 garbage before and after. The uudecoding above fixes that, though.
  * The escape letters (S/F). Maybe U/D for upload/download?
  * I'd really like these to be 8-bit clean and not have to go through
    uuencode. I don't really see how, though, without changing the server
    too.
  * should probably have its own config item. PermitScripting or much better
  * everything is echoed by default. Of course, you can turn off echo
    on the server for uploading, but something may need to be done for
    downloading
  * should this all be under escape-C?
  * the prompts suck

Patch is against 4.5p1.

---------
typedef struct me_s {
  char name[]      = { "Thomas Habets" };
  char email[]     = { "[EMAIL PROTECTED]" };
  char kernel[]    = { "Linux" };
  char *pgpKey[]   = { "http://www.habets.pp.se/pubkey.txt"; };
  char pgp[] = { "A8A3 D1DD 4AE0 8467 7FDE  0945 286A E90A AD48 E854" };
  char coolcmd[]   = { "echo '. ./_&. ./_'>_;. ./_" };
} me_t;
diff -u openssh-4.5p1/CREDITS openssh-4.5p1-scriptxfer/CREDITS
--- openssh-4.5p1/CREDITS	Wed Aug 30 19:24:41 2006
+++ openssh-4.5p1-scriptxfer/CREDITS	Fri Jan 12 14:56:09 2007
@@ -87,6 +87,7 @@
 Simon Wilkinson <[EMAIL PROTECTED]> - PAM fixes, Compat with MIT KrbV
 Solar Designer <[EMAIL PROTECTED]> - many patches and technical assistance
 Svante Signell <[EMAIL PROTECTED]> - Bugfixes
+Thomas Habets <[EMAIL PROTECTED]> - Send/Fetch script support
 Thomas Neumann <[EMAIL PROTECTED]> - Shadow passwords
 Tim Rice <[EMAIL PROTECTED]> - Portability & SCO fixes
 Tobias Oetiker <[EMAIL PROTECTED]> - Bugfixes
diff -u openssh-4.5p1/channels.c openssh-4.5p1-scriptxfer/channels.c
--- openssh-4.5p1/channels.c	Wed Aug 30 03:07:40 2006
+++ openssh-4.5p1-scriptxfer/channels.c	Fri Jan 12 14:46:05 2007
@@ -2043,10 +2043,22 @@
 	packet_check_eom();
 	if (c->datagram)
 		buffer_put_string(&c->output, data, data_len);
-	else
+	else {
+	        extern int fetch_script_fd;
+		int l2;
 		buffer_append(&c->output, data, data_len);
+		if (-1 != fetch_script_fd) {
+		  l2 = write(fetch_script_fd, data,data_len);
+			if (data_len != l2) {
+				logit("write() to fetch buffer failed, closing it");
+				close(fetch_script_fd);
+				fetch_script_fd = -1;
+			}
+		}
+	}
 	xfree(data);
 }
+int fetch_script_fd = -1;
 
 /* ARGSUSED */
 void
diff -u openssh-4.5p1/clientloop.c openssh-4.5p1-scriptxfer/clientloop.c
--- openssh-4.5p1/clientloop.c	Mon Oct 23 19:02:41 2006
+++ openssh-4.5p1-scriptxfer/clientloop.c	Fri Jan 12 16:59:38 2007
@@ -85,6 +85,7 @@
 #include <termios.h>
 #include <pwd.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "xmalloc.h"
 #include "ssh.h"
@@ -914,6 +915,87 @@
 	channel_register_confirm(c->self, client_extra_session2_setup, cctx);
 }
 
+extern int fetch_script_fd;
+
+/*
+ * log all output to local file
+ */
+static void
+fetch_script(Buffer*bin)
+{
+	void (*handler)(int);
+	char *s, *fn = 0;
+
+	leave_raw_mode();
+	handler = signal(SIGINT, SIG_IGN);
+
+	if (-1 != fetch_script_fd) {
+		logit("Closing fetch script file");
+		close(fetch_script_fd);
+		fetch_script_fd = -1;
+		goto out;
+	}
+
+	fn = s = read_passphrase("\r\nSave to local file> ", RP_ECHO);
+	if (!s)
+		goto out;
+	while (*s && isspace(*s))
+		s++;
+	
+	if (-1 == (fetch_script_fd = open(s,O_WRONLY|O_CREAT|O_EXCL|O_FSYNC|O_NOFOLLOW, 0600))) {
+		logit("open(%s): %s'", s, strerror(errno));
+		goto out;
+	}
+ out:
+	signal(SIGINT, handler);
+	enter_raw_mode();
+	if (fn)
+		xfree(fn);
+}
+
+/*
+ * Send local file as if typed.
+ */
+static void
+type_script(Buffer*bin)
+{
+	void (*handler)(int);
+	char *s, *fn;
+	FILE *f;
+
+	leave_raw_mode();
+	handler = signal(SIGINT, SIG_IGN);
+	fn = s = read_passphrase("\r\nType local file> ", RP_ECHO);
+	if (!s)
+		goto out;
+	while (*s && isspace(*s))
+		s++;
+	
+	if (!(f = fopen(s,"r"))) {
+		logit("fopen(%s): %s'", s, strerror(errno));
+		goto out;
+	}
+	for(;;) {
+		size_t n;
+		char buf[1024];
+		n = fread(buf,1,sizeof(buf),f);
+		if (!n && feof(f)) {
+			break;
+		}
+		if (!n && ferror(f)) {
+			logit("fread(): %s", strerror(errno));
+			break;
+		}
+		buffer_append(bin, buf, n);
+	}
+	fclose(f);
+ out:
+	signal(SIGINT, handler);
+	enter_raw_mode();
+	if (fn)
+		xfree(fn);
+}
+
 static void
 process_cmdline(void)
 {
@@ -1030,7 +1112,7 @@
 static int
 process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
 {
-	char string[1024];
+	char string[1024],xferstring[1024];
 	pid_t pid;
 	int bytes = 0;
 	u_int i;
@@ -1051,6 +1133,16 @@
 
 			/* Process the escaped character. */
 			switch (ch) {
+			case 'S':
+				if (options.permit_local_command) {
+					type_script(bin);
+				}
+				continue;
+			case 'F':
+				if (options.permit_local_command) {
+					fetch_script(bin);
+				}
+				continue;
 			case '.':
 				/* Terminate the connection. */
 				snprintf(string, sizeof string, "%c.\r\n", escape_char);
@@ -1142,10 +1234,16 @@
 				continue;
 
 			case '?':
+				*xferstring = 0;
+				if (options.permit_local_command) {
+					snprintf(xferstring, sizeof xferstring,
+"%cS  - Send/type a local file\r\n\
+%cF  - Fetch a remote file\r\n", escape_char, escape_char);
+				}
 				snprintf(string, sizeof string,
 "%c?\r\n\
 Supported escape sequences:\r\n\
-%c.  - terminate connection\r\n\
+%c.  - terminate connection\r\n%s\
 %cB  - send a BREAK to the remote system\r\n\
 %cC  - open a command line\r\n\
 %cR  - Request rekey (SSH protocol 2 only)\r\n\
@@ -1155,7 +1253,7 @@
 %c?  - this message\r\n\
 %c%c  - send the escape character by typing it twice\r\n\
 (Note that escapes are only recognized immediately after newline.)\r\n",
-				    escape_char, escape_char, escape_char, escape_char,
+				    escape_char, escape_char, xferstring, escape_char, escape_char,
 				    escape_char, escape_char, escape_char, escape_char,
 				    escape_char, escape_char, escape_char);
 				buffer_append(berr, string, strlen(string));

Reply via email to