xref: /original-bsd/libexec/rlogind/rlogind.c (revision 0842ddeb)
1 /*-
2  * Copyright (c) 1983, 1988, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1983, 1988, 1989, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)rlogind.c	8.2 (Berkeley) 04/28/95";
16 #endif /* not lint */
17 
18 /*
19  * remote login server:
20  *	\0
21  *	remuser\0
22  *	locuser\0
23  *	terminal_type/speed\0
24  *	data
25  */
26 
27 #define	FD_SETSIZE	16		/* don't need many bits for select */
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <signal.h>
32 #include <termios.h>
33 
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 
41 #include <pwd.h>
42 #include <syslog.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include "pathnames.h"
49 
50 #ifndef TIOCPKT_WINDOW
51 #define TIOCPKT_WINDOW 0x80
52 #endif
53 
54 #ifdef	KERBEROS
55 #include <kerberosIV/des.h>
56 #include <kerberosIV/krb.h>
57 #define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
58 
59 AUTH_DAT	*kdata;
60 KTEXT		ticket;
61 u_char		auth_buf[sizeof(AUTH_DAT)];
62 u_char		tick_buf[sizeof(KTEXT_ST)];
63 Key_schedule	schedule;
64 int		doencrypt, retval, use_kerberos, vacuous;
65 
66 #define		ARGSTR			"alnkvx"
67 #else
68 #define		ARGSTR			"aln"
69 #endif	/* KERBEROS */
70 
71 char	*env[2];
72 #define	NMAX 30
73 char	lusername[NMAX+1], rusername[NMAX+1];
74 static	char term[64] = "TERM=";
75 #define	ENVSIZE	(sizeof("TERM=")-1)	/* skip null for concatenation */
76 int	keepalive = 1;
77 int	check_all = 0;
78 
79 struct	passwd *pwd;
80 
81 void	doit __P((int, struct sockaddr_in *));
82 int	control __P((int, char *, int));
83 void	protocol __P((int, int));
84 void	cleanup __P((int));
85 void	fatal __P((int, char *, int));
86 int	do_rlogin __P((struct sockaddr_in *));
87 void	getstr __P((char *, int, char *));
88 void	setup_term __P((int));
89 int	do_krb_login __P((struct sockaddr_in *));
90 void	usage __P((void));
91 int	local_domain __P((char *));
92 char	*topdomain __P((char *));
93 
94 int
95 main(argc, argv)
96 	int argc;
97 	char *argv[];
98 {
99 	extern int __check_rhosts_file;
100 	struct sockaddr_in from;
101 	int ch, fromlen, on;
102 
103 	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
104 
105 	opterr = 0;
106 	while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
107 		switch (ch) {
108 		case 'a':
109 			check_all = 1;
110 			break;
111 		case 'l':
112 			__check_rhosts_file = 0;
113 			break;
114 		case 'n':
115 			keepalive = 0;
116 			break;
117 #ifdef KERBEROS
118 		case 'k':
119 			use_kerberos = 1;
120 			break;
121 		case 'v':
122 			vacuous = 1;
123 			break;
124 #ifdef CRYPT
125 		case 'x':
126 			doencrypt = 1;
127 			break;
128 #endif
129 #endif
130 		case '?':
131 		default:
132 			usage();
133 			break;
134 		}
135 	argc -= optind;
136 	argv += optind;
137 
138 #ifdef	KERBEROS
139 	if (use_kerberos && vacuous) {
140 		usage();
141 		fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
142 	}
143 #endif
144 	fromlen = sizeof (from);
145 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
146 		syslog(LOG_ERR,"Can't get peer name of remote host: %m");
147 		fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
148 	}
149 	on = 1;
150 	if (keepalive &&
151 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
152 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
153 	on = IPTOS_LOWDELAY;
154 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
155 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
156 	doit(0, &from);
157 }
158 
159 int	child;
160 int	netf;
161 char	line[MAXPATHLEN];
162 int	confirmed;
163 
164 struct winsize win = { 0, 0, 0, 0 };
165 
166 
167 void
168 doit(f, fromp)
169 	int f;
170 	struct sockaddr_in *fromp;
171 {
172 	int master, pid, on = 1;
173 	int authenticated = 0;
174 	register struct hostent *hp;
175 	char hostname[2 * MAXHOSTNAMELEN + 1];
176 	char c;
177 
178 	alarm(60);
179 	read(f, &c, 1);
180 
181 	if (c != 0)
182 		exit(1);
183 #ifdef	KERBEROS
184 	if (vacuous)
185 		fatal(f, "Remote host requires Kerberos authentication", 0);
186 #endif
187 
188 	alarm(0);
189 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
190 	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
191 	    fromp->sin_family);
192 	if (hp)
193 		(void)strcpy(hostname, hp->h_name);
194 	else
195 		(void)strcpy(hostname, inet_ntoa(fromp->sin_addr));
196 
197 #ifdef	KERBEROS
198 	if (use_kerberos) {
199 		retval = do_krb_login(fromp);
200 		if (retval == 0)
201 			authenticated++;
202 		else if (retval > 0)
203 			fatal(f, krb_err_txt[retval], 0);
204 		write(f, &c, 1);
205 		confirmed = 1;		/* we sent the null! */
206 	} else
207 #endif
208 	{
209 		if (fromp->sin_family != AF_INET ||
210 		    fromp->sin_port >= IPPORT_RESERVED ||
211 		    fromp->sin_port < IPPORT_RESERVED/2) {
212 			syslog(LOG_NOTICE, "Connection from %s on illegal port",
213 				inet_ntoa(fromp->sin_addr));
214 			fatal(f, "Permission denied", 0);
215 		}
216 #ifdef IP_OPTIONS
217 		{
218 		u_char optbuf[BUFSIZ/3], *cp;
219 		char lbuf[BUFSIZ], *lp;
220 		int optsize = sizeof(optbuf), ipproto;
221 		struct protoent *ip;
222 
223 		if ((ip = getprotobyname("ip")) != NULL)
224 			ipproto = ip->p_proto;
225 		else
226 			ipproto = IPPROTO_IP;
227 		if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
228 		    &optsize) == 0 && optsize != 0) {
229 			lp = lbuf;
230 			for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
231 				sprintf(lp, " %2.2x", *cp);
232 			syslog(LOG_NOTICE,
233 			    "Connection received using IP options (ignored):%s",
234 			    lbuf);
235 			if (setsockopt(0, ipproto, IP_OPTIONS,
236 			    (char *)NULL, optsize) != 0) {
237 				syslog(LOG_ERR,
238 				    "setsockopt IP_OPTIONS NULL: %m");
239 				exit(1);
240 			}
241 		}
242 		}
243 #endif
244 		if (do_rlogin(fromp) == 0)
245 			authenticated++;
246 	}
247 	if (confirmed == 0) {
248 		write(f, "", 1);
249 		confirmed = 1;		/* we sent the null! */
250 	}
251 #ifdef	KERBEROS
252 #ifdef	CRYPT
253 	if (doencrypt)
254 		(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE) - 1);
255 #endif
256 #endif
257 	netf = f;
258 
259 	pid = forkpty(&master, line, NULL, &win);
260 	if (pid < 0) {
261 		if (errno == ENOENT)
262 			fatal(f, "Out of ptys", 0);
263 		else
264 			fatal(f, "Forkpty", 1);
265 	}
266 	if (pid == 0) {
267 		if (f > 2)	/* f should always be 0, but... */
268 			(void) close(f);
269 		setup_term(0);
270 		if (authenticated) {
271 #ifdef	KERBEROS
272 			if (use_kerberos && (pwd->pw_uid == 0))
273 				syslog(LOG_INFO|LOG_AUTH,
274 				    "ROOT Kerberos login from %s.%s@%s on %s\n",
275 				    kdata->pname, kdata->pinst, kdata->prealm,
276 				    hostname);
277 #endif
278 
279 			execle(_PATH_LOGIN, "login", "-p",
280 			    "-h", hostname, "-f", "--", lusername, NULL, env);
281 		} else
282 			execle(_PATH_LOGIN, "login", "-p",
283 			    "-h", hostname, "--", lusername, NULL, env);
284 		fatal(STDERR_FILENO, _PATH_LOGIN, 1);
285 		/*NOTREACHED*/
286 	}
287 #ifdef	CRYPT
288 #ifdef	KERBEROS
289 	/*
290 	 * If encrypted, don't turn on NBIO or the des read/write
291 	 * routines will croak.
292 	 */
293 
294 	if (!doencrypt)
295 #endif
296 #endif
297 		ioctl(f, FIONBIO, &on);
298 	ioctl(master, FIONBIO, &on);
299 	ioctl(master, TIOCPKT, &on);
300 	signal(SIGCHLD, cleanup);
301 	protocol(f, master);
302 	signal(SIGCHLD, SIG_IGN);
303 	cleanup(0);
304 }
305 
306 char	magic[2] = { 0377, 0377 };
307 char	oobdata[] = {TIOCPKT_WINDOW};
308 
309 /*
310  * Handle a "control" request (signaled by magic being present)
311  * in the data stream.  For now, we are only willing to handle
312  * window size changes.
313  */
314 int
315 control(pty, cp, n)
316 	int pty;
317 	char *cp;
318 	int n;
319 {
320 	struct winsize w;
321 
322 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
323 		return (0);
324 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
325 	memmove(&w, cp+4, sizeof(w));
326 	w.ws_row = ntohs(w.ws_row);
327 	w.ws_col = ntohs(w.ws_col);
328 	w.ws_xpixel = ntohs(w.ws_xpixel);
329 	w.ws_ypixel = ntohs(w.ws_ypixel);
330 	(void)ioctl(pty, TIOCSWINSZ, &w);
331 	return (4+sizeof (w));
332 }
333 
334 /*
335  * rlogin "protocol" machine.
336  */
337 void
338 protocol(f, p)
339 	register int f, p;
340 {
341 	char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
342 	register pcc = 0, fcc = 0;
343 	int cc, nfd, n;
344 	char cntl;
345 
346 	/*
347 	 * Must ignore SIGTTOU, otherwise we'll stop
348 	 * when we try and set slave pty's window shape
349 	 * (our controlling tty is the master pty).
350 	 */
351 	(void) signal(SIGTTOU, SIG_IGN);
352 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
353 	if (f > p)
354 		nfd = f + 1;
355 	else
356 		nfd = p + 1;
357 	if (nfd > FD_SETSIZE) {
358 		syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
359 		fatal(f, "internal error (select mask too small)", 0);
360 	}
361 	for (;;) {
362 		fd_set ibits, obits, ebits, *omask;
363 
364 		FD_ZERO(&ebits);
365 		FD_ZERO(&ibits);
366 		FD_ZERO(&obits);
367 		omask = (fd_set *)NULL;
368 		if (fcc) {
369 			FD_SET(p, &obits);
370 			omask = &obits;
371 		} else
372 			FD_SET(f, &ibits);
373 		if (pcc >= 0)
374 			if (pcc) {
375 				FD_SET(f, &obits);
376 				omask = &obits;
377 			} else
378 				FD_SET(p, &ibits);
379 		FD_SET(p, &ebits);
380 		if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
381 			if (errno == EINTR)
382 				continue;
383 			fatal(f, "select", 1);
384 		}
385 		if (n == 0) {
386 			/* shouldn't happen... */
387 			sleep(5);
388 			continue;
389 		}
390 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
391 		if (FD_ISSET(p, &ebits)) {
392 			cc = read(p, &cntl, 1);
393 			if (cc == 1 && pkcontrol(cntl)) {
394 				cntl |= oobdata[0];
395 				send(f, &cntl, 1, MSG_OOB);
396 				if (cntl & TIOCPKT_FLUSHWRITE) {
397 					pcc = 0;
398 					FD_CLR(p, &ibits);
399 				}
400 			}
401 		}
402 		if (FD_ISSET(f, &ibits)) {
403 #ifdef	CRYPT
404 #ifdef	KERBEROS
405 			if (doencrypt)
406 				fcc = des_read(f, fibuf, sizeof(fibuf));
407 			else
408 #endif
409 #endif
410 				fcc = read(f, fibuf, sizeof(fibuf));
411 			if (fcc < 0 && errno == EWOULDBLOCK)
412 				fcc = 0;
413 			else {
414 				register char *cp;
415 				int left, n;
416 
417 				if (fcc <= 0)
418 					break;
419 				fbp = fibuf;
420 
421 			top:
422 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
423 					if (cp[0] == magic[0] &&
424 					    cp[1] == magic[1]) {
425 						left = fcc - (cp-fibuf);
426 						n = control(p, cp, left);
427 						if (n) {
428 							left -= n;
429 							if (left > 0)
430 								bcopy(cp+n, cp, left);
431 							fcc -= n;
432 							goto top; /* n^2 */
433 						}
434 					}
435 				FD_SET(p, &obits);		/* try write */
436 			}
437 		}
438 
439 		if (FD_ISSET(p, &obits) && fcc > 0) {
440 			cc = write(p, fbp, fcc);
441 			if (cc > 0) {
442 				fcc -= cc;
443 				fbp += cc;
444 			}
445 		}
446 
447 		if (FD_ISSET(p, &ibits)) {
448 			pcc = read(p, pibuf, sizeof (pibuf));
449 			pbp = pibuf;
450 			if (pcc < 0 && errno == EWOULDBLOCK)
451 				pcc = 0;
452 			else if (pcc <= 0)
453 				break;
454 			else if (pibuf[0] == 0) {
455 				pbp++, pcc--;
456 #ifdef	CRYPT
457 #ifdef	KERBEROS
458 				if (!doencrypt)
459 #endif
460 #endif
461 					FD_SET(f, &obits);	/* try write */
462 			} else {
463 				if (pkcontrol(pibuf[0])) {
464 					pibuf[0] |= oobdata[0];
465 					send(f, &pibuf[0], 1, MSG_OOB);
466 				}
467 				pcc = 0;
468 			}
469 		}
470 		if ((FD_ISSET(f, &obits)) && pcc > 0) {
471 #ifdef	CRYPT
472 #ifdef	KERBEROS
473 			if (doencrypt)
474 				cc = des_write(f, pbp, pcc);
475 			else
476 #endif
477 #endif
478 				cc = write(f, pbp, pcc);
479 			if (cc < 0 && errno == EWOULDBLOCK) {
480 				/*
481 				 * This happens when we try write after read
482 				 * from p, but some old kernels balk at large
483 				 * writes even when select returns true.
484 				 */
485 				if (!FD_ISSET(p, &ibits))
486 					sleep(5);
487 				continue;
488 			}
489 			if (cc > 0) {
490 				pcc -= cc;
491 				pbp += cc;
492 			}
493 		}
494 	}
495 }
496 
497 void
498 cleanup(signo)
499 	int signo;
500 {
501 	char *p;
502 
503 	p = line + sizeof(_PATH_DEV) - 1;
504 	if (logout(p))
505 		logwtmp(p, "", "");
506 	(void)chmod(line, 0666);
507 	(void)chown(line, 0, 0);
508 	*p = 'p';
509 	(void)chmod(line, 0666);
510 	(void)chown(line, 0, 0);
511 	shutdown(netf, 2);
512 	exit(1);
513 }
514 
515 void
516 fatal(f, msg, syserr)
517 	int f;
518 	char *msg;
519 	int syserr;
520 {
521 	int len;
522 	char buf[BUFSIZ], *bp = buf;
523 
524 	/*
525 	 * Prepend binary one to message if we haven't sent
526 	 * the magic null as confirmation.
527 	 */
528 	if (!confirmed)
529 		*bp++ = '\01';		/* error indicator */
530 	if (syserr)
531 		len = sprintf(bp, "rlogind: %s: %s.\r\n",
532 		    msg, strerror(errno));
533 	else
534 		len = sprintf(bp, "rlogind: %s.\r\n", msg);
535 	(void) write(f, buf, bp + len - buf);
536 	exit(1);
537 }
538 
539 int
540 do_rlogin(dest)
541 	struct sockaddr_in *dest;
542 {
543 	getstr(rusername, sizeof(rusername), "remuser too long");
544 	getstr(lusername, sizeof(lusername), "locuser too long");
545 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
546 
547 	pwd = getpwnam(lusername);
548 	if (pwd == NULL)
549 		return (-1);
550 	if (pwd->pw_uid == 0)
551 		return (-1);
552 	/* XXX why don't we syslog() failure? */
553 	return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername));
554 }
555 
556 void
557 getstr(buf, cnt, errmsg)
558 	char *buf;
559 	int cnt;
560 	char *errmsg;
561 {
562 	char c;
563 
564 	do {
565 		if (read(0, &c, 1) != 1)
566 			exit(1);
567 		if (--cnt < 0)
568 			fatal(STDOUT_FILENO, errmsg, 0);
569 		*buf++ = c;
570 	} while (c != 0);
571 }
572 
573 void
574 setup_term(fd)
575 	int fd;
576 {
577 	register char *cp = index(term+ENVSIZE, '/');
578 	char *speed;
579 	struct termios tt;
580 
581 #ifndef notyet
582 	tcgetattr(fd, &tt);
583 	if (cp) {
584 		*cp++ = '\0';
585 		speed = cp;
586 		cp = index(speed, '/');
587 		if (cp)
588 			*cp++ = '\0';
589 		cfsetspeed(&tt, atoi(speed));
590 	}
591 
592 	tt.c_iflag = TTYDEF_IFLAG;
593 	tt.c_oflag = TTYDEF_OFLAG;
594 	tt.c_lflag = TTYDEF_LFLAG;
595 	tcsetattr(fd, TCSAFLUSH, &tt);
596 #else
597 	if (cp) {
598 		*cp++ = '\0';
599 		speed = cp;
600 		cp = index(speed, '/');
601 		if (cp)
602 			*cp++ = '\0';
603 		tcgetattr(fd, &tt);
604 		cfsetspeed(&tt, atoi(speed));
605 		tcsetattr(fd, TCSAFLUSH, &tt);
606 	}
607 #endif
608 
609 	env[0] = term;
610 	env[1] = 0;
611 }
612 
613 #ifdef	KERBEROS
614 #define	VERSION_SIZE	9
615 
616 /*
617  * Do the remote kerberos login to the named host with the
618  * given inet address
619  *
620  * Return 0 on valid authorization
621  * Return -1 on valid authentication, no authorization
622  * Return >0 for error conditions
623  */
624 int
625 do_krb_login(dest)
626 	struct sockaddr_in *dest;
627 {
628 	int rc;
629 	char instance[INST_SZ], version[VERSION_SIZE];
630 	long authopts = 0L;	/* !mutual */
631 	struct sockaddr_in faddr;
632 
633 	kdata = (AUTH_DAT *) auth_buf;
634 	ticket = (KTEXT) tick_buf;
635 
636 	instance[0] = '*';
637 	instance[1] = '\0';
638 
639 #ifdef	CRYPT
640 	if (doencrypt) {
641 		rc = sizeof(faddr);
642 		if (getsockname(0, (struct sockaddr *)&faddr, &rc))
643 			return (-1);
644 		authopts = KOPT_DO_MUTUAL;
645 		rc = krb_recvauth(
646 			authopts, 0,
647 			ticket, "rcmd",
648 			instance, dest, &faddr,
649 			kdata, "", schedule, version);
650 		 des_set_key(kdata->session, schedule);
651 
652 	} else
653 #endif
654 		rc = krb_recvauth(
655 			authopts, 0,
656 			ticket, "rcmd",
657 			instance, dest, (struct sockaddr_in *) 0,
658 			kdata, "", (bit_64 *) 0, version);
659 
660 	if (rc != KSUCCESS)
661 		return (rc);
662 
663 	getstr(lusername, sizeof(lusername), "locuser");
664 	/* get the "cmd" in the rcmd protocol */
665 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
666 
667 	pwd = getpwnam(lusername);
668 	if (pwd == NULL)
669 		return (-1);
670 
671 	/* returns nonzero for no access */
672 	if (kuserok(kdata, lusername) != 0)
673 		return (-1);
674 
675 	return (0);
676 
677 }
678 #endif /* KERBEROS */
679 
680 void
681 usage()
682 {
683 #ifdef KERBEROS
684 	syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
685 #else
686 	syslog(LOG_ERR, "usage: rlogind [-aln]");
687 #endif
688 }
689 
690 /*
691  * Check whether host h is in our local domain,
692  * defined as sharing the last two components of the domain part,
693  * or the entire domain part if the local domain has only one component.
694  * If either name is unqualified (contains no '.'),
695  * assume that the host is local, as it will be
696  * interpreted as such.
697  */
698 int
699 local_domain(h)
700 	char *h;
701 {
702 	char localhost[MAXHOSTNAMELEN];
703 	char *p1, *p2;
704 
705 	localhost[0] = 0;
706 	(void) gethostname(localhost, sizeof(localhost));
707 	p1 = topdomain(localhost);
708 	p2 = topdomain(h);
709 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
710 		return (1);
711 	return (0);
712 }
713 
714 char *
715 topdomain(h)
716 	char *h;
717 {
718 	register char *p;
719 	char *maybe = NULL;
720 	int dots = 0;
721 
722 	for (p = h + strlen(h); p >= h; p--) {
723 		if (*p == '.') {
724 			if (++dots == 2)
725 				return (p);
726 			maybe = p;
727 		}
728 	}
729 	return (maybe);
730 }
731