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