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 static void free_defs(); 269 270 /* 271 * open_all - open devices in pmtab if the entry is 272 * - valid, fd = 0, and pid = 0 273 */ 274 static void 275 open_all() 276 { 277 struct pmtab *tp; 278 int check_modtime; 279 sigset_t cset; 280 sigset_t tset; 281 282 #ifdef DEBUG 283 debug("in open_all"); 284 #endif 285 check_modtime = TRUE; 286 287 for (tp = PMtab; tp; tp = tp->p_next) { 288 if ((tp->p_status > 0) && (tp->p_fd == 0) && 289 (tp->p_pid == 0) && 290 !(tp->p_ttyflags & I_FLAG) && (!((State == PM_DISABLED) && 291 ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) { 292 /* 293 * if we have not check modification time and 294 * /etc/ttydefs was modified, need to re-read it 295 */ 296 if (check_modtime && mod_ttydefs()) { 297 check_modtime = FALSE; 298 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 299 tset = cset; 300 (void) sigaddset(&tset, SIGCLD); 301 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 302 free_defs(); 303 #ifdef DEBUG 304 debug("/etc/ttydefs is modified, re-read it"); 305 #endif 306 read_ttydefs(NULL, FALSE); 307 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 308 } 309 open_device(tp); 310 if (tp->p_fd > 0) 311 got_carrier(tp); 312 } else if (((tp->p_status == LOCKED) || 313 (tp->p_status == SESSION) || 314 (tp->p_status == UNACCESS)) && 315 (tp->p_fd > 0) && 316 (!((State == PM_DISABLED) && 317 ((tp->p_dmsg == NULL)||(*(tp->p_dmsg) == '\0'))))) { 318 if (check_modtime && mod_ttydefs()) { 319 check_modtime = FALSE; 320 (void) sigprocmask(SIG_SETMASK, NULL, &cset); 321 tset = cset; 322 (void) sigaddset(&tset, SIGCLD); 323 (void) sigprocmask(SIG_SETMASK, &tset, NULL); 324 free_defs(); 325 #ifdef DEBUG 326 debug("/etc/ttydefs is modified, re-read it"); 327 #endif 328 read_ttydefs(NULL, FALSE); 329 (void) sigprocmask(SIG_SETMASK, &cset, NULL); 330 } 331 tp->p_status = VALID; 332 open_device(tp); 333 if (tp->p_fd > 0) 334 got_carrier(tp); 335 } 336 } 337 } 338 339 void 340 set_softcar(pmptr) 341 struct pmtab *pmptr; 342 { 343 344 int fd, val = 0; 345 346 #ifdef DEBUG 347 debug("in set_softcar"); 348 #endif 349 /* 350 * If soft carrier is not set one way or 351 * the other, leave it alone. 352 */ 353 if (*pmptr->p_softcar == '\0') 354 return; 355 356 if (*pmptr->p_softcar == 'y') 357 val = 1; 358 359 if ((fd = open(pmptr->p_device, O_RDONLY|O_NONBLOCK|O_NOCTTY)) < 0) { 360 log("open (%s) failed: %s", pmptr->p_device, strerror(errno)); 361 return; 362 } 363 364 if (ioctl(fd, TIOCSSOFTCAR, &val) < 0) 365 log("set soft-carrier (%s) failed: %s", pmptr->p_device, 366 strerror(errno)); 367 368 close(fd); 369 } 370 371 372 /* 373 * open_device(pmptr) - open the device 374 * - check device lock 375 * - change owner of device 376 * - push line disciplines 377 * - set termio 378 */ 379 380 void 381 open_device(pmptr) 382 struct pmtab *pmptr; 383 { 384 int fd, tmpfd; 385 struct sigaction sigact; 386 387 #ifdef DEBUG 388 debug("in open_device"); 389 #endif 390 391 if (pmptr->p_status == GETTY) { 392 revokedevaccess(pmptr->p_device, 0, 0, 0); 393 394 if ((fd = open(pmptr->p_device, O_RDWR)) == -1) 395 fatal("open (%s) failed: %s", pmptr->p_device, 396 strerror(errno)); 397 398 } else { 399 if (check_spawnlimit(pmptr) == -1) { 400 pmptr->p_status = NOTVALID; 401 log("service <%s> is respawning too rapidly", 402 pmptr->p_tag); 403 return; 404 } 405 if (pmptr->p_fd > 0) { /* file already open */ 406 fd = pmptr->p_fd; 407 pmptr->p_fd = 0; 408 } else if ((fd = open(pmptr->p_device, O_RDWR|O_NONBLOCK)) 409 == -1) { 410 log("open (%s) failed: %s", pmptr->p_device, 411 strerror(errno)); 412 if ((errno == ENODEV) || (errno == EBUSY)) { 413 pmptr->p_status = UNACCESS; 414 Nlocked++; 415 if (Nlocked == 1) { 416 sigact.sa_flags = 0; 417 sigact.sa_handler = sigalarm; 418 (void) sigemptyset(&sigact.sa_mask); 419 (void) sigaction(SIGALRM, &sigact, NULL); 420 (void) alarm(ALARMTIME); 421 } 422 } else 423 Retry = TRUE; 424 return; 425 } 426 /* set close-on-exec flag */ 427 if (fcntl(fd, F_SETFD, 1) == -1) 428 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 429 430 if (tm_checklock(fd) != 0) { 431 pmptr->p_status = LOCKED; 432 (void) close(fd); 433 Nlocked++; 434 if (Nlocked == 1) { 435 sigact.sa_flags = 0; 436 sigact.sa_handler = sigalarm; 437 (void) sigemptyset(&sigact.sa_mask); 438 (void) sigaction(SIGALRM, &sigact, NULL); 439 (void) alarm(ALARMTIME); 440 } 441 return; 442 } 443 if (check_session(fd) != 0) { 444 if ((Initialized) && (pmptr->p_inservice != SESSION)) { 445 log("Warning -- active session exists on <%s>", 446 pmptr->p_device); 447 } else { 448 /* 449 * this may happen if a service is running 450 * and ttymon dies and is restarted, 451 * or another process is running on the 452 * port. 453 */ 454 pmptr->p_status = SESSION; 455 pmptr->p_inservice = 0; 456 (void) close(fd); 457 Nlocked++; 458 if (Nlocked == 1) { 459 sigact.sa_flags = 0; 460 sigact.sa_handler = sigalarm; 461 (void) sigemptyset(&sigact.sa_mask); 462 (void) sigaction(SIGALRM, &sigact, 463 NULL); 464 (void) alarm(ALARMTIME); 465 } 466 return; 467 } 468 } 469 pmptr->p_inservice = 0; 470 } 471 472 if (pmptr->p_ttyflags & H_FLAG) { 473 /* drop DTR */ 474 (void) hang_up_line(fd); 475 /* 476 * After hang_up_line, the stream is in STRHUP state. 477 * We need to do another open to reinitialize streams 478 * then we can close one fd 479 */ 480 if ((tmpfd = open(pmptr->p_device, O_RDWR|O_NONBLOCK)) == -1) { 481 log("open (%s) failed: %s", pmptr->p_device, 482 strerror(errno)); 483 Retry = TRUE; 484 (void) close(fd); 485 return; 486 } 487 (void) close(tmpfd); 488 } 489 490 #ifdef DEBUG 491 debug("open_device (%s), fd = %d", pmptr->p_device, fd); 492 #endif 493 494 /* Change ownership of the tty line to root/uucp and */ 495 /* set protections to only allow root/uucp to read the line. */ 496 497 if (pmptr->p_ttyflags & (B_FLAG|C_FLAG)) 498 (void) fchown(fd, Uucp_uid, Tty_gid); 499 else 500 (void) fchown(fd, ROOTUID, Tty_gid); 501 (void) fchmod(fd, 0620); 502 503 if ((pmptr->p_modules != NULL)&&(*(pmptr->p_modules) != '\0')) { 504 if (push_linedisc(fd, pmptr->p_modules, pmptr->p_device) 505 == -1) { 506 Retry = TRUE; 507 (void) close(fd); 508 return; 509 } 510 } 511 512 if (initial_termio(fd, pmptr) == -1) { 513 Retry = TRUE; 514 (void) close(fd); 515 return; 516 } 517 518 di_devperm_logout((const char *)pmptr->p_device); 519 pmptr->p_fd = fd; 520 } 521 522 /* 523 * set_poll(fdp) - put all fd's in a pollfd array 524 * - set poll event to POLLIN and POLLMSG 525 * - return number of fd to be polled 526 */ 527 528 static int 529 set_poll(fdp) 530 struct pollfd *fdp; 531 { 532 struct pmtab *tp; 533 int nfd = 0; 534 535 for (tp = PMtab; tp; tp = tp->p_next) { 536 if (tp->p_fd > 0) { 537 fdp->fd = tp->p_fd; 538 fdp->events = POLLIN; 539 fdp++; 540 nfd++; 541 } 542 } 543 return (nfd); 544 } 545 546 /* 547 * check_spawnlimit - return 0 if spawnlimit is not reached 548 * - otherwise return -1 549 */ 550 static int 551 check_spawnlimit(pmptr) 552 struct pmtab *pmptr; 553 { 554 time_t now; 555 556 (void) time(&now); 557 if (pmptr->p_time == 0L) 558 pmptr->p_time = now; 559 if (pmptr->p_respawn >= SPAWN_LIMIT) { 560 if ((now - pmptr->p_time) < SPAWN_INTERVAL) { 561 pmptr->p_time = now; 562 pmptr->p_respawn = 0; 563 return (-1); 564 } 565 pmptr->p_time = now; 566 pmptr->p_respawn = 0; 567 } 568 pmptr->p_respawn++; 569 return (0); 570 } 571 572 /* 573 * mod_ttydefs - to check if /etc/ttydefs has been modified 574 * - return TRUE if file modified 575 * - otherwise, return FALSE 576 */ 577 static int 578 mod_ttydefs() 579 { 580 struct stat statbuf; 581 extern long Mtime; 582 if (stat(TTYDEFS, &statbuf) == -1) { 583 /* if stat failed, don't bother reread ttydefs */ 584 return (FALSE); 585 } 586 if ((long)statbuf.st_mtime != Mtime) { 587 Mtime = (long)statbuf.st_mtime; 588 return (TRUE); 589 } 590 return (FALSE); 591 } 592 593 /* 594 * free_defs - free the Gdef table 595 */ 596 static void 597 free_defs() 598 { 599 int i; 600 struct Gdef *tp; 601 tp = &Gdef[0]; 602 for (i = 0; i < Ndefs; i++, tp++) { 603 free(tp->g_id); 604 free(tp->g_iflags); 605 free(tp->g_fflags); 606 free(tp->g_nextid); 607 tp->g_id = NULL; 608 tp->g_iflags = NULL; 609 tp->g_fflags = NULL; 610 tp->g_nextid = NULL; 611 } 612 Ndefs = 0; 613 } 614 615 /* 616 * struct Gdef *get_speed(ttylabel) 617 * - search "/etc/ttydefs" for speed and term. specification 618 * using "ttylabel". If "ttylabel" is NULL, default 619 * to DEFAULT 620 * arg: ttylabel - label/id of speed settings. 621 */ 622 623 struct Gdef * 624 get_speed(char *ttylabel) 625 { 626 register struct Gdef *sp; 627 extern struct Gdef DEFAULT; 628 629 if ((ttylabel != NULL) && (*ttylabel != '\0')) { 630 if ((sp = find_def(ttylabel)) == NULL) { 631 log("unable to find <%s> in \"%s\"", ttylabel, TTYDEFS); 632 sp = &DEFAULT; /* use default */ 633 } 634 } else sp = &DEFAULT; /* use default */ 635 return (sp); 636 } 637 638 /* 639 * setup_PCpipe() - setup the pipe between Parent and Children 640 * - the pipe is used for a tmchild to send its 641 * pid to inform ttymon that it is about to 642 * invoke service 643 * - the pipe also serves as a mean for tmchild 644 * to detect failure of ttymon 645 */ 646 void 647 setup_PCpipe() 648 { 649 int flag = 0; 650 651 if (pipe(PCpipe) == -1) 652 fatal("pipe() failed: %s", strerror(errno)); 653 654 /* set close-on-exec flag */ 655 if (fcntl(PCpipe[0], F_SETFD, 1) == -1) 656 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 657 658 if (fcntl(PCpipe[1], F_SETFD, 1) == -1) 659 fatal("F_SETFD fcntl failed: %s", strerror(errno)); 660 661 /* set O_NONBLOCK flag */ 662 if (fcntl(PCpipe[0], F_GETFL, flag) == -1) 663 fatal("F_GETFL failed: %s", strerror(errno)); 664 665 flag |= O_NONBLOCK; 666 if (fcntl(PCpipe[0], F_SETFL, flag) == -1) 667 fatal("F_SETFL failed: %s", strerror(errno)); 668 669 /* set message discard mode */ 670 if (ioctl(PCpipe[0], I_SRDOPT, RMSGD) == -1) 671 fatal("I_SRDOPT RMSGD failed: %s", strerror(errno)); 672 673 /* register to receive SIGPOLL when data come */ 674 if (ioctl(PCpipe[0], I_SETSIG, S_INPUT) == -1) 675 fatal("I_SETSIG S_INPUT failed: %s", strerror(errno)); 676 677 #ifdef DEBUG 678 log("PCpipe[0]\t = %d", PCpipe[0]); 679 log("PCpipe[1]\t = %d", PCpipe[1]); 680 #endif 681 } 682