--- /dev/null
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rcmd.c 5.22 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * 2-14-91 ka
+ * Modified sources to add SPX strong authentication, called fcmd.c
+ *
+ * 5-24-91 ka
+ * Modified sources to remove SPX and Kerberos specific authentication.
+ * Replaced with GSS API
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <errno.h>
+
+#include <syslog.h>
+#include "gssapi_defs.h"
+
+#define START_PORT 5120
+
+#define TOKEN_MAJIC_NUMBER_BYTE0 1
+#define TOKEN_MAJIC_NUMBER_BYTE1 1
+
+extern errno;
+char *index();
+
+fcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, targetname,
+context_handle, mutual_flag, deleg_flag, debugflag)
+ int *sock;
+ char **ahost;
+ int rport;
+ char *locuser, *remuser, *cmd;
+ int *fd2p;
+ char *targetname;
+ int *context_handle;
+ int mutual_flag, deleg_flag, debugflag;
+{
+ int s, timo = 1, pid;
+ long oldmask;
+ struct sockaddr_in sin, sin2, from;
+ char c;
+ int lport = START_PORT;
+ struct hostent *hp;
+ fd_set reads;
+
+ unsigned char token[GSS_C_MAX_TOKEN], chanbinding[8];
+ unsigned char *charp;
+ char tokenheader[4], recv_tokenheader[4];
+ int tokenlen, i, j, status = 0, hostlen, xcc, cc, mutual_len;
+ int chanbinding_len, replay_flag=0, seq_flag=0;
+ char hostname[GSS_C_MAX_PRINTABLE_NAME];
+ char mutual_resp[GSS_C_MAX_TOKEN];
+ char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
+/*
+ * GSS API support
+ */
+ gss_OID_set actual_mechs;
+ gss_OID actual_mech_type, output_name_type;
+ gss_cred_id_t gss_cred_handle;
+ gss_ctx_id_t actual_ctxhandle;
+ int msg_ctx = 0, new_status;
+ int req_flags = 0, ret_flags, lifetime_rec, major_status;
+ gss_buffer_desc output_token, input_token, input_name_buffer;
+ gss_buffer_desc output_name_buffer, status_string;
+ gss_name_t desired_targname;
+ gss_channel_bindings input_chan_bindings;
+
+ pid = getpid();
+ hp = gethostbyname(*ahost);
+ if (hp == 0) {
+ fprintf(stderr, "%s : unknown host\n", *ahost);
+ return (-1);
+ }
+ *ahost = hp->h_name;
+ oldmask = sigblock(sigmask(SIGURG));
+ for (;;) {
+ s = rresvport(&lport);
+ if (s < 0) {
+ if (errno == EAGAIN)
+ fprintf(stderr, "socket: All ports in use\n");
+ else
+ perror("rcmd: socket");
+ sigsetmask(oldmask);
+ return (-1);
+ }
+ fcntl(s, F_SETOWN, pid);
+ sin.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
+ sin.sin_port = rport;
+ if (connect(s, (caddr_t)&sin, sizeof (sin), 0) >= 0)
+ break;
+ (void) close(s);
+ if (errno == EADDRINUSE) {
+ lport--;
+ continue;
+ }
+ if (errno == ECONNREFUSED && timo <= 16) {
+ sleep(timo);
+ timo *= 2;
+ continue;
+ }
+ if (hp->h_addr_list[1] != NULL) {
+ int oerrno = errno;
+
+ fprintf(stderr,
+ "connect to address %s: ", inet_ntoa(sin.sin_addr));
+ errno = oerrno;
+ perror(0);
+ hp->h_addr_list++;
+ bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
+ hp->h_length);
+ fprintf(stderr, "Trying %s...\n",
+ inet_ntoa(sin.sin_addr));
+ continue;
+ }
+ perror(hp->h_name);
+ sigsetmask(oldmask);
+ return (-1);
+ }
+
+ lport--;
+ if (fd2p == 0) {
+ write(s, "", 1);
+ lport = 0;
+ } else {
+ char num[8];
+ int s2 = rresvport(&lport), s3;
+ int len = sizeof (from);
+
+ if (s2 < 0)
+ goto bad;
+ listen(s2, 1);
+ (void) sprintf(num, "%d", lport);
+ if (write(s, num, strlen(num)+1) != strlen(num)+1) {
+ perror("write: setting up stderr");
+ (void) close(s2);
+ goto bad;
+ }
+ FD_ZERO(&reads);
+ FD_SET(s, &reads);
+ FD_SET(s2, &reads);
+ errno = 0;
+ if (select(32, &reads, 0, 0, 0) < 1 ||
+ !FD_ISSET(s2, &reads)) {
+ if (errno != 0)
+ perror("select: setting up stderr");
+ else
+ fprintf(stderr,
+ "select: protocol failure in circuit setup.\n");
+ (void) close(s2);
+ goto bad;
+ }
+ s3 = accept(s2, &from, &len, 0);
+ (void) close(s2);
+ if (s3 < 0) {
+ perror("accept");
+ lport = 0;
+ goto bad;
+ }
+ *fd2p = s3;
+ from.sin_port = ntohs((u_short)from.sin_port);
+ if (from.sin_family != AF_INET ||
+ from.sin_port >= IPPORT_RESERVED) {
+ fprintf(stderr,
+ "socket: protocol failure in circuit setup.\n");
+ goto bad2;
+ }
+ }
+/*
+ * GSS API authentication
+ * import name
+ * init context
+ * send token
+ * if (mutual) init context
+ *
+ */
+ {
+ char myhost[32];
+ int from_addr=0, to_addr=0, myhostlen, j;
+ struct hostent *my_hp;
+
+ strcpy(targ_printable, "SERVICE:rlogin@");
+ strcat(targ_printable, targetname);
+ if (debugflag) {
+ printf("call gss_import_name for '%s'\n", targ_printable);
+ }
+
+ input_name_buffer.length = strlen(targ_printable);
+ input_name_buffer.value = targ_printable;
+
+ major_status = gss_import_name(&status,
+ &input_name_buffer,
+ GSS_C_NULL_OID,
+ &desired_targname);
+
+ major_status = gss_display_name(&status,
+ desired_targname,
+ &output_name_buffer,
+ &output_name_type);
+
+ printf("target is '%s'\n", output_name_buffer.value);
+
+ major_status = gss_release_buffer(&status, &output_name_buffer);
+
+ j=gethostname(myhost, sizeof(myhost));
+ my_hp=gethostbyname(myhost);
+ if (my_hp != 0) {
+ bcopy(my_hp->h_addr_list[0],
+ (caddr_t)&sin2.sin_addr, my_hp->h_length);
+#ifdef ultrix
+ from_addr = sin2.sin_addr.S_un.S_addr;
+#else
+ from_addr = sin2.sin_addr.s_addr;
+#endif
+ from_addr = htonl(from_addr);
+ }
+#ifdef ultrix
+ to_addr = sin.sin_addr.S_un.S_addr;
+#else
+ to_addr = sin.sin_addr.s_addr;
+#endif
+ to_addr = htonl(to_addr);
+
+ input_chan_bindings = (gss_channel_bindings)
+ malloc(sizeof(gss_channel_bindings_desc));
+
+ input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
+ input_chan_bindings->initiator_address.length = 4;
+ input_chan_bindings->initiator_address.value = (char *) malloc(4);
+ input_chan_bindings->initiator_address.value[0] = ((from_addr
+& 0xff000000) >> 24);
+ input_chan_bindings->initiator_address.value[1] = ((from_addr
+& 0xff0000) >> 16);
+ input_chan_bindings->initiator_address.value[2] = ((from_addr
+& 0xff00) >> 8);
+ input_chan_bindings->initiator_address.value[3] = (from_addr & 0xff);
+ input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
+ input_chan_bindings->acceptor_address.length = 4;
+ input_chan_bindings->acceptor_address.value = (char *) malloc(4);
+ input_chan_bindings->acceptor_address.value[0] = ((to_addr &
+0xff000000) >> 24);
+ input_chan_bindings->acceptor_address.value[1] = ((to_addr &
+0xff0000) >> 16);
+ input_chan_bindings->acceptor_address.value[2] = ((to_addr &
+0xff00) >> 8);
+ input_chan_bindings->acceptor_address.value[3] = (to_addr & 0xff);
+ input_chan_bindings->application_data.length = 0;
+ }
+
+ req_flags = 0;
+ if (deleg_flag) req_flags = req_flags | 1;
+ if (mutual_flag) req_flags = req_flags | 2;
+ if (replay_flag) req_flags = req_flags | 4;
+ if (seq_flag) req_flags = req_flags | 8;
+
+ major_status = gss_init_sec_context(&status, /* minor status */
+ GSS_C_NO_CREDENTIAL, /* cred handle */
+ &actual_ctxhandle, /* ctx handle */
+ desired_targname, /* target name */
+ GSS_C_NULL_OID, /* mech type */
+ req_flags, /* req flags */
+ 0, /* time req */
+ input_chan_bindings, /* chan binding */
+ GSS_C_NO_BUFFER, /* input token */
+ &actual_mech_type, /* actual mech */
+ &output_token, /* output token */
+ &ret_flags, /* ret flags */
+ &lifetime_rec); /* time rec */
+
+
+ if ((major_status!=GSS_S_COMPLETE)&&
+ (major_status!=GSS_S_CONTINUE_NEEDED)) {
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ printf("%s\n", status_string.value);
+ return(-1);
+ }
+
+ tokenheader[0] = TOKEN_MAJIC_NUMBER_BYTE0;
+ tokenheader[1] = TOKEN_MAJIC_NUMBER_BYTE1;
+ tokenheader[2] = ((output_token.length & 0xff00) >> 8);
+ tokenheader[3] = (output_token.length & 0xff);
+
+ j = sphinx_net_write(s, tokenheader, 4);
+
+ j = sphinx_net_write(s, output_token.value, output_token.length);
+
+ (void) write(s, locuser, strlen(locuser)+1);
+ (void) write(s, remuser, strlen(remuser)+1);
+ (void) write(s, cmd, strlen(cmd)+1);
+
+ if (read(s, &c, 1) != 1) {
+ perror(*ahost);
+ goto bad2;
+ }
+
+ i = 0;
+ if (major_status == GSS_S_CONTINUE_NEEDED) {
+
+ xcc = 4;
+ while (xcc > 0) {
+ if ((cc = read(s, &recv_tokenheader[i], xcc)) < 0) {
+ syslog(LOG_INFO,"read(s, recv_tokenheader, %d): %m",xcc);
+ break;
+ }
+ i +=cc;
+ xcc -= cc;
+ }
+
+ if ((recv_tokenheader[0] != TOKEN_MAJIC_NUMBER_BYTE0) ||
+ (recv_tokenheader[1] != TOKEN_MAJIC_NUMBER_BYTE1)) {
+ printf("illegal mutual response token format\n");
+ syslog(LOG_INFO, "cannot go from v2.1 client to v2.0 server");
+ return(-1);
+ }
+ xcc = recv_tokenheader[2] * 256 + recv_tokenheader[3];
+
+ mutual_len = 0;
+ while (xcc > 0) {
+ if ((cc = read(s, &mutual_resp[mutual_len], xcc)) < 0) {
+ syslog(LOG_INFO,"read(s, mutual_resp, %d): %m",xcc);
+ break;
+ }
+ mutual_len +=cc;
+ xcc -= cc;
+ }
+
+ input_token.length = mutual_len;
+ input_token.value = mutual_resp;
+
+ major_status = gss_init_sec_context(&status, /* minor status */
+ GSS_C_NO_CREDENTIAL, /* cred handle */
+ &actual_ctxhandle, /* ctx handle */
+ desired_targname, /* target name */
+ GSS_C_NULL_OID, /* mech type */
+ req_flags, /* req flags */
+ 0, /* time req */
+ input_chan_bindings, /* chan binding */
+ &input_token, /* input token */
+ &actual_mech_type, /* actual mech */
+ &output_token, /* output token */
+ &ret_flags, /* ret flags */
+ &lifetime_rec); /* time rec */
+
+ if (major_status!=GSS_S_COMPLETE) {
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ printf("%s\n", status_string.value);
+ return(-1);
+ }
+ }
+
+ major_status = gss_release_name(&status, desired_targname);
+
+#ifdef SPX_CHALLENGE
+ /*
+ * if trying to login to root account, make up response proving
+ * that the user is interactive.
+ *
+ * response is the signed mutual response with the user's long term
+ * private key.
+ *
+ */
+ if (strcmp(remuser, "root")==0) {
+ major_status = spx_make_response(&status,
+ GSS_C_NO_CREDENTIAL,
+ actual_ctxhandle,
+ token,
+ &tokenlen);
+
+ if (major_status != GSS_S_COMPLETE) {
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ printf("%s\n", status_string.value);
+ return(-1);
+ }
+
+ tokenheader[0] = TOKEN_MAJIC_NUMBER_BYTE0;
+ tokenheader[1] = TOKEN_MAJIC_NUMBER_BYTE1;
+ tokenheader[2] = ((tokenlen & 0xff00) >> 8);
+ tokenheader[3] = (tokenlen & 0xff);
+
+ j = sphinx_net_write(s, tokenheader, 4);
+
+ charp = token;
+ j = sphinx_net_write(s, (char *)charp, tokenlen);
+
+ }
+#endif /* SPX_CHALLENGE */
+ *context_handle = actual_ctxhandle;
+
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad2;
+ }
+ sigsetmask(oldmask);
+ return (s);
+bad2:
+ if (lport)
+ (void) close(*fd2p);
+bad:
+ (void) close(s);
+ sigsetmask(oldmask);
+ return (-1);
+}
+
+rresvport(alport)
+ int *alport;
+{
+ struct sockaddr_in sin;
+ int s;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+ for (;;) {
+ sin.sin_port = htons((u_short)*alport);
+ if (bind(s, (caddr_t)&sin, sizeof (sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void) close(s);
+ return (-1);
+ }
+ (*alport)--;
+ if (*alport == IPPORT_RESERVED/2) {
+ (void) close(s);
+ errno = EAGAIN; /* close */
+ return (-1);
+ }
+ }
+}
+
+int _check_rhosts_file = 1;
+
+ruserok(rhost, superuser, ruser, luser)
+ char *rhost;
+ int superuser;
+ char *ruser, *luser;
+{
+ FILE *hostf;
+ char fhost[MAXHOSTNAMELEN];
+ int first = 1;
+ register char *sp, *p;
+ int baselen = -1;
+
+ sp = rhost;
+ p = fhost;
+ while (*sp) {
+ if (*sp == '.') {
+ if (baselen == -1)
+ baselen = sp - rhost;
+ *p++ = *sp++;
+ } else {
+ *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
+ }
+ }
+ *p = '\0';
+ hostf = superuser ? (FILE *)0 : fopen("/etc/hosts.equiv", "r");
+again:
+ if (hostf) {
+ if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
+ (void) fclose(hostf);
+ return(0);
+ }
+ (void) fclose(hostf);
+ }
+ if (first == 1 && (_check_rhosts_file || superuser)) {
+ struct stat sbuf;
+ struct passwd *pwd;
+ char pbuf[MAXPATHLEN];
+
+ first = 0;
+ if ((pwd = getpwnam(luser)) == NULL)
+ return(-1);
+ (void)strcpy(pbuf, pwd->pw_dir);
+ (void)strcat(pbuf, "/.rhosts");
+ if ((hostf = fopen(pbuf, "r")) == NULL)
+ return(-1);
+ /*
+ * if owned by someone other than user or root or if
+ * writeable by anyone but the owner, quit
+ */
+ if (fstat(fileno(hostf), &sbuf) ||
+ sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
+ sbuf.st_mode&022) {
+ fclose(hostf);
+ return(-1);
+ }
+ goto again;
+ }
+ return (-1);
+}
+
+/* don't make static, used by lpd(8) */
+_validuser(hostf, rhost, luser, ruser, baselen)
+ char *rhost, *luser, *ruser;
+ FILE *hostf;
+ int baselen;
+{
+ char *user;
+ char ahost[MAXHOSTNAMELEN];
+ register char *p;
+
+ while (fgets(ahost, sizeof (ahost), hostf)) {
+ p = ahost;
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ *p = isupper(*p) ? tolower(*p) : *p;
+ p++;
+ }
+ if (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ user = p;
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
+ p++;
+ } else
+ user = p;
+ *p = '\0';
+ if (_checkhost(rhost, ahost, baselen) &&
+ !strcmp(ruser, *user ? user : luser)) {
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+static
+_checkhost(rhost, lhost, len)
+ char *rhost, *lhost;
+ int len;
+{
+ static char ldomain[MAXHOSTNAMELEN + 1];
+ static char *domainp = NULL;
+ static int nodomain = 0;
+ register char *cp;
+
+ if (len == -1)
+ return(!strcmp(rhost, lhost));
+ if (strncmp(rhost, lhost, len))
+ return(0);
+ if (!strcmp(rhost, lhost))
+ return(1);
+ if (*(lhost + len) != '\0')
+ return(0);
+ if (nodomain)
+ return(0);
+ if (!domainp) {
+ if (gethostname(ldomain, sizeof(ldomain)) == -1) {
+ nodomain = 1;
+ return(0);
+ }
+ ldomain[MAXHOSTNAMELEN] = NULL;
+ if ((domainp = index(ldomain, '.')) == (char *)NULL) {
+ nodomain = 1;
+ return(0);
+ }
+ for (cp = ++domainp; *cp; ++cp)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ }
+ return(!strcmp(domainp, rhost + len +1));
+}
--- /dev/null
+/*
+ * Copyright (c) 1983, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement: ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rlogin.c 5.29 (Berkeley) 6/27/90";
+#endif /* not lint */
+
+/*
+ * $Source$
+ * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall
+ * Exp Locker: kfall $
+ */
+
+/*
+ * 2-14-91 ka
+ * Modified sources to add SPX strong authentication, called flogin.c
+ *
+ * 5-24-91 ka
+ * Modified sources to remove SPX and Kerberos specific authentication.
+ * Replaced with GSS API
+ *
+ */
+
+/*
+ * rlogin - remote login
+ */
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netdb.h>
+
+#include <sgtty.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <varargs.h>
+#include <pwd.h>
+#include <stdio.h>
+#ifdef ultrix
+#include <unistd.h>
+#endif
+#include <string.h>
+
+#include "gssapi_defs.h"
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0 /* standard in */
+#endif
+
+#define FLOGIN_PORT 221
+
+#ifndef TIOCPKT_WINDOW
+#define TIOCPKT_WINDOW 0x80
+#endif
+
+/* concession to Sun */
+#ifndef SIGUSR1
+#define SIGUSR1 30
+#endif
+
+extern int errno;
+int eight, litout, rem;
+char cmdchar;
+char *speeds[] = {
+ "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
+ "1800", "2400", "4800", "9600", "19200", "38400"
+};
+
+#ifdef sun
+struct winsize {
+ unsigned short ws_row, ws_col;
+ unsigned short ws_xpixel, ws_ypixel;
+};
+#endif
+struct winsize winsize;
+
+#ifndef sun
+#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
+#endif
+
+void exit();
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+ struct passwd *pw;
+ struct servent *sp;
+ struct sgttyb ttyb;
+ long omask;
+ int argoff, ch, dflag, one, uid;
+ char *host, *p, *user, term[1024];
+ void lostpeer();
+ char *getenv();
+ int mutual_flag = 1, deleg_flag = 1, sock = 0;
+ int debugflag = 0;
+ gss_cred_id_t context_handle;
+
+ argoff = dflag = 0;
+ one = 1;
+ host = user = NULL;
+ cmdchar = '~';
+
+ if (p = rindex(argv[0], '/'))
+ ++p;
+ else
+ p = argv[0];
+
+ /* handle "flogin host flags" */
+ if (!host && argc > 2 && argv[1][0] != '-') {
+ host = argv[1];
+ argoff = 1;
+ }
+
+#define OPTIONS "8Lde:l:vn"
+
+ while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
+ switch(ch) {
+ case '8':
+ eight = 1;
+ break;
+ case 'L':
+ litout = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ cmdchar = optarg[0];
+ break;
+ case 'l':
+ user = optarg;
+ break;
+ case 'v':
+ debugflag = 1;
+ break;
+ case 'n':
+ deleg_flag = 0;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ optind += argoff;
+ argc -= optind;
+ argv += optind;
+
+ /* if haven't gotten a host yet, do so */
+ if (!host && !(host = *argv++))
+ usage();
+
+ if (*argv)
+ usage();
+
+ if (!(pw = getpwuid(uid = getuid()))) {
+ (void)fprintf(stderr, "flogin: unknown user id.\n");
+ exit(1);
+ }
+ if (!user)
+ user = pw->pw_name;
+
+ sp = NULL;
+
+ /*
+ * if remote login to root account, force no delegation
+ */
+ if (strcmp(user, "root")==0) deleg_flag=0;
+ sp = getservbyname("flogin", "tcp");
+ if (sp == NULL) {
+ sp = (struct servent *) malloc(sizeof(struct servent));
+ sp->s_port = htons(FLOGIN_PORT);
+ }
+
+ if (sp == NULL)
+ sp = getservbyname("login", "tcp");
+ if (sp == NULL) {
+ (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
+ exit(1);
+ }
+
+ (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
+ if (ioctl(0, TIOCGETP, &ttyb) == 0) {
+ (void)strcat(term, "/");
+ (void)strcat(term, speeds[ttyb.sg_ospeed]);
+ }
+
+ (void)get_window_size(0, &winsize);
+
+ (void)signal(SIGPIPE, lostpeer);
+ /* will use SIGUSR1 for window size hack, so hold it off */
+ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+
+ rem = fcmd(&sock, &host, sp->s_port, pw->pw_name,
+ user, term, 0, host, &context_handle,
+ mutual_flag, deleg_flag, debugflag);
+
+ if (rem < 0)
+ exit(1);
+
+ if (dflag &&
+ setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
+ (void)fprintf(stderr, "flogin: setsockopt: errno %d.\n",
+ errno);
+
+ (void)setuid(uid);
+ doit(omask);
+ /*NOTREACHED*/
+}
+
+int child, defflags, deflflags, tabflag;
+char deferase, defkill;
+struct tchars deftc;
+struct ltchars defltc;
+struct tchars notc = { -1, -1, -1, -1, -1, -1 };
+struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
+
+doit(omask)
+ long omask;
+{
+ struct sgttyb sb;
+ void catch_child(), copytochild(), exit(), writeroob();
+
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ defflags = sb.sg_flags;
+ tabflag = defflags & TBDELAY;
+ defflags &= ECHO | CRMOD;
+ deferase = sb.sg_erase;
+ defkill = sb.sg_kill;
+ (void)ioctl(0, TIOCLGET, (char *)&deflflags);
+ (void)ioctl(0, TIOCGETC, (char *)&deftc);
+ notc.t_startc = deftc.t_startc;
+ notc.t_stopc = deftc.t_stopc;
+ (void)ioctl(0, TIOCGLTC, (char *)&defltc);
+ (void)signal(SIGINT, SIG_IGN);
+ setsignal(SIGHUP, exit);
+ setsignal(SIGQUIT, exit);
+ child = fork();
+ if (child == -1) {
+ (void)fprintf(stderr, "rlogin: fork: errno %d.\n", errno);
+ done(1);
+ }
+ if (child == 0) {
+ mode(1);
+ if (reader(omask) == 0) {
+ msg("connection closed.");
+ exit(0);
+ }
+ sleep(1);
+ msg("\007connection closed.");
+ exit(1);
+ }
+
+ /*
+ * We may still own the socket, and may have a pending SIGURG (or might
+ * receive one soon) that we really want to send to the reader. Set a
+ * trap that simply copies such signals to the child.
+ */
+ (void)signal(SIGURG, copytochild);
+ (void)signal(SIGUSR1, writeroob);
+ (void)sigsetmask(omask);
+ (void)signal(SIGCHLD, catch_child);
+ writer();
+ msg("closed connection.");
+ done(0);
+}
+
+/* trap a signal, unless it is being ignored. */
+setsignal(sig, act)
+ int sig;
+ void (*act)();
+{
+ int omask = sigblock(sigmask(sig));
+
+ if (signal(sig, act) == SIG_IGN)
+ (void)signal(sig, SIG_IGN);
+ (void)sigsetmask(omask);
+}
+
+done(status)
+ int status;
+{
+ int w;
+
+ mode(0);
+ if (child > 0) {
+ /* make sure catch_child does not snap it up */
+ (void)signal(SIGCHLD, SIG_DFL);
+ if (kill(child, SIGKILL) >= 0)
+ while ((w = wait((union wait *)0)) > 0 && w != child);
+ }
+ exit(status);
+}
+
+int dosigwinch;
+
+/*
+ * This is called when the reader process gets the out-of-band (urgent)
+ * request to turn on the window-changing protocol.
+ */
+void
+writeroob()
+{
+ void sigwinch();
+
+ if (dosigwinch == 0) {
+ sendwindow();
+ (void)signal(SIGWINCH, sigwinch);
+ }
+ dosigwinch = 1;
+}
+
+void
+catch_child()
+{
+ union wait status;
+ int pid;
+
+ for (;;) {
+ pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
+ if (pid == 0)
+ return;
+ /* if the child (reader) dies, just quit */
+ if (pid < 0 || pid == child && !WIFSTOPPED(status))
+ done((int)(status.w_termsig | status.w_retcode));
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * writer: write to remote: 0 -> line.
+ * ~. terminate
+ * ~^Z suspend rlogin process.
+ * ~^Y suspend rlogin process, but leave reader alone.
+ */
+writer()
+{
+ char c;
+ register int bol, local, n;
+
+ bol = 1; /* beginning of line */
+ local = 0;
+ for (;;) {
+ n = read(STDIN_FILENO, &c, 1);
+ if (n <= 0) {
+ if (n < 0 && errno == EINTR)
+ continue;
+ break;
+ }
+ /*
+ * If we're at the beginning of the line and recognize a
+ * command character, then we echo locally. Otherwise,
+ * characters are echo'd remotely. If the command character
+ * is doubled, this acts as a force and local echo is
+ * suppressed.
+ */
+ if (bol) {
+ bol = 0;
+ if (c == cmdchar) {
+ bol = 0;
+ local = 1;
+ continue;
+ }
+ } else if (local) {
+ local = 0;
+ if (c == '.' || c == deftc.t_eofc) {
+ echo(c);
+ break;
+ }
+ if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
+ bol = 1;
+ echo(c);
+ stop(c);
+ continue;
+ }
+ if (c != cmdchar) {
+ (void)write(rem, &cmdchar, 1);
+ }
+ }
+
+ if (write(rem, &c, 1) == 0) {
+ msg("line gone");
+ break;
+ }
+ bol = c == defkill || c == deftc.t_eofc ||
+ c == deftc.t_intrc || c == defltc.t_suspc ||
+ c == '\r' || c == '\n';
+ }
+}
+
+echo(c)
+register char c;
+{
+ register char *p;
+ char buf[8];
+
+ p = buf;
+ c &= 0177;
+ *p++ = cmdchar;
+ if (c < ' ') {
+ *p++ = '^';
+ *p++ = c + '@';
+ } else if (c == 0177) {
+ *p++ = '^';
+ *p++ = '?';
+ } else
+ *p++ = c;
+ *p++ = '\r';
+ *p++ = '\n';
+ (void)write(1, buf, p - buf);
+}
+
+stop(cmdc)
+ char cmdc;
+{
+ mode(0);
+ (void)signal(SIGCHLD, SIG_IGN);
+ (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
+ (void)signal(SIGCHLD, catch_child);
+ mode(1);
+ sigwinch(); /* check for size changes */
+}
+
+void
+sigwinch()
+{
+ struct winsize ws;
+
+ if (dosigwinch && get_window_size(0, &ws) == 0 &&
+ bcmp(&ws, &winsize, sizeof(ws))) {
+ winsize = ws;
+ sendwindow();
+ }
+}
+
+/*
+ * Send the window size to the server via the magic escape
+ */
+sendwindow()
+{
+ struct winsize *wp;
+ char obuf[4 + sizeof (struct winsize)];
+
+ wp = (struct winsize *)(obuf+4);
+ obuf[0] = 0377;
+ obuf[1] = 0377;
+ obuf[2] = 's';
+ obuf[3] = 's';
+ wp->ws_row = htons(winsize.ws_row);
+ wp->ws_col = htons(winsize.ws_col);
+ wp->ws_xpixel = htons(winsize.ws_xpixel);
+ wp->ws_ypixel = htons(winsize.ws_ypixel);
+
+ (void)write(rem, obuf, sizeof(obuf));
+}
+
+/*
+ * reader: read from remote: line -> 1
+ */
+#define READING 1
+#define WRITING 2
+
+jmp_buf rcvtop;
+int ppid, rcvcnt, rcvstate;
+char rcvbuf[8 * 1024];
+
+void
+oob()
+{
+ struct sgttyb sb;
+ int atmark, n, out, rcvd;
+ char waste[BUFSIZ], mark;
+
+ out = O_RDWR;
+ rcvd = 0;
+ while (recv(rem, &mark, 1, MSG_OOB) < 0)
+ switch (errno) {
+ case EWOULDBLOCK:
+ /*
+ * Urgent data not here yet. It may not be possible
+ * to send it yet if we are blocked for output and
+ * our input buffer is full.
+ */
+ if (rcvcnt < sizeof(rcvbuf)) {
+ n = read(rem, rcvbuf + rcvcnt,
+ sizeof(rcvbuf) - rcvcnt);
+ if (n <= 0)
+ return;
+ rcvd += n;
+ } else {
+ n = read(rem, waste, sizeof(waste));
+ if (n <= 0)
+ return;
+ }
+ continue;
+ default:
+ return;
+ }
+ if (mark & TIOCPKT_WINDOW) {
+ /* Let server know about window size changes */
+ (void)kill(ppid, SIGUSR1);
+ }
+ if (!eight && (mark & TIOCPKT_NOSTOP)) {
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~CBREAK;
+ sb.sg_flags |= RAW;
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ notc.t_stopc = -1;
+ notc.t_startc = -1;
+ (void)ioctl(0, TIOCSETC, (char *)¬c);
+ }
+ if (!eight && (mark & TIOCPKT_DOSTOP)) {
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ sb.sg_flags &= ~RAW;
+ sb.sg_flags |= CBREAK;
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ notc.t_stopc = deftc.t_stopc;
+ notc.t_startc = deftc.t_startc;
+ (void)ioctl(0, TIOCSETC, (char *)¬c);
+ }
+ if (mark & TIOCPKT_FLUSHWRITE) {
+ (void)ioctl(1, TIOCFLUSH, (char *)&out);
+ for (;;) {
+ if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+ (void)fprintf(stderr, "rlogin: ioctl: errno %d.\n",
+ errno);
+ break;
+ }
+ if (atmark)
+ break;
+ n = read(rem, waste, sizeof (waste));
+ if (n <= 0)
+ break;
+ }
+ /*
+ * Don't want any pending data to be output, so clear the recv
+ * buffer. If we were hanging on a write when interrupted,
+ * don't want it to restart. If we were reading, restart
+ * anyway.
+ */
+ rcvcnt = 0;
+ longjmp(rcvtop, 1);
+ }
+
+ /* oob does not do FLUSHREAD (alas!) */
+
+ /*
+ * If we filled the receive buffer while a read was pending, longjmp
+ * to the top to restart appropriately. Don't abort a pending write,
+ * however, or we won't know how much was written.
+ */
+ if (rcvd && rcvstate == READING)
+ longjmp(rcvtop, 1);
+}
+
+/* reader: read from remote: line -> 1 */
+reader(omask)
+ int omask;
+{
+ void oob();
+
+#if !defined(BSD) || BSD < 43
+ int pid = -getpid();
+#else
+ int pid = getpid();
+#endif
+ int n, remaining;
+ char *bufp = rcvbuf;
+
+ (void)signal(SIGTTOU, SIG_IGN);
+ (void)signal(SIGURG, oob);
+ ppid = getppid();
+ (void)fcntl(rem, F_SETOWN, pid);
+ (void)setjmp(rcvtop);
+ (void)sigsetmask(omask);
+ for (;;) {
+ while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
+ rcvstate = WRITING;
+ n = write(1, bufp, remaining);
+ if (n < 0) {
+ if (errno != EINTR)
+ return(-1);
+ continue;
+ }
+ bufp += n;
+ }
+ bufp = rcvbuf;
+ rcvcnt = 0;
+ rcvstate = READING;
+
+ rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
+ if (rcvcnt == 0)
+ return (0);
+ if (rcvcnt < 0) {
+ if (errno == EINTR)
+ continue;
+ (void)fprintf(stderr, "rlogin: read: errno %d.\n",
+ errno);
+ return(-1);
+ }
+ }
+}
+
+mode(f)
+{
+ struct ltchars *ltc;
+ struct sgttyb sb;
+ struct tchars *tc;
+ int lflags;
+
+ (void)ioctl(0, TIOCGETP, (char *)&sb);
+ (void)ioctl(0, TIOCLGET, (char *)&lflags);
+ switch(f) {
+ case 0:
+ sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
+ sb.sg_flags |= defflags|tabflag;
+ tc = &deftc;
+ ltc = &defltc;
+ sb.sg_kill = defkill;
+ sb.sg_erase = deferase;
+ lflags = deflflags;
+ break;
+ case 1:
+ sb.sg_flags |= (eight ? RAW : CBREAK);
+ sb.sg_flags &= ~defflags;
+ /* preserve tab delays, but turn off XTABS */
+ if ((sb.sg_flags & TBDELAY) == XTABS)
+ sb.sg_flags &= ~TBDELAY;
+ tc = ¬c;
+ ltc = &noltc;
+ sb.sg_kill = sb.sg_erase = -1;
+ if (litout)
+ lflags |= LLITOUT;
+ break;
+ default:
+ return;
+ }
+ (void)ioctl(0, TIOCSLTC, (char *)ltc);
+ (void)ioctl(0, TIOCSETC, (char *)tc);
+ (void)ioctl(0, TIOCSETN, (char *)&sb);
+ (void)ioctl(0, TIOCLSET, (char *)&lflags);
+}
+
+void
+lostpeer()
+{
+ (void)signal(SIGPIPE, SIG_IGN);
+ msg("\007connection closed.");
+ done(1);
+}
+
+/* copy SIGURGs to the child process. */
+void
+copytochild()
+{
+ (void)kill(child, SIGURG);
+}
+
+msg(str)
+ char *str;
+{
+ (void)fprintf(stderr, "flogin: %s\r\n", str);
+}
+
+warning(msg)
+char *msg;
+{
+ (void) fprintf(stderr, msg);
+ fflush(stderr);
+}
+
+
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
+ "8L", " ");
+ exit(1);
+}
+
+/*
+ * The following routine provides compatibility (such as it is) between 4.2BSD
+ * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
+ */
+#ifdef sun
+int
+get_window_size(fd, wp)
+ int fd;
+ struct winsize *wp;
+{
+ struct ttysize ts;
+ int error;
+
+ if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
+ return(error);
+ wp->ws_row = ts.ts_lines;
+ wp->ws_col = ts.ts_cols;
+ wp->ws_xpixel = 0;
+ wp->ws_ypixel = 0;
+ return(0);
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * 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\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rlogind.c 5.17 (Berkeley) 8/31/88";
+#endif /* not lint */
+
+/*
+ * remote login server:
+ * remuser\0
+ * locuser\0
+ * terminal info\0
+ * data
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sgtty.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <strings.h>
+
+#define LOGIN_PROGRAM "/usr/etc/login.sphinx"
+
+#define des_read read
+#define des_write write
+
+# ifndef TIOCPKT_WINDOW
+# define TIOCPKT_WINDOW 0x80
+# endif TIOCPKT_WINDOW
+
+extern int errno;
+int reapchild();
+struct passwd *getpwnam();
+char *malloc();
+
+int Pfd;
+
+/* ARGSUSED */
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int on = 1, fromlen;
+ struct sockaddr_in from;
+
+ fromlen = sizeof (from);
+ if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ fprintf(stderr, "%s: ", argv[0]);
+ perror("getpeername");
+ _exit(1);
+ }
+ if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ }
+ doit(0, &from);
+}
+
+int child;
+int cleanup();
+int netf;
+char *line;
+extern char *inet_ntoa();
+
+struct winsize win = { 0, 0, 0, 0 };
+
+
+doit(f, fromp)
+ int f;
+ struct sockaddr_in *fromp;
+{
+ int i, p, t, pid, on = 1;
+ int pipes[2];
+
+ register struct hostent *hp;
+ struct hostent hostent;
+ char c;
+
+ alarm(60);
+ read(f, &c, 1);
+ if (c != 0)
+ exit(1);
+ alarm(0);
+ fromp->sin_port = ntohs((u_short)fromp->sin_port);
+ hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
+ fromp->sin_family);
+ if (hp == 0) {
+ /*
+ * Only the name is used below.
+ */
+ hp = &hostent;
+ hp->h_name = inet_ntoa(fromp->sin_addr);
+ }
+
+ if (fromp->sin_family != AF_INET ||
+ fromp->sin_port < IPPORT_RESERVED)
+ fatal(f, "Permission denied");
+
+ write(f, "", 1);
+ for (c = 'p'; c <= 's'; c++) {
+ struct stat stb;
+ line = "/dev/ptyXX";
+ line[strlen("/dev/pty")] = c;
+ line[strlen("/dev/ptyp")] = '0';
+ if (stat(line, &stb) < 0)
+ break;
+ for (i = 0; i < 16; i++) {
+ line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+ p = open(line, O_RDWR);
+ if (p > 0)
+ goto gotpty;
+ }
+ }
+ fatal(f, "Out of ptys");
+ /*NOTREACHED*/
+gotpty:
+ (void) ioctl(p, TIOCSWINSZ, &win);
+ netf = f;
+ line[strlen("/dev/")] = 't';
+ t = open(line, O_RDWR);
+ if (t < 0)
+ fatalperror(f, line);
+ if (fchmod(t, 0))
+ fatalperror(f, line);
+ (void)signal(SIGHUP, SIG_IGN);
+ vhangup();
+ (void)signal(SIGHUP, SIG_DFL);
+ t = open(line, O_RDWR);
+ if (t < 0)
+ fatalperror(f, line);
+ {
+ struct sgttyb b;
+
+ (void)ioctl(t, TIOCGETP, &b);
+ b.sg_flags = RAW|ANYP;
+ (void)ioctl(t, TIOCSETP, &b);
+ }
+#ifdef DEBUG
+ {
+ int tt = open("/dev/tty", O_RDWR);
+ if (tt > 0) {
+ (void) ioctl(tt, TIOCNOTTY, 0);
+ (void) close(tt);
+ }
+ }
+#endif
+ t = open(line, 2);
+ if (t < 0)
+ fatalperror(f, line, errno);
+ { struct sgttyb b;
+ gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
+ }
+
+ if (pipe(pipes) < 0) {
+ fatalperror(2, "pipe", errno);
+ }
+
+ pid = fork();
+ if (pid < 0)
+ fatalperror(f, "", errno);
+ if (pid == 0) {
+ close(f), close(p);
+ close(pipes[1]);
+ dup2(t, 0), dup2(t, 1), dup2(t, 2);
+ if (pipes[0] != 3) { dup2(pipes[0], 3); close(pipes[0]); }
+ close(t);
+
+ /* 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.
+ It seems to work fine on 4.3BSD with this code enabled.
+ */
+ pid = getpgrp(getpid());
+ ioctl(0, TIOCSPGRP, &pid);
+ execl("/usr/etc/login.sphinx", "login.sphinx", "-g", hp->h_name, 0);
+ fatalperror(2, "/usr/etc/login.sphinx", errno);
+ /*NOTREACHED*/
+ }
+ close(t);
+ close(pipes[0]);
+ ioctl(f, FIONBIO, &on);
+ ioctl(p, FIONBIO, &on);
+ ioctl(p, TIOCPKT, &on);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGCHLD, cleanup);
+ setpgrp(0, 0);
+ protocol(f, p, pipes[1]);
+ signal(SIGCHLD, SIG_IGN);
+ cleanup();
+}
+
+char magic[2] = { 0377, 0377 };
+char oobdata[] = {TIOCPKT_WINDOW};
+
+/*
+ * 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)
+ int pty;
+ char *cp;
+ int n;
+{
+ struct winsize w;
+
+ if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
+ return (0);
+ oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
+ bcopy(cp+4, (char *)&w, sizeof(w));
+ w.ws_row = ntohs(w.ws_row);
+ w.ws_col = ntohs(w.ws_col);
+ w.ws_xpixel = ntohs(w.ws_xpixel);
+ w.ws_ypixel = ntohs(w.ws_ypixel);
+ (void)ioctl(pty, TIOCSWINSZ, &w);
+ return (4+sizeof (w));
+}
+
+/*
+ * flogin "protocol" machine.
+ */
+protocol(f, p, pipe)
+ int f, p, pipe;
+{
+ char pibuf[1024], fibuf[1024], *pbp, *fbp;
+ register pcc = 0, fcc = 0;
+ int cc;
+ int on = 1, off = 0, done = 0;
+ char cntl;
+
+ /*
+ * Must ignore SIGTTOU, otherwise we'll stop
+ * when we try and set slave pty's window shape
+ * (our controlling tty is the master pty).
+ */
+ (void) signal(SIGTTOU, SIG_IGN);
+ send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
+ ioctl(f, FIONBIO, &off);
+ for (cc = 0; cc < 4; cc++) {
+ if (1 != read(f, &fibuf[cc], 1)) {
+ done = 1;
+ break;
+ }
+ }
+ if (!done) {
+ int len = ((u_char *)fibuf)[2] * 256 + ((u_char *)fibuf)[3];
+ pcc = write(pipe, fibuf, cc);
+ if (pcc <= 0) {
+ done = 1;
+ syslog(LOG_INFO, "write(pipe [%d], fibuf, %d): %d:
+%m",pipe, cc, pcc);
+ }
+ while (!done && len > 0) {
+ char *fbp = fibuf;
+ cc = read(f, fibuf, len);
+ if (cc <= 0) {
+ done = 1;
+ syslog(LOG_INFO, "read(f, fibuf, %d): %d: %m",len, cc);
+ break;
+ }
+ len -= cc;
+ while (cc > 0) {
+ pcc = write(pipe, fbp, cc);
+ if (pcc <= 0) {
+ done = 1;
+ syslog(LOG_INFO, "write(pipe [%d], fbp, %d):
+%d: %m",pipe, cc, pcc);
+ break;
+ }
+ cc -= pcc;
+ fbp += pcc;
+ }
+ }
+ }
+ ioctl(f, FIONBIO, &on);
+
+ close(pipe); fcc = 0; pcc = 0;
+ for (;;) {
+ int ibits, obits, ebits;
+
+ ibits = 0;
+ obits = 0;
+ if (fcc)
+ obits |= (1<<p);
+ else
+ ibits |= (1<<f);
+ if (pcc >= 0)
+ if (pcc)
+ obits |= (1<<f);
+ else
+ ibits |= (1<<p);
+ ebits = (1<<p);
+ if (select(32, &ibits, &obits, &ebits, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ fatalperror(f, "select");
+ }
+ if (ibits == 0 && obits == 0 && ebits == 0) {
+ /* shouldn't happen... */
+ sleep(5);
+ continue;
+ }
+#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
+ if (ebits & (1<<p)) {
+ 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;
+ ibits &= ~(1<<p);
+ }
+ }
+ }
+ if (ibits & (1<<f)) {
+ fcc = read(f, fibuf, sizeof(fibuf));
+ if (fcc < 0 && errno == EWOULDBLOCK)
+ fcc = 0;
+ else {
+ register char *cp;
+ int left, n;
+
+ if (fcc <= 0)
+ 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)
+
+bcopy(cp+n, cp, left);
+ fcc -= n;
+ goto top; /* n^2 */
+ }
+ }
+ }
+ }
+
+ if ((obits & (1<<p)) && fcc > 0) {
+ cc = write(p, fbp, fcc);
+ if (cc > 0) {
+ fcc -= cc;
+ fbp += cc;
+ }
+ }
+
+ if (ibits & (1<<p)) {
+ pcc = read(p, pibuf, sizeof (pibuf));
+ pbp = pibuf;
+ if (pcc < 0 && errno == EWOULDBLOCK)
+ pcc = 0;
+ else if (pcc <= 0)
+ break;
+ else if (pibuf[0] == 0)
+ pbp++, pcc--;
+ else {
+ if (pkcontrol(pibuf[0])) {
+ pibuf[0] |= oobdata[0];
+ send(f, &pibuf[0], 1, MSG_OOB);
+ }
+ pcc = 0;
+ }
+ }
+ if ((obits & (1<<f)) && pcc > 0) {
+ cc = des_write(f, pbp, pcc);
+ if (cc < 0 && errno == EWOULDBLOCK) {
+ /* also shouldn't happen */
+ sleep(5);
+ continue;
+ }
+ if (cc > 0) {
+ pcc -= cc;
+ pbp += cc;
+ }
+ }
+ }
+}
+
+cleanup()
+{
+ char *p;
+
+ p = line + sizeof("/dev/") - 1;
+ if (!logout(p))
+ logwtmp(p, "", "");
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ *p = 'p';
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ shutdown(netf, 2);
+ exit(1);
+}
+
+fatal(f, msg)
+ int f;
+ char *msg;
+{
+ char buf[BUFSIZ];
+
+ buf[0] = '\01'; /* error indicator */
+ (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
+ (void) write(f, buf, strlen(buf));
+ exit(1);
+}
+
+fatalperror(f, msg)
+ int f;
+ char *msg;
+{
+ char buf[BUFSIZ];
+ 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);
+ fatal(f, buf);
+}
--- /dev/null
+/*
+ * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * 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) 1980, 1987, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89";
+#endif /* not lint */
+
+/*
+ * login [ name ]
+ * login -r hostname (for rlogind)
+ * login -h hostname (for telnetd, etc.)
+ * login -f name (for pre-authenticated login: datakit, xterm, etc.)
+ * ifdef KERBEROS
+ * login -e name (for pre-authenticated encrypted, must do term
+ * negotiation)
+ * login -k hostname (for Kerberos rlogind with password access)
+ * login -K hostname (for Kerberos rlogind with restricted access)
+ * endif KERBEROS
+ */
+
+#include <sys/param.h>
+#ifndef VFS
+#include <sys/quota.h>
+#endif VFS
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <utmp.h>
+#include <signal.h>
+#include <lastlog.h>
+#include <errno.h>
+#ifndef NOTTYENT
+#include <ttyent.h>
+#endif /* NOTTYENT */
+#include <syslog.h>
+#include <grp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "gssapi_defs.h"
+
+#define TOKEN_MAJIC_NUMBER_BYTE0 1
+#define TOKEN_MAJIC_NUMBER_BYTE1 1
+
+char userfullname[GSS_C_MAX_PRINTABLE_NAME];
+char userlocalname[GSS_C_MAX_PRINTABLE_NAME];
+gss_cred_id_t gss_delegated_cred_handle;
+
+#ifdef UIDGID_T
+uid_t getuid();
+#define uid_type uid_t
+#define gid_type gid_t
+#else
+int getuid();
+#define uid_type int
+#define gid_type int
+#endif /* UIDGID_T */
+
+#define TTYGRPNAME "tty" /* name of group to own ttys */
+
+#define MOTDFILE "/etc/motd"
+#define MAILDIR "/usr/spool/mail"
+#define NOLOGIN "/etc/nologin"
+#define HUSHLOGIN ".hushlogin"
+#define LASTLOG "/usr/adm/lastlog"
+#define BSHELL "/bin/sh"
+
+#ifdef VFS
+#define QUOTAWARN "/usr/ucb/quota" /* warn user about quotas */
+#endif VFS
+
+#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host)
+#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name)
+
+/*
+ * This bounds the time given to login. Not a define so it can
+ * be patched on machines where it's too small.
+ */
+int timeout = 300;
+
+struct passwd *pwd;
+char term[64], *hostname, *username;
+
+gss_ctx_id_t context_handle;
+
+struct sgttyb sgttyb;
+struct tchars tc = {
+ CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
+};
+struct ltchars ltc = {
+ CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
+};
+
+extern int errno;
+
+#ifdef POSIX
+typedef void sigtype;
+#else
+typedef int sigtype;
+#endif /* POSIX */
+
+#define EXCL_TEST if (rflag || kflag || Kflag || eflag || \
+ fflag || hflag) { \
+ fprintf(stderr, \
+ "login: only one of -r, -k, -K, -e,
+-h and -f allowed.\n"); \
+ exit(1);\
+ }
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern int optind;
+ extern char *optarg, **environ;
+ struct group *gr;
+ register int ch;
+ register char *p;
+
+ int gflag;
+
+ int fflag, hflag, pflag, rflag, cnt;
+ int kflag, Kflag, eflag;
+ int quietlog, passwd_req, ioctlval, major_status, minor_status;
+ sigtype timedout();
+ char *domain, *salt, *envinit[1], *ttyn, *tty;
+ char tbuf[MAXPATHLEN + 2];
+ char *ttyname(), *stypeof(), *crypt(), *getpass();
+ time_t time();
+ off_t lseek();
+
+ (void)signal(SIGALRM, timedout);
+ (void)alarm((u_int)timeout);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+#ifndef VFS
+ (void)quota(Q_SETUID, 0, 0, 0);
+#endif VFS
+
+ /*
+ * -s is used by flogind to cause the SPX autologin protocol;
+ * -p is used by getty to tell login not to destroy the environment
+ * -r is used by rlogind to cause the autologin protocol;
+ * -f is used to skip a second login authentication
+ * -e is used to skip a second login authentication, but allows
+ * login as root.
+ * -h is used by other servers to pass the name of the
+ * remote host to login so that it may be placed in utmp and wtmp
+ * -k is used by klogind to cause the Kerberos autologin protocol;
+ * -K is used by klogind to cause the Kerberos autologin protocol with
+ * restricted access.;
+ */
+ (void)gethostname(tbuf, sizeof(tbuf));
+ domain = index(tbuf, '.');
+
+ fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
+ passwd_req = 1;
+ while ((ch = getopt(argc, argv, "feh:pr:k:K:g:")) != EOF)
+ switch (ch) {
+ case 'f':
+ EXCL_TEST;
+ fflag = 1;
+ break;
+ case 'h':
+ EXCL_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -h for super-user only.\n");
+ exit(1);
+ }
+ hflag = 1;
+ if (domain && (p = index(optarg, '.')) &&
+ strcmp(p, domain) == 0)
+ *p = 0;
+ hostname = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ EXCL_TEST;
+ if (getuid()) {
+ fprintf(stderr,
+ "login: -r for super-user only.\n");
+ exit(1);
+ }
+ /* "-r hostname" must be last args */
+ if (optind != argc) {
+ fprintf(stderr, "Syntax error.\n");
+ exit(1);
+ }
+ rflag = 1;
+ passwd_req = (doremotelogin(optarg) == -1);
+ if (domain && (p = index(optarg, '.')) &&
+ !strcmp(p, domain))
+ *p = '\0';
+ hostname = optarg;
+ break;
+ case 'g':
+ if (optind != argc) {
+ fprintf(stderr, "Syntax error.\n");
+ exit(1);
+ }
+ gflag = do_gss_login(optarg);
+ if (gflag == 1) passwd_req = 0;
+ else {
+ (void)ioctl(0, TIOCHPCL, (char *)0);
+ sleepexitnew(1,1);
+ }
+ hostname = optarg;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: login [-fp] [username]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+ if (*argv)
+ username = *argv;
+
+ ioctlval = 0;
+ (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
+ (void)ioctl(0, TIOCNXCL, (char *)0);
+ (void)fcntl(0, F_SETFL, ioctlval);
+ (void)ioctl(0, TIOCGETP, (char *)&sgttyb);
+
+ /*
+ * If talking to an rlogin process, propagate the terminal type and
+ * baud rate across the network.
+ */
+
+ if (rflag || kflag || Kflag || eflag || gflag)
+ doremoteterm(&sgttyb);
+ sgttyb.sg_erase = CERASE;
+ sgttyb.sg_kill = CKILL;
+ (void)ioctl(0, TIOCSLTC, (char *)<c);
+ (void)ioctl(0, TIOCSETC, (char *)&tc);
+ (void)ioctl(0, TIOCSETP, (char *)&sgttyb);
+
+ for (cnt = getdtablesize(); cnt > 2; cnt--)
+ (void) close(cnt);
+
+ ttyn = ttyname(0);
+ if (ttyn == NULL || *ttyn == '\0')
+ ttyn = "/dev/tty??";
+ if (tty = rindex(ttyn, '/'))
+ ++tty;
+ else
+ tty = ttyn;
+
+ for (cnt = 0;; username = NULL) {
+ ioctlval = 0;
+ (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+
+ if (username == NULL) {
+ fflag = 0;
+ getloginname();
+ }
+ if (pwd = getpwnam(username))
+ salt = pwd->pw_passwd;
+ else
+ salt = "xx";
+
+ /* if user not super-user, check for disabled logins */
+ if (pwd == NULL || pwd->pw_uid)
+ checknologin();
+
+ /*
+ * Disallow automatic login to root; if not invoked by
+ * root, disallow if the uid's differ.
+ */
+ if (fflag && pwd) {
+ int uid = (int) getuid();
+
+ passwd_req = pwd->pw_uid == 0 ||
+ (uid && uid != pwd->pw_uid);
+ }
+
+ /*
+ * If no remote login authentication and a password exists
+ * for this user, prompt for one and verify it.
+ */
+ if (!passwd_req || pwd && !*pwd->pw_passwd)
+ break;
+
+ (void) setpriority(PRIO_PROCESS, 0, -4);
+ p = crypt(getpass("password:"), salt);
+ (void) setpriority(PRIO_PROCESS, 0, 0);
+ if (pwd && !strcmp(p, pwd->pw_passwd))
+ break;
+
+ printf("Login incorrect\n");
+ if (++cnt >= 5) {
+ if (hostname)
+ syslog(LOG_ERR,
+ "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
+ tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
+ username);
+ else
+ syslog(LOG_ERR,
+ "REPEATED LOGIN FAILURES ON %s, %.*s",
+ tty, UT_NAMESIZE, username);
+ (void)ioctl(0, TIOCHPCL, (char *)0);
+ sleepexit(1);
+ }
+ }
+
+ /* committed to login -- turn off timeout */
+ (void)alarm((u_int)0);
+
+ /*
+ * If valid so far and root is logging in, see if root logins on
+ * this terminal are permitted.
+ */
+#ifndef SPX_CHALLENGE
+ if (pwd->pw_uid == 0 && !rootterm(tty)) {
+ if (hostname)
+ syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
+ tty, UT_HOSTSIZE, hostname);
+ else
+ syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
+ printf("Login incorrect\n");
+ sleepexit(1);
+ }
+#else
+ if (pwd->pw_uid == 0) {
+ syslog(LOG_INFO, "%s (%s)", userfullname, userlocalname);
+ }
+
+#endif /* SPX_CHALLENGE */
+
+#ifndef VFS
+ if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
+ switch(errno) {
+ case EUSERS:
+ fprintf(stderr,
+ "Too many users logged on already.\nTry again later.\n");
+ break;
+ case EPROCLIM:
+ fprintf(stderr,
+ "You have too many processes running.\n");
+ break;
+ default:
+ perror("quota (Q_SETUID)");
+ }
+ sleepexit(0);
+ }
+#endif /* !VFS */
+
+ if (chdir(pwd->pw_dir) < 0) {
+ printf("No directory %s!\n", pwd->pw_dir);
+ if (chdir("/"))
+ exit(0);
+ pwd->pw_dir = "/";
+ printf("Logging in with home = \"/\".\n");
+ }
+
+ /* nothing else left to fail -- really log in */
+ {
+ struct utmp utmp;
+
+ (void)time(&utmp.ut_time);
+ (void) strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
+ if (hostname)
+ (void) strncpy(utmp.ut_host, hostname,
+ sizeof(utmp.ut_host));
+ else
+ bzero(utmp.ut_host, sizeof(utmp.ut_host));
+ (void) strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+ login(&utmp);
+ }
+
+ quietlog = access(HUSHLOGIN, F_OK) == 0;
+ dolastlog(quietlog, tty);
+
+ if (!hflag && !rflag && !kflag && !Kflag && !eflag && !gflag) { /* XXX */
+ static struct winsize win = { 0, 0, 0, 0 };
+
+ (void)ioctl(0, TIOCSWINSZ, (char *)&win);
+ }
+
+ (void)chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+ (void)chmod(ttyn, 0620);
+ (void)setgid((gid_type) pwd->pw_gid);
+
+ (void) initgroups(username, pwd->pw_gid);
+
+#ifndef VFS
+ quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
+#endif
+ (void)setuid((uid_type) pwd->pw_uid);
+
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = BSHELL;
+ /* turn on new line discipline for the csh */
+ else if (!strcmp(pwd->pw_shell, "/bin/csh")) {
+ ioctlval = NTTYDISC;
+ (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+ }
+
+ /* destroy environment unless user has requested preservation */
+ if (!pflag)
+ environ = envinit;
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+ if (term[0] == '\0')
+ (void) strncpy(term, stypeof(tty), sizeof(term));
+ (void)setenv("TERM", term, 0);
+ (void)setenv("USER", pwd->pw_name, 1);
+ (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:/usr/local/bin:", 0);
+ major_status = gss__stash_default_cred(&minor_status,
+ gss_delegated_cred_handle);
+
+ if (tty[sizeof("tty")-1] == 'd')
+ syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+ if (pwd->pw_uid == 0)
+ if (hostname)
+ syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
+ tty, UT_HOSTSIZE, hostname);
+ else
+ syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
+
+ if (!quietlog) {
+ struct stat st;
+
+ motd();
+ (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
+ if (stat(tbuf, &st) == 0 && st.st_size != 0)
+ printf("You have %smail.\n",
+ (st.st_mtime > st.st_atime) ? "new " : "");
+ }
+
+#ifdef VFS
+ if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN);
+#endif VFS
+ (void)signal(SIGALRM, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGTSTP, SIG_IGN);
+
+ tbuf[0] = '-';
+ (void) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
+ p + 1 : pwd->pw_shell);
+ execlp(pwd->pw_shell, tbuf, 0);
+ fprintf(stderr, "login: no shell: ");
+ perror(pwd->pw_shell);
+ exit(0);
+}
+
+getloginname()
+{
+ register int ch;
+ register char *p;
+ static char nbuf[UT_NAMESIZE + 1];
+
+ for (;;) {
+ printf("login: ");
+ for (p = nbuf; (ch = getchar()) != '\n'; ) {
+ if (ch == EOF)
+ exit(0);
+ if (p < nbuf + UT_NAMESIZE)
+ *p++ = ch;
+ }
+ if (p > nbuf)
+ if (nbuf[0] == '-')
+ fprintf(stderr,
+ "login names may not start with '-'.\n");
+ else {
+ *p = '\0';
+ username = nbuf;
+ break;
+ }
+ }
+}
+
+sigtype
+timedout()
+{
+ fprintf(stderr, "Login timed out after %d seconds\n", timeout);
+ exit(0);
+}
+
+#ifdef NOTTYENT
+int root_tty_security = 0;
+#endif
+rootterm(tty)
+ char *tty;
+{
+#ifdef NOTTYENT
+ return(root_tty_security);
+#else
+ struct ttyent *t;
+
+ return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
+#endif NOTTYENT
+}
+
+jmp_buf motdinterrupt;
+
+motd()
+{
+ register int fd, nchars;
+ sigtype (*oldint)(), sigint();
+ char tbuf[8192];
+
+ if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
+ return;
+ signal(SIGINT, sigint);
+
+ if (setjmp(motdinterrupt) == 0)
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+ (void)close(fd);
+}
+
+sigtype
+sigint()
+{
+ longjmp(motdinterrupt, 1);
+}
+
+checknologin()
+{
+ register int fd, nchars;
+ char tbuf[8192];
+
+ if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+ sleepexit(0);
+ }
+}
+
+dolastlog(quiet, tty)
+ int quiet;
+ char *tty;
+{
+ struct lastlog ll;
+ int fd;
+
+ if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
+ (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
+ if (!quiet) {
+ if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
+ ll.ll_time != 0) {
+ printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&ll.ll_time));
+ if (*ll.ll_host != '\0')
+ printf("from %.*s\n",
+ sizeof(ll.ll_host), ll.ll_host);
+ else
+ printf("on %.*s\n",
+ sizeof(ll.ll_line), ll.ll_line);
+ }
+ (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
+ }
+ (void)time(&ll.ll_time);
+ (void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+ if (hostname)
+ (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+ else
+ (void) bzero(ll.ll_host, sizeof(ll.ll_host));
+ (void)write(fd, (char *)&ll, sizeof(ll));
+ (void)close(fd);
+ }
+}
+
+#undef UNKNOWN
+#define UNKNOWN "su"
+
+char *
+stypeof(ttyid)
+ char *ttyid;
+{
+#ifdef NOTTYENT
+ return(UNKNOWN);
+#else
+ struct ttyent *t;
+
+ return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
+#endif
+}
+
+doremotelogin(host)
+ char *host;
+{
+ static char lusername[UT_NAMESIZE+1];
+ char rusername[UT_NAMESIZE+1];
+
+ getstr(rusername, sizeof(rusername), "remuser");
+ getstr(lusername, sizeof(lusername), "locuser");
+ getstr(term, sizeof(term), "Terminal type");
+ username = lusername;
+ pwd = getpwnam(username);
+ if (pwd == NULL)
+ return(-1);
+ return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
+}
+
+do_gss_login(host)
+ char *host;
+{
+ int j, tokenlen, partlen, numbuf, i, debugflag = 0, auth_valid;
+ unsigned char token[GSS_C_MAX_TOKEN], *charp, *cp;
+ unsigned char tokenheader[4], send_tokenheader[4];
+ char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
+ char lhostname[GSS_C_MAX_PRINTABLE_NAME];
+ unsigned char chanbinding[8];
+ int chanbinding_len;
+ static char lusername[UT_NAMESIZE+1], rusername[UT_NAMESIZE+1];
+ int hostlen, xcc, need_to_exit = 0;
+/*
+ * GSS API support
+ */
+ gss_OID_set actual_mechs;
+ gss_OID actual_mech_type, output_name_type;
+ int major_status, status, msg_ctx = 0, new_status;
+ int req_flags = 0, ret_flags, lifetime_rec;
+ gss_cred_id_t gss_cred_handle;
+ gss_ctx_id_t actual_ctxhandle;
+ gss_buffer_desc output_token, input_token, input_name_buffer;
+ gss_buffer_desc status_string;
+ gss_name_t desired_targname, src_name;
+ gss_channel_bindings input_chan_bindings;
+
+
+ j = sphinx_net_read(3, tokenheader, 4);
+ if ((tokenheader[0] != TOKEN_MAJIC_NUMBER_BYTE0) ||
+(tokenheader[1] != TOKEN_MAJIC_NUMBER_BYTE1)) {
+ exit(0);
+ }
+ tokenlen = tokenheader[2] * 256 + tokenheader[3];
+
+ if (tokenlen > sizeof(token)) {
+ syslog(LOG_INFO, "token is too large, size is %d, buffer size
+is %d", tokenlen, sizeof(token));
+ exit(0);
+ }
+
+ charp = token;
+ j = sphinx_net_read(3, token, tokenlen);
+ if (j != tokenlen)
+ syslog(LOG_INFO,"%d = read(3, token, %d)",j, tokenlen);
+ close(3);
+
+ gethostname(lhostname, sizeof(lhostname));
+
+ strcpy(targ_printable, "SERVICE:rlogin@");
+ strcat(targ_printable, lhostname);
+/*
+ strcpy(targetname, lhostname);
+ if ((cp = index(targetname, '.')) != 0) *cp = '\0';
+*/
+
+ input_name_buffer.length = strlen(targ_printable);
+ input_name_buffer.value = targ_printable;
+
+ major_status = gss_import_name(&status,
+ &input_name_buffer,
+ GSS_C_NULL_OID,
+ &desired_targname);
+
+ major_status = gss_acquire_cred(&status,
+ desired_targname,
+ 0,
+ GSS_C_NULL_OID_SET,
+ GSS_C_ACCEPT,
+ &gss_cred_handle,
+ &actual_mechs,
+ &lifetime_rec);
+
+ major_status = gss_release_name(&status, desired_targname);
+
+ if (major_status != GSS_S_COMPLETE) {
+ xcc = write(0, "AuthentError", 12);
+ if (xcc <= 0)
+ syslog(LOG_INFO, "write(0, resp, 12): %m");
+
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf(stderr, "%s - ", status_string.value);
+ return(0);
+ }
+
+ getstr(rusername, sizeof (rusername), "remuser");
+ getstr(lusername, sizeof (lusername), "locuser");
+ getstr(term, sizeof(term), "Terminal type");
+
+ username = lusername;
+
+ pwd = getpwnam(lusername);
+ if (pwd == NULL) {
+ syslog(LOG_INFO,"passwd entry for '%s' is NULL",lusername);
+/*
+ xcc = write(0, "Auth Error ", 12);
+ if (xcc <= 0)
+ syslog(LOG_INFO, "write(0, resp, 12): %m");
+ fprintf(stderr, "SPX : user account '%s' doesn't exist - ", lusername);
+*/
+ }
+
+ if (major_status != GSS_S_COMPLETE) {
+ xcc = write(0, "AuthentError", 12);
+ if (xcc <= 0)
+ syslog(LOG_INFO, "write(0, resp, 12): %m");
+
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf(stderr, "%s - ", status_string.value);
+ return(0);
+ }
+
+ if (pwd != NULL) seteuid(pwd->pw_uid);
+
+ {
+ char myhost[32];
+ int from_addr=0, to_addr=0, myhostlen, j;
+ struct hostent *my_hp, *from_hp;
+ struct sockaddr_in sin, sin2;
+
+ from_hp=gethostbyname(host);
+ if (from_hp != 0) {
+ bcopy(from_hp->h_addr_list[0],
+ (caddr_t)&sin.sin_addr, from_hp->h_length);
+#ifdef ultrix
+ from_addr = sin.sin_addr.S_un.S_addr;
+#else
+ from_addr = sin.sin_addr.s_addr;
+#endif
+ } else {
+ from_addr = inet_addr(host);
+ }
+ from_addr = htonl(from_addr);
+ j=gethostname(myhost, sizeof(myhost));
+ my_hp=gethostbyname(myhost);
+ if (my_hp != 0) {
+ bcopy(my_hp->h_addr_list[0],
+ (caddr_t)&sin2.sin_addr, my_hp->h_length);
+#ifdef ultrix
+ to_addr = sin2.sin_addr.S_un.S_addr;
+#else
+ to_addr = sin2.sin_addr.s_addr;
+#endif
+ to_addr = htonl(to_addr);
+ }
+
+ input_chan_bindings = (gss_channel_bindings)
+ malloc(sizeof(gss_channel_bindings_desc));
+
+ input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
+ input_chan_bindings->initiator_address.length = 4;
+ input_chan_bindings->initiator_address.value = (char *) malloc(4);
+ input_chan_bindings->initiator_address.value[0] = ((from_addr
+& 0xff000000) >> 24);
+ input_chan_bindings->initiator_address.value[1] = ((from_addr
+& 0xff0000) >> 16);
+ input_chan_bindings->initiator_address.value[2] = ((from_addr
+& 0xff00) >> 8);
+ input_chan_bindings->initiator_address.value[3] = (from_addr & 0xff);
+ input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
+ input_chan_bindings->acceptor_address.length = 4;
+ input_chan_bindings->acceptor_address.value = (char *) malloc(4);
+ input_chan_bindings->acceptor_address.value[0] = ((to_addr &
+0xff000000) >> 24);
+ input_chan_bindings->acceptor_address.value[1] = ((to_addr &
+0xff0000) >> 16);
+ input_chan_bindings->acceptor_address.value[2] = ((to_addr &
+0xff00) >> 8);
+ input_chan_bindings->acceptor_address.value[3] = (to_addr & 0xff);
+ input_chan_bindings->application_data.length = 0;
+ }
+
+ input_token.length = tokenlen;
+ input_token.value = token;
+
+ major_status = gss_accept_sec_context(&status,
+ &context_handle,
+ gss_cred_handle,
+ &input_token,
+ input_chan_bindings,
+ &src_name,
+ &actual_mech_type,
+ &output_token,
+ &ret_flags,
+ &lifetime_rec,
+ &gss_delegated_cred_handle);
+
+ if (output_token.length != 0) {
+
+ send_tokenheader[0] = TOKEN_MAJIC_NUMBER_BYTE0;
+ send_tokenheader[1] = TOKEN_MAJIC_NUMBER_BYTE1;
+ send_tokenheader[2] = ((output_token.length & 0xff00) >> 8);
+ send_tokenheader[3] = (output_token.length & 0xff);
+
+ xcc = write(0, (char *) send_tokenheader, 4);
+ if (xcc != 4)
+ syslog(LOG_INFO, "write(0, send_tokenheader, 4): %m");
+
+ xcc = write(0, (char *) output_token.value, output_token.length);
+ if (xcc <= 0)
+ syslog(LOG_INFO, "write(0, resp, %d): %m",output_token.length);
+ }
+
+ if (pwd == NULL) {
+ fprintf(stderr, "SPX : user account '%s' doesn't exist - ", lusername);
+ return(-1);
+ }
+ if (getuid()) {
+ syslog(LOG_INFO,"getuid() is 0, so return nouser");
+ return(0);
+ }
+
+ if (major_status != GSS_S_COMPLETE) {
+ syslog(LOG_INFO, "got error on accept\n");
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf(stderr, "%s - ", status_string.value);
+ return(-1);
+ }
+
+#ifdef SPX_CHALLENGE
+ /*
+ * if trying to login to root account, then we need to verify response
+ * proving that the user is interactive.
+ *
+ */
+ if (strcmp(lusername, "root")==0) {
+ j = sphinx_net_read(0, tokenheader, 4);
+ if (j != 4)
+ syslog(LOG_INFO,"%d = read(0, token, 4)",j);
+
+ if ((tokenheader[0] != TOKEN_MAJIC_NUMBER_BYTE0) ||
+(tokenheader[1] != TOKEN_MAJIC_NUMBER_BYTE1)) {
+ exit(0);
+ }
+ tokenlen = tokenheader[2] * 256 + tokenheader[3];
+ if (tokenlen > sizeof(token)) {
+ syslog(LOG_INFO, "token too large, %d/%d",tokenlen,sizeof(token));
+ exit(0);
+ }
+
+ charp = token;
+ j = sphinx_net_read(0, token, tokenlen);
+ if (j != tokenlen)
+ syslog(LOG_INFO,"%d = read(0, token, %d)",j, tokenlen);
+ major_status = spx_verify_response(&status,
+ context_handle,
+ gss_cred_handle,
+ token,
+ tokenlen);
+ if (major_status != GSS_S_COMPLETE) {
+ gss_display_status(&new_status,
+ status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx,
+ &status_string);
+ fprintf(stderr, "%s - ", status_string.value);
+ return(0);
+ }
+ }
+#endif /* SPX_CHALLENGE */
+
+ seteuid(0);
+
+ {
+ gss_buffer_desc fullname_buffer, luser_buffer, acl_file_buffer;
+ gss_buffer_desc service_buffer, resource_buffer;
+ gss_OID fullname_type;
+ int access_mode;
+ char acl_file[160], service[60], resource[160];
+
+ major_status = gss_display_name(&status,
+ src_name,
+ &fullname_buffer,
+ &fullname_type);
+
+ luser_buffer.value = lusername;
+ luser_buffer.length = strlen(lusername);
+
+ strcpy(acl_file, pwd->pw_dir);
+ strcat(acl_file, "/.sphinx");
+ acl_file_buffer.value = acl_file;
+ acl_file_buffer.length = strlen(acl_file);
+
+ strcpy(service, "flogin");
+ service_buffer.value = service;
+ service_buffer.length = 6;
+ resource[0] = '\0';
+ resource_buffer.value = resource;
+ resource_buffer.length = 0;
+ access_mode = GSS_C_READ | GSS_C_WRITE;
+
+ major_status = gss__check_authorization(&status,
+ &fullname_buffer,
+ &luser_buffer,
+ &acl_file_buffer,
+ &service_buffer,
+ access_mode,
+ &resource_buffer);
+
+ if (major_status != GSS_S_COMPLETE) {
+ if (strcmp(lusername, "root")==0)
+ syslog(LOG_INFO, "root authorization denied - '%s'", src_name);
+ fprintf(stderr, "SPX : authorization denied to user account
+'%s' - ", lusername);
+ return(-1);
+ } else {
+ strcpy(userfullname, src_name);
+ strcpy(userlocalname, rusername);
+ }
+ major_status = gss_release_buffer(&status, &fullname_buffer);
+ return(1);
+ }
+}
+
+getstr(buf, cnt, err)
+ char *buf, *err;
+ int cnt;
+{
+ char ch;
+
+ do {
+ if (read(0, &ch, sizeof(ch)) != sizeof(ch))
+ exit(1);
+ if (--cnt < 0) {
+ fprintf(stderr, "%s too long\r\n", err);
+ sleepexit(1);
+ }
+ *buf++ = ch;
+ } while (ch);
+}
+
+char *speeds[] = {
+ "0", "50", "75", "110", "134", "150", "200", "300", "600",
+ "1200", "1800", "2400", "4800", "9600", "19200", "38400",
+};
+#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
+
+doremoteterm(tp)
+ struct sgttyb *tp;
+{
+ register char *cp = index(term, '/'), **cpp;
+ char *speed;
+
+ if (cp) {
+ *cp++ = '\0';
+ speed = cp;
+ cp = index(speed, '/');
+ if (cp)
+ *cp++ = '\0';
+ for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
+ if (strcmp(*cpp, speed) == 0) {
+ tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
+ break;
+ }
+ }
+ tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
+}
+
+sleepexitnew(eval, interval)
+ int eval, interval;
+{
+ sleep((u_int)interval);
+ exit(eval);
+}
+
+
+sleepexit(eval)
+ int eval;
+{
+ sleep((u_int)5);
+ exit(eval);
+}