From: Theodore Tso Date: Mon, 3 Jun 1991 15:59:54 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: krb5-1.0-beta1~35 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=f20ad9f3cd9987c598dce272081aad593e24d7e0;p=krb5.git *** empty log message *** git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2135 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/gssapi/sample/fcmd.c b/src/lib/gssapi/sample/fcmd.c new file mode 100644 index 000000000..a3de08fb1 --- /dev/null +++ b/src/lib/gssapi/sample/fcmd.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#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 index 000000000..1bb041ccd --- /dev/null +++ b/src/lib/gssapi/sample/flogin.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef ultrix +#include +#endif +#include + +#include "gssapi_defs.h" + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 /* standard in */ +#endif + +#define FLOGIN_PORT 221 + +#ifndef TIOCPKT_WINDOW +#define TIOCPKT_WINDOW 0x80 +#endif + +/* concession to Sun */ +#ifndef SIGUSR1 +#define SIGUSR1 30 +#endif + +extern int errno; +int eight, litout, rem; +char cmdchar; +char *speeds[] = { + "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", + "1800", "2400", "4800", "9600", "19200", "38400" +}; + +#ifdef sun +struct winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; +#endif +struct winsize winsize; + +#ifndef sun +#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) +#endif + +void exit(); + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + struct passwd *pw; + struct servent *sp; + struct sgttyb ttyb; + long omask; + int argoff, ch, dflag, one, uid; + char *host, *p, *user, term[1024]; + void lostpeer(); + char *getenv(); + int mutual_flag = 1, deleg_flag = 1, sock = 0; + int debugflag = 0; + gss_cred_id_t context_handle; + + argoff = dflag = 0; + one = 1; + host = user = NULL; + cmdchar = '~'; + + if (p = rindex(argv[0], '/')) + ++p; + else + p = argv[0]; + + /* handle "flogin host flags" */ + if (!host && argc > 2 && argv[1][0] != '-') { + host = argv[1]; + argoff = 1; + } + +#define OPTIONS "8Lde:l:vn" + + while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) + switch(ch) { + case '8': + eight = 1; + break; + case 'L': + litout = 1; + break; + case 'd': + dflag = 1; + break; + case 'e': + cmdchar = optarg[0]; + break; + case 'l': + user = optarg; + break; + case 'v': + debugflag = 1; + break; + case 'n': + deleg_flag = 0; + break; + case '?': + default: + usage(); + } + optind += argoff; + argc -= optind; + argv += optind; + + /* if haven't gotten a host yet, do so */ + if (!host && !(host = *argv++)) + usage(); + + if (*argv) + usage(); + + if (!(pw = getpwuid(uid = getuid()))) { + (void)fprintf(stderr, "flogin: unknown user id.\n"); + exit(1); + } + if (!user) + user = pw->pw_name; + + sp = NULL; + + /* + * if remote login to root account, force no delegation + */ + if (strcmp(user, "root")==0) deleg_flag=0; + sp = getservbyname("flogin", "tcp"); + if (sp == NULL) { + sp = (struct servent *) malloc(sizeof(struct servent)); + sp->s_port = htons(FLOGIN_PORT); + } + + if (sp == NULL) + sp = getservbyname("login", "tcp"); + if (sp == NULL) { + (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); + exit(1); + } + + (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); + if (ioctl(0, TIOCGETP, &ttyb) == 0) { + (void)strcat(term, "/"); + (void)strcat(term, speeds[ttyb.sg_ospeed]); + } + + (void)get_window_size(0, &winsize); + + (void)signal(SIGPIPE, lostpeer); + /* will use SIGUSR1 for window size hack, so hold it off */ + omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); + + rem = fcmd(&sock, &host, sp->s_port, pw->pw_name, + user, term, 0, host, &context_handle, + mutual_flag, deleg_flag, debugflag); + + if (rem < 0) + exit(1); + + if (dflag && + setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) + (void)fprintf(stderr, "flogin: setsockopt: errno %d.\n", + errno); + + (void)setuid(uid); + doit(omask); + /*NOTREACHED*/ +} + +int child, defflags, deflflags, tabflag; +char deferase, defkill; +struct tchars deftc; +struct ltchars defltc; +struct tchars notc = { -1, -1, -1, -1, -1, -1 }; +struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; + +doit(omask) + long omask; +{ + struct sgttyb sb; + void catch_child(), copytochild(), exit(), writeroob(); + + (void)ioctl(0, TIOCGETP, (char *)&sb); + defflags = sb.sg_flags; + tabflag = defflags & TBDELAY; + defflags &= ECHO | CRMOD; + deferase = sb.sg_erase; + defkill = sb.sg_kill; + (void)ioctl(0, TIOCLGET, (char *)&deflflags); + (void)ioctl(0, TIOCGETC, (char *)&deftc); + notc.t_startc = deftc.t_startc; + notc.t_stopc = deftc.t_stopc; + (void)ioctl(0, TIOCGLTC, (char *)&defltc); + (void)signal(SIGINT, SIG_IGN); + setsignal(SIGHUP, exit); + setsignal(SIGQUIT, exit); + child = fork(); + if (child == -1) { + (void)fprintf(stderr, "rlogin: fork: errno %d.\n", errno); + done(1); + } + if (child == 0) { + mode(1); + if (reader(omask) == 0) { + msg("connection closed."); + exit(0); + } + sleep(1); + msg("\007connection closed."); + exit(1); + } + + /* + * We may still own the socket, and may have a pending SIGURG (or might + * receive one soon) that we really want to send to the reader. Set a + * trap that simply copies such signals to the child. + */ + (void)signal(SIGURG, copytochild); + (void)signal(SIGUSR1, writeroob); + (void)sigsetmask(omask); + (void)signal(SIGCHLD, catch_child); + writer(); + msg("closed connection."); + done(0); +} + +/* trap a signal, unless it is being ignored. */ +setsignal(sig, act) + int sig; + void (*act)(); +{ + int omask = sigblock(sigmask(sig)); + + if (signal(sig, act) == SIG_IGN) + (void)signal(sig, SIG_IGN); + (void)sigsetmask(omask); +} + +done(status) + int status; +{ + int w; + + mode(0); + if (child > 0) { + /* make sure catch_child does not snap it up */ + (void)signal(SIGCHLD, SIG_DFL); + if (kill(child, SIGKILL) >= 0) + while ((w = wait((union wait *)0)) > 0 && w != child); + } + exit(status); +} + +int dosigwinch; + +/* + * This is called when the reader process gets the out-of-band (urgent) + * request to turn on the window-changing protocol. + */ +void +writeroob() +{ + void sigwinch(); + + if (dosigwinch == 0) { + sendwindow(); + (void)signal(SIGWINCH, sigwinch); + } + dosigwinch = 1; +} + +void +catch_child() +{ + union wait status; + int pid; + + for (;;) { + pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0); + if (pid == 0) + return; + /* if the child (reader) dies, just quit */ + if (pid < 0 || pid == child && !WIFSTOPPED(status)) + done((int)(status.w_termsig | status.w_retcode)); + } + /* NOTREACHED */ +} + +/* + * writer: write to remote: 0 -> line. + * ~. terminate + * ~^Z suspend rlogin process. + * ~^Y suspend rlogin process, but leave reader alone. + */ +writer() +{ + char c; + register int bol, local, n; + + bol = 1; /* beginning of line */ + local = 0; + for (;;) { + n = read(STDIN_FILENO, &c, 1); + if (n <= 0) { + if (n < 0 && errno == EINTR) + continue; + break; + } + /* + * If we're at the beginning of the line and recognize a + * command character, then we echo locally. Otherwise, + * characters are echo'd remotely. If the command character + * is doubled, this acts as a force and local echo is + * suppressed. + */ + if (bol) { + bol = 0; + if (c == cmdchar) { + bol = 0; + local = 1; + continue; + } + } else if (local) { + local = 0; + if (c == '.' || c == deftc.t_eofc) { + echo(c); + break; + } + if (c == defltc.t_suspc || c == defltc.t_dsuspc) { + bol = 1; + echo(c); + stop(c); + continue; + } + if (c != cmdchar) { + (void)write(rem, &cmdchar, 1); + } + } + + if (write(rem, &c, 1) == 0) { + msg("line gone"); + break; + } + bol = c == defkill || c == deftc.t_eofc || + c == deftc.t_intrc || c == defltc.t_suspc || + c == '\r' || c == '\n'; + } +} + +echo(c) +register char c; +{ + register char *p; + char buf[8]; + + p = buf; + c &= 0177; + *p++ = cmdchar; + if (c < ' ') { + *p++ = '^'; + *p++ = c + '@'; + } else if (c == 0177) { + *p++ = '^'; + *p++ = '?'; + } else + *p++ = c; + *p++ = '\r'; + *p++ = '\n'; + (void)write(1, buf, p - buf); +} + +stop(cmdc) + char cmdc; +{ + mode(0); + (void)signal(SIGCHLD, SIG_IGN); + (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); + (void)signal(SIGCHLD, catch_child); + mode(1); + sigwinch(); /* check for size changes */ +} + +void +sigwinch() +{ + struct winsize ws; + + if (dosigwinch && get_window_size(0, &ws) == 0 && + bcmp(&ws, &winsize, sizeof(ws))) { + winsize = ws; + sendwindow(); + } +} + +/* + * Send the window size to the server via the magic escape + */ +sendwindow() +{ + struct winsize *wp; + char obuf[4 + sizeof (struct winsize)]; + + wp = (struct winsize *)(obuf+4); + obuf[0] = 0377; + obuf[1] = 0377; + obuf[2] = 's'; + obuf[3] = 's'; + wp->ws_row = htons(winsize.ws_row); + wp->ws_col = htons(winsize.ws_col); + wp->ws_xpixel = htons(winsize.ws_xpixel); + wp->ws_ypixel = htons(winsize.ws_ypixel); + + (void)write(rem, obuf, sizeof(obuf)); +} + +/* + * reader: read from remote: line -> 1 + */ +#define READING 1 +#define WRITING 2 + +jmp_buf rcvtop; +int ppid, rcvcnt, rcvstate; +char rcvbuf[8 * 1024]; + +void +oob() +{ + struct sgttyb sb; + int atmark, n, out, rcvd; + char waste[BUFSIZ], mark; + + out = O_RDWR; + rcvd = 0; + while (recv(rem, &mark, 1, MSG_OOB) < 0) + switch (errno) { + case EWOULDBLOCK: + /* + * Urgent data not here yet. It may not be possible + * to send it yet if we are blocked for output and + * our input buffer is full. + */ + if (rcvcnt < sizeof(rcvbuf)) { + n = read(rem, rcvbuf + rcvcnt, + sizeof(rcvbuf) - rcvcnt); + if (n <= 0) + return; + rcvd += n; + } else { + n = read(rem, waste, sizeof(waste)); + if (n <= 0) + return; + } + continue; + default: + return; + } + if (mark & TIOCPKT_WINDOW) { + /* Let server know about window size changes */ + (void)kill(ppid, SIGUSR1); + } + if (!eight && (mark & TIOCPKT_NOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~CBREAK; + sb.sg_flags |= RAW; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = -1; + notc.t_startc = -1; + (void)ioctl(0, TIOCSETC, (char *)¬c); + } + if (!eight && (mark & TIOCPKT_DOSTOP)) { + (void)ioctl(0, TIOCGETP, (char *)&sb); + sb.sg_flags &= ~RAW; + sb.sg_flags |= CBREAK; + (void)ioctl(0, TIOCSETN, (char *)&sb); + notc.t_stopc = deftc.t_stopc; + notc.t_startc = deftc.t_startc; + (void)ioctl(0, TIOCSETC, (char *)¬c); + } + if (mark & TIOCPKT_FLUSHWRITE) { + (void)ioctl(1, TIOCFLUSH, (char *)&out); + for (;;) { + if (ioctl(rem, SIOCATMARK, &atmark) < 0) { + (void)fprintf(stderr, "rlogin: ioctl: errno %d.\n", + errno); + break; + } + if (atmark) + break; + n = read(rem, waste, sizeof (waste)); + if (n <= 0) + break; + } + /* + * Don't want any pending data to be output, so clear the recv + * buffer. If we were hanging on a write when interrupted, + * don't want it to restart. If we were reading, restart + * anyway. + */ + rcvcnt = 0; + longjmp(rcvtop, 1); + } + + /* oob does not do FLUSHREAD (alas!) */ + + /* + * If we filled the receive buffer while a read was pending, longjmp + * to the top to restart appropriately. Don't abort a pending write, + * however, or we won't know how much was written. + */ + if (rcvd && rcvstate == READING) + longjmp(rcvtop, 1); +} + +/* reader: read from remote: line -> 1 */ +reader(omask) + int omask; +{ + void oob(); + +#if !defined(BSD) || BSD < 43 + int pid = -getpid(); +#else + int pid = getpid(); +#endif + int n, remaining; + char *bufp = rcvbuf; + + (void)signal(SIGTTOU, SIG_IGN); + (void)signal(SIGURG, oob); + ppid = getppid(); + (void)fcntl(rem, F_SETOWN, pid); + (void)setjmp(rcvtop); + (void)sigsetmask(omask); + for (;;) { + while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { + rcvstate = WRITING; + n = write(1, bufp, remaining); + if (n < 0) { + if (errno != EINTR) + return(-1); + continue; + } + bufp += n; + } + bufp = rcvbuf; + rcvcnt = 0; + rcvstate = READING; + + rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); + if (rcvcnt == 0) + return (0); + if (rcvcnt < 0) { + if (errno == EINTR) + continue; + (void)fprintf(stderr, "rlogin: read: errno %d.\n", + errno); + return(-1); + } + } +} + +mode(f) +{ + struct ltchars *ltc; + struct sgttyb sb; + struct tchars *tc; + int lflags; + + (void)ioctl(0, TIOCGETP, (char *)&sb); + (void)ioctl(0, TIOCLGET, (char *)&lflags); + switch(f) { + case 0: + sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); + sb.sg_flags |= defflags|tabflag; + tc = &deftc; + ltc = &defltc; + sb.sg_kill = defkill; + sb.sg_erase = deferase; + lflags = deflflags; + break; + case 1: + sb.sg_flags |= (eight ? RAW : CBREAK); + sb.sg_flags &= ~defflags; + /* preserve tab delays, but turn off XTABS */ + if ((sb.sg_flags & TBDELAY) == XTABS) + sb.sg_flags &= ~TBDELAY; + tc = ¬c; + ltc = &noltc; + sb.sg_kill = sb.sg_erase = -1; + if (litout) + lflags |= LLITOUT; + break; + default: + return; + } + (void)ioctl(0, TIOCSLTC, (char *)ltc); + (void)ioctl(0, TIOCSETC, (char *)tc); + (void)ioctl(0, TIOCSETN, (char *)&sb); + (void)ioctl(0, TIOCLSET, (char *)&lflags); +} + +void +lostpeer() +{ + (void)signal(SIGPIPE, SIG_IGN); + msg("\007connection closed."); + done(1); +} + +/* copy SIGURGs to the child process. */ +void +copytochild() +{ + (void)kill(child, SIGURG); +} + +msg(str) + char *str; +{ + (void)fprintf(stderr, "flogin: %s\r\n", str); +} + +warning(msg) +char *msg; +{ + (void) fprintf(stderr, msg); + fflush(stderr); +} + + +usage() +{ + (void)fprintf(stderr, + "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", + "8L", " "); + exit(1); +} + +/* + * The following routine provides compatibility (such as it is) between 4.2BSD + * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. + */ +#ifdef sun +int +get_window_size(fd, wp) + int fd; + struct winsize *wp; +{ + struct ttysize ts; + int error; + + if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) + return(error); + wp->ws_row = ts.ts_lines; + wp->ws_col = ts.ts_cols; + wp->ws_xpixel = 0; + wp->ws_ypixel = 0; + return(0); +} +#endif diff --git a/src/lib/gssapi/sample/flogind.c b/src/lib/gssapi/sample/flogind.c new file mode 100644 index 000000000..97ae7040e --- /dev/null +++ b/src/lib/gssapi/sample/flogind.c @@ -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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#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<= 0) + if (pcc) + obits |= (1< 0) + +bcopy(cp+n, cp, left); + fcc -= n; + goto top; /* n^2 */ + } + } + } + } + + if ((obits & (1< 0) { + cc = write(p, fbp, fcc); + if (cc > 0) { + fcc -= cc; + fbp += cc; + } + } + + if (ibits & (1< 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 index 000000000..b984b2b63 --- /dev/null +++ b/src/lib/gssapi/sample/login.c @@ -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 +#ifndef VFS +#include +#endif VFS +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifndef NOTTYENT +#include +#endif /* NOTTYENT */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "gssapi_defs.h" + +#define TOKEN_MAJIC_NUMBER_BYTE0 1 +#define TOKEN_MAJIC_NUMBER_BYTE1 1 + +char userfullname[GSS_C_MAX_PRINTABLE_NAME]; +char userlocalname[GSS_C_MAX_PRINTABLE_NAME]; +gss_cred_id_t gss_delegated_cred_handle; + +#ifdef UIDGID_T +uid_t getuid(); +#define uid_type uid_t +#define gid_type gid_t +#else +int getuid(); +#define uid_type int +#define gid_type int +#endif /* UIDGID_T */ + +#define TTYGRPNAME "tty" /* name of group to own ttys */ + +#define MOTDFILE "/etc/motd" +#define MAILDIR "/usr/spool/mail" +#define NOLOGIN "/etc/nologin" +#define HUSHLOGIN ".hushlogin" +#define LASTLOG "/usr/adm/lastlog" +#define BSHELL "/bin/sh" + +#ifdef VFS +#define QUOTAWARN "/usr/ucb/quota" /* warn user about quotas */ +#endif VFS + +#define UT_HOSTSIZE sizeof(((struct utmp *)0)->ut_host) +#define UT_NAMESIZE sizeof(((struct utmp *)0)->ut_name) + +/* + * This bounds the time given to login. Not a define so it can + * be patched on machines where it's too small. + */ +int timeout = 300; + +struct passwd *pwd; +char term[64], *hostname, *username; + +gss_ctx_id_t context_handle; + +struct sgttyb sgttyb; +struct tchars tc = { + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK +}; +struct ltchars ltc = { + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT +}; + +extern int errno; + +#ifdef POSIX +typedef void sigtype; +#else +typedef int sigtype; +#endif /* POSIX */ + +#define EXCL_TEST if (rflag || kflag || Kflag || eflag || \ + fflag || hflag) { \ + fprintf(stderr, \ + "login: only one of -r, -k, -K, -e, +-h and -f allowed.\n"); \ + exit(1);\ + } +main(argc, argv) + int argc; + char **argv; +{ + extern int optind; + extern char *optarg, **environ; + struct group *gr; + register int ch; + register char *p; + + int gflag; + + int fflag, hflag, pflag, rflag, cnt; + int kflag, Kflag, eflag; + int quietlog, passwd_req, ioctlval, major_status, minor_status; + sigtype timedout(); + char *domain, *salt, *envinit[1], *ttyn, *tty; + char tbuf[MAXPATHLEN + 2]; + char *ttyname(), *stypeof(), *crypt(), *getpass(); + time_t time(); + off_t lseek(); + + (void)signal(SIGALRM, timedout); + (void)alarm((u_int)timeout); + (void)signal(SIGQUIT, SIG_IGN); + (void)signal(SIGINT, SIG_IGN); + (void)setpriority(PRIO_PROCESS, 0, 0); +#ifndef VFS + (void)quota(Q_SETUID, 0, 0, 0); +#endif VFS + + /* + * -s is used by flogind to cause the SPX autologin protocol; + * -p is used by getty to tell login not to destroy the environment + * -r is used by rlogind to cause the autologin protocol; + * -f is used to skip a second login authentication + * -e is used to skip a second login authentication, but allows + * login as root. + * -h is used by other servers to pass the name of the + * remote host to login so that it may be placed in utmp and wtmp + * -k is used by klogind to cause the Kerberos autologin protocol; + * -K is used by klogind to cause the Kerberos autologin protocol with + * restricted access.; + */ + (void)gethostname(tbuf, sizeof(tbuf)); + domain = index(tbuf, '.'); + + fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0; + passwd_req = 1; + while ((ch = getopt(argc, argv, "feh:pr:k:K:g:")) != EOF) + switch (ch) { + case 'f': + EXCL_TEST; + fflag = 1; + break; + case 'h': + EXCL_TEST; + if (getuid()) { + fprintf(stderr, + "login: -h for super-user only.\n"); + exit(1); + } + hflag = 1; + if (domain && (p = index(optarg, '.')) && + strcmp(p, domain) == 0) + *p = 0; + hostname = optarg; + break; + case 'p': + pflag = 1; + break; + case 'r': + EXCL_TEST; + if (getuid()) { + fprintf(stderr, + "login: -r for super-user only.\n"); + exit(1); + } + /* "-r hostname" must be last args */ + if (optind != argc) { + fprintf(stderr, "Syntax error.\n"); + exit(1); + } + rflag = 1; + passwd_req = (doremotelogin(optarg) == -1); + if (domain && (p = index(optarg, '.')) && + !strcmp(p, domain)) + *p = '\0'; + hostname = optarg; + break; + case 'g': + if (optind != argc) { + fprintf(stderr, "Syntax error.\n"); + exit(1); + } + gflag = do_gss_login(optarg); + if (gflag == 1) passwd_req = 0; + else { + (void)ioctl(0, TIOCHPCL, (char *)0); + sleepexitnew(1,1); + } + hostname = optarg; + break; + case '?': + default: + fprintf(stderr, "usage: login [-fp] [username]\n"); + exit(1); + } + argc -= optind; + argv += optind; + if (*argv) + username = *argv; + + ioctlval = 0; + (void)ioctl(0, TIOCLSET, (char *)&ioctlval); + (void)ioctl(0, TIOCNXCL, (char *)0); + (void)fcntl(0, F_SETFL, ioctlval); + (void)ioctl(0, TIOCGETP, (char *)&sgttyb); + + /* + * If talking to an rlogin process, propagate the terminal type and + * baud rate across the network. + */ + + if (rflag || kflag || Kflag || eflag || gflag) + doremoteterm(&sgttyb); + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; + (void)ioctl(0, TIOCSLTC, (char *)<c); + (void)ioctl(0, TIOCSETC, (char *)&tc); + (void)ioctl(0, TIOCSETP, (char *)&sgttyb); + + for (cnt = getdtablesize(); cnt > 2; cnt--) + (void) close(cnt); + + ttyn = ttyname(0); + if (ttyn == NULL || *ttyn == '\0') + ttyn = "/dev/tty??"; + if (tty = rindex(ttyn, '/')) + ++tty; + else + tty = ttyn; + + for (cnt = 0;; username = NULL) { + ioctlval = 0; + (void)ioctl(0, TIOCSETD, (char *)&ioctlval); + + if (username == NULL) { + fflag = 0; + getloginname(); + } + if (pwd = getpwnam(username)) + salt = pwd->pw_passwd; + else + salt = "xx"; + + /* if user not super-user, check for disabled logins */ + if (pwd == NULL || pwd->pw_uid) + checknologin(); + + /* + * Disallow automatic login to root; if not invoked by + * root, disallow if the uid's differ. + */ + if (fflag && pwd) { + int uid = (int) getuid(); + + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); + } + + /* + * If no remote login authentication and a password exists + * for this user, prompt for one and verify it. + */ + if (!passwd_req || pwd && !*pwd->pw_passwd) + break; + + (void) setpriority(PRIO_PROCESS, 0, -4); + p = crypt(getpass("password:"), salt); + (void) setpriority(PRIO_PROCESS, 0, 0); + if (pwd && !strcmp(p, pwd->pw_passwd)) + break; + + printf("Login incorrect\n"); + if (++cnt >= 5) { + if (hostname) + syslog(LOG_ERR, + "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", + tty, UT_HOSTSIZE, hostname, UT_NAMESIZE, + username); + else + syslog(LOG_ERR, + "REPEATED LOGIN FAILURES ON %s, %.*s", + tty, UT_NAMESIZE, username); + (void)ioctl(0, TIOCHPCL, (char *)0); + sleepexit(1); + } + } + + /* committed to login -- turn off timeout */ + (void)alarm((u_int)0); + + /* + * If valid so far and root is logging in, see if root logins on + * this terminal are permitted. + */ +#ifndef SPX_CHALLENGE + if (pwd->pw_uid == 0 && !rootterm(tty)) { + if (hostname) + syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s", + tty, UT_HOSTSIZE, hostname); + else + syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty); + printf("Login incorrect\n"); + sleepexit(1); + } +#else + if (pwd->pw_uid == 0) { + syslog(LOG_INFO, "%s (%s)", userfullname, userlocalname); + } + +#endif /* SPX_CHALLENGE */ + +#ifndef VFS + if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { + switch(errno) { + case EUSERS: + fprintf(stderr, + "Too many users logged on already.\nTry again later.\n"); + break; + case EPROCLIM: + fprintf(stderr, + "You have too many processes running.\n"); + break; + default: + perror("quota (Q_SETUID)"); + } + sleepexit(0); + } +#endif /* !VFS */ + + if (chdir(pwd->pw_dir) < 0) { + printf("No directory %s!\n", pwd->pw_dir); + if (chdir("/")) + exit(0); + pwd->pw_dir = "/"; + printf("Logging in with home = \"/\".\n"); + } + + /* nothing else left to fail -- really log in */ + { + struct utmp utmp; + + (void)time(&utmp.ut_time); + (void) strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + if (hostname) + (void) strncpy(utmp.ut_host, hostname, + sizeof(utmp.ut_host)); + else + bzero(utmp.ut_host, sizeof(utmp.ut_host)); + (void) strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + login(&utmp); + } + + quietlog = access(HUSHLOGIN, F_OK) == 0; + dolastlog(quietlog, tty); + + if (!hflag && !rflag && !kflag && !Kflag && !eflag && !gflag) { /* XXX */ + static struct winsize win = { 0, 0, 0, 0 }; + + (void)ioctl(0, TIOCSWINSZ, (char *)&win); + } + + (void)chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + (void)chmod(ttyn, 0620); + (void)setgid((gid_type) pwd->pw_gid); + + (void) initgroups(username, pwd->pw_gid); + +#ifndef VFS + quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); +#endif + (void)setuid((uid_type) pwd->pw_uid); + + if (*pwd->pw_shell == '\0') + pwd->pw_shell = BSHELL; + /* turn on new line discipline for the csh */ + else if (!strcmp(pwd->pw_shell, "/bin/csh")) { + ioctlval = NTTYDISC; + (void)ioctl(0, TIOCSETD, (char *)&ioctlval); + } + + /* destroy environment unless user has requested preservation */ + if (!pflag) + environ = envinit; + (void)setenv("HOME", pwd->pw_dir, 1); + (void)setenv("SHELL", pwd->pw_shell, 1); + if (term[0] == '\0') + (void) strncpy(term, stypeof(tty), sizeof(term)); + (void)setenv("TERM", term, 0); + (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:/usr/local/bin:", 0); + major_status = gss__stash_default_cred(&minor_status, + gss_delegated_cred_handle); + + if (tty[sizeof("tty")-1] == 'd') + syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); + if (pwd->pw_uid == 0) + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", + tty, UT_HOSTSIZE, hostname); + else + syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); + + if (!quietlog) { + struct stat st; + + motd(); + (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); + } + +#ifdef VFS + if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN); +#endif VFS + (void)signal(SIGALRM, SIG_DFL); + (void)signal(SIGQUIT, SIG_DFL); + (void)signal(SIGINT, SIG_DFL); + (void)signal(SIGTSTP, SIG_IGN); + + tbuf[0] = '-'; + (void) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell); + execlp(pwd->pw_shell, tbuf, 0); + fprintf(stderr, "login: no shell: "); + perror(pwd->pw_shell); + exit(0); +} + +getloginname() +{ + register int ch; + register char *p; + static char nbuf[UT_NAMESIZE + 1]; + + for (;;) { + printf("login: "); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) + exit(0); + if (p < nbuf + UT_NAMESIZE) + *p++ = ch; + } + if (p > nbuf) + if (nbuf[0] == '-') + fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + } +} + +sigtype +timedout() +{ + fprintf(stderr, "Login timed out after %d seconds\n", timeout); + exit(0); +} + +#ifdef NOTTYENT +int root_tty_security = 0; +#endif +rootterm(tty) + char *tty; +{ +#ifdef NOTTYENT + return(root_tty_security); +#else + struct ttyent *t; + + return((t = getttynam(tty)) && t->ty_status&TTY_SECURE); +#endif NOTTYENT +} + +jmp_buf motdinterrupt; + +motd() +{ + register int fd, nchars; + sigtype (*oldint)(), sigint(); + char tbuf[8192]; + + if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) + return; + signal(SIGINT, sigint); + + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + (void)close(fd); +} + +sigtype +sigint() +{ + longjmp(motdinterrupt, 1); +} + +checknologin() +{ + register int fd, nchars; + char tbuf[8192]; + + if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + (void)write(fileno(stdout), tbuf, nchars); + sleepexit(0); + } +} + +dolastlog(quiet, tty) + int quiet; + char *tty; +{ + struct lastlog ll; + int fd; + + if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + if (!quiet) { + if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && + ll.ll_time != 0) { + printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + if (*ll.ll_host != '\0') + printf("from %.*s\n", + sizeof(ll.ll_host), ll.ll_host); + else + printf("on %.*s\n", + sizeof(ll.ll_line), ll.ll_line); + } + (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + } + (void)time(&ll.ll_time); + (void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + if (hostname) + (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + else + (void) bzero(ll.ll_host, sizeof(ll.ll_host)); + (void)write(fd, (char *)&ll, sizeof(ll)); + (void)close(fd); + } +} + +#undef UNKNOWN +#define UNKNOWN "su" + +char * +stypeof(ttyid) + char *ttyid; +{ +#ifdef NOTTYENT + return(UNKNOWN); +#else + struct ttyent *t; + + return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); +#endif +} + +doremotelogin(host) + char *host; +{ + static char lusername[UT_NAMESIZE+1]; + char rusername[UT_NAMESIZE+1]; + + getstr(rusername, sizeof(rusername), "remuser"); + getstr(lusername, sizeof(lusername), "locuser"); + getstr(term, sizeof(term), "Terminal type"); + username = lusername; + pwd = getpwnam(username); + if (pwd == NULL) + return(-1); + return(ruserok(host, (pwd->pw_uid == 0), rusername, username)); +} + +do_gss_login(host) + char *host; +{ + int j, tokenlen, partlen, numbuf, i, debugflag = 0, auth_valid; + unsigned char token[GSS_C_MAX_TOKEN], *charp, *cp; + unsigned char tokenheader[4], send_tokenheader[4]; + char targ_printable[GSS_C_MAX_PRINTABLE_NAME]; + char lhostname[GSS_C_MAX_PRINTABLE_NAME]; + unsigned char chanbinding[8]; + int chanbinding_len; + static char lusername[UT_NAMESIZE+1], rusername[UT_NAMESIZE+1]; + int hostlen, xcc, need_to_exit = 0; +/* + * GSS API support + */ + gss_OID_set actual_mechs; + gss_OID actual_mech_type, output_name_type; + int major_status, status, msg_ctx = 0, new_status; + int req_flags = 0, ret_flags, lifetime_rec; + gss_cred_id_t gss_cred_handle; + gss_ctx_id_t actual_ctxhandle; + gss_buffer_desc output_token, input_token, input_name_buffer; + gss_buffer_desc status_string; + gss_name_t desired_targname, src_name; + gss_channel_bindings input_chan_bindings; + + + j = sphinx_net_read(3, tokenheader, 4); + if ((tokenheader[0] != TOKEN_MAJIC_NUMBER_BYTE0) || +(tokenheader[1] != TOKEN_MAJIC_NUMBER_BYTE1)) { + exit(0); + } + tokenlen = tokenheader[2] * 256 + tokenheader[3]; + + if (tokenlen > sizeof(token)) { + syslog(LOG_INFO, "token is too large, size is %d, buffer size +is %d", tokenlen, sizeof(token)); + exit(0); + } + + charp = token; + j = sphinx_net_read(3, token, tokenlen); + if (j != tokenlen) + syslog(LOG_INFO,"%d = read(3, token, %d)",j, tokenlen); + close(3); + + gethostname(lhostname, sizeof(lhostname)); + + strcpy(targ_printable, "SERVICE:rlogin@"); + strcat(targ_printable, lhostname); +/* + strcpy(targetname, lhostname); + if ((cp = index(targetname, '.')) != 0) *cp = '\0'; +*/ + + input_name_buffer.length = strlen(targ_printable); + input_name_buffer.value = targ_printable; + + major_status = gss_import_name(&status, + &input_name_buffer, + GSS_C_NULL_OID, + &desired_targname); + + major_status = gss_acquire_cred(&status, + desired_targname, + 0, + GSS_C_NULL_OID_SET, + GSS_C_ACCEPT, + &gss_cred_handle, + &actual_mechs, + &lifetime_rec); + + major_status = gss_release_name(&status, desired_targname); + + if (major_status != GSS_S_COMPLETE) { + xcc = write(0, "AuthentError", 12); + if (xcc <= 0) + syslog(LOG_INFO, "write(0, resp, 12): %m"); + + gss_display_status(&new_status, + status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + fprintf(stderr, "%s - ", status_string.value); + return(0); + } + + getstr(rusername, sizeof (rusername), "remuser"); + getstr(lusername, sizeof (lusername), "locuser"); + getstr(term, sizeof(term), "Terminal type"); + + username = lusername; + + pwd = getpwnam(lusername); + if (pwd == NULL) { + syslog(LOG_INFO,"passwd entry for '%s' is NULL",lusername); +/* + xcc = write(0, "Auth Error ", 12); + if (xcc <= 0) + syslog(LOG_INFO, "write(0, resp, 12): %m"); + fprintf(stderr, "SPX : user account '%s' doesn't exist - ", lusername); +*/ + } + + if (major_status != GSS_S_COMPLETE) { + xcc = write(0, "AuthentError", 12); + if (xcc <= 0) + syslog(LOG_INFO, "write(0, resp, 12): %m"); + + gss_display_status(&new_status, + status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + fprintf(stderr, "%s - ", status_string.value); + return(0); + } + + if (pwd != NULL) seteuid(pwd->pw_uid); + + { + char myhost[32]; + int from_addr=0, to_addr=0, myhostlen, j; + struct hostent *my_hp, *from_hp; + struct sockaddr_in sin, sin2; + + from_hp=gethostbyname(host); + if (from_hp != 0) { + bcopy(from_hp->h_addr_list[0], + (caddr_t)&sin.sin_addr, from_hp->h_length); +#ifdef ultrix + from_addr = sin.sin_addr.S_un.S_addr; +#else + from_addr = sin.sin_addr.s_addr; +#endif + } else { + from_addr = inet_addr(host); + } + from_addr = htonl(from_addr); + j=gethostname(myhost, sizeof(myhost)); + my_hp=gethostbyname(myhost); + if (my_hp != 0) { + bcopy(my_hp->h_addr_list[0], + (caddr_t)&sin2.sin_addr, my_hp->h_length); +#ifdef ultrix + to_addr = sin2.sin_addr.S_un.S_addr; +#else + to_addr = sin2.sin_addr.s_addr; +#endif + to_addr = htonl(to_addr); + } + + input_chan_bindings = (gss_channel_bindings) + malloc(sizeof(gss_channel_bindings_desc)); + + input_chan_bindings->initiator_addrtype = GSS_C_AF_INET; + input_chan_bindings->initiator_address.length = 4; + input_chan_bindings->initiator_address.value = (char *) malloc(4); + input_chan_bindings->initiator_address.value[0] = ((from_addr +& 0xff000000) >> 24); + input_chan_bindings->initiator_address.value[1] = ((from_addr +& 0xff0000) >> 16); + input_chan_bindings->initiator_address.value[2] = ((from_addr +& 0xff00) >> 8); + input_chan_bindings->initiator_address.value[3] = (from_addr & 0xff); + input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET; + input_chan_bindings->acceptor_address.length = 4; + input_chan_bindings->acceptor_address.value = (char *) malloc(4); + input_chan_bindings->acceptor_address.value[0] = ((to_addr & +0xff000000) >> 24); + input_chan_bindings->acceptor_address.value[1] = ((to_addr & +0xff0000) >> 16); + input_chan_bindings->acceptor_address.value[2] = ((to_addr & +0xff00) >> 8); + input_chan_bindings->acceptor_address.value[3] = (to_addr & 0xff); + input_chan_bindings->application_data.length = 0; + } + + input_token.length = tokenlen; + input_token.value = token; + + major_status = gss_accept_sec_context(&status, + &context_handle, + gss_cred_handle, + &input_token, + input_chan_bindings, + &src_name, + &actual_mech_type, + &output_token, + &ret_flags, + &lifetime_rec, + &gss_delegated_cred_handle); + + if (output_token.length != 0) { + + send_tokenheader[0] = TOKEN_MAJIC_NUMBER_BYTE0; + send_tokenheader[1] = TOKEN_MAJIC_NUMBER_BYTE1; + send_tokenheader[2] = ((output_token.length & 0xff00) >> 8); + send_tokenheader[3] = (output_token.length & 0xff); + + xcc = write(0, (char *) send_tokenheader, 4); + if (xcc != 4) + syslog(LOG_INFO, "write(0, send_tokenheader, 4): %m"); + + xcc = write(0, (char *) output_token.value, output_token.length); + if (xcc <= 0) + syslog(LOG_INFO, "write(0, resp, %d): %m",output_token.length); + } + + if (pwd == NULL) { + fprintf(stderr, "SPX : user account '%s' doesn't exist - ", lusername); + return(-1); + } + if (getuid()) { + syslog(LOG_INFO,"getuid() is 0, so return nouser"); + return(0); + } + + if (major_status != GSS_S_COMPLETE) { + syslog(LOG_INFO, "got error on accept\n"); + gss_display_status(&new_status, + status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + fprintf(stderr, "%s - ", status_string.value); + return(-1); + } + +#ifdef SPX_CHALLENGE + /* + * if trying to login to root account, then we need to verify response + * proving that the user is interactive. + * + */ + if (strcmp(lusername, "root")==0) { + j = sphinx_net_read(0, tokenheader, 4); + if (j != 4) + syslog(LOG_INFO,"%d = read(0, token, 4)",j); + + if ((tokenheader[0] != TOKEN_MAJIC_NUMBER_BYTE0) || +(tokenheader[1] != TOKEN_MAJIC_NUMBER_BYTE1)) { + exit(0); + } + tokenlen = tokenheader[2] * 256 + tokenheader[3]; + if (tokenlen > sizeof(token)) { + syslog(LOG_INFO, "token too large, %d/%d",tokenlen,sizeof(token)); + exit(0); + } + + charp = token; + j = sphinx_net_read(0, token, tokenlen); + if (j != tokenlen) + syslog(LOG_INFO,"%d = read(0, token, %d)",j, tokenlen); + major_status = spx_verify_response(&status, + context_handle, + gss_cred_handle, + token, + tokenlen); + if (major_status != GSS_S_COMPLETE) { + gss_display_status(&new_status, + status, + GSS_C_MECH_CODE, + GSS_C_NULL_OID, + &msg_ctx, + &status_string); + fprintf(stderr, "%s - ", status_string.value); + return(0); + } + } +#endif /* SPX_CHALLENGE */ + + seteuid(0); + + { + gss_buffer_desc fullname_buffer, luser_buffer, acl_file_buffer; + gss_buffer_desc service_buffer, resource_buffer; + gss_OID fullname_type; + int access_mode; + char acl_file[160], service[60], resource[160]; + + major_status = gss_display_name(&status, + src_name, + &fullname_buffer, + &fullname_type); + + luser_buffer.value = lusername; + luser_buffer.length = strlen(lusername); + + strcpy(acl_file, pwd->pw_dir); + strcat(acl_file, "/.sphinx"); + acl_file_buffer.value = acl_file; + acl_file_buffer.length = strlen(acl_file); + + strcpy(service, "flogin"); + service_buffer.value = service; + service_buffer.length = 6; + resource[0] = '\0'; + resource_buffer.value = resource; + resource_buffer.length = 0; + access_mode = GSS_C_READ | GSS_C_WRITE; + + major_status = gss__check_authorization(&status, + &fullname_buffer, + &luser_buffer, + &acl_file_buffer, + &service_buffer, + access_mode, + &resource_buffer); + + if (major_status != GSS_S_COMPLETE) { + if (strcmp(lusername, "root")==0) + syslog(LOG_INFO, "root authorization denied - '%s'", src_name); + fprintf(stderr, "SPX : authorization denied to user account +'%s' - ", lusername); + return(-1); + } else { + strcpy(userfullname, src_name); + strcpy(userlocalname, rusername); + } + major_status = gss_release_buffer(&status, &fullname_buffer); + return(1); + } +} + +getstr(buf, cnt, err) + char *buf, *err; + int cnt; +{ + char ch; + + do { + if (read(0, &ch, sizeof(ch)) != sizeof(ch)) + exit(1); + if (--cnt < 0) { + fprintf(stderr, "%s too long\r\n", err); + sleepexit(1); + } + *buf++ = ch; + } while (ch); +} + +char *speeds[] = { + "0", "50", "75", "110", "134", "150", "200", "300", "600", + "1200", "1800", "2400", "4800", "9600", "19200", "38400", +}; +#define NSPEEDS (sizeof(speeds) / sizeof(speeds[0])) + +doremoteterm(tp) + struct sgttyb *tp; +{ + register char *cp = index(term, '/'), **cpp; + char *speed; + + if (cp) { + *cp++ = '\0'; + speed = cp; + cp = index(speed, '/'); + if (cp) + *cp++ = '\0'; + for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) + if (strcmp(*cpp, speed) == 0) { + tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; + break; + } + } + tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; +} + +sleepexitnew(eval, interval) + int eval, interval; +{ + sleep((u_int)interval); + exit(eval); +} + + +sleepexit(eval) + int eval; +{ + sleep((u_int)5); + exit(eval); +}