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
KSSL_DEBUG(const char * format,...)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
get_portnum(const char * s,ushort_t * rport)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 *
create_instance_name(const char * arg,char ** inaddr_any_name,boolean_t is_create)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
usage_all(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
main(int argc,char ** argv)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