xref: /original-bsd/libexec/telnetd/telnetd.c (revision c0f053f7)
1 /*
2  * Copyright (c) 1983, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983, 1986 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)telnetd.c	5.37 (Berkeley) 05/11/89";
26 #endif /* not lint */
27 
28 /*
29  * Telnet server.
30  */
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <sys/wait.h>
34 #include <sys/file.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 
38 #include <netinet/in.h>
39 
40 #include <arpa/telnet.h>
41 
42 #include <stdio.h>
43 #include <signal.h>
44 #include <errno.h>
45 #include <sgtty.h>
46 #include <netdb.h>
47 #include <syslog.h>
48 #include <ctype.h>
49 #include "pathnames.h"
50 
51 #define	OPT_NO			0		/* won't do this option */
52 #define	OPT_YES			1		/* will do this option */
53 #define	OPT_YES_BUT_ALWAYS_LOOK	2
54 #define	OPT_NO_BUT_ALWAYS_LOOK	3
55 char	hisopts[256];
56 char	myopts[256];
57 
58 char	doopt[] = { IAC, DO, '%', 'c', 0 };
59 char	dont[] = { IAC, DONT, '%', 'c', 0 };
60 char	will[] = { IAC, WILL, '%', 'c', 0 };
61 char	wont[] = { IAC, WONT, '%', 'c', 0 };
62 
63 /*
64  * I/O data buffers, pointers, and counters.
65  */
66 char	ptyibuf[BUFSIZ], *ptyip = ptyibuf;
67 
68 char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
69 
70 char	netibuf[BUFSIZ], *netip = netibuf;
71 #define	NIACCUM(c)	{   *netip++ = c; \
72 			    ncc++; \
73 			}
74 
75 char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
76 char	*neturg = 0;		/* one past last bye of urgent data */
77 	/* the remote system seems to NOT be an old 4.2 */
78 int	not42 = 1;
79 
80 #define	BANNER	"\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r"
81 
82 		/* buffer for sub-options */
83 char	subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
84 #define	SB_CLEAR()	subpointer = subbuffer;
85 #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
86 #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
87 				*subpointer++ = (c); \
88 			}
89 #define	SB_GET()	((*subpointer++)&0xff)
90 #define	SB_EOF()	(subpointer >= subend)
91 
92 int	pcc, ncc;
93 
94 int	pty, net;
95 int	inter;
96 extern	char **environ;
97 extern	int errno;
98 char	*line;
99 int	SYNCHing = 0;		/* we are in TELNET SYNCH mode */
100 /*
101  * The following are some clocks used to decide how to interpret
102  * the relationship between various variables.
103  */
104 
105 struct {
106     int
107 	system,			/* what the current time is */
108 	echotoggle,		/* last time user entered echo character */
109 	modenegotiated,		/* last time operating mode negotiated */
110 	didnetreceive,		/* last time we read data from network */
111 	ttypeopt,		/* ttype will/won't received */
112 	ttypesubopt,		/* ttype subopt is received */
113 	getterminal,		/* time started to get terminal information */
114 	gotDM;			/* when did we last see a data mark */
115 } clocks;
116 
117 #define	settimer(x)	(clocks.x = ++clocks.system)
118 #define	sequenceIs(x,y)	(clocks.x < clocks.y)
119 
120 main(argc, argv)
121 	char *argv[];
122 {
123 	struct sockaddr_in from;
124 	int on = 1, fromlen;
125 
126 	if ((argc > 1) && (strcmp(argv[1], "-debug") == 0)) {
127 	    int s, ns, foo;
128 	    struct servent *sp;
129 	    static struct sockaddr_in sin = { AF_INET };
130 
131 	    argc--, argv++;
132 	    if (argc > 1) {
133 		    sin.sin_port = atoi(argv[1]);
134 		    sin.sin_port = htons((u_short)sin.sin_port);
135 	    } else {
136 		sp = getservbyname("telnet", "tcp");
137 		if (sp == 0) {
138 			fprintf(stderr,
139 				"telnetd: tcp/telnet: unknown service\n");
140 			exit(1);
141 		}
142 		sin.sin_port = sp->s_port;
143 	    }
144 
145 	    s = socket(AF_INET, SOCK_STREAM, 0);
146 	    if (s < 0) {
147 		    perror("telnetd: socket");;
148 		    exit(1);
149 	    }
150 	    if (bind(s, &sin, sizeof sin) < 0) {
151 		perror("bind");
152 		exit(1);
153 	    }
154 	    if (listen(s, 1) < 0) {
155 		perror("listen");
156 		exit(1);
157 	    }
158 	    foo = sizeof sin;
159 	    ns = accept(s, &sin, &foo);
160 	    if (ns < 0) {
161 		perror("accept");
162 		exit(1);
163 	    }
164 	    dup2(ns, 0);
165 	    close(s);
166 	}
167 	openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
168 	fromlen = sizeof (from);
169 	if (getpeername(0, &from, &fromlen) < 0) {
170 		fprintf(stderr, "%s: ", argv[0]);
171 		perror("getpeername");
172 		_exit(1);
173 	}
174 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
175 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
176 	}
177 	doit(0, &from);
178 }
179 
180 char	*terminaltype = 0;
181 char	*envinit[2];
182 int	cleanup();
183 
184 /*
185  * ttloop
186  *
187  *	A small subroutine to flush the network output buffer, get some data
188  * from the network, and pass it through the telnet state machine.  We
189  * also flush the pty input buffer (by dropping its data) if it becomes
190  * too full.
191  */
192 
193 void
194 ttloop()
195 {
196     if (nfrontp-nbackp) {
197 	netflush();
198     }
199     ncc = read(net, netibuf, sizeof netibuf);
200     if (ncc < 0) {
201 	syslog(LOG_INFO, "ttloop:  read: %m\n");
202 	exit(1);
203     } else if (ncc == 0) {
204 	syslog(LOG_INFO, "ttloop:  peer died: %m\n");
205 	exit(1);
206     }
207     netip = netibuf;
208     telrcv();			/* state machine */
209     if (ncc > 0) {
210 	pfrontp = pbackp = ptyobuf;
211 	telrcv();
212     }
213 }
214 
215 /*
216  * getterminalspeed
217  *
218  *     Ask the other end to send along its terminal speed.
219  * subopt does the rest.
220  */
221 
222 void
223 getterminalspeed()
224 {
225   static char sbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
226 
227   bcopy(sbuf, nfrontp, sizeof sbuf);
228   nfrontp += sizeof sbuf;
229 }
230 
231 /*
232  * getterminaltype
233  *
234  *	Ask the other end to send along its terminal type.
235  * Output is the variable terminaltype filled in.
236  */
237 
238 void
239 getterminaltype()
240 {
241     static char sbuf[] = { IAC, DO, TELOPT_TTYPE };
242 
243     settimer(getterminal);
244     bcopy(sbuf, nfrontp, sizeof sbuf);
245     nfrontp += sizeof sbuf;
246     hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
247     while (sequenceIs(ttypeopt, getterminal)) {
248 	ttloop();
249     }
250     if (hisopts[TELOPT_TTYPE] == OPT_YES) {
251 	static char sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
252 
253 	bcopy(sbbuf, nfrontp, sizeof sbbuf);
254 	nfrontp += sizeof sbbuf;
255 	while (sequenceIs(ttypesubopt, getterminal)) {
256 	    ttloop();
257 	}
258     }
259 }
260 
261 /*
262  * Get a pty, scan input lines.
263  */
264 doit(f, who)
265 	int f;
266 	struct sockaddr_in *who;
267 {
268 	char *host, *inet_ntoa();
269 	int i, p, t;
270 	struct sgttyb b;
271 	struct hostent *hp;
272 	int c;
273 
274 	for (c = 'p'; c <= 's'; c++) {
275 		struct stat stb;
276 
277 		line = "/dev/ptyXX";
278 		line[strlen("/dev/pty")] = c;
279 		line[strlen("/dev/ptyp")] = '0';
280 		if (stat(line, &stb) < 0)
281 			break;
282 		for (i = 0; i < 16; i++) {
283 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
284 			p = open(line, O_RDWR);
285 			if (p > 0)
286 				goto gotpty;
287 		}
288 	}
289 	fatal(f, "All network ports in use");
290 	/*NOTREACHED*/
291 gotpty:
292 	dup2(f, 0);
293 	line[strlen("/dev/")] = 't';
294 	t = open(_PATH_TTY, O_RDWR);
295 	if (t >= 0) {
296 		ioctl(t, TIOCNOTTY, 0);
297 		close(t);
298 	}
299 	t = open(line, O_RDWR);
300 	if (t < 0)
301 		fatalperror(f, line);
302 	if (fchmod(t, 0))
303 		fatalperror(f, line);
304 	(void)signal(SIGHUP, SIG_IGN);
305 	vhangup();
306 	(void)signal(SIGHUP, SIG_DFL);
307 	t = open(line, O_RDWR);
308 	if (t < 0)
309 		fatalperror(f, line);
310 	ioctl(t, TIOCGETP, &b);
311 	b.sg_flags = CRMOD|XTABS|ANYP;
312 	ioctl(t, TIOCSETP, &b);
313 	ioctl(p, TIOCGETP, &b);
314 	b.sg_flags &= ~ECHO;
315 	b.sg_ospeed = b.sg_ispeed = B9600;
316 	ioctl(p, TIOCSETP, &b);
317 	hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
318 		who->sin_family);
319 	if (hp)
320 		host = hp->h_name;
321 	else
322 		host = inet_ntoa(who->sin_addr);
323 
324 	net = f;
325 	pty = p;
326 
327 	/*
328 	 * get terminal type and size.
329 	 */
330 	getterminaltype();
331 
332 	if ((i = fork()) < 0)
333 		fatalperror(f, "fork");
334 	if (i) {
335 		close(t);
336 		telnet(f, p);
337 	}
338 	if (setsid() < 0)
339 		fatalperror(f, "setsid");
340 	if (ioctl(t, TIOCSCTTY, 0) < 0)
341 		fatalperror(f, "ioctl(sctty)");
342 	close(f);
343 	close(p);
344 	dup2(t, 0);
345 	dup2(t, 1);
346 	dup2(t, 2);
347 	close(t);
348 	envinit[0] = terminaltype;
349 	envinit[1] = 0;
350 	environ = envinit;
351 	/*
352 	 * -h : pass on name of host.
353 	 *		WARNING:  -h is accepted by login if and only if
354 	 *			getuid() == 0.
355 	 * -p : don't clobber the environment (so terminal type stays set).
356 	 */
357 	execl(_PATH_LOGIN, "login", "-h", host,
358 					terminaltype ? "-p" : 0, 0);
359 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
360 	fatalperror(2, _PATH_LOGIN);
361 	/*NOTREACHED*/
362 }
363 
364 fatal(f, msg)
365 	int f;
366 	char *msg;
367 {
368 	char buf[BUFSIZ];
369 
370 	(void) sprintf(buf, "telnetd: %s.\r\n", msg);
371 	(void) write(f, buf, strlen(buf));
372 	exit(1);
373 }
374 
375 fatalperror(f, msg)
376 	int f;
377 	char *msg;
378 {
379 	char buf[BUFSIZ];
380 	extern char *sys_errlist[];
381 
382 	(void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
383 	fatal(f, buf);
384 }
385 
386 
387 /*
388  * Check a descriptor to see if out of band data exists on it.
389  */
390 
391 
392 stilloob(s)
393 int	s;		/* socket number */
394 {
395     static struct timeval timeout = { 0 };
396     fd_set	excepts;
397     int value;
398 
399     do {
400 	FD_ZERO(&excepts);
401 	FD_SET(s, &excepts);
402 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
403     } while ((value == -1) && (errno == EINTR));
404 
405     if (value < 0) {
406 	fatalperror(pty, "select");
407     }
408     if (FD_ISSET(s, &excepts)) {
409 	return 1;
410     } else {
411 	return 0;
412     }
413 }
414 
415 /*
416  * Main loop.  Select from pty and network, and
417  * hand data to telnet receiver finite state machine.
418  */
419 telnet(f, p)
420 {
421 	int on = 1;
422 	char hostname[MAXHOSTNAMELEN];
423 #define	TABBUFSIZ	512
424 	char	defent[TABBUFSIZ];
425 	char	defstrs[TABBUFSIZ];
426 #undef	TABBUFSIZ
427 	char *HE;
428 	char *HN;
429 	char *IM;
430 
431 	ioctl(f, FIONBIO, &on);
432 	ioctl(p, FIONBIO, &on);
433 	ioctl(p, TIOCPKT, &on);
434 #if	defined(SO_OOBINLINE)
435 	setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
436 #endif	/* defined(SO_OOBINLINE) */
437 	signal(SIGTSTP, SIG_IGN);
438 	/*
439 	 * Ignoring SIGTTOU keeps the kernel from blocking us
440 	 * in ttioctl() in /sys/tty.c.
441 	 */
442 	signal(SIGTTOU, SIG_IGN);
443 	signal(SIGCHLD, cleanup);
444 	setpgrp(0, 0);
445 
446 	/*
447 	 * Request to do remote echo and to suppress go ahead.
448 	 */
449 	if (!myopts[TELOPT_ECHO]) {
450 	    dooption(TELOPT_ECHO);
451 	}
452 	if (!myopts[TELOPT_SGA]) {
453 	    dooption(TELOPT_SGA);
454 	}
455 	if (!hisopts[TELOPT_NAWS]) {
456 	   willoption(TELOPT_NAWS);
457 	   hisopts[TELOPT_NAWS] = OPT_NO;
458 	}
459 	if (!hisopts[TELOPT_TSPEED]) {
460 	   willoption(TELOPT_TSPEED);
461 	   hisopts[TELOPT_TSPEED] = OPT_NO;
462 	}
463 	if (!hisopts[TELOPT_LFLOW]) {
464 	   willoption(TELOPT_LFLOW);
465 	   hisopts[TELOPT_LFLOW] = OPT_NO;
466 	}
467 
468 	/*
469 	 * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
470 	 * because 4.2 clients are unable to deal with TCP urgent data.
471 	 *
472 	 * To find out, we send out a "DO ECHO".  If the remote system
473 	 * answers "WILL ECHO" it is probably a 4.2 client, and we note
474 	 * that fact ("WILL ECHO" ==> that the client will echo what
475 	 * WE, the server, sends it; it does NOT mean that the client will
476 	 * echo the terminal input).
477 	 */
478 	(void) sprintf(nfrontp, doopt, TELOPT_ECHO);
479 	nfrontp += sizeof doopt-2;
480 	hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
481 
482 	/*
483 	 * Show banner that getty never gave.
484 	 *
485 	 * We put the banner in the pty input buffer.  This way, it
486 	 * gets carriage return null processing, etc., just like all
487 	 * other pty --> client data.
488 	 */
489 
490 	gethostname(hostname, sizeof (hostname));
491 	if (getent(defent, "default") == 1) {
492 		char *getstr();
493 		char *p=defstrs;
494 
495 		HE = getstr("he", &p);
496 		HN = getstr("hn", &p);
497 		IM = getstr("im", &p);
498 		if (HN && *HN)
499 			strcpy(hostname, HN);
500 		edithost(HE, hostname);
501 		if (IM && *IM)
502 			putf(IM, ptyibuf+1);
503 	} else {
504 		sprintf(ptyibuf+1, BANNER, hostname);
505 	}
506 
507 	ptyip = ptyibuf+1;		/* Prime the pump */
508 	pcc = strlen(ptyip);		/* ditto */
509 
510 	/* Clear ptybuf[0] - where the packet information is received */
511 	ptyibuf[0] = 0;
512 
513 	/*
514 	 * Call telrcv() once to pick up anything received during
515 	 * terminal type negotiation.
516 	 */
517 	telrcv();
518 
519 	for (;;) {
520 		fd_set ibits, obits, xbits;
521 		register int c;
522 
523 		if (ncc < 0 && pcc < 0)
524 			break;
525 
526 		FD_ZERO(&ibits);
527 		FD_ZERO(&obits);
528 		FD_ZERO(&xbits);
529 		/*
530 		 * Never look for input if there's still
531 		 * stuff in the corresponding output buffer
532 		 */
533 		if (nfrontp - nbackp || pcc > 0) {
534 			FD_SET(f, &obits);
535 		} else {
536 			FD_SET(p, &ibits);
537 		}
538 		if (pfrontp - pbackp || ncc > 0) {
539 			FD_SET(p, &obits);
540 		} else {
541 			FD_SET(f, &ibits);
542 		}
543 		if (!SYNCHing) {
544 			FD_SET(f, &xbits);
545 		}
546 		FD_SET(p, &xbits);
547 		if ((c = select(16, &ibits, &obits, &xbits,
548 						(struct timeval *)0)) < 1) {
549 			if (c == -1) {
550 				if (errno == EINTR) {
551 					continue;
552 				}
553 			}
554 			sleep(5);
555 			continue;
556 		}
557 
558 		/*
559 		 * Any urgent data?
560 		 */
561 		if (FD_ISSET(net, &xbits)) {
562 		    SYNCHing = 1;
563 		}
564 
565 		/*
566 		 * Something to read from the network...
567 		 */
568 		if (FD_ISSET(net, &ibits)) {
569 #if	!defined(SO_OOBINLINE)
570 			/*
571 			 * In 4.2 (and 4.3 beta) systems, the
572 			 * OOB indication and data handling in the kernel
573 			 * is such that if two separate TCP Urgent requests
574 			 * come in, one byte of TCP data will be overlaid.
575 			 * This is fatal for Telnet, but we try to live
576 			 * with it.
577 			 *
578 			 * In addition, in 4.2 (and...), a special protocol
579 			 * is needed to pick up the TCP Urgent data in
580 			 * the correct sequence.
581 			 *
582 			 * What we do is:  if we think we are in urgent
583 			 * mode, we look to see if we are "at the mark".
584 			 * If we are, we do an OOB receive.  If we run
585 			 * this twice, we will do the OOB receive twice,
586 			 * but the second will fail, since the second
587 			 * time we were "at the mark", but there wasn't
588 			 * any data there (the kernel doesn't reset
589 			 * "at the mark" until we do a normal read).
590 			 * Once we've read the OOB data, we go ahead
591 			 * and do normal reads.
592 			 *
593 			 * There is also another problem, which is that
594 			 * since the OOB byte we read doesn't put us
595 			 * out of OOB state, and since that byte is most
596 			 * likely the TELNET DM (data mark), we would
597 			 * stay in the TELNET SYNCH (SYNCHing) state.
598 			 * So, clocks to the rescue.  If we've "just"
599 			 * received a DM, then we test for the
600 			 * presence of OOB data when the receive OOB
601 			 * fails (and AFTER we did the normal mode read
602 			 * to clear "at the mark").
603 			 */
604 		    if (SYNCHing) {
605 			int atmark;
606 
607 			ioctl(net, SIOCATMARK, (char *)&atmark);
608 			if (atmark) {
609 			    ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
610 			    if ((ncc == -1) && (errno == EINVAL)) {
611 				ncc = read(net, netibuf, sizeof (netibuf));
612 				if (sequenceIs(didnetreceive, gotDM)) {
613 				    SYNCHing = stilloob(net);
614 				}
615 			    }
616 			} else {
617 			    ncc = read(net, netibuf, sizeof (netibuf));
618 			}
619 		    } else {
620 			ncc = read(net, netibuf, sizeof (netibuf));
621 		    }
622 		    settimer(didnetreceive);
623 #else	/* !defined(SO_OOBINLINE)) */
624 		    ncc = read(net, netibuf, sizeof (netibuf));
625 #endif	/* !defined(SO_OOBINLINE)) */
626 		    if (ncc < 0 && errno == EWOULDBLOCK)
627 			ncc = 0;
628 		    else {
629 			if (ncc <= 0) {
630 			    break;
631 			}
632 			netip = netibuf;
633 		    }
634 		}
635 
636 		/*
637 		 * Something to read from the pty...
638 		 */
639 		if (FD_ISSET(p, &ibits) || FD_ISSET(p, &xbits)) {
640 			pcc = read(p, ptyibuf, BUFSIZ);
641 			if (pcc < 0 && errno == EWOULDBLOCK)
642 				pcc = 0;
643 			else {
644 				if (pcc <= 0)
645 					break;
646 				if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
647 					netclear();     /* clear buffer back */
648 					*nfrontp++ = IAC;
649 					*nfrontp++ = DM;
650 					neturg = nfrontp-1; /* off by one XXX */
651 				}
652 				if (hisopts[TELOPT_LFLOW] &&
653 				    (ptyibuf[0] &
654 				      (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
655 					sprintf(nfrontp,"%c%c%c%c%c%c",
656 					    IAC, SB, TELOPT_LFLOW,
657 					    ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
658 					    IAC, SE);
659 					nfrontp += 6;
660 				}
661 				pcc--;
662 				ptyip = ptyibuf+1;
663                        }
664 		}
665 
666 		while (pcc > 0) {
667 			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
668 				break;
669 			c = *ptyip++ & 0377, pcc--;
670 			if (c == IAC)
671 				*nfrontp++ = c;
672 			*nfrontp++ = c;
673 			/* Don't do CR-NUL if we are in binary mode */
674 			if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
675 				if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
676 					*nfrontp++ = *ptyip++ & 0377;
677 					pcc--;
678 				} else
679 					*nfrontp++ = '\0';
680 			}
681 		}
682 		if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
683 			netflush();
684 		if (ncc > 0)
685 			telrcv();
686 		if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
687 			ptyflush();
688 	}
689 	cleanup();
690 }
691 
692 /*
693  * State for recv fsm
694  */
695 #define	TS_DATA		0	/* base state */
696 #define	TS_IAC		1	/* look for double IAC's */
697 #define	TS_CR		2	/* CR-LF ->'s CR */
698 #define	TS_SB		3	/* throw away begin's... */
699 #define	TS_SE		4	/* ...end's (suboption negotiation) */
700 #define	TS_WILL		5	/* will option negotiation */
701 #define	TS_WONT		6	/* wont " */
702 #define	TS_DO		7	/* do " */
703 #define	TS_DONT		8	/* dont " */
704 
705 telrcv()
706 {
707 	register int c;
708 	static int state = TS_DATA;
709 
710 	while (ncc > 0) {
711 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
712 			return;
713 		c = *netip++ & 0377, ncc--;
714 		switch (state) {
715 
716 		case TS_CR:
717 			state = TS_DATA;
718 			/* Strip off \n or \0 after a \r */
719 			if ((c == 0) || (c == '\n')) {
720 				break;
721 			}
722 			/* FALL THROUGH */
723 
724 		case TS_DATA:
725 			if (c == IAC) {
726 				state = TS_IAC;
727 				break;
728 			}
729 			if (inter > 0)
730 				break;
731 			/*
732 			 * We now map \r\n ==> \r for pragmatic reasons.
733 			 * Many client implementations send \r\n when
734 			 * the user hits the CarriageReturn key.
735 			 *
736 			 * We USED to map \r\n ==> \n, since \r\n says
737 			 * that we want to be in column 1 of the next
738 			 * printable line, and \n is the standard
739 			 * unix way of saying that (\r is only good
740 			 * if CRMOD is set, which it normally is).
741 			 */
742 			if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
743 				state = TS_CR;
744 			}
745 			*pfrontp++ = c;
746 			break;
747 
748 		case TS_IAC:
749 			switch (c) {
750 
751 			/*
752 			 * Send the process on the pty side an
753 			 * interrupt.  Do this with a NULL or
754 			 * interrupt char; depending on the tty mode.
755 			 */
756 			case IP:
757 				interrupt();
758 				break;
759 
760 			case BREAK:
761 				sendbrk();
762 				break;
763 
764 			/*
765 			 * Are You There?
766 			 */
767 			case AYT:
768 				strcpy(nfrontp, "\r\n[Yes]\r\n");
769 				nfrontp += 9;
770 				break;
771 
772 			/*
773 			 * Abort Output
774 			 */
775 			case AO: {
776 					struct ltchars tmpltc;
777 
778 					ptyflush();	/* half-hearted */
779 					ioctl(pty, TIOCGLTC, &tmpltc);
780 					if (tmpltc.t_flushc != '\377') {
781 						*pfrontp++ = tmpltc.t_flushc;
782 					}
783 					netclear();	/* clear buffer back */
784 					*nfrontp++ = IAC;
785 					*nfrontp++ = DM;
786 					neturg = nfrontp-1; /* off by one XXX */
787 					break;
788 				}
789 
790 			/*
791 			 * Erase Character and
792 			 * Erase Line
793 			 */
794 			case EC:
795 			case EL: {
796 					struct sgttyb b;
797 					char ch;
798 
799 					ptyflush();	/* half-hearted */
800 					ioctl(pty, TIOCGETP, &b);
801 					ch = (c == EC) ?
802 						b.sg_erase : b.sg_kill;
803 					if (ch != '\377') {
804 						*pfrontp++ = ch;
805 					}
806 					break;
807 				}
808 
809 			/*
810 			 * Check for urgent data...
811 			 */
812 			case DM:
813 				SYNCHing = stilloob(net);
814 				settimer(gotDM);
815 				break;
816 
817 
818 			/*
819 			 * Begin option subnegotiation...
820 			 */
821 			case SB:
822 				state = TS_SB;
823 				SB_CLEAR();
824 				continue;
825 
826 			case WILL:
827 				state = TS_WILL;
828 				continue;
829 
830 			case WONT:
831 				state = TS_WONT;
832 				continue;
833 
834 			case DO:
835 				state = TS_DO;
836 				continue;
837 
838 			case DONT:
839 				state = TS_DONT;
840 				continue;
841 
842 			case IAC:
843 				*pfrontp++ = c;
844 				break;
845 			}
846 			state = TS_DATA;
847 			break;
848 
849 		case TS_SB:
850 			if (c == IAC) {
851 				state = TS_SE;
852 			} else {
853 				SB_ACCUM(c);
854 			}
855 			break;
856 
857 		case TS_SE:
858 			if (c != SE) {
859 				if (c != IAC) {
860 					SB_ACCUM(IAC);
861 				}
862 				SB_ACCUM(c);
863 				state = TS_SB;
864 			} else {
865 				SB_TERM();
866 				suboption();	/* handle sub-option */
867 				state = TS_DATA;
868 			}
869 			break;
870 
871 		case TS_WILL:
872 			if (hisopts[c] != OPT_YES)
873 				willoption(c);
874 			state = TS_DATA;
875 			if (c == TELOPT_TSPEED)
876 				getterminalspeed();
877 			continue;
878 
879 		case TS_WONT:
880 			if (hisopts[c] != OPT_NO)
881 				wontoption(c);
882 			state = TS_DATA;
883 			continue;
884 
885 		case TS_DO:
886 			if (myopts[c] != OPT_YES)
887 				dooption(c);
888 			state = TS_DATA;
889 			continue;
890 
891 		case TS_DONT:
892 			if (myopts[c] != OPT_NO) {
893 				dontoption(c);
894 			}
895 			state = TS_DATA;
896 			continue;
897 
898 		default:
899 			syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
900 			printf("telnetd: panic state=%d\n", state);
901 			exit(1);
902 		}
903 	}
904 }
905 
906 willoption(option)
907 	int option;
908 {
909 	char *fmt;
910 
911 	switch (option) {
912 
913 	case TELOPT_BINARY:
914 		mode(RAW, 0);
915 		fmt = doopt;
916 		break;
917 
918 	case TELOPT_ECHO:
919 		not42 = 0;		/* looks like a 4.2 system */
920 		/*
921 		 * Now, in a 4.2 system, to break them out of ECHOing
922 		 * (to the terminal) mode, we need to send a "WILL ECHO".
923 		 * Kludge upon kludge!
924 		 */
925 		if (myopts[TELOPT_ECHO] == OPT_YES) {
926 		    dooption(TELOPT_ECHO);
927 		}
928 		fmt = dont;
929 		break;
930 
931 	case TELOPT_TTYPE:
932 		settimer(ttypeopt);
933 		if (hisopts[TELOPT_TTYPE] == OPT_YES_BUT_ALWAYS_LOOK) {
934 		    hisopts[TELOPT_TTYPE] = OPT_YES;
935 		    return;
936 		}
937 		fmt = doopt;
938 		break;
939 
940 	case TELOPT_NAWS:
941 	case TELOPT_TSPEED:
942 	case TELOPT_LFLOW:
943 	case TELOPT_SGA:
944 		fmt = doopt;
945 		break;
946 
947 	case TELOPT_TM:
948 		fmt = dont;
949 		break;
950 
951 	default:
952 		fmt = dont;
953 		break;
954 	}
955 	if (fmt == doopt) {
956 		hisopts[option] = OPT_YES;
957 	} else {
958 		hisopts[option] = OPT_NO;
959 	}
960 	(void) sprintf(nfrontp, fmt, option);
961 	nfrontp += sizeof (dont) - 2;
962 }
963 
964 wontoption(option)
965 	int option;
966 {
967 	char *fmt;
968 
969 	switch (option) {
970 	case TELOPT_ECHO:
971 		not42 = 1;		/* doesn't seem to be a 4.2 system */
972 		break;
973 
974 	case TELOPT_BINARY:
975 		mode(0, RAW);
976 		break;
977 
978 	case TELOPT_TTYPE:
979 	    settimer(ttypeopt);
980 	    break;
981 	}
982 
983 	fmt = dont;
984 	hisopts[option] = OPT_NO;
985 	(void) sprintf(nfrontp, fmt, option);
986 	nfrontp += sizeof (doopt) - 2;
987 }
988 
989 dooption(option)
990 	int option;
991 {
992 	char *fmt;
993 
994 	switch (option) {
995 
996 	case TELOPT_TM:
997 		fmt = wont;
998 		break;
999 
1000 	case TELOPT_ECHO:
1001 		mode(ECHO|CRMOD, 0);
1002 		fmt = will;
1003 		break;
1004 
1005 	case TELOPT_BINARY:
1006 		mode(RAW, 0);
1007 		fmt = will;
1008 		break;
1009 
1010 	case TELOPT_SGA:
1011 		fmt = will;
1012 		break;
1013 
1014 	default:
1015 		fmt = wont;
1016 		break;
1017 	}
1018 	if (fmt == will) {
1019 	    myopts[option] = OPT_YES;
1020 	} else {
1021 	    myopts[option] = OPT_NO;
1022 	}
1023 	(void) sprintf(nfrontp, fmt, option);
1024 	nfrontp += sizeof (doopt) - 2;
1025 }
1026 
1027 
1028 dontoption(option)
1029 int option;
1030 {
1031     char *fmt;
1032 
1033     switch (option) {
1034     case TELOPT_ECHO:		/* we should stop echoing */
1035 	mode(0, ECHO);
1036 	fmt = wont;
1037 	break;
1038 
1039     default:
1040 	fmt = wont;
1041 	break;
1042     }
1043 
1044     if (fmt = wont) {
1045 	myopts[option] = OPT_NO;
1046     } else {
1047 	myopts[option] = OPT_YES;
1048     }
1049     (void) sprintf(nfrontp, fmt, option);
1050     nfrontp += sizeof (wont) - 2;
1051 }
1052 
1053 /*
1054  * Given a string, assign the "best" speed which we support.
1055  *
1056  * "Best" is defined as rounding up, unless what is presented is
1057  * higher than the highest.
1058  */
1059 
1060 string2speed(s)
1061   char *s;
1062 {
1063 	/*
1064 	 * The order here is important.  The index of each speed needs to
1065 	 * correspond with the sgtty structure value for that speed.
1066 	 *
1067 	 * Additionally, the search algorithm assumes the table is in
1068 	 * ascending sequence.
1069 	 */
1070 	static int ttyspeeds[] = {
1071 		0, 50, 75, 110, 134, 150, 200, 300,
1072 		600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 };
1073 #define NUMSPEEDS sizeof ttyspeeds/sizeof ttyspeeds[0]
1074 	int i;
1075 	int theirspeed = atoi(s);
1076 
1077 	for (i = 0; i < NUMSPEEDS; i++) {
1078 		if (ttyspeeds[i] == theirspeed) {	/* Exact match */
1079 			return(i);
1080 		} else if (ttyspeeds[i] > theirspeed) {
1081 			if (i > 0) {
1082 				return i-1;
1083 			}
1084 		}
1085 	}
1086 	/* Their number is greater than any of our numbers */
1087 	return(NUMSPEEDS-1);
1088 }
1089 
1090 /*
1091  * suboption()
1092  *
1093  *	Look at the sub-option buffer, and try to be helpful to the other
1094  * side.
1095  *
1096  *	Currently we recognize:
1097  *
1098  *	Terminal type is
1099  *	Terminal size
1100  *	Terminal speed is
1101  */
1102 
1103 suboption()
1104 {
1105     switch (SB_GET()) {
1106     case TELOPT_TTYPE: {		/* Yaaaay! */
1107 	static char terminalname[5+41] = "TERM=";
1108 
1109 	settimer(ttypesubopt);
1110 
1111 	if (SB_GET() != TELQUAL_IS) {
1112 	    return;		/* ??? XXX but, this is the most robust */
1113 	}
1114 
1115 	terminaltype = terminalname+strlen(terminalname);
1116 
1117 	while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
1118 								    !SB_EOF()) {
1119 	    register int c;
1120 
1121 	    c = SB_GET();
1122 	    if (isupper(c)) {
1123 		c = tolower(c);
1124 	    }
1125 	    *terminaltype++ = c;    /* accumulate name */
1126 	}
1127 	*terminaltype = 0;
1128 	terminaltype = terminalname;
1129 	break;
1130     }
1131     case TELOPT_NAWS: {
1132 	struct winsize win;
1133 
1134 	ioctl(pty, TIOCGWINSZ, &win);
1135 	settimer(ttypesubopt);
1136 
1137 	syslog(LOG_INFO, "%x %x %x %x",
1138 	subpointer[0],subpointer[1],subpointer[2],subpointer[3]);
1139 	win.ws_col = SB_GET() << 8;
1140 	win.ws_col |= SB_GET();
1141 	win.ws_row = SB_GET() << 8;
1142 	win.ws_row |= SB_GET();
1143 	syslog(LOG_INFO, "col %d row %d", win.ws_col, win.ws_row);
1144 	ioctl(pty, TIOCSWINSZ, &win);
1145 	break;
1146     }
1147     case TELOPT_TSPEED: {
1148 	char speeds[41],*cp=speeds;
1149 	struct sgttyb b;
1150 	int ispeed,ospeed;
1151 	char *ispeeds,*ospeeds;
1152 
1153 	if (SB_GET() != TELQUAL_IS) {
1154 	    return;             /* ??? XXX but, this is the most robust */
1155 	}
1156 
1157 	ispeeds = NULL;
1158 	ospeeds = speeds;
1159 	ispeed = 0;
1160 	ospeed = 0;
1161 	while ((cp < (speeds + sizeof speeds-1)) && !SB_EOF()) {
1162 	    register int c;
1163 
1164 	    c = SB_GET();
1165 	    if (c == ',') {
1166 		c = 0;
1167 		ispeeds = cp+1;
1168 	    }
1169 	    *cp++ = c;    /* accumulate name */
1170 	}
1171 	*cp = 0;
1172 
1173 	if (ispeeds)
1174 	    ispeed = string2speed(ispeeds);
1175 	if (ospeeds)
1176 	    ospeed = string2speed(ospeeds);
1177 
1178 	if (ispeed && ospeed) {
1179 	    ioctl(pty, TIOCGETP, &b);
1180 	    b.sg_ospeed = ospeed;
1181 	    b.sg_ispeed = ispeed;
1182 	    ioctl(pty, TIOCSETP, &b);
1183 	}
1184 
1185 	break;
1186     }
1187     default:
1188 	;
1189     }
1190 }
1191 
1192 mode(on, off)
1193 	int on, off;
1194 {
1195 	struct sgttyb b;
1196 
1197 	ptyflush();
1198 	ioctl(pty, TIOCGETP, &b);
1199 	b.sg_flags |= on;
1200 	b.sg_flags &= ~off;
1201 	ioctl(pty, TIOCSETP, &b);
1202 }
1203 
1204 /*
1205  * Send interrupt to process on other side of pty.
1206  * If it is in raw mode, just write NULL;
1207  * otherwise, write intr char.
1208  */
1209 interrupt()
1210 {
1211 	struct sgttyb b;
1212 	struct tchars tchars;
1213 
1214 	ptyflush();	/* half-hearted */
1215 	ioctl(pty, TIOCGETP, &b);
1216 	if (b.sg_flags & RAW) {
1217 		*pfrontp++ = '\0';
1218 		return;
1219 	}
1220 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
1221 		'\177' : tchars.t_intrc;
1222 }
1223 
1224 /*
1225  * Send quit to process on other side of pty.
1226  * If it is in raw mode, just write NULL;
1227  * otherwise, write quit char.
1228  */
1229 sendbrk()
1230 {
1231 	struct sgttyb b;
1232 	struct tchars tchars;
1233 
1234 	ptyflush();	/* half-hearted */
1235 	ioctl(pty, TIOCGETP, &b);
1236 	if (b.sg_flags & RAW) {
1237 		*pfrontp++ = '\0';
1238 		return;
1239 	}
1240 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
1241 		'\034' : tchars.t_quitc;
1242 }
1243 
1244 ptyflush()
1245 {
1246 	int n;
1247 
1248 	if ((n = pfrontp - pbackp) > 0)
1249 		n = write(pty, pbackp, n);
1250 	if (n < 0)
1251 		return;
1252 	pbackp += n;
1253 	if (pbackp == pfrontp)
1254 		pbackp = pfrontp = ptyobuf;
1255 }
1256 
1257 /*
1258  * nextitem()
1259  *
1260  *	Return the address of the next "item" in the TELNET data
1261  * stream.  This will be the address of the next character if
1262  * the current address is a user data character, or it will
1263  * be the address of the character following the TELNET command
1264  * if the current address is a TELNET IAC ("I Am a Command")
1265  * character.
1266  */
1267 
1268 char *
1269 nextitem(current)
1270 char	*current;
1271 {
1272     if ((*current&0xff) != IAC) {
1273 	return current+1;
1274     }
1275     switch (*(current+1)&0xff) {
1276     case DO:
1277     case DONT:
1278     case WILL:
1279     case WONT:
1280 	return current+3;
1281     case SB:		/* loop forever looking for the SE */
1282 	{
1283 	    register char *look = current+2;
1284 
1285 	    for (;;) {
1286 		if ((*look++&0xff) == IAC) {
1287 		    if ((*look++&0xff) == SE) {
1288 			return look;
1289 		    }
1290 		}
1291 	    }
1292 	}
1293     default:
1294 	return current+2;
1295     }
1296 }
1297 
1298 
1299 /*
1300  * netclear()
1301  *
1302  *	We are about to do a TELNET SYNCH operation.  Clear
1303  * the path to the network.
1304  *
1305  *	Things are a bit tricky since we may have sent the first
1306  * byte or so of a previous TELNET command into the network.
1307  * So, we have to scan the network buffer from the beginning
1308  * until we are up to where we want to be.
1309  *
1310  *	A side effect of what we do, just to keep things
1311  * simple, is to clear the urgent data pointer.  The principal
1312  * caller should be setting the urgent data pointer AFTER calling
1313  * us in any case.
1314  */
1315 
1316 netclear()
1317 {
1318     register char *thisitem, *next;
1319     char *good;
1320 #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
1321 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
1322 
1323     thisitem = netobuf;
1324 
1325     while ((next = nextitem(thisitem)) <= nbackp) {
1326 	thisitem = next;
1327     }
1328 
1329     /* Now, thisitem is first before/at boundary. */
1330 
1331     good = netobuf;	/* where the good bytes go */
1332 
1333     while (nfrontp > thisitem) {
1334 	if (wewant(thisitem)) {
1335 	    int length;
1336 
1337 	    next = thisitem;
1338 	    do {
1339 		next = nextitem(next);
1340 	    } while (wewant(next) && (nfrontp > next));
1341 	    length = next-thisitem;
1342 	    bcopy(thisitem, good, length);
1343 	    good += length;
1344 	    thisitem = next;
1345 	} else {
1346 	    thisitem = nextitem(thisitem);
1347 	}
1348     }
1349 
1350     nbackp = netobuf;
1351     nfrontp = good;		/* next byte to be sent */
1352     neturg = 0;
1353 }
1354 
1355 /*
1356  *  netflush
1357  *		Send as much data as possible to the network,
1358  *	handling requests for urgent data.
1359  */
1360 
1361 
1362 netflush()
1363 {
1364     int n;
1365 
1366     if ((n = nfrontp - nbackp) > 0) {
1367 	/*
1368 	 * if no urgent data, or if the other side appears to be an
1369 	 * old 4.2 client (and thus unable to survive TCP urgent data),
1370 	 * write the entire buffer in non-OOB mode.
1371 	 */
1372 	if ((neturg == 0) || (not42 == 0)) {
1373 	    n = write(net, nbackp, n);	/* normal write */
1374 	} else {
1375 	    n = neturg - nbackp;
1376 	    /*
1377 	     * In 4.2 (and 4.3) systems, there is some question about
1378 	     * what byte in a sendOOB operation is the "OOB" data.
1379 	     * To make ourselves compatible, we only send ONE byte
1380 	     * out of band, the one WE THINK should be OOB (though
1381 	     * we really have more the TCP philosophy of urgent data
1382 	     * rather than the Unix philosophy of OOB data).
1383 	     */
1384 	    if (n > 1) {
1385 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
1386 	    } else {
1387 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
1388 	    }
1389 	}
1390     }
1391     if (n < 0) {
1392 	if (errno == EWOULDBLOCK)
1393 	    return;
1394 	/* should blow this guy away... */
1395 	return;
1396     }
1397     nbackp += n;
1398     if (nbackp >= neturg) {
1399 	neturg = 0;
1400     }
1401     if (nbackp == nfrontp) {
1402 	nbackp = nfrontp = netobuf;
1403     }
1404 }
1405 
1406 cleanup()
1407 {
1408 	char *p;
1409 
1410 	p = line + sizeof("/dev/") - 1;
1411 	if (logout(p))
1412 		logwtmp(p, "", "");
1413 	(void)chmod(line, 0666);
1414 	(void)chown(line, 0, 0);
1415 	*p = 'p';
1416 	(void)chmod(line, 0666);
1417 	(void)chown(line, 0, 0);
1418 	shutdown(net, 2);
1419 	exit(1);
1420 }
1421 
1422 char	editedhost[32];
1423 
1424 edithost(pat, host)
1425 	register char *pat;
1426 	register char *host;
1427 {
1428 	register char *res = editedhost;
1429 
1430 	if (!pat)
1431 		pat = "";
1432 	while (*pat) {
1433 		switch (*pat) {
1434 
1435 		case '#':
1436 			if (*host)
1437 				host++;
1438 			break;
1439 
1440 		case '@':
1441 			if (*host)
1442 				*res++ = *host++;
1443 			break;
1444 
1445 		default:
1446 			*res++ = *pat;
1447 			break;
1448 
1449 		}
1450 		if (res == &editedhost[sizeof editedhost - 1]) {
1451 			*res = '\0';
1452 			return;
1453 		}
1454 		pat++;
1455 	}
1456 	if (*host)
1457 		strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
1458 	else
1459 		*res = '\0';
1460 	editedhost[sizeof editedhost - 1] = '\0';
1461 }
1462 
1463 static char *putlocation;
1464 
1465 puts(s)
1466 register char *s;
1467 {
1468 
1469 	while (*s)
1470 		putchr(*s++);
1471 }
1472 
1473 putchr(cc)
1474 {
1475 	*putlocation++ = cc;
1476 }
1477 
1478 putf(cp, where)
1479 register char *cp;
1480 char *where;
1481 {
1482 	char *slash;
1483 	char datebuffer[60];
1484 	extern char *rindex();
1485 
1486 	putlocation = where;
1487 
1488 	while (*cp) {
1489 		if (*cp != '%') {
1490 			putchr(*cp++);
1491 			continue;
1492 		}
1493 		switch (*++cp) {
1494 
1495 		case 't':
1496 			slash = rindex(line, '/');
1497 			if (slash == (char *) 0)
1498 				puts(line);
1499 			else
1500 				puts(&slash[1]);
1501 			break;
1502 
1503 		case 'h':
1504 			puts(editedhost);
1505 			break;
1506 
1507 		case 'd':
1508 			get_date(datebuffer);
1509 			puts(datebuffer);
1510 			break;
1511 
1512 		case '%':
1513 			putchr('%');
1514 			break;
1515 		}
1516 		cp++;
1517 	}
1518 }
1519