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