144262Sbostic /*-
2*61877Sbostic  * Copyright (c) 1990, 1993
3*61877Sbostic  *	The Regents of the University of California.  All rights reserved.
444262Sbostic  *
544262Sbostic  * %sccs.include.redist.c%
644262Sbostic  */
744262Sbostic 
838272Ssam #ifndef lint
9*61877Sbostic static char copyright[] =
10*61877Sbostic "@(#) Copyright (c) 1990, 1993\n\
11*61877Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1244262Sbostic #endif /* not lint */
1344262Sbostic 
1444262Sbostic #ifndef lint
15*61877Sbostic static char sccsid[] = "@(#)sliplogin.c	8.1 (Berkeley) 06/06/93";
1644262Sbostic #endif /* not lint */
1744262Sbostic 
1838272Ssam /*
1938272Ssam  * sliplogin.c
2038373Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
2138272Ssam  *
2238272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
2344851Strent  * It sets the line discipline to slip, invokes a shell script to initialize
2444851Strent  * the network interface, then pauses forever waiting for hangup.
2538272Ssam  *
2638272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
2738272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
2838272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
2938272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
3038272Ssam  *
3144851Strent  * There are two forms of usage:
3238272Ssam  *
3338272Ssam  * "sliplogin"
3446400Skarels  * Invoked simply as "sliplogin", the program looks up the username
3546400Skarels  * in the file /etc/slip.hosts.
3646400Skarels  * If an entry is found, the line on fd0 is configured for SLIP operation
3738272Ssam  * as specified in the file.
3838272Ssam  *
3946400Skarels  * "sliplogin IPhostlogin </dev/ttyb"
4038272Ssam  * Invoked by root with a username, the name is looked up in the
4146400Skarels  * /etc/slip.hosts file and if found fd0 is configured as in case 1.
4238272Ssam  */
4338272Ssam 
4444851Strent #include <sys/param.h>
4538272Ssam #include <sys/socket.h>
4644860Sbostic #include <sys/signal.h>
4738272Ssam #include <sys/file.h>
4838272Ssam #include <sys/syslog.h>
4938272Ssam #include <netdb.h>
5044860Sbostic 
5146400Skarels #if BSD >= 199006
5246400Skarels #define POSIX
5344851Strent #endif
5446400Skarels #ifdef POSIX
5544851Strent #include <sys/termios.h>
5646400Skarels #include <sys/ioctl.h>
5738272Ssam #include <ttyent.h>
5846400Skarels #else
5946400Skarels #include <sgtty.h>
6044851Strent #endif
6144851Strent #include <netinet/in.h>
6244851Strent #include <net/if.h>
6344851Strent #include <net/if_slvar.h>
6438272Ssam 
6544860Sbostic #include <stdio.h>
6644860Sbostic #include <errno.h>
6744860Sbostic #include <ctype.h>
6844860Sbostic #include <string.h>
6944860Sbostic #include "pathnames.h"
7038372Ssam 
7144851Strent int	unit;
7244851Strent int	speed;
7346400Skarels int	uid;
7444851Strent char	loginargs[BUFSIZ];
7546400Skarels char	loginfile[MAXPATHLEN];
7644851Strent char	loginname[BUFSIZ];
7738272Ssam 
7838272Ssam void
7944851Strent findid(name)
8044851Strent 	char *name;
8138272Ssam {
8244851Strent 	FILE *fp;
8344851Strent 	static char slopt[5][16];
8444851Strent 	static char laddr[16];
8544851Strent 	static char raddr[16];
8644851Strent 	static char mask[16];
8744851Strent 	char user[16];
8844851Strent 	int i, j, n;
8938272Ssam 
9044851Strent 	(void)strcpy(loginname, name);
9144860Sbostic 	if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
9244860Sbostic 		(void)fprintf(stderr, "sliplogin: %s: %s\n",
9344860Sbostic 		    _PATH_ACCESS, strerror(errno));
9444860Sbostic 		syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
9544860Sbostic 		exit(1);
9644851Strent 	}
9744851Strent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
9844851Strent 		if (ferror(fp))
9944851Strent 			break;
10044851Strent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
10144851Strent                         user, laddr, raddr, mask, slopt[0], slopt[1],
10244851Strent 			slopt[2], slopt[3], slopt[4]);
10344851Strent 		if (user[0] == '#' || isspace(user[0]))
10444851Strent 			continue;
10544851Strent 		if (strcmp(user, name) != 0)
10644851Strent 			continue;
10738272Ssam 
10844851Strent 		/*
10944851Strent 		 * we've found the guy we're looking for -- see if
11044851Strent 		 * there's a login file we can use.  First check for
11144851Strent 		 * one specific to this host.  If none found, try for
11244851Strent 		 * a generic one.
11344851Strent 		 */
11444860Sbostic 		(void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
11546400Skarels 		if (access(loginfile, R_OK|X_OK) != 0) {
11644860Sbostic 			(void)strcpy(loginfile, _PATH_LOGIN);
11744851Strent 			if (access(loginfile, R_OK|X_OK)) {
11844851Strent 				fputs("access denied - no login file\n",
11944851Strent 				      stderr);
12044851Strent 				syslog(LOG_ERR,
12144851Strent 				       "access denied for %s - no %s\n",
12244860Sbostic 				       name, _PATH_LOGIN);
12344851Strent 				exit(5);
12444851Strent 			}
12546400Skarels 		}
12644851Strent 
12744851Strent 		(void) fclose(fp);
12844851Strent 		return;
12944851Strent 	}
13044851Strent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
13144851Strent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
13244851Strent 	exit(4);
13344851Strent 	/* NOTREACHED */
13438272Ssam }
13538272Ssam 
13644851Strent char *
13744851Strent sigstr(s)
13844851Strent 	int s;
13944851Strent {
14044851Strent 	static char buf[32];
14138272Ssam 
14244851Strent 	switch (s) {
14344851Strent 	case SIGHUP:	return("HUP");
14444851Strent 	case SIGINT:	return("INT");
14544851Strent 	case SIGQUIT:	return("QUIT");
14644851Strent 	case SIGILL:	return("ILL");
14744851Strent 	case SIGTRAP:	return("TRAP");
14844851Strent 	case SIGIOT:	return("IOT");
14944851Strent 	case SIGEMT:	return("EMT");
15044851Strent 	case SIGFPE:	return("FPE");
15144851Strent 	case SIGKILL:	return("KILL");
15244851Strent 	case SIGBUS:	return("BUS");
15344851Strent 	case SIGSEGV:	return("SEGV");
15444851Strent 	case SIGSYS:	return("SYS");
15544851Strent 	case SIGPIPE:	return("PIPE");
15644851Strent 	case SIGALRM:	return("ALRM");
15744851Strent 	case SIGTERM:	return("TERM");
15844851Strent 	case SIGURG:	return("URG");
15944851Strent 	case SIGSTOP:	return("STOP");
16044851Strent 	case SIGTSTP:	return("TSTP");
16144851Strent 	case SIGCONT:	return("CONT");
16244851Strent 	case SIGCHLD:	return("CHLD");
16344851Strent 	case SIGTTIN:	return("TTIN");
16444851Strent 	case SIGTTOU:	return("TTOU");
16544851Strent 	case SIGIO:	return("IO");
16644851Strent 	case SIGXCPU:	return("XCPU");
16744851Strent 	case SIGXFSZ:	return("XFSZ");
16844851Strent 	case SIGVTALRM:	return("VTALRM");
16944851Strent 	case SIGPROF:	return("PROF");
17044851Strent 	case SIGWINCH:	return("WINCH");
17144851Strent #ifdef SIGLOST
17244851Strent 	case SIGLOST:	return("LOST");
17344851Strent #endif
17444851Strent 	case SIGUSR1:	return("USR1");
17544851Strent 	case SIGUSR2:	return("USR2");
17644851Strent 	}
17744851Strent 	(void)sprintf(buf, "sig %d", s);
17844851Strent 	return(buf);
17944851Strent }
18038272Ssam 
18146929Sbostic void
18240016Ssam hup_handler(s)
18340016Ssam 	int s;
18438373Skarels {
18546400Skarels 	char logoutfile[MAXPATHLEN];
18646400Skarels 
18746400Skarels 	(void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
18846400Skarels 	if (access(logoutfile, R_OK|X_OK) != 0)
18946400Skarels 		(void)strcpy(logoutfile, _PATH_LOGOUT);
19044851Strent 	if (access(logoutfile, R_OK|X_OK) == 0) {
19146400Skarels 		char logincmd[2*MAXPATHLEN+32];
19240016Ssam 
19346400Skarels 		(void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
19444851Strent 			      loginargs);
19546400Skarels 		(void) system(logincmd);
19644851Strent 	}
19746400Skarels 	(void) close(0);
19844851Strent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
19944851Strent 	       sigstr(s));
20044851Strent 	exit(1);
20144851Strent 	/* NOTREACHED */
20238373Skarels }
20338373Skarels 
20438272Ssam main(argc, argv)
20538272Ssam 	int argc;
20638272Ssam 	char *argv[];
20738272Ssam {
20846400Skarels 	int fd, s, ldisc, odisc;
20944851Strent 	char *name;
21046400Skarels #ifdef POSIX
21146400Skarels 	struct termios tios, otios;
21244851Strent #else
21346400Skarels 	struct sgttyb tty, otty;
21444851Strent #endif
21544851Strent 	char logincmd[2*BUFSIZ+32];
21644851Strent 	extern uid_t getuid();
21738272Ssam 
21844851Strent 	if ((name = strrchr(argv[0], '/')) == NULL)
21944851Strent 		name = argv[0];
22038272Ssam 	s = getdtablesize();
22138272Ssam 	for (fd = 3 ; fd < s ; fd++)
22244851Strent 		(void) close(fd);
22344851Strent 	openlog(name, LOG_PID, LOG_DAEMON);
22446400Skarels 	uid = getuid();
22544851Strent 	if (argc > 1) {
22644851Strent 		findid(argv[1]);
22744851Strent 
22840016Ssam 		/*
22940016Ssam 		 * Disassociate from current controlling terminal, if any,
23040016Ssam 		 * and ensure that the slip line is our controlling terminal.
23140016Ssam 		 */
23246400Skarels #ifdef POSIX
23346400Skarels 		if (fork() > 0)
23446400Skarels 			exit(0);
23546400Skarels 		if (setsid() != 0)
23646400Skarels 			perror("setsid");
23744851Strent #else
23840016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
23944851Strent 			extern char *ttyname();
24044851Strent 
24144851Strent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
24240016Ssam 			(void) close(fd);
24340016Ssam 			/* open slip tty again to acquire as controlling tty? */
24440016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
24540016Ssam 			if (fd >= 0)
24640016Ssam 				(void) close(fd);
24740016Ssam 		}
24840016Ssam 		(void) setpgrp(0, getpid());
24940016Ssam #endif
25046400Skarels 		if (argc > 2) {
25146400Skarels 			if ((fd = open(argv[2], O_RDWR)) == -1) {
25246400Skarels 				perror(argv[2]);
25346400Skarels 				exit(2);
25446400Skarels 			}
25546400Skarels 			(void) dup2(fd, 0);
25646400Skarels 			if (fd > 2)
25746400Skarels 				close(fd);
25846400Skarels 		}
25946400Skarels #ifdef TIOCSCTTY
26046400Skarels 		if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0)
26146400Skarels 			perror("ioctl (TIOCSCTTY)");
26246400Skarels #endif
26344851Strent 	} else {
26446400Skarels 		extern char *getlogin();
26544851Strent 
26646400Skarels 		if ((name = getlogin()) == NULL) {
26744851Strent 			(void) fprintf(stderr, "access denied - no username\n");
26846400Skarels 			syslog(LOG_ERR, "access denied - getlogin returned 0\n");
26944851Strent 			exit(1);
27044851Strent 		}
27144851Strent 		findid(name);
27244851Strent 	}
27344851Strent 	(void) fchmod(0, 0600);
27444851Strent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
27546400Skarels #ifdef POSIX
27638272Ssam 	/* set up the line parameters */
27746400Skarels 	if (tcgetattr(0, &tios) < 0) {
27846400Skarels 		syslog(LOG_ERR, "tcgetattr: %m");
27938272Ssam 		exit(1);
28038272Ssam 	}
28140016Ssam 	otios = tios;
28246400Skarels 	cfmakeraw(&tios);
28346400Skarels 	tios.c_iflag &= ~IMAXBEL;
28446400Skarels 	if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
28546400Skarels 		syslog(LOG_ERR, "tcsetattr: %m");
28638272Ssam 		exit(1);
28738272Ssam 	}
28846400Skarels 	speed = cfgetispeed(&tios);
28944851Strent #else
29044851Strent 	/* set up the line parameters */
29144851Strent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
29244851Strent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
29344851Strent 		exit(1);
29444851Strent 	}
29544851Strent 	otty = tty;
29644851Strent 	speed = tty.sg_ispeed;
29744851Strent 	tty.sg_flags = RAW | ANYP;
29844851Strent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
29944851Strent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
30044851Strent 		exit(1);
30144851Strent 	}
30244851Strent #endif
30338373Skarels 	/* find out what ldisc we started with */
30438373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
30538373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
30638373Skarels 		exit(1);
30738373Skarels 	}
30838372Ssam 	ldisc = SLIPDISC;
30938372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
31040016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
31138272Ssam 		exit(1);
31238272Ssam 	}
31338272Ssam 	/* find out what unit number we were assigned */
31446400Skarels 	if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) {
31546684Skarels 		syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
31638272Ssam 		exit(1);
31738272Ssam 	}
31844851Strent 	(void) signal(SIGHUP, hup_handler);
31944851Strent 	(void) signal(SIGTERM, hup_handler);
32044851Strent 
32144851Strent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
32244851Strent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
32344851Strent 		      loginargs);
32444851Strent 	/*
32544851Strent 	 * aim stdout and errout at /dev/null so logincmd output won't
32644851Strent 	 * babble into the slip tty line.
32744851Strent 	 */
32846400Skarels 	(void) close(1);
32946929Sbostic 	if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
33044851Strent 		if (fd < 0) {
33144851Strent 			syslog(LOG_ERR, "open /dev/null: %m");
33238272Ssam 			exit(1);
33338272Ssam 		}
33446400Skarels 		(void) dup2(fd, 1);
33546400Skarels 		(void) close(fd);
33638272Ssam 	}
33746400Skarels 	(void) dup2(1, 2);
33846400Skarels 
33946400Skarels 	/*
34046400Skarels 	 * Run login and logout scripts as root (real and effective);
34146400Skarels 	 * current route(8) is setuid root, and checks the real uid
34246400Skarels 	 * to see whether changes are allowed (or just "route get").
34346400Skarels 	 */
34446400Skarels 	(void) setuid(0);
34544851Strent 	if (s = system(logincmd)) {
34644851Strent 		syslog(LOG_ERR, "%s login failed: exit status %d from %s",
34744851Strent 		       loginname, s, loginfile);
34844851Strent 		(void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
34944851Strent 		exit(6);
35038272Ssam 	}
35138272Ssam 
35238272Ssam 	/* twiddle thumbs until we get a signal */
35344851Strent 	while (1)
35438272Ssam 		sigpause(0);
35538272Ssam 
35644851Strent 	/* NOTREACHED */
35738272Ssam }
358