* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
* 1) Check authentication.
* 2) Check authorization via the access-control files:
* ~/.k5login (using krb5_kuserok) and/or
- * ~/.rhosts (using ruserok).
* 3) Prompt for password if any checks fail, or if so configured.
* Allow login if all goes well either by calling the accompanying
* login.krb5 or /bin/login, according to the definition of
- * DO_NOT_USE_K_LOGIN.
+ * DO_NOT_USE_K_LOGIN.l
*
* 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).
+ * -k means trust krb4 or krb5
+* -5 means trust krb5
+* -4 means trust krb4
* -p and -P means prompt for password.
- * 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 login without password. If the -p option is
- * passed with -r or -k, then if both checks fail, allow login but
- * only after password verification.
- * If uppercase -R or -K, then those checks must be passed,
- * regardless of other checks, else no login with or without password.
* If the -P option is passed, then the password is verified in
* addition to all other checks. If -p is not passed with -k or -r,
* and both checks fail, then login permission is denied.
- * -x and -e means use encryption.
+ * - -e means use encryption.
*
* If no command-line arguments are present, then the presence of the
* letters kKrRexpP in the program-name before "logind" determine the
* KERBEROS - Define this if application is to be kerberised.
* CRYPT - Define this if encryption is to be an option.
* DO_NOT_USE_K_LOGIN - Define this if you want to use /bin/login
- * instead of the accompanying login.krb5. In that case,
- * the remote user's name must be present in the local
- * .rhosts file, regardless of any options specified.
+ * instead of the accompanying login.krb5.
* KRB5_KRB4_COMPAT - Define this if v4 rlogin clients are also to be served.
* ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
* checked even for v4 clients (instead of .klogin).
*/
#define LOG_REMOTE_REALM
#define CRYPT
-
+#define USE_LOGIN_F
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
#include <sys/socket.h>
+#endif
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/file.h>
#include <signal.h>
-#ifdef hpux
+#if defined(hpux) || defined(__hpux)
#include <sys/ptyio.h>
#endif
#ifdef sysvimp
#else
#include <sgtty.h>
#endif
-
+
+#ifndef KERBEROS
+/* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
#include <netdb.h>
+#endif
#include <syslog.h>
#include <string.h>
#include <sys/param.h>
-#include <utmp.h>
#ifdef HAVE_STREAMS
/* krlogin doesn't test sys/tty... */
#include <sys/filio.h>
#endif
-#ifndef SETPGRP_TWOARG
-#define setpgrp(a,b) setpgrp()
-#endif
-
#ifndef HAVE_KILLPG
#define killpg(pid, sig) kill(-(pid), (sig))
#endif
+#ifdef HAVE_PTSNAME
+/* HP/UX 9.04 has but does not declare ptsname. */
+extern char *ptsname ();
+#endif
+
#ifdef NO_WINSIZE
struct winsize {
unsigned short ws_row, ws_col;
#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
#endif
+#include "fake-addrinfo.h"
+
#ifdef KERBEROS
-#include "krb5.h"
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
#include <kerberosIV/krb.h>
-
-#ifdef BUFSIZ
-#undef BUFSIZ
+#endif
+#include <libpty.h>
+#ifdef HAVE_UTMP_H
+#include <utmp.h>
+#include <k5-util.h>
#endif
int auth_sys = 0; /* Which version of Kerberos used to authenticate */
int non_privileged = 0; /* set when connection is seen to be from */
/* a non-privileged port */
+#ifdef KRB5_KRB4_COMPAT
AUTH_DAT *v4_kdata;
Key_schedule v4_schedule;
-int v4_des_read(), v4_des_write();
-
-#define BUFSIZ 5120
-
-int v5_des_read(), v5_des_write();
+#endif
#include "com_err.h"
+#include "defines.h"
-#define SECURE_MESSAGE "This rlogin session is using DES encryption for all data transmissions.\r\n"
-
-int (*des_read)(), (*des_write)();
-char des_inbuf[2*BUFSIZ]; /* needs to be > largest read size */
-char des_outbuf[2*BUFSIZ]; /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
-krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
+#define SECURE_MESSAGE "This rlogin session is encrypting all data transmissions.\r\n"
krb5_authenticator *kdata;
krb5_ticket *ticket = 0;
krb5_context bsd_context;
+krb5_ccache ccache = NULL;
krb5_keytab keytab = NULL;
-#define ARGSTR "rRkKeExXpPD:S:M:L:?"
+#define ARGSTR "k54ciepPD:S:M:L:fw:?"
#else /* !KERBEROS */
-#define ARGSTR "rRpPD:?"
-#define (*des_read) read
-#define (*des_write) write
+#define ARGSTR "rpPD:f?"
#endif /* KERBEROS */
#ifndef LOGIN_PROGRAM
#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
#endif
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#ifndef MAXDNAME
+#define MAXDNAME 256 /*per the rfc*/
+#endif
+
char lusername[UT_NAMESIZE+1];
char rusername[UT_NAMESIZE+1];
char *krusername = 0;
char term[64];
-char rhost_name[128];
+char rhost_name[MAXDNAME];
+char rhost_addra[16];
krb5_principal client;
+int do_inband = 0;
-extern int errno;
int reapchild();
char *progname;
static int Pfd;
+#if defined(NEED_DAEMON_PROTO)
+extern int daemon(int, int);
+#endif
+
#if (defined(_AIX) && defined(i386)) || defined(ibm032) || (defined(vax) && !defined(ultrix)) || (defined(SunOS) && SunOS > 40) || defined(solaris20)
#define VHANG_FIRST
#endif
#define VHANG_LAST /* vhangup must occur on close, not open */
#endif
-void fatal(), fatalperror(), doit(), usage(), do_krb_login();
-int princ_maps_to_lname(), default_realm();
-krb5_sigtype cleanup();
-
-int must_pass_rhosts = 0, must_pass_k5 = 0, must_pass_one = 0;
+void fatal(int, const char *), fatalperror(int, const char *), doit(int, struct sockaddr *), usage(void), do_krb_login(char *, char *), getstr(int, char *, int, char *);
+void protocol(int, int);
+int princ_maps_to_lname(krb5_principal, char *), default_realm(krb5_principal);
+krb5_sigtype cleanup(int);
+krb5_error_code recvauth(int *);
+
+/* 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 do_encrypt = 0, passwd_if_fail = 0, passwd_req = 0;
+int checksum_required = 0, checksum_ignored = 0;
-main(argc, argv)
+int stripdomain = 1;
+int maxhostlen = 0;
+int always_ip = 0;
+
+int main(argc, argv)
int argc;
char **argv;
{
extern int opterr, optind;
extern char * optarg;
- int on = 1, fromlen, ch, i;
- struct sockaddr_in from;
- char *options;
+ int on = 1, ch;
+ socklen_t fromlen;
+ struct sockaddr_storage from;
int debug_port = 0;
int fd;
+ int do_fork = 0;
#ifdef KERBEROS
krb5_error_code status;
#endif
progname = *argv;
+ pty_init();
+
#ifndef LOG_NDELAY
#define LOG_NDELAY 0
#endif
-#ifdef KERBEROS
- krb5_init_context(&bsd_context);
- krb5_init_ets(bsd_context);
-#endif
-
#ifndef LOG_AUTH /* 4.2 syslog */
openlog(progname, LOG_PID | LOG_NDELAY);
#else
openlog(progname, LOG_PID | LOG_NDELAY, LOG_AUTH);
#endif /* 4.2 syslog */
- if (argc == 1) { /* Get parameters from program name. */
- if (strlen(progname) > MAX_PROG_NAME) {
- usage();
- 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, "logind")) {
- char **newargv;
-
- newargv = (char **) malloc(sizeof(char *) * 3);
-
- strcpy(options, "-");
- strncat(options, progname, i);
-
- argc = 2;
-
- newargv[0] = argv[0];
- newargv[1] = options;
- newargv[2] = NULL;
-
- argv = newargv;
- break;
- }
- if (options[0] == '\0') {
- usage();
+#ifdef KERBEROS
+ status = krb5_init_context(&bsd_context);
+ if (status) {
+ syslog(LOG_ERR, "Error initializing krb5: %s",
+ error_message(status));
exit(1);
- }
}
+#endif
/* Analyse 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
#ifdef CRYPT
case 'x': /* Use encryption. */
case 'X':
break;
#endif
case 'S':
- if (status = krb5_kt_resolve(bsd_context, optarg, &keytab)) {
+ if ((status = krb5_kt_resolve(bsd_context, optarg, &keytab))) {
com_err(progname, status, "while resolving srvtab file %s",
optarg);
exit(2);
debug_port = atoi(optarg);
break;
case 'L':
-#ifndef DO_NOT_USE_K_LOGIN
login_program = optarg;
-#endif
+ break;
+ case 'f':
+ do_fork = 1;
+ break;
+ 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:
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, (struct sockaddr *) &from, &fromlen)) < 0) {
- fprintf(stderr, "Error in accept: %s\n", strerror(errno));
- exit(2);
- }
-
- close(s);
- }
- else {
- if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
- syslog(LOG_ERR,"Can't get peer name of remote host: %m");
+ if (debug_port || do_fork) {
+ int s;
+ struct servent *ent;
+ struct sockaddr_in sock_in;
+
+ if (!debug_port) {
+ if (do_encrypt) {
+ ent = getservbyname("eklogin", "tcp");
+ if (ent == NULL)
+ debug_port = 2105;
+ else
+ debug_port = ent->s_port;
+ } else {
+ ent = getservbyname("klogin", "tcp");
+ if (ent == NULL)
+ debug_port = 543;
+ else
+ debug_port = ent->s_port;
+ }
+ }
+ if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
+ fprintf(stderr, "Error in socket: %s\n", strerror(errno));
+ exit(2);
+ }
+ memset((char *) &sock_in, 0,sizeof(sock_in));
+ sock_in.sin_family = AF_INET;
+ sock_in.sin_port = htons(debug_port);
+ sock_in.sin_addr.s_addr = INADDR_ANY;
+
+ if (!do_fork)
+ (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on));
+
+ if ((bind(s, (struct sockaddr *) &sock_in, sizeof(sock_in))) < 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 (do_fork) {
+ if (daemon(0, 0)) {
+ fprintf(stderr, "daemon() failed\n");
+ exit(2);
+ }
+ while (1) {
+ int child_pid;
+
+ fd = accept(s, (struct sockaddr *) &from, &fromlen);
+ if (s < 0) {
+ if (errno != EINTR)
+ syslog(LOG_ERR, "accept: %s", error_message(errno));
+ continue;
+ }
+ child_pid = fork();
+ switch (child_pid) {
+ case -1:
+ syslog(LOG_ERR, "fork: %s", error_message(errno));
+ case 0:
+ (void) close(s);
+ doit(fd, (struct sockaddr *) &from);
+ close(fd);
+ exit(0);
+ default:
+ wait(0);
+ close(fd);
+ }
+ }
+ }
+
+ if ((fd = accept(s, (struct sockaddr *) &from, &fromlen)) < 0) {
+ fprintf(stderr, "Error in accept: %s\n", strerror(errno));
+ exit(2);
+ }
+
+ close(s);
+ } else { /* !do_fork && !debug_port */
+ if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ syslog(LOG_ERR,"Can't get peer name of remote host: %m");
#ifdef STDERR_FILENO
- fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
+ fatal(STDERR_FILENO, "Can't get peer name of remote host");
#else
- fatal(3, "Can't get peer name of remote host", 1);
+ fatal(2, "Can't get peer name of remote host");
#endif
- }
- fd = 0;
- }
+ }
+ fd = 0;
+ }
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
- syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
-
- doit(fd, &from);
+ doit(fd, (struct sockaddr *) &from);
+ return 0;
}
int pid; /* child process id */
void doit(f, fromp)
- int f;
- struct sockaddr_in *fromp;
+ int f;
+ struct sockaddr *fromp;
{
- int i, p, t, vfd, on = 1;
- register struct hostent *hp;
+ int p, t, on = 1;
char c;
+ char hname[NI_MAXHOST];
char buferror[255];
struct passwd *pwd;
#ifdef POSIX_SIGNALS
struct sigaction sa;
#endif
-
+ int retval;
+ char *rhost_sane;
+ int syncpipe[2];
+
netf = -1;
+ if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE,
+ (const char *) &on, sizeof (on)) < 0)
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ if (auth_ok == 0) {
+ syslog(LOG_CRIT, "No authentication systems were enabled; all connections will be refused.");
+ fatal(f, "All authentication systems disabled; connection refused.");
+ }
+
+ if (checksum_required&&checksum_ignored) {
+ syslog( LOG_CRIT, "Checksums are required and ignored; these options are mutually exclusive--check the documentation.");
+ fatal(f, "Configuration error: mutually exclusive options specified");
+ }
+
alarm(60);
read(f, &c, 1);
}
alarm(0);
+ /* Initialize syncpipe */
+ if (pipe( syncpipe ) < 0 )
+ fatalperror ( f , "");
+
#ifdef POSIX_SIGNALS
/* Initialize "sa" structure. */
sa.sa_flags = 0;
#endif
- fromp->sin_port = ntohs((u_short)fromp->sin_port);
- hp = gethostbyaddr((char *) &fromp->sin_addr, sizeof (struct in_addr),
- fromp->sin_family);
- if (hp == 0) {
- /*
- * Only the name is used below.
- */
- sprintf(rhost_name,"%s",inet_ntoa(fromp->sin_addr));
- }
-
- /* Save hostent information.... */
- else strcpy(rhost_name,hp->h_name);
+ retval = getnameinfo(fromp, socklen(fromp), hname, sizeof(hname), 0, 0,
+ NI_NUMERICHOST);
+ if (retval)
+ fatal(f, gai_strerror(retval));
+ strncpy(rhost_addra, hname, sizeof(rhost_addra));
+ rhost_addra[sizeof (rhost_addra) -1] = '\0';
+ retval = getnameinfo(fromp, socklen(fromp), hname, sizeof(hname), 0, 0, 0);
+ if (retval)
+ fatal(f, gai_strerror(retval));
+ strncpy(rhost_name, hname, sizeof(rhost_name));
+ rhost_name[sizeof (rhost_name) - 1] = '\0';
+
+#ifndef KERBEROS
if (fromp->sin_family != AF_INET)
+ /* Not a real problem, we just haven't bothered to update
+ the port number checking code to handle ipv6. */
fatal(f, "Permission denied - Malformed from address\n");
-#ifdef KERBEROS
- if (must_pass_k5 || must_pass_one) {
- /* setup des buffers */
- desinbuf.data = des_inbuf;
- desoutbuf.data = des_outbuf; /* Set up des buffers */
- }
- /* Must come from privileged port when .rhosts is being looked into */
- if ((must_pass_rhosts || must_pass_one)
- && (fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2))
- non_privileged = 1;
-#else /* !KERBEROS */
if (fromp->sin_port >= IPPORT_RESERVED ||
fromp->sin_port < IPPORT_RESERVED/2)
fatal(f, "Permission denied - Connection from bad port");
#if defined(KERBEROS)
/* All validation, and authorization goes through do_krb_login() */
- do_krb_login(rhost_name);
+ do_krb_login(rhost_addra, rhost_name);
#else
getstr(f, rusername, sizeof(rusername), "remuser");
getstr(f, lusername, sizeof(lusername), "locuser");
getstr(f, term, sizeof(term), "Terminal type");
+ rcmd_stream_init_normal();
#endif
write(f, "", 1);
- if (getpty(&p,line))
- fatal(f, "Out of ptys");
+ if ((retval = pty_getpty(&p,line, sizeof(line)))) {
+ com_err(progname, retval, "while getting master pty");
+ exit(2);
+ }
+
Pfd = p;
#ifdef TIOCSWINSZ
(void) ioctl(p, TIOCSWINSZ, &win);
#endif
-#ifdef VHANG_FIRST
- vfd = open(line, O_RDWR);
- if (vfd < 0)
- fatalperror(f, line);
-#ifdef NOFCHMOD
- if (chmod(line, 0))
- fatalperror(f, line);
-#else
- if (fchmod(vfd, 0))
- fatalperror(f, line);
-#endif
- if (f == 0) { /* if operating standalone, do not reset tty!! */
-#ifdef POSIX_SIGNALS
- sa.sa_handler = SIG_IGN;
- (void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
- vhangup();
- sa.sa_handler = SIG_DFL;
- (void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
-#else
- signal(SIGHUP, SIG_IGN);
- vhangup();
- signal(SIGHUP, SIG_DFL);
-#endif
- }
-#endif /* VHANG_FIRST */
-
-#ifdef TIOCNOTTY
- {
- int con_fd;
- /* Void tty association first */
- if ((con_fd = open("/dev/tty", O_RDWR)) >= 0) {
- ioctl(con_fd, TIOCNOTTY, 0);
- close(con_fd);
- }
- }
-#endif
-
-#ifdef HAVE_SETSID
- (void) setsid();
-#endif
-
-#ifdef ultrix
- /* The Ultrix (and other BSD tty drivers) require the process group
- * to be zero, in order to acquire the new tty as a controlling tty. */
- (void) setpgrp(0, 0);
-#endif
-
- t = open(line, O_RDWR);
- if (t < 0)
- fatalperror(f, line);
-
-#ifdef ultrix
- setpgrp(0, getpid());
-#endif
-
-#if defined(VHANG_FIRST) && !defined(VHANG_NO_CLOSE)
- (void) close(vfd);
-#endif
-
-#ifdef TIOCSCTTY
- if(ioctl(t, TIOCSCTTY, 0) < 0) /* set controlling tty */
- fatalperror(f, "setting controlling tty");
-#endif
-
#ifdef POSIX_SIGNALS
sa.sa_handler = cleanup;
(void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
#else
struct sgttyb b;
#endif /* POSIX_TERMIOS */
-
-#ifdef HAVE_STREAMS
-#ifdef HAVE_LINE_PUSH
- while (ioctl (t, I_POP, 0) == 0); /*Clear out any old lined's*/
- if (line_push(t) < 0)
- fatalperror(f, "IPUSH");
-#else
-#ifdef sun
- while (ioctl (t, I_POP, 0) == 0); /*Clear out any old lined's*/
- if (ioctl(t, I_PUSH, "ptem") < 0)
- fatalperror(f, "IPUSH-ptem");
- if (ioctl(t, I_PUSH, "ldterm") < 0)
- fatalperror(f, "IPUSH-ldterm");
- if (ioctl(t, I_PUSH, "ttcompat") < 0)
- fatalperror(f, "IPUSH-ttcompat");
-#endif /* sun */
-#endif /* HAVE_LINE_PUSH */
-#endif /* HAVE_STREAMS */
+ if ((retval = pty_open_slave(line, &t))) {
+ fatal(f, error_message(retval));
+ exit(1);
+ }
- /*
- * Under Ultrix 3.0, the pgrp of the slave pty terminal
- * needs to be set explicitly. Why rlogind works at all
- * without this on 4.3BSD is a mystery.
- */
- close(f), close(p);
- dup2(t, 0), dup2(t, 1), dup2(t, 2);
- if (t > 2)
- close(t);
-
-#ifdef GETPGRP_ONEARG
- pid = getpgrp(getpid());
-#else
- pid = getpgrp();
-#endif
-
-#ifdef TIOCSPGRP
- ioctl(0, TIOCSPGRP, &pid);
-#endif
#if defined(POSIX_TERMIOS) && !defined(ultrix)
- tcsetpgrp(0, pid);
- tcgetattr(0,&new_termio);
- new_termio.c_lflag &= ~(ICANON|ECHO|ISIG);
- /* so that login can read the authenticator */
- new_termio.c_iflag &= ~(IXON|IXANY|BRKINT|INLCR|ICRNL|ISTRIP);
+ tcgetattr(t,&new_termio);
+#if !defined(USE_LOGIN_F)
+ new_termio.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN);
+ new_termio.c_iflag &= ~(IXON|IXANY|BRKINT|INLCR|ICRNL);
+#else
+ new_termio.c_lflag |= (ICANON|ECHO|ISIG|IEXTEN);
+ new_termio.c_oflag |= (ONLCR|OPOST);
+ new_termio.c_iflag |= (IXON|IXANY|BRKINT|INLCR|ICRNL);
+#endif /*Do we need binary stream?*/
+ new_termio.c_iflag &= ~(ISTRIP);
/* new_termio.c_iflag = 0; */
/* new_termio.c_oflag = 0; */
new_termio.c_cc[VMIN] = 1;
new_termio.c_cc[VTIME] = 0;
- tcsetattr(0,TCSANOW,&new_termio);
+ tcsetattr(t,TCSANOW,&new_termio);
#else
- (void)ioctl(0, TIOCGETP, &b);
+ (void)ioctl(t, TIOCGETP, &b);
b.sg_flags = RAW|ANYP;
- (void)ioctl(0, TIOCSETP, &b);
+ (void)ioctl(t, TIOCSETP, &b);
#endif /* POSIX_TERMIOS */
pid = 0; /*reset pid incase exec fails*/
** and we don't get the right tty affiliation, and
** other kinds of hell breaks loose ...
*/
- (void) write(1, &c, 1);
+ (void) write(syncpipe[1], &c, 1);
+ (void) close(syncpipe[1]);
+ (void) close(syncpipe[0]);
+
+ close(f), close(p);
+ dup2(t, 0), dup2(t, 1), dup2(t, 2);
+ if (t > 2)
+ close(t);
#if defined(sysvimp)
setcompat (COMPAT_CLRPGROUP | (getcompat() & ~COMPAT_BSDTTY));
pwd = (struct passwd *) getpwnam(lusername);
if (pwd && (pwd->pw_uid == 0)) {
if (passwd_req)
- syslog(LOG_NOTICE, "ROOT login by %s (%s@%s) forcing password access",
- krusername ? krusername : "", rusername, rhost_name);
+ syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s)) forcing password access",
+ krusername ? krusername : "",
+ rusername, rhost_addra, rhost_name);
else
- syslog(LOG_NOTICE, "ROOT login by %s (%s@%s) ",
- krusername ? krusername : "", rusername, rhost_name);
+ syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s))",
+ krusername ? krusername : "",
+ rusername, rhost_addra, rhost_name);
}
#ifdef KERBEROS
#if defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
{
if (passwd_req)
syslog(LOG_NOTICE,
- "login by %s (%s@%s) as %s forcing password access\n",
+ "login by %s (%s@%s (%s)) as %s forcing password access",
krusername ? krusername : "", rusername,
- rhost_name, lusername);
+ rhost_addra, rhost_name, lusername);
else
syslog(LOG_NOTICE,
- "login by %s (%s@%s) as %s\n",
+ "login by %s (%s@%s (%s)) as %s",
krusername ? krusername : "", rusername,
- rhost_name, lusername);
+ rhost_addra, rhost_name, lusername);
}
#endif /* LOG_REMOTE_REALM || LOG_OTHER_USERS || LOG_ALL_LOGINS */
#endif /* KERBEROS */
#ifndef NO_UT_PID
{
- struct utmp ent;
- ent.ut_pid = getpid();
- ent.ut_type = LOGIN_PROCESS;
- update_utmp(&ent, "rlogin", line, ""/*host*/);
+ pty_update_utmp(PTY_LOGIN_PROCESS, getpid(), "rlogin", line,
+ ""/*host*/, PTY_TTYSLOT_USABLE);
}
#endif
-#ifdef DO_NOT_USE_K_LOGIN
- execl(login_program, "login", "-r", rhost_name, 0);
-#else
- if (passwd_req)
- execl(login_program, "login","-h", rhost_name, lusername, 0);
- else
- execl(login_program, "login", "-h", rhost_name, "-e", lusername, 0);
-#endif
-
- fatalperror(2, login_program);
+#ifdef USE_LOGIN_F
+/* use the vendors login, which has -p and -f. Tested on
+ * AIX 4.1.4 and HPUX 10
+ */
+ {
+ char *cp;
+ if ((cp = strchr(term,'/')))
+ *cp = '\0';
+ setenv("TERM",term, 1);
+ }
+
+ retval = pty_make_sane_hostname((struct sockaddr *) fromp, maxhostlen,
+ stripdomain, always_ip,
+ &rhost_sane);
+ if (retval)
+ fatalperror(f, "failed make_sane_hostname");
+ if (passwd_req)
+ execl(login_program, "login", "-p", "-h", rhost_sane,
+ lusername, 0);
+ else
+ execl(login_program, "login", "-p", "-h", rhost_sane,
+ "-f", lusername, 0);
+#else /* USE_LOGIN_F */
+ execl(login_program, "login", "-r", rhost_sane, 0);
+#endif /* USE_LOGIN_F */
+ syslog(LOG_ERR, "failed exec of %s: %s",
+ login_program, error_message(errno));
+ fatalperror(f, login_program);
/*NOTREACHED*/
} /* if (pid == 0) */
** turning off echo on the slave side ...
** The master blocks here until it reads a byte.
*/
- close(t);
- if (read(p, &c, 1) != 1) {
+
+(void) close(syncpipe[1]);
+ if (read(syncpipe[0], &c, 1) != 1) {
/*
* Problems read failed ...
*/
sprintf(buferror, "Cannot read slave pty %s ",line);
fatalperror(p,buferror);
}
+ close(syncpipe[0]);
+
#if defined(KERBEROS)
if (do_encrypt) {
- if (((*des_write)(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE))) < 0){
+ if (rcmd_stream_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE), 0) < 0){
sprintf(buferror, "Cannot encrypt-write network.");
fatal(p,buferror);
}
/* FIONBIO doesn't always work on ptys, use fcntl to set O_NDELAY? */
(void) fcntl(p,F_SETFL,fcntl(p,F_GETFL,0) | O_NDELAY);
-/*** XXX -- make this portable ***/
-#if defined(TIOCPKT) && !defined(__svr4__) || defined(solaris20)
- ioctl(p, TIOCPKT, &on);
-#endif
-
#ifdef POSIX_SIGNALS
sa.sa_handler = SIG_IGN;
(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
signal(SIGTSTP, SIG_IGN);
#endif
-#ifdef hpux
- setpgrp2(0, 0);
-#else
- setpgrp(0, 0);
-#endif
-#ifdef DO_NOT_USE_K_LOGIN
+#if !defined(USE_LOGIN_F)
/* Pass down rusername and lusername to login. */
(void) write(p, rusername, strlen(rusername) +1);
(void) write(p, lusername, strlen(lusername) +1);
-#endif
/* stuff term info down to login */
- if( write(p, term, strlen(term)+1) != strlen(term)+1 ){
+ if ((write(p, term, strlen(term)+1) != (int) strlen(term)+1)) {
/*
* Problems write failed ...
*/
sprintf(buferror,"Cannot write slave pty %s ",line);
fatalperror(f,buferror);
}
+
+#endif
protocol(f, p);
signal(SIGCHLD, SIG_IGN);
- cleanup();
+ cleanup(0);
}
unsigned char magic[2] = { 0377, 0377 };
char oobdata[] = {0};
#endif
+static
+void sendoob(fd, byte)
+ int fd;
+ char *byte;
+{
+ char message[5];
+ int cc;
+
+ if (do_inband) {
+ message[0] = '\377';
+ message[1] = '\377';
+ message[2] = 'o';
+ message[3] = 'o';
+ message[4] = *byte;
+
+ cc = rcmd_stream_write(fd, message, sizeof(message), 0);
+ while (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ /* also shouldn't happen */
+ sleep(5);
+ cc = rcmd_stream_write(fd, message, sizeof(message), 0);
+ }
+ } else {
+ send(fd, byte, 1, MSG_OOB);
+ }
+}
+
/*
* Handle a "control" request (signaled by magic being present)
* in the data stream. For now, we are only willing to handle
* window size changes.
*/
-control(pty, cp, n)
+static int control(pty, cp, n)
int pty;
unsigned char *cp;
int n;
{
struct winsize w;
- int pgrp;
+ int pgrp, got_pgrp;
- if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
+ if (n < (int) 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
return (0);
#ifdef TIOCSWINSZ
oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
w.ws_xpixel = ntohs(w.ws_xpixel);
w.ws_ypixel = ntohs(w.ws_ypixel);
(void)ioctl(pty, TIOCSWINSZ, &w);
- if (ioctl(pty, TIOCGPGRP, &pgrp) >= 0)
+#ifdef HAVE_TCGETPGRP
+ pgrp = tcgetpgrp (pty);
+ got_pgrp = pgrp != -1;
+#else
+ got_pgrp = ioctl(pty, TIOCGPGRP, &pgrp) >= 0;
+#endif
+ if (got_pgrp)
(void) killpg(pgrp, SIGWINCH);
#endif
return (4+sizeof (w));
/*
* rlogin "protocol" machine.
*/
-protocol(f, p)
+void protocol(f, p)
int f, p;
{
- unsigned char pibuf[1024], fibuf[1024], *pbp, *fbp;
- register pcc = 0, fcc = 0;
+ unsigned char pibuf[BUFSIZ], qpibuf[BUFSIZ*2], fibuf[BUFSIZ], *pbp=0, *fbp=0;
+ register int pcc = 0, fcc = 0;
int cc;
- char cntl;
#ifdef POSIX_SIGNALS
struct sigaction sa;
#endif
+#ifdef TIOCPKT
+ register int tiocpkt_on = 0;
+ int on = 1;
+#endif
+#if defined(TIOCPKT) && !(defined(__svr4__) || defined(HAVE_STREAMS)) \
+ || defined(solaris20)
+ /* if system has TIOCPKT, try to turn it on. Some drivers
+ * may not support it. Save flag for later.
+ */
+ if ( ioctl(p, TIOCPKT, &on) < 0)
+ tiocpkt_on = 0;
+ else tiocpkt_on = 1;
+#endif
+
/*
* Must ignore SIGTTOU, otherwise we'll stop
* when we try and set slave pty's window shape
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef TIOCSWINSZ
- send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
+ sendoob(f, oobdata);
#endif
for (;;) {
fd_set ibits, obits, ebits;
FD_SET(p, &obits);
else
FD_SET(f, &ibits);
- if (pcc >= 0)
- if (pcc)
+ if (pcc >= 0) {
+ if (pcc) {
FD_SET(f, &obits);
- else
+ } else {
FD_SET(p, &ibits);
- FD_SET(p, &ebits);
-
+ }
+ }
+
if (select(8*sizeof(ibits), &ibits, &obits, &ebits, 0) < 0) {
if (errno == EINTR)
continue;
fatalperror(f, "select");
}
#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
- if (FD_ISSET(p, &ebits)) {
- cc = read(p, &cntl, 1);
- if (cc == 1 && pkcontrol(cntl)) {
- cntl |= oobdata[0];
- send(f, &cntl, 1, MSG_OOB);
- if (cntl & TIOCPKT_FLUSHWRITE) {
- pcc = 0;
- FD_CLR(p, &ibits);
- }
- }
- }
if (FD_ISSET(f, &ibits)) {
- fcc = (*des_read)(f, fibuf, sizeof (fibuf));
- if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
- fcc = 0;
- else {
+ fcc = rcmd_stream_read(f, fibuf, sizeof (fibuf), 0);
+ if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
+ fcc = 0;
+ } else {
register unsigned char *cp;
- int left, n;
+ int n;
+ size_t left;
if (fcc <= 0)
- break;
+ break;
fbp = fibuf;
- top:
- for (cp = fibuf; cp < fibuf+fcc-1; cp++)
- if (cp[0] == magic[0] &&
- cp[1] == magic[1]) {
- left = fcc - (cp-fibuf);
- n = control(p, cp, left);
- if (n) {
- left -= n;
- if (left > 0)
- memmove(cp, cp+n, left);
- fcc -= n;
- goto top; /* n^2 */
- }
- }
+ for (cp = fibuf; cp < fibuf+fcc-1; cp++) {
+ if (cp[0] == magic[0] &&
+ cp[1] == magic[1]) {
+ left = (fibuf+fcc) - cp;
+ n = control(p, cp, left);
+ if (n) {
+ left -= n;
+ fcc -= n;
+ if (left > 0)
+ memmove(cp, cp+n, left);
+ cp--;
+ }
+ }
+ }
}
}
if (FD_ISSET(p, &ibits)) {
pcc = read(p, pibuf, sizeof (pibuf));
pbp = pibuf;
- if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
- pcc = 0;
- else if (pcc <= 0)
- break;
- else if (pibuf[0] == 0)
- pbp++, pcc--;
-#ifndef sun
- else {
- if (pkcontrol(pibuf[0])) {
- pibuf[0] |= oobdata[0];
- send(f, &pibuf[0], 1, MSG_OOB);
- }
+ if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
pcc = 0;
+ } else if (pcc <= 0) {
+ break;
+ }
+#ifdef TIOCPKT
+ else if (tiocpkt_on) {
+ if (pibuf[0] == 0) {
+ pbp++, pcc--;
+ } else {
+ if (pkcontrol(pibuf[0])) {
+ pibuf[0] |= oobdata[0];
+ sendoob(f, pibuf);
+ }
+ pcc = 0;
+ }
}
#endif
+
+ /* quote any double-\377's if necessary */
+
+ if (do_inband) {
+ unsigned char *qpbp;
+ int qpcc, i;
+
+ qpbp = qpibuf;
+ qpcc = 0;
+
+ for (i=0; i<pcc;) {
+ if (pbp[i] == 0377u && (i+1)<pcc && pbp[i+1] == 0377u) {
+ qpbp[qpcc] = '\377';
+ qpbp[qpcc+1] = '\377';
+ qpbp[qpcc+2] = 'q';
+ qpbp[qpcc+3] = 'q';
+ i += 2;
+ qpcc += 4;
+ } else {
+ qpbp[qpcc] = pbp[i];
+ i++;
+ qpcc++;
+ }
+ }
+
+ pbp = qpbp;
+ pcc = qpcc;
+ }
}
+
if (FD_ISSET(f, &obits) && pcc > 0) {
- cc = (*des_write)(f, pbp, pcc);
+ cc = rcmd_stream_write(f, pbp, pcc, 0);
if (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
/* also shouldn't happen */
sleep(5);
-krb5_sigtype cleanup()
+krb5_sigtype cleanup(signumber)
+ int signumber;
{
- struct utmp ut;
-
-#ifndef NO_UT_PID
- ut.ut_pid = 0;
- ut.ut_type = DEAD_PROCESS;
-#endif
- update_utmp(&ut, "", line, (char *)0);
-
- (void)chmod(line, 0666);
- (void)chown(line, 0, 0);
-#ifndef HAVE_STREAMS
- line[strlen("/dev/")] = 'p';
- (void)chmod(line, 0666);
- (void)chown(line, 0, 0);
-#endif
-#ifdef VHANG_LAST
- close(Pfd);
- vhangup();
-#endif
+ pty_cleanup (line, pid, 1);
shutdown(netf, 2);
+ if (ccache)
+ krb5_cc_destroy(bsd_context, ccache);
exit(1);
}
void fatal(f, msg)
int f;
- char *msg;
+ const char *msg;
{
char buf[512];
int out = 1 ; /* Output queue of f */
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, TCFLSH, out);
#endif
- cleanup();
+ cleanup(0);
}
exit(1);
}
void fatalperror(f, msg)
int f;
- char *msg;
+ const char *msg;
{
char buf[512];
- extern int sys_nerr;
- extern char *sys_errlist[];
- if ((unsigned)errno < sys_nerr)
- (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
- else
- (void) sprintf(buf, "%s: Error %d", msg, errno);
+ (void) sprintf(buf, "%s: %s", msg, error_message(errno));
fatal(f, buf);
}
#ifdef KERBEROS
void
-do_krb_login(host)
- char *host;
+do_krb_login(host_addr, hostname)
+ char *host_addr, *hostname;
{
krb5_error_code status;
- struct passwd *pwd;
- int passed_krb, passed_rhosts;
- char *msg_fail;
-
- passed_krb = passed_rhosts = 0;
+ char *msg_fail = NULL;
+ int valid_checksum;
if (getuid()) {
exit(1);
/* Check authentication. This can be either Kerberos V5, */
/* Kerberos V4, or host-based. */
- if (status = recvauth()) {
+ if ((status = recvauth(&valid_checksum))) {
if (ticket)
krb5_free_ticket(bsd_context, ticket);
if (status != 255)
syslog(LOG_ERR,
- "Authentication failed from %s: %s\n",
- host,error_message(status));
+ "Authentication failed from %s (%s): %s\n",host_addr,
+ hostname,error_message(status));
fatal(netf, "Kerberos authentication failed");
return;
}
}
#endif
- if (must_pass_k5 || must_pass_one) {
+
#if (defined(ALWAYS_V5_KUSEROK) || !defined(KRB5_KRB4_COMPAT))
/* krb5_kuserok returns 1 if OK */
if (client && krb5_kuserok(bsd_context, client, lusername))
- passed_krb++;
+ auth_sent |= ((auth_sys == KRB5_RECVAUTH_V4)?AUTH_KRB4:AUTH_KRB5);
#else
if (auth_sys == KRB5_RECVAUTH_V4) {
/* kuserok returns 0 if OK */
if (!kuserok(v4_kdata, lusername))
- passed_krb++;
+ auth_sent |= AUTH_KRB4;
} else {
/* krb5_kuserok returns 1 if OK */
if (client && krb5_kuserok(bsd_context, client, lusername))
- passed_krb++;
+ auth_sent |= AUTH_KRB5;
}
#endif
- }
-
- /* The kerberos authenticated request must pass ruserok also
- if asked for. */
+
- if (!must_pass_k5 &&
- (must_pass_rhosts || (!passed_krb && must_pass_one))) {
- /* Cannot check .rhosts unless connection from a privileged port. */
- if (non_privileged)
- fatal(netf, "Permission denied - Connection from bad port");
- pwd = (struct passwd *) getpwnam(lusername);
- if (pwd &&
- !ruserok(rhost_name, pwd->pw_uid == 0, rusername, lusername))
- passed_rhosts++;
+ if (checksum_required && !valid_checksum) {
+ if (auth_sent & AUTH_KRB5) {
+ syslog(LOG_WARNING, "Client did not supply required checksum--connection rejected.");
+
+ fatal(netf, "You are using an old Kerberos5 without initial connection support; only newer clients are authorized.");
+ } else {
+ syslog(LOG_WARNING,
+ "Configuration error: Requiring checksums with -c is inconsistent with allowing Kerberos V4 connections.");
+ }
}
-
- if ((must_pass_k5 && passed_krb) ||
- (must_pass_rhosts && passed_rhosts) ||
- (must_pass_one && (passed_krb || passed_rhosts)))
- return;
+ if (auth_ok&auth_sent) /* This should be bitwise.*/
+ return;
if (ticket)
krb5_free_ticket(bsd_context, ticket);
- msg_fail = (char *) malloc( strlen(krusername) + strlen(lusername) + 80 );
+ if (krusername)
+ msg_fail = (char *)malloc(strlen(krusername) + strlen(lusername) + 80);
if (!msg_fail)
fatal(netf, "User is not authorized to login to specified account");
- sprintf(msg_fail, "User %s is not authorized to login to account %s",
- krusername, lusername);
+
+ if (auth_sent)
+ sprintf(msg_fail, "Access denied because of improper credentials");
+ else
+ sprintf(msg_fail, "User %s is not authorized to login to account %s",
+ krusername, lusername);
+
fatal(netf, msg_fail);
/* NOTREACHED */
}
+#endif /* KERBEROS */
+
-getstr(fd, buf, cnt, err)
+void getstr(fd, buf, cnt, err)
int fd;
char *buf;
int cnt;
-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 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 =
- (((krb5_ui_4)len_buf[0]<<24) |
- ((krb5_ui_4)len_buf[1]<<16) |
- ((krb5_ui_4)len_buf[2]<<8) |
- (krb5_ui_4)len_buf[3]);
-#else
- {
- unsigned char c;
- int gotzero = 0;
-
- /* See the comment in v4_des_read. */
- do {
- cc = krb5_net_read(bsd_context, fd, &c, 1);
- /* we should check for non-blocking here, but we'd have
- to make it save partial reads as well. */
- if (cc < 0) return 0; /* read error */
- if (cc == 1) {
- if (c == 0) gotzero = 1;
- }
- } while (!gotzero);
-
- if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
- rd_len = c;
- if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
- rd_len = (rd_len << 8) | c;
- if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
- rd_len = (rd_len << 8) | c;
- }
-#endif
- 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.");
- 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++;
- sleep(1);
- if (retry > MAXRETRIES){
- syslog(LOG_ERR,
- "des_read retry count exceeded %d\n",
- retry);
- return(0);
- }
- 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.");
- 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);
-}
-#endif /* KERBEROS */
-
-
-
-getpty(fd,slave)
- int *fd;
- char *slave;
-{
- char c;
- char *p;
- int i,ptynum;
- struct stat stb;
-
-#ifdef HAVE_OPENPTY
- int slavefd;
-
- if(openpty(fd, &slavefd, slave, (struct termios *) 0,
- (struct winsize *) 0)) return 1;
- return 0;
-#else
-
- *fd = open("/dev/ptmx", O_RDWR|O_NDELAY); /* Solaris, IRIX */
- if (*fd < 0) *fd = open("/dev/ptc", O_RDWR|O_NDELAY); /* AIX */
- if (*fd < 0) *fd = open("/dev/pty", O_RDWR|O_NDELAY); /* sysvimp */
-
- if (*fd >= 0) {
-
-#ifdef HAVE_GRANTPT
- if (grantpt(*fd) || unlockpt(*fd)) return 1;
-#endif
-
-#ifdef HAVE_TTYNAME
- p = ttyname(*fd);
-#else
-#ifdef HAVE_PTSNAME
- p = ptsname(*fd);
-#else
- /* XXX If we don't have either what do we do */
-#endif
-#endif
- if (p) {
- strcpy(slave, p);
- return 0;
- }
-
- if (fstat(*fd, &stb) < 0) {
- close(*fd);
- return 1;
- }
- ptynum = (int)(stb.st_rdev&0xFF);
- sprintf(slave, "/dev/ttyp%x", ptynum);
- return 0;
-
- } else {
-
- for (c = 'p'; c <= 's'; c++) {
- sprintf(slave,"/dev/ptyXX");
- slave[strlen("/dev/pty")] = c;
- slave[strlen("/dev/ptyp")] = '0';
- if (stat(slave, &stb) < 0)
- break;
- for (i = 0; i < 16; i++) {
- slave[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
- *fd = open(slave, O_RDWR);
- if (*fd < 0) continue;
-
- /* got pty */
- slave[strlen("/dev/")] = 't';
- return 0;
- }
- }
- return 1;
- }
-#endif /* HAVE_OPENPTY */
-}
-
-
-
void usage()
{
#ifdef KERBEROS
syslog(LOG_ERR,
- "usage: klogind [-rRkKxpP] [-D port] or [r/R][k/K][x/e][p/P]logind");
+ "usage: klogind [-ke45pPf] [-D port] [-w[ip|maxhostlen[,[no]striplocal]]] or [r/R][k/K][x/e][p/P]logind");
#else
syslog(LOG_ERR,
- "usage: rlogind [-rRpP] [-D port] or [r/R][p/P]logind");
+ "usage: rlogind [-rpPf] [-D port] or [r/R][p/P]logind");
#endif
}
#ifdef KERBEROS
-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;
-}
-
#ifndef KRB_SENDAUTH_VLEN
#define KRB_SENDAUTH_VLEN 8 /* length for version strings */
chars */
krb5_error_code
-recvauth()
+recvauth(valid_checksum)
+ int *valid_checksum;
{
krb5_auth_context auth_context = NULL;
krb5_error_code status;
- struct sockaddr_in peersin, laddr;
- char krb_vers[KRB_SENDAUTH_VLEN + 1];
- int len;
- krb5_principal server;
+ struct sockaddr_storage peersin, laddr;
+ socklen_t len;
krb5_data inbuf;
+#ifdef KRB5_KRB4_COMPAT
char v4_instance[INST_SZ]; /* V4 Instance */
- char v4_version[9];
+#endif
+ krb5_data version;
+ krb5_authenticator *authenticator;
+ krb5_rcache rcache;
+ enum kcmd_proto kcmd_proto;
+ krb5_keyblock *key;
+ *valid_checksum = 0;
len = sizeof(laddr);
if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
exit(1);
exit(1);
}
- 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
- if (status = krb5_auth_con_init(bsd_context, &auth_context))
+ if ((status = krb5_auth_con_init(bsd_context, &auth_context)))
return status;
/* Only need remote address for rd_cred() to verify client */
- if (status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
- KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))
+ if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
+ KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
return status;
- if (status = krb5_compat_recvauth(bsd_context, &auth_context, &netf,
- "KCMDV0.1",
- server, /* Specify daemon principal */
+ status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
+ if (status) return status;
+
+ 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,
+ &netf,
+ NULL, /* Specify daemon principal */
0, /* no flags */
keytab, /* normally NULL to use v5srvtab */
do_encrypt ? KOPT_DO_MUTUAL : 0, /*v4_opts*/
"rcmd", /* v4_service */
v4_instance, /* v4_instance */
- &peersin, /* foriegn address */
- &laddr, /* our local address */
+ ss2sin(&peersin), /* foriegn address */
+ ss2sin(&laddr), /* our local address */
"", /* use default srvtab */
&ticket, /* return ticket */
&auth_sys, /* which authentication system*/
- &v4_kdata, v4_schedule, v4_version)) {
-
+ &v4_kdata, v4_schedule,
+ &version);
+#else
+ auth_sys = KRB5_RECVAUTH_V5;
+ status = krb5_recvauth_version(bsd_context, &auth_context, &netf,
+ NULL, 0, keytab, &ticket, &version);
+#endif
+ if (status) {
if (auth_sys == KRB5_RECVAUTH_V5) {
/*
* clean up before exiting
getstr(netf, lusername, sizeof (lusername), "locuser");
getstr(netf, term, sizeof(term), "Terminal type");
+ kcmd_proto = KCMD_UNKNOWN_PROTOCOL;
+ if (auth_sys == KRB5_RECVAUTH_V5) {
+ if (version.length != 9) {
+ fatal (netf, "bad application version length");
+ }
+ if (!memcmp (version.data, "KCMDV0.1", 9))
+ kcmd_proto = KCMD_OLD_PROTOCOL;
+ else if (!memcmp (version.data, "KCMDV0.2", 9))
+ kcmd_proto = KCMD_NEW_PROTOCOL;
+ }
+#ifdef KRB5_KRB4_COMPAT
+ if (auth_sys == KRB5_RECVAUTH_V4)
+ kcmd_proto = KCMD_V4_PROTOCOL;
+#endif
+
+ if ((auth_sys == KRB5_RECVAUTH_V5)
+ && !(checksum_ignored
+ && kcmd_proto == KCMD_OLD_PROTOCOL)) {
+
+ if ((status = krb5_auth_con_getauthenticator(bsd_context, auth_context,
+ &authenticator)))
+ return status;
+
+ if (authenticator->checksum) {
+ struct sockaddr_in adr;
+ socklen_t adr_length = sizeof(adr);
+ char * chksumbuf = (char *) malloc(strlen(term)+strlen(lusername)+32);
+ if (getsockname(netf, (struct sockaddr *) &adr, &adr_length) != 0)
+ goto error_cleanup;
+ if (chksumbuf == 0)
+ goto error_cleanup;
+
+ sprintf(chksumbuf,"%u:", ntohs(adr.sin_port));
+ strcat(chksumbuf,term);
+ strcat(chksumbuf,lusername);
+
+ 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);
+ }
+
+
#ifdef KRB5_KRB4_COMPAT
if (auth_sys == KRB5_RECVAUTH_V4) {
- des_read = v4_des_read;
- des_write = v4_des_write;
+ rcmd_stream_init_krb4(v4_kdata->session, do_encrypt, 1, 1);
/* 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(rusername, v4_kdata->pname);
- krusername = (char *) malloc(strlen(v4_kdata->pname) + 1 +
- strlen(v4_kdata->pinst) + 1 +
- strlen(v4_kdata->prealm) + 1);
- sprintf(krusername, "%s/%s@%s", v4_kdata->pname,
- v4_kdata->pinst, v4_kdata->prealm);
+ strncpy(rusername, v4_kdata->pname, sizeof(rusername) - 1);
+ rusername[sizeof(rusername) - 1] = '\0';
+
+ 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, &krusername);
- if (status = krb5_parse_name(bsd_context, krusername, &client))
- return(status);
- return 0;
+ return status;
}
#endif
/* Must be V5 */
- if (status = krb5_copy_principal(bsd_context, ticket->enc_part2->client,
- &client))
+ if ((status = krb5_copy_principal(bsd_context, ticket->enc_part2->client,
+ &client)))
return status;
- des_read = v5_des_read;
- des_write = v5_des_write;
+ key = 0;
+ status = krb5_auth_con_getrecvsubkey (bsd_context, auth_context, &key);
+ if (status)
+ fatal (netf, "Server can't get session subkey");
+ if (!key && do_encrypt && kcmd_proto == KCMD_NEW_PROTOCOL)
+ fatal (netf, "No session subkey sent");
+ if (key && kcmd_proto == KCMD_OLD_PROTOCOL) {
+#ifdef HEIMDAL_FRIENDLY
+ key = 0;
+#else
+ fatal (netf, "Session subkey not permitted under old kcmd protocol");
+#endif
+ }
+ if (key == 0)
+ key = ticket->enc_part2->session;
+
+ rcmd_stream_init_krb5 (key, do_encrypt, 1, 0, kcmd_proto);
+
+ do_inband = (kcmd_proto == KCMD_NEW_PROTOCOL);
getstr(netf, rusername, sizeof(rusername), "remuser");
- if (status = krb5_unparse_name(bsd_context, client, &krusername))
+ if ((status = krb5_unparse_name(bsd_context, client, &krusername)))
return status;
- /* Setup up eblock if encrypted login session */
- /* otherwise zero out session key */
- if (do_encrypt) {
- 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 (status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf))
+ if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf)))
fatal(netf, "Error reading message");
if ((inbuf.length) && /* Forwarding being done, read creds */
(status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf,
- ticket, lusername))) {
+ ticket, &ccache))) {
fatal(netf, "Can't get forwarded credentials");
}
return 0;
}
-
-#ifdef KRB5_KRB4_COMPAT
-
-int
-v4_des_read(fd, buf, len)
-int fd;
-register char *buf;
-int len;
-{
- int nreturned = 0;
- krb5_ui_4 net_len, rd_len;
- int cc;
- 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 0
- if ((cc = krb_net_read(fd, (char *)len_buf, 4)) != 4) {
- /* XXX can't read enough, pipe
- must have closed */
- return(0);
- }
- net_len = (((krb5_ui_4)len_buf[0]<<24) |
- ((krb5_ui_4)len_buf[1]<<16) |
- ((krb5_ui_4)len_buf[2]<<8) |
- (krb5_ui_4)len_buf[3]);
-#else
- {
- unsigned char c;
- int gotzero = 0;
-
- /* We're fetching the length which is MSB first, and the MSB
- has to be zero unless the client is sending more than 2^24
- (16M) bytes in a single write (which is why this code is in
- rlogin but not rcp or rsh.) The only reasons we'd get something
- other than zero are:
- -- corruption of the tcp stream (which will show up when
- everything else is out of sync too)
- -- un-caught Berkeley-style "pseudo out-of-band data" which
- happens any time the user hits ^C twice.
- The latter is *very* common, as shown by an 'rlogin -x -d'
- using the CNS V4 rlogin. Mark EIchin 1/95
- */
- do {
- cc = krb_net_read(fd, &c, 1);
- if (cc < 0) return 0; /* read error */
- if (cc == 1) {
- if (c == 0) gotzero = 1;
- }
- } while (!gotzero);
-
- if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
- net_len = c;
- if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
- net_len = (net_len << 8) | c;
- if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
- net_len = (net_len << 8) | c;
- }
-
-#endif
- if (net_len < 0 || net_len > sizeof(des_inbuf)) {
- /* XXX preposterous length, probably out of sync.
- act as if pipe closed */
- return(0);
- }
- /* the writer tells us how much real data we are getting, but
- we need to read the pad bytes (8-byte boundary) */
- rd_len = roundup(net_len, 8);
- if ((cc = krb_net_read(fd, des_inbuf, rd_len)) != rd_len) {
- /* XXX can't read enough, pipe
- must have closed */
- return(0);
- }
- (void) pcbc_encrypt(des_inbuf,
- storage,
- (net_len < 8) ? 8 : net_len,
- v4_schedule,
- v4_kdata->session,
- DECRYPT);
- /*
- * when the cleartext block is < 8 bytes, it is "right-justified"
- * in the block, so we need to adjust the pointer to the data
- */
- if (net_len < 8)
- store_ptr = storage + 8 - net_len;
- else
- store_ptr = storage;
- nstored = net_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
-v4_des_write(fd, buf, len)
-int fd;
-char *buf;
-int len;
-{
- static char garbage_buf[8];
- unsigned char len_buf[4];
-
- if (!do_encrypt)
- return(write(fd, buf, len));
-
- /*
- * pcbc_encrypt outputs in 8-byte (64 bit) increments
- *
- * it zero-fills the cleartext to 8-byte padding,
- * so if we have cleartext of < 8 bytes, we want
- * to insert random garbage before it so that the ciphertext
- * differs for each transmission of the same cleartext.
- * if len < 8 - sizeof(long), sizeof(long) bytes of random
- * garbage should be sufficient; leave the rest as-is in the buffer.
- * if len > 8 - sizeof(long), just garbage fill the rest.
- */
-
-#ifdef min
-#undef min
-#endif
-#define min(a,b) ((a < b) ? a : b)
-
- if (len < 8) {
- krb5_random_confounder(8 - len, garbage_buf);
- /* this "right-justifies" the data in the buffer */
- (void) memcpy(garbage_buf + 8 - len, buf, len);
- }
- (void) pcbc_encrypt((len < 8) ? garbage_buf : buf,
- des_outbuf,
- (len < 8) ? 8 : len,
- v4_schedule,
- v4_kdata->session,
- ENCRYPT);
-
- /* tell the other end the real amount, but send an 8-byte padded
- packet */
- 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);
- (void) write(fd, des_outbuf, roundup(len,8));
- return(len);
-}
-
-#endif /* KRB5_KRB4_COMPAT */
#endif /* KERBEROS */