xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 36454)
1 /*
2  * Copyright (c) 1983 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 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.20 (Berkeley) 12/20/88";
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 (not used currently)
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 
44 #include <netinet/in.h>
45 
46 #include <errno.h>
47 #include <pwd.h>
48 #include <signal.h>
49 #include <sys/ioctl.h>
50 #include <sys/termios.h>
51 #include <stdio.h>
52 #include <netdb.h>
53 #include <syslog.h>
54 #include <strings.h>
55 #include <utmp.h>
56 
57 #ifdef	KERBEROS
58 #include <sys/param.h>
59 #include <kerberos/krb.h>
60 #define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
61 
62 AUTH_DAT	*kdata;
63 KTEXT		ticket;
64 u_char		auth_buf[sizeof(AUTH_DAT)];
65 u_char		tick_buf[sizeof(KTEXT_ST)];
66 Key_schedule	schedule;
67 int		encrypt = 0, retval;
68 int		do_krb_login();
69 
70 #define		OLD_RCMD		0x00
71 #define		KERB_RCMD		0x01
72 #define		KERB_RCMD_MUTUAL	0x02
73 #endif	/* KERBEROS */
74 
75 char	*envinit[2];
76 struct	utmp	utmp;
77 #define	NMAX	sizeof(utmp.ut_name)
78 char		lusername[NMAX+1], rusername[NMAX+1];
79 static char	term[64] = "TERM=";
80 #define	ENVSIZE	(strlen("TERM="))
81 struct	passwd	nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
82 
83 #define	SUPERUSER(pwd)	((pwd)->pw_uid == 0)
84 
85 # ifndef TIOCPKT_WINDOW
86 # define TIOCPKT_WINDOW 0x80
87 # endif TIOCPKT_WINDOW
88 
89 extern	int errno;
90 int	reapchild();
91 struct	passwd *getpwnam(), *pwd;
92 char	*malloc();
93 
94 /*ARGSUSED*/
95 main(argc, argv)
96 	int argc;
97 	char **argv;
98 {
99 	extern int opterr, optind, _check_rhosts_file;
100 	int ch;
101 	int on = 1, fromlen;
102 	struct sockaddr_in from;
103 
104 	openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
105 
106 	opterr = 0;
107 	while ((ch = getopt(argc, argv, "l")) != EOF)
108 		switch((char)ch) {
109 		case 'l':
110 			_check_rhosts_file = 0;
111 			break;
112 		case '?':
113 		default:
114 			syslog(LOG_ERR, "usage: rlogind [-l]");
115 			break;
116 		}
117 	argc -= optind;
118 	argv += optind;
119 
120 	fromlen = sizeof (from);
121 	if (getpeername(0, &from, &fromlen) < 0) {
122 		fprintf(stderr, "%s: ", argv[0]);
123 		perror("getpeername");
124 		exit(1);
125 	}
126 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
127 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
128 	}
129 	doit(0, &from);
130 }
131 
132 int	child;
133 int	cleanup();
134 int	netf;
135 char	*line;
136 extern	char	*inet_ntoa();
137 
138 struct winsize win = { 0, 0, 0, 0 };
139 
140 
141 doit(f, fromp)
142 	int f;
143 	struct sockaddr_in *fromp;
144 {
145 	int i, p, t, pid, on = 1;
146 	int	authenticated = 0;
147 	register struct hostent *hp;
148 	struct hostent hostent;
149 	char c;
150 
151 	alarm(60);
152 	read(f, &c, 1);
153 
154 #ifdef	KERBEROS
155 	/*
156 	 * XXX 1st char tells us which client we're talking to
157 	 */
158 	switch(c) {
159 
160 	case	KERB_RCMD:
161 		break;
162 
163 	case	KERB_RCMD_MUTUAL:
164 		encrypt = 1;
165 		break;
166 
167 
168 	case	OLD_RCMD:
169 	default:
170 		fatal(f, "Remote host requires Kerberos authentication");
171 	}
172 #else
173 	if (c != 0)
174 		exit(1);
175 #endif
176 
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 	}
189 
190 #ifdef	KERBEROS
191 	retval = do_krb_login(hp->h_name, fromp, encrypt);
192 	write(f, &c, 1);
193 	if(retval == 0) {
194 		authenticated++;
195 	} else {
196 		if(retval > 0)
197 			fatal(f, krb_err_txt[retval]);
198 	}
199 #else
200 	if (fromp->sin_family != AF_INET ||
201 	    fromp->sin_port >= IPPORT_RESERVED ||
202 	    fromp->sin_port < IPPORT_RESERVED/2)
203 		fatal(f, "Permission denied");
204 	write(f, "", 1);
205 	if(do_rlogin(hp->h_name) == 0)
206 		authenticated++;
207 #endif
208 
209 	for (c = 'p'; c <= 's'; c++) {
210 		struct stat stb;
211 		line = "/dev/ptyXX";
212 		line[strlen("/dev/pty")] = c;
213 		line[strlen("/dev/ptyp")] = '0';
214 		if (stat(line, &stb) < 0)
215 			break;
216 		for (i = 0; i < 16; i++) {
217 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
218 			p = open(line, O_RDWR);
219 			if (p > 0)
220 				goto gotpty;
221 		}
222 	}
223 	fatal(f, "Out of ptys");
224 	/*NOTREACHED*/
225 gotpty:
226 	(void) ioctl(p, TIOCSWINSZ, &win);
227 	netf = f;
228 	line[strlen("/dev/")] = 't';
229 	t = open(line, O_RDWR);
230 	if (t < 0)
231 		fatalperror(f, line);
232 	if (fchmod(t, 0))
233 		fatalperror(f, line);
234 	(void)signal(SIGHUP, SIG_IGN);
235 	vhangup();
236 	(void)signal(SIGHUP, SIG_DFL);
237 	t = open(line, O_RDWR);
238 	if (t < 0)
239 		fatalperror(f, line);
240 	setup_term(t);
241 #ifdef DEBUG
242 	{
243 		int tt = open("/dev/tty", O_RDWR);
244 		if (tt > 0) {
245 			(void)ioctl(tt, TIOCNOTTY, 0);
246 			(void)close(tt);
247 		}
248 	}
249 #endif
250 	pid = fork();
251 	if (pid < 0)
252 		fatalperror(f, "");
253 	if (pid == 0) {
254 		if(setsid() < 0)
255 			fatalperror(f, "setsid");
256 		if(ioctl(t, TIOCSCTTY, 0) < 0)
257 			fatalperror(f, "ioctl(sctty)");
258 		close(f), close(p);
259 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
260 		close(t);
261 		if(authenticated)
262 			execl("/bin/login", "login",
263 				"-h", hp->h_name,
264 				"-f", pwd->pw_name,
265 				"-p", 0
266 			);
267 		else
268 			execl("/bin/login", "login",
269 				"-h", hp->h_name,
270 				"-p", pwd->pw_name,
271 				0
272 			);
273 		fatalperror(2, "/bin/login");
274 		/*NOTREACHED*/
275 	}
276 	close(t);
277 
278 #ifdef	KERBEROS
279 	/*
280 	 * If encrypted, don't turn on NBIO or the des read/write
281 	 * routines will croak.
282 	 */
283 
284 	if(encrypt)
285 		(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE));
286 	else
287 		ioctl(f, FIONBIO, &on);
288 #else
289 	ioctl(f, FIONBIO, &on);
290 #endif
291 
292 	ioctl(p, FIONBIO, &on);
293 	ioctl(p, TIOCPKT, &on);
294 	signal(SIGTSTP, SIG_IGN);
295 	signal(SIGCHLD, cleanup);
296 	setpgrp(0, 0);
297 	protocol(f, p);
298 	signal(SIGCHLD, SIG_IGN);
299 	cleanup();
300 }
301 
302 char	magic[2] = { 0377, 0377 };
303 char	oobdata[] = {TIOCPKT_WINDOW};
304 
305 /*
306  * Handle a "control" request (signaled by magic being present)
307  * in the data stream.  For now, we are only willing to handle
308  * window size changes.
309  */
310 control(pty, cp, n)
311 	int pty;
312 	char *cp;
313 	int n;
314 {
315 	struct winsize w;
316 
317 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
318 		return (0);
319 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
320 	bcopy(cp+4, (char *)&w, sizeof(w));
321 	w.ws_row = ntohs(w.ws_row);
322 	w.ws_col = ntohs(w.ws_col);
323 	w.ws_xpixel = ntohs(w.ws_xpixel);
324 	w.ws_ypixel = ntohs(w.ws_ypixel);
325 	(void)ioctl(pty, TIOCSWINSZ, &w);
326 	return (4+sizeof (w));
327 }
328 
329 /*
330  * rlogin "protocol" machine.
331  */
332 protocol(f, p)
333 	int f, p;
334 {
335 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
336 	register pcc = 0, fcc = 0;
337 	int cc;
338 	char cntl;
339 
340 	/*
341 	 * Must ignore SIGTTOU, otherwise we'll stop
342 	 * when we try and set slave pty's window shape
343 	 * (our controlling tty is the master pty).
344 	 */
345 	(void) signal(SIGTTOU, SIG_IGN);
346 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
347 	for (;;) {
348 		int ibits, obits, ebits;
349 
350 		ibits = 0;
351 		obits = 0;
352 		if (fcc)
353 			obits |= (1<<p);
354 		else
355 			ibits |= (1<<f);
356 		if (pcc >= 0)
357 			if (pcc)
358 				obits |= (1<<f);
359 			else
360 				ibits |= (1<<p);
361 		ebits = (1<<p);
362 		if (select(16, &ibits, &obits, &ebits, 0) < 0) {
363 			if (errno == EINTR)
364 				continue;
365 			fatalperror(f, "select");
366 		}
367 		if (ibits == 0 && obits == 0 && ebits == 0) {
368 			/* shouldn't happen... */
369 			sleep(5);
370 			continue;
371 		}
372 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
373 		if (ebits & (1<<p)) {
374 			cc = read(p, &cntl, 1);
375 			if (cc == 1 && pkcontrol(cntl)) {
376 				cntl |= oobdata[0];
377 				send(f, &cntl, 1, MSG_OOB);
378 				if (cntl & TIOCPKT_FLUSHWRITE) {
379 					pcc = 0;
380 					ibits &= ~(1<<p);
381 				}
382 			}
383 		}
384 		if (ibits & (1<<f)) {
385 #ifdef	KERBEROS
386 			if(encrypt) {
387 				fcc = des_read(f, fibuf, sizeof(fibuf));
388 			} else {
389 				fcc = read(f, fibuf, sizeof(fibuf));
390 			}
391 #else
392 			fcc = read(f, fibuf, sizeof (fibuf));
393 #endif
394 			if (fcc < 0 && errno == EWOULDBLOCK)
395 				fcc = 0;
396 			else {
397 				register char *cp;
398 				int left, n;
399 
400 				if (fcc <= 0)
401 					break;
402 				fbp = fibuf;
403 
404 			top:
405 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
406 					if (cp[0] == magic[0] &&
407 					    cp[1] == magic[1]) {
408 						left = fcc - (cp-fibuf);
409 						n = control(p, cp, left);
410 						if (n) {
411 							left -= n;
412 							if (left > 0)
413 								bcopy(cp+n, cp, left);
414 							fcc -= n;
415 							goto top; /* n^2 */
416 						}
417 					}
418 			}
419 		}
420 
421 		if ((obits & (1<<p)) && fcc > 0) {
422 			cc = write(p, fbp, fcc);
423 			if (cc > 0) {
424 				fcc -= cc;
425 				fbp += cc;
426 			}
427 		}
428 
429 		if (ibits & (1<<p)) {
430 			pcc = read(p, pibuf, sizeof (pibuf));
431 			pbp = pibuf;
432 			if (pcc < 0 && errno == EWOULDBLOCK)
433 				pcc = 0;
434 			else if (pcc <= 0)
435 				break;
436 			else if (pibuf[0] == 0)
437 				pbp++, pcc--;
438 			else {
439 				if (pkcontrol(pibuf[0])) {
440 					pibuf[0] |= oobdata[0];
441 					send(f, &pibuf[0], 1, MSG_OOB);
442 				}
443 				pcc = 0;
444 			}
445 		}
446 		if ((obits & (1<<f)) && pcc > 0) {
447 #ifdef	KERBEROS
448 			if(encrypt) {
449 				cc = des_write(f, pbp, pcc);
450 			} else {
451 				cc = write(f, pbp, pcc);
452 			}
453 #else
454 			cc = write(f, pbp, pcc);
455 #endif
456 			if (cc < 0 && errno == EWOULDBLOCK) {
457 				/* also shouldn't happen */
458 				sleep(5);
459 				continue;
460 			}
461 			if (cc > 0) {
462 				pcc -= cc;
463 				pbp += cc;
464 			}
465 		}
466 	}
467 }
468 
469 cleanup()
470 {
471 	char *p;
472 
473 	p = line + sizeof("/dev/") - 1;
474 	if (logout(p))
475 		logwtmp(p, "", "");
476 	(void)chmod(line, 0666);
477 	(void)chown(line, 0, 0);
478 	*p = 'p';
479 	(void)chmod(line, 0666);
480 	(void)chown(line, 0, 0);
481 	shutdown(netf, 2);
482 	exit(1);
483 }
484 
485 fatal(f, msg)
486 	int f;
487 	char *msg;
488 {
489 	char buf[BUFSIZ];
490 
491 	buf[0] = '\01';		/* error indicator */
492 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
493 	(void) write(f, buf, strlen(buf));
494 	exit(1);
495 }
496 
497 fatalperror(f, msg)
498 	int f;
499 	char *msg;
500 {
501 	char buf[BUFSIZ];
502 	extern int sys_nerr;
503 	extern char *sys_errlist[];
504 
505 	if ((unsigned)errno < sys_nerr)
506 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
507 	else
508 		(void) sprintf(buf, "%s: Error %d", msg, errno);
509 	fatal(f, buf);
510 }
511 
512 
513 int
514 do_rlogin(host)
515 	char	*host;
516 {
517 	getstr(rusername, sizeof(rusername), "remuser");
518 	getstr(lusername, sizeof(lusername), "locuser");
519 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
520 
521 	if(getuid()) {
522 		pwd = &nouser;
523 		return(-1);
524 	}
525 	pwd = getpwnam(lusername);
526 	if(pwd == NULL) {
527 		pwd = &nouser;
528 		pwd->pw_name = lusername;	/* pass on to login */
529 		return(-1);
530 	}
531 	return(ruserok(host, SUPERUSER(pwd), rusername, lusername));
532 }
533 
534 
535 getstr(buf, cnt, err)
536 	char	*buf;
537 	int	cnt;
538 	char	*err;
539 {
540 	char	c;
541 	do {
542 		if(read(0, &c, 1) != 1)
543 			exit(1);
544 		if(--cnt < 0) {
545 			printf("%s too long\r\n", err);
546 			exit(1);
547 		}
548 		*buf++ = c;
549 	} while(c != 0);
550 }
551 
552 extern	char	**environ;
553 
554 setup_term(fd)
555 	int	fd;
556 {
557 	struct	termios	tt;
558 	struct	sgttyb	tp;
559 	register char	*cp = index(term+ENVSIZE, '/'), **cpp;
560 	char		*speed;
561 
562 	tcgetattr(fd, &tt);
563 	if(cp) {
564 		*cp++ = '\0';
565 		speed = cp;
566 		cp = index(speed, '/');
567 		if(cp)
568 			*cp++ = '\0';
569 		cfsetspeed(&tt, atoi(speed));
570 	}
571 	tt.c_iflag = BRKINT|ICRNL|IXON|ISTRIP|IEXTEN|IMAXBEL;
572 	tt.c_oflag = OPOST|ONLCR|OXTABS;
573 	tt.c_lflag = ISIG|ICANON|ECHO;
574 	tcsetattr(fd, TCSADFLUSH, &tt);
575 
576 	envinit[0] = term;
577 	envinit[1] = 0;
578 	environ = envinit;
579 }
580 
581 #ifdef	KERBEROS
582 #define	VERSION_SIZE	9
583 
584 /*
585  * Do the remote kerberos login to the named host with the
586  * given inet address
587  *
588  * Return 0 on valid authorization
589  * Return -1 on valid authentication, no authorization
590  * Return >0 for error conditions
591  */
592 
593 int
594 do_krb_login(host, dest, encrypt)
595 	char			*host;
596 	struct	sockaddr_in	*dest;
597 	int			encrypt;
598 {
599 	int	rc;
600 	char	instance[INST_SZ], version[VERSION_SIZE];
601 	long	authopts = 0L;	/* !mutual */
602 	struct	sockaddr_in	faddr;
603 
604 	if(getuid()) {
605 		pwd = &nouser;
606 		return(KFAILURE);
607 	}
608 
609 	kdata = (AUTH_DAT *) auth_buf;
610 	ticket = (KTEXT) tick_buf;
611 	strcpy(instance, "*");
612 
613 	if(encrypt) {
614 		rc = sizeof(faddr);
615 		if(getsockname(0, &faddr, &rc)) {
616 			pwd = &nouser;
617 			return(-1);
618 		}
619 		authopts = KOPT_DO_MUTUAL;
620 		rc = krb_recvauth(
621 			authopts, 0,
622 			ticket, "rcmd",
623 			instance, dest, &faddr,
624 			kdata, "", schedule, version
625 		 );
626 		 des_set_key(kdata->session, schedule);
627 
628 	} else {
629 		rc = krb_recvauth(
630 			authopts, 0,
631 			ticket, "rcmd",
632 			instance, dest, (struct sockaddr_in *) 0,
633 			kdata, "", (bit_64 *) 0, version
634 		 );
635 	}
636 
637 	if(rc != KSUCCESS) {
638 		pwd = &nouser;
639 		return(rc);
640 	}
641 
642 	if((rc = krb_kntoln(kdata, rusername)) != KSUCCESS) {
643 		pwd = &nouser;
644 		return(rc);
645 	}
646 
647 	getstr(lusername, sizeof(lusername), "locuser");
648 	/* get the "cmd" in the rcmd protocol */
649 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
650 
651 	pwd = getpwnam(lusername);
652 	if(pwd == NULL) {
653 		pwd = &nouser;
654 		pwd->pw_name = lusername;
655 		return(-1);
656 	}
657 
658 	/* XXX need to use something other than ruserok */
659 	/* returns -1 for invalid authentication */
660 	return(ruserok(host, SUPERUSER(pwd), rusername, lusername));
661 }
662 #endif
663