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
get_classful_prefix(in_addr_t addr)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
get_network_prefix(in_addr_t * addrp)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
parse_address(tsol_rhent_t * rh,const char * addrbuf)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 *
rhstr_to_ent(tsol_rhstr_t * rhstrp,int * errp,char ** errstrp)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
tsol_freerhent(tsol_rhent_t * rh)266 tsol_freerhent(tsol_rhent_t *rh)
267 {
268 if (rh != NULL)
269 free(rh);
270 }
271