xref: /original-bsd/sbin/startslip/startslip.c (revision 09da47ed)
1 
2 /*-
3  * Copyright (c) 1990, 1991, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char copyright[] =
11 "@(#) Copyright (c) 1990, 1991, 1993\n\
12 	The Regents of the University of California.  All rights reserved.\n";
13 #endif /* not lint */
14 
15 #ifndef lint
16 static char sccsid[] = "@(#)startslip.c	8.1 (Berkeley) 06/05/93";
17 #endif /* not lint */
18 
19 #include <sys/param.h>
20 #if BSD >= 199006
21 #define POSIX
22 #endif
23 #ifdef POSIX
24 #include <sys/termios.h>
25 #include <sys/ioctl.h>
26 #else
27 #include <sgtty.h>
28 #endif
29 #include <sys/socket.h>
30 #include <sys/syslog.h>
31 #include <netinet/in.h>
32 #include <net/if.h>
33 #include <net/if_slvar.h>
34 #include <netdb.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <signal.h>
39 
40 #define DEFAULT_BAUD    B9600
41 int     speed = DEFAULT_BAUD;
42 #define	FC_NONE		0	/* flow control: none */
43 #define	FC_SW		1	/* flow control: software (XON/XOFF) */
44 #define	FC_HW		2	/* flow control: hardware (RTS/CTS) */
45 int	flowcontrol = FC_NONE;
46 char	*annex;
47 int	hup;
48 int	logged_in;
49 int	wait_time = 60;		/* then back off */
50 #define	MAXTRIES	6	/* w/60 sec and doubling, takes an hour */
51 #define	PIDFILE		"/var/run/startslip.pid"
52 
53 #ifdef DEBUG
54 int	debug = 1;
55 #undef LOG_ERR
56 #undef LOG_INFO
57 #define syslog fprintf
58 #define LOG_ERR stderr
59 #define LOG_INFO stderr
60 #else
61 int	debug = 0;
62 #endif
63 #define	printd	if (debug) printf
64 
65 main(argc, argv)
66 	int argc;
67 	char **argv;
68 {
69 	extern char *optarg;
70 	extern int optind;
71 	char *cp, **ap;
72 	int ch, disc;
73 	int fd = -1;
74 	void sighup();
75 	FILE *wfd = NULL, *pfd;
76 	char *dialerstring = 0, buf[BUFSIZ];
77 	int first = 1, tries = 0;
78 	int pausefirst = 0;
79 	int pid;
80 #ifdef POSIX
81 	struct termios t;
82 #else
83 	struct sgttyb sgtty;
84 #endif
85 
86 	while ((ch = getopt(argc, argv, "db:s:p:A:F:")) != EOF)
87 		switch (ch) {
88 		case 'd':
89 			debug = 1;
90 			break;
91 #ifdef POSIX
92 		case 'b':
93 			speed = atoi(optarg);
94 			break;
95 #endif
96 		case 'p':
97 			pausefirst = atoi(optarg);
98 			break;
99 		case 's':
100 			dialerstring = optarg;
101 			break;
102 		case 'A':
103 			annex = optarg;
104 			break;
105 		case 'F':
106 #ifdef POSIX
107 			if (strcmp(optarg, "none") == 0)
108 				flowcontrol = FC_NONE;
109 			else if (strcmp(optarg, "sw") == 0)
110 				flowcontrol = FC_SW;
111 			else if (strcmp(optarg, "hw") == 0)
112 				flowcontrol = FC_HW;
113 			else {
114 				(void)fprintf(stderr,
115 					"flow control: none, sw, hw\n");
116 				exit(1);
117 			}
118 			break;
119 #else
120 			(void)fprintf(stderr, "flow control not supported\n");
121 			exit(1);
122 #endif
123 		case '?':
124 		default:
125 			usage();
126 		}
127 	argc -= optind;
128 	argv += optind;
129 
130 	if (argc != 3)
131 		usage();
132 
133 	openlog("startslip", LOG_PID, LOG_DAEMON);
134 
135 #if BSD <= 43
136 	if (debug == 0 && (fd = open("/dev/tty", 0)) >= 0) {
137 		ioctl(fd, TIOCNOTTY, 0);
138 		close(fd);
139 		fd = -1;
140 	}
141 #endif
142 
143 	if (debug)
144 		setbuf(stdout, NULL);
145 
146 	if (pfd = fopen(PIDFILE, "r")) {
147 		pid = 0;
148 		fscanf(pfd, "%d", &pid);
149 		if (pid > 0)
150 			kill(pid, SIGUSR1);
151 		fclose(pfd);
152 	}
153 restart:
154 	logged_in = 0;
155 	if (++tries > MAXTRIES) {
156 		syslog(LOG_ERR, "exiting after %d tries\n", tries);
157 		/* ???
158 		if (first)
159 		*/
160 			exit(1);
161 	}
162 
163 	/*
164 	 * We may get a HUP below, when the parent (session leader/
165 	 * controlling process) exits; ignore HUP until into new session.
166 	 */
167 	signal(SIGHUP, SIG_IGN);
168 	hup = 0;
169 	if (fork() > 0) {
170 		if (pausefirst)
171 			sleep(pausefirst);
172 		if (first)
173 			printd("parent exit\n");
174 		exit(0);
175 	}
176 	pausefirst = 0;
177 #ifdef POSIX
178 	if (setsid() == -1)
179 		perror("setsid");
180 #endif
181 	pid = getpid();
182 	printd("restart: pid %d: ", pid);
183 	if (pfd = fopen(PIDFILE, "w")) {
184 		fprintf(pfd, "%d\n", pid);
185 		fclose(pfd);
186 	}
187 	if (wfd) {
188 		printd("fclose, ");
189 		fclose(wfd);
190 		wfd == NULL;
191 	}
192 	if (fd >= 0) {
193 		printd("close, ");
194 		close(fd);
195 		sleep(5);
196 	}
197 	printd("open");
198 	if ((fd = open(argv[0], O_RDWR)) < 0) {
199 		perror(argv[0]);
200 		syslog(LOG_ERR, "open %s: %m\n", argv[0]);
201 		if (first)
202 			exit(1);
203 		else {
204 			sleep(wait_time * tries);
205 			goto restart;
206 		}
207 	}
208 	printd(" %d", fd);
209 #ifdef TIOCSCTTY
210 	if (ioctl(fd, TIOCSCTTY, 0) < 0)
211 		perror("ioctl (TIOCSCTTY)");
212 #endif
213 	signal(SIGHUP, sighup);
214 	if (debug) {
215 		if (ioctl(fd, TIOCGETD, &disc) < 0)
216 			perror("ioctl(TIOCSETD)");
217 		printf(" (disc was %d)", disc);
218 	}
219 	disc = TTYDISC;
220 	if (ioctl(fd, TIOCSETD, &disc) < 0) {
221 	        perror("ioctl(TIOCSETD)");
222 		syslog(LOG_ERR, "%s: ioctl (TIOCSETD 0): %m\n",
223 		    argv[0]);
224 	}
225 	printd(", ioctl");
226 #ifdef POSIX
227 	if (tcgetattr(fd, &t) < 0) {
228 		perror("tcgetattr");
229 		syslog(LOG_ERR, "%s: tcgetattr: %m\n", argv[0]);
230 	        exit(2);
231 	}
232 	cfmakeraw(&t);
233 	t.c_iflag &= ~IMAXBEL;
234 	switch (flowcontrol) {
235 	case FC_HW:
236 		t.c_cflag |= (CRTS_IFLOW|CCTS_OFLOW);
237 		break;
238 	case FC_SW:
239 		t.c_iflag |= (IXON|IXOFF);
240 		break;
241 	case FC_NONE:
242 		t.c_cflag &= ~(CRTS_IFLOW|CCTS_OFLOW);
243 		t.c_iflag &= ~(IXON|IXOFF);
244 		break;
245 	}
246 	cfsetspeed(&t, speed);
247 	if (tcsetattr(fd, TCSAFLUSH, &t) < 0) {
248 		perror("tcsetattr");
249 		syslog(LOG_ERR, "%s: tcsetattr: %m\n", argv[0]);
250 	        if (first)
251 			exit(2);
252 		else {
253 			sleep(wait_time * tries);
254 			goto restart;
255 		}
256 	}
257 #else
258 	if (ioctl(fd, TIOCGETP, &sgtty) < 0) {
259 	        perror("ioctl (TIOCGETP)");
260 		syslog(LOG_ERR, "%s: ioctl (TIOCGETP): %m\n",
261 		    argv[0]);
262 	        exit(2);
263 	}
264 	sgtty.sg_flags = RAW | ANYP;
265 	sgtty.sg_erase = sgtty.sg_kill = 0377;
266 	sgtty.sg_ispeed = sgtty.sg_ospeed = speed;
267 	if (ioctl(fd, TIOCSETP, &sgtty) < 0) {
268 	        perror("ioctl (TIOCSETP)");
269 		syslog(LOG_ERR, "%s: ioctl (TIOCSETP): %m\n",
270 		    argv[0]);
271 	        if (first)
272 			exit(2);
273 		else {
274 			sleep(wait_time * tries);
275 			goto restart;
276 		}
277 	}
278 #endif
279 	sleep(2);		/* wait for flakey line to settle */
280 	if (hup)
281 		goto restart;
282 
283 	wfd = fdopen(fd, "w+");
284 	if (wfd == NULL) {
285 		syslog(LOG_ERR, "can't fdopen slip line\n");
286 		exit(10);
287 	}
288 	setbuf(wfd, (char *)0);
289 	if (dialerstring) {
290 		printd(", send dialstring");
291 		fprintf(wfd, "%s\r", dialerstring);
292 	} else
293 		putc('\r', wfd);
294 	printd("\n");
295 
296 	/*
297 	 * Log in
298 	 */
299 	printd("look for login: ");
300 	for (;;) {
301 		if (getline(buf, BUFSIZ, fd) == 0 || hup) {
302 			sleep(wait_time * tries);
303 			goto restart;
304 		}
305 		if (annex) {
306 			if (bcmp(buf, annex, strlen(annex)) == 0) {
307 				fprintf(wfd, "slip\r");
308 				printd("Sent \"slip\"\n");
309 				continue;
310 			}
311 			if (bcmp(&buf[1], "sername:", 8) == 0) {
312 				fprintf(wfd, "%s\r", argv[1]);
313 				printd("Sent login: %s\n", argv[1]);
314 				continue;
315 			}
316 			if (bcmp(&buf[1], "assword:", 8) == 0) {
317 				fprintf(wfd, "%s\r", argv[2]);
318 				printd("Sent password: %s\n", argv[2]);
319 				break;
320 			}
321 		} else {
322 			if (bcmp(&buf[1], "ogin:", 5) == 0) {
323 				fprintf(wfd, "%s\r", argv[1]);
324 				printd("Sent login: %s\n", argv[1]);
325 				continue;
326 			}
327 			if (bcmp(&buf[1], "assword:", 8) == 0) {
328 				fprintf(wfd, "%s\r", argv[2]);
329 				printd("Sent password: %s\n", argv[2]);
330 				break;
331 			}
332 		}
333 	}
334 
335 	/*
336 	 * Security hack.  Do not want private information such as the
337 	 * password and possible phone number to be left around.
338 	 * So we clobber the arguments.
339 	 */
340 	for (ap = argv - optind + 1; ap < argv + 3; ap++)
341 		for (cp = *ap; *cp != 0; cp++)
342 			*cp = '\0';
343 
344 	/*
345 	 * Attach
346 	 */
347 	printd("setd");
348 	disc = SLIPDISC;
349 	if (ioctl(fd, TIOCSETD, &disc) < 0) {
350 	        perror("ioctl(TIOCSETD)");
351 		syslog(LOG_ERR, "%s: ioctl (TIOCSETD SLIP): %m\n",
352 		    argv[0]);
353 	        exit(1);
354 	}
355 	if (first && debug == 0) {
356 		close(0);
357 		close(1);
358 		close(2);
359 		(void) open("/dev/null", O_RDWR);
360 		(void) dup2(0, 1);
361 		(void) dup2(0, 2);
362 	}
363 	(void) system("ifconfig sl0 up");
364 	printd(", ready\n");
365 	if (!first)
366 		syslog(LOG_INFO, "reconnected (%d tries).\n", tries);
367 	first = 0;
368 	tries = 0;
369 	logged_in = 1;
370 	while (hup == 0) {
371 		sigpause(0L);
372 		printd("sigpause return\n");
373 	}
374 	goto restart;
375 }
376 
377 void
378 sighup()
379 {
380 
381 	printd("hup\n");
382 	if (hup == 0 && logged_in)
383 		syslog(LOG_INFO, "hangup signal\n");
384 	hup = 1;
385 }
386 
387 getline(buf, size, fd)
388 	char *buf;
389 	int size, fd;
390 {
391 	register int i;
392 	int ret;
393 
394 	size--;
395 	for (i = 0; i < size; i++) {
396 		if (hup)
397 			return (0);
398 	        if ((ret = read(fd, &buf[i], 1)) == 1) {
399 	                buf[i] &= 0177;
400 	                if (buf[i] == '\r' || buf[i] == '\0')
401 	                        buf[i] = '\n';
402 	                if (buf[i] != '\n' && buf[i] != ':')
403 	                        continue;
404 	                buf[i + 1] = '\0';
405 			printd("Got %d: \"%s\"\n", i + 1, buf);
406 	                return (i+1);
407 	        }
408 		if (ret <= 0) {
409 			if (ret < 0)
410 				perror("getline: read");
411 			else
412 				fprintf(stderr, "read returned 0\n");
413 			buf[i] = '\0';
414 			printd("returning 0 after %d: \"%s\"\n", i, buf);
415 			return (0);
416 		}
417 	}
418 	return (0);
419 }
420 
421 usage()
422 {
423 	(void)fprintf(stderr,
424 	    "usage: startslip [-d] [-b speed] [-s string] [-A annexname] [-F flowcontrol] dev user passwd\n");
425 	exit(1);
426 }
427