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