xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1c28749e9Skais /*
2c28749e9Skais  * CDDL HEADER START
3c28749e9Skais  *
4c28749e9Skais  * The contents of this file are subject to the terms of the
5164c0dd6Skrishna  * Common Development and Distribution License (the "License").
6164c0dd6Skrishna  * You may not use this file except in compliance with the License.
7c28749e9Skais  *
8c28749e9Skais  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c28749e9Skais  * or http://www.opensolaris.org/os/licensing.
10c28749e9Skais  * See the License for the specific language governing permissions
11c28749e9Skais  * and limitations under the License.
12c28749e9Skais  *
13c28749e9Skais  * When distributing Covered Code, include this CDDL HEADER in each
14c28749e9Skais  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c28749e9Skais  * If applicable, add the following below this CDDL HEADER, with the
16c28749e9Skais  * fields enclosed by brackets "[]" replaced with your own identifying
17c28749e9Skais  * information: Portions Copyright [yyyy] [name of copyright owner]
18c28749e9Skais  *
19c28749e9Skais  * CDDL HEADER END
20c28749e9Skais  */
21c28749e9Skais /*
2211d0a659SVladimir Kotal  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23c28749e9Skais  */
24c28749e9Skais 
25c28749e9Skais #include <arpa/inet.h> /* inet_addr() */
26c28749e9Skais #include <ctype.h>
27c28749e9Skais #include <libscf.h>
28c28749e9Skais #include <netdb.h> /* hostent */
29c28749e9Skais #include <netinet/in.h> /* ip_addr_t */
30c28749e9Skais #include <stdio.h>
31c28749e9Skais #include <errno.h>
32c28749e9Skais #include <limits.h>
33c28749e9Skais #include <stdlib.h>
34c28749e9Skais #include <fcntl.h>
35c28749e9Skais #include <strings.h>
36c28749e9Skais #include <sys/varargs.h>
37665923daSVladimir Kotal #include <zone.h>
38c28749e9Skais #include "ksslcfg.h"
39c28749e9Skais 
40c28749e9Skais /*
41c28749e9Skais  * ksslcfg(1M)
42c28749e9Skais  *
43c28749e9Skais  * ksslcfg manages smf(5) instances for the Kernel SSL proxy module.
44c28749e9Skais  * It makes use of kssladm(1M) which does the grunt work.
45c28749e9Skais  */
46c28749e9Skais 
472ec7cc7fSKrishna Yenduri /*
482ec7cc7fSKrishna Yenduri  * This version number is rather meaningless. In any case,
492ec7cc7fSKrishna Yenduri  * version 2.0 adds support for IPv6 addresses.
502ec7cc7fSKrishna Yenduri  */
512ec7cc7fSKrishna Yenduri #define	KSSLCFG_VERSION "Version 2.0"
52c28749e9Skais 
53c28749e9Skais boolean_t verbose = B_FALSE;
54c28749e9Skais const char *SERVICE_NAME = "network/ssl/proxy";
55c28749e9Skais 
56c28749e9Skais void
KSSL_DEBUG(const char * format,...)57c28749e9Skais KSSL_DEBUG(const char *format, ...)
58c28749e9Skais {
59c28749e9Skais 	va_list ap;
60c28749e9Skais 
61c28749e9Skais 	if (verbose) {
62c28749e9Skais 		va_start(ap, format);
63c28749e9Skais 		(void) vprintf(format, ap);
64c28749e9Skais 		va_end(ap);
65c28749e9Skais 	}
66c28749e9Skais }
67c28749e9Skais 
6811d0a659SVladimir Kotal /*
6911d0a659SVladimir Kotal  * Convert string to port number and check for errors. Return 0 on error,
7011d0a659SVladimir Kotal  * 1 on success.
7111d0a659SVladimir Kotal  */
72c28749e9Skais int
get_portnum(const char * s,ushort_t * rport)73c28749e9Skais get_portnum(const char *s, ushort_t *rport)
74c28749e9Skais {
7511d0a659SVladimir Kotal 	long long tmp_port;
7611d0a659SVladimir Kotal 	char *ep;
77c28749e9Skais 
78c28749e9Skais 	errno = 0;
7911d0a659SVladimir Kotal 	tmp_port = strtoll(s, &ep, 10);
8011d0a659SVladimir Kotal 	if (s == ep || *ep != '\0' || errno != 0)
81c28749e9Skais 		return (0);
8211d0a659SVladimir Kotal 	if (tmp_port < 1 || tmp_port > 65535)
8311d0a659SVladimir Kotal 		return (0);
84c28749e9Skais 
85c28749e9Skais 	if (rport != NULL)
8611d0a659SVladimir Kotal 		*rport = (ushort_t)tmp_port;
8711d0a659SVladimir Kotal 
88c28749e9Skais 	return (1);
89c28749e9Skais }
90c28749e9Skais 
91c28749e9Skais #define	ANY_ADDR	"INADDR_ANY"
92c28749e9Skais 
93c28749e9Skais /*
94c28749e9Skais  * An instance name is formed using either the host name in the fully
95c28749e9Skais  * qualified domain name form (FQDN) which should map to a specific IP address
96c28749e9Skais  * or using INADDR_ANY which means all IP addresses.
97c28749e9Skais  *
98c28749e9Skais  * We do a lookup or reverse lookup to get the host name. It is assumed that
99c28749e9Skais  * the returned name is in the FQDN form. i.e. DNS is used.
100c28749e9Skais  */
101c28749e9Skais char *
create_instance_name(const char * arg,char ** inaddr_any_name,boolean_t is_create)102c28749e9Skais create_instance_name(const char *arg, char **inaddr_any_name,
103c28749e9Skais     boolean_t is_create)
104c28749e9Skais {
105c28749e9Skais 	int len;
106c28749e9Skais 	uint16_t port;
107c28749e9Skais 	char *cname;
108c28749e9Skais 	char *instance_name;
109c28749e9Skais 	const char *prefix = "kssl-";
1102ec7cc7fSKrishna Yenduri 	char *first_space;
111c28749e9Skais 
1122ec7cc7fSKrishna Yenduri 	first_space = strchr(arg, ' ');
1132ec7cc7fSKrishna Yenduri 	if (first_space == NULL) {	/* No host name. Use INADDR_ANY. */
114c28749e9Skais 		if (get_portnum(arg, &port) == 0) {
115c28749e9Skais 			(void) fprintf(stderr,
116c28749e9Skais 			    gettext("Error: Invalid port value -- %s\n"),
117c28749e9Skais 			    arg);
118c28749e9Skais 			return (NULL);
119c28749e9Skais 		}
120c28749e9Skais 		KSSL_DEBUG("port=%d\n", port);
121c28749e9Skais 		if ((cname = strdup(ANY_ADDR)) == NULL)
122c28749e9Skais 			return (NULL);
123c28749e9Skais 	} else {
124c28749e9Skais 		char *temp_str;
125c28749e9Skais 		char *ptr;
126c28749e9Skais 		struct hostent *hp;
127c28749e9Skais 		boolean_t do_warn;
1282ec7cc7fSKrishna Yenduri 		int error_num;
1292ec7cc7fSKrishna Yenduri 		in_addr_t v4addr;
1302ec7cc7fSKrishna Yenduri 		in6_addr_t v6addr;
131c28749e9Skais 
132c28749e9Skais 		if (get_portnum(first_space + 1, &port) == 0) {
133c28749e9Skais 			(void) fprintf(stderr,
134c28749e9Skais 			    gettext("Error: Invalid port value -- %s\n"),
135c28749e9Skais 			    first_space + 1);
136c28749e9Skais 			return (NULL);
137c28749e9Skais 		}
138c28749e9Skais 		KSSL_DEBUG("port=%d\n", port);
139c28749e9Skais 
140c28749e9Skais 		if ((temp_str = strdup(arg)) == NULL)
141c28749e9Skais 			return (NULL);
142c28749e9Skais 		*(strchr(temp_str, ' ')) = '\0';
143c28749e9Skais 
1442ec7cc7fSKrishna Yenduri 		if (inet_pton(AF_INET6, temp_str, &v6addr) == 1) {
1452ec7cc7fSKrishna Yenduri 			/* Do a reverse lookup for the IPv6 address */
1462ec7cc7fSKrishna Yenduri 			hp = getipnodebyaddr(&v6addr, sizeof (v6addr),
1472ec7cc7fSKrishna Yenduri 			    AF_INET6, &error_num);
1482ec7cc7fSKrishna Yenduri 		} else if (inet_pton(AF_INET, temp_str, &v4addr) == 1) {
1492ec7cc7fSKrishna Yenduri 			/* Do a reverse lookup for the IPv4 address */
1502ec7cc7fSKrishna Yenduri 			hp = getipnodebyaddr(&v4addr, sizeof (v4addr),
1512ec7cc7fSKrishna Yenduri 			    AF_INET, &error_num);
152c28749e9Skais 		} else {
1532ec7cc7fSKrishna Yenduri 			/* Do a lookup for the host name */
1542ec7cc7fSKrishna Yenduri 			hp = getipnodebyname(temp_str, AF_INET6, AI_DEFAULT,
1552ec7cc7fSKrishna Yenduri 			    &error_num);
1562ec7cc7fSKrishna Yenduri 		}
1572ec7cc7fSKrishna Yenduri 
1582ec7cc7fSKrishna Yenduri 		if (hp == NULL) {
159c28749e9Skais 			(void) fprintf(stderr,
1602ec7cc7fSKrishna Yenduri 			    gettext("Error: Unknown host -- %s\n"), temp_str);
161c28749e9Skais 			free(temp_str);
162c28749e9Skais 			return (NULL);
163c28749e9Skais 		}
164c28749e9Skais 
165c28749e9Skais 		if ((ptr = cname = strdup(hp->h_name)) == NULL) {
1662ec7cc7fSKrishna Yenduri 			freehostent(hp);
167c28749e9Skais 			free(temp_str);
168c28749e9Skais 			return (NULL);
169c28749e9Skais 		}
1702ec7cc7fSKrishna Yenduri 
1712ec7cc7fSKrishna Yenduri 		freehostent(hp);
1722ec7cc7fSKrishna Yenduri 
173c28749e9Skais 		do_warn = B_TRUE;
174c28749e9Skais 		/* "s/./-/g" */
175c28749e9Skais 		while ((ptr = strchr(ptr, '.')) != NULL) {
176c28749e9Skais 			if (do_warn)
177c28749e9Skais 				do_warn = B_FALSE;
178c28749e9Skais 			*ptr = '-';
179c28749e9Skais 			ptr++;
180c28749e9Skais 		}
181c28749e9Skais 
182c28749e9Skais 		if (do_warn && is_create) {
183c28749e9Skais 			(void) fprintf(stderr,
184c28749e9Skais 			    gettext("Warning: %s does not appear to have a"
185c28749e9Skais 			    " registered DNS name.\n"), temp_str);
186c28749e9Skais 		}
187c28749e9Skais 
188c28749e9Skais 		free(temp_str);
189c28749e9Skais 	}
190c28749e9Skais 
191c28749e9Skais 	KSSL_DEBUG("Cannonical host name =%s\n", cname);
192c28749e9Skais 
193c28749e9Skais 	len = strlen(prefix) + strlen(cname) + 10;
194c28749e9Skais 	if ((instance_name = malloc(len)) == NULL) {
195c28749e9Skais 		(void) fprintf(stderr,
196c28749e9Skais 		    gettext("Error: memory allocation failure.\n"));
197c28749e9Skais 		return (NULL);
198c28749e9Skais 	}
199c28749e9Skais 	(void) snprintf(instance_name, len, "%s%s-%d", prefix, cname, port);
200c28749e9Skais 
201c28749e9Skais 	if (is_create) {
202c28749e9Skais 		len = strlen(prefix) + strlen(ANY_ADDR) + 10;
203c28749e9Skais 		if ((*inaddr_any_name = malloc(len)) == NULL) {
204c28749e9Skais 			(void) fprintf(stderr,
205c28749e9Skais 			    gettext("Error: memory allocation failure.\n"));
206*9b1bd49fSVladimir Kotal 			free(instance_name);
207c28749e9Skais 			free(cname);
208c28749e9Skais 			return (NULL);
209c28749e9Skais 		}
210c28749e9Skais 
211c28749e9Skais 		(void) snprintf(*inaddr_any_name, len,
212c28749e9Skais 		    "%s%s-%d", prefix, ANY_ADDR, port);
213c28749e9Skais 	}
214c28749e9Skais 
215c28749e9Skais 	free(cname);
216c28749e9Skais 	KSSL_DEBUG("instance_name=%s\n", instance_name);
217c28749e9Skais 	return (instance_name);
218c28749e9Skais }
219c28749e9Skais 
220c28749e9Skais static void
usage_all(void)221c28749e9Skais usage_all(void)
222c28749e9Skais {
223c28749e9Skais 	(void) fprintf(stderr, gettext("Usage:\n"));
224c28749e9Skais 	usage_create(B_FALSE);
225c28749e9Skais 	usage_delete(B_FALSE);
226c28749e9Skais 	(void) fprintf(stderr, "ksslcfg -V\n");
227c28749e9Skais 	(void) fprintf(stderr, "ksslcfg -?\n");
228c28749e9Skais }
229c28749e9Skais 
230c28749e9Skais 
231c28749e9Skais int
main(int argc,char ** argv)232c28749e9Skais main(int argc, char **argv)
233c28749e9Skais {
234c28749e9Skais 	int rv = SUCCESS;
235c28749e9Skais 
236c28749e9Skais 	(void) setlocale(LC_ALL, "");
237c28749e9Skais #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
238c28749e9Skais #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
239c28749e9Skais #endif
240c28749e9Skais 	(void) textdomain(TEXT_DOMAIN);
241c28749e9Skais 
242665923daSVladimir Kotal 	/* Running from within a non-global zone is not supported yet. */
243665923daSVladimir Kotal 	if (getzoneid() != GLOBAL_ZONEID) {
244665923daSVladimir Kotal 		(void) fprintf(stderr,
245665923daSVladimir Kotal 		    gettext("Error: Configuring KSSL from within a non-global "
246665923daSVladimir Kotal 		    "zone is not supported.\nPlease run the command from "
247665923daSVladimir Kotal 		    "the global zone.\n"));
248665923daSVladimir Kotal 		return (ERROR_USAGE);
249665923daSVladimir Kotal 	}
250665923daSVladimir Kotal 
251c28749e9Skais 	if (argc < 2) {
252c28749e9Skais 		usage_all();
253c28749e9Skais 		return (ERROR_USAGE);
254c28749e9Skais 	}
255c28749e9Skais 
256c28749e9Skais 	if (strcmp(argv[1], "create") == 0) {
257c28749e9Skais 		rv = do_create(argc, argv);
258c28749e9Skais 	} else if (strcmp(argv[1], "delete") == 0) {
259c28749e9Skais 		rv = do_delete(argc, argv);
260c28749e9Skais 	} else if (strcmp(argv[1], "-V") == 0) {
261c28749e9Skais 		(void) printf("%s\n", KSSLCFG_VERSION);
262c28749e9Skais 	} else if (strcmp(argv[1], "-?") == 0) {
263c28749e9Skais 		usage_all();
264c28749e9Skais 	} else {
265c28749e9Skais 		(void) fprintf(stderr,
266c28749e9Skais 		    gettext("Error: Unknown subcommand -- %s\n"), argv[1]);
267c28749e9Skais 		usage_all();
268c28749e9Skais 		rv = ERROR_USAGE;
269c28749e9Skais 	}
270c28749e9Skais 
271c28749e9Skais 	return (rv);
272c28749e9Skais }
273