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