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*44851Strent static char sccsid[] = "@(#)sliplogin.c	5.2 (Berkeley) 07/01/90";
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.
23*44851Strent  * It sets the line discipline to slip, invokes a shell script to initialize
24*44851Strent  * 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  *
31*44851Strent  * There are two forms of usage:
3238272Ssam  *
3338272Ssam  * "sliplogin"
3438272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
3538272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
3638272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
3738272Ssam  * as specified in the file.
3838272Ssam  *
3938272Ssam  * "sliplogin IPhost1 </dev/ttyb"
4038272Ssam  * Invoked by root with a username, the name is looked up in the
4138272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
4238272Ssam  */
4338272Ssam 
4438272Ssam #include <sys/types.h>
45*44851Strent #include <sys/param.h>
4638272Ssam #include <sys/socket.h>
4738372Ssam #include <sys/ioctl.h>
4838272Ssam #include <sys/file.h>
4938272Ssam #include <sys/syslog.h>
5038272Ssam #include <stdio.h>
5138272Ssam #include <errno.h>
5238272Ssam #include <ctype.h>
5338272Ssam #include <netdb.h>
5438272Ssam #include <signal.h>
55*44851Strent #include <string.h>
56*44851Strent #if defined(BSD4_4)
57*44851Strent #define TERMIOS
58*44851Strent #endif
59*44851Strent #ifdef TERMIOS
60*44851Strent #include <sys/termios.h>
6138272Ssam #include <ttyent.h>
62*44851Strent #endif
63*44851Strent #include <netinet/in.h>
64*44851Strent #include <net/if.h>
65*44851Strent #include <net/if_slvar.h>
6638272Ssam 
67*44851Strent #ifndef ACCESSFILE
68*44851Strent #define ACCESSFILE "/etc/slip.hosts"
69*44851Strent #endif
70*44851Strent #ifndef LOGINFILE
71*44851Strent #define LOGINFILE "/etc/slip.login"
72*44851Strent #define LOGOUTFILE "/etc/slip.logout"
73*44851Strent #endif
7438372Ssam 
7538372Ssam 
76*44851Strent int	unit;
77*44851Strent int     slip_mode;
78*44851Strent int	speed;
79*44851Strent char	loginargs[BUFSIZ];
80*44851Strent char	loginfile[BUFSIZ];
81*44851Strent char	logoutfile[BUFSIZ];
82*44851Strent char	loginname[BUFSIZ];
8338272Ssam 
84*44851Strent struct slip_modes {
85*44851Strent 	char	*sm_name;
86*44851Strent 	int	sm_value;
87*44851Strent }	 modes[] = {
88*44851Strent 	"normal",	0,
89*44851Strent 	"compress",	SC_COMPRESS,
90*44851Strent 	"noicmp",	SC_NOICMP,
91*44851Strent 	"autocomp",	SC_AUTOCOMP
92*44851Strent };
9338272Ssam 
9438272Ssam void
95*44851Strent findid(name)
96*44851Strent 	char *name;
9738272Ssam {
98*44851Strent 	FILE *fp;
99*44851Strent 	static char slopt[5][16];
100*44851Strent 	static char laddr[16];
101*44851Strent 	static char raddr[16];
102*44851Strent 	static char mask[16];
103*44851Strent 	char user[16];
104*44851Strent 	int i, j, n;
10538272Ssam 
106*44851Strent 	(void)strcpy(loginname, name);
107*44851Strent 	if ((fp = fopen(ACCESSFILE, "r")) == NULL) {
108*44851Strent 		perror(ACCESSFILE);
109*44851Strent 		syslog(LOG_ERR, "%s: %m\n", ACCESSFILE);
110*44851Strent 		exit(3);
111*44851Strent 	}
112*44851Strent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
11340016Ssam 
114*44851Strent 		if (ferror(fp))
115*44851Strent 			break;
116*44851Strent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
117*44851Strent                         user, laddr, raddr, mask, slopt[0], slopt[1],
118*44851Strent 			slopt[2], slopt[3], slopt[4]);
119*44851Strent 		if (user[0] == '#' || isspace(user[0]))
120*44851Strent 			continue;
121*44851Strent 		if (strcmp(user, name) != 0)
122*44851Strent 			continue;
12338272Ssam 
124*44851Strent 		slip_mode = 0;
125*44851Strent 		for (i = 0; i < n - 4; i++) {
126*44851Strent 			for (j = 0; j < sizeof(modes)/sizeof(struct slip_modes);
127*44851Strent 				j++) {
128*44851Strent 				if (strcmp(modes[j].sm_name, slopt[i]) == 0) {
129*44851Strent 					slip_mode |= modes[j].sm_value;
130*44851Strent 					break;
131*44851Strent 				}
132*44851Strent 			}
133*44851Strent 		}
13438272Ssam 
135*44851Strent 		/*
136*44851Strent 		 * we've found the guy we're looking for -- see if
137*44851Strent 		 * there's a login file we can use.  First check for
138*44851Strent 		 * one specific to this host.  If none found, try for
139*44851Strent 		 * a generic one.
140*44851Strent 		 */
141*44851Strent 		(void)sprintf(loginfile, "%s.%s", LOGINFILE, name);
142*44851Strent 		if (access(loginfile, R_OK|X_OK)) {
143*44851Strent 			(void)strcpy(loginfile, LOGINFILE);
144*44851Strent 			(void)strcpy(logoutfile, LOGOUTFILE);
145*44851Strent 			if (access(loginfile, R_OK|X_OK)) {
146*44851Strent 				fputs("access denied - no login file\n",
147*44851Strent 				      stderr);
148*44851Strent 				syslog(LOG_ERR,
149*44851Strent 				       "access denied for %s - no %s\n",
150*44851Strent 				       name, LOGINFILE);
151*44851Strent 				exit(5);
152*44851Strent 			}
153*44851Strent 		} else
154*44851Strent 			(void)sprintf(logoutfile, "%s.%s", LOGOUTFILE, name);
155*44851Strent 
156*44851Strent 		(void) fclose(fp);
157*44851Strent 		return;
158*44851Strent 	}
159*44851Strent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
160*44851Strent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
161*44851Strent 	exit(4);
162*44851Strent 	/* NOTREACHED */
16338272Ssam }
16438272Ssam 
165*44851Strent char *
166*44851Strent sigstr(s)
167*44851Strent 	int s;
168*44851Strent {
169*44851Strent 	static char buf[32];
17038272Ssam 
171*44851Strent 	switch (s) {
172*44851Strent 	case SIGHUP:	return("HUP");
173*44851Strent 	case SIGINT:	return("INT");
174*44851Strent 	case SIGQUIT:	return("QUIT");
175*44851Strent 	case SIGILL:	return("ILL");
176*44851Strent 	case SIGTRAP:	return("TRAP");
177*44851Strent 	case SIGIOT:	return("IOT");
178*44851Strent 	case SIGEMT:	return("EMT");
179*44851Strent 	case SIGFPE:	return("FPE");
180*44851Strent 	case SIGKILL:	return("KILL");
181*44851Strent 	case SIGBUS:	return("BUS");
182*44851Strent 	case SIGSEGV:	return("SEGV");
183*44851Strent 	case SIGSYS:	return("SYS");
184*44851Strent 	case SIGPIPE:	return("PIPE");
185*44851Strent 	case SIGALRM:	return("ALRM");
186*44851Strent 	case SIGTERM:	return("TERM");
187*44851Strent 	case SIGURG:	return("URG");
188*44851Strent 	case SIGSTOP:	return("STOP");
189*44851Strent 	case SIGTSTP:	return("TSTP");
190*44851Strent 	case SIGCONT:	return("CONT");
191*44851Strent 	case SIGCHLD:	return("CHLD");
192*44851Strent 	case SIGTTIN:	return("TTIN");
193*44851Strent 	case SIGTTOU:	return("TTOU");
194*44851Strent 	case SIGIO:	return("IO");
195*44851Strent 	case SIGXCPU:	return("XCPU");
196*44851Strent 	case SIGXFSZ:	return("XFSZ");
197*44851Strent 	case SIGVTALRM:	return("VTALRM");
198*44851Strent 	case SIGPROF:	return("PROF");
199*44851Strent 	case SIGWINCH:	return("WINCH");
200*44851Strent #ifdef SIGLOST
201*44851Strent 	case SIGLOST:	return("LOST");
202*44851Strent #endif
203*44851Strent 	case SIGUSR1:	return("USR1");
204*44851Strent 	case SIGUSR2:	return("USR2");
205*44851Strent 	}
206*44851Strent 	(void)sprintf(buf, "sig %d", s);
207*44851Strent 	return(buf);
208*44851Strent }
20938272Ssam 
210*44851Strent int
21140016Ssam hup_handler(s)
21240016Ssam 	int s;
21338373Skarels {
214*44851Strent 	if (access(logoutfile, R_OK|X_OK) == 0) {
215*44851Strent 		char logincmd[2*BUFSIZ+32];
21640016Ssam 
217*44851Strent 		(void)sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
218*44851Strent 			      loginargs);
219*44851Strent 		(void)system(logincmd);
220*44851Strent 	}
221*44851Strent 	(void)close(0);
222*44851Strent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
223*44851Strent 	       sigstr(s));
224*44851Strent 	exit(1);
225*44851Strent 	/* NOTREACHED */
22638373Skarels }
22738373Skarels 
22838272Ssam main(argc, argv)
22938272Ssam 	int argc;
23038272Ssam 	char *argv[];
23138272Ssam {
23238373Skarels 	int	fd, s, ldisc, odisc;
233*44851Strent 	char *name;
234*44851Strent #ifdef TERMIOS
23538373Skarels 	struct	termios tios, otios;
236*44851Strent #else
237*44851Strent 	struct	sgttyb tty, otty;
238*44851Strent #endif
239*44851Strent 	char logincmd[2*BUFSIZ+32];
240*44851Strent 	extern uid_t getuid();
24138272Ssam 
242*44851Strent 	if ((name = strrchr(argv[0], '/')) == NULL)
243*44851Strent 		name = argv[0];
24438272Ssam 	s = getdtablesize();
24538272Ssam 	for (fd = 3 ; fd < s ; fd++)
246*44851Strent 		(void) close(fd);
247*44851Strent 	openlog(name, LOG_PID, LOG_DAEMON);
248*44851Strent 	if (argc > 1) {
249*44851Strent 		if (argc > 2) {
250*44851Strent 			(void)fprintf(stderr, "Usage: %s loginname\n", argv[0]);
25138272Ssam 			exit(1);
25238272Ssam 		}
253*44851Strent 		findid(argv[1]);
254*44851Strent 
25540016Ssam 		/*
25640016Ssam 		 * Disassociate from current controlling terminal, if any,
25740016Ssam 		 * and ensure that the slip line is our controlling terminal.
25840016Ssam 		 */
259*44851Strent #ifdef TERMIOS
260*44851Strent 		(void) setsid();
261*44851Strent 		(void) ioctl(0, TIOCSCTTY, (caddr_t)0);
262*44851Strent #else
26340016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
264*44851Strent 			extern char *ttyname();
265*44851Strent 
266*44851Strent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
26740016Ssam 			(void) close(fd);
26840016Ssam 			/* open slip tty again to acquire as controlling tty? */
26940016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
27040016Ssam 			if (fd >= 0)
27140016Ssam 				(void) close(fd);
27240016Ssam 		}
27340016Ssam 		(void) setpgrp(0, getpid());
27440016Ssam #endif
275*44851Strent 	} else {
276*44851Strent 		extern char *getenv();
277*44851Strent 
278*44851Strent 		if ((name = getenv("USER")) == NULL) {
279*44851Strent 			(void) fprintf(stderr, "access denied - no username\n");
280*44851Strent 			syslog(LOG_ERR, "access denied - no username\n");
281*44851Strent 			exit(1);
282*44851Strent 		}
283*44851Strent 		findid(name);
284*44851Strent 	}
285*44851Strent 	(void) fchmod(0, 0600);
286*44851Strent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
287*44851Strent #ifdef TERMIOS
28838272Ssam 	/* set up the line parameters */
28940016Ssam 	if (ioctl(0, TIOCGETA, (caddr_t)&tios) < 0) {
29040016Ssam 		syslog(LOG_ERR, "ioctl (TIOCGETA): %m");
29138272Ssam 		exit(1);
29238272Ssam 	}
29340016Ssam 	otios = tios;
29440016Ssam 	tios.c_cflag = CS8|CREAD|HUPCL;
29538272Ssam 	tios.c_iflag = IGNBRK;
29638372Ssam 	tios.c_oflag = tios.c_lflag = 0;
29740016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&tios) < 0) {
29840016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (1): %m");
29938272Ssam 		exit(1);
30038272Ssam 	}
301*44851Strent #else
302*44851Strent 	/* set up the line parameters */
303*44851Strent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
304*44851Strent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
305*44851Strent 		exit(1);
306*44851Strent 	}
307*44851Strent 	otty = tty;
308*44851Strent 	speed = tty.sg_ispeed;
309*44851Strent 	tty.sg_flags = RAW | ANYP;
310*44851Strent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
311*44851Strent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
312*44851Strent 		exit(1);
313*44851Strent 	}
314*44851Strent #endif
31538373Skarels 	/* find out what ldisc we started with */
31638373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
31738373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
31838373Skarels 		exit(1);
31938373Skarels 	}
32038372Ssam 	ldisc = SLIPDISC;
32138372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
32240016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
32338272Ssam 		exit(1);
32438272Ssam 	}
32538272Ssam 	/* find out what unit number we were assigned */
32638372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
32738373Skarels 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
32838272Ssam 		exit(1);
32938272Ssam 	}
330*44851Strent 	(void) signal(SIGHUP, hup_handler);
331*44851Strent 	(void) signal(SIGTERM, hup_handler);
332*44851Strent 
333*44851Strent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
334*44851Strent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
335*44851Strent 		      loginargs);
336*44851Strent 	/*
337*44851Strent 	 * aim stdout and errout at /dev/null so logincmd output won't
338*44851Strent 	 * babble into the slip tty line.
339*44851Strent 	 */
340*44851Strent 	(void)close(1);
341*44851Strent 	if ((fd = open("/dev/null", O_WRONLY, 0)) != 1) {
342*44851Strent 		if (fd < 0) {
343*44851Strent 			syslog(LOG_ERR, "open /dev/null: %m");
34438272Ssam 			exit(1);
34538272Ssam 		}
346*44851Strent 		(void)dup2(fd, 1);
347*44851Strent 		(void)close(fd);
34838272Ssam 	}
349*44851Strent 	(void)dup2(1,2);
350*44851Strent 	if (s = system(logincmd)) {
351*44851Strent 		syslog(LOG_ERR, "%s login failed: exit status %d from %s",
352*44851Strent 		       loginname, s, loginfile);
353*44851Strent 		(void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
354*44851Strent 		exit(6);
35538272Ssam 	}
35638373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
35738373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
35838373Skarels 		exit(1);
35938373Skarels 	}
36038272Ssam 
36138272Ssam 	/* twiddle thumbs until we get a signal */
362*44851Strent 	while (1)
36338272Ssam 		sigpause(0);
36438272Ssam 
365*44851Strent 	/* NOTREACHED */
36638272Ssam }
367