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