121174Sdist /* 236517Skarels * Copyright (c) 1983, 1988 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[] = 2036517Skarels "@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\ 2121174Sdist All rights reserved.\n"; 2235441Sbostic #endif /* not lint */ 236446Swnj 2421174Sdist #ifndef lint 25*36633Skarels static char sccsid[] = "@(#)rlogind.c 5.27 (Berkeley) 01/25/89"; 2635441Sbostic #endif /* not lint */ 2721174Sdist 2816369Skarels /* 2916369Skarels * remote login server: 3036453Skfall * \0 3116369Skarels * remuser\0 3216369Skarels * locuser\0 3336453Skfall * terminal_type/speed\0 3436518Skarels * data 3516369Skarels */ 3616369Skarels 376446Swnj #include <stdio.h> 38*36633Skarels #include <sys/types.h> 396446Swnj #include <sys/stat.h> 406446Swnj #include <sys/socket.h> 4113554Ssam #include <sys/wait.h> 4218357Ssam #include <sys/file.h> 43*36633Skarels #include <sys/param.h> 449208Ssam 459208Ssam #include <netinet/in.h> 469208Ssam 476446Swnj #include <errno.h> 486446Swnj #include <pwd.h> 496446Swnj #include <signal.h> 50*36633Skarels #include <sys/ioctl.h> 51*36633Skarels #include <sys/termios.h> 526446Swnj #include <stdio.h> 538380Ssam #include <netdb.h> 5417187Sralph #include <syslog.h> 5518357Ssam #include <strings.h> 566446Swnj 5736518Skarels #ifndef TIOCPKT_WINDOW 5836518Skarels #define TIOCPKT_WINDOW 0x80 5936518Skarels #endif 6036518Skarels 61*36633Skarels #ifdef KERBEROS 62*36633Skarels #include <kerberos/krb.h> 63*36633Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 64*36633Skarels 65*36633Skarels AUTH_DAT *kdata; 66*36633Skarels KTEXT ticket; 67*36633Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 68*36633Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 69*36633Skarels Key_schedule schedule; 70*36633Skarels int encrypt, retval, use_kerberos = 0, vacuous = 0; 71*36633Skarels int do_krb_login(); 72*36633Skarels 73*36633Skarels #define OLD_RCMD 0x00 74*36633Skarels #define KERB_RCMD 0x00 75*36633Skarels #define KERB_RCMD_MUTUAL 0x03 76*36633Skarels 77*36633Skarels #define ARGSTR "lnkv" 78*36633Skarels #else 79*36633Skarels #define ARGSTR "ln" 80*36633Skarels #endif /* KERBEROS */ 81*36633Skarels 8236518Skarels char *env[2]; 8336518Skarels #define NMAX 30 8436517Skarels char lusername[NMAX+1], rusername[NMAX+1]; 8536517Skarels static char term[64] = "TERM="; 8636517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 8736517Skarels int keepalive = 1; 8836453Skfall 8936453Skfall #define SUPERUSER(pwd) ((pwd)->pw_uid == 0) 9036453Skfall 9134424Sbostic extern int errno; 9210417Ssam int reapchild(); 9336453Skfall struct passwd *getpwnam(), *pwd; 9424723Smckusick char *malloc(); 9516369Skarels 966446Swnj main(argc, argv) 976446Swnj int argc; 986446Swnj char **argv; 996446Swnj { 10036319Sbostic extern int opterr, optind, _check_rhosts_file; 10136319Sbostic int ch; 10234424Sbostic int on = 1, fromlen; 1036446Swnj struct sockaddr_in from; 1046446Swnj 10536625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 10636319Sbostic 10736319Sbostic opterr = 0; 108*36633Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 10936517Skarels switch (ch) { 11036319Sbostic case 'l': 11136319Sbostic _check_rhosts_file = 0; 11236319Sbostic break; 11336517Skarels case 'n': 11436517Skarels keepalive = 0; 11536517Skarels break; 116*36633Skarels #ifdef KERBEROS 117*36633Skarels case 'k': 118*36633Skarels use_kerberos = 1; 119*36633Skarels break; 120*36633Skarels case 'v': 121*36633Skarels vacuous = 1; 122*36633Skarels break; 123*36633Skarels #endif 12436319Sbostic case '?': 12536319Sbostic default: 126*36633Skarels usage(); 12736319Sbostic break; 12836319Sbostic } 12936319Sbostic argc -= optind; 13036319Sbostic argv += optind; 13136319Sbostic 132*36633Skarels #ifdef KERBEROS 133*36633Skarels if (use_kerberos && vacuous) { 134*36633Skarels usage(); 135*36633Skarels fatal("only one of -k and -v allowed\n"); 136*36633Skarels } 137*36633Skarels #endif 13816369Skarels fromlen = sizeof (from); 13916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 140*36633Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 141*36633Skarels fatalperror("Can't get peer name of remote host"); 1428380Ssam } 14336517Skarels if (keepalive && 14436517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 14517187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 14616369Skarels doit(0, &from); 1476446Swnj } 1486446Swnj 1496446Swnj int child; 1506446Swnj int cleanup(); 1516446Swnj int netf; 1526446Swnj char *line; 15324724Smckusick extern char *inet_ntoa(); 1546446Swnj 15524889Smckusick struct winsize win = { 0, 0, 0, 0 }; 15624723Smckusick 15724889Smckusick 1586446Swnj doit(f, fromp) 1596446Swnj int f; 1606446Swnj struct sockaddr_in *fromp; 1616446Swnj { 16218357Ssam int i, p, t, pid, on = 1; 16336631Skarels int authenticated = 0, hostok = 0; 164*36633Skarels register struct hostent *hp; 16536632Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 16624724Smckusick struct hostent hostent; 1678380Ssam char c; 1686446Swnj 1696446Swnj alarm(60); 1706446Swnj read(f, &c, 1); 171*36633Skarels 172*36633Skarels #ifdef KERBEROS 173*36633Skarels /* 174*36633Skarels * XXX 1st char tells us which client we're talking to 175*36633Skarels */ 176*36633Skarels switch (c) { 177*36633Skarels 178*36633Skarels case OLD_RCMD: /* OLD_RCMD is same as KERB_RCMD */ 179*36633Skarels if (vacuous) 180*36633Skarels fatal(f, "Remote host requires Kerberos authentication"); 181*36633Skarels break; 182*36633Skarels 183*36633Skarels case KERB_RCMD_MUTUAL: 184*36633Skarels encrypt = 1; 185*36633Skarels break; 186*36633Skarels 187*36633Skarels default: 188*36633Skarels fatal(f, "Remote protocol error"); 189*36633Skarels } 190*36633Skarels #else 1916446Swnj if (c != 0) 1926446Swnj exit(1); 193*36633Skarels #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); 20536631Skarels } else if (local_domain(hp->h_name)) { 20636631Skarels /* 20736631Skarels * If name returned by gethostbyaddr is in our domain, 20836631Skarels * attempt to verify that we haven't been fooled by someone 20936631Skarels * in a remote net; look up the name and check that this 21036631Skarels * address corresponds to the name. 21136631Skarels */ 21236631Skarels strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 21336631Skarels remotehost[sizeof(remotehost) - 1] = 0; 21436631Skarels hp = gethostbyname(remotehost); 21536631Skarels if (hp) 21636631Skarels for (; hp->h_addr_list[0]; hp->h_addr_list++) { 21736631Skarels if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr, 21836631Skarels sizeof(fromp->sin_addr))) { 21936631Skarels hostok++; 22036631Skarels break; 22136625Skfall } 22236625Skfall } 22311345Ssam } 22436453Skfall 225*36633Skarels #ifdef KERBEROS 226*36633Skarels if (use_kerberos) { 227*36633Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 228*36633Skarels write(f, &c, 1); 229*36633Skarels if (retval == 0) 230*36633Skarels authenticated++; 231*36633Skarels else if (retval > 0) 232*36633Skarels fatal(f, krb_err_txt[retval]); 233*36633Skarels } else 234*36633Skarels #endif 23536631Skarels if (fromp->sin_family != AF_INET || 23636631Skarels fromp->sin_port >= IPPORT_RESERVED || 23736631Skarels fromp->sin_port < IPPORT_RESERVED/2) { 23836631Skarels syslog(LOG_NOTICE, "Connection from %s on illegal port", 23936631Skarels inet_ntoa(fromp->sin_addr)); 24036631Skarels fatal(f, "Permission denied"); 24136631Skarels } 24236632Skarels write(f, "", 1); 243*36633Skarels 24436632Skarels if (do_rlogin(hp->h_name) == 0) { 24536632Skarels if (hostok) 246*36633Skarels authenticated++; 24736632Skarels else 248*36633Skarels write(f, "rlogind: Host address mismatch.\r\n", 249*36633Skarels sizeof("rlogind: Host address mismatch.\r\n") - 1); 25036632Skarels } 25136609Skfall 2526446Swnj for (c = 'p'; c <= 's'; c++) { 2536446Swnj struct stat stb; 2546446Swnj line = "/dev/ptyXX"; 2556446Swnj line[strlen("/dev/pty")] = c; 2566446Swnj line[strlen("/dev/ptyp")] = '0'; 2576446Swnj if (stat(line, &stb) < 0) 2586446Swnj break; 2596446Swnj for (i = 0; i < 16; i++) { 26034424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 26134424Sbostic p = open(line, O_RDWR); 2626446Swnj if (p > 0) 2636446Swnj goto gotpty; 2646446Swnj } 2656446Swnj } 26624723Smckusick fatal(f, "Out of ptys"); 2679242Ssam /*NOTREACHED*/ 2686446Swnj gotpty: 26924889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 27016227Skarels netf = f; 2716446Swnj line[strlen("/dev/")] = 't'; 27234424Sbostic t = open(line, O_RDWR); 27334424Sbostic if (t < 0) 27434424Sbostic fatalperror(f, line); 27534424Sbostic if (fchmod(t, 0)) 27634424Sbostic fatalperror(f, line); 27734424Sbostic (void)signal(SIGHUP, SIG_IGN); 27834424Sbostic vhangup(); 27934424Sbostic (void)signal(SIGHUP, SIG_DFL); 28034424Sbostic t = open(line, O_RDWR); 28134424Sbostic if (t < 0) 28234424Sbostic fatalperror(f, line); 28336453Skfall setup_term(t); 2846446Swnj #ifdef DEBUG 28534424Sbostic { 28634424Sbostic int tt = open("/dev/tty", O_RDWR); 28734424Sbostic if (tt > 0) { 28834424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 28934424Sbostic (void)close(tt); 29034424Sbostic } 2916446Swnj } 2926446Swnj #endif 2939242Ssam pid = fork(); 2949242Ssam if (pid < 0) 29534424Sbostic fatalperror(f, ""); 29618357Ssam if (pid == 0) { 297*36633Skarels if (setsid() < 0) 298*36633Skarels fatalperror(f, "setsid"); 299*36633Skarels if (ioctl(t, TIOCSCTTY, 0) < 0) 300*36633Skarels fatalperror(f, "ioctl(sctty)"); 30118357Ssam close(f), close(p); 30218357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 30316227Skarels close(t); 30436631Skarels if (authenticated) 305*36633Skarels execl("/bin/login", "login", "-p", 306*36633Skarels "-h", hp->h_name, "-f", lusername, 0); 30736525Skfall else 308*36633Skarels execl("/bin/login", "login", "-p", 309*36633Skarels "-h", hp->h_name, lusername, 0); 31034424Sbostic fatalperror(2, "/bin/login"); 31118357Ssam /*NOTREACHED*/ 31218357Ssam } 31318357Ssam close(t); 31436453Skfall 315*36633Skarels #ifdef KERBEROS 316*36633Skarels /* 317*36633Skarels * If encrypted, don't turn on NBIO or the des read/write 318*36633Skarels * routines will croak. 319*36633Skarels */ 320*36633Skarels 321*36633Skarels if (encrypt) 322*36633Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 323*36633Skarels else 324*36633Skarels #endif 325*36633Skarels ioctl(f, FIONBIO, &on); 32618357Ssam ioctl(p, FIONBIO, &on); 32718357Ssam ioctl(p, TIOCPKT, &on); 32818357Ssam signal(SIGTSTP, SIG_IGN); 32918357Ssam signal(SIGCHLD, cleanup); 33024724Smckusick setpgrp(0, 0); 33118357Ssam protocol(f, p); 33230600Smckusick signal(SIGCHLD, SIG_IGN); 33318357Ssam cleanup(); 33418357Ssam } 3359242Ssam 33618357Ssam char magic[2] = { 0377, 0377 }; 33725423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 33818357Ssam 33918357Ssam /* 34018357Ssam * Handle a "control" request (signaled by magic being present) 34118357Ssam * in the data stream. For now, we are only willing to handle 34218357Ssam * window size changes. 34318357Ssam */ 34418357Ssam control(pty, cp, n) 34518357Ssam int pty; 34618357Ssam char *cp; 34718357Ssam int n; 34818357Ssam { 34928705Smckusick struct winsize w; 35018357Ssam 35128705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 35218357Ssam return (0); 35325423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 35428705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 35528705Smckusick w.ws_row = ntohs(w.ws_row); 35628705Smckusick w.ws_col = ntohs(w.ws_col); 35728705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 35828705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 35928705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 36028705Smckusick return (4+sizeof (w)); 36118357Ssam } 36218357Ssam 36318357Ssam /* 36418357Ssam * rlogin "protocol" machine. 36518357Ssam */ 36618357Ssam protocol(f, p) 36718357Ssam int f, p; 36818357Ssam { 36918357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 37018357Ssam register pcc = 0, fcc = 0; 37136517Skarels int cc, nfd, pmask, fmask; 37225740Skarels char cntl; 37318357Ssam 37418482Ssam /* 37518484Ssam * Must ignore SIGTTOU, otherwise we'll stop 37618484Ssam * when we try and set slave pty's window shape 37725423Skarels * (our controlling tty is the master pty). 37818482Ssam */ 37918484Ssam (void) signal(SIGTTOU, SIG_IGN); 38025423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 38136517Skarels if (f > p) 38236517Skarels nfd = f + 1; 38336517Skarels else 38436517Skarels nfd = p + 1; 38536517Skarels fmask = 1 << f; 38636517Skarels pmask = 1 << p; 38718357Ssam for (;;) { 38825740Skarels int ibits, obits, ebits; 38918357Ssam 39025740Skarels ibits = 0; 39125740Skarels obits = 0; 39218357Ssam if (fcc) 39336517Skarels obits |= pmask; 39418357Ssam else 39536517Skarels ibits |= fmask; 39618357Ssam if (pcc >= 0) 39718357Ssam if (pcc) 39836517Skarels obits |= fmask; 3999242Ssam else 40036517Skarels ibits |= pmask; 40136517Skarels ebits = pmask; 40236517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 40336517Skarels &ebits, 0) < 0) { 40418357Ssam if (errno == EINTR) 4056446Swnj continue; 40634424Sbostic fatalperror(f, "select"); 40718357Ssam } 40825740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 40918357Ssam /* shouldn't happen... */ 41018357Ssam sleep(5); 41118357Ssam continue; 41218357Ssam } 41325740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 41436517Skarels if (ebits & pmask) { 41525740Skarels cc = read(p, &cntl, 1); 41625740Skarels if (cc == 1 && pkcontrol(cntl)) { 41725740Skarels cntl |= oobdata[0]; 41825740Skarels send(f, &cntl, 1, MSG_OOB); 41925740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 42025740Skarels pcc = 0; 42136517Skarels ibits &= ~pmask; 42225740Skarels } 42325740Skarels } 42425740Skarels } 42536517Skarels if (ibits & fmask) { 426*36633Skarels #ifdef KERBEROS 427*36633Skarels if (encrypt) 428*36633Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 429*36633Skarels else 430*36633Skarels #endif 431*36633Skarels fcc = read(f, fibuf, sizeof(fibuf)); 43218357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 43318357Ssam fcc = 0; 43418357Ssam else { 43518357Ssam register char *cp; 43618357Ssam int left, n; 43718357Ssam 43818357Ssam if (fcc <= 0) 43916227Skarels break; 44018357Ssam fbp = fibuf; 44124723Smckusick 44218357Ssam top: 44325423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 44418357Ssam if (cp[0] == magic[0] && 44518357Ssam cp[1] == magic[1]) { 44618357Ssam left = fcc - (cp-fibuf); 44718357Ssam n = control(p, cp, left); 44818357Ssam if (n) { 44918357Ssam left -= n; 45018357Ssam if (left > 0) 45125423Skarels bcopy(cp+n, cp, left); 45218357Ssam fcc -= n; 45318357Ssam goto top; /* n^2 */ 45425423Skarels } 45525423Skarels } 45636517Skarels obits |= pmask; /* try write */ 45725423Skarels } 45825423Skarels } 45924723Smckusick 46036517Skarels if ((obits & pmask) && fcc > 0) { 46125423Skarels cc = write(p, fbp, fcc); 46224723Smckusick if (cc > 0) { 46324723Smckusick fcc -= cc; 46424723Smckusick fbp += cc; 4656446Swnj } 46618357Ssam } 46724723Smckusick 46836517Skarels if (ibits & pmask) { 46918357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 47018357Ssam pbp = pibuf; 47118357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 47218357Ssam pcc = 0; 47318357Ssam else if (pcc <= 0) 47418357Ssam break; 47536517Skarels else if (pibuf[0] == 0) { 47618357Ssam pbp++, pcc--; 477*36633Skarels #ifdef KERBEROS 478*36633Skarels if (!encrypt) 479*36633Skarels #endif 480*36633Skarels obits |= fmask; /* try a write */ 48136517Skarels } else { 48218357Ssam if (pkcontrol(pibuf[0])) { 48325423Skarels pibuf[0] |= oobdata[0]; 48418357Ssam send(f, &pibuf[0], 1, MSG_OOB); 48516227Skarels } 48618357Ssam pcc = 0; 4876446Swnj } 48818357Ssam } 48936517Skarels if ((obits & fmask) && pcc > 0) { 490*36633Skarels #ifdef KERBEROS 491*36633Skarels if (encrypt) 492*36633Skarels cc = des_write(f, pbp, pcc); 493*36633Skarels else 494*36633Skarels #endif 495*36633Skarels cc = write(f, pbp, pcc); 49625423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 49725423Skarels /* also shouldn't happen */ 49825423Skarels sleep(5); 49925423Skarels continue; 50025423Skarels } 50118357Ssam if (cc > 0) { 50218357Ssam pcc -= cc; 50318357Ssam pbp += cc; 50418357Ssam } 5056446Swnj } 5066446Swnj } 5076446Swnj } 5086446Swnj 5096446Swnj cleanup() 5106446Swnj { 51135440Sbostic char *p; 51235440Sbostic 51335440Sbostic p = line + sizeof("/dev/") - 1; 51435440Sbostic if (logout(p)) 51535440Sbostic logwtmp(p, "", ""); 51635440Sbostic (void)chmod(line, 0666); 51735440Sbostic (void)chown(line, 0, 0); 51835440Sbostic *p = 'p'; 51935440Sbostic (void)chmod(line, 0666); 52035440Sbostic (void)chown(line, 0, 0); 52110192Ssam shutdown(netf, 2); 5226446Swnj exit(1); 5236446Swnj } 5246446Swnj 5259242Ssam fatal(f, msg) 5269242Ssam int f; 5279242Ssam char *msg; 5289242Ssam { 5299242Ssam char buf[BUFSIZ]; 5309242Ssam 5319242Ssam buf[0] = '\01'; /* error indicator */ 53213554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5339242Ssam (void) write(f, buf, strlen(buf)); 5349242Ssam exit(1); 5359242Ssam } 5369242Ssam 53734424Sbostic fatalperror(f, msg) 5389242Ssam int f; 5399242Ssam char *msg; 5409242Ssam { 5419242Ssam char buf[BUFSIZ]; 54216227Skarels extern int sys_nerr; 5439242Ssam extern char *sys_errlist[]; 5449242Ssam 54518357Ssam if ((unsigned)errno < sys_nerr) 54616227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 54716227Skarels else 54816227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5499242Ssam fatal(f, buf); 5509242Ssam } 55136453Skfall 55236453Skfall do_rlogin(host) 55336518Skarels char *host; 55436453Skfall { 55536453Skfall 55636518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 55736518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 55836518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 55936518Skarels 56036518Skarels if (getuid()) 56136453Skfall return(-1); 56236453Skfall pwd = getpwnam(lusername); 56336518Skarels if (pwd == NULL) 56436453Skfall return(-1); 56536453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 56636453Skfall } 56736453Skfall 56836453Skfall 56936518Skarels getstr(buf, cnt, errmsg) 57036518Skarels char *buf; 57136518Skarels int cnt; 57236518Skarels char *errmsg; 57336453Skfall { 57436518Skarels char c; 57536518Skarels 57636453Skfall do { 57736518Skarels if (read(0, &c, 1) != 1) 57836453Skfall exit(1); 57936518Skarels if (--cnt < 0) 58036518Skarels fatal(1, errmsg); 58136453Skfall *buf++ = c; 58236518Skarels } while (c != 0); 58336453Skfall } 58436453Skfall 58536518Skarels extern char **environ; 58636453Skfall 58736519Skarels setup_term(fd) 58836519Skarels int fd; 58936519Skarels { 590*36633Skarels struct termios tt; 591*36633Skarels register char *cp = index(term+ENVSIZE, '/'); 59236519Skarels char *speed; 59336519Skarels 594*36633Skarels tcgetattr(fd, &tt); 59536519Skarels if (cp) { 59636519Skarels *cp++ = '\0'; 59736519Skarels speed = cp; 59836519Skarels cp = index(speed, '/'); 59936519Skarels if (cp) 60036519Skarels *cp++ = '\0'; 601*36633Skarels cfsetspeed(&tt, atoi(speed)); 60236519Skarels } 603*36633Skarels tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 604*36633Skarels tt.c_oflag = OPOST|ONLCR|OXTABS; 605*36633Skarels tt.c_lflag = ISIG|ICANON|ECHO; 606*36633Skarels tcsetattr(fd, TCSADFLUSH, &tt); 60736519Skarels 60836519Skarels env[0] = term; 60936519Skarels env[1] = 0; 61036519Skarels environ = env; 61136519Skarels } 61236609Skfall 613*36633Skarels #ifdef KERBEROS 614*36633Skarels #define VERSION_SIZE 9 615*36633Skarels 61636609Skfall /* 617*36633Skarels * Do the remote kerberos login to the named host with the 618*36633Skarels * given inet address 619*36633Skarels * 620*36633Skarels * Return 0 on valid authorization 621*36633Skarels * Return -1 on valid authentication, no authorization 622*36633Skarels * Return >0 for error conditions 623*36633Skarels */ 624*36633Skarels do_krb_login(host, dest, encrypt) 625*36633Skarels char *host; 626*36633Skarels struct sockaddr_in *dest; 627*36633Skarels int encrypt; 628*36633Skarels { 629*36633Skarels int rc; 630*36633Skarels char instance[INST_SZ], version[VERSION_SIZE]; 631*36633Skarels long authopts = 0L; /* !mutual */ 632*36633Skarels struct sockaddr_in faddr; 633*36633Skarels 634*36633Skarels if (getuid()) 635*36633Skarels return(KFAILURE); 636*36633Skarels 637*36633Skarels kdata = (AUTH_DAT *) auth_buf; 638*36633Skarels ticket = (KTEXT) tick_buf; 639*36633Skarels strcpy(instance, "*"); 640*36633Skarels 641*36633Skarels if (encrypt) { 642*36633Skarels rc = sizeof(faddr); 643*36633Skarels if (getsockname(0, &faddr, &rc)) 644*36633Skarels return(-1); 645*36633Skarels authopts = KOPT_DO_MUTUAL; 646*36633Skarels rc = krb_recvauth( 647*36633Skarels authopts, 0, 648*36633Skarels ticket, "rcmd", 649*36633Skarels instance, dest, &faddr, 650*36633Skarels kdata, "", schedule, version); 651*36633Skarels des_set_key(kdata->session, schedule); 652*36633Skarels 653*36633Skarels } else { 654*36633Skarels rc = krb_recvauth( 655*36633Skarels authopts, 0, 656*36633Skarels ticket, "rcmd", 657*36633Skarels instance, dest, (struct sockaddr_in *) 0, 658*36633Skarels kdata, "", (bit_64 *) 0, version); 659*36633Skarels } 660*36633Skarels 661*36633Skarels if (rc != KSUCCESS) 662*36633Skarels return(rc); 663*36633Skarels 664*36633Skarels if ((rc = krb_kntoln(kdata, rusername)) != KSUCCESS) 665*36633Skarels return(rc); 666*36633Skarels 667*36633Skarels getstr(lusername, sizeof(lusername), "locuser"); 668*36633Skarels /* get the "cmd" in the rcmd protocol */ 669*36633Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 670*36633Skarels 671*36633Skarels pwd = getpwnam(lusername); 672*36633Skarels if (pwd == NULL) 673*36633Skarels return(-1); 674*36633Skarels 675*36633Skarels /* returns nonzero for no access */ 676*36633Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 677*36633Skarels if (kuserok(kdata,lusername) != 0) 678*36633Skarels return(-1); 679*36633Skarels 680*36633Skarels return(0); 681*36633Skarels 682*36633Skarels } 683*36633Skarels 684*36633Skarels #endif /* KERBEROS */ 685*36633Skarels 686*36633Skarels usage() 687*36633Skarels { 688*36633Skarels #ifdef KERBEROS 689*36633Skarels syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]"); 690*36633Skarels #else 691*36633Skarels syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 692*36633Skarels #endif 693*36633Skarels } 694*36633Skarels 695*36633Skarels /* 69636631Skarels * Check whether host h is in our local domain, 69736631Skarels * as determined by the part of the name following 69836631Skarels * the first '.' in its name and in ours. 69936631Skarels * If either name is unqualified (contains no '.'), 70036631Skarels * assume that the host is local, as it will be 70136631Skarels * interpreted as such. 70236631Skarels */ 70336631Skarels local_domain(h) 70436631Skarels char *h; 70536625Skfall { 70636631Skarels char localhost[MAXHOSTNAMELEN]; 70736631Skarels char *p1, *p2 = index(h, '.'); 70836631Skarels 70936631Skarels (void) gethostname(localhost, sizeof(localhost)); 71036631Skarels p1 = index(localhost, '.'); 71136631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 71236625Skfall return(1); 71336625Skfall return(0); 71436625Skfall } 715