X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c6ccd5c22a25aca610b0120b3eec1e6efd1aab97..6226c9390d23d6868edde63b9568891cd88631cc:/unix/uxplink.c diff --git a/unix/uxplink.c b/unix/uxplink.c index 69816dcc..1daafe4b 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -13,7 +13,10 @@ #include #include #include +#include +#ifndef HAVE_NO_SYS_SELECT_H #include +#endif #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" @@ -135,9 +138,11 @@ void ldisc_update(void *frontend, int echo, int edit) if (edit) { mode.c_iflag |= ICRNL; mode.c_lflag |= ISIG | ICANON; + mode.c_oflag |= OPOST; } else { mode.c_iflag &= ~ICRNL; mode.c_lflag &= ~(ISIG | ICANON); + mode.c_oflag &= ~OPOST; /* Solaris sets these to unhelpful values */ mode.c_cc[VMIN] = 1; mode.c_cc[VTIME] = 0; @@ -147,6 +152,17 @@ void ldisc_update(void *frontend, int echo, int edit) mode.c_iflag &= ~IXON; mode.c_iflag &= ~IXOFF; } + /* + * Mark parity errors and (more important) BREAK on input. This + * is more complex than it need be because POSIX-2001 suggests + * that escaping of valid 0xff in the input stream is dependent on + * IGNPAR being clear even though marking of BREAK isn't. NetBSD + * 2.0 goes one worse and makes it dependent on INPCK too. We + * deal with this by forcing these flags into a useful state and + * then faking the state in which we found them in from_tty() if + * we get passed a parity or framing error. + */ + mode.c_iflag = (mode.c_iflag | INPCK | PARMRK) & ~IGNPAR; tcsetattr(0, TCSANOW, &mode); } @@ -268,6 +284,22 @@ char *get_ttymode(void *frontend, const char *mode) #if defined(IXANY) GET_BOOL("IXANY", IXANY, c_iflag, ); #endif + /* Configuration of OPOST */ +#if defined(OLCUC) + GET_BOOL("OLCUC", OLCUC, c_oflag, ); +#endif +#if defined(ONLCR) + GET_BOOL("ONLCR", ONLCR, c_oflag, ); +#endif +#if defined(OCRNL) + GET_BOOL("OCRNL", OCRNL, c_oflag, ); +#endif +#if defined(ONOCR) + GET_BOOL("ONOCR", ONOCR, c_oflag, ); +#endif +#if defined(ONLRET) + GET_BOOL("ONLRET", ONLRET, c_oflag, ); +#endif /* * Modes that want to be set in only one place, and that we have @@ -288,6 +320,9 @@ char *get_ttymode(void *frontend, const char *mode) #if defined(IXOFF) GET_BOOL("IXOFF", IXOFF, c_iflag, ); #endif +#if defined(OPOST) + GET_BOOL("OPOST", OPOST, c_oflag, ); +#endif /* * We do not propagate the following modes: @@ -296,12 +331,12 @@ char *get_ttymode(void *frontend, const char *mode) * IGNPAR PARMRK INPCK CS7 CS8 PARENB PARODD * - Things that want to be enabled in one place that we don't * squash locally. - * IUCLC OLCUC + * IUCLC * - Status bits. * PENDIN * - Things I don't know what to do with. (FIXME) - * ISTRIP IMAXBEL NOFLSH TOSTOP IEXTEN OPOST - * INLCR IGNCR ICRNL ONLCR OCRNL ONOCR ONLRET + * ISTRIP IMAXBEL NOFLSH TOSTOP IEXTEN + * INLCR IGNCR ICRNL */ #undef GET_CHAR @@ -359,6 +394,91 @@ int from_backend(void *frontend_handle, int is_stderr, return osize + esize; } +int from_backend_untrusted(void *frontend_handle, const char *data, int len) +{ + /* + * No "untrusted" output should get here (the way the code is + * currently, it's all diverted by FLAG_STDERR). + */ + assert(!"Unexpected call to from_backend_untrusted()"); + return 0; /* not reached */ +} + +int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) +{ + int ret; + ret = cmdline_get_passwd_input(p, in, inlen); + if (ret == -1) + ret = console_get_userpass_input(p, in, inlen); + return ret; +} + +/* + * Handle data from a local tty in PARMRK format. + */ +static void from_tty(void *buf, unsigned len) +{ + char *p, *q, *end; + static enum {NORMAL, FF, FF00} state = NORMAL; + + p = buf; end = buf + len; + while (p < end) { + switch (state) { + case NORMAL: + if (*p == '\xff') { + p++; + state = FF; + } else { + q = memchr(p, '\xff', end - p); + if (q == NULL) q = end; + back->send(backhandle, p, q - p); + p = q; + } + break; + case FF: + if (*p == '\xff') { + back->send(backhandle, p, 1); + p++; + state = NORMAL; + } else if (*p == '\0') { + p++; + state = FF00; + } else abort(); + break; + case FF00: + if (*p == '\0') { + back->special(backhandle, TS_BRK); + } else { + /* + * Pretend that PARMRK wasn't set. This involves + * faking what INPCK and IGNPAR would have done if + * we hadn't overridden them. Unfortunately, we + * can't do this entirely correctly because INPCK + * distinguishes between framing and parity + * errors, but PARMRK format represents both in + * the same way. We assume that parity errors are + * more common than framing errors, and hence + * treat all input errors as being subject to + * INPCK. + */ + if (orig_termios.c_iflag & INPCK) { + /* If IGNPAR is set, we throw away the character. */ + if (!(orig_termios.c_iflag & IGNPAR)) { + /* PE/FE get passed on as NUL. */ + *p = 0; + back->send(backhandle, p, 1); + } + } else { + /* INPCK not set. Assume we got a parity error. */ + back->send(backhandle, p, 1); + } + } + p++; + state = NORMAL; + } + } +} + int signalpipe[2]; void sigwinch(int signum) @@ -407,6 +527,8 @@ static void usage(void) printf(" -4 -6 force use of IPv4 or IPv6\n"); printf(" -C enable compression\n"); printf(" -i key private key file for authentication\n"); + printf(" -noagent disable use of Pageant\n"); + printf(" -agent enable use of Pageant\n"); printf(" -m file read remote command(s) from file\n"); printf(" -s remote command is an SSH subsystem (SSH-2 only)\n"); printf(" -N don't start a shell/command (SSH-2 only)\n"); @@ -433,8 +555,6 @@ int main(int argc, char **argv) void *ldisc, *logctx; long now; - ssh_get_line = console_get_line; - fdlist = NULL; fdcount = fdsize = 0; /* @@ -510,8 +630,6 @@ int main(int argc, char **argv) if (!*cfg.host) { char *q = p; - do_defaults(NULL, &cfg); - /* * If the hostname starts with "telnet:", set the * protocol to Telnet and process the string as a @@ -781,7 +899,7 @@ int main(int argc, char **argv) FD_SET_MAX(signalpipe[0], maxfd, rset); if (connopen && !sending && - back->socket(backhandle) != NULL && + back->connected(backhandle) && back->sendok(backhandle) && back->sendbuffer(backhandle) < MAX_STDIN_BACKLOG) { /* If we're OK to send, then try to read from stdin. */ @@ -896,7 +1014,7 @@ int main(int argc, char **argv) char buf[4096]; int ret; - if (connopen && back->socket(backhandle) != NULL) { + if (connopen && back->connected(backhandle)) { ret = read(0, buf, sizeof(buf)); if (ret < 0) { perror("stdin: read"); @@ -905,7 +1023,10 @@ int main(int argc, char **argv) back->special(backhandle, TS_EOF); sending = FALSE; /* send nothing further after this */ } else { - back->send(backhandle, buf, ret); + if (local_tty) + from_tty(buf, ret); + else + back->send(backhandle, buf, ret); } } } @@ -918,7 +1039,7 @@ int main(int argc, char **argv) try_output(1); } - if ((!connopen || back->socket(backhandle) == NULL) && + if ((!connopen || !back->connected(backhandle)) && bufchain_size(&stdout_data) == 0 && bufchain_size(&stderr_data) == 0) break; /* we closed the connection */