138272Ssam #ifndef lint
2*40016Ssam static char sccsid[] = "@(#)sliplogin.c	1.4 (Berkeley) 02/06/90";
3*40016Ssam /* from static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18"; */
438272Ssam #endif
538272Ssam 
638272Ssam /*
738272Ssam  * sliplogin.c
838373Skarels  * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!]
938272Ssam  *
1038272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
1138272Ssam  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
1238272Ssam  * initializes the network interface, and pauses forever waiting for hangup.
1338272Ssam  *
1438272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
1538272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
1638272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
1738272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
1838272Ssam  * - a simple slattach-like program used to test the STREAMS SLIP code.
1938272Ssam  *
2038272Ssam  * There are three basic forms of usage:
2138272Ssam  *
2238272Ssam  * "sliplogin"
2338272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
2438272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
2538272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
2638272Ssam  * as specified in the file.
2738272Ssam  *
2838272Ssam  * "sliplogin IPhost1 </dev/ttyb"
2938272Ssam  * Invoked by root with a username, the name is looked up in the
3038272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
3138272Ssam  *
3238272Ssam  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
3338272Ssam  * Finally, if invoked with a remote addr, local addr, and optionally
3438272Ssam  * a net mask, the line on fd0 is setup as specified if the user is root.
3538272Ssam  *
3638272Ssam  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
3738272Ssam  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
3838272Ssam  */
3938272Ssam 
4038272Ssam #include <sys/types.h>
4138272Ssam #include <sys/socket.h>
4238272Ssam #include <sys/termios.h>
4338372Ssam #include <sys/ioctl.h>
4438272Ssam #include <sys/file.h>
4538272Ssam #include <sys/syslog.h>
4638272Ssam 
4738272Ssam #include <netinet/in.h>
4838272Ssam #include <net/if.h>
4938373Skarels #include <net/if_slvar.h>	/* XXX */
5038272Ssam 
5138272Ssam #include <stdio.h>
5238272Ssam #include <errno.h>
5338272Ssam #include <ctype.h>
5438272Ssam #include <netdb.h>
5538272Ssam 
5638272Ssam #include <signal.h>
5738272Ssam #include <strings.h>
5838272Ssam #include <pwd.h>
5938272Ssam #include <ttyent.h>
6038272Ssam 
6138372Ssam #define	SLIPIFNAME	"sl"
6238372Ssam 
6338372Ssam #define ADDR	1
6438372Ssam #define MASK	2
6538372Ssam 
66*40016Ssam #define	DCD_CHECK_INTERVAL 0	/* if > 0, time between automatic DCD checks */
6738272Ssam #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
6838272Ssam 
6938272Ssam int gotalarm = 0;
7038272Ssam int timeleft = DCD_CHECK_INTERVAL;
7138272Ssam 
7238272Ssam #if	defined(SIGDCD) && SIGDCD > 0
7338272Ssam void
7438272Ssam dcd_handler()
7538272Ssam {
7638272Ssam #if	DCD_SETTLING_TIME > 0
7738272Ssam 	timeleft = alarm(DCD_SETTLING_TIME);
7838272Ssam #else
7938272Ssam 	gotalarm = 1;
8038272Ssam #endif	/* DCD_SETTLING_TIME */
8138272Ssam }
8238272Ssam #endif
8338272Ssam 
84*40016Ssam #if DCD_CHECK_INTERVAL > 0
85*40016Ssam void
86*40016Ssam alarm_handler()
87*40016Ssam {
88*40016Ssam #ifdef SIGDCD
89*40016Ssam 	if (timeleft > DCD_SETTLING_TIME)
90*40016Ssam 		(void) alarm(timeleft-DCD_SETTLING_TIME);
91*40016Ssam 	else
92*40016Ssam #endif /* SIGDCD */
93*40016Ssam 		(void) alarm(DCD_CHECK_INTERVAL);
94*40016Ssam 	gotalarm = 1;
95*40016Ssam 	timeleft = 0;
96*40016Ssam }
97*40016Ssam 
9838272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
9938272Ssam 
10038272Ssam int
10138272Ssam lowdcd(fd)
10238272Ssam 	int fd;
10338272Ssam {
10438272Ssam 	int mbits;
10538272Ssam 
10638272Ssam 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
10738272Ssam 		return 1;	/* port is dead, we die */
10838272Ssam 	return !(mbits & TIOCM_CAR);
10938272Ssam }
110*40016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */
11138272Ssam 
11238272Ssam char	*Accessfile = "/etc/hosts.slip";
11338272Ssam 
11438272Ssam extern char *malloc(), *ttyname();
11538272Ssam extern struct passwd *getpwuid();
11638272Ssam 
11738272Ssam char	*dstaddr, *localaddr, *netmask;
11838373Skarels int	slip_mode, unit;
11938272Ssam 
12038373Skarels struct slip_modes {
12138373Skarels 	char	*sm_name;
12238373Skarels 	int	sm_value;
12338373Skarels }	 modes[] = {
12438373Skarels 	"normal",	0,		/* slip "standard" ala Rick Adams */
12538373Skarels 	"compress",	SC_COMPRESS,	/* Van Jacobsen's tcp header comp. */
12638373Skarels 	"noicmp",	SC_NOICMP,	/* Sam's(?) ICMP suppression */
12738373Skarels } ;
12838373Skarels 
12938373Skarels void
130*40016Ssam hup_handler(s)
131*40016Ssam 	int s;
13238373Skarels {
133*40016Ssam 
134*40016Ssam 	syslog(LOG_INFO,
135*40016Ssam 	    "%s%d: connection closed: process aborted, sig %d, remote %s\n",
136*40016Ssam 	    SLIPIFNAME, unit, s, dstaddr);
137*40016Ssam 	if (close(0) < 0)
138*40016Ssam 		syslog(LOG_ERR, "(hup) close: %m");
139*40016Ssam 	else
140*40016Ssam 		syslog(LOG_INFO, "(hup) close completed");
14138373Skarels 	exit(1) ;
14238373Skarels }
14338373Skarels 
14438272Ssam main(argc, argv)
14538272Ssam 	int argc;
14638272Ssam 	char *argv[];
14738272Ssam {
14838373Skarels 	int	fd, s, ldisc, odisc;
14938373Skarels 	struct	termios tios, otios;
15038272Ssam 	struct	ifreq ifr;
15138272Ssam 
15238272Ssam 	s = getdtablesize();
15338272Ssam 	for (fd = 3 ; fd < s ; fd++)
15438272Ssam 		close(fd);
15538272Ssam 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
15638272Ssam 	if (getuid() == 0) {
15738272Ssam 		if (argc <= 1) {
15838272Ssam 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
15938272Ssam 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
16038272Ssam 					argv[0]);
16138272Ssam 			exit(1);
16238272Ssam 		} else if (argc == 2) {
16338272Ssam 			findid(argv[1]);
16438272Ssam 			fprintf(stderr, "local %s remote %s mask %s\n",
16538272Ssam 				localaddr, dstaddr, netmask);
16638272Ssam 		} if (argc > 2) {
16738272Ssam 			if (argc < 3 || argc > 4) {
16838272Ssam 				fprintf(stderr,
16938272Ssam 					"Usage: %s dstaddr localaddr [mask]\n",
17038272Ssam 					argv[0]);
17138272Ssam 				exit(1);
17238272Ssam 			}
17338272Ssam 			dstaddr = argv[1];
17438272Ssam 			localaddr = argv[2];
17538272Ssam 			if (argc == 4)
17638272Ssam 				netmask = argv[3];
17738272Ssam 			else
17838272Ssam 				netmask = "default";
17938272Ssam 		}
180*40016Ssam 		/*
181*40016Ssam 		 * Disassociate from current controlling terminal, if any,
182*40016Ssam 		 * and ensure that the slip line is our controlling terminal.
183*40016Ssam 		 */
184*40016Ssam #if !defined(BSD) || BSD < 198810
185*40016Ssam 		if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
186*40016Ssam 			(void) ioctl(fd, TIOCNOTTY, 0);
187*40016Ssam 			(void) close(fd);
188*40016Ssam 			/* open slip tty again to acquire as controlling tty? */
189*40016Ssam 			fd = open(ttyname(0), O_RDWR, 0);
190*40016Ssam 			if (fd >= 0)
191*40016Ssam 				(void) close(fd);
192*40016Ssam 		}
193*40016Ssam 		(void) setpgrp(0, getpid());
194*40016Ssam #else
195*40016Ssam 		(void) setsid();
196*40016Ssam 		(void) ioctl(0, TIOCSCTTY, 0); /* not sure this will work */
197*40016Ssam #endif
19838272Ssam 	} else
19938272Ssam 		findid((char *)0);
20038272Ssam 	fchmod(0, 0600);
20138272Ssam 	/* set up the line parameters */
202*40016Ssam 	if (ioctl(0, TIOCGETA, (caddr_t)&tios) < 0) {
203*40016Ssam 		syslog(LOG_ERR, "ioctl (TIOCGETA): %m");
20438272Ssam 		exit(1);
20538272Ssam 	}
206*40016Ssam 	otios = tios;
207*40016Ssam 	tios.c_cflag = CS8|CREAD|HUPCL;
20838272Ssam 	tios.c_iflag = IGNBRK;
20938372Ssam 	tios.c_oflag = tios.c_lflag = 0;
210*40016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&tios) < 0) {
211*40016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (1): %m");
21238272Ssam 		exit(1);
21338272Ssam 	}
21438373Skarels 	/* find out what ldisc we started with */
21538373Skarels 	if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
21638373Skarels 		syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
21738373Skarels 		exit(1);
21838373Skarels 	}
21938372Ssam 	ldisc = SLIPDISC;
22038372Ssam 	if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
221*40016Ssam 		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
22238272Ssam 		exit(1);
22338272Ssam 	}
22438272Ssam 	/* find out what unit number we were assigned */
22538372Ssam 	if (ioctl(0, TIOCGETD, (caddr_t)&unit) < 0) {
22638373Skarels 		syslog(LOG_ERR, "ioctl (TIOCGETD) (2): %m");
22738272Ssam 		exit(1);
22838272Ssam 	}
229*40016Ssam 	syslog(LOG_INFO, "attaching %s%d: local %s remote %s mask %s\n",
23038372Ssam 		SLIPIFNAME, unit, localaddr, dstaddr, netmask);
23138372Ssam #ifdef notdef
23238272Ssam 	/* set the local and remote interface addresses */
23338272Ssam 	s = socket(AF_INET, SOCK_DGRAM, 0);
23438272Ssam 	if (getuid() != 0 || argc == 4) {
23538272Ssam 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
23638372Ssam 		in_getaddr(netmask, &ifr.ifr_addr, MASK);
23738272Ssam 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
23838272Ssam 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
23938272Ssam 			exit(1);
24038272Ssam 		}
24138272Ssam 	}
24238272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
24338372Ssam 	in_getaddr(dstaddr, &ifr.ifr_addr, ADDR);
24438272Ssam 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
24538272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
24638272Ssam 		exit(1);
24738272Ssam 	}
24838272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
24938372Ssam 	in_getaddr(localaddr, &ifr.ifr_addr, ADDR);
25038272Ssam 	/* this has the side-effect of marking the interface up */
25138272Ssam 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
25238272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
25338272Ssam 		exit(1);
25438272Ssam 	}
25538372Ssam #else
25638372Ssam 	/* XXX -- give up for now and just invoke ifconfig XXX */
25738372Ssam 	{ char cmd[256];
25838372Ssam 	  sprintf(cmd, "/sbin/ifconfig %s%d inet %s %s netmask %s",
25938372Ssam 	      SLIPIFNAME, unit, localaddr, dstaddr, netmask);
26038372Ssam 	  system(cmd);
26138372Ssam 	}
262*40016Ssam #endif
26338373Skarels 	if (ioctl(0, SLIOCSFLAGS, (caddr_t)&slip_mode) < 0) {
26438373Skarels 		syslog(LOG_ERR, "ioctl (SLIOCSFLAGS): %m");
26538373Skarels 		exit(1);
26638373Skarels 	}
26738272Ssam 
26838272Ssam 	/* set up signal handlers */
26938272Ssam #if	defined(SIGDCD) && SIGDCD > 0
27038272Ssam 	(void) signal(SIGDCD, dcd_handler);
27138272Ssam #endif
27238272Ssam 	(void) sigblock(sigmask(SIGALRM));
27338373Skarels 	(void) signal(SIGHUP, hup_handler);
27438373Skarels 	(void) signal(SIGTERM, hup_handler);
27538272Ssam 
276*40016Ssam #if DCD_CHECK_INTERVAL > 0
27738272Ssam 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
278*40016Ssam 	(void) signal(SIGALRM, alarm_handler);
27938373Skarels 	(void) alarm(DCD_CHECK_INTERVAL);
280*40016Ssam #endif
28138272Ssam 
28238272Ssam 	/* twiddle thumbs until we get a signal */
28338272Ssam 	while (1) {
28438272Ssam 		sigpause(0);
285*40016Ssam #if DCD_CHECK_INTERVAL > 0
28638272Ssam 		(void) sigblock(sigmask(SIGALRM));
28738272Ssam 		if (gotalarm && lowdcd(0))
28838272Ssam 			break;
28938272Ssam 		gotalarm = 0;
290*40016Ssam #endif /* DCD_CHECK_INTERVAL > 0 */
29138272Ssam 	}
29238272Ssam 
293*40016Ssam #ifdef notdef
29438373Skarels 	if (lowdcd(0))
29538373Skarels 		syslog(LOG_NOTICE,
29638373Skarels 			"connection closed: loss of carrier %s%d: remote %s\n",
29738373Skarels 			SLIPIFNAME, unit, dstaddr);
298*40016Ssam #endif
29938373Skarels 
30038373Skarels 	if (ioctl(0, TIOCSETD, (caddr_t)&odisc) < 0) {
30138373Skarels 		syslog(LOG_ERR, "ioctl(TIOCSETD) (2): %m");
30238373Skarels 		exit(1);
30338373Skarels 	}
304*40016Ssam 	if (ioctl(0, TIOCSETA, (caddr_t)&otios) < 0) {
305*40016Ssam 		syslog(LOG_ERR, "ioctl (TIOCSETA) (2): %m");
30638373Skarels 		exit(1);
30738373Skarels 	}
308*40016Ssam 	if (close(0) < 0) {
309*40016Ssam 		syslog(LOG_ERR, "close: %m");
310*40016Ssam 		exit(1);
311*40016Ssam 	}
31238272Ssam 	exit(0);
31338272Ssam }
31438272Ssam 
31538272Ssam findid(name)
31638272Ssam 	char *name;
31738272Ssam {
31838272Ssam 	char buf[BUFSIZ];
31938272Ssam 	static char mode[16];
32038272Ssam 	static char laddr[16];
32138272Ssam 	static char raddr[16];
32238272Ssam 	static char mask[16];
32338272Ssam 	char user[16];
32438272Ssam 	FILE *fp;
32538272Ssam 	struct passwd *pw;
32638272Ssam 	int n;
32738272Ssam 
32838272Ssam 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
32938272Ssam 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
33038272Ssam 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
33138272Ssam 		exit(1);
33238272Ssam 	} else if (name == NULL)
33338272Ssam 		name = pw->pw_name;
33438272Ssam 	if ((fp = fopen(Accessfile, "r")) == NULL) {
33538272Ssam 		perror(Accessfile);
33638272Ssam 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
33738272Ssam 		exit(3);
33838272Ssam 	}
33938272Ssam 	while (fgets(buf, sizeof(buf) - 1, fp)) {
34038272Ssam 		if (ferror(fp))
34138272Ssam 			break;
34238272Ssam 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
34338272Ssam 			user, mode, laddr, raddr, mask);
34438272Ssam 		if (user[0] == '#' || n != 5)
34538272Ssam 			continue;
34638272Ssam 		if (strcmp(user, name) == 0) {
34738373Skarels 			char *p,*q; int val, i, domore;
34838373Skarels 
34938373Skarels 			p = q = mode;	val = 0;
35038373Skarels 		loop:
35138373Skarels 			while (isalnum(*p)) p++;
35238373Skarels 			if(ispunct(*p) || *p == '\0') {
35338373Skarels 				if(ispunct(*p)) domore = 1; else domore = 0;
35438373Skarels 				*p++ = '\0' ;
35538373Skarels 				for (i = 0; i <
35638373Skarels 					sizeof(modes)/sizeof(struct slip_modes)
35738373Skarels 					 ; i++) {
35838373Skarels 					if (strcmp(modes[i].sm_name, q) == 0) {
35938373Skarels 						val |= modes[i].sm_value ;
36038373Skarels 						break;
36138373Skarels 					} ;
36238373Skarels }
36338373Skarels 				q = p;
36438373Skarels 				if(domore)goto loop;
36538373Skarels 			}
36638373Skarels 
36738373Skarels 			slip_mode = val ;
36838272Ssam 			localaddr = laddr;
36938272Ssam 			dstaddr = raddr;
37038272Ssam 			netmask = mask;
37138272Ssam 			fclose(fp);
37238272Ssam 			return 0;
37338272Ssam 		}
37438272Ssam 		if (feof(fp))
37538272Ssam 			break;
37638272Ssam 	}
37738272Ssam 	fputs("SLIP access denied\n", stderr);
37838272Ssam 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
37938272Ssam 	exit(4);
38038272Ssam }
38138272Ssam 
38238372Ssam in_getaddr(s, saddr, which)
38338272Ssam 	char *s;
38438272Ssam 	struct sockaddr *saddr;
38538372Ssam 	int which;
38638272Ssam {
38738272Ssam 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
38838272Ssam 	struct hostent *hp;
38938272Ssam 	struct netent *np;
39038272Ssam 	int val;
39138272Ssam 	extern struct in_addr inet_makeaddr();
39238272Ssam 
39338272Ssam 	bzero((caddr_t)saddr, sizeof *saddr);
39438372Ssam 	if (which == ADDR) {
39538372Ssam 		sin->sin_len = sizeof (*sin);
39638372Ssam 		sin->sin_family = AF_INET;
39738372Ssam 	} else
39838372Ssam 		sin->sin_len = 8;
39938272Ssam 	val = inet_addr(s);
40038272Ssam 	if (val != -1) {
40138272Ssam 		sin->sin_addr.s_addr = val;
40238272Ssam 		return;
40338272Ssam 	}
40438272Ssam 	hp = gethostbyname(s);
40538272Ssam 	if (hp) {
40638272Ssam 		sin->sin_family = hp->h_addrtype;
40738272Ssam 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
40838272Ssam 		return;
40938272Ssam 	}
41038272Ssam 	np = getnetbyname(s);
41138272Ssam 	if (np) {
41238272Ssam 		sin->sin_family = np->n_addrtype;
41338272Ssam 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
41438272Ssam 		return;
41538272Ssam 	}
41638272Ssam 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
41738272Ssam 	syslog(LOG_ERR, "%s: bad value\n", s);
41838272Ssam 	exit(1);
41938272Ssam }
420