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