/* telnet.c */ #define TELNETMASTER /* * Includes */ #include #include #include "vtel.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "kbkeys.h" #include "tsxutl.h" #include "rtfile.h" #include "kbdutl.h" #include "cliutl.h" #include "usrblk.h" #include "inicli.h" #include "suspnd.h" /* * Internal routines */ extern int dosess(); /* process loop */ extern int initsession(); /* (sknum) inititialize session socket */ extern int inprocess(); /* (sknum) process incoming data */ extern VOID parsewrite(); /* (tw,str,len) write from parse */ extern VOID parse(); /* (tw,st,cnt) telnet negotiations */ extern int newkey(); /* (tw) filter for command sequences */ extern int dokey(); /* (tw,c) process keyboard keys */ extern VOID lsterr(); /* list error routine for TSXUTL.C */ extern int question(); /* (cstr,clen,qstr) question routine */ extern int rtresp(); /* (st,ln) get response */ extern int keygets(); /* (str,lim,echo) get line from keyboard */ extern int getword(); /* (string,word) extract a word */ extern char *stptok(); /* (p,to,len,dlm) stop on token */ extern char *stpblk(); /* (ch) stop on blank */ extern VOID strlwr(); /* (st) convert string to lower case */ extern int chkusr(); /* check username / password */ extern int Scompass(); /* (ps,en) compare passwords */ extern VOID printtxt(); /* (txt) printout text */ /* * debug - * * bit 0 (0x01) enable printing of internal events * bit 1 (0x02) enable printing of telnet negotiations */ #define DBUGTRUE -1 /* all debuggers */ static char *usetxt[] = { "", #ifdef DEBUGOPTION " TELNET destination [?] [-hp] [-d level]", " ? List the Help Text and Exit TELNET", " d level Debug Level", " 1 - enable event printing", " 2 - enable telnet negotiation printing", #else " TELNET destination [?] [-hp]", " ? List the Help Text and Exit TELNET", #endif " h List the Help Text and Open Connection", " p filename Specify the Password Filespec", "", 0 }; static char *hlptxt[] = { "", "Keyboard usage for Telnet-11", "-------- ----- --- ---------", "", "The metacharacter 'M->' is ^A", "M->C open capture file M->Q are you there?", "M->D close capture file M->R toggle follow character", "M->F FTP [internet address] M->S skip to end of buffer", "M->H this help screen M->T toggle backspace/delete", "M->I type my internet address M->U erase line", "M->K erase character M->X close connection", "M->O abort output M->Y interrupt process", "M->@ send a true null character", "", " ^? abort Telnet session", "", 0 }; char xs[2]; /* dumby array for TSXUTL.C */ static char /* password file */ *pass = "sy:paswrd.fil"; int pswdreqd = 1; /* password required */ int viewmode = 1; struct twin *current = NULL; /* current session */ char parsedat[80]; /* parsing data */ /* Definitions for telnet protocol */ #define ABORT (-3) #define STNORM 0 #define SE 240 /* \360 */ #define NOP 241 /* \361 */ #define DM 242 /* \362 */ #define BREAK 243 /* \363 */ #define IP 244 /* \364 */ #define AO 245 /* \365 */ #define AYT 246 /* \366 */ #define EC 247 /* \367 */ #define EL 248 /* \370 */ #define GOAHEAD 249 /* \371 */ #define SB 250 /* \372 */ #define WILLTEL 251 /* \373 */ #define WONTTEL 252 /* \374 */ #define DOTEL 253 /* \375 */ #define DONTTEL 254 /* \376 */ #define IAC 255 /* \377 */ /* Assigned Telnet Options */ #define BINARY 0 #define ECHO 1 #define RECONNECT 2 #define SGA 3 #define AMSN 4 #define STATUS 5 #define TIMING 6 #define RCTAN 7 #define OLW 8 #define OPS 9 #define OCRD 10 #define OHTS 11 #define OHTD 12 #define OFFD 13 #define OVTS 14 #define OVTD 15 #define OLFD 16 #define XASCII 17 #define LOGOUT 18 #define BYTEM 19 #define DET 20 #define SUPDUP 21 #define SUPDUPOUT 22 #define SENDLOC 23 #define TERMTYPE 24 #define EOR 25 #define TACACSUID 26 #define OUTPUTMARK 27 #define TERMLOCNUM 28 #define REGIME3270 29 #define X3PAD 30 #define NAWS 31 #define TERMSPEED 32 #define TFLOWCNTRL 33 #define LINEMODE 34 #define MODE 1 #define EDIT 1 #define TRAPSIG 2 #define MODE_ACK 4 #define FORWARDMASK 2 #define SLC 3 #define NO_SUPPORT 0 #define CANTCHANGE 1 #define SLC_VALUE 2 #define SLC_DEFAULT 3 #define SLC_LEVELBITS 3 #define SLC_AWK 128 #define SLC_SYNCH 1 #define SLC_BRK 2 #define SLC_IP 3 #define SLC_AO 4 #define SLC_AYT 5 #define SLC_EOR 6 #define SLC_ABORT 7 #define SLC_EOF 8 #define SLC_SUSP 9 #define SLC_EC 10 #define SLC_EL 11 #define SLC_EW 12 #define SLC_RP 13 #define SLC_LNEXT 14 #define SLC_XON 15 #define SLC_XOFF 16 #define SLC_FORW1 17 #define SLC_FORW2 18 #define XDISPLOC 35 #define XOPTIONS 255 #define ESCFOUND 5 #define IACFOUND 6 #define NEGOTIATE 1 char *telstates[4]={ "Will", "Won't", "Do", "Don't" }; char *teloptions[256]={ "Binary", /* 0 */ "Echo", "Reconnection", "Supress Go Ahead", "Message Size Negotiation", "Status", /* 5 */ "Timing Mark", "Remote Controlled Trans and Echo", "Output Line Width", "Output Page Size", "Output Carriage-Return Disposition", /* 10 */ "Output Horizontal Tab Stops", "Output Horizontal Tab Disposition", "Output Formfeed Disposition", "Output Vertical Tabstops", "Output Vertical Tab Disposition", /* 15 */ "Output Linefeed Disposition", "Extended ASCII", "Logout", "Byte Macro", "Data Entry Terminal", /* 20 */ "SUPDUP", "SUPDUP Output", "Send Location", "Terminal Type", "End of Record", /* 25 */ "TACACS User Identification", "Output Marking", "Terminal Location Number", "3270 Regime", "X.3 PAD", /* 30 */ "Negotiate About Window Size", "Terminal Speed", "Toggle Flow Control", "Linemode", "X Display Location", /* 35 */ "36","37","38","39", "40","41","42","43","44","45","46","47","48","49", "50","51","52","53","54","55","56","57","58","59", "60","61","62","63","64","65","66","67","68","69", "70","71","72","73","74","75","76","77","78","79", "80","81","82","83","84","85","86","87","88","89", "90","91","92","93","94","95","96","97","98","99", "100","101","102","103","104","105","106","107","108","109", "110","111","112","113","114","115","116","117","118","119", "120","121","122","123","124","125","126","127","128","129", "130","131","132","133","134","135","136","137","138","139", "140","141","142","143","144","145","146","147","148","149", "150","151","152","153","154","155","156","157","158","159", "160","161","162","163","164","165","166","167","168","169", "170","171","172","173","174","175","176","177","178","179", "180","181","182","183","184","185","186","187","188","189", "190","191","192","193","194","195","196","197","198","199", "200","201","202","203","204","205","206","207","208","209", "210","211","212","213","214","215","216","217","218","219", "220","221","222","223","224","225","226","227","228","229", "230","231","232","233","234","235","236","237","238","239", "240","241","242","243","244","245","246","247","248","249", "250","251","252","253","254", "Extended Options List" /* 255 */ }; char *LMoptions[]={ "None", "SYNCH", "BREAK", "IP", "ABORT OUTPUT", "AYT", "EOR", "ABORT", "EOF", "SUSP", "EC", "EL", "EW", "RP", "LNEXT", "XON", "XOFF", "FORW1", "FORW2" }; char *LMflags[]={ "NOSUPPORT", "CANTCHANGE", "VALUE", "DEFAULT" }; main(argc,argv) int argc; char *argv[]; { int c,i,j,k; int ev,sknum; register struct socket *skt; /* * Initialize for TSX+ clients */ inicli(); /* * Initialize kb handler * Set the break character to ^C */ kb_init(0x03); /* * identify self */ printtxt(vrstxt); /* * parse arguments */ parsedat[0] = '\0'; for(i=1; isession); do { ev = dosess(); if(ev==0) suspnd(0); } while (ev != -1); suspnd(0); errhandle(); kb_puts("\r\nEscaping from Telnet\r\n"); exit(0); } /* * dosess * * dosess is an infinite loop serving two sources * of external input in order of precedence: * - keyboard strokes * - message events */ int dosess() { int c,cl,ev,dat; /* * do all key translations */ switch(viewmode) { default: /* * This gives precedence to the * keyboard over the network. */ while(0<=(c=newkey(current))) { if(c==A_BRK) return(-1); } break; case 1: if(fndbrk) return(-1); c = kb_char(); if(c == A_X) { return(-1); } else if(c != -1) { kb_puts("\r\nOther commands require an open session."); kb_puts("\r\n^A X - Escape from Telnet.\r\n"); } break; } /* * Check for any relevant messages * that need to be handled by me */ ev = Sgetevent(SCKTCLASS | CONCLASS | USERCLASS | ERRCLASS | MSGCLASS | ABORTCLASS, &cl, &dat); if(ev!=0) { switch(cl) { case CONCLASS: switch(ev) { case CONOPEN: /* a connection has just opened */ if(initsession(dat)) break; /* Start negotiation on network */ /* IAC, DOTEL, ECHO, IAC, DOTEL, SGA, IAC, WILLTEL, NAWS */ skwrite(dat,"\377\375\001\377\375\003\377\373\037",9); skenque(dat,1); #ifdef DEBUGOPTION if(debug&0x02) { /* Print to the console what we just did */ kbprintf("SEND: %s %s\r\n", telstates[DOTEL-WILLTEL],teloptions[ECHO]); kbprintf("SEND: %s %s\r\n", telstates[DOTEL-WILLTEL],teloptions[SGA]); kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[TERMTYPE]); kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[LINEMODE]); kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[NAWS]); } #endif viewmode = 0; break; case CONCLOSE: /* connection is closing */ if(0session); mp = skt->mpp; for(i=1; i<19; i++) tw->slc[i] = -1; /* * All parameters were zeroed when the socket * was allocated in TCPIP. */ tw->pnum = sknum; tw->termstate = VTTYPE; strncpy(tw->termtype,"vt100",sizeof(tw->termtype)); tw->termtype[sizeof(tw->termtype)-1] = 0; tw->linemode[0] = 0; tw->echo = 1; if(mp->delete==127) { tw->bksp = 8; tw->del = 127; } else { tw->bksp = 127; tw->del = 8; } tw->crfollow = mp->crmap; tw->halfdup = mp->halfdup; tw->width = 80; tw->rows = 24; tw->slc[SLC_IP] = 3; tw->slc[SLC_EC] = tw->del; tw->slc[SLC_EL] = 21; tw->slc[SLC_EOF] = 4; tw->slc[SLC_ABORT] = 3; return(0); } /* * inprocess * * take incoming data and process it. Close the connection if it * is the end of the connection. */ int inprocess(sknum) int sknum; { register struct socket *skt; register struct twin *tw; register int cnt; char s[80]; skt = (struct socket *) skvalid(sknum); if(skt==-1) return(A_BRK); tw = &(skt->session); cnt = skread(sknum,s,80); /* get some from incoming queue */ if(cnt<0) { /* close this session, if over */ skclose(sknum); skrelease(sknum,1); if(tw->capon) { rtclose(tw->capfp); /* close the capture file */ tw->capon = 0; } kb_puts("\r\nConnection closed.\r\n"); return(A_BRK); } if(cnt) { skdeque(sknum); /* dequeue the data */ parse(tw,s,cnt); /* display on screen, etc.*/ } return(0); } /* * parsewrite * * write out some chars from parse * Has a choice of where to send the stuff */ VOID parsewrite(tw,str,len) struct twin *tw; register char *str; int len; { register int i; register char *t; char s[86]; /* * send the string where it belongs * 1. Check for a capture file. If so, echo a copy of the string * 2. Check for dumb terminal type, convert special chars * 3. send to screen */ if(tw->capon) /* capture to file? */ fwrite(str,len,1,tw->capfp); /* * raw mode for debugging, passes through escape sequences * and other special characters as <27> symbols * * this attempts to output strings of characters * to reduce the overhead of single character i/o */ if(tw->termstate==DUMBTYPE) { for (t=s,i=0; i126) { kbprintf("<%d>",*str&0xFF); kb_puts(s); t = s; } else { t++; } } } else { for(t=s,i=0; itelstate) { case ESCFOUND: parsewrite(tw,"\033",1); /* send the missing ESC */ tw->telstate = STNORM; break; case IACFOUND: /* telnet option negotiation */ if(cst==IAC) { /* real data=255 */ tw->telstate = STNORM; st++; break; } if(248telstate = cst; /* by what the option is */ st++; break; } kbprintf("\r\n strange telnet option %d\r\n", cst & 0xFF); orig = st; tw->telstate = STNORM; break; case GOAHEAD: orig = st; tw->telstate = STNORM; break; case DOTEL: #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("RECV: %s %s\r\n", telstates[tw->telstate-WILLTEL],teloptions[cst]); } #endif switch(cst) { case SGA: if(!tw->igoahead) { /* suppress go-ahead */ /* IAC, WILLTEL, cst */ skwrite(tw->pnum,"\377\373",2); skwchar(tw->pnum,cst); tw->igoahead = 1; st++; #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[cst]); } #endif } else { #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("NO REPLY NEEDED: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[SGA]); } #endif } orig = st; tw->telstate = STNORM; break; case TERMTYPE: if (!tw->termsent) { /* IAC, WILLTEL, cst */ skwrite(tw->pnum,"\377\373",2); skwchar(tw->pnum,cst); tw->termsent = 1; st++; #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[cst]); } #endif } else { #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("NO REPLY NEEDED: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[TERMTYPE]); } #endif } orig = st; tw->telstate = STNORM; break; case LINEMODE: /* IAC, WILLTEL, LINEMODE, IAC, SB, LINEMODE, SLC */ skwrite(tw->pnum,"\377\373\042\377\372\042\003",7); #ifdef DEBUGOPTION if(debug&0x02) { kb_puts("SEND: SB LINEMODE SLC\r\n"); } #endif for (i=1; i<19; i++) { ss = s; *ss++ = i; if (tw->slc[i]==-1) { *ss++ = NO_SUPPORT; *ss++ = 0; } else { *ss++ = CANTCHANGE; *ss++ = tw->slc[i]; } skwrite(tw->pnum,s,3); #ifdef DEBUGOPTION if(debug&0x02) { if(tw->slc[i]==-1) { kbprintf(" %s NO_SUPPORT 0\r\n", LMoptions[i]); } else { kbprintf(" %s CANTCHANGE %d\r\n", LMoptions[i], tw->slc[i]); } } #endif } /* IAC, SE */ skwrite(tw->pnum,"\377\360",2); orig = st; tw->telstate = STNORM; break; case NAWS: /* IAC, SB, NAWS */ skwrite(tw->pnum,"\377\372\037",3); ss = s; *ss++ = 0; *ss++ = tw->width; *ss++ = 0; *ss++ = tw->rows; skwrite(tw->pnum,s,4); /* IAC, SE */ skwrite(tw->pnum,"\377\360",2); #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: SB NAWS 0 %d 0 %d IAC SE\r\n", tw->width & 0xFF, tw->rows & 0xFF); } #endif orig = st; tw->telstate = STNORM; break; default: /* refuse it */ /* IAC, WONTTEL, cst */ skwrite(tw->pnum,"\377\374",2); skwchar(tw->pnum,cst); st++; #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[WONTTEL-WILLTEL],teloptions[cst]); } #endif orig = st; tw->telstate = STNORM; break; } break; case DONTTEL: #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("RECV: %s %s\r\n", telstates[tw->telstate-WILLTEL],teloptions[cst]); } #endif orig = st; tw->telstate = STNORM; break; case WILLTEL: #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("RECV: %s %s\r\n", telstates[tw->telstate-WILLTEL],teloptions[cst]); } #endif tw->telstate = STNORM; nst = *(++st) & 0xFF; switch(cst) { case SGA: /* suppress go-ahead */ if(tw->ugoahead) break; /* IAC, DOTEL, SGA */ skwrite(tw->pnum,"\377\375\003",3); tw->ugoahead = 1; #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[DOTEL-WILLTEL],teloptions[nst]); } #endif break; case ECHO: /* echo */ if(tw->echo) break; tw->echo = 1; /* IAC, DOTEL, ECHO */ skwrite(tw->pnum,"\377\375\001",3); skwrite(tw->pnum,tw->linemode,strlen(tw->linemode)); tw->linemode[0] = 0; #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[DOTEL-WILLTEL],teloptions[nst]); } #endif break; case TIMING: break; default: /* refuse it */ /* IAC, DONTTEL, cst */ skwrite(tw->pnum,"\377\376",2); skwchar(tw->pnum,cst); #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("SEND: %s %s\r\n", telstates[DONTTEL-WILLTEL],teloptions[nst]); } #endif break; } orig = st; break; case WONTTEL: #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("RECV: %s %s\r\n", telstates[tw->telstate-WILLTEL],teloptions[cst]); } #endif switch(cst) { /* which option? */ case ECHO: /* echo */ if(!tw->echo) break; /* IAC, DONTTEL, ECHO */ skwrite(tw->pnum,"\377\376\001",3); tw->echo = 0; break; case TIMING: break; default: break; } st++; orig = st; tw->telstate = STNORM; break; case SB: orig = st; i = tw->substate = 0; /* Defined for each */ tw->telstate = NEGOTIATE; break; case NEGOTIATE: if(tw->substate <200) { switch(cst) { case IAC: parsedat[i] = 0; tw->substate = cst; break; default: parsedat[i++] = cst; break; } st++; } else { switch( tw->substate) { case IAC: tw->substate = cst; st++; if (tw->substate==SE) { switch( parsedat[0]) { case TERMTYPE: if (parsedat[1]==1) { /* IAC, SB, TERMTYPE, 0 */ skwrite(tw->pnum,"\377\372\030\000",4); skwrite(tw->pnum, tw->termtype, strlen(tw->termtype)); /* IAC, SE */ skwrite(tw->pnum,"\377\360",2); #ifdef DEBUGOPTION if(debug&0x02) { kb_puts("RECV: SB TERMINAL-TYPE SEND\r\n"); kb_puts("SEND: SB TERMINAL-TYPE IS "); kb_puts(tw->termtype); kb_nline(); } #endif } break; case LINEMODE: switch(parsedat[1]) { case MODE: if (parsedat[2] & EDIT) { tw->lmflag = 1; } else { tw->lmflag = 0; } /* IAC, SB, LINEMODE, MODE */ skwrite(tw->pnum,"\377\372\042\001",4); skwchar(tw->pnum,parsedat[2]|MODE_ACK); /* IAC, SE */ skwrite(tw->pnum,"\377\360",2); #ifdef DEBUGOPTION if(debug&0x02) { kbprintf("RECV: LINEMODE MODE %d\r\n", parsedat[2] & 0xFF); } #endif break; case DOTEL: /* IAC, SB, LINEMODE */ /* WONTTEL, TRAPSIG */ /* IAC, SE */ skwrite(tw->pnum, "\377\372\042\374\002\377\360",7); break; case WILLTEL: /* IAC, SB, LINEMODE */ /* DONTTEL, TRAPSIG */ /* IAC, SE */ skwrite(tw->pnum, "\377\372\042\376\002\377\360",7); break; case SLC: #ifdef DEBUGOPTION if(debug&0x02) { kb_puts("RECV: SB LINEMODE SLC\r\n"); for(i=2;(parsedat[i]!=0) && (parsedat[i]!=IAC); i+=3) { if(parsedat[i+1] & SLC_AWK) { kbprintf(" %s %s|AWK %d\r\n", LMoptions[parsedat[i]], LMflags[parsedat[i+1] & SLC_LEVELBITS], parsedat[i+2]); } else { kbprintf(" %s %s %d\r\n", LMoptions[parsedat[i]], LMflags[parsedat[i+1] & SLC_LEVELBITS], parsedat[i+2]); } } } #endif /* First check to see if we need to reply */ for(i=2;(parsedat[i]!=0) && (parsedat[i]!=IAC); i+=3) { if(!(parsedat[i+1] & SLC_AWK)) break; } /* if we do then send a reply */ #ifdef DEBUGOPTION if(debug&0x02) { kb_puts("SEND: SB LINEMODE SLC\r\n"); } #endif if ((parsedat[i]!=IAC) && (parsedat[i]!=0)) { /* IAC, SB, LINEMODE, SLC */ skwrite(tw->pnum,"\377\372\042\003",4); for (i=2; (parsedat[i]!=0) && (parsedat[i]!=IAC); i+=3) { if (!(parsedat[i+1] & SLC_AWK)) { ss = s; *ss++ = i; if (tw->slc[parsedat[i]]==-1) { *ss++ = NO_SUPPORT; *ss++ = 0; } else { *ss++ = CANTCHANGE; *ss++ = tw->slc[parsedat[i]]; } skwrite(tw->pnum,s,3); #ifdef DEBUGOPTION if(debug&0x02) { if(tw->slc[parsedat[i]]==-1) { kbprintf(" %s NO_SUPPORT 0\r\n", LMoptions[parsedat[i]]); } else { kbprintf(" %s CANTCHANGE %d\r\n", LMoptions[parsedat[i]], tw->slc[parsedat[i]]); } } #endif } } /* IAC, SE */ skwrite(tw->pnum,"\377\360",2); } /* otherwise just exit */ break; default: break; } break; default: break; } } orig = st; tw->telstate = STNORM; break; default: orig = st; tw->telstate = STNORM; break; } } break; default: tw->telstate = STNORM; break; } /* * quick scan of the remaining string, * skip chars while they are uninteresting */ if(tw->telstate==STNORM) { /* * skip along as fast as possible until * an interesting character is found */ while(stbinary) *st &= 0x7F; /* mask off high bit */ st++; } parsewrite(tw,orig,st-orig); orig = st; /* forget what we have sent already */ if(sttelstate = IACFOUND; break; case 27: /* ESCape code */ if(st==mark || (*st & 0xFF)==12 || (*st & 0xFF)=='^') tw->telstate = ESCFOUND; break; default: kbprintf("strange char -- value = 0x%4.4X\r\n", cst); break; } } } } /* * process this */ if(pushsk) skenque(tw->pnum,1); } /* newkey * * filter for command key sequences */ int newkey(tw) register struct twin *tw; { register int c; int ch; if(fndbrk) { fndbrk = 0; c = A_BRK; } else if(tw->lmflag) { /* Telnet line mode is on */ c = kb_gets(tw->linemode,79,!tw->echo); if(c==13) { /* pressed return */ parse(tw,"\r\n",2); /* echo the return */ strcat(tw->linemode,"\r\n"); skwrite(tw->pnum,tw->linemode,strlen(tw->linemode)); tw->linemode[0] = 0; c = 0; } else if(c>0) { /* write string, pass c to command interp */ if(tw->linemode[0]) { skwrite(tw->pnum,tw->linemode,strlen(tw->linemode)); tw->linemode[0] = 0; } } } else if(tw->echo) { c = kb_char(); /* a char available ? */ } else if(tw->halfdup) { /* half duplex */ c = kb_char(); if(c==13) { parse(tw,"\r\n",2); /* echo crlf */ skwchar(tw->pnum,13); c = 10; } else if(c>0 && c<128) { ch = c; parse(tw,(char *)&ch,1); /* echo char */ } } else { /* kludge linemode */ c = kb_gets(tw->linemode,79,1); if(c==13) { /* pressed return */ parse(tw,"\r\n",2); /* echo the return */ strcat(tw->linemode,"\r\n"); skwrite(tw->pnum,tw->linemode,strlen(tw->linemode)); tw->linemode[0] = 0; c = 0; } else if(c>0) { /* write string, pass c to command interp */ if(tw->linemode[0]) { skwrite(tw->pnum,tw->linemode,strlen(tw->linemode)); tw->linemode[0] = 0; } } } if(c>0) c = dokey(tw,c); if(pushsk) skenque(tw->pnum,1); return(c); } /* * dokey * * Translates, * filters for command keys, * and sends keys. */ int dokey(tw,c) register struct twin *tw; register int c; { register struct socket *skt; char *xxip; char s[80]; int i; switch (c) { case 8: c = tw->bksp; /* different bs mapping */ break; case 13: /* different CR mapping */ skwchar(tw->pnum,c); skwchar(tw->pnum,tw->crfollow); c = 0; break; case 127: c = tw->del; /* different del mapping */ break; case THENUL: /* user wants the true NUL char */ skwchar(tw->pnum,0); c = 0; break; case A_C: /* open capture file */ if(!tw->capon) { kb_puts("\r\nEnter capture file name, ESC to abort: "); s[0] = 0; while(0>=(i = kb_gets(s,sizeof(s)-1,1))) suspnd(0); if(i!=27 && s[0]!=0) { kb_nline(); if((tw->capfp = rtopen(s,"wn",1,1)) != NULL) { tw->capon = 1; stptok(tw->capfp->io_name, tw->capfil, 15, "["); strlwr(tw->capfil); } } } if(tw->capon) { kbprintf("\r\nCapture file %s is open.", tw->capfil); } kb_nline(); c = 0; break; case A_D: /* close capture file */ if(tw->capon) { rtclose(tw->capfp); tw->capon = 0; kbprintf("\r\nCapture file %s is closed.\r\n", tw->capfil); } else { kb_puts("\r\nCapture file not open.\r\n"); } c = 0; break; case A_F: /* an ftp command */ skt = (struct socket *) mapskt(tw->pnum); xxip = skt->tcpout.i.ipsource; sprintf(s,"ftp %d.%d.%d.%d\r\n", *(xxip+0)&0xFF, *(xxip+1)&0xFF, *(xxip+2)&0xFF, *(xxip+3)&0xFF); skwrite(tw->pnum,s,strlen(s)); if(!tw->echo) parse(tw,s,strlen(s)); c=0; break; case A_H: /* help display */ printtxt(hlptxt); kbprintf("bksp = %d / del = %d / crfollow = %s\r\n\r\n", tw->bksp, tw->del, tw->crfollow ? "LINEFEED" : "NUL"); c = 0; break; case A_I: /* my internet address */ case A_J: /* their internet address */ skt = (struct socket *) mapskt(tw->pnum); if(c==A_I) { xxip = skt->tcpout.i.ipsource; } else { xxip = skt->tcpout.i.ipdest; } sprintf(s,"%d.%d.%d.%d", *(xxip+0)&0xFF, *(xxip+1)&0xFF, *(xxip+2)&0xFF, *(xxip+3)&0xFF); skwrite(tw->pnum,s,strlen(s)); if(!tw->echo) /* echo the string */ parse(tw,s,strlen(s)); c = 0; break; case A_K: /* erase char */ skwrite(tw->pnum,"\377\367",2); c = 0; break; case A_O: /* abort output */ skwrite(tw->pnum,"\377\365",2); skempty(tw->pnum); c = 0; break; case A_Q: /* are you there? */ skwrite(tw->pnum,"\377\366",2); c = 0; break; case A_R: /* toggle crfollow character */ if(tw->crfollow) { tw->crfollow = 0; } else { tw->crfollow = 10; } kbprintf("crfollow = %s\r\n", tw->crfollow ? "LINEFEED" : "NUL"); c = 0; break; case A_S: /* skip to end */ skempty(tw->pnum); c = 0; break; case A_T: /* toggle backspace / delete */ c = tw->bksp; tw->bksp = tw->del; tw->del = c; kbprintf("bksp = %d / del = %d\r\n", tw->bksp,tw->del); c = 0; break; case A_U: /* erase line */ skwrite(tw->pnum,"\377\370",2); c = 0; break; case A_X: /* close the connection */ kb_puts("\r\nClose the connection? (Y/N) "); kb_out(c = kb_gchar()); if(tolower(c)=='y') { kb_puts("\r\n Attempting to close . . ."); skptuev(ABORTCLASS,USERABORT,tw->pnum); } kb_nline(); c = 0; break; case A_Y: /* interrupt */ skwrite(tw->pnum,"\377\364",2); skempty(tw->pnum); c = 0; break; case A_BRK: /* abort Telnet */ kb_puts("\r\nAbort the connection? (Y/N) "); kb_out(c = kb_gchar()); kb_nline(); if(tolower(c)=='y') { if(tw->capon) { rtclose(tw->capfp); /* close the capture file */ tw->capon = 0; } skclose(tw->pnum); skrelease(tw->pnum,1); return(A_BRK); } c = 0; break; default: break; } if(c>0) skwchar(tw->pnum,c); return(c); } /* * This is the error print routine for TSXUTL.C * It will be called only if there is an internal error */ VOID lsterr() { if(*errstr) { kb_puts(errstr); kb_nline(); errstr[0] = '\0'; } } /* * General looping question routine * loops until a response is given * returns 1 on ABORT * else 0 */ static int question(cstr,clen,qstr) char *cstr,*qstr; int clen; { while(!(*(stpblk(cstr)))) { /* * get arg from user */ kb_puts(qstr); if(rtresp(cstr,clen)) return(1); } return(0); } /* * Routine to get a keyboard response * returns 1 on ABORT * else 0 */ int rtresp(st,ln) char *st; int ln; { return((keygets(st,ln,1)==ABORT) ? 1 : 0); } /* * keygets * * read a line from the keyboard * returns ABORT if keyboard input aborted * or non-zero on success */ int keygets(str,lim,echo) register char *str; /* where to put the line */ int lim,echo; /* max chars to read, echo? */ { register char *save; int c; save = str; /* beginning of line */ *save = '\0'; if(fndbrk) { fndbrk = 0; kb_puts("^C\r\n"); return(ABORT); } while(1) { /* * build string from keyboard */ c = kb_gets(str,lim,echo); if(1 <= c && c <= 31) { kb_nline(); return(strlen(save)); } /* * check for abort */ if(fndbrk) { fndbrk = 0; *save = '\0'; kb_puts("^C\r\n"); return(ABORT); } suspnd(0); } } /* * getword: remove a word from a string. Things within quotes are * assumed to be one word. * return TRUE on success, FALSE on end of string */ static int getword(string,word) char *string; register char *word; { register char *p; register int i; char *q; i = 0; /* * skip leading blanks */ p = stpblk(string); if(!(*p)) { /* * no words in string */ word[0] = '\0'; return(FALSE); } if(*p == '\"') { /* * word delimited by quotes */ while(p[++i] && p[i] != '\"') word[i-1] = p[i]; word[i-1] = '\0'; if(!p[i]) { /* * Missing \". Assumed at end of string. */ } else { i++; } q = p+i; } else { /* * get word, max len 79 */ q = stptok(p, word, 79, " \t\r\n"); } /* * remove trailing blanks */ p = stpblk(q); /* * remove extracted stuff */ strcpy(string,p); return(TRUE); } static char *stptok( p, toword, ilen, delim) register char *p; char *toword; int ilen; char *delim; { register char *adv; register int i; int j,end; adv = toword; end = 0; j = strlen(delim); do { for(i=0; i= (toword+ilen-1)) end++; *adv++=*p++; } } while(!end); *adv='\0'; return(p); } static char *stpblk(ch) register char *ch; { while(*ch == ' ' || *ch == '\t') ch++; return(ch); } static VOID strlwr(st) register char *st; { while(*st) { *st = tolower(*st); *st++; } } /* * chkusr * * Check the password file for the user/password * combination. An inaccessable password file * results in an invalid return. * * If the user/password are validated and * the user has the rquired privelege, * then a valid return is made. * * Returns valid(0)/invalid(1) */ int chkusr() { FILE *fp; struct userblock user; char username[USERPASSLEN+2]; char password[USERPASSLEN+2]; char command[100]; char word[100]; /* * username */ if(question(command,100,"Username: ")) return(1); getword(command,word); username[0] = '\0'; strncat(username,word,USERPASSLEN); strlwr(username); /* * password */ if(!(*stpblk(command))) { kb_puts("Password: "); if(keygets(command,100,0) == ABORT) return(1); } getword(command,word); password[0] = '\0'; strncat(password,word,USERPASSLEN); strlwr(password); /* * Check username / password file */ if(NULL==(fp = rtopen(pass,"rn",0,0))) { return(1); } while (NULL != fread(&user,sizeof(struct userblock),1,fp)) { /* * does username / password check ? */ if(!strncmp(username,&user.username,USERPASSLEN) && (user.userflag[0]&PASSNOTREQUIRED || Scompass(password,&user.password)) ) { rtclose(fp); /* * Check Telnet privileges */ if(!(user.userflag[1] & LTELNET_PRIV)) { kb_puts("No Privilege for TELNET\r\n"); return(1); } /* * User valid */ return(0); } } kb_puts("Invalid Username / Password.\r\n"); rtclose(fp); return(1); } /* * Scompass ( ps, en ) * * Compute and check the encrypted password */ int Scompass(ps,en) char *ps,*en; { int i,ck; char *p,c; ck = 0; p = ps; /* * checksum the string */ while (*p) ck += *p++; c = ck; /* * XOR with checksum */ i = USERPASSLEN; while (i--) { if((((*ps ^ c)|32)&127)!=*en) return(0); /* * increment checksum to hide length */ if(*ps) { ps++; } else { c++; } en++; } return(1); } /* * printout text */ VOID printtxt(txt) char **txt; { char **dp; for (dp = txt; *dp; dp++) { kb_puts(*dp); kb_nline(); } }