1b88df7feSbostic /*-
29122c3bfSbostic  * Copyright (c) 1990, 1993
39122c3bfSbostic  *	The Regents of the University of California.  All rights reserved.
4b88df7feSbostic  *
5b88df7feSbostic  * %sccs.include.redist.c%
6b88df7feSbostic  */
7b88df7feSbostic 
8a14e21ddSsam #ifndef lint
99122c3bfSbostic static char copyright[] =
109122c3bfSbostic "@(#) Copyright (c) 1990, 1993\n\
119122c3bfSbostic 	The Regents of the University of California.  All rights reserved.\n";
12b88df7feSbostic #endif /* not lint */
13b88df7feSbostic 
14b88df7feSbostic #ifndef lint
15*3d29b849Scgd static char sccsid[] = "@(#)sliplogin.c	8.2 (Berkeley) 02/01/94";
16b88df7feSbostic #endif /* not lint */
17b88df7feSbostic 
18a14e21ddSsam /*
19a14e21ddSsam  * sliplogin.c
20a18a0028Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
21a14e21ddSsam  *
22a14e21ddSsam  * This program initializes its own tty port to be an async TCP/IP interface.
23aa9b0ccbStrent  * It sets the line discipline to slip, invokes a shell script to initialize
24aa9b0ccbStrent  * the network interface, then pauses forever waiting for hangup.
25a14e21ddSsam  *
26a14e21ddSsam  * It is a remote descendant of several similar programs with incestuous ties:
27a14e21ddSsam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
28a14e21ddSsam  * - slattach, probably by Rick Adams but touched by countless hordes.
29a14e21ddSsam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
30a14e21ddSsam  *
31aa9b0ccbStrent  * There are two forms of usage:
32a14e21ddSsam  *
33a14e21ddSsam  * "sliplogin"
34c4a0303eSkarels  * Invoked simply as "sliplogin", the program looks up the username
35c4a0303eSkarels  * in the file /etc/slip.hosts.
36c4a0303eSkarels  * If an entry is found, the line on fd0 is configured for SLIP operation
37a14e21ddSsam  * as specified in the file.
38a14e21ddSsam  *
39c4a0303eSkarels  * "sliplogin IPhostlogin </dev/ttyb"
40a14e21ddSsam  * Invoked by root with a username, the name is looked up in the
41c4a0303eSkarels  * /etc/slip.hosts file and if found fd0 is configured as in case 1.
42a14e21ddSsam  */
43a14e21ddSsam 
44aa9b0ccbStrent #include <sys/param.h>
45a14e21ddSsam #include <sys/socket.h>
467ada4fb7Sbostic #include <sys/signal.h>
47a14e21ddSsam #include <sys/file.h>
48a14e21ddSsam #include <sys/syslog.h>
49a14e21ddSsam #include <netdb.h>
507ada4fb7Sbostic 
51c4a0303eSkarels #if BSD >= 199006
52c4a0303eSkarels #define POSIX
53aa9b0ccbStrent #endif
54c4a0303eSkarels #ifdef POSIX
55aa9b0ccbStrent #include <sys/termios.h>
56c4a0303eSkarels #include <sys/ioctl.h>
57a14e21ddSsam #include <ttyent.h>
58c4a0303eSkarels #else
59c4a0303eSkarels #include <sgtty.h>
60aa9b0ccbStrent #endif
61*3d29b849Scgd #include <net/slip.h>
62ca1574aaSsam 
637ada4fb7Sbostic #include <stdio.h>
647ada4fb7Sbostic #include <errno.h>
657ada4fb7Sbostic #include <ctype.h>
667ada4fb7Sbostic #include <string.h>
677ada4fb7Sbostic #include "pathnames.h"
685347ed73Ssam 
69aa9b0ccbStrent int	unit;
70aa9b0ccbStrent int	speed;
71c4a0303eSkarels int	uid;
72aa9b0ccbStrent char	loginargs[BUFSIZ];
73c4a0303eSkarels char	loginfile[MAXPATHLEN];
74aa9b0ccbStrent char	loginname[BUFSIZ];
75a18a0028Skarels 
76a18a0028Skarels void
findid(name)77aa9b0ccbStrent findid(name)
78aa9b0ccbStrent 	char *name;
79aa9b0ccbStrent {
80aa9b0ccbStrent 	FILE *fp;
81aa9b0ccbStrent 	static char slopt[5][16];
82aa9b0ccbStrent 	static char laddr[16];
83aa9b0ccbStrent 	static char raddr[16];
84aa9b0ccbStrent 	static char mask[16];
85aa9b0ccbStrent 	char user[16];
86aa9b0ccbStrent 	int i, j, n;
87aa9b0ccbStrent 
88aa9b0ccbStrent 	(void)strcpy(loginname, name);
897ada4fb7Sbostic 	if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) {
907ada4fb7Sbostic 		(void)fprintf(stderr, "sliplogin: %s: %s\n",
917ada4fb7Sbostic 		    _PATH_ACCESS, strerror(errno));
927ada4fb7Sbostic 		syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
937ada4fb7Sbostic 		exit(1);
94aa9b0ccbStrent 	}
95aa9b0ccbStrent 	while (fgets(loginargs, sizeof(loginargs) - 1, fp)) {
96aa9b0ccbStrent 		if (ferror(fp))
97aa9b0ccbStrent 			break;
98aa9b0ccbStrent 		n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
99aa9b0ccbStrent                         user, laddr, raddr, mask, slopt[0], slopt[1],
100aa9b0ccbStrent 			slopt[2], slopt[3], slopt[4]);
101aa9b0ccbStrent 		if (user[0] == '#' || isspace(user[0]))
102aa9b0ccbStrent 			continue;
103aa9b0ccbStrent 		if (strcmp(user, name) != 0)
104aa9b0ccbStrent 			continue;
105aa9b0ccbStrent 
106aa9b0ccbStrent 		/*
107aa9b0ccbStrent 		 * we've found the guy we're looking for -- see if
108aa9b0ccbStrent 		 * there's a login file we can use.  First check for
109aa9b0ccbStrent 		 * one specific to this host.  If none found, try for
110aa9b0ccbStrent 		 * a generic one.
111aa9b0ccbStrent 		 */
1127ada4fb7Sbostic 		(void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name);
113c4a0303eSkarels 		if (access(loginfile, R_OK|X_OK) != 0) {
1147ada4fb7Sbostic 			(void)strcpy(loginfile, _PATH_LOGIN);
115aa9b0ccbStrent 			if (access(loginfile, R_OK|X_OK)) {
116aa9b0ccbStrent 				fputs("access denied - no login file\n",
117aa9b0ccbStrent 				      stderr);
118aa9b0ccbStrent 				syslog(LOG_ERR,
119aa9b0ccbStrent 				       "access denied for %s - no %s\n",
1207ada4fb7Sbostic 				       name, _PATH_LOGIN);
121aa9b0ccbStrent 				exit(5);
122aa9b0ccbStrent 			}
123c4a0303eSkarels 		}
124aa9b0ccbStrent 
125aa9b0ccbStrent 		(void) fclose(fp);
126aa9b0ccbStrent 		return;
127aa9b0ccbStrent 	}
128aa9b0ccbStrent 	(void)fprintf(stderr, "SLIP access denied for %s\n", name);
129aa9b0ccbStrent 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
130aa9b0ccbStrent 	exit(4);
131aa9b0ccbStrent 	/* NOTREACHED */
132aa9b0ccbStrent }
133aa9b0ccbStrent 
134aa9b0ccbStrent char *
sigstr(s)135aa9b0ccbStrent sigstr(s)
136aa9b0ccbStrent 	int s;
137aa9b0ccbStrent {
138aa9b0ccbStrent 	static char buf[32];
139aa9b0ccbStrent 
140aa9b0ccbStrent 	switch (s) {
141aa9b0ccbStrent 	case SIGHUP:	return("HUP");
142aa9b0ccbStrent 	case SIGINT:	return("INT");
143aa9b0ccbStrent 	case SIGQUIT:	return("QUIT");
144aa9b0ccbStrent 	case SIGILL:	return("ILL");
145aa9b0ccbStrent 	case SIGTRAP:	return("TRAP");
146aa9b0ccbStrent 	case SIGIOT:	return("IOT");
147aa9b0ccbStrent 	case SIGEMT:	return("EMT");
148aa9b0ccbStrent 	case SIGFPE:	return("FPE");
149aa9b0ccbStrent 	case SIGKILL:	return("KILL");
150aa9b0ccbStrent 	case SIGBUS:	return("BUS");
151aa9b0ccbStrent 	case SIGSEGV:	return("SEGV");
152aa9b0ccbStrent 	case SIGSYS:	return("SYS");
153aa9b0ccbStrent 	case SIGPIPE:	return("PIPE");
154aa9b0ccbStrent 	case SIGALRM:	return("ALRM");
155aa9b0ccbStrent 	case SIGTERM:	return("TERM");
156aa9b0ccbStrent 	case SIGURG:	return("URG");
157aa9b0ccbStrent 	case SIGSTOP:	return("STOP");
158aa9b0ccbStrent 	case SIGTSTP:	return("TSTP");
159aa9b0ccbStrent 	case SIGCONT:	return("CONT");
160aa9b0ccbStrent 	case SIGCHLD:	return("CHLD");
161aa9b0ccbStrent 	case SIGTTIN:	return("TTIN");
162aa9b0ccbStrent 	case SIGTTOU:	return("TTOU");
163aa9b0ccbStrent 	case SIGIO:	return("IO");
164aa9b0ccbStrent 	case SIGXCPU:	return("XCPU");
165aa9b0ccbStrent 	case SIGXFSZ:	return("XFSZ");
166aa9b0ccbStrent 	case SIGVTALRM:	return("VTALRM");
167aa9b0ccbStrent 	case SIGPROF:	return("PROF");
168aa9b0ccbStrent 	case SIGWINCH:	return("WINCH");
169aa9b0ccbStrent #ifdef SIGLOST
170aa9b0ccbStrent 	case SIGLOST:	return("LOST");
171aa9b0ccbStrent #endif
172aa9b0ccbStrent 	case SIGUSR1:	return("USR1");
173aa9b0ccbStrent 	case SIGUSR2:	return("USR2");
174aa9b0ccbStrent 	}
175aa9b0ccbStrent 	(void)sprintf(buf, "sig %d", s);
176aa9b0ccbStrent 	return(buf);
177aa9b0ccbStrent }
178aa9b0ccbStrent 
17927d38c72Sbostic void
hup_handler(s)1805347ed73Ssam hup_handler(s)
1815347ed73Ssam 	int s;
182a18a0028Skarels {
183c4a0303eSkarels 	char logoutfile[MAXPATHLEN];
184c4a0303eSkarels 
185c4a0303eSkarels 	(void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname);
186c4a0303eSkarels 	if (access(logoutfile, R_OK|X_OK) != 0)
187c4a0303eSkarels 		(void)strcpy(logoutfile, _PATH_LOGOUT);
188aa9b0ccbStrent 	if (access(logoutfile, R_OK|X_OK) == 0) {
189c4a0303eSkarels 		char logincmd[2*MAXPATHLEN+32];
1905347ed73Ssam 
191aa9b0ccbStrent 		(void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed,
192aa9b0ccbStrent 			      loginargs);
193aa9b0ccbStrent 		(void) system(logincmd);
194aa9b0ccbStrent 	}
195aa9b0ccbStrent 	(void) close(0);
196aa9b0ccbStrent 	syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit,
197aa9b0ccbStrent 	       sigstr(s));
198a18a0028Skarels 	exit(1);
199aa9b0ccbStrent 	/* NOTREACHED */
200a18a0028Skarels }
201a14e21ddSsam 
main(argc,argv)202a14e21ddSsam main(argc, argv)
203a14e21ddSsam 	int argc;
204a14e21ddSsam 	char *argv[];
205a14e21ddSsam {
206a18a0028Skarels 	int fd, s, ldisc, odisc;
207aa9b0ccbStrent 	char *name;
208c4a0303eSkarels #ifdef POSIX
209a18a0028Skarels 	struct termios tios, otios;
210aa9b0ccbStrent #else
211aa9b0ccbStrent 	struct sgttyb tty, otty;
212aa9b0ccbStrent #endif
213aa9b0ccbStrent 	char logincmd[2*BUFSIZ+32];
214aa9b0ccbStrent 	extern uid_t getuid();
215a14e21ddSsam 
216aa9b0ccbStrent 	if ((name = strrchr(argv[0], '/')) == NULL)
217aa9b0ccbStrent 		name = argv[0];
218a14e21ddSsam 	s = getdtablesize();
219a14e21ddSsam 	for (fd = 3 ; fd < s ; fd++)
220aa9b0ccbStrent 		(void) close(fd);
221aa9b0ccbStrent 	openlog(name, LOG_PID, LOG_DAEMON);
222c4a0303eSkarels 	uid = getuid();
223aa9b0ccbStrent 	if (argc > 1) {
224a14e21ddSsam 		findid(argv[1]);
225aa9b0ccbStrent 
2265347ed73Ssam 		/*
2275347ed73Ssam 		 * Disassociate from current controlling terminal, if any,
2285347ed73Ssam 		 * and ensure that the slip line is our controlling terminal.
2295347ed73Ssam 		 */
230c4a0303eSkarels #ifdef POSIX
231c4a0303eSkarels 		if (fork() > 0)
232c4a0303eSkarels 			exit(0);
233c4a0303eSkarels 		if (setsid() != 0)
234c4a0303eSkarels 			perror("setsid");
235aa9b0ccbStrent #else
236a14e21ddSsam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
237aa9b0ccbStrent 			extern char *ttyname();
238aa9b0ccbStrent 
239aa9b0ccbStrent 			(void) ioctl(fd, TIOCNOTTY, (caddr_t)0);
240a14e21ddSsam 			(void) close(fd);
2415347ed73Ssam 			/* open slip tty again to acquire as controlling tty? */
242a18a0028Skarels 			fd = open(ttyname(0), O_RDWR, 0);
243a18a0028Skarels 			if (fd >= 0)
244a18a0028Skarels 				(void) close(fd);
245a18a0028Skarels 		}
2465347ed73Ssam 		(void) setpgrp(0, getpid());
2475347ed73Ssam #endif
248c4a0303eSkarels 		if (argc > 2) {
249c4a0303eSkarels 			if ((fd = open(argv[2], O_RDWR)) == -1) {
250c4a0303eSkarels 				perror(argv[2]);
251c4a0303eSkarels 				exit(2);
252c4a0303eSkarels 			}
253c4a0303eSkarels 			(void) dup2(fd, 0);
254c4a0303eSkarels 			if (fd > 2)
255c4a0303eSkarels 				close(fd);
256c4a0303eSkarels 		}
257c4a0303eSkarels #ifdef TIOCSCTTY
258c4a0303eSkarels 		if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0)
259c4a0303eSkarels 			perror("ioctl (TIOCSCTTY)");
260c4a0303eSkarels #endif
261aa9b0ccbStrent 	} else {
262c4a0303eSkarels 		extern char *getlogin();
263aa9b0ccbStrent 
264c4a0303eSkarels 		if ((name = getlogin()) == NULL) {
265aa9b0ccbStrent 			(void) fprintf(stderr, "access denied - no username\n");
266c4a0303eSkarels 			syslog(LOG_ERR, "access denied - getlogin returned 0\n");
267aa9b0ccbStrent 			exit(1);
268aa9b0ccbStrent 		}
269aa9b0ccbStrent 		findid(name);
270aa9b0ccbStrent 	}
271aa9b0ccbStrent 	(void) fchmod(0, 0600);
272aa9b0ccbStrent 	(void) fprintf(stderr, "starting slip login for %s\n", loginname);
273c4a0303eSkarels #ifdef POSIX
274a14e21ddSsam 	/* set up the line parameters */
275c4a0303eSkarels 	if (tcgetattr(0, &tios) < 0) {
276c4a0303eSkarels 		syslog(LOG_ERR, "tcgetattr: %m");
277a14e21ddSsam 		exit(1);
278a14e21ddSsam 	}
279a18a0028Skarels 	otios = tios;
280c4a0303eSkarels 	cfmakeraw(&tios);
281c4a0303eSkarels 	tios.c_iflag &= ~IMAXBEL;
282c4a0303eSkarels 	if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
283c4a0303eSkarels 		syslog(LOG_ERR, "tcsetattr: %m");
284a18a0028Skarels 		exit(1);
285a18a0028Skarels 	}
286c4a0303eSkarels 	speed = cfgetispeed(&tios);
287aa9b0ccbStrent #else
288aa9b0ccbStrent 	/* set up the line parameters */
289aa9b0ccbStrent 	if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) {
290aa9b0ccbStrent 		syslog(LOG_ERR, "ioctl (TIOCGETP): %m");
291aa9b0ccbStrent 		exit(1);
292aa9b0ccbStrent 	}
293aa9b0ccbStrent 	otty = tty;
294aa9b0ccbStrent 	speed = tty.sg_ispeed;
295aa9b0ccbStrent 	tty.sg_flags = RAW | ANYP;
296aa9b0ccbStrent 	if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) {
297aa9b0ccbStrent 		syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
298aa9b0ccbStrent 		exit(1);
299aa9b0ccbStrent 	}
300aa9b0ccbStrent #endif
301a18a0028Skarels 	/* find out what ldisc we started with */
302a18a0028Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
303a18a0028Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
304a14e21ddSsam 		exit(1);
305a14e21ddSsam 	}
306ca1574aaSsam 	ldisc = SLIPDISC;
307ca1574aaSsam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
3085347ed73Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
309a14e21ddSsam 		exit(1);
310a14e21ddSsam 	}
311a14e21ddSsam 	/* find out what unit number we were assigned */
312c4a0303eSkarels 	if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) {
313f0479b09Skarels 		syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m");
314a14e21ddSsam 		exit(1);
315a14e21ddSsam 	}
316aa9b0ccbStrent 	(void) signal(SIGHUP, hup_handler);
317aa9b0ccbStrent 	(void) signal(SIGTERM, hup_handler);
318aa9b0ccbStrent 
319aa9b0ccbStrent 	syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname);
320aa9b0ccbStrent 	(void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed,
321aa9b0ccbStrent 		      loginargs);
322aa9b0ccbStrent 	/*
323aa9b0ccbStrent 	 * aim stdout and errout at /dev/null so logincmd output won't
324aa9b0ccbStrent 	 * babble into the slip tty line.
325aa9b0ccbStrent 	 */
326aa9b0ccbStrent 	(void) close(1);
32727d38c72Sbostic 	if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) {
328aa9b0ccbStrent 		if (fd < 0) {
329aa9b0ccbStrent 			syslog(LOG_ERR, "open /dev/null: %m");
330a14e21ddSsam 			exit(1);
331a14e21ddSsam 		}
332aa9b0ccbStrent 		(void) dup2(fd, 1);
333aa9b0ccbStrent 		(void) close(fd);
334a14e21ddSsam 	}
335aa9b0ccbStrent 	(void) dup2(1, 2);
336c4a0303eSkarels 
337c4a0303eSkarels 	/*
338c4a0303eSkarels 	 * Run login and logout scripts as root (real and effective);
339c4a0303eSkarels 	 * current route(8) is setuid root, and checks the real uid
340c4a0303eSkarels 	 * to see whether changes are allowed (or just "route get").
341c4a0303eSkarels 	 */
342c4a0303eSkarels 	(void) setuid(0);
343aa9b0ccbStrent 	if (s = system(logincmd)) {
344aa9b0ccbStrent 		syslog(LOG_ERR, "%s login failed: exit status %d from %s",
345aa9b0ccbStrent 		       loginname, s, loginfile);
346aa9b0ccbStrent 		(void) ioctl(0, TIOCSETD, (caddr_t)&odisc);
347aa9b0ccbStrent 		exit(6);
348a14e21ddSsam 	}
349a14e21ddSsam 
350a14e21ddSsam 	/* twiddle thumbs until we get a signal */
351aa9b0ccbStrent 	while (1)
352a14e21ddSsam 		sigpause(0);
353a14e21ddSsam 
354aa9b0ccbStrent 	/* NOTREACHED */
355a14e21ddSsam }
356