/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
*/
/* just for FIONBIO ... */
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <pwd.h>
#include <netdb.h>
#include <locale.h>
#include <priv_utils.h>
#include <k5-int.h>
#include <profile/prof_int.h>
#include <com_err.h>
#include <kcmd.h>
#include <krb5.h>
/* signal disposition - signal handler or SIG_IGN, SIG_ERR, etc. */
typedef void (*sigdisp_t)(int);
{ "autologin", &krb5auth_flag, 0 },
};
static int no_krb5auth_flag = 0;
/* Flag set, if -PN / -PO is specified */
/* Flags set, if corres. cmd line options are turned on */
{ "encrypt", &encrypt_flag, 0 },
{ "forward", &fflag, 0 },
{ "forwardable", &Fflag, 0 },
};
static char *rcmdproto;
{ "rcmd_protocol", &rcmdproto, 0 },
};
static void sendsig(int);
static int desrshread(int, char *, int);
static int desrshwrite(int, char *, int);
static int options;
static int rfd2;
static int portnumber;
#ifdef DEBUG
#else
#endif /* DEBUG */
static void
{
}
static int
{
}
/*
* Get signal disposition (or signal handler) for a given signal
*/
static sigdisp_t
{
return (act.sa_handler);
}
/*
* If you do a command like "rsh host output | wc"
* and wc terminates, then the parent will receive SIGPIPE
* and the child needs to be terminated.
*/
/* ARGSUSED */
static void
{
if (child_pid != -1)
}
static void
usage(void) {
gettext("usage: rsh [ -PN / -PO ] [ -l login ] [ -n ] "
"[ -k realm ] [ -a ] [ -x ] [ -f / -F ] host command"),
gettext(" rsh [ -PN / -PO ] [ -l login ] [ -k realm ] "
"[ -a ] [ -x ] [ -f / -F ] host"));
}
static void
{
usage();
}
static void
usage_forward(void)
{
}
/*
* rsh - remote shell
*/
/* VARARGS */
int
{
int c, rem;
int cc;
int omask;
c = (argc + 1) * sizeof (char *);
perror("malloc");
return (EXIT_FAILURE);
}
(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.
*/
/*
* 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
* is a host name. If it does exist, we accept "remsh" as an
* "rsh" alias.
*/
}
/* Handle legacy synopsis "rsh hostname options [command]". */
if (argc < 2)
usage();
argc--;
argv++;
}
}
switch (c) {
#ifdef DEBUG
case 'D':
break;
#endif /* DEBUG */
case 'F':
if (fflag)
Fflag = 1;
break;
case 'f':
if (Fflag)
fflag = 1;
break;
case 'P':
else
"allowed.\n"));
if (rcmdoption_done)
"allowed.\n"));
break;
case 'a':
break;
case 'K':
break;
case 'd':
break;
case 'k':
break;
case 'l':
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.
*/
perror("open");
return (EXIT_FAILURE);
}
}
break;
case 'x':
encrypt_flag = 1;
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();
}
}
if (argc == 0)
usage();
argc--;
}
if (argc == 0) {
if (nflag)
usage();
if (asrsh)
*argv0 = "rlogin";
"program found.\n"));
return (EXIT_FAILURE);
}
gettext("Insufficient privileges, "
"rsh must be set-uid root\n"));
return (EXIT_FAILURE);
}
return (EXIT_FAILURE);
}
/*
* 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;
} else if (!krb5auth_flag) {
/* is autologin set in krb5.conf? */
/* 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
*/
}
}
if (krb5auth_flag) {
if (!bsd_context) {
if (status) {
"while initializing krb5");
return (EXIT_FAILURE);
}
}
/*
* Get our local realm to look up local realm options.
*/
if (status) {
gettext("while getting default realm"));
return (EXIT_FAILURE);
}
/*
* Check the realms section in krb5.conf for encryption,
* forward & forwardable info
*/
/*
* Check the appdefaults section
*/
/*
* 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;
}
} else {
"KCMD protocol (%s)"), rcmdproto);
return (EXIT_FAILURE);
}
}
if (encrypt_flag && (!krb5_privacy_allowed())) {
"supported.\n"));
return (EXIT_FAILURE);
}
}
/*
*/
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;
}
}
perror("malloc");
if (encrypt_flag) {
int length;
}
int length;
*cp++ = ' ';
cc--;
}
}
if (krb5auth_flag) {
/*
* Piggy-back forwarding flags on top of authopts;
* they will be reset in kcmd
*/
if (Fflag)
NULL, /* No need for sequence number */
NULL, /* No need for server seq # */
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) {
"to host %s failed - %s\n"
"Fallback to normal rsh denied."),
return (EXIT_FAILURE);
}
/* check NO_TKT_FILE or equivalent... */
if (status != -1) {
gettext("rsh: kcmd to host %s failed - %s\n"
"trying normal rsh...\n\n"),
} else {
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;
(void) init_service(B_FALSE);
} else {
/*
* Set up buffers for desread and deswrite.
*/
if (kcmd_proto == KCMD_NEW_PROTOCOL) {
&session_key);
if (status) {
"determining subkey for session");
return (EXIT_FAILURE);
}
if (session_key == NULL) {
"negotiated for connection");
return (EXIT_FAILURE);
}
}
if (encrypt_flag) {
char *s = gettext("This rsh session is using "
"encryption for all data transmissions.");
}
}
}
/*
* Don't merge this with the "if" statement above because
* "krb5auth_flag" might be set to false inside it.
*/
if (!krb5auth_flag) {
if (rem < 0)
return (EXIT_FAILURE);
}
if (rfd2 < 0) {
"stderr\n"));
return (EXIT_FAILURE);
}
sizeof (one)) < 0)
perror("rsh: setsockopt (stdin)");
sizeof (one)) < 0)
perror("rsh: setsockopt (stderr)");
}
if (nflag) {
} else {
if (child_pid < 0) {
perror("rsh: fork");
return (EXIT_FAILURE);
}
if (!encrypt_flag) {
}
if (child_pid == 0) {
/* Child */
char *bp;
int wc;
errno = 0;
if (cc <= 0)
goto done;
perror("rsh: select");
return (EXIT_FAILURE);
}
goto rewrite;
}
goto rewrite;
if (wc < 0) {
if (errno == EWOULDBLOCK)
goto rewrite;
goto done;
}
if (cc == 0)
goto reread;
goto rewrite;
done:
return (EXIT_SUCCESS);
}
}
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
do {
if (readfrom_rem)
if (readfrom_rfd2)
NULL) < 0) {
perror("rsh: select");
return (EXIT_FAILURE);
}
continue;
}
errno = 0;
if (cc <= 0) {
if (errno != EWOULDBLOCK)
} else {
}
}
errno = 0;
if (cc <= 0) {
if (errno != EWOULDBLOCK)
} else
}
} while (readfrom_rem || readfrom_rfd2);
if (!nflag)
return (EXIT_SUCCESS);
}
static void
{
char buffer;
}
static boolean_t
{
if (krb5flag) {
return (B_FALSE);
}
} else {
return (B_TRUE);
}
}
return (B_TRUE);
}
static int
{
}
static int
{
}