static void log_option(Telnet telnet, char *sender, int cmd, int option) { char *buf; /* * The strange-looking "<?""?>" below is there to avoid a * trigraph - a double question mark followed by > maps to a * closing brace character! */ buf = dupprintf("%s:\t%s %s", sender, (cmd == WILL ? "WILL" : cmd == WONT ? "WONT" : cmd == DO ? "DO" : cmd == DONT ? "DONT" : "<?""?>"), telopt(option)); logevent(telnet->frontend, buf); sfree(buf); }
void term_init() { tel_init(); telopt(1, WILL, TELOPT_SGA); telopt(1, DO, TELOPT_SGA); telopt(1, WILL, TELOPT_BINARY); telopt(1, DO, TELOPT_BINARY); telopt(1, WILL, TELOPT_ECHO); telopt(1, DO, TELOPT_WINCH); }
static void process_subneg(Telnet telnet) { unsigned char b[2048], *p, *q; int var, value, n; char *e; switch (telnet->sb_opt) { case TELOPT_TSPEED: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED; b[3] = TELQUAL_IS; strcpy((char *)(b + 4), telnet->cfg.termspeed); n = 4 + strlen(telnet->cfg.termspeed); b[n] = IAC; b[n + 1] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 2); logevent(telnet->frontend, "server:\tSB TSPEED SEND"); logbuf = dupprintf("client:\tSB TSPEED IS %s", telnet->cfg.termspeed); logevent(telnet->frontend, logbuf); sfree(logbuf); } else logevent(telnet->frontend, "server:\tSB TSPEED <something weird>"); break; case TELOPT_TTYPE: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE; b[3] = TELQUAL_IS; for (n = 0; telnet->cfg.termtype[n]; n++) b[n + 4] = (telnet->cfg.termtype[n] >= 'a' && telnet->cfg.termtype[n] <= 'z' ? telnet->cfg.termtype[n] + 'A' - 'a' : telnet->cfg.termtype[n]); b[n + 4] = IAC; b[n + 5] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 6); b[n + 4] = 0; logevent(telnet->frontend, "server:\tSB TTYPE SEND"); logbuf = dupprintf("client:\tSB TTYPE IS %s", b + 4); logevent(telnet->frontend, logbuf); sfree(logbuf); } else logevent(telnet->frontend, "server:\tSB TTYPE <something weird>\r\n"); break; case TELOPT_OLD_ENVIRON: case TELOPT_NEW_ENVIRON: p = telnet->sb_buf; q = p + telnet->sb_len; if (p < q && *p == TELQUAL_SEND) { char *logbuf; p++; logbuf = dupprintf("server:\tSB %s SEND", telopt(telnet->sb_opt)); logevent(telnet->frontend, logbuf); sfree(logbuf); if (telnet->sb_opt == TELOPT_OLD_ENVIRON) { if (telnet->cfg.rfc_environ) { value = RFC_VALUE; var = RFC_VAR; } else { value = BSD_VALUE; var = BSD_VAR; } /* * Try to guess the sense of VAR and VALUE. */ while (p < q) { if (*p == RFC_VAR) { value = RFC_VALUE; var = RFC_VAR; } else if (*p == BSD_VAR) { value = BSD_VALUE; var = BSD_VAR; } p++; } } else { /* * With NEW_ENVIRON, the sense of VAR and VALUE * isn't in doubt. */ value = RFC_VALUE; var = RFC_VAR; } b[0] = IAC; b[1] = SB; b[2] = telnet->sb_opt; b[3] = TELQUAL_IS; n = 4; e = telnet->cfg.environmt; while (*e) { b[n++] = var; while (*e && *e != '\t') b[n++] = *e++; if (*e == '\t') e++; b[n++] = value; while (*e) b[n++] = *e++; e++; } if (*telnet->cfg.username) { b[n++] = var; b[n++] = 'U'; b[n++] = 'S'; b[n++] = 'E'; b[n++] = 'R'; b[n++] = value; e = telnet->cfg.username; while (*e) b[n++] = *e++; } b[n++] = IAC; b[n++] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n); logbuf = dupprintf("client:\tSB %s IS %s%s%s%s", telopt(telnet->sb_opt), *telnet->cfg.username ? "USER="******"", telnet->cfg.username, *telnet->cfg.username ? " " : "", n == 6 ? "<nothing>" : (*telnet->cfg.environmt ? "<stuff>" : "")); logevent(telnet->frontend, logbuf); sfree(logbuf); } break; } }
static void handlenetinput(int len) { int i; int cstart = 0; for (i = 0; i < len; i++) { byte c = G.buf[i]; if (G.telstate == 0) /* most of the time state == 0 */ { if (c == IAC) { cstart = i; G.telstate = TS_IAC; } } else switch (G.telstate) { case TS_0: if (c == IAC) G.telstate = TS_IAC; else G.buf[cstart++] = c; break; case TS_IAC: if (c == IAC) /* IAC IAC -> 0xFF */ { G.buf[cstart++] = c; G.telstate = TS_0; break; } /* else */ switch (c) { case SB: G.telstate = TS_SUB1; break; case DO: case DONT: case WILL: case WONT: G.telwish = c; G.telstate = TS_OPT; break; default: G.telstate = TS_0; /* DATA MARK must be added later */ } break; case TS_OPT: /* WILL, WONT, DO, DONT */ telopt(c); G.telstate = TS_0; break; case TS_SUB1: /* Subnegotiation */ case TS_SUB2: /* Subnegotiation */ if (subneg(c)) G.telstate = TS_0; break; } } if (G.telstate) { if (G.iaclen) iacflush(); if (G.telstate == TS_0) G.telstate = 0; len = cstart; } if (len) write(1, G.buf, len); }
static void handle_net_input(int len) { int i; int cstart = 0; for (i = 0; i < len; i++) { byte c = G.buf[i]; if (G.telstate == TS_NORMAL) { /* most typical state */ if (c == IAC) { cstart = i; G.telstate = TS_IAC; } else if (c == '\r') { cstart = i + 1; G.telstate = TS_CR; } /* No IACs were seen so far, no need to copy * bytes within G.buf: */ continue; } switch (G.telstate) { case TS_CR: /* Prev char was CR. If cur one is NUL, ignore it. * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling. */ G.telstate = TS_COPY; if (c == '\0') break; /* else: fall through - need to handle CR IAC ... properly */ case TS_COPY: /* Prev char was ordinary */ /* Similar to NORMAL, but in TS_COPY we need to copy bytes */ if (c == IAC) G.telstate = TS_IAC; else G.buf[cstart++] = c; if (c == '\r') G.telstate = TS_CR; break; case TS_IAC: /* Prev char was IAC */ if (c == IAC) { /* IAC IAC -> one IAC */ G.buf[cstart++] = c; G.telstate = TS_COPY; break; } /* else */ switch (c) { case SB: G.telstate = TS_SUB1; break; case DO: case DONT: case WILL: case WONT: G.telwish = c; G.telstate = TS_OPT; break; /* DATA MARK must be added later */ default: G.telstate = TS_COPY; } break; case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */ telopt(c); G.telstate = TS_COPY; break; case TS_SUB1: /* Subnegotiation */ case TS_SUB2: /* Subnegotiation */ subneg(c); /* can change G.telstate */ break; } } if (G.telstate != TS_NORMAL) { /* We had some IACs, or CR */ if (G.iaclen) iac_flush(); if (G.telstate == TS_COPY) /* we aren't in the middle of IAC */ G.telstate = TS_NORMAL; len = cstart; } if (len) full_write(STDOUT_FILENO, G.buf, len); }