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