#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
+#ifndef AUTO_WINSOCK
+#ifdef WINSOCK_TWO
+#include <winsock2.h>
+#else
#include <winsock.h>
+#endif
+#endif
#include "putty.h"
#include "tree234.h"
#include "ssh.h"
-#include "scp.h"
#ifndef FALSE
#define FALSE 0
#endif
#define logevent(s) { logevent(s); \
- if (!(flags & FLAG_CONNECTION) && (flags & FLAG_VERBOSE)) \
+ if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
fprintf(stderr, "%s\n", s); }
+#define bombout(msg) ( ssh_state == SSH_STATE_CLOSED, closesocket(s), \
+ s = INVALID_SOCKET, connection_fatal msg )
+
#define SSH1_MSG_DISCONNECT 1 /* 0x1 */
#define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */
#define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */
#define crWaitUntil(c) do { crReturn(0); } while (!(c))
#define crWaitUntilV(c) do { crReturnV; } while (!(c))
-extern struct ssh_cipher ssh_3des;
-extern struct ssh_cipher ssh_3des_ssh2;
-extern struct ssh_cipher ssh_des;
-extern struct ssh_cipher ssh_blowfish_ssh1;
-extern struct ssh_cipher ssh_blowfish_ssh2;
+extern const struct ssh_cipher ssh_3des;
+extern const struct ssh_cipher ssh_3des_ssh2;
+extern const struct ssh_cipher ssh_des;
+extern const struct ssh_cipher ssh_blowfish_ssh1;
+extern const struct ssh_cipher ssh_blowfish_ssh2;
/*
* Ciphers for SSH2. We miss out single-DES because it isn't
* supported; also 3DES and Blowfish are both done differently from
* SSH1. (3DES uses outer chaining; Blowfish has the opposite
* endianness and different-sized keys.)
- *
- * The first entry in this array is set up to be whatever the user
- * asks for as a cipher. Thereafter there is a fixed preference
- * order of fallback ciphers.
*/
-struct ssh_cipher *ciphers[] = { NULL, &ssh_blowfish_ssh2, &ssh_3des_ssh2 };
-
-extern struct ssh_kex ssh_diffiehellman;
-struct ssh_kex *kex_algs[] = { &ssh_diffiehellman };
+const static struct ssh_cipher *ciphers[] = { &ssh_blowfish_ssh2, &ssh_3des_ssh2 };
-extern struct ssh_hostkey ssh_dss;
-struct ssh_hostkey *hostkey_algs[] = { &ssh_dss };
+extern const struct ssh_kex ssh_diffiehellman;
+const static struct ssh_kex *kex_algs[] = { &ssh_diffiehellman };
-extern struct ssh_mac ssh_sha1;
+extern const struct ssh_hostkey ssh_dss;
+const static struct ssh_hostkey *hostkey_algs[] = { &ssh_dss };
-static SHA_State exhash;
+extern const struct ssh_mac ssh_sha1;
static void nullmac_key(unsigned char *key) { }
static void nullmac_generate(unsigned char *blk, int len, unsigned long seq) { }
static int nullmac_verify(unsigned char *blk, int len, unsigned long seq) { return 1; }
-struct ssh_mac ssh_mac_none = {
+const static struct ssh_mac ssh_mac_none = {
nullmac_key, nullmac_key, nullmac_generate, nullmac_verify, "none", 0
};
-struct ssh_mac *macs[] = { &ssh_sha1, &ssh_mac_none };
+const static struct ssh_mac *macs[] = { &ssh_sha1, &ssh_mac_none };
-struct ssh_compress ssh_comp_none = {
+const static struct ssh_compress ssh_comp_none = {
"none"
};
-struct ssh_compress *compressions[] = { &ssh_comp_none };
-
-static SOCKET s = INVALID_SOCKET;
-
-static unsigned char session_key[32];
-static struct ssh_cipher *cipher = NULL;
-static struct ssh_cipher *cscipher = NULL;
-static struct ssh_cipher *sccipher = NULL;
-static struct ssh_mac *csmac = NULL;
-static struct ssh_mac *scmac = NULL;
-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 (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL;
-
-static char *savedhost;
-static int ssh_send_ok;
+const static struct ssh_compress *compressions[] = { &ssh_comp_none };
/*
* 2-3-4 tree storing channels.
} v2;
} u;
};
+
+struct Packet {
+ long length;
+ int type;
+ unsigned char *data;
+ unsigned char *body;
+ long savedpos;
+ long maxlen;
+};
+
+static SHA_State exhash;
+
+static SOCKET s = INVALID_SOCKET;
+
+static unsigned char session_key[32];
+static const struct ssh_cipher *cipher = NULL;
+static const struct ssh_cipher *cscipher = NULL;
+static const struct ssh_cipher *sccipher = NULL;
+static const struct ssh_mac *csmac = NULL;
+static const struct ssh_mac *scmac = NULL;
+static const struct ssh_compress *cscomp = NULL;
+static const struct ssh_compress *sccomp = NULL;
+static const struct ssh_kex *kex = NULL;
+static const struct ssh_hostkey *hostkey = NULL;
+int (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL;
+
+static char *savedhost;
+static int savedport;
+static int ssh_send_ok;
+
static tree234 *ssh_channels; /* indexed by local id */
+static struct ssh_channel *mainchan; /* primary session channel */
+
+static enum {
+ SSH_STATE_BEFORE_SIZE,
+ SSH_STATE_INTERMED,
+ SSH_STATE_SESSION,
+ SSH_STATE_CLOSED
+} ssh_state = SSH_STATE_BEFORE_SIZE;
+
+static int size_needed = FALSE;
+
+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);
+static void ssh_size(void);
+
+static int (*s_rdpkt)(unsigned char **data, int *datalen);
+
+static struct rdpkt1_state_tag {
+ long len, pad, biglen, to_read;
+ unsigned long realcrc, gotcrc;
+ unsigned char *p;
+ int i;
+ int chunk;
+} rdpkt1_state;
+
+static struct rdpkt2_state_tag {
+ long len, pad, payload, packetlen, maclen;
+ int i;
+ int cipherblk;
+ unsigned long incoming_sequence;
+} rdpkt2_state;
+
static int ssh_channelcmp(void *av, void *bv) {
struct ssh_channel *a = (struct ssh_channel *)av;
struct ssh_channel *b = (struct ssh_channel *)bv;
return 0;
}
-static struct ssh_channel *mainchan; /* primary session channel */
-
-static enum {
- SSH_STATE_BEFORE_SIZE,
- SSH_STATE_INTERMED,
- SSH_STATE_SESSION,
- SSH_STATE_CLOSED
-} ssh_state = SSH_STATE_BEFORE_SIZE;
-
-static int size_needed = FALSE;
-
static void s_write (char *buf, int len) {
while (len > 0) {
int i = send (s, buf, len, 0);
noise_ultralight(i);
- if (i <= 0)
- fatalbox("Lost connection while sending");
+ if (i <= 0) {
+ bombout(("Lost connection while sending"));
+ return;
+ }
if (i > 0)
len -= i, buf += i;
}
}
static void c_write (char *buf, int len) {
- if (!(flags & FLAG_CONNECTION)) {
+ if ((flags & FLAG_STDERR)) {
int i;
for (i = 0; i < len; i++)
if (buf[i] != '\r')
c_write1(*buf++);
}
-struct Packet {
- long length;
- int type;
- unsigned char *data;
- unsigned char *body;
- long savedpos;
- long maxlen;
-};
-
-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);
-static void ssh_size(void);
-
-static int (*s_rdpkt)(unsigned char **data, int *datalen);
+static void c_writedata (char *buf, int len) {
+ while (len--)
+ c_write1(*buf++);
+}
/*
* Collect incoming data in the incoming packet buffer.
*/
static int ssh1_rdpkt(unsigned char **data, int *datalen)
{
- static long len, pad, biglen, to_read;
- static unsigned long realcrc, gotcrc;
- static unsigned char *p;
- static int i;
+ struct rdpkt1_state_tag *st = &rdpkt1_state;
crBegin;
pktin.type = 0;
pktin.length = 0;
- for (i = len = 0; i < 4; i++) {
+ for (st->i = st->len = 0; st->i < 4; st->i++) {
while ((*datalen) == 0)
- crReturn(4-i);
- len = (len << 8) + **data;
+ crReturn(4-st->i);
+ st->len = (st->len << 8) + **data;
(*data)++, (*datalen)--;
}
#ifdef FWHACK
- if (len == 0x52656d6f) { /* "Remo"te server has closed ... */
- len = 0x300; /* big enough to carry to end */
+ if (st->len == 0x52656d6f) { /* "Remo"te server has closed ... */
+ st->len = 0x300; /* big enough to carry to end */
}
#endif
- pad = 8 - (len % 8);
- biglen = len + pad;
- pktin.length = len - 5;
+ st->pad = 8 - (st->len % 8);
+ st->biglen = st->len + st->pad;
+ pktin.length = st->len - 5;
- if (pktin.maxlen < biglen) {
- pktin.maxlen = biglen;
- pktin.data = (pktin.data == NULL ? malloc(biglen+APIEXTRA) :
- realloc(pktin.data, biglen+APIEXTRA));
+ if (pktin.maxlen < st->biglen) {
+ pktin.maxlen = st->biglen;
+ pktin.data = (pktin.data == NULL ? malloc(st->biglen+APIEXTRA) :
+ realloc(pktin.data, st->biglen+APIEXTRA));
if (!pktin.data)
fatalbox("Out of memory");
}
- to_read = biglen;
- p = pktin.data;
- while (to_read > 0) {
- static int chunk;
- chunk = to_read;
+ st->to_read = st->biglen;
+ st->p = pktin.data;
+ while (st->to_read > 0) {
+ st->chunk = st->to_read;
while ((*datalen) == 0)
- crReturn(to_read);
- if (chunk > (*datalen))
- chunk = (*datalen);
- memcpy(p, *data, chunk);
- *data += chunk;
- *datalen -= chunk;
- p += chunk;
- to_read -= chunk;
+ crReturn(st->to_read);
+ if (st->chunk > (*datalen))
+ st->chunk = (*datalen);
+ memcpy(st->p, *data, st->chunk);
+ *data += st->chunk;
+ *datalen -= st->chunk;
+ st->p += st->chunk;
+ st->to_read -= st->chunk;
}
if (cipher)
- cipher->decrypt(pktin.data, biglen);
+ cipher->decrypt(pktin.data, st->biglen);
- pktin.type = pktin.data[pad];
- pktin.body = pktin.data + pad + 1;
+ pktin.type = pktin.data[st->pad];
+ pktin.body = pktin.data + st->pad + 1;
- realcrc = crc32(pktin.data, biglen-4);
- gotcrc = GET_32BIT(pktin.data+biglen-4);
- if (gotcrc != realcrc) {
- fatalbox("Incorrect CRC received on packet");
+ st->realcrc = crc32(pktin.data, st->biglen-4);
+ st->gotcrc = GET_32BIT(pktin.data+st->biglen-4);
+ if (st->gotcrc != st->realcrc) {
+ bombout(("Incorrect CRC received on packet"));
+ crReturn(0);
}
if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
pktin.type == SSH1_SMSG_AUTH_TIS_CHALLENGE ||
pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
long strlen = GET_32BIT(pktin.body);
- if (strlen + 4 != pktin.length)
- fatalbox("Received data packet with bogus string length");
+ if (strlen + 4 != pktin.length) {
+ bombout(("Received data packet with bogus string length"));
+ crReturn(0);
+ }
}
if (pktin.type == SSH1_MSG_DEBUG) {
static int ssh2_rdpkt(unsigned char **data, int *datalen)
{
- static long len, pad, payload, packetlen, maclen;
- static int i;
- static int cipherblk;
- static unsigned long incoming_sequence = 0;
+ struct rdpkt2_state_tag *st = &rdpkt2_state;
crBegin;
next_packet:
-
pktin.type = 0;
pktin.length = 0;
-
- if (cipher)
- cipherblk = cipher->blksize;
+ if (sccipher)
+ st->cipherblk = sccipher->blksize;
else
- cipherblk = 8;
- if (cipherblk < 8)
- cipherblk = 8;
-
- if (pktin.maxlen < cipherblk) {
- pktin.maxlen = cipherblk;
- pktin.data = (pktin.data == NULL ? malloc(cipherblk+APIEXTRA) :
- realloc(pktin.data, cipherblk+APIEXTRA));
+ st->cipherblk = 8;
+ if (st->cipherblk < 8)
+ st->cipherblk = 8;
+
+ if (pktin.maxlen < st->cipherblk) {
+ pktin.maxlen = st->cipherblk;
+ pktin.data = (pktin.data == NULL ? malloc(st->cipherblk+APIEXTRA) :
+ realloc(pktin.data, st->cipherblk+APIEXTRA));
if (!pktin.data)
fatalbox("Out of memory");
}
* Acquire and decrypt the first block of the packet. This will
* contain the length and padding details.
*/
- for (i = len = 0; i < cipherblk; i++) {
+ for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
while ((*datalen) == 0)
- crReturn(cipherblk-i);
- pktin.data[i] = *(*data)++;
+ crReturn(st->cipherblk-st->i);
+ pktin.data[st->i] = *(*data)++;
(*datalen)--;
}
#ifdef FWHACK
}
#endif
if (sccipher)
- sccipher->decrypt(pktin.data, cipherblk);
+ sccipher->decrypt(pktin.data, st->cipherblk);
/*
* Now get the length and padding figures.
*/
- len = GET_32BIT(pktin.data);
- pad = pktin.data[4];
+ st->len = GET_32BIT(pktin.data);
+ st->pad = pktin.data[4];
/*
* This enables us to deduce the payload length.
*/
- payload = len - pad - 1;
+ st->payload = st->len - st->pad - 1;
- pktin.length = payload + 5;
+ pktin.length = st->payload + 5;
/*
* So now we can work out the total packet length.
*/
- packetlen = len + 4;
- maclen = scmac ? scmac->len : 0;
+ st->packetlen = st->len + 4;
+ st->maclen = scmac ? scmac->len : 0;
/*
* Adjust memory allocation if packet is too big.
*/
- if (pktin.maxlen < packetlen+maclen) {
- pktin.maxlen = packetlen+maclen;
+ if (pktin.maxlen < st->packetlen+st->maclen) {
+ pktin.maxlen = st->packetlen+st->maclen;
pktin.data = (pktin.data == NULL ? malloc(pktin.maxlen+APIEXTRA) :
realloc(pktin.data, pktin.maxlen+APIEXTRA));
if (!pktin.data)
/*
* Read and decrypt the remainder of the packet.
*/
- for (i = cipherblk; i < packetlen + maclen; i++) {
+ for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen; st->i++) {
while ((*datalen) == 0)
- crReturn(packetlen + maclen - i);
- pktin.data[i] = *(*data)++;
+ crReturn(st->packetlen + st->maclen - st->i);
+ pktin.data[st->i] = *(*data)++;
(*datalen)--;
}
/* Decrypt everything _except_ the MAC. */
if (sccipher)
- sccipher->decrypt(pktin.data + cipherblk, packetlen - cipherblk);
+ sccipher->decrypt(pktin.data + st->cipherblk,
+ st->packetlen - st->cipherblk);
#if 0
- debug(("Got packet len=%d pad=%d\r\n", len, pad));
- for (i = 0; i < packetlen; i++)
- debug((" %02x", (unsigned char)pktin.data[i]));
+ debug(("Got packet len=%d pad=%d\r\n", st->len, st->pad));
+ for (st->i = 0; st->i < st->packetlen; st->i++)
+ debug((" %02x", (unsigned char)pktin.data[st->i]));
debug(("\r\n"));
#endif
/*
* Check the MAC.
*/
- if (scmac && !scmac->verify(pktin.data, len+4, incoming_sequence))
- fatalbox("Incorrect MAC received on packet");
- incoming_sequence++; /* whether or not we MACed */
+ if (scmac && !scmac->verify(pktin.data, st->len+4, st->incoming_sequence)) {
+ bombout(("Incorrect MAC received on packet"));
+ crReturn(0);
+ }
+ st->incoming_sequence++; /* whether or not we MACed */
pktin.savedpos = 6;
pktin.type = pktin.data[5];
if (port < 0)
port = 22; /* default ssh port */
+ savedport = port;
#ifdef FWHACK
FWhost = host;
* state.
*/
#include <stdio.h>
-void sha_string(SHA_State *s, void *str, int len) {
+static void sha_string(SHA_State *s, void *str, int len) {
unsigned char lenblk[4];
PUT_32BIT(lenblk, len);
SHA_Bytes(s, lenblk, 4);
/*
* SSH2 packet construction functions.
*/
-void ssh2_pkt_adddata(void *data, int len) {
+static void ssh2_pkt_adddata(void *data, int len) {
pktout.length += len;
if (pktout.maxlen < pktout.length) {
pktout.maxlen = pktout.length + 256;
}
memcpy(pktout.data+pktout.length-len, data, len);
}
-void ssh2_pkt_addbyte(unsigned char byte) {
+static void ssh2_pkt_addbyte(unsigned char byte) {
ssh2_pkt_adddata(&byte, 1);
}
-void ssh2_pkt_init(int pkt_type) {
+static void ssh2_pkt_init(int pkt_type) {
pktout.length = 5;
ssh2_pkt_addbyte((unsigned char)pkt_type);
}
-void ssh2_pkt_addbool(unsigned char value) {
+static void ssh2_pkt_addbool(unsigned char value) {
ssh2_pkt_adddata(&value, 1);
}
-void ssh2_pkt_adduint32(unsigned long value) {
+static void ssh2_pkt_adduint32(unsigned long value) {
unsigned char x[4];
PUT_32BIT(x, value);
ssh2_pkt_adddata(x, 4);
}
-void ssh2_pkt_addstring_start(void) {
+static void ssh2_pkt_addstring_start(void) {
ssh2_pkt_adduint32(0);
pktout.savedpos = pktout.length;
}
-void ssh2_pkt_addstring_str(char *data) {
+static void ssh2_pkt_addstring_str(char *data) {
ssh2_pkt_adddata(data, strlen(data));
PUT_32BIT(pktout.data + pktout.savedpos - 4,
pktout.length - pktout.savedpos);
}
-void ssh2_pkt_addstring_data(char *data, int len) {
+static void ssh2_pkt_addstring_data(char *data, int len) {
ssh2_pkt_adddata(data, len);
PUT_32BIT(pktout.data + pktout.savedpos - 4,
pktout.length - pktout.savedpos);
}
-void ssh2_pkt_addstring(char *data) {
+static void ssh2_pkt_addstring(char *data) {
ssh2_pkt_addstring_start();
ssh2_pkt_addstring_str(data);
}
-char *ssh2_mpint_fmt(Bignum b, int *len) {
+static char *ssh2_mpint_fmt(Bignum b, int *len) {
unsigned char *p;
int i, n = b[0];
p = malloc(n * 2 + 1);
*len = n*2+1-i;
return p;
}
-void ssh2_pkt_addmp(Bignum b) {
+static void ssh2_pkt_addmp(Bignum b) {
unsigned char *p;
int len;
p = ssh2_mpint_fmt(b, &len);
ssh2_pkt_addstring_data(p, len);
free(p);
}
-void ssh2_pkt_send(void) {
+static void ssh2_pkt_send(void) {
int cipherblk, maclen, padding, i;
static unsigned long outgoing_sequence = 0;
}
#endif
-void sha_mpint(SHA_State *s, Bignum b) {
+static void sha_mpint(SHA_State *s, Bignum b) {
unsigned char *p;
int len;
p = ssh2_mpint_fmt(b, &len);
/*
* SSH2 packet decode functions.
*/
-unsigned long ssh2_pkt_getuint32(void) {
+static unsigned long ssh2_pkt_getuint32(void) {
unsigned long value;
if (pktin.length - pktin.savedpos < 4)
return 0; /* arrgh, no way to decline (FIXME?) */
pktin.savedpos += 4;
return value;
}
-void ssh2_pkt_getstring(char **p, int *length) {
+static void ssh2_pkt_getstring(char **p, int *length) {
*p = NULL;
if (pktin.length - pktin.savedpos < 4)
return;
*p = pktin.data+pktin.savedpos;
pktin.savedpos += *length;
}
-Bignum ssh2_pkt_getmp(void) {
+static Bignum ssh2_pkt_getmp(void) {
char *p;
int i, j, length;
Bignum b;
ssh2_pkt_getstring(&p, &length);
if (!p)
return NULL;
- if (p[0] & 0x80)
- fatalbox("internal error: Can't handle negative mpints");
+ if (p[0] & 0x80) {
+ bombout(("internal error: Can't handle negative mpints"));
+ return NULL;
+ }
b = newbn((length+1)/2);
for (i = 0; i < length; i++) {
j = length - 1 - i;
break;
}
+ rdpkt2_state.incoming_sequence = 0;
+
*vsp = 0;
sprintf(vlog, "Server version: %s", vstring);
vlog[strcspn(vlog, "\r\n")] = '\0';
static int tried_publickey;
static unsigned char session_id[16];
int cipher_type;
+ static char username[100];
crBegin;
if (!ispkt) crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_PUBLIC_KEY)
- fatalbox("Public key packet not received");
+ if (pktin.type != SSH1_SMSG_PUBLIC_KEY) {
+ bombout(("Public key packet not received"));
+ crReturn(0);
+ }
logevent("Received public keys");
j = makekey(pktin.body+8+i, &hostkey, &keystr2, 0);
/*
- * Hash the host key and print the hash in the log box. Just as
- * a last resort in case the registry's host key checking is
- * compromised, we'll allow the user some ability to verify
- * host keys by eye.
+ * Log the host key fingerprint.
*/
- MD5Init(&md5c);
- MD5Update(&md5c, keystr2, hostkey.bytes);
- MD5Final(session_id, &md5c);
{
char logmsg[80];
- int i;
- logevent("Host key MD5 is:");
+ logevent("Host key fingerprint is:");
strcpy(logmsg, " ");
- for (i = 0; i < 16; i++)
- sprintf(logmsg+strlen(logmsg), "%02x", session_id[i]);
+ hostkey.comment = NULL;
+ rsa_fingerprint(logmsg+strlen(logmsg), sizeof(logmsg)-strlen(logmsg),
+ &hostkey);
logevent(logmsg);
}
* First format the key into a string.
*/
int len = rsastr_len(&hostkey);
+ char fingerprint[100];
char *keystr = malloc(len);
if (!keystr)
fatalbox("Out of memory");
rsastr_fmt(keystr, &hostkey);
- verify_ssh_host_key(savedhost, keystr);
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
+ verify_ssh_host_key(savedhost, savedport, "rsa", keystr, fingerprint);
free(keystr);
}
crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_SUCCESS)
- fatalbox("Encryption not successfully enabled");
+ if (pktin.type != SSH1_SMSG_SUCCESS) {
+ bombout(("Encryption not successfully enabled"));
+ crReturn(0);
+ }
logevent("Successfully started encryption");
fflush(stdout);
{
- static char username[100];
static int pos = 0;
static char c;
- if ((flags & FLAG_CONNECTION) && !*cfg.username) {
+ if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
c_write("login as: ", 10);
+ ssh_send_ok = 1;
while (pos >= 0) {
crWaitUntil(!ispkt);
while (inlen--) switch (c = *in++) {
char stuff[200];
strncpy(username, cfg.username, 99);
username[99] = '\0';
- if (flags & FLAG_VERBOSE) {
+ if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
sprintf(stuff, "Sent username \"%s\".\r\n", username);
c_write(stuff, strlen(stuff));
}
while (pktin.type == SSH1_SMSG_FAILURE) {
static char password[100];
+ static char prompt[200];
static int pos;
static char c;
static int pwpkt_type;
crWaitUntil(ispkt);
if (pktin.type == SSH1_SMSG_SUCCESS) {
logevent("Pageant's response accepted");
- c_write("Authenticated using RSA key \"",
- 29);
- c_write(commentp, commentlen);
- c_write("\" from agent\r\n", 14);
+ if (flags & FLAG_VERBOSE) {
+ c_write("Authenticated using RSA key \"",
+ 29);
+ c_write(commentp, commentlen);
+ c_write("\" from agent\r\n", 14);
+ }
authed = TRUE;
} else
logevent("Pageant's response not accepted");
if (*cfg.keyfile && !tried_publickey)
pwpkt_type = SSH1_CMSG_AUTH_RSA;
- if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD && !FLAG_WINDOWED) {
- char prompt[200];
- sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
+ if (pktin.type == SSH1_SMSG_FAILURE &&
+ cfg.try_tis_auth &&
+ (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
+ pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
+ logevent("Requested TIS authentication");
+ send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
+ logevent("TIS authentication declined");
+ if (flags & FLAG_INTERACTIVE)
+ c_write("TIS authentication refused.\r\n", 29);
+ } else {
+ int challengelen = ((pktin.body[0] << 24) |
+ (pktin.body[1] << 16) |
+ (pktin.body[2] << 8) |
+ (pktin.body[3]));
+ logevent("Received TIS challenge");
+ if (challengelen > sizeof(prompt)-1)
+ challengelen = sizeof(prompt)-1; /* prevent overrun */
+ memcpy(prompt, pktin.body+4, challengelen);
+ prompt[challengelen] = '\0';
+ }
+ }
+ if (pktin.type == SSH1_SMSG_FAILURE &&
+ cfg.try_tis_auth &&
+ (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
+ pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
+ logevent("Requested CryptoCard authentication");
+ send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
+ crWaitUntil(ispkt);
+ if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
+ logevent("CryptoCard authentication declined");
+ c_write("CryptoCard authentication refused.\r\n", 29);
+ } else {
+ int challengelen = ((pktin.body[0] << 24) |
+ (pktin.body[1] << 16) |
+ (pktin.body[2] << 8) |
+ (pktin.body[3]));
+ logevent("Received CryptoCard challenge");
+ if (challengelen > sizeof(prompt)-1)
+ challengelen = sizeof(prompt)-1; /* prevent overrun */
+ memcpy(prompt, pktin.body+4, challengelen);
+ strncpy(prompt + challengelen, "\r\nResponse : ",
+ sizeof(prompt)-challengelen);
+ prompt[sizeof(prompt)-1] = '\0';
+ }
+ }
+ if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
+ sprintf(prompt, "%.90s@%.90s's password: ",
+ username, savedhost);
+ }
+ if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
+ char *comment = NULL;
+ if (flags & FLAG_VERBOSE)
+ c_write("Trying public key authentication.\r\n", 35);
+ if (!rsakey_encrypted(cfg.keyfile, &comment)) {
+ if (flags & FLAG_VERBOSE)
+ c_write("No passphrase required.\r\n", 25);
+ goto tryauth;
+ }
+ sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
+ free(comment);
+ }
+
+ if (ssh_get_password) {
if (!ssh_get_password(prompt, password, sizeof(password))) {
/*
* get_password failed to get a password (for
crReturn(1);
}
} else {
-
- if (pktin.type == SSH1_SMSG_FAILURE &&
- cfg.try_tis_auth &&
- (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
- pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
- logevent("Requested TIS authentication");
- send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
- crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
- logevent("TIS authentication declined");
- c_write("TIS authentication refused.\r\n", 29);
- } else {
- int challengelen = ((pktin.body[0] << 24) |
- (pktin.body[1] << 16) |
- (pktin.body[2] << 8) |
- (pktin.body[3]));
- logevent("Received TIS challenge");
- c_write(pktin.body+4, challengelen);
- }
- }
- if (pktin.type == SSH1_SMSG_FAILURE &&
- cfg.try_tis_auth &&
- (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
- pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
- logevent("Requested CryptoCard authentication");
- send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
- crWaitUntil(ispkt);
- if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
- logevent("CryptoCard authentication declined");
- c_write("CryptoCard authentication refused.\r\n", 29);
- } else {
- int challengelen = ((pktin.body[0] << 24) |
- (pktin.body[1] << 16) |
- (pktin.body[2] << 8) |
- (pktin.body[3]));
- logevent("Received CryptoCard challenge");
- c_write(pktin.body+4, challengelen);
- c_write("\r\nResponse : ", 13);
- }
- }
- if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD)
- c_write("password: ", 10);
- if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
- if (flags & FLAG_VERBOSE)
- c_write("Trying public key authentication.\r\n", 35);
- if (!rsakey_encrypted(cfg.keyfile)) {
- if (flags & FLAG_VERBOSE)
- c_write("No passphrase required.\r\n", 25);
- goto tryauth;
- }
- c_write("passphrase: ", 12);
- }
-
+ c_write(prompt, strlen(prompt));
pos = 0;
+ ssh_send_ok = 1;
while (pos >= 0) {
crWaitUntil(!ispkt);
while (inlen--) switch (c = *in++) {
}
}
c_write("\r\n", 2);
-
- }
+ }
tryauth:
if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
crWaitUntil(ispkt);
if (pktin.type == SSH1_SMSG_FAILURE) {
- if (flags & FLAG_VERBOSE)
- c_write("Server refused our public key.\r\n", 32);
+ c_write("Server refused our public key.\r\n", 32);
continue; /* go and try password */
}
- if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE)
- fatalbox("Bizarre response to offer of public key");
+ if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+ bombout(("Bizarre response to offer of public key"));
+ crReturn(0);
+ }
ssh1_read_bignum(pktin.body, &challenge);
response = rsadecrypt(challenge, &pubkey);
freebn(pubkey.private_exponent); /* burn the evidence */
45);
continue; /* go and try password */
} else if (pktin.type != SSH1_SMSG_SUCCESS) {
- fatalbox("Bizarre response to RSA authentication response");
+ bombout(("Bizarre response to RSA authentication response"));
+ crReturn(0);
}
break; /* we're through! */
ssh_state = SSH_STATE_CLOSED;
crReturn(1);
} else if (pktin.type != SSH1_SMSG_SUCCESS) {
- fatalbox("Strange packet received, type %d", pktin.type);
+ bombout(("Strange packet received, type %d", pktin.type));
+ crReturn(0);
}
}
send_packet(SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);
do { crReturnV; } while (!ispkt);
if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
- fatalbox("Protocol confusion");
+ bombout(("Protocol confusion"));
+ crReturnV;
} else if (pktin.type == SSH1_SMSG_FAILURE) {
logevent("Agent forwarding refused");
} else
ssh_state = SSH_STATE_INTERMED;
do { crReturnV; } while (!ispkt);
if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
- fatalbox("Protocol confusion");
+ bombout(("Protocol confusion"));
+ crReturnV;
} else if (pktin.type == SSH1_SMSG_FAILURE) {
c_write("Server refused to allocate pty\r\n", 32);
}
ssh_send_ok = 1;
ssh_channels = newtree234(ssh_channelcmp);
+ begin_session();
while (1) {
crReturnV;
if (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");
c->localid = i;
c->closes = 0;
c->type = SSH1_SMSG_AGENT_OPEN; /* identify channel type */
+ c->u.a.lensofar = 0;
add234(ssh_channels, c);
send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
PKT_INT, c->remoteid, PKT_INT, c->localid,
} else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
} else {
- fatalbox("Strange packet received: type %d", pktin.type);
+ bombout(("Strange packet received: type %d", pktin.type));
+ crReturnV;
}
} else {
send_packet(SSH1_CMSG_STDIN_DATA,
/*
* Utility routine for decoding comma-separated strings in KEXINIT.
*/
-int in_commasep_string(char *needle, char *haystack, int haylen) {
+static int in_commasep_string(char *needle, char *haystack, int haylen) {
int needlen = strlen(needle);
while (1) {
/*
/*
* SSH2 key creation method.
*/
-void ssh2_mkkey(Bignum K, char *H, char chr, char *keyspace) {
+static void ssh2_mkkey(Bignum K, char *H, char chr, char *keyspace) {
SHA_State s;
/* First 20 bytes. */
SHA_Init(&s);
static int i, len;
static char *str;
static Bignum e, f, K;
- static struct ssh_cipher *cscipher_tobe = NULL;
- static struct ssh_cipher *sccipher_tobe = NULL;
- static struct ssh_mac *csmac_tobe = NULL;
- static struct ssh_mac *scmac_tobe = NULL;
- static struct ssh_compress *cscomp_tobe = NULL;
- static struct ssh_compress *sccomp_tobe = NULL;
- static char *hostkeydata, *sigdata, *keystr;
+ static const struct ssh_cipher *cscipher_tobe = NULL;
+ static const struct ssh_cipher *sccipher_tobe = NULL;
+ static const struct ssh_mac *csmac_tobe = NULL;
+ static const struct ssh_mac *scmac_tobe = NULL;
+ static const struct ssh_compress *cscomp_tobe = NULL;
+ static const struct ssh_compress *sccomp_tobe = NULL;
+ static char *hostkeydata, *sigdata, *keystr, *fingerprint;
static int hostkeylen, siglen;
static unsigned char exchange_hash[20];
static unsigned char keyspace[40];
+ static const struct ssh_cipher *preferred_cipher;
crBegin;
random_init();
* Set up the preferred cipher.
*/
if (cfg.cipher == CIPHER_BLOWFISH) {
- ciphers[0] = &ssh_blowfish_ssh2;
+ preferred_cipher = &ssh_blowfish_ssh2;
} else if (cfg.cipher == CIPHER_DES) {
logevent("Single DES not supported in SSH2; using 3DES");
- ciphers[0] = &ssh_3des_ssh2;
+ preferred_cipher = &ssh_3des_ssh2;
} else if (cfg.cipher == CIPHER_3DES) {
- ciphers[0] = &ssh_3des_ssh2;
+ preferred_cipher = &ssh_3des_ssh2;
} else {
/* Shouldn't happen, but we do want to initialise to _something_. */
- ciphers[0] = &ssh_3des_ssh2;
+ preferred_cipher = &ssh_3des_ssh2;
}
begin_key_exchange:
}
/* List client->server encryption algorithms. */
ssh2_pkt_addstring_start();
- for (i = 0; i < lenof(ciphers); i++) {
- ssh2_pkt_addstring_str(ciphers[i]->name);
- if (i < lenof(ciphers)-1)
+ for (i = 0; i < lenof(ciphers)+1; i++) {
+ const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1];
+ ssh2_pkt_addstring_str(c->name);
+ if (i < lenof(ciphers))
ssh2_pkt_addstring_str(",");
}
/* List server->client encryption algorithms. */
ssh2_pkt_addstring_start();
- for (i = 0; i < lenof(ciphers); i++) {
- ssh2_pkt_addstring_str(ciphers[i]->name);
- if (i < lenof(ciphers)-1)
+ for (i = 0; i < lenof(ciphers)+1; i++) {
+ const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1];
+ ssh2_pkt_addstring_str(c->name);
+ if (i < lenof(ciphers))
ssh2_pkt_addstring_str(",");
}
/* List client->server MAC algorithms. */
* to.
*/
if (pktin.type != SSH2_MSG_KEXINIT) {
- fatalbox("expected key exchange packet from server");
+ bombout(("expected key exchange packet from server"));
+ crReturn(0);
}
kex = NULL; hostkey = NULL; cscipher_tobe = NULL; sccipher_tobe = NULL;
csmac_tobe = NULL; scmac_tobe = NULL; cscomp_tobe = NULL; sccomp_tobe = NULL;
}
}
ssh2_pkt_getstring(&str, &len); /* client->server cipher */
- for (i = 0; i < lenof(ciphers); i++) {
- if (in_commasep_string(ciphers[i]->name, str, len)) {
- cscipher_tobe = ciphers[i];
+ for (i = 0; i < lenof(ciphers)+1; i++) {
+ const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1];
+ if (in_commasep_string(c->name, str, len)) {
+ cscipher_tobe = c;
break;
}
}
ssh2_pkt_getstring(&str, &len); /* server->client cipher */
- for (i = 0; i < lenof(ciphers); i++) {
- if (in_commasep_string(ciphers[i]->name, str, len)) {
- sccipher_tobe = ciphers[i];
+ for (i = 0; i < lenof(ciphers)+1; i++) {
+ const struct ssh_cipher *c = i==0 ? preferred_cipher : ciphers[i-1];
+ if (in_commasep_string(c->name, str, len)) {
+ sccipher_tobe = c;
break;
}
}
* Currently we only support Diffie-Hellman and DSS, so let's
* bomb out if those aren't selected.
*/
- if (kex != &ssh_diffiehellman || hostkey != &ssh_dss)
- fatalbox("internal fault: chaos in SSH 2 transport layer");
+ if (kex != &ssh_diffiehellman || hostkey != &ssh_dss) {
+ bombout(("internal fault: chaos in SSH 2 transport layer"));
+ crReturn(0);
+ }
/*
* Now we begin the fun. Generate and send e for Diffie-Hellman.
crWaitUntil(ispkt);
if (pktin.type != SSH2_MSG_KEXDH_REPLY) {
- fatalbox("expected key exchange packet from server");
+ bombout(("expected key exchange packet from server"));
+ crReturn(0);
}
ssh2_pkt_getstring(&hostkeydata, &hostkeylen);
f = ssh2_pkt_getmp();
#endif
hostkey->setkey(hostkeydata, hostkeylen);
- if (!hostkey->verifysig(sigdata, siglen, exchange_hash, 20))
- fatalbox("Server failed host key check");
+ if (!hostkey->verifysig(sigdata, siglen, exchange_hash, 20)) {
+ bombout(("Server failed host key check"));
+ crReturn(0);
+ }
/*
* Expect SSH2_MSG_NEWKEYS from server.
*/
crWaitUntil(ispkt);
- if (pktin.type != SSH2_MSG_NEWKEYS)
- fatalbox("expected new-keys packet from server");
+ if (pktin.type != SSH2_MSG_NEWKEYS) {
+ bombout(("expected new-keys packet from server"));
+ crReturn(0);
+ }
/*
* Authenticate remote host: verify host key. (We've already
* checked the signature of the exchange hash.)
*/
keystr = hostkey->fmtkey();
- verify_ssh_host_key(savedhost, keystr);
+ fingerprint = hostkey->fingerprint();
+ verify_ssh_host_key(savedhost, savedport, hostkey->keytype,
+ keystr, fingerprint);
+ logevent("Host key fingerprint is:");
+ logevent(fingerprint);
+ free(fingerprint);
free(keystr);
/*
ssh2_pkt_addstring("ssh-userauth");
ssh2_pkt_send();
crWaitUntilV(ispkt);
- if (pktin.type != SSH2_MSG_SERVICE_ACCEPT)
- fatalbox("Server refused user authentication protocol");
+ if (pktin.type != SSH2_MSG_SERVICE_ACCEPT) {
+ bombout(("Server refused user authentication protocol"));
+ crReturnV;
+ }
/*
* FIXME: currently we support only password authentication.
static int pos = 0;
static char c;
- if ((flags & FLAG_CONNECTION) && !*cfg.username) {
+ if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
c_write("login as: ", 10);
+ ssh_send_ok = 1;
while (pos >= 0) {
crWaitUntilV(!ispkt);
while (inlen--) switch (c = *in++) {
char stuff[200];
strncpy(username, cfg.username, 99);
username[99] = '\0';
- if (flags & FLAG_VERBOSE) {
+ if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
sprintf(stuff, "Using username \"%s\".\r\n", username);
c_write(stuff, strlen(stuff));
}
}
- if (!(flags & FLAG_WINDOWED)) {
+ if (ssh_get_password) {
char prompt[200];
- sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
+ sprintf(prompt, "%.90s@%.90s's password: ", username, savedhost);
if (!ssh_get_password(prompt, password, sizeof(password))) {
/*
* get_password failed to get a password (for
}
} else {
c_write("password: ", 10);
+ ssh_send_ok = 1;
pos = 0;
while (pos >= 0) {
ssh2_pkt_send();
crWaitUntilV(ispkt);
if (pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
- fatalbox("Server refused to open a session");
+ bombout(("Server refused to open a session"));
+ crReturnV;
/* FIXME: error data comes back in FAILURE packet */
}
if (ssh2_pkt_getuint32() != mainchan->localid) {
- fatalbox("Server's channel confirmation cited wrong channel");
+ bombout(("Server's channel confirmation cited wrong channel"));
+ crReturnV;
}
mainchan->remoteid = ssh2_pkt_getuint32();
mainchan->u.v2.remwindow = ssh2_pkt_getuint32();
/*
* Now allocate a pty for the session.
*/
- ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
- ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
- ssh2_pkt_addstring("pty-req");
- ssh2_pkt_addbool(1); /* want reply */
- ssh2_pkt_addstring(cfg.termtype);
- ssh2_pkt_adduint32(cols);
- ssh2_pkt_adduint32(rows);
- ssh2_pkt_adduint32(0); /* pixel width */
- ssh2_pkt_adduint32(0); /* pixel height */
- ssh2_pkt_addstring_start();
- ssh2_pkt_addstring_data("\0", 1); /* TTY_OP_END, no special options */
- ssh2_pkt_send();
+ if (!cfg.nopty) {
+ ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+ ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
+ ssh2_pkt_addstring("pty-req");
+ ssh2_pkt_addbool(1); /* want reply */
+ ssh2_pkt_addstring(cfg.termtype);
+ ssh2_pkt_adduint32(cols);
+ ssh2_pkt_adduint32(rows);
+ ssh2_pkt_adduint32(0); /* pixel width */
+ ssh2_pkt_adduint32(0); /* pixel height */
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_addstring_data("\0", 1);/* TTY_OP_END, no special options */
+ ssh2_pkt_send();
- do { /* FIXME: pay attention to these */
- crWaitUntilV(ispkt);
- } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ do {
+ crWaitUntilV(ispkt);
+ if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+ /* FIXME: be able to handle other channels here */
+ if (ssh2_pkt_getuint32() != mainchan->localid)
+ continue; /* wrong channel */
+ mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
+ }
+ } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
- if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
- if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- fatalbox("Server got confused by pty request");
+ if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
+ if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
+ bombout(("Server got confused by pty request"));
+ crReturnV;
+ }
+ c_write("Server refused to allocate pty\r\n", 32);
+ } else {
+ logevent("Allocated pty");
}
- c_write("Server refused to allocate pty\r\n", 32);
- } else {
- logevent("Allocated pty");
}
/*
- * Start a shell.
+ * Start a shell or a remote command.
*/
ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
- ssh2_pkt_addstring("shell");
- ssh2_pkt_addbool(1); /* want reply */
+ if (*cfg.remote_cmd) {
+ ssh2_pkt_addstring("exec");
+ ssh2_pkt_addbool(1); /* want reply */
+ ssh2_pkt_addstring(cfg.remote_cmd);
+ } else {
+ ssh2_pkt_addstring("shell");
+ ssh2_pkt_addbool(1); /* want reply */
+ }
ssh2_pkt_send();
do {
crWaitUntilV(ispkt);
} while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
- fatalbox("Server got confused by shell request");
+ bombout(("Server got confused by shell/command request"));
+ crReturnV;
}
- fatalbox("Server refused to start a shell");
+ bombout(("Server refused to start a shell/command"));
+ crReturnV;
} else {
- logevent("Started a shell");
+ logevent("Started a shell/command");
}
/*
* Transfer data!
*/
ssh_send_ok = 1;
+ begin_session();
while (1) {
static int try_send;
crReturnV;
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
mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
try_send = TRUE;
} else {
- fatalbox("Strange packet received: type %d", pktin.type);
+ bombout(("Strange packet received: type %d", pktin.type));
+ crReturnV;
}
} else {
/*
if (s == INVALID_SOCKET)
return 1;
- if (WSAGETSELECTERROR(lParam) != 0)
+ if (WSAGETSELECTERROR(lParam) != 0) {
+ closesocket(s);
+ s = INVALID_SOCKET;
return -WSAGETSELECTERROR(lParam);
+ }
switch (WSAGETSELECTEVENT(lParam)) {
case FD_READ:
ret = recv(s, buf, sizeof(buf), 0);
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
return 1;
- if (ret < 0) /* any _other_ error */
+ if (ret < 0) { /* any _other_ error */
+ closesocket(s);
+ s = INVALID_SOCKET;
return -10000-WSAGetLastError();
+ }
if (ret == 0) {
s = INVALID_SOCKET;
return 0;
*/
static void ssh_special (Telnet_Special code) {
if (code == TS_EOF) {
- if (ssh_version = 1) {
+ if (ssh_version == 1) {
send_packet(SSH1_CMSG_EOF, PKT_END);
} else {
ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);
ssh2_pkt_adduint32(mainchan->remoteid);
ssh2_pkt_send();
}
+ logevent("Sent EOF message");
+ } else if (code == TS_PING) {
+ if (ssh_version == 1) {
+ send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
+ } else {
+ ssh2_pkt_init(SSH2_MSG_IGNORE);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_send();
+ }
} else {
/* do nothing */
}
}
-
-/*
- * 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 {
- fatalbox("Strange packet received: type %d", pktin.type);
- }
- }
-
- 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; }
ssh_size,
ssh_special,
ssh_socket,
- ssh_sendok
+ ssh_sendok,
+ 22
};