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));