📄 rlogin.c
字号:
* signals to the child. We can now unblock SIGURG and SIGUSR1 * that were set above. */ /* Reenables SIGURG and SIUSR1. */ sigprocmask (SIG_SETMASK, smask, (sigset_t *) 0); setsig (SIGCHLD, catch_child); writer (); /* If the write returns, it means the user entered "~." on the terminal. In this case we terminate and the server will eventually get an EOF on its end of the network connection. This should cause the server to log you out on the remote system. */ msg ("closed connection."); done (0);}/* Enable a signal handler, unless the signal is already being ignored. This function is called before the fork (), for SIGHUP and SIGQUIT. *//* Trap a signal, unless it is being ignored. */voidsetsignal (int sig){ sig_t handler; sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, sig); sigprocmask(SIG_BLOCK, &sigs, &sigs); handler = setsig (sig, exit); if (handler == SIG_IGN) setsig (sig, handler); sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);}/* This function is called by the parent: (1) at the end (user terminates the client end); (2) SIGCLD signal - the sigcld_parent () function. (3) SIGPPE signal - the connection has dropped. We send the child a SIGKILL signal, which it can't ignore, then wait for it to terminate. */voiddone (int status){ pid_t w; int wstatus; mode(0); if (child > 0) { /* make sure catch_child does not snap it up */ setsig (SIGCHLD, SIG_DFL); if (kill (child, SIGKILL) >= 0) while ((w = wait (&wstatus)) > 0 && w != child) continue; } exit (status);}int dosigwinch;/* * This is called when the reader process gets the out-of-band (urgent) * request to turn on the window-changing protocol. */voidwriteroob (int signo){ (void)signo; if (dosigwinch == 0) { sendwindow (); setsig (SIGWINCH, sigwinch); } dosigwinch = 1;}voidcatch_child (int signo){ int status; pid_t pid; (void)signo; for (;;) { pid = waitpid (-1, &status, WNOHANG | WUNTRACED); if (pid == 0) return; /* if the child (reader) dies, just quit */ if (pid < 0 || (pid == child && !WIFSTOPPED (status))) done (WEXITSTATUS (status) | WTERMSIG (status)); } /* NOTREACHED */}/* * writer: write to remote: 0 -> line. * ~. terminate * ~^Z suspend rlogin process. * ~<delayed-suspend char> suspend rlogin process, but leave reader alone. */voidwriter (){ register int bol, local, n; char c; bol = 1; /* beginning of line */ local = 0; for (;;) { n = read (STDIN_FILENO, &c, 1); if (n <= 0) { if (n < 0 && errno == EINTR) continue; break; } /* * If we're at the beginning of the line and recognize a * command character, then we echo locally. Otherwise, * characters are echo'd remotely. If the command character * is doubled, this acts as a force and local echo is * suppressed. */ if (bol) { bol = 0; if (!noescape && c == escapechar) { local = 1; continue; } } else if (local) { local = 0; if (c == '.' || c == deftt.c_cc[VEOF]) { echo (c); break; } if (c == deftt.c_cc[VSUSP]#ifdef VDSUSP || c == deftt.c_cc[VDSUSP]#endif ) { bol = 1; echo (c); stop (c); continue; } if (c != escapechar)#ifdef ENCRYPTION#ifdef KERBEROS if (doencrypt) des_write (rem, (char *)&escapechar, 1); else#endif#endif write (rem, &escapechar, 1); }#ifdef ENCRYPTION#ifdef KERBEROS if (doencrypt) { if (des_write (rem, &c, 1) == 0) { msg ("line gone"); break; } } else#endif#endif if (write (rem, &c, 1) == 0) { msg ("line gone"); break; } bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] || c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] || c == '\r' || c == '\n'; }}voidecho (register char c){ register char *p; char buf[8]; p = buf; c &= 0177; *p++ = escapechar; if (c < ' ') { *p++ = '^'; *p++ = c + '@'; } else if (c == 0177) { *p++ = '^'; *p++ = '?'; } else *p++ = c; *p++ = '\r'; *p++ = '\n'; write (STDOUT_FILENO, buf, p - buf);}voidstop (char cmdc){ mode (0); setsig (SIGCHLD, SIG_IGN); kill (cmdc == deftt.c_cc[VSUSP] ? 0 : getpid (), SIGTSTP); setsig (SIGCHLD, catch_child); mode (1); sigwinch (0); /* check for size changes */}voidsigwinch (int signo){ struct winsize ws; (void)signo; if (dosigwinch && get_window_size(0, &ws) == 0 && memcmp(&ws, &winsize, sizeof ws)) { winsize = ws; sendwindow (); }}/* * Send the window size to the server via the magic escape */voidsendwindow (){ struct winsize *wp; char obuf[4 + sizeof (struct winsize)]; wp = (struct winsize *)(obuf+4); obuf[0] = 0377; obuf[1] = 0377; obuf[2] = 's'; obuf[3] = 's'; wp->ws_row = htons (winsize.ws_row); wp->ws_col = htons (winsize.ws_col); wp->ws_xpixel = htons (winsize.ws_xpixel); wp->ws_ypixel = htons (winsize.ws_ypixel);#ifdef ENCRYPTION#ifdef KERBEROS if(doencrypt) des_write (rem, obuf, sizeof obuf); else#endif#endif write (rem, obuf, sizeof obuf);}/* * reader: read from remote: line -> 1 */#define READING 1#define WRITING 2jmp_buf rcvtop;pid_t ppid;int rcvcnt, rcvstate;char rcvbuf[8 * 1024];voidoob (int signo){ struct termios tt; int atmark, n, out, rcvd; char waste[BUFSIZ], mark; (void)signo; out = O_RDWR; rcvd = 0; while (recv (rem, &mark, 1, MSG_OOB) < 0) { switch (errno) { case EWOULDBLOCK: /* * Urgent data not here yet. It may not be possible * to send it yet if we are blocked for output and * our input buffer is full. */ if ((size_t)rcvcnt < sizeof rcvbuf) { n = read (rem, rcvbuf + rcvcnt, sizeof(rcvbuf) - rcvcnt); if (n <= 0) return; rcvd += n; } else { n = read (rem, waste, sizeof waste); if (n <= 0) return; } continue; default: return; } } if (mark & TIOCPKT_WINDOW) { /* Let server know about window size changes */ kill (ppid, SIGUSR1); } if (!eight && (mark & TIOCPKT_NOSTOP)) { tcgetattr (0, &tt); tt.c_iflag &= ~(IXON | IXOFF); tt.c_cc[VSTOP] = _POSIX_VDISABLE; tt.c_cc[VSTART] = _POSIX_VDISABLE; tcsetattr (0, TCSANOW, &tt); } if (!eight && (mark & TIOCPKT_DOSTOP)) { tcgetattr(0, &tt); tt.c_iflag |= (IXON|IXOFF); tt.c_cc[VSTOP] = deftt.c_cc[VSTOP]; tt.c_cc[VSTART] = deftt.c_cc[VSTART]; tcsetattr (0, TCSANOW, &tt); } if (mark & TIOCPKT_FLUSHWRITE) {#ifdef TIOCFLUSH ioctl (1, TIOCFLUSH, (char *)&out);#endif for (;;) { if (ioctl (rem, SIOCATMARK, &atmark) < 0) { warn ("ioctl SIOCATMARK (ignored)"); break; } if (atmark) break; n = read (rem, waste, sizeof waste); if (n <= 0) break; } /* * Don't want any pending data to be output, so clear the recv * buffer. If we were hanging on a write when interrupted, * don't want it to restart. If we were reading, restart * anyway. */ rcvcnt = 0; longjmp (rcvtop, 1); } /* oob does not do FLUSHREAD (alas!) */ /* * If we filled the receive buffer while a read was pending, longjmp * to the top to restart appropriately. Don't abort a pending write, * however, or we won't know how much was written. */ if (rcvd && rcvstate == READING) longjmp (rcvtop, 1);}/* reader: read from remote: line -> 1 */intreader (sigset_t *smask){ pid_t pid; int n, remaining; char *bufp;#if BSD >= 43 || defined(SUNOS4) pid = getpid (); /* modern systems use positives for pid */#else pid = -getpid (); /* old broken systems use negatives */#endif setsig (SIGTTOU, SIG_IGN); setsig (SIGURG, oob); ppid = getppid (); fcntl (rem, F_SETOWN, pid); setjmp (rcvtop); sigprocmask (SIG_SETMASK, smask, (sigset_t *) 0); bufp = rcvbuf; for (;;) { while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { rcvstate = WRITING; n = write (STDOUT_FILENO, bufp, remaining); if (n < 0) { if (errno != EINTR) return -1; continue; } bufp += n; } bufp = rcvbuf; rcvcnt = 0; rcvstate = READING;#ifdef ENCRYPTION#ifdef KERBEROS if (doencrypt) rcvcnt = des_read (rem, rcvbuf, sizeof rcvbuf); else#endif#endif rcvcnt = read (rem, rcvbuf, sizeof rcvbuf); if (rcvcnt == 0) return 0; if (rcvcnt < 0) { if (errno == EINTR) continue; warn ("read"); return -1; } }}voidmode (int f){ struct termios tt; switch (f) { case 0: tcsetattr (0, TCSADRAIN, &deftt); break; case 1: tt = deftt; tt.c_oflag &= ~(OPOST); tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); tt.c_iflag &= ~(ICRNL); tt.c_cc[VMIN] = 1; tt.c_cc[VTIME] = 0; if (eight) { tt.c_iflag &= ~(IXON | IXOFF | ISTRIP); tt.c_cc[VSTOP] = _POSIX_VDISABLE; tt.c_cc[VSTART] = _POSIX_VDISABLE; } tcsetattr(0, TCSADRAIN, &tt); break; default: return; }}voidlostpeer (int signo){ (void)signo; setsig (SIGPIPE, SIG_IGN); msg ("\007connection closed."); done (1);}/* copy SIGURGs to the child process. */voidcopytochild (int signo){ (void)signo; kill (child, SIGURG);}voidmsg (const char *str){ fprintf (stderr, "rlogin: %s\r\n", str);}#ifdef KERBEROS/* VARARGS */void#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__warning (const char *fmt, ...)#elsewarning (fmt, va_alist) char *fmt; va_dcl#endif{ va_list ap; fprintf (stderr, "rlogin: warning, using standard rlogin: ");#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ va_start (ap, fmt);#else va_start (ap);#endif vfprintf (stderr, fmt, ap); va_end (ap); fprintf (stderr, ".\n");}#endifvoidusage (int status){ if (status) { fprintf (stderr, "Usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",#ifdef KERBEROS# ifdef ENCRYPTION "8EKx", " [-k realm] "# else "8EK", " [-k realm] "# endif#else "8EL", " "#endif ); fprintf (stderr, "Try rlogin --help for more information.\n"); } else { puts ("Usage: rlogin [OPTION] ... hostname"); puts ("Rlogin starts a terminal session on a remote host host."); puts ("\ -8, --8-bit allows an eight-bit input data path at all times"); puts ("\ -E, --no-escape stops any character from being recognized as an escape\n\ character"); puts ("\ -d, --debug turns on socket debugging (see setsockopt(2))"); puts ("\ -e, --escape=CHAR allows user specification of the escape character,\n\ which is ``~'' by default"); puts ("\ -l, --user USER run as USER on the remote system");#ifdef KERBEROS puts ("\ -K, --kerberos turns off all Kerberos authentication"); puts ("\ -k, --realm=REALM requests rlogin to obtain tickets for the remote host in\n\ REALM realm instead of the remote host's realm");#ifdef ENCRYPTION puts ("\ -x, --encrypt turns on DES encryption for all data passed via the\n\ rlogin session");#endif#endif puts ("\ -V, --version display program version"); puts ("\ -h, --help display usage instructions"); fprintf (stdout, "\nSubmit bug reports to %s.\n", PACKAGE_BUGREPORT); } exit (status);}/* * The following routine provides compatibility (such as it is) between older * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. */#ifdef OLDSUNintget_window_size (int fd, struct winsize *wp){ struct ttysize ts; int error; if ((error = ioctl (0, TIOCGSIZE, &ts)) != 0) return error; wp->ws_row = ts.ts_lines; wp->ws_col = ts.ts_cols; wp->ws_xpixel = 0; wp->ws_ypixel = 0; return 0;}#endifu_intgetescape (register char *p){ long val; int len; if ((len = strlen (p)) == 1) /* use any single char, including '\'. */ return ((u_int)*p); /* otherwise, \nnn */ if (*p == '\\' && len >= 2 && len <= 4) { val = strtol (++p, NULL, 8); for (;;) { if (!*++p) return ((u_int)val); if (*p < '0' || *p > '8') break; } } msg ("illegal option value -- e"); usage (1); /* NOTREACHED */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -