*** empty log message ***
authorTheodore Tso <tytso@mit.edu>
Mon, 3 Jun 1991 15:59:54 +0000 (15:59 +0000)
committerTheodore Tso <tytso@mit.edu>
Mon, 3 Jun 1991 15:59:54 +0000 (15:59 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2135 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/gssapi/sample/fcmd.c [new file with mode: 0644]
src/lib/gssapi/sample/flogin.c [new file with mode: 0644]
src/lib/gssapi/sample/flogind.c [new file with mode: 0644]
src/lib/gssapi/sample/login.c [new file with mode: 0644]

diff --git a/src/lib/gssapi/sample/fcmd.c b/src/lib/gssapi/sample/fcmd.c
new file mode 100644 (file)
index 0000000..a3de08f
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * 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));
+}
diff --git a/src/lib/gssapi/sample/flogin.c b/src/lib/gssapi/sample/flogin.c
new file mode 100644 (file)
index 0000000..1bb041c
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * 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 *)&notc);
+       }
+       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 *)&notc);
+       }
+       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 = &notc;
+               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
diff --git a/src/lib/gssapi/sample/flogind.c b/src/lib/gssapi/sample/flogind.c
new file mode 100644 (file)
index 0000000..97ae704
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * 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);
+}
diff --git a/src/lib/gssapi/sample/login.c b/src/lib/gssapi/sample/login.c
new file mode 100644 (file)
index 0000000..b984b2b
--- /dev/null
@@ -0,0 +1,1016 @@
+/*
+ * 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 *)&ltc);
+       (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);
+}