* 1) Check authentication.
* 2) Check authorization via the access-control files:
* ~/.k5login (using krb5_kuserok) and/or
- * ~/.rhosts (using ruserok).
* Execute command if configured authoriztion checks pass, else deny
* permission.
*
* The configuration is done either by command-line arguments passed by inetd,
* or by the name of the daemon. If command-line arguments are present, they
* take priority. The options are:
- * -k and -K means check .k5login (using krb5_kuserok).
- * -r and -R means check .rhosts (using ruserok).
- * The difference between upper and lower case is as follows:
- * If lower case -r or -k, then as long as one of krb5_kuserok or ruserok
- * passes, allow access. If both fail, no access. The program does not fall
- * back on password verification.
- * If uppercase -R or -K, then those checks must be passed, regardless of
- * other checks, else no access.
+ * -k means trust krb4 or krb5
+ * -5 means trust krb5
+ * -4 means trust krb4 (using .klogin)
*
- * If no command-line arguments are present, then the presence of the
- * letters kKrR in the program-name before "shd" determine the
- * behaviour of the program exactly as with the command-line arguments.
*/
/* DEFINES:
#define SERVE_NON_KRB
#define LOG_REMOTE_REALM
#define LOG_CMD
-
+
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
+#if !defined(KERBEROS) || !defined(KRB5_KRB4_COMPAT)
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
#include <sys/socket.h>
+#endif
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <stdio.h>
+#include <grp.h>
#include <errno.h>
#include <pwd.h>
#include <ctype.h>
#include <string.h>
+#include <libpty.h>
+#include <sys/wait.h>
#ifdef HAVE_SYS_LABEL_H
/* only SunOS 4? */
#include <sys/audit.h>
#include <pwdadj.h>
#endif
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
#include <signal.h>
+#if !defined(KERBEROS) || !defined(KRB5_KRB4_COMPAT)
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
#include <netdb.h>
-
+#endif
+
#ifdef CRAY
#ifndef NO_UDB
#include <udb.h>
#endif
#ifdef KERBEROS
-#include "krb5.h"
-#include "com_err.h"
+#include <krb5.h>
+#include <com_err.h>
#include "loginpaths.h"
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+#endif
+#include <k5-util.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#if defined(_PATH_NOLOGIN)
+#define NOLOGIN _PATH_NOLOGIN
+#else
+#define NOLOGIN "/etc/nologin"
+#endif
-#define ARGSTR "rRxXeEkKD:S:M:AP:?"
+#include "defines.h"
-#define SECURE_MESSAGE "This rsh session is using DES encryption for all data transmissions.\r\n"
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
-#ifdef BUFSIZ
-#undef BUFSIZ
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
#endif
-#define BUFSIZ 5120
+
+#define ARGSTR "ek54ciD:S:M:AP:?L:w:"
+
+
+
#define MAXRETRIES 4
-char des_inbuf[2*BUFSIZ]; /* needs to be > largest read size */
-krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
-char des_outbuf[2*BUFSIZ]; /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
krb5_context bsd_context;
char *srvtab = NULL;
+krb5_keytab keytab = NULL;
+krb5_ccache ccache = NULL;
-void fatal();
-int v5_des_read();
-int v5_des_write();
-
-int (*des_read)() = v5_des_read;
-int (*des_write)() = v5_des_write;
+void fatal(int, const char *);
+int require_encrypt = 0;
int do_encrypt = 0;
int anyport = 0;
char *kprogdir = KPROGDIR;
int netf;
+int maxhostlen = 0;
+int stripdomain = 1;
+int always_ip = 0;
+
+static krb5_error_code recvauth(int netfd, struct sockaddr *peersin,
+ int *valid_checksum);
#else /* !KERBEROS */
-#define ARGSTR "rRD:?"
-#define (*des_read) read
-#define (*des_write) write
+#define ARGSTR "RD:?"
#endif /* KERBEROS */
+
#ifndef HAVE_KILLPG
#define killpg(pid, sig) kill(-(pid), (sig))
#endif
-int must_pass_rhosts = 0, must_pass_k5 = 0, must_pass_one = 0;
-int failed_k5 = 0;
+/* There are two authentication related masks:
+ * auth_ok and auth_sent.
+* The auth_ok mask is the oring of authentication systems any one
+* of which can be used.
+* The auth_sent mask is the oring of one or more authentication/authorization
+* systems that succeeded. If the anding
+* of these two masks is true, then authorization is successful.
+*/
+#define AUTH_KRB4 (0x1)
+#define AUTH_KRB5 (0x2)
+int auth_ok = 0, auth_sent = 0;
+int checksum_required = 0, checksum_ignored = 0;
char *progname;
#define MAX_PROG_NAME 10
+/* Leave room for 4 environment variables to be passed */
+#define MAXENV 4
+#define SAVEENVPAD 0,0,0,0 /* padding for envinit slots */
+char *save_env[MAXENV];
+int num_env = 0;
+
#ifdef CRAY
int secflag;
extern
#endif /* CRAY */
-int errno;
-/*VARARGS1*/
-int error();
+void error (char *fmt, ...)
+#if !defined (__cplusplus) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
+ __attribute__ ((__format__ (__printf__, 1, 2)))
+#endif
+ ;
+void usage(void), getstr(int, char *, int, char *),
+ doit(int, struct sockaddr *);
-#ifdef __SCO__
-/* sco has getgroups and setgroups but no initgroups */
+#ifndef HAVE_INITGROUPS
int initgroups(char* name, gid_t basegid) {
gid_t others[NGROUPS_MAX+1];
int ngrps;
#endif
-main(argc, argv)
+int main(argc, argv)
int argc;
char **argv;
{
#if defined(BSD) && BSD+0 >= 43
struct linger linger;
#endif
- int on = 1, fromlen;
- struct sockaddr_in from;
+ int on = 1;
+ socklen_t fromlen;
+ struct sockaddr_storage from;
extern int opterr, optind;
extern char *optarg;
- char *options;
int ch;
- int i;
int fd;
int debug_port = 0;
+#ifdef KERBEROS
+ krb5_error_code status;
+#endif
#ifdef CRAY
secflag = sysconf(_SC_CRAY_SECURE_SYS);
#endif
- progname = *argv;
+ progname = strrchr (*argv, '/');
+ progname = progname ? progname + 1 : *argv;
#ifndef LOG_ODELAY /* 4.2 syslog */
openlog(progname, LOG_PID);
#else
-#ifndef LOG_DAEMON
-#define LOG_DAEMON 0
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
#endif
- openlog(progname, LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ openlog(progname, LOG_PID | LOG_ODELAY, LOG_AUTH);
#endif /* 4.2 syslog */
#ifdef KERBEROS
- krb5_init_context(&bsd_context);
- krb5_init_ets(bsd_context);
-#endif
-
- if (argc == 1) { /* Get parameters from program name. */
- if (strlen(progname) > MAX_PROG_NAME) {
- usage();
+ status = krb5_init_context(&bsd_context);
+ if (status) {
+ syslog(LOG_ERR, "Error initializing krb5: %s",
+ error_message(status));
exit(1);
- }
- options = (char *) malloc(MAX_PROG_NAME+1);
- options[0] = '\0';
- for (i = 0; (progname[i] != '\0') && (i < MAX_PROG_NAME); i++)
- if (!strcmp(progname+i, "shd")) {
- strcpy(options, "-");
- strncat(options, progname, i);
- options[i+1] = '\0';
-#if 0
- /*
- * Since we are just going to break out afterwards, we'll
- * re-use the variable "i" to move the command line args.
- */
- for (i=argc-1; i>0; i--) argv[i+1] = argv[i];
-#endif
- argv[++argc] = NULL;
-
- argv[1] = options;
- break;
- }
}
+#endif
/* Analyze parameters. */
opterr = 0;
- while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+ while ((ch = getopt(argc, argv, ARGSTR)) != -1)
switch (ch) {
- case 'r':
- must_pass_one = 1; /* If just 'r', any one check must succeed */
- break;
- case 'R': /* If 'R', must pass .rhosts check*/
- must_pass_rhosts = 1;
- if (must_pass_one)
- must_pass_one = 0;
- break;
#ifdef KERBEROS
case 'k':
- must_pass_one = 1; /* If just 'k', any one check must succeed */
- break;
- case 'K': /* If 'K', must pass .k5login check*/
- must_pass_k5 = 1;
- if (must_pass_one)
- must_pass_one = 0;
- break;
+#ifdef KRB5_KRB4_COMPAT
+ auth_ok |= (AUTH_KRB5|AUTH_KRB4);
+#else
+ auth_ok |= AUTH_KRB5;
+#endif /* KRB5_KRB4_COMPAT*/
+ break;
+
+ case '5':
+ auth_ok |= AUTH_KRB5;
+ break;
+ case 'c':
+ checksum_required = 1;
+ break;
+ case 'i':
+ checksum_ignored = 1;
+ break;
+
+#ifdef KRB5_KRB4_COMPAT
+ case '4':
+ auth_ok |= AUTH_KRB4;
+ break;
+#endif
- case 'x':
- case 'X':
case 'e':
- case 'E':
- do_encrypt = 1;
+ require_encrypt = 1;
break;
case 'S':
- srvtab = optarg;
+ if ((status = krb5_kt_resolve(bsd_context, optarg, &keytab))) {
+ com_err(progname, status, "while resolving srvtab file %s",
+ optarg);
+ exit(2);
+ }
break;
case 'M':
case 'P':
kprogdir = optarg;
break;
+
+ case 'L':
+ if (num_env < MAXENV) {
+ save_env[num_env] = strdup(optarg);
+ if(!save_env[num_env++]) {
+ com_err(progname, ENOMEM, "in saving environment");
+ exit(2);
+ }
+ } else {
+ fprintf(stderr, "%s: Only %d -L arguments allowed\n",
+ progname, MAXENV);
+ exit(2);
+ }
+ break;
#endif
case 'D':
debug_port = atoi(optarg);
break;
- case '?':
- default:
+ case 'w':
+ if (!strcmp(optarg, "ip"))
+ always_ip = 1;
+ else {
+ char *cp;
+ cp = strchr(optarg, ',');
+ if (cp == NULL)
+ maxhostlen = atoi(optarg);
+ else if (*(++cp)) {
+ if (!strcmp(cp, "striplocal"))
+ stripdomain = 1;
+ else if (!strcmp(cp, "nostriplocal"))
+ stripdomain = 0;
+ else {
+ usage();
+ exit(1);
+ }
+ *(--cp) = '\0';
+ maxhostlen = atoi(optarg);
+ }
+ }
+ break;
+ case '?':
+ default:
usage();
exit(1);
break;
fromlen = sizeof (from);
- if (debug_port) {
- int s;
- struct sockaddr_in sin;
-
- if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
- fprintf(stderr, "Error in socket: %s\n", strerror(errno));
- exit(2);
- }
-
- memset((char *) &sin, 0,sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(debug_port);
- sin.sin_addr.s_addr = INADDR_ANY;
-
- (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
- (char *)&on, sizeof(on));
-
- if ((bind(s, (struct sockaddr *) &sin, sizeof(sin))) < 0) {
- fprintf(stderr, "Error in bind: %s\n", strerror(errno));
- exit(2);
- }
-
- if ((listen(s, 5)) < 0) {
- fprintf(stderr, "Error in listen: %s\n", strerror(errno));
- exit(2);
- }
-
- if ((fd = accept(s, &from, &fromlen)) < 0) {
- fprintf(stderr, "Error in accept: %s\n", strerror(errno));
- exit(2);
- }
-
- close(s);
- } else {
+ if (debug_port)
+ fd = accept_a_connection(debug_port, (struct sockaddr *)&from,
+ &fromlen);
+ else {
if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
fprintf(stderr, "%s: ", progname);
perror("getpeername");
_exit(1);
}
-
+
fd = 0;
}
-
+
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
sizeof (on)) < 0)
- syslog(LOG_WARNING,
- "setsockopt (SO_KEEPALIVE): %m");
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
#if defined(BSD) && BSD+0 >= 43
linger.l_onoff = 1;
linger.l_linger = 60; /* XXX */
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger,
sizeof (linger)) < 0)
- syslog(LOG_WARNING , "setsockopt (SO_LINGER): %m");
+ syslog(LOG_WARNING , "setsockopt (SO_LINGER): %m");
#endif
- doit(dup(fd), &from);
+
+ if (checksum_required&&checksum_ignored) {
+ syslog(LOG_CRIT, "Checksums are required and ignored; these options are mutually exclusive--check the documentation.");
+ fatal(fd, "Configuration error: mutually exclusive options specified");
+ }
+
+ doit(dup(fd), (struct sockaddr *) &from);
+ return 0;
}
#ifdef CRAY
char term[64] = "TERM=network";
char path_rest[] = RPATH;
+char remote_addr[64+NI_MAXHOST]; /* = "KRB5REMOTEADDR=" */
+char remote_port[64+NI_MAXSERV]; /* = "KRB5REMOTEPORT=" */
+char local_addr[64+NI_MAXHOST]; /* = "KRB5LOCALADDR=" */
+char local_port[64+NI_MAXSERV]; /* = "KRB5LOCALPORT=" */
+#define ADDRPAD 0,0,0,0
+#define KRBPAD 0 /* KRB5CCNAME, optional */
+
+/* The following include extra space for TZ and MAXENV pointers... */
+#define COMMONVARS homedir, shell, 0/*path*/, username, term
#ifdef CRAY
-char *envinit[] =
-{homedir, shell, 0, username, "TZ=GMT0", tmpdir, term, 0};
-#define TZENV 4
-#define TMPDIRENV 5
+char *envinit[] =
+{COMMONVARS, "TZ=GMT0", tmpdir, SAVEENVPAD, KRBPAD, ADDRPAD, 0};
+#define TMPDIRENV 6
char *getenv();
#else /* CRAY */
#ifdef KERBEROS
-char *envinit[] =
-{homedir, shell, 0, username, term, 0};
+char *envinit[] =
+{COMMONVARS, 0/*tz*/, SAVEENVPAD, KRBPAD, ADDRPAD, 0};
#else /* KERBEROS */
-char *envinit[] =
-{homedir, shell, 0, username, term, 0};
+char *envinit[] =
+{COMMONVARS, 0/*tz*/, SAVEENVPAD, ADDRPAD, 0};
#endif /* KERBEROS */
#endif /* CRAY */
+#define TZENV 5
#define PATHENV 2
extern char **environ;
krb5_principal client;
krb5_authenticator *kdata;
-#include <kerberosIV/krb.h>
+#ifdef KRB5_KRB4_COMPAT
AUTH_DAT *v4_kdata;
KTEXT v4_ticket;
+#endif
int auth_sys = 0; /* Which version of Kerberos used to authenticate */
#define KRB5_RECVAUTH_V4 4
#define KRB5_RECVAUTH_V5 5
-doit(f, fromp)
+static krb5_sigtype
+cleanup(signumber)
+ int signumber;
+{
+#ifdef POSIX_SIGNALS
+ struct sigaction sa;
+
+ (void)sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGINT, &sa, (struct sigaction *)0);
+ (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
+ (void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
+ (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
+ (void)sigaction(SIGHUP, &sa, (struct sigaction *)0);
+
+ (void)kill(-pid, SIGTERM);
+#else
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ killpg(pid, SIGTERM);
+#endif
+ wait(0);
+
+ pty_logwtmp(ttyn,"","");
+ syslog(LOG_INFO ,"Daemon terminated via signal %d.", signumber);
+ if (ccache)
+ krb5_cc_destroy(bsd_context, ccache);
+ exit(0);
+}
+
+
+void doit(f, fromp)
int f;
- struct sockaddr_in *fromp;
+ struct sockaddr *fromp;
{
char *cp;
-
#ifdef KERBEROS
- krb5_address peeraddr;
krb5_error_code status;
#endif
-
- int tmpint;
-
- int ioctlval, cnt;
- char *salt, *ttynm, *tty;
- register char *p;
+ int valid_checksum;
+ int cnt;
char *crypt();
struct passwd *pwd;
char *path;
-
#ifdef CRAY
#ifndef NO_UDB
struct udb *ue;
long packet_compart; /* Packet compartments */
#endif /* CRAY */
- int s;
- struct hostent *hp;
- char *hostname;
+ int s = -1;
+ char hostname[NI_MAXHOST];
+ char *sane_host;
+ char hostaddra[NI_MAXHOST];
+ int aierr;
short port;
int pv[2], pw[2], px[2], cc;
fd_set ready, readfrom;
- char buf[BUFSIZ], sig;
- int one = 1;
- krb5_sigtype cleanup();
- int fd;
- struct sockaddr_in fromaddr;
- int non_privileged = 0;
+ char buf[RCMD_BUFSIZ], sig;
+ struct sockaddr_storage localaddr;
#ifdef POSIX_SIGNALS
struct sigaction sa;
#endif
#ifdef HAVE_GETTOSBYNAME
struct tosent *tp;
+
if ((tp = gettosbyname("interactive", "tcp")) &&
(setsockopt(f, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
#ifdef TOS_WARN
#endif
#endif /* IP_TOS */
- fromaddr = *fromp;
+ {
+ socklen_t sin_len = sizeof (localaddr);
+ if (getsockname(f, (struct sockaddr*)&localaddr, &sin_len) < 0) {
+ perror("getsockname");
+ exit(1);
+ }
+ }
#ifdef POSIX_SIGNALS
(void)sigemptyset(&sa.sa_mask);
}
}
#endif
- fromp->sin_port = ntohs((u_short)fromp->sin_port);
- if (fromp->sin_family != AF_INET) {
+ if (fromp->sa_family != AF_INET
+#if defined(KRB5_USE_INET6) && defined(KERBEROS)
+ && fromp->sa_family != AF_INET6
+#endif
+ ) {
syslog(LOG_ERR , "malformed from address\n");
exit(1);
}
#ifdef KERBEROS
netf = f;
- desinbuf.data = des_inbuf;
- desoutbuf.data = des_outbuf;
- if ((must_pass_rhosts || must_pass_one)
- && (fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2))
- non_privileged = 1;
#else
- if (fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2) {
- syslog(LOG_ERR , "connection from bad port\n");
- exit(1);
+ {
+ struct sockaddr_in *frompin = sa2sin(fromp);
+ frompin->sin_port = ntohs((u_short)frompin->sin_port);
+ if (frompin->sin_port >= IPPORT_RESERVED ||
+ frompin->sin_port < IPPORT_RESERVED/2) {
+ syslog(LOG_ERR , "connection from bad port\n");
+ exit(1);
+ }
}
#endif /* KERBEROS */
}
(void) alarm(0);
if (port != 0) {
- int lport;
if (anyport) {
- lport = 5120; /* arbitrary */
- s = getport(&lport);
+ int addrfamily = fromp->sa_family;
+ s = getport(0, &addrfamily);
} else {
- lport = IPPORT_RESERVED - 1;
+ int lport = IPPORT_RESERVED - 1;
+#ifdef HAVE_RRESVPORT_AF
+ s = rresvport_af(&lport, fromp->sa_family);
+#else
s = rresvport(&lport);
+#endif
}
if (s < 0) {
syslog(LOG_ERR ,
"can't get stderr port: %m");
exit(1);
}
-#ifdef KERBEROS
- if ((must_pass_rhosts || must_pass_one)
- && port >= IPPORT_RESERVED)
- non_privileged = 1;
-#else
+#ifndef KERBEROS
if (port >= IPPORT_RESERVED) {
syslog(LOG_ERR , "2nd port not reserved\n");
exit(1);
}
#endif /* KERBEROS */
- fromp->sin_port = htons((u_short)port);
- if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
+ switch (fromp->sa_family) {
+ case AF_INET:
+ sa2sin(fromp)->sin_port = htons((u_short)port);
+ break;
+#ifdef KRB5_USE_INET6
+ case AF_INET6:
+ sa2sin6(fromp)->sin6_port = htons((u_short)port);
+ break;
+#endif
+ }
+ if (connect(s, (struct sockaddr *)fromp, socklen(fromp)) < 0) {
syslog(LOG_INFO ,
"connect second port: %m");
exit(1);
dup2(f, 0);
dup2(f, 1);
dup2(f, 2);
- hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
- fromp->sin_family);
- if (hp){
- hostname = malloc(strlen(hp->h_name) + 1);
- strcpy(hostname,hp->h_name);
+ aierr = getnameinfo(fromp, socklen(fromp), hostname, sizeof(hostname),
+ 0, 0, 0);
+ if (aierr) {
+ error("failed to get remote host address: %s", gai_strerror(aierr));
+ exit(1);
}
- else {
- hostname = malloc(strlen((char *)inet_ntoa(fromp->sin_addr)) + 1);
- strcpy(hostname,(char *)inet_ntoa(fromp->sin_addr));
+ aierr = getnameinfo(fromp, socklen(fromp), hostaddra, sizeof(hostaddra),
+ 0, 0, NI_NUMERICHOST);
+ if (aierr) {
+ error("failed to get remote host address: %s", gai_strerror(aierr));
+ exit(1);
}
- peeraddr.addrtype = fromp->sin_family;
- peeraddr.length = SIZEOF_INADDR;
- peeraddr.contents = (krb5_octet *)&fromp->sin_addr;
-
#ifdef KERBEROS
- if (status = recvauth(f, fromaddr, peeraddr)) {
+ status = pty_make_sane_hostname((struct sockaddr *) fromp, maxhostlen,
+ stripdomain, always_ip, &sane_host);
+ if (status) {
+ error("failed make_sane_hostname: %s\n", error_message(status));
+ exit(1);
+ }
+
+ if ((status = recvauth(f, fromp, &valid_checksum))) {
error("Authentication failed: %s\n", error_message(status));
exit(1);
}
- if (!strncmp(cmdbuf, "-x ", 3))
- do_encrypt = 1;
#else
getstr(f, remuser, sizeof(remuser), "remuser");
getstr(f, locuser, sizeof(locuser), "locuser");
getstr(f, cmdbuf, sizeof(cmdbuf), "command");
+ rcmd_stream_init_normal();
#endif /* KERBEROS */
#ifdef CRAY
pwd = getpwnam(locuser);
if (pwd == (struct passwd *) 0 ) {
syslog(LOG_ERR ,
- "Principal %s (%s@%s) for local user %s has no account.\n",
- kremuser, remuser, hostname, locuser);
+ "Principal %s (%s@%s (%s)) for local user %s has no account.\n",
+ kremuser, remuser, hostaddra, hostname,
+ locuser); /* xxx sprintf buffer in syslog*/
error("Login incorrect.\n");
exit(1);
}
endudb();
if (secflag) {
if(getsysv(&sysv, sizeof(struct sysv)) != 0) {
- loglogin(hostname, SLG_LLERR, 0, ue);
+ loglogin(sane_host, SLG_LLERR, 0, ue);
error("Permission denied.\n");
exit(1);
}
if ((packet_level != ue->ue_deflvl) ||
((packet_compart & ue->ue_comparts) != packet_compart )){
- loglogin(hostname, SLG_LLERR, 0, ue);
+ loglogin(sane_host, SLG_LLERR, 0, ue);
error("Permission denied.\n");
exit(1);
}
if (ue->ue_disabled != 0) {
- loglogin(hostname,SLG_LOCK,ue->ue_logfails,ue);
+ loglogin(sane_host,SLG_LOCK,ue->ue_logfails,ue);
error("Permission denied.\n");
exit(1);
}
privileges. */
if (port) {
/* Place entry into wtmp */
- sprintf(ttyn,"krsh%1d",getpid());
- logwtmp(ttyn,locuser,hostname);
+ sprintf(ttyn,"krsh%ld",(long) (getpid() % 9999999));
+ pty_logwtmp(ttyn,locuser,sane_host);
}
/* We are simply execing a program over rshd : log entry into wtmp,
as kexe(pid), then finish out the session right after that.
Syslog should have the information as to what was exec'd */
else {
- logwtmp(ttyn,locuser,hostname);
+ pty_logwtmp(ttyn,locuser,sane_host);
}
#ifdef CRAY
if (getusrv(&usrv)){
syslog(LOG_ERR,"Cannot getusrv");
error("Permission denied.\n");
- loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+ loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
goto signout_please;
}
/*
if((ue->ue_valcat & TFM_TRUSTED) ||
(sysv.sy_oldtfm &&
((ue->ue_comparts & TRUSTED_SUBJECT) == TRUSTED_SUBJECT))) {
- loglogin(hostname, SLG_TRSUB, ue->ue_logfails,ue);
+ loglogin(sane_host, SLG_TRSUB, ue->ue_logfails,ue);
error("Permission denied.\n");
goto signout_please;
}
- loglogin(hostname, SLG_OKLOG, ue->ue_logfails,ue);
+ loglogin(sane_host, SLG_OKLOG, ue->ue_logfails,ue);
/* Setup usrv structure with user udb info and
packet_level and packet_compart. */
if (ue->ue_minlvl > 0)
nal_error++;
/*
- /*
- * Address not in NAL, if EXEMPT_NAL is not
- * true, then even an unclassified user is
- * not allowed.
- */
- if (!EXEMPT_NAL)
+ * Address not in NAL, if EXEMPT_NAL is not
+ * true, then even an unclassified user is
+ * not allowed.
+ */
+ if (!EXEMPT_NAL)
nal_error++;
- else {
- usrv.sv_minlvl = 0;
- usrv.sv_maxlvl = 0;
- usrv.sv_valcmp = 0;
- usrv.sv_actcmp = 0;
- usrv.sv_actlvl = 0;
- }
+ else {
+ usrv.sv_minlvl = 0;
+ usrv.sv_maxlvl = 0;
+ usrv.sv_valcmp = 0;
+ usrv.sv_actcmp = 0;
+ usrv.sv_actlvl = 0;
+ }
}
if (nal_error) {
- loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+ loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
error("Permission denied.\n");
goto signout_please;
}
sethost(paddr);
if (setusrv(&usrv) == -1) {
- loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+ loglogin(sane_host, SLG_LVERR, ue->ue_logfails,ue);
error("Permission denied.\n");
goto signout_please;
}
#endif /*CRAY*/
if (chdir(pwd->pw_dir) < 0) {
- syslog(LOG_ERR ,
- "Principal %s (%s@%s) for local user %s has no home directory.\n",
- kremuser, remuser, hostname, locuser);
- error("No remote directory.\n");
+ if(chdir("/") < 0) {
+ error("No remote directory.\n");
goto signout_please;
+ }
+ pwd->pw_dir = "/";
}
#ifdef KERBEROS
- if (must_pass_k5 || must_pass_one) {
+
#if defined(KRB5_KRB4_COMPAT) && !defined(ALWAYS_V5_KUSEROK)
if (auth_sys == KRB5_RECVAUTH_V4) {
/* kuserok returns 0 if OK */
if (kuserok(v4_kdata, locuser)){
syslog(LOG_ERR ,
- "Principal %s (%s@%s) for local user %s failed kuserok.\n",
- kremuser, remuser, hostname, locuser);
- if (must_pass_k5) {
- error("Permission denied.\n");
- goto signout_please;
+ "Principal %s (%s@%s (%s)) for local user %s failed kuserok.\n",
+ kremuser, remuser, hostaddra, hostname, locuser);
}
- failed_k5 = 1;
- }
+ else auth_sent |= AUTH_KRB4;
} else
#endif
{
/* krb5_kuserok returns 1 if OK */
if (!krb5_kuserok(bsd_context, client, locuser)){
syslog(LOG_ERR ,
- "Principal %s (%s@%s) for local user %s failed krb5_kuserok.\n",
- kremuser, remuser, hostname, locuser);
- if (must_pass_k5) {
- error("Permission denied.\n");
- goto signout_please;
- }
- failed_k5 = 1;
+ "Principal %s (%s@%s (%s)) for local user %s failed krb5_kuserok.\n",
+ kremuser, remuser, hostaddra, hostname, locuser);
}
- }
- }
-
- if (must_pass_rhosts || (failed_k5 && must_pass_one)) {
- /* Cannot check .rhosts unless connection from privileged port */
- if (non_privileged) {
- syslog(LOG_ERR , "connection from bad port\n");
- exit(1);
+ else
+ auth_sent |=
+ ((auth_sys == KRB5_RECVAUTH_V4) ? AUTH_KRB4 : AUTH_KRB5);
}
- if (ruserok(hostname, pwd->pw_uid == 0,
- remuser, locuser) < 0) {
- syslog(LOG_ERR ,
- "Principal %s (%s@%s) for local user %s failed ruserok.\n",
- kremuser, remuser, hostname, locuser);
- error("Permission denied.\n");
- goto signout_please;
- }
- }
+
#else
if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
- ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
+ ruserok(hostname[0] ? hostname : hostaddra,
+ pwd->pw_uid == 0, remuser, locuser) < 0) {
error("Permission denied.\n");
goto signout_please;
}
#endif /* KERBEROS */
+
+
+ if (checksum_required && !valid_checksum) {
+ if (auth_sent & AUTH_KRB5) {
+ syslog(LOG_WARNING, "Client did not supply required checksum--connection rejected.");
+ error( "You are using an old Kerberos5 client without checksum support; only newer clients are authorized.\n");
+ goto signout_please;
+ } else {
+ syslog(LOG_WARNING,
+ "Configuration error: Requiring checksums with -c is inconsistent with allowing Kerberos V4 connections.");
+ }
+ }
+ if (require_encrypt&&(!do_encrypt)) {
+ error("You must use encryption.\n");
+ goto signout_please;
+ }
+ if (!(auth_ok&auth_sent)) {
+ if (auth_sent)
+ error("Another authentication mechanism must be used to access this host.\n");
+ else
+ error("Permission denied.\n");
+ goto signout_please;
+ }
- if (pwd->pw_uid && !access("/etc/nologin", F_OK)) {
+ if (pwd->pw_uid && !access(NOLOGIN, F_OK)) {
error("Logins currently disabled.\n");
goto signout_please;
}
pwd = (struct passwd *) getpwnam(locuser);
if (pwd && (pwd->pw_uid == 0)) {
#ifdef LOG_CMD
- syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s) as ROOT",
- cmdbuf, kremuser, remuser, hostname);
+ syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s (%s)) as ROOT",
+ cmdbuf, kremuser, remuser, hostaddra, hostname);
#else
- syslog(LOG_NOTICE ,"Access as ROOT by principal %s (%s@%s)",
- kremuser, remuser, hostname);
+ syslog(LOG_NOTICE ,"Access as ROOT by principal %s (%s@%s (%s))",
+ kremuser, remuser, hostaddra, hostname);
#endif
}
#if defined(KERBEROS) && defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
#if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
{
#ifdef LOG_CMD
- syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s) as local user %s",
- cmdbuf, kremuser, remuser, hostname, locuser);
+ syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s (%s)) as local user %s",
+ cmdbuf, kremuser, remuser, hostaddra, hostname, locuser);
#else
- syslog(LOG_NOTICE ,"Access as %s by principal %s (%s@%s)",
- locuser, kremuser, remuser, hostname);
+ syslog(LOG_NOTICE ,"Access as %s by principal %s (%s@%s (%s))",
+ locuser, kremuser, remuser, hostaddra, hostname);
#endif
}
#endif
(void) write(2, "", 1);
- if (port) {
- if (pipe(pv) < 0) {
+ if (port||do_encrypt) {
+ if (port&&(pipe(pv) < 0)) {
error("Can't make pipe.\n");
goto signout_please;
}
(void)sigaction(SIGINT, &sa, (struct sigaction *)0);
(void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
(void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
- (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
(void)sigaction(SIGHUP, &sa, (struct sigaction *)0);
sa.sa_handler = SIG_IGN;
+ /* SIGPIPE is a crutch that we don't need if we check
+ the exit status of write. */
+ (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
(void)sigaction(SIGCHLD, &sa, (struct sigaction *)0);
#else
signal(SIGINT, cleanup);
signal(SIGQUIT, cleanup);
signal(SIGTERM, cleanup);
- signal(SIGPIPE, cleanup);
signal(SIGHUP, cleanup);
+ /* SIGPIPE is a crutch that we don't need if we check
+ the exit status of write. */
+ signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD,SIG_IGN);
#endif
(void) close(0); (void) close(1); (void) close(2);
- (void) close(pv[1]);
+ if(port)
+ (void) close(pv[1]);
(void) close(pw[1]);
(void) close(px[0]);
- ioctl(pv[0], FIONBIO, (char *)&one);
- ioctl(pw[0], FIONBIO, (char *)&one);
- /* should set s nbio! */
-
- if (do_encrypt)
- if (((*des_write)(s, SECURE_MESSAGE, sizeof(SECURE_MESSAGE))) < 0)
- fatal(pw[0], "Cannot encrypt-write network.");
+
FD_ZERO(&readfrom);
FD_SET(f, &readfrom);
- FD_SET(s, &readfrom);
- FD_SET(pv[0], &readfrom);
+ if(port) {
+ FD_SET(s, &readfrom);
+ FD_SET(pv[0], &readfrom);
+ }
FD_SET(pw[0], &readfrom);
+ /* read from f, write to px[1] -- child stdin */
+ /* read from s, signal child */
+ /* read from pv[0], write to s -- child stderr */
+ /* read from pw[0], write to f -- child stdout */
+
do {
ready = readfrom;
if (select(8*sizeof(ready), &ready, (fd_set *)0,
- (fd_set *)0, (struct timeval *)0) < 0)
- break;
- if (FD_ISSET(s, &ready)) {
- if ((*des_read)(s, &sig, 1) <= 0)
+ (fd_set *)0, (struct timeval *)0) < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (port&&FD_ISSET(pv[0], &ready)) {
+ /* read from the child stderr, write to the net */
+ errno = 0;
+ cc = read(pv[0], buf, sizeof (buf));
+ if (cc <= 0) {
+ shutdown(s, 1+1);
+ FD_CLR(pv[0], &readfrom);
+ } else {
+ (void) rcmd_stream_write(s, buf, (unsigned) cc, 1);
+ }
+ }
+ if (FD_ISSET(pw[0], &ready)) {
+ /* read from the child stdout, write to the net */
+ errno = 0;
+ cc = read(pw[0], buf, sizeof (buf));
+ if (cc <= 0) {
+ shutdown(f, 1+1);
+ FD_CLR(pw[0], &readfrom);
+ } else {
+ (void) rcmd_stream_write(f, buf, (unsigned) cc, 0);
+ }
+ }
+ if (port&&FD_ISSET(s, &ready)) {
+ /* read from the alternate channel, signal the child */
+ if (rcmd_stream_read(s, &sig, 1, 1) <= 0) {
FD_CLR(s, &readfrom);
- else {
+ } else {
#ifdef POSIX_SIGNALS
sa.sa_handler = cleanup;
(void)sigaction(sig, &sa, (struct sigaction *)0);
}
}
if (FD_ISSET(f, &ready)) {
+ /* read from the net, write to child stdin */
errno = 0;
- cc = (*des_read)(f, buf, sizeof(buf));
+ cc = rcmd_stream_read(f, buf, sizeof(buf), 0);
if (cc <= 0) {
(void) close(px[1]);
FD_CLR(f, &readfrom);
- } else
- (void) write(px[1], buf, cc);
+ } else {
+ int wcc;
+ wcc = write(px[1], buf, (unsigned) cc);
+ if (wcc == -1) {
+ /* pipe closed, don't read any more */
+ /* might check for EPIPE */
+ (void) close(px[1]);
+ FD_CLR(f, &readfrom);
+ } else if (wcc != cc) {
+ syslog(LOG_INFO, "only wrote %d/%d to child",
+ wcc, cc);
}
- if (FD_ISSET(pv[0], &ready)) {
- errno = 0;
- cc = read(pv[0], buf, sizeof (buf));
- if (cc <= 0) {
- shutdown(s, 1+1);
- FD_CLR(pv[0], &readfrom);
- } else
- (void) (*des_write)(s, buf, cc);
}
- if (FD_ISSET(pw[0], &ready)) {
- errno = 0;
- cc = read(pw[0], buf, sizeof (buf));
- if (cc <= 0) {
- shutdown(f, 1+1);
- FD_CLR(pw[0], &readfrom);
- } else
- (void) (*des_write)(f, buf, cc);
}
- } while (FD_ISSET(s, &readfrom) ||
+ } while ((port&&FD_ISSET(s, &readfrom)) ||
FD_ISSET(f, &readfrom) ||
- FD_ISSET(pv[0], &readfrom) ||
+ (port&&FD_ISSET(pv[0], &readfrom) )||
FD_ISSET(pw[0], &readfrom));
#ifdef KERBEROS
syslog(LOG_INFO ,
"Shell process completed.");
#endif
/* Finish session in wmtp */
- logwtmp(ttyn,"","");
+ pty_logwtmp(ttyn,"","");
+ if (ccache)
+ krb5_cc_destroy(bsd_context, ccache);
exit(0);
}
+#if defined(HAVE_SETSID)&&(!defined(ULTRIX))
+ setsid();
+#else
#ifdef SETPGRP_TWOARG
setpgrp(0, getpid());
#else
setpgrp();
-#endif
+#endif /*setpgrp_twoarg*/
+#endif /*HAVE_SETSID*/
(void) close(s);
(void) close(f);
(void) close(pw[0]);
- (void) close(pv[0]);
+ if (port)
+ (void) close(pv[0]);
(void) close(px[1]);
(void) dup2(px[0], 0);
(void) dup2(pw[1], 1);
- (void) dup2(pv[1], 2);
+ if(port)
+ (void) dup2(pv[1], 2);
+ else dup2(pw[1], 2);
(void) close(px[0]);
(void) close(pw[1]);
- (void) close(pv[1]);
+ if(port)
+ (void) close(pv[1]);
}
/* We are simply execing a program over rshd : log entry into wtmp,
as kexe(pid), then finish out the session right after that.
Syslog should have the information as to what was exec'd */
else {
- logwtmp(ttyn,"","");
+ pty_logwtmp(ttyn,"","");
}
if (*pwd->pw_shell == '\0')
initgroups(pwd->pw_name, pwd->pw_gid);
}
#endif
+#ifdef HAVE_SETLUID
+ /*
+ * If we're on a system which keeps track of login uids, then
+ * set the login uid.
+ */
+ setluid((uid_t) pwd->pw_uid);
+#endif /* HAVE_SETLUID */
(void) setuid((uid_t)pwd->pw_uid);
- environ = envinit;
+ /* if TZ is set in the parent, drag it in */
+ {
+ char **findtz = environ;
+ while(*findtz) {
+ if(!strncmp(*findtz,"TZ=",3)) {
+ envinit[TZENV] = *findtz;
+ break;
+ }
+ findtz++;
+ }
+ }
strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
strncat(shell, pwd->pw_shell, sizeof(shell)-7);
strncat(username, pwd->pw_name, sizeof(username)-6);
}
sprintf(path, "PATH=%s:%s", kprogdir, path_rest);
envinit[PATHENV] = path;
- cp = strrchr(pwd->pw_shell, '/');
- if (cp)
- cp++;
- else
- cp = pwd->pw_shell;
+ /* If we have KRB5CCNAME set, then copy into the
+ * child's environment. This can't really have
+ * a fixed position because tz may or may not be set.
+ */
+ if (getenv("KRB5CCNAME")) {
+ int i;
+ char *buf2 = (char *)malloc(strlen(getenv("KRB5CCNAME"))
+ +strlen("KRB5CCNAME=")+1);
+ if (buf2) {
+ sprintf(buf2, "KRB5CCNAME=%s",getenv("KRB5CCNAME"));
+
+ for (i = 0; envinit[i]; i++);
+ envinit[i] = buf2;
+ }
+ }
+
+ {
+ char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ int i;
+ /* these four are covered by ADDRPAD */
+
+ for (i = 0; envinit[i]; i++);
+
+ aierr = getnameinfo((struct sockaddr *)&localaddr,
+ socklen((struct sockaddr *)&localaddr),
+ hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (aierr)
+ goto skip_localaddr_env;
+ sprintf(local_addr, "KRB5LOCALADDR=%s", hbuf);
+ envinit[i++] =local_addr;
+
+ sprintf(local_port, "KRB5LOCALPORT=%s", sbuf);
+ envinit[i++] =local_port;
+ skip_localaddr_env:
+
+ aierr = getnameinfo(fromp, socklen(fromp),
+ hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (aierr)
+ goto skip_remoteaddr_env;
+ sprintf(remote_addr, "KRB5REMOTEADDR=%s", hbuf);
+ envinit[i++] =remote_addr;
+
+ sprintf(remote_port, "KRB5REMOTEPORT=%s", sbuf);
+ envinit[i++] =remote_port;
+
+ skip_remoteaddr_env:
+ ;
+ }
+
+ /* If we do anything else, make sure there is space in the array. */
+
+ for(cnt=0; cnt < num_env; cnt++) {
+ int i;
+ char *buf2;
+
+ if(getenv(save_env[cnt])) {
+ buf2 = (char *)malloc(strlen(getenv(save_env[cnt]))
+ +strlen(save_env[cnt]+2));
+ if (buf2) {
+ sprintf(buf2, "%s=%s", save_env[cnt],
+ getenv(save_env[cnt]));
+ for (i = 0; envinit[i]; i++);
+ envinit[i] = buf2;
+ }
+ }
+ }
+
+ /* XXX - If we do anything else, make sure there is space in the array. */
+
+ environ = envinit;
+
#ifdef KERBEROS
/* To make Kerberos rcp work correctly, we must ensure that we
invoke Kerberos rcp on this end, not normal rcp, even if the
if (!strncmp(cmdbuf, "rcp ", 4) ||
(do_encrypt && !strncmp(cmdbuf, "-x rcp ", 7))) {
char *copy;
- struct stat s;
+ struct stat s2;
+ int offst = 0;
copy = malloc(strlen(cmdbuf) + 1);
if (copy == NULL) {
}
strcpy(copy, cmdbuf);
if (do_encrypt && !strncmp(cmdbuf, "-x ", 3)) {
- strcpy(cmdbuf + 3, kprogdir);
- cp = copy + 6;
+ offst = 3;
+ }
+
+ strcpy((char *) cmdbuf + offst, kprogdir);
+ cp = copy + 3 + offst;
+
+ cmdbuf[sizeof(cmdbuf) - 1] = '\0';
+ if (auth_sys == KRB5_RECVAUTH_V4) {
+ strncat(cmdbuf, "/v4rcp", sizeof(cmdbuf) - 1 - strlen(cmdbuf));
} else {
- strcpy(cmdbuf, kprogdir);
- cp = copy + 3;
+ strncat(cmdbuf, "/rcp", sizeof(cmdbuf) - 1 - strlen(cmdbuf));
}
- strcat(cmdbuf, "/rcp");
- if (stat(cmdbuf, &s) >= 0)
- strcat(cmdbuf, cp);
+ if (stat((char *)cmdbuf + offst, &s2) >= 0)
+ strncat(cmdbuf, cp, sizeof(cmdbuf) - 1 - strlen(cmdbuf));
else
- strcpy(cmdbuf, copy);
+ strncpy(cmdbuf, copy, sizeof(cmdbuf) - 1 - strlen(cmdbuf));
free(copy);
}
#endif
+ cp = strrchr(pwd->pw_shell, '/');
+ if (cp)
+ cp++;
+ else
+ cp = pwd->pw_shell;
+
if (do_encrypt && !strncmp(cmdbuf, "-x ", 3)) {
execl(pwd->pw_shell, cp, "-c", (char *)cmdbuf + 3, 0);
}
- else
+ else {
execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
-
+ }
perror(pwd->pw_shell);
perror(cp);
exit(1);
signout_please:
- logwtmp(ttyn,"","");
+ if (ccache)
+ krb5_cc_destroy(bsd_context, ccache);
+ ccache = NULL;
+ pty_logwtmp(ttyn,"","");
exit(1);
}
-
+void
+#ifdef HAVE_STDARG_H
+error(char *fmt, ...)
+#else
/*VARARGS1*/
-error(fmt, a1, a2, a3)
+error(fmt, va_alist)
char *fmt;
- char *a1, *a2, *a3;
+ va_dcl
+#endif
{
- char buf[BUFSIZ];
+ va_list ap;
+ char buf[RCMD_BUFSIZ], *cp = buf;
- buf[0] = 1;
- (void) sprintf(buf+1, "%s: ", progname);
- (void) sprintf(buf+strlen(buf), fmt, a1, a2, a3);
+#ifdef HAVE_STDARG_H
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ *cp++ = 1;
+ (void) sprintf(cp, "%s: ", progname);
+ (void) vsprintf(buf+strlen(buf), fmt, ap);
+ va_end(ap);
(void) write(2, buf, strlen(buf));
syslog(LOG_ERR ,"%s",buf+1);
}
-
-getstr(fd, buf, cnt, err)
- char *buf;
- int cnt;
- char *err;
+void getstr(fd, buf, cnt, err)
+ int fd;
+ char *buf;
+ int cnt;
+ char *err;
{
char c;
} while (c != 0);
}
-
-
-krb5_sigtype
- cleanup()
-{
-#ifdef POSIX_SIGNALS
- struct sigaction sa;
-
- (void)sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- sa.sa_handler = SIG_IGN;
- (void)sigaction(SIGINT, &sa, (struct sigaction *)0);
- (void)sigaction(SIGQUIT, &sa, (struct sigaction *)0);
- (void)sigaction(SIGTERM, &sa, (struct sigaction *)0);
- (void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
- (void)sigaction(SIGHUP, &sa, (struct sigaction *)0);
-
- (void)kill(-pid, SIGTERM);
-#else
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-
- killpg(pid, SIGTERM);
-#endif
- wait(0);
-
- logwtmp(ttyn,"","");
- syslog(LOG_INFO ,"Shell process completed.");
- exit(0);
-}
-
-
-
#ifdef CRAY
char *makejtmp(uid, gid, jid)
register int uid, gid, jid;
{
- extern int errno;
-
register char *endc, *tdp = &tmpdir[strlen(tmpdir)];
register int i;
-usage()
+void usage()
{
#ifdef KERBEROS
- syslog(LOG_ERR, "usage: kshd [-rRkK] or [r/R][k/K]shd");
+ syslog(LOG_ERR, "usage: kshd [-54ecikK] ");
#else
syslog(LOG_ERR, "usage: rshd");
#endif
}
-
-int princ_maps_to_lname(principal, luser)
- krb5_principal principal;
- char *luser;
-{
- char kuser[10];
- if (!(krb5_aname_to_localname(bsd_context, principal,
- sizeof(kuser), kuser))
- && (strcmp(kuser, luser) == 0)) {
- return 1;
- }
- return 0;
-}
-
-
-int default_realm(principal)
- krb5_principal principal;
-{
- char *def_realm;
- int realm_length;
- int retval;
-
- realm_length = krb5_princ_realm(bsd_context, principal)->length;
-
- if (retval = krb5_get_default_realm(bsd_context, &def_realm)) {
- return 0;
- }
-
- if ((realm_length != strlen(def_realm)) ||
- (memcmp(def_realm, krb5_princ_realm(bsd_context, principal)->data,
- realm_length))) {
- free(def_realm);
- return 0;
- }
- free(def_realm);
- return 1;
-}
-
#ifdef KERBEROS
#ifndef KRB_SENDAUTH_VLEN
#define KRB_SENDAUTH_VERS "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN
chars */
-krb5_error_code
-recvauth(netf, peersin, peeraddr)
- int netf;
- struct sockaddr_in peersin;
- krb5_address peeraddr;
+static krb5_error_code
+recvauth(netfd, peersin, valid_checksum)
+ int netfd;
+ struct sockaddr *peersin;
+ int *valid_checksum;
{
- krb5_auth_context *auth_context = NULL;
+ krb5_auth_context auth_context = NULL;
krb5_error_code status;
struct sockaddr_in laddr;
- char krb_vers[KRB_SENDAUTH_VLEN + 1];
- int len;
- krb5_principal server;
+ socklen_t len;
krb5_data inbuf;
+#ifdef KRB5_KRB4_COMPAT
char v4_instance[INST_SZ]; /* V4 Instance */
- char v4_version[9];
+#endif
+ krb5_authenticator *authenticator;
krb5_ticket *ticket;
+ krb5_rcache rcache;
+ struct passwd *pwd;
+ uid_t uid;
+ gid_t gid;
+ enum kcmd_proto kcmd_proto;
+ krb5_data version;
+ *valid_checksum = 0;
len = sizeof(laddr);
- if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
+ if (getsockname(netfd, (struct sockaddr *)&laddr, &len)) {
exit(1);
}
#define SIZEOF_INADDR sizeof(struct in_addr)
#endif
- if (status = krb5_sname_to_principal(bsd_context, NULL, "host",
- KRB5_NT_SRV_HST, &server)) {
- syslog(LOG_ERR, "parse server name %s: %s", "host",
- error_message(status));
- exit(1);
- }
-
+#ifdef KRB5_KRB4_COMPAT
strcpy(v4_instance, "*");
+#endif
+
+ status = krb5_auth_con_init(bsd_context, &auth_context);
+ if (status)
+ return status;
- if (status = krb5_auth_con_init(bsd_context, &auth_context))
+ status = krb5_auth_con_genaddrs(bsd_context, auth_context, netfd,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+ if (status)
return status;
- krb5_auth_con_setaddrs(bsd_context, auth_context, NULL, &peeraddr);
+ status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
+ if (status) return status;
- status = krb5_compat_recvauth(bsd_context, &auth_context, &netf,
- "KCMDV0.1",
- server, /* Specify daemon principal */
- 0, /* default rc_type */
+ if (! rcache) {
+ krb5_principal server;
+
+ status = krb5_sname_to_principal(bsd_context, 0, 0,
+ KRB5_NT_SRV_HST, &server);
+ if (status) return status;
+
+ status = krb5_get_server_rcache(bsd_context,
+ krb5_princ_component(bsd_context, server, 0),
+ &rcache);
+ krb5_free_principal(bsd_context, server);
+ if (status) return status;
+
+ status = krb5_auth_con_setrcache(bsd_context, auth_context, rcache);
+ if (status) return status;
+ }
+
+#ifdef KRB5_KRB4_COMPAT
+ status = krb5_compat_recvauth_version(bsd_context, &auth_context, &netfd,
+ NULL, /* Specify daemon principal */
0, /* no flags */
- srvtab, /* normally NULL to use v5srvtab */
+ keytab, /* normally NULL to use v5srvtab */
0, /* v4_opts */
"rcmd", /* v4_service */
v4_instance, /* v4_instance */
- &peersin, /* foreign address */
+ (struct sockaddr_in *)peersin, /* foreign address */
&laddr, /* our local address */
"", /* use default srvtab */
&ticket, /* return ticket */
&auth_sys, /* which authentication system*/
- &v4_kdata, 0, v4_version);
-
+ &v4_kdata, 0, &version);
+#else
+ status = krb5_recvauth_version(bsd_context, &auth_context, &netfd,
+ NULL, /* daemon principal */
+ 0, /* no flags */
+ keytab, /* normally NULL to use v5srvtab */
+ &ticket, /* return ticket */
+ &version); /* application version string */
+ auth_sys = KRB5_RECVAUTH_V5;
+#endif
if (status) {
if (auth_sys == KRB5_RECVAUTH_V5) {
/*
* clean up before exiting
*/
- getstr(netf, locuser, sizeof(locuser), "locuser");
- getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
- getstr(netf, remuser, sizeof(locuser), "remuser");
+ getstr(netfd, locuser, sizeof(locuser), "locuser");
+ getstr(netfd, cmdbuf, sizeof(cmdbuf), "command");
+ getstr(netfd, remuser, sizeof(locuser), "remuser");
}
return status;
}
- getstr(netf, locuser, sizeof(locuser), "locuser");
- getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
+ getstr(netfd, locuser, sizeof(locuser), "locuser");
+ getstr(netfd, cmdbuf, sizeof(cmdbuf), "command");
+#ifdef KRB5_KRB4_COMPAT
if (auth_sys == KRB5_RECVAUTH_V4) {
+ rcmd_stream_init_normal();
+
/* We do not really know the remote user's login name.
* Assume it to be the same as the first component of the
* principal's name.
*/
strcpy(remuser, v4_kdata->pname);
- kremuser = (char *) malloc(strlen(v4_kdata->pname) + 1 +
- strlen(v4_kdata->pinst) + 1 +
- strlen(v4_kdata->prealm) + 1);
- sprintf(kremuser, "%s/%s@%s", v4_kdata->pname,
- v4_kdata->pinst, v4_kdata->prealm);
+
+ status = krb5_425_conv_principal(bsd_context, v4_kdata->pname,
+ v4_kdata->pinst, v4_kdata->prealm,
+ &client);
+ if (status) return status;
+
+ status = krb5_unparse_name(bsd_context, client, &kremuser);
- if (status = krb5_parse_name(bsd_context, kremuser, &client))
- return(status);
- return 0;
+ return status;
}
+#endif /* KRB5_KRB4_COMPAT */
/* Must be V5 */
- getstr(netf, remuser, sizeof(locuser), "remuser");
-
- if (status = krb5_unparse_name(bsd_context, ticket->enc_part2->client,
- &kremuser))
+ kcmd_proto = KCMD_UNKNOWN_PROTOCOL;
+ if (version.length != 9)
+ fatal (netfd, "bad application version length");
+ if (!memcmp (version.data, "KCMDV0.1", 9))
+ kcmd_proto = KCMD_OLD_PROTOCOL;
+ if (!memcmp (version.data, "KCMDV0.2", 9))
+ kcmd_proto = KCMD_NEW_PROTOCOL;
+
+ getstr(netfd, remuser, sizeof(locuser), "remuser");
+
+ if ((status = krb5_unparse_name(bsd_context, ticket->enc_part2->client,
+ &kremuser)))
+ return status;
+
+ if ((status = krb5_copy_principal(bsd_context, ticket->enc_part2->client,
+ &client)))
return status;
+ if ((status = krb5_auth_con_getauthenticator(bsd_context, auth_context,
+ &authenticator)))
+ return status;
- /* Setup eblock for encrypted sessions. */
- krb5_use_keytype(bsd_context, &eblock, ticket->enc_part2->session->keytype);
- if (status = krb5_process_key(bsd_context, &eblock, ticket->enc_part2->session))
- fatal(netf, "Permission denied");
+ if (authenticator->checksum && !checksum_ignored) {
+ struct sockaddr_storage adr;
+ unsigned int adr_length = sizeof(adr);
+ int e;
+ unsigned int buflen = strlen(cmdbuf)+strlen(locuser)+32;
+ char * chksumbuf = (char *) malloc(buflen);
+
+ if (chksumbuf == 0)
+ goto error_cleanup;
+ if (getsockname(netfd, (struct sockaddr *) &adr, &adr_length) != 0)
+ goto error_cleanup;
+
+ e = getnameinfo((struct sockaddr *)&adr, adr_length, 0, 0,
+ chksumbuf, buflen, NI_NUMERICSERV);
+ if (e) {
+ free(chksumbuf);
+ fatal(netfd, "local error: can't examine port number");
+ }
+ if (strlen(chksumbuf) > 30) {
+ free(chksumbuf);
+ fatal(netfd, "wacky local port number?!");
+ }
+ strcat(chksumbuf, ":");
+ strcat(chksumbuf,cmdbuf);
+ strcat(chksumbuf,locuser);
+
+ status = krb5_verify_checksum(bsd_context,
+ authenticator->checksum->checksum_type,
+ authenticator->checksum,
+ chksumbuf, strlen(chksumbuf),
+ ticket->enc_part2->session->contents,
+ ticket->enc_part2->session->length);
+
+ error_cleanup:
+ if (chksumbuf)
+ free(chksumbuf);
+ if (status) {
+ krb5_free_authenticator(bsd_context, authenticator);
+ return status;
+ }
+ *valid_checksum = 1;
+ }
+ krb5_free_authenticator(bsd_context, authenticator);
+
+
+ if (!strncmp(cmdbuf, "-x ", 3))
+ do_encrypt = 1;
+
+ {
+ krb5_keyblock *key;
+ status = krb5_auth_con_getrecvsubkey (bsd_context, auth_context,
+ &key);
+ if (status)
+ fatal (netfd, "Server can't get session subkey");
+ if (!key && do_encrypt && kcmd_proto == KCMD_NEW_PROTOCOL)
+ fatal (netfd, "No session subkey sent");
+ if (key && kcmd_proto == KCMD_OLD_PROTOCOL) {
+#ifdef HEIMDAL_FRIENDLY
+ key = 0;
+#else
+ fatal (netfd, "Session subkey not allowed in old kcmd protocol");
+#endif
+ }
+ if (key == 0)
+ key = ticket->enc_part2->session;
+ rcmd_stream_init_krb5 (key, do_encrypt, 0, 0, kcmd_proto);
+ }
- /* Null out the "session" because eblock.key references the session
+ /* Null out the "session" because kcmd.c references the session
* key here, and we do not want krb5_free_ticket() to destroy it. */
ticket->enc_part2->session = 0;
- if (status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf)) {
+ if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netfd,
+ &inbuf))) {
error("Error reading message: %s\n", error_message(status));
exit(1);
}
if (inbuf.length) { /* Forwarding being done, read creds */
- if (status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf,
- ticket, locuser)) {
+ pwd = getpwnam(locuser);
+ if (!pwd) {
+ error("Login incorrect.\n");
+ exit(1);
+ }
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+ if ((status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf,
+ ticket, &ccache))) {
error("Can't get forwarded credentials: %s\n",
error_message(status));
exit(1);
}
+ if (chown(krb5_cc_get_name(bsd_context, ccache), uid, gid) == -1) {
+ error("Can't chown forwarded credentials: %s\n",
+ error_message(errno));
+ exit(1);
+ }
}
krb5_free_ticket(bsd_context, ticket);
return 0;
}
+#endif /* KERBEROS */
-char storage[2*BUFSIZ]; /* storage for the decryption */
-int nstored = 0;
-char *store_ptr = storage;
-
-int
-v5_des_read(fd, buf, len)
- int fd;
- register char *buf;
- int len;
-{
- int nreturned = 0;
- krb5_ui_4 net_len,rd_len;
- int cc,retry;
- unsigned char len_buf[4];
-
- if (!do_encrypt)
- return(read(fd, buf, len));
-
- if (nstored >= len) {
- memcpy(buf, store_ptr, len);
- store_ptr += len;
- nstored -= len;
- return(len);
- } else if (nstored) {
- memcpy(buf, store_ptr, nstored);
- nreturned += nstored;
- buf += nstored;
- len -= nstored;
- nstored = 0;
- }
-
- if ((cc = krb5_net_read(bsd_context, fd, (char *)len_buf, 4)) != 4) {
- if ((cc < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
- return(cc);
- /* XXX can't read enough, pipe must have closed */
- return(0);
- }
- rd_len =
- ((len_buf[0]<<24) |
- (len_buf[1]<<16) |
- (len_buf[2]<<8) |
- len_buf[3]);
- net_len = krb5_encrypt_size(rd_len, eblock.crypto_entry);
- if (net_len < 0 || net_len > sizeof(des_inbuf)) {
- /* XXX preposterous length, probably out of sync.
- act as if pipe closed */
- syslog(LOG_ERR,"Read size problem (rd_len=%d, net_len=%d)",
- rd_len, net_len);
- return(0);
- }
- retry = 0;
- datard:
- if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
- /* XXX can't read enough, pipe must have closed */
- if ((cc < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
- retry++;
- if (retry > MAXRETRIES){
- syslog(LOG_ERR, "des_read retry count exceeded %d\n", retry);
- return(0);
- }
- sleep(1);
- goto datard;
- }
- syslog(LOG_ERR,
- "Read data received %d != expected %d.",
- cc, net_len);
- return(0);
- }
-
- /* decrypt info */
- if (krb5_decrypt(bsd_context, desinbuf.data, (krb5_pointer) storage, net_len,
- &eblock, 0)) {
- syslog(LOG_ERR,"Read decrypt problem.");
- return(0);
- }
-
- store_ptr = storage;
- nstored = rd_len;
- if (nstored > len) {
- memcpy(buf, store_ptr, len);
- nreturned += len;
- store_ptr += len;
- nstored -= len;
- } else {
- memcpy(buf, store_ptr, nstored);
- nreturned += nstored;
- nstored = 0;
- }
- return(nreturned);
-}
-
-
-int
-v5_des_write(fd, buf, len)
- int fd;
- char *buf;
- int len;
-{
- unsigned char len_buf[4];
-
- if (!do_encrypt)
- return(write(fd, buf, len));
-
- desoutbuf.length = krb5_encrypt_size(len, eblock.crypto_entry);
- if (desoutbuf.length > sizeof(des_outbuf)){
- syslog(LOG_ERR,"Write size problem (%d > %d)",
- desoutbuf.length, sizeof(des_outbuf));
- return(-1);
- }
-
- if (krb5_encrypt(bsd_context, (krb5_pointer)buf, desoutbuf.data, len, &eblock, 0)) {
- syslog(LOG_ERR,"Write encrypt problem.");
- return(-1);
- }
-
- len_buf[0] = (len & 0xff000000) >> 24;
- len_buf[1] = (len & 0xff0000) >> 16;
- len_buf[2] = (len & 0xff00) >> 8;
- len_buf[3] = (len & 0xff);
- (void) write(fd, len_buf, 4);
-
- if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length){
- syslog(LOG_ERR,"Could not write out all data.");
- return(-1);
- }
- else return(len);
-}
-
void fatal(f, msg)
int f;
- char *msg;
+ const char *msg;
{
char buf[512];
+#ifndef POSIX_TERMIOS
int out = 1 ; /* Output queue of f */
+#endif
buf[0] = '\01'; /* error indicator */
(void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
if ((f == netf) && (pid > 0))
- (void) (*des_write)(f, buf, strlen(buf));
+ (void) rcmd_stream_write(f, buf, strlen(buf), 0);
else
(void) write(f, buf, strlen(buf));
syslog(LOG_ERR,"%s\n",msg);
#else
(void) ioctl(f, TIOCFLUSH, (char *)&out);
#endif
- cleanup();
+ cleanup(-1);
}
exit(1);
}
-#endif /* KERBEROS */