xref: /csrg-svn/sbin/startslip/startslip.c (revision 61552)
152905Skarels 
245365Smckusick /*-
3*61552Sbostic  * Copyright (c) 1990, 1991, 1993
4*61552Sbostic  *	The Regents of the University of California.  All rights reserved.
545365Smckusick  *
645365Smckusick  * %sccs.include.redist.c%
745365Smckusick  */
845365Smckusick 
945365Smckusick #ifndef lint
10*61552Sbostic static char copyright[] =
11*61552Sbostic "@(#) Copyright (c) 1990, 1991, 1993\n\
12*61552Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1345365Smckusick #endif /* not lint */
1445365Smckusick 
1545365Smckusick #ifndef lint
16*61552Sbostic static char sccsid[] = "@(#)startslip.c	8.1 (Berkeley) 06/05/93";
1745365Smckusick #endif /* not lint */
1845365Smckusick 
1945365Smckusick #include <sys/param.h>
2052905Skarels #if BSD >= 199006
2152905Skarels #define POSIX
2252905Skarels #endif
2352905Skarels #ifdef POSIX
2452905Skarels #include <sys/termios.h>
2552905Skarels #include <sys/ioctl.h>
2652905Skarels #else
2745367Smckusick #include <sgtty.h>
2852905Skarels #endif
2945365Smckusick #include <sys/socket.h>
3045365Smckusick #include <sys/syslog.h>
3145365Smckusick #include <netinet/in.h>
3245365Smckusick #include <net/if.h>
3345365Smckusick #include <net/if_slvar.h>
3445365Smckusick #include <netdb.h>
3545365Smckusick #include <errno.h>
3645365Smckusick #include <fcntl.h>
3745365Smckusick #include <stdio.h>
3845367Smckusick #include <signal.h>
3945365Smckusick 
4045365Smckusick #define DEFAULT_BAUD    B9600
4145365Smckusick int     speed = DEFAULT_BAUD;
4259681Shibler #define	FC_NONE		0	/* flow control: none */
4359681Shibler #define	FC_SW		1	/* flow control: software (XON/XOFF) */
4459681Shibler #define	FC_HW		2	/* flow control: hardware (RTS/CTS) */
4559681Shibler int	flowcontrol = FC_NONE;
4659681Shibler char	*annex;
4745367Smckusick int	hup;
4852906Smckusick int	logged_in;
4952906Smckusick int	wait_time = 60;		/* then back off */
5052906Smckusick #define	MAXTRIES	6	/* w/60 sec and doubling, takes an hour */
5152906Smckusick #define	PIDFILE		"/var/run/startslip.pid"
5252906Smckusick 
5345365Smckusick #ifdef DEBUG
5445365Smckusick int	debug = 1;
5545365Smckusick #undef LOG_ERR
5645365Smckusick #undef LOG_INFO
5745365Smckusick #define syslog fprintf
5845365Smckusick #define LOG_ERR stderr
5945365Smckusick #define LOG_INFO stderr
6045365Smckusick #else
6145365Smckusick int	debug = 0;
6245365Smckusick #endif
6345365Smckusick #define	printd	if (debug) printf
6445365Smckusick 
main(argc,argv)6545365Smckusick main(argc, argv)
6645365Smckusick 	int argc;
6745365Smckusick 	char **argv;
6845365Smckusick {
6945365Smckusick 	extern char *optarg;
7045365Smckusick 	extern int optind;
7158555Selan 	char *cp, **ap;
7245367Smckusick 	int ch, disc;
7352906Smckusick 	int fd = -1;
7452906Smckusick 	void sighup();
7552906Smckusick 	FILE *wfd = NULL, *pfd;
7645365Smckusick 	char *dialerstring = 0, buf[BUFSIZ];
7752906Smckusick 	int first = 1, tries = 0;
7852906Smckusick 	int pausefirst = 0;
7952906Smckusick 	int pid;
8052905Skarels #ifdef POSIX
8152905Skarels 	struct termios t;
8252905Skarels #else
8345365Smckusick 	struct sgttyb sgtty;
8452905Skarels #endif
8545365Smckusick 
8659681Shibler 	while ((ch = getopt(argc, argv, "db:s:p:A:F:")) != EOF)
8752905Skarels 		switch (ch) {
8845365Smckusick 		case 'd':
8945365Smckusick 			debug = 1;
9045365Smckusick 			break;
9152905Skarels #ifdef POSIX
9252905Skarels 		case 'b':
9352905Skarels 			speed = atoi(optarg);
9452905Skarels 			break;
9552905Skarels #endif
9652906Smckusick 		case 'p':
9752906Smckusick 			pausefirst = atoi(optarg);
9852906Smckusick 			break;
9945365Smckusick 		case 's':
10045365Smckusick 			dialerstring = optarg;
10145365Smckusick 			break;
10259681Shibler 		case 'A':
10359681Shibler 			annex = optarg;
10459681Shibler 			break;
10559681Shibler 		case 'F':
10659681Shibler #ifdef POSIX
10759681Shibler 			if (strcmp(optarg, "none") == 0)
10859681Shibler 				flowcontrol = FC_NONE;
10959681Shibler 			else if (strcmp(optarg, "sw") == 0)
11059681Shibler 				flowcontrol = FC_SW;
11159681Shibler 			else if (strcmp(optarg, "hw") == 0)
11259681Shibler 				flowcontrol = FC_HW;
11359681Shibler 			else {
11459681Shibler 				(void)fprintf(stderr,
11559681Shibler 					"flow control: none, sw, hw\n");
11659681Shibler 				exit(1);
11759681Shibler 			}
11859681Shibler 			break;
11959681Shibler #else
12059681Shibler 			(void)fprintf(stderr, "flow control not supported\n");
12159681Shibler 			exit(1);
12259681Shibler #endif
12345365Smckusick 		case '?':
12445365Smckusick 		default:
12545365Smckusick 			usage();
12645365Smckusick 		}
12745365Smckusick 	argc -= optind;
12845365Smckusick 	argv += optind;
12945365Smckusick 
13045365Smckusick 	if (argc != 3)
13145365Smckusick 		usage();
13245365Smckusick 
13345365Smckusick 	openlog("startslip", LOG_PID, LOG_DAEMON);
13445365Smckusick 
13545365Smckusick #if BSD <= 43
13645367Smckusick 	if (debug == 0 && (fd = open("/dev/tty", 0)) >= 0) {
13745365Smckusick 		ioctl(fd, TIOCNOTTY, 0);
13845365Smckusick 		close(fd);
13952905Skarels 		fd = -1;
14045365Smckusick 	}
14145365Smckusick #endif
14245365Smckusick 
14352905Skarels 	if (debug)
14452905Skarels 		setbuf(stdout, NULL);
14552906Smckusick 
14652906Smckusick 	if (pfd = fopen(PIDFILE, "r")) {
14752906Smckusick 		pid = 0;
14852906Smckusick 		fscanf(pfd, "%d", &pid);
14952906Smckusick 		if (pid > 0)
15052906Smckusick 			kill(pid, SIGUSR1);
15152906Smckusick 		fclose(pfd);
15252906Smckusick 	}
15345365Smckusick restart:
15452906Smckusick 	logged_in = 0;
15552906Smckusick 	if (++tries > MAXTRIES) {
15652906Smckusick 		syslog(LOG_ERR, "exiting after %d tries\n", tries);
15752906Smckusick 		/* ???
15852906Smckusick 		if (first)
15952906Smckusick 		*/
16052906Smckusick 			exit(1);
16152906Smckusick 	}
16252906Smckusick 
16352905Skarels 	/*
16452905Skarels 	 * We may get a HUP below, when the parent (session leader/
16552905Skarels 	 * controlling process) exits; ignore HUP until into new session.
16652905Skarels 	 */
16752905Skarels 	signal(SIGHUP, SIG_IGN);
16845367Smckusick 	hup = 0;
16952906Smckusick 	if (fork() > 0) {
17052906Smckusick 		if (pausefirst)
17152906Smckusick 			sleep(pausefirst);
17252906Smckusick 		if (first)
17352906Smckusick 			printd("parent exit\n");
17452905Skarels 		exit(0);
17552906Smckusick 	}
17652906Smckusick 	pausefirst = 0;
17752905Skarels #ifdef POSIX
17852905Skarels 	if (setsid() == -1)
17952905Skarels 		perror("setsid");
18052905Skarels #endif
18152906Smckusick 	pid = getpid();
18252906Smckusick 	printd("restart: pid %d: ", pid);
18352906Smckusick 	if (pfd = fopen(PIDFILE, "w")) {
18452906Smckusick 		fprintf(pfd, "%d\n", pid);
18552906Smckusick 		fclose(pfd);
18652906Smckusick 	}
18752905Skarels 	if (wfd) {
18852906Smckusick 		printd("fclose, ");
18952905Skarels 		fclose(wfd);
19052905Skarels 		wfd == NULL;
19152905Skarels 	}
19252905Skarels 	if (fd >= 0) {
19352906Smckusick 		printd("close, ");
19445365Smckusick 		close(fd);
19552905Skarels 		sleep(5);
19652905Skarels 	}
19752906Smckusick 	printd("open");
19845365Smckusick 	if ((fd = open(argv[0], O_RDWR)) < 0) {
19945365Smckusick 		perror(argv[0]);
20052906Smckusick 		syslog(LOG_ERR, "open %s: %m\n", argv[0]);
20145365Smckusick 		if (first)
20245365Smckusick 			exit(1);
20345365Smckusick 		else {
20452906Smckusick 			sleep(wait_time * tries);
20545365Smckusick 			goto restart;
20645365Smckusick 		}
20745365Smckusick 	}
20852905Skarels 	printd(" %d", fd);
20945517Smckusick #ifdef TIOCSCTTY
21045517Smckusick 	if (ioctl(fd, TIOCSCTTY, 0) < 0)
21145517Smckusick 		perror("ioctl (TIOCSCTTY)");
21245517Smckusick #endif
21352905Skarels 	signal(SIGHUP, sighup);
21445367Smckusick 	if (debug) {
21545367Smckusick 		if (ioctl(fd, TIOCGETD, &disc) < 0)
21645367Smckusick 			perror("ioctl(TIOCSETD)");
21752905Skarels 		printf(" (disc was %d)", disc);
21845367Smckusick 	}
21945367Smckusick 	disc = TTYDISC;
22045367Smckusick 	if (ioctl(fd, TIOCSETD, &disc) < 0) {
22145367Smckusick 	        perror("ioctl(TIOCSETD)");
22252906Smckusick 		syslog(LOG_ERR, "%s: ioctl (TIOCSETD 0): %m\n",
22345367Smckusick 		    argv[0]);
22445367Smckusick 	}
22552905Skarels 	printd(", ioctl");
22652905Skarels #ifdef POSIX
22752905Skarels 	if (tcgetattr(fd, &t) < 0) {
22852905Skarels 		perror("tcgetattr");
22952906Smckusick 		syslog(LOG_ERR, "%s: tcgetattr: %m\n", argv[0]);
23052905Skarels 	        exit(2);
23145365Smckusick 	}
23252905Skarels 	cfmakeraw(&t);
23352906Smckusick 	t.c_iflag &= ~IMAXBEL;
23459681Shibler 	switch (flowcontrol) {
23559681Shibler 	case FC_HW:
23659681Shibler 		t.c_cflag |= (CRTS_IFLOW|CCTS_OFLOW);
23759681Shibler 		break;
23859681Shibler 	case FC_SW:
23959681Shibler 		t.c_iflag |= (IXON|IXOFF);
24059681Shibler 		break;
24159681Shibler 	case FC_NONE:
24259681Shibler 		t.c_cflag &= ~(CRTS_IFLOW|CCTS_OFLOW);
24359681Shibler 		t.c_iflag &= ~(IXON|IXOFF);
24459681Shibler 		break;
24559681Shibler 	}
24652905Skarels 	cfsetspeed(&t, speed);
24752906Smckusick 	if (tcsetattr(fd, TCSAFLUSH, &t) < 0) {
24852905Skarels 		perror("tcsetattr");
24952906Smckusick 		syslog(LOG_ERR, "%s: tcsetattr: %m\n", argv[0]);
25052905Skarels 	        if (first)
25152905Skarels 			exit(2);
25252905Skarels 		else {
25352906Smckusick 			sleep(wait_time * tries);
25452905Skarels 			goto restart;
25552905Skarels 		}
25652905Skarels 	}
25752905Skarels #else
25845365Smckusick 	if (ioctl(fd, TIOCGETP, &sgtty) < 0) {
25945365Smckusick 	        perror("ioctl (TIOCGETP)");
26052906Smckusick 		syslog(LOG_ERR, "%s: ioctl (TIOCGETP): %m\n",
26152905Skarels 		    argv[0]);
26245365Smckusick 	        exit(2);
26345365Smckusick 	}
26445365Smckusick 	sgtty.sg_flags = RAW | ANYP;
26545365Smckusick 	sgtty.sg_erase = sgtty.sg_kill = 0377;
26645365Smckusick 	sgtty.sg_ispeed = sgtty.sg_ospeed = speed;
26745365Smckusick 	if (ioctl(fd, TIOCSETP, &sgtty) < 0) {
26845365Smckusick 	        perror("ioctl (TIOCSETP)");
26952906Smckusick 		syslog(LOG_ERR, "%s: ioctl (TIOCSETP): %m\n",
27045365Smckusick 		    argv[0]);
27152905Skarels 	        if (first)
27252905Skarels 			exit(2);
27352905Skarels 		else {
27452906Smckusick 			sleep(wait_time * tries);
27552905Skarels 			goto restart;
27652905Skarels 		}
27745365Smckusick 	}
27852905Skarels #endif
27952906Smckusick 	sleep(2);		/* wait for flakey line to settle */
28052906Smckusick 	if (hup)
28152906Smckusick 		goto restart;
28252906Smckusick 
28352906Smckusick 	wfd = fdopen(fd, "w+");
28452906Smckusick 	if (wfd == NULL) {
28552906Smckusick 		syslog(LOG_ERR, "can't fdopen slip line\n");
28652906Smckusick 		exit(10);
28752906Smckusick 	}
28852906Smckusick 	setbuf(wfd, (char *)0);
28952905Skarels 	if (dialerstring) {
29052905Skarels 		printd(", send dialstring");
29152906Smckusick 		fprintf(wfd, "%s\r", dialerstring);
29252906Smckusick 	} else
29352906Smckusick 		putc('\r', wfd);
29452905Skarels 	printd("\n");
29552905Skarels 
29645365Smckusick 	/*
29745365Smckusick 	 * Log in
29845365Smckusick 	 */
29952905Skarels 	printd("look for login: ");
30052906Smckusick 	for (;;) {
30152906Smckusick 		if (getline(buf, BUFSIZ, fd) == 0 || hup) {
30252906Smckusick 			sleep(wait_time * tries);
30352905Skarels 			goto restart;
30452906Smckusick 		}
30559681Shibler 		if (annex) {
30659681Shibler 			if (bcmp(buf, annex, strlen(annex)) == 0) {
30759681Shibler 				fprintf(wfd, "slip\r");
30859681Shibler 				printd("Sent \"slip\"\n");
30959681Shibler 				continue;
31059681Shibler 			}
31159681Shibler 			if (bcmp(&buf[1], "sername:", 8) == 0) {
31259681Shibler 				fprintf(wfd, "%s\r", argv[1]);
31359681Shibler 				printd("Sent login: %s\n", argv[1]);
31459681Shibler 				continue;
31559681Shibler 			}
31659681Shibler 			if (bcmp(&buf[1], "assword:", 8) == 0) {
31759684Shibler 				fprintf(wfd, "%s\r", argv[2]);
31859684Shibler 				printd("Sent password: %s\n", argv[2]);
31959681Shibler 				break;
32059681Shibler 			}
32159681Shibler 		} else {
32259681Shibler 			if (bcmp(&buf[1], "ogin:", 5) == 0) {
32359681Shibler 				fprintf(wfd, "%s\r", argv[1]);
32459681Shibler 				printd("Sent login: %s\n", argv[1]);
32559681Shibler 				continue;
32659681Shibler 			}
32759681Shibler 			if (bcmp(&buf[1], "assword:", 8) == 0) {
32859681Shibler 				fprintf(wfd, "%s\r", argv[2]);
32959681Shibler 				printd("Sent password: %s\n", argv[2]);
33059681Shibler 				break;
33159681Shibler 			}
33259681Shibler 		}
33345365Smckusick 	}
33458555Selan 
33558555Selan 	/*
33658555Selan 	 * Security hack.  Do not want private information such as the
33758555Selan 	 * password and possible phone number to be left around.
33858555Selan 	 * So we clobber the arguments.
33958555Selan 	 */
34058555Selan 	for (ap = argv - optind + 1; ap < argv + 3; ap++)
34158555Selan 		for (cp = *ap; *cp != 0; cp++)
34258555Selan 			*cp = '\0';
34352906Smckusick 
34445365Smckusick 	/*
34545365Smckusick 	 * Attach
34645365Smckusick 	 */
34752906Smckusick 	printd("setd");
34845367Smckusick 	disc = SLIPDISC;
34945367Smckusick 	if (ioctl(fd, TIOCSETD, &disc) < 0) {
35045365Smckusick 	        perror("ioctl(TIOCSETD)");
35152906Smckusick 		syslog(LOG_ERR, "%s: ioctl (TIOCSETD SLIP): %m\n",
35245365Smckusick 		    argv[0]);
35345365Smckusick 	        exit(1);
35445365Smckusick 	}
35552905Skarels 	if (first && debug == 0) {
35645517Smckusick 		close(0);
35745517Smckusick 		close(1);
35845517Smckusick 		close(2);
35945517Smckusick 		(void) open("/dev/null", O_RDWR);
36045517Smckusick 		(void) dup2(0, 1);
36145517Smckusick 		(void) dup2(0, 2);
36245365Smckusick 	}
36345365Smckusick 	(void) system("ifconfig sl0 up");
36452905Skarels 	printd(", ready\n");
36552906Smckusick 	if (!first)
36652906Smckusick 		syslog(LOG_INFO, "reconnected (%d tries).\n", tries);
36752905Skarels 	first = 0;
36852906Smckusick 	tries = 0;
36952906Smckusick 	logged_in = 1;
37045517Smckusick 	while (hup == 0) {
37145367Smckusick 		sigpause(0L);
37252905Skarels 		printd("sigpause return\n");
37345517Smckusick 	}
37445365Smckusick 	goto restart;
37545365Smckusick }
37645365Smckusick 
37752906Smckusick void
sighup()37845365Smckusick sighup()
37945365Smckusick {
38045365Smckusick 
38145367Smckusick 	printd("hup\n");
38252906Smckusick 	if (hup == 0 && logged_in)
38352906Smckusick 		syslog(LOG_INFO, "hangup signal\n");
38445367Smckusick 	hup = 1;
38545365Smckusick }
38645365Smckusick 
getline(buf,size,fd)38745365Smckusick getline(buf, size, fd)
38845365Smckusick 	char *buf;
38945365Smckusick 	int size, fd;
39045365Smckusick {
39145365Smckusick 	register int i;
39245517Smckusick 	int ret;
39345365Smckusick 
39445365Smckusick 	size--;
39545365Smckusick 	for (i = 0; i < size; i++) {
39645367Smckusick 		if (hup)
39745367Smckusick 			return (0);
39845517Smckusick 	        if ((ret = read(fd, &buf[i], 1)) == 1) {
39945365Smckusick 	                buf[i] &= 0177;
40052967Smckusick 	                if (buf[i] == '\r' || buf[i] == '\0')
40145365Smckusick 	                        buf[i] = '\n';
40245365Smckusick 	                if (buf[i] != '\n' && buf[i] != ':')
40345365Smckusick 	                        continue;
40445365Smckusick 	                buf[i + 1] = '\0';
40552967Smckusick 			printd("Got %d: \"%s\"\n", i + 1, buf);
40645365Smckusick 	                return (i+1);
40745365Smckusick 	        }
40852906Smckusick 		if (ret <= 0) {
40952906Smckusick 			if (ret < 0)
41052906Smckusick 				perror("getline: read");
41152906Smckusick 			else
41252906Smckusick 				fprintf(stderr, "read returned 0\n");
41345517Smckusick 			buf[i] = '\0';
41445517Smckusick 			printd("returning 0 after %d: \"%s\"\n", i, buf);
41545517Smckusick 			return (0);
41645517Smckusick 		}
41745365Smckusick 	}
41845367Smckusick 	return (0);
41945365Smckusick }
42045365Smckusick 
usage()42145365Smckusick usage()
42245365Smckusick {
42358289Sbostic 	(void)fprintf(stderr,
42459681Shibler 	    "usage: startslip [-d] [-b speed] [-s string] [-A annexname] [-F flowcontrol] dev user passwd\n");
42545365Smckusick 	exit(1);
42645365Smckusick }
427