📄 rsh.c
字号:
/*- * Copyright (c) 1983, 1990, 1993, 1994, 2002 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#ifdef HAVE_SYS_FILIO_H# include <sys/filio.h>#endif#include <sys/file.h>#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include <netinet/in.h>#include <netdb.h>#include <err.h>#include <errno.h>#include <pwd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include <getopt.h>#ifdef HAVE_SYS_SELECT_H# include <sys/select.h>#endif#ifdef KERBEROS# include <kerberosIV/des.h># include <kerberosIV/krb.h>CREDENTIALS cred;Key_schedule schedule;int use_kerberos = 1, doencrypt;char dst_realm_buf[REALM_SZ], *dest_realm;extern char *krb_realmofhost();#endif/* * rsh - remote shell */int rfd2;char *copyargs __P ((char **));void sendsig __P ((int));void talk __P ((int, sigset_t *, pid_t, int));void usage __P ((void));void warning __P ((const char *, ...));/* basename (argv[0]). NetBSD, linux, & gnu libc all define it. */extern char *__progname;#ifdef KERBEROS#ifdef ENCRYPTION#define OPTIONS "8Kdek:l:nxVh"#else#define OPTIONS "8Kdek:l:nVh"#endif#else#define OPTIONS "8KLdel:nVh"#endifstatic const char *short_options = OPTIONS;static struct option long_options[] ={ { "debug", no_argument, 0, 'd' }, { "user", required_argument, 0, 'l' }, { "escape", required_argument, 0, 'e' }, { "8-bit", no_argument, 0, '8' }, { "kerberos", no_argument, 0, 'K' }, { "no-input", no_argument, 0, 'n' },#ifdef KERBEROS { "realm", required_argument, 0, 'k' }, { "encrypt", no_argument, 0, 'x' },#endif { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { 0, 0, 0, 0 }};static voidpusage (FILE *stream){ fprintf (stream, "Usage: %s [-nd%s]%s[-l USER] [USER@]HOST [COMMAND [ARG...]]\n", __progname,#ifdef KERBEROS#ifdef ENCRYPTION "x", " [-k REALM] "#else "", " [-k REALM] "#endif#else "", " "#endif );}/* Print a help message describing all options to STDOUT and exit with a status of 0. */static voidhelp (void){ pusage (stdout); puts ("Execute COMMAND on remote system HOST"); puts ("When use as rlogin:"); 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 Obtain tickets for the remote host in REALM\n\ instead of the remote host's realm");# ifdef ENCRYPTION puts ("\ -x, --encrypt encrypt all data using DES");# endif#endif puts ("\ -n, --no-input use /dev/null as input"); puts ("\ --help give this help list"); puts ("\ -V, --version print program version"); fprintf (stdout, "\nSubmit bug reports to %s.\n", PACKAGE_BUGREPORT); exit (0);}/* Print a message saying to use --help to STDERR, and exit with a status of 1. */static voidtry_help (void){ fprintf (stderr, "Try `%s --help' for more information.\n", __progname); exit (1);}voidusage(){ pusage (stderr); try_help ();}intmain (int argc, char **argv){ struct passwd *pw; struct servent *sp; sigset_t sigs, osigs; int asrsh, ch, dflag, nflag, rem; pid_t pid = 0; uid_t uid; char *args, *host, *user;#ifndef HAVE___PROGNAME extern char *__progname; __progname = argv[0];#endif asrsh = dflag = nflag = 0; host = user = NULL; /* If called as something other than "rsh", use it as the host name */ { char *p = strrchr(argv[0], '/'); if (p) ++p; else p = argv[0]; if (strcmp (p, "rsh")) host = p; else asrsh = 1; } while ((ch = getopt_long (argc, argv, short_options, long_options, 0)) != EOF) { switch (ch) { case 'L': /* -8Lew are ignored to allow rlogin aliases */ case 'e': case 'w': case '8': break; case 'd': dflag = 1; break; case 'l': user = optarg; break; case 'K':#ifdef KERBEROS use_kerberos = 0;#endif break;#ifdef KERBEROS case 'k': strncpy (dest_realm_buf, optarg, sizeof dest_realm_buf); dest_realm_buf [REALM_SZ - 1] = '\0'; dest_realm = dst_realm_buf; break;# ifdef ENCRYPTION case 'x': doencrypt = 1; des_set_key (cred.session, schedule); break;# endif#endif case 'n': nflag = 1; break; case 'h': help (); case 'V': printf ("rsh (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); exit (0); case '?': try_help (); default: usage(); } } if (optind < argc) host = argv[optind++]; /* To few args. */ if (!host) usage (); /* If no further arguments, must have been called as rlogin. */ if (!argv[optind]) { if (asrsh) *argv = (char *)"rlogin"; seteuid (getuid ()); setuid (getuid ()); execv (PATH_RLOGIN, argv); errx (1, "can't exec %s", PATH_RLOGIN); } argc -= optind; argv += optind; /* We must be setuid root. */ if (geteuid ()) errx (1, "must be setuid root.\n"); if (!(pw = getpwuid (uid = getuid ()))) errx(1, "unknown user id"); /* Accept user1@host format, though "-l user2" overrides user1 */ { char *p = strchr (host, '@'); if (p) { *p = '\0'; if (!user && p > host) user = host; host = p + 1; if (*host == '\0') usage (); } if (!user) user = pw->pw_name; }#ifdef KERBEROS#ifdef ENCRYPTION /* -x turns off -n */ if (doencrypt) nflag = 0;#endif#endif args = copyargs (argv); sp = NULL;#ifdef KERBEROS if (use_kerberos) { sp = getservbyname ((doencrypt ? "ekshell" : "kshell"), "tcp"); if (sp == NULL) { use_kerberos = 0; warning ("can't get entry for %s/tcp service", doencrypt ? "ekshell" : "kshell"); } }#endif if (sp == NULL) sp = getservbyname("shell", "tcp"); if (sp == NULL) errx (1, "shell/tcp: unknown service");#ifdef KERBEROS try_connect: if (use_kerberos) { struct hostent *hp; /* fully qualify hostname (needed for krb_realmofhost) */ hp = gethostbyname(host); if (hp != NULL && !(host = strdup (hp->h_name))) err (1, NULL); rem = KSUCCESS; errno = 0; if (dest_realm == NULL) dest_realm = krb_realmofhost (host);#ifdef ENCRYPTION if (doencrypt) rem = krcmd_mutual (&host, sp->s_port, user, args, &rfd2, dest_realm, &cred, schedule); else#endif rem = krcmd (&host, sp->s_port, user, args, &rfd2, dest_realm); if (rem < 0) { use_kerberos = 0; sp = getservbyname ("shell", "tcp"); if (sp == NULL) errx (1, "shell/tcp: unknown service"); if (errno == ECONNREFUSED) warning ("remote host doesn't support Kerberos"); if (errno == ENOENT) warning ("can't provide Kerberos auth data"); goto try_connect; } } else { if (doencrypt) errx (1, "the -x flag requires Kerberos authentication"); rem = rcmd (&host, sp->s_port, pw->pw_name, user, args, &rfd2); }#else rem = rcmd (&host, sp->s_port, pw->pw_name, user, args, &rfd2);#endif if (rem < 0) exit (1); if (rfd2 < 0) errx (1, "can't establish stderr"); if (dflag) { int one = 1; if (setsockopt (rem, SOL_SOCKET, SO_DEBUG, (char *) &one, sizeof one) < 0) warn ("setsockopt"); if (setsockopt (rfd2, SOL_SOCKET, SO_DEBUG, (char *) &one, sizeof one) < 0) warn ("setsockopt"); } seteuid (uid); setuid (uid);#ifdef HAVE_SIGACTION sigemptyset (&sigs); sigaddset (&sigs, SIGINT); sigaddset (&sigs, SIGQUIT); sigaddset (&sigs, SIGTERM); sigprocmask (SIG_BLOCK, &sigs, &osigs);#else sigs = sigmask (SIGINT) | sigmask (SIGQUIT) | sigmask (SIGTERM); osigs = sigblock (sigs);#endif if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, sendsig); if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) signal (SIGQUIT, sendsig); if (signal (SIGTERM, SIG_IGN) != SIG_IGN) signal (SIGTERM, sendsig); if (!nflag) { pid = fork (); if (pid < 0) err (1, "fork"); }#ifdef KERBEROS#ifdef ENCRYPTION if (!doencrypt)#endif#endif { int one = 1; ioctl (rfd2, FIONBIO, &one); ioctl (rem, FIONBIO, &one); } talk (nflag, &osigs, pid, rem); if (!nflag) kill (pid, SIGKILL); return 0;}voidtalk (int nflag, sigset_t *osigs, pid_t pid, int rem){ int cc, wc; fd_set readfrom, ready, rembits; char *bp, buf[BUFSIZ]; if (!nflag && pid == 0) { close (rfd2); reread: errno = 0; if ((cc = read (STDIN_FILENO, buf, sizeof buf)) <= 0) goto done; bp = buf; rewrite: FD_ZERO (&rembits); FD_SET (rem, &rembits); if (select (rem + 1, 0, &rembits, 0, 0) < 0) { if (errno != EINTR) err (1, "select"); goto rewrite; } if (!FD_ISSET (rem, &rembits)) goto rewrite;#ifdef KERBEROS#ifdef ENCRYPTION if (doencrypt) wc = des_write (rem, bp, cc); else#endif#endif wc = write (rem, bp, cc); if (wc < 0) { if (errno == EWOULDBLOCK) goto rewrite; goto done; } bp += wc; cc -= wc; if (cc == 0) goto reread; goto rewrite; done: shutdown (rem, 1); exit (0); }#ifdef HAVE_SIGACTION sigprocmask (SIG_SETMASK, osigs, NULL);#else sigsetmask (*osigs);#endif FD_ZERO (&readfrom); FD_SET (rfd2, &readfrom); FD_SET (rem, &readfrom); do { int maxfd = rem; if (rfd2 > maxfd) maxfd = rfd2; ready = readfrom; if (select (maxfd + 1, &ready, 0, 0, 0) < 0) { if (errno != EINTR) err (1, "select"); continue; } if (FD_ISSET (rfd2, &ready)) { errno = 0;#ifdef KERBEROS#ifdef CRYPT if (doenencryption) cc = des_read (rfd2, buf, sizeof buf); else#endif#endif cc = read (rfd2, buf, sizeof buf); if (cc <= 0) { if (errno != EWOULDBLOCK) FD_CLR (rfd2, &readfrom); } else write (2, buf, cc); } if (FD_ISSET (rem, &ready)) { errno = 0;#ifdef KERBEROS#ifdef ENCRYPTION if (doencrypt) cc = des_read (rem, buf, sizeof buf); else#endif#endif cc = read (rem, buf, sizeof buf); if (cc <= 0) { if (errno != EWOULDBLOCK) FD_CLR (rem, &readfrom); } else write (1, buf, cc); } } while (FD_ISSET (rfd2, &readfrom) || FD_ISSET (rem, &readfrom));}voidsendsig (int sig){ char signo; signo = sig;#ifdef KERBEROS#ifdef ENCRYPTION if (doencrypt) des_write (rfd2, &signo, 1); else#endif#endif write (rfd2, &signo, 1);}#ifdef KERBEROS/* VARARGS */void#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__warning (const char * fmt, ...)#elsewarning (va_alist)va_dcl#endif{ va_list ap;#if !(defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__) const char *fmt;#endif fprintf (stderr, "%s: warning, using standard rsh: ", __progname);#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ va_start (ap, fmt);#else va_start (ap);#endif fmt = va_arg (ap, char *); vfprintf (stderr, fmt, ap); va_end (ap); fprintf (stderr, ".\n");}#endifchar *copyargs (char **argv){ int cc; char **ap, *args, *p; cc = 0; for (ap = argv; *ap; ++ap) cc += strlen (*ap) + 1; if (!(args = malloc ((u_int)cc))) err (1, NULL); for (p = args, ap = argv; *ap; ++ap) { strcpy (p, *ap); for (p = strcpy (p, *ap); *p; ++p); if (ap[1]) *p++ = ' '; } return args;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -