xref: /csrg-svn/libexec/telnetd/utility.c (revision 38905)
1*38905Sborman /*
2*38905Sborman  * Copyright (c) 1989 Regents of the University of California.
3*38905Sborman  * All rights reserved.
4*38905Sborman  *
5*38905Sborman  * Redistribution and use in source and binary forms are permitted
6*38905Sborman  * provided that the above copyright notice and this paragraph are
7*38905Sborman  * duplicated in all such forms and that any documentation,
8*38905Sborman  * advertising materials, and other materials related to such
9*38905Sborman  * distribution and use acknowledge that the software was developed
10*38905Sborman  * by the University of California, Berkeley.  The name of the
11*38905Sborman  * University may not be used to endorse or promote products derived
12*38905Sborman  * from this software without specific prior written permission.
13*38905Sborman  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38905Sborman  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38905Sborman  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*38905Sborman  */
17*38905Sborman 
18*38905Sborman #ifndef lint
19*38905Sborman static char sccsid[] = "@(#)utility.c	5.1 (Berkeley) 09/01/89";
20*38905Sborman #endif /* not lint */
21*38905Sborman 
22*38905Sborman 
23*38905Sborman #include "telnetd.h"
24*38905Sborman 
25*38905Sborman /*
26*38905Sborman  * utility functions performing io related tasks
27*38905Sborman  */
28*38905Sborman 
29*38905Sborman /*
30*38905Sborman  * ttloop
31*38905Sborman  *
32*38905Sborman  *	A small subroutine to flush the network output buffer, get some data
33*38905Sborman  * from the network, and pass it through the telnet state machine.  We
34*38905Sborman  * also flush the pty input buffer (by dropping its data) if it becomes
35*38905Sborman  * too full.
36*38905Sborman  */
37*38905Sborman 
38*38905Sborman void
39*38905Sborman ttloop()
40*38905Sborman {
41*38905Sborman     void netflush();
42*38905Sborman 
43*38905Sborman     if (nfrontp-nbackp) {
44*38905Sborman 	netflush();
45*38905Sborman     }
46*38905Sborman     ncc = read(net, netibuf, sizeof netibuf);
47*38905Sborman     if (ncc < 0) {
48*38905Sborman 	syslog(LOG_INFO, "ttloop:  read: %m\n");
49*38905Sborman 	exit(1);
50*38905Sborman     } else if (ncc == 0) {
51*38905Sborman 	syslog(LOG_INFO, "ttloop:  peer died: %m\n");
52*38905Sborman 	exit(1);
53*38905Sborman     }
54*38905Sborman     netip = netibuf;
55*38905Sborman     telrcv();			/* state machine */
56*38905Sborman     if (ncc > 0) {
57*38905Sborman 	pfrontp = pbackp = ptyobuf;
58*38905Sborman 	telrcv();
59*38905Sborman     }
60*38905Sborman }  /* end of ttloop */
61*38905Sborman 
62*38905Sborman /*
63*38905Sborman  * Check a descriptor to see if out of band data exists on it.
64*38905Sborman  */
65*38905Sborman stilloob(s)
66*38905Sborman int	s;		/* socket number */
67*38905Sborman {
68*38905Sborman     static struct timeval timeout = { 0 };
69*38905Sborman     fd_set	excepts;
70*38905Sborman     int value;
71*38905Sborman 
72*38905Sborman     do {
73*38905Sborman 	FD_ZERO(&excepts);
74*38905Sborman 	FD_SET(s, &excepts);
75*38905Sborman 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
76*38905Sborman     } while ((value == -1) && (errno == EINTR));
77*38905Sborman 
78*38905Sborman     if (value < 0) {
79*38905Sborman 	fatalperror(pty, "select");
80*38905Sborman     }
81*38905Sborman     if (FD_ISSET(s, &excepts)) {
82*38905Sborman 	return 1;
83*38905Sborman     } else {
84*38905Sborman 	return 0;
85*38905Sborman     }
86*38905Sborman }
87*38905Sborman 
88*38905Sborman ptyflush()
89*38905Sborman {
90*38905Sborman 	int n;
91*38905Sborman 
92*38905Sborman 	if ((n = pfrontp - pbackp) > 0)
93*38905Sborman 		n = write(pty, pbackp, n);
94*38905Sborman 	if (n < 0)
95*38905Sborman 		return;
96*38905Sborman 	pbackp += n;
97*38905Sborman 	if (pbackp == pfrontp)
98*38905Sborman 		pbackp = pfrontp = ptyobuf;
99*38905Sborman }
100*38905Sborman 
101*38905Sborman /*
102*38905Sborman  * nextitem()
103*38905Sborman  *
104*38905Sborman  *	Return the address of the next "item" in the TELNET data
105*38905Sborman  * stream.  This will be the address of the next character if
106*38905Sborman  * the current address is a user data character, or it will
107*38905Sborman  * be the address of the character following the TELNET command
108*38905Sborman  * if the current address is a TELNET IAC ("I Am a Command")
109*38905Sborman  * character.
110*38905Sborman  */
111*38905Sborman char *
112*38905Sborman nextitem(current)
113*38905Sborman char	*current;
114*38905Sborman {
115*38905Sborman     if ((*current&0xff) != IAC) {
116*38905Sborman 	return current+1;
117*38905Sborman     }
118*38905Sborman     switch (*(current+1)&0xff) {
119*38905Sborman     case DO:
120*38905Sborman     case DONT:
121*38905Sborman     case WILL:
122*38905Sborman     case WONT:
123*38905Sborman 	return current+3;
124*38905Sborman     case SB:		/* loop forever looking for the SE */
125*38905Sborman 	{
126*38905Sborman 	    register char *look = current+2;
127*38905Sborman 
128*38905Sborman 	    for (;;) {
129*38905Sborman 		if ((*look++&0xff) == IAC) {
130*38905Sborman 		    if ((*look++&0xff) == SE) {
131*38905Sborman 			return look;
132*38905Sborman 		    }
133*38905Sborman 		}
134*38905Sborman 	    }
135*38905Sborman 	}
136*38905Sborman     default:
137*38905Sborman 	return current+2;
138*38905Sborman     }
139*38905Sborman }  /* end of nextitem */
140*38905Sborman 
141*38905Sborman 
142*38905Sborman /*
143*38905Sborman  * netclear()
144*38905Sborman  *
145*38905Sborman  *	We are about to do a TELNET SYNCH operation.  Clear
146*38905Sborman  * the path to the network.
147*38905Sborman  *
148*38905Sborman  *	Things are a bit tricky since we may have sent the first
149*38905Sborman  * byte or so of a previous TELNET command into the network.
150*38905Sborman  * So, we have to scan the network buffer from the beginning
151*38905Sborman  * until we are up to where we want to be.
152*38905Sborman  *
153*38905Sborman  *	A side effect of what we do, just to keep things
154*38905Sborman  * simple, is to clear the urgent data pointer.  The principal
155*38905Sborman  * caller should be setting the urgent data pointer AFTER calling
156*38905Sborman  * us in any case.
157*38905Sborman  */
158*38905Sborman netclear()
159*38905Sborman {
160*38905Sborman     register char *thisitem, *next;
161*38905Sborman     char *good;
162*38905Sborman #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
163*38905Sborman 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
164*38905Sborman 
165*38905Sborman     thisitem = netobuf;
166*38905Sborman 
167*38905Sborman     while ((next = nextitem(thisitem)) <= nbackp) {
168*38905Sborman 	thisitem = next;
169*38905Sborman     }
170*38905Sborman 
171*38905Sborman     /* Now, thisitem is first before/at boundary. */
172*38905Sborman 
173*38905Sborman     good = netobuf;	/* where the good bytes go */
174*38905Sborman 
175*38905Sborman     while (nfrontp > thisitem) {
176*38905Sborman 	if (wewant(thisitem)) {
177*38905Sborman 	    int length;
178*38905Sborman 
179*38905Sborman 	    next = thisitem;
180*38905Sborman 	    do {
181*38905Sborman 		next = nextitem(next);
182*38905Sborman 	    } while (wewant(next) && (nfrontp > next));
183*38905Sborman 	    length = next-thisitem;
184*38905Sborman 	    bcopy(thisitem, good, length);
185*38905Sborman 	    good += length;
186*38905Sborman 	    thisitem = next;
187*38905Sborman 	} else {
188*38905Sborman 	    thisitem = nextitem(thisitem);
189*38905Sborman 	}
190*38905Sborman     }
191*38905Sborman 
192*38905Sborman     nbackp = netobuf;
193*38905Sborman     nfrontp = good;		/* next byte to be sent */
194*38905Sborman     neturg = 0;
195*38905Sborman }  /* end of netclear */
196*38905Sborman 
197*38905Sborman /*
198*38905Sborman  *  netflush
199*38905Sborman  *		Send as much data as possible to the network,
200*38905Sborman  *	handling requests for urgent data.
201*38905Sborman  */
202*38905Sborman void
203*38905Sborman netflush()
204*38905Sborman {
205*38905Sborman     int n;
206*38905Sborman     extern int not42;
207*38905Sborman 
208*38905Sborman     if ((n = nfrontp - nbackp) > 0) {
209*38905Sborman 	/*
210*38905Sborman 	 * if no urgent data, or if the other side appears to be an
211*38905Sborman 	 * old 4.2 client (and thus unable to survive TCP urgent data),
212*38905Sborman 	 * write the entire buffer in non-OOB mode.
213*38905Sborman 	 */
214*38905Sborman 	if ((neturg == 0) || (not42 == 0)) {
215*38905Sborman 	    n = write(net, nbackp, n);	/* normal write */
216*38905Sborman 	} else {
217*38905Sborman 	    n = neturg - nbackp;
218*38905Sborman 	    /*
219*38905Sborman 	     * In 4.2 (and 4.3) systems, there is some question about
220*38905Sborman 	     * what byte in a sendOOB operation is the "OOB" data.
221*38905Sborman 	     * To make ourselves compatible, we only send ONE byte
222*38905Sborman 	     * out of band, the one WE THINK should be OOB (though
223*38905Sborman 	     * we really have more the TCP philosophy of urgent data
224*38905Sborman 	     * rather than the Unix philosophy of OOB data).
225*38905Sborman 	     */
226*38905Sborman 	    if (n > 1) {
227*38905Sborman 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
228*38905Sborman 	    } else {
229*38905Sborman 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
230*38905Sborman 	    }
231*38905Sborman 	}
232*38905Sborman     }
233*38905Sborman     if (n < 0) {
234*38905Sborman 	if (errno == EWOULDBLOCK || errno == EINTR)
235*38905Sborman 		return;
236*38905Sborman 	cleanup();
237*38905Sborman     }
238*38905Sborman     nbackp += n;
239*38905Sborman     if (nbackp >= neturg) {
240*38905Sborman 	neturg = 0;
241*38905Sborman     }
242*38905Sborman     if (nbackp == nfrontp) {
243*38905Sborman 	nbackp = nfrontp = netobuf;
244*38905Sborman     }
245*38905Sborman     return;
246*38905Sborman }  /* end of netflush */
247*38905Sborman 
248*38905Sborman 
249*38905Sborman /*
250*38905Sborman  * writenet
251*38905Sborman  *
252*38905Sborman  * Just a handy little function to write a bit of raw data to the net.
253*38905Sborman  * It will force a transmit of the buffer if necessary
254*38905Sborman  *
255*38905Sborman  * arguments
256*38905Sborman  *    ptr - A pointer to a character string to write
257*38905Sborman  *    len - How many bytes to write
258*38905Sborman  */
259*38905Sborman writenet(ptr, len)
260*38905Sborman register char *ptr;
261*38905Sborman register int len;
262*38905Sborman {
263*38905Sborman 	/* flush buffer if no room for new data) */
264*38905Sborman 	if ((&netobuf[BUFSIZ] - nfrontp) < len) {
265*38905Sborman 		/* if this fails, don't worry, buffer is a little big */
266*38905Sborman 		netflush();
267*38905Sborman 	}
268*38905Sborman 
269*38905Sborman 	bcopy(ptr, nfrontp, len);
270*38905Sborman 	nfrontp += len;
271*38905Sborman 
272*38905Sborman }  /* end of writenet */
273*38905Sborman 
274*38905Sborman 
275*38905Sborman /*
276*38905Sborman  * miscellaneous functions doing a variety of little jobs follow ...
277*38905Sborman  */
278*38905Sborman 
279*38905Sborman 
280*38905Sborman fatal(f, msg)
281*38905Sborman 	int f;
282*38905Sborman 	char *msg;
283*38905Sborman {
284*38905Sborman 	char buf[BUFSIZ];
285*38905Sborman 
286*38905Sborman 	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
287*38905Sborman 	(void) write(f, buf, (int)strlen(buf));
288*38905Sborman 	sleep(1);	/*XXX*/
289*38905Sborman 	exit(1);
290*38905Sborman }
291*38905Sborman 
292*38905Sborman fatalperror(f, msg)
293*38905Sborman 	int f;
294*38905Sborman 	char *msg;
295*38905Sborman {
296*38905Sborman 	char buf[BUFSIZ];
297*38905Sborman 	extern char *sys_errlist[];
298*38905Sborman 
299*38905Sborman 	(void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
300*38905Sborman 	fatal(f, buf);
301*38905Sborman }
302*38905Sborman 
303*38905Sborman char editedhost[32];
304*38905Sborman 
305*38905Sborman edithost(pat, host)
306*38905Sborman 	register char *pat;
307*38905Sborman 	register char *host;
308*38905Sborman {
309*38905Sborman 	register char *res = editedhost;
310*38905Sborman 	char *strncpy();
311*38905Sborman 
312*38905Sborman 	if (!pat)
313*38905Sborman 		pat = "";
314*38905Sborman 	while (*pat) {
315*38905Sborman 		switch (*pat) {
316*38905Sborman 
317*38905Sborman 		case '#':
318*38905Sborman 			if (*host)
319*38905Sborman 				host++;
320*38905Sborman 			break;
321*38905Sborman 
322*38905Sborman 		case '@':
323*38905Sborman 			if (*host)
324*38905Sborman 				*res++ = *host++;
325*38905Sborman 			break;
326*38905Sborman 
327*38905Sborman 		default:
328*38905Sborman 			*res++ = *pat;
329*38905Sborman 			break;
330*38905Sborman 		}
331*38905Sborman 		if (res == &editedhost[sizeof editedhost - 1]) {
332*38905Sborman 			*res = '\0';
333*38905Sborman 			return;
334*38905Sborman 		}
335*38905Sborman 		pat++;
336*38905Sborman 	}
337*38905Sborman 	if (*host)
338*38905Sborman 		(void) strncpy(res, host,
339*38905Sborman 				sizeof editedhost - (res - editedhost) -1);
340*38905Sborman 	else
341*38905Sborman 		*res = '\0';
342*38905Sborman 	editedhost[sizeof editedhost - 1] = '\0';
343*38905Sborman }
344*38905Sborman 
345*38905Sborman static char *putlocation;
346*38905Sborman 
347*38905Sborman putstr(s)
348*38905Sborman register char *s;
349*38905Sborman {
350*38905Sborman 
351*38905Sborman 	while (*s)
352*38905Sborman 		putchr(*s++);
353*38905Sborman }
354*38905Sborman 
355*38905Sborman putchr(cc)
356*38905Sborman {
357*38905Sborman 	*putlocation++ = cc;
358*38905Sborman }
359*38905Sborman 
360*38905Sborman putf(cp, where)
361*38905Sborman register char *cp;
362*38905Sborman char *where;
363*38905Sborman {
364*38905Sborman 	char *slash;
365*38905Sborman #ifndef	NO_GETTYTAB
366*38905Sborman 	char datebuffer[60];
367*38905Sborman #endif	/* NO_GETTYTAB */
368*38905Sborman 	extern char *rindex();
369*38905Sborman 
370*38905Sborman 	putlocation = where;
371*38905Sborman 
372*38905Sborman 	while (*cp) {
373*38905Sborman 		if (*cp != '%') {
374*38905Sborman 			putchr(*cp++);
375*38905Sborman 			continue;
376*38905Sborman 		}
377*38905Sborman 		switch (*++cp) {
378*38905Sborman 
379*38905Sborman 		case 't':
380*38905Sborman 			slash = rindex(line, '/');
381*38905Sborman 			if (slash == (char *) 0)
382*38905Sborman 				putstr(line);
383*38905Sborman 			else
384*38905Sborman 				putstr(&slash[1]);
385*38905Sborman 			break;
386*38905Sborman 
387*38905Sborman 		case 'h':
388*38905Sborman 			putstr(editedhost);
389*38905Sborman 			break;
390*38905Sborman 
391*38905Sborman #ifndef	NO_GETTYTAB
392*38905Sborman 		case 'd':
393*38905Sborman 			get_date(datebuffer);
394*38905Sborman 			putstr(datebuffer);
395*38905Sborman 			break;
396*38905Sborman #endif	/* NO_GETTYTAB */
397*38905Sborman 
398*38905Sborman 		case '%':
399*38905Sborman 			putchr('%');
400*38905Sborman 			break;
401*38905Sborman 		}
402*38905Sborman 		cp++;
403*38905Sborman 	}
404*38905Sborman }
405*38905Sborman 
406*38905Sborman /*ARGSUSED*/
407*38905Sborman #ifdef	NO_GETTYTAB
408*38905Sborman getent(cp, name)
409*38905Sborman char *cp, *name;
410*38905Sborman {
411*38905Sborman 	return(0);
412*38905Sborman }
413*38905Sborman 
414*38905Sborman /*ARGSUSED*/
415*38905Sborman char *
416*38905Sborman getstr(cp, cpp)
417*38905Sborman char *cp, **cpp;
418*38905Sborman {
419*38905Sborman 	return(0);
420*38905Sborman }
421*38905Sborman #endif	/* NO_GETTYTAB */
422