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