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