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