|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)telnetd.c 4.26 (Berkeley) 83/08/06";
3: #endif
4:
5: /*
6: * Stripped-down telnet server.
7: */
8: #include <stdio.h>
9: #include <sys/param.h>
10: #include <sys/types.h>
11: #include <sys/stat.h>
12:
13: #include <errno.h>
14: #include <pwd.h>
15: #include <signal.h>
16: #include <sgtty.h>
17: #include <stdio.h>
18: #include <wait.h>
19: #include <sys/inet/in.h>
20: #include <sys/ttyld.h>
21: #include <sys/stream.h>
22: #include "config.h"
23: #include "telnet.h"
24:
25: #define BELL '\07'
26: #define DEBUG if (debug)
27:
28: /* option settings (remote and local) */
29: static char hisopts[256];
30: static char myopts[256];
31:
32: /* formats for option messages */
33: static char doopt[] = { IAC, DO, '%', 'c', 0 };
34: static char dont[] = { IAC, DONT, '%', 'c', 0 };
35: static char will[] = { IAC, WILL, '%', 'c', 0 };
36: static char wont[] = { IAC, WONT, '%', 'c', 0 };
37:
38: static int ptno; /* number of the pt */
39: static int ptfd, netfd; /* fd's to pt and tcp */
40: static int done; /* true if session is to be ended */
41: static int debug; /* true if debugging is to be output */
42: static struct sgttyb ptb; /* result of an IOCGETP on the pt */
43: static struct tchars ptt; /* result of an IOCGETC on the pt */
44:
45: /* predefined */
46: static reapchild();
47: static catchint();
48:
49: /* imported */
50: extern char **environ;
51: extern int errno;
52: extern char *strrchr(), *strchr();
53:
54:
55: /*
56: * The following macros and routines are used to
57: * manage the I/O buffers. They're a cross between
58: * stream buffers and standard I/O.
59: */
60: struct buffer {
61: char *b_rp; /* read pointer */
62: char *b_wp; /* write pointer */
63: char b_buf[BUFSIZ]; /* the buffer */
64: };
65: struct buffer ptibuf, *ptin = &ptibuf;
66: struct buffer ptobuf, *ptout = &ptobuf;
67: struct buffer netibuf, *netin = &netibuf;
68: struct buffer netobuf, *netout = &netobuf;
69:
70: #define binit(bp) (bp->b_rp = bp->b_wp = bp->b_buf)
71: #define bytes_filled(bp) (bp->b_wp - bp->b_rp)
72: #define space_left(bp) (bp->b_buf+sizeof(bp->b_buf) - bp->b_wp)
73: #define bput(bp, c) (*(bp->b_wp++) = c)
74: #define bget(bp) (*(bp->b_rp++) & 0377)
75:
76: /* read whatever the buffer can take */
77: static int
78: bread(bp, fd)
79: struct buffer *bp;
80: int fd;
81: {
82: int cc;
83:
84: /* normalize the buffer */
85: if (bytes_filled(bp) == 0)
86: bp->b_rp = bp->b_wp = bp->b_buf;
87:
88: /* fill it */
89: cc = read(fd, bp->b_wp, space_left(bp));
90: if (cc > 0)
91: bp->b_wp += cc;
92: return cc;
93: }
94:
95: /* read at most n bytes */
96: static int
97: breadn(bp, fd, n)
98: struct buffer *bp;
99: int fd, n;
100: {
101: int cc;
102:
103: /* normalize the buffer */
104: if (bytes_filled(bp) == 0)
105: bp->b_rp = bp->b_wp = bp->b_buf;
106: if (n > space_left(bp))
107: n = space_left(bp);
108:
109: /* fill it */
110: cc = read(fd, bp->b_wp, n);
111: if (cc > 0)
112: bp->b_wp += cc;
113: return cc;
114: }
115:
116: /* empty the buffer */
117: static int
118: bwrite(bp, fd)
119: struct buffer *bp;
120: int fd;
121: {
122: int cc;
123:
124:
125: cc = write(fd, bp->b_rp, bytes_filled(bp));
126:
127: /* normalize the buffer */
128: if (cc == bytes_filled(bp))
129: binit(bp);
130: return cc;
131: }
132: static int
133: bputs(bp, s)
134: struct buffer *bp;
135: char *s;
136: {
137: while (*s)
138: bput(bp, *s++);
139: }
140:
141: /*
142: * Establish a tcp socket and fork off a process for each connection.
143: */
144: main(argc, argv)
145: char *argv[];
146: {
147: int pid;
148: int f, dev;
149: unsigned long faddr;
150: int myport, fport;
151: struct in_service *sp;
152:
153: sp = in_service("telnet", "tcp", 0);
154: if (sp == 0) {
155: fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
156: exit(1);
157: }
158: myport = sp->port;
159: argc--, argv++;
160: if (argc > 0 && !strcmp(*argv, "-d")) {
161: debug++;
162: argc--, argv++;
163: }
164: signal(SIGPIPE, SIG_IGN);
165: signal(SIGHUP, SIG_IGN);
166:
167: do {
168: f = tcp_sock();
169: if (f < 0) {
170: perror("telnetd: socket");;
171: sleep(5);
172: continue;
173: }
174: if (tcp_listen(f, myport, 0, 0) < 0) {
175: close(f);
176: f = -1;
177: sleep(30);
178: continue;
179: }
180: } while (f < 0);
181:
182: signal(SIGCHLD, reapchild);
183: for (;;) {
184: int s;
185:
186: s = tcp_accept(f, &faddr, &fport, &dev);
187: if (s < 0) {
188: if (errno == EINTR)
189: continue;
190: perror("telnetd: accept");
191: sleep(1);
192: continue;
193: }
194: switch(fork()) {
195: case -1:
196: printf("Out of processes\n");
197: break;
198: case 0:
199: doit(s, faddr, fport, dev);
200: exit(0);
201: }
202: close(s);
203: }
204: /*NOTREACHED*/
205: }
206:
207: static
208: reapchild()
209: {
210: union wait status;
211:
212: while (wait3(&status, WNOHANG, 0) > 0)
213: ;
214: }
215:
216: char *envinit[] = { "TERM=network", 0 };
217:
218: /*
219: * Get a pt. Put a login on one side and a telnet receiver on
220: * the other.
221: */
222: static
223: doit(f, faddr, fport, dev)
224: int f;
225: unsigned long faddr;
226: {
227: char *host, *in_ntoa(), *ptname();
228: int pfd[2];
229: # define TERMEND pfd[0]
230: # define PROCEND pfd[1]
231: extern int tty_ld, mesg_ld;
232:
233: /* get a pt pair */
234: if ((ptno = ptpipe(pfd)) < 0)
235: fatalperror(f, "out of pts", errno);
236:
237: host = (char *)in_host(faddr);
238: if (host == 0)
239: host = in_ntoa(faddr);
240: DEBUG fprintf(stderr, "telnet from %s: login on %s\n", host, ptname(ptno));
241: DEBUG fprintf(stderr, "telnetd pid = %d\n", getpid());
242:
243:
244: /* get the pt's characteristics */
245: ioctl(PROCEND, TIOCGETC, &ptt);
246: ioctl(PROCEND, TIOCGETP, &ptb);
247:
248: /* make it really look like a terminal */
249: ioctl(TERMEND, FIOPUSHLD, (struct sgttyb *)&mesg_ld);
250: ioctl(PROCEND, FIOPUSHLD, (struct sgttyb *)&tty_ld);
251:
252: /* prepare for the death of a child */
253: signal(SIGCHLD, catchint);
254: switch (fork()) {
255: case -1:
256: fatalperror(f, "fork", errno);
257: case 0:
258: /* a process which is the remote login */
259: getty(PROCEND);
260: default:
261: /* the protocol process */
262: close(PROCEND);
263: netfd = f;
264: ptfd = TERMEND;
265: telnet();
266: }
267:
268: /*NOTREACHED*/
269: }
270:
271: static
272: fatal(f, msg)
273: int f;
274: char *msg;
275: {
276: char buf[BUFSIZ];
277:
278: (void) sprintf(buf, "telnetd: %s.\n", msg);
279: (void) write(f, buf, strlen(buf));
280: exit(1);
281: }
282:
283: static
284: fatalperror(f, msg, errno)
285: int f;
286: char *msg;
287: int errno;
288: {
289: char buf[BUFSIZ];
290: extern char *sys_errlist[];
291:
292: (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
293: fatal(f, buf);
294: }
295:
296: static
297: terminate(s)
298: char *s;
299: {
300: DEBUG fprintf(stderr, "session on %s terminated because of %s\n",
301: ptname(ptno), s);
302: done = 1;
303: }
304:
305: /* loop on input from the pt and the network */
306: static
307: telnet()
308: {
309: register int c;
310: int n;
311: fd_set ibits, obits;
312:
313: binit(ptin);
314: binit(ptout);
315: binit(netin);
316: binit(netout);
317:
318: /* Request to do remote echo. */
319: dooption(TELOPT_ECHO);
320: myopts[TELOPT_ECHO] = 1;
321:
322: while(!done) {
323: FD_ZERO(ibits);
324: FD_ZERO(obits);
325:
326: /* process anything sitting in the input buffers */
327: if (bytes_filled(ptin) > 0)
328: ptprocess();
329: if (bytes_filled(netin) > 0)
330: netprocess();
331:
332: /* select for read only if there's room to read into */
333: if (space_left(netin) > 0)
334: FD_SET(netfd, ibits);
335: if (space_left(ptin) > 0)
336: FD_SET(ptfd, ibits);
337:
338: /* select for write only if there's something to write */
339: if (bytes_filled(ptout) > 0)
340: FD_SET(ptfd, obits);
341: if (bytes_filled(netout) > 0)
342: FD_SET(netfd, obits);
343:
344: n = select(NOFILE, &ibits, &obits, 100000);
345: if (n < 0)
346: break;
347: else if (n == 0)
348: continue;
349:
350: /* fill input buffers */
351: if (FD_ISSET(netfd, ibits))
352: netrcv();
353: if (FD_ISSET(ptfd, ibits))
354: ptrcv();
355:
356: /* flush output buffers */
357: if (FD_ISSET(netfd, obits) && bytes_filled(netout) > 0)
358: netflush();
359: if (FD_ISSET(ptfd, obits) && bytes_filled(ptout) > 0)
360: ptflush();
361: }
362: rmut();
363: close(netfd);
364: close(ptfd);
365: exit(0);
366: }
367:
368: struct mesg {
369: short type;
370: short size;
371: };
372: static struct mesg m;
373:
374: /* read from the pt */
375: static
376: ptrcv()
377: {
378: /* get the header if we don't already have one */
379: if (m.size <= 0)
380: if (read(ptfd, &m, sizeof(m)) != sizeof(m)) {
381: terminate("pt read");
382: return;
383: }
384: switch(m.type) {
385: case M_HANGUP:
386: terminate("pt hangup");
387: break;
388: case M_DATA:
389: datamesg();
390: break;
391: case M_IOCTL:
392: ioctlmesg();
393: break;
394: case M_IOCACK:
395: fprintf(stderr, "IOCACK\n");
396: flushmesg();
397: break;
398: case M_IOCNAK:
399: fprintf(stderr, "IOCNAK\n");
400: flushmesg();
401: break;
402: default:
403: othermesg();
404: break;
405: }
406: }
407:
408: /* flush a message from the pt */
409: static
410: flushmesg()
411: {
412: union stmsg s;
413: int cc;
414:
415: /* flush it */
416: while (m.size > 0) {
417: fprintf(stderr, "flush\n");
418: cc = read(ptfd, &s, sizeof(s));
419: if (cc < 0) {
420: terminate("pt read");
421: return;
422: }
423: m.size -= cc;
424: }
425: }
426:
427: /* handle an ioctl message from the pt */
428: static
429: ioctlmesg()
430: {
431: struct mesg rm;
432: union stmsg s;
433: int cc;
434:
435: rm.size = m.size;
436: if (m.size > 0) {
437: cc = read(ptfd, &s, sizeof(s));
438: if (cc < 0) {
439: terminate("pt read");
440: return;
441: }
442: m.size -= cc;
443: }
444: rm.type = M_IOCACK;
445: switch (s.ioc0.com) {
446:
447: case TIOCSETN:
448: case TIOCSETP:
449: ptb = s.ioc1.sb;
450: rm.size = 0;
451: break;
452:
453: case TIOCGETP:
454: s.ioc1.sb.sg_ispeed = B9600;
455: s.ioc1.sb.sg_ospeed = B9600;
456: ptb = s.ioc1.sb;
457: break;
458:
459: default:
460: rm.type = M_IOCNAK;
461: rm.size = 0;
462: break;
463: }
464: if (write(ptfd, &rm, sizeof(rm)) != sizeof(rm)) {
465: terminate("pt write");
466: return;
467: }
468: if (rm.size > 0)
469: if (write(ptfd, &s, rm.size) != rm.size) {
470: terminate("pt write");
471: return;
472: }
473:
474: flushmesg();
475: }
476:
477: /* read bytes from the pt and write to the network connection */
478: static
479: datamesg()
480: {
481: int cc;
482:
483: cc = breadn(ptin, ptfd, m.size);
484: if (cc < 0)
485: terminate("pt read");
486: else
487: m.size -= cc;
488: }
489:
490: /* handle an unrecognized type of message */
491: static
492: othermesg()
493: {
494: struct mesg rm;
495: char buf[132];
496: int rcc, wcc;
497:
498: wcc = write(ptfd, &m, sizeof(m));
499: if (wcc != sizeof(m)) {
500: terminate("pt write");
501: return;
502: }
503: while (m.size > 0) {
504: rcc = read(ptfd, buf, sizeof(buf));
505: if (rcc < 0) {
506: terminate("pt read");
507: return;
508: }
509: wcc = write(ptfd, buf, rcc);
510: if (wcc != rcc) {
511: terminate("pt write");
512: return;
513: }
514: m.size -= rcc;
515: }
516: }
517:
518: /* set pt mode */
519: static
520: mode(on, off)
521: int on, off;
522: {
523: ptflush();
524: ptb.sg_flags |= on;
525: ptb.sg_flags &= ~off;
526: if(ioctl(ptfd, TIOCSETP, &ptb)<0)
527: terminate("setting mode of pt");
528: }
529:
530: /* flush the pt's output buffer */
531: ptflush()
532: {
533: struct mesg rm;
534:
535: rm.type = M_DATA;
536: rm.size = bytes_filled(ptout);
537: if (rm.size > 0) {
538: if (write(ptfd, &rm, sizeof(rm)) < sizeof(rm))
539: terminate("pt write");
540: else if (bwrite(ptout, ptfd) <= 0)
541: terminate("pt write");
542: }
543: }
544:
545: /* process bytes from the pt */
546: static
547: ptprocess()
548: {
549: register int c;
550:
551: while(bytes_filled(ptin) && space_left(netout) > 1) {
552: c = bget(ptin);
553: if (c == IAC)
554: bput(netout, c);
555: bput(netout, c);
556: }
557: }
558:
559: /* read bytes from the net */
560: static
561: netrcv()
562: {
563: if (bread(netin, netfd) < 0)
564: terminate("net read");
565: }
566:
567: /* flush the netwrk's output buffer */
568: netflush()
569: {
570: if (bwrite(netout, netfd) < 0)
571: terminate("net write");
572: }
573:
574: /*
575: * State for recv fsm
576: */
577: #define TS_DATA 0 /* base state */
578: #define TS_IAC 1 /* look for double IAC's */
579: #define TS_CR 2 /* CR-LF ->'s CR */
580: #define TS_BEGINNEG 3 /* throw away begin's... */
581: #define TS_ENDNEG 4 /* ...end's (suboption negotiation) */
582: #define TS_WILL 5 /* will option negotiation */
583: #define TS_WONT 6 /* wont " */
584: #define TS_DO 7 /* do " */
585: #define TS_DONT 8 /* dont " */
586:
587: static
588: netprocess()
589: {
590: static int state = TS_DATA;
591: register int c;
592: char buf[10];
593:
594: while (bytes_filled(netin)) {
595: c = bget(netin);
596: switch (state) {
597:
598: case TS_DATA:
599: if (c == IAC) {
600: state = TS_IAC;
601: break;
602: }
603: bput(ptout, c);
604: if (!myopts[TELOPT_BINARY] && c == '\r')
605: state = TS_CR;
606: break;
607:
608: case TS_CR:
609: if (c && c != '\n')
610: bput(ptout, c);
611: state = TS_DATA;
612: break;
613:
614: case TS_IAC:
615: switch (c) {
616:
617: /*
618: * Send the process on the pty side an
619: * interrupt. Do this with a NULL or
620: * interrupt char; depending on the tty mode.
621: */
622: case BREAK:
623: case IP:
624: interrupt();
625: break;
626:
627: /*
628: * Are You There?
629: */
630: case AYT:
631: bput(ptout, BELL);
632: break;
633:
634: /*
635: * Erase Character and
636: * Erase Line
637: */
638: case EC:
639: case EL:
640: ptflush();
641: bput(ptout, (c == EC) ? ptb.sg_erase : ptb.sg_kill);
642: break;
643:
644: /*
645: * Check for urgent data...
646: */
647: case DM:
648: break;
649:
650: /*
651: * Begin option subnegotiation...
652: */
653: case SB:
654: state = TS_BEGINNEG;
655: continue;
656:
657: case WILL:
658: case WONT:
659: case DO:
660: case DONT:
661: state = TS_WILL + (c - WILL);
662: continue;
663:
664: case IAC:
665: bput(ptout, c);
666: break;
667: }
668: state = TS_DATA;
669: break;
670:
671: case TS_BEGINNEG:
672: if (c == IAC)
673: state = TS_ENDNEG;
674: break;
675:
676: case TS_ENDNEG:
677: state = c == SE ? TS_DATA : TS_BEGINNEG;
678: break;
679:
680: case TS_WILL:
681: if (!hisopts[c])
682: willoption(c);
683: state = TS_DATA;
684: continue;
685:
686: case TS_WONT:
687: if (hisopts[c])
688: wontoption(c);
689: state = TS_DATA;
690: continue;
691:
692: case TS_DO:
693: if (!myopts[c])
694: dooption(c);
695: state = TS_DATA;
696: continue;
697:
698: case TS_DONT:
699: if (myopts[c]) {
700: myopts[c] = 0;
701: sprintf(buf, wont, c);
702: bputs(netout, buf);
703: }
704: state = TS_DATA;
705: continue;
706:
707: default:
708: printf("telnetd: panic state=%d\n", state);
709: exit(1);
710: }
711: }
712: }
713:
714: static
715: willoption(option)
716: int option;
717: {
718: char *fmt;
719: char buf[10];
720:
721: switch (option) {
722:
723: case TELOPT_BINARY:
724: mode(RAW, 0);
725: goto common;
726:
727: case TELOPT_ECHO:
728: mode(0, ECHO|CRMOD);
729: /*FALL THRU*/
730:
731: case TELOPT_SGA:
732: common:
733: hisopts[option] = 1;
734: fmt = doopt;
735: break;
736:
737: case TELOPT_TM:
738: fmt = dont;
739: break;
740:
741: default:
742: fmt = dont;
743: break;
744: }
745: sprintf(buf, fmt, option);
746: bputs(netout, buf);
747: }
748:
749: static
750: wontoption(option)
751: int option;
752: {
753: char *fmt;
754: char buf[10];
755:
756: switch (option) {
757:
758: case TELOPT_ECHO:
759: mode(ECHO|CRMOD, 0);
760: goto common;
761:
762: case TELOPT_BINARY:
763: mode(0, RAW);
764: /*FALL THRU*/
765:
766: case TELOPT_SGA:
767: common:
768: hisopts[option] = 0;
769: fmt = dont;
770: break;
771:
772: default:
773: fmt = dont;
774: }
775: sprintf(buf, fmt, option);
776: bputs(netout, buf);
777: }
778:
779: static
780: dooption(option)
781: int option;
782: {
783: char *fmt;
784: char buf[10];
785:
786: switch (option) {
787:
788: case TELOPT_TM:
789: fmt = wont;
790: break;
791:
792: case TELOPT_ECHO:
793: mode(ECHO|CRMOD, 0);
794: goto common;
795:
796: case TELOPT_BINARY:
797: mode(RAW, 0);
798: /*FALL THRU*/
799:
800: case TELOPT_SGA:
801: common:
802: fmt = will;
803: break;
804:
805: default:
806: fmt = wont;
807: break;
808: }
809: sprintf(buf, fmt, option);
810: bputs(netout, buf);
811: }
812:
813: /*
814: * Send interrupt to process on other side of pty.
815: * If it is in raw mode, just write NULL;
816: * otherwise, write intr char.
817: */
818: static
819: interrupt()
820: {
821: ptflush();
822: ioctl(ptfd, TIOCGETC, &ptt);
823: bput(ptout, ptb.sg_flags & RAW ? '\0' : ptt.t_intrc);
824: }
825:
826: static
827: catchint()
828: {
829: terminate("child death");
830: }
831:
832: #include <utmp.h>
833:
834: struct utmp wtmp;
835: char wtmpf[] = "/usr/adm/wtmp";
836: char utmp[] = "/etc/utmp";
837: #define SCPYN(a, b) strncpy(a, b, sizeof (a))
838: #define SCMPN(a, b) strncmp(a, b, sizeof (a))
839:
840: static
841: rmut()
842: {
843: register f;
844: int found = 0;
845: char *line, *dev;
846:
847: dev = ptname(ptno);
848: line = dev + 5;
849:
850: DEBUG fprintf(stderr, "closing connection on %s\n", line);
851:
852: f = open(utmp, 2);
853: if (f >= 0) {
854: while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
855: if (SCMPN(wtmp.ut_line, line) || wtmp.ut_name[0]==0)
856: continue;
857: lseek(f, -(long)sizeof (wtmp), 1);
858: SCPYN(wtmp.ut_name, "");
859: time(&wtmp.ut_time);
860: write(f, (char *)&wtmp, sizeof (wtmp));
861: found++;
862: }
863: close(f);
864: }
865: if (found) {
866: f = open(wtmpf, 1);
867: if (f >= 0) {
868: SCPYN(wtmp.ut_line, line);
869: SCPYN(wtmp.ut_name, "");
870: time(&wtmp.ut_time);
871: lseek(f, (long)0, 2);
872: write(f, (char *)&wtmp, sizeof (wtmp));
873: close(f);
874: }
875: }
876: chown(dev, 0, 0);
877: chmod(dev, 0666);
878: }
879:
880: static
881: getty(f)
882: {
883: int i;
884: struct sgttyb b;
885: char banner[128];
886:
887: ioctl(f, TIOCSPGRP, 0);
888: signal(SIGTERM, SIG_DFL) ;
889: signal(SIGPIPE, SIG_DFL) ;
890: signal(SIGQUIT, SIG_DFL) ;
891: signal(SIGINT, SIG_DFL) ;
892: signal(SIGALRM, SIG_DFL) ;
893: signal(SIGHUP, SIG_DFL) ;
894: signal(SIGCHLD, SIG_DFL) ;
895: close(0) ;
896: close(1) ;
897: close(2) ;
898: close(3) ;
899: dup(f) ;
900: dup(f) ;
901: dup(f) ;
902: dup(f); /* for /dev/tty */
903: for (i=4; i<NOFILE; i++)
904: close(i) ;
905: ioctl(0, TIOCGETP, &b);
906: b.sg_flags |= CRMOD|XTABS|ANYP|ECHO;
907: b.sg_erase = '#';
908: b.sg_kill = '@';
909: ioctl(0, TIOCSETP, &b);
910: sprintf(banner, "%s (%s) ", whoami(), strrchr(ptname(ptno), '/')+1);
911: write (netfd, banner, strlen(banner));
912: execl(LOGIN, "login", 0);
913: fatalperror(2, LOGIN, errno);
914: exit(1);
915:
916: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.