/* rcnct.c */ #define RCNCTMASTER /* * Includes */ #include #include #include "vrcnct.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 rcnctd(); extern int parse(); 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 " RCNCT [?] [-d level] [-hmp filespec] [-acelrt] [parameters]", " d level Debug Level", " 1 - enable event printing", " ? List the Help Text and Exit RCNCT", #else " RCNCT [?] [-hmp filespec] [-acelrt] [parameters]", " ? List the Help Text and Exit RCNCT", #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 RCNCT after Disconnect", " t j TSX line j is cross connected to CL line i", "", 0 }; /* Definitions for supported telnet protocols */ #define IP 244 /* \364 */ #define AO 245 /* \365 */ #define AYT 246 /* \366 */ #define IAC 255 /* \377 */ #define IACFOUND 6 #define CRFOUND 3 #define STNORM 0 /* * 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 */ rcncskt = -1, /* RCNCT 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; 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:rcnct.msg"; /* message file */ char *help = "sy:rcnct.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; i 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 CNCT Server */ VOID rcnctd(code) int code; { register int c,cnt,i; char word[80],*p,s[80]; FILE *fp; if(rcncskt < 0) return; /* * Take incoming data and process it. */ if(cnctopen) { cnt = skread(rcncskt,s,80); if(cnt > 0) { skdeque(rcncskt); 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(rcncskt >= 0) { sksendwait(rcncskt,1,(long) SENDWAIT); skclose(rcncskt); rcncskt = skrelease(rcncskt,1); } if(rflag && !aflag) { /* * Start listening to the remote CNCT 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; p = skt->tcpout.i.ipsource; sprintf(rsp, /*Net*/ " %s\r\n", vrstxt[1] /*Net*/ ); rctresp(rsp); sprintf(rsp, /*Net*/ " Remote CNCT 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 { if((fp = rtopen(help,"r",0,0)) != NULL) { transfer(fp); rtclose(fp); } /* * Log Session */ logsession(rcncskt,"RCNCT:"); 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("rcnctd(%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*/ "RCNCT: %s", username /*Log*/ ); logsession(rcncskt,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(rcncskt,&outbuffer[outidx],outcnt); } if(outcnt>0) { /* * send successful, adjust counts */ outidx += outcnt; skenque(rcncskt,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(rcncskt,"\010\040\010",3); skenque(rcncskt,1); } if(waitpos) { --waitpos; } continue; } else { if(echo) { skwchar(rcncskt,c); skenque(rcncskt,1); } } if(command[waitpos] == '\r') { skwrite(rcncskt,"\r\n",2); skenque(rcncskt,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; } } /* * parse * * Parse the incoming date for specific telnet style commands */ int parse(c) register int c; { register int *telstate; c &= 0xFF; /* * telnet modes */ telstate = &(skt->session.telstate); switch(*telstate) { case CRFOUND: if(c == '\012') { return('\0'); } case STNORM: if(c == IAC) { *telstate = IACFOUND; return('\0'); } else if(c == '\015') { *telstate = CRFOUND; } return(c); case IACFOUND: switch(c) { case IP: c = 'C' & 0x1F; break; case AO: c = 'O' & 0x1F; break; case AYT: rctresp( /*Net*/ "Remote CNCT Running\r\n" /*Net*/ ); default: c = '\0'; break; } break; default: break; } *telstate = STNORM; return(c); } /* * 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(!(RCNCT_PRIV & user.userflag[1])) { sprintf(rsp, /*Net*/ "User '%s' does not have remote CNCT 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); }