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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * From "misc.c 5.15 00/05/31 SMI; TSOL 2.x"
26 */
27
28 /*
29 * Miscellaneous user interfaces to trusted label functions.
30 */
31
32
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <libintl.h>
39 #include <libtsnet.h>
40 #include <tsol/label.h>
41
42 #include <net/route.h>
43
44 #define MAX_ATTR_LEN 1024
45
46 /*
47 * Parse off an entry from a line. Entry is stored in 'outbuf'. Returned
48 * value is a pointer to the first unprocessed input character from 'instr'.
49 */
50 const char *
parse_entry(char * outbuf,size_t outlen,const char * instr,const char * delimit)51 parse_entry(char *outbuf, size_t outlen, const char *instr,
52 const char *delimit)
53 {
54 boolean_t escape_state = B_FALSE;
55 boolean_t any_white;
56 char chr;
57
58 any_white = strchr(delimit, '\n') != NULL;
59
60 /*
61 * User may specify outlen as 0 to skip over a field without storing
62 * it anywhere. Otherwise, we need at least one byte for the
63 * terminating NUL plus one byte to store another byte from instr.
64 */
65 while (outlen != 1 && (chr = *instr++) != '\0') {
66 if (!escape_state) {
67 if (chr == '\\') {
68 escape_state = B_TRUE;
69 continue;
70 }
71 if (strchr(delimit, chr) != NULL)
72 break;
73 if (any_white && isspace(chr))
74 break;
75 }
76 escape_state = B_FALSE;
77 if (outlen > 0) {
78 *outbuf++ = chr;
79 outlen--;
80 }
81 }
82 if (outlen != 1)
83 instr--;
84 if (escape_state)
85 instr--;
86 if (outlen > 0)
87 *outbuf = '\0';
88 return (instr);
89 }
90
91 char *
sl_to_str(const m_label_t * sl)92 sl_to_str(const m_label_t *sl)
93 {
94 char *sl_str = NULL;
95 static char unknown_str[] = "UNKNOWN";
96
97 if (sl == NULL)
98 return (strdup(unknown_str));
99
100 if ((label_to_str(sl, &sl_str, M_LABEL, DEF_NAMES) != 0) &&
101 (label_to_str(sl, &sl_str, M_INTERNAL, DEF_NAMES) != 0))
102 return (strdup(unknown_str));
103
104 return (sl_str);
105 }
106
107 static const char *rtsa_keywords[] = {
108 #define SAK_MINSL 0
109 "min_sl",
110 #define SAK_MAXSL 1
111 "max_sl",
112 #define SAK_DOI 2
113 "doi",
114 #define SAK_CIPSO 3
115 "cipso",
116 #define SAK_SL 4
117 "sl",
118 #define SAK_INVAL 5
119 NULL
120 };
121
122 const char *
rtsa_to_str(const struct rtsa_s * rtsa,char * line,size_t len)123 rtsa_to_str(const struct rtsa_s *rtsa, char *line, size_t len)
124 {
125 size_t slen;
126 uint32_t mask, i;
127 char *sl_str = NULL;
128
129 slen = 0;
130 *line = '\0';
131 mask = rtsa->rtsa_mask;
132
133 for (i = 1; mask != 0 && i != 0 && slen < len - 1; i <<= 1) {
134 if (!(i & (RTSA_MINSL|RTSA_MAXSL|RTSA_DOI|RTSA_CIPSO)))
135 continue;
136 if (!(i & mask))
137 continue;
138 if (slen != 0)
139 line[slen++] = ',';
140 switch (i & mask) {
141 case RTSA_MINSL:
142 if ((mask & RTSA_MAXSL) &&
143 blequal(&rtsa->rtsa_slrange.lower_bound,
144 &rtsa->rtsa_slrange.upper_bound)) {
145
146 sl_str =
147 sl_to_str(&rtsa->rtsa_slrange.lower_bound);
148 slen += snprintf(line + slen, len - slen,
149 "sl=%s", sl_str);
150 free(sl_str);
151 sl_str = NULL;
152 mask ^= RTSA_MAXSL;
153 break;
154 }
155 sl_str = sl_to_str(&rtsa->rtsa_slrange.lower_bound);
156 slen += snprintf(line + slen, len - slen, "min_sl=%s",
157 sl_str);
158 free(sl_str);
159 sl_str = NULL;
160 break;
161 case RTSA_MAXSL:
162 sl_str = sl_to_str(&rtsa->rtsa_slrange.upper_bound);
163 slen += snprintf(line + slen, len - slen, "max_sl=%s",
164 sl_str);
165 free(sl_str);
166 sl_str = NULL;
167 break;
168 case RTSA_DOI:
169 slen += snprintf(line + slen, len - slen, "doi=%d",
170 rtsa->rtsa_doi);
171 break;
172 case RTSA_CIPSO:
173 slen += snprintf(line + slen, len - slen, "cipso");
174 break;
175 }
176 }
177
178 return (line);
179 }
180
181 boolean_t
rtsa_keyword(const char * options,struct rtsa_s * sp,int * errp,char ** errstrp)182 rtsa_keyword(const char *options, struct rtsa_s *sp, int *errp, char **errstrp)
183 {
184 const char *valptr, *nxtopt;
185 uint32_t mask = 0, doi;
186 int key;
187 m_label_t *min_sl = NULL, *max_sl = NULL;
188 char attrbuf[MAX_ATTR_LEN];
189 const char **keyword;
190 int err;
191 char *errstr, *cp;
192
193 if (errp == NULL)
194 errp = &err;
195 if (errstrp == NULL)
196 errstrp = &errstr;
197
198 *errstrp = (char *)options;
199
200 while (*options != '\0') {
201 valptr = parse_entry(attrbuf, sizeof (attrbuf), options, ",=");
202
203 if (attrbuf[0] == '\0') {
204 *errstrp = (char *)options;
205 *errp = LTSNET_ILL_ENTRY;
206 goto out_err;
207 }
208 for (keyword = rtsa_keywords; *keyword != NULL; keyword++)
209 if (strcmp(*keyword, attrbuf) == 0)
210 break;
211 if ((key = keyword - rtsa_keywords) == SAK_INVAL) {
212 *errstrp = (char *)options;
213 *errp = LTSNET_ILL_KEY;
214 goto out_err;
215 }
216 if ((key == SAK_CIPSO && *valptr == '=') ||
217 (key != SAK_CIPSO && *valptr != '=')) {
218 *errstrp = (char *)valptr;
219 *errp = LTSNET_ILL_VALDELIM;
220 goto out_err;
221 }
222
223 nxtopt = valptr;
224 if (*valptr == '=') {
225 valptr++;
226 nxtopt = parse_entry(attrbuf, sizeof (attrbuf),
227 valptr, ",=");
228 if (*nxtopt == '=') {
229 *errstrp = (char *)nxtopt;
230 *errp = LTSNET_ILL_KEYDELIM;
231 goto out_err;
232 }
233 }
234 if (*nxtopt == ',')
235 nxtopt++;
236
237 switch (key) {
238 case SAK_MINSL:
239 if (mask & RTSA_MINSL) {
240 *errstrp = (char *)options;
241 *errp = LTSNET_DUP_KEY;
242 goto out_err;
243 }
244 m_label_free(min_sl); /* in case of duplicate */
245 min_sl = NULL;
246 if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
247 L_NO_CORRECTION, NULL) != 0) {
248 *errstrp = (char *)valptr;
249 *errp = LTSNET_ILL_LOWERBOUND;
250 goto out_err;
251 }
252 mask |= RTSA_MINSL;
253 break;
254
255 case SAK_MAXSL:
256 if (mask & RTSA_MAXSL) {
257 *errstrp = (char *)options;
258 *errp = LTSNET_DUP_KEY;
259 goto out_err;
260 }
261 m_label_free(max_sl); /* in case of duplicate */
262 max_sl = NULL;
263 if (str_to_label(attrbuf, &max_sl, MAC_LABEL,
264 L_NO_CORRECTION, NULL) != 0) {
265 *errstrp = (char *)valptr;
266 *errp = LTSNET_ILL_UPPERBOUND;
267 goto out_err;
268 }
269 mask |= RTSA_MAXSL;
270 break;
271
272 case SAK_SL:
273 if (mask & (RTSA_MAXSL|RTSA_MINSL)) {
274 *errstrp = (char *)options;
275 *errp = LTSNET_DUP_KEY;
276 goto out_err;
277 }
278 m_label_free(min_sl); /* in case of duplicate */
279 min_sl = NULL;
280 if (str_to_label(attrbuf, &min_sl, MAC_LABEL,
281 L_NO_CORRECTION, NULL) != 0) {
282 *errstrp = (char *)valptr;
283 *errp = LTSNET_ILL_LABEL;
284 goto out_err;
285 }
286 *max_sl = *min_sl;
287 mask |= (RTSA_MINSL | RTSA_MAXSL);
288 break;
289
290 case SAK_DOI:
291 if (mask & RTSA_DOI) {
292 *errstrp = (char *)options;
293 *errp = LTSNET_DUP_KEY;
294 goto out_err;
295 }
296 errno = 0;
297 doi = strtoul(attrbuf, &cp, 0);
298 if (doi == 0 || errno != 0 || *cp != '\0') {
299 *errstrp = (char *)valptr;
300 *errp = LTSNET_ILL_DOI;
301 goto out_err;
302 }
303 mask |= RTSA_DOI;
304 break;
305
306 case SAK_CIPSO:
307 if (mask & RTSA_CIPSO) {
308 *errstrp = (char *)options;
309 *errp = LTSNET_DUP_KEY;
310 goto out_err;
311 }
312 mask |= RTSA_CIPSO;
313 break;
314 }
315
316 options = nxtopt;
317 }
318
319 /* Defaults to CIPSO if not specified */
320 mask |= RTSA_CIPSO;
321
322 /* If RTSA_CIPSO is specified, RTSA_DOI must be specified */
323 if (!(mask & RTSA_DOI)) {
324 *errp = LTSNET_NO_DOI;
325 goto out_err;
326 }
327
328 /* SL range must be specified */
329 if (!(mask & (RTSA_MINSL|RTSA_MAXSL))) {
330 *errp = LTSNET_NO_RANGE;
331 goto out_err;
332 }
333 if (!(mask & RTSA_MINSL)) {
334 *errp = LTSNET_NO_LOWERBOUND;
335 goto out_err;
336 }
337 if (!(mask & RTSA_MAXSL)) {
338 *errp = LTSNET_NO_UPPERBOUND;
339 goto out_err;
340 }
341
342 /* SL range must have upper bound dominating lower bound */
343 if (!bldominates(max_sl, min_sl)) {
344 *errp = LTSNET_ILL_RANGE;
345 goto out_err;
346 }
347
348 if (mask & RTSA_MINSL)
349 sp->rtsa_slrange.lower_bound = *min_sl;
350 if (mask & RTSA_MAXSL)
351 sp->rtsa_slrange.upper_bound = *max_sl;
352 if (mask & RTSA_DOI)
353 sp->rtsa_doi = doi;
354 sp->rtsa_mask = mask;
355
356 m_label_free(min_sl);
357 m_label_free(max_sl);
358
359 return (B_TRUE);
360
361 out_err:
362 m_label_free(min_sl);
363 m_label_free(max_sl);
364
365 return (B_FALSE);
366 }
367
368 /* Keep in sync with libtsnet.h */
369 static const char *tsol_errlist[] = {
370 "No error",
371 "System error",
372 "Empty string or end of list",
373 "Entry is malformed",
374 "Missing name",
375 "Missing attributes",
376 "Illegal name",
377 "Illegal keyword delimiter",
378 "Unknown keyword",
379 "Duplicate keyword",
380 "Illegal value delimiter",
381 "Missing host type",
382 "Illegal host type",
383 "Missing label",
384 "Illegal label",
385 "Missing label range",
386 "Illegal label range",
387 "No lower bound in range",
388 "Illegal lower bound in range",
389 "No upper bound in range",
390 "Illegal upper bound in range",
391 "Missing DOI",
392 "Illegal DOI",
393 "Too many entries in set",
394 "Missing address/network",
395 "Illegal address/network",
396 "Illegal flag",
397 "Illegal MLP specification",
398 "Unacceptable keyword for type"
399 };
400 static const int tsol_nerr = sizeof (tsol_errlist) / sizeof (*tsol_errlist);
401
402 const char *
tsol_strerror(int libtserr,int errnoval)403 tsol_strerror(int libtserr, int errnoval)
404 {
405 if (libtserr == LTSNET_SYSERR)
406 return (strerror(errnoval));
407 if (libtserr >= 0 && libtserr < tsol_nerr)
408 return (gettext(tsol_errlist[libtserr]));
409 return (gettext("Unknown error"));
410 }
411