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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * VNTSD main 29 * 30 * VNTSD takes the following options: 31 * -i <device instance> 32 * VCC device instance to use, e.g. virtual-console-concentrator@0. 33 * Required option. 34 * -p <ip address> 35 * IP address VNTSD listens to. 36 * -d 37 * Do not daemonize. This is only available in a DEBUG build. 38 * -t timeout for inactivity 0 = indefinite 39 * -A enable Authorization checking. Mutually exclusive with -p. 40 */ 41 42 #include <stdio.h> 43 #include <stdio_ext.h> 44 #include <sys/types.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <sys/socket.h> 49 #include <arpa/inet.h> 50 #include <time.h> 51 #include <netinet/in.h> 52 #include <thread.h> 53 #include <signal.h> 54 #include <fcntl.h> 55 #include <ctype.h> 56 #include <libintl.h> 57 #include <locale.h> 58 #include <syslog.h> 59 #include <sys/socket.h> 60 #include <netdb.h> 61 #include "vntsd.h" 62 #include "chars.h" 63 64 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 65 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't. */ 66 #endif 67 68 /* global variables */ 69 70 #ifdef DEBUG 71 int vntsddbg = 0x8; 72 #endif 73 74 #define MINUTE 60 75 76 #define VNTSD_INVALID_LISTEN_ADDR ((in_addr_t)-1) 77 78 #define LOCALHOST_IPv4 "127.0.0.1" 79 #define LOCALHOST_IPv6 "::1" 80 81 static vntsd_t *vntsdp; 82 83 84 static void vntsd_exit(void); 85 /* Signal handler for SIGINT, SIGKILL and SIGHUP */ 86 static void 87 exit_sig_handler(int sig) 88 { 89 90 D1(stderr, "t@%d exit_sig_handler%d \n", thr_self(), sig); 91 92 if (thr_self() != vntsdp->tid) { 93 /* not main thread, pass to main thread */ 94 (void) thr_kill(vntsdp->tid, sig); 95 } else { 96 exit(0); 97 } 98 } 99 100 /* 101 * Before a thread reads in client's input, it attaches to vntsd timer so that 102 * it can be waken up if a client does not access the connection for 103 * VNTSD_INPUT_TIMEOUT(10) minutes. 104 */ 105 106 /* attach a thread to timer */ 107 int 108 vntsd_attach_timer(vntsd_timeout_t *tmop) 109 { 110 int rv; 111 112 if (vntsdp->timeout == 0) { 113 return (VNTSD_SUCCESS); 114 } 115 116 (void) mutex_lock(&vntsdp->tmo_lock); 117 rv = vntsd_que_append(&vntsdp->tmoq, (void *)tmop); 118 (void) mutex_unlock(&vntsdp->tmo_lock); 119 return (rv); 120 } 121 122 /* detach a thread from timer */ 123 int 124 vntsd_detach_timer(vntsd_timeout_t *tmop) 125 { 126 int rv; 127 128 if (vntsdp->timeout == 0) { 129 return (VNTSD_SUCCESS); 130 } 131 132 (void) mutex_lock(&vntsdp->tmo_lock); 133 rv = vntsd_que_rm(&vntsdp->tmoq, (void *)tmop); 134 (void) mutex_unlock(&vntsdp->tmo_lock); 135 136 return (rv); 137 } 138 139 /* check threadd's timeout */ 140 static boolean_t 141 chk_timeout(vntsd_timeout_t *tmop) 142 { 143 tmop->minutes++; 144 145 if (tmop->minutes == vntsdp->timeout) { 146 /* wake up the thread */ 147 tmop->clientp->status |= VNTSD_CLIENT_TIMEOUT; 148 (void) thr_kill(tmop->tid, SIGALRM); 149 } 150 151 /* return false to walk the queue */ 152 return (B_FALSE); 153 } 154 155 /* reset timer */ 156 static int 157 reset_timeout(void *arg1, void *arg2) 158 { 159 vntsd_timeout_t *tmop = arg1; 160 thread_t tid = (uintptr_t)arg2; 161 162 if (tmop->tid == tid) { 163 tmop->minutes = 0; 164 } 165 /* return false to walk the queue */ 166 return (B_FALSE); 167 } 168 169 void 170 vntsd_reset_timer(thread_t tid) 171 { 172 if (vntsdp->timeout == 0) { 173 return; 174 } 175 176 (void) mutex_lock(&vntsdp->tmo_lock); 177 (void) vntsd_que_find(vntsdp->tmoq, reset_timeout, 178 (void *)(uintptr_t)tid); 179 (void) mutex_unlock(&vntsdp->tmo_lock); 180 } 181 182 /* 183 * When alarm goes off, wake up timeout threads. Alarm is set off every 184 * minutes. 185 */ 186 static void 187 vntsd_alarm_sig_handler(int sig) 188 { 189 static thread_t main_thread = 0; 190 191 D1(stderr, "t@%d alarm signal %d\n", thr_self(), sig); 192 if (vntsdp->timeout == 0) { 193 DERR(stderr, "t@%d alarm signal should not recv %d\n", 194 thr_self(), sig); 195 return; 196 } 197 198 199 if (main_thread == 0) { 200 /* initialize thread id */ 201 main_thread = thr_self(); 202 } else if (main_thread != thr_self()) { 203 /* get signal because thread is timeout */ 204 return; 205 } 206 207 /* in main thread */ 208 (void) mutex_lock(&vntsdp->tmo_lock); 209 210 /* wake up timeout threads */ 211 (void) vntsd_que_walk(vntsdp->tmoq, (el_func_t)chk_timeout); 212 (void) mutex_unlock(&vntsdp->tmo_lock); 213 214 /* reset alarm */ 215 (void) alarm(MINUTE); 216 } 217 218 /* got a SIGUSER1 siginal */ 219 static void 220 vntsd_sig_handler(int sig) 221 { 222 char err_msg[VNTSD_LINE_LEN]; 223 224 (void) snprintf(err_msg, sizeof (err_msg), "sig_handler() sig=%d", 225 sig); 226 227 if (sig != SIGUSR1) { 228 vntsd_log(VNTSD_STATUS_SIG, err_msg); 229 } 230 } 231 232 /* vntsd exits */ 233 static void 234 vntsd_exit(void) 235 { 236 D1(stderr, "t@%d vntsd_exit\n", thr_self()); 237 238 (void) mutex_lock(&vntsdp->lock); 239 240 if (vntsdp->timeout > 0) { 241 /* cancel the timer */ 242 (void) alarm(0); 243 } 244 /* delete all groups */ 245 vntsd_free_que(&vntsdp->grouppq, (clean_func_t)vntsd_clean_group); 246 247 /* close control port */ 248 (void) close(vntsdp->ctrl_fd); 249 250 assert(vntsdp->tmoq == NULL); 251 (void) mutex_unlock(&vntsdp->lock); 252 253 /* clean up vntsdp */ 254 (void) mutex_destroy(&vntsdp->tmo_lock); 255 (void) mutex_destroy(&vntsdp->lock); 256 free(vntsdp); 257 closelog(); 258 } 259 260 /* 261 * vntsd_help() 262 * print out valid command line options 263 */ 264 static void 265 vntsd_help(void) 266 { 267 (void) fprintf(stderr, gettext("Usage: vntsd -i <VCC device instance> " 268 "[-p <listen address>] [-t <timeout in minutes>] [-A]\n")); 269 } 270 271 /* 272 * get_listen_ip_addr() 273 * check for a valid control domain ip address in format of xxx.xxx.xxx.xxx. 274 * if ip address is valid and is assigned to this host, return ip address 275 * or else return VNTSD_INVALID_LISTEN_ADDR. 276 */ 277 static in_addr_t 278 get_listen_ip_addr(char *listen_addr) 279 { 280 char host_name[MAXPATHLEN]; 281 in_addr_t addr; 282 struct addrinfo hints; 283 struct addrinfo *res, *infop; 284 int err; 285 struct sockaddr_in *sa; 286 287 if (gethostname(host_name, MAXPATHLEN) != 0) { 288 syslog(LOG_ERR, "Can not get host name!"); 289 return (VNTSD_INVALID_LISTEN_ADDR); 290 } 291 292 if ((int)(addr = inet_addr(listen_addr)) == -1) 293 /* bad IP address format */ 294 return (VNTSD_INVALID_LISTEN_ADDR); 295 296 bzero(&hints, sizeof (hints)); 297 hints.ai_family = PF_INET; 298 hints.ai_socktype = SOCK_STREAM; 299 300 err = getaddrinfo(host_name, NULL, &hints, &res); 301 if (err != 0) { 302 syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(err)); 303 return (VNTSD_INVALID_LISTEN_ADDR); 304 } 305 306 infop = res; 307 while (infop != NULL) { 308 /* LINTED E_BAD_PTR_CAST_ALIGN */ 309 sa = (struct sockaddr_in *)infop->ai_addr; 310 if (sa->sin_addr.s_addr == addr) { 311 /* ip address found */ 312 freeaddrinfo(res); 313 return (addr); 314 } 315 infop = infop->ai_next; 316 } 317 318 /* ip address not found */ 319 freeaddrinfo(res); 320 return (VNTSD_INVALID_LISTEN_ADDR); 321 } 322 323 #ifdef DEBUG 324 #define DEBUG_OPTIONS "d" 325 #else 326 #define DEBUG_OPTIONS "" 327 #endif 328 329 int 330 main(int argc, char ** argv) 331 { 332 char *path; 333 struct pollfd poll_drv[1]; 334 struct sigaction act; 335 struct rlimit rlim; 336 char *listen_addr = NULL; 337 pid_t pid; 338 int i; 339 int option; 340 int sz; 341 int fd; 342 int n; 343 344 /* internationalization */ 345 (void) setlocale(LC_MESSAGES, ""); 346 (void) textdomain(TEXT_DOMAIN); 347 vntsd_init_esctable_msgs(); 348 349 /* initialization */ 350 bzero(&act, sizeof (act)); 351 352 /* 353 * ensure that we can obtain sufficient file descriptors for all 354 * the accept() calls when a machine contains many domains. 355 */ 356 (void) getrlimit(RLIMIT_NOFILE, &rlim); 357 if (rlim.rlim_cur < rlim.rlim_max) 358 rlim.rlim_cur = rlim.rlim_max; 359 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) 360 vntsd_log(VNTSD_STATUS_CONTINUE, "Unable to increase file " 361 "descriptor limit."); 362 (void) enable_extended_FILE_stdio(-1, -1); 363 364 vntsdp = calloc(1, sizeof (vntsd_t)); 365 if (vntsdp == NULL) { 366 vntsd_log(VNTSD_ERR_NO_MEM, "main:vntsdp"); 367 exit(1); 368 } 369 370 vntsdp->ctrl_fd = -1; 371 vntsdp->devinst = NULL; 372 373 (void) mutex_init(&vntsdp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL); 374 (void) mutex_init(&vntsdp->tmo_lock, USYNC_THREAD|LOCK_ERRORCHECK, 375 NULL); 376 377 /* get CLI options */ 378 while ((option = getopt(argc, argv, "i:t:p:A"DEBUG_OPTIONS)) != EOF) { 379 switch (option) { 380 #ifdef DEBUG 381 case 'd': 382 vntsdp->options |= VNTSD_OPT_DAEMON_OFF; 383 break; 384 #endif 385 case 'i': 386 vntsdp->devinst = optarg; 387 break; 388 case 'p': 389 listen_addr = optarg; 390 break; 391 392 case 't': 393 n = sscanf(optarg, "%d", &(vntsdp->timeout)); 394 if (n != 1) { 395 vntsdp->timeout = -1; 396 } 397 break; 398 399 case 'A': 400 /* 401 * This option enables authorization checking of the 402 * user for the console(s) being accessed. As the 403 * authorization checking can be done only for a local 404 * client process, it requires that vntsd listen only 405 * on the loopback address. It means while this option 406 * is enabled, vntsd cannot listen on either INADDR_ANY 407 * or a specific ip address and thus the telnet client 408 * must also run on the local machine in order to 409 * connect to vntsd. The '-p' option if specified while 410 * this option is enabled, will be ignored and the auth 411 * checking takes precedence forcing vntsd to listen on 412 * the loopback interface. 413 */ 414 vntsdp->options |= VNTSD_OPT_AUTH_CHECK; 415 break; 416 417 default: 418 vntsd_help(); 419 exit(1); 420 } 421 } 422 423 if ((vntsdp->devinst == NULL) || (vntsdp->timeout == -1)) { 424 vntsd_help(); 425 exit(1); 426 } 427 428 if (listen_addr == NULL || strcmp(listen_addr, "localhost") == 0 || 429 strcmp(listen_addr, LOCALHOST_IPv4) == 0 || 430 strcmp(listen_addr, LOCALHOST_IPv6) == 0) { 431 /* by default listen on loopback interface */ 432 vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 433 } else if ((vntsdp->options & VNTSD_OPT_AUTH_CHECK) != 0) { 434 vntsd_log(VNTSD_STATUS_AUTH_ENABLED, 435 "Listen address ignored as authorization checking " 436 "is enabled"); 437 vntsdp->ip_addr.s_addr = htonl(INADDR_LOOPBACK); 438 } else if (strcmp(listen_addr, "any") == 0) { 439 vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); 440 } else { 441 vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); 442 if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { 443 syslog(LOG_ERR, 444 "Invalid listen address '%s'\n", 445 listen_addr); 446 exit(2); 447 } 448 } 449 450 D3(stderr, "options = %llx, instance = %s, listen = %s\n", 451 vntsdp->options, vntsdp->devinst, 452 listen_addr ? listen_addr : "<null>"); 453 454 /* open VCC driver control port */ 455 sz = strlen(VCC_DEVICE_CTL_PATH) + strlen(vntsdp->devinst) + 1; 456 path = calloc(sz, 1); 457 if (path == NULL) { 458 vntsd_log(VNTSD_ERR_NO_MEM, "main(): alloc dev path"); 459 exit(1); 460 } 461 (void) snprintf(path, sz-1, VCC_DEVICE_CTL_PATH, vntsdp->devinst, 462 sizeof (vntsdp->devinst)); 463 vntsdp->ctrl_fd = open(path, O_RDWR); 464 465 if (vntsdp->ctrl_fd == -1) { 466 /* print error if device is not present */ 467 syslog(LOG_ERR, 468 "Error opening VCC device control port: %s", 469 path); 470 /* tell SMF no retry */ 471 exit(2); 472 } 473 474 free(path); 475 476 if ((vntsdp->options & VNTSD_OPT_DAEMON_OFF) == 0) { 477 /* daemonize it */ 478 pid = fork(); 479 if (pid < 0) { 480 perror("fork"); 481 exit(1); 482 } 483 if (pid > 0) { 484 /* parent */ 485 exit(0); 486 } 487 488 /* 489 * child process (daemon) 490 * 491 * Close all file descriptors other than 2 and the ctrl fd. 492 */ 493 (void) close(0); 494 (void) close(1); 495 for (i = 3; i < vntsdp->ctrl_fd; i++) { 496 (void) close(i); 497 } 498 closefrom(vntsdp->ctrl_fd + 1); 499 500 /* obtain a new process group */ 501 (void) setsid(); 502 fd = open("/dev/null", O_RDWR); 503 if (fd < 0) { 504 syslog(LOG_ERR, "Can not open /dev/null"); 505 exit(1); 506 } 507 /* handle standard I/O */ 508 if (dup2(fd, 0) < 0) { 509 syslog(LOG_ERR, "Failed dup2()"); 510 exit(1); 511 } 512 513 if (dup2(fd, 1) < 0) { 514 syslog(LOG_ERR, "Failed dup2()"); 515 exit(1); 516 } 517 518 /* ignore terminal signals */ 519 (void) signal(SIGTSTP, SIG_IGN); 520 (void) signal(SIGTTOU, SIG_IGN); 521 (void) signal(SIGTTIN, SIG_IGN); 522 } 523 524 525 /* set up signal handlers */ 526 527 /* exit signals */ 528 act.sa_handler = exit_sig_handler; 529 530 (void) sigemptyset(&act.sa_mask); 531 (void) sigaction(SIGINT, &act, NULL); 532 (void) sigaction(SIGTERM, &act, NULL); 533 (void) sigaction(SIGHUP, &act, NULL); 534 535 /* vntsd internal signals */ 536 act.sa_handler = vntsd_sig_handler; 537 (void) sigemptyset(&act.sa_mask); 538 (void) sigaction(SIGUSR1, &act, NULL); 539 540 541 act.sa_handler = vntsd_alarm_sig_handler; 542 (void) sigemptyset(&act.sa_mask); 543 (void) sigaction(SIGALRM, &act, NULL); 544 545 546 /* setup exit */ 547 (void) atexit(vntsd_exit); 548 549 550 551 /* initialization */ 552 openlog("vntsd", LOG_CONS, LOG_DAEMON); 553 554 555 /* set alarm */ 556 if (vntsdp->timeout > 0) { 557 (void) alarm(MINUTE); 558 } 559 560 vntsdp->tid = thr_self(); 561 562 /* get exiting consoles from vcc */ 563 vntsd_get_config(vntsdp); 564 565 for (; ; ) { 566 /* poll vcc for configuration change */ 567 bzero(poll_drv, sizeof (poll_drv)); 568 569 poll_drv[0].fd = vntsdp->ctrl_fd; 570 poll_drv[0].events = POLLIN; 571 572 if (poll(poll_drv, 1, -1) == -1) { 573 if (errno == EINTR) { 574 /* wake up because a consle was deleted */ 575 vntsd_delete_cons(vntsdp); 576 continue; 577 } 578 vntsd_log(VNTSD_ERR_VCC_POLL, 579 "vcc control poll err! aborting.."); 580 exit(1); 581 } 582 583 D1(stderr, "t@%d driver event %x\n", thr_self(), 584 poll_drv[0].revents); 585 586 vntsd_daemon_wakeup(vntsdp); 587 /* 588 * Main thread may miss a console-delete signal when it is 589 * not polling vcc. check if any console is deleted. 590 */ 591 vntsd_delete_cons(vntsdp); 592 593 } 594 595 /*NOTREACHED*/ 596 return (0); 597 } 598 599 /* export ip_addr */ 600 struct in_addr 601 vntsd_ip_addr(void) 602 { 603 return (vntsdp->ip_addr); 604 } 605 606 /* 607 * ioctl to vcc control port 608 * Supported ioctls interface are: 609 * ioctl code parameters return data 610 * VCC_NUM_CONSOLE none uint_t no consoles 611 * VCC_CONS_TBL none array of vcc_cons_t 612 * VCC_INQUIRY none vcc_response_t response 613 * VCC_CONS_INFO uint_t portno vcc_cons_t 614 * VCC_CONS_STATUS uint_t portno 615 * VCC_FORCE_CLOSE uint_t portno 616 */ 617 int 618 vntsd_vcc_ioctl(int ioctl_code, uint_t portno, void *buf) 619 { 620 D1(stderr, "t@%d vcc_ioctl@%d code=%x\n", thr_self(), portno, 621 ioctl_code); 622 623 if ((ioctl_code == (VCC_CONS_INFO)) || 624 (ioctl_code == (VCC_FORCE_CLOSE))) { 625 /* construct vcc in buf */ 626 *((uint_t *)buf) = portno; 627 } 628 629 if (ioctl(vntsdp->ctrl_fd, ioctl_code, (caddr_t)buf)) { 630 /* ioctl request error */ 631 return (VNTSD_STATUS_VCC_IO_ERR); 632 } 633 634 return (VNTSD_SUCCESS); 635 } 636 637 /* 638 * check if a vcc i/o error is caused by removal of a console. If so 639 * wake up main thread to cleanup the console. 640 */ 641 int 642 vntsd_vcc_err(vntsd_cons_t *consp) 643 { 644 vntsd_group_t *groupp; 645 646 assert(consp); 647 groupp = consp->group; 648 assert(groupp); 649 650 if (consp->status & VNTSD_CONS_DELETED) { 651 /* console was deleted */ 652 return (VNTSD_STATUS_VCC_IO_ERR); 653 } 654 655 if (vntsd_vcc_cons_alive(consp)) { 656 /* console is ok */ 657 return (VNTSD_STATUS_CONTINUE); 658 } 659 660 /* console needs to be deleted */ 661 (void) mutex_lock(&consp->lock); 662 consp->status |= VNTSD_CONS_DELETED; 663 664 /* 665 * main thread will close all clients after receiving console 666 * delete signal. 667 */ 668 (void) mutex_unlock(&consp->lock); 669 670 /* mark the group */ 671 (void) mutex_lock(&groupp->lock); 672 groupp->status |= VNTSD_GROUP_CLEAN_CONS; 673 (void) mutex_unlock(&groupp->lock); 674 675 /* signal main thread to deleted console */ 676 (void) thr_kill(vntsdp->tid, SIGUSR1); 677 678 return (VNTSD_STATUS_VCC_IO_ERR); 679 } 680