144262Sbostic /*-
244262Sbostic  * Copyright (c) 1990 The Regents of the University of California.
344262Sbostic  * All rights reserved.
444262Sbostic  *
544262Sbostic  * %sccs.include.redist.c%
644262Sbostic  */
744262Sbostic 
838272Ssam #ifndef lint
944262Sbostic char copyright[] =
1044262Sbostic "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
1144262Sbostic  All rights reserved.\n";
1244262Sbostic #endif /* not lint */
1344262Sbostic 
1444262Sbostic #ifndef lint
15*46684Skarels static char sccsid[] = "@(#)sliplogin.c	5.5 (Berkeley) 02/26/91";
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;
7244860Sbostic int	slip_mode;
7344851Strent int	speed;
7446400Skarels int	uid;
7544851Strent char	loginargs[BUFSIZ];
7646400Skarels char	loginfile[MAXPATHLEN];
7744851Strent char	loginname[BUFSIZ];
7838272Ssam 
7944851Strent struct slip_modes {
8044851Strent 	char	*sm_name;
8144851Strent 	int	sm_value;
8244851Strent }	 modes[] = {
8344851Strent 	"normal",	0,
8444851Strent 	"compress",	SC_COMPRESS,
8544851Strent 	"noicmp",	SC_NOICMP,
8644851Strent 	"autocomp",	SC_AUTOCOMP
8744851Strent };
8838272Ssam 
8938272Ssam void
9044851Strent findid(name)
9144851Strent 	char *name;
9238272Ssam {
9344851Strent 	FILE *fp;
9444851Strent 	static char slopt[5][16];
9544851Strent 	static char laddr[16];
9644851Strent 	static char raddr[16];
9744851Strent 	static char mask[16];
9844851Strent 	char user[16];
9944851Strent 	int i, j, n;
10038272Ssam 
10144851Strent 	(void)strcpy(loginname, name);
10244860Sbostic 	if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
10344860Sbostic 		(void)fprintf(stderr, "sliplogin: %s: %s\n",
10444860Sbostic 		    _PATH_ACCESS, strerror(errno));
10544860Sbostic 		syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
10644860Sbostic 		exit(1);
10744851Strent 	}
10844851Strent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
10944851Strent 		if (ferror(fp))
11044851Strent 			break;
11144851Strent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
11244851Strent                         user, laddr, raddr, mask, slopt[0], slopt[1],
11344851Strent 			slopt[2], slopt[3], slopt[4]);
11444851Strent 		if (user[0] == '#' || isspace(user[0]))
11544851Strent 			continue;
11644851Strent 		if (strcmp(user, name) != 0)
11744851Strent 			continue;
11838272Ssam 
11944851Strent 		slip_mode = 0;
12044851Strent 		for (i = 0; i < n - 4; i++) {
12144851Strent 			for (j = 0; j < sizeof(modes)/sizeof(struct slip_modes);
12244851Strent 				j++) {
12344851Strent 				if (strcmp(modes[j].sm_name, slopt[i]) == 0) {
12444851Strent 					slip_mode |= modes[j].sm_value;
12544851Strent 					break;
12644851Strent 				}
12744851Strent 			}
12844851Strent 		}
12938272Ssam 
13044851Strent 		/*
13144851Strent 		 * we've found the guy we're looking for -- see if
13244851Strent 		 * there's a login file we can use.  First check for
13344851Strent 		 * one specific to this host.  If none found, try for
13444851Strent 		 * a generic one.
13544851Strent 		 */
13644860Sbostic 		(void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
13746400Skarels 		if (access(loginfile, R_OK|X_OK) != 0) {
13844860Sbostic 			(void)strcpy(loginfile, _PATH_LOGIN);
13944851Strent 			if (access(loginfile, R_OK|X_OK)) {
14044851Strent 				fputs("access denied - no login file\n",
14144851Strent 				      stderr);
14244851Strent 				syslog(LOG_ERR,
14344851Strent 				       "access denied for %s - no %s\n",
14444860Sbostic 				       name, _PATH_LOGIN);
14544851Strent 				exit(5);
14644851Strent 			}
14746400Skarels 		}
14844851Strent 
14944851Strent 		(void) fclose(fp);
15044851Strent 		return;
15144851Strent 	}
15244851Strent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
15344851Strent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
15444851Strent 	exit(4);
15544851Strent 	/* NOTREACHED */
15638272Ssam }
15738272Ssam 
15844851Strent char *
15944851Strent sigstr(s)
16044851Strent 	int s;
16144851Strent {
16244851Strent 	static char buf[32];
16338272Ssam 
16444851Strent 	switch (s) {
16544851Strent 	case SIGHUP:	return("HUP");
16644851Strent 	case SIGINT:	return("INT");
16744851Strent 	case SIGQUIT:	return("QUIT");
16844851Strent 	case SIGILL:	return("ILL");
16944851Strent 	case SIGTRAP:	return("TRAP");
17044851Strent 	case SIGIOT:	return("IOT");
17144851Strent 	case SIGEMT:	return("EMT");
17244851Strent 	case SIGFPE:	return("FPE");
17344851Strent 	case SIGKILL:	return("KILL");
17444851Strent 	case SIGBUS:	return("BUS");
17544851Strent 	case SIGSEGV:	return("SEGV");
17644851Strent 	case SIGSYS:	return("SYS");
17744851Strent 	case SIGPIPE:	return("PIPE");
17844851Strent 	case SIGALRM:	return("ALRM");
17944851Strent 	case SIGTERM:	return("TERM");
18044851Strent 	case SIGURG:	return("URG");
18144851Strent 	case SIGSTOP:	return("STOP");
18244851Strent 	case SIGTSTP:	return("TSTP");
18344851Strent 	case SIGCONT:	return("CONT");
18444851Strent 	case SIGCHLD:	return("CHLD");
18544851Strent 	case SIGTTIN:	return("TTIN");
18644851Strent 	case SIGTTOU:	return("TTOU");
18744851Strent 	case SIGIO:	return("IO");
18844851Strent 	case SIGXCPU:	return("XCPU");
18944851Strent 	case SIGXFSZ:	return("XFSZ");
19044851Strent 	case SIGVTALRM:	return("VTALRM");
19144851Strent 	case SIGPROF:	return("PROF");
19244851Strent 	case SIGWINCH:	return("WINCH");
19344851Strent #ifdef SIGLOST
19444851Strent 	case SIGLOST:	return("LOST");
19544851Strent #endif
19644851Strent 	case SIGUSR1:	return("USR1");
19744851Strent 	case SIGUSR2:	return("USR2");
19844851Strent 	}
19944851Strent 	(void)sprintf(buf, "sig %d", s);
20044851Strent 	return(buf);
20144851Strent }
20238272Ssam 
20344851Strent int
20440016Ssam hup_handler(s)
20540016Ssam 	int s;
20638373Skarels {
20746400Skarels 	char logoutfile[MAXPATHLEN];
20846400Skarels 
20946400Skarels 	(void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
21046400Skarels 	if (access(logoutfile, R_OK|X_OK) != 0)
21146400Skarels 		(void)strcpy(logoutfile, _PATH_LOGOUT);
21244851Strent 	if (access(logoutfile, R_OK|X_OK) == 0) {
21346400Skarels 		char logincmd[2*MAXPATHLEN+32];
21440016Ssam 
21546400Skarels 		(void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
21644851Strent 			      loginargs);
21746400Skarels 		(void) system(logincmd);
21844851Strent 	}
21946400Skarels 	(void) close(0);
22044851Strent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
22144851Strent 	       sigstr(s));
22244851Strent 	exit(1);
22344851Strent 	/* NOTREACHED */
22438373Skarels }
22538373Skarels 
22638272Ssam main(argc, argv)
22738272Ssam 	int argc;
22838272Ssam 	char *argv[];
22938272Ssam {
23046400Skarels 	int fd, s, ldisc, odisc;
23144851Strent 	char *name;
23246400Skarels #ifdef POSIX
23346400Skarels 	struct termios tios, otios;
23444851Strent #else
23546400Skarels 	struct sgttyb tty, otty;
23644851Strent #endif
23744851Strent 	char logincmd[2*BUFSIZ+32];
23844851Strent 	extern uid_t getuid();
23938272Ssam 
24044851Strent 	if ((name = strrchr(argv[0], '/')) == NULL)
24144851Strent 		name = argv[0];
24238272Ssam 	s = getdtablesize();
24338272Ssam 	for (fd = 3 ; fd < s ; fd++)
24444851Strent 		(void) close(fd);
24544851Strent 	openlog(name, LOG_PID, LOG_DAEMON);
24646400Skarels 	uid = getuid();
24744851Strent 	if (argc > 1) {
24844851Strent 		findid(argv[1]);
24944851Strent 
25040016Ssam 		/*
25140016Ssam 		 * Disassociate from current controlling terminal, if any,
25240016Ssam 		 * and ensure that the slip line is our controlling terminal.
25340016Ssam 		 */
25446400Skarels #ifdef POSIX
25546400Skarels 		if (fork() > 0)
25646400Skarels 			exit(0);
25746400Skarels 		if (setsid() != 0)
25846400Skarels 			perror("setsid");
25944851Strent #else
26040016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
26144851Strent 			extern char *ttyname();
26244851Strent 
26344851Strent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
26440016Ssam 			(void) close(fd);
26540016Ssam 			/* open slip tty again to acquire as controlling tty? */
26640016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
26740016Ssam 			if (fd >= 0)
26840016Ssam 				(void) close(fd);
26940016Ssam 		}
27040016Ssam 		(void) setpgrp(0, getpid());
27140016Ssam #endif
27246400Skarels 		if (argc > 2) {
27346400Skarels 			if ((fd = open(argv[2], O_RDWR)) == -1) {
27446400Skarels 				perror(argv[2]);
27546400Skarels 				exit(2);
27646400Skarels 			}
27746400Skarels 			(void) dup2(fd, 0);
27846400Skarels 			if (fd > 2)
27946400Skarels 				close(fd);
28046400Skarels 		}
28146400Skarels #ifdef TIOCSCTTY
28246400Skarels 		if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0)
28346400Skarels 			perror("ioctl (TIOCSCTTY)");
28446400Skarels #endif
28544851Strent 	} else {
28646400Skarels 		extern char *getlogin();
28744851Strent 
28846400Skarels 		if ((name = getlogin()) == NULL) {
28944851Strent 			(void) fprintf(stderr, "access denied - no username\n");
29046400Skarels 			syslog(LOG_ERR, "access denied - getlogin returned 0\n");
29144851Strent 			exit(1);
29244851Strent 		}
29344851Strent 		findid(name);
29444851Strent 	}
29544851Strent 	(void) fchmod(0, 0600);
29644851Strent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
29746400Skarels #ifdef POSIX
29838272Ssam 	/* set up the line parameters */
29946400Skarels 	if (tcgetattr(0, &tios) < 0) {
30046400Skarels 		syslog(LOG_ERR, "tcgetattr: %m");
30138272Ssam 		exit(1);
30238272Ssam 	}
30340016Ssam 	otios = tios;
30446400Skarels 	cfmakeraw(&tios);
30546400Skarels 	tios.c_iflag &= ~IMAXBEL;
30646400Skarels 	if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
30746400Skarels 		syslog(LOG_ERR, "tcsetattr: %m");
30838272Ssam 		exit(1);
30938272Ssam 	}
31046400Skarels 	speed = cfgetispeed(&tios);
31144851Strent #else
31244851Strent 	/* set up the line parameters */
31344851Strent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
31444851Strent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
31544851Strent 		exit(1);
31644851Strent 	}
31744851Strent 	otty = tty;
31844851Strent 	speed = tty.sg_ispeed;
31944851Strent 	tty.sg_flags = RAW | ANYP;
32044851Strent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
32144851Strent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
32244851Strent 		exit(1);
32344851Strent 	}
32444851Strent #endif
32538373Skarels 	/* find out what ldisc we started with */
32638373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
32738373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
32838373Skarels 		exit(1);
32938373Skarels 	}
33038372Ssam 	ldisc = SLIPDISC;
33138372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
33240016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
33338272Ssam 		exit(1);
33438272Ssam 	}
33538272Ssam 	/* find out what unit number we were assigned */
33646400Skarels 	if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) {
337*46684Skarels 		syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
33838272Ssam 		exit(1);
33938272Ssam 	}
34044851Strent 	(void) signal(SIGHUP, hup_handler);
34144851Strent 	(void) signal(SIGTERM, hup_handler);
34244851Strent 
34344851Strent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
34444851Strent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
34544851Strent 		      loginargs);
34644851Strent 	/*
34744851Strent 	 * aim stdout and errout at /dev/null so logincmd output won't
34844851Strent 	 * babble into the slip tty line.
34944851Strent 	 */
35046400Skarels 	(void) close(1);
35146400Skarels 	if ((fd = open("/dev/null", O_WRONLY)) != 1) {
35244851Strent 		if (fd < 0) {
35344851Strent 			syslog(LOG_ERR, "open /dev/null: %m");
35438272Ssam 			exit(1);
35538272Ssam 		}
35646400Skarels 		(void) dup2(fd, 1);
35746400Skarels 		(void) close(fd);
35838272Ssam 	}
35946400Skarels 	(void) dup2(1, 2);
36046400Skarels 
36146400Skarels 	/*
36246400Skarels 	 * Run login and logout scripts as root (real and effective);
36346400Skarels 	 * current route(8) is setuid root, and checks the real uid
36446400Skarels 	 * to see whether changes are allowed (or just "route get").
36546400Skarels 	 */
36646400Skarels 	(void) setuid(0);
36744851Strent 	if (s = system(logincmd)) {
36844851Strent 		syslog(LOG_ERR, "%s login failed: exit status %d from %s",
36944851Strent 		       loginname, s, loginfile);
37044851Strent 		(void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
37144851Strent 		exit(6);
37238272Ssam 	}
37338373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
37438373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
37538373Skarels 		exit(1);
37638373Skarels 	}
37738272Ssam 
37838272Ssam 	/* twiddle thumbs until we get a signal */
37944851Strent 	while (1)
38038272Ssam 		sigpause(0);
38138272Ssam 
38244851Strent 	/* NOTREACHED */
38338272Ssam }
384