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