147928Sbostic /*-
261439Sbostic * Copyright (c) 1983, 1988, 1989, 1993
361439Sbostic * The Regents of the University of California. All rights reserved.
435441Sbostic *
547928Sbostic * %sccs.include.redist.c%
621174Sdist */
721174Sdist
86446Swnj #ifndef lint
961439Sbostic static char copyright[] =
1061439Sbostic "@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
1161439Sbostic The Regents of the University of California. All rights reserved.\n";
1235441Sbostic #endif /* not lint */
136446Swnj
1421174Sdist #ifndef lint
15*69044Sbostic static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 04/28/95";
1635441Sbostic #endif /* not lint */
1721174Sdist
1816369Skarels /*
1916369Skarels * remote login server:
2036453Skfall * \0
2116369Skarels * remuser\0
2216369Skarels * locuser\0
2336453Skfall * terminal_type/speed\0
2436518Skarels * data
2516369Skarels */
2616369Skarels
2740917Skarels #define FD_SETSIZE 16 /* don't need many bits for select */
2837290Sbostic #include <sys/param.h>
296446Swnj #include <sys/stat.h>
3037290Sbostic #include <sys/ioctl.h>
3146982Sbostic #include <signal.h>
3246982Sbostic #include <termios.h>
339208Ssam
3446982Sbostic #include <sys/socket.h>
359208Ssam #include <netinet/in.h>
3644347Skarels #include <netinet/in_systm.h>
3744347Skarels #include <netinet/ip.h>
3846982Sbostic #include <arpa/inet.h>
3946982Sbostic #include <netdb.h>
409208Ssam
416446Swnj #include <pwd.h>
4217187Sralph #include <syslog.h>
4346982Sbostic #include <errno.h>
4440917Skarels #include <stdio.h>
4540917Skarels #include <unistd.h>
4646982Sbostic #include <stdlib.h>
4746982Sbostic #include <string.h>
4840917Skarels #include "pathnames.h"
496446Swnj
5036518Skarels #ifndef TIOCPKT_WINDOW
5136518Skarels #define TIOCPKT_WINDOW 0x80
5236518Skarels #endif
5336518Skarels
5440917Skarels #ifdef KERBEROS
5541761Skfall #include <kerberosIV/des.h>
5640917Skarels #include <kerberosIV/krb.h>
5740917Skarels #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
5840917Skarels
5940917Skarels AUTH_DAT *kdata;
6040917Skarels KTEXT ticket;
6140917Skarels u_char auth_buf[sizeof(AUTH_DAT)];
6240917Skarels u_char tick_buf[sizeof(KTEXT_ST)];
6340917Skarels Key_schedule schedule;
6446982Sbostic int doencrypt, retval, use_kerberos, vacuous;
6540917Skarels
6640917Skarels #define ARGSTR "alnkvx"
6740917Skarels #else
6840917Skarels #define ARGSTR "aln"
6940917Skarels #endif /* KERBEROS */
7040917Skarels
7136518Skarels char *env[2];
7236518Skarels #define NMAX 30
7336517Skarels char lusername[NMAX+1], rusername[NMAX+1];
7436517Skarels static char term[64] = "TERM=";
7536517Skarels #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
7636517Skarels int keepalive = 1;
7739058Skarels int check_all = 0;
7836453Skfall
7946982Sbostic struct passwd *pwd;
8016369Skarels
8154547Sleres void doit __P((int, struct sockaddr_in *));
8254547Sleres int control __P((int, char *, int));
8354547Sleres void protocol __P((int, int));
8454554Sbostic void cleanup __P((int));
8554547Sleres void fatal __P((int, char *, int));
8654547Sleres int do_rlogin __P((struct sockaddr_in *));
8754547Sleres void getstr __P((char *, int, char *));
8854547Sleres void setup_term __P((int));
8954547Sleres int do_krb_login __P((struct sockaddr_in *));
9054547Sleres void usage __P((void));
9154547Sleres int local_domain __P((char *));
9254547Sleres char *topdomain __P((char *));
9354547Sleres
9454547Sleres int
main(argc,argv)956446Swnj main(argc, argv)
966446Swnj int argc;
9754547Sleres char *argv[];
986446Swnj {
9954547Sleres extern int __check_rhosts_file;
1006446Swnj struct sockaddr_in from;
10154547Sleres int ch, fromlen, on;
1026446Swnj
10336625Skfall openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
10436319Sbostic
10536319Sbostic opterr = 0;
10640917Skarels while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
10736517Skarels switch (ch) {
10839058Skarels case 'a':
10939058Skarels check_all = 1;
11039058Skarels break;
11136319Sbostic case 'l':
11254547Sleres __check_rhosts_file = 0;
11336319Sbostic break;
11436517Skarels case 'n':
11536517Skarels keepalive = 0;
11636517Skarels break;
11740917Skarels #ifdef KERBEROS
11840917Skarels case 'k':
11940917Skarels use_kerberos = 1;
12040917Skarels break;
12140917Skarels case 'v':
12240917Skarels vacuous = 1;
12340917Skarels break;
12454547Sleres #ifdef CRYPT
12554547Sleres case 'x':
12654547Sleres doencrypt = 1;
12754547Sleres break;
12840917Skarels #endif
12954547Sleres #endif
13036319Sbostic case '?':
13136319Sbostic default:
13240917Skarels usage();
13336319Sbostic break;
13436319Sbostic }
13536319Sbostic argc -= optind;
13636319Sbostic argv += optind;
13736319Sbostic
13840917Skarels #ifdef KERBEROS
13940917Skarels if (use_kerberos && vacuous) {
14040917Skarels usage();
14140917Skarels fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
14240917Skarels }
14340917Skarels #endif
14416369Skarels fromlen = sizeof (from);
14546982Sbostic if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
14640917Skarels syslog(LOG_ERR,"Can't get peer name of remote host: %m");
14740917Skarels fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
1488380Ssam }
14954547Sleres on = 1;
15036517Skarels if (keepalive &&
15136517Skarels setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
15217187Sralph syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
15344347Skarels on = IPTOS_LOWDELAY;
15444347Skarels if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
15544347Skarels syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
15616369Skarels doit(0, &from);
1576446Swnj }
1586446Swnj
1596446Swnj int child;
1606446Swnj int netf;
16144349Smarc char line[MAXPATHLEN];
16240917Skarels int confirmed;
1636446Swnj
16424889Smckusick struct winsize win = { 0, 0, 0, 0 };
16524723Smckusick
16624889Smckusick
16754547Sleres void
doit(f,fromp)1686446Swnj doit(f, fromp)
1696446Swnj int f;
1706446Swnj struct sockaddr_in *fromp;
1716446Swnj {
17254547Sleres int master, pid, on = 1;
17354547Sleres int authenticated = 0;
17440917Skarels register struct hostent *hp;
17554589Sbostic char hostname[2 * MAXHOSTNAMELEN + 1];
1768380Ssam char c;
1776446Swnj
1786446Swnj alarm(60);
1796446Swnj read(f, &c, 1);
18040917Skarels
18139249Smarc if (c != 0)
18236715Skfall exit(1);
18340917Skarels #ifdef KERBEROS
18440917Skarels if (vacuous)
18540917Skarels fatal(f, "Remote host requires Kerberos authentication", 0);
18640917Skarels #endif
18736453Skfall
1886446Swnj alarm(0);
18916227Skarels fromp->sin_port = ntohs((u_short)fromp->sin_port);
19046982Sbostic hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
19154547Sleres fromp->sin_family);
19254547Sleres if (hp)
19354589Sbostic (void)strcpy(hostname, hp->h_name);
19454547Sleres else
19554589Sbostic (void)strcpy(hostname, inet_ntoa(fromp->sin_addr));
19636711Skfall
19740917Skarels #ifdef KERBEROS
19840917Skarels if (use_kerberos) {
19954547Sleres retval = do_krb_login(fromp);
20042264Sbostic if (retval == 0)
20140917Skarels authenticated++;
20240917Skarels else if (retval > 0)
20340917Skarels fatal(f, krb_err_txt[retval], 0);
20440917Skarels write(f, &c, 1);
20540917Skarels confirmed = 1; /* we sent the null! */
20640917Skarels } else
20740917Skarels #endif
20840917Skarels {
20954547Sleres if (fromp->sin_family != AF_INET ||
21054547Sleres fromp->sin_port >= IPPORT_RESERVED ||
21154547Sleres fromp->sin_port < IPPORT_RESERVED/2) {
21254547Sleres syslog(LOG_NOTICE, "Connection from %s on illegal port",
21354547Sleres inet_ntoa(fromp->sin_addr));
21454547Sleres fatal(f, "Permission denied", 0);
21554547Sleres }
21636702Skarels #ifdef IP_OPTIONS
21754547Sleres {
21854547Sleres u_char optbuf[BUFSIZ/3], *cp;
21954547Sleres char lbuf[BUFSIZ], *lp;
22054547Sleres int optsize = sizeof(optbuf), ipproto;
22154547Sleres struct protoent *ip;
22236702Skarels
22354547Sleres if ((ip = getprotobyname("ip")) != NULL)
22454547Sleres ipproto = ip->p_proto;
22554547Sleres else
22654547Sleres ipproto = IPPROTO_IP;
22754547Sleres if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
22854547Sleres &optsize) == 0 && optsize != 0) {
22954547Sleres lp = lbuf;
23054547Sleres for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
23154547Sleres sprintf(lp, " %2.2x", *cp);
23254547Sleres syslog(LOG_NOTICE,
23354547Sleres "Connection received using IP options (ignored):%s",
23454547Sleres lbuf);
23554547Sleres if (setsockopt(0, ipproto, IP_OPTIONS,
23654547Sleres (char *)NULL, optsize) != 0) {
23754547Sleres syslog(LOG_ERR,
23854547Sleres "setsockopt IP_OPTIONS NULL: %m");
23954547Sleres exit(1);
24054547Sleres }
24154547Sleres }
24254547Sleres }
24336702Skarels #endif
24454547Sleres if (do_rlogin(fromp) == 0)
24554547Sleres authenticated++;
24636631Skarels }
24740917Skarels if (confirmed == 0) {
24840917Skarels write(f, "", 1);
24940917Skarels confirmed = 1; /* we sent the null! */
25039249Smarc }
25140917Skarels #ifdef KERBEROS
25254547Sleres #ifdef CRYPT
25354547Sleres if (doencrypt)
25456424Sbostic (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE) - 1);
25539249Smarc #endif
25654547Sleres #endif
25744349Smarc netf = f;
25844349Smarc
25944349Smarc pid = forkpty(&master, line, NULL, &win);
26044349Smarc if (pid < 0) {
26144349Smarc if (errno == ENOENT)
26244349Smarc fatal(f, "Out of ptys", 0);
26344349Smarc else
26444349Smarc fatal(f, "Forkpty", 1);
26544349Smarc }
26618357Ssam if (pid == 0) {
26754547Sleres if (f > 2) /* f should always be 0, but... */
26844349Smarc (void) close(f);
26944349Smarc setup_term(0);
27043363Skfall if (authenticated) {
27144347Skarels #ifdef KERBEROS
27243363Skfall if (use_kerberos && (pwd->pw_uid == 0))
27343363Skfall syslog(LOG_INFO|LOG_AUTH,
27443363Skfall "ROOT Kerberos login from %s.%s@%s on %s\n",
27543363Skfall kdata->pname, kdata->pinst, kdata->prealm,
27654547Sleres hostname);
27744347Skarels #endif
27843363Skfall
279*69044Sbostic execle(_PATH_LOGIN, "login", "-p",
280*69044Sbostic "-h", hostname, "-f", "--", lusername, NULL, env);
28143363Skfall } else
282*69044Sbostic execle(_PATH_LOGIN, "login", "-p",
283*69044Sbostic "-h", hostname, "--", lusername, NULL, env);
28440917Skarels fatal(STDERR_FILENO, _PATH_LOGIN, 1);
28518357Ssam /*NOTREACHED*/
28618357Ssam }
28754547Sleres #ifdef CRYPT
28854547Sleres #ifdef KERBEROS
28954547Sleres /*
29054547Sleres * If encrypted, don't turn on NBIO or the des read/write
29154547Sleres * routines will croak.
29254547Sleres */
29354547Sleres
29454547Sleres if (!doencrypt)
29554547Sleres #endif
29654547Sleres #endif
29740917Skarels ioctl(f, FIONBIO, &on);
29844349Smarc ioctl(master, FIONBIO, &on);
29944349Smarc ioctl(master, TIOCPKT, &on);
30018357Ssam signal(SIGCHLD, cleanup);
30144349Smarc protocol(f, master);
30230600Smckusick signal(SIGCHLD, SIG_IGN);
30354554Sbostic cleanup(0);
30418357Ssam }
3059242Ssam
30618357Ssam char magic[2] = { 0377, 0377 };
30725423Skarels char oobdata[] = {TIOCPKT_WINDOW};
30818357Ssam
30918357Ssam /*
31018357Ssam * Handle a "control" request (signaled by magic being present)
31118357Ssam * in the data stream. For now, we are only willing to handle
31218357Ssam * window size changes.
31318357Ssam */
31454547Sleres int
control(pty,cp,n)31518357Ssam control(pty, cp, n)
31618357Ssam int pty;
31718357Ssam char *cp;
31818357Ssam int n;
31918357Ssam {
32028705Smckusick struct winsize w;
32118357Ssam
32228705Smckusick if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
32318357Ssam return (0);
32425423Skarels oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
325*69044Sbostic memmove(&w, cp+4, sizeof(w));
32628705Smckusick w.ws_row = ntohs(w.ws_row);
32728705Smckusick w.ws_col = ntohs(w.ws_col);
32828705Smckusick w.ws_xpixel = ntohs(w.ws_xpixel);
32928705Smckusick w.ws_ypixel = ntohs(w.ws_ypixel);
33028705Smckusick (void)ioctl(pty, TIOCSWINSZ, &w);
33128705Smckusick return (4+sizeof (w));
33218357Ssam }
33318357Ssam
33418357Ssam /*
33518357Ssam * rlogin "protocol" machine.
33618357Ssam */
33754547Sleres void
protocol(f,p)33818357Ssam protocol(f, p)
33940917Skarels register int f, p;
34018357Ssam {
34140917Skarels char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
34218357Ssam register pcc = 0, fcc = 0;
34340917Skarels int cc, nfd, n;
34425740Skarels char cntl;
34518357Ssam
34618482Ssam /*
34718484Ssam * Must ignore SIGTTOU, otherwise we'll stop
34818484Ssam * when we try and set slave pty's window shape
34925423Skarels * (our controlling tty is the master pty).
35018482Ssam */
35118484Ssam (void) signal(SIGTTOU, SIG_IGN);
35225423Skarels send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
35336517Skarels if (f > p)
35436517Skarels nfd = f + 1;
35536517Skarels else
35636517Skarels nfd = p + 1;
35740917Skarels if (nfd > FD_SETSIZE) {
35840917Skarels syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
35940917Skarels fatal(f, "internal error (select mask too small)", 0);
36040917Skarels }
36118357Ssam for (;;) {
36240917Skarels fd_set ibits, obits, ebits, *omask;
36318357Ssam
36442956Sbostic FD_ZERO(&ebits);
36540917Skarels FD_ZERO(&ibits);
36640917Skarels FD_ZERO(&obits);
36740917Skarels omask = (fd_set *)NULL;
36840917Skarels if (fcc) {
36940917Skarels FD_SET(p, &obits);
37040917Skarels omask = &obits;
37140917Skarels } else
37240917Skarels FD_SET(f, &ibits);
37318357Ssam if (pcc >= 0)
37440917Skarels if (pcc) {
37540917Skarels FD_SET(f, &obits);
37640917Skarels omask = &obits;
37740917Skarels } else
37840917Skarels FD_SET(p, &ibits);
37940917Skarels FD_SET(p, &ebits);
38040917Skarels if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
38118357Ssam if (errno == EINTR)
3826446Swnj continue;
38340917Skarels fatal(f, "select", 1);
38418357Ssam }
38540917Skarels if (n == 0) {
38618357Ssam /* shouldn't happen... */
38718357Ssam sleep(5);
38818357Ssam continue;
38918357Ssam }
39025740Skarels #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
39140917Skarels if (FD_ISSET(p, &ebits)) {
39225740Skarels cc = read(p, &cntl, 1);
39325740Skarels if (cc == 1 && pkcontrol(cntl)) {
39425740Skarels cntl |= oobdata[0];
39525740Skarels send(f, &cntl, 1, MSG_OOB);
39625740Skarels if (cntl & TIOCPKT_FLUSHWRITE) {
39725740Skarels pcc = 0;
39840917Skarels FD_CLR(p, &ibits);
39925740Skarels }
40025740Skarels }
40125740Skarels }
40240917Skarels if (FD_ISSET(f, &ibits)) {
40354547Sleres #ifdef CRYPT
40454547Sleres #ifdef KERBEROS
40554547Sleres if (doencrypt)
40654547Sleres fcc = des_read(f, fibuf, sizeof(fibuf));
40754547Sleres else
40854547Sleres #endif
40954547Sleres #endif
41040917Skarels fcc = read(f, fibuf, sizeof(fibuf));
41118357Ssam if (fcc < 0 && errno == EWOULDBLOCK)
41218357Ssam fcc = 0;
41318357Ssam else {
41418357Ssam register char *cp;
41518357Ssam int left, n;
41618357Ssam
41718357Ssam if (fcc <= 0)
41816227Skarels break;
41918357Ssam fbp = fibuf;
42024723Smckusick
42118357Ssam top:
42225423Skarels for (cp = fibuf; cp < fibuf+fcc-1; cp++)
42318357Ssam if (cp[0] == magic[0] &&
42418357Ssam cp[1] == magic[1]) {
42518357Ssam left = fcc - (cp-fibuf);
42618357Ssam n = control(p, cp, left);
42718357Ssam if (n) {
42818357Ssam left -= n;
42918357Ssam if (left > 0)
43025423Skarels bcopy(cp+n, cp, left);
43118357Ssam fcc -= n;
43218357Ssam goto top; /* n^2 */
43325423Skarels }
43425423Skarels }
43540917Skarels FD_SET(p, &obits); /* try write */
43625423Skarels }
43725423Skarels }
43824723Smckusick
43940917Skarels if (FD_ISSET(p, &obits) && fcc > 0) {
44025423Skarels cc = write(p, fbp, fcc);
44124723Smckusick if (cc > 0) {
44224723Smckusick fcc -= cc;
44324723Smckusick fbp += cc;
4446446Swnj }
44518357Ssam }
44624723Smckusick
44740917Skarels if (FD_ISSET(p, &ibits)) {
44818357Ssam pcc = read(p, pibuf, sizeof (pibuf));
44918357Ssam pbp = pibuf;
45018357Ssam if (pcc < 0 && errno == EWOULDBLOCK)
45118357Ssam pcc = 0;
45218357Ssam else if (pcc <= 0)
45318357Ssam break;
45436517Skarels else if (pibuf[0] == 0) {
45518357Ssam pbp++, pcc--;
45654547Sleres #ifdef CRYPT
45754547Sleres #ifdef KERBEROS
45854547Sleres if (!doencrypt)
45954547Sleres #endif
46054547Sleres #endif
46140917Skarels FD_SET(f, &obits); /* try write */
46236517Skarels } else {
46318357Ssam if (pkcontrol(pibuf[0])) {
46425423Skarels pibuf[0] |= oobdata[0];
46518357Ssam send(f, &pibuf[0], 1, MSG_OOB);
46616227Skarels }
46718357Ssam pcc = 0;
4686446Swnj }
46918357Ssam }
47040917Skarels if ((FD_ISSET(f, &obits)) && pcc > 0) {
47154547Sleres #ifdef CRYPT
47254547Sleres #ifdef KERBEROS
47354547Sleres if (doencrypt)
47454547Sleres cc = des_write(f, pbp, pcc);
47554547Sleres else
47654547Sleres #endif
47754547Sleres #endif
47840917Skarels cc = write(f, pbp, pcc);
47925423Skarels if (cc < 0 && errno == EWOULDBLOCK) {
48040917Skarels /*
48140917Skarels * This happens when we try write after read
48240917Skarels * from p, but some old kernels balk at large
48340917Skarels * writes even when select returns true.
48440917Skarels */
48540917Skarels if (!FD_ISSET(p, &ibits))
48640917Skarels sleep(5);
48725423Skarels continue;
48825423Skarels }
48918357Ssam if (cc > 0) {
49018357Ssam pcc -= cc;
49118357Ssam pbp += cc;
49218357Ssam }
4936446Swnj }
4946446Swnj }
4956446Swnj }
4966446Swnj
49746982Sbostic void
cleanup(signo)49854554Sbostic cleanup(signo)
49954554Sbostic int signo;
5006446Swnj {
50135440Sbostic char *p;
50235440Sbostic
50340917Skarels p = line + sizeof(_PATH_DEV) - 1;
50435440Sbostic if (logout(p))
50535440Sbostic logwtmp(p, "", "");
50648380Skarels (void)chmod(line, 0666);
50735440Sbostic (void)chown(line, 0, 0);
50835440Sbostic *p = 'p';
50948380Skarels (void)chmod(line, 0666);
51035440Sbostic (void)chown(line, 0, 0);
51110192Ssam shutdown(netf, 2);
5126446Swnj exit(1);
5136446Swnj }
5146446Swnj
51554547Sleres void
fatal(f,msg,syserr)51640917Skarels fatal(f, msg, syserr)
51754547Sleres int f;
5189242Ssam char *msg;
51954547Sleres int syserr;
5209242Ssam {
52140917Skarels int len;
52240917Skarels char buf[BUFSIZ], *bp = buf;
5239242Ssam
52440917Skarels /*
52540917Skarels * Prepend binary one to message if we haven't sent
52640917Skarels * the magic null as confirmation.
52740917Skarels */
52840917Skarels if (!confirmed)
52940917Skarels *bp++ = '\01'; /* error indicator */
53040917Skarels if (syserr)
53140917Skarels len = sprintf(bp, "rlogind: %s: %s.\r\n",
53240917Skarels msg, strerror(errno));
53340917Skarels else
53440917Skarels len = sprintf(bp, "rlogind: %s.\r\n", msg);
53540917Skarels (void) write(f, buf, bp + len - buf);
5369242Ssam exit(1);
5379242Ssam }
5389242Ssam
53954547Sleres int
do_rlogin(dest)54054547Sleres do_rlogin(dest)
54154547Sleres struct sockaddr_in *dest;
54236453Skfall {
54336518Skarels getstr(rusername, sizeof(rusername), "remuser too long");
54436518Skarels getstr(lusername, sizeof(lusername), "locuser too long");
54536518Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
54636518Skarels
54736453Skfall pwd = getpwnam(lusername);
54836518Skarels if (pwd == NULL)
54954547Sleres return (-1);
55042264Sbostic if (pwd->pw_uid == 0)
55154547Sleres return (-1);
55254547Sleres /* XXX why don't we syslog() failure? */
55354547Sleres return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername));
55436453Skfall }
55536453Skfall
55654547Sleres void
getstr(buf,cnt,errmsg)55736518Skarels getstr(buf, cnt, errmsg)
55836518Skarels char *buf;
55936518Skarels int cnt;
56036518Skarels char *errmsg;
56136453Skfall {
56236518Skarels char c;
56336518Skarels
56436453Skfall do {
56536518Skarels if (read(0, &c, 1) != 1)
56636453Skfall exit(1);
56736518Skarels if (--cnt < 0)
56840917Skarels fatal(STDOUT_FILENO, errmsg, 0);
56936453Skfall *buf++ = c;
57036518Skarels } while (c != 0);
57136453Skfall }
57236453Skfall
57354547Sleres void
setup_term(fd)57436519Skarels setup_term(fd)
57536519Skarels int fd;
57636519Skarels {
57740917Skarels register char *cp = index(term+ENVSIZE, '/');
57836519Skarels char *speed;
57939118Skarels struct termios tt;
58036519Skarels
58140917Skarels #ifndef notyet
58236711Skfall tcgetattr(fd, &tt);
58336519Skarels if (cp) {
58436519Skarels *cp++ = '\0';
58536519Skarels speed = cp;
58636519Skarels cp = index(speed, '/');
58736519Skarels if (cp)
58836519Skarels *cp++ = '\0';
58936711Skfall cfsetspeed(&tt, atoi(speed));
59036519Skarels }
59138710Skfall
59239118Skarels tt.c_iflag = TTYDEF_IFLAG;
59339118Skarels tt.c_oflag = TTYDEF_OFLAG;
59439118Skarels tt.c_lflag = TTYDEF_LFLAG;
59543272Sbostic tcsetattr(fd, TCSAFLUSH, &tt);
59639118Skarels #else
59739118Skarels if (cp) {
59839118Skarels *cp++ = '\0';
59939118Skarels speed = cp;
60039118Skarels cp = index(speed, '/');
60139118Skarels if (cp)
60239118Skarels *cp++ = '\0';
60340917Skarels tcgetattr(fd, &tt);
60440917Skarels cfsetspeed(&tt, atoi(speed));
60543272Sbostic tcsetattr(fd, TCSAFLUSH, &tt);
60638710Skfall }
60738710Skfall #endif
60836519Skarels
60936519Skarels env[0] = term;
61036519Skarels env[1] = 0;
61136519Skarels }
61236609Skfall
61340917Skarels #ifdef KERBEROS
61440917Skarels #define VERSION_SIZE 9
61540917Skarels
61636609Skfall /*
61740917Skarels * Do the remote kerberos login to the named host with the
61840917Skarels * given inet address
61940917Skarels *
62040917Skarels * Return 0 on valid authorization
62140917Skarels * Return -1 on valid authentication, no authorization
62240917Skarels * Return >0 for error conditions
62340917Skarels */
62454547Sleres int
do_krb_login(dest)62554547Sleres do_krb_login(dest)
62640917Skarels struct sockaddr_in *dest;
62740917Skarels {
62840917Skarels int rc;
62940917Skarels char instance[INST_SZ], version[VERSION_SIZE];
63040917Skarels long authopts = 0L; /* !mutual */
63140917Skarels struct sockaddr_in faddr;
63240917Skarels
63340917Skarels kdata = (AUTH_DAT *) auth_buf;
63440917Skarels ticket = (KTEXT) tick_buf;
63540917Skarels
63642264Sbostic instance[0] = '*';
63742264Sbostic instance[1] = '\0';
63842264Sbostic
63954547Sleres #ifdef CRYPT
64054547Sleres if (doencrypt) {
64154547Sleres rc = sizeof(faddr);
64254547Sleres if (getsockname(0, (struct sockaddr *)&faddr, &rc))
64354547Sleres return (-1);
64454547Sleres authopts = KOPT_DO_MUTUAL;
64540917Skarels rc = krb_recvauth(
64640917Skarels authopts, 0,
64740917Skarels ticket, "rcmd",
64854547Sleres instance, dest, &faddr,
64954547Sleres kdata, "", schedule, version);
65054547Sleres des_set_key(kdata->session, schedule);
65154547Sleres
65254547Sleres } else
65354547Sleres #endif
65454547Sleres rc = krb_recvauth(
65554547Sleres authopts, 0,
65654547Sleres ticket, "rcmd",
65740917Skarels instance, dest, (struct sockaddr_in *) 0,
65840917Skarels kdata, "", (bit_64 *) 0, version);
65940917Skarels
66040917Skarels if (rc != KSUCCESS)
66154547Sleres return (rc);
66240917Skarels
66340917Skarels getstr(lusername, sizeof(lusername), "locuser");
66440917Skarels /* get the "cmd" in the rcmd protocol */
66540917Skarels getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
66640917Skarels
66740917Skarels pwd = getpwnam(lusername);
66840917Skarels if (pwd == NULL)
66954547Sleres return (-1);
67040917Skarels
67140917Skarels /* returns nonzero for no access */
67254547Sleres if (kuserok(kdata, lusername) != 0)
67354547Sleres return (-1);
67440917Skarels
67554547Sleres return (0);
67640917Skarels
67740917Skarels }
67840917Skarels #endif /* KERBEROS */
67940917Skarels
68054547Sleres void
usage()68140917Skarels usage()
68240917Skarels {
68340917Skarels #ifdef KERBEROS
68440917Skarels syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
68540917Skarels #else
68640917Skarels syslog(LOG_ERR, "usage: rlogind [-aln]");
68740917Skarels #endif
68840917Skarels }
68940917Skarels
69040917Skarels /*
69136631Skarels * Check whether host h is in our local domain,
69239058Skarels * defined as sharing the last two components of the domain part,
69339058Skarels * or the entire domain part if the local domain has only one component.
69436631Skarels * If either name is unqualified (contains no '.'),
69536631Skarels * assume that the host is local, as it will be
69636631Skarels * interpreted as such.
69736631Skarels */
69854547Sleres int
local_domain(h)69936631Skarels local_domain(h)
70036631Skarels char *h;
70136625Skfall {
70236631Skarels char localhost[MAXHOSTNAMELEN];
70354547Sleres char *p1, *p2;
70436631Skarels
70539058Skarels localhost[0] = 0;
70636631Skarels (void) gethostname(localhost, sizeof(localhost));
70739058Skarels p1 = topdomain(localhost);
70839058Skarels p2 = topdomain(h);
70936631Skarels if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
71054547Sleres return (1);
71154547Sleres return (0);
71236625Skfall }
71339058Skarels
71439058Skarels char *
topdomain(h)71539058Skarels topdomain(h)
71639058Skarels char *h;
71739058Skarels {
71839058Skarels register char *p;
71939058Skarels char *maybe = NULL;
72039058Skarels int dots = 0;
72139058Skarels
72239058Skarels for (p = h + strlen(h); p >= h; p--) {
72339058Skarels if (*p == '.') {
72439058Skarels if (++dots == 2)
72539058Skarels return (p);
72639058Skarels maybe = p;
72739058Skarels }
72839058Skarels }
72939058Skarels return (maybe);
73039058Skarels }
731