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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * From "tsol_tndb_parser.c 7.24 01/09/05 SMI; TSOL 2.x" 26 * 27 * These functions parse entries in the "thrhdb" (remote host database) file. 28 * Each entry in the file has two fields, separated by a colon. The first 29 * field is the IP host or network address. The second is the name of the 30 * template to use (from tnrhtp). 31 * 32 * In order to help preserve sanity, we do not allow more than one unescaped 33 * colon in a line. 34 */ 35 36 #include <stdio.h> 37 #include <ctype.h> 38 #include <stdlib.h> 39 #include <stddef.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <libtsnet.h> 43 #include <sys/types.h> 44 #include <sys/socket.h> 45 #include <netinet/in.h> 46 #include <inet/ip.h> 47 #include <arpa/inet.h> 48 #include <nss.h> 49 #include <errno.h> 50 51 /* 52 * This routine deals with old pre-CIDR subnet address specifications. In the 53 * bad old days, a subnet was represented as: 54 * 55 * Expression Implied Prefix 56 * 10.1.1.0 /24 57 * 10.1.0.0 /16 58 * 10.0.0.0 /8 59 * 0.0.0.0 /0 60 */ 61 static int 62 get_classful_prefix(in_addr_t addr) 63 { 64 int bits; 65 66 if (addr == 0) 67 return (0); 68 addr = ntohl(addr); 69 for (bits = IP_ABITS; bits > 0 && (addr & 0xFF) == 0; bits -= 8) 70 addr >>= 8; 71 72 return (bits); 73 } 74 75 /* 76 * This routine deals with old pre-CIDR network address specifications. In the 77 * bad old days, a network was represented as: 78 * 79 * Expression Implied Prefix 80 * 10.1.1 /24 81 * 10.1 /16 82 * 10 /8 83 * 84 * This routine must compute the mask and left-align the address. 85 */ 86 static int 87 get_network_prefix(in_addr_t *addrp) 88 { 89 int bits; 90 in_addr_t addr; 91 92 addr = ntohl(*addrp); 93 for (bits = IP_ABITS; bits > 0 && addr < 0x01000000; bits -= 8) 94 addr <<= 8; 95 *addrp = htonl(addr); 96 97 return (bits); 98 } 99 100 static boolean_t 101 parse_address(tsol_rhent_t *rh, const char *addrbuf) 102 { 103 int upper_lim; 104 int len; 105 const uchar_t *aptr; 106 107 if (strchr(addrbuf, ':') == NULL) { 108 /* IPv4 address */ 109 rh->rh_address.ta_family = AF_INET; 110 if (inet_pton(AF_INET, addrbuf, 111 &rh->rh_address.ta_addr_v4) > 0) { 112 if (rh->rh_prefix == -1) 113 rh->rh_prefix = get_classful_prefix(rh-> 114 rh_address.ta_addr_v4.s_addr); 115 } else if ((rh->rh_address.ta_addr_v4.s_addr = 116 inet_network(addrbuf)) != (in_addr_t)-1) { 117 len = get_network_prefix(&rh->rh_address.ta_addr_v4. 118 s_addr); 119 if (rh->rh_prefix == -1) 120 rh->rh_prefix = len; 121 } else { 122 return (B_FALSE); 123 } 124 upper_lim = IP_ABITS; 125 aptr = (const uchar_t *)&rh->rh_address.ta_addr_v4; 126 } else { 127 /* IPv6 address */ 128 rh->rh_address.ta_family = AF_INET6; 129 if (inet_pton(AF_INET6, addrbuf, 130 &rh->rh_address.ta_addr_v6) <= 0) 131 return (B_FALSE); 132 if (rh->rh_prefix == -1) 133 rh->rh_prefix = IPV6_ABITS; 134 upper_lim = IPV6_ABITS; 135 aptr = (const uchar_t *)&rh->rh_address.ta_addr_v6; 136 } 137 138 if (rh->rh_prefix < 0 || rh->rh_prefix > upper_lim) 139 return (B_FALSE); 140 141 /* 142 * Verify that there are no bits set in the "host" portion of the 143 * IP address. 144 */ 145 len = rh->rh_prefix; 146 aptr += len / 8; 147 if ((len & 7) != 0) { 148 if ((*aptr++ & (0xff >> (len & 7))) != 0) 149 return (B_FALSE); 150 len = (len + 7) & ~7; 151 } 152 while (len < upper_lim) { 153 if (*aptr++ != 0) 154 return (B_FALSE); 155 len += 8; 156 } 157 158 return (B_TRUE); 159 } 160 161 tsol_rhent_t * 162 rhstr_to_ent(tsol_rhstr_t *rhstrp, int *errp, char **errstrp) 163 { 164 int len; 165 int err = 0; 166 char *cp, *cp2, *errstr; 167 char *address = rhstrp->address; 168 char *template = rhstrp->template; 169 char addrbuf[1024]; 170 tsol_rhent_t *rhentp = NULL; 171 172 /* 173 * The user can specify NULL pointers for these. Make sure that we 174 * don't have to deal with checking for NULL everywhere by just 175 * pointing to our own variables if the user gives NULL. 176 */ 177 if (errp == NULL) 178 errp = &err; 179 if (errstrp == NULL) 180 errstrp = &errstr; 181 /* The default, unless we find a more specific error locus. */ 182 *errstrp = address; 183 184 if (address == NULL || *address == '#' || *address == '\n') { 185 *errp = LTSNET_EMPTY; 186 if (template && *template != '\0' && *template != '#' && 187 *template != '\n') 188 *errstrp = template; 189 else if (address == NULL) 190 *errstrp = " "; 191 goto err_ret; 192 } 193 if (*address == '\0') { 194 *errp = LTSNET_NO_ADDR; 195 if (template && *template != '\0' && *template != '#' && 196 *template != '\n') 197 *errstrp = template; 198 goto err_ret; 199 } 200 if (template == NULL || *template == '#' || *template == '\n' || 201 *template == '\0') { 202 *errp = LTSNET_NO_HOSTTYPE; 203 goto err_ret; 204 } 205 if ((rhentp = calloc(1, sizeof (*rhentp))) == NULL) { 206 *errp = LTSNET_SYSERR; 207 return (NULL); 208 } 209 if ((cp = strrchr(address, '/')) != NULL) { 210 len = cp - address; 211 if (len >= sizeof (addrbuf)) { 212 *errp = LTSNET_ILL_ADDR; 213 goto err_ret; 214 } 215 (void) memset(addrbuf, '\0', sizeof (addrbuf)); 216 (void) memcpy(addrbuf, address, len); 217 cp++; 218 errno = 0; 219 rhentp->rh_prefix = strtol(cp, &cp2, 0); 220 if (errno != 0) { 221 *errp = LTSNET_SYSERR; 222 *errstrp = cp2; 223 goto err_ret; 224 } 225 if ((isdigit(*cp) == 0)) { 226 *errp = LTSNET_ILL_ADDR; 227 *errstrp = address; 228 goto err_ret; 229 } 230 } else { 231 rhentp->rh_prefix = -1; 232 (void) strlcpy(addrbuf, address, sizeof (addrbuf)); 233 } 234 if (strlcpy(rhentp->rh_template, template, 235 sizeof (rhentp->rh_template)) >= sizeof (rhentp->rh_template)) { 236 *errstrp = template; 237 *errp = LTSNET_ILL_NAME; 238 goto err_ret; 239 } 240 if (!parse_address(rhentp, addrbuf)) { 241 *errp = LTSNET_ILL_ADDR; 242 *errstrp = address; 243 goto err_ret; 244 } 245 246 #ifdef DEBUG 247 (void) fprintf(stdout, "rhstr_to_ent: %s:%s\n", 248 address, rhentp->rh_template); 249 #endif /* DEBUG */ 250 251 return (rhentp); 252 253 err_ret: 254 err = errno; 255 tsol_freerhent(rhentp); 256 errno = err; 257 #ifdef DEBUG 258 (void) fprintf(stderr, "\nrhstr_to_ent: %s: %s\n", 259 *errstrp, (char *)tsol_strerror(*errp, errno)); 260 #endif /* DEBUG */ 261 262 return (NULL); 263 } 264 265 void 266 tsol_freerhent(tsol_rhent_t *rh) 267 { 268 if (rh != NULL) 269 free(rh); 270 } 271