mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Move the ttymode formatter into sshcommon.c.
While I'm at it, I've brought it all into a single function: the parsing of data from Conf, the list of modes, and even the old callback system for writing to the destination buffer is now a simple if statement that formats mode parameters as byte or uint32 depending on SSH version. Also, the terminal speeds and the end byte are part of the same setup, so it's all together in one place instead of scattered all over ssh.c.
This commit is contained in:
parent
783f03d5ed
commit
12abb95394
190
ssh.c
190
ssh.c
@ -50,111 +50,6 @@ static const char *const ssh2_disconnect_reasons[] = {
|
||||
#define DH_MIN_SIZE 1024
|
||||
#define DH_MAX_SIZE 8192
|
||||
|
||||
/*
|
||||
* Codes for terminal modes.
|
||||
* Most of these are the same in SSH-1 and SSH-2.
|
||||
* This list is derived from RFC 4254 and
|
||||
* SSH-1 RFC-1.2.31.
|
||||
*/
|
||||
static const struct ssh_ttymode {
|
||||
const char* const mode;
|
||||
int opcode;
|
||||
enum { TTY_OP_CHAR, TTY_OP_BOOL } type;
|
||||
} ssh_ttymodes[] = {
|
||||
/* "V" prefix discarded for special characters relative to SSH specs */
|
||||
{ "INTR", 1, TTY_OP_CHAR },
|
||||
{ "QUIT", 2, TTY_OP_CHAR },
|
||||
{ "ERASE", 3, TTY_OP_CHAR },
|
||||
{ "KILL", 4, TTY_OP_CHAR },
|
||||
{ "EOF", 5, TTY_OP_CHAR },
|
||||
{ "EOL", 6, TTY_OP_CHAR },
|
||||
{ "EOL2", 7, TTY_OP_CHAR },
|
||||
{ "START", 8, TTY_OP_CHAR },
|
||||
{ "STOP", 9, TTY_OP_CHAR },
|
||||
{ "SUSP", 10, TTY_OP_CHAR },
|
||||
{ "DSUSP", 11, TTY_OP_CHAR },
|
||||
{ "REPRINT", 12, TTY_OP_CHAR },
|
||||
{ "WERASE", 13, TTY_OP_CHAR },
|
||||
{ "LNEXT", 14, TTY_OP_CHAR },
|
||||
{ "FLUSH", 15, TTY_OP_CHAR },
|
||||
{ "SWTCH", 16, TTY_OP_CHAR },
|
||||
{ "STATUS", 17, TTY_OP_CHAR },
|
||||
{ "DISCARD", 18, TTY_OP_CHAR },
|
||||
{ "IGNPAR", 30, TTY_OP_BOOL },
|
||||
{ "PARMRK", 31, TTY_OP_BOOL },
|
||||
{ "INPCK", 32, TTY_OP_BOOL },
|
||||
{ "ISTRIP", 33, TTY_OP_BOOL },
|
||||
{ "INLCR", 34, TTY_OP_BOOL },
|
||||
{ "IGNCR", 35, TTY_OP_BOOL },
|
||||
{ "ICRNL", 36, TTY_OP_BOOL },
|
||||
{ "IUCLC", 37, TTY_OP_BOOL },
|
||||
{ "IXON", 38, TTY_OP_BOOL },
|
||||
{ "IXANY", 39, TTY_OP_BOOL },
|
||||
{ "IXOFF", 40, TTY_OP_BOOL },
|
||||
{ "IMAXBEL", 41, TTY_OP_BOOL },
|
||||
{ "IUTF8", 42, TTY_OP_BOOL },
|
||||
{ "ISIG", 50, TTY_OP_BOOL },
|
||||
{ "ICANON", 51, TTY_OP_BOOL },
|
||||
{ "XCASE", 52, TTY_OP_BOOL },
|
||||
{ "ECHO", 53, TTY_OP_BOOL },
|
||||
{ "ECHOE", 54, TTY_OP_BOOL },
|
||||
{ "ECHOK", 55, TTY_OP_BOOL },
|
||||
{ "ECHONL", 56, TTY_OP_BOOL },
|
||||
{ "NOFLSH", 57, TTY_OP_BOOL },
|
||||
{ "TOSTOP", 58, TTY_OP_BOOL },
|
||||
{ "IEXTEN", 59, TTY_OP_BOOL },
|
||||
{ "ECHOCTL", 60, TTY_OP_BOOL },
|
||||
{ "ECHOKE", 61, TTY_OP_BOOL },
|
||||
{ "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */
|
||||
{ "OPOST", 70, TTY_OP_BOOL },
|
||||
{ "OLCUC", 71, TTY_OP_BOOL },
|
||||
{ "ONLCR", 72, TTY_OP_BOOL },
|
||||
{ "OCRNL", 73, TTY_OP_BOOL },
|
||||
{ "ONOCR", 74, TTY_OP_BOOL },
|
||||
{ "ONLRET", 75, TTY_OP_BOOL },
|
||||
{ "CS7", 90, TTY_OP_BOOL },
|
||||
{ "CS8", 91, TTY_OP_BOOL },
|
||||
{ "PARENB", 92, TTY_OP_BOOL },
|
||||
{ "PARODD", 93, TTY_OP_BOOL }
|
||||
};
|
||||
|
||||
/* Miscellaneous other tty-related constants. */
|
||||
#define SSH_TTY_OP_END 0
|
||||
/* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */
|
||||
#define SSH1_TTY_OP_ISPEED 192
|
||||
#define SSH1_TTY_OP_OSPEED 193
|
||||
#define SSH2_TTY_OP_ISPEED 128
|
||||
#define SSH2_TTY_OP_OSPEED 129
|
||||
|
||||
/* Helper functions for parsing tty-related config. */
|
||||
static unsigned int ssh_tty_parse_specchar(char *s)
|
||||
{
|
||||
unsigned int ret;
|
||||
if (*s) {
|
||||
char *next = NULL;
|
||||
ret = ctrlparse(s, &next);
|
||||
if (!next) ret = s[0];
|
||||
} else {
|
||||
ret = 255; /* special value meaning "don't set" */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static unsigned int ssh_tty_parse_boolean(char *s)
|
||||
{
|
||||
if (stricmp(s, "yes") == 0 ||
|
||||
stricmp(s, "on") == 0 ||
|
||||
stricmp(s, "true") == 0 ||
|
||||
stricmp(s, "+") == 0)
|
||||
return 1; /* true */
|
||||
else if (stricmp(s, "no") == 0 ||
|
||||
stricmp(s, "off") == 0 ||
|
||||
stricmp(s, "false") == 0 ||
|
||||
stricmp(s, "-") == 0)
|
||||
return 0; /* false */
|
||||
else
|
||||
return (atoi(s) != 0);
|
||||
}
|
||||
|
||||
/* Safely convert rekey_time to unsigned long minutes */
|
||||
static unsigned long rekey_mins(int rekey_time, unsigned long def)
|
||||
{
|
||||
@ -870,41 +765,6 @@ static void bomb_out(Ssh ssh, char *text)
|
||||
|
||||
#define bombout(msg) bomb_out(ssh, dupprintf msg)
|
||||
|
||||
/* Helper function for common bits of parsing ttymodes. */
|
||||
static void parse_ttymodes(
|
||||
BinarySink *bs, Ssh ssh,
|
||||
void (*do_mode)(BinarySink *, const struct ssh_ttymode *, char *))
|
||||
{
|
||||
int i;
|
||||
const struct ssh_ttymode *mode;
|
||||
char *val;
|
||||
|
||||
for (i = 0; i < lenof(ssh_ttymodes); i++) {
|
||||
mode = ssh_ttymodes + i;
|
||||
/* Every mode known to the current version of the code should be
|
||||
* mentioned; this was ensured when settings were loaded. */
|
||||
val = conf_get_str_str(ssh->conf, CONF_ttymodes, mode->mode);
|
||||
|
||||
/*
|
||||
* val[0] can be
|
||||
* - 'V', indicating that an explicit value follows it;
|
||||
* - 'A', indicating that we should pass the value through from
|
||||
* the local environment via get_ttymode; or
|
||||
* - 'N', indicating that we should explicitly not send this
|
||||
* mode.
|
||||
*/
|
||||
if (val[0] == 'A') {
|
||||
val = get_ttymode(ssh->frontend, mode->mode);
|
||||
if (val) {
|
||||
do_mode(bs, mode, val);
|
||||
sfree(val);
|
||||
}
|
||||
} else if (val[0] == 'V') {
|
||||
do_mode(bs, mode, val + 1); /* skip the 'V' */
|
||||
} /* else 'N', or something from the future we don't understand */
|
||||
}
|
||||
}
|
||||
|
||||
static int ssh_channelcmp(void *av, void *bv)
|
||||
{
|
||||
struct ssh_channel *a = (struct ssh_channel *) av;
|
||||
@ -3363,22 +3223,6 @@ static void ssh1_smsg_exit_status(Ssh ssh, PktIn *pktin)
|
||||
ssh_disconnect(ssh, NULL, NULL, 0, TRUE);
|
||||
}
|
||||
|
||||
/* Helper function to deal with sending tty modes for REQUEST_PTY */
|
||||
static void ssh1_send_ttymode(BinarySink *bs,
|
||||
const struct ssh_ttymode *mode, char *val)
|
||||
{
|
||||
put_byte(bs, mode->opcode);
|
||||
|
||||
switch (mode->type) {
|
||||
case TTY_OP_CHAR:
|
||||
put_byte(bs, ssh_tty_parse_specchar(val));
|
||||
break;
|
||||
case TTY_OP_BOOL:
|
||||
put_byte(bs, ssh_tty_parse_boolean(val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl)
|
||||
{
|
||||
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
|
||||
@ -3478,12 +3322,9 @@ static void do_ssh1_connection(void *vctx)
|
||||
put_uint32(pkt, ssh->term_width);
|
||||
put_uint32(pkt, 0); /* width in pixels */
|
||||
put_uint32(pkt, 0); /* height in pixels */
|
||||
parse_ttymodes(BinarySink_UPCAST(pkt), ssh, ssh1_send_ttymode);
|
||||
put_byte(pkt, SSH1_TTY_OP_ISPEED);
|
||||
put_uint32(pkt, ssh->ispeed);
|
||||
put_byte(pkt, SSH1_TTY_OP_OSPEED);
|
||||
put_uint32(pkt, ssh->ospeed);
|
||||
put_byte(pkt, SSH_TTY_OP_END);
|
||||
write_ttymodes_to_packet_from_conf(
|
||||
BinarySink_UPCAST(pkt), ssh->frontend, ssh->conf,
|
||||
1, ssh->ospeed, ssh->ispeed);
|
||||
ssh_pkt_write(ssh, pkt);
|
||||
ssh->state = SSH_STATE_INTERMED;
|
||||
crMaybeWaitUntilV((pktin = pq_pop(&ssh->pq_ssh1_connection)) != NULL);
|
||||
@ -6825,22 +6666,6 @@ static void ssh2_msg_userauth_banner(Ssh ssh, PktIn *pktin)
|
||||
}
|
||||
}
|
||||
|
||||
/* Helper function to deal with sending tty modes for "pty-req" */
|
||||
static void ssh2_send_ttymode(BinarySink *bs,
|
||||
const struct ssh_ttymode *mode, char *val)
|
||||
{
|
||||
put_byte(bs, mode->opcode);
|
||||
|
||||
switch (mode->type) {
|
||||
case TTY_OP_CHAR:
|
||||
put_uint32(bs, ssh_tty_parse_specchar(val));
|
||||
break;
|
||||
case TTY_OP_BOOL:
|
||||
put_uint32(bs, ssh_tty_parse_boolean(val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssh2_setup_x11(struct ssh_channel *c, PktIn *pktin,
|
||||
void *ctx)
|
||||
{
|
||||
@ -6935,12 +6760,9 @@ static void ssh2_setup_pty(struct ssh_channel *c, PktIn *pktin,
|
||||
put_uint32(pktout, 0); /* pixel height */
|
||||
{
|
||||
strbuf *modebuf = strbuf_new();
|
||||
parse_ttymodes(BinarySink_UPCAST(modebuf), ssh, ssh2_send_ttymode);
|
||||
put_byte(modebuf, SSH2_TTY_OP_ISPEED);
|
||||
put_uint32(modebuf, ssh->ispeed);
|
||||
put_byte(modebuf, SSH2_TTY_OP_OSPEED);
|
||||
put_uint32(modebuf, ssh->ospeed);
|
||||
put_byte(modebuf, SSH_TTY_OP_END);
|
||||
write_ttymodes_to_packet_from_conf(
|
||||
BinarySink_UPCAST(modebuf), ssh->frontend, ssh->conf,
|
||||
2, ssh->ospeed, ssh->ispeed);
|
||||
put_stringsb(pktout, modebuf);
|
||||
}
|
||||
ssh2_pkt_send(ssh, pktout);
|
||||
|
5
ssh.h
5
ssh.h
@ -1321,3 +1321,8 @@ enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_LOG2_ENUM) };
|
||||
#define TMP_DECLARE_REAL_ENUM(thing) thing = 1 << log2_##thing,
|
||||
enum { SSH_IMPL_BUG_LIST(TMP_DECLARE_REAL_ENUM) };
|
||||
#undef TMP_DECLARE_REAL_ENUM
|
||||
|
||||
/* Shared function that writes tty modes into a pty request */
|
||||
void write_ttymodes_to_packet_from_conf(
|
||||
BinarySink *bs, Frontend *frontend, Conf *conf,
|
||||
int ssh_version, int ospeed, int ispeed);
|
||||
|
180
sshcommon.c
180
sshcommon.c
@ -4,7 +4,9 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "putty.h"
|
||||
#include "ssh.h"
|
||||
#include "sshchan.h"
|
||||
|
||||
@ -286,3 +288,181 @@ int chan_no_eager_close(Channel *chan, int sent_local_eof, int rcvd_remote_eof)
|
||||
{
|
||||
return FALSE; /* default: never proactively ask for a close */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Common routine to marshal tty modes into an SSH packet.
|
||||
*/
|
||||
|
||||
void write_ttymodes_to_packet_from_conf(
|
||||
BinarySink *bs, Frontend *frontend, Conf *conf,
|
||||
int ssh_version, int ospeed, int ispeed)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Codes for terminal modes.
|
||||
* Most of these are the same in SSH-1 and SSH-2.
|
||||
* This list is derived from RFC 4254 and
|
||||
* SSH-1 RFC-1.2.31.
|
||||
*/
|
||||
static const struct ssh_ttymode {
|
||||
const char *mode;
|
||||
int opcode;
|
||||
enum { TTY_OP_CHAR, TTY_OP_BOOL } type;
|
||||
} ssh_ttymodes[] = {
|
||||
/* "V" prefix discarded for special characters relative to SSH specs */
|
||||
{ "INTR", 1, TTY_OP_CHAR },
|
||||
{ "QUIT", 2, TTY_OP_CHAR },
|
||||
{ "ERASE", 3, TTY_OP_CHAR },
|
||||
{ "KILL", 4, TTY_OP_CHAR },
|
||||
{ "EOF", 5, TTY_OP_CHAR },
|
||||
{ "EOL", 6, TTY_OP_CHAR },
|
||||
{ "EOL2", 7, TTY_OP_CHAR },
|
||||
{ "START", 8, TTY_OP_CHAR },
|
||||
{ "STOP", 9, TTY_OP_CHAR },
|
||||
{ "SUSP", 10, TTY_OP_CHAR },
|
||||
{ "DSUSP", 11, TTY_OP_CHAR },
|
||||
{ "REPRINT", 12, TTY_OP_CHAR },
|
||||
{ "WERASE", 13, TTY_OP_CHAR },
|
||||
{ "LNEXT", 14, TTY_OP_CHAR },
|
||||
{ "FLUSH", 15, TTY_OP_CHAR },
|
||||
{ "SWTCH", 16, TTY_OP_CHAR },
|
||||
{ "STATUS", 17, TTY_OP_CHAR },
|
||||
{ "DISCARD", 18, TTY_OP_CHAR },
|
||||
{ "IGNPAR", 30, TTY_OP_BOOL },
|
||||
{ "PARMRK", 31, TTY_OP_BOOL },
|
||||
{ "INPCK", 32, TTY_OP_BOOL },
|
||||
{ "ISTRIP", 33, TTY_OP_BOOL },
|
||||
{ "INLCR", 34, TTY_OP_BOOL },
|
||||
{ "IGNCR", 35, TTY_OP_BOOL },
|
||||
{ "ICRNL", 36, TTY_OP_BOOL },
|
||||
{ "IUCLC", 37, TTY_OP_BOOL },
|
||||
{ "IXON", 38, TTY_OP_BOOL },
|
||||
{ "IXANY", 39, TTY_OP_BOOL },
|
||||
{ "IXOFF", 40, TTY_OP_BOOL },
|
||||
{ "IMAXBEL", 41, TTY_OP_BOOL },
|
||||
{ "IUTF8", 42, TTY_OP_BOOL },
|
||||
{ "ISIG", 50, TTY_OP_BOOL },
|
||||
{ "ICANON", 51, TTY_OP_BOOL },
|
||||
{ "XCASE", 52, TTY_OP_BOOL },
|
||||
{ "ECHO", 53, TTY_OP_BOOL },
|
||||
{ "ECHOE", 54, TTY_OP_BOOL },
|
||||
{ "ECHOK", 55, TTY_OP_BOOL },
|
||||
{ "ECHONL", 56, TTY_OP_BOOL },
|
||||
{ "NOFLSH", 57, TTY_OP_BOOL },
|
||||
{ "TOSTOP", 58, TTY_OP_BOOL },
|
||||
{ "IEXTEN", 59, TTY_OP_BOOL },
|
||||
{ "ECHOCTL", 60, TTY_OP_BOOL },
|
||||
{ "ECHOKE", 61, TTY_OP_BOOL },
|
||||
{ "PENDIN", 62, TTY_OP_BOOL }, /* XXX is this a real mode? */
|
||||
{ "OPOST", 70, TTY_OP_BOOL },
|
||||
{ "OLCUC", 71, TTY_OP_BOOL },
|
||||
{ "ONLCR", 72, TTY_OP_BOOL },
|
||||
{ "OCRNL", 73, TTY_OP_BOOL },
|
||||
{ "ONOCR", 74, TTY_OP_BOOL },
|
||||
{ "ONLRET", 75, TTY_OP_BOOL },
|
||||
{ "CS7", 90, TTY_OP_BOOL },
|
||||
{ "CS8", 91, TTY_OP_BOOL },
|
||||
{ "PARENB", 92, TTY_OP_BOOL },
|
||||
{ "PARODD", 93, TTY_OP_BOOL }
|
||||
};
|
||||
|
||||
/* Miscellaneous other tty-related constants. */
|
||||
enum {
|
||||
/* The opcodes for ISPEED/OSPEED differ between SSH-1 and SSH-2. */
|
||||
SSH1_TTY_OP_ISPEED = 192,
|
||||
SSH1_TTY_OP_OSPEED = 193,
|
||||
SSH2_TTY_OP_ISPEED = 128,
|
||||
SSH2_TTY_OP_OSPEED = 129,
|
||||
|
||||
SSH_TTY_OP_END = 0
|
||||
};
|
||||
|
||||
for (i = 0; i < lenof(ssh_ttymodes); i++) {
|
||||
const struct ssh_ttymode *mode = ssh_ttymodes + i;
|
||||
const char *sval = conf_get_str_str(conf, CONF_ttymodes, mode->mode);
|
||||
char *to_free = NULL;
|
||||
|
||||
/* Every mode known to the current version of the code should be
|
||||
* mentioned; this was ensured when settings were loaded. */
|
||||
|
||||
/*
|
||||
* sval[0] can be
|
||||
* - 'V', indicating that an explicit value follows it;
|
||||
* - 'A', indicating that we should pass the value through from
|
||||
* the local environment via get_ttymode; or
|
||||
* - 'N', indicating that we should explicitly not send this
|
||||
* mode.
|
||||
*/
|
||||
if (sval[0] == 'A') {
|
||||
sval = to_free = get_ttymode(frontend, mode->mode);
|
||||
} else if (sval[0] == 'V') {
|
||||
sval++; /* skip the 'V' */
|
||||
} else {
|
||||
/* else 'N', or something from the future we don't understand */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sval) {
|
||||
/*
|
||||
* Parse the string representation of the tty mode
|
||||
* into the integer value it will take on the wire.
|
||||
*/
|
||||
unsigned ival = 0;
|
||||
|
||||
switch (mode->type) {
|
||||
case TTY_OP_CHAR:
|
||||
if (*sval) {
|
||||
char *next = NULL;
|
||||
/* We know ctrlparse won't write to the string, so
|
||||
* casting away const is ugly but allowable. */
|
||||
ival = ctrlparse((char *)sval, &next);
|
||||
if (!next)
|
||||
ival = sval[0];
|
||||
} else {
|
||||
ival = 255; /* special value meaning "don't set" */
|
||||
}
|
||||
break;
|
||||
case TTY_OP_BOOL:
|
||||
if (stricmp(sval, "yes") == 0 ||
|
||||
stricmp(sval, "on") == 0 ||
|
||||
stricmp(sval, "true") == 0 ||
|
||||
stricmp(sval, "+") == 0)
|
||||
ival = 1; /* true */
|
||||
else if (stricmp(sval, "no") == 0 ||
|
||||
stricmp(sval, "off") == 0 ||
|
||||
stricmp(sval, "false") == 0 ||
|
||||
stricmp(sval, "-") == 0)
|
||||
ival = 0; /* false */
|
||||
else
|
||||
ival = (atoi(sval) != 0);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Bad mode->type");
|
||||
}
|
||||
|
||||
/*
|
||||
* And write it into the output packet. The parameter
|
||||
* value is formatted as a byte in SSH-1, but a uint32
|
||||
* in SSH-2.
|
||||
*/
|
||||
put_byte(bs, mode->opcode);
|
||||
if (ssh_version == 1)
|
||||
put_byte(bs, ival);
|
||||
else
|
||||
put_uint32(bs, ival);
|
||||
}
|
||||
|
||||
sfree(to_free);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finish off with the terminal speeds (which are formatted as
|
||||
* uint32 in both protocol versions) and the end marker.
|
||||
*/
|
||||
put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_ISPEED : SSH2_TTY_OP_ISPEED);
|
||||
put_uint32(bs, ispeed);
|
||||
put_byte(bs, ssh_version == 1 ? SSH1_TTY_OP_OSPEED : SSH2_TTY_OP_OSPEED);
|
||||
put_uint32(bs, ospeed);
|
||||
put_byte(bs, SSH_TTY_OP_END);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user