xref: /titanic_51/usr/src/cmd/cvcd/sparc/sun4u/starcat/cvcd.c (revision 3a3e8d7acddcf5f846fdd54de49bd37c17e44d43)
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