1*38272Ssam #ifndef lint
2*38272Ssam static char *sccsid = "@(#)sliplogin.c	1.3	MS/ACF	89/04/18";
3*38272Ssam #endif
4*38272Ssam 
5*38272Ssam /*
6*38272Ssam  * sliplogin.c
7*38272Ssam  *
8*38272Ssam  * This program initializes its own tty port to be an async TCP/IP interface.
9*38272Ssam  * It merely sets up the SLIP module all by its lonesome on the STREAMS stack,
10*38272Ssam  * initializes the network interface, and pauses forever waiting for hangup.
11*38272Ssam  *
12*38272Ssam  * It is a remote descendant of several similar programs with incestuous ties:
13*38272Ssam  * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL.
14*38272Ssam  * - slattach, probably by Rick Adams but touched by countless hordes.
15*38272Ssam  * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it.
16*38272Ssam  * - a simple slattach-like program used to test the STREAMS SLIP code.
17*38272Ssam  *
18*38272Ssam  * There are three basic forms of usage:
19*38272Ssam  *
20*38272Ssam  * "sliplogin"
21*38272Ssam  * Invoked simply as "sliplogin" and a realuid != 0, the program looks up
22*38272Ssam  * the uid in /etc/passwd, and then the username in the file /etc/hosts.slip.
23*38272Ssam  * If and entry is found, the line on fd0 is configured for SLIP operation
24*38272Ssam  * as specified in the file.
25*38272Ssam  *
26*38272Ssam  * "sliplogin IPhost1 </dev/ttyb"
27*38272Ssam  * Invoked by root with a username, the name is looked up in the
28*38272Ssam  * /etc/hosts.slip file and if found fd0 is configured as in case 1.
29*38272Ssam  *
30*38272Ssam  * "sliplogin 192.100.1.1 192.100.1.2 255.255.255.0 < /dev/ttyb"
31*38272Ssam  * Finally, if invoked with a remote addr, local addr, and optionally
32*38272Ssam  * a net mask, the line on fd0 is setup as specified if the user is root.
33*38272Ssam  *
34*38272Ssam  * Doug Kingston 8810??		- logging + first pass at adding I_STR ioctl's
35*38272Ssam  * Rayan Zachariassen 881011	- version for SunOS STREAMS SLIP
36*38272Ssam  */
37*38272Ssam 
38*38272Ssam #include <sys/types.h>
39*38272Ssam #include <sys/socket.h>
40*38272Ssam #include <sys/stropts.h>
41*38272Ssam #include <sys/termios.h>
42*38272Ssam #include <sys/ttold.h>
43*38272Ssam #include <sys/sockio.h>
44*38272Ssam #include <sys/file.h>
45*38272Ssam #include <sys/syslog.h>
46*38272Ssam 
47*38272Ssam #include <sys/slip.h>
48*38272Ssam 
49*38272Ssam #include <netinet/in.h>
50*38272Ssam #include <net/if.h>
51*38272Ssam 
52*38272Ssam #include <stdio.h>
53*38272Ssam #include <errno.h>
54*38272Ssam #include <ctype.h>
55*38272Ssam #include <netdb.h>
56*38272Ssam 
57*38272Ssam #include <signal.h>
58*38272Ssam #include <strings.h>
59*38272Ssam #include <pwd.h>
60*38272Ssam #ifdef BSD >= 43
61*38272Ssam #include <ttyent.h>
62*38272Ssam #endif
63*38272Ssam 
64*38272Ssam #define	DCD_CHECK_INTERVAL 0	/* if > 0, time between automatic DCD checks */
65*38272Ssam #define	DCD_SETTLING_TIME 1	/* time between DCD change and status check */
66*38272Ssam 
67*38272Ssam int gotalarm = 0;
68*38272Ssam int timeleft = DCD_CHECK_INTERVAL;
69*38272Ssam 
70*38272Ssam void
71*38272Ssam alarm_handler()
72*38272Ssam {
73*38272Ssam 	if (timeleft > DCD_SETTLING_TIME)
74*38272Ssam 		(void) alarm(timeleft-DCD_SETTLING_TIME);
75*38272Ssam 	else
76*38272Ssam 		(void) alarm(DCD_CHECK_INTERVAL);
77*38272Ssam 	gotalarm = 1;
78*38272Ssam 	timeleft = 0;
79*38272Ssam }
80*38272Ssam 
81*38272Ssam #if	defined(SIGDCD) && SIGDCD > 0
82*38272Ssam void
83*38272Ssam dcd_handler()
84*38272Ssam {
85*38272Ssam #if	DCD_SETTLING_TIME > 0
86*38272Ssam 	timeleft = alarm(DCD_SETTLING_TIME);
87*38272Ssam #else
88*38272Ssam 	gotalarm = 1;
89*38272Ssam #endif	/* DCD_SETTLING_TIME */
90*38272Ssam }
91*38272Ssam #endif
92*38272Ssam 
93*38272Ssam /* Use TIOCMGET to test if DCD is low on the port of the passed descriptor */
94*38272Ssam 
95*38272Ssam int
96*38272Ssam lowdcd(fd)
97*38272Ssam 	int fd;
98*38272Ssam {
99*38272Ssam 	int mbits;
100*38272Ssam 
101*38272Ssam 	if (ioctl(fd, TIOCMGET, (caddr_t)&mbits) < 0)
102*38272Ssam 		return 1;	/* port is dead, we die */
103*38272Ssam 	return !(mbits & TIOCM_CAR);
104*38272Ssam }
105*38272Ssam 
106*38272Ssam char	*Accessfile = "/etc/hosts.slip";
107*38272Ssam 
108*38272Ssam extern char *malloc(), *ttyname();
109*38272Ssam extern struct passwd *getpwuid();
110*38272Ssam 
111*38272Ssam char	*dstaddr, *localaddr, *netmask;
112*38272Ssam 
113*38272Ssam main(argc, argv)
114*38272Ssam 	int argc;
115*38272Ssam 	char *argv[];
116*38272Ssam {
117*38272Ssam 	int	fd, s, unit;
118*38272Ssam 	struct	termios tios;
119*38272Ssam 	struct	ifreq ifr;
120*38272Ssam 
121*38272Ssam 	s = getdtablesize();
122*38272Ssam 	for (fd = 3 ; fd < s ; fd++)
123*38272Ssam 		close(fd);
124*38272Ssam 
125*38272Ssam 	openlog("sliplogin", LOG_PID, LOG_DAEMON);
126*38272Ssam 
127*38272Ssam 	if (getuid() == 0) {
128*38272Ssam 		if (argc <= 1) {
129*38272Ssam 			fprintf(stderr, "Usage: %s loginname\n", argv[0]);
130*38272Ssam 			fprintf(stderr, "   or: %s dstaddr localaddr [mask]\n",
131*38272Ssam 					argv[0]);
132*38272Ssam 			exit(1);
133*38272Ssam 		} else if (argc == 2) {
134*38272Ssam 			findid(argv[1]);
135*38272Ssam 			fprintf(stderr, "local %s remote %s mask %s\n",
136*38272Ssam 				localaddr, dstaddr, netmask);
137*38272Ssam 		} if (argc > 2) {
138*38272Ssam 			if (argc < 3 || argc > 4) {
139*38272Ssam 				fprintf(stderr,
140*38272Ssam 					"Usage: %s dstaddr localaddr [mask]\n",
141*38272Ssam 					argv[0]);
142*38272Ssam 				exit(1);
143*38272Ssam 			}
144*38272Ssam 			dstaddr = argv[1];
145*38272Ssam 			localaddr = argv[2];
146*38272Ssam 			if (argc == 4)
147*38272Ssam 				netmask = argv[3];
148*38272Ssam 			else
149*38272Ssam 				netmask = "default";
150*38272Ssam 		}
151*38272Ssam 	} else
152*38272Ssam 		findid((char *)0);
153*38272Ssam 
154*38272Ssam 	/* ensure that the slip line is our controlling terminal */
155*38272Ssam 	if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
156*38272Ssam 		(void) ioctl(fd, TIOCNOTTY, 0);
157*38272Ssam 		(void) close(fd);
158*38272Ssam 		fd = open(ttyname(0), O_RDWR, 0);
159*38272Ssam 		if (fd >= 0)
160*38272Ssam 			(void) close(fd);
161*38272Ssam 		(void) setpgrp(0, getpid());
162*38272Ssam 	}
163*38272Ssam 
164*38272Ssam 	fchmod(0, 0600);
165*38272Ssam 
166*38272Ssam 	/* pop all streams modules */
167*38272Ssam 	while (ioctl(0, I_POP, 0) == 0)
168*38272Ssam 		continue;
169*38272Ssam 
170*38272Ssam 	/* set up the line parameters */
171*38272Ssam 	if (ioctl(0, TCGETS, (caddr_t)&tios) < 0) {
172*38272Ssam 		syslog(LOG_ERR, "ioctl (TCGETS): %m");
173*38272Ssam 		exit(1);
174*38272Ssam 	}
175*38272Ssam 	tios.c_cflag &= 0xf;	/* only save the speed */
176*38272Ssam 	tios.c_cflag |= CS8|CREAD|HUPCL;
177*38272Ssam 	tios.c_iflag = IGNBRK;
178*38272Ssam 	if (ioctl(0, TCSETS, (caddr_t)&tios) < 0) {
179*38272Ssam 		syslog(LOG_ERR, "ioctl (TCSETS): %m");
180*38272Ssam 		exit(1);
181*38272Ssam 	}
182*38272Ssam 
183*38272Ssam 	/* push the SLIP module */
184*38272Ssam 	if (ioctl(0, I_PUSH, "slip") < 0) {
185*38272Ssam 		syslog(LOG_ERR, "ioctl (I_PUSH): %m");
186*38272Ssam 		exit(1);
187*38272Ssam 	}
188*38272Ssam 
189*38272Ssam 	/* find out what unit number we were assigned */
190*38272Ssam 	if (ioctl(0, SLIOGUNIT, (caddr_t)&unit) < 0) {
191*38272Ssam 		syslog(LOG_ERR, "ioctl (SLIOGUNIT): %m");
192*38272Ssam 		exit(1);
193*38272Ssam 	}
194*38272Ssam 
195*38272Ssam 	syslog(LOG_NOTICE, "attaching slip%d: local %s remote %s mask %s\n",
196*38272Ssam 		unit, localaddr, dstaddr, netmask);
197*38272Ssam 
198*38272Ssam 	/* set the local and remote interface addresses */
199*38272Ssam 	s = socket(AF_INET, SOCK_DGRAM, 0);
200*38272Ssam 
201*38272Ssam 	if (getuid() != 0 || argc == 4) {
202*38272Ssam 		(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
203*38272Ssam 		in_getaddr(netmask, &ifr.ifr_addr);
204*38272Ssam 		if (ioctl(s, SIOCSIFNETMASK, (caddr_t)&ifr) < 0) {
205*38272Ssam 			syslog(LOG_ERR, "ioctl (SIOCSIFNETMASK): %m");
206*38272Ssam 			exit(1);
207*38272Ssam 		}
208*38272Ssam 	}
209*38272Ssam 
210*38272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
211*38272Ssam 	in_getaddr(dstaddr, &ifr.ifr_addr);
212*38272Ssam 	if (ioctl(s, SIOCSIFDSTADDR, (caddr_t)&ifr) < 0) {
213*38272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFDSTADDR): %m");
214*38272Ssam 		exit(1);
215*38272Ssam 	}
216*38272Ssam 
217*38272Ssam 	(void) sprintf(ifr.ifr_name, "%s%d", SLIPIFNAME, unit);
218*38272Ssam 	in_getaddr(localaddr, &ifr.ifr_addr);
219*38272Ssam 	/* this has the side-effect of marking the interface up */
220*38272Ssam 	if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) {
221*38272Ssam 		syslog(LOG_ERR, "ioctl (SIOCSIFADDR): %m");
222*38272Ssam 		exit(1);
223*38272Ssam 	}
224*38272Ssam 
225*38272Ssam 	/* set up signal handlers */
226*38272Ssam #if	defined(SIGDCD) && SIGDCD > 0
227*38272Ssam 	(void) signal(SIGDCD, dcd_handler);
228*38272Ssam #endif
229*38272Ssam 	(void) sigblock(sigmask(SIGALRM));
230*38272Ssam 	(void) signal(SIGALRM, alarm_handler);
231*38272Ssam 	/* a SIGHUP will kill us */
232*38272Ssam 
233*38272Ssam 	/* timeleft = 60 * 60 * 24 * 365 ; (void) alarm(timeleft); */
234*38272Ssam 
235*38272Ssam 	/* twiddle thumbs until we get a signal */
236*38272Ssam 	while (1) {
237*38272Ssam 		sigpause(0);
238*38272Ssam 		(void) sigblock(sigmask(SIGALRM));
239*38272Ssam 		if (gotalarm && lowdcd(0))
240*38272Ssam 			break;
241*38272Ssam 		gotalarm = 0;
242*38272Ssam 	}
243*38272Ssam 
244*38272Ssam 	/* closing the descriptor should pop the slip module */
245*38272Ssam 	exit(0);
246*38272Ssam }
247*38272Ssam 
248*38272Ssam findid(name)
249*38272Ssam 	char *name;
250*38272Ssam {
251*38272Ssam 	char buf[BUFSIZ];
252*38272Ssam 	static char mode[16];
253*38272Ssam 	static char laddr[16];
254*38272Ssam 	static char raddr[16];
255*38272Ssam 	static char mask[16];
256*38272Ssam 	char user[16];
257*38272Ssam 	FILE *fp;
258*38272Ssam 	struct passwd *pw;
259*38272Ssam 	int n;
260*38272Ssam 
261*38272Ssam 	if (name == NULL && (pw = getpwuid(getuid())) == NULL) {
262*38272Ssam 		fprintf(stderr, "Your UID (%d) is unknown\n", getuid());
263*38272Ssam 		syslog(LOG_ERR, "UID (%d) is unknown\n", getuid());
264*38272Ssam 		exit(1);
265*38272Ssam 	} else if (name == NULL)
266*38272Ssam 		name = pw->pw_name;
267*38272Ssam 	if ((fp = fopen(Accessfile, "r")) == NULL) {
268*38272Ssam 		perror(Accessfile);
269*38272Ssam 		syslog(LOG_ERR, "%s: %m\n", Accessfile);
270*38272Ssam 		exit(3);
271*38272Ssam 	}
272*38272Ssam 	while (fgets(buf, sizeof(buf) - 1, fp)) {
273*38272Ssam 		if (ferror(fp))
274*38272Ssam 			break;
275*38272Ssam 		n = sscanf(buf, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n",
276*38272Ssam 			user, mode, laddr, raddr, mask);
277*38272Ssam 		if (user[0] == '#' || n != 5)
278*38272Ssam 			continue;
279*38272Ssam 		if (strcmp(user, name) == 0) {
280*38272Ssam 			/* eventually deal with "mode" */
281*38272Ssam 			localaddr = laddr;
282*38272Ssam 			dstaddr = raddr;
283*38272Ssam 			netmask = mask;
284*38272Ssam 			fclose(fp);
285*38272Ssam 			return 0;
286*38272Ssam 		}
287*38272Ssam 		if (feof(fp))
288*38272Ssam 			break;
289*38272Ssam 	}
290*38272Ssam 	fputs("SLIP access denied\n", stderr);
291*38272Ssam 	syslog(LOG_ERR, "SLIP access denied for %s\n", name);
292*38272Ssam 	exit(4);
293*38272Ssam }
294*38272Ssam 
295*38272Ssam in_getaddr(s, saddr)
296*38272Ssam 	char *s;
297*38272Ssam 	struct sockaddr *saddr;
298*38272Ssam {
299*38272Ssam 	register struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
300*38272Ssam 	struct hostent *hp;
301*38272Ssam 	struct netent *np;
302*38272Ssam 	int val;
303*38272Ssam 	extern struct in_addr inet_makeaddr();
304*38272Ssam 
305*38272Ssam 	bzero((caddr_t)saddr, sizeof *saddr);
306*38272Ssam 	sin->sin_family = AF_INET;
307*38272Ssam 	val = inet_addr(s);
308*38272Ssam 	if (val != -1) {
309*38272Ssam 		sin->sin_addr.s_addr = val;
310*38272Ssam 		return;
311*38272Ssam 	}
312*38272Ssam 	hp = gethostbyname(s);
313*38272Ssam 	if (hp) {
314*38272Ssam 		sin->sin_family = hp->h_addrtype;
315*38272Ssam 		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
316*38272Ssam 		return;
317*38272Ssam 	}
318*38272Ssam 	np = getnetbyname(s);
319*38272Ssam 	if (np) {
320*38272Ssam 		sin->sin_family = np->n_addrtype;
321*38272Ssam 		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
322*38272Ssam 		return;
323*38272Ssam 	}
324*38272Ssam 	fprintf(stderr, "sliplogin: %s: bad value\n", s);
325*38272Ssam 	syslog(LOG_ERR, "%s: bad value\n", s);
326*38272Ssam 	exit(1);
327*38272Ssam }
328*38272Ssam 
329