121174Sdist /* 240917Skarels * Copyright (c) 1983, 1988, 1989 The Regents of the University of California. 335441Sbostic * All rights reserved. 435441Sbostic * 535441Sbostic * Redistribution and use in source and binary forms are permitted 635441Sbostic * provided that the above copyright notice and this paragraph are 735441Sbostic * duplicated in all such forms and that any documentation, 835441Sbostic * advertising materials, and other materials related to such 935441Sbostic * distribution and use acknowledge that the software was developed 1035441Sbostic * by the University of California, Berkeley. The name of the 1135441Sbostic * University may not be used to endorse or promote products derived 1235441Sbostic * from this software without specific prior written permission. 1335441Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435441Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535441Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621174Sdist */ 1721174Sdist 186446Swnj #ifndef lint 1921174Sdist char copyright[] = 2040917Skarels "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*46982Sbostic static char sccsid[] = "@(#)rlogind.c 5.51 (Berkeley) 03/04/91"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 2840917Skarels #ifdef KERBEROS 2940917Skarels /* From: 3040917Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 3140917Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 3240917Skarels */ 3340917Skarels #endif 3440917Skarels 3516369Skarels /* 3616369Skarels * remote login server: 3736453Skfall * \0 3816369Skarels * remuser\0 3916369Skarels * locuser\0 4036453Skfall * terminal_type/speed\0 4136518Skarels * data 4216369Skarels */ 4316369Skarels 4440917Skarels #define FD_SETSIZE 16 /* don't need many bits for select */ 4537290Sbostic #include <sys/param.h> 466446Swnj #include <sys/stat.h> 4737290Sbostic #include <sys/ioctl.h> 48*46982Sbostic #include <signal.h> 49*46982Sbostic #include <termios.h> 509208Ssam 51*46982Sbostic #include <sys/socket.h> 529208Ssam #include <netinet/in.h> 5344347Skarels #include <netinet/in_systm.h> 5444347Skarels #include <netinet/ip.h> 55*46982Sbostic #include <arpa/inet.h> 56*46982Sbostic #include <netdb.h> 579208Ssam 586446Swnj #include <pwd.h> 5917187Sralph #include <syslog.h> 60*46982Sbostic #include <errno.h> 6140917Skarels #include <stdio.h> 6240917Skarels #include <unistd.h> 63*46982Sbostic #include <stdlib.h> 64*46982Sbostic #include <string.h> 6540917Skarels #include "pathnames.h" 666446Swnj 6736518Skarels #ifndef TIOCPKT_WINDOW 6836518Skarels #define TIOCPKT_WINDOW 0x80 6936518Skarels #endif 7036518Skarels 7140917Skarels #ifdef KERBEROS 7241761Skfall #include <kerberosIV/des.h> 7340917Skarels #include <kerberosIV/krb.h> 7440917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 7540917Skarels 7640917Skarels AUTH_DAT *kdata; 7740917Skarels KTEXT ticket; 7840917Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 7940917Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 8040917Skarels Key_schedule schedule; 81*46982Sbostic int doencrypt, retval, use_kerberos, vacuous; 8240917Skarels 8340917Skarels #define ARGSTR "alnkvx" 8440917Skarels #else 8540917Skarels #define ARGSTR "aln" 8640917Skarels #endif /* KERBEROS */ 8740917Skarels 8836518Skarels char *env[2]; 8936518Skarels #define NMAX 30 9036517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 9136517Skarels static char term[64] = "TERM="; 9236517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 9336517Skarels int keepalive = 1; 9439058Skarels int check_all = 0; 9536453Skfall 96*46982Sbostic struct passwd *pwd; 9716369Skarels 986446Swnj main(argc, argv) 996446Swnj int argc; 1006446Swnj char **argv; 1016446Swnj { 10240917Skarels extern int opterr, optind; 10340917Skarels extern int _check_rhosts_file; 10436319Sbostic int ch; 10534424Sbostic int on = 1, fromlen; 1066446Swnj struct sockaddr_in from; 1076446Swnj 10836625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 10936319Sbostic 11036319Sbostic opterr = 0; 11140917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11236517Skarels switch (ch) { 11339058Skarels case 'a': 11439058Skarels check_all = 1; 11539058Skarels break; 11636319Sbostic case 'l': 11736319Sbostic _check_rhosts_file = 0; 11836319Sbostic break; 11936517Skarels case 'n': 12036517Skarels keepalive = 0; 12136517Skarels break; 12240917Skarels #ifdef KERBEROS 12340917Skarels case 'k': 12440917Skarels use_kerberos = 1; 12540917Skarels break; 12640917Skarels case 'v': 12740917Skarels vacuous = 1; 12840917Skarels break; 129*46982Sbostic #ifdef CRYPT 130*46982Sbostic case 'x': 131*46982Sbostic doencrypt = 1; 132*46982Sbostic break; 13340917Skarels #endif 134*46982Sbostic #endif 13536319Sbostic case '?': 13636319Sbostic default: 13740917Skarels usage(); 13836319Sbostic break; 13936319Sbostic } 14036319Sbostic argc -= optind; 14136319Sbostic argv += optind; 14236319Sbostic 14340917Skarels #ifdef KERBEROS 14440917Skarels if (use_kerberos && vacuous) { 14540917Skarels usage(); 14640917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 14740917Skarels } 14840917Skarels #endif 14916369Skarels fromlen = sizeof (from); 150*46982Sbostic if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 15140917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15240917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1538380Ssam } 15436517Skarels if (keepalive && 15536517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 15617187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 15744347Skarels on = IPTOS_LOWDELAY; 15844347Skarels if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 15944347Skarels syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 16016369Skarels doit(0, &from); 1616446Swnj } 1626446Swnj 1636446Swnj int child; 164*46982Sbostic void cleanup(); 1656446Swnj int netf; 16644349Smarc char line[MAXPATHLEN]; 16740917Skarels int confirmed; 16824724Smckusick extern char *inet_ntoa(); 1696446Swnj 17024889Smckusick struct winsize win = { 0, 0, 0, 0 }; 17124723Smckusick 17224889Smckusick 1736446Swnj doit(f, fromp) 1746446Swnj int f; 1756446Swnj struct sockaddr_in *fromp; 1766446Swnj { 17744349Smarc int i, master, pid, on = 1; 17836631Skarels int authenticated = 0, hostok = 0; 17940917Skarels register struct hostent *hp; 18039249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 18124724Smckusick struct hostent hostent; 1828380Ssam char c; 1836446Swnj 1846446Swnj alarm(60); 1856446Swnj read(f, &c, 1); 18640917Skarels 18739249Smarc if (c != 0) 18836715Skfall exit(1); 18940917Skarels #ifdef KERBEROS 19040917Skarels if (vacuous) 19140917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 19240917Skarels #endif 19336453Skfall 1946446Swnj alarm(0); 19516227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 196*46982Sbostic hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr), 1978380Ssam fromp->sin_family); 19811345Ssam if (hp == 0) { 19924724Smckusick /* 20024724Smckusick * Only the name is used below. 20124724Smckusick */ 20224724Smckusick hp = &hostent; 20324724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20436635Skarels hostok++; 20540917Skarels } else if (check_all || local_domain(hp->h_name)) { 20636635Skarels /* 20736635Skarels * If name returned by gethostbyaddr is in our domain, 20836635Skarels * attempt to verify that we haven't been fooled by someone 20936635Skarels * in a remote net; look up the name and check that this 21036635Skarels * address corresponds to the name. 21136635Skarels */ 21236635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21336635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21436635Skarels hp = gethostbyname(remotehost); 21536635Skarels if (hp) 21636635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21736635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21836635Skarels sizeof(fromp->sin_addr))) { 21936635Skarels hostok++; 22036635Skarels break; 22136635Skarels } 22236633Skarels } else 22336635Skarels hostok++; 22436711Skfall 22540917Skarels #ifdef KERBEROS 22640917Skarels if (use_kerberos) { 22742264Sbostic if (!hostok) 22844347Skarels fatal(f, "rlogind: Host address mismatch.", 0); 229*46982Sbostic retval = do_krb_login(hp->h_name, fromp); 23042264Sbostic if (retval == 0) 23140917Skarels authenticated++; 23240917Skarels else if (retval > 0) 23340917Skarels fatal(f, krb_err_txt[retval], 0); 23440917Skarels write(f, &c, 1); 23540917Skarels confirmed = 1; /* we sent the null! */ 23640917Skarels } else 23740917Skarels #endif 23840917Skarels { 23940917Skarels if (fromp->sin_family != AF_INET || 24040917Skarels fromp->sin_port >= IPPORT_RESERVED || 24140917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 24240917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 24340917Skarels inet_ntoa(fromp->sin_addr)); 24440917Skarels fatal(f, "Permission denied", 0); 24540917Skarels } 24636702Skarels #ifdef IP_OPTIONS 24740917Skarels { 24840917Skarels u_char optbuf[BUFSIZ/3], *cp; 24940917Skarels char lbuf[BUFSIZ], *lp; 25040917Skarels int optsize = sizeof(optbuf), ipproto; 25140917Skarels struct protoent *ip; 25236702Skarels 25340917Skarels if ((ip = getprotobyname("ip")) != NULL) 25440917Skarels ipproto = ip->p_proto; 25540917Skarels else 25640917Skarels ipproto = IPPROTO_IP; 25740917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25840917Skarels &optsize) == 0 && optsize != 0) { 25940917Skarels lp = lbuf; 26040917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 26140917Skarels sprintf(lp, " %2.2x", *cp); 26240917Skarels syslog(LOG_NOTICE, 26340917Skarels "Connection received using IP options (ignored):%s", 26440917Skarels lbuf); 26540917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 266*46982Sbostic (char *)NULL, optsize) != 0) { 26740917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26840917Skarels exit(1); 26940917Skarels } 27040917Skarels } 27140917Skarels } 27236702Skarels #endif 27340917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27439249Smarc authenticated++; 27536631Skarels } 27640917Skarels if (confirmed == 0) { 27740917Skarels write(f, "", 1); 27840917Skarels confirmed = 1; /* we sent the null! */ 27939249Smarc } 28040917Skarels #ifdef KERBEROS 281*46982Sbostic #ifdef CRYPT 282*46982Sbostic if (doencrypt) 283*46982Sbostic (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 284*46982Sbostic #endif 28540917Skarels if (use_kerberos == 0) 28639249Smarc #endif 28740917Skarels if (!authenticated && !hostok) 28840917Skarels write(f, "rlogind: Host address mismatch.\r\n", 28940917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 29040917Skarels 29144349Smarc netf = f; 29244349Smarc 29344349Smarc pid = forkpty(&master, line, NULL, &win); 29444349Smarc if (pid < 0) { 29544349Smarc if (errno == ENOENT) 29644349Smarc fatal(f, "Out of ptys", 0); 29744349Smarc else 29844349Smarc fatal(f, "Forkpty", 1); 29944349Smarc } 30018357Ssam if (pid == 0) { 30144349Smarc if (f > 2) /* f should always be 0, but... */ 30244349Smarc (void) close(f); 30344349Smarc setup_term(0); 30443363Skfall if (authenticated) { 30544347Skarels #ifdef KERBEROS 30643363Skfall if (use_kerberos && (pwd->pw_uid == 0)) 30743363Skfall syslog(LOG_INFO|LOG_AUTH, 30843363Skfall "ROOT Kerberos login from %s.%s@%s on %s\n", 30943363Skfall kdata->pname, kdata->pinst, kdata->prealm, 31043363Skfall hp->h_name); 31144347Skarels #endif 31243363Skfall 31340917Skarels execl(_PATH_LOGIN, "login", "-p", 31440917Skarels "-h", hp->h_name, "-f", lusername, 0); 31543363Skfall } else 31640917Skarels execl(_PATH_LOGIN, "login", "-p", 31740917Skarels "-h", hp->h_name, lusername, 0); 31840917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 31918357Ssam /*NOTREACHED*/ 32018357Ssam } 321*46982Sbostic #ifdef CRYPT 322*46982Sbostic #ifdef KERBEROS 323*46982Sbostic /* 324*46982Sbostic * If encrypted, don't turn on NBIO or the des read/write 325*46982Sbostic * routines will croak. 326*46982Sbostic */ 327*46982Sbostic 328*46982Sbostic if (!doencrypt) 329*46982Sbostic #endif 330*46982Sbostic #endif 33140917Skarels ioctl(f, FIONBIO, &on); 33244349Smarc ioctl(master, FIONBIO, &on); 33344349Smarc ioctl(master, TIOCPKT, &on); 33418357Ssam signal(SIGCHLD, cleanup); 33544349Smarc protocol(f, master); 33630600Smckusick signal(SIGCHLD, SIG_IGN); 33718357Ssam cleanup(); 33818357Ssam } 3399242Ssam 34018357Ssam char magic[2] = { 0377, 0377 }; 34125423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 34218357Ssam 34318357Ssam /* 34418357Ssam * Handle a "control" request (signaled by magic being present) 34518357Ssam * in the data stream. For now, we are only willing to handle 34618357Ssam * window size changes. 34718357Ssam */ 34818357Ssam control(pty, cp, n) 34918357Ssam int pty; 35018357Ssam char *cp; 35118357Ssam int n; 35218357Ssam { 35328705Smckusick struct winsize w; 35418357Ssam 35528705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 35618357Ssam return (0); 35725423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 35828705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 35928705Smckusick w.ws_row = ntohs(w.ws_row); 36028705Smckusick w.ws_col = ntohs(w.ws_col); 36128705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 36228705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 36328705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 36428705Smckusick return (4+sizeof (w)); 36518357Ssam } 36618357Ssam 36718357Ssam /* 36818357Ssam * rlogin "protocol" machine. 36918357Ssam */ 37018357Ssam protocol(f, p) 37140917Skarels register int f, p; 37218357Ssam { 37340917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 37418357Ssam register pcc = 0, fcc = 0; 37540917Skarels int cc, nfd, n; 37625740Skarels char cntl; 37718357Ssam 37818482Ssam /* 37918484Ssam * Must ignore SIGTTOU, otherwise we'll stop 38018484Ssam * when we try and set slave pty's window shape 38125423Skarels * (our controlling tty is the master pty). 38218482Ssam */ 38318484Ssam (void) signal(SIGTTOU, SIG_IGN); 38425423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 38536517Skarels if (f > p) 38636517Skarels nfd = f + 1; 38736517Skarels else 38836517Skarels nfd = p + 1; 38940917Skarels if (nfd > FD_SETSIZE) { 39040917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 39140917Skarels fatal(f, "internal error (select mask too small)", 0); 39240917Skarels } 39318357Ssam for (;;) { 39440917Skarels fd_set ibits, obits, ebits, *omask; 39518357Ssam 39642956Sbostic FD_ZERO(&ebits); 39740917Skarels FD_ZERO(&ibits); 39840917Skarels FD_ZERO(&obits); 39940917Skarels omask = (fd_set *)NULL; 40040917Skarels if (fcc) { 40140917Skarels FD_SET(p, &obits); 40240917Skarels omask = &obits; 40340917Skarels } else 40440917Skarels FD_SET(f, &ibits); 40518357Ssam if (pcc >= 0) 40640917Skarels if (pcc) { 40740917Skarels FD_SET(f, &obits); 40840917Skarels omask = &obits; 40940917Skarels } else 41040917Skarels FD_SET(p, &ibits); 41140917Skarels FD_SET(p, &ebits); 41240917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 41318357Ssam if (errno == EINTR) 4146446Swnj continue; 41540917Skarels fatal(f, "select", 1); 41618357Ssam } 41740917Skarels if (n == 0) { 41818357Ssam /* shouldn't happen... */ 41918357Ssam sleep(5); 42018357Ssam continue; 42118357Ssam } 42225740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 42340917Skarels if (FD_ISSET(p, &ebits)) { 42425740Skarels cc = read(p, &cntl, 1); 42525740Skarels if (cc == 1 && pkcontrol(cntl)) { 42625740Skarels cntl |= oobdata[0]; 42725740Skarels send(f, &cntl, 1, MSG_OOB); 42825740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 42925740Skarels pcc = 0; 43040917Skarels FD_CLR(p, &ibits); 43125740Skarels } 43225740Skarels } 43325740Skarels } 43440917Skarels if (FD_ISSET(f, &ibits)) { 435*46982Sbostic #ifdef CRYPT 436*46982Sbostic #ifdef KERBEROS 437*46982Sbostic if (doencrypt) 438*46982Sbostic fcc = des_read(f, fibuf, sizeof(fibuf)); 439*46982Sbostic else 440*46982Sbostic #endif 441*46982Sbostic #endif 44240917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 44318357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 44418357Ssam fcc = 0; 44518357Ssam else { 44618357Ssam register char *cp; 44718357Ssam int left, n; 44818357Ssam 44918357Ssam if (fcc <= 0) 45016227Skarels break; 45118357Ssam fbp = fibuf; 45224723Smckusick 45318357Ssam top: 45425423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 45518357Ssam if (cp[0] == magic[0] && 45618357Ssam cp[1] == magic[1]) { 45718357Ssam left = fcc - (cp-fibuf); 45818357Ssam n = control(p, cp, left); 45918357Ssam if (n) { 46018357Ssam left -= n; 46118357Ssam if (left > 0) 46225423Skarels bcopy(cp+n, cp, left); 46318357Ssam fcc -= n; 46418357Ssam goto top; /* n^2 */ 46525423Skarels } 46625423Skarels } 46740917Skarels FD_SET(p, &obits); /* try write */ 46825423Skarels } 46925423Skarels } 47024723Smckusick 47140917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 47225423Skarels cc = write(p, fbp, fcc); 47324723Smckusick if (cc > 0) { 47424723Smckusick fcc -= cc; 47524723Smckusick fbp += cc; 4766446Swnj } 47718357Ssam } 47824723Smckusick 47940917Skarels if (FD_ISSET(p, &ibits)) { 48018357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 48118357Ssam pbp = pibuf; 48218357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 48318357Ssam pcc = 0; 48418357Ssam else if (pcc <= 0) 48518357Ssam break; 48636517Skarels else if (pibuf[0] == 0) { 48718357Ssam pbp++, pcc--; 488*46982Sbostic #ifdef CRYPT 489*46982Sbostic #ifdef KERBEROS 490*46982Sbostic if (!doencrypt) 491*46982Sbostic #endif 492*46982Sbostic #endif 49340917Skarels FD_SET(f, &obits); /* try write */ 49436517Skarels } else { 49518357Ssam if (pkcontrol(pibuf[0])) { 49625423Skarels pibuf[0] |= oobdata[0]; 49718357Ssam send(f, &pibuf[0], 1, MSG_OOB); 49816227Skarels } 49918357Ssam pcc = 0; 5006446Swnj } 50118357Ssam } 50240917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 503*46982Sbostic #ifdef CRYPT 504*46982Sbostic #ifdef KERBEROS 505*46982Sbostic if (doencrypt) 506*46982Sbostic cc = des_write(f, pbp, pcc); 507*46982Sbostic else 508*46982Sbostic #endif 509*46982Sbostic #endif 51040917Skarels cc = write(f, pbp, pcc); 51125423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 51240917Skarels /* 51340917Skarels * This happens when we try write after read 51440917Skarels * from p, but some old kernels balk at large 51540917Skarels * writes even when select returns true. 51640917Skarels */ 51740917Skarels if (!FD_ISSET(p, &ibits)) 51840917Skarels sleep(5); 51925423Skarels continue; 52025423Skarels } 52118357Ssam if (cc > 0) { 52218357Ssam pcc -= cc; 52318357Ssam pbp += cc; 52418357Ssam } 5256446Swnj } 5266446Swnj } 5276446Swnj } 5286446Swnj 529*46982Sbostic void 5306446Swnj cleanup() 5316446Swnj { 53235440Sbostic char *p; 53335440Sbostic 53440917Skarels p = line + sizeof(_PATH_DEV) - 1; 53535440Sbostic if (logout(p)) 53635440Sbostic logwtmp(p, "", ""); 537*46982Sbostic (void)chmod(line, DEFFILEMODE); 53835440Sbostic (void)chown(line, 0, 0); 53935440Sbostic *p = 'p'; 540*46982Sbostic (void)chmod(line, DEFFILEMODE); 54135440Sbostic (void)chown(line, 0, 0); 54210192Ssam shutdown(netf, 2); 5436446Swnj exit(1); 5446446Swnj } 5456446Swnj 54640917Skarels fatal(f, msg, syserr) 54740917Skarels int f, syserr; 5489242Ssam char *msg; 5499242Ssam { 55040917Skarels int len; 55140917Skarels char buf[BUFSIZ], *bp = buf; 5529242Ssam 55340917Skarels /* 55440917Skarels * Prepend binary one to message if we haven't sent 55540917Skarels * the magic null as confirmation. 55640917Skarels */ 55740917Skarels if (!confirmed) 55840917Skarels *bp++ = '\01'; /* error indicator */ 55940917Skarels if (syserr) 56040917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 56140917Skarels msg, strerror(errno)); 56240917Skarels else 56340917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 56440917Skarels (void) write(f, buf, bp + len - buf); 5659242Ssam exit(1); 5669242Ssam } 5679242Ssam 56836453Skfall do_rlogin(host) 56936518Skarels char *host; 57036453Skfall { 57136518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 57236518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 57336518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 57436518Skarels 57536453Skfall pwd = getpwnam(lusername); 57636518Skarels if (pwd == NULL) 57736453Skfall return(-1); 57842264Sbostic if (pwd->pw_uid == 0) 57942264Sbostic return(-1); 58042264Sbostic return(ruserok(host, 0, rusername, lusername)); 58136453Skfall } 58236453Skfall 58336453Skfall 58436518Skarels getstr(buf, cnt, errmsg) 58536518Skarels char *buf; 58636518Skarels int cnt; 58736518Skarels char *errmsg; 58836453Skfall { 58936518Skarels char c; 59036518Skarels 59136453Skfall do { 59236518Skarels if (read(0, &c, 1) != 1) 59336453Skfall exit(1); 59436518Skarels if (--cnt < 0) 59540917Skarels fatal(STDOUT_FILENO, errmsg, 0); 59636453Skfall *buf++ = c; 59736518Skarels } while (c != 0); 59836453Skfall } 59936453Skfall 60036518Skarels extern char **environ; 60136453Skfall 60236519Skarels setup_term(fd) 60336519Skarels int fd; 60436519Skarels { 60540917Skarels register char *cp = index(term+ENVSIZE, '/'); 60636519Skarels char *speed; 60739118Skarels struct termios tt; 60836519Skarels 60940917Skarels #ifndef notyet 61036711Skfall tcgetattr(fd, &tt); 61136519Skarels if (cp) { 61236519Skarels *cp++ = '\0'; 61336519Skarels speed = cp; 61436519Skarels cp = index(speed, '/'); 61536519Skarels if (cp) 61636519Skarels *cp++ = '\0'; 61736711Skfall cfsetspeed(&tt, atoi(speed)); 61836519Skarels } 61938710Skfall 62039118Skarels tt.c_iflag = TTYDEF_IFLAG; 62139118Skarels tt.c_oflag = TTYDEF_OFLAG; 62239118Skarels tt.c_lflag = TTYDEF_LFLAG; 62343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 62439118Skarels #else 62539118Skarels if (cp) { 62639118Skarels *cp++ = '\0'; 62739118Skarels speed = cp; 62839118Skarels cp = index(speed, '/'); 62939118Skarels if (cp) 63039118Skarels *cp++ = '\0'; 63140917Skarels tcgetattr(fd, &tt); 63240917Skarels cfsetspeed(&tt, atoi(speed)); 63343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 63438710Skfall } 63538710Skfall #endif 63636519Skarels 63736519Skarels env[0] = term; 63836519Skarels env[1] = 0; 63936519Skarels environ = env; 64036519Skarels } 64136609Skfall 64240917Skarels #ifdef KERBEROS 64340917Skarels #define VERSION_SIZE 9 64440917Skarels 64536609Skfall /* 64640917Skarels * Do the remote kerberos login to the named host with the 64740917Skarels * given inet address 64840917Skarels * 64940917Skarels * Return 0 on valid authorization 65040917Skarels * Return -1 on valid authentication, no authorization 65140917Skarels * Return >0 for error conditions 65240917Skarels */ 653*46982Sbostic do_krb_login(host, dest) 65440917Skarels char *host; 65540917Skarels struct sockaddr_in *dest; 65640917Skarels { 65740917Skarels int rc; 65840917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 65940917Skarels long authopts = 0L; /* !mutual */ 66040917Skarels struct sockaddr_in faddr; 66140917Skarels 66240917Skarels kdata = (AUTH_DAT *) auth_buf; 66340917Skarels ticket = (KTEXT) tick_buf; 66440917Skarels 66542264Sbostic instance[0] = '*'; 66642264Sbostic instance[1] = '\0'; 66742264Sbostic 668*46982Sbostic #ifdef CRYPT 669*46982Sbostic if (doencrypt) { 670*46982Sbostic rc = sizeof(faddr); 671*46982Sbostic if (getsockname(0, (struct sockaddr *)&faddr, &rc)) 672*46982Sbostic return(-1); 673*46982Sbostic authopts = KOPT_DO_MUTUAL; 67440917Skarels rc = krb_recvauth( 67540917Skarels authopts, 0, 67640917Skarels ticket, "rcmd", 677*46982Sbostic instance, dest, &faddr, 678*46982Sbostic kdata, "", schedule, version); 679*46982Sbostic des_set_key(kdata->session, schedule); 680*46982Sbostic 681*46982Sbostic } else 682*46982Sbostic #endif 683*46982Sbostic rc = krb_recvauth( 684*46982Sbostic authopts, 0, 685*46982Sbostic ticket, "rcmd", 68640917Skarels instance, dest, (struct sockaddr_in *) 0, 68740917Skarels kdata, "", (bit_64 *) 0, version); 68840917Skarels 68940917Skarels if (rc != KSUCCESS) 69040917Skarels return(rc); 69140917Skarels 69240917Skarels getstr(lusername, sizeof(lusername), "locuser"); 69340917Skarels /* get the "cmd" in the rcmd protocol */ 69440917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 69540917Skarels 69640917Skarels pwd = getpwnam(lusername); 69740917Skarels if (pwd == NULL) 69840917Skarels return(-1); 69940917Skarels 70040917Skarels /* returns nonzero for no access */ 70140917Skarels if (kuserok(kdata,lusername) != 0) 70240917Skarels return(-1); 70340917Skarels 70440917Skarels return(0); 70540917Skarels 70640917Skarels } 70740917Skarels #endif /* KERBEROS */ 70840917Skarels 70940917Skarels usage() 71040917Skarels { 71140917Skarels #ifdef KERBEROS 71240917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 71340917Skarels #else 71440917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 71540917Skarels #endif 71640917Skarels } 71740917Skarels 71840917Skarels /* 71936631Skarels * Check whether host h is in our local domain, 72039058Skarels * defined as sharing the last two components of the domain part, 72139058Skarels * or the entire domain part if the local domain has only one component. 72236631Skarels * If either name is unqualified (contains no '.'), 72336631Skarels * assume that the host is local, as it will be 72436631Skarels * interpreted as such. 72536631Skarels */ 72636631Skarels local_domain(h) 72736631Skarels char *h; 72836625Skfall { 72936631Skarels char localhost[MAXHOSTNAMELEN]; 73039058Skarels char *p1, *p2, *topdomain(); 73136631Skarels 73239058Skarels localhost[0] = 0; 73336631Skarels (void) gethostname(localhost, sizeof(localhost)); 73439058Skarels p1 = topdomain(localhost); 73539058Skarels p2 = topdomain(h); 73636631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 73736625Skfall return(1); 73836625Skfall return(0); 73936625Skfall } 74039058Skarels 74139058Skarels char * 74239058Skarels topdomain(h) 74339058Skarels char *h; 74439058Skarels { 74539058Skarels register char *p; 74639058Skarels char *maybe = NULL; 74739058Skarels int dots = 0; 74839058Skarels 74939058Skarels for (p = h + strlen(h); p >= h; p--) { 75039058Skarels if (*p == '.') { 75139058Skarels if (++dots == 2) 75239058Skarels return (p); 75339058Skarels maybe = p; 75439058Skarels } 75539058Skarels } 75639058Skarels return (maybe); 75739058Skarels } 758