X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ebeebc7d17bee9f42de8b11ee91ac92ae0664639..8c5eec2f1483710dd0abd91a5708e55e267e49f9:/usr/src/libexec/telnetd/telnetd.c diff --git a/usr/src/libexec/telnetd/telnetd.c b/usr/src/libexec/telnetd/telnetd.c index c7ce8c5986..e8928a7819 100644 --- a/usr/src/libexec/telnetd/telnetd.c +++ b/usr/src/libexec/telnetd/telnetd.c @@ -1,20 +1,41 @@ -static char sccsid[] = "@(#)telnetd.c 4.3 (Berkeley) %G%"; +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1983 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)telnetd.c 5.1 (Berkeley) %G%"; +#endif not lint + /* * Stripped-down telnet server. */ +#include +#include +#include +#include +#include + +#include + +#include + #include #include #include #include -#include -#include -#include -#include -#include "telnet.h" +#include +#include -#define INFINITY 10000000 -#define BELL '\07' -#define swab(x) ((((x) >> 8) | ((x) << 8)) & 0xffff) +#define BELL '\07' +#define BANNER "\r\n\r\n4.2 BSD UNIX (%s)\r\n\r\r\n\r%s" char hisopts[256]; char myopts[256]; @@ -30,104 +51,92 @@ char wont[] = { IAC, WONT, '%', 'c', 0 }; char ptyibuf[BUFSIZ], *ptyip = ptyibuf; char ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf; char netibuf[BUFSIZ], *netip = netibuf; -char netobuf[BUFSIZ] = - { IAC, DO, TELOPT_ECHO, '\r', '\n' }, - *nfrontp = netobuf + 5, *nbackp = netobuf; +char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; int pcc, ncc; int pty, net; int inter; +extern char **environ; extern int errno; -char line[] = "/dev/ptyp0"; - -struct sockaddr_in sin = { AF_INET, swab(IPPORT_TELNET) }; -int options = SO_ACCEPTCONN; - -/* - * Debugging hooks. Turned on with a SIGTERM. - * Successive SIGTERM's toggle the switch. - */ -int toggle(); -int debug; -FILE *log; -char logfile[80] = "/tmp/teldebugx"; +char *line; main(argc, argv) char *argv[]; { - int s, pid; - union wait status; - - argc--, argv++; - if (argc > 0 && !strcmp(argv[0], "-d")) - options |= SO_DEBUG; - for (;;) { - errno = 0; - if ((s = socket(SOCK_STREAM, 0, &sin, options)) < 0) { - perror("socket"); - sleep(5); - continue; - } - if (accept(s, 0) < 0) { - perror("accept"); - close(s); - sleep(1); - continue; - } - if ((pid = fork()) < 0) - printf("Out of processes\n"); - else if (pid == 0) - doit(s); - close(s); - while (wait3(status, WNOHANG, 0) > 0) - continue; + struct sockaddr_in from; + int on = 1, fromlen; + + fromlen = sizeof (from); + if (getpeername(0, &from, &fromlen) < 0) { + fprintf(stderr, "%s: ", argv[0]); + perror("getpeername"); + _exit(1); } - /*NOTREACHED*/ + if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) { + openlog(argv[0], LOG_PID, 0); + syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); + } + doit(0, &from); } +char *envinit[] = { "TERM=network", 0 }; int cleanup(); /* * Get a pty, scan input lines. */ -doit(f) +doit(f, who) + int f; + struct sockaddr_in *who; { - char *cp = line; - int i, p, cc, t; + char *host, *inet_ntoa(); + int i, p, t; struct sgttyb b; + struct hostent *hp; + char c; - for (i = 0; i < 16; i++) { - cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; - p = open(cp, 2); - if (p > 0) - goto gotpty; + for (c = 'p'; c <= 's'; c++) { + struct stat stb; + + line = "/dev/ptyXX"; + line[strlen("/dev/pty")] = c; + line[strlen("/dev/ptyp")] = '0'; + if (stat(line, &stb) < 0) + break; + for (i = 0; i < 16; i++) { + line[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; + p = open(line, 2); + if (p > 0) + goto gotpty; + } } - dup2(f, 1); - printf("All network ports in use.\n"); - exit(1); + fatal(f, "All network ports in use"); + /*NOTREACHED*/ gotpty: - logfile[strlen("/tmp/teldebug")] = "0123456789abcdef"[i]; dup2(f, 0); - cp[strlen("/dev/")] = 't'; - t = open("/dev/tty", 2); + line[strlen("/dev/")] = 't'; + t = open("/dev/tty", O_RDWR); if (t >= 0) { ioctl(t, TIOCNOTTY, 0); close(t); } - t = open(cp, 2); - if (t < 0) { - dup2(f, 2); - perror(cp); - exit(1); - } + t = open(line, O_RDWR); + if (t < 0) + fatalperror(f, line, errno); ioctl(t, TIOCGETP, &b); - b.sg_flags = ECHO|CRMOD|XTABS|ANYP; + b.sg_flags = CRMOD|XTABS|ANYP; ioctl(t, TIOCSETP, &b); - if ((i = fork()) < 0) { - dup2(f, 2); - perror("fork"); - exit(1); - } + ioctl(p, TIOCGETP, &b); + b.sg_flags &= ~ECHO; + ioctl(p, TIOCSETP, &b); + hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr), + who->sin_family); + if (hp) + host = hp->h_name; + else + host = inet_ntoa(who->sin_addr); + if ((i = fork()) < 0) + fatalperror(f, "fork", errno); if (i) telnet(f, p); close(f); @@ -136,11 +145,35 @@ gotpty: dup2(t, 1); dup2(t, 2); close(t); - execl("/bin/login", "telnet-login", 0); - perror("/bin/login"); + environ = envinit; + execl("/bin/login", "login", "-h", host, 0); + fatalperror(f, "/bin/login", errno); + /*NOTREACHED*/ +} + +fatal(f, msg) + int f; + char *msg; +{ + char buf[BUFSIZ]; + + (void) sprintf(buf, "telnetd: %s.\r\n", msg); + (void) write(f, buf, strlen(buf)); exit(1); } +fatalperror(f, msg, errno) + int f; + char *msg; + int errno; +{ + char buf[BUFSIZ]; + extern char *sys_errlist[]; + + (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]); + fatal(f, buf); +} + /* * Main loop. Select from pty and network, and * hand data to telnet receiver finite state machine. @@ -148,14 +181,25 @@ gotpty: telnet(f, p) { int on = 1; + char hostname[32]; net = f, pty = p; ioctl(f, FIONBIO, &on); ioctl(p, FIONBIO, &on); signal(SIGTSTP, SIG_IGN); - sigset(SIGCHLD, cleanup); - sigset(SIGTERM, toggle); - + signal(SIGCHLD, cleanup); + + /* + * Request to do remote echo. + */ + dooption(TELOPT_ECHO); + myopts[TELOPT_ECHO] = 1; + /* + * Show banner that getty never gave. + */ + gethostname(hostname, sizeof (hostname)); + sprintf(nfrontp, BANNER, hostname, ""); + nfrontp += strlen(nfrontp); for (;;) { int ibits = 0, obits = 0; register int c; @@ -164,22 +208,17 @@ telnet(f, p) * Never look for input if there's still * stuff in the corresponding output buffer */ - if (nfrontp - nbackp) + if (nfrontp - nbackp || pcc > 0) obits |= (1 << f); else ibits |= (1 << p); - if (pfrontp - pbackp) + if (pfrontp - pbackp || ncc > 0) obits |= (1 << p); else ibits |= (1 << f); if (ncc < 0 && pcc < 0) break; - if (debug) - fprintf(log, "select: ibits=%d, obits=%d\n", - ibits, obits); - select(32, &ibits, &obits, INFINITY); - if (debug) - fprintf(log, "ibits=%d, obits=%d\n", ibits, obits); + select(16, &ibits, &obits, 0, 0); if (ibits == 0 && obits == 0) { sleep(5); continue; @@ -190,8 +229,6 @@ telnet(f, p) */ if (ibits & (1 << f)) { ncc = read(f, netibuf, BUFSIZ); - if (debug) - fprintf(log, "read %d from net\n", ncc); if (ncc < 0 && errno == EWOULDBLOCK) ncc = 0; else { @@ -206,8 +243,6 @@ telnet(f, p) */ if (ibits & (1 << p)) { pcc = read(p, ptyibuf, BUFSIZ); - if (debug) - fprintf(log, "read %d from pty\n", pcc); if (pcc < 0 && errno == EWOULDBLOCK) pcc = 0; else { @@ -295,7 +330,8 @@ telrcv() * Are You There? */ case AYT: - *pfrontp++ = BELL; + strcpy(nfrontp, "\r\n[Yes]\r\n"); + nfrontp += 9; break; /* @@ -368,13 +404,13 @@ telrcv() if (myopts[c]) { myopts[c] = 0; sprintf(nfrontp, wont, c); - nfrontp += sizeof(wont) - 2; + nfrontp += sizeof (wont) - 2; } state = TS_DATA; continue; default: - printf("netser: panic state=%d\n", state); + printf("telnetd: panic state=%d\n", state); exit(1); } } @@ -410,7 +446,7 @@ willoption(option) break; } sprintf(nfrontp, fmt, option); - nfrontp += sizeof(dont) - 2; + nfrontp += sizeof (dont) - 2; } wontoption(option) @@ -438,7 +474,7 @@ wontoption(option) fmt = dont; } sprintf(nfrontp, fmt, option); - nfrontp += sizeof(doopt) - 2; + nfrontp += sizeof (doopt) - 2; } dooption(option) @@ -470,7 +506,7 @@ dooption(option) break; } sprintf(nfrontp, fmt, option); - nfrontp += sizeof(doopt) - 2; + nfrontp += sizeof (doopt) - 2; } mode(on, off) @@ -511,8 +547,8 @@ ptyflush() if ((n = pfrontp - pbackp) > 0) n = write(pty, pbackp, n); - if (n < 0 && errno == EWOULDBLOCK) - n = 0; + if (n < 0) + return; pbackp += n; if (pbackp == pfrontp) pbackp = pfrontp = ptyobuf; @@ -524,37 +560,23 @@ netflush() if ((n = nfrontp - nbackp) > 0) n = write(net, nbackp, n); - if (n < 0 && errno == EWOULDBLOCK) - n = 0; + if (n < 0) { + if (errno == EWOULDBLOCK) + return; + /* should blow this guy away... */ + return; + } nbackp += n; if (nbackp == nfrontp) nbackp = nfrontp = netobuf; } -toggle() -{ - if (debug) { - fprintf(log, "log stopped\n"); - if (log) - fclose(log); - } else { - if ((log = fopen(logfile, "a")) != NULL) { - setbuf(log, 0); - fprintf(log, "log started on /dev/pty%c\n", - logfile[strlen("/tmp/teldebug")]); - fprintf(log, "net=%d, pty=%d\n", net, pty); - } - } - debug = !debug; -} - cleanup() { - int how = 2; rmut(); - vhangup(); - ioctl(net, SIOCDONE, &how); + vhangup(); /* XXX */ + shutdown(net, 2); kill(0, SIGKILL); exit(1); } @@ -564,35 +586,36 @@ cleanup() struct utmp wtmp; char wtmpf[] = "/usr/adm/wtmp"; char utmp[] = "/etc/utmp"; -#define SCPYN(a, b) strncpy(a, b, sizeof(a)) -#define SCMPN(a, b) strncmp(a, b, sizeof(a)) +#define SCPYN(a, b) strncpy(a, b, sizeof (a)) +#define SCMPN(a, b) strncmp(a, b, sizeof (a)) rmut() { register f; int found = 0; - f = open(utmp, 2); + f = open(utmp, O_RDWR); if (f >= 0) { - while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) { + while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) continue; - lseek(f, -(long)sizeof(wtmp), 1); + lseek(f, -(long)sizeof (wtmp), L_INCR); SCPYN(wtmp.ut_name, ""); + SCPYN(wtmp.ut_host, ""); time(&wtmp.ut_time); - write(f, (char *)&wtmp, sizeof(wtmp)); + write(f, (char *)&wtmp, sizeof (wtmp)); found++; } close(f); } if (found) { - f = open(wtmpf, 1); + f = open(wtmpf, O_WRONLY|O_APPEND); if (f >= 0) { SCPYN(wtmp.ut_line, line+5); SCPYN(wtmp.ut_name, ""); + SCPYN(wtmp.ut_host, ""); time(&wtmp.ut_time); - lseek(f, (long)0, 2); - write(f, (char *)&wtmp, sizeof(wtmp)); + write(f, (char *)&wtmp, sizeof (wtmp)); close(f); } }