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