From: jacob Date: Mon, 18 Oct 2004 00:41:48 +0000 (+0000) Subject: Add support for logging "exit-signal", why not. X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/commitdiff_plain/2b7540a7ff9881394a7f344aa50aa4abd08c358c?hp=6f2d0cde66cd10cdbcefb1401c422f0171a48549 Add support for logging "exit-signal", why not. This is disgustingly huge because old versions of OpenSSH got the message format wrong, so we have to infer which format is in use. Tested with Debian stable OpenSSH (3.4p1), with `uint32' packet, and lshd, which uses the correct `string' packet, and also let me test "core dumped" and the explanatory message. git-svn-id: svn://svn.tartarus.org/sgt/putty@4653 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/ssh.c b/ssh.c index c127fc5c..268fc049 100644 --- a/ssh.c +++ b/ssh.c @@ -6354,6 +6354,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) unsigned localid; char *type; int typelen, want_reply; + int reply = SSH2_MSG_CHANNEL_FAILURE; /* default */ struct ssh_channel *c; localid = ssh_pkt_getuint32(ssh); @@ -6385,18 +6386,93 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * the request type string to see if it's something * we recognise. */ - if (typelen == 11 && !memcmp(type, "exit-status", 11) && - c == ssh->mainchan) { - /* We recognise "exit-status" on the primary channel. */ - char buf[100]; - ssh->exitcode = ssh_pkt_getuint32(ssh); - sprintf(buf, "Server sent command exit status %d", - ssh->exitcode); - logevent(buf); - if (want_reply) { - ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_SUCCESS); - ssh2_pkt_adduint32(ssh, c->remoteid); - ssh2_pkt_send(ssh); + if (c == ssh->mainchan) { + /* + * We recognise "exit-status" and "exit-signal" on + * the primary channel. + */ + if (typelen == 11 && + !memcmp(type, "exit-status", 11)) { + + ssh->exitcode = ssh_pkt_getuint32(ssh); + logeventf(ssh, "Server sent command exit status %d", + ssh->exitcode); + reply = SSH2_MSG_CHANNEL_SUCCESS; + + } else if (typelen == 11 && + !memcmp(type, "exit-signal", 11)) { + + int is_plausible = TRUE, is_int = FALSE; + char *fmt_sig = "", *fmt_msg = ""; + char *msg; + int msglen = 0, core = FALSE; + /* ICK: older versions of OpenSSH (e.g. 3.4p1) + * provide an `int' for the signal, despite its + * having been a `string' in the drafts since at + * least 2001. (Fixed in session.c 1.147.) Try to + * infer which we can safely parse it as. */ + { + unsigned char *p = ssh->pktin.body + + ssh->pktin.savedpos; + long len = ssh->pktin.length - ssh->pktin.savedpos; + unsigned long num = GET_32BIT(p); /* what is it? */ + /* If it's 0, it hardly matters; assume string */ + if (num == 0) { + is_int = FALSE; + } else { + int maybe_int = FALSE, maybe_str = FALSE; +#define CHECK_HYPOTHESIS(offset, result) \ + do { \ + long q = offset; \ + if (q+4 <= len) { \ + q = q + 4 + GET_32BIT(p+q); \ + if (q+4 <= len && (q = q + 4 + GET_32BIT(p+q)) && q == len) \ + result = TRUE; \ + } \ + } while(0) + CHECK_HYPOTHESIS(4+1, maybe_int); + CHECK_HYPOTHESIS(4+num+1, maybe_str); +#undef CHECK_HYPOTHESIS + if (maybe_int && !maybe_str) + is_int = TRUE; + else if (!maybe_int && maybe_str) + is_int = FALSE; + else + /* Crikey. Either or neither. Panic. */ + is_plausible = FALSE; + } + } + if (is_plausible) { + if (is_int) { + /* Old non-standard OpenSSH. */ + int signum = ssh_pkt_getuint32(ssh); + fmt_sig = dupprintf(" %d", signum); + } else { + /* As per the drafts. */ + char *sig; + int siglen; + ssh_pkt_getstring(ssh, &sig, &siglen); + /* Signal name isn't supposed to be blank, but + * let's cope gracefully if it is. */ + if (siglen) { + fmt_sig = dupprintf(" \"%.*s\"", + siglen, sig); + } + } + core = ssh2_pkt_getbool(ssh); + ssh_pkt_getstring(ssh, &msg, &msglen); + if (msglen) { + fmt_msg = dupprintf(" (\"%.*s\")", msglen, msg); + } + /* ignore lang tag */ + } /* else don't attempt to parse */ + logeventf(ssh, "Server exited on signal%s%s%s", + fmt_sig, core ? " (core dumped)" : "", + fmt_msg); + if (*fmt_sig) sfree(fmt_sig); + if (*fmt_msg) sfree(fmt_msg); + reply = SSH2_MSG_CHANNEL_SUCCESS; + } } else { /* @@ -6405,11 +6481,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * or respond with CHANNEL_FAILURE, depending * on want_reply. */ - if (want_reply) { - ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_FAILURE); - ssh2_pkt_adduint32(ssh, c->remoteid); - ssh2_pkt_send(ssh); - } + reply = SSH2_MSG_CHANNEL_FAILURE; + } + if (want_reply) { + ssh2_pkt_init(ssh, reply); + ssh2_pkt_adduint32(ssh, c->remoteid); + ssh2_pkt_send(ssh); } } else if (ssh->pktin.type == SSH2_MSG_GLOBAL_REQUEST) { char *type;