xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/kssl/ksslcfg/ksslcfg.c (revision 11d0a659fdd288190c17d8600ecd218e9a9b546d)
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 "ksslcfg.h"
38 
39 /*
40  * ksslcfg(1M)
41  *
42  * ksslcfg manages smf(5) instances for the Kernel SSL proxy module.
43  * It makes use of kssladm(1M) which does the grunt work.
44  */
45 
46 /*
47  * This version number is rather meaningless. In any case,
48  * version 2.0 adds support for IPv6 addresses.
49  */
50 #define	KSSLCFG_VERSION "Version 2.0"
51 
52 boolean_t verbose = B_FALSE;
53 const char *SERVICE_NAME = "network/ssl/proxy";
54 
55 void
56 KSSL_DEBUG(const char *format, ...)
57 {
58 	va_list ap;
59 
60 	if (verbose) {
61 		va_start(ap, format);
62 		(void) vprintf(format, ap);
63 		va_end(ap);
64 	}
65 }
66 
67 /*
68  * Convert string to port number and check for errors. Return 0 on error,
69  * 1 on success.
70  */
71 int
72 get_portnum(const char *s, ushort_t *rport)
73 {
74 	long long tmp_port;
75 	char *ep;
76 
77 	errno = 0;
78 	tmp_port = strtoll(s, &ep, 10);
79 	if (s == ep || *ep != '\0' || errno != 0)
80 		return (0);
81 	if (tmp_port < 1 || tmp_port > 65535)
82 		return (0);
83 
84 	if (rport != NULL)
85 		*rport = (ushort_t)tmp_port;
86 
87 	return (1);
88 }
89 
90 #define	ANY_ADDR	"INADDR_ANY"
91 
92 /*
93  * An instance name is formed using either the host name in the fully
94  * qualified domain name form (FQDN) which should map to a specific IP address
95  * or using INADDR_ANY which means all IP addresses.
96  *
97  * We do a lookup or reverse lookup to get the host name. It is assumed that
98  * the returned name is in the FQDN form. i.e. DNS is used.
99  */
100 char *
101 create_instance_name(const char *arg, char **inaddr_any_name,
102     boolean_t is_create)
103 {
104 	int len;
105 	uint16_t port;
106 	char *cname;
107 	char *instance_name;
108 	const char *prefix = "kssl-";
109 	char *first_space;
110 
111 	first_space = strchr(arg, ' ');
112 	if (first_space == NULL) {	/* No host name. Use INADDR_ANY. */
113 		if (get_portnum(arg, &port) == 0) {
114 			(void) fprintf(stderr,
115 			    gettext("Error: Invalid port value -- %s\n"),
116 			    arg);
117 			return (NULL);
118 		}
119 		KSSL_DEBUG("port=%d\n", port);
120 		if ((cname = strdup(ANY_ADDR)) == NULL)
121 			return (NULL);
122 	} else {
123 		char *temp_str;
124 		char *ptr;
125 		struct hostent *hp;
126 		boolean_t do_warn;
127 		int error_num;
128 		in_addr_t v4addr;
129 		in6_addr_t v6addr;
130 
131 		if (get_portnum(first_space + 1, &port) == 0) {
132 			(void) fprintf(stderr,
133 			    gettext("Error: Invalid port value -- %s\n"),
134 			    first_space + 1);
135 			return (NULL);
136 		}
137 		KSSL_DEBUG("port=%d\n", port);
138 
139 		if ((temp_str = strdup(arg)) == NULL)
140 			return (NULL);
141 		*(strchr(temp_str, ' ')) = '\0';
142 
143 		if (inet_pton(AF_INET6, temp_str, &v6addr) == 1) {
144 			/* Do a reverse lookup for the IPv6 address */
145 			hp = getipnodebyaddr(&v6addr, sizeof (v6addr),
146 			    AF_INET6, &error_num);
147 		} else if (inet_pton(AF_INET, temp_str, &v4addr) == 1) {
148 			/* Do a reverse lookup for the IPv4 address */
149 			hp = getipnodebyaddr(&v4addr, sizeof (v4addr),
150 			    AF_INET, &error_num);
151 		} else {
152 			/* Do a lookup for the host name */
153 			hp = getipnodebyname(temp_str, AF_INET6, AI_DEFAULT,
154 			    &error_num);
155 		}
156 
157 		if (hp == NULL) {
158 			(void) fprintf(stderr,
159 			    gettext("Error: Unknown host -- %s\n"), temp_str);
160 			free(temp_str);
161 			return (NULL);
162 		}
163 
164 		if ((ptr = cname = strdup(hp->h_name)) == NULL) {
165 			freehostent(hp);
166 			free(temp_str);
167 			return (NULL);
168 		}
169 
170 		freehostent(hp);
171 
172 		do_warn = B_TRUE;
173 		/* "s/./-/g" */
174 		while ((ptr = strchr(ptr, '.')) != NULL) {
175 			if (do_warn)
176 				do_warn = B_FALSE;
177 			*ptr = '-';
178 			ptr++;
179 		}
180 
181 		if (do_warn && is_create) {
182 			(void) fprintf(stderr,
183 			    gettext("Warning: %s does not appear to have a"
184 			    " registered DNS name.\n"), temp_str);
185 		}
186 
187 		free(temp_str);
188 	}
189 
190 	KSSL_DEBUG("Cannonical host name =%s\n", cname);
191 
192 	len = strlen(prefix) + strlen(cname) + 10;
193 	if ((instance_name = malloc(len)) == NULL) {
194 		(void) fprintf(stderr,
195 		    gettext("Error: memory allocation failure.\n"));
196 		return (NULL);
197 	}
198 	(void) snprintf(instance_name, len, "%s%s-%d", prefix, cname, port);
199 
200 	if (is_create) {
201 		len = strlen(prefix) + strlen(ANY_ADDR) + 10;
202 		if ((*inaddr_any_name = malloc(len)) == NULL) {
203 			(void) fprintf(stderr,
204 			    gettext("Error: memory allocation failure.\n"));
205 			free(cname);
206 			return (NULL);
207 		}
208 
209 		(void) snprintf(*inaddr_any_name, len,
210 		    "%s%s-%d", prefix, ANY_ADDR, port);
211 	}
212 
213 	free(cname);
214 	KSSL_DEBUG("instance_name=%s\n", instance_name);
215 	return (instance_name);
216 }
217 
218 static void
219 usage_all(void)
220 {
221 	(void) fprintf(stderr, gettext("Usage:\n"));
222 	usage_create(B_FALSE);
223 	usage_delete(B_FALSE);
224 	(void) fprintf(stderr, "ksslcfg -V\n");
225 	(void) fprintf(stderr, "ksslcfg -?\n");
226 }
227 
228 
229 int
230 main(int argc, char **argv)
231 {
232 	int rv = SUCCESS;
233 
234 	(void) setlocale(LC_ALL, "");
235 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
236 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
237 #endif
238 	(void) textdomain(TEXT_DOMAIN);
239 
240 	if (argc < 2) {
241 		usage_all();
242 		return (ERROR_USAGE);
243 	}
244 
245 	if (strcmp(argv[1], "create") == 0) {
246 		rv = do_create(argc, argv);
247 	} else if (strcmp(argv[1], "delete") == 0) {
248 		rv = do_delete(argc, argv);
249 	} else if (strcmp(argv[1], "-V") == 0) {
250 		(void) printf("%s\n", KSSLCFG_VERSION);
251 	} else if (strcmp(argv[1], "-?") == 0) {
252 		usage_all();
253 	} else {
254 		(void) fprintf(stderr,
255 		    gettext("Error: Unknown subcommand -- %s\n"), argv[1]);
256 		usage_all();
257 		rv = ERROR_USAGE;
258 	}
259 
260 	return (rv);
261 }
262