xref: /illumos-gate/usr/src/lib/libscf/common/scf_type.c (revision b56bf881a9655cb27b53cba1468312f7c6dfb0a2)
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 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <assert.h>
27 #include <repcache_protocol.h>
28 #include "scf_type.h"
29 #include <errno.h>
30 #include <libgen.h>
31 #include <libscf_priv.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
38 
39 #define	UTF8_TOP_N(n) \
40 	(0xff ^ (0xff >> (n)))		/* top N bits set */
41 
42 #define	UTF8_BOTTOM_N(n) \
43 	((1 << (n)) - 1)		/* bottom N bits set */
44 
45 /*
46  * The first byte of an n-byte UTF8 encoded character looks like:
47  *
48  *	n	bits
49  *
50  *	1	0xxxxxxx
51  *	2	110xxxxx
52  *	3	1110xxxx
53  *	4	11110xxx
54  *	5	111110xx
55  *	6	1111110x
56  *
57  * Continuation bytes are 01xxxxxx.
58  */
59 
60 #define	UTF8_MAX_BYTES	6
61 
62 /*
63  * number of bits in an n-byte UTF-8 encoding.  for multi-byte encodings,
64  * You get (7 - n) bits in the first byte, and 6 bits for each additional byte.
65  */
66 #define	UTF8_BITS(n)	/* 1 <= n <= 6 */			\
67 	((n) == 1)? 7 :						\
68 	(7 - (n) + 6 * ((n) - 1))
69 
70 #define	UTF8_SINGLE_BYTE(c) \
71 	(((c) & UTF8_TOP_N(1)) == 0)	/* 0xxxxxxx */
72 
73 #define	UTF8_HEAD_CHECK(c, n)		/* 2 <= n <= 6 */		\
74 	(((c) & UTF8_TOP_N((n) + 1)) == UTF8_TOP_N(n))
75 
76 #define	UTF8_HEAD_VALUE(c, n)		/* 2 <= n <= 6 */		\
77 	((c) & UTF8_BOTTOM_N(7 - (n)))	/* 'x' mask */
78 
79 #define	UTF8_CONT_CHECK(c) \
80 	(((c) & UTF8_TOP_N(2)) == UTF8_TOP_N(1))	/* 10xxxxxx */
81 
82 /*
83  * adds in the 6 new bits from a continuation byte
84  */
85 #define	UTF8_VALUE_UPDATE(v, c) \
86 	(((v) << 6) | ((c) & UTF8_BOTTOM_N(6)))
87 
88 /*
89  * URI components
90  */
91 
92 #define	URI_COMPONENT_COUNT	5
93 
94 enum {
95 	URI_SCHEME = 0x0,		/* URI scheme */
96 	URI_AUTHORITY,			/* URI authority */
97 	URI_PATH,			/* URI path */
98 	URI_QUERY,			/* URI query */
99 	URI_FRAGMENT			/* URI fragment  */
100 };
101 
102 static int
valid_utf8(const char * str_arg)103 valid_utf8(const char *str_arg)
104 {
105 	const char *str = str_arg;
106 	uint_t c;
107 	uint32_t v;
108 	int i, n;
109 
110 	while ((c = *str++) != 0) {
111 		if (UTF8_SINGLE_BYTE(c))
112 			continue;	/* ascii */
113 
114 		for (n = 2; n <= UTF8_MAX_BYTES; n++)
115 			if (UTF8_HEAD_CHECK(c, n))
116 				break;
117 
118 		if (n > UTF8_MAX_BYTES)
119 			return (0);		/* invalid head byte */
120 
121 		v = UTF8_HEAD_VALUE(c, n);
122 
123 		for (i = 1; i < n; i++) {
124 			c = *str++;
125 			if (!UTF8_CONT_CHECK(c))
126 				return (0);	/* invalid byte */
127 
128 			v = UTF8_VALUE_UPDATE(v, c);
129 		}
130 
131 		/*
132 		 * if v could have been encoded in the next smallest
133 		 * encoding, the string is not well-formed UTF-8.
134 		 */
135 		if ((v >> (UTF8_BITS(n - 1))) == 0)
136 			return (0);
137 	}
138 
139 	/*
140 	 * we've reached the end of the string -- make sure it is short enough
141 	 */
142 	return ((str - str_arg) < REP_PROTOCOL_VALUE_LEN);
143 }
144 
145 static int
valid_string(const char * str)146 valid_string(const char *str)
147 {
148 	return (strlen(str) < REP_PROTOCOL_VALUE_LEN);
149 }
150 
151 static int
valid_opaque(const char * str_arg)152 valid_opaque(const char *str_arg)
153 {
154 	const char *str = str_arg;
155 	uint_t c;
156 	ptrdiff_t len;
157 
158 	while ((c = *str++) != 0)
159 		if ((c < '0' || c > '9') && (c < 'a' || c > 'f') &&
160 		    (c < 'A' || c > 'F'))
161 			return (0);		/* not hex digit */
162 
163 	len = (str - str_arg) - 1;		/* not counting NIL byte */
164 	return ((len % 2) == 0 && len / 2 < REP_PROTOCOL_VALUE_LEN);
165 }
166 
167 /*
168  * Return 1 if the supplied parameter is a conformant URI (as defined
169  * by RFC 2396), 0 otherwise.
170  */
171 static int
valid_uri(const char * str)172 valid_uri(const char *str)
173 {
174 	/*
175 	 * URI Regular Expression. Compiled with regcmp(1).
176 	 *
177 	 * ^(([^:/?#]+:){0,1})$0(//([^/?#]*)$1){0,1}([^?#]*)$2
178 	 * (?([^#]*)$3){0,1}(#(.*)$4){0,1}
179 	 */
180 	char exp[] = {
181 		040, 074, 00, 060, 012, 0126, 05, 072, 057, 077, 043, 024,
182 		072, 057, 00, 00, 01, 014, 00, 00, 060, 020, 024, 057,
183 		024, 057, 074, 01, 0125, 04, 057, 077, 043, 014, 01, 01,
184 		057, 01, 00, 01, 074, 02, 0125, 03, 077, 043, 014, 02,
185 		02, 060, 014, 024, 077, 074, 03, 0125, 02, 043, 014, 03,
186 		03, 057, 02, 00, 01, 060, 012, 024, 043, 074, 04, 021,
187 		014, 04, 04, 057, 03, 00, 01, 064, 00,
188 		0};
189 	char uri[URI_COMPONENT_COUNT][REP_PROTOCOL_VALUE_LEN];
190 
191 	/*
192 	 * If the string is too long, then the URI cannot be valid. Also,
193 	 * this protects against buffer overflow attacks on the uri array.
194 	 */
195 	if (strlen(str) >= REP_PROTOCOL_VALUE_LEN)
196 		return (0);
197 
198 	if (regex(exp, str, uri[URI_SCHEME], uri[URI_AUTHORITY], uri[URI_PATH],
199 	    uri[URI_QUERY], uri[URI_FRAGMENT]) == NULL) {
200 		return (0);
201 	}
202 	/*
203 	 * To be a valid URI, the length of the URI_PATH must not be zero
204 	 */
205 	if (strlen(uri[URI_PATH]) == 0) {
206 		return (0);
207 	}
208 	return (1);
209 }
210 
211 /*
212  * Return 1 if the supplied parameter is a conformant fmri, 0
213  * otherwise.
214  */
215 static int
valid_fmri(const char * str)216 valid_fmri(const char *str)
217 {
218 	int ret;
219 	char fmri[REP_PROTOCOL_VALUE_LEN] = { 0 };
220 
221 	/*
222 	 * Try to parse the fmri, if we can parse it then it
223 	 * must be syntactically correct. Work on a copy of
224 	 * the fmri since the parsing process can modify the
225 	 * supplied string.
226 	 */
227 	if (strlcpy(fmri, str, sizeof (fmri)) >= sizeof (fmri))
228 		return (0);
229 
230 	ret = ! scf_parse_fmri(fmri, NULL, NULL, NULL, NULL, NULL, NULL);
231 
232 	return (ret);
233 }
234 
235 /*
236  * check_prefix()
237  * Return 1 if the prefix is a valid IPv4 or IPv6 network prefix, 0 otherwise
238  */
239 static int
check_net_prefix(const char * p,int max_len)240 check_net_prefix(const char *p, int max_len)
241 {
242 	char *end;
243 	int len;
244 
245 	len = strtol(p, &end, 10);
246 	if (p == end || len < 0 || len > max_len)
247 		return (0);
248 
249 	return (1);
250 }
251 
252 /*
253  * Return 1 if the supplied IP address is valid, 0 otherwise.
254  */
255 static int
valid_ip(int af,const char * str)256 valid_ip(int af, const char *str)
257 {
258 	void *unused[4];
259 	const char *addr = str;
260 	char buf[INET6_ADDRSTRLEN]; /* enough for both IPv4 and IPv6 */
261 	char *net_prefix;
262 	int buf_sz;
263 	int plen;
264 
265 	switch (af) {
266 	case AF_INET:
267 		buf_sz = INET_ADDRSTRLEN;
268 		plen = 32; /* bit size of an IPv4 */
269 		break;
270 
271 	case AF_INET6:
272 		buf_sz = INET6_ADDRSTRLEN;
273 		plen = 128; /* bit size of an IPv6 */
274 		break;
275 
276 	default:
277 		assert(0);
278 		abort();
279 	}
280 
281 	/* check network prefix for the IP address */
282 	if ((net_prefix = strchr(str, '/')) != NULL) {
283 		if (check_net_prefix(++net_prefix, plen) == 0)
284 			return (0);
285 
286 		(void) strlcpy(buf, str, buf_sz);
287 		if ((net_prefix = strchr(buf, '/')) != NULL)
288 			*net_prefix = '\0';
289 
290 		addr = buf;
291 	}
292 
293 	return (inet_pton(af, addr, unused));
294 }
295 
296 rep_protocol_value_type_t
scf_proto_underlying_type(rep_protocol_value_type_t t)297 scf_proto_underlying_type(rep_protocol_value_type_t t)
298 {
299 	switch (t) {
300 	case REP_PROTOCOL_TYPE_BOOLEAN:
301 	case REP_PROTOCOL_TYPE_COUNT:
302 	case REP_PROTOCOL_TYPE_INTEGER:
303 	case REP_PROTOCOL_TYPE_TIME:
304 	case REP_PROTOCOL_TYPE_STRING:
305 	case REP_PROTOCOL_TYPE_OPAQUE:
306 		return (t);
307 
308 	case REP_PROTOCOL_SUBTYPE_USTRING:
309 		return (REP_PROTOCOL_TYPE_STRING);
310 
311 	case REP_PROTOCOL_SUBTYPE_URI:
312 		return (REP_PROTOCOL_SUBTYPE_USTRING);
313 	case REP_PROTOCOL_SUBTYPE_FMRI:
314 		return (REP_PROTOCOL_SUBTYPE_URI);
315 
316 	case REP_PROTOCOL_SUBTYPE_HOST:
317 		return (REP_PROTOCOL_SUBTYPE_USTRING);
318 	case REP_PROTOCOL_SUBTYPE_HOSTNAME:
319 		return (REP_PROTOCOL_SUBTYPE_HOST);
320 	case REP_PROTOCOL_SUBTYPE_NETADDR:
321 		return (REP_PROTOCOL_SUBTYPE_HOST);
322 	case REP_PROTOCOL_SUBTYPE_NETADDR_V4:
323 		return (REP_PROTOCOL_SUBTYPE_NETADDR);
324 	case REP_PROTOCOL_SUBTYPE_NETADDR_V6:
325 		return (REP_PROTOCOL_SUBTYPE_NETADDR);
326 
327 	case REP_PROTOCOL_TYPE_INVALID:
328 	default:
329 		return (REP_PROTOCOL_TYPE_INVALID);
330 	}
331 }
332 
333 int
scf_is_compatible_protocol_type(rep_protocol_value_type_t base,rep_protocol_value_type_t new)334 scf_is_compatible_protocol_type(rep_protocol_value_type_t base,
335     rep_protocol_value_type_t new)
336 {
337 	rep_protocol_value_type_t t, cur;
338 
339 	if (base == REP_PROTOCOL_TYPE_INVALID)
340 		return (0);
341 
342 	if (base == new)
343 		return (1);
344 
345 	for (t = new; t != (cur = scf_proto_underlying_type(t)); t = cur) {
346 		if (cur == REP_PROTOCOL_TYPE_INVALID)
347 			return (0);
348 		if (cur == base)
349 			return (1);		/* base is parent of new */
350 	}
351 	return (0);
352 }
353 
354 static int
valid_encoded_value(rep_protocol_value_type_t t,const char * v)355 valid_encoded_value(rep_protocol_value_type_t t, const char *v)
356 {
357 	char *p;
358 	ulong_t ns;
359 
360 	switch (t) {
361 	case REP_PROTOCOL_TYPE_BOOLEAN:
362 		return ((*v == '0' || *v == '1') && v[1] == 0);
363 
364 	case REP_PROTOCOL_TYPE_COUNT:
365 		errno = 0;
366 		if (strtoull(v, &p, 10) != 0 && *v == '0')
367 			return (0);
368 		return (errno == 0 && p != v && *p == 0);
369 
370 	case REP_PROTOCOL_TYPE_INTEGER:
371 		errno = 0;
372 		if (strtoll(v, &p, 10) != 0 && *v == '0')
373 			return (0);
374 		return (errno == 0 && p != v && *p == 0);
375 
376 	case REP_PROTOCOL_TYPE_TIME:
377 		errno = 0;
378 		(void) strtoll(v, &p, 10);
379 		if (errno != 0 || p == v || (*p != 0 && *p != '.'))
380 			return (0);
381 		if (*p == '.') {
382 			v = p + 1;
383 			errno = 0;
384 			ns = strtoul(v, &p, 10);
385 
386 			/* must be exactly 9 digits */
387 			if ((p - v) != 9 || errno != 0 || *p != 0)
388 				return (0);
389 			if (ns >= NANOSEC)
390 				return (0);
391 		}
392 		return (1);
393 
394 	case REP_PROTOCOL_TYPE_STRING:
395 		return (valid_string(v));
396 
397 	case REP_PROTOCOL_TYPE_OPAQUE:
398 		return (valid_opaque(v));
399 
400 	/*
401 	 * The remaining types are subtypes -- because of the way
402 	 * scf_validate_encoded_value() works, we can rely on the fact
403 	 * that v is a valid example of our base type.  We only have to
404 	 * check our own additional restrictions.
405 	 */
406 	case REP_PROTOCOL_SUBTYPE_USTRING:
407 		return (valid_utf8(v));
408 
409 	case REP_PROTOCOL_SUBTYPE_URI:
410 		return (valid_uri(v));
411 
412 	case REP_PROTOCOL_SUBTYPE_FMRI:
413 		return (valid_fmri(v));
414 
415 	case REP_PROTOCOL_SUBTYPE_HOST:
416 		return (valid_encoded_value(REP_PROTOCOL_SUBTYPE_HOSTNAME, v) ||
417 		    valid_encoded_value(REP_PROTOCOL_SUBTYPE_NETADDR, v));
418 
419 	case REP_PROTOCOL_SUBTYPE_HOSTNAME:
420 		/* XXX check for valid hostname */
421 		return (valid_utf8(v));
422 
423 	case REP_PROTOCOL_SUBTYPE_NETADDR:
424 		return (valid_ip(AF_INET, v) || valid_ip(AF_INET6, v));
425 
426 	case REP_PROTOCOL_SUBTYPE_NETADDR_V4:
427 		return (valid_ip(AF_INET, v));
428 
429 	case REP_PROTOCOL_SUBTYPE_NETADDR_V6:
430 		return (valid_ip(AF_INET6, v));
431 
432 	case REP_PROTOCOL_TYPE_INVALID:
433 	default:
434 		return (0);
435 	}
436 }
437 
438 int
scf_validate_encoded_value(rep_protocol_value_type_t t,const char * v)439 scf_validate_encoded_value(rep_protocol_value_type_t t, const char *v)
440 {
441 	rep_protocol_value_type_t base, cur;
442 
443 	base = scf_proto_underlying_type(t);
444 	while ((cur = scf_proto_underlying_type(base)) != base)
445 		base = cur;
446 
447 	if (base != t && !valid_encoded_value(base, v))
448 		return (0);
449 
450 	return (valid_encoded_value(t, v));
451 }
452