]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sbin/startslip/startslip.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sbin / startslip / startslip.c
1 /*-
2  * Copyright (c) 1990, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 static const char copyright[] =
32 "@(#) Copyright (c) 1990, 1991, 1993\n\
33         The Regents of the University of California.  All rights reserved.\n";
34 #endif /* not lint */
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)startslip.c 8.1 (Berkeley) 6/5/93";
39 #endif
40 static const char rcsid[] =
41   "$FreeBSD$";
42 #endif /* not lint */
43
44 #include <sys/types.h>
45 #include <sys/time.h>
46
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <libutil.h>
51 #include <paths.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <syslog.h>
57 #include <termios.h>
58 #include <unistd.h>
59
60 #include <net/slip.h>
61
62 #define DEFAULT_BAUD    B9600
63 int     speed = DEFAULT_BAUD;
64 #define FC_NONE         0       /* flow control: none */
65 #define FC_HW           1       /* flow control: hardware (RTS/CTS) */
66 int     flowcontrol = FC_NONE;
67 int     modem_control = 1;      /* !CLOCAL+HUPCL iff we watch carrier. */
68 int     sl_unit = -1;
69 int     uucp_lock = 0;          /* uucp locking */
70 char    *annex;
71 char    *username;
72 int     hup;
73 int     terminate;
74 int     locked = 0;             /* uucp lock active */
75 int     logged_in = 0;
76 int     wait_time = 60;         /* then back off */
77 int     script_timeout = 90;    /* connect script default timeout */
78 time_t  conn_time, start_time;
79 int     MAXTRIES = 6;           /* w/60 sec and doubling, takes an hour */
80 #define PIDFILE         "%sstartslip.%s.pid"
81
82 #define MAXDIALS 20
83 char *dials[MAXDIALS];
84 int diali, dialc;
85
86 int fd = -1;
87 FILE *pfd;
88 char *dvname, *devicename;
89 char pidfile[80];
90
91 #ifdef DEBUG
92 int     debug = 1;
93 #undef LOG_ERR
94 #undef LOG_INFO
95 #define syslog fprintf
96 #define LOG_ERR stderr
97 #define LOG_INFO stderr
98 #else
99 int     debug = 0;
100 #endif
101 #define printd  if (debug) printf
102
103 int carrier(void);
104 void down(int);
105 int getline(char *, int, int, time_t);
106 void sighup(int);
107 void sigterm(int);
108 void sigurg(int);
109 static void usage(void);
110
111 int
112 main(int argc, char **argv)
113 {
114         char *cp, **ap;
115         int ch, disc;
116         FILE *wfd = NULL;
117         char *dialerstring = 0, buf[BUFSIZ];
118         int unitnum, keepal = 0, outfill = 0;
119         char unitname[32];
120         char *password;
121         char *upscript = NULL, *downscript = NULL;
122         int first = 1, tries = 0;
123         time_t fintimeout;
124         long lpid;
125         pid_t pid;
126         struct termios t;
127
128         while ((ch = getopt(argc, argv, "dhlb:s:t:w:A:U:D:W:K:O:S:L")) != -1)
129                 switch (ch) {
130                 case 'd':
131                         debug = 1;
132                         break;
133                 case 'b':
134                         speed = atoi(optarg);
135                         break;
136                 case 's':
137                         if (diali >= MAXDIALS)
138                                 errx(1, "max dial strings number (%d) exceeded", MAXDIALS);
139                         dials[diali++] = strdup(optarg);
140                         break;
141                 case 't':
142                         script_timeout = atoi(optarg);
143                         break;
144                 case 'w':
145                         wait_time = atoi(optarg);
146                         break;
147                 case 'W':
148                         MAXTRIES = atoi(optarg);
149                         break;
150                 case 'A':
151                         annex = strdup(optarg);
152                         break;
153                 case 'U':
154                         upscript = strdup(optarg);
155                         break;
156                 case 'D':
157                         downscript = strdup(optarg);
158                         break;
159                 case 'L':
160                         uucp_lock = 1;
161                         break;
162                 case 'l':
163                         modem_control = 0;
164                         break;
165                 case 'h':
166                         flowcontrol = FC_HW;
167                         break;
168                 case 'K':
169                         keepal = atoi(optarg);
170                         break;
171                 case 'O':
172                         outfill = atoi(optarg);
173                         break;
174                 case 'S':
175                         sl_unit = atoi(optarg);
176                         break;
177                 case '?':
178                 default:
179                         usage();
180                 }
181         argc -= optind;
182         argv += optind;
183
184         if (argc != 3)
185                 usage();
186
187         /*
188          * Copy these so they exist after we clobber them.
189          */
190         devicename = strdup(argv[0]);
191         username = strdup(argv[1]);
192         password = strdup(argv[2]);
193
194         /*
195          * Security hack.  Do not want private information such as the
196          * password and possible phone number to be left around.
197          * So we clobber the arguments.
198          */
199         for (ap = argv - optind + 1; ap < argv + 3; ap++)
200                 for (cp = *ap; *cp != 0; cp++)
201                         *cp = '\0';
202
203         openlog("startslip", LOG_PID|LOG_PERROR, LOG_DAEMON);
204
205         if (debug)
206                 setbuf(stdout, NULL);
207
208         signal(SIGTERM, sigterm);
209         if ((dvname = strrchr(devicename, '/')) == NULL)
210                 dvname = devicename;
211         else
212                 dvname++;
213         if (snprintf(pidfile, sizeof(pidfile), PIDFILE, _PATH_VARRUN, dvname)
214             >= (int)sizeof(pidfile))
215                 usage();
216
217         if ((pfd = fopen(pidfile, "r")) != NULL) {
218                 if (fscanf(pfd, "%ld\n", &lpid) == 1) {
219                         pid = lpid;
220                         if (pid == lpid && pid > 0)
221                                 kill(pid, SIGTERM);
222                 }
223                 fclose(pfd);
224                 pfd = NULL;     /* not remove pidfile yet */
225                 sleep(5);       /* allow down script to be completed */
226         } else
227 restart:
228         signal(SIGHUP, SIG_IGN);
229         signal(SIGURG, SIG_IGN);
230         hup = 0;
231         if (wfd) {
232                 printd("fclose, ");
233                 fclose(wfd);
234                 conn_time = time(NULL) - start_time;
235                 if (uucp_lock)
236                         uu_unlock(dvname);
237                 locked = 0;
238                 wfd = NULL;
239                 fd = -1;
240                 sleep(5);
241         } else if (fd >= 0) {
242                 printd("close, ");
243                 close(fd);
244                 conn_time = time(NULL) - start_time;
245                 if (uucp_lock)
246                         uu_unlock(dvname);
247                 locked = 0;
248                 fd = -1;
249                 sleep(5);
250         }
251         if (logged_in) {
252                 syslog(LOG_INFO, "%s: connection time elapsed: %ld secs",
253                     username, (long)conn_time);
254                 sprintf(buf, "LINE=%d %s %s down",
255                 diali ? (dialc - 1) % diali : 0,
256                 downscript ? downscript : _PATH_IFCONFIG , unitname);
257                 (void) system(buf);
258                 logged_in = 0;
259         }
260         if (terminate)
261                 down(0);
262         tries++;
263         if (MAXTRIES > 0 && tries > MAXTRIES) {
264                 syslog(LOG_ERR, "%s: exiting login after %d tries", username, tries);
265                 /* ???
266                 if (first)
267                 */
268                         down(3);
269         }
270         if (tries > 1) {
271                 syslog(LOG_INFO, "%s: sleeping %d seconds (%d tries)",
272                         username, wait_time * (tries - 1), tries);
273                 sleep(wait_time * (tries - 1));
274                 if (terminate)
275                         goto restart;
276         }
277
278         if (daemon(1, debug) < 0) {
279                 syslog(LOG_ERR, "%s: daemon: %m", username);
280                 down(2);
281         }
282
283         pid = getpid();
284         printd("restart: pid %ld: ", (long)pid);
285         if ((pfd = fopen(pidfile, "w")) != NULL) {
286                 fprintf(pfd, "%ld\n", (long)pid);
287                 fclose(pfd);
288         }
289         printd("open");
290         if (uucp_lock) {
291                 int res;
292                 if ((res = uu_lock(dvname)) != UU_LOCK_OK) {
293                         if (res != UU_LOCK_INUSE)
294                                 syslog(LOG_ERR, "uu_lock: %s", uu_lockerr(res));
295                         syslog(LOG_ERR, "%s: can't lock %s", username, devicename);
296                         goto restart;
297                 }
298                 locked = 1;
299         }
300         if ((fd = open(devicename, O_RDWR | O_NONBLOCK)) < 0) {
301                 syslog(LOG_ERR, "%s: open %s: %m", username, devicename);
302                 if (first)
303                         down(1);
304                 else {
305                         if (uucp_lock)
306                                 uu_unlock(dvname);
307                         locked = 0;
308                         goto restart;
309                 }
310         }
311         printd(" %d", fd);
312         signal(SIGHUP, sighup);
313         if (ioctl(fd, TIOCSCTTY, 0) < 0) {
314                 syslog(LOG_ERR, "%s: ioctl (TIOCSCTTY): %m", username);
315                 down(2);
316         }
317         if (tcsetpgrp(fd, getpid()) < 0) {
318                 syslog(LOG_ERR, "%s: tcsetpgrp failed: %m", username);
319                 down(2);
320         }
321         printd(", ioctl\n");
322         if (tcgetattr(fd, &t) < 0) {
323                 syslog(LOG_ERR, "%s: tcgetattr(%s): %m", username, devicename);
324                 down(2);
325         }
326         cfmakeraw(&t);
327         switch (flowcontrol) {
328         case FC_HW:
329                 t.c_cflag |= (CRTS_IFLOW|CCTS_OFLOW);
330                 break;
331         case FC_NONE:
332                 t.c_cflag &= ~(CRTS_IFLOW|CCTS_OFLOW);
333                 break;
334         }
335         if (modem_control)
336                 t.c_cflag |= HUPCL;
337         else
338                 t.c_cflag &= ~(HUPCL);
339         t.c_cflag |= CLOCAL;    /* until modem commands passes */
340         cfsetispeed(&t, speed);
341         cfsetospeed(&t, speed);
342         if (tcsetattr(fd, TCSAFLUSH, &t) < 0) {
343                 syslog(LOG_ERR, "%s: tcsetattr(%s): %m", username, devicename);
344                 down(2);
345         }
346         sleep(2);               /* wait for flakey line to settle */
347         if (hup || terminate)
348                 goto restart;
349
350         wfd = fdopen(fd, "w+");
351         if (wfd == NULL) {
352                 syslog(LOG_ERR, "%s: can't fdopen %s: %m", username, devicename);
353                 down(2);
354         }
355         setbuf(wfd, NULL);
356
357         if (diali > 0)
358                 dialerstring = dials[dialc++ % diali];
359         if (dialerstring) {
360                 syslog(LOG_INFO, "%s: dialer string: %s\\r", username, dialerstring);
361                 fprintf(wfd, "%s\r", dialerstring);
362         }
363         printd("\n");
364
365         fintimeout = time(NULL) + script_timeout;
366         if (modem_control) {
367                 printd("waiting for carrier\n");
368                 while (time(NULL) < fintimeout && !carrier()) {
369                         sleep(1);
370                         if (hup || terminate)
371                                 goto restart;
372                 }
373                 if (!carrier())
374                         goto restart;
375                 t.c_cflag &= ~(CLOCAL);
376                 if (tcsetattr(fd, TCSANOW, &t) < 0) {
377                         syslog(LOG_ERR, "%s: tcsetattr(%s): %m", username, devicename);
378                         down(2);
379                 }
380                 /* Only now we able to receive HUP on carrier drop! */
381         }
382
383         /*
384          * Log in
385          */
386         printd("look for login: ");
387         for (;;) {
388                 if (getline(buf, BUFSIZ, fd, fintimeout) == 0 || hup || terminate)
389                         goto restart;
390                 if (annex) {
391                         if (bcmp(buf, annex, strlen(annex)) == 0) {
392                                 fprintf(wfd, "slip\r");
393                                 printd("Sent \"slip\"\n");
394                                 continue;
395                         }
396                         if (bcmp(&buf[1], "sername:", 8) == 0) {
397                                 fprintf(wfd, "%s\r", username);
398                                 printd("Sent login: %s\n", username);
399                                 continue;
400                         }
401                         if (bcmp(&buf[1], "assword:", 8) == 0) {
402                                 fprintf(wfd, "%s\r", password);
403                                 printd("Sent password: %s\n", password);
404                                 break;
405                         }
406                 } else {
407                         if (strstr(&buf[1], "ogin:") != NULL) {
408                                 fprintf(wfd, "%s\r", username);
409                                 printd("Sent login: %s\n", username);
410                                 continue;
411                         }
412                         if (strstr(&buf[1], "assword:") != NULL) {
413                                 fprintf(wfd, "%s\r", password);
414                                 printd("Sent password: %s\n", password);
415                                 break;
416                         }
417                 }
418         }
419
420         sleep(5);       /* Wait until login completed */
421         if (hup || terminate)
422                 goto restart;
423         start_time = time(NULL);
424         /*
425          * Attach
426          */
427         printd("setd");
428         disc = SLIPDISC;
429         if (ioctl(fd, TIOCSETD, &disc) < 0) {
430                 syslog(LOG_ERR, "%s: ioctl (%s, TIOCSETD): %m",
431                     username, devicename);
432                 down(2);
433         }
434         if (sl_unit >= 0 && ioctl(fd, SLIOCSUNIT, &sl_unit) < 0) {
435                 syslog(LOG_ERR, "%s: ioctl(SLIOCSUNIT): %m", username);
436                 down(2);
437         }
438         if (ioctl(fd, SLIOCGUNIT, &unitnum) < 0) {
439                 syslog(LOG_ERR, "%s: ioctl(SLIOCGUNIT): %m", username);
440                 down(2);
441         }
442         sprintf(unitname, "sl%d", unitnum);
443
444         if (keepal > 0) {
445                 signal(SIGURG, sigurg);
446                 if (ioctl(fd, SLIOCSKEEPAL, &keepal) < 0) {
447                         syslog(LOG_ERR, "%s: ioctl(SLIOCSKEEPAL): %m", username);
448                         down(2);
449                 }
450         }
451         if (outfill > 0 && ioctl(fd, SLIOCSOUTFILL, &outfill) < 0) {
452                 syslog(LOG_ERR, "%s: ioctl(SLIOCSOUTFILL): %m", username);
453                 down(2);
454         }
455
456         sprintf(buf, "LINE=%d %s %s up",
457                 diali ? (dialc - 1) % diali : 0,
458                 upscript ? upscript : _PATH_IFCONFIG , unitname);
459         (void) system(buf);
460
461         printd(", ready\n");
462         if (!first)
463                 syslog(LOG_INFO, "%s: reconnected on %s (%d tries)", username, unitname, tries);
464         else
465                 syslog(LOG_INFO, "%s: connected on %s", username, unitname);
466         first = 0;
467         tries = 0;
468         logged_in = 1;
469         while (hup == 0 && terminate == 0) {
470                 sigpause(0L);
471                 printd("sigpause return\n");
472         }
473         goto restart;
474         return(0); /* not reached */
475 }
476
477 void
478 sighup(int sig __unused)
479 {
480
481         printd("hup\n");
482         if (hup == 0 && logged_in)
483                 syslog(LOG_INFO, "%s: got hangup signal", username);
484         hup = 1;
485 }
486
487 void
488 sigurg(int sig __unused)
489 {
490
491         printd("urg\n");
492         if (hup == 0 && logged_in)
493                 syslog(LOG_INFO, "%s: got dead line signal", username);
494         hup = 1;
495 }
496
497 void
498 sigterm(int sig __unused)
499 {
500
501         printd("terminate\n");
502         if (terminate == 0 && logged_in)
503                 syslog(LOG_INFO, "%s: got terminate signal", username);
504         terminate = 1;
505 }
506
507 int
508 getline(char *buf, int size, int fd, time_t fintimeout)
509 {
510         int i;
511         int ret;
512         fd_set readfds;
513         struct timeval tv;
514         time_t timeout;
515
516         size--;
517         for (i = 0; i < size; i++) {
518                 if (hup || terminate)
519                         return (0);
520                 if ((timeout = fintimeout - time(NULL)) <= 0)
521                         goto tout;
522                 FD_ZERO(&readfds);
523                 FD_SET(fd, &readfds);
524                 tv.tv_sec = timeout;
525                 tv.tv_usec = 0;
526                 if ((ret = select(fd + 1, &readfds, NULL, NULL, &tv)) < 0) {
527                         if (errno != EINTR)
528                                 syslog(LOG_ERR, "%s: getline: select: %m", username);
529                 } else {
530                         if (! ret) {
531                         tout:
532                                 printd("getline: timed out\n");
533                                 return (0);
534                         }
535                         if ((ret = read(fd, &buf[i], 1)) == 1) {
536                                 buf[i] &= 0177;
537                                 if (buf[i] == '\r' || buf[i] == '\0') {
538                                         i--;
539                                         continue;
540                                 }
541                                 if (buf[i] != '\n' && buf[i] != ':')
542                                         continue;
543                                 buf[i + 1] = '\0';
544                                 printd("Got %d: %s", i + 1, buf);
545                                 return (i+1);
546                         }
547                         if (ret <= 0) {
548                                 if (ret < 0) {
549                                         syslog(LOG_ERR, "%s: getline: read: %m", username);
550                                 } else
551                                         syslog(LOG_ERR, "%s: read returned 0", username);
552                                 buf[i] = '\0';
553                                 printd("returning %d after %d: %s\n", ret, i, buf);
554                                 return (0);
555                         }
556                 }
557         }
558         return (0);
559 }
560
561 int
562 carrier(void)
563 {
564         int comstate;
565
566         if (ioctl(fd, TIOCMGET, &comstate) < 0) {
567                 syslog(LOG_ERR, "%s: ioctl (%s, TIOCMGET): %m",
568                     username, devicename);
569                 down(2);
570         }
571         return !!(comstate & TIOCM_CD);
572 }
573
574 void
575 down(int code)
576 {
577         if (fd > -1)
578                 close(fd);
579         if (pfd)
580                 unlink(pidfile);
581         if (uucp_lock && locked)
582                 uu_unlock(dvname);
583         exit(code);
584 }
585
586 static void
587 usage(void)
588 {
589         (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",  
590 "usage: startslip [-d] [-b speed] [-s string1 [-s string2 [...]]] [-h] [-l]",
591 "                 [-L] [-A annexname] [-U upscript] [-D downscript]",
592 "                 [-t script_timeout] [-W maxtries] [-w retry_pause]",
593 "                 [-K keepalive] [-O outfill] [-S unit] device user password");
594         exit(1);
595 }