Exemplo n.º 1
0
/*
 * Approximate sigsys() system call
 * This is almost useless since one only calls sigsys()
 * in the child of a vfork().  If you have vfork(), you have new signals
 * anyway.  The real sigsys() does all the stuff needed to support
 * the real sigset() library.  We don't bother here, assuming that
 * you are either ignoring or defaulting a signal in the child.
 */
sigtype 
sigsys(int sig, sigtype func)
{
	sigtype old;

	old = sigdisp(sig);
	signal(sig, func);
	return(old);
}
Exemplo n.º 2
0
/*
 * Set the (permanent) disposition of a signal.
 * If the signal is subsequently (or even now) held,
 * the action you set here can be enabled using sigrelse().
 */
sigtype 
sigset(int sig, sigtype func)
{
	sigtype old;

	if (sig < 1 || sig > NSIG) {
		errno = EINVAL;
		return(SIG_ERR);
	}
	old = sigdisp(sig);
	/*
	 * Does anyone actually call sigset with SIG_HOLD!?
	 */
	if (func == SIG_HOLD) {
		sighold(sig);
		return(old);
	}
	sigtable[sig].s_flag |= SSET;
	sigtable[sig].s_func = func;
	if (func == SIG_DFL) {
		/*
		 * If signal has been held, must retain
		 * the catch so that we can note occurrance
		 * of signal.
		 */
		if ((sigtable[sig].s_flag & SHELD) == 0)
			signal(sig, SIG_DFL);
		else
			signal(sig, _Sigtramp);
		return(old);
	}
	if (func == SIG_IGN) {
		/*
		 * Clear pending signal
		 */
		signal(sig, SIG_IGN);
		sigtable[sig].s_flag &= ~SDEFER;
		return(old);
	}
	signal(sig, _Sigtramp);
	return(old);
}
Exemplo n.º 3
0
/*
 * Release a signal
 * If the signal occurred while we had it held, cause the signal.
 */
sigtype 
sigrelse(int sig)
{
	sigtype old;

	if (sig < 1 || sig > NSIG) {
		errno = EINVAL;
		return(SIG_ERR);
	}
	old = sigdisp(sig);
	if ((sigtable[sig].s_flag & SHELD) == 0)
		return(old);
	sigtable[sig].s_flag &= ~SHELD;
	if (sigtable[sig].s_flag & SDEFER)
		_Sigtramp(sig);
	/*
	 * If disposition was the default, then we can unset the
	 * catch to _Sigtramp() and let the system do the work.
	 */
	if (sigtable[sig].s_func == SIG_DFL)
		signal(sig, SIG_DFL);
	return(old);
}
Exemplo n.º 4
0
/*
 * Hold a signal.
 * This CAN be tricky if the signal's disposition is SIG_DFL.
 * In that case, we still catch the signal so we can note it
 */
