void send_dont(int c, int init) { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || my_want_state_is_dont(c)) return; set_my_want_state_dont(c); do_dont_resp[c]++; } if (telnetport < 0) return; NET2ADD(IAC, DONT); NETADD(c); printoption("SENT", DONT, c); }
static void send_negotiation(struct connectdata *conn, int cmd, int option) { unsigned char buf[3]; ssize_t bytes_written; int err; struct SessionHandle *data = conn->data; buf[0] = CURL_IAC; buf[1] = (unsigned char)cmd; buf[2] = (unsigned char)option; bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3); if(bytes_written < 0) { err = SOCKERRNO; failf(data,"Sending data failed (%d)",err); } printoption(conn->data, "SENT", cmd, option); }
/* * The will/wont/do/dont state machines are based on Dave Borman's * Telnet option processing state machine. * * These correspond to the following states: * my_state = the last negotiated state * want_state = what I want the state to go to * want_resp = how many requests I have sent * All state defaults are negative, and resp defaults to 0. * * When initiating a request to change state to new_state: * * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { * do nothing; * } else { * want_state = new_state; * send new_state; * want_resp++; * } * * When receiving new_state: * * if (want_resp) { * want_resp--; * if (want_resp && (new_state == my_state)) * want_resp--; * } * if ((want_resp == 0) && (new_state != want_state)) { * if (ok_to_switch_to new_state) * want_state = new_state; * else * want_resp++; * send want_state; * } * my_state = new_state; * * Note that new_state is implied in these functions by the function itself. * will and do imply positive new_state, wont and dont imply negative. * * Finally, there is one catch. If we send a negative response to a * positive request, my_state will be the positive while want_state will * remain negative. my_state will revert to negative when the negative * acknowlegment arrives from the peer. Thus, my_state generally tells * us not only the last negotiated state, but also tells us what the peer * wants to be doing as well. It is important to understand this difference * as we may wish to be processing data streams based on our desired state * (want_state) or based on what the peer thinks the state is (my_state). * * This all works fine because if the peer sends a positive request, the data * that we receive prior to negative acknowlegment will probably be affected * by the positive state, and we can process it as such (if we can; if we * can't then it really doesn't matter). If it is that important, then the * peer probably should be buffering until this option state negotiation * is complete. * */ void send_do(int option, int init) { if (init) { if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || his_want_state_is_will(option)) return; /* * Special case for TELOPT_TM: We send a DO, but pretend * that we sent a DONT, so that we can send more DOs if * we want to. */ if (option == TELOPT_TM) set_his_want_state_wont(option); else set_his_want_state_will(option); do_dont_resp[option]++; } netoprintf((char *)doopt, option); DIAG(TD_OPTIONS, printoption("td: send do", option)); }
int telrcv(void) { int c; int scc; unsigned char *sbp; int count; int returnValue = 0; scc = 0; count = 0; while (TTYROOM() > 2) { if (scc == 0) { if (count) { ring_consumed(&netiring, count); returnValue = 1; count = 0; } sbp = netiring.consume; scc = ring_full_consecutive(&netiring); if (scc == 0) { /* No more data coming in */ break; } } c = *sbp++ & 0xff, scc--; count++; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ switch (telrcv_state) { case TS_CR: telrcv_state = TS_DATA; if (c == '\0') { break; /* Ignore \0 after CR */ } else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { TTYADD(c); break; } /* Else, fall through */ case TS_DATA: if (c == IAC) { telrcv_state = TS_IAC; break; } /* * The 'crmod' hack (see following) is needed * since we can't * set CRMOD on output only. * Machines like MULTICS like to send \r without * \n; since we must turn off CRMOD to get proper * input, the mapping is done here (sigh). */ if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { if (scc > 0) { c = *sbp&0xff; #ifdef ENCRYPTION if (decrypt_input) c = (*decrypt_input)(c); #endif /* ENCRYPTION */ if (c == 0) { sbp++, scc--; count++; /* a "true" CR */ TTYADD('\r'); } else if (my_want_state_is_dont(TELOPT_ECHO) && (c == '\n')) { sbp++, scc--; count++; TTYADD('\n'); } else { #ifdef ENCRYPTION if (decrypt_input) (*decrypt_input)(-1); #endif /* ENCRYPTION */ TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { telrcv_state = TS_CR; TTYADD('\r'); if (crmod) { TTYADD('\n'); } } } else { TTYADD(c); } continue; case TS_IAC: process_iac: switch (c) { case WILL: telrcv_state = TS_WILL; continue; case WONT: telrcv_state = TS_WONT; continue; case DO: telrcv_state = TS_DO; continue; case DONT: telrcv_state = TS_DONT; continue; case DM: /* * We may have missed an urgent notification, * so make sure we flush whatever is in the * buffer currently. */ printoption("RCVD", IAC, DM); SYNCHing = 1; (void) ttyflush(1); SYNCHing = stilloob(); settimer(gotDM); break; case SB: SB_CLEAR(); telrcv_state = TS_SB; continue; case IAC: TTYADD(IAC); break; case NOP: case GA: default: printoption("RCVD", IAC, c); break; } telrcv_state = TS_DATA; continue; case TS_WILL: printoption("RCVD", WILL, c); willoption(c); telrcv_state = TS_DATA; continue; case TS_WONT: printoption("RCVD", WONT, c); wontoption(c); telrcv_state = TS_DATA; continue; case TS_DO: printoption("RCVD", DO, c); dooption(c); if (c == TELOPT_NAWS) { sendnaws(); } else if (c == TELOPT_LFLOW) { localflow = 1; setcommandmode(); setconnmode(0); } telrcv_state = TS_DATA; continue; case TS_DONT: printoption("RCVD", DONT, c); dontoption(c); flushline = 1; setconnmode(0); /* set new tty mode (maybe) */ telrcv_state = TS_DATA; continue; case TS_SB: if (c == IAC) { telrcv_state = TS_SE; } else { SB_ACCUM(c); } continue; case TS_SE: if (c != SE) { if (c != IAC) { /* * This is an error. We only expect to get * "IAC IAC" or "IAC SE". Several things may * have happend. An IAC was not doubled, the * IAC SE was left off, or another option got * inserted into the suboption are all possibilities. * If we assume that the IAC was not doubled, * and really the IAC SE was left off, we could * get into an infinate loop here. So, instead, * we terminate the suboption, and process the * partial suboption if we can. */ SB_ACCUM(IAC); SB_ACCUM(c); subpointer -= 2; SB_TERM(); printoption("In SUBOPTION processing, RCVD", IAC, c); suboption(); /* handle sub-option */ telrcv_state = TS_IAC; goto process_iac; } SB_ACCUM(c); telrcv_state = TS_SB; } else { SB_ACCUM(IAC); SB_ACCUM(SE); subpointer -= 2; SB_TERM(); suboption(); /* handle sub-option */ telrcv_state = TS_DATA; } } } if (count) ring_consumed(&netiring, count); return returnValue||count; }
static void telrcv(struct connectdata *conn, unsigned char *inbuf, /* Data received from socket */ ssize_t count) /* Number of bytes received */ { unsigned char c; int in = 0; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet; while(count--) { c = inbuf[in++]; switch (tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if (c == '\0') { break; /* Ignore \0 after CR */ } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); continue; case CURL_TS_DATA: if (c == CURL_IAC) { tn->telrcv_state = CURL_TS_IAC; break; } else if(c == '\r') { tn->telrcv_state = CURL_TS_CR; } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); continue; case CURL_TS_IAC: process_iac: switch (c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; continue; case CURL_WONT: tn->telrcv_state = CURL_TS_WONT; continue; case CURL_DO: tn->telrcv_state = CURL_TS_DO; continue; case CURL_DONT: tn->telrcv_state = CURL_TS_DONT; continue; case CURL_SB: CURL_SB_CLEAR(tn); tn->telrcv_state = CURL_TS_SB; continue; case CURL_IAC: Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1); break; case CURL_DM: case CURL_NOP: case CURL_GA: default: printoption(data, "RCVD", CURL_IAC, c); break; } tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_WILL: printoption(data, "RCVD", CURL_WILL, c); tn->please_negotiate = 1; rec_will(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_WONT: printoption(data, "RCVD", CURL_WONT, c); tn->please_negotiate = 1; rec_wont(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_DO: printoption(data, "RCVD", CURL_DO, c); tn->please_negotiate = 1; rec_do(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_DONT: printoption(data, "RCVD", CURL_DONT, c); tn->please_negotiate = 1; rec_dont(conn, c); tn->telrcv_state = CURL_TS_DATA; continue; case CURL_TS_SB: if (c == CURL_IAC) { tn->telrcv_state = CURL_TS_SE; } else { CURL_SB_ACCUM(tn,c); } continue; case CURL_TS_SE: if (c != CURL_SE) { if (c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". * Several things may have happend. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get * into an infinate loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, c); tn->subpointer -= 2; CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_IAC; goto process_iac; } CURL_SB_ACCUM(tn,c); tn->telrcv_state = CURL_TS_SB; } else { CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_DATA; } break; } } }
void sendayt(void) { NET2ADD(IAC, AYT); printoption("SENT", IAC, AYT); }
void sendeof(void) { NET2ADD(IAC, xEOF); printoption("SENT", IAC, xEOF); }
void xmitEC(void) { NET2ADD(IAC, EC); printoption("SENT", IAC, EC); }
void xmitEL(void) { NET2ADD(IAC, EL); printoption("SENT", IAC, EL); }
static CURLcode telrcv(struct connectdata *conn, const unsigned char *inbuf, /* Data received from socket */ ssize_t count) /* Number of bytes received */ { unsigned char c; CURLcode result; int in = 0; int startwrite=-1; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ if(startwrite >= 0) { \ result = Curl_client_write(conn, \ CLIENTWRITE_BODY, \ (char *)&inbuf[startwrite], \ in-startwrite); \ if(result) \ return result; \ } \ startwrite = -1 #define writebyte() \ if(startwrite < 0) \ startwrite = in #define bufferflush() startskipping() while(count--) { c = inbuf[in]; switch (tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if(c == '\0') { startskipping(); break; /* Ignore \0 after CR */ } writebyte(); break; case CURL_TS_DATA: if(c == CURL_IAC) { tn->telrcv_state = CURL_TS_IAC; startskipping(); break; } else if(c == '\r') tn->telrcv_state = CURL_TS_CR; writebyte(); break; case CURL_TS_IAC: process_iac: DEBUGASSERT(startwrite < 0); switch (c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; break; case CURL_WONT: tn->telrcv_state = CURL_TS_WONT; break; case CURL_DO: tn->telrcv_state = CURL_TS_DO; break; case CURL_DONT: tn->telrcv_state = CURL_TS_DONT; break; case CURL_SB: CURL_SB_CLEAR(tn); tn->telrcv_state = CURL_TS_SB; break; case CURL_IAC: tn->telrcv_state = CURL_TS_DATA; writebyte(); break; case CURL_DM: case CURL_NOP: case CURL_GA: default: tn->telrcv_state = CURL_TS_DATA; printoption(data, "RCVD", CURL_IAC, c); break; } break; case CURL_TS_WILL: printoption(data, "RCVD", CURL_WILL, c); tn->please_negotiate = 1; rec_will(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_WONT: printoption(data, "RCVD", CURL_WONT, c); tn->please_negotiate = 1; rec_wont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DO: printoption(data, "RCVD", CURL_DO, c); tn->please_negotiate = 1; rec_do(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_DONT: printoption(data, "RCVD", CURL_DONT, c); tn->please_negotiate = 1; rec_dont(conn, c); tn->telrcv_state = CURL_TS_DATA; break; case CURL_TS_SB: if(c == CURL_IAC) tn->telrcv_state = CURL_TS_SE; else CURL_SB_ACCUM(tn, c); break; case CURL_TS_SE: if(c != CURL_SE) { if(c != CURL_IAC) { /* * This is an error. We only expect to get "IAC IAC" or "IAC SE". * Several things may have happened. An IAC was not doubled, the * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get * into an infinate loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, c); tn->subpointer -= 2; CURL_SB_TERM(tn); printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_IAC; goto process_iac; } CURL_SB_ACCUM(tn, c); tn->telrcv_state = CURL_TS_SB; } else { CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SE); tn->subpointer -= 2; CURL_SB_TERM(tn); suboption(conn); /* handle sub-option */ tn->telrcv_state = CURL_TS_DATA; } break; } ++in; } bufferflush(); return CURLE_OK; }
void telrcv() { register int c; static int state = TS_DATA; #if defined(CRAY2) && defined(UNICOS5) char *opfrontp = pfrontp; #endif while (ncc > 0) { if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) break; c = *netip++ & 0377, ncc--; switch (state) { case TS_CR: state = TS_DATA; /* Strip off \n or \0 after a \r */ if ((c == 0) || (c == '\n')) { break; } /* FALL THROUGH */ case TS_DATA: if (c == IAC) { state = TS_IAC; break; } /* * We now map \r\n ==> \r for pragmatic reasons. * Many client implementations send \r\n when * the user hits the CarriageReturn key. * * We USED to map \r\n ==> \n, since \r\n says * that we want to be in column 1 of the next * printable line, and \n is the standard * unix way of saying that (\r is only good * if CRMOD is set, which it normally is). */ if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { int nc = *netip; #ifdef LINEMODE /* * If we are operating in linemode, * convert to local end-of-line. */ if (linemode && (ncc > 0) && (('\n' == nc) || ((0 == nc) && tty_iscrnl())) ) { netip++; ncc--; c = '\n'; } else #endif { state = TS_CR; } } *pfrontp++ = c; break; case TS_IAC: gotiac: switch (c) { /* * Send the process on the pty side an * interrupt. Do this with a NULL or * interrupt char; depending on the tty mode. */ case IP: DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); interrupt(); break; case BREAK: DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); sendbrk(); break; /* * Are You There? */ case AYT: DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); recv_ayt(); break; /* * Abort Output */ case AO: { DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); ptyflush(); /* half-hearted */ init_termbuf(); if (slctab[SLC_AO].sptr && *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { *pfrontp++ = (unsigned char)*slctab[SLC_AO].sptr; } netclear(); /* clear buffer back */ *nfrontp++ = IAC; *nfrontp++ = DM; neturg = nfrontp-1; /* off by one XXX */ DIAG(TD_OPTIONS, printoption("td: send IAC", DM)); break; } /* * Erase Character and * Erase Line */ case EC: case EL: { cc_t ch; DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); ptyflush(); /* half-hearted */ init_termbuf(); if (c == EC) ch = *slctab[SLC_EC].sptr; else ch = *slctab[SLC_EL].sptr; if (ch != (cc_t)(_POSIX_VDISABLE)) *pfrontp++ = (unsigned char)ch; break; } /* * Check for urgent data... */ case DM: DIAG(TD_OPTIONS, printoption("td: recv IAC", c)); SYNCHing = stilloob(net); settimer(gotDM); break; /* * Begin option subnegotiation... */ case SB: state = TS_SB; SB_CLEAR(); continue; case WILL: state = TS_WILL; continue; case WONT: state = TS_WONT; continue; case DO: state = TS_DO; continue; case DONT: state = TS_DONT; continue; case EOR: if (his_state_is_will(TELOPT_EOR)) doeof(); break; /* * Handle RFC 10xx Telnet linemode option additions * to command stream (EOF, SUSP, ABORT). */ case xEOF: doeof(); break; case SUSP: sendsusp(); break; case ABORT: sendbrk(); break; case IAC: *pfrontp++ = c; break; } state = TS_DATA; break; case TS_SB: if (c == IAC) { state = TS_SE; } else { SB_ACCUM(c); } break; case TS_SE: if (c != SE) { if (c != IAC) { /* * bad form of suboption negotiation. * handle it in such a way as to avoid * damage to local state. Parse * suboption buffer found so far, * then treat remaining stream as * another command sequence. */ /* for DIAGNOSTICS */ SB_ACCUM(IAC); SB_ACCUM(c); subpointer -= 2; SB_TERM(); suboption(); state = TS_IAC; goto gotiac; } SB_ACCUM(c); state = TS_SB; } else { /* for DIAGNOSTICS */ SB_ACCUM(IAC); SB_ACCUM(SE); subpointer -= 2; SB_TERM(); suboption(); /* handle sub-option */ state = TS_DATA; } break; case TS_WILL: willoption(c); state = TS_DATA; continue; case TS_WONT: wontoption(c); state = TS_DATA; continue; case TS_DO: dooption(c); state = TS_DATA; continue; case TS_DONT: dontoption(c); state = TS_DATA; continue; default: syslog(LOG_ERR, "telnetd: panic state=%d\n", state); printf("telnetd: panic state=%d\n", state); exit(1); } } #if defined(CRAY2) && defined(UNICOS5) if (!linemode) { char xptyobuf[BUFSIZ+NETSLOP]; char xbuf2[BUFSIZ]; register char *cp; int n = pfrontp - opfrontp, oc; memmove(xptyobuf, opfrontp, n); pfrontp = opfrontp; pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, xbuf2, &oc, BUFSIZ); for (cp = xbuf2; oc > 0; --oc) if ((*nfrontp++ = *cp++) == IAC) *nfrontp++ = IAC; } #endif /* defined(CRAY2) && defined(UNICOS5) */ } /* end of telrcv */
void dontoption(int option) { /* * Process client input. */ DIAG(TD_OPTIONS, printoption("td: recv dont", option)); if (will_wont_resp[option]) { will_wont_resp[option]--; if (will_wont_resp[option] && my_state_is_wont(option)) will_wont_resp[option]--; } if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { switch (option) { case TELOPT_BINARY: init_termbuf(); tty_binaryout(0); set_termbuf(); break; case TELOPT_ECHO: /* we should stop echoing */ #ifdef LINEMODE #ifdef KLUDGELINEMODE if (lmodetype == NO_LINEMODE) #else if (his_state_is_wont(TELOPT_LINEMODE)) #endif #endif { init_termbuf(); tty_setecho(0); set_termbuf(); } break; case TELOPT_SGA: #if defined(LINEMODE) && defined(KLUDGELINEMODE) /* * If kludge linemode is in use, then we * must process an incoming do SGA for * linemode purposes. */ if (lmodetype == KLUDGE_LINEMODE) { /* * The client is asking us to turn * linemode on. */ clientstat(TELOPT_LINEMODE, WILL, 0); /* * If we did not turn line mode on, * then what do we say? Will SGA? * This violates design of telnet. * Gross. Very Gross. */ } break; #else set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); set_my_state_wont(option); if (turn_on_sga ^= 1) send_will(option,1); return; #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ default: break; } set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); } set_my_state_wont(option); }
void dooption(int option) { int changeok = 0; /* * Process client input. */ DIAG(TD_OPTIONS, printoption("td: recv do", option)); if (will_wont_resp[option]) { will_wont_resp[option]--; if (will_wont_resp[option] && my_state_is_will(option)) will_wont_resp[option]--; } if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { switch (option) { case TELOPT_ECHO: #ifdef LINEMODE #ifdef KLUDGELINEMODE if (lmodetype == NO_LINEMODE) #else if (his_state_is_wont(TELOPT_LINEMODE)) #endif #endif { init_termbuf(); tty_setecho(1); set_termbuf(); } changeok++; break; case TELOPT_BINARY: init_termbuf(); tty_binaryout(1); set_termbuf(); changeok++; break; case TELOPT_SGA: #if defined(LINEMODE) && defined(KLUDGELINEMODE) /* * If kludge linemode is in use, then we must * process an incoming do SGA for linemode * purposes. */ if (lmodetype == KLUDGE_LINEMODE) { /* * Receipt of "do SGA" in kludge * linemode is the peer asking us to * turn off linemode. Make note of * the request. */ clientstat(TELOPT_LINEMODE, WONT, 0); /* * If linemode did not get turned off * then don't tell peer that we did. * Breaking here forces a wont SGA to * be returned. */ if (linemode) break; } #else turn_on_sga = 0; #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ changeok++; break; case TELOPT_STATUS: changeok++; break; case TELOPT_TM: /* * Special case for TM. We send a WILL, but * pretend we sent a WONT. */ send_will(option, 0); set_my_want_state_wont(option); set_my_state_wont(option); return; case TELOPT_LOGOUT: /* * When we get a LOGOUT option, respond * with a WILL LOGOUT, make sure that * it gets written out to the network, * and then just go away... */ set_my_want_state_will(TELOPT_LOGOUT); send_will(TELOPT_LOGOUT, 0); set_my_state_will(TELOPT_LOGOUT); (void)netflush(); cleanup(0); /* NOT REACHED */ break; #if defined(ENCRYPT) case TELOPT_ENCRYPT: changeok++; break; #endif case TELOPT_LINEMODE: case TELOPT_TTYPE: case TELOPT_NAWS: case TELOPT_TSPEED: case TELOPT_LFLOW: case TELOPT_XDISPLOC: case TELOPT_ENVIRON: default: break; } if (changeok) { set_my_want_state_will(option); send_will(option, 0); } else { will_wont_resp[option]++; send_wont(option, 0); } } set_my_state_will(option); }
void wontoption(int option) { /* * Process client input. */ DIAG(TD_OPTIONS, printoption("td: recv wont", option)); if (do_dont_resp[option]) { do_dont_resp[option]--; if (do_dont_resp[option] && his_state_is_wont(option)) do_dont_resp[option]--; } if (do_dont_resp[option] == 0) { if (his_want_state_is_will(option)) { /* it is always ok to change to negative state */ switch (option) { case TELOPT_ECHO: not42 = 1; /* doesn't seem to be a 4.2 system */ break; case TELOPT_BINARY: init_termbuf(); tty_binaryin(0); set_termbuf(); break; #ifdef LINEMODE case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE /* * If real linemode is supported, then client is * asking to turn linemode off. */ if (lmodetype != REAL_LINEMODE) break; lmodetype = KLUDGE_LINEMODE; # endif /* KLUDGELINEMODE */ clientstat(TELOPT_LINEMODE, WONT, 0); break; #endif /* LINEMODE */ case TELOPT_TM: /* * If we get a WONT TM, and had sent a DO TM, * don't respond with a DONT TM, just leave it * as is. Short circut the state machine to * achive this. */ set_his_want_state_wont(TELOPT_TM); return; case TELOPT_LFLOW: /* * If we are not going to support flow control * option, then let peer know that we can't * change the flow control characters. */ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; break; #if defined(AUTHENTICATE) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif /* * For options that we might spin waiting for * sub-negotiation, if the client turns off the * option rather than responding to the request, * we have to treat it here as if we got a response * to the sub-negotiation, (by updating the timers) * so that we'll break out of the loop. */ case TELOPT_TTYPE: settimer(ttypesubopt); break; case TELOPT_TSPEED: settimer(tspeedsubopt); break; case TELOPT_XDISPLOC: settimer(xdisplocsubopt); break; case TELOPT_ENVIRON: settimer(environsubopt); break; default: break; } set_his_want_state_wont(option); if (his_state_is_will(option)) send_dont(option, 0); } else { switch (option) { case TELOPT_TM: #if defined(LINEMODE) && defined(KLUDGELINEMODE) if (lmodetype < REAL_LINEMODE) { lmodetype = NO_LINEMODE; clientstat(TELOPT_LINEMODE, WONT, 0); send_will(TELOPT_SGA, 1); send_will(TELOPT_ECHO, 1); } #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ break; #if defined(AUTHENTICATE) case TELOPT_AUTHENTICATION: auth_finished(0, AUTH_REJECT); break; #endif default: break; } } } } /* end of wontoption */
void willoption(int option) { int changeok = 0; void (*func)(void) = 0; /* * process input from peer. */ DIAG(TD_OPTIONS, printoption("td: recv will", option)); if (do_dont_resp[option]) { do_dont_resp[option]--; if (do_dont_resp[option] && his_state_is_will(option)) do_dont_resp[option]--; } if (do_dont_resp[option] == 0) { if (his_want_state_is_wont(option)) { switch (option) { case TELOPT_BINARY: init_termbuf(); tty_binaryin(1); set_termbuf(); changeok++; break; case TELOPT_ECHO: /* * See comments below for more info. */ not42 = 0; /* looks like a 4.2 system */ break; case TELOPT_TM: #if defined(LINEMODE) && defined(KLUDGELINEMODE) /* * This telnetd implementation does not really * support timing marks, it just uses them to * support the kludge linemode stuff. If we * receive a will or wont TM in response to our * do TM request that may have been sent to * determine kludge linemode support, process * it, otherwise TM should get a negative * response back. */ /* * Handle the linemode kludge stuff. * If we are not currently supporting any * linemode at all, then we assume that this * is the client telling us to use kludge * linemode in response to our query. Set the * linemode type that is to be supported, note * that the client wishes to use linemode, and * eat the will TM as though it never arrived. */ if (lmodetype < KLUDGE_LINEMODE) { lmodetype = KLUDGE_LINEMODE; clientstat(TELOPT_LINEMODE, WILL, 0); send_wont(TELOPT_SGA, 1); } #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ /* * We never respond to a WILL TM, and * we leave the state WONT. */ return; case TELOPT_LFLOW: /* * If we are going to support flow control * option, then don't worry peer that we can't * change the flow control characters. */ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; slctab[SLC_XON].defset.flag |= SLC_DEFAULT; slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; case TELOPT_TTYPE: case TELOPT_SGA: case TELOPT_NAWS: case TELOPT_TSPEED: case TELOPT_XDISPLOC: case TELOPT_ENVIRON: changeok++; break; #ifdef LINEMODE case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE /* * Note client's desire to use linemode. */ lmodetype = REAL_LINEMODE; #endif /* KLUDGELINEMODE */ func = doclientstat; changeok++; break; #endif /* LINEMODE */ #ifdef AUTHENTICATE case TELOPT_AUTHENTICATION: func = auth_request; changeok++; break; #endif #ifdef ENCRYPT case TELOPT_ENCRYPT: func = encrypt_send_support; changeok++; break; #endif default: break; } if (changeok) { set_his_want_state_will(option); send_do(option, 0); } else { do_dont_resp[option]++; send_dont(option, 0); } } else { /* * Option processing that should happen when * we receive conformation of a change in * state that we had requested. */ switch (option) { case TELOPT_ECHO: not42 = 0; /* looks like a 4.2 system */ /* * Egads, he responded "WILL ECHO". Turn * it off right now! */ send_dont(option, 1); /* * "WILL ECHO". Kludge upon kludge! * A 4.2 client is now echoing user input at * the tty. This is probably undesireable and * it should be stopped. The client will * respond WONT TM to the DO TM that we send to * check for kludge linemode. When the WONT TM * arrives, linemode will be turned off and a * change propogated to the pty. This change * will cause us to process the new pty state * in localstat(), which will notice that * linemode is off and send a WILL ECHO * so that we are properly in character mode and * all is well. */ break; #ifdef LINEMODE case TELOPT_LINEMODE: # ifdef KLUDGELINEMODE /* * Note client's desire to use linemode. */ lmodetype = REAL_LINEMODE; # endif /* KLUDGELINEMODE */ func = doclientstat; break; #endif /* LINEMODE */ #ifdef AUTHENTICATE case TELOPT_AUTHENTICATION: func = auth_request; break; #endif #ifdef ENCRYPT case TELOPT_ENCRYPT: func = encrypt_send_support; break; #endif } } } set_his_state_will(option); if (func) (*func)(); }