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