xref: /csrg-svn/libexec/telnetd/utility.c (revision 42673)
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