/* rtlnta.c */ #define RTELNETMASTER /* * Includes */ #include #include #include "vrtel.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "kbkeys.h" #include "cliutl.h" #include "tsxutl.h" #include "rtfile.h" #include "kbdutl.h" #include "inicli.h" #include "jobmon.h" #include "usrblk.h" #include "suspnd.h" /* * Internal routines */ extern VOID printtxt(); extern int cltsxline(); extern int setrtel(); extern int dosess(); extern VOID rctresp(); extern VOID transfer(); extern VOID lsterr(); extern int rtresp(); extern char *stptok(); extern char *stpblk(); extern VOID strlwr(); extern int getword(); extern VOID rteld(); extern VOID initsession(); extern int parse(); extern int cparse(); extern int Scheckpass(); extern int Scompass(); /* * debug - * * bit 0 (0x01) enable printing of internal events * bit 1 (0x02) enable printing of telnet negotiations */ #define DBUGTRUE -1 /* all debuggers */ char *usetxt[] = { "", #ifdef DEBUGOPTION " RTELNT [?] [-d level] [-hmp filespec] [-acelrt] [parameters]", " ? List the Help Text and Exit RTELNT", " d level Debug Level", " 1 - enable event printing", #else " RTELNT [?] [-hmp filespec] [-acelrt] [parameters]", " ? List the Help Text and Exit RTELNT", #endif " a Attach to Service", " c i CL line i is cross connected to TSX line j", " e Enable Monitoring of all Transactions", " h Specify the Help Filespec", " l n Number of CL/TSX line pairs", " m Specify the Message Filespec", " p Specify the Password Filespec", " r Restart RTELNT after Disconnect", " t j TSX line j is cross connected to CL line i", "", 0 }; /* Definitions for telnet protocol */ #define ABORT (-3) #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 IACFOUND 6 #define CRFOUND 3 #define WILLSB 2 #define NEGOTIATE 1 #define STNORM 0 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" }; /* * Global Buffers / Pointers */ char pathname[94], /* path */ username[80], /* username */ password[80], /* password */ command[80], /* command string */ rsp[256], /* response string */ scratch[256]; /* scratch string */ struct userblock user; /* usernames / passwords / mailboxes */ char xs[2]; /* dumby buffer required by TSXUTL.C */ int aflag = 0, /* attach flag */ rflag = 0, /* restart flag */ mflag = 0, /* monitor flag */ pswdreqd = 1, /* password required */ clunit = -1, /* CL unit number */ tsxline = -1, /* TSX line number */ ctpairs = 1, /* CL/TSX line pairs */ cline = -1, /* CLn line in use */ tline = -1, /* TSX line in use */ cltl = -1, /* CL/TSX line error */ rtelcskt = -1, /* RTELNT socket number */ rfstate = 0, /* current process state */ retstate = 0, /* return state */ waitpos = 0, /* incoming command index */ echo = 1, /* echo flag */ cnctopen = 0, /* connection open flag */ cnctclose = 0, /* connection to be closed flag */ logincnt = 0; /* login retry counter */ struct socket /* socket structure */ *skt = NULL; struct twin /* window structure */ *tw = NULL; char parsedat[80]; /* Telnet parsing */ int pindex; /* parsing index */ char outbuffer[512]; int outcnt = 0, /* count to transfer */ outotal = 0, /* count left to transfer */ outidx = 0; /* array index */ char inpbuffer[256]; int inpcnt = 0, /* count to transfer */ rdidx = 0, /* read array index */ wrtidx = 0; /* write array index */ char *pass = "sy:paswrd.fil"; /* password file */ char *mesg = "sy:rtelnt.msg"; /* message file */ char *help = "sy:rtelnt.hlp"; /* help file */ /* * printout text */ VOID printtxt(txt) char **txt; { char **dp; for (dp = txt; *dp; dp++) { kb_puts(*dp); kb_nline(); } } main(argc,argv) int argc; char *argv[]; { int ev,i,j,k,c; /* * Initialize for TSX+ clients */ inicli(); /* * Initialize kb handler * Set the break character to ^C */ kb_init(0x03); /* * identify self */ printtxt(vrstxt); /* * parse arguments */ for(i=1; isession); return(sknum); } /* * dosess * * dosess is an infinite loop serving * incoming messages from TCPIP */ int dosess() { int cl,ev,dat; /* * 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: /* * RTELNT Connection Socket */ rteld(ev); break; case MSGCLASS: /* messages */ case ERRCLASS: /* error message */ kb_puts(skerrstring(ev)); kb_nline(); break; case ABORTCLASS: /* abort */ switch(ev) { case CLIENT: kbprintf("\r\nRTELNT session aborted by TCPIP\r\n"); Stmrset(ABORTCLASS,EXITABORT,dat,5); case USERABORT: if(skrelease(dat,0) < 0) { skptuev(CONCLASS,CONDATA,dat); } else { skclose(dat); Stmrset(ABORTCLASS,USERABORT,dat,1); } break; case EXITABORT: return(-1); break; default: break; } break; default: break; } } else { rteld(0); } return(ev); } /* * Dump response to client */ VOID rctresp(s) register char *s; { skwrite(rtelcskt, s, strlen(s)); skenque(rtelcskt, 1); if(mflag) { kbprintf(" {%d} ", strlen(s)); kb_puts(s); } } /* * transfer * * Transfer Message File */ transfer(fp) FILE *fp; { int fini; fini = FALSE; sprintf(rsp," "); do { if(skroom(rtelcskt) > LOWWATER) { if(fgetss(rsp+4,sizeof(rsp)-7,fp) != NULL) { strcat(rsp,"\r\n"); rctresp(rsp); } else { fini = TRUE; } } else { suspnd(0); } } while(fini != TRUE); } /* * 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'; } } /* * This routine is a dumby routine for TSXUTL.C * It should never be called, but returns a 1 [ABORT] */ int rtresp() { kb_puts("rtresp: This dumby routine should never be called"); return(1); } 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); } char *stpblk(ch) register char *ch; { while(*ch == ' ' || *ch == '\t') ch++; return(ch); } VOID strlwr(st) register char *st; { while(*st) { *st = tolower(*st); *st++; } } /* * 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 */ 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); } /* * Remote TELNET Server */ VOID rteld(code) int code; { register int c,cnt,i; char word[80],*p,s[80]; FILE *fp; if(rtelcskt < 0) return; /* * Take incoming data and process it. */ if(cnctopen) { cnt = skread(rtelcskt,s,80); if(cnt > 0) { skdeque(rtelcskt); for(p=s,i=0; i= sizeof(inpbuffer)) { wrtidx = 0; } } } } if(cnt < 0) { cnctclose = 1; } } /* * close this session, if over */ if((code == CONCLOSE) || (jbabrt() == tline) || cnctclose) { /* * Connection not open */ cnctopen = 0; cnctclose = 0; /* * Kill the TSX job attached through the CL unit */ killjob(tline); if(rtelcskt >= 0) { sksendwait(rtelcskt,1,(long) SENDWAIT); skclose(rtelcskt); rtelcskt = skrelease(rtelcskt,1); } if(rflag && !aflag) { /* * Start listening to the remote TELNET port */ while((setrtel()<0) && !fndbrk) { /* * Could not get a socket, wait 5 seconds */ suspnd(300); } } else { fndbrk = 1; } } switch(rfstate) { case 0: if(code!=CONOPEN) break; /* * Connection open */ cnctopen = 1; initsession(rtelcskt); p = skt->tcpout.i.ipsource; sprintf(rsp, /*Net*/ " %s\r\n", vrstxt[1] /*Net*/ ); rctresp(rsp); sprintf(rsp, /*Net*/ " Remote TELNET Server @%s [%d.%d.%d.%d]\r\n", skt->hostname, *(p+0)&0xFF, *(p+1)&0xFF, *(p+2)&0xFF, *(p+3)&0xFF /*Net*/ ); rctresp(rsp); p = skt->tcpout.i.ipdest; sprintf(rsp, /*Net*/ " Initiated from host: %d.%d.%d.%d\r\n", *(p+0)&0xFF, *(p+1)&0xFF, *(p+2)&0xFF, *(p+3)&0xFF /*Net*/ ); rctresp(rsp); if((fp = rtopen(mesg,"r",0,0)) != NULL) { transfer(fp); rtclose(fp); } if(pswdreqd) { /* * Request Username */ rctresp( /*Net*/ "Username> " /*Net*/ ); rfstate = 50; retstate = 1; echo = 1; } else { /* * Help File */ if((fp = rtopen(help,"r",0,0)) != NULL) { transfer(fp); rtclose(fp); } /* * Log Session */ logsession(rtelcskt,"RTELNT:"); sl_putc('\r'); rfstate = 3; retstate = 3; echo = 0; } waitpos = 0; break; case 1: if(getword(command,word) == FALSE) { /* * Request Username Again */ rctresp( /*Net*/ "Username> " /*Net*/ ); rfstate = 50; retstate = 1; waitpos = 0; echo = 1; break; } #ifdef DEBUGOPTION if(debug&0x04) { kbprintf("rteld(%d): %s %s\r\n", code,word,command); } #endif logincnt += 1; /* * keep user name */ username[0] = '\0'; strncat(username,word,USERPASSLEN); strlwr(username); /* * Request Password */ rctresp( /*Net*/ "Password> " /*Net*/ ); rfstate = 50; retstate = 2; waitpos = 0; echo = 0; break; case 2: /* * keep password */ password[0] = '\0'; strncat(password,command,USERPASSLEN); strlwr(password); if(Scheckpass(username,password)) { /* * User Specific Message File */ if(user.msgfil.path[0] != '\0' && (fp = rtopen(&user.msgfil.path,"r",0,0)) != NULL) { sprintf(rsp, /*Net*/ " Message to User %s\r\n", username /*Net*/ ); rctresp(rsp); transfer(fp); rtclose(fp); } /* * Help File */ if((fp = rtopen(help,"r",0,0)) != NULL) { transfer(fp); rtclose(fp); } /* * Log Session */ sprintf(scratch, /*Log*/ "RTELNT: %s", username /*Log*/ ); logsession(rtelcskt,scratch); sl_putc('\r'); rfstate = 3; retstate = 3; waitpos = 0; } else { if(logincnt >= 3) { cnctclose = 1; rfstate = 0; retstate = 0; break; } /* * Request Username Again */ rctresp( /*Net*/ "Invalid Username/Password\r\n\r\nUsername> " /*Net*/ ); rfstate = 50; retstate = 1; waitpos = 0; echo = 1; } break; case 3: /* * transfer CL line characters * to the other host via the NET */ if(outotal <= outidx) { /* * need to read again */ outcnt = sl_gets(outbuffer,sizeof(outbuffer)); outotal = outcnt; outidx = 0; } outcnt = outotal - outidx; if(outcnt>0) { outcnt = skwrite(rtelcskt,&outbuffer[outidx],outcnt); } if(outcnt>0) { /* * send successful, adjust counts */ outidx += outcnt; skenque(rtelcskt,1); } /* * transfer incoming characters to the CL line */ while(inpcnt) { if(sl_putc(inpbuffer[rdidx]) != EOF) { rdidx += 1; inpcnt -= 1; if(rdidx >= sizeof(inpbuffer)) { rdidx = 0; } } else { break; } } break; case 50: /* * subroutine to wait * for a particular character */ while(inpcnt) { c = inpbuffer[rdidx]; command[waitpos] = c; rdidx += 1; inpcnt -= 1; if(rdidx >= sizeof(inpbuffer)) { rdidx = 0; } if((c == '\177') || (c == '\010')) { if(echo && waitpos) { skwrite(rtelcskt,"\010\040\010",3); skenque(rtelcskt,1); } if(waitpos) { --waitpos; } continue; } else { if(echo) { skwchar(rtelcskt,c); skenque(rtelcskt,1); } } if(command[waitpos] == '\r') { skwrite(rtelcskt,"\r\n",2); skenque(rtelcskt,1); rfstate = retstate; /* * find end of string */ while ( (command[waitpos] < 33) && (waitpos >= 0) ) waitpos--; /* * put in terminator */ command[++waitpos] = '\0'; break; } else { if(waitpos < sizeof(inpbuffer)-1) waitpos += 1; } } break; default: break; } } /* * initsession * * initializes the session within the socket */ VOID initsession(sknum) int sknum; { int i; /* * All parameters were zeroed when the socket * was allocated in TCPIP. */ tw->pnum = sknum; /* * clear the machine string */ for(i=1; i<19; i++) tw->slc[i] = -1; tw->echo = 1; tw->igoahead = 1; tw->slc[SLC_IP] = 3; tw->slc[SLC_EC] = 127; tw->slc[SLC_EL] = 21; tw->slc[SLC_EOF] = 4; tw->slc[SLC_ABORT] = 3; /* Start negotiation on network */ /* IAC, WILLTEL, ECHO, IAC, WILLTEL, SGA */ skwrite(rtelcskt,"\377\373\001\377\373\003",6); /* IAC, DONTTEL, ECHO */ skwrite(rtelcskt,"\377\376\001",3); skenque(rtelcskt,1); #ifdef DEBUGOPTION if(debug&0x02) { /* Print to the console what we just did */ kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[ECHO]); kbprintf("SEND: %s %s\r\n", telstates[WILLTEL-WILLTEL],teloptions[SGA]); kbprintf("SEND: %s %s\r\n", telstates[DONTTEL-WILLTEL],teloptions[ECHO]); } #endif } /* * Scheckpass ( us, ps ) * * Check the password file for the user/password * combination. An inaccessable password file * results in an invalid return. * * If the user/password is invalid or the * default directory is not accessable * Scheckpass returns invalid. * * Returns valid(1)/invalid(0) */ int Scheckpass(us,ps) char *us,*ps; { FILE *fp; if(NULL==(fp = rtopen(pass,"rn",0,0))) { return(0); } while (NULL != fread(&user,sizeof(struct userblock),1,fp)) { /* * does password check ? */ if(!strncmp(us,&user.username,USERPASSLEN) && (PASSNOTREQUIRED & user.userflag[0] || Scompass(ps,&user.password))) { rtclose(fp); if(!(RTELNET_PRIV & user.userflag[1])) { sprintf(rsp, /*Net*/ "User '%s' does not have remote TELNET privilege\r\n", username /*Net*/ ); rctresp(rsp); return(0); } /* * Verify Users default directory */ getpath(pathname); if(cd(&user.defdir.path)) { /* * failed */ sprintf(rsp, /*Net*/ "%s\r\n", errstr /*Net*/ ); rctresp(rsp); cd(pathname); errstr[0] = '\0'; return(0); } else { /* * success */ cd(pathname); return(1); } } } rtclose(fp); return(0); } /* * 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); }