X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/0d201bfb8495ca95cac852a499a0097495b58a6c..67a9ec92936c66ea894bb964905f42a0d18d4f18:/ssh.c diff --git a/ssh.c b/ssh.c index bfc10b02..c419a89d 100644 --- a/ssh.c +++ b/ssh.c @@ -780,8 +780,8 @@ static unsigned long ssh_pkt_getuint32(struct Packet *pkt); static int ssh2_pkt_getbool(struct Packet *pkt); static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length); static void ssh2_timer(void *ctx, long now); -static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, - struct Packet *pktin); +static void do_ssh2_transport(Ssh ssh, void *vin, int inlen, + struct Packet *pktin); static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin); struct rdpkt1_state_tag { @@ -1019,14 +1019,15 @@ static void logeventf(Ssh ssh, const char *fmt, ...) sfree(buf); } -#define bombout(msg) \ - do { \ - char *text = dupprintf msg; \ - ssh_do_close(ssh, FALSE); \ - logevent(text); \ - connection_fatal(ssh->frontend, "%s", text); \ - sfree(text); \ - } while (0) +static void bomb_out(Ssh ssh, char *text) +{ + ssh_do_close(ssh, FALSE); + logevent(text); + connection_fatal(ssh->frontend, "%s", text); + sfree(text); +} + +#define bombout(msg) bomb_out(ssh, dupprintf msg) /* Functions to leave bits out of the SSH packet log file. */ @@ -1062,12 +1063,14 @@ static void parse_ttymodes(Ssh ssh, * follows it, or 'A' indicating that we should pass the * value through from the local environment via get_ttymode. */ - if (val[0] == 'A') + if (val[0] == 'A') { val = get_ttymode(ssh->frontend, key); - else - val++; /* skip the 'V' */ - if (val) - do_mode(data, key, val); + if (val) { + do_mode(data, key, val); + sfree(val); + } + } else + do_mode(data, key, val + 1); /* skip the 'V' */ } } @@ -5473,7 +5476,7 @@ static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr, /* * Handle the SSH-2 transport layer. */ -static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, +static void do_ssh2_transport(Ssh ssh, void *vin, int inlen, struct Packet *pktin) { unsigned char *in = (unsigned char *)vin; @@ -5714,7 +5717,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh2_pkt_send_noqueue(ssh, s->pktout); if (!pktin) - crWaitUntil(pktin); + crWaitUntilV(pktin); /* * Now examine the other side's KEXINIT to see what we're up @@ -5726,7 +5729,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (pktin->type != SSH2_MSG_KEXINIT) { bombout(("expected key exchange packet from server")); - crStop(0); + crStopV; } ssh->kex = NULL; ssh->hostkey = NULL; @@ -5761,7 +5764,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (!ssh->kex) { bombout(("Couldn't agree a key exchange algorithm (available: %s)", str ? str : "(null)")); - crStop(0); + crStopV; } /* * Note that the server's guess is considered wrong if it doesn't match @@ -5779,7 +5782,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (!ssh->hostkey) { bombout(("Couldn't agree a host key algorithm (available: %s)", str ? str : "(null)")); - crStop(0); + crStopV; } s->guessok = s->guessok && @@ -5803,7 +5806,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (!s->cscipher_tobe) { bombout(("Couldn't agree a client-to-server cipher (available: %s)", str ? str : "(null)")); - crStop(0); + crStopV; } ssh_pkt_getstring(pktin, &str, &len); /* server->client cipher */ @@ -5825,7 +5828,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (!s->sccipher_tobe) { bombout(("Couldn't agree a server-to-client cipher (available: %s)", str ? str : "(null)")); - crStop(0); + crStopV; } ssh_pkt_getstring(pktin, &str, &len); /* client->server mac */ @@ -5889,11 +5892,11 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { - crReturn(0); + crReturnV; if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); - crStop(0); + crStopV; } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; @@ -5902,7 +5905,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at kex warning", NULL, 0, TRUE); - crStop(0); + crStopV; } } @@ -5914,11 +5917,11 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { - crReturn(0); + crReturnV; if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); - crStop(0); + crStopV; } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; @@ -5927,7 +5930,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); - crStop(0); + crStopV; } } @@ -5939,11 +5942,11 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { - crReturn(0); + crReturnV; if (pktin) { bombout(("Unexpected data from server while" " waiting for user response")); - crStop(0); + crStopV; } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; @@ -5952,7 +5955,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at cipher warning", NULL, 0, TRUE); - crStop(0); + crStopV; } } @@ -5967,7 +5970,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, pktin->data + 5, pktin->length - 5); if (s->ignorepkt) /* first_kex_packet_follows */ - crWaitUntil(pktin); /* Ignore packet */ + crWaitUntilV(pktin); /* Ignore packet */ } if (ssh->kex->main_type == KEXTYPE_DH) { @@ -6004,16 +6007,16 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh2_pkt_adduint32(s->pktout, s->pbits); ssh2_pkt_send_noqueue(ssh, s->pktout); - crWaitUntil(pktin); + crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) { bombout(("expected key exchange group packet from server")); - crStop(0); + crStopV; } s->p = ssh2_pkt_getmp(pktin); s->g = ssh2_pkt_getmp(pktin); if (!s->p || !s->g) { bombout(("unable to read mp-ints from incoming group packet")); - crStop(0); + crStopV; } ssh->kex_ctx = dh_setup_gex(s->p, s->g); s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; @@ -6039,10 +6042,10 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh2_pkt_send_noqueue(ssh, s->pktout); set_busy_status(ssh->frontend, BUSY_WAITING); /* wait for server */ - crWaitUntil(pktin); + crWaitUntilV(pktin); if (pktin->type != s->kex_reply_value) { bombout(("expected key exchange reply packet from server")); - crStop(0); + crStopV; } set_busy_status(ssh->frontend, BUSY_CPU); /* cogitate */ ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); @@ -6050,7 +6053,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, s->f = ssh2_pkt_getmp(pktin); if (!s->f) { bombout(("unable to parse key exchange reply packet")); - crStop(0); + crStopV; } ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); @@ -6083,10 +6086,10 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, * RSA key exchange. First expect a KEXRSA_PUBKEY packet * from the server. */ - crWaitUntil(pktin); + crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) { bombout(("expected RSA public key packet from server")); - crStop(0); + crStopV; } ssh_pkt_getstring(pktin, &s->hostkeydata, &s->hostkeylen); @@ -6105,7 +6108,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (!s->rsakey) { sfree(s->rsakeydata); bombout(("unable to parse RSA public key from server")); - crStop(0); + crStopV; } hash_string(ssh->kex->hash, ssh->exhash, s->rsakeydata, s->rsakeylen); @@ -6165,11 +6168,11 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh_rsakex_freekey(s->rsakey); - crWaitUntil(pktin); + crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_KEXRSA_DONE) { sfree(s->rsakeydata); bombout(("expected signature packet from server")); - crStop(0); + crStopV; } ssh_pkt_getstring(pktin, &s->sigdata, &s->siglen); @@ -6193,7 +6196,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, (char *)s->exchange_hash, ssh->kex->hash->hlen)) { bombout(("Server's host key did not match the signature supplied")); - crStop(0); + crStopV; } /* @@ -6210,11 +6213,11 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, ssh_dialog_callback, ssh); if (s->dlgret < 0) { do { - crReturn(0); + crReturnV; if (pktin) { bombout(("Unexpected data from server while waiting" " for user host key response")); - crStop(0); + crStopV; } } while (pktin || inlen > 0); s->dlgret = ssh->user_response; @@ -6223,7 +6226,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, if (s->dlgret == 0) { ssh_disconnect(ssh, "User aborted at host key verification", NULL, 0, TRUE); - crStop(0); + crStopV; } if (!s->got_session_id) { /* don't bother logging this in rekeys */ logevent("Host key fingerprint is:"); @@ -6313,10 +6316,10 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, /* * Expect SSH2_MSG_NEWKEYS from server. */ - crWaitUntil(pktin); + crWaitUntilV(pktin); if (pktin->type != SSH2_MSG_NEWKEYS) { bombout(("expected new-keys packet from server")); - crStop(0); + crStopV; } ssh->incoming_data_size = 0; /* start counting from here */ @@ -6418,7 +6421,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, */ do_ssh2_authconn(ssh, NULL, 0, NULL); } - crReturn(1); + crReturnV; } if (pktin) { logevent("Server initiated key re-exchange"); @@ -6477,7 +6480,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, } goto begin_key_exchange; - crFinish(1); + crFinishV; } /* @@ -7465,136 +7468,126 @@ static void ssh2_send_ttymode(void *data, char *mode, char *val) ssh2_pkt_adduint32(pktout, arg); } -static void ssh2_maybe_setup_x11(struct ssh_channel *c, struct Packet *pktin, - void *ctx) +static void ssh2_setup_x11(struct ssh_channel *c, struct Packet *pktin, + void *ctx) { - struct ssh2_maybe_setup_x11_state { + struct ssh2_setup_x11_state { int crLine; }; Ssh ssh = c->ssh; struct Packet *pktout; - crStateP(ssh2_maybe_setup_x11_state, ctx); + crStateP(ssh2_setup_x11_state, ctx); crBeginState; + logevent("Requesting X11 forwarding"); + pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req", + ssh2_setup_x11, s); + ssh2_pkt_addbool(pktout, 0); /* many connections */ + ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname); /* - * Potentially enable X11 forwarding. + * Note that while we blank the X authentication data here, we don't + * take any special action to blank the start of an X11 channel, + * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection + * without having session blanking enabled is likely to leak your + * cookie into the log. */ - if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_x11_forward) && - (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), - conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) { - logevent("Requesting X11 forwarding"); - pktout = ssh2_chanreq_init(ssh->mainchan, "x11-req", - ssh2_maybe_setup_x11, s); - ssh2_pkt_addbool(pktout, 0); /* many connections */ - ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthprotoname); - /* - * Note that while we blank the X authentication data here, we don't - * take any special action to blank the start of an X11 channel, - * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection - * without having session blanking enabled is likely to leak your - * cookie into the log. - */ - dont_log_password(ssh, pktout, PKTLOG_BLANK); - ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthdatastring); - end_log_omission(ssh, pktout); - ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum); - ssh2_pkt_send(ssh, pktout); + dont_log_password(ssh, pktout, PKTLOG_BLANK); + ssh2_pkt_addstring(pktout, ssh->x11disp->remoteauthdatastring); + end_log_omission(ssh, pktout); + ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum); + ssh2_pkt_send(ssh, pktout); - crWaitUntilV(pktin); + crWaitUntilV(pktin); - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logevent("X11 forwarding enabled"); - ssh->X11_fwd_enabled = TRUE; - } else - logevent("X11 forwarding refused"); - } + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + logevent("X11 forwarding enabled"); + ssh->X11_fwd_enabled = TRUE; + } else + logevent("X11 forwarding refused"); } + crFinishFreeV; } -static void ssh2_maybe_setup_agent(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_agent(struct ssh_channel *c, struct Packet *pktin, void *ctx) { - struct ssh2_maybe_setup_agent_state { + struct ssh2_setup_agent_state { int crLine; }; Ssh ssh = c->ssh; struct Packet *pktout; - crStateP(ssh2_maybe_setup_agent_state, ctx); + crStateP(ssh2_setup_agent_state, ctx); crBeginState; - if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) { - logevent("Requesting OpenSSH-style agent forwarding"); - pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com", - ssh2_maybe_setup_agent, s); - ssh2_pkt_send(ssh, pktout); + logevent("Requesting OpenSSH-style agent forwarding"); + pktout = ssh2_chanreq_init(ssh->mainchan, "auth-agent-req@openssh.com", + ssh2_setup_agent, s); + ssh2_pkt_send(ssh, pktout); - crWaitUntilV(pktin); + crWaitUntilV(pktin); - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logevent("Agent forwarding enabled"); - ssh->agentfwd_enabled = TRUE; - } else - logevent("Agent forwarding refused"); - } + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + logevent("Agent forwarding enabled"); + ssh->agentfwd_enabled = TRUE; + } else + logevent("Agent forwarding refused"); } + crFinishFreeV; } -static void ssh2_maybe_setup_pty(struct ssh_channel *c, struct Packet *pktin, +static void ssh2_setup_pty(struct ssh_channel *c, struct Packet *pktin, void *ctx) { - struct ssh2_maybe_setup_pty_state { + struct ssh2_setup_pty_state { int crLine; }; Ssh ssh = c->ssh; struct Packet *pktout; - crStateP(ssh2_maybe_setup_pty_state, ctx); + crStateP(ssh2_setup_pty_state, ctx); crBeginState; - if (ssh->mainchan && !ssh->ncmode && !conf_get_int(ssh->conf, CONF_nopty)) { - /* Unpick the terminal-speed string. */ - /* XXX perhaps we should allow no speeds to be sent. */ - ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ - sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); - /* Build the pty request. */ - pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req", - ssh2_maybe_setup_pty, s); - ssh2_pkt_addstring(pktout, conf_get_str(ssh->conf, CONF_termtype)); - ssh2_pkt_adduint32(pktout, ssh->term_width); - ssh2_pkt_adduint32(pktout, ssh->term_height); - ssh2_pkt_adduint32(pktout, 0); /* pixel width */ - ssh2_pkt_adduint32(pktout, 0); /* pixel height */ - ssh2_pkt_addstring_start(pktout); - parse_ttymodes(ssh, ssh2_send_ttymode, (void *)pktout); - ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_ISPEED); - ssh2_pkt_adduint32(pktout, ssh->ispeed); - ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_OSPEED); - ssh2_pkt_adduint32(pktout, ssh->ospeed); - ssh2_pkt_addstring_data(pktout, "\0", 1); /* TTY_OP_END */ - ssh2_pkt_send(ssh, pktout); - ssh->state = SSH_STATE_INTERMED; + /* Unpick the terminal-speed string. */ + /* XXX perhaps we should allow no speeds to be sent. */ + ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ + sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); + /* Build the pty request. */ + pktout = ssh2_chanreq_init(ssh->mainchan, "pty-req", + ssh2_setup_pty, s); + ssh2_pkt_addstring(pktout, conf_get_str(ssh->conf, CONF_termtype)); + ssh2_pkt_adduint32(pktout, ssh->term_width); + ssh2_pkt_adduint32(pktout, ssh->term_height); + ssh2_pkt_adduint32(pktout, 0); /* pixel width */ + ssh2_pkt_adduint32(pktout, 0); /* pixel height */ + ssh2_pkt_addstring_start(pktout); + parse_ttymodes(ssh, ssh2_send_ttymode, (void *)pktout); + ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_ISPEED); + ssh2_pkt_adduint32(pktout, ssh->ispeed); + ssh2_pkt_addbyte(pktout, SSH2_TTY_OP_OSPEED); + ssh2_pkt_adduint32(pktout, ssh->ospeed); + ssh2_pkt_addstring_data(pktout, "\0", 1); /* TTY_OP_END */ + ssh2_pkt_send(ssh, pktout); + ssh->state = SSH_STATE_INTERMED; + + crWaitUntilV(pktin); - crWaitUntilV(pktin); - - if (pktin) { - if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { - logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", - ssh->ospeed, ssh->ispeed); - ssh->got_pty = TRUE; - } else { - c_write_str(ssh, "Server refused to allocate pty\r\n"); - ssh->editing = ssh->echoing = 1; - } - } - } else { - ssh->editing = ssh->echoing = 1; + if (pktin) { + if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) { + logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", + ssh->ospeed, ssh->ispeed); + ssh->got_pty = TRUE; + } else { + c_write_str(ssh, "Server refused to allocate pty\r\n"); + ssh->editing = ssh->echoing = 1; + } } + crFinishFreeV; } @@ -7618,7 +7611,7 @@ static void ssh2_setup_env(struct ssh_channel *c, struct Packet *pktin, * then wait for a whole bunch of successes or failures. */ s->num_env = 0; - if (ssh->mainchan && !ssh->ncmode) { + { char *key, *val; for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key); @@ -9241,22 +9234,34 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Potentially enable X11 forwarding. */ - ssh2_maybe_setup_x11(ssh->mainchan, NULL, NULL); + /* + * Potentially enable X11 forwarding. + */ + if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_x11_forward) && + (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), + conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) + ssh2_setup_x11(ssh->mainchan, NULL, NULL); /* * Potentially enable agent forwarding. */ - ssh2_maybe_setup_agent(ssh->mainchan, NULL, NULL); + if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) + ssh2_setup_agent(ssh->mainchan, NULL, NULL); /* * Now allocate a pty for the session. */ - ssh2_maybe_setup_pty(ssh->mainchan, NULL, NULL); + if (ssh->mainchan && !ssh->ncmode && !conf_get_int(ssh->conf, CONF_nopty)) { + ssh2_setup_pty(ssh->mainchan, NULL, NULL); + } else { + ssh->editing = ssh->echoing = 1; + } /* * Send environment variables. */ - ssh2_setup_env(ssh->mainchan, NULL, NULL); + if (ssh->mainchan && !ssh->ncmode) + ssh2_setup_env(ssh->mainchan, NULL, NULL); /* * Start a shell or a remote command. We may have to attempt