2 * Copyright (c) 1983, 1988, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * remote login server:
39 * terminal_type/speed\0
45 RCSID("$Id: rlogind.c,v 1.109.2.2 2000/06/23 02:37:06 assar Exp $");
47 extern int __check_rhosts_file;
49 char *INSECURE_MESSAGE =
50 "\r\n*** Connection not encrypted! Communication may be eavesdropped. ***"
51 "\r\n*** Use telnet or rlogin -x instead! ***\r\n";
54 char *SECURE_MESSAGE =
55 "This rlogin session is using DES encryption for all transmissions.\r\n";
57 #define SECURE_MESSAGE INSECURE_MESSAGE
62 u_char auth_buf[sizeof(AUTH_DAT)];
63 u_char tick_buf[sizeof(KTEXT_ST)];
64 Key_schedule schedule;
65 int doencrypt, retval, use_kerberos, vacuous;
67 #define ARGSTR "Daip:lnkvxL:"
71 char lusername[NMAX+1], rusername[NMAX+1];
72 static char term[64] = "TERM=";
73 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
80 static const char *new_login = _PATH_LOGIN;
82 static void doit (int, struct sockaddr_in *);
83 static int control (int, char *, int);
84 static void protocol (int, int);
85 static RETSIGTYPE cleanup (int);
86 void fatal (int, const char *, int);
87 static int do_rlogin (struct sockaddr_in *);
88 static void setup_term (int);
89 static int do_krb_login (struct sockaddr_in *);
90 static void usage (void);
93 readstream(int p, char *ibuf, int bufsize)
96 return read(p, ibuf, bufsize);
98 static int flowison = -1; /* current state of flow: -1 is unknown */
99 static struct strbuf strbufc, strbufd;
100 static unsigned char ctlbuf[BUFSIZ];
101 static int use_read = 1;
114 ret = read(p, ibuf, bufsize);
115 if (ret < 0 && errno == EBADMSG)
121 strbufc.maxlen = BUFSIZ;
122 strbufc.buf = (char *)ctlbuf;
123 strbufd.maxlen = bufsize-1;
125 strbufd.buf = ibuf+1;
128 ret = getmsg(p, &strbufc, &strbufd, &flags);
129 if (ret < 0) /* error of some sort -- probably EAGAIN */
132 if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
134 if (strbufd.len > 0) { /* real data */
135 return(strbufd.len + 1); /* count header char */
144 * It's a control message. Return 1, to look at the flag we set
149 if (ibuf[1] & FLUSHW)
150 ibuf[0] = TIOCPKT_FLUSHWRITE;
154 memcpy(&ip, (ibuf+1), sizeof(ip));
156 switch (ip.ioc_cmd) {
162 (ibuf+1 + sizeof(struct iocblk)),
164 vstop = tsp.c_cc[VSTOP];
165 vstart = tsp.c_cc[VSTART];
166 ixon = tsp.c_iflag & IXON;
174 newflow = (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
175 if (newflow != flowison) { /* it's a change */
177 ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
182 /* nothing worth doing anything about */
190 rlogind_logout(const char *line)
192 struct utmpx utmpx, *utxp;
196 memset(&utmpx, 0, sizeof(utmpx));
197 utmpx.ut_type = USER_PROCESS;
198 strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
199 utxp = getutxline(&utmpx);
201 utxp->ut_user[0] = '\0';
202 utxp->ut_type = DEAD_PROCESS;
203 #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
204 #ifdef _STRUCT___EXIT_STATUS
205 utxp->ut_exit.__e_termination = 0;
206 utxp->ut_exit.__e_exit = 0;
207 #elif defined(__osf__) /* XXX */
208 utxp->ut_exit.ut_termination = 0;
209 utxp->ut_exit.ut_exit = 0;
211 utxp->ut_exit.e_termination = 0;
212 utxp->ut_exit.e_exit = 0;
215 gettimeofday(&utxp->ut_tv, NULL);
218 updwtmpx(WTMPX_FILE, utxp);
228 rlogind_logout(const char *line)
234 if (!(fp = fopen(_PATH_UTMP, "r+")))
237 while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) {
238 if (!ut.ut_name[0] ||
239 strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
241 memset(ut.ut_name, 0, sizeof(ut.ut_name));
242 #ifdef HAVE_STRUCT_UTMP_UT_HOST
243 memset(ut.ut_host, 0, sizeof(ut.ut_host));
245 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
246 ut.ut_type = DEAD_PROCESS;
248 #ifdef HAVE_STRUCT_UTMP_UT_EXIT
249 #ifdef _STRUCT___EXIT_STATUS
250 ut.ut_exit.__e_termination = 0;
251 ut.ut_exit.__e_exit = 0;
252 #elif defined(__osf__) /* XXX */
253 ut.ut_exit.ut_termination = 0;
254 ut.ut_exit.ut_exit = 0;
256 ut.ut_exit.e_termination = 0;
257 ut.ut_exit.e_exit = 0;
260 ut.ut_time = time(NULL);
261 fseek(fp, (long)-sizeof(struct utmp), SEEK_CUR);
262 fwrite(&ut, sizeof(struct utmp), 1, fp);
263 fseek(fp, (long)0, SEEK_CUR);
273 logwtmp(const char *line, const char *name, const char *host)
279 memset (&ut, 0, sizeof(ut));
280 if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
282 if (!fstat(fd, &buf)) {
283 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
284 strncpy(ut.ut_name, name, sizeof(ut.ut_name));
285 #ifdef HAVE_STRUCT_UTMP_UT_ID
286 strncpy(ut.ut_id, make_id((char *)line), sizeof(ut.ut_id));
288 #ifdef HAVE_STRUCT_UTMP_UT_HOST
289 strncpy(ut.ut_host, host, sizeof(ut.ut_host));
291 #ifdef HAVE_STRUCT_UTMP_UT_PID
292 ut.ut_pid = getpid();
294 #ifdef HAVE_STRUCT_UTMP_UT_TYPE
296 ut.ut_type = USER_PROCESS;
298 ut.ut_type = DEAD_PROCESS;
300 ut.ut_time = time(NULL);
301 if (write(fd, &ut, sizeof(struct utmp)) !=
303 ftruncate(fd, buf.st_size);
310 main(int argc, char **argv)
312 struct sockaddr_in from;
317 set_progname(argv[0]);
319 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
322 while ((ch = getopt(argc, argv, ARGSTR)) != -1)
333 portnum = htons(atoi(optarg));
336 __check_rhosts_file = 0;
361 if (use_kerberos && vacuous) {
363 fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
367 portnum = get_login_port (use_kerberos, doencrypt);
368 mini_inetd (portnum);
371 fromlen = sizeof (from);
372 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
373 syslog(LOG_ERR,"Can't get peer name of remote host: %m");
374 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
377 #ifdef HAVE_SETSOCKOPT
380 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (void *)&on,
382 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
386 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, (void *)&on,
388 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
393 if (setsockopt(0, IPPROTO_IP, IP_TOS, (void *)&on, sizeof(int)) < 0)
394 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
396 #endif /* HAVE_SETSOCKOPT */
403 char line[MaxPathLen];
406 struct winsize win = { 0, 0, 0, 0 };
410 doit(int f, struct sockaddr_in *fromp)
412 int master, pid, on = 1;
413 int authenticated = 0;
414 char hostname[2 * MaxHostNameLen + 1];
423 fatal(f, "Remote host requires Kerberos authentication", 0);
426 inaddr2str (fromp->sin_addr, hostname, sizeof(hostname));
429 retval = do_krb_login(fromp);
433 fatal(f, krb_get_err_text(retval), 0);
435 confirmed = 1; /* we sent the null! */
437 fromp->sin_port = ntohs((u_short)fromp->sin_port);
438 if (fromp->sin_family != AF_INET ||
439 fromp->sin_port >= IPPORT_RESERVED ||
440 fromp->sin_port < IPPORT_RESERVED/2) {
441 syslog(LOG_NOTICE, "Connection from %s on illegal port",
442 inet_ntoa(fromp->sin_addr));
443 fatal(f, "Permission denied", 0);
445 ip_options_and_die (0, fromp);
446 if (do_rlogin(fromp) == 0)
449 if (confirmed == 0) {
451 confirmed = 1; /* we sent the null! */
455 des_enc_write(f, SECURE_MESSAGE,
456 strlen(SECURE_MESSAGE),
457 schedule, &kdata->session);
460 write(f, INSECURE_MESSAGE, strlen(INSECURE_MESSAGE));
464 pid = forkpty(&master, line, NULL, NULL);
466 pid = forkpty_truncate(&master, line, sizeof(line), NULL, NULL);
470 fatal(f, "Out of ptys", 0);
472 fatal(f, "Forkpty", 1);
475 if (f > 2) /* f should always be 0, but... */
478 if (lusername[0] == '-'){
479 syslog(LOG_ERR, "tried to pass user \"%s\" to login",
481 fatal(STDERR_FILENO, "invalid user", 0);
484 if (use_kerberos && (pwd->pw_uid == 0))
485 syslog(LOG_INFO|LOG_AUTH,
486 "ROOT Kerberos login from %s on %s\n",
487 krb_unparse_name_long(kdata->pname,
492 execl(new_login, "login", "-p",
493 "-h", hostname, "-f", "--", lusername, 0);
494 } else if (use_kerberos) {
495 fprintf(stderr, "User `%s' is not authorized to login as `%s'!\n",
496 krb_unparse_name_long(kdata->pname,
502 execl(new_login, "login", "-p",
503 "-h", hostname, "--", lusername, 0);
504 fatal(STDERR_FILENO, new_login, 1);
508 * If encrypted, don't turn on NBIO or the des read/write
509 * routines will croak.
513 ioctl(f, FIONBIO, &on);
514 ioctl(master, FIONBIO, &on);
515 ioctl(master, TIOCPKT, &on);
517 signal(SIGTSTP, SIG_IGN);
519 signal(SIGCHLD, cleanup);
522 signal(SIGCHLD, SIG_IGN);
526 const char magic[2] = { 0377, 0377 };
529 * Handle a "control" request (signaled by magic being present)
530 * in the data stream. For now, we are only willing to handle
531 * window size changes.
534 control(int master, char *cp, int n)
540 if (n < 4 + 4 * sizeof (u_int16_t) || cp[2] != 's' || cp[3] != 's')
544 p += krb_get_int(p, &tmp, 2, 0);
546 p += krb_get_int(p, &tmp, 2, 0);
549 p += krb_get_int(p, &tmp, 2, 0);
550 #ifdef HAVE_WS_XPIXEL
553 p += krb_get_int(p, &tmp, 2, 0);
554 #ifdef HAVE_WS_YPIXEL
557 ioctl(master, TIOCSWINSZ, &w);
564 send_oob(int fd, char c)
566 static char last_oob = 0xFF;
568 #if (SunOS >= 50) || defined(__hpux)
570 * PSoriasis and HP-UX always send TIOCPKT_DOSTOP at startup so we
571 * can avoid sending OOB data and thus not break on Linux by merging
572 * TIOCPKT_DOSTOP into the first TIOCPKT_WINDOW.
574 static int oob_kludge = 2;
577 oob_kludge--; /* First time send nothing */
580 else if (oob_kludge == 1)
582 oob_kludge--; /* Second time merge TIOCPKT_WINDOW */
587 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
589 /* Multiple OOB data breaks on Linux, avoid it when possible. */
591 send(fd, &c, 1, MSG_OOB);
596 * rlogin "protocol" machine.
599 protocol(int f, int master)
601 char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
602 int pcc = 0, fcc = 0;
605 unsigned char oob_queue = 0;
609 * Must ignore SIGTTOU, otherwise we'll stop
610 * when we try and set slave pty's window shape
611 * (our controlling tty is the master pty).
613 signal(SIGTTOU, SIG_IGN);
616 send_oob(f, TIOCPKT_WINDOW); /* indicate new rlogin */
622 if (nfd > FD_SETSIZE) {
623 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
624 fatal(f, "internal error (select mask too small)", 0);
627 fd_set ibits, obits, ebits, *omask;
632 omask = (fd_set *)NULL;
634 FD_SET(master, &obits);
643 FD_SET(master, &ibits);
645 FD_SET(master, &ebits);
646 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
649 fatal(f, "select", 1);
652 /* shouldn't happen... */
656 if (FD_ISSET(master, &ebits)) {
657 cc = readstream(master, &cntl, 1);
658 if (cc == 1 && pkcontrol(cntl)) {
659 #if 0 /* Kludge around */
663 if (cntl & TIOCPKT_FLUSHWRITE) {
665 FD_CLR(master, &ibits);
669 if (FD_ISSET(f, &ibits)) {
672 fcc = des_enc_read(f, fibuf,
674 schedule, &kdata->session);
677 fcc = read(f, fibuf, sizeof(fibuf));
678 if (fcc < 0 && errno == EWOULDBLOCK)
689 for (cp = fibuf; cp < fibuf+fcc-1; cp++)
690 if (cp[0] == magic[0] &&
692 left = fcc - (cp-fibuf);
693 n = control(master, cp, left);
697 memmove(cp, cp+n, left);
702 FD_SET(master, &obits); /* try write */
706 if (FD_ISSET(master, &obits) && fcc > 0) {
707 cc = write(master, fbp, fcc);
714 if (FD_ISSET(master, &ibits)) {
715 pcc = readstream(master, pibuf, sizeof (pibuf));
717 if (pcc < 0 && errno == EWOULDBLOCK)
721 else if (pibuf[0] == 0) {
724 FD_SET(f, &obits); /* try write */
726 if (pkcontrol(pibuf[0])) {
727 oob_queue = pibuf[0];
728 #if 0 /* Kludge around */
729 send_oob(f, pibuf[0]);
735 if ((FD_ISSET(f, &obits)) && pcc > 0) {
738 cc = des_enc_write(f, pbp, pcc, schedule, &kdata->session);
741 cc = write(f, pbp, pcc);
742 if (cc < 0 && errno == EWOULDBLOCK) {
744 * This happens when we try write after read
745 * from p, but some old kernels balk at large
746 * writes even when select returns true.
748 if (!FD_ISSET(master, &ibits))
755 /* Only send urg data when normal data
756 * has just been sent.
757 * Linux has deep problems with more
758 * than one byte of OOB data.
761 send_oob (f, oob_queue);
772 char *p = clean_ttyname (line);
774 if (rlogind_logout(p) == 0)
782 signal(SIGHUP, SIG_IGN);
785 #endif /* HAVE_VHANGUP */
790 fatal(int f, const char *msg, int syserr)
793 char buf[BUFSIZ], *bp = buf;
796 * Prepend binary one to message if we haven't sent
797 * the magic null as confirmation.
800 *bp++ = '\01'; /* error indicator */
802 snprintf(bp, sizeof(buf) - (bp - buf),
803 "rlogind: %s: %s.\r\n",
804 msg, strerror(errno));
806 snprintf(bp, sizeof(buf) - (bp - buf),
807 "rlogind: %s.\r\n", msg);
811 des_enc_write(f, buf, bp + len - buf, schedule, &kdata->session);
814 write(f, buf, bp + len - buf);
819 xgetstr(char *buf, int cnt, char *errmsg)
824 if (read(0, &c, 1) != 1)
827 fatal(STDOUT_FILENO, errmsg, 0);
833 do_rlogin(struct sockaddr_in *dest)
835 xgetstr(rusername, sizeof(rusername), "remuser too long");
836 xgetstr(lusername, sizeof(lusername), "locuser too long");
837 xgetstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
839 pwd = k_getpwnam(lusername);
842 if (pwd->pw_uid == 0 && strcmp("root", lusername) != 0)
844 syslog(LOG_ALERT, "NIS attack, user %s has uid 0", lusername);
847 return (iruserok(dest->sin_addr.s_addr,
856 char *cp = strchr(term+ENVSIZE, '/');
866 cp = strchr(speed, '/');
869 s = int2speed_t (atoi (speed));
871 cfsetospeed (&tt, s);
872 cfsetispeed (&tt, s);
876 tt.c_iflag &= ~INPCK;
877 tt.c_iflag |= ICRNL|IXON;
878 tt.c_oflag |= OPOST|ONLCR;
883 tt.c_oflag &= ~ONLRET;
885 tt.c_lflag |= (ECHO|ECHOE|ECHOK|ISIG|ICANON);
886 tt.c_cflag &= ~PARENB;
890 tt.c_cc[VEOF] = CEOF;
891 tcsetattr(fd, TCSAFLUSH, &tt);
898 #define VERSION_SIZE 9
901 * Do the remote kerberos login to the named host with the
904 * Return 0 on valid authorization
905 * Return -1 on valid authentication, no authorization
906 * Return >0 for error conditions
909 do_krb_login(struct sockaddr_in *dest)
912 char instance[INST_SZ], version[VERSION_SIZE];
913 long authopts = 0L; /* !mutual */
914 struct sockaddr_in faddr;
916 kdata = (AUTH_DAT *) auth_buf;
917 ticket = (KTEXT) tick_buf;
919 k_getsockinst(0, instance, sizeof(instance));
923 if (getsockname(0, (struct sockaddr *)&faddr, &rc))
925 authopts = KOPT_DO_MUTUAL;
929 instance, dest, &faddr,
930 kdata, "", schedule, version);
931 des_set_key(&kdata->session, schedule);
937 instance, dest, (struct sockaddr_in *) 0,
938 kdata, "", 0, version);
943 xgetstr(lusername, sizeof(lusername), "locuser");
944 /* get the "cmd" in the rcmd protocol */
945 xgetstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
947 pwd = k_getpwnam(lusername);
950 if (pwd->pw_uid == 0 && strcmp("root", lusername) != 0)
952 syslog(LOG_ALERT, "NIS attack, user %s has uid 0", lusername);
956 /* returns nonzero for no access */
957 if (kuserok(kdata, lusername) != 0)
968 "usage: rlogind [-Dailn] [-p port] [-x] [-L login] [-k | -v]");