sigtype 
sighold(int sig)
{
	sigtype old;

	if (sig < 1 || sig > NSIG) {
		errno = EINVAL;
		return(SIG_ERR);
	}
	old = sigdisp(sig);
	if (sigtable[sig].s_flag & SHELD)
		return(old);
	/*
	 * When the default action is required, we have to
	 * set up to catch the signal to note signal's occurrance.
	 */
	if (old == SIG_DFL) {
		sigtable[sig].s_flag |= SSET;
		signal(sig, _Sigtramp);
	}
	sigtable[sig].s_flag |= SHELD;
	return(old);
}
Exemplo n.º 5
0
/* VARARGS */
int
main(int argc, char **argv)
{
    int c, rem;
    char *cmd, *cp, **ap, buf[RSH_BUFSIZ], **argv0, *args, *args_no_x;
    char *host = NULL, *user = NULL;
    int cc;
    boolean_t asrsh = B_FALSE;
    struct passwd *pwd;
    boolean_t readfrom_rem;
    boolean_t readfrom_rfd2;
    int one = 1;
    int omask;
    boolean_t nflag = B_FALSE;
    char *krb_realm = NULL;
    krb5_flags authopts;
    krb5_error_code status;
    enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;
    uid_t uid = getuid();

    c = (argc + 1) * sizeof (char *);
    if ((argv0 = malloc(c)) == NULL) {
        perror("malloc");
        return (EXIT_FAILURE);
    }
    (void) memcpy(argv0, argv, c);

    (void) setlocale(LC_ALL, "");

    (void) textdomain(TEXT_DOMAIN);

    /*
     * Determine command name used to invoke to rlogin(1). Users can
     * create links named by a host pointing to the binary and type
     * "hostname" to log into that host afterwards.
     */
    cmd = strrchr(argv[0], '/');
    cmd = (cmd != NULL) ? (cmd + 1) : argv[0];

    /*
     *	Add "remsh" as an alias for "rsh" (System III, V networking
     *	add-ons often used this name for the remote shell since rsh
     *	was already taken for the restricted shell).  Note that this
     *	usurps the ability to use "remsh" as the name of a host (by
     *	symlinking it to rsh), so we go one step farther:  if the
     *	file "/usr/bin/remsh" does not exist, we behave as if "remsh"
     *	is a host name.  If it does exist, we accept "remsh" as an
     *	"rsh" alias.
     */
    if (strcmp(cmd, "remsh") == 0) {
        struct stat sb;

        if (stat("/usr/bin/remsh", &sb) < 0)
            host = cmd;
    } else if (strcmp(cmd, "rsh") != 0) {
        host = cmd;
    }

    /* Handle legacy synopsis "rsh hostname options [command]". */
    if (host == NULL) {
        if (argc < 2)
            usage();
        if (*argv[1] != '-') {
            host = argv[1];
            argc--;
            argv[1] = argv[0];
            argv++;
            asrsh = B_TRUE;
        }
    }

    while ((c = getopt(argc, argv,
                       DEBUGOPTSTRING "8AFKLP:ade:fk:l:nwx")) != -1) {
        switch (c) {
#ifdef DEBUG
        case 'D':
            portnumber = htons(atoi(optarg));
            krb5auth_flag++;
            break;
#endif /* DEBUG */
        case 'F':
            if (fflag)
                usage_forward();
            Fflag = 1;
            krb5auth_flag++;
            fwdable_done = B_TRUE;
            break;
        case 'f':
            if (Fflag)
                usage_forward();
            fflag = 1;
            krb5auth_flag++;
            fwd_done = B_TRUE;
            break;
        case 'P':
            if (strcmp(optarg, "N") == 0)
                kcmd_proto = KCMD_NEW_PROTOCOL;
            else if (strcmp(optarg, "O") == 0)
                kcmd_proto = KCMD_OLD_PROTOCOL;
            else
                die(gettext("rsh: Only -PN or -PO "
                            "allowed.\n"));
            if (rcmdoption_done)
                die(gettext("rsh: Only one of -PN and -PO "
                            "allowed.\n"));
            rcmdoption_done = B_TRUE;
            krb5auth_flag++;
            break;
        case 'a':
            krb5auth_flag++;
            break;
        case 'K':
            no_krb5auth_flag++;
            break;
        case 'd':
            options |= SO_DEBUG;
            break;
        case 'k':
            krb_realm = optarg;
            krb5auth_flag++;
            break;
        case 'l':
            user = optarg;
            break;
        case 'n':
            if (!nflag) {
                if (close(STDIN_FILENO) < 0) {
                    perror("close");
                    return (EXIT_FAILURE);
                }
                /*
                 * "STDION_FILENO" defined to 0 by POSIX
                 * and hence the lowest file descriptor.
                 * So the open(2) below is guaranteed to
                 * reopen it because we closed it above.
                 */
                if (open("/dev/null", O_RDONLY) < 0) {
                    perror("open");
                    return (EXIT_FAILURE);
                }
                nflag = B_TRUE;
            }
            break;
        case 'x':
            encrypt_flag = 1;
            krb5auth_flag++;
            encrypt_done = B_TRUE;
            break;
        /*
         * Ignore the -L, -w, -e and -8 flags to allow aliases with
         * rlogin to work. Actually rlogin(1) doesn't understand
         * -w either but because "rsh -w hostname command" used
         * to work we still accept it.
         */
        case '8':
        case 'L':
        case 'e':
        case 'w':
        /*
         * On the lines of the -L, -w, -e and -8 options above, we
         * ignore the -A option too, in order to allow aliases with
         * rlogin to work.
         *
         * Mind you !, the -a option to trigger Kerberos authentication
         * in rsh, has a totally different usage in rlogin, its the
         * -A option (in rlogin) which needs to be used to talk
         * Kerberos.
         */
        case 'A':
            break;
        default:
            usage();
        }
    }

    argc -= optind;
    argv += optind;

    if (host == NULL) {
        if (argc == 0)
            usage();
        argc--;
        host = *argv++;
        asrsh = B_TRUE;
    }

    if (argc == 0) {
        (void) setreuid(uid, uid);
        if (nflag)
            usage();
        if (asrsh)
            *argv0 = "rlogin";
        (void) execv(rlogin_path, argv0);
        perror(rlogin_path);

        (void) fprintf(stderr, gettext("No local rlogin "
                                       "program found.\n"));
        return (EXIT_FAILURE);
    }

    if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
        (void) fprintf(stderr,
                       gettext("Insufficient privileges, "
                               "rsh must be set-uid root\n"));
        return (EXIT_FAILURE);
    }

    pwd = getpwuid(uid);
    if (pwd == NULL) {
        (void) fprintf(stderr, gettext("who are you?\n"));
        return (EXIT_FAILURE);
    }
    if (user == NULL)
        user = pwd->pw_name;

    /*
     * if the user disables krb5 on the cmdline (-K), then skip
     * all krb5 setup.
     *
     * if the user does not disable krb5 or enable krb5 on the
     * cmdline, check krb5.conf to see if it should be enabled.
     */

    if (no_krb5auth_flag) {
        krb5auth_flag = 0;
        Fflag = fflag = encrypt_flag = 0;
    } else if (!krb5auth_flag) {
        /* is autologin set in krb5.conf? */
        status = krb5_init_context(&bsd_context);
        /* don't sweat failure here */
        if (!status) {
            /*
             * note that the call to profile_get_options_boolean
             * with autologin_option can affect value of
             * krb5auth_flag
             */
            (void) profile_get_options_boolean(bsd_context->profile,
                                               appdef,
                                               autologin_option);
        }
    }

    if (krb5auth_flag) {
        if (!bsd_context) {
            status = krb5_init_context(&bsd_context);
            if (status) {
                com_err("rsh", status,
                        "while initializing krb5");
                return (EXIT_FAILURE);

            }
        }

        /*
         * Get our local realm to look up local realm options.
         */
        status = krb5_get_default_realm(bsd_context, &realmdef[1]);
        if (status) {
            com_err("rsh", status,
                    gettext("while getting default realm"));
            return (EXIT_FAILURE);
        }
        /*
         * Check the realms section in krb5.conf for encryption,
         * forward & forwardable info
         */
        profile_get_options_boolean(bsd_context->profile, realmdef,
                                    option);
        /*
         * Check the appdefaults section
         */
        profile_get_options_boolean(bsd_context->profile, appdef,
                                    option);
        profile_get_options_string(bsd_context->profile, appdef,
                                   rcmdversion);
        /*
         * Set the *_flag variables, if the corresponding *_done are
         * set to 1, because we dont want the config file values
         * overriding the command line options.
         */
        if (encrypt_done)
            encrypt_flag = 1;
        if (fwd_done) {
            fflag = 1;
            Fflag = 0;
        } else if (fwdable_done) {
            Fflag = 1;
            fflag = 0;
        }
        if (!rcmdoption_done && (rcmdproto != NULL)) {
            if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
                kcmd_proto = KCMD_NEW_PROTOCOL;
            } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
                kcmd_proto = KCMD_OLD_PROTOCOL;
            } else {
                (void) fprintf(stderr, gettext("Unrecognized "
                                               "KCMD protocol (%s)"), rcmdproto);
                return (EXIT_FAILURE);
            }
        }


        if (encrypt_flag && (!krb5_privacy_allowed())) {
            (void) fprintf(stderr, gettext("rsh: Encryption not "
                                           "supported.\n"));
            return (EXIT_FAILURE);
        }
    }

    /*
     * Connect with the service (shell/kshell) on the daemon side
     */
    if (portnumber == 0) {
        while (!init_service(krb5auth_flag)) {
            /*
             * Connecting to the 'kshell' service failed,
             * fallback to normal rsh; Reset all KRB5 flags
             * and connect to 'shell' service on the server
             */
            krb5auth_flag = 0;
            encrypt_flag = fflag = Fflag = 0;
        }
    }

    cc = encrypt_flag ? strlen(dash_x) : 0;
    for (ap = argv; *ap != NULL; ap++)
        cc += strlen(*ap) + 1;
    cp = args = malloc(cc);
    if (cp == NULL)
        perror("malloc");
    if (encrypt_flag) {
        int length;

        length = strlcpy(args, dash_x, cc);
        cp += length;
        cc -= length;
    }
    args_no_x = args;

    for (ap = argv; *ap != NULL; ap++) {
        int length;

        length = strlcpy(cp, *ap, cc);
        assert(length < cc);
        cp += length;
        cc -= length;
        if (ap[1] != NULL) {
            *cp++ = ' ';
            cc--;
        }
    }

    if (krb5auth_flag) {
        authopts = AP_OPTS_MUTUAL_REQUIRED;
        /*
         * Piggy-back forwarding flags on top of authopts;
         * they will be reset in kcmd
         */
        if (fflag || Fflag)
            authopts |= OPTS_FORWARD_CREDS;
        if (Fflag)
            authopts |= OPTS_FORWARDABLE_CREDS;

        status = kcmd(&rem, &host, portnumber,
                      pwd->pw_name, user,
                      args, &rfd2, "host", krb_realm,
                      bsd_context, &auth_context, &cred,
                      NULL,	/* No need for sequence number */
                      NULL,	/* No need for server seq # */
                      authopts,
                      1,	/* Always set anyport */
                      &kcmd_proto);
        if (status != 0) {
            /*
             * If new protocol requested, we dont fallback to
             * less secure ones.
             */
            if (kcmd_proto == KCMD_NEW_PROTOCOL) {
                (void) fprintf(stderr, gettext("rsh: kcmdv2 "
                                               "to host %s failed - %s\n"
                                               "Fallback to normal rsh denied."),
                               host, error_message(status));
                return (EXIT_FAILURE);
            }
            /* check NO_TKT_FILE or equivalent... */
            if (status != -1) {
                (void) fprintf(stderr,
                               gettext("rsh: kcmd to host %s failed - %s\n"
                                       "trying normal rsh...\n\n"),
                               host, error_message(status));
            } else {
                (void) fprintf(stderr,
                               gettext("trying normal rsh...\n"));
            }
            /*
             * kcmd() failed, so we now fallback to normal rsh,
             * after resetting the KRB5 flags and the 'args' array
             */
            krb5auth_flag = 0;
            encrypt_flag = fflag = Fflag = 0;
            args = args_no_x;
            (void) init_service(B_FALSE);
        } else {
            /*
             * Set up buffers for desread and deswrite.
             */
            desinbuf.data = des_inbuf;
            desoutbuf.data = des_outbuf;
            desinbuf.length = sizeof (des_inbuf);
            desoutbuf.length = sizeof (des_outbuf);

            session_key = &cred->keyblock;

            if (kcmd_proto == KCMD_NEW_PROTOCOL) {
                status = krb5_auth_con_getlocalsubkey(
                             bsd_context,
                             auth_context,
                             &session_key);
                if (status) {
                    com_err("rsh", status,
                            "determining subkey for session");
                    return (EXIT_FAILURE);
                }
                if (session_key == NULL) {
                    com_err("rsh", 0, "no subkey "
                            "negotiated for connection");
                    return (EXIT_FAILURE);
                }
            }

            eblock.crypto_entry = session_key->enctype;
            eblock.key = (krb5_keyblock *)session_key;

            init_encrypt(encrypt_flag, bsd_context, kcmd_proto,
                         &desinbuf, &desoutbuf, CLIENT, &eblock);
            if (encrypt_flag) {
                char *s = gettext("This rsh session is using "
                                  "encryption for all data transmissions.");
                (void) write(STDERR_FILENO, s, strlen(s));
                (void) write(STDERR_FILENO, "\r\n", 2);
            }
        }
    }

    /*
     * Don't merge this with the "if" statement above because
     * "krb5auth_flag" might be set to false inside it.
     */
    if (!krb5auth_flag) {
        rem = rcmd_af(&host, portnumber, pwd->pw_name, user, args,
                      &rfd2, AF_INET6);
        if (rem < 0)
            return (EXIT_FAILURE);
    }
    __priv_relinquish();

    if (rfd2 < 0) {
        (void) fprintf(stderr, gettext("rsh: can't establish "
                                       "stderr\n"));
        return (EXIT_FAILURE);
    }
    if (options & SO_DEBUG) {
        if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, (char *)&one,
                       sizeof (one)) < 0)
            perror("rsh: setsockopt (stdin)");
        if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, (char *)&one,
                       sizeof (one)) < 0)
            perror("rsh: setsockopt (stderr)");
    }
    omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));

    if (sigdisp(SIGINT) != SIG_IGN)
        (void) sigset(SIGINT, sendsig);
    if (sigdisp(SIGQUIT) != SIG_IGN)
        (void) sigset(SIGQUIT, sendsig);
    if (sigdisp(SIGTERM) != SIG_IGN)
        (void) sigset(SIGTERM, sendsig);

    if (nflag) {
        (void) shutdown(rem, SHUT_WR);
    } else {
        child_pid = fork();
        if (child_pid < 0) {
            perror("rsh: fork");
            return (EXIT_FAILURE);
        }

        if (!encrypt_flag) {
            (void) ioctl(rfd2, FIONBIO, &one);
            (void) ioctl(rem, FIONBIO, &one);
        }

        if (child_pid == 0) {
            /* Child */
            fd_set remset;
            char *bp;
            int  wc;
            (void) close(rfd2);
reread:
            errno = 0;
            cc = read(0, buf, sizeof (buf));
            if (cc <= 0)
                goto done;
            bp = buf;
rewrite:
            FD_ZERO(&remset);
            FD_SET(rem, &remset);
            if (select(rem + 1, NULL, &remset, NULL, NULL) < 0) {
                if (errno != EINTR) {
                    perror("rsh: select");
                    return (EXIT_FAILURE);
                }
                goto rewrite;
            }
            if (!FD_ISSET(rem, &remset))
                goto rewrite;
            writeiv = B_FALSE;
            wc = desrshwrite(rem, bp, cc);
            if (wc < 0) {
                if (errno == EWOULDBLOCK)
                    goto rewrite;
                goto done;
            }
            cc -= wc;
            bp += wc;
            if (cc == 0)
                goto reread;
            goto rewrite;
done:
            (void) shutdown(rem, SHUT_WR);
            return (EXIT_SUCCESS);
        }
    }

