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 B9600 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 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 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 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 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 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 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 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 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