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);
logevent("Using SSH protocol version 2");
s_write(vstring, strlen(vstring));
ssh_protocol = ssh2_protocol;
+ ssh_version = 2;
s_rdpkt = ssh2_rdpkt;
} else {
/*
logevent("Using SSH protocol version 1");
s_write(vstring, strlen(vstring));
ssh_protocol = ssh1_protocol;
+ ssh_version = 1;
s_rdpkt = ssh1_rdpkt;
}
return 1;
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;
}
/*
+ * 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;
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");
* 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);
* 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();
} 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();
}
/*
- * (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 */
+ }
}
}
wpps (sesskey, "UserName", cfg.username);
wppi (sesskey, "NoPTY", cfg.nopty);
+ wpps (sesskey, "RemoteCmd", cfg.remote_cmd);
wpps (sesskey, "Cipher", cfg.cipher == CIPHER_BLOWFISH ? "blowfish" :
cfg.cipher == CIPHER_DES ? "des" : "3des");
wppi (sesskey, "AuthTIS", cfg.try_tis_auth);
}
gpps (sesskey, "UserName", "", cfg.username, sizeof(cfg.username));
gppi (sesskey, "NoPTY", 0, &cfg.nopty);
+ gpps (sesskey, "RemoteCmd", "", cfg.remote_cmd, sizeof(cfg.remote_cmd));
{
char cipher[10];
gpps (sesskey, "Cipher", "3des", cipher, 10);