147928Sbostic /*- 240917Skarels * Copyright (c) 1983, 1988, 1989 The Regents of the University of California. 335441Sbostic * All rights reserved. 435441Sbostic * 547928Sbostic * %sccs.include.redist.c% 621174Sdist */ 721174Sdist 86446Swnj #ifndef lint 921174Sdist char copyright[] = 1040917Skarels "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\ 1121174Sdist All rights reserved.\n"; 1235441Sbostic #endif /* not lint */ 136446Swnj 1421174Sdist #ifndef lint 15*48380Skarels static char sccsid[] = "@(#)rlogind.c 5.53 (Berkeley) 04/20/91"; 1635441Sbostic #endif /* not lint */ 1721174Sdist 1840917Skarels #ifdef KERBEROS 1940917Skarels /* From: 2040917Skarels * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $ 2140917Skarels * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $ 2240917Skarels */ 2340917Skarels #endif 2440917Skarels 2516369Skarels /* 2616369Skarels * remote login server: 2736453Skfall * \0 2816369Skarels * remuser\0 2916369Skarels * locuser\0 3036453Skfall * terminal_type/speed\0 3136518Skarels * data 3216369Skarels */ 3316369Skarels 3440917Skarels #define FD_SETSIZE 16 /* don't need many bits for select */ 3537290Sbostic #include <sys/param.h> 366446Swnj #include <sys/stat.h> 3737290Sbostic #include <sys/ioctl.h> 3846982Sbostic #include <signal.h> 3946982Sbostic #include <termios.h> 409208Ssam 4146982Sbostic #include <sys/socket.h> 429208Ssam #include <netinet/in.h> 4344347Skarels #include <netinet/in_systm.h> 4444347Skarels #include <netinet/ip.h> 4546982Sbostic #include <arpa/inet.h> 4646982Sbostic #include <netdb.h> 479208Ssam 486446Swnj #include <pwd.h> 4917187Sralph #include <syslog.h> 5046982Sbostic #include <errno.h> 5140917Skarels #include <stdio.h> 5240917Skarels #include <unistd.h> 5346982Sbostic #include <stdlib.h> 5446982Sbostic #include <string.h> 5540917Skarels #include "pathnames.h" 566446Swnj 5736518Skarels #ifndef TIOCPKT_WINDOW 5836518Skarels #define TIOCPKT_WINDOW 0x80 5936518Skarels #endif 6036518Skarels 6140917Skarels #ifdef KERBEROS 6241761Skfall #include <kerberosIV/des.h> 6340917Skarels #include <kerberosIV/krb.h> 6440917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 6540917Skarels 6640917Skarels AUTH_DAT *kdata; 6740917Skarels KTEXT ticket; 6840917Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 6940917Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 7040917Skarels Key_schedule schedule; 7146982Sbostic int doencrypt, retval, use_kerberos, vacuous; 7240917Skarels 7340917Skarels #define ARGSTR "alnkvx" 7440917Skarels #else 7540917Skarels #define ARGSTR "aln" 7640917Skarels #endif /* KERBEROS */ 7740917Skarels 7836518Skarels char *env[2]; 7936518Skarels #define NMAX 30 8036517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8136517Skarels static char term[64] = "TERM="; 8236517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 8336517Skarels int keepalive = 1; 8439058Skarels int check_all = 0; 8536453Skfall 8646982Sbostic struct passwd *pwd; 8716369Skarels 886446Swnj main(argc, argv) 896446Swnj int argc; 906446Swnj char **argv; 916446Swnj { 9240917Skarels extern int opterr, optind; 9340917Skarels extern int _check_rhosts_file; 9436319Sbostic int ch; 9534424Sbostic int on = 1, fromlen; 966446Swnj struct sockaddr_in from; 976446Swnj 9836625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 9936319Sbostic 10036319Sbostic opterr = 0; 10140917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 10236517Skarels switch (ch) { 10339058Skarels case 'a': 10439058Skarels check_all = 1; 10539058Skarels break; 10636319Sbostic case 'l': 10736319Sbostic _check_rhosts_file = 0; 10836319Sbostic break; 10936517Skarels case 'n': 11036517Skarels keepalive = 0; 11136517Skarels break; 11240917Skarels #ifdef KERBEROS 11340917Skarels case 'k': 11440917Skarels use_kerberos = 1; 11540917Skarels break; 11640917Skarels case 'v': 11740917Skarels vacuous = 1; 11840917Skarels break; 11946982Sbostic #ifdef CRYPT 12046982Sbostic case 'x': 12146982Sbostic doencrypt = 1; 12246982Sbostic break; 12340917Skarels #endif 12446982Sbostic #endif 12536319Sbostic case '?': 12636319Sbostic default: 12740917Skarels usage(); 12836319Sbostic break; 12936319Sbostic } 13036319Sbostic argc -= optind; 13136319Sbostic argv += optind; 13236319Sbostic 13340917Skarels #ifdef KERBEROS 13440917Skarels if (use_kerberos && vacuous) { 13540917Skarels usage(); 13640917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 13740917Skarels } 13840917Skarels #endif 13916369Skarels fromlen = sizeof (from); 14046982Sbostic if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 14140917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 14240917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 1438380Ssam } 14436517Skarels if (keepalive && 14536517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 14617187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 14744347Skarels on = IPTOS_LOWDELAY; 14844347Skarels if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 14944347Skarels syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 15016369Skarels doit(0, &from); 1516446Swnj } 1526446Swnj 1536446Swnj int child; 15446982Sbostic void cleanup(); 1556446Swnj int netf; 15644349Smarc char line[MAXPATHLEN]; 15740917Skarels int confirmed; 15824724Smckusick extern char *inet_ntoa(); 1596446Swnj 16024889Smckusick struct winsize win = { 0, 0, 0, 0 }; 16124723Smckusick 16224889Smckusick 1636446Swnj doit(f, fromp) 1646446Swnj int f; 1656446Swnj struct sockaddr_in *fromp; 1666446Swnj { 16744349Smarc int i, master, pid, on = 1; 16836631Skarels int authenticated = 0, hostok = 0; 16940917Skarels register struct hostent *hp; 17039249Smarc char remotehost[2 * MAXHOSTNAMELEN + 1]; 17124724Smckusick struct hostent hostent; 1728380Ssam char c; 1736446Swnj 1746446Swnj alarm(60); 1756446Swnj read(f, &c, 1); 17640917Skarels 17739249Smarc if (c != 0) 17836715Skfall exit(1); 17940917Skarels #ifdef KERBEROS 18040917Skarels if (vacuous) 18140917Skarels fatal(f, "Remote host requires Kerberos authentication", 0); 18240917Skarels #endif 18336453Skfall 1846446Swnj alarm(0); 18516227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port); 18646982Sbostic hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr), 1878380Ssam fromp->sin_family); 18811345Ssam if (hp == 0) { 18924724Smckusick /* 19024724Smckusick * Only the name is used below. 19124724Smckusick */ 19224724Smckusick hp = &hostent; 19324724Smckusick hp->h_name = inet_ntoa(fromp->sin_addr); 19436635Skarels hostok++; 19540917Skarels } else if (check_all || local_domain(hp->h_name)) { 19636635Skarels /* 19736635Skarels * If name returned by gethostbyaddr is in our domain, 19836635Skarels * attempt to verify that we haven't been fooled by someone 19936635Skarels * in a remote net; look up the name and check that this 20036635Skarels * address corresponds to the name. 20136635Skarels */ 20236635Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 20336635Skarels remotehost[sizeof(remotehost) - 1] = 0; 20436635Skarels hp = gethostbyname(remotehost); 20536635Skarels if (hp) 20636635Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) 20736635Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 20836635Skarels sizeof(fromp->sin_addr))) { 20936635Skarels hostok++; 21036635Skarels break; 21136635Skarels } 21236633Skarels } else 21336635Skarels hostok++; 21436711Skfall 21540917Skarels #ifdef KERBEROS 21640917Skarels if (use_kerberos) { 21742264Sbostic if (!hostok) 21844347Skarels fatal(f, "rlogind: Host address mismatch.", 0); 21946982Sbostic retval = do_krb_login(hp->h_name, fromp); 22042264Sbostic if (retval == 0) 22140917Skarels authenticated++; 22240917Skarels else if (retval > 0) 22340917Skarels fatal(f, krb_err_txt[retval], 0); 22440917Skarels write(f, &c, 1); 22540917Skarels confirmed = 1; /* we sent the null! */ 22640917Skarels } else 22740917Skarels #endif 22840917Skarels { 22940917Skarels if (fromp->sin_family != AF_INET || 23040917Skarels fromp->sin_port >= IPPORT_RESERVED || 23140917Skarels fromp->sin_port < IPPORT_RESERVED/2) { 23240917Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 23340917Skarels inet_ntoa(fromp->sin_addr)); 23440917Skarels fatal(f, "Permission denied", 0); 23540917Skarels } 23636702Skarels #ifdef IP_OPTIONS 23740917Skarels { 23840917Skarels u_char optbuf[BUFSIZ/3], *cp; 23940917Skarels char lbuf[BUFSIZ], *lp; 24040917Skarels int optsize = sizeof(optbuf), ipproto; 24140917Skarels struct protoent *ip; 24236702Skarels 24340917Skarels if ((ip = getprotobyname("ip")) != NULL) 24440917Skarels ipproto = ip->p_proto; 24540917Skarels else 24640917Skarels ipproto = IPPROTO_IP; 24740917Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 24840917Skarels &optsize) == 0 && optsize != 0) { 24940917Skarels lp = lbuf; 25040917Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 25140917Skarels sprintf(lp, " %2.2x", *cp); 25240917Skarels syslog(LOG_NOTICE, 25340917Skarels "Connection received using IP options (ignored):%s", 25440917Skarels lbuf); 25540917Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 25646982Sbostic (char *)NULL, optsize) != 0) { 25740917Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 25840917Skarels exit(1); 25940917Skarels } 26040917Skarels } 26140917Skarels } 26236702Skarels #endif 26340917Skarels if (do_rlogin(hp->h_name) == 0 && hostok) 26439249Smarc authenticated++; 26536631Skarels } 26640917Skarels if (confirmed == 0) { 26740917Skarels write(f, "", 1); 26840917Skarels confirmed = 1; /* we sent the null! */ 26939249Smarc } 27040917Skarels #ifdef KERBEROS 27146982Sbostic #ifdef CRYPT 27246982Sbostic if (doencrypt) 27346982Sbostic (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 27446982Sbostic #endif 27540917Skarels if (use_kerberos == 0) 27639249Smarc #endif 27740917Skarels if (!authenticated && !hostok) 27840917Skarels write(f, "rlogind: Host address mismatch.\r\n", 27940917Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 28040917Skarels 28144349Smarc netf = f; 28244349Smarc 28344349Smarc pid = forkpty(&master, line, NULL, &win); 28444349Smarc if (pid < 0) { 28544349Smarc if (errno == ENOENT) 28644349Smarc fatal(f, "Out of ptys", 0); 28744349Smarc else 28844349Smarc fatal(f, "Forkpty", 1); 28944349Smarc } 29018357Ssam if (pid == 0) { 29144349Smarc if (f > 2) /* f should always be 0, but... */ 29244349Smarc (void) close(f); 29344349Smarc setup_term(0); 29443363Skfall if (authenticated) { 29544347Skarels #ifdef KERBEROS 29643363Skfall if (use_kerberos && (pwd->pw_uid == 0)) 29743363Skfall syslog(LOG_INFO|LOG_AUTH, 29843363Skfall "ROOT Kerberos login from %s.%s@%s on %s\n", 29943363Skfall kdata->pname, kdata->pinst, kdata->prealm, 30043363Skfall hp->h_name); 30144347Skarels #endif 30243363Skfall 30340917Skarels execl(_PATH_LOGIN, "login", "-p", 30440917Skarels "-h", hp->h_name, "-f", lusername, 0); 30543363Skfall } else 30640917Skarels execl(_PATH_LOGIN, "login", "-p", 30740917Skarels "-h", hp->h_name, lusername, 0); 30840917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1); 30918357Ssam /*NOTREACHED*/ 31018357Ssam } 31146982Sbostic #ifdef CRYPT 31246982Sbostic #ifdef KERBEROS 31346982Sbostic /* 31446982Sbostic * If encrypted, don't turn on NBIO or the des read/write 31546982Sbostic * routines will croak. 31646982Sbostic */ 31746982Sbostic 31846982Sbostic if (!doencrypt) 31946982Sbostic #endif 32046982Sbostic #endif 32140917Skarels ioctl(f, FIONBIO, &on); 32244349Smarc ioctl(master, FIONBIO, &on); 32344349Smarc ioctl(master, TIOCPKT, &on); 32418357Ssam signal(SIGCHLD, cleanup); 32544349Smarc protocol(f, master); 32630600Smckusick signal(SIGCHLD, SIG_IGN); 32718357Ssam cleanup(); 32818357Ssam } 3299242Ssam 33018357Ssam char magic[2] = { 0377, 0377 }; 33125423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 33218357Ssam 33318357Ssam /* 33418357Ssam * Handle a "control" request (signaled by magic being present) 33518357Ssam * in the data stream. For now, we are only willing to handle 33618357Ssam * window size changes. 33718357Ssam */ 33818357Ssam control(pty, cp, n) 33918357Ssam int pty; 34018357Ssam char *cp; 34118357Ssam int n; 34218357Ssam { 34328705Smckusick struct winsize w; 34418357Ssam 34528705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 34618357Ssam return (0); 34725423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 34828705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 34928705Smckusick w.ws_row = ntohs(w.ws_row); 35028705Smckusick w.ws_col = ntohs(w.ws_col); 35128705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 35228705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 35328705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 35428705Smckusick return (4+sizeof (w)); 35518357Ssam } 35618357Ssam 35718357Ssam /* 35818357Ssam * rlogin "protocol" machine. 35918357Ssam */ 36018357Ssam protocol(f, p) 36140917Skarels register int f, p; 36218357Ssam { 36340917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 36418357Ssam register pcc = 0, fcc = 0; 36540917Skarels int cc, nfd, n; 36625740Skarels char cntl; 36718357Ssam 36818482Ssam /* 36918484Ssam * Must ignore SIGTTOU, otherwise we'll stop 37018484Ssam * when we try and set slave pty's window shape 37125423Skarels * (our controlling tty is the master pty). 37218482Ssam */ 37318484Ssam (void) signal(SIGTTOU, SIG_IGN); 37425423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 37536517Skarels if (f > p) 37636517Skarels nfd = f + 1; 37736517Skarels else 37836517Skarels nfd = p + 1; 37940917Skarels if (nfd > FD_SETSIZE) { 38040917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 38140917Skarels fatal(f, "internal error (select mask too small)", 0); 38240917Skarels } 38318357Ssam for (;;) { 38440917Skarels fd_set ibits, obits, ebits, *omask; 38518357Ssam 38642956Sbostic FD_ZERO(&ebits); 38740917Skarels FD_ZERO(&ibits); 38840917Skarels FD_ZERO(&obits); 38940917Skarels omask = (fd_set *)NULL; 39040917Skarels if (fcc) { 39140917Skarels FD_SET(p, &obits); 39240917Skarels omask = &obits; 39340917Skarels } else 39440917Skarels FD_SET(f, &ibits); 39518357Ssam if (pcc >= 0) 39640917Skarels if (pcc) { 39740917Skarels FD_SET(f, &obits); 39840917Skarels omask = &obits; 39940917Skarels } else 40040917Skarels FD_SET(p, &ibits); 40140917Skarels FD_SET(p, &ebits); 40240917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 40318357Ssam if (errno == EINTR) 4046446Swnj continue; 40540917Skarels fatal(f, "select", 1); 40618357Ssam } 40740917Skarels if (n == 0) { 40818357Ssam /* shouldn't happen... */ 40918357Ssam sleep(5); 41018357Ssam continue; 41118357Ssam } 41225740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 41340917Skarels if (FD_ISSET(p, &ebits)) { 41425740Skarels cc = read(p, &cntl, 1); 41525740Skarels if (cc == 1 && pkcontrol(cntl)) { 41625740Skarels cntl |= oobdata[0]; 41725740Skarels send(f, &cntl, 1, MSG_OOB); 41825740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 41925740Skarels pcc = 0; 42040917Skarels FD_CLR(p, &ibits); 42125740Skarels } 42225740Skarels } 42325740Skarels } 42440917Skarels if (FD_ISSET(f, &ibits)) { 42546982Sbostic #ifdef CRYPT 42646982Sbostic #ifdef KERBEROS 42746982Sbostic if (doencrypt) 42846982Sbostic fcc = des_read(f, fibuf, sizeof(fibuf)); 42946982Sbostic else 43046982Sbostic #endif 43146982Sbostic #endif 43240917Skarels fcc = read(f, fibuf, sizeof(fibuf)); 43318357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 43418357Ssam fcc = 0; 43518357Ssam else { 43618357Ssam register char *cp; 43718357Ssam int left, n; 43818357Ssam 43918357Ssam if (fcc <= 0) 44016227Skarels break; 44118357Ssam fbp = fibuf; 44224723Smckusick 44318357Ssam top: 44425423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 44518357Ssam if (cp[0] == magic[0] && 44618357Ssam cp[1] == magic[1]) { 44718357Ssam left = fcc - (cp-fibuf); 44818357Ssam n = control(p, cp, left); 44918357Ssam if (n) { 45018357Ssam left -= n; 45118357Ssam if (left > 0) 45225423Skarels bcopy(cp+n, cp, left); 45318357Ssam fcc -= n; 45418357Ssam goto top; /* n^2 */ 45525423Skarels } 45625423Skarels } 45740917Skarels FD_SET(p, &obits); /* try write */ 45825423Skarels } 45925423Skarels } 46024723Smckusick 46140917Skarels if (FD_ISSET(p, &obits) && fcc > 0) { 46225423Skarels cc = write(p, fbp, fcc); 46324723Smckusick if (cc > 0) { 46424723Smckusick fcc -= cc; 46524723Smckusick fbp += cc; 4666446Swnj } 46718357Ssam } 46824723Smckusick 46940917Skarels if (FD_ISSET(p, &ibits)) { 47018357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 47118357Ssam pbp = pibuf; 47218357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 47318357Ssam pcc = 0; 47418357Ssam else if (pcc <= 0) 47518357Ssam break; 47636517Skarels else if (pibuf[0] == 0) { 47718357Ssam pbp++, pcc--; 47846982Sbostic #ifdef CRYPT 47946982Sbostic #ifdef KERBEROS 48046982Sbostic if (!doencrypt) 48146982Sbostic #endif 48246982Sbostic #endif 48340917Skarels FD_SET(f, &obits); /* try write */ 48436517Skarels } else { 48518357Ssam if (pkcontrol(pibuf[0])) { 48625423Skarels pibuf[0] |= oobdata[0]; 48718357Ssam send(f, &pibuf[0], 1, MSG_OOB); 48816227Skarels } 48918357Ssam pcc = 0; 4906446Swnj } 49118357Ssam } 49240917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) { 49346982Sbostic #ifdef CRYPT 49446982Sbostic #ifdef KERBEROS 49546982Sbostic if (doencrypt) 49646982Sbostic cc = des_write(f, pbp, pcc); 49746982Sbostic else 49846982Sbostic #endif 49946982Sbostic #endif 50040917Skarels cc = write(f, pbp, pcc); 50125423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 50240917Skarels /* 50340917Skarels * This happens when we try write after read 50440917Skarels * from p, but some old kernels balk at large 50540917Skarels * writes even when select returns true. 50640917Skarels */ 50740917Skarels if (!FD_ISSET(p, &ibits)) 50840917Skarels sleep(5); 50925423Skarels continue; 51025423Skarels } 51118357Ssam if (cc > 0) { 51218357Ssam pcc -= cc; 51318357Ssam pbp += cc; 51418357Ssam } 5156446Swnj } 5166446Swnj } 5176446Swnj } 5186446Swnj 51946982Sbostic void 5206446Swnj cleanup() 5216446Swnj { 52235440Sbostic char *p; 52335440Sbostic 52440917Skarels p = line + sizeof(_PATH_DEV) - 1; 52535440Sbostic if (logout(p)) 52635440Sbostic logwtmp(p, "", ""); 527*48380Skarels (void)chmod(line, 0666); 52835440Sbostic (void)chown(line, 0, 0); 52935440Sbostic *p = 'p'; 530*48380Skarels (void)chmod(line, 0666); 53135440Sbostic (void)chown(line, 0, 0); 53210192Ssam shutdown(netf, 2); 5336446Swnj exit(1); 5346446Swnj } 5356446Swnj 53640917Skarels fatal(f, msg, syserr) 53740917Skarels int f, syserr; 5389242Ssam char *msg; 5399242Ssam { 54040917Skarels int len; 54140917Skarels char buf[BUFSIZ], *bp = buf; 5429242Ssam 54340917Skarels /* 54440917Skarels * Prepend binary one to message if we haven't sent 54540917Skarels * the magic null as confirmation. 54640917Skarels */ 54740917Skarels if (!confirmed) 54840917Skarels *bp++ = '\01'; /* error indicator */ 54940917Skarels if (syserr) 55040917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n", 55140917Skarels msg, strerror(errno)); 55240917Skarels else 55340917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg); 55440917Skarels (void) write(f, buf, bp + len - buf); 5559242Ssam exit(1); 5569242Ssam } 5579242Ssam 55836453Skfall do_rlogin(host) 55936518Skarels char *host; 56036453Skfall { 56136518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 56236518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 56336518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 56436518Skarels 56536453Skfall pwd = getpwnam(lusername); 56636518Skarels if (pwd == NULL) 56736453Skfall return(-1); 56842264Sbostic if (pwd->pw_uid == 0) 56942264Sbostic return(-1); 57042264Sbostic return(ruserok(host, 0, rusername, lusername)); 57136453Skfall } 57236453Skfall 57336453Skfall 57436518Skarels getstr(buf, cnt, errmsg) 57536518Skarels char *buf; 57636518Skarels int cnt; 57736518Skarels char *errmsg; 57836453Skfall { 57936518Skarels char c; 58036518Skarels 58136453Skfall do { 58236518Skarels if (read(0, &c, 1) != 1) 58336453Skfall exit(1); 58436518Skarels if (--cnt < 0) 58540917Skarels fatal(STDOUT_FILENO, errmsg, 0); 58636453Skfall *buf++ = c; 58736518Skarels } while (c != 0); 58836453Skfall } 58936453Skfall 59036518Skarels extern char **environ; 59136453Skfall 59236519Skarels setup_term(fd) 59336519Skarels int fd; 59436519Skarels { 59540917Skarels register char *cp = index(term+ENVSIZE, '/'); 59636519Skarels char *speed; 59739118Skarels struct termios tt; 59836519Skarels 59940917Skarels #ifndef notyet 60036711Skfall tcgetattr(fd, &tt); 60136519Skarels if (cp) { 60236519Skarels *cp++ = '\0'; 60336519Skarels speed = cp; 60436519Skarels cp = index(speed, '/'); 60536519Skarels if (cp) 60636519Skarels *cp++ = '\0'; 60736711Skfall cfsetspeed(&tt, atoi(speed)); 60836519Skarels } 60938710Skfall 61039118Skarels tt.c_iflag = TTYDEF_IFLAG; 61139118Skarels tt.c_oflag = TTYDEF_OFLAG; 61239118Skarels tt.c_lflag = TTYDEF_LFLAG; 61343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 61439118Skarels #else 61539118Skarels if (cp) { 61639118Skarels *cp++ = '\0'; 61739118Skarels speed = cp; 61839118Skarels cp = index(speed, '/'); 61939118Skarels if (cp) 62039118Skarels *cp++ = '\0'; 62140917Skarels tcgetattr(fd, &tt); 62240917Skarels cfsetspeed(&tt, atoi(speed)); 62343272Sbostic tcsetattr(fd, TCSAFLUSH, &tt); 62438710Skfall } 62538710Skfall #endif 62636519Skarels 62736519Skarels env[0] = term; 62836519Skarels env[1] = 0; 62936519Skarels environ = env; 63036519Skarels } 63136609Skfall 63240917Skarels #ifdef KERBEROS 63340917Skarels #define VERSION_SIZE 9 63440917Skarels 63536609Skfall /* 63640917Skarels * Do the remote kerberos login to the named host with the 63740917Skarels * given inet address 63840917Skarels * 63940917Skarels * Return 0 on valid authorization 64040917Skarels * Return -1 on valid authentication, no authorization 64140917Skarels * Return >0 for error conditions 64240917Skarels */ 64346982Sbostic do_krb_login(host, dest) 64440917Skarels char *host; 64540917Skarels struct sockaddr_in *dest; 64640917Skarels { 64740917Skarels int rc; 64840917Skarels char instance[INST_SZ], version[VERSION_SIZE]; 64940917Skarels long authopts = 0L; /* !mutual */ 65040917Skarels struct sockaddr_in faddr; 65140917Skarels 65240917Skarels kdata = (AUTH_DAT *) auth_buf; 65340917Skarels ticket = (KTEXT) tick_buf; 65440917Skarels 65542264Sbostic instance[0] = '*'; 65642264Sbostic instance[1] = '\0'; 65742264Sbostic 65846982Sbostic #ifdef CRYPT 65946982Sbostic if (doencrypt) { 66046982Sbostic rc = sizeof(faddr); 66146982Sbostic if (getsockname(0, (struct sockaddr *)&faddr, &rc)) 66246982Sbostic return(-1); 66346982Sbostic authopts = KOPT_DO_MUTUAL; 66440917Skarels rc = krb_recvauth( 66540917Skarels authopts, 0, 66640917Skarels ticket, "rcmd", 66746982Sbostic instance, dest, &faddr, 66846982Sbostic kdata, "", schedule, version); 66946982Sbostic des_set_key(kdata->session, schedule); 67046982Sbostic 67146982Sbostic } else 67246982Sbostic #endif 67346982Sbostic rc = krb_recvauth( 67446982Sbostic authopts, 0, 67546982Sbostic ticket, "rcmd", 67640917Skarels instance, dest, (struct sockaddr_in *) 0, 67740917Skarels kdata, "", (bit_64 *) 0, version); 67840917Skarels 67940917Skarels if (rc != KSUCCESS) 68040917Skarels return(rc); 68140917Skarels 68240917Skarels getstr(lusername, sizeof(lusername), "locuser"); 68340917Skarels /* get the "cmd" in the rcmd protocol */ 68440917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 68540917Skarels 68640917Skarels pwd = getpwnam(lusername); 68740917Skarels if (pwd == NULL) 68840917Skarels return(-1); 68940917Skarels 69040917Skarels /* returns nonzero for no access */ 69140917Skarels if (kuserok(kdata,lusername) != 0) 69240917Skarels return(-1); 69340917Skarels 69440917Skarels return(0); 69540917Skarels 69640917Skarels } 69740917Skarels #endif /* KERBEROS */ 69840917Skarels 69940917Skarels usage() 70040917Skarels { 70140917Skarels #ifdef KERBEROS 70240917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 70340917Skarels #else 70440917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]"); 70540917Skarels #endif 70640917Skarels } 70740917Skarels 70840917Skarels /* 70936631Skarels * Check whether host h is in our local domain, 71039058Skarels * defined as sharing the last two components of the domain part, 71139058Skarels * or the entire domain part if the local domain has only one component. 71236631Skarels * If either name is unqualified (contains no '.'), 71336631Skarels * assume that the host is local, as it will be 71436631Skarels * interpreted as such. 71536631Skarels */ 71636631Skarels local_domain(h) 71736631Skarels char *h; 71836625Skfall { 71936631Skarels char localhost[MAXHOSTNAMELEN]; 72039058Skarels char *p1, *p2, *topdomain(); 72136631Skarels 72239058Skarels localhost[0] = 0; 72336631Skarels (void) gethostname(localhost, sizeof(localhost)); 72439058Skarels p1 = topdomain(localhost); 72539058Skarels p2 = topdomain(h); 72636631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 72736625Skfall return(1); 72836625Skfall return(0); 72936625Skfall } 73039058Skarels 73139058Skarels char * 73239058Skarels topdomain(h) 73339058Skarels char *h; 73439058Skarels { 73539058Skarels register char *p; 73639058Skarels char *maybe = NULL; 73739058Skarels int dots = 0; 73839058Skarels 73939058Skarels for (p = h + strlen(h); p >= h; p--) { 74039058Skarels if (*p == '.') { 74139058Skarels if (++dots == 2) 74239058Skarels return (p); 74339058Skarels maybe = p; 74439058Skarels } 74539058Skarels } 74639058Skarels return (maybe); 74739058Skarels } 748