138905Sborman /* 238905Sborman * Copyright (c) 1989 Regents of the University of California. 338905Sborman * All rights reserved. 438905Sborman * 5*42673Sbostic * %sccs.include.redist.c% 638905Sborman */ 738905Sborman 838905Sborman #ifndef lint 9*42673Sbostic static char sccsid[] = "@(#)utility.c 5.3 (Berkeley) 06/01/90"; 1038905Sborman #endif /* not lint */ 1138905Sborman 1238905Sborman 1338905Sborman #include "telnetd.h" 1438905Sborman 1538905Sborman /* 1638905Sborman * utility functions performing io related tasks 1738905Sborman */ 1838905Sborman 1938905Sborman /* 2038905Sborman * ttloop 2138905Sborman * 2238905Sborman * A small subroutine to flush the network output buffer, get some data 2338905Sborman * from the network, and pass it through the telnet state machine. We 2438905Sborman * also flush the pty input buffer (by dropping its data) if it becomes 2538905Sborman * too full. 2638905Sborman */ 2738905Sborman 2838905Sborman void 2938905Sborman ttloop() 3038905Sborman { 3138905Sborman void netflush(); 3238905Sborman 3338905Sborman if (nfrontp-nbackp) { 3438905Sborman netflush(); 3538905Sborman } 3638905Sborman ncc = read(net, netibuf, sizeof netibuf); 3738905Sborman if (ncc < 0) { 3838905Sborman syslog(LOG_INFO, "ttloop: read: %m\n"); 3938905Sborman exit(1); 4038905Sborman } else if (ncc == 0) { 4138905Sborman syslog(LOG_INFO, "ttloop: peer died: %m\n"); 4238905Sborman exit(1); 4338905Sborman } 4438905Sborman netip = netibuf; 4538905Sborman telrcv(); /* state machine */ 4638905Sborman if (ncc > 0) { 4738905Sborman pfrontp = pbackp = ptyobuf; 4838905Sborman telrcv(); 4938905Sborman } 5038905Sborman } /* end of ttloop */ 5138905Sborman 5238905Sborman /* 5338905Sborman * Check a descriptor to see if out of band data exists on it. 5438905Sborman */ 5538905Sborman stilloob(s) 5638905Sborman int s; /* socket number */ 5738905Sborman { 5838905Sborman static struct timeval timeout = { 0 }; 5938905Sborman fd_set excepts; 6038905Sborman int value; 6138905Sborman 6238905Sborman do { 6338905Sborman FD_ZERO(&excepts); 6438905Sborman FD_SET(s, &excepts); 6538905Sborman value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout); 6638905Sborman } while ((value == -1) && (errno == EINTR)); 6738905Sborman 6838905Sborman if (value < 0) { 6938905Sborman fatalperror(pty, "select"); 7038905Sborman } 7138905Sborman if (FD_ISSET(s, &excepts)) { 7238905Sborman return 1; 7338905Sborman } else { 7438905Sborman return 0; 7538905Sborman } 7638905Sborman } 7738905Sborman 7838905Sborman ptyflush() 7938905Sborman { 8038905Sborman int n; 8138905Sborman 8238905Sborman if ((n = pfrontp - pbackp) > 0) 8338905Sborman n = write(pty, pbackp, n); 8438905Sborman if (n < 0) 8538905Sborman return; 8638905Sborman pbackp += n; 8738905Sborman if (pbackp == pfrontp) 8838905Sborman pbackp = pfrontp = ptyobuf; 8938905Sborman } 9038905Sborman 9138905Sborman /* 9238905Sborman * nextitem() 9338905Sborman * 9438905Sborman * Return the address of the next "item" in the TELNET data 9538905Sborman * stream. This will be the address of the next character if 9638905Sborman * the current address is a user data character, or it will 9738905Sborman * be the address of the character following the TELNET command 9838905Sborman * if the current address is a TELNET IAC ("I Am a Command") 9938905Sborman * character. 10038905Sborman */ 10138905Sborman char * 10238905Sborman nextitem(current) 10338905Sborman char *current; 10438905Sborman { 10538905Sborman if ((*current&0xff) != IAC) { 10638905Sborman return current+1; 10738905Sborman } 10838905Sborman switch (*(current+1)&0xff) { 10938905Sborman case DO: 11038905Sborman case DONT: 11138905Sborman case WILL: 11238905Sborman case WONT: 11338905Sborman return current+3; 11438905Sborman case SB: /* loop forever looking for the SE */ 11538905Sborman { 11638905Sborman register char *look = current+2; 11738905Sborman 11838905Sborman for (;;) { 11938905Sborman if ((*look++&0xff) == IAC) { 12038905Sborman if ((*look++&0xff) == SE) { 12138905Sborman return look; 12238905Sborman } 12338905Sborman } 12438905Sborman } 12538905Sborman } 12638905Sborman default: 12738905Sborman return current+2; 12838905Sborman } 12938905Sborman } /* end of nextitem */ 13038905Sborman 13138905Sborman 13238905Sborman /* 13338905Sborman * netclear() 13438905Sborman * 13538905Sborman * We are about to do a TELNET SYNCH operation. Clear 13638905Sborman * the path to the network. 13738905Sborman * 13838905Sborman * Things are a bit tricky since we may have sent the first 13938905Sborman * byte or so of a previous TELNET command into the network. 14038905Sborman * So, we have to scan the network buffer from the beginning 14138905Sborman * until we are up to where we want to be. 14238905Sborman * 14338905Sborman * A side effect of what we do, just to keep things 14438905Sborman * simple, is to clear the urgent data pointer. The principal 14538905Sborman * caller should be setting the urgent data pointer AFTER calling 14638905Sborman * us in any case. 14738905Sborman */ 14838905Sborman netclear() 14938905Sborman { 15038905Sborman register char *thisitem, *next; 15138905Sborman char *good; 15238905Sborman #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 15338905Sborman ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 15438905Sborman 15538905Sborman thisitem = netobuf; 15638905Sborman 15738905Sborman while ((next = nextitem(thisitem)) <= nbackp) { 15838905Sborman thisitem = next; 15938905Sborman } 16038905Sborman 16138905Sborman /* Now, thisitem is first before/at boundary. */ 16238905Sborman 16338905Sborman good = netobuf; /* where the good bytes go */ 16438905Sborman 16538905Sborman while (nfrontp > thisitem) { 16638905Sborman if (wewant(thisitem)) { 16738905Sborman int length; 16838905Sborman 16938905Sborman next = thisitem; 17038905Sborman do { 17138905Sborman next = nextitem(next); 17238905Sborman } while (wewant(next) && (nfrontp > next)); 17338905Sborman length = next-thisitem; 17438905Sborman bcopy(thisitem, good, length); 17538905Sborman good += length; 17638905Sborman thisitem = next; 17738905Sborman } else { 17838905Sborman thisitem = nextitem(thisitem); 17938905Sborman } 18038905Sborman } 18138905Sborman 18238905Sborman nbackp = netobuf; 18338905Sborman nfrontp = good; /* next byte to be sent */ 18438905Sborman neturg = 0; 18538905Sborman } /* end of netclear */ 18638905Sborman 18738905Sborman /* 18838905Sborman * netflush 18938905Sborman * Send as much data as possible to the network, 19038905Sborman * handling requests for urgent data. 19138905Sborman */ 19238905Sborman void 19338905Sborman netflush() 19438905Sborman { 19538905Sborman int n; 19638905Sborman extern int not42; 19738905Sborman 19838905Sborman if ((n = nfrontp - nbackp) > 0) { 19938905Sborman /* 20038905Sborman * if no urgent data, or if the other side appears to be an 20138905Sborman * old 4.2 client (and thus unable to survive TCP urgent data), 20238905Sborman * write the entire buffer in non-OOB mode. 20338905Sborman */ 20438905Sborman if ((neturg == 0) || (not42 == 0)) { 20538905Sborman n = write(net, nbackp, n); /* normal write */ 20638905Sborman } else { 20738905Sborman n = neturg - nbackp; 20838905Sborman /* 20938905Sborman * In 4.2 (and 4.3) systems, there is some question about 21038905Sborman * what byte in a sendOOB operation is the "OOB" data. 21138905Sborman * To make ourselves compatible, we only send ONE byte 21238905Sborman * out of band, the one WE THINK should be OOB (though 21338905Sborman * we really have more the TCP philosophy of urgent data 21438905Sborman * rather than the Unix philosophy of OOB data). 21538905Sborman */ 21638905Sborman if (n > 1) { 21738905Sborman n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 21838905Sborman } else { 21938905Sborman n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 22038905Sborman } 22138905Sborman } 22238905Sborman } 22338905Sborman if (n < 0) { 22438905Sborman if (errno == EWOULDBLOCK || errno == EINTR) 22538905Sborman return; 22638905Sborman cleanup(); 22738905Sborman } 22838905Sborman nbackp += n; 22938905Sborman if (nbackp >= neturg) { 23038905Sborman neturg = 0; 23138905Sborman } 23238905Sborman if (nbackp == nfrontp) { 23338905Sborman nbackp = nfrontp = netobuf; 23438905Sborman } 23538905Sborman return; 23638905Sborman } /* end of netflush */ 23738905Sborman 23838905Sborman 23938905Sborman /* 24038905Sborman * writenet 24138905Sborman * 24238905Sborman * Just a handy little function to write a bit of raw data to the net. 24338905Sborman * It will force a transmit of the buffer if necessary 24438905Sborman * 24538905Sborman * arguments 24638905Sborman * ptr - A pointer to a character string to write 24738905Sborman * len - How many bytes to write 24838905Sborman */ 24938905Sborman writenet(ptr, len) 25038905Sborman register char *ptr; 25138905Sborman register int len; 25238905Sborman { 25338905Sborman /* flush buffer if no room for new data) */ 25438905Sborman if ((&netobuf[BUFSIZ] - nfrontp) < len) { 25538905Sborman /* if this fails, don't worry, buffer is a little big */ 25638905Sborman netflush(); 25738905Sborman } 25838905Sborman 25938905Sborman bcopy(ptr, nfrontp, len); 26038905Sborman nfrontp += len; 26138905Sborman 26238905Sborman } /* end of writenet */ 26338905Sborman 26438905Sborman 26538905Sborman /* 26638905Sborman * miscellaneous functions doing a variety of little jobs follow ... 26738905Sborman */ 26838905Sborman 26938905Sborman 27038905Sborman fatal(f, msg) 27138905Sborman int f; 27238905Sborman char *msg; 27338905Sborman { 27438905Sborman char buf[BUFSIZ]; 27538905Sborman 27638905Sborman (void) sprintf(buf, "telnetd: %s.\r\n", msg); 27738905Sborman (void) write(f, buf, (int)strlen(buf)); 27838905Sborman sleep(1); /*XXX*/ 27938905Sborman exit(1); 28038905Sborman } 28138905Sborman 28238905Sborman fatalperror(f, msg) 28338905Sborman int f; 28438905Sborman char *msg; 28538905Sborman { 28642411Sbostic char buf[BUFSIZ], *strerror(); 28738905Sborman 28842411Sbostic (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); 28938905Sborman fatal(f, buf); 29038905Sborman } 29138905Sborman 29238905Sborman char editedhost[32]; 29338905Sborman 29438905Sborman edithost(pat, host) 29538905Sborman register char *pat; 29638905Sborman register char *host; 29738905Sborman { 29838905Sborman register char *res = editedhost; 29938905Sborman char *strncpy(); 30038905Sborman 30138905Sborman if (!pat) 30238905Sborman pat = ""; 30338905Sborman while (*pat) { 30438905Sborman switch (*pat) { 30538905Sborman 30638905Sborman case '#': 30738905Sborman if (*host) 30838905Sborman host++; 30938905Sborman break; 31038905Sborman 31138905Sborman case '@': 31238905Sborman if (*host) 31338905Sborman *res++ = *host++; 31438905Sborman break; 31538905Sborman 31638905Sborman default: 31738905Sborman *res++ = *pat; 31838905Sborman break; 31938905Sborman } 32038905Sborman if (res == &editedhost[sizeof editedhost - 1]) { 32138905Sborman *res = '\0'; 32238905Sborman return; 32338905Sborman } 32438905Sborman pat++; 32538905Sborman } 32638905Sborman if (*host) 32738905Sborman (void) strncpy(res, host, 32838905Sborman sizeof editedhost - (res - editedhost) -1); 32938905Sborman else 33038905Sborman *res = '\0'; 33138905Sborman editedhost[sizeof editedhost - 1] = '\0'; 33238905Sborman } 33338905Sborman 33438905Sborman static char *putlocation; 33538905Sborman 33638905Sborman putstr(s) 33738905Sborman register char *s; 33838905Sborman { 33938905Sborman 34038905Sborman while (*s) 34138905Sborman putchr(*s++); 34238905Sborman } 34338905Sborman 34438905Sborman putchr(cc) 34538905Sborman { 34638905Sborman *putlocation++ = cc; 34738905Sborman } 34838905Sborman 34938905Sborman putf(cp, where) 35038905Sborman register char *cp; 35138905Sborman char *where; 35238905Sborman { 35338905Sborman char *slash; 35438905Sborman #ifndef NO_GETTYTAB 35538905Sborman char datebuffer[60]; 35638905Sborman #endif /* NO_GETTYTAB */ 35738905Sborman extern char *rindex(); 35838905Sborman 35938905Sborman putlocation = where; 36038905Sborman 36138905Sborman while (*cp) { 36238905Sborman if (*cp != '%') { 36338905Sborman putchr(*cp++); 36438905Sborman continue; 36538905Sborman } 36638905Sborman switch (*++cp) { 36738905Sborman 36838905Sborman case 't': 36938905Sborman slash = rindex(line, '/'); 37038905Sborman if (slash == (char *) 0) 37138905Sborman putstr(line); 37238905Sborman else 37338905Sborman putstr(&slash[1]); 37438905Sborman break; 37538905Sborman 37638905Sborman case 'h': 37738905Sborman putstr(editedhost); 37838905Sborman break; 37938905Sborman 38038905Sborman #ifndef NO_GETTYTAB 38138905Sborman case 'd': 38238905Sborman get_date(datebuffer); 38338905Sborman putstr(datebuffer); 38438905Sborman break; 38538905Sborman #endif /* NO_GETTYTAB */ 38638905Sborman 38738905Sborman case '%': 38838905Sborman putchr('%'); 38938905Sborman break; 39038905Sborman } 39138905Sborman cp++; 39238905Sborman } 39338905Sborman } 39438905Sborman 39538905Sborman /*ARGSUSED*/ 39638905Sborman #ifdef NO_GETTYTAB 39738905Sborman getent(cp, name) 39838905Sborman char *cp, *name; 39938905Sborman { 40038905Sborman return(0); 40138905Sborman } 40238905Sborman 40338905Sborman /*ARGSUSED*/ 40438905Sborman char * 40538905Sborman getstr(cp, cpp) 40638905Sborman char *cp, **cpp; 40738905Sborman { 40838905Sborman return(0); 40938905Sborman } 41038905Sborman #endif /* NO_GETTYTAB */ 411