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