17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3a3e8d7aSmb158278 * Common Development and Distribution License (the "License"). 6*3a3e8d7aSmb158278 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*3a3e8d7aSmb158278 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * This code implements the Starcat Virtual Console host daemon (see cvcd(1M)). 307c478bd9Sstevel@tonic-gate * It accepts one TCP connection at a time on a well-known port. Once a 317c478bd9Sstevel@tonic-gate * connection is accepted, the console redirection driver (cvcdredir(7D)) is 327c478bd9Sstevel@tonic-gate * opened, and console I/O is routed back and forth between the two file 332eaee53eSmb158278 * descriptors (network and redirection driver). Per-socket IPsec is used to 342eaee53eSmb158278 * secure the connection if it is enabled with the "-a", "-u" and or "-e" 352eaee53eSmb158278 * command line options. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <stdarg.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <string.h> 427c478bd9Sstevel@tonic-gate #include <strings.h> 43*3a3e8d7aSmb158278 #include <ctype.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate #include <fcntl.h> 467c478bd9Sstevel@tonic-gate #include <sys/filio.h> /* Just to get FIONBIO... */ 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <errno.h> 497c478bd9Sstevel@tonic-gate #include <stropts.h> 507c478bd9Sstevel@tonic-gate #include <signal.h> 517c478bd9Sstevel@tonic-gate #include <syslog.h> 527c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 537c478bd9Sstevel@tonic-gate #include <sys/stat.h> 547c478bd9Sstevel@tonic-gate #include <locale.h> 557c478bd9Sstevel@tonic-gate #include <limits.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #include <sys/priocntl.h> 587c478bd9Sstevel@tonic-gate #include <sys/tspriocntl.h> 597c478bd9Sstevel@tonic-gate #include <sys/rtpriocntl.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #include <netdb.h> 627c478bd9Sstevel@tonic-gate #include <sys/socket.h> 637c478bd9Sstevel@tonic-gate #include <tiuser.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #include <sys/sc_cvcio.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate /* 692eaee53eSmb158278 * Header files for per-socket IPsec 702eaee53eSmb158278 */ 712eaee53eSmb158278 #include <netinet/in.h> 722eaee53eSmb158278 #include <net/pfkeyv2.h> 732eaee53eSmb158278 742eaee53eSmb158278 /* 752eaee53eSmb158278 * The IPsec socket option struct, from ipsec(7P): 762eaee53eSmb158278 * 772eaee53eSmb158278 * typedef struct ipsec_req { 782eaee53eSmb158278 * uint_t ipsr_ah_req; AH request 792eaee53eSmb158278 * uint_t ipsr_esp_req; ESP request 802eaee53eSmb158278 * uint_t ipsr_self_encap_req; Self-Encap request 812eaee53eSmb158278 * uint8_t ipsr_auth_alg; Auth algs for AH 822eaee53eSmb158278 * uint8_t ipsr_esp_alg; Encr algs for ESP 832eaee53eSmb158278 * uint8_t ipsr_esp_auth_alg; Auth algs for ESP 842eaee53eSmb158278 * } ipsec_req_t; 852eaee53eSmb158278 * 862eaee53eSmb158278 * The -a option sets the ipsr_auth_alg field. Allowable arguments 872eaee53eSmb158278 * are "none", "md5", or "sha1". The -e option sets the ipsr_esp_alg 882eaee53eSmb158278 * field. Allowable arguments are "none", "des", or "3des". "none" 892eaee53eSmb158278 * is the default for both options. The -u option sets ipsr_esp_auth_alg. 902eaee53eSmb158278 * Allowable arguments are the same as -a. 912eaee53eSmb158278 * 922eaee53eSmb158278 * The arguments ("md5", "des", etc.) are named so that they match 932eaee53eSmb158278 * kmd(1m)'s accepted arguments which are listed on the SC in 942eaee53eSmb158278 * /etc/opt/SUNWSMS/SMS/config/kmd_policy.cf. 952eaee53eSmb158278 */ 962eaee53eSmb158278 #define AH_REQ (IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE) 972eaee53eSmb158278 #define ESP_REQ (IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE) 982eaee53eSmb158278 #define SELF_ENCAP_REQ 0x0 992eaee53eSmb158278 1002eaee53eSmb158278 /* 1012eaee53eSmb158278 * A type to hold the command line argument string used to select a 1022eaee53eSmb158278 * particular authentication header (AH) or encapsulating security 1032eaee53eSmb158278 * payload (ESP) algorithm and the ID used for that algorithm when 1042eaee53eSmb158278 * filling the ipsec_req_t structure which is passed to 1052eaee53eSmb158278 * setsockopt(3SOCKET). 1062eaee53eSmb158278 */ 1072eaee53eSmb158278 typedef struct cvcd_alg { 1082eaee53eSmb158278 char *arg_name; 1092eaee53eSmb158278 uint8_t alg_id; 1102eaee53eSmb158278 } cvcd_alg_t; 1112eaee53eSmb158278 1122eaee53eSmb158278 /* 1137c478bd9Sstevel@tonic-gate * Misc. defines. 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate #define NODENAME "/etc/nodename" 1167c478bd9Sstevel@tonic-gate #define NETWORK_PFD 0 1177c478bd9Sstevel@tonic-gate #define REDIR_PFD 1 1187c478bd9Sstevel@tonic-gate #define LISTEN_PFD 2 1197c478bd9Sstevel@tonic-gate #define NUM_PFDS 3 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate /* 1227c478bd9Sstevel@tonic-gate * Function prototypes 1237c478bd9Sstevel@tonic-gate */ 1247c478bd9Sstevel@tonic-gate static void cvcd_set_priority(void); 1252eaee53eSmb158278 static int cvcd_init_host_socket(int port, uint8_t ah_auth_alg, 1262eaee53eSmb158278 uint8_t esp_encr_alg, uint8_t esp_auth_alg); 1277c478bd9Sstevel@tonic-gate static void cvcd_do_network_console(void); 1287c478bd9Sstevel@tonic-gate static void cvcd_err(int code, char *format, ...); 1297c478bd9Sstevel@tonic-gate static void cvcd_usage(void); 1302eaee53eSmb158278 static uint8_t cvcd_get_alg(cvcd_alg_t *algs, char *arg); 131*3a3e8d7aSmb158278 static boolean_t cvcd_global_policy(void); 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Globals 1357c478bd9Sstevel@tonic-gate */ 1367c478bd9Sstevel@tonic-gate static struct pollfd pfds[NUM_PFDS]; 1377c478bd9Sstevel@tonic-gate static char progname[MAXPATHLEN]; 1387c478bd9Sstevel@tonic-gate static int debug = 0; 1397c478bd9Sstevel@tonic-gate 1402eaee53eSmb158278 /* 1412eaee53eSmb158278 * Array of acceptable -a, -u and -e arguments. 1422eaee53eSmb158278 */ 1432eaee53eSmb158278 static cvcd_alg_t auth_algs_array[] = { 1442eaee53eSmb158278 { "none", SADB_AALG_NONE }, /* -a none or -u none */ 1452eaee53eSmb158278 { "md5", SADB_AALG_MD5HMAC }, /* -a md5 or -u md5 */ 1462eaee53eSmb158278 { "sha1", SADB_AALG_SHA1HMAC }, /* -a sha1 or -u sha1 */ 1472eaee53eSmb158278 { NULL, 0x0 } 1482eaee53eSmb158278 }, esp_algs_array[] = { 1492eaee53eSmb158278 { "none", SADB_EALG_NONE }, /* -e none */ 1502eaee53eSmb158278 { "des", SADB_EALG_DESCBC }, /* -e des */ 1512eaee53eSmb158278 { "3des", SADB_EALG_3DESCBC }, /* -e 3des */ 1522eaee53eSmb158278 { NULL, 0x0 } 1532eaee53eSmb158278 }; 1542eaee53eSmb158278 1552eaee53eSmb158278 156360e6f5eSmathue int 1577c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1587c478bd9Sstevel@tonic-gate { 1597c478bd9Sstevel@tonic-gate int err; 1607c478bd9Sstevel@tonic-gate int opt; 1617c478bd9Sstevel@tonic-gate int tport = 0; 1627c478bd9Sstevel@tonic-gate char *hostname; 1637c478bd9Sstevel@tonic-gate struct utsname utsname; 1647c478bd9Sstevel@tonic-gate int fd; 1657c478bd9Sstevel@tonic-gate int i; 1667c478bd9Sstevel@tonic-gate struct servent *se; 1677c478bd9Sstevel@tonic-gate char prefix[256]; 1682eaee53eSmb158278 uint8_t ah_auth_alg = SADB_AALG_NONE; 1692eaee53eSmb158278 uint8_t esp_encr_alg = SADB_EALG_NONE; 1702eaee53eSmb158278 uint8_t esp_auth_alg = SADB_AALG_NONE; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1737c478bd9Sstevel@tonic-gate (void) strcpy(progname, argv[0]); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate #ifdef DEBUG 1762eaee53eSmb158278 while ((opt = getopt(argc, argv, "a:e:u:dp:")) != EOF) { 1777c478bd9Sstevel@tonic-gate #else 1782eaee53eSmb158278 while ((opt = getopt(argc, argv, "a:e:u:")) != EOF) { 1797c478bd9Sstevel@tonic-gate #endif 1807c478bd9Sstevel@tonic-gate switch (opt) { 1812eaee53eSmb158278 case 'a' : 1822eaee53eSmb158278 case 'u' : 1832eaee53eSmb158278 if (opt == 'a') 1842eaee53eSmb158278 ah_auth_alg = cvcd_get_alg( 1852eaee53eSmb158278 auth_algs_array, optarg); 1862eaee53eSmb158278 else 1872eaee53eSmb158278 esp_auth_alg = cvcd_get_alg( 1882eaee53eSmb158278 auth_algs_array, optarg); 1892eaee53eSmb158278 break; 1902eaee53eSmb158278 1912eaee53eSmb158278 case 'e' : esp_encr_alg = cvcd_get_alg( 1922eaee53eSmb158278 esp_algs_array, optarg); 1932eaee53eSmb158278 break; 1947c478bd9Sstevel@tonic-gate #ifdef DEBUG 1957c478bd9Sstevel@tonic-gate case 'd' : debug = 1; 1967c478bd9Sstevel@tonic-gate break; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate case 'p' : tport = atoi(optarg); 1997c478bd9Sstevel@tonic-gate break; 2007c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate default : cvcd_usage(); 2037c478bd9Sstevel@tonic-gate exit(1); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (uname(&utsname) == -1) { 2087c478bd9Sstevel@tonic-gate perror("HOSTNAME not defined"); 2097c478bd9Sstevel@tonic-gate exit(1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate hostname = utsname.nodename; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * hostname may still be NULL, depends on when cvcd was started 2157c478bd9Sstevel@tonic-gate * in the boot sequence. If it is NULL, try one more time 2167c478bd9Sstevel@tonic-gate * to get a hostname -> look in the /etc/nodename file. 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate if (!strlen(hostname)) { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * try to get the hostname from the /etc/nodename file 2217c478bd9Sstevel@tonic-gate * we reuse the utsname.nodename buffer here! hostname 2227c478bd9Sstevel@tonic-gate * already points to it. 2237c478bd9Sstevel@tonic-gate */ 2247c478bd9Sstevel@tonic-gate if ((fd = open(NODENAME, O_RDONLY)) > 0) { 2257c478bd9Sstevel@tonic-gate if ((i = read(fd, utsname.nodename, SYS_NMLN)) <= 0) { 2267c478bd9Sstevel@tonic-gate cvcd_err(LOG_WARNING, 2277c478bd9Sstevel@tonic-gate "failed to acquire hostname"); 2287c478bd9Sstevel@tonic-gate } else { 2297c478bd9Sstevel@tonic-gate utsname.nodename[i-1] = '\0'; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate (void) close(fd); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * If all attempts to get the hostname have failed, put something 2367c478bd9Sstevel@tonic-gate * meaningful in the buffer. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate if (!strlen(hostname)) { 2397c478bd9Sstevel@tonic-gate (void) strcpy(utsname.nodename, "(unknown)"); 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * Must be root. 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate if (debug == 0 && geteuid() != 0) { 2467c478bd9Sstevel@tonic-gate fprintf(stderr, "cvcd: Must be root"); 2477c478bd9Sstevel@tonic-gate exit(1); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * Daemonize... 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate if (debug == 0) { 2542eaee53eSmb158278 closefrom(0); 2557c478bd9Sstevel@tonic-gate (void) chdir("/"); 2567c478bd9Sstevel@tonic-gate (void) umask(0); 2577c478bd9Sstevel@tonic-gate if (fork() != 0) { 2587c478bd9Sstevel@tonic-gate exit(0); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate (void) setpgrp(); 2617c478bd9Sstevel@tonic-gate (void) sprintf(prefix, "%s-(HOSTNAME:%s)", progname, hostname); 2627c478bd9Sstevel@tonic-gate openlog(prefix, LOG_CONS | LOG_NDELAY, LOG_LOCAL0); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * Initialize the array of pollfds used to track the listening socket, 2677c478bd9Sstevel@tonic-gate * the connection to the console redirection driver, and the network 2687c478bd9Sstevel@tonic-gate * connection. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate (void) memset((void *)pfds, 0, NUM_PFDS * sizeof (struct pollfd)); 2717c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_PFDS; i++) { 2727c478bd9Sstevel@tonic-gate pfds[i].fd = -1; 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* SPR 94004 */ 2767c478bd9Sstevel@tonic-gate (void) sigignore(SIGTERM); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * SPR 83644: cvc and kadb are not compatible under heavy loads. 2807c478bd9Sstevel@tonic-gate * Fix: will give cvcd highest TS priority at execution time. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate cvcd_set_priority(); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * If not already determined by a command-line flag, figure out which 2867c478bd9Sstevel@tonic-gate * port we're supposed to be listening on. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate if (tport == 0) { 2897c478bd9Sstevel@tonic-gate if ((se = getservbyname(CVCD_SERVICE, "tcp")) == NULL) { 2907c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "getservbyname(%s) not found", 2917c478bd9Sstevel@tonic-gate CVCD_SERVICE); 2927c478bd9Sstevel@tonic-gate exit(1); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate tport = se->s_port; 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate if (debug == 1) { 2987c478bd9Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "tport = %d, debug = %d", tport, debug); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * Attempt to initialize the socket we'll use to listen for incoming 3037c478bd9Sstevel@tonic-gate * connections. No need to check the return value, as the call will 3047c478bd9Sstevel@tonic-gate * exit if it fails. 3057c478bd9Sstevel@tonic-gate */ 3062eaee53eSmb158278 pfds[LISTEN_PFD].fd = cvcd_init_host_socket(tport, ah_auth_alg, 3072eaee53eSmb158278 esp_encr_alg, esp_auth_alg); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* 3107c478bd9Sstevel@tonic-gate * Now that we're all set up, we loop forever waiting for connections 3117c478bd9Sstevel@tonic-gate * (one at a time) and then driving network console activity over them. 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate for (;;) { 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * Start by waiting for an incoming connection. 3167c478bd9Sstevel@tonic-gate */ 3177c478bd9Sstevel@tonic-gate do { 3187c478bd9Sstevel@tonic-gate pfds[LISTEN_PFD].events = POLLIN; 3197c478bd9Sstevel@tonic-gate err = poll(&(pfds[LISTEN_PFD]), 1, -1); 3207c478bd9Sstevel@tonic-gate if (err == -1) { 3217c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); 3227c478bd9Sstevel@tonic-gate exit(1); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate if ((err > 0) && 3257c478bd9Sstevel@tonic-gate (pfds[LISTEN_PFD].revents & POLLIN)) { 3267c478bd9Sstevel@tonic-gate fd = accept(pfds[LISTEN_PFD].fd, NULL, NULL); 3277c478bd9Sstevel@tonic-gate if ((fd == -1) && (errno != EWOULDBLOCK)) { 3287c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "accept: %s", 3297c478bd9Sstevel@tonic-gate strerror(errno)); 3307c478bd9Sstevel@tonic-gate exit(1); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate } while (fd == -1); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * We have a connection. Set the new socket nonblocking, and 3377c478bd9Sstevel@tonic-gate * initialize the appropriate pollfd. In theory, the new socket 3387c478bd9Sstevel@tonic-gate * is _already_ non-blocking because accept() is supposed to 3397c478bd9Sstevel@tonic-gate * hand us a socket with the same properties as the socket we're 3407c478bd9Sstevel@tonic-gate * listening on, but it won't hurt to make sure. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate opt = 1; 3437c478bd9Sstevel@tonic-gate err = ioctl(fd, FIONBIO, &opt); 3447c478bd9Sstevel@tonic-gate if (err == -1) { 3457c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "ioctl: %s", strerror(errno)); 3467c478bd9Sstevel@tonic-gate (void) close(fd); 3477c478bd9Sstevel@tonic-gate continue; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate pfds[NETWORK_PFD].fd = fd; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Since we're ready to do network console stuff, go ahead and 3537c478bd9Sstevel@tonic-gate * open the Network Console redirection driver, which will 3547c478bd9Sstevel@tonic-gate * switch traffic from the IOSRAM path to the network path if 3557c478bd9Sstevel@tonic-gate * the network path has been selected in cvc. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate fd = open(CVCREDIR_DEV, O_RDWR|O_NDELAY); 3587c478bd9Sstevel@tonic-gate if (fd == -1) { 3597c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "open(redir): %s", strerror(errno)); 3607c478bd9Sstevel@tonic-gate exit(1); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate pfds[REDIR_PFD].fd = fd; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * We have a network connection and we have the redirection 3667c478bd9Sstevel@tonic-gate * driver open, so drive the network console until something 3677c478bd9Sstevel@tonic-gate * changes. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate cvcd_do_network_console(); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * cvcd_do_network_console doesn't return until there's a 3737c478bd9Sstevel@tonic-gate * problem, so we need to close the network connection and the 3747c478bd9Sstevel@tonic-gate * redirection driver and start the whole loop over again. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate (void) close(pfds[NETWORK_PFD].fd); 3777c478bd9Sstevel@tonic-gate pfds[NETWORK_PFD].fd = -1; 3787c478bd9Sstevel@tonic-gate (void) close(pfds[REDIR_PFD].fd); 3797c478bd9Sstevel@tonic-gate pfds[REDIR_PFD].fd = -1; 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3837c478bd9Sstevel@tonic-gate return (1); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3862eaee53eSmb158278 /* 3872eaee53eSmb158278 * cvcd_get_alg 3882eaee53eSmb158278 * 3892eaee53eSmb158278 * Returns the ID of the first algorithm found in 3902eaee53eSmb158278 * the 'algs' array with a name matching 'arg'. If 3912eaee53eSmb158278 * there is no matching algorithm, the function does 3922eaee53eSmb158278 * not return. The 'algs' array must be terminated 3932eaee53eSmb158278 * by an entry containing a NULL 'arg_name' field. 3942eaee53eSmb158278 */ 3952eaee53eSmb158278 static uint8_t 3962eaee53eSmb158278 cvcd_get_alg(cvcd_alg_t *algs, char *arg) 3972eaee53eSmb158278 { 3982eaee53eSmb158278 cvcd_alg_t *alg; 3992eaee53eSmb158278 4002eaee53eSmb158278 for (alg = algs; alg->arg_name != NULL && arg != NULL; alg++) { 4012eaee53eSmb158278 if (strncmp(alg->arg_name, arg, strlen(alg->arg_name) + 1) 4022eaee53eSmb158278 == 0) { 4032eaee53eSmb158278 return (alg->alg_id); 4042eaee53eSmb158278 } 4052eaee53eSmb158278 } 4062eaee53eSmb158278 4072eaee53eSmb158278 cvcd_usage(); 4082eaee53eSmb158278 exit(1); 4092eaee53eSmb158278 /* NOTREACHED */ 4102eaee53eSmb158278 } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * cvcd_set_priority 4147c478bd9Sstevel@tonic-gate * 4157c478bd9Sstevel@tonic-gate * DESCRIBE 4167c478bd9Sstevel@tonic-gate * SPR 83644: cvc and kadb are not compatible under heavy loads. 4177c478bd9Sstevel@tonic-gate * Fix: will give cvcd highest TS priority at execution time. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate static void 4207c478bd9Sstevel@tonic-gate cvcd_set_priority(void) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate id_t pid, tsID; 4237c478bd9Sstevel@tonic-gate pcparms_t pcparms; 4247c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp; 4257c478bd9Sstevel@tonic-gate short tsmaxpri; 4267c478bd9Sstevel@tonic-gate pcinfo_t info; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate pid = getpid(); 4297c478bd9Sstevel@tonic-gate pcparms.pc_cid = PC_CLNULL; 4307c478bd9Sstevel@tonic-gate tsparmsp = (tsparms_t *)pcparms.pc_clparms; 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* Get scheduler properties for this PID */ 4337c478bd9Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS, (caddr_t)&pcparms) == -1L) { 4347c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "Warning: can't set priority."); 4357c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "priocntl(GETPARMS): %s", strerror(errno)); 4367c478bd9Sstevel@tonic-gate return; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* Get class ID and maximum priority for TS process class */ 4407c478bd9Sstevel@tonic-gate (void) strcpy(info.pc_clname, "TS"); 4417c478bd9Sstevel@tonic-gate if (priocntl(0L, 0L, PC_GETCID, (caddr_t)&info) == -1L) { 4427c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "Warning: can't set priority."); 4437c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "priocntl(GETCID): %s", strerror(errno)); 4447c478bd9Sstevel@tonic-gate return; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate tsmaxpri = ((struct tsinfo *)info.pc_clinfo)->ts_maxupri; 4477c478bd9Sstevel@tonic-gate tsID = info.pc_cid; 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* Print priority info in debug mode */ 4507c478bd9Sstevel@tonic-gate if (debug) { 4517c478bd9Sstevel@tonic-gate if (pcparms.pc_cid == tsID) { 4527c478bd9Sstevel@tonic-gate cvcd_err(LOG_DEBUG, 4537c478bd9Sstevel@tonic-gate "PID: %d, current priority: %d, Max priority: %d.", 4547c478bd9Sstevel@tonic-gate pid, tsparmsp->ts_upri, tsmaxpri); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate /* Change proc's priority to maxtspri */ 4587c478bd9Sstevel@tonic-gate pcparms.pc_cid = tsID; 4597c478bd9Sstevel@tonic-gate tsparmsp->ts_upri = tsmaxpri; 4607c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim = tsmaxpri; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_SETPARMS, (caddr_t)&pcparms) == -1L) { 4637c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "Warning: can't set priority."); 4647c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "priocntl(SETPARMS): %s", strerror(errno)); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* Print new priority info in debug mode */ 4687c478bd9Sstevel@tonic-gate if (debug) { 4697c478bd9Sstevel@tonic-gate if (priocntl(P_PID, pid, PC_GETPARMS, (caddr_t)&pcparms) == 4707c478bd9Sstevel@tonic-gate -1L) { 4717c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "priocntl(GETPARMS): %s", 4727c478bd9Sstevel@tonic-gate strerror(errno)); 4737c478bd9Sstevel@tonic-gate } else { 4747c478bd9Sstevel@tonic-gate cvcd_err(LOG_DEBUG, "PID: %d, new priority: %d.", pid, 4757c478bd9Sstevel@tonic-gate tsparmsp->ts_upri); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * cvcd_init_host_socket 4837c478bd9Sstevel@tonic-gate * 4847c478bd9Sstevel@tonic-gate * Given a TCP port number, create and initialize a socket appropriate for 4857c478bd9Sstevel@tonic-gate * accepting incoming connections to that port. 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate static int 4882eaee53eSmb158278 cvcd_init_host_socket(int port, uint8_t ah_auth_alg, uint8_t esp_encr_alg, 4892eaee53eSmb158278 uint8_t esp_auth_alg) 4907c478bd9Sstevel@tonic-gate { 4917c478bd9Sstevel@tonic-gate int err; 4927c478bd9Sstevel@tonic-gate int fd; 4937c478bd9Sstevel@tonic-gate int optval; 4947c478bd9Sstevel@tonic-gate int optlen = sizeof (optval); 4952eaee53eSmb158278 ipsec_req_t ipsec_req; /* For per-socket IPsec */ 4962eaee53eSmb158278 struct sockaddr_in6 sin6; /* IPv6 listen socket */ 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Start by creating the socket, which needs to support IPv6. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 5027c478bd9Sstevel@tonic-gate if (fd == -1) { 5037c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "socket: %s", strerror(errno)); 5047c478bd9Sstevel@tonic-gate exit(1); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate /* 5087c478bd9Sstevel@tonic-gate * Set the SO_REUSEADDR option, and make the socket non-blocking. 5097c478bd9Sstevel@tonic-gate */ 5107c478bd9Sstevel@tonic-gate optval = 1; 5117c478bd9Sstevel@tonic-gate err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen); 5127c478bd9Sstevel@tonic-gate if (err == -1) { 5137c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "setsockopt: %s", strerror(errno)); 5147c478bd9Sstevel@tonic-gate exit(1); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate err = ioctl(fd, FIONBIO, &optval); 5187c478bd9Sstevel@tonic-gate if (err == -1) { 5197c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "ioctl: %s", strerror(errno)); 5207c478bd9Sstevel@tonic-gate exit(1); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate /* 5242eaee53eSmb158278 * Enable per-socket IPsec if the user specified an AH or ESP 525*3a3e8d7aSmb158278 * algorithm to use and global policy is not in effect. 5262eaee53eSmb158278 */ 527*3a3e8d7aSmb158278 if (!cvcd_global_policy() && 528*3a3e8d7aSmb158278 (ah_auth_alg != SADB_AALG_NONE || esp_encr_alg != SADB_EALG_NONE || 529*3a3e8d7aSmb158278 esp_auth_alg != SADB_AALG_NONE)) { 5302eaee53eSmb158278 bzero(&ipsec_req, sizeof (ipsec_req)); 5312eaee53eSmb158278 5322eaee53eSmb158278 /* Hardcoded values */ 5332eaee53eSmb158278 ipsec_req.ipsr_self_encap_req = SELF_ENCAP_REQ; 5342eaee53eSmb158278 /* User defined */ 5352eaee53eSmb158278 ipsec_req.ipsr_auth_alg = ah_auth_alg; 5362eaee53eSmb158278 ipsec_req.ipsr_esp_alg = esp_encr_alg; 5372eaee53eSmb158278 if (ah_auth_alg != SADB_AALG_NONE) 5382eaee53eSmb158278 ipsec_req.ipsr_ah_req = AH_REQ; 5392eaee53eSmb158278 if (esp_encr_alg != SADB_EALG_NONE || 5402eaee53eSmb158278 esp_auth_alg != SADB_AALG_NONE) { 5412eaee53eSmb158278 ipsec_req.ipsr_esp_req = ESP_REQ; 5422eaee53eSmb158278 ipsec_req.ipsr_esp_auth_alg = esp_auth_alg; 5432eaee53eSmb158278 } 5442eaee53eSmb158278 5452eaee53eSmb158278 err = setsockopt(fd, IPPROTO_IPV6, IPV6_SEC_OPT, 5462eaee53eSmb158278 (void *)&ipsec_req, sizeof (ipsec_req)); 5472eaee53eSmb158278 5482eaee53eSmb158278 if (err == -1) { 5492eaee53eSmb158278 cvcd_err(LOG_ERR, "failed to enable per-socket IPsec"); 5502eaee53eSmb158278 cvcd_err(LOG_ERR, "setsockopt: %s", strerror(errno)); 5512eaee53eSmb158278 exit(1); 5522eaee53eSmb158278 } 5532eaee53eSmb158278 } 5542eaee53eSmb158278 5552eaee53eSmb158278 /* 5567c478bd9Sstevel@tonic-gate * Bind the socket to our local address and port. 5577c478bd9Sstevel@tonic-gate */ 5587c478bd9Sstevel@tonic-gate bzero(&sin6, sizeof (sin6)); 5597c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 5607c478bd9Sstevel@tonic-gate sin6.sin6_port = htons(port); 5617c478bd9Sstevel@tonic-gate sin6.sin6_addr = in6addr_any; 5627c478bd9Sstevel@tonic-gate err = bind(fd, (struct sockaddr *)&sin6, sizeof (sin6)); 5637c478bd9Sstevel@tonic-gate if (err == -1) { 5647c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "bind: %s", strerror(errno)); 5657c478bd9Sstevel@tonic-gate exit(1); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate /* 5697c478bd9Sstevel@tonic-gate * Indicate that we want to accept connections on this socket. Since we 5707c478bd9Sstevel@tonic-gate * only allow one connection at a time anyway, specify a maximum backlog 5717c478bd9Sstevel@tonic-gate * of 1. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate err = listen(fd, 1); 5747c478bd9Sstevel@tonic-gate if (err == -1) { 5757c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "listen: %s", strerror(errno)); 5767c478bd9Sstevel@tonic-gate exit(1); 5777c478bd9Sstevel@tonic-gate } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate return (fd); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * cvcd_do_network_console 5857c478bd9Sstevel@tonic-gate * 5867c478bd9Sstevel@tonic-gate * With established connections to the network and the redirection driver, 5877c478bd9Sstevel@tonic-gate * shuttle data between the two until something goes wrong. 5887c478bd9Sstevel@tonic-gate */ 5897c478bd9Sstevel@tonic-gate static void 5907c478bd9Sstevel@tonic-gate cvcd_do_network_console(void) 5917c478bd9Sstevel@tonic-gate { 5927c478bd9Sstevel@tonic-gate int i; 5937c478bd9Sstevel@tonic-gate int err; 5947c478bd9Sstevel@tonic-gate int count; 5957c478bd9Sstevel@tonic-gate short revents; 5967c478bd9Sstevel@tonic-gate int input_len = 0; 5977c478bd9Sstevel@tonic-gate int output_len = 0; 5987c478bd9Sstevel@tonic-gate int input_off = 0; 5997c478bd9Sstevel@tonic-gate int output_off = 0; 6007c478bd9Sstevel@tonic-gate char input_buf[MAXPKTSZ]; 6017c478bd9Sstevel@tonic-gate char output_buf[MAXPKTSZ]; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate for (;;) { 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Wait for activity on any of the open file descriptors, which 6067c478bd9Sstevel@tonic-gate * includes the ability to write data if we have any to write. 6077c478bd9Sstevel@tonic-gate * If poll() fails, break out of the network console processing 6087c478bd9Sstevel@tonic-gate * loop. 6097c478bd9Sstevel@tonic-gate */ 6107c478bd9Sstevel@tonic-gate pfds[LISTEN_PFD].events = POLLIN; 6117c478bd9Sstevel@tonic-gate pfds[NETWORK_PFD].events = POLLIN; 6127c478bd9Sstevel@tonic-gate if (output_len != 0) { 6137c478bd9Sstevel@tonic-gate pfds[NETWORK_PFD].events |= POLLOUT; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate pfds[REDIR_PFD].events = POLLIN; 6167c478bd9Sstevel@tonic-gate if (input_len != 0) { 6177c478bd9Sstevel@tonic-gate pfds[REDIR_PFD].events |= POLLOUT; 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate err = poll(pfds, NUM_PFDS, -1); 6207c478bd9Sstevel@tonic-gate if (err == -1) { 6217c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "poll: %s", strerror(errno)); 6227c478bd9Sstevel@tonic-gate break; 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * If any errors or hangups were detected, or one of our file 6277c478bd9Sstevel@tonic-gate * descriptors is bad, bail out of the network console 6287c478bd9Sstevel@tonic-gate * processing loop. 6297c478bd9Sstevel@tonic-gate */ 6307c478bd9Sstevel@tonic-gate for (i = 0; i < NUM_PFDS; i++) { 6317c478bd9Sstevel@tonic-gate revents = pfds[i].revents; 6327c478bd9Sstevel@tonic-gate if (revents & (POLLERR | POLLHUP | POLLNVAL)) { 6337c478bd9Sstevel@tonic-gate cvcd_err(LOG_NOTICE, 6347c478bd9Sstevel@tonic-gate "poll: status on %s fd:%s%s%s", 6357c478bd9Sstevel@tonic-gate ((i == LISTEN_PFD) ? "listen" : 6367c478bd9Sstevel@tonic-gate ((i == NETWORK_PFD) ? "network" : "redir")), 6377c478bd9Sstevel@tonic-gate (revents & POLLERR) ? " error" : "", 6387c478bd9Sstevel@tonic-gate (revents & POLLHUP) ? " hangup" : "", 6397c478bd9Sstevel@tonic-gate (revents & POLLNVAL) ? " bad fd" : ""); 6407c478bd9Sstevel@tonic-gate goto fail; /* 'break' wouldn't work here */ 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate /* 6457c478bd9Sstevel@tonic-gate * Start by rejecting any connection attempts, since we only 6467c478bd9Sstevel@tonic-gate * allow one network connection at a time. 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate if (pfds[LISTEN_PFD].revents & POLLIN) { 6497c478bd9Sstevel@tonic-gate int fd; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate fd = accept(pfds[LISTEN_PFD].fd, NULL, NULL); 6527c478bd9Sstevel@tonic-gate if (fd > 0) { 6537c478bd9Sstevel@tonic-gate (void) close(fd); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* 6587c478bd9Sstevel@tonic-gate * If we have data waiting to be written in one direction or the 6597c478bd9Sstevel@tonic-gate * other, go ahead and try to send the data on its way. We're 6607c478bd9Sstevel@tonic-gate * going to attempt the writes regardless of whether the poll 6617c478bd9Sstevel@tonic-gate * indicated that the destinations are ready, because we want to 6627c478bd9Sstevel@tonic-gate * find out if either descriptor has a problem (e.g. broken 6637c478bd9Sstevel@tonic-gate * network link). 6647c478bd9Sstevel@tonic-gate * If an "unexpected" error is detected, give up and break out 6657c478bd9Sstevel@tonic-gate * of the network console processing loop. 6667c478bd9Sstevel@tonic-gate */ 6677c478bd9Sstevel@tonic-gate if (output_len != 0) { 6687c478bd9Sstevel@tonic-gate count = write(pfds[NETWORK_PFD].fd, 6697c478bd9Sstevel@tonic-gate &(output_buf[output_off]), output_len); 6707c478bd9Sstevel@tonic-gate if ((count == -1) && (errno != EAGAIN)) { 6717c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "write(network): %s", 6727c478bd9Sstevel@tonic-gate strerror(errno)); 6737c478bd9Sstevel@tonic-gate break; 6747c478bd9Sstevel@tonic-gate } else if (count > 0) { 6757c478bd9Sstevel@tonic-gate output_len -= count; 6767c478bd9Sstevel@tonic-gate if (output_len == 0) { 6777c478bd9Sstevel@tonic-gate output_off = 0; 6787c478bd9Sstevel@tonic-gate } else { 6797c478bd9Sstevel@tonic-gate output_off += count; 6807c478bd9Sstevel@tonic-gate } 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (input_len != 0) { 6857c478bd9Sstevel@tonic-gate count = write(pfds[REDIR_PFD].fd, 6867c478bd9Sstevel@tonic-gate &(input_buf[input_off]), input_len); 6877c478bd9Sstevel@tonic-gate if ((count == -1) && (errno != EAGAIN)) { 6887c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "write(redir): %s", 6897c478bd9Sstevel@tonic-gate strerror(errno)); 6907c478bd9Sstevel@tonic-gate break; 6917c478bd9Sstevel@tonic-gate } else if (count > 0) { 6927c478bd9Sstevel@tonic-gate input_len -= count; 6937c478bd9Sstevel@tonic-gate if (input_len == 0) { 6947c478bd9Sstevel@tonic-gate input_off = 0; 6957c478bd9Sstevel@tonic-gate } else { 6967c478bd9Sstevel@tonic-gate input_off += count; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Finally, take a look at each data source and, if there isn't 7037c478bd9Sstevel@tonic-gate * any residual data from that source still waiting to be 7047c478bd9Sstevel@tonic-gate * processed, see if more data can be read. We don't want to 7057c478bd9Sstevel@tonic-gate * read more data from a source if we haven't finished 7067c478bd9Sstevel@tonic-gate * processing the last data we read from it because doing so 7077c478bd9Sstevel@tonic-gate * would maximize the amount of data lost if the network console 7087c478bd9Sstevel@tonic-gate * failed or was closed. 7097c478bd9Sstevel@tonic-gate * If an "unexpected" error is detected, give up and break out 7107c478bd9Sstevel@tonic-gate * of the network console processing loop. 7117c478bd9Sstevel@tonic-gate * The call to read() appears to be in the habit of returning 0 7127c478bd9Sstevel@tonic-gate * when you've read all of the data from a stream that has been 7137c478bd9Sstevel@tonic-gate * hung up, and poll apparently feels that that condition 7147c478bd9Sstevel@tonic-gate * justifies setting POLLIN, so we're going to treat 0 as an 7157c478bd9Sstevel@tonic-gate * error return from read(). 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate if ((output_len == 0) && (pfds[REDIR_PFD].revents & POLLIN)) { 7187c478bd9Sstevel@tonic-gate count = read(pfds[REDIR_PFD].fd, output_buf, MAXPKTSZ); 7197c478bd9Sstevel@tonic-gate if (count <= 0) { 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Reading 0 simply means there is no data 7227c478bd9Sstevel@tonic-gate * available, since this is a terminal. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate if ((count < 0) && (errno != EAGAIN)) { 7257c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "read(redir): %s", 7267c478bd9Sstevel@tonic-gate strerror(errno)); 7277c478bd9Sstevel@tonic-gate break; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } else { 7307c478bd9Sstevel@tonic-gate output_len = count; 7317c478bd9Sstevel@tonic-gate output_off = 0; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if ((input_len == 0) && (pfds[NETWORK_PFD].revents & POLLIN)) { 7367c478bd9Sstevel@tonic-gate count = read(pfds[NETWORK_PFD].fd, input_buf, MAXPKTSZ); 7377c478bd9Sstevel@tonic-gate if (count <= 0) { 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * Reading 0 here implies a hangup, since this 7407c478bd9Sstevel@tonic-gate * is a non-blocking socket that poll() reported 7417c478bd9Sstevel@tonic-gate * as having data available. This will 7427c478bd9Sstevel@tonic-gate * typically occur when the console user drops 7437c478bd9Sstevel@tonic-gate * to OBP or intentially switches to IOSRAM 7447c478bd9Sstevel@tonic-gate * mode. 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate if (count == 0) { 7477c478bd9Sstevel@tonic-gate cvcd_err(LOG_NOTICE, 7487c478bd9Sstevel@tonic-gate "read(network): hangup detected"); 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate } else if (errno != EAGAIN) { 7517c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "read(network): %s", 7527c478bd9Sstevel@tonic-gate strerror(errno)); 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate } else { 7567c478bd9Sstevel@tonic-gate input_len = count; 7577c478bd9Sstevel@tonic-gate input_off = 0; 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate } /* End forever loop */ 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* 7637c478bd9Sstevel@tonic-gate * If we get here, something bad happened during an attempt to access 7647c478bd9Sstevel@tonic-gate * either the redirection driver or the network connection. There 7657c478bd9Sstevel@tonic-gate * doesn't appear to be any way to avoid the possibility of losing 7667c478bd9Sstevel@tonic-gate * console input and/or input in that case, so we should at least report 7677c478bd9Sstevel@tonic-gate * the loss if it happens. 7687c478bd9Sstevel@tonic-gate * XXX - We could do more, but is it worth the effort? Logging the 7697c478bd9Sstevel@tonic-gate * lost data would be pretty easy... actually preserving it 7707c478bd9Sstevel@tonic-gate * in the console flow would be a lot harder. We're more robust 7717c478bd9Sstevel@tonic-gate * than the previous generation at this point, at least, so 7727c478bd9Sstevel@tonic-gate * perhaps that's enough for now? 7737c478bd9Sstevel@tonic-gate */ 7747c478bd9Sstevel@tonic-gate fail: 7757c478bd9Sstevel@tonic-gate if (input_len != 0) { 7767c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "console input lost"); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate if (output_len != 0) { 7797c478bd9Sstevel@tonic-gate cvcd_err(LOG_ERR, "console output lost"); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate static void 7857c478bd9Sstevel@tonic-gate cvcd_usage() 7867c478bd9Sstevel@tonic-gate { 7877c478bd9Sstevel@tonic-gate #if defined(DEBUG) 7882eaee53eSmb158278 (void) printf("%s [-d] [-p port] " 7892eaee53eSmb158278 "[-a none|md5|sha1] [-e none|des|3des] [-u none|md5|sha1]\n", 7902eaee53eSmb158278 progname); 7917c478bd9Sstevel@tonic-gate #else 7922eaee53eSmb158278 (void) printf("%s [-a none|md5|sha1] [-e none|des|3des] " 7932eaee53eSmb158278 "[-u none|md5|sha1]\n", progname); 7947c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7987c478bd9Sstevel@tonic-gate * cvcd_err () 7997c478bd9Sstevel@tonic-gate * 8007c478bd9Sstevel@tonic-gate * Description: 8017c478bd9Sstevel@tonic-gate * Log messages via syslog daemon. 8027c478bd9Sstevel@tonic-gate * 8037c478bd9Sstevel@tonic-gate * Input: 8047c478bd9Sstevel@tonic-gate * code - logging code 8057c478bd9Sstevel@tonic-gate * format - messages to log 8067c478bd9Sstevel@tonic-gate * 8077c478bd9Sstevel@tonic-gate * Output: 8087c478bd9Sstevel@tonic-gate * void 8097c478bd9Sstevel@tonic-gate * 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate static void 8127c478bd9Sstevel@tonic-gate cvcd_err(int code, char *format, ...) 8137c478bd9Sstevel@tonic-gate { 8147c478bd9Sstevel@tonic-gate va_list varg_ptr; 8157c478bd9Sstevel@tonic-gate char buf[MAXPKTSZ]; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate va_start(varg_ptr, format); 8187c478bd9Sstevel@tonic-gate (void) vsnprintf(buf, MAXPKTSZ, format, varg_ptr); 8197c478bd9Sstevel@tonic-gate va_end(varg_ptr); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate if (debug == 0) { 8227c478bd9Sstevel@tonic-gate syslog(code, buf); 8237c478bd9Sstevel@tonic-gate } else { 8247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", progname, buf); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate } 827*3a3e8d7aSmb158278 828*3a3e8d7aSmb158278 /* 829*3a3e8d7aSmb158278 * has_cvcd_token 830*3a3e8d7aSmb158278 * 831*3a3e8d7aSmb158278 * Look for "?port [cvc_hostd|442]" in input buf. 832*3a3e8d7aSmb158278 * Assume only a single thread calls here. 833*3a3e8d7aSmb158278 */ 834*3a3e8d7aSmb158278 static boolean_t 835*3a3e8d7aSmb158278 has_cvcd_token(char *buf) 836*3a3e8d7aSmb158278 { 837*3a3e8d7aSmb158278 char *token; 838*3a3e8d7aSmb158278 char *delims = "{} \t\n"; 839*3a3e8d7aSmb158278 boolean_t port = B_FALSE; 840*3a3e8d7aSmb158278 841*3a3e8d7aSmb158278 while ((token = strtok(buf, delims)) != NULL) { 842*3a3e8d7aSmb158278 buf = NULL; 843*3a3e8d7aSmb158278 if (port == B_TRUE) { 844*3a3e8d7aSmb158278 if (strcmp(token, "cvc_hostd") == 0 || 845*3a3e8d7aSmb158278 strcmp(token, "442") == 0) { 846*3a3e8d7aSmb158278 return (B_TRUE); 847*3a3e8d7aSmb158278 } else { 848*3a3e8d7aSmb158278 return (B_FALSE); 849*3a3e8d7aSmb158278 } 850*3a3e8d7aSmb158278 } 851*3a3e8d7aSmb158278 if (strlen(token) == 5) { 852*3a3e8d7aSmb158278 token++; 853*3a3e8d7aSmb158278 if (strcmp(token, "port") == 0) { 854*3a3e8d7aSmb158278 port = B_TRUE; 855*3a3e8d7aSmb158278 continue; 856*3a3e8d7aSmb158278 } 857*3a3e8d7aSmb158278 } 858*3a3e8d7aSmb158278 } 859*3a3e8d7aSmb158278 return (B_FALSE); 860*3a3e8d7aSmb158278 } 861*3a3e8d7aSmb158278 862*3a3e8d7aSmb158278 /* 863*3a3e8d7aSmb158278 * cvcd_global_policy 864*3a3e8d7aSmb158278 * 865*3a3e8d7aSmb158278 * Check global policy file for cvcd entry. Just covers common cases. 866*3a3e8d7aSmb158278 */ 867*3a3e8d7aSmb158278 static boolean_t 868*3a3e8d7aSmb158278 cvcd_global_policy() 869*3a3e8d7aSmb158278 { 870*3a3e8d7aSmb158278 FILE *fp; 871*3a3e8d7aSmb158278 char buf[256]; 872*3a3e8d7aSmb158278 boolean_t rv = B_FALSE; 873*3a3e8d7aSmb158278 874*3a3e8d7aSmb158278 fp = fopen("/etc/inet/ipsecinit.conf", "r"); 875*3a3e8d7aSmb158278 if (fp == NULL) 876*3a3e8d7aSmb158278 return (B_FALSE); 877*3a3e8d7aSmb158278 while (fgets(buf, sizeof (buf), fp) != NULL) { 878*3a3e8d7aSmb158278 if (buf[0] == '#') 879*3a3e8d7aSmb158278 continue; 880*3a3e8d7aSmb158278 if (has_cvcd_token(buf)) { 881*3a3e8d7aSmb158278 rv = B_TRUE; 882*3a3e8d7aSmb158278 cvcd_err(LOG_NOTICE, "cvcd using global policy"); 883*3a3e8d7aSmb158278 break; 884*3a3e8d7aSmb158278 } 885*3a3e8d7aSmb158278 } 886*3a3e8d7aSmb158278 (void) fclose(fp); 887*3a3e8d7aSmb158278 return (rv); 888*3a3e8d7aSmb158278 } 889