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