#define	MAX(a, b)	(((a) > (b)) ? (a) : (b))

    sigsetmask(omask);
    readfrom_rem = B_TRUE;
    readfrom_rfd2 = B_TRUE;
    (void) sigset(SIGPIPE, sigpipehandler);
    do {
        fd_set readyset;

        FD_ZERO(&readyset);
        if (readfrom_rem)
            FD_SET(rem, &readyset);
        if (readfrom_rfd2)
            FD_SET(rfd2, &readyset);
        if (select(MAX(rem, rfd2) + 1, &readyset, NULL, NULL,
                   NULL) < 0) {
            if (errno != EINTR) {
                perror("rsh: select");
                return (EXIT_FAILURE);
            }
            continue;
        }
        if (FD_ISSET(rfd2, &readyset)) {
            errno = 0;
            readiv = B_TRUE;
            cc = desrshread(rfd2, buf, sizeof (buf));
            if (cc <= 0) {
                if (errno != EWOULDBLOCK)
                    readfrom_rfd2 = B_FALSE;
            } else {
                (void) write(STDERR_FILENO, buf, cc);
            }
        }
        if (FD_ISSET(rem, &readyset)) {
            errno = 0;
            readiv = B_FALSE;
            cc = desrshread(rem, buf, sizeof (buf));
            if (cc <= 0) {
                if (errno != EWOULDBLOCK)
                    readfrom_rem = B_FALSE;
            } else
                (void) write(STDOUT_FILENO, buf, cc);
        }
    } while (readfrom_rem || readfrom_rfd2);

    if (!nflag)
        (void) kill(child_pid, SIGKILL);
    return (EXIT_SUCCESS);
}
Exemplo n.º 6
0
static void
doit(int oldmask)
{
	struct sgttyb sb;
	int atmark;

	if (ioctl(STDIN_FILENO, TIOCGETP, (char *)&sb) == -1)
		perror("ioctl TIOCGETP");
	defflags = sb.sg_flags;
	tabflag = defflags & O_TBDELAY;
	defflags &= ECHO | O_CRMOD;
	deferase = sb.sg_erase;
	defkill = sb.sg_kill;
	if (ioctl(STDIN_FILENO, TIOCLGET, (char *)&deflflags) == -1)
		perror("ioctl TIOCLGET");
	if (ioctl(STDIN_FILENO, TIOCGETC, (char *)&deftc) == -1)
		perror("ioctl TIOCGETC");
	notc.t_startc = deftc.t_startc;
	notc.t_stopc = deftc.t_stopc;
	if (ioctl(STDIN_FILENO, TIOCGLTC, (char *)&defltc) == -1)
		perror("ioctl TIOCGLTC");
	(void) sigset(SIGINT, SIG_IGN);
	if (sigdisp(SIGHUP) != SIG_IGN)
		(void) sigset(SIGHUP, exit);
	if (sigdisp(SIGQUIT) != SIG_IGN)
		(void) sigset(SIGQUIT, exit);
	child = fork();
	if (child == (pid_t)-1) {
		perror("rlogin: fork");
		done(EXIT_FAILURE);
	}
	if (child == 0) {
		mode(1);
		if (reader(oldmask) == 0) {
			prf(gettext("Connection to %.*s closed."),
			    MAXHOSTNAMELEN, host);
			exit(EXIT_SUCCESS);
		}
		(void) sleep(1);
		prf(gettext("\aConnection to %.*s closed."),
		    MAXHOSTNAMELEN, host);
		exit(EXIT_FAILURE);
	}

	/*
	 * We may still own the socket, and may have a pending SIGURG (or might
	 * receive one soon) that we really want to send to the reader.  Set a
	 * trap that simply copies such signals to the child.
	 */
#ifdef F_SETOWN_BUG_FIXED
	(void) sigset(SIGURG, copytochild);
#else
	(void) sigset(SIGURG, SIG_IGN);
#endif /* F_SETOWN_BUG_FIXED */
	(void) sigset(SIGUSR1, writeroob);
	/*
	 * Of course, if the urgent byte already arrived, allowing SIGURG
	 * won't get us notification.  So, we check to see if we've got
	 * an urgent byte.  If so, force a call to writeroob() to pretend
	 * we got SIGURG.
	 */
	if (ioctl(rem, SIOCATMARK, &atmark) >= 0) {
		if (atmark)
			writeroob(0);
	}
	sigsetmask(oldmask);
	(void) sigset(SIGCHLD, catchild);
	writer();
	prf(gettext("Closed connection to %.*s."), MAXHOSTNAMELEN, host);
	done(EXIT_SUCCESS);
}