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