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*44349Smarc static char sccsid[] = "@(#)rlogind.c 5.48 (Berkeley) 06/27/90"; 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> 476446Swnj #include <sys/socket.h> 4813554Ssam #include <sys/wait.h> 4918357Ssam #include <sys/file.h> 5040917Skarels #include <sys/signal.h> 5137290Sbostic #include <sys/ioctl.h> 5237290Sbostic #include <sys/termios.h> 539208Ssam 549208Ssam #include <netinet/in.h> 5544347Skarels #include <netinet/in_systm.h> 5644347Skarels #include <netinet/ip.h> 579208Ssam 586446Swnj #include <errno.h> 596446Swnj #include <pwd.h> 608380Ssam #include <netdb.h> 6117187Sralph #include <syslog.h> 6242030Sbostic #include <string.h> 6340917Skarels #include <stdio.h> 6440917Skarels #include <unistd.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; 8140917Skarels int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 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 9634424Sbostic extern int errno; 9710417Ssam int reapchild(); 9836453Skfall struct passwd *getpwnam(), *pwd; 9924723Smckusick char *malloc(); 10016369Skarels 1016446Swnj main(argc, argv) 1026446Swnj int argc; 1036446Swnj char **argv; 1046446Swnj { 10540917Skarels extern int opterr, optind; 10640917Skarels extern int _check_rhosts_file; 10736319Sbostic int ch; 10834424Sbostic int on = 1, fromlen; 1096446Swnj struct sockaddr_in from; 1106446Swnj 11136625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 11236319Sbostic 11336319Sbostic opterr = 0; 11440917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 11536517Skarels switch (ch) { 11639058Skarels case 'a': 11739058Skarels check_all = 1; 11839058Skarels break; 11936319Sbostic case 'l': 12036319Sbostic _check_rhosts_file = 0; 12136319Sbostic break; 12236517Skarels case 'n': 12336517Skarels keepalive = 0; 12436517Skarels break; 12540917Skarels #ifdef KERBEROS 12640917Skarels case 'k': 12740917Skarels use_kerberos = 1; 12840917Skarels break; 12940917Skarels case 'v': 13040917Skarels vacuous = 1; 13140917Skarels break; 13240917Skarels case 'x': 13340917Skarels encrypt = 1; 13440917Skarels break; 13540917Skarels #endif 13636319Sbostic case '?': 13736319Sbostic default: 13840917Skarels usage(); 13936319Sbostic break; 14036319Sbostic } 14136319Sbostic argc -= optind; 14236319Sbostic argv += optind; 14336319Sbostic 14440917Skarels #ifdef KERBEROS 14540917Skarels if (use_kerberos && vacuous) { 14640917Skarels usage(); 14740917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 14840917Skarels } 14940917Skarels #endif 15016369Skarels fromlen = sizeof (from); 15116369Skarels if (getpeername(0, &from, &fromlen) < 0) { 15240917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 15340917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1548380Ssam } 15536517Skarels if (keepalive && 15636517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 15717187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 15844347Skarels on = IPTOS_LOWDELAY; 15944347Skarels if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 16044347Skarels syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 16116369Skarels doit(0, &from); 1626446Swnj } 1636446Swnj 1646446Swnj int child; 1656446Swnj int cleanup(); 1666446Swnj int netf; 167*44349Smarc char line[MAXPATHLEN]; 16840917Skarels int confirmed; 16924724Smckusick extern char *inet_ntoa(); 1706446Swnj 17124889Smckusick struct winsize win = { 0, 0, 0, 0 }; 17224723Smckusick 17324889Smckusick 1746446Swnj doit(f, fromp) 1756446Swnj int f; 1766446Swnj struct sockaddr_in *fromp; 1776446Swnj { 178*44349Smarc int i, master, pid, on = 1; 17936631Skarels int authenticated = 0, hostok = 0; 18040917Skarels register struct hostent *hp; 18139249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 18224724Smckusick struct hostent hostent; 1838380Ssam char c; 1846446Swnj 1856446Swnj alarm(60); 1866446Swnj read(f, &c, 1); 18740917Skarels 18839249Smarc if (c != 0) 18936715Skfall exit(1); 19040917Skarels #ifdef KERBEROS 19140917Skarels if (vacuous) 19240917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 19340917Skarels #endif 19436453Skfall 1956446Swnj alarm(0); 19616227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 1978380Ssam hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr), 1988380Ssam fromp->sin_family); 19911345Ssam if (hp == 0) { 20024724Smckusick /* 20124724Smckusick * Only the name is used below. 20224724Smckusick */ 20324724Smckusick hp = &hostent; 20424724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 20536635Skarels hostok++; 20640917Skarels } else if (check_all || local_domain(hp->h_name)) { 20736635Skarels /* 20836635Skarels * If name returned by gethostbyaddr is in our domain, 20936635Skarels * attempt to verify that we haven't been fooled by someone 21036635Skarels * in a remote net; look up the name and check that this 21136635Skarels * address corresponds to the name. 21236635Skarels */ 21336635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21436635Skarels remotehost[sizeof(remotehost) - 1] = 0; 21536635Skarels hp = gethostbyname(remotehost); 21636635Skarels if (hp) 21736635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 21836635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21936635Skarels sizeof(fromp->sin_addr))) { 22036635Skarels hostok++; 22136635Skarels break; 22236635Skarels } 22336633Skarels } else 22436635Skarels hostok++; 22536711Skfall 22640917Skarels #ifdef KERBEROS 22740917Skarels if (use_kerberos) { 22842264Sbostic if (!hostok) 22944347Skarels fatal(f, "rlogind: Host address mismatch.", 0); 23040917Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 23142264Sbostic if (retval == 0) 23240917Skarels authenticated++; 23340917Skarels else if (retval > 0) 23440917Skarels fatal(f, krb_err_txt[retval], 0); 23540917Skarels write(f, &c, 1); 23640917Skarels confirmed = 1; /* we sent the null! */ 23740917Skarels } else 23840917Skarels #endif 23940917Skarels { 24040917Skarels if (fromp->sin_family != AF_INET || 24140917Skarels fromp->sin_port >= IPPORT_RESERVED || 24240917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 24340917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 24440917Skarels inet_ntoa(fromp->sin_addr)); 24540917Skarels fatal(f, "Permission denied", 0); 24640917Skarels } 24736702Skarels #ifdef IP_OPTIONS 24840917Skarels { 24940917Skarels u_char optbuf[BUFSIZ/3], *cp; 25040917Skarels char lbuf[BUFSIZ], *lp; 25140917Skarels int optsize = sizeof(optbuf), ipproto; 25240917Skarels struct protoent *ip; 25336702Skarels 25440917Skarels if ((ip = getprotobyname("ip")) != NULL) 25540917Skarels ipproto = ip->p_proto; 25640917Skarels else 25740917Skarels ipproto = IPPROTO_IP; 25840917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 25940917Skarels &optsize) == 0 && optsize != 0) { 26040917Skarels lp = lbuf; 26140917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 26240917Skarels sprintf(lp, " %2.2x", *cp); 26340917Skarels syslog(LOG_NOTICE, 26440917Skarels "Connection received using IP options (ignored):%s", 26540917Skarels lbuf); 26640917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 26740917Skarels (char *)NULL, &optsize) != 0) { 26840917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 26940917Skarels exit(1); 27040917Skarels } 27140917Skarels } 27240917Skarels } 27336702Skarels #endif 27440917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 27539249Smarc authenticated++; 27636631Skarels } 27740917Skarels if (confirmed == 0) { 27840917Skarels write(f, "", 1); 27940917Skarels confirmed = 1; /* we sent the null! */ 28039249Smarc } 28140917Skarels #ifdef KERBEROS 28240917Skarels if (encrypt) 28340917Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 28440917Skarels 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 291*44349Smarc netf = f; 292*44349Smarc 293*44349Smarc pid = forkpty(&master, line, NULL, &win); 294*44349Smarc if (pid < 0) { 295*44349Smarc if (errno == ENOENT) 296*44349Smarc fatal(f, "Out of ptys", 0); 297*44349Smarc else 298*44349Smarc fatal(f, "Forkpty", 1); 299*44349Smarc } 30018357Ssam if (pid == 0) { 301*44349Smarc if (f > 2) /* f should always be 0, but... */ 302*44349Smarc (void) close(f); 303*44349Smarc 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 } 32140917Skarels #ifdef KERBEROS 32240917Skarels /* 32340917Skarels * If encrypted, don't turn on NBIO or the des read/write 32440917Skarels * routines will croak. 32540917Skarels */ 32640917Skarels 32740917Skarels if (!encrypt) 32840917Skarels #endif 32940917Skarels ioctl(f, FIONBIO, &on); 330*44349Smarc ioctl(master, FIONBIO, &on); 331*44349Smarc ioctl(master, TIOCPKT, &on); 33218357Ssam signal(SIGCHLD, cleanup); 333*44349Smarc protocol(f, master); 33430600Smckusick signal(SIGCHLD, SIG_IGN); 33518357Ssam cleanup(); 33618357Ssam } 3379242Ssam 33818357Ssam char magic[2] = { 0377, 0377 }; 33925423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 34018357Ssam 34118357Ssam /* 34218357Ssam * Handle a "control" request (signaled by magic being present) 34318357Ssam * in the data stream. For now, we are only willing to handle 34418357Ssam * window size changes. 34518357Ssam */ 34618357Ssam control(pty, cp, n) 34718357Ssam int pty; 34818357Ssam char *cp; 34918357Ssam int n; 35018357Ssam { 35128705Smckusick struct winsize w; 35218357Ssam 35328705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 35418357Ssam return (0); 35525423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 35628705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 35728705Smckusick w.ws_row = ntohs(w.ws_row); 35828705Smckusick w.ws_col = ntohs(w.ws_col); 35928705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 36028705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 36128705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 36228705Smckusick return (4+sizeof (w)); 36318357Ssam } 36418357Ssam 36518357Ssam /* 36618357Ssam * rlogin "protocol" machine. 36718357Ssam */ 36818357Ssam protocol(f, p) 36940917Skarels register int f, p; 37018357Ssam { 37140917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 37218357Ssam register pcc = 0, fcc = 0; 37340917Skarels int cc, nfd, n; 37425740Skarels char cntl; 37518357Ssam 37618482Ssam /* 37718484Ssam * Must ignore SIGTTOU, otherwise we'll stop 37818484Ssam * when we try and set slave pty's window shape 37925423Skarels * (our controlling tty is the master pty). 38018482Ssam */ 38118484Ssam (void) signal(SIGTTOU, SIG_IGN); 38225423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 38336517Skarels if (f > p) 38436517Skarels nfd = f + 1; 38536517Skarels else 38636517Skarels nfd = p + 1; 38740917Skarels if (nfd > FD_SETSIZE) { 38840917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 38940917Skarels fatal(f, "internal error (select mask too small)", 0); 39040917Skarels } 39118357Ssam for (;;) { 39240917Skarels fd_set ibits, obits, ebits, *omask; 39318357Ssam 39442956Sbostic FD_ZERO(&ebits); 39540917Skarels FD_ZERO(&ibits); 39640917Skarels FD_ZERO(&obits); 39740917Skarels omask = (fd_set *)NULL; 39840917Skarels if (fcc) { 39940917Skarels FD_SET(p, &obits); 40040917Skarels omask = &obits; 40140917Skarels } else 40240917Skarels FD_SET(f, &ibits); 40318357Ssam if (pcc >= 0) 40440917Skarels if (pcc) { 40540917Skarels FD_SET(f, &obits); 40640917Skarels omask = &obits; 40740917Skarels } else 40840917Skarels FD_SET(p, &ibits); 40940917Skarels FD_SET(p, &ebits); 41040917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 41118357Ssam if (errno == EINTR) 4126446Swnj continue; 41340917Skarels fatal(f, "select", 1); 41418357Ssam } 41540917Skarels if (n == 0) { 41618357Ssam /* shouldn't happen... */ 41718357Ssam sleep(5); 41818357Ssam continue; 41918357Ssam } 42025740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 42140917Skarels if (FD_ISSET(p, &ebits)) { 42225740Skarels cc = read(p, &cntl, 1); 42325740Skarels if (cc == 1 && pkcontrol(cntl)) { 42425740Skarels cntl |= oobdata[0]; 42525740Skarels send(f, &cntl, 1, MSG_OOB); 42625740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 42725740Skarels pcc = 0; 42840917Skarels FD_CLR(p, &ibits); 42925740Skarels } 43025740Skarels } 43125740Skarels } 43240917Skarels if (FD_ISSET(f, &ibits)) { 43340917Skarels #ifdef KERBEROS 43440917Skarels if (encrypt) 43540917Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 43640917Skarels else 43740917Skarels #endif 43840917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 43918357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 44018357Ssam fcc = 0; 44118357Ssam else { 44218357Ssam register char *cp; 44318357Ssam int left, n; 44418357Ssam 44518357Ssam if (fcc <= 0) 44616227Skarels break; 44718357Ssam fbp = fibuf; 44824723Smckusick 44918357Ssam top: 45025423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 45118357Ssam if (cp[0] == magic[0] && 45218357Ssam cp[1] == magic[1]) { 45318357Ssam left = fcc - (cp-fibuf); 45418357Ssam n = control(p, cp, left); 45518357Ssam if (n) { 45618357Ssam left -= n; 45718357Ssam if (left > 0) 45825423Skarels bcopy(cp+n, cp, left); 45918357Ssam fcc -= n; 46018357Ssam goto top; /* n^2 */ 46125423Skarels } 46225423Skarels } 46340917Skarels FD_SET(p, &obits); /* try write */ 46425423Skarels } 46525423Skarels } 46624723Smckusick 46740917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 46825423Skarels cc = write(p, fbp, fcc); 46924723Smckusick if (cc > 0) { 47024723Smckusick fcc -= cc; 47124723Smckusick fbp += cc; 4726446Swnj } 47318357Ssam } 47424723Smckusick 47540917Skarels if (FD_ISSET(p, &ibits)) { 47618357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 47718357Ssam pbp = pibuf; 47818357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 47918357Ssam pcc = 0; 48018357Ssam else if (pcc <= 0) 48118357Ssam break; 48236517Skarels else if (pibuf[0] == 0) { 48318357Ssam pbp++, pcc--; 48440917Skarels #ifdef KERBEROS 48540917Skarels if (!encrypt) 48640917Skarels #endif 48740917Skarels FD_SET(f, &obits); /* try write */ 48836517Skarels } else { 48918357Ssam if (pkcontrol(pibuf[0])) { 49025423Skarels pibuf[0] |= oobdata[0]; 49118357Ssam send(f, &pibuf[0], 1, MSG_OOB); 49216227Skarels } 49318357Ssam pcc = 0; 4946446Swnj } 49518357Ssam } 49640917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 49740917Skarels #ifdef KERBEROS 49840917Skarels if (encrypt) 49940917Skarels cc = des_write(f, pbp, pcc); 50040917Skarels else 50140917Skarels #endif 50240917Skarels cc = write(f, pbp, pcc); 50325423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 50440917Skarels /* 50540917Skarels * This happens when we try write after read 50640917Skarels * from p, but some old kernels balk at large 50740917Skarels * writes even when select returns true. 50840917Skarels */ 50940917Skarels if (!FD_ISSET(p, &ibits)) 51040917Skarels sleep(5); 51125423Skarels continue; 51225423Skarels } 51318357Ssam if (cc > 0) { 51418357Ssam pcc -= cc; 51518357Ssam pbp += cc; 51618357Ssam } 5176446Swnj } 5186446Swnj } 5196446Swnj } 5206446Swnj 5216446Swnj cleanup() 5226446Swnj { 52335440Sbostic char *p; 52435440Sbostic 52540917Skarels p = line + sizeof(_PATH_DEV) - 1; 52635440Sbostic if (logout(p)) 52735440Sbostic logwtmp(p, "", ""); 52835440Sbostic (void)chmod(line, 0666); 52935440Sbostic (void)chown(line, 0, 0); 53035440Sbostic *p = 'p'; 53135440Sbostic (void)chmod(line, 0666); 53235440Sbostic (void)chown(line, 0, 0); 53310192Ssam shutdown(netf, 2); 5346446Swnj exit(1); 5356446Swnj } 5366446Swnj 53740917Skarels fatal(f, msg, syserr) 53840917Skarels int f, syserr; 5399242Ssam char *msg; 5409242Ssam { 54140917Skarels int len; 54240917Skarels char buf[BUFSIZ], *bp = buf; 5439242Ssam 54440917Skarels /* 54540917Skarels * Prepend binary one to message if we haven't sent 54640917Skarels * the magic null as confirmation. 54740917Skarels */ 54840917Skarels if (!confirmed) 54940917Skarels *bp++ = '\01'; /* error indicator */ 55040917Skarels if (syserr) 55140917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 55240917Skarels msg, strerror(errno)); 55340917Skarels else 55440917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 55540917Skarels (void) write(f, buf, bp + len - buf); 5569242Ssam exit(1); 5579242Ssam } 5589242Ssam 55936453Skfall do_rlogin(host) 56036518Skarels char *host; 56136453Skfall { 56236518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 56336518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 56436518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 56536518Skarels 56636453Skfall pwd = getpwnam(lusername); 56736518Skarels if (pwd == NULL) 56836453Skfall return(-1); 56942264Sbostic if (pwd->pw_uid == 0) 57042264Sbostic return(-1); 57142264Sbostic return(ruserok(host, 0, rusername, lusername)); 57236453Skfall } 57336453Skfall 57436453Skfall 57536518Skarels getstr(buf, cnt, errmsg) 57636518Skarels char *buf; 57736518Skarels int cnt; 57836518Skarels char *errmsg; 57936453Skfall { 58036518Skarels char c; 58136518Skarels 58236453Skfall do { 58336518Skarels if (read(0, &c, 1) != 1) 58436453Skfall exit(1); 58536518Skarels if (--cnt < 0) 58640917Skarels fatal(STDOUT_FILENO, errmsg, 0); 58736453Skfall *buf++ = c; 58836518Skarels } while (c != 0); 58936453Skfall } 59036453Skfall 59136518Skarels extern char **environ; 59236453Skfall 59336519Skarels setup_term(fd) 59436519Skarels int fd; 59536519Skarels { 59640917Skarels register char *cp = index(term+ENVSIZE, '/'); 59736519Skarels char *speed; 59839118Skarels struct termios tt; 59936519Skarels 60040917Skarels #ifndef notyet 60136711Skfall tcgetattr(fd, &tt); 60236519Skarels if (cp) { 60336519Skarels *cp++ = '\0'; 60436519Skarels speed = cp; 60536519Skarels cp = index(speed, '/'); 60636519Skarels if (cp) 60736519Skarels *cp++ = '\0'; 60836711Skfall cfsetspeed(&tt, atoi(speed)); 60936519Skarels } 61038710Skfall 61139118Skarels tt.c_iflag = TTYDEF_IFLAG; 61239118Skarels tt.c_oflag = TTYDEF_OFLAG; 61339118Skarels tt.c_lflag = TTYDEF_LFLAG; 61443272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 61539118Skarels #else 61639118Skarels if (cp) { 61739118Skarels *cp++ = '\0'; 61839118Skarels speed = cp; 61939118Skarels cp = index(speed, '/'); 62039118Skarels if (cp) 62139118Skarels *cp++ = '\0'; 62240917Skarels tcgetattr(fd, &tt); 62340917Skarels cfsetspeed(&tt, atoi(speed)); 62443272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 62538710Skfall } 62638710Skfall #endif 62736519Skarels 62836519Skarels env[0] = term; 62936519Skarels env[1] = 0; 63036519Skarels environ = env; 63136519Skarels } 63236609Skfall 63340917Skarels #ifdef KERBEROS 63440917Skarels #define VERSION_SIZE 9 63540917Skarels 63636609Skfall /* 63740917Skarels * Do the remote kerberos login to the named host with the 63840917Skarels * given inet address 63940917Skarels * 64040917Skarels * Return 0 on valid authorization 64140917Skarels * Return -1 on valid authentication, no authorization 64240917Skarels * Return >0 for error conditions 64340917Skarels */ 64440917Skarels do_krb_login(host, dest, encrypt) 64540917Skarels char *host; 64640917Skarels struct sockaddr_in *dest; 64740917Skarels int encrypt; 64840917Skarels { 64940917Skarels int rc; 65040917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 65140917Skarels long authopts = 0L; /* !mutual */ 65240917Skarels struct sockaddr_in faddr; 65340917Skarels 65440917Skarels kdata = (AUTH_DAT *) auth_buf; 65540917Skarels ticket = (KTEXT) tick_buf; 65640917Skarels 65742264Sbostic instance[0] = '*'; 65842264Sbostic instance[1] = '\0'; 65942264Sbostic 66040917Skarels if (encrypt) { 66140917Skarels rc = sizeof(faddr); 66240917Skarels if (getsockname(0, &faddr, &rc)) 66340917Skarels return(-1); 66440917Skarels authopts = KOPT_DO_MUTUAL; 66540917Skarels rc = krb_recvauth( 66640917Skarels authopts, 0, 66740917Skarels ticket, "rcmd", 66840917Skarels instance, dest, &faddr, 66940917Skarels kdata, "", schedule, version); 67040917Skarels des_set_key(kdata->session, schedule); 67140917Skarels 67240917Skarels } else { 67340917Skarels rc = krb_recvauth( 67440917Skarels authopts, 0, 67540917Skarels ticket, "rcmd", 67640917Skarels instance, dest, (struct sockaddr_in *) 0, 67740917Skarels kdata, "", (bit_64 *) 0, version); 67840917Skarels } 67940917Skarels 68040917Skarels if (rc != KSUCCESS) 68140917Skarels return(rc); 68240917Skarels 68340917Skarels getstr(lusername, sizeof(lusername), "locuser"); 68440917Skarels /* get the "cmd" in the rcmd protocol */ 68540917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 68640917Skarels 68740917Skarels pwd = getpwnam(lusername); 68840917Skarels if (pwd == NULL) 68940917Skarels return(-1); 69040917Skarels 69140917Skarels /* returns nonzero for no access */ 69240917Skarels if (kuserok(kdata,lusername) != 0) 69340917Skarels return(-1); 69440917Skarels 69540917Skarels return(0); 69640917Skarels 69740917Skarels } 69840917Skarels #endif /* KERBEROS */ 69940917Skarels 70040917Skarels usage() 70140917Skarels { 70240917Skarels #ifdef KERBEROS 70340917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 70440917Skarels #else 70540917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 70640917Skarels #endif 70740917Skarels } 70840917Skarels 70940917Skarels /* 71036631Skarels * Check whether host h is in our local domain, 71139058Skarels * defined as sharing the last two components of the domain part, 71239058Skarels * or the entire domain part if the local domain has only one component. 71336631Skarels * If either name is unqualified (contains no '.'), 71436631Skarels * assume that the host is local, as it will be 71536631Skarels * interpreted as such. 71636631Skarels */ 71736631Skarels local_domain(h) 71836631Skarels char *h; 71936625Skfall { 72036631Skarels char localhost[MAXHOSTNAMELEN]; 72139058Skarels char *p1, *p2, *topdomain(); 72236631Skarels 72339058Skarels localhost[0] = 0; 72436631Skarels (void) gethostname(localhost, sizeof(localhost)); 72539058Skarels p1 = topdomain(localhost); 72639058Skarels p2 = topdomain(h); 72736631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 72836625Skfall return(1); 72936625Skfall return(0); 73036625Skfall } 73139058Skarels 73239058Skarels char * 73339058Skarels topdomain(h) 73439058Skarels char *h; 73539058Skarels { 73639058Skarels register char *p; 73739058Skarels char *maybe = NULL; 73839058Skarels int dots = 0; 73939058Skarels 74039058Skarels for (p = h + strlen(h); p >= h; p--) { 74139058Skarels if (*p == '.') { 74239058Skarels if (++dots == 2) 74339058Skarels return (p); 74439058Skarels maybe = p; 74539058Skarels } 74639058Skarels } 74739058Skarels return (maybe); 74839058Skarels } 749