1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 #include <stdio_ext.h> 30 #include <stdlib.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <poll.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/stropts.h> 39 #include <sys/resource.h> 40 #include <sys/termios.h> 41 #include <pwd.h> 42 #include <grp.h> 43 #include <unistd.h> 44 #include <ulimit.h> 45 46 #include "sac.h" 47 #include "ttymon.h" 48 #include "tmstruct.h" 49 #include "tmextern.h" 50 51 static int Initialized; 52 53 extern int Retry; 54 extern struct pollfd *Pollp; 55 static void initialize(); 56 static void open_all(); 57 static int set_poll(); 58 static int check_spawnlimit(); 59 static int mod_ttydefs(); 60 61 void open_device(); 62 void set_softcar(); 63 64 extern int check_session(); 65 extern void sigalarm(); 66 extern void revokedevaccess(char *, uid_t, gid_t, mode_t); 67 /* can't include libdevinfo.h */ 68 extern int di_devperm_logout(const char *); 69 70 /* 71 * ttymon - a port monitor under SAC 72 * - monitor ports, set terminal modes, baud rate 73 * and line discipline for the port 74 * - invoke service on port if connection request received 75 * - Usage: ttymon 76 * ttymon -g [options] 77 * Valid options are 78 * -h 79 * -d device 80 * -l ttylabel 81 * -t timeout 82 * -m modules 83 * -p prompt 84 * 85 * - ttymon without args is invoked by SAC 86 * - ttymon -g is invoked by process that needs to 87 * have login service on the fly 88 */ 89 90 int 91 main(int argc, char *argv[]) 92 { 93 int nfds; 94 extern char *lastname(); 95 96 /* 97 * Only the superuser should execute this command. 98 */ 99 if (getuid() != 0) 100 return (1); 101 102 /* remember original signal mask and dispositions */ 103 (void) sigprocmask(SIG_SETMASK, NULL, &Origmask); 104 (void) sigaction(SIGINT, NULL, &Sigint); 105 (void) sigaction(SIGALRM, NULL, &Sigalrm); 106 (void) sigaction(SIGPOLL, NULL, &Sigpoll); 107 (void) sigaction(SIGQUIT, NULL, &Sigquit); 108 (void) sigaction(SIGCLD, NULL, &Sigcld); 109 (void) sigaction(SIGTERM, NULL, &Sigterm); 110 #ifdef DEBUG 111 (void) sigaction(SIGUSR1, NULL, &Sigusr1); 112 (void) sigaction(SIGUSR2, NULL, &Sigusr2); 113 #endif 114 115 /* 116 * SIGQUIT needs to be ignored. Otherwise, hitting ^\ from 117 * console kills ttymon. 118 */ 119 (void) signal(SIGQUIT, SIG_IGN); 120 121 if ((argc > 1) || (strcmp(lastname(argv[0]), "getty") == 0)) { 122 ttymon_express(argc, argv); 123 return (1); /*NOTREACHED*/ 124 } 125 126 initialize(); 127 128 for (;;) { 129 nfds = set_poll(Pollp); 130 if (!Reread_flag) { 131 if (nfds > 0) 132 do_poll(Pollp, nfds); 133 else 134 (void) pause(); 135 } 136 /* 137 * READDB messages may arrive during poll or pause. 138 * So the flag needs to be checked again. 139 */ 140 if (Reread_flag) { 141 Reread_flag = FALSE; 142 re_read(); 143 } 144 while (Retry) { 145 Retry = FALSE; 146 open_all(); 147 } 148 } 149 } 150 151 static void 152 initialize() 153 { 154 struct pmtab *tp; 155 register struct passwd *pwdp; 156 register struct group *gp; 157 struct rlimit rlimit; 158 extern struct rlimit Rlimit; 159 extern uid_t Uucp_uid; 160 extern gid_t Tty_gid; 161 162 #ifdef DEBUG 163 extern opendebug(); 164 #endif 165 Initialized = FALSE; 166 /* 167 * get_environ() must be called first, 168 * otherwise we don't know where the log file is 169 */ 170 get_environ(); 171 openttymonlog(); 172 openpid(); 173 openpipes(); 174 setup_PCpipe(); 175 176 log("PMTAG: %s", Tag); 177 log("Starting state: %s", 178 (State == PM_ENABLED) ? "enabled" : "disabled"); 179 180 #ifdef DEBUG 181 opendebug(FALSE); 182 debug("***** ttymon in initialize *****"); 183 log("debug mode is \t on"); 184 #endif 185 186 catch_signals(); 187 188 /* register to receive SIGPOLL when data comes to pmpipe */ 189 if (ioctl(Pfd, I_SETSIG, S_INPUT) < 0) 190 fatal("I_SETSIG on pmpipe failed: %s", strerror(errno)); 191 192 sacpoll(); /* this is needed because there may be data already */ 193 194 Maxfiles = (int)ulimit(4, 0L); /* get max number of open files */ 195 if (Maxfiles < 0) 196 fatal("ulimit(4,0L) failed: %s", strerror(errno)); 197 198 if (getrlimit(RLIMIT_NOFILE, &Rlimit) == -1) 199 fatal("getrlimit failed: %s", strerror(errno)); 200 201 rlimit.rlim_cur = rlimit.rlim_max = Rlimit.rlim_max; 202 if (setrlimit(RLIMIT_NOFILE, &rlimit) == -1) 203 fatal("setrlimit failed: %s", strerror(errno)); 204 205 (void) enable_extended_FILE_stdio(-1, -1); 206 207 Maxfiles = rlimit.rlim_cur; 208 Maxfds = Maxfiles - FILE_RESERVED; 209 210 log("max open files = %d", Maxfiles); 211 log("max ports ttymon can monitor = %d", Maxfds); 212 213 read_pmtab(); 214 215 /* 216 * setup poll array 217 * - we allocate 10 extra pollfd so that 218 * we do not have to re-malloc when there is 219 * minor fluctuation in Nentries 220 */ 221 Npollfd = Nentries + 10; 222 if (Npollfd > Maxfds) 223 Npollfd = Maxfds; 224 if ((Pollp = (struct pollfd *) 225 malloc((unsigned)(Npollfd * sizeof (struct pollfd)))) 226 == (struct pollfd *)NULL) 227 fatal("malloc for Pollp failed"); 228 229 (void) mod_ttydefs(); /* just to initialize Mtime */ 230 if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) 231 fatal("check /etc/ttydefs version failed"); 232 233 read_ttydefs(NULL, FALSE); 234 235 /* initialize global variables, Uucp_uid & Tty_gid */ 236 if ((pwdp = getpwnam(UUCP)) != NULL) 237 Uucp_uid = pwdp->pw_uid; 238 if ((gp = getgrnam(TTY)) == NULL) 239 log("no group entry for <tty>, default is used"); 240 else 241 Tty_gid = gp->gr_gid; 242 endgrent(); 243 endpwent(); 244 #ifdef DEBUG 245 debug("Uucp_uid = %u, Tty_gid = %u", Uucp_uid, Tty_gid); 246 #endif 247 248 log("Initialization Completed"); 249 250 /* open the devices ttymon monitors */ 251 Retry = TRUE; 252 while (Retry) { 253 Retry = FALSE; 254 for (tp = PMtab; tp; tp = tp->p_next) { 255 if ((tp->p_status > 0) && (tp->p_fd == 0) && 256 (tp->p_pid == 0) && !(tp->p_ttyflags & I_FLAG) && 257 (!((State == PM_DISABLED) && 258 ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) { 259 open_device(tp); 260 if (tp->p_fd > 0) 261 got_carrier(tp); 262 } 263 } 264 } 265 Initialized = TRUE; 266 } 267 268 /* 269 * open_all - open devices in pmtab if the entry is 270 * - valid, fd = 0, and pid = 0 271 */ 272 static void 273 open_all() 274 { 275 struct pmtab *tp; 276 int check_modtime; 277 static void free_defs(); 278 sigset_t cset; 279 sigset_t tset; 280 281 #ifdef DEBUG 282 debug("in open_all"); 283 #endif 284 check_modtime = TRUE; 285 286 for (tp = PMtab; tp; tp = tp->p_next) { 287 if ((tp->p_status > 0) && (tp->p_fd == 0) && 288 (tp->p_pid == 0) && 289 !(tp->p_ttyflags & I_FLAG) && (!((State == PM_DISABLED) && 290 ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) { 291 /* 292 * if we have not check modification time and 293 * /etc/ttydefs was modified, need to re-read it 294 */ 295 if (check_modtime && mod_ttydefs()) { 296 check_modtime = FALSE; 297 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 298 tset = cset; 299 (void) sigaddset(&tset, SIGCLD); 300 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 301 free_defs(); 302 #ifdef DEBUG 303 debug("/etc/ttydefs is modified, re-read it"); 304 #endif 305 read_ttydefs(NULL, FALSE); 306 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 307 } 308 open_device(tp); 309 if (tp->p_fd > 0) 310 got_carrier(tp); 311 } else if (((tp->p_status == LOCKED) || 312 (tp->p_status == SESSION) || 313 (tp->p_status == UNACCESS)) && 314 (tp->p_fd > 0) && 315 (!((State == PM_DISABLED) && 316 ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) { 317 if (check_modtime && mod_ttydefs()) { 318 check_modtime = FALSE; 319 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 320 tset = cset; 321 (void) sigaddset(&tset, SIGCLD); 322 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 323 free_defs(); 324 #ifdef DEBUG 325 debug("/etc/ttydefs is modified, re-read it"); 326 #endif 327 read_ttydefs(NULL, FALSE); 328 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 329 } 330 tp->p_status = VALID; 331 open_device(tp); 332 if (tp->p_fd > 0) 333 got_carrier(tp); 334 } 335 } 336 } 337 338 void 339 set_softcar(pmptr) 340 struct pmtab *pmptr; 341 { 342 343 int fd, val = 0; 344 345 #ifdef DEBUG 346 debug("in set_softcar"); 347 #endif 348 /* 349 * If soft carrier is not set one way or 350 * the other, leave it alone. 351 */ 352 if (*pmptr->p_softcar == '\0') 353 return; 354 355 if (*pmptr->p_softcar == 'y') 356 val = 1; 357 358 if ((fd = open(pmptr->p_device, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) { 359 log("open (%s) failed: %s", pmptr->p_device, strerror(errno)); 360 return; 361 } 362 363 if (ioctl(fd, TIOCSSOFTCAR, &val) < 0) 364 log("set soft-carrier (%s) failed: %s", pmptr->p_device, 365 strerror(errno)); 366 367 close(fd); 368 } 369 370 371 /* 372 * open_device(pmptr) - open the device 373 * - check device lock 374 * - change owner of device 375 * - push line disciplines 376 * - set termio 377 */ 378 379 void 380 open_device(pmptr) 381 struct pmtab *pmptr; 382 { 383 int fd, tmpfd; 384 struct sigaction sigact; 385 386 #ifdef DEBUG 387 debug("in open_device"); 388 #endif 389 390 if (pmptr->p_status == GETTY) { 391 revokedevaccess(pmptr->p_device, 0, 0, 0); 392 393 if ((fd = open(pmptr->p_device, O_RDWR)) == -1) 394 fatal("open (%s) failed: %s", pmptr->p_device, 395 strerror(errno)); 396 397 } else { 398 if (check_spawnlimit(pmptr) == -1) { 399 pmptr->p_status = NOTVALID; 400 log("service <%s> is respawning too rapidly", 401 pmptr->p_tag); 402 return; 403 } 404 if (pmptr->p_fd > 0) { /* file already open */ 405 fd = pmptr->p_fd; 406 pmptr->p_fd = 0; 407 } else if ((fd = open(pmptr->p_device, O_RDWR|O_NONBLOCK)) 408 == -1) { 409 log("open (%s) failed: %s", pmptr->p_device, 410 strerror(errno)); 411 if ((errno == ENODEV) || (errno == EBUSY)) { 412 pmptr->p_status = UNACCESS; 413 Nlocked++; 414 if (Nlocked == 1) { 415 sigact.sa_flags = 0; 416 sigact.sa_handler = sigalarm; 417 (void) sigemptyset(&sigact.sa_mask); 418 (void) sigaction(SIGALRM, &sigact, NULL); 419 (void) alarm(ALARMTIME); 420 } 421 } else 422 Retry = TRUE; 423 return; 424 } 425 /* set close-on-exec flag */ 426 if (fcntl(fd, F_SETFD, 1) == -1) 427 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 428 429 if (tm_checklock(fd) != 0) { 430 pmptr->p_status = LOCKED; 431 (void) close(fd); 432 Nlocked++; 433 if (Nlocked == 1) { 434 sigact.sa_flags = 0; 435 sigact.sa_handler = sigalarm; 436 (void) sigemptyset(&sigact.sa_mask); 437 (void) sigaction(SIGALRM, &sigact, NULL); 438 (void) alarm(ALARMTIME); 439 } 440 return; 441 } 442 if (check_session(fd) != 0) { 443 if ((Initialized) && (pmptr->p_inservice != SESSION)) { 444 log("Warning -- active session exists on <%s>", 445 pmptr->p_device); 446 } else { 447 /* 448 * this may happen if a service is running 449 * and ttymon dies and is restarted, 450 * or another process is running on the 451 * port. 452 */ 453 pmptr->p_status = SESSION; 454 pmptr->p_inservice = 0; 455 (void) close(fd); 456 Nlocked++; 457 if (Nlocked == 1) { 458 sigact.sa_flags = 0; 459 sigact.sa_handler = sigalarm; 460 (void) sigemptyset(&sigact.sa_mask); 461 (void) sigaction(SIGALRM, &sigact, 462 NULL); 463 (void) alarm(ALARMTIME); 464 } 465 return; 466 } 467 } 468 pmptr->p_inservice = 0; 469 } 470 471 if (pmptr->p_ttyflags & H_FLAG) { 472 /* drop DTR */ 473 (void) hang_up_line(fd); 474 /* 475 * After hang_up_line, the stream is in STRHUP state. 476 * We need to do another open to reinitialize streams 477 * then we can close one fd 478 */ 479 if ((tmpfd = open(pmptr->p_device, O_RDWR|O_NONBLOCK)) == -1) { 480 log("open (%s) failed: %s", pmptr->p_device, 481 strerror(errno)); 482 Retry = TRUE; 483 (void) close(fd); 484 return; 485 } 486 (void) close(tmpfd); 487 } 488 489 #ifdef DEBUG 490 debug("open_device (%s), fd = %d", pmptr->p_device, fd); 491 #endif 492 493 /* Change ownership of the tty line to root/uucp and */ 494 /* set protections to only allow root/uucp to read the line. */ 495 496 if (pmptr->p_ttyflags & (B_FLAG|C_FLAG)) 497 (void) fchown(fd, Uucp_uid, Tty_gid); 498 else 499 (void) fchown(fd, ROOTUID, Tty_gid); 500 (void) fchmod(fd, 0620); 501 502 if ((pmptr->p_modules != NULL)&&(*(pmptr->p_modules) != '\0')) { 503 if (push_linedisc(fd, pmptr->p_modules, pmptr->p_device) 504 == -1) { 505 Retry = TRUE; 506 (void) close(fd); 507 return; 508 } 509 } 510 511 if (initial_termio(fd, pmptr) == -1) { 512 Retry = TRUE; 513 (void) close(fd); 514 return; 515 } 516 517 di_devperm_logout((const char *)pmptr->p_device); 518 pmptr->p_fd = fd; 519 } 520 521 /* 522 * set_poll(fdp) - put all fd's in a pollfd array 523 * - set poll event to POLLIN and POLLMSG 524 * - return number of fd to be polled 525 */ 526 527 static int 528 set_poll(fdp) 529 struct pollfd *fdp; 530 { 531 struct pmtab *tp; 532 int nfd = 0; 533 534 for (tp = PMtab; tp; tp = tp->p_next) { 535 if (tp->p_fd > 0) { 536 fdp->fd = tp->p_fd; 537 fdp->events = POLLIN; 538 fdp++; 539 nfd++; 540 } 541 } 542 return (nfd); 543 } 544 545 /* 546 * check_spawnlimit - return 0 if spawnlimit is not reached 547 * - otherwise return -1 548 */ 549 static int 550 check_spawnlimit(pmptr) 551 struct pmtab *pmptr; 552 { 553 time_t now; 554 555 (void) time(&now); 556 if (pmptr->p_time == 0L) 557 pmptr->p_time = now; 558 if (pmptr->p_respawn >= SPAWN_LIMIT) { 559 if ((now - pmptr->p_time) < SPAWN_INTERVAL) { 560 pmptr->p_time = now; 561 pmptr->p_respawn = 0; 562 return (-1); 563 } 564 pmptr->p_time = now; 565 pmptr->p_respawn = 0; 566 } 567 pmptr->p_respawn++; 568 return (0); 569 } 570 571 /* 572 * mod_ttydefs - to check if /etc/ttydefs has been modified 573 * - return TRUE if file modified 574 * - otherwise, return FALSE 575 */ 576 static int 577 mod_ttydefs() 578 { 579 struct stat statbuf; 580 extern long Mtime; 581 if (stat(TTYDEFS, &statbuf) == -1) { 582 /* if stat failed, don't bother reread ttydefs */ 583 return (FALSE); 584 } 585 if ((long)statbuf.st_mtime != Mtime) { 586 Mtime = (long)statbuf.st_mtime; 587 return (TRUE); 588 } 589 return (FALSE); 590 } 591 592 /* 593 * free_defs - free the Gdef table 594 */ 595 static void 596 free_defs() 597 { 598 int i; 599 struct Gdef *tp; 600 tp = &Gdef[0]; 601 for (i = 0; i < Ndefs; i++, tp++) { 602 free(tp->g_id); 603 free(tp->g_iflags); 604 free(tp->g_fflags); 605 free(tp->g_nextid); 606 tp->g_id = NULL; 607 tp->g_iflags = NULL; 608 tp->g_fflags = NULL; 609 tp->g_nextid = NULL; 610 } 611 Ndefs = 0; 612 } 613 614 /* 615 * struct Gdef *get_speed(ttylabel) 616 * - search "/etc/ttydefs" for speed and term. specification 617 * using "ttylabel". If "ttylabel" is NULL, default 618 * to DEFAULT 619 * arg: ttylabel - label/id of speed settings. 620 */ 621 622 struct Gdef * 623 get_speed(char *ttylabel) 624 { 625 register struct Gdef *sp; 626 extern struct Gdef DEFAULT; 627 628 if ((ttylabel != NULL) && (*ttylabel != '\0')) { 629 if ((sp = find_def(ttylabel)) == NULL) { 630 log("unable to find <%s> in \"%s\"", ttylabel, TTYDEFS); 631 sp = &DEFAULT; /* use default */ 632 } 633 } else sp = &DEFAULT; /* use default */ 634 return (sp); 635 } 636 637 /* 638 * setup_PCpipe() - setup the pipe between Parent and Children 639 * - the pipe is used for a tmchild to send its 640 * pid to inform ttymon that it is about to 641 * invoke service 642 * - the pipe also serves as a mean for tmchild 643 * to detect failure of ttymon 644 */ 645 void 646 setup_PCpipe() 647 { 648 int flag = 0; 649 650 if (pipe(PCpipe) == -1) 651 fatal("pipe() failed: %s", strerror(errno)); 652 653 /* set close-on-exec flag */ 654 if (fcntl(PCpipe[0], F_SETFD, 1) == -1) 655 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 656 657 if (fcntl(PCpipe[1], F_SETFD, 1) == -1) 658 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 659 660 /* set O_NONBLOCK flag */ 661 if (fcntl(PCpipe[0], F_GETFL, flag) == -1) 662 fatal("F_GETFL failed: %s", strerror(errno)); 663 664 flag |= O_NONBLOCK; 665 if (fcntl(PCpipe[0], F_SETFL, flag) == -1) 666 fatal("F_SETFL failed: %s", strerror(errno)); 667 668 /* set message discard mode */ 669 if (ioctl(PCpipe[0], I_SRDOPT, RMSGD) == -1) 670 fatal("I_SRDOPT RMSGD failed: %s", strerror(errno)); 671 672 /* register to receive SIGPOLL when data come */ 673 if (ioctl(PCpipe[0], I_SETSIG, S_INPUT) == -1) 674 fatal("I_SETSIG S_INPUT failed: %s", strerror(errno)); 675 676 #ifdef DEBUG 677 log("PCpipe[0]\t = %d", PCpipe[0]); 678 log("PCpipe[1]\t = %d", PCpipe[1]); 679 #endif 680 } 681