X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/7cca0d811c4d1b5bb346cd60fdfa461a558aefec..8ccc75b0d2187cd9e35913749de0ed00e9ef5931:/ssh.c diff --git a/ssh.c b/ssh.c index 7511e085..82d61e98 100644 --- a/ssh.c +++ b/ssh.c @@ -16,7 +16,7 @@ #endif #define logevent(s) { logevent(s); \ - if (IS_SCP && (scp_flags & SCP_VERBOSE) != 0) \ + if (!(flags & FLAG_CONNECTION) && (flags & FLAG_VERBOSE)) \ fprintf(stderr, "%s\n", s); } #define SSH1_MSG_DISCONNECT 1 @@ -160,10 +160,10 @@ static struct ssh_compress *cscomp = NULL; static struct ssh_compress *sccomp = NULL; static struct ssh_kex *kex = NULL; static struct ssh_hostkey *hostkey = NULL; -int scp_flags = 0; int (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL; static char *savedhost; +static int ssh_send_ok; static enum { SSH_STATE_BEFORE_SIZE, @@ -177,11 +177,9 @@ static int size_needed = FALSE; static void s_write (char *buf, int len) { while (len > 0) { int i = send (s, buf, len, 0); - if (IS_SCP) { - noise_ultralight(i); - if (i <= 0) - fatalbox("Lost connection while sending"); - } + noise_ultralight(i); + if (i <= 0) + fatalbox("Lost connection while sending"); if (i > 0) len -= i, buf += i; } @@ -191,8 +189,7 @@ static int s_read (char *buf, int len) { int ret = 0; while (len > 0) { int i = recv (s, buf, len, 0); - if (IS_SCP) - noise_ultralight(i); + noise_ultralight(i); if (i > 0) len -= i, buf += i, ret += i; else @@ -202,10 +199,11 @@ static int s_read (char *buf, int len) { } static void c_write (char *buf, int len) { - if (IS_SCP) { - if (len > 0 && buf[len-1] == '\n') len--; - if (len > 0 && buf[len-1] == '\r') len--; - if (len > 0) { fwrite(buf, len, 1, stderr); fputc('\n', stderr); } + if (!(flags & FLAG_CONNECTION)) { + int i; + for (i = 0; i < len; i++) + if (buf[i] != '\r') + fputc(buf[i], stderr); return; } while (len--) @@ -224,6 +222,7 @@ struct Packet { static struct Packet pktin = { 0, 0, NULL, NULL, 0 }; static struct Packet pktout = { 0, 0, NULL, NULL, 0 }; +static int ssh_version; static void (*ssh_protocol)(unsigned char *in, int inlen, int ispkt); static void ssh1_protocol(unsigned char *in, int inlen, int ispkt); static void ssh2_protocol(unsigned char *in, int inlen, int ispkt); @@ -975,6 +974,7 @@ static int do_ssh_init(void) { logevent("Using SSH protocol version 2"); s_write(vstring, strlen(vstring)); ssh_protocol = ssh2_protocol; + ssh_version = 2; s_rdpkt = ssh2_rdpkt; } else { /* @@ -988,8 +988,10 @@ static int do_ssh_init(void) { logevent("Using SSH protocol version 1"); s_write(vstring, strlen(vstring)); ssh_protocol = ssh1_protocol; + ssh_version = 1; s_rdpkt = ssh1_rdpkt; } + ssh_send_ok = 0; return 1; } @@ -1133,7 +1135,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) static char username[100]; static int pos = 0; static char c; - if (!IS_SCP && !*cfg.username) { + if (!(flags & FLAG_CONNECTION) && !*cfg.username) { c_write("login as: ", 10); while (pos >= 0) { crWaitUntil(!ispkt); @@ -1173,9 +1175,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) char stuff[200]; strncpy(username, cfg.username, 99); username[99] = '\0'; - if (!IS_SCP) { + if (flags & FLAG_VERBOSE) { sprintf(stuff, "Sent username \"%s\".\r\n", username); - c_write(stuff, strlen(stuff)); + c_write(stuff, strlen(stuff)); } } @@ -1204,7 +1206,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (*cfg.keyfile && !tried_publickey) pwpkt_type = SSH1_CMSG_AUTH_RSA; - if (IS_SCP) { + if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD && !FLAG_WINDOWED) { char prompt[200]; sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost); if (!ssh_get_password(prompt, password, sizeof(password))) { @@ -1242,9 +1244,11 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) c_write("password: ", 10); if (pwpkt_type == SSH1_CMSG_AUTH_RSA) { - c_write("Trying public key authentication.\r\n", 35); + if (flags & FLAG_VERBOSE) + c_write("Trying public key authentication.\r\n", 35); if (!rsakey_encrypted(cfg.keyfile)) { - c_write("No passphrase required.\r\n", 25); + if (flags & FLAG_VERBOSE) + c_write("No passphrase required.\r\n", 25); goto tryauth; } c_write("passphrase: ", 12); @@ -1313,7 +1317,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (pktin.type == SSH1_SMSG_FAILURE) { - c_write("Server refused our public key.\r\n", 32); + if (flags & FLAG_VERBOSE) + c_write("Server refused our public key.\r\n", 32); continue; /* go and try password */ } if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) @@ -1337,7 +1342,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (pktin.type == SSH1_SMSG_FAILURE) { - c_write("Failed to authenticate with our public key.\r\n", 45); + if (flags & FLAG_VERBOSE) + c_write("Failed to authenticate with our public key.\r\n", + 45); continue; /* go and try password */ } else if (pktin.type != SSH1_SMSG_SUCCESS) { fatalbox("Bizarre response to RSA authentication response"); @@ -1351,7 +1358,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) memset(password, 0, strlen(password)); crWaitUntil(ispkt); if (pktin.type == SSH1_SMSG_FAILURE) { - c_write("Access denied\r\n", 15); + if (flags & FLAG_VERBOSE) + c_write("Access denied\r\n", 15); logevent("Authentication refused"); } else if (pktin.type == SSH1_MSG_DISCONNECT) { logevent("Received disconnect request"); @@ -1395,13 +1403,17 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) { logevent("Allocated pty"); } - send_packet(SSH1_CMSG_EXEC_SHELL, PKT_END); + if (*cfg.remote_cmd) + send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cfg.remote_cmd, PKT_END); + else + send_packet(SSH1_CMSG_EXEC_SHELL, PKT_END); logevent("Started session"); ssh_state = SSH_STATE_SESSION; if (size_needed) ssh_size(); + ssh_send_ok = 1; while (1) { crReturnV; if (ispkt) { @@ -1741,11 +1753,15 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt) } /* + * SSH2: remote identifier for the main session channel. + */ +static unsigned long ssh_remote_channel; + +/* * Handle the SSH2 userauth and connection layers. */ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) { - static unsigned long their_channel; static unsigned long remote_winsize; static unsigned long remote_maxpkt; @@ -1775,7 +1791,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) static int pos = 0; static char c; - if (!IS_SCP && !*cfg.username) { + if ((flags & FLAG_CONNECTION) && !*cfg.username) { c_write("login as: ", 10); while (pos >= 0) { crWaitUntilV(!ispkt); @@ -1815,13 +1831,13 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) char stuff[200]; strncpy(username, cfg.username, 99); username[99] = '\0'; - if (!IS_SCP) { + if (flags & FLAG_VERBOSE) { sprintf(stuff, "Using username \"%s\".\r\n", username); c_write(stuff, strlen(stuff)); } } - if (IS_SCP) { + if (!(flags & FLAG_WINDOWED)) { char prompt[200]; sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost); if (!ssh_get_password(prompt, password, sizeof(password))) { @@ -1906,7 +1922,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) if (ssh2_pkt_getuint32() != 100) { fatalbox("Server's channel confirmation cited wrong channel"); } - their_channel = ssh2_pkt_getuint32(); + ssh_remote_channel = ssh2_pkt_getuint32(); remote_winsize = ssh2_pkt_getuint32(); remote_maxpkt = ssh2_pkt_getuint32(); logevent("Opened channel for session"); @@ -1915,7 +1931,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) * Now allocate a pty for the session. */ ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); - ssh2_pkt_adduint32(their_channel); /* recipient channel */ + ssh2_pkt_adduint32(ssh_remote_channel); /* recipient channel */ ssh2_pkt_addstring("pty-req"); ssh2_pkt_addbool(1); /* want reply */ ssh2_pkt_addstring(cfg.termtype); @@ -1944,7 +1960,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) * Start a shell. */ ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); - ssh2_pkt_adduint32(their_channel); /* recipient channel */ + ssh2_pkt_adduint32(ssh_remote_channel); /* recipient channel */ ssh2_pkt_addstring("shell"); ssh2_pkt_addbool(1); /* want reply */ ssh2_pkt_send(); @@ -1963,6 +1979,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) /* * Transfer data! */ + ssh_send_ok = 1; while (1) { crReturnV; if (ispkt) { @@ -1991,7 +2008,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) } else { /* FIXME: for now, ignore window size */ ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA); - ssh2_pkt_adduint32(their_channel); + ssh2_pkt_adduint32(ssh_remote_channel); ssh2_pkt_addstring_start(); ssh2_pkt_addstring_data(in, inlen); ssh2_pkt_send(); @@ -2033,7 +2050,7 @@ static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) { if (!do_ssh_init()) return "Protocol initialisation error"; - if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR) + if (hwnd && WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR) switch (WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; default: return "WSAAsyncSelect(): unknown error"; @@ -2117,10 +2134,22 @@ static void ssh_size(void) { } /* - * (Send Telnet special codes) + * Send Telnet special codes. TS_EOF is useful for `plink', so you + * can send an EOF and collect resulting output (e.g. `plink + * hostname sort'). */ static void ssh_special (Telnet_Special code) { - /* do nothing */ + if (code == TS_EOF) { + if (ssh_version = 1) { + send_packet(SSH1_CMSG_EOF, PKT_END); + } else { + ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF); + ssh2_pkt_adduint32(ssh_remote_channel); + ssh2_pkt_send(); + } + } else { + /* do nothing */ + } } @@ -2134,8 +2163,6 @@ static void get_packet(void) long to_read; int len; - assert(IS_SCP); - p = NULL; len = 0; @@ -2164,8 +2191,6 @@ int ssh_scp_recv(unsigned char *buf, int len) static unsigned char *pending_input_ptr; int to_read = len; - assert(IS_SCP); - if (pending_input_len >= to_read) { memcpy(buf, pending_input_ptr, to_read); pending_input_ptr += to_read; @@ -2229,7 +2254,6 @@ int ssh_scp_recv(unsigned char *buf, int len) */ void ssh_scp_send(unsigned char *buf, int len) { - assert(IS_SCP); if (s == INVALID_SOCKET) return; send_packet(SSH1_CMSG_STDIN_DATA, @@ -2242,7 +2266,6 @@ void ssh_scp_send(unsigned char *buf, int len) */ void ssh_scp_send_eof(void) { - assert(IS_SCP); if (s == INVALID_SOCKET) return; send_packet(SSH1_CMSG_EOF, PKT_END); @@ -2258,8 +2281,6 @@ char *ssh_scp_init(char *host, int port, char *cmd, char **realhost) { char buf[160], *p; - assert(IS_SCP); - #ifdef MSCRYPTOAPI if (crypto_startup() == 0) return "Microsoft high encryption pack not installed!"; @@ -2295,11 +2316,16 @@ char *ssh_scp_init(char *host, int port, char *cmd, char **realhost) return NULL; } +static SOCKET ssh_socket(void) { return s; } + +static int ssh_sendok(void) { return ssh_send_ok; } Backend ssh_backend = { ssh_init, ssh_msg, ssh_send, ssh_size, - ssh_special + ssh_special, + ssh_socket, + ssh_sendok };