#include <termios.h>
#include <pwd.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
+#ifndef HAVE_NO_SYS_SELECT_H
#include <sys/select.h>
+#endif
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
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;
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);
}
#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
#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:
* 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
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)
void *ldisc, *logctx;
long now;
- ssh_get_line = console_get_line;
-
fdlist = NULL;
fdcount = fdsize = 0;
/*
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);
}
}
}