From 0fed43e9f4974570791bdb8a5d61631a4e84d1b0 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Wed, 27 Sep 2000 09:36:39 +0000 Subject: [PATCH] Remove the special hooks in ssh.c for pscp. pscp now uses the standard interface to the outside of the ssh module. This means pscp now works without change in SSH2. [originally from svn r638] --- Makefile | 2 +- scp.c | 153 +++++++++++++++++++++++++++++++++++++++++------ scp.h | 12 ---- ssh.c | 177 +++---------------------------------------------------- 4 files changed, 145 insertions(+), 199 deletions(-) delete mode 100644 scp.h diff --git a/Makefile b/Makefile index 13419307..62e34ea4 100644 --- a/Makefile +++ b/Makefile @@ -204,7 +204,7 @@ sshdh.$(OBJ): sshdh.c ssh.h sshdss.$(OBJ): sshdss.c ssh.h sshbn.$(OBJ): sshbn.c ssh.h sshpubk.$(OBJ): sshpubk.c ssh.h -scp.$(OBJ): scp.c putty.h scp.h +scp.$(OBJ): scp.c putty.h version.$(OBJ): version.c be_all.$(OBJ): be_all.c be_nossh.$(OBJ): be_nossh.c diff --git a/scp.c b/scp.c index b2ba5015..7a0a2253 100644 --- a/scp.c +++ b/scp.c @@ -26,7 +26,6 @@ #define PUTTY_DO_GLOBALS #include "putty.h" -#include "scp.h" #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \ ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000) @@ -77,7 +76,6 @@ static void gui_update_stats(char *name, unsigned long size, int percentage, tim * These functions are needed to link with other modules, but * (should) never get called. */ -void term_out(void) { abort(); } void begin_session(void) { } void write_clip (void *data, int len) { } void term_deselect(void) { } @@ -178,6 +176,120 @@ void connection_fatal(char *fmt, ...) exit(1); } +/* + * Receive a block of data from the SSH link. Block until all data + * is available. + * + * To do this, we repeatedly call the SSH protocol module, with our + * own trap in term_out() to catch the data that comes back. We do + * this until we have enough data. + */ +static unsigned char *outptr; /* where to put the data */ +static unsigned outlen; /* how much data required */ +static unsigned char *pending = NULL; /* any spare data */ +static unsigned pendlen=0, pendsize=0; /* length and phys. size of buffer */ +void term_out(void) { + /* + * Here we must deal with a block of data, in `inbuf', size + * `inbuf_head'. + */ + unsigned char *p = inbuf; + unsigned len = inbuf_head; + + inbuf_head = 0; + + /* + * If this is before the real session begins, just return. + */ + if (!outptr) + return; + + if (outlen > 0) { + unsigned used = outlen; + if (used > len) used = len; + memcpy(outptr, p, used); + outptr += used; outlen -= used; + p += used; len -= used; + } + + if (len > 0) { + if (pendsize < pendlen + len) { + pendsize = pendlen + len + 4096; + pending = (pending ? realloc(pending, pendsize) : + malloc(pendsize)); + if (!pending) + fatalbox("Out of memory"); + } + memcpy(pending+pendlen, p, len); + pendlen += len; + } +} +static int ssh_scp_recv(unsigned char *buf, int len) { + SOCKET s; + + outptr = buf; + outlen = len; + + /* + * See if the pending-input block contains some of what we + * need. + */ + if (pendlen > 0) { + unsigned pendused = pendlen; + if (pendused > outlen) + pendused = outlen; + memcpy(outptr, pending, pendused); + memmove(pending, pending+pendused, pendlen-pendused); + outptr += pendused; + outlen -= pendused; + pendlen -= pendused; + if (pendlen == 0) { + pendsize = 0; + free(pending); + pending = NULL; + } + if (outlen == 0) + return len; + } + + while (outlen > 0) { + fd_set readfds; + s = back->socket(); + if (s == INVALID_SOCKET) { + connection_open = FALSE; + return 0; + } + FD_ZERO(&readfds); + FD_SET(s, &readfds); + if (select(1, &readfds, NULL, NULL, NULL) < 0) + return 0; /* doom */ + back->msg(0, FD_READ); + term_out(); + } + + return len; +} + +/* + * Loop through the ssh connection and authentication process. + */ +static void ssh_scp_init(void) { + SOCKET s; + + s = back->socket(); + if (s == INVALID_SOCKET) + return; + while (!back->sendok()) { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(s, &readfds); + if (select(1, &readfds, NULL, NULL, NULL) < 0) + return; /* doom */ + back->msg(0, FD_READ); + term_out(); + } +} + /* * Print an error message and exit after closing the SSH link. */ @@ -194,7 +306,7 @@ static void bump(char *fmt, ...) if (connection_open) { char ch; - ssh_scp_send_eof(); + back->special(TS_EOF); ssh_scp_recv(&ch, 1); } exit(1); @@ -278,9 +390,16 @@ static void do_cmd(char *host, char *user, char *cmd) if (portnumber) cfg.port = portnumber; - err = ssh_scp_init(cfg.host, cfg.port, cmd, &realhost); + strncpy(cfg.remote_cmd, cmd, sizeof(cfg.remote_cmd)); + cfg.remote_cmd[sizeof(cfg.remote_cmd)-1] = '\0'; + cfg.nopty = TRUE; + + back = &ssh_backend; + + err = back->init(NULL, cfg.host, cfg.port, &realhost); if (err != NULL) bump("ssh_init: %s", err); + ssh_scp_init(); if (verbose && realhost != NULL) tell_user(stderr, "Connected to %s\n", realhost); @@ -398,7 +517,7 @@ static void run_err(const char *fmt, ...) strcpy(str, "\01scp: "); vsprintf(str+strlen(str), fmt, ap); strcat(str, "\n"); - ssh_scp_send(str, strlen(str)); + back->send(str, strlen(str)); tell_user(stderr, "%s",str); va_end(ap); } @@ -469,7 +588,7 @@ static void source(char *src) TIME_WIN_TO_POSIX(actime, atime); TIME_WIN_TO_POSIX(wrtime, mtime); sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime); - ssh_scp_send(buf, strlen(buf)); + back->send(buf, strlen(buf)); if (response()) return; } @@ -478,7 +597,7 @@ static void source(char *src) sprintf(buf, "C0644 %lu %s\n", size, last); if (verbose) tell_user(stderr, "Sending file modes: %s", buf); - ssh_scp_send(buf, strlen(buf)); + back->send(buf, strlen(buf)); if (response()) return; @@ -496,7 +615,7 @@ static void source(char *src) if (statistics) printf("\n"); bump("%s: Read error", src); } - ssh_scp_send(transbuf, k); + back->send(transbuf, k); if (statistics) { stat_bytes += k; if (time(NULL) != stat_lasttime || @@ -509,7 +628,7 @@ static void source(char *src) } CloseHandle(f); - ssh_scp_send("", 1); + back->send("", 1); (void) response(); } @@ -538,7 +657,7 @@ static void rsource(char *src) sprintf(buf, "D0755 0 %s\n", last); if (verbose) tell_user(stderr, "Entering directory: %s", buf); - ssh_scp_send(buf, strlen(buf)); + back->send(buf, strlen(buf)); if (response()) return; @@ -560,7 +679,7 @@ static void rsource(char *src) FindClose(dir); sprintf(buf, "E\n"); - ssh_scp_send(buf, strlen(buf)); + back->send(buf, strlen(buf)); (void) response(); } @@ -592,7 +711,7 @@ static void sink(char *targ) if (targetshouldbedirectory && !targisdir) bump("%s: Not a directory", targ); - ssh_scp_send("", 1); + back->send("", 1); while (1) { settime = 0; gottime: @@ -616,13 +735,13 @@ static void sink(char *targ) case '\02': /* fatal error */ bump("%s", buf+1); case 'E': - ssh_scp_send("", 1); + back->send("", 1); return; case 'T': if (sscanf(buf, "T%ld %*d %ld %*d", &mtime, &atime) == 2) { settime = 1; - ssh_scp_send("", 1); + back->send("", 1); goto gottime; } bump("Protocol error: Illegal time format"); @@ -672,7 +791,7 @@ static void sink(char *targ) continue; } - ssh_scp_send("", 1); + back->send("", 1); if (statistics) { stat_bytes = 0; @@ -725,7 +844,7 @@ static void sink(char *targ) run_err("%s: Write error", namebuf); continue; } - ssh_scp_send("", 1); + back->send("", 1); } } @@ -1032,7 +1151,7 @@ int main(int argc, char *argv[]) if (connection_open) { char ch; - ssh_scp_send_eof(); + back->special(TS_EOF); ssh_scp_recv(&ch, 1); } WSACleanup(); diff --git a/scp.h b/scp.h deleted file mode 100644 index bb7c0f73..00000000 --- a/scp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * scp.h - * Joris van Rantwijk, Aug 1999, Jun 2000. - */ - -/* Exported from ssh.c */ -extern int scp_flags; -char * ssh_scp_init(char *host, int port, char *cmd, char **realhost); -int ssh_scp_recv(unsigned char *buf, int len); -void ssh_scp_send(unsigned char *buf, int len); -void ssh_scp_send_eof(void); - diff --git a/ssh.c b/ssh.c index 0db92fc2..cdb12bfc 100644 --- a/ssh.c +++ b/ssh.c @@ -13,7 +13,6 @@ #include "putty.h" #include "tree234.h" #include "ssh.h" -#include "scp.h" #ifndef FALSE #define FALSE 0 @@ -291,6 +290,11 @@ static void c_write (char *buf, int len) { c_write1(*buf++); } +static void c_writedata (char *buf, int len) { + while (len--) + c_write1(*buf++); +} + struct Packet { long length; int type; @@ -1645,7 +1649,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) { if (pktin.type == SSH1_SMSG_STDOUT_DATA || pktin.type == SSH1_SMSG_STDERR_DATA) { long len = GET_32BIT(pktin.body); - c_write(pktin.body+4, len); + c_writedata(pktin.body+4, len); } else if (pktin.type == SSH1_MSG_DISCONNECT) { ssh_state = SSH_STATE_CLOSED; logevent("Received disconnect request"); @@ -2176,7 +2180,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) if (!(flags & FLAG_INTERACTIVE)) { char prompt[200]; - sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost); + sprintf(prompt, "%.90s@%.90s's password: ", cfg.username, savedhost); if (!ssh_get_password(prompt, password, sizeof(password))) { /* * get_password failed to get a password (for @@ -2365,7 +2369,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) continue; /* extended but not stderr */ ssh2_pkt_getstring(&data, &length); if (data) { - c_write(data, length); + c_writedata(data, length); /* * Enlarge the window again at the remote side, * just in case it ever runs down and they fail @@ -2592,171 +2596,6 @@ static void ssh_special (Telnet_Special code) { } } - -/* - * Read and decrypt one incoming SSH packet. - * (only used by pSCP) - */ -static void get_packet(void) -{ - unsigned char buf[4096], *p; - long to_read; - int len; - - p = NULL; - len = 0; - - while ((to_read = s_rdpkt(&p, &len)) > 0) { - if (to_read > sizeof(buf)) to_read = sizeof(buf); - len = s_read(buf, to_read); - if (len != to_read) { - closesocket(s); - s = INVALID_SOCKET; - return; - } - p = buf; - } - - assert(len == 0); -} - -/* - * Receive a block of data over the SSH link. Block until - * all data is available. Return nr of bytes read (0 if lost connection). - * (only used by pSCP) - */ -int ssh_scp_recv(unsigned char *buf, int len) -{ - static int pending_input_len = 0; - static unsigned char *pending_input_ptr; - int to_read = len; - - if (pending_input_len >= to_read) { - memcpy(buf, pending_input_ptr, to_read); - pending_input_ptr += to_read; - pending_input_len -= to_read; - return len; - } - - if (pending_input_len > 0) { - memcpy(buf, pending_input_ptr, pending_input_len); - buf += pending_input_len; - to_read -= pending_input_len; - pending_input_len = 0; - } - - if (s == INVALID_SOCKET) - return 0; - while (to_read > 0) { - get_packet(); - if (s == INVALID_SOCKET) - return 0; - if (pktin.type == SSH1_SMSG_STDOUT_DATA) { - int plen = GET_32BIT(pktin.body); - if (plen <= to_read) { - memcpy(buf, pktin.body + 4, plen); - buf += plen; - to_read -= plen; - } else { - memcpy(buf, pktin.body + 4, to_read); - pending_input_len = plen - to_read; - pending_input_ptr = pktin.body + 4 + to_read; - to_read = 0; - } - } else if (pktin.type == SSH1_SMSG_STDERR_DATA) { - int plen = GET_32BIT(pktin.body); - fwrite(pktin.body + 4, plen, 1, stderr); - } else if (pktin.type == SSH1_MSG_DISCONNECT) { - logevent("Received disconnect request"); - } else if (pktin.type == SSH1_SMSG_SUCCESS || - pktin.type == SSH1_SMSG_FAILURE) { - /* ignore */ - } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) { - char logbuf[100]; - sprintf(logbuf, "Remote exit status: %d", GET_32BIT(pktin.body)); - logevent(logbuf); - send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END); - logevent("Closing connection"); - closesocket(s); - s = INVALID_SOCKET; - } else { - bombout(("Strange packet received: type %d", pktin.type)); - return 0; - } - } - - return len; -} - -/* - * Send a block of data over the SSH link. - * Block until all data is sent. - * (only used by pSCP) - */ -void ssh_scp_send(unsigned char *buf, int len) -{ - if (s == INVALID_SOCKET) - return; - send_packet(SSH1_CMSG_STDIN_DATA, - PKT_INT, len, PKT_DATA, buf, len, PKT_END); -} - -/* - * Send an EOF notification to the server. - * (only used by pSCP) - */ -void ssh_scp_send_eof(void) -{ - if (s == INVALID_SOCKET) - return; - send_packet(SSH1_CMSG_EOF, PKT_END); -} - -/* - * Set up the connection, login on the remote host and - * start execution of a command. - * Returns an error message, or NULL on success. - * (only used by pSCP) - */ -char *ssh_scp_init(char *host, int port, char *cmd, char **realhost) -{ - char buf[160], *p; - -#ifdef MSCRYPTOAPI - if (crypto_startup() == 0) - return "Microsoft high encryption pack not installed!"; -#endif - - p = connect_to_host(host, port, realhost); - if (p != NULL) - return p; - - random_init(); - - if (!do_ssh_init()) - return "Protocol initialisation error"; - - /* Exchange keys and login */ - do { - get_packet(); - if (s == INVALID_SOCKET) - return "Connection closed by remote host"; - } while (!do_ssh1_login(NULL, 0, 1)); - - if (ssh_state == SSH_STATE_CLOSED) { - closesocket(s); - s = INVALID_SOCKET; - return "Session initialisation error"; - } - - /* Execute command */ - sprintf(buf, "Sending command: %.100s", cmd); - logevent(buf); - send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END); - - return NULL; -} - static SOCKET ssh_socket(void) { return s; } static int ssh_sendok(void) { return ssh_send_ok; }