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*36702Skarels static char sccsid[] = "@(#)rlogind.c 5.32 (Berkeley) 02/07/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> 3836636Skarels #include <sys/types.h> 396446Swnj #include <sys/stat.h> 406446Swnj #include <sys/socket.h> 4113554Ssam #include <sys/wait.h> 4218357Ssam #include <sys/file.h> 4336636Skarels #include <sys/param.h> 449208Ssam 459208Ssam #include <netinet/in.h> 469208Ssam 476446Swnj #include <errno.h> 486446Swnj #include <pwd.h> 496446Swnj #include <signal.h> 5036636Skarels #include <sys/ioctl.h> 5136636Skarels #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 6136636Skarels #ifdef KERBEROS 6236636Skarels #include <kerberos/krb.h> 6336636Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 6436636Skarels 6536636Skarels AUTH_DAT *kdata; 6636636Skarels KTEXT ticket; 6736636Skarels u_char auth_buf[sizeof(AUTH_DAT)]; 6836636Skarels u_char tick_buf[sizeof(KTEXT_ST)]; 6936636Skarels Key_schedule schedule; 7036639Skfall int encrypt = 0, retval, use_kerberos = 0, vacuous = 0; 7136636Skarels int do_krb_login(); 7236636Skarels 7336636Skarels #define OLD_RCMD 0x00 7436636Skarels #define KERB_RCMD 0x00 7536636Skarels #define KERB_RCMD_MUTUAL 0x03 7636636Skarels 7736636Skarels #define ARGSTR "lnkv" 7836636Skarels #else 7936636Skarels #define ARGSTR "ln" 8036636Skarels #endif /* KERBEROS */ 8136636Skarels 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; 10836636Skarels 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; 11636636Skarels #ifdef KERBEROS 11736636Skarels case 'k': 11836636Skarels use_kerberos = 1; 11936636Skarels break; 12036636Skarels case 'v': 12136636Skarels vacuous = 1; 12236636Skarels break; 12336636Skarels #endif 12436319Sbostic case '?': 12536319Sbostic default: 12636636Skarels usage(); 12736319Sbostic break; 12836319Sbostic } 12936319Sbostic argc -= optind; 13036319Sbostic argv += optind; 13136319Sbostic 13236636Skarels #ifdef KERBEROS 13336636Skarels if (use_kerberos && vacuous) { 13436636Skarels usage(); 13536636Skarels fatal("only one of -k and -v allowed\n"); 13636636Skarels } 13736636Skarels #endif 13816369Skarels fromlen = sizeof (from); 13916369Skarels if (getpeername(0, &from, &fromlen) < 0) { 14036636Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 14136636Skarels 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; 16436636Skarels register struct hostent *hp; 16536635Skarels char remotehost[2 * MAXHOSTNAMELEN + 1]; 16624724Smckusick struct hostent hostent; 1678380Ssam char c; 1686446Swnj 1696446Swnj alarm(60); 1706446Swnj read(f, &c, 1); 17136636Skarels 17236636Skarels #ifdef KERBEROS 17336636Skarels /* 17436639Skfall * XXX: 1st char tells us which client we're talking to 17536636Skarels */ 17636636Skarels switch (c) { 17736636Skarels 17836639Skfall case OLD_RCMD: /* NB: OLD_RCMD == KERB_RCMD */ 17936636Skarels if (vacuous) 18036636Skarels fatal(f, "Remote host requires Kerberos authentication"); 18136636Skarels break; 18236636Skarels 18336636Skarels case KERB_RCMD_MUTUAL: 18436636Skarels encrypt = 1; 18536636Skarels break; 18636636Skarels 18736636Skarels default: 18836636Skarels fatal(f, "Remote protocol error"); 18936636Skarels } 19036636Skarels #else 1916446Swnj if (c != 0) 1926446Swnj exit(1); 19336636Skarels #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++; 20636636Skarels } else if (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++; 22536636Skarels 22636636Skarels #ifdef KERBEROS 22736636Skarels if (use_kerberos) { 22836636Skarels retval = do_krb_login(hp->h_name, fromp, encrypt); 22936636Skarels write(f, &c, 1); 23036639Skfall if (retval == 0 && hostok) 23136636Skarels authenticated++; 23236636Skarels else if (retval > 0) 23336636Skarels fatal(f, krb_err_txt[retval]); 23436639Skfall else if(!hostok) 23536639Skfall fatal(f, "krlogind: Host address mismatch.\r\n"); 23636636Skarels } else 23736633Skarels #endif 23836639Skfall { 23936639Skfall if (fromp->sin_family != AF_INET || 24036639Skfall fromp->sin_port >= IPPORT_RESERVED || 24136639Skfall fromp->sin_port < IPPORT_RESERVED/2) { 24236639Skfall syslog(LOG_NOTICE, "Connection from %s on illegal port", 24336639Skfall inet_ntoa(fromp->sin_addr)); 24436639Skfall fatal(f, "Permission denied"); 24536639Skfall } 246*36702Skarels #ifdef IP_OPTIONS 247*36702Skarels { 248*36702Skarels u_char optbuf[BUFSIZ/3], *cp; 249*36702Skarels char lbuf[BUFSIZ], *lp; 250*36702Skarels int optsize = sizeof(optbuf), ipproto; 251*36702Skarels struct protoent *ip; 252*36702Skarels 253*36702Skarels if ((ip = getprotobyname("ip")) != NULL) 254*36702Skarels ipproto = ip->p_proto; 255*36702Skarels else 256*36702Skarels ipproto = IPPROTO_IP; 257*36702Skarels if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 258*36702Skarels &optsize) == 0 && optsize != 0) { 259*36702Skarels lp = lbuf; 260*36702Skarels for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 261*36702Skarels sprintf(lp, " %2.2x", *cp); 262*36702Skarels syslog(LOG_NOTICE, 263*36702Skarels "Connection received using IP options (ignored):%s", 264*36702Skarels lbuf); 265*36702Skarels if (setsockopt(0, ipproto, IP_OPTIONS, 266*36702Skarels (char *)NULL, &optsize) != 0) { 267*36702Skarels syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 268*36702Skarels exit(1); 269*36702Skarels } 270*36702Skarels } 271*36702Skarels } 272*36702Skarels #endif 27336639Skfall write(f, "", 1); 27436639Skfall 27536639Skfall if (do_rlogin(hp->h_name) == 0) { 27636639Skfall if (hostok) 27736639Skfall authenticated++; 27836639Skfall else 27936639Skfall write(f, "rlogind: Host address mismatch.\r\n", 28036639Skfall sizeof("rlogind: Host address mismatch.\r\n") - 1); 28136639Skfall } 28236631Skarels } 28336636Skarels 2846446Swnj for (c = 'p'; c <= 's'; c++) { 2856446Swnj struct stat stb; 2866446Swnj line = "/dev/ptyXX"; 2876446Swnj line[strlen("/dev/pty")] = c; 2886446Swnj line[strlen("/dev/ptyp")] = '0'; 2896446Swnj if (stat(line, &stb) < 0) 2906446Swnj break; 2916446Swnj for (i = 0; i < 16; i++) { 29234424Sbostic line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; 29334424Sbostic p = open(line, O_RDWR); 2946446Swnj if (p > 0) 2956446Swnj goto gotpty; 2966446Swnj } 2976446Swnj } 29824723Smckusick fatal(f, "Out of ptys"); 2999242Ssam /*NOTREACHED*/ 3006446Swnj gotpty: 30124889Smckusick (void) ioctl(p, TIOCSWINSZ, &win); 30216227Skarels netf = f; 3036446Swnj line[strlen("/dev/")] = 't'; 30434424Sbostic t = open(line, O_RDWR); 30534424Sbostic if (t < 0) 30634424Sbostic fatalperror(f, line); 30734424Sbostic if (fchmod(t, 0)) 30834424Sbostic fatalperror(f, line); 30934424Sbostic (void)signal(SIGHUP, SIG_IGN); 31034424Sbostic vhangup(); 31134424Sbostic (void)signal(SIGHUP, SIG_DFL); 31234424Sbostic t = open(line, O_RDWR); 31334424Sbostic if (t < 0) 31434424Sbostic fatalperror(f, line); 31536453Skfall setup_term(t); 3166446Swnj #ifdef DEBUG 31734424Sbostic { 31834424Sbostic int tt = open("/dev/tty", O_RDWR); 31934424Sbostic if (tt > 0) { 32034424Sbostic (void)ioctl(tt, TIOCNOTTY, 0); 32134424Sbostic (void)close(tt); 32234424Sbostic } 3236446Swnj } 3246446Swnj #endif 3259242Ssam pid = fork(); 3269242Ssam if (pid < 0) 32734424Sbostic fatalperror(f, ""); 32818357Ssam if (pid == 0) { 32936636Skarels if (setsid() < 0) 33036636Skarels fatalperror(f, "setsid"); 33136636Skarels if (ioctl(t, TIOCSCTTY, 0) < 0) 33236636Skarels fatalperror(f, "ioctl(sctty)"); 33318357Ssam close(f), close(p); 33418357Ssam dup2(t, 0), dup2(t, 1), dup2(t, 2); 33516227Skarels close(t); 33636631Skarels if (authenticated) 33736636Skarels execl("/bin/login", "login", "-p", 33836636Skarels "-h", hp->h_name, "-f", lusername, 0); 33936525Skfall else 34036636Skarels execl("/bin/login", "login", "-p", 34136636Skarels "-h", hp->h_name, lusername, 0); 34234424Sbostic fatalperror(2, "/bin/login"); 34318357Ssam /*NOTREACHED*/ 34418357Ssam } 34518357Ssam close(t); 34636453Skfall 34736636Skarels #ifdef KERBEROS 34836636Skarels /* 34936636Skarels * If encrypted, don't turn on NBIO or the des read/write 35036636Skarels * routines will croak. 35136636Skarels */ 35236636Skarels 35336636Skarels if (encrypt) 35436636Skarels (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)); 35536636Skarels else 35636636Skarels #endif 35736636Skarels ioctl(f, FIONBIO, &on); 35818357Ssam ioctl(p, FIONBIO, &on); 35918357Ssam ioctl(p, TIOCPKT, &on); 36018357Ssam signal(SIGTSTP, SIG_IGN); 36118357Ssam signal(SIGCHLD, cleanup); 36224724Smckusick setpgrp(0, 0); 36318357Ssam protocol(f, p); 36430600Smckusick signal(SIGCHLD, SIG_IGN); 36518357Ssam cleanup(); 36618357Ssam } 3679242Ssam 36818357Ssam char magic[2] = { 0377, 0377 }; 36925423Skarels char oobdata[] = {TIOCPKT_WINDOW}; 37018357Ssam 37118357Ssam /* 37218357Ssam * Handle a "control" request (signaled by magic being present) 37318357Ssam * in the data stream. For now, we are only willing to handle 37418357Ssam * window size changes. 37518357Ssam */ 37618357Ssam control(pty, cp, n) 37718357Ssam int pty; 37818357Ssam char *cp; 37918357Ssam int n; 38018357Ssam { 38128705Smckusick struct winsize w; 38218357Ssam 38328705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 38418357Ssam return (0); 38525423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 38628705Smckusick bcopy(cp+4, (char *)&w, sizeof(w)); 38728705Smckusick w.ws_row = ntohs(w.ws_row); 38828705Smckusick w.ws_col = ntohs(w.ws_col); 38928705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel); 39028705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel); 39128705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w); 39228705Smckusick return (4+sizeof (w)); 39318357Ssam } 39418357Ssam 39518357Ssam /* 39618357Ssam * rlogin "protocol" machine. 39718357Ssam */ 39818357Ssam protocol(f, p) 39918357Ssam int f, p; 40018357Ssam { 40118357Ssam char pibuf[1024], fibuf[1024], *pbp, *fbp; 40218357Ssam register pcc = 0, fcc = 0; 40336517Skarels int cc, nfd, pmask, fmask; 40425740Skarels char cntl; 40518357Ssam 40618482Ssam /* 40718484Ssam * Must ignore SIGTTOU, otherwise we'll stop 40818484Ssam * when we try and set slave pty's window shape 40925423Skarels * (our controlling tty is the master pty). 41018482Ssam */ 41118484Ssam (void) signal(SIGTTOU, SIG_IGN); 41225423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 41336517Skarels if (f > p) 41436517Skarels nfd = f + 1; 41536517Skarels else 41636517Skarels nfd = p + 1; 41736517Skarels fmask = 1 << f; 41836517Skarels pmask = 1 << p; 41918357Ssam for (;;) { 42025740Skarels int ibits, obits, ebits; 42118357Ssam 42225740Skarels ibits = 0; 42325740Skarels obits = 0; 42418357Ssam if (fcc) 42536517Skarels obits |= pmask; 42618357Ssam else 42736517Skarels ibits |= fmask; 42818357Ssam if (pcc >= 0) 42918357Ssam if (pcc) 43036517Skarels obits |= fmask; 4319242Ssam else 43236517Skarels ibits |= pmask; 43336517Skarels ebits = pmask; 43436517Skarels if (select(nfd, &ibits, obits ? &obits : (int *)NULL, 43536517Skarels &ebits, 0) < 0) { 43618357Ssam if (errno == EINTR) 4376446Swnj continue; 43834424Sbostic fatalperror(f, "select"); 43918357Ssam } 44025740Skarels if (ibits == 0 && obits == 0 && ebits == 0) { 44118357Ssam /* shouldn't happen... */ 44218357Ssam sleep(5); 44318357Ssam continue; 44418357Ssam } 44525740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 44636517Skarels if (ebits & pmask) { 44725740Skarels cc = read(p, &cntl, 1); 44825740Skarels if (cc == 1 && pkcontrol(cntl)) { 44925740Skarels cntl |= oobdata[0]; 45025740Skarels send(f, &cntl, 1, MSG_OOB); 45125740Skarels if (cntl & TIOCPKT_FLUSHWRITE) { 45225740Skarels pcc = 0; 45336517Skarels ibits &= ~pmask; 45425740Skarels } 45525740Skarels } 45625740Skarels } 45736517Skarels if (ibits & fmask) { 45836636Skarels #ifdef KERBEROS 45936636Skarels if (encrypt) 46036636Skarels fcc = des_read(f, fibuf, sizeof(fibuf)); 46136636Skarels else 46236636Skarels #endif 46336636Skarels fcc = read(f, fibuf, sizeof(fibuf)); 46418357Ssam if (fcc < 0 && errno == EWOULDBLOCK) 46518357Ssam fcc = 0; 46618357Ssam else { 46718357Ssam register char *cp; 46818357Ssam int left, n; 46918357Ssam 47018357Ssam if (fcc <= 0) 47116227Skarels break; 47218357Ssam fbp = fibuf; 47324723Smckusick 47418357Ssam top: 47525423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++) 47618357Ssam if (cp[0] == magic[0] && 47718357Ssam cp[1] == magic[1]) { 47818357Ssam left = fcc - (cp-fibuf); 47918357Ssam n = control(p, cp, left); 48018357Ssam if (n) { 48118357Ssam left -= n; 48218357Ssam if (left > 0) 48325423Skarels bcopy(cp+n, cp, left); 48418357Ssam fcc -= n; 48518357Ssam goto top; /* n^2 */ 48625423Skarels } 48725423Skarels } 48836517Skarels obits |= pmask; /* try write */ 48925423Skarels } 49025423Skarels } 49124723Smckusick 49236517Skarels if ((obits & pmask) && fcc > 0) { 49325423Skarels cc = write(p, fbp, fcc); 49424723Smckusick if (cc > 0) { 49524723Smckusick fcc -= cc; 49624723Smckusick fbp += cc; 4976446Swnj } 49818357Ssam } 49924723Smckusick 50036517Skarels if (ibits & pmask) { 50118357Ssam pcc = read(p, pibuf, sizeof (pibuf)); 50218357Ssam pbp = pibuf; 50318357Ssam if (pcc < 0 && errno == EWOULDBLOCK) 50418357Ssam pcc = 0; 50518357Ssam else if (pcc <= 0) 50618357Ssam break; 50736517Skarels else if (pibuf[0] == 0) { 50818357Ssam pbp++, pcc--; 50936636Skarels #ifdef KERBEROS 51036636Skarels if (!encrypt) 51136636Skarels #endif 51236636Skarels obits |= fmask; /* try a write */ 51336517Skarels } else { 51418357Ssam if (pkcontrol(pibuf[0])) { 51525423Skarels pibuf[0] |= oobdata[0]; 51618357Ssam send(f, &pibuf[0], 1, MSG_OOB); 51716227Skarels } 51818357Ssam pcc = 0; 5196446Swnj } 52018357Ssam } 52136517Skarels if ((obits & fmask) && pcc > 0) { 52236636Skarels #ifdef KERBEROS 52336636Skarels if (encrypt) 52436636Skarels cc = des_write(f, pbp, pcc); 52536636Skarels else 52636636Skarels #endif 52736636Skarels cc = write(f, pbp, pcc); 52825423Skarels if (cc < 0 && errno == EWOULDBLOCK) { 52925423Skarels /* also shouldn't happen */ 53025423Skarels sleep(5); 53125423Skarels continue; 53225423Skarels } 53318357Ssam if (cc > 0) { 53418357Ssam pcc -= cc; 53518357Ssam pbp += cc; 53618357Ssam } 5376446Swnj } 5386446Swnj } 5396446Swnj } 5406446Swnj 5416446Swnj cleanup() 5426446Swnj { 54335440Sbostic char *p; 54435440Sbostic 54535440Sbostic p = line + sizeof("/dev/") - 1; 54635440Sbostic if (logout(p)) 54735440Sbostic logwtmp(p, "", ""); 54835440Sbostic (void)chmod(line, 0666); 54935440Sbostic (void)chown(line, 0, 0); 55035440Sbostic *p = 'p'; 55135440Sbostic (void)chmod(line, 0666); 55235440Sbostic (void)chown(line, 0, 0); 55310192Ssam shutdown(netf, 2); 5546446Swnj exit(1); 5556446Swnj } 5566446Swnj 5579242Ssam fatal(f, msg) 5589242Ssam int f; 5599242Ssam char *msg; 5609242Ssam { 5619242Ssam char buf[BUFSIZ]; 5629242Ssam 5639242Ssam buf[0] = '\01'; /* error indicator */ 56413554Ssam (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg); 5659242Ssam (void) write(f, buf, strlen(buf)); 5669242Ssam exit(1); 5679242Ssam } 5689242Ssam 56934424Sbostic fatalperror(f, msg) 5709242Ssam int f; 5719242Ssam char *msg; 5729242Ssam { 5739242Ssam char buf[BUFSIZ]; 57416227Skarels extern int sys_nerr; 5759242Ssam extern char *sys_errlist[]; 5769242Ssam 57718357Ssam if ((unsigned)errno < sys_nerr) 57816227Skarels (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); 57916227Skarels else 58016227Skarels (void) sprintf(buf, "%s: Error %d", msg, errno); 5819242Ssam fatal(f, buf); 5829242Ssam } 58336453Skfall 58436453Skfall do_rlogin(host) 58536518Skarels char *host; 58636453Skfall { 58736453Skfall 58836518Skarels getstr(rusername, sizeof(rusername), "remuser too long"); 58936518Skarels getstr(lusername, sizeof(lusername), "locuser too long"); 59036518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 59136518Skarels 59236518Skarels if (getuid()) 59336453Skfall return(-1); 59436453Skfall pwd = getpwnam(lusername); 59536518Skarels if (pwd == NULL) 59636453Skfall return(-1); 59736453Skfall return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); 59836453Skfall } 59936453Skfall 60036453Skfall 60136518Skarels getstr(buf, cnt, errmsg) 60236518Skarels char *buf; 60336518Skarels int cnt; 60436518Skarels char *errmsg; 60536453Skfall { 60636518Skarels char c; 60736518Skarels 60836453Skfall do { 60936518Skarels if (read(0, &c, 1) != 1) 61036453Skfall exit(1); 61136518Skarels if (--cnt < 0) 61236518Skarels fatal(1, errmsg); 61336453Skfall *buf++ = c; 61436518Skarels } while (c != 0); 61536453Skfall } 61636453Skfall 61736518Skarels extern char **environ; 61836453Skfall 61936519Skarels setup_term(fd) 62036519Skarels int fd; 62136519Skarels { 62236636Skarels struct termios tt; 62336636Skarels register char *cp = index(term+ENVSIZE, '/'); 62436519Skarels char *speed; 62536519Skarels 62636636Skarels tcgetattr(fd, &tt); 62736519Skarels if (cp) { 62836519Skarels *cp++ = '\0'; 62936519Skarels speed = cp; 63036519Skarels cp = index(speed, '/'); 63136519Skarels if (cp) 63236519Skarels *cp++ = '\0'; 63336636Skarels cfsetspeed(&tt, atoi(speed)); 63436519Skarels } 63536636Skarels tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL; 63636636Skarels tt.c_oflag = OPOST|ONLCR|OXTABS; 63736636Skarels tt.c_lflag = ISIG|ICANON|ECHO; 63836636Skarels tcsetattr(fd, TCSADFLUSH, &tt); 63936519Skarels 64036519Skarels env[0] = term; 64136519Skarels env[1] = 0; 64236519Skarels environ = env; 64336519Skarels } 64436609Skfall 64536636Skarels #ifdef KERBEROS 64636636Skarels #define VERSION_SIZE 9 64736636Skarels 64836609Skfall /* 64936636Skarels * Do the remote kerberos login to the named host with the 65036636Skarels * given inet address 65136636Skarels * 65236636Skarels * Return 0 on valid authorization 65336636Skarels * Return -1 on valid authentication, no authorization 65436636Skarels * Return >0 for error conditions 65536636Skarels */ 65636636Skarels do_krb_login(host, dest, encrypt) 65736636Skarels char *host; 65836636Skarels struct sockaddr_in *dest; 65936636Skarels int encrypt; 66036636Skarels { 66136636Skarels int rc; 66236636Skarels char instance[INST_SZ], version[VERSION_SIZE]; 66336636Skarels long authopts = 0L; /* !mutual */ 66436636Skarels struct sockaddr_in faddr; 66536636Skarels 66636636Skarels if (getuid()) 66736636Skarels return(KFAILURE); 66836636Skarels 66936636Skarels kdata = (AUTH_DAT *) auth_buf; 67036636Skarels ticket = (KTEXT) tick_buf; 67136636Skarels strcpy(instance, "*"); 67236636Skarels 67336636Skarels if (encrypt) { 67436636Skarels rc = sizeof(faddr); 67536636Skarels if (getsockname(0, &faddr, &rc)) 67636636Skarels return(-1); 67736636Skarels authopts = KOPT_DO_MUTUAL; 67836636Skarels rc = krb_recvauth( 67936636Skarels authopts, 0, 68036636Skarels ticket, "rcmd", 68136636Skarels instance, dest, &faddr, 68236636Skarels kdata, "", schedule, version); 68336636Skarels des_set_key(kdata->session, schedule); 68436636Skarels 68536636Skarels } else { 68636636Skarels rc = krb_recvauth( 68736636Skarels authopts, 0, 68836636Skarels ticket, "rcmd", 68936636Skarels instance, dest, (struct sockaddr_in *) 0, 69036636Skarels kdata, "", (bit_64 *) 0, version); 69136636Skarels } 69236636Skarels 69336636Skarels if (rc != KSUCCESS) 69436636Skarels return(rc); 69536636Skarels 69636636Skarels if ((rc = krb_kntoln(kdata, rusername)) != KSUCCESS) 69736636Skarels return(rc); 69836636Skarels 69936636Skarels getstr(lusername, sizeof(lusername), "locuser"); 70036636Skarels /* get the "cmd" in the rcmd protocol */ 70136636Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 70236636Skarels 70336636Skarels pwd = getpwnam(lusername); 70436636Skarels if (pwd == NULL) 70536636Skarels return(-1); 70636636Skarels 70736636Skarels /* returns nonzero for no access */ 70836636Skarels /* return(ruserok(host, SUPERUSER(pwd), rusername, lusername)); */ 70936636Skarels if (kuserok(kdata,lusername) != 0) 71036636Skarels return(-1); 71136636Skarels 71236636Skarels return(0); 71336636Skarels 71436636Skarels } 71536636Skarels 71636636Skarels #endif /* KERBEROS */ 71736636Skarels 71836636Skarels usage() 71936636Skarels { 72036636Skarels #ifdef KERBEROS 72136636Skarels syslog(LOG_ERR, "usage: rlogind [-k | -v] [-l] [-n]"); 72236636Skarels #else 72336636Skarels syslog(LOG_ERR, "usage: rlogind [-l] [-n]"); 72436636Skarels #endif 72536636Skarels } 72636636Skarels 72736636Skarels /* 72836631Skarels * Check whether host h is in our local domain, 72936631Skarels * as determined by the part of the name following 73036631Skarels * the first '.' in its name and in ours. 73136631Skarels * If either name is unqualified (contains no '.'), 73236631Skarels * assume that the host is local, as it will be 73336631Skarels * interpreted as such. 73436631Skarels */ 73536631Skarels local_domain(h) 73636631Skarels char *h; 73736625Skfall { 73836631Skarels char localhost[MAXHOSTNAMELEN]; 73936631Skarels char *p1, *p2 = index(h, '.'); 74036631Skarels 74136631Skarels (void) gethostname(localhost, sizeof(localhost)); 74236631Skarels p1 = index(localhost, '.'); 74336631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 74436625Skfall return(1); 74536625Skfall return(0); 74636625Skfall } 747