telnet.c revision 144231
129088Smarkm/* 229088Smarkm * Copyright (c) 1988, 1990, 1993 329088Smarkm * The Regents of the University of California. All rights reserved. 429088Smarkm * 529088Smarkm * Redistribution and use in source and binary forms, with or without 629088Smarkm * modification, are permitted provided that the following conditions 729088Smarkm * are met: 829088Smarkm * 1. Redistributions of source code must retain the above copyright 929088Smarkm * notice, this list of conditions and the following disclaimer. 1029088Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1129088Smarkm * notice, this list of conditions and the following disclaimer in the 1229088Smarkm * documentation and/or other materials provided with the distribution. 1329088Smarkm * 3. All advertising materials mentioning features or use of this software 1429088Smarkm * must display the following acknowledgement: 1529088Smarkm * This product includes software developed by the University of 1629088Smarkm * California, Berkeley and its contributors. 1729088Smarkm * 4. Neither the name of the University nor the names of its contributors 1829088Smarkm * may be used to endorse or promote products derived from this software 1929088Smarkm * without specific prior written permission. 2029088Smarkm * 2129088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2229088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2329088Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2429088Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2529088Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2629088Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2729088Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2829088Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2929088Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3029088Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3129088Smarkm * SUCH DAMAGE. 3229088Smarkm */ 3329088Smarkm 34114630Sobrien#if 0 3529088Smarkm#ifndef lint 3629181Smarkmstatic const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; 3763248Speter#endif 38114630Sobrien#endif 39114630Sobrien#include <sys/cdefs.h> 40114630Sobrien__FBSDID("$FreeBSD: head/contrib/telnet/telnet/telnet.c 144231 2005-03-28 14:45:12Z nectar $"); 4129088Smarkm 4229088Smarkm#include <sys/types.h> 4329088Smarkm 4429088Smarkm/* By the way, we need to include curses.h before telnet.h since, 4529088Smarkm * among other things, telnet.h #defines 'DO', which is a variable 4629088Smarkm * declared in curses.h. 4729088Smarkm */ 4829088Smarkm 4929088Smarkm#include <ctype.h> 5087139Smarkm#include <curses.h> 5187139Smarkm#include <signal.h> 5229181Smarkm#include <stdlib.h> 5387139Smarkm#include <term.h> 5429181Smarkm#include <unistd.h> 5587139Smarkm#include <arpa/telnet.h> 5629181Smarkm 5729088Smarkm#include "ring.h" 5829088Smarkm 5929088Smarkm#include "defines.h" 6029088Smarkm#include "externs.h" 6129088Smarkm#include "types.h" 6229088Smarkm#include "general.h" 6329088Smarkm 6487139Smarkm#ifdef AUTHENTICATION 6529181Smarkm#include <libtelnet/auth.h> 6629181Smarkm#endif 6787139Smarkm#ifdef ENCRYPTION 6829181Smarkm#include <libtelnet/encrypt.h> 6929181Smarkm#endif 7029181Smarkm#include <libtelnet/misc.h> 7129088Smarkm 7229088Smarkm#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) 7329088Smarkm 7429088Smarkmstatic unsigned char subbuffer[SUBBUFSIZE], 7529088Smarkm *subpointer, *subend; /* buffer for sub-options */ 7629088Smarkm#define SB_CLEAR() subpointer = subbuffer; 7729088Smarkm#define SB_TERM() { subend = subpointer; SB_CLEAR(); } 7829088Smarkm#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 7929088Smarkm *subpointer++ = (c); \ 8029088Smarkm } 8129088Smarkm 8229088Smarkm#define SB_GET() ((*subpointer++)&0xff) 8329088Smarkm#define SB_PEEK() ((*subpointer)&0xff) 8429088Smarkm#define SB_EOF() (subpointer >= subend) 8529088Smarkm#define SB_LEN() (subend - subpointer) 8629088Smarkm 8729088Smarkmchar options[256]; /* The combined options */ 8829088Smarkmchar do_dont_resp[256]; 8929088Smarkmchar will_wont_resp[256]; 9029088Smarkm 9129088Smarkmint 9229088Smarkm eight = 0, 9329088Smarkm autologin = 0, /* Autologin anyone? */ 9429088Smarkm skiprc = 0, 9529088Smarkm connected, 9629088Smarkm showoptions, 9729088Smarkm ISend, /* trying to send network data in */ 98114911Smarkm telnet_debug = 0, 9929088Smarkm crmod, 10029088Smarkm netdata, /* Print out network data flow */ 10129088Smarkm crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 10229088Smarkm telnetport, 10329088Smarkm SYNCHing, /* we are in TELNET SYNCH mode */ 10429088Smarkm flushout, /* flush output */ 10529088Smarkm autoflush = 0, /* flush output when interrupting? */ 10629088Smarkm autosynch, /* send interrupt characters with SYNCH? */ 10729088Smarkm localflow, /* we handle flow control locally */ 10829088Smarkm restartany, /* if flow control enabled, restart on any character */ 10929088Smarkm localchars, /* we recognize interrupt/quit */ 11029088Smarkm donelclchars, /* the user has set "localchars" */ 11129088Smarkm donebinarytoggle, /* the user has put us in binary */ 11229088Smarkm dontlecho, /* do we suppress local echoing right now? */ 11329181Smarkm globalmode, 11447973Sru doaddrlookup = 1, /* do a reverse address lookup? */ 11529181Smarkm clienteof = 0; 11629088Smarkm 11729088Smarkmchar *prompt = 0; 11881965Smarkm#ifdef ENCRYPTION 11976616Speterchar *line; /* hack around breakage in sra.c :-( !! */ 12081965Smarkm#endif 12129088Smarkm 12229088Smarkmcc_t escape; 12329088Smarkmcc_t rlogin; 12429088Smarkm#ifdef KLUDGELINEMODE 12529088Smarkmcc_t echoc; 12629088Smarkm#endif 12729088Smarkm 12829088Smarkm/* 12929088Smarkm * Telnet receiver states for fsm 13029088Smarkm */ 13129088Smarkm#define TS_DATA 0 13229088Smarkm#define TS_IAC 1 13329088Smarkm#define TS_WILL 2 13429088Smarkm#define TS_WONT 3 13529088Smarkm#define TS_DO 4 13629088Smarkm#define TS_DONT 5 13729088Smarkm#define TS_CR 6 13829088Smarkm#define TS_SB 7 /* sub-option collection */ 13929088Smarkm#define TS_SE 8 /* looking for sub-option end */ 14029088Smarkm 14129088Smarkmstatic int telrcv_state; 14229088Smarkm#ifdef OLD_ENVIRON 14329088Smarkmunsigned char telopt_environ = TELOPT_NEW_ENVIRON; 14429088Smarkm#else 14529088Smarkm# define telopt_environ TELOPT_NEW_ENVIRON 14629088Smarkm#endif 14729088Smarkm 14887139Smarkmjmp_buf toplevel; 14929088Smarkmjmp_buf peerdied; 15029088Smarkm 15129088Smarkmint flushline; 15229088Smarkmint linemode; 15329088Smarkm 15429088Smarkm#ifdef KLUDGELINEMODE 15529088Smarkmint kludgelinemode = 1; 15629088Smarkm#endif 15729088Smarkm 15887139Smarkmstatic int is_unique(char *, char **, char **); 15987139Smarkm 16029088Smarkm/* 16129088Smarkm * The following are some clocks used to decide how to interpret 16229088Smarkm * the relationship between various variables. 16329088Smarkm */ 16429088Smarkm 16529088SmarkmClocks clocks; 16629088Smarkm 16729088Smarkm/* 16829088Smarkm * Initialize telnet environment. 16929088Smarkm */ 17029088Smarkm 17187139Smarkmvoid 17287139Smarkminit_telnet(void) 17329088Smarkm{ 17429088Smarkm env_init(); 17529088Smarkm 17629088Smarkm SB_CLEAR(); 17729088Smarkm ClearArray(options); 17829088Smarkm 17987139Smarkm connected = ISend = localflow = donebinarytoggle = 0; 18087139Smarkm#ifdef AUTHENTICATION 18187139Smarkm#ifdef ENCRYPTION 18229088Smarkm auth_encrypt_connect(connected); 18387139Smarkm#endif 18487139Smarkm#endif 18529088Smarkm restartany = -1; 18629088Smarkm 18729088Smarkm SYNCHing = 0; 18829088Smarkm 18929088Smarkm /* Don't change NetTrace */ 19029088Smarkm 19129088Smarkm escape = CONTROL(']'); 19229088Smarkm rlogin = _POSIX_VDISABLE; 19329088Smarkm#ifdef KLUDGELINEMODE 19429088Smarkm echoc = CONTROL('E'); 19529088Smarkm#endif 19629088Smarkm 19729088Smarkm flushline = 1; 19829088Smarkm telrcv_state = TS_DATA; 19929088Smarkm} 20029088Smarkm 20129088Smarkm 20229088Smarkm/* 20329088Smarkm * These routines are in charge of sending option negotiations 20429088Smarkm * to the other side. 20529088Smarkm * 20629088Smarkm * The basic idea is that we send the negotiation if either side 20729088Smarkm * is in disagreement as to what the current state should be. 20829088Smarkm */ 20929088Smarkm 21087139Smarkmvoid 21187139Smarkmsend_do(int c, int init) 21229088Smarkm{ 21329088Smarkm if (init) { 21429088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 21529088Smarkm my_want_state_is_do(c)) 21629088Smarkm return; 21729088Smarkm set_my_want_state_do(c); 21829088Smarkm do_dont_resp[c]++; 21929088Smarkm } 220142790Stobez if (telnetport < 0) 221142790Stobez return; 22229088Smarkm NET2ADD(IAC, DO); 22329088Smarkm NETADD(c); 22429088Smarkm printoption("SENT", DO, c); 22529088Smarkm} 22629088Smarkm 22787139Smarkmvoid 22887139Smarkmsend_dont(int c, int init) 22929088Smarkm{ 23029088Smarkm if (init) { 23129088Smarkm if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 23229088Smarkm my_want_state_is_dont(c)) 23329088Smarkm return; 23429088Smarkm set_my_want_state_dont(c); 23529088Smarkm do_dont_resp[c]++; 23629088Smarkm } 237142790Stobez if (telnetport < 0) 238142790Stobez return; 23929088Smarkm NET2ADD(IAC, DONT); 24029088Smarkm NETADD(c); 24129088Smarkm printoption("SENT", DONT, c); 24229088Smarkm} 24329088Smarkm 24487139Smarkmvoid 24587139Smarkmsend_will(int c, int init) 24629088Smarkm{ 24729088Smarkm if (init) { 24829088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 24929088Smarkm my_want_state_is_will(c)) 25029088Smarkm return; 25129088Smarkm set_my_want_state_will(c); 25229088Smarkm will_wont_resp[c]++; 25329088Smarkm } 254142790Stobez if (telnetport < 0) 255142790Stobez return; 25629088Smarkm NET2ADD(IAC, WILL); 25729088Smarkm NETADD(c); 25829088Smarkm printoption("SENT", WILL, c); 25929088Smarkm} 26029088Smarkm 26187139Smarkmvoid 26287139Smarkmsend_wont(int c, int init) 26329088Smarkm{ 26429088Smarkm if (init) { 26529088Smarkm if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 26629088Smarkm my_want_state_is_wont(c)) 26729088Smarkm return; 26829088Smarkm set_my_want_state_wont(c); 26929088Smarkm will_wont_resp[c]++; 27029088Smarkm } 271142790Stobez if (telnetport < 0) 272142790Stobez return; 27329088Smarkm NET2ADD(IAC, WONT); 27429088Smarkm NETADD(c); 27529088Smarkm printoption("SENT", WONT, c); 27629088Smarkm} 27729088Smarkm 27887139Smarkmvoid 27987139Smarkmwilloption(int option) 28029088Smarkm{ 28129088Smarkm int new_state_ok = 0; 28229088Smarkm 28329088Smarkm if (do_dont_resp[option]) { 28429088Smarkm --do_dont_resp[option]; 28529088Smarkm if (do_dont_resp[option] && my_state_is_do(option)) 28629088Smarkm --do_dont_resp[option]; 28729088Smarkm } 28829088Smarkm 28929088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 29029088Smarkm 29129088Smarkm switch (option) { 29229088Smarkm 29329088Smarkm case TELOPT_ECHO: 29429088Smarkm case TELOPT_BINARY: 29529088Smarkm case TELOPT_SGA: 29629088Smarkm settimer(modenegotiated); 297103955Smarkm /* FALLTHROUGH */ 29829088Smarkm case TELOPT_STATUS: 29987139Smarkm#ifdef AUTHENTICATION 30029088Smarkm case TELOPT_AUTHENTICATION: 30129088Smarkm#endif 30229088Smarkm#ifdef ENCRYPTION 30329088Smarkm case TELOPT_ENCRYPT: 30429088Smarkm#endif /* ENCRYPTION */ 30529088Smarkm new_state_ok = 1; 30629088Smarkm break; 30729088Smarkm 30829088Smarkm case TELOPT_TM: 30929088Smarkm if (flushout) 31029088Smarkm flushout = 0; 31129088Smarkm /* 31229088Smarkm * Special case for TM. If we get back a WILL, 31329088Smarkm * pretend we got back a WONT. 31429088Smarkm */ 31529088Smarkm set_my_want_state_dont(option); 31629088Smarkm set_my_state_dont(option); 31729088Smarkm return; /* Never reply to TM will's/wont's */ 31829088Smarkm 31929088Smarkm case TELOPT_LINEMODE: 32029088Smarkm default: 32129088Smarkm break; 32229088Smarkm } 32329088Smarkm 32429088Smarkm if (new_state_ok) { 32529088Smarkm set_my_want_state_do(option); 32629088Smarkm send_do(option, 0); 32729088Smarkm setconnmode(0); /* possibly set new tty mode */ 32829088Smarkm } else { 32929088Smarkm do_dont_resp[option]++; 33029088Smarkm send_dont(option, 0); 33129088Smarkm } 33229088Smarkm } 33329088Smarkm set_my_state_do(option); 33429088Smarkm#ifdef ENCRYPTION 33529088Smarkm if (option == TELOPT_ENCRYPT) 33629088Smarkm encrypt_send_support(); 33729088Smarkm#endif /* ENCRYPTION */ 33829088Smarkm} 33929088Smarkm 34087139Smarkmvoid 34187139Smarkmwontoption(int option) 34229088Smarkm{ 34329088Smarkm if (do_dont_resp[option]) { 34429088Smarkm --do_dont_resp[option]; 34529088Smarkm if (do_dont_resp[option] && my_state_is_dont(option)) 34629088Smarkm --do_dont_resp[option]; 34729088Smarkm } 34829088Smarkm 34929088Smarkm if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 35029088Smarkm 35129088Smarkm switch (option) { 35229088Smarkm 35329088Smarkm#ifdef KLUDGELINEMODE 35429088Smarkm case TELOPT_SGA: 35529088Smarkm if (!kludgelinemode) 35629088Smarkm break; 357103955Smarkm /* FALLTHROUGH */ 35829088Smarkm#endif 35929088Smarkm case TELOPT_ECHO: 36029088Smarkm settimer(modenegotiated); 36129088Smarkm break; 36229088Smarkm 36329088Smarkm case TELOPT_TM: 36429088Smarkm if (flushout) 36529088Smarkm flushout = 0; 36629088Smarkm set_my_want_state_dont(option); 36729088Smarkm set_my_state_dont(option); 36829088Smarkm return; /* Never reply to TM will's/wont's */ 36929088Smarkm 37029088Smarkm default: 37129088Smarkm break; 37229088Smarkm } 37329088Smarkm set_my_want_state_dont(option); 37429088Smarkm if (my_state_is_do(option)) 37529088Smarkm send_dont(option, 0); 37629088Smarkm setconnmode(0); /* Set new tty mode */ 37729088Smarkm } else if (option == TELOPT_TM) { 37829088Smarkm /* 37929088Smarkm * Special case for TM. 38029088Smarkm */ 38129088Smarkm if (flushout) 38229088Smarkm flushout = 0; 38329088Smarkm set_my_want_state_dont(option); 38429088Smarkm } 38529088Smarkm set_my_state_dont(option); 38629088Smarkm} 38729088Smarkm 38887139Smarkmstatic void 38987139Smarkmdooption(int option) 39029088Smarkm{ 39129088Smarkm int new_state_ok = 0; 39229088Smarkm 39329088Smarkm if (will_wont_resp[option]) { 39429088Smarkm --will_wont_resp[option]; 39529088Smarkm if (will_wont_resp[option] && my_state_is_will(option)) 39629088Smarkm --will_wont_resp[option]; 39729088Smarkm } 39829088Smarkm 39929088Smarkm if (will_wont_resp[option] == 0) { 40029088Smarkm if (my_want_state_is_wont(option)) { 40129088Smarkm 40229088Smarkm switch (option) { 40329088Smarkm 40429088Smarkm case TELOPT_TM: 40529088Smarkm /* 40629088Smarkm * Special case for TM. We send a WILL, but pretend 40729088Smarkm * we sent WONT. 40829088Smarkm */ 40929088Smarkm send_will(option, 0); 41029088Smarkm set_my_want_state_wont(TELOPT_TM); 41129088Smarkm set_my_state_wont(TELOPT_TM); 41229088Smarkm return; 41329088Smarkm 41429088Smarkm case TELOPT_BINARY: /* binary mode */ 41529088Smarkm case TELOPT_NAWS: /* window size */ 41629088Smarkm case TELOPT_TSPEED: /* terminal speed */ 41729088Smarkm case TELOPT_LFLOW: /* local flow control */ 41829088Smarkm case TELOPT_TTYPE: /* terminal type option */ 41929088Smarkm case TELOPT_SGA: /* no big deal */ 42029088Smarkm#ifdef ENCRYPTION 42129088Smarkm case TELOPT_ENCRYPT: /* encryption variable option */ 42229088Smarkm#endif /* ENCRYPTION */ 42329088Smarkm new_state_ok = 1; 42429088Smarkm break; 42529088Smarkm 42629088Smarkm case TELOPT_NEW_ENVIRON: /* New environment variable option */ 42729088Smarkm#ifdef OLD_ENVIRON 42829088Smarkm if (my_state_is_will(TELOPT_OLD_ENVIRON)) 42929088Smarkm send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */ 43029088Smarkm goto env_common; 43129088Smarkm case TELOPT_OLD_ENVIRON: /* Old environment variable option */ 43229088Smarkm if (my_state_is_will(TELOPT_NEW_ENVIRON)) 43329088Smarkm break; /* Don't enable if new one is in use! */ 43429088Smarkm env_common: 43529088Smarkm telopt_environ = option; 43629088Smarkm#endif 43729088Smarkm new_state_ok = 1; 43829088Smarkm break; 43929088Smarkm 44087139Smarkm#ifdef AUTHENTICATION 44129088Smarkm case TELOPT_AUTHENTICATION: 44229088Smarkm if (autologin) 44329088Smarkm new_state_ok = 1; 44429088Smarkm break; 44529088Smarkm#endif 44629088Smarkm 44729088Smarkm case TELOPT_XDISPLOC: /* X Display location */ 44887139Smarkm if (env_getvalue("DISPLAY")) 44929088Smarkm new_state_ok = 1; 45029088Smarkm break; 45129088Smarkm 45229088Smarkm case TELOPT_LINEMODE: 45329088Smarkm#ifdef KLUDGELINEMODE 45429088Smarkm kludgelinemode = 0; 45529088Smarkm send_do(TELOPT_SGA, 1); 45629088Smarkm#endif 45729088Smarkm set_my_want_state_will(TELOPT_LINEMODE); 45829088Smarkm send_will(option, 0); 45929088Smarkm set_my_state_will(TELOPT_LINEMODE); 46029088Smarkm slc_init(); 46129088Smarkm return; 46229088Smarkm 46329088Smarkm case TELOPT_ECHO: /* We're never going to echo... */ 46429088Smarkm default: 46529088Smarkm break; 46629088Smarkm } 46729088Smarkm 46829088Smarkm if (new_state_ok) { 46929088Smarkm set_my_want_state_will(option); 47029088Smarkm send_will(option, 0); 47129088Smarkm setconnmode(0); /* Set new tty mode */ 47229088Smarkm } else { 47329088Smarkm will_wont_resp[option]++; 47429088Smarkm send_wont(option, 0); 47529088Smarkm } 47629088Smarkm } else { 47729088Smarkm /* 47829088Smarkm * Handle options that need more things done after the 47929088Smarkm * other side has acknowledged the option. 48029088Smarkm */ 48129088Smarkm switch (option) { 48229088Smarkm case TELOPT_LINEMODE: 48329088Smarkm#ifdef KLUDGELINEMODE 48429088Smarkm kludgelinemode = 0; 48529088Smarkm send_do(TELOPT_SGA, 1); 48629088Smarkm#endif 48729088Smarkm set_my_state_will(option); 48829088Smarkm slc_init(); 48929088Smarkm send_do(TELOPT_SGA, 0); 49029088Smarkm return; 49129088Smarkm } 49229088Smarkm } 49329088Smarkm } 49429088Smarkm set_my_state_will(option); 49529088Smarkm} 49629088Smarkm 49787139Smarkmstatic void 49887139Smarkmdontoption(int option) 49929088Smarkm{ 50029088Smarkm 50129088Smarkm if (will_wont_resp[option]) { 50229088Smarkm --will_wont_resp[option]; 50329088Smarkm if (will_wont_resp[option] && my_state_is_wont(option)) 50429088Smarkm --will_wont_resp[option]; 50529088Smarkm } 50629088Smarkm 50729088Smarkm if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 50829088Smarkm switch (option) { 50929088Smarkm case TELOPT_LINEMODE: 51029088Smarkm linemode = 0; /* put us back to the default state */ 51129088Smarkm break; 51229088Smarkm#ifdef OLD_ENVIRON 51329088Smarkm case TELOPT_NEW_ENVIRON: 51429088Smarkm /* 51529088Smarkm * The new environ option wasn't recognized, try 51629088Smarkm * the old one. 51729088Smarkm */ 51829088Smarkm send_will(TELOPT_OLD_ENVIRON, 1); 51929088Smarkm telopt_environ = TELOPT_OLD_ENVIRON; 52029088Smarkm break; 52129088Smarkm#endif 52229088Smarkm } 52329088Smarkm /* we always accept a DONT */ 52429088Smarkm set_my_want_state_wont(option); 52529088Smarkm if (my_state_is_will(option)) 52629088Smarkm send_wont(option, 0); 52729088Smarkm setconnmode(0); /* Set new tty mode */ 52829088Smarkm } 52929088Smarkm set_my_state_wont(option); 53029088Smarkm} 53129088Smarkm 53229088Smarkm/* 53329088Smarkm * Given a buffer returned by tgetent(), this routine will turn 53472089Sasmodai * the pipe separated list of names in the buffer into an array 53529088Smarkm * of pointers to null terminated names. We toss out any bad, 53629088Smarkm * duplicate, or verbose names (names with spaces). 53729088Smarkm */ 53829088Smarkm 53987139Smarkmstatic const char *name_unknown = "UNKNOWN"; 54087139Smarkmstatic const char *unknown[] = { NULL, NULL }; 54129088Smarkm 54287139Smarkmstatic const char ** 54387139Smarkmmklist(char *buf, char *name) 54429088Smarkm{ 54587139Smarkm int n; 54687139Smarkm char c, *cp, **argvp, *cp2, **argv, **avt; 54729088Smarkm 54829088Smarkm if (name) { 54981965Smarkm if (strlen(name) > 40) { 55029088Smarkm name = 0; 55129088Smarkm unknown[0] = name_unknown; 55229088Smarkm } else { 55329088Smarkm unknown[0] = name; 55429088Smarkm upcase(name); 55529088Smarkm } 55629088Smarkm } else 55729088Smarkm unknown[0] = name_unknown; 55829088Smarkm /* 55929088Smarkm * Count up the number of names. 56029088Smarkm */ 56129088Smarkm for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 56229088Smarkm if (*cp == '|') 56329088Smarkm n++; 56429088Smarkm } 56529088Smarkm /* 56629088Smarkm * Allocate an array to put the name pointers into 56729088Smarkm */ 56829088Smarkm argv = (char **)malloc((n+3)*sizeof(char *)); 56929088Smarkm if (argv == 0) 57029088Smarkm return(unknown); 57129088Smarkm 57229088Smarkm /* 57329088Smarkm * Fill up the array of pointers to names. 57429088Smarkm */ 57529088Smarkm *argv = 0; 57629088Smarkm argvp = argv+1; 57729088Smarkm n = 0; 57829088Smarkm for (cp = cp2 = buf; (c = *cp); cp++) { 57929088Smarkm if (c == '|' || c == ':') { 58029088Smarkm *cp++ = '\0'; 58129088Smarkm /* 58229088Smarkm * Skip entries that have spaces or are over 40 58329088Smarkm * characters long. If this is our environment 58429088Smarkm * name, then put it up front. Otherwise, as 58529088Smarkm * long as this is not a duplicate name (case 58629088Smarkm * insensitive) add it to the list. 58729088Smarkm */ 58829088Smarkm if (n || (cp - cp2 > 41)) 58929088Smarkm ; 59029088Smarkm else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 59129088Smarkm *argv = cp2; 59229088Smarkm else if (is_unique(cp2, argv+1, argvp)) 59329088Smarkm *argvp++ = cp2; 59429088Smarkm if (c == ':') 59529088Smarkm break; 59629088Smarkm /* 59729088Smarkm * Skip multiple delimiters. Reset cp2 to 59829088Smarkm * the beginning of the next name. Reset n, 59929088Smarkm * the flag for names with spaces. 60029088Smarkm */ 60129088Smarkm while ((c = *cp) == '|') 60229088Smarkm cp++; 60329088Smarkm cp2 = cp; 60429088Smarkm n = 0; 60529088Smarkm } 60629088Smarkm /* 60729088Smarkm * Skip entries with spaces or non-ascii values. 60829088Smarkm * Convert lower case letters to upper case. 60929088Smarkm */ 61029088Smarkm if ((c == ' ') || !isascii(c)) 61129088Smarkm n = 1; 61229088Smarkm else if (islower(c)) 61329088Smarkm *cp = toupper(c); 61429088Smarkm } 61529088Smarkm 61629088Smarkm /* 61729088Smarkm * Check for an old V6 2 character name. If the second 61829088Smarkm * name points to the beginning of the buffer, and is 61929088Smarkm * only 2 characters long, move it to the end of the array. 62029088Smarkm */ 62129088Smarkm if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 62229088Smarkm --argvp; 62329088Smarkm for (avt = &argv[1]; avt < argvp; avt++) 62429088Smarkm *avt = *(avt+1); 62529088Smarkm *argvp++ = buf; 62629088Smarkm } 62729088Smarkm 62829088Smarkm /* 62929088Smarkm * Duplicate last name, for TTYPE option, and null 63029088Smarkm * terminate the array. If we didn't find a match on 63129088Smarkm * our terminal name, put that name at the beginning. 63229088Smarkm */ 63329088Smarkm cp = *(argvp-1); 63429088Smarkm *argvp++ = cp; 63529088Smarkm *argvp = 0; 63629088Smarkm 63729088Smarkm if (*argv == 0) { 63829088Smarkm if (name) 63929088Smarkm *argv = name; 64029088Smarkm else { 64129088Smarkm --argvp; 64229088Smarkm for (avt = argv; avt < argvp; avt++) 64329088Smarkm *avt = *(avt+1); 64429088Smarkm } 64529088Smarkm } 64629088Smarkm if (*argv) 64787139Smarkm return((const char **)argv); 64829088Smarkm else 64929088Smarkm return(unknown); 65029088Smarkm} 65129088Smarkm 65287139Smarkmstatic int 65387139Smarkmis_unique(char *name, char **as, char **ae) 65429088Smarkm{ 65587139Smarkm char **ap; 65687139Smarkm int n; 65729088Smarkm 65829088Smarkm n = strlen(name) + 1; 65929088Smarkm for (ap = as; ap < ae; ap++) 66029088Smarkm if (strncasecmp(*ap, name, n) == 0) 66129088Smarkm return(0); 66229088Smarkm return (1); 66329088Smarkm} 66429088Smarkm 66529088Smarkm#ifdef TERMCAP 66629088Smarkmchar termbuf[1024]; 66729088Smarkm 66887139Smarkm/*ARGSUSED*/ 66987139Smarkmstatic int 67087139Smarkmsetupterm(char *tname, int fd, int *errp) 67129088Smarkm{ 67229088Smarkm if (tgetent(termbuf, tname) == 1) { 67329088Smarkm termbuf[1023] = '\0'; 67429088Smarkm if (errp) 67529088Smarkm *errp = 1; 67629088Smarkm return(0); 67729088Smarkm } 67829088Smarkm if (errp) 67929088Smarkm *errp = 0; 68029088Smarkm return(-1); 68129088Smarkm} 68229088Smarkm#else 68329088Smarkm#define termbuf ttytype 68429088Smarkmextern char ttytype[]; 68529088Smarkm#endif 68629088Smarkm 68729088Smarkmint resettermname = 1; 68829088Smarkm 68987139Smarkmstatic const char * 69087139Smarkmgettermname(void) 69129088Smarkm{ 69229088Smarkm char *tname; 69387139Smarkm static const char **tnamep = 0; 69487139Smarkm static const char **next; 69529088Smarkm int err; 69629088Smarkm 69729088Smarkm if (resettermname) { 69829088Smarkm resettermname = 0; 69929088Smarkm if (tnamep && tnamep != unknown) 70029088Smarkm free(tnamep); 70187139Smarkm if ((tname = env_getvalue("TERM")) && 70229088Smarkm (setupterm(tname, 1, &err) == 0)) { 70329088Smarkm tnamep = mklist(termbuf, tname); 70429088Smarkm } else { 70581965Smarkm if (tname && (strlen(tname) <= 40)) { 70629088Smarkm unknown[0] = tname; 70729088Smarkm upcase(tname); 70829088Smarkm } else 70929088Smarkm unknown[0] = name_unknown; 71029088Smarkm tnamep = unknown; 71129088Smarkm } 71229088Smarkm next = tnamep; 71329088Smarkm } 71429088Smarkm if (*next == 0) 71529088Smarkm next = tnamep; 71629088Smarkm return(*next++); 71729088Smarkm} 71829088Smarkm/* 71929088Smarkm * suboption() 72029088Smarkm * 72129088Smarkm * Look at the sub-option buffer, and try to be helpful to the other 72229088Smarkm * side. 72329088Smarkm * 72429088Smarkm * Currently we recognize: 72529088Smarkm * 72629088Smarkm * Terminal type, send request. 72729088Smarkm * Terminal speed (send request). 72829088Smarkm * Local flow control (is request). 72929088Smarkm * Linemode 73029088Smarkm */ 73129088Smarkm 73287139Smarkmstatic void 73387139Smarkmsuboption(void) 73429088Smarkm{ 73529088Smarkm unsigned char subchar; 73629088Smarkm 73729088Smarkm printsub('<', subbuffer, SB_LEN()+2); 73829088Smarkm switch (subchar = SB_GET()) { 73929088Smarkm case TELOPT_TTYPE: 74029088Smarkm if (my_want_state_is_wont(TELOPT_TTYPE)) 74129088Smarkm return; 74229088Smarkm if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 74329088Smarkm return; 74429088Smarkm } else { 74587139Smarkm const char *name; 74629088Smarkm unsigned char temp[50]; 74729088Smarkm int len; 74829088Smarkm 74929088Smarkm name = gettermname(); 75029088Smarkm len = strlen(name) + 4 + 2; 75129088Smarkm if (len < NETROOM()) { 75287139Smarkm sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, 75329088Smarkm TELQUAL_IS, name, IAC, SE); 75429088Smarkm ring_supply_data(&netoring, temp, len); 75529088Smarkm printsub('>', &temp[2], len-2); 75629088Smarkm } else { 75729088Smarkm ExitString("No room in buffer for terminal type.\n", 1); 75829088Smarkm /*NOTREACHED*/ 75929088Smarkm } 76029088Smarkm } 76129088Smarkm break; 76229088Smarkm case TELOPT_TSPEED: 76329088Smarkm if (my_want_state_is_wont(TELOPT_TSPEED)) 76429088Smarkm return; 76529088Smarkm if (SB_EOF()) 76629088Smarkm return; 76729088Smarkm if (SB_GET() == TELQUAL_SEND) { 76829088Smarkm long ospeed, ispeed; 76929088Smarkm unsigned char temp[50]; 77029088Smarkm int len; 77129088Smarkm 77229088Smarkm TerminalSpeeds(&ispeed, &ospeed); 77329088Smarkm 77429181Smarkm sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, 77529088Smarkm TELQUAL_IS, ospeed, ispeed, IAC, SE); 77629088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 77729088Smarkm 77829088Smarkm if (len < NETROOM()) { 77929088Smarkm ring_supply_data(&netoring, temp, len); 78029088Smarkm printsub('>', temp+2, len - 2); 78129088Smarkm } 78229088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 78329088Smarkm } 78429088Smarkm break; 78529088Smarkm case TELOPT_LFLOW: 78629088Smarkm if (my_want_state_is_wont(TELOPT_LFLOW)) 78729088Smarkm return; 78829088Smarkm if (SB_EOF()) 78929088Smarkm return; 79029088Smarkm switch(SB_GET()) { 79129088Smarkm case LFLOW_RESTART_ANY: 79229088Smarkm restartany = 1; 79329088Smarkm break; 79429088Smarkm case LFLOW_RESTART_XON: 79529088Smarkm restartany = 0; 79629088Smarkm break; 79729088Smarkm case LFLOW_ON: 79829088Smarkm localflow = 1; 79929088Smarkm break; 80029088Smarkm case LFLOW_OFF: 80129088Smarkm localflow = 0; 80229088Smarkm break; 80329088Smarkm default: 80429088Smarkm return; 80529088Smarkm } 80629088Smarkm setcommandmode(); 80729088Smarkm setconnmode(0); 80829088Smarkm break; 80929088Smarkm 81029088Smarkm case TELOPT_LINEMODE: 81129088Smarkm if (my_want_state_is_wont(TELOPT_LINEMODE)) 81229088Smarkm return; 81329088Smarkm if (SB_EOF()) 81429088Smarkm return; 81529088Smarkm switch (SB_GET()) { 81629088Smarkm case WILL: 81729088Smarkm lm_will(subpointer, SB_LEN()); 81829088Smarkm break; 81929088Smarkm case WONT: 82029088Smarkm lm_wont(subpointer, SB_LEN()); 82129088Smarkm break; 82229088Smarkm case DO: 82329088Smarkm lm_do(subpointer, SB_LEN()); 82429088Smarkm break; 82529088Smarkm case DONT: 82629088Smarkm lm_dont(subpointer, SB_LEN()); 82729088Smarkm break; 82829088Smarkm case LM_SLC: 82929088Smarkm slc(subpointer, SB_LEN()); 83029088Smarkm break; 83129088Smarkm case LM_MODE: 83229088Smarkm lm_mode(subpointer, SB_LEN(), 0); 83329088Smarkm break; 83429088Smarkm default: 83529088Smarkm break; 83629088Smarkm } 83729088Smarkm break; 83829088Smarkm 83929088Smarkm#ifdef OLD_ENVIRON 84029088Smarkm case TELOPT_OLD_ENVIRON: 84129088Smarkm#endif 84229088Smarkm case TELOPT_NEW_ENVIRON: 84329088Smarkm if (SB_EOF()) 84429088Smarkm return; 84529088Smarkm switch(SB_PEEK()) { 84629088Smarkm case TELQUAL_IS: 84729088Smarkm case TELQUAL_INFO: 84829088Smarkm if (my_want_state_is_dont(subchar)) 84929088Smarkm return; 85029088Smarkm break; 85129088Smarkm case TELQUAL_SEND: 85229088Smarkm if (my_want_state_is_wont(subchar)) { 85329088Smarkm return; 85429088Smarkm } 85529088Smarkm break; 85629088Smarkm default: 85729088Smarkm return; 85829088Smarkm } 85929088Smarkm env_opt(subpointer, SB_LEN()); 86029088Smarkm break; 86129088Smarkm 86229088Smarkm case TELOPT_XDISPLOC: 86329088Smarkm if (my_want_state_is_wont(TELOPT_XDISPLOC)) 86429088Smarkm return; 86529088Smarkm if (SB_EOF()) 86629088Smarkm return; 86729088Smarkm if (SB_GET() == TELQUAL_SEND) { 86829088Smarkm unsigned char temp[50], *dp; 86929088Smarkm int len; 87029088Smarkm 87187139Smarkm if ((dp = env_getvalue("DISPLAY")) == NULL || 87267827Skris strlen(dp) > sizeof(temp) - 7) { 87329088Smarkm /* 87429088Smarkm * Something happened, we no longer have a DISPLAY 87567827Skris * variable. Or it is too long. So, turn off the option. 87629088Smarkm */ 87729088Smarkm send_wont(TELOPT_XDISPLOC, 1); 87829088Smarkm break; 87929088Smarkm } 88087139Smarkm snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, 88167827Skris TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); 88229088Smarkm len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 88329088Smarkm 88429088Smarkm if (len < NETROOM()) { 88529088Smarkm ring_supply_data(&netoring, temp, len); 88629088Smarkm printsub('>', temp+2, len - 2); 88729088Smarkm } 88829088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 88929088Smarkm } 89029088Smarkm break; 89129088Smarkm 89287139Smarkm#ifdef AUTHENTICATION 89329088Smarkm case TELOPT_AUTHENTICATION: { 89429088Smarkm if (!autologin) 89529088Smarkm break; 89629088Smarkm if (SB_EOF()) 89729088Smarkm return; 89829088Smarkm switch(SB_GET()) { 89929088Smarkm case TELQUAL_IS: 90029088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 90129088Smarkm return; 90229088Smarkm auth_is(subpointer, SB_LEN()); 90329088Smarkm break; 90429088Smarkm case TELQUAL_SEND: 90529088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 90629088Smarkm return; 90729088Smarkm auth_send(subpointer, SB_LEN()); 90829088Smarkm break; 90929088Smarkm case TELQUAL_REPLY: 91029088Smarkm if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 91129088Smarkm return; 91229088Smarkm auth_reply(subpointer, SB_LEN()); 91329088Smarkm break; 91429088Smarkm case TELQUAL_NAME: 91529088Smarkm if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 91629088Smarkm return; 91729088Smarkm auth_name(subpointer, SB_LEN()); 91829088Smarkm break; 91929088Smarkm } 92029088Smarkm } 92129088Smarkm break; 92229088Smarkm#endif 92329088Smarkm#ifdef ENCRYPTION 92429088Smarkm case TELOPT_ENCRYPT: 92529088Smarkm if (SB_EOF()) 92629088Smarkm return; 92729088Smarkm switch(SB_GET()) { 92829088Smarkm case ENCRYPT_START: 92929088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 93029088Smarkm return; 93129088Smarkm encrypt_start(subpointer, SB_LEN()); 93229088Smarkm break; 93329088Smarkm case ENCRYPT_END: 93429088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 93529088Smarkm return; 93629088Smarkm encrypt_end(); 93729088Smarkm break; 93829088Smarkm case ENCRYPT_SUPPORT: 93929088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 94029088Smarkm return; 94129088Smarkm encrypt_support(subpointer, SB_LEN()); 94229088Smarkm break; 94329088Smarkm case ENCRYPT_REQSTART: 94429088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 94529088Smarkm return; 94629088Smarkm encrypt_request_start(subpointer, SB_LEN()); 94729088Smarkm break; 94829088Smarkm case ENCRYPT_REQEND: 94929088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 95029088Smarkm return; 95129088Smarkm /* 95229088Smarkm * We can always send an REQEND so that we cannot 95329088Smarkm * get stuck encrypting. We should only get this 95429088Smarkm * if we have been able to get in the correct mode 95529088Smarkm * anyhow. 95629088Smarkm */ 95729088Smarkm encrypt_request_end(); 95829088Smarkm break; 95929088Smarkm case ENCRYPT_IS: 96029088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 96129088Smarkm return; 96229088Smarkm encrypt_is(subpointer, SB_LEN()); 96329088Smarkm break; 96429088Smarkm case ENCRYPT_REPLY: 96529088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 96629088Smarkm return; 96729088Smarkm encrypt_reply(subpointer, SB_LEN()); 96829088Smarkm break; 96929088Smarkm case ENCRYPT_ENC_KEYID: 97029088Smarkm if (my_want_state_is_dont(TELOPT_ENCRYPT)) 97129088Smarkm return; 97229088Smarkm encrypt_enc_keyid(subpointer, SB_LEN()); 97329088Smarkm break; 97429088Smarkm case ENCRYPT_DEC_KEYID: 97529088Smarkm if (my_want_state_is_wont(TELOPT_ENCRYPT)) 97629088Smarkm return; 97729088Smarkm encrypt_dec_keyid(subpointer, SB_LEN()); 97829088Smarkm break; 97929088Smarkm default: 98029088Smarkm break; 98129088Smarkm } 98229088Smarkm break; 98329088Smarkm#endif /* ENCRYPTION */ 98429088Smarkm default: 98529088Smarkm break; 98629088Smarkm } 98729088Smarkm} 98829088Smarkm 98929088Smarkmstatic unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 99029088Smarkm 99187139Smarkmvoid 99287139Smarkmlm_will(unsigned char *cmd, int len) 99329088Smarkm{ 99429088Smarkm if (len < 1) { 99529088Smarkm/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 99629088Smarkm return; 99729088Smarkm } 99829088Smarkm switch(cmd[0]) { 99929088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 100029088Smarkm default: 100129088Smarkm str_lm[3] = DONT; 100229088Smarkm str_lm[4] = cmd[0]; 100387139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 100429088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 100529088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 100629088Smarkm } 100729088Smarkm/*@*/ else printf("lm_will: not enough room in buffer\n"); 100829088Smarkm break; 100929088Smarkm } 101029088Smarkm} 101129088Smarkm 101287139Smarkmvoid 101387139Smarkmlm_wont(unsigned char *cmd, int len) 101429088Smarkm{ 101529088Smarkm if (len < 1) { 101629088Smarkm/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 101729088Smarkm return; 101829088Smarkm } 101929088Smarkm switch(cmd[0]) { 102029088Smarkm case LM_FORWARDMASK: /* We shouldn't ever get this... */ 102129088Smarkm default: 102229088Smarkm /* We are always DONT, so don't respond */ 102329088Smarkm return; 102429088Smarkm } 102529088Smarkm} 102629088Smarkm 102787139Smarkmvoid 102887139Smarkmlm_do(unsigned char *cmd, int len) 102929088Smarkm{ 103029088Smarkm if (len < 1) { 103129088Smarkm/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 103229088Smarkm return; 103329088Smarkm } 103429088Smarkm switch(cmd[0]) { 103529088Smarkm case LM_FORWARDMASK: 103629088Smarkm default: 103729088Smarkm str_lm[3] = WONT; 103829088Smarkm str_lm[4] = cmd[0]; 103987139Smarkm if (NETROOM() > (int)sizeof(str_lm)) { 104029088Smarkm ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 104129088Smarkm printsub('>', &str_lm[2], sizeof(str_lm)-2); 104229088Smarkm } 104329088Smarkm/*@*/ else printf("lm_do: not enough room in buffer\n"); 104429088Smarkm break; 104529088Smarkm } 104629088Smarkm} 104729088Smarkm 104887139Smarkmvoid 104987139Smarkmlm_dont(unsigned char *cmd, int len) 105029088Smarkm{ 105129088Smarkm if (len < 1) { 105229088Smarkm/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 105329088Smarkm return; 105429088Smarkm } 105529088Smarkm switch(cmd[0]) { 105629088Smarkm case LM_FORWARDMASK: 105729088Smarkm default: 105829088Smarkm /* we are always WONT, so don't respond */ 105929088Smarkm break; 106029088Smarkm } 106129088Smarkm} 106229088Smarkm 106329088Smarkmstatic unsigned char str_lm_mode[] = { 106429088Smarkm IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 106529088Smarkm}; 106629088Smarkm 106787139Smarkmvoid 106887139Smarkmlm_mode(unsigned char *cmd, int len, int init) 106929088Smarkm{ 107029088Smarkm if (len != 1) 107129088Smarkm return; 107229088Smarkm if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 107329088Smarkm return; 107429088Smarkm if (*cmd&MODE_ACK) 107529088Smarkm return; 107629088Smarkm linemode = *cmd&(MODE_MASK&~MODE_ACK); 107729088Smarkm str_lm_mode[4] = linemode; 107829088Smarkm if (!init) 107929088Smarkm str_lm_mode[4] |= MODE_ACK; 108087139Smarkm if (NETROOM() > (int)sizeof(str_lm_mode)) { 108129088Smarkm ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 108229088Smarkm printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 108329088Smarkm } 108429088Smarkm/*@*/ else printf("lm_mode: not enough room in buffer\n"); 108529088Smarkm setconnmode(0); /* set changed mode */ 108629088Smarkm} 108729088Smarkm 108829088Smarkm 108929088Smarkm 109029088Smarkm/* 109129088Smarkm * slc() 109229088Smarkm * Handle special character suboption of LINEMODE. 109329088Smarkm */ 109429088Smarkm 109529088Smarkmstruct spc { 109629088Smarkm cc_t val; 109729088Smarkm cc_t *valp; 109829088Smarkm char flags; /* Current flags & level */ 109929088Smarkm char mylevel; /* Maximum level & flags */ 110029088Smarkm} spc_data[NSLC+1]; 110129088Smarkm 110229088Smarkm#define SLC_IMPORT 0 110329088Smarkm#define SLC_EXPORT 1 110429088Smarkm#define SLC_RVALUE 2 110529088Smarkmstatic int slc_mode = SLC_EXPORT; 110629088Smarkm 110787139Smarkmvoid 110887139Smarkmslc_init(void) 110929088Smarkm{ 111087139Smarkm struct spc *spcp; 111129088Smarkm 111229088Smarkm localchars = 1; 111329088Smarkm for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 111429088Smarkm spcp->val = 0; 111529088Smarkm spcp->valp = 0; 111629088Smarkm spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 111729088Smarkm } 111829088Smarkm 111929088Smarkm#define initfunc(func, flags) { \ 112029088Smarkm spcp = &spc_data[func]; \ 112129181Smarkm if ((spcp->valp = tcval(func))) { \ 112229088Smarkm spcp->val = *spcp->valp; \ 112329088Smarkm spcp->mylevel = SLC_VARIABLE|flags; \ 112429088Smarkm } else { \ 112529088Smarkm spcp->val = 0; \ 112629088Smarkm spcp->mylevel = SLC_DEFAULT; \ 112729088Smarkm } \ 112829088Smarkm } 112929088Smarkm 113029088Smarkm initfunc(SLC_SYNCH, 0); 113129088Smarkm /* No BRK */ 113229088Smarkm initfunc(SLC_AO, 0); 113329088Smarkm initfunc(SLC_AYT, 0); 113429088Smarkm /* No EOR */ 113529088Smarkm initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 113629088Smarkm initfunc(SLC_EOF, 0); 113729088Smarkm#ifndef SYSV_TERMIO 113829088Smarkm initfunc(SLC_SUSP, SLC_FLUSHIN); 113929088Smarkm#endif 114029088Smarkm initfunc(SLC_EC, 0); 114129088Smarkm initfunc(SLC_EL, 0); 114229088Smarkm#ifndef SYSV_TERMIO 114329088Smarkm initfunc(SLC_EW, 0); 114429088Smarkm initfunc(SLC_RP, 0); 114529088Smarkm initfunc(SLC_LNEXT, 0); 114629088Smarkm#endif 114729088Smarkm initfunc(SLC_XON, 0); 114829088Smarkm initfunc(SLC_XOFF, 0); 114929088Smarkm#ifdef SYSV_TERMIO 115029088Smarkm spc_data[SLC_XON].mylevel = SLC_CANTCHANGE; 115129088Smarkm spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE; 115229088Smarkm#endif 115329088Smarkm initfunc(SLC_FORW1, 0); 115429088Smarkm#ifdef USE_TERMIO 115529088Smarkm initfunc(SLC_FORW2, 0); 115629088Smarkm /* No FORW2 */ 115729088Smarkm#endif 115829088Smarkm 115929088Smarkm initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 116029088Smarkm#undef initfunc 116129088Smarkm 116229088Smarkm if (slc_mode == SLC_EXPORT) 116329088Smarkm slc_export(); 116429088Smarkm else 116529088Smarkm slc_import(1); 116629088Smarkm 116729088Smarkm} 116829088Smarkm 116987139Smarkmvoid 117087139Smarkmslcstate(void) 117129088Smarkm{ 117229088Smarkm printf("Special characters are %s values\n", 117329088Smarkm slc_mode == SLC_IMPORT ? "remote default" : 117429088Smarkm slc_mode == SLC_EXPORT ? "local" : 117529088Smarkm "remote"); 117629088Smarkm} 117729088Smarkm 117887139Smarkmvoid 117987139Smarkmslc_mode_export(void) 118029088Smarkm{ 118129088Smarkm slc_mode = SLC_EXPORT; 118229088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 118329088Smarkm slc_export(); 118429088Smarkm} 118529088Smarkm 118687139Smarkmvoid 118787139Smarkmslc_mode_import(int def) 118829088Smarkm{ 118929088Smarkm slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 119029088Smarkm if (my_state_is_will(TELOPT_LINEMODE)) 119129088Smarkm slc_import(def); 119229088Smarkm} 119329088Smarkm 119429088Smarkmunsigned char slc_import_val[] = { 119529088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 119629088Smarkm}; 119729088Smarkmunsigned char slc_import_def[] = { 119829088Smarkm IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 119929088Smarkm}; 120029088Smarkm 120187139Smarkmvoid 120287139Smarkmslc_import(int def) 120329088Smarkm{ 120487139Smarkm if (NETROOM() > (int)sizeof(slc_import_val)) { 120529088Smarkm if (def) { 120629088Smarkm ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 120729088Smarkm printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 120829088Smarkm } else { 120929088Smarkm ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 121029088Smarkm printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 121129088Smarkm } 121229088Smarkm } 121329088Smarkm/*@*/ else printf("slc_import: not enough room\n"); 121429088Smarkm} 121529088Smarkm 121687139Smarkmvoid 121787139Smarkmslc_export(void) 121829088Smarkm{ 121987139Smarkm struct spc *spcp; 122029088Smarkm 122129088Smarkm TerminalDefaultChars(); 122229088Smarkm 122329088Smarkm slc_start_reply(); 122429088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 122529088Smarkm if (spcp->mylevel != SLC_NOSUPPORT) { 122629088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 122729088Smarkm spcp->flags = SLC_NOSUPPORT; 122829088Smarkm else 122929088Smarkm spcp->flags = spcp->mylevel; 123029088Smarkm if (spcp->valp) 123129088Smarkm spcp->val = *spcp->valp; 123229088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 123329088Smarkm } 123429088Smarkm } 123529088Smarkm slc_end_reply(); 123629088Smarkm (void)slc_update(); 123729088Smarkm setconnmode(1); /* Make sure the character values are set */ 123829088Smarkm} 123929088Smarkm 124087139Smarkmvoid 124187139Smarkmslc(unsigned char *cp, int len) 124229088Smarkm{ 124387139Smarkm struct spc *spcp; 124487139Smarkm int func,level; 124529088Smarkm 124629088Smarkm slc_start_reply(); 124729088Smarkm 124829088Smarkm for (; len >= 3; len -=3, cp +=3) { 124929088Smarkm 125029088Smarkm func = cp[SLC_FUNC]; 125129088Smarkm 125229088Smarkm if (func == 0) { 125329088Smarkm /* 125429088Smarkm * Client side: always ignore 0 function. 125529088Smarkm */ 125629088Smarkm continue; 125729088Smarkm } 125829088Smarkm if (func > NSLC) { 125929088Smarkm if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 126029088Smarkm slc_add_reply(func, SLC_NOSUPPORT, 0); 126129088Smarkm continue; 126229088Smarkm } 126329088Smarkm 126429088Smarkm spcp = &spc_data[func]; 126529088Smarkm 126629088Smarkm level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 126729088Smarkm 126829088Smarkm if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 126929088Smarkm ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 127029088Smarkm continue; 127129088Smarkm } 127229088Smarkm 127329088Smarkm if (level == (SLC_DEFAULT|SLC_ACK)) { 127429088Smarkm /* 127529088Smarkm * This is an error condition, the SLC_ACK 127629088Smarkm * bit should never be set for the SLC_DEFAULT 127729088Smarkm * level. Our best guess to recover is to 127829088Smarkm * ignore the SLC_ACK bit. 127929088Smarkm */ 128029088Smarkm cp[SLC_FLAGS] &= ~SLC_ACK; 128129088Smarkm } 128229088Smarkm 128329088Smarkm if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 128429088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 128529088Smarkm spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 128629088Smarkm continue; 128729088Smarkm } 128829088Smarkm 128929088Smarkm level &= ~SLC_ACK; 129029088Smarkm 129129088Smarkm if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 129229088Smarkm spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 129329088Smarkm spcp->val = (cc_t)cp[SLC_VALUE]; 129429088Smarkm } 129529088Smarkm if (level == SLC_DEFAULT) { 129629088Smarkm if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 129729088Smarkm spcp->flags = spcp->mylevel; 129829088Smarkm else 129929088Smarkm spcp->flags = SLC_NOSUPPORT; 130029088Smarkm } 130129088Smarkm slc_add_reply(func, spcp->flags, spcp->val); 130229088Smarkm } 130329088Smarkm slc_end_reply(); 130429088Smarkm if (slc_update()) 130529088Smarkm setconnmode(1); /* set the new character values */ 130629088Smarkm} 130729088Smarkm 130887139Smarkmvoid 130987139Smarkmslc_check(void) 131029088Smarkm{ 131187139Smarkm struct spc *spcp; 131229088Smarkm 131329088Smarkm slc_start_reply(); 131429088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 131529088Smarkm if (spcp->valp && spcp->val != *spcp->valp) { 131629088Smarkm spcp->val = *spcp->valp; 131729088Smarkm if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 131829088Smarkm spcp->flags = SLC_NOSUPPORT; 131929088Smarkm else 132029088Smarkm spcp->flags = spcp->mylevel; 132129088Smarkm slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 132229088Smarkm } 132329088Smarkm } 132429088Smarkm slc_end_reply(); 132529088Smarkm setconnmode(1); 132629088Smarkm} 132729088Smarkm 132829088Smarkmunsigned char slc_reply[128]; 1329144231Snectarunsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)]; 133029088Smarkmunsigned char *slc_replyp; 133129088Smarkm 133287139Smarkmvoid 133387139Smarkmslc_start_reply(void) 133429088Smarkm{ 133529088Smarkm slc_replyp = slc_reply; 133629088Smarkm *slc_replyp++ = IAC; 133729088Smarkm *slc_replyp++ = SB; 133829088Smarkm *slc_replyp++ = TELOPT_LINEMODE; 133929088Smarkm *slc_replyp++ = LM_SLC; 134029088Smarkm} 134129088Smarkm 134287139Smarkmvoid 134387139Smarkmslc_add_reply(unsigned char func, unsigned char flags, cc_t value) 134429088Smarkm{ 1345144231Snectar /* A sequence of up to 6 bytes my be written for this member of the SLC 1346144231Snectar * suboption list by this function. The end of negotiation command, 1347144231Snectar * which is written by slc_end_reply(), will require 2 additional 1348144231Snectar * bytes. Do not proceed unless there is sufficient space for these 1349144231Snectar * items. 1350144231Snectar */ 1351144231Snectar if (&slc_replyp[6+2] > slc_reply_eom) 1352144231Snectar return; 135329088Smarkm if ((*slc_replyp++ = func) == IAC) 135429088Smarkm *slc_replyp++ = IAC; 135529088Smarkm if ((*slc_replyp++ = flags) == IAC) 135629088Smarkm *slc_replyp++ = IAC; 135729088Smarkm if ((*slc_replyp++ = (unsigned char)value) == IAC) 135829088Smarkm *slc_replyp++ = IAC; 135929088Smarkm} 136029088Smarkm 136187139Smarkmvoid 136287139Smarkmslc_end_reply(void) 136329088Smarkm{ 136487139Smarkm int len; 136529088Smarkm 1366144231Snectar /* The end of negotiation command requires 2 bytes. */ 1367144231Snectar if (&slc_replyp[2] > slc_reply_eom) 1368144231Snectar return; 136929088Smarkm *slc_replyp++ = IAC; 137029088Smarkm *slc_replyp++ = SE; 137129088Smarkm len = slc_replyp - slc_reply; 137229088Smarkm if (len <= 6) 137329088Smarkm return; 137429088Smarkm if (NETROOM() > len) { 137529088Smarkm ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 137629088Smarkm printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 137729088Smarkm } 137829088Smarkm/*@*/else printf("slc_end_reply: not enough room\n"); 137929088Smarkm} 138029088Smarkm 138187139Smarkmint 138287139Smarkmslc_update(void) 138329088Smarkm{ 138487139Smarkm struct spc *spcp; 138529088Smarkm int need_update = 0; 138629088Smarkm 138729088Smarkm for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 138829088Smarkm if (!(spcp->flags&SLC_ACK)) 138929088Smarkm continue; 139029088Smarkm spcp->flags &= ~SLC_ACK; 139129088Smarkm if (spcp->valp && (*spcp->valp != spcp->val)) { 139229088Smarkm *spcp->valp = spcp->val; 139329088Smarkm need_update = 1; 139429088Smarkm } 139529088Smarkm } 139629088Smarkm return(need_update); 139729088Smarkm} 139829088Smarkm 139929088Smarkm#ifdef OLD_ENVIRON 140029088Smarkm# ifdef ENV_HACK 140129088Smarkm/* 140229088Smarkm * Earlier version of telnet/telnetd from the BSD code had 140329088Smarkm * the definitions of VALUE and VAR reversed. To ensure 140429088Smarkm * maximum interoperability, we assume that the server is 140529088Smarkm * an older BSD server, until proven otherwise. The newer 140629088Smarkm * BSD servers should be able to handle either definition, 140729088Smarkm * so it is better to use the wrong values if we don't 140829088Smarkm * know what type of server it is. 140929088Smarkm */ 141029088Smarkmint env_auto = 1; 141129088Smarkmint old_env_var = OLD_ENV_VAR; 141229088Smarkmint old_env_value = OLD_ENV_VALUE; 141329088Smarkm# else 141429088Smarkm# define old_env_var OLD_ENV_VAR 141529088Smarkm# define old_env_value OLD_ENV_VALUE 141629088Smarkm# endif 141729088Smarkm#endif 141829088Smarkm 141987139Smarkmvoid 142087139Smarkmenv_opt(unsigned char *buf, int len) 142129088Smarkm{ 142287139Smarkm unsigned char *ep = 0, *epc = 0; 142387139Smarkm int i; 142429088Smarkm 142529088Smarkm switch(buf[0]&0xff) { 142629088Smarkm case TELQUAL_SEND: 142729088Smarkm env_opt_start(); 142829088Smarkm if (len == 1) { 142929088Smarkm env_opt_add(NULL); 143029088Smarkm } else for (i = 1; i < len; i++) { 143129088Smarkm switch (buf[i]&0xff) { 143229088Smarkm#ifdef OLD_ENVIRON 143329088Smarkm case OLD_ENV_VAR: 143429088Smarkm# ifdef ENV_HACK 143529088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON 143629088Smarkm && env_auto) { 143729088Smarkm /* Server has the same definitions */ 143829088Smarkm old_env_var = OLD_ENV_VAR; 143929088Smarkm old_env_value = OLD_ENV_VALUE; 144029088Smarkm } 1441103955Smarkm /* FALLTHROUGH */ 144229088Smarkm# endif 144329088Smarkm case OLD_ENV_VALUE: 144429088Smarkm /* 144529088Smarkm * Although OLD_ENV_VALUE is not legal, we will 144629088Smarkm * still recognize it, just in case it is an 144729088Smarkm * old server that has VAR & VALUE mixed up... 144829088Smarkm */ 1449103955Smarkm /* FALLTHROUGH */ 145029088Smarkm#else 145129088Smarkm case NEW_ENV_VAR: 145229088Smarkm#endif 145329088Smarkm case ENV_USERVAR: 145429088Smarkm if (ep) { 145529088Smarkm *epc = 0; 145629088Smarkm env_opt_add(ep); 145729088Smarkm } 145829088Smarkm ep = epc = &buf[i+1]; 145929088Smarkm break; 146029088Smarkm case ENV_ESC: 146129088Smarkm i++; 1462103955Smarkm /*FALLTHROUGH*/ 146329088Smarkm default: 146429088Smarkm if (epc) 146529088Smarkm *epc++ = buf[i]; 146629088Smarkm break; 146729088Smarkm } 146829088Smarkm } 146929088Smarkm if (ep) { 147029088Smarkm *epc = 0; 147129088Smarkm env_opt_add(ep); 147229088Smarkm } 147329088Smarkm env_opt_end(1); 147429088Smarkm break; 147529088Smarkm 147629088Smarkm case TELQUAL_IS: 147729088Smarkm case TELQUAL_INFO: 147829088Smarkm /* Ignore for now. We shouldn't get it anyway. */ 147929088Smarkm break; 148029088Smarkm 148129088Smarkm default: 148229088Smarkm break; 148329088Smarkm } 148429088Smarkm} 148529088Smarkm 1486144231Snectar#define OPT_REPLY_SIZE (2 * SUBBUFSIZE) 1487144231Snectarunsigned char *opt_reply = NULL; 148829088Smarkmunsigned char *opt_replyp; 148929088Smarkmunsigned char *opt_replyend; 149029088Smarkm 149187139Smarkmvoid 149287139Smarkmenv_opt_start(void) 149329088Smarkm{ 149429088Smarkm if (opt_reply) 149529088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 149629088Smarkm else 149729088Smarkm opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE); 149829088Smarkm if (opt_reply == NULL) { 149929088Smarkm/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 150029088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 150129088Smarkm return; 150229088Smarkm } 150329088Smarkm opt_replyp = opt_reply; 150429088Smarkm opt_replyend = opt_reply + OPT_REPLY_SIZE; 150529088Smarkm *opt_replyp++ = IAC; 150629088Smarkm *opt_replyp++ = SB; 150729088Smarkm *opt_replyp++ = telopt_environ; 150829088Smarkm *opt_replyp++ = TELQUAL_IS; 150929088Smarkm} 151029088Smarkm 151187139Smarkmvoid 151287139Smarkmenv_opt_start_info(void) 151329088Smarkm{ 151429088Smarkm env_opt_start(); 151529088Smarkm if (opt_replyp) 151629088Smarkm opt_replyp[-1] = TELQUAL_INFO; 151729088Smarkm} 151829088Smarkm 151987139Smarkmvoid 152087139Smarkmenv_opt_add(unsigned char *ep) 152129088Smarkm{ 152287139Smarkm unsigned char *vp, c; 152329088Smarkm 152429088Smarkm if (opt_reply == NULL) /*XXX*/ 152529088Smarkm return; /*XXX*/ 152629088Smarkm 152729088Smarkm if (ep == NULL || *ep == '\0') { 152829088Smarkm /* Send user defined variables first. */ 152929088Smarkm env_default(1, 0); 153029181Smarkm while ((ep = env_default(0, 0))) 153129088Smarkm env_opt_add(ep); 153229088Smarkm 153329088Smarkm /* Now add the list of well know variables. */ 153429088Smarkm env_default(1, 1); 153529181Smarkm while ((ep = env_default(0, 1))) 153629088Smarkm env_opt_add(ep); 153729088Smarkm return; 153829088Smarkm } 153929088Smarkm vp = env_getvalue(ep); 1540144231Snectar if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) + 1541144231Snectar 2 * strlen((char *)ep) + 6 > opt_replyend) 1542144231Snectar { 154387139Smarkm int len; 154429088Smarkm opt_replyend += OPT_REPLY_SIZE; 154529088Smarkm len = opt_replyend - opt_reply; 154629088Smarkm opt_reply = (unsigned char *)realloc(opt_reply, len); 154729088Smarkm if (opt_reply == NULL) { 154829088Smarkm/*@*/ printf("env_opt_add: realloc() failed!!!\n"); 154929088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 155029088Smarkm return; 155129088Smarkm } 155229088Smarkm opt_replyp = opt_reply + len - (opt_replyend - opt_replyp); 155329088Smarkm opt_replyend = opt_reply + len; 155429088Smarkm } 155529088Smarkm if (opt_welldefined(ep)) 155629088Smarkm#ifdef OLD_ENVIRON 155729088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 155829088Smarkm *opt_replyp++ = old_env_var; 155929088Smarkm else 156029088Smarkm#endif 156129088Smarkm *opt_replyp++ = NEW_ENV_VAR; 156229088Smarkm else 156329088Smarkm *opt_replyp++ = ENV_USERVAR; 156429088Smarkm for (;;) { 156529181Smarkm while ((c = *ep++)) { 1566144231Snectar if (opt_replyp + (2 + 2) > opt_replyend) 1567144231Snectar return; 156829088Smarkm switch(c&0xff) { 156929088Smarkm case IAC: 157029088Smarkm *opt_replyp++ = IAC; 157129088Smarkm break; 157229088Smarkm case NEW_ENV_VAR: 157329088Smarkm case NEW_ENV_VALUE: 157429088Smarkm case ENV_ESC: 157529088Smarkm case ENV_USERVAR: 157629088Smarkm *opt_replyp++ = ENV_ESC; 157729088Smarkm break; 157829088Smarkm } 157929088Smarkm *opt_replyp++ = c; 158029088Smarkm } 158129181Smarkm if ((ep = vp)) { 1582144231Snectar if (opt_replyp + (1 + 2 + 2) > opt_replyend) 1583144231Snectar return; 158429088Smarkm#ifdef OLD_ENVIRON 158529088Smarkm if (telopt_environ == TELOPT_OLD_ENVIRON) 158629088Smarkm *opt_replyp++ = old_env_value; 158729088Smarkm else 158829088Smarkm#endif 158929088Smarkm *opt_replyp++ = NEW_ENV_VALUE; 159029088Smarkm vp = NULL; 159129088Smarkm } else 159229088Smarkm break; 159329088Smarkm } 159429088Smarkm} 159529088Smarkm 159687139Smarkmint 159787139Smarkmopt_welldefined(const char *ep) 159829088Smarkm{ 159929088Smarkm if ((strcmp(ep, "USER") == 0) || 160029088Smarkm (strcmp(ep, "DISPLAY") == 0) || 160129088Smarkm (strcmp(ep, "PRINTER") == 0) || 160229088Smarkm (strcmp(ep, "SYSTEMTYPE") == 0) || 160329088Smarkm (strcmp(ep, "JOB") == 0) || 160429088Smarkm (strcmp(ep, "ACCT") == 0)) 160529088Smarkm return(1); 160629088Smarkm return(0); 160729088Smarkm} 160887139Smarkm 160987139Smarkmvoid 161087139Smarkmenv_opt_end(int emptyok) 161129088Smarkm{ 161287139Smarkm int len; 161329088Smarkm 1614144231Snectar if (opt_replyp + 2 > opt_replyend) 1615144231Snectar return; 1616144231Snectar len = opt_replyp + 2 - opt_reply; 161729088Smarkm if (emptyok || len > 6) { 161829088Smarkm *opt_replyp++ = IAC; 161929088Smarkm *opt_replyp++ = SE; 162029088Smarkm if (NETROOM() > len) { 162129088Smarkm ring_supply_data(&netoring, opt_reply, len); 162229088Smarkm printsub('>', &opt_reply[2], len - 2); 162329088Smarkm } 162429088Smarkm/*@*/ else printf("slc_end_reply: not enough room\n"); 162529088Smarkm } 162629088Smarkm if (opt_reply) { 162729088Smarkm free(opt_reply); 162829088Smarkm opt_reply = opt_replyp = opt_replyend = NULL; 162929088Smarkm } 163029088Smarkm} 163129088Smarkm 163229088Smarkm 163329088Smarkm 163487139Smarkmint 163587139Smarkmtelrcv(void) 163629088Smarkm{ 163787139Smarkm int c; 163887139Smarkm int scc; 163987139Smarkm unsigned char *sbp; 164029088Smarkm int count; 164129088Smarkm int returnValue = 0; 164229088Smarkm 164329088Smarkm scc = 0; 164429088Smarkm count = 0; 164529088Smarkm while (TTYROOM() > 2) { 164629088Smarkm if (scc == 0) { 164729088Smarkm if (count) { 164829088Smarkm ring_consumed(&netiring, count); 164929088Smarkm returnValue = 1; 165029088Smarkm count = 0; 165129088Smarkm } 165229088Smarkm sbp = netiring.consume; 165329088Smarkm scc = ring_full_consecutive(&netiring); 165429088Smarkm if (scc == 0) { 165529088Smarkm /* No more data coming in */ 165629088Smarkm break; 165729088Smarkm } 165829088Smarkm } 165929088Smarkm 166029088Smarkm c = *sbp++ & 0xff, scc--; count++; 166129088Smarkm#ifdef ENCRYPTION 166229088Smarkm if (decrypt_input) 166329088Smarkm c = (*decrypt_input)(c); 166429088Smarkm#endif /* ENCRYPTION */ 166529088Smarkm 166629088Smarkm switch (telrcv_state) { 166729088Smarkm 166829088Smarkm case TS_CR: 166929088Smarkm telrcv_state = TS_DATA; 167029088Smarkm if (c == '\0') { 167129088Smarkm break; /* Ignore \0 after CR */ 167229088Smarkm } 167329088Smarkm else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 167429088Smarkm TTYADD(c); 167529088Smarkm break; 167629088Smarkm } 1677103955Smarkm /* FALLTHROUGH */ 167829088Smarkm 167929088Smarkm case TS_DATA: 1680142790Stobez if (c == IAC && telnetport >= 0) { 168129088Smarkm telrcv_state = TS_IAC; 168229088Smarkm break; 168329088Smarkm } 168429088Smarkm /* 168529088Smarkm * The 'crmod' hack (see following) is needed 168629088Smarkm * since we can't * set CRMOD on output only. 168729088Smarkm * Machines like MULTICS like to send \r without 168829088Smarkm * \n; since we must turn off CRMOD to get proper 168929088Smarkm * input, the mapping is done here (sigh). 169029088Smarkm */ 169129088Smarkm if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 169229088Smarkm if (scc > 0) { 169329088Smarkm c = *sbp&0xff; 169429088Smarkm#ifdef ENCRYPTION 169529088Smarkm if (decrypt_input) 169629088Smarkm c = (*decrypt_input)(c); 169729088Smarkm#endif /* ENCRYPTION */ 169829088Smarkm if (c == 0) { 169929088Smarkm sbp++, scc--; count++; 170029088Smarkm /* a "true" CR */ 170129088Smarkm TTYADD('\r'); 170229088Smarkm } else if (my_want_state_is_dont(TELOPT_ECHO) && 170329088Smarkm (c == '\n')) { 170429088Smarkm sbp++, scc--; count++; 170529088Smarkm TTYADD('\n'); 170629088Smarkm } else { 170729088Smarkm#ifdef ENCRYPTION 170829088Smarkm if (decrypt_input) 170929088Smarkm (*decrypt_input)(-1); 171029088Smarkm#endif /* ENCRYPTION */ 171129088Smarkm 171229088Smarkm TTYADD('\r'); 171329088Smarkm if (crmod) { 171429088Smarkm TTYADD('\n'); 171529088Smarkm } 171629088Smarkm } 171729088Smarkm } else { 171829088Smarkm telrcv_state = TS_CR; 171929088Smarkm TTYADD('\r'); 172029088Smarkm if (crmod) { 172129088Smarkm TTYADD('\n'); 172229088Smarkm } 172329088Smarkm } 172429088Smarkm } else { 172529088Smarkm TTYADD(c); 172629088Smarkm } 172729088Smarkm continue; 172829088Smarkm 172929088Smarkm case TS_IAC: 173029088Smarkmprocess_iac: 173129088Smarkm switch (c) { 173229088Smarkm 173329088Smarkm case WILL: 173429088Smarkm telrcv_state = TS_WILL; 173529088Smarkm continue; 173629088Smarkm 173729088Smarkm case WONT: 173829088Smarkm telrcv_state = TS_WONT; 173929088Smarkm continue; 174029088Smarkm 174129088Smarkm case DO: 174229088Smarkm telrcv_state = TS_DO; 174329088Smarkm continue; 174429088Smarkm 174529088Smarkm case DONT: 174629088Smarkm telrcv_state = TS_DONT; 174729088Smarkm continue; 174829088Smarkm 174929088Smarkm case DM: 175029088Smarkm /* 175129088Smarkm * We may have missed an urgent notification, 175229088Smarkm * so make sure we flush whatever is in the 175329088Smarkm * buffer currently. 175429088Smarkm */ 175529088Smarkm printoption("RCVD", IAC, DM); 175629088Smarkm SYNCHing = 1; 175729088Smarkm (void) ttyflush(1); 175829088Smarkm SYNCHing = stilloob(); 175929088Smarkm settimer(gotDM); 176029088Smarkm break; 176129088Smarkm 176229088Smarkm case SB: 176329088Smarkm SB_CLEAR(); 176429088Smarkm telrcv_state = TS_SB; 176529088Smarkm continue; 176629088Smarkm 176729088Smarkm case IAC: 176829088Smarkm TTYADD(IAC); 176929088Smarkm break; 177029088Smarkm 177129088Smarkm case NOP: 177229088Smarkm case GA: 177329088Smarkm default: 177429088Smarkm printoption("RCVD", IAC, c); 177529088Smarkm break; 177629088Smarkm } 177729088Smarkm telrcv_state = TS_DATA; 177829088Smarkm continue; 177929088Smarkm 178029088Smarkm case TS_WILL: 178129088Smarkm printoption("RCVD", WILL, c); 178229088Smarkm willoption(c); 178329088Smarkm telrcv_state = TS_DATA; 178429088Smarkm continue; 178529088Smarkm 178629088Smarkm case TS_WONT: 178729088Smarkm printoption("RCVD", WONT, c); 178829088Smarkm wontoption(c); 178929088Smarkm telrcv_state = TS_DATA; 179029088Smarkm continue; 179129088Smarkm 179229088Smarkm case TS_DO: 179329088Smarkm printoption("RCVD", DO, c); 179429088Smarkm dooption(c); 179529088Smarkm if (c == TELOPT_NAWS) { 179629088Smarkm sendnaws(); 179729088Smarkm } else if (c == TELOPT_LFLOW) { 179829088Smarkm localflow = 1; 179929088Smarkm setcommandmode(); 180029088Smarkm setconnmode(0); 180129088Smarkm } 180229088Smarkm telrcv_state = TS_DATA; 180329088Smarkm continue; 180429088Smarkm 180529088Smarkm case TS_DONT: 180629088Smarkm printoption("RCVD", DONT, c); 180729088Smarkm dontoption(c); 180829088Smarkm flushline = 1; 180929088Smarkm setconnmode(0); /* set new tty mode (maybe) */ 181029088Smarkm telrcv_state = TS_DATA; 181129088Smarkm continue; 181229088Smarkm 181329088Smarkm case TS_SB: 181429088Smarkm if (c == IAC) { 181529088Smarkm telrcv_state = TS_SE; 181629088Smarkm } else { 181729088Smarkm SB_ACCUM(c); 181829088Smarkm } 181929088Smarkm continue; 182029088Smarkm 182129088Smarkm case TS_SE: 182229088Smarkm if (c != SE) { 182329088Smarkm if (c != IAC) { 182429088Smarkm /* 182529088Smarkm * This is an error. We only expect to get 182629088Smarkm * "IAC IAC" or "IAC SE". Several things may 182729088Smarkm * have happend. An IAC was not doubled, the 182829088Smarkm * IAC SE was left off, or another option got 182929088Smarkm * inserted into the suboption are all possibilities. 183029088Smarkm * If we assume that the IAC was not doubled, 183129088Smarkm * and really the IAC SE was left off, we could 183229088Smarkm * get into an infinate loop here. So, instead, 183329088Smarkm * we terminate the suboption, and process the 183429088Smarkm * partial suboption if we can. 183529088Smarkm */ 183629088Smarkm SB_ACCUM(IAC); 183729088Smarkm SB_ACCUM(c); 183829088Smarkm subpointer -= 2; 183929088Smarkm SB_TERM(); 184029088Smarkm 184129088Smarkm printoption("In SUBOPTION processing, RCVD", IAC, c); 184229088Smarkm suboption(); /* handle sub-option */ 184329088Smarkm telrcv_state = TS_IAC; 184429088Smarkm goto process_iac; 184529088Smarkm } 184629088Smarkm SB_ACCUM(c); 184729088Smarkm telrcv_state = TS_SB; 184829088Smarkm } else { 184929088Smarkm SB_ACCUM(IAC); 185029088Smarkm SB_ACCUM(SE); 185129088Smarkm subpointer -= 2; 185229088Smarkm SB_TERM(); 185329088Smarkm suboption(); /* handle sub-option */ 185429088Smarkm telrcv_state = TS_DATA; 185529088Smarkm } 185629088Smarkm } 185729088Smarkm } 185829088Smarkm if (count) 185929088Smarkm ring_consumed(&netiring, count); 186029088Smarkm return returnValue||count; 186129088Smarkm} 186229088Smarkm 186329088Smarkmstatic int bol = 1, local = 0; 186429088Smarkm 186587139Smarkmint 186687139Smarkmrlogin_susp(void) 186729088Smarkm{ 186829088Smarkm if (local) { 186929088Smarkm local = 0; 187029088Smarkm bol = 1; 187129088Smarkm command(0, "z\n", 2); 187229088Smarkm return(1); 187329088Smarkm } 187429088Smarkm return(0); 187529088Smarkm} 187629088Smarkm 187787139Smarkmstatic int 187887139Smarkmtelsnd(void) 187929088Smarkm{ 188029088Smarkm int tcc; 188129088Smarkm int count; 188229088Smarkm int returnValue = 0; 188329088Smarkm unsigned char *tbp; 188429088Smarkm 188529088Smarkm tcc = 0; 188629088Smarkm count = 0; 188729088Smarkm while (NETROOM() > 2) { 188887139Smarkm int sc; 188987139Smarkm int c; 189029088Smarkm 189129088Smarkm if (tcc == 0) { 189229088Smarkm if (count) { 189329088Smarkm ring_consumed(&ttyiring, count); 189429088Smarkm returnValue = 1; 189529088Smarkm count = 0; 189629088Smarkm } 189729088Smarkm tbp = ttyiring.consume; 189829088Smarkm tcc = ring_full_consecutive(&ttyiring); 189929088Smarkm if (tcc == 0) { 190029088Smarkm break; 190129088Smarkm } 190229088Smarkm } 190329088Smarkm c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 190429088Smarkm if (rlogin != _POSIX_VDISABLE) { 190529088Smarkm if (bol) { 190629088Smarkm bol = 0; 190729088Smarkm if (sc == rlogin) { 190829088Smarkm local = 1; 190929088Smarkm continue; 191029088Smarkm } 191129088Smarkm } else if (local) { 191229088Smarkm local = 0; 191329088Smarkm if (sc == '.' || c == termEofChar) { 191429088Smarkm bol = 1; 191529088Smarkm command(0, "close\n", 6); 191629088Smarkm continue; 191729088Smarkm } 191829088Smarkm if (sc == termSuspChar) { 191929088Smarkm bol = 1; 192029088Smarkm command(0, "z\n", 2); 192129088Smarkm continue; 192229088Smarkm } 192329088Smarkm if (sc == escape) { 192487139Smarkm command(0, tbp, tcc); 192529088Smarkm bol = 1; 192629088Smarkm count += tcc; 192729088Smarkm tcc = 0; 192829088Smarkm flushline = 1; 192929088Smarkm break; 193029088Smarkm } 193129088Smarkm if (sc != rlogin) { 193229088Smarkm ++tcc; 193329088Smarkm --tbp; 193429088Smarkm --count; 193529088Smarkm c = sc = rlogin; 193629088Smarkm } 193729088Smarkm } 193829088Smarkm if ((sc == '\n') || (sc == '\r')) 193929088Smarkm bol = 1; 194047973Sru } else if (escape != _POSIX_VDISABLE && sc == escape) { 194129088Smarkm /* 194229088Smarkm * Double escape is a pass through of a single escape character. 194329088Smarkm */ 194429088Smarkm if (tcc && strip(*tbp) == escape) { 194529088Smarkm tbp++; 194629088Smarkm tcc--; 194729088Smarkm count++; 194829088Smarkm bol = 0; 194929088Smarkm } else { 195029088Smarkm command(0, (char *)tbp, tcc); 195129088Smarkm bol = 1; 195229088Smarkm count += tcc; 195329088Smarkm tcc = 0; 195429088Smarkm flushline = 1; 195529088Smarkm break; 195629088Smarkm } 195729088Smarkm } else 195829088Smarkm bol = 0; 195929088Smarkm#ifdef KLUDGELINEMODE 196029088Smarkm if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 196129088Smarkm if (tcc > 0 && strip(*tbp) == echoc) { 196229088Smarkm tcc--; tbp++; count++; 196329088Smarkm } else { 196429088Smarkm dontlecho = !dontlecho; 196529088Smarkm settimer(echotoggle); 196629088Smarkm setconnmode(0); 196729088Smarkm flushline = 1; 196829088Smarkm break; 196929088Smarkm } 197029088Smarkm } 197129088Smarkm#endif 197229088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 197329088Smarkm if (TerminalSpecialChars(sc) == 0) { 197429088Smarkm bol = 1; 197529088Smarkm break; 197629088Smarkm } 197729088Smarkm } 197829088Smarkm if (my_want_state_is_wont(TELOPT_BINARY)) { 197929088Smarkm switch (c) { 198029088Smarkm case '\n': 198129088Smarkm /* 198229088Smarkm * If we are in CRMOD mode (\r ==> \n) 198329088Smarkm * on our local machine, then probably 198429088Smarkm * a newline (unix) is CRLF (TELNET). 198529088Smarkm */ 198629088Smarkm if (MODE_LOCAL_CHARS(globalmode)) { 198729088Smarkm NETADD('\r'); 198829088Smarkm } 198929088Smarkm NETADD('\n'); 199029088Smarkm bol = flushline = 1; 199129088Smarkm break; 199229088Smarkm case '\r': 199329088Smarkm if (!crlf) { 199429088Smarkm NET2ADD('\r', '\0'); 199529088Smarkm } else { 199629088Smarkm NET2ADD('\r', '\n'); 199729088Smarkm } 199829088Smarkm bol = flushline = 1; 199929088Smarkm break; 200029088Smarkm case IAC: 200129088Smarkm NET2ADD(IAC, IAC); 200229088Smarkm break; 200329088Smarkm default: 200429088Smarkm NETADD(c); 200529088Smarkm break; 200629088Smarkm } 200729088Smarkm } else if (c == IAC) { 200829088Smarkm NET2ADD(IAC, IAC); 200929088Smarkm } else { 201029088Smarkm NETADD(c); 201129088Smarkm } 201229088Smarkm } 201329088Smarkm if (count) 201429088Smarkm ring_consumed(&ttyiring, count); 201529088Smarkm return returnValue||count; /* Non-zero if we did anything */ 201629088Smarkm} 201729088Smarkm 201829088Smarkm/* 201929088Smarkm * Scheduler() 202029088Smarkm * 202129088Smarkm * Try to do something. 202229088Smarkm * 202329088Smarkm * If we do something useful, return 1; else return 0. 202429088Smarkm * 202529088Smarkm */ 202629088Smarkm 202787139Smarkmstatic int 202887139SmarkmScheduler(int block) 202929088Smarkm{ 203029088Smarkm /* One wants to be a bit careful about setting returnValue 203129088Smarkm * to one, since a one implies we did some useful work, 203229088Smarkm * and therefore probably won't be called to block next 203329088Smarkm */ 203429088Smarkm int returnValue; 203529088Smarkm int netin, netout, netex, ttyin, ttyout; 203629088Smarkm 203729088Smarkm /* Decide which rings should be processed */ 203829088Smarkm 203929088Smarkm netout = ring_full_count(&netoring) && 204029088Smarkm (flushline || 204129088Smarkm (my_want_state_is_wont(TELOPT_LINEMODE) 204229088Smarkm#ifdef KLUDGELINEMODE 204329088Smarkm && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 204429088Smarkm#endif 204529088Smarkm ) || 204629088Smarkm my_want_state_is_will(TELOPT_BINARY)); 204729088Smarkm ttyout = ring_full_count(&ttyoring); 204829088Smarkm 204929181Smarkm ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); 205029088Smarkm 205129088Smarkm netin = !ISend && ring_empty_count(&netiring); 205229088Smarkm 205329088Smarkm netex = !SYNCHing; 205429088Smarkm 205529088Smarkm /* Call to system code to process rings */ 205629088Smarkm 205729088Smarkm returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 205829088Smarkm 205929088Smarkm /* Now, look at the input rings, looking for work to do. */ 206029088Smarkm 206129088Smarkm if (ring_full_count(&ttyiring)) { 206229088Smarkm returnValue |= telsnd(); 206329088Smarkm } 206429088Smarkm 206529088Smarkm if (ring_full_count(&netiring)) { 206629088Smarkm returnValue |= telrcv(); 206729088Smarkm } 206829088Smarkm return returnValue; 206929088Smarkm} 207029088Smarkm 207187139Smarkm#ifdef AUTHENTICATION 207287139Smarkm#define __unusedhere 207387139Smarkm#else 207487139Smarkm#define __unusedhere __unused 207587139Smarkm#endif 207629088Smarkm/* 207729088Smarkm * Select from tty and network... 207829088Smarkm */ 207987139Smarkmvoid 208087139Smarkmtelnet(char *user __unusedhere) 208129088Smarkm{ 208229088Smarkm sys_telnet_init(); 208329088Smarkm 208487139Smarkm#ifdef AUTHENTICATION 208587139Smarkm#ifdef ENCRYPTION 208629088Smarkm { 208729088Smarkm static char local_host[256] = { 0 }; 208829088Smarkm 208929088Smarkm if (!local_host[0]) { 209029088Smarkm gethostname(local_host, sizeof(local_host)); 209129088Smarkm local_host[sizeof(local_host)-1] = 0; 209229088Smarkm } 209329088Smarkm auth_encrypt_init(local_host, hostname, "TELNET", 0); 209429088Smarkm auth_encrypt_user(user); 209529088Smarkm } 209687139Smarkm#endif 209787139Smarkm#endif 2098142790Stobez if (telnetport > 0) { 209987139Smarkm#ifdef AUTHENTICATION 210029088Smarkm if (autologin) 210129088Smarkm send_will(TELOPT_AUTHENTICATION, 1); 210229088Smarkm#endif 210329088Smarkm#ifdef ENCRYPTION 210429088Smarkm send_do(TELOPT_ENCRYPT, 1); 210529088Smarkm send_will(TELOPT_ENCRYPT, 1); 210629088Smarkm#endif /* ENCRYPTION */ 210729088Smarkm send_do(TELOPT_SGA, 1); 210829088Smarkm send_will(TELOPT_TTYPE, 1); 210929088Smarkm send_will(TELOPT_NAWS, 1); 211029088Smarkm send_will(TELOPT_TSPEED, 1); 211129088Smarkm send_will(TELOPT_LFLOW, 1); 211229088Smarkm send_will(TELOPT_LINEMODE, 1); 211329088Smarkm send_will(TELOPT_NEW_ENVIRON, 1); 211429088Smarkm send_do(TELOPT_STATUS, 1); 211587139Smarkm if (env_getvalue("DISPLAY")) 211629088Smarkm send_will(TELOPT_XDISPLOC, 1); 211729088Smarkm if (eight) 211829088Smarkm tel_enter_binary(eight); 211929088Smarkm } 212029088Smarkm 212129088Smarkm for (;;) { 212229088Smarkm int schedValue; 212329088Smarkm 212429088Smarkm while ((schedValue = Scheduler(0)) != 0) { 212529088Smarkm if (schedValue == -1) { 212629088Smarkm setcommandmode(); 212729088Smarkm return; 212829088Smarkm } 212929088Smarkm } 213029088Smarkm 213129088Smarkm if (Scheduler(1) == -1) { 213229088Smarkm setcommandmode(); 213329088Smarkm return; 213429088Smarkm } 213529088Smarkm } 213629088Smarkm} 213729088Smarkm 213829088Smarkm#if 0 /* XXX - this not being in is a bug */ 213929088Smarkm/* 214029088Smarkm * nextitem() 214129088Smarkm * 214229088Smarkm * Return the address of the next "item" in the TELNET data 214329088Smarkm * stream. This will be the address of the next character if 214429088Smarkm * the current address is a user data character, or it will 214529088Smarkm * be the address of the character following the TELNET command 214629088Smarkm * if the current address is a TELNET IAC ("I Am a Command") 214729088Smarkm * character. 214829088Smarkm */ 214929088Smarkm 215087139Smarkmstatic char * 215187139Smarkmnextitem(char *current) 215229088Smarkm{ 215329088Smarkm if ((*current&0xff) != IAC) { 215429088Smarkm return current+1; 215529088Smarkm } 215629088Smarkm switch (*(current+1)&0xff) { 215729088Smarkm case DO: 215829088Smarkm case DONT: 215929088Smarkm case WILL: 216029088Smarkm case WONT: 216129088Smarkm return current+3; 216229088Smarkm case SB: /* loop forever looking for the SE */ 216329088Smarkm { 216487139Smarkm char *look = current+2; 216529088Smarkm 216629088Smarkm for (;;) { 216729088Smarkm if ((*look++&0xff) == IAC) { 216829088Smarkm if ((*look++&0xff) == SE) { 216929088Smarkm return look; 217029088Smarkm } 217129088Smarkm } 217229088Smarkm } 217329088Smarkm } 217429088Smarkm default: 217529088Smarkm return current+2; 217629088Smarkm } 217729088Smarkm} 217829088Smarkm#endif /* 0 */ 217929088Smarkm 218029088Smarkm/* 218129088Smarkm * netclear() 218229088Smarkm * 218329088Smarkm * We are about to do a TELNET SYNCH operation. Clear 218429088Smarkm * the path to the network. 218529088Smarkm * 218629088Smarkm * Things are a bit tricky since we may have sent the first 218729088Smarkm * byte or so of a previous TELNET command into the network. 218829088Smarkm * So, we have to scan the network buffer from the beginning 218929088Smarkm * until we are up to where we want to be. 219029088Smarkm * 219129088Smarkm * A side effect of what we do, just to keep things 219229088Smarkm * simple, is to clear the urgent data pointer. The principal 219329088Smarkm * caller should be setting the urgent data pointer AFTER calling 219429088Smarkm * us in any case. 219529088Smarkm */ 219629088Smarkm 219787139Smarkmstatic void 219887139Smarkmnetclear(void) 219929088Smarkm{ 220087139Smarkm /* Deleted */ 220129088Smarkm} 220229088Smarkm 220329088Smarkm/* 220429088Smarkm * These routines add various telnet commands to the data stream. 220529088Smarkm */ 220629088Smarkm 220787139Smarkmstatic void 220887139Smarkmdoflush(void) 220929088Smarkm{ 221029088Smarkm NET2ADD(IAC, DO); 221129088Smarkm NETADD(TELOPT_TM); 221229088Smarkm flushline = 1; 221329088Smarkm flushout = 1; 221429088Smarkm (void) ttyflush(1); /* Flush/drop output */ 221529088Smarkm /* do printoption AFTER flush, otherwise the output gets tossed... */ 221629088Smarkm printoption("SENT", DO, TELOPT_TM); 221729088Smarkm} 221829088Smarkm 221987139Smarkmvoid 222087139SmarkmxmitAO(void) 222129088Smarkm{ 222229088Smarkm NET2ADD(IAC, AO); 222329088Smarkm printoption("SENT", IAC, AO); 222429088Smarkm if (autoflush) { 222529088Smarkm doflush(); 222629088Smarkm } 222729088Smarkm} 222829088Smarkm 222987139Smarkmvoid 223087139SmarkmxmitEL(void) 223129088Smarkm{ 223229088Smarkm NET2ADD(IAC, EL); 223329088Smarkm printoption("SENT", IAC, EL); 223429088Smarkm} 223529088Smarkm 223687139Smarkmvoid 223787139SmarkmxmitEC(void) 223829088Smarkm{ 223929088Smarkm NET2ADD(IAC, EC); 224029088Smarkm printoption("SENT", IAC, EC); 224129088Smarkm} 224229088Smarkm 224387139Smarkmint 224487139Smarkmdosynch(char *ch __unused) 224529088Smarkm{ 224629088Smarkm netclear(); /* clear the path to the network */ 224729088Smarkm NETADD(IAC); 224829088Smarkm setneturg(); 224929088Smarkm NETADD(DM); 225029088Smarkm printoption("SENT", IAC, DM); 225129088Smarkm return 1; 225229088Smarkm} 225329088Smarkm 225429088Smarkmint want_status_response = 0; 225529088Smarkm 225687139Smarkmint 225787139Smarkmget_status(char *ch __unused) 225829088Smarkm{ 225929088Smarkm unsigned char tmp[16]; 226087139Smarkm unsigned char *cp; 226129088Smarkm 226229088Smarkm if (my_want_state_is_dont(TELOPT_STATUS)) { 226329088Smarkm printf("Remote side does not support STATUS option\n"); 226429088Smarkm return 0; 226529088Smarkm } 226629088Smarkm cp = tmp; 226729088Smarkm 226829088Smarkm *cp++ = IAC; 226929088Smarkm *cp++ = SB; 227029088Smarkm *cp++ = TELOPT_STATUS; 227129088Smarkm *cp++ = TELQUAL_SEND; 227229088Smarkm *cp++ = IAC; 227329088Smarkm *cp++ = SE; 227429088Smarkm if (NETROOM() >= cp - tmp) { 227529088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 227629088Smarkm printsub('>', tmp+2, cp - tmp - 2); 227729088Smarkm } 227829088Smarkm ++want_status_response; 227929088Smarkm return 1; 228029088Smarkm} 228129088Smarkm 228287139Smarkmvoid 228387139Smarkmintp(void) 228429088Smarkm{ 228529088Smarkm NET2ADD(IAC, IP); 228629088Smarkm printoption("SENT", IAC, IP); 228729088Smarkm flushline = 1; 228829088Smarkm if (autoflush) { 228929088Smarkm doflush(); 229029088Smarkm } 229129088Smarkm if (autosynch) { 229287139Smarkm dosynch(NULL); 229329088Smarkm } 229429088Smarkm} 229529088Smarkm 229687139Smarkmvoid 229787139Smarkmsendbrk(void) 229829088Smarkm{ 229929088Smarkm NET2ADD(IAC, BREAK); 230029088Smarkm printoption("SENT", IAC, BREAK); 230129088Smarkm flushline = 1; 230229088Smarkm if (autoflush) { 230329088Smarkm doflush(); 230429088Smarkm } 230529088Smarkm if (autosynch) { 230687139Smarkm dosynch(NULL); 230729088Smarkm } 230829088Smarkm} 230929088Smarkm 231087139Smarkmvoid 231187139Smarkmsendabort(void) 231229088Smarkm{ 231329088Smarkm NET2ADD(IAC, ABORT); 231429088Smarkm printoption("SENT", IAC, ABORT); 231529088Smarkm flushline = 1; 231629088Smarkm if (autoflush) { 231729088Smarkm doflush(); 231829088Smarkm } 231929088Smarkm if (autosynch) { 232087139Smarkm dosynch(NULL); 232129088Smarkm } 232229088Smarkm} 232329088Smarkm 232487139Smarkmvoid 232587139Smarkmsendsusp(void) 232629088Smarkm{ 232729088Smarkm NET2ADD(IAC, SUSP); 232829088Smarkm printoption("SENT", IAC, SUSP); 232929088Smarkm flushline = 1; 233029088Smarkm if (autoflush) { 233129088Smarkm doflush(); 233229088Smarkm } 233329088Smarkm if (autosynch) { 233487139Smarkm dosynch(NULL); 233529088Smarkm } 233629088Smarkm} 233729088Smarkm 233887139Smarkmvoid 233987139Smarkmsendeof(void) 234029088Smarkm{ 234129088Smarkm NET2ADD(IAC, xEOF); 234229088Smarkm printoption("SENT", IAC, xEOF); 234329088Smarkm} 234429088Smarkm 234587139Smarkmvoid 234687139Smarkmsendayt(void) 234729088Smarkm{ 234829088Smarkm NET2ADD(IAC, AYT); 234929088Smarkm printoption("SENT", IAC, AYT); 235029088Smarkm} 235129088Smarkm 235229088Smarkm/* 235329088Smarkm * Send a window size update to the remote system. 235429088Smarkm */ 235529088Smarkm 235687139Smarkmvoid 235787139Smarkmsendnaws(void) 235829088Smarkm{ 235929088Smarkm long rows, cols; 236029088Smarkm unsigned char tmp[16]; 236187139Smarkm unsigned char *cp; 236229088Smarkm 236329088Smarkm if (my_state_is_wont(TELOPT_NAWS)) 236429088Smarkm return; 236529088Smarkm 236629088Smarkm#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 236729088Smarkm if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 236829088Smarkm 236929088Smarkm if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 237029088Smarkm return; 237129088Smarkm } 237229088Smarkm 237329088Smarkm cp = tmp; 237429088Smarkm 237529088Smarkm *cp++ = IAC; 237629088Smarkm *cp++ = SB; 237729088Smarkm *cp++ = TELOPT_NAWS; 237829088Smarkm PUTSHORT(cp, cols); 237929088Smarkm PUTSHORT(cp, rows); 238029088Smarkm *cp++ = IAC; 238129088Smarkm *cp++ = SE; 238229088Smarkm if (NETROOM() >= cp - tmp) { 238329088Smarkm ring_supply_data(&netoring, tmp, cp-tmp); 238429088Smarkm printsub('>', tmp+2, cp - tmp - 2); 238529088Smarkm } 238629088Smarkm} 238729088Smarkm 238887139Smarkmvoid 238987139Smarkmtel_enter_binary(int rw) 239029088Smarkm{ 239129088Smarkm if (rw&1) 239229088Smarkm send_do(TELOPT_BINARY, 1); 239329088Smarkm if (rw&2) 239429088Smarkm send_will(TELOPT_BINARY, 1); 239529088Smarkm} 239629088Smarkm 239787139Smarkmvoid 239887139Smarkmtel_leave_binary(int rw) 239929088Smarkm{ 240029088Smarkm if (rw&1) 240129088Smarkm send_dont(TELOPT_BINARY, 1); 240229088Smarkm if (rw&2) 240329088Smarkm send_wont(TELOPT_BINARY, 1); 240429088Smarkm} 2405