diff --git a/plink.c b/plink.c index 6c211503..f8a9f7ce 100644 --- a/plink.c +++ b/plink.c @@ -444,6 +444,7 @@ int main(int argc, char **argv) SOCKET *sklist; int skcount, sksize; int connopen; + int exitcode; char extra_portfwd[sizeof(cfg.portfwd)]; ssh_get_line = get_line; @@ -967,5 +968,10 @@ int main(int argc, char **argv) break; /* we closed the connection */ } WSACleanup(); - return 0; + exitcode = back->exitcode(); + if (exitcode < 0) { + fprintf(stderr, "Remote process exit code unavailable\n"); + exitcode = 1; /* this is an error condition */ + } + return exitcode; } diff --git a/putty.h b/putty.h index 28639a9b..266d6ac4 100644 --- a/putty.h +++ b/putty.h @@ -214,6 +214,7 @@ typedef struct { void (*size) (void); void (*special) (Telnet_Special code); Socket(*socket) (void); + int (*exitcode) (void); int (*sendok) (void); int (*ldisc) (int); /* diff --git a/raw.c b/raw.c index e3fcbc00..0d27bb77 100644 --- a/raw.c +++ b/raw.c @@ -162,6 +162,12 @@ static int raw_ldisc(int option) return 0; } +static int raw_exitcode(void) +{ + /* Exit codes are a meaningless concept in the Raw protocol */ + return 0; +} + Backend raw_backend = { raw_init, raw_send, @@ -169,6 +175,7 @@ Backend raw_backend = { raw_size, raw_special, raw_socket, + raw_exitcode, raw_sendok, raw_ldisc, raw_unthrottle, diff --git a/rlogin.c b/rlogin.c index 97699aea..ba7dd37b 100644 --- a/rlogin.c +++ b/rlogin.c @@ -217,6 +217,12 @@ static int rlogin_ldisc(int option) return 0; } +static int rlogin_exitcode(void) +{ + /* If we ever implement RSH, we'll probably need to do this properly */ + return 0; +} + Backend rlogin_backend = { rlogin_init, rlogin_send, @@ -224,6 +230,7 @@ Backend rlogin_backend = { rlogin_size, rlogin_special, rlogin_socket, + rlogin_exitcode, rlogin_sendok, rlogin_ldisc, rlogin_unthrottle, diff --git a/ssh.c b/ssh.c index dcb791da..e0fed88b 100644 --- a/ssh.c +++ b/ssh.c @@ -499,6 +499,7 @@ static int ssh_echoing, ssh_editing; static tree234 *ssh_channels; /* indexed by local id */ static struct ssh_channel *mainchan; /* primary session channel */ +static int ssh_exitcode = -1; static tree234 *ssh_rportfwds; @@ -3110,6 +3111,11 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) /* may be from EXEC_SHELL on some servers * if no pty is available or in other odd cases. Ignore */ } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) { + char buf[100]; + ssh_exitcode = GET_32BIT(pktin.body); + sprintf(buf, "Server sent command exit status %d", + ssh_exitcode); + logevent(buf); send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END); /* * In case `helpful' firewalls or proxies tack @@ -5061,14 +5067,35 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) } /* - * We don't recognise any form of channel request, - * so we now either ignore the request or respond - * with CHANNEL_FAILURE, depending on want_reply. + * Having got the channel number, we now look at + * the request type string to see if it's something + * we recognise. */ - if (want_reply) { - ssh2_pkt_init(SSH2_MSG_CHANNEL_FAILURE); - ssh2_pkt_adduint32(c->remoteid); - ssh2_pkt_send(); + if (typelen == 11 && !memcmp(type, "exit-status", 11) && + c == mainchan) { + /* We recognise "exit-status" on the primary channel. */ + char buf[100]; + ssh_exitcode = ssh2_pkt_getuint32(); + sprintf(buf, "Server sent command exit status %d", + ssh_exitcode); + logevent(buf); + if (want_reply) { + ssh2_pkt_init(SSH2_MSG_CHANNEL_SUCCESS); + ssh2_pkt_adduint32(c->remoteid); + ssh2_pkt_send(); + } + } else { + /* + * This is a channel request we don't know + * about, so we now either ignore the request + * or respond with CHANNEL_FAILURE, depending + * on want_reply. + */ + if (want_reply) { + ssh2_pkt_init(SSH2_MSG_CHANNEL_FAILURE); + ssh2_pkt_adduint32(c->remoteid); + ssh2_pkt_send(); + } } } else if (pktin.type == SSH2_MSG_CHANNEL_OPEN) { char *type; @@ -5443,6 +5470,11 @@ static int ssh_ldisc(int option) return FALSE; } +static int ssh_return_exitcode(void) +{ + return ssh_exitcode; +} + Backend ssh_backend = { ssh_init, ssh_send, @@ -5450,6 +5482,7 @@ Backend ssh_backend = { ssh_size, ssh_special, ssh_socket, + ssh_return_exitcode, ssh_sendok, ssh_ldisc, ssh_unthrottle, diff --git a/telnet.c b/telnet.c index 5c5d2ce3..5e5fb247 100644 --- a/telnet.c +++ b/telnet.c @@ -848,6 +848,12 @@ static int telnet_ldisc(int option) return FALSE; } +static int telnet_exitcode(void) +{ + /* Telnet doesn't transmit exit codes back to the client */ + return 0; +} + Backend telnet_backend = { telnet_init, telnet_send, @@ -855,6 +861,7 @@ Backend telnet_backend = { telnet_size, telnet_special, telnet_socket, + telnet_exitcode, telnet_sendok, telnet_ldisc, telnet_unthrottle,