xref: /openbsd-src/lib/libradius/radius_attr.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /*	$OpenBSD: radius_attr.c,v 1.1 2015/07/20 23:52:29 yasuoka Exp $ */
2 
3 /*-
4  * Copyright (c) 2009 Internet Initiative Japan Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 
33 #include <md5.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "radius.h"
40 
41 #include "radius_local.h"
42 
43 #define FIND_ATTRIBUTE_BEGIN(constness, redolabel)		\
44 	constness RADIUS_ATTRIBUTE* attr;			\
45 	constness RADIUS_ATTRIBUTE* end;			\
46 								\
47 	attr = ATTRS_BEGIN(packet->pdata);			\
48 	end  = ATTRS_END(packet->pdata);			\
49 								\
50 	for (;; ATTRS_ADVANCE(attr))				\
51 	{							\
52 	redolabel						\
53 		if (attr >= end)				\
54 			break;					\
55 		if (attr->type != type)				\
56 			continue;				\
57 		{
58 
59 #define FIND_ATTRIBUTE_END \
60 	} }
61 
62 #define FIND_VS_ATTRIBUTE_BEGIN(constness, redolabel)		\
63 	constness RADIUS_ATTRIBUTE* attr;			\
64 	constness RADIUS_ATTRIBUTE* end;			\
65 								\
66 	attr = ATTRS_BEGIN(packet->pdata);			\
67 	end  = ATTRS_END(packet->pdata);			\
68 								\
69 	for (;; ATTRS_ADVANCE(attr))				\
70 	{							\
71 	redolabel						\
72 		if (attr >= end)				\
73 			break;					\
74 		if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)	\
75 			continue;				\
76 		if (attr->vendor != htonl(vendor))		\
77 			continue;				\
78 		if (attr->vtype != vtype)			\
79 			continue;				\
80 		{
81 
82 #define FIND_VS_ATTRIBUTE_END					\
83 	} }
84 
85 
86 int
87 radius_get_raw_attr_ptr(const RADIUS_PACKET * packet, uint8_t type,
88     const void **ptr, size_t * length)
89 {
90 	FIND_ATTRIBUTE_BEGIN(const,) {
91 		*length = attr->length - 2;
92 		*ptr = attr->data;
93 		return (0);
94 	} FIND_ATTRIBUTE_END;
95 
96 	return (-1);
97 }
98 
99 int
100 radius_get_vs_raw_attr_ptr(const RADIUS_PACKET * packet, uint32_t vendor,
101     uint8_t vtype, const void **ptr, size_t * length)
102 {
103 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
104 		*length = attr->vlength - 2;
105 		*ptr = attr->vdata;
106 		return (0);
107 	} FIND_VS_ATTRIBUTE_END;
108 
109 	return (-1);
110 }
111 
112 int
113 radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf,
114     size_t * length)
115 {
116 	FIND_ATTRIBUTE_BEGIN(const,) {
117 		*length = MINIMUM(attr->length - 2, *length);
118 		memcpy(buf, attr->data, *length);
119 		return (0);
120 	} FIND_ATTRIBUTE_END;
121 
122 	return (-1);
123 }
124 
125 int
126 radius_get_vs_raw_attr(const RADIUS_PACKET * packet, uint32_t vendor,
127     uint8_t vtype, void *buf, size_t * length)
128 {
129 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
130 		*length = MINIMUM(attr->vlength - 2, *length);
131 		memcpy(buf, attr->vdata, *length);
132 		return (0);
133 	} FIND_VS_ATTRIBUTE_END;
134 
135 	return (-1);
136 }
137 
138 int
139 radius_get_raw_attr_cat(const RADIUS_PACKET * packet, uint8_t type, void *buf,
140     size_t * length)
141 {
142 	size_t	 off = 0;
143 
144 	FIND_ATTRIBUTE_BEGIN(const,) {
145 		if (buf != NULL) {
146 			if (off + attr->length - 2 <= *length)
147 				memcpy((char *)buf + off, attr->data,
148 				    attr->length - 2);
149 			else
150 				return (-1);
151 		}
152 		off += attr->length - 2;
153 	} FIND_ATTRIBUTE_END;
154 
155 	*length = off;
156 
157 	return (0);
158 }
159 
160 int
161 radius_get_vs_raw_attr_cat(const RADIUS_PACKET * packet, uint32_t vendor,
162     uint8_t vtype, void *buf, size_t * length)
163 {
164 	size_t	 off = 0;
165 
166 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
167 		if (buf != NULL) {
168 			if (off + attr->vlength - 2 <= *length)
169 				memcpy((char *)buf + off, attr->vdata,
170 				    attr->vlength - 2);
171 			else
172 				return (-1);
173 		}
174 		off += attr->vlength - 2;
175 	} FIND_VS_ATTRIBUTE_END;
176 
177 	*length = off;
178 
179 	return (0);
180 }
181 
182 int
183 radius_put_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf,
184     size_t length)
185 {
186 	RADIUS_ATTRIBUTE	*newattr;
187 
188 	if (length > 255 - 2)
189 		return (-1);
190 
191 	if (radius_ensure_add_capacity(packet, length + 2) != 0)
192 		return (-1);
193 
194 	newattr = ATTRS_END(packet->pdata);
195 	newattr->type = type;
196 	newattr->length = length + 2;
197 	memcpy(newattr->data, buf, length);
198 	packet->pdata->length = htons(radius_get_length(packet) + length + 2);
199 
200 	return (0);
201 }
202 
203 int
204 radius_put_vs_raw_attr(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype,
205     const void *buf, size_t length)
206 {
207 	RADIUS_ATTRIBUTE	*newattr;
208 
209 	if (length > 255 - 8)
210 		return (-1);
211 	if ((vendor & 0xff000000U) != 0)
212 		return (-1);
213 
214 	if (radius_ensure_add_capacity(packet, length + 8) != 0)
215 		return (-1);
216 
217 	newattr = ATTRS_END(packet->pdata);
218 	newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
219 	newattr->length = length + 8;
220 	newattr->vendor = htonl(vendor);
221 	newattr->vtype = vtype;
222 	newattr->vlength = length + 2;
223 	memcpy(newattr->vdata, buf, length);
224 	packet->pdata->length = htons(radius_get_length(packet) + length + 8);
225 
226 	return (0);
227 }
228 
229 int
230 radius_put_raw_attr_cat(RADIUS_PACKET * packet, uint8_t type, const void *buf,
231     size_t length)
232 {
233 	int	 off, len0;
234 
235 	off = 0;
236 	while (off < length) {
237 		len0 = MINIMUM(length - off, 255 - 2);
238 
239 		if (radius_put_raw_attr(packet, type, (const char *)buf + off,
240 		    len0) != 0)
241 			return (-1);
242 
243 		off += len0;
244 	}
245 
246 	return (0);
247 }
248 
249 int
250 radius_put_vs_raw_attr_cat(RADIUS_PACKET * packet, uint32_t vendor,
251     uint8_t vtype, const void *buf, size_t length)
252 {
253 	int	 off, len0;
254 
255 	off = 0;
256 	while (off < length) {
257 		len0 = MINIMUM(length - off, 255 - 8);
258 
259 		if (radius_put_vs_raw_attr(packet, vendor, vtype,
260 		    (const char *)buf + off, len0) != 0)
261 			return (-1);
262 
263 		off += len0;
264 	}
265 
266 	return (0);
267 }
268 
269 int
270 radius_set_raw_attr(RADIUS_PACKET * packet,
271     uint8_t type, const void *buf, size_t length)
272 {
273 	FIND_ATTRIBUTE_BEGIN(,) {
274 		if (length != attr->length - 2)
275 			return (-1);
276 		memcpy(attr->data, buf, length);
277 		return (0);
278 	} FIND_ATTRIBUTE_END;
279 
280 	return (-1);
281 }
282 
283 int
284 radius_set_vs_raw_attr(RADIUS_PACKET * packet,
285     uint32_t vendor, uint8_t vtype, const void *buf, size_t length)
286 {
287 	FIND_VS_ATTRIBUTE_BEGIN(,) {
288 		if (length != attr->vlength - 2)
289 			return (-1);
290 		memcpy(attr->vdata, buf, length);
291 		return (0);
292 	} FIND_VS_ATTRIBUTE_END;
293 
294 	return (-1);
295 }
296 
297 int
298 radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type)
299 {
300 	FIND_ATTRIBUTE_BEGIN(, redo:) {
301 		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
302 		packet->pdata->length =
303 		    htons(ntohs(packet->pdata->length) - attr->length);
304 		memmove(attr, next, ((char *)end) - ((char *)next));
305 		end = ATTRS_END(packet->pdata);
306 		goto redo;
307 	} FIND_ATTRIBUTE_END;
308 
309 	return (0);
310 }
311 
312 int
313 radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
314 {
315 	FIND_VS_ATTRIBUTE_BEGIN(, redo:) {
316 		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
317 		packet->pdata->length =
318 		    htons(ntohs(packet->pdata->length) - attr->length);
319 		memmove(attr, next, ((char *)end) - ((char *)next));
320 		end = ATTRS_END(packet->pdata);
321 		goto redo;
322 	} FIND_VS_ATTRIBUTE_END;
323 
324 	return (0);
325 }
326 
327 bool
328 radius_has_attr(const RADIUS_PACKET * packet, uint8_t type)
329 {
330 	FIND_ATTRIBUTE_BEGIN(const,) {
331 		return (true);
332 	} FIND_VS_ATTRIBUTE_END;
333 
334 	return (false);
335 }
336 
337 bool
338 radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
339 {
340 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
341 		return (true);
342 	} FIND_VS_ATTRIBUTE_END;
343 
344 	return (false);
345 }
346 
347 int
348 radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str,
349     size_t len)
350 {
351 	const void	*p;
352 	size_t		 origlen;
353 
354 	if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0)
355 		return (-1);
356 	if (memchr(p, 0, origlen) != NULL)
357 		return (-1);
358 	if (len >= 1) {
359 		len = MINIMUM(origlen, len - 1);
360 		memcpy(str, (const char *)p, len);
361 		str[len] = '\0';
362 	}
363 	return (0);
364 }
365 
366 int
367 radius_get_vs_string_attr(const RADIUS_PACKET * packet,
368     uint32_t vendor, uint8_t vtype, char *str, size_t len)
369 {
370 	const void *p;
371 	size_t origlen;
372 
373 	if (radius_get_vs_raw_attr_ptr(packet,
374 		vendor, vtype, &p, &origlen) != 0)
375 		return (-1);
376 	if (memchr(p, 0, origlen) != NULL)
377 		return (-1);
378 	if (len >= 1) {
379 		len = MINIMUM(origlen, len - 1);
380 		memcpy(str, (const char *)p, len);
381 		str[len] = '\0';
382 	}
383 
384 	return (0);
385 }
386 
387 int
388 radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str)
389 {
390 	return radius_put_raw_attr(packet, type, str, strlen(str));
391 }
392 
393 int
394 radius_put_vs_string_attr(RADIUS_PACKET * packet,
395     uint32_t vendor, uint8_t vtype, const char *str)
396 {
397 	return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str));
398 }
399 
400 
401 #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ftname, tname, hton, ntoh) \
402 int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
403 	uint8_t type, tname *val)					\
404 {									\
405 	const void *p;							\
406 	tname nval;							\
407 	size_t len;							\
408 									\
409 	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
410 		return (-1);						\
411 	if (len != sizeof(tname))					\
412 		return (-1);						\
413 	memcpy(&nval, p, sizeof(tname));				\
414 	*val = ntoh(nval);						\
415 	return (0);							\
416 }									\
417 									\
418 int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
419 	uint32_t vendor, uint8_t vtype, tname *val)			\
420 {									\
421 	const void *p;							\
422 	tname nval;							\
423 	size_t len;							\
424 									\
425 	if (radius_get_vs_raw_attr_ptr(packet,				\
426 			vendor, vtype, &p, &len) != 0)			\
427 		return (-1);						\
428 	if (len != sizeof(tname))					\
429 		return (-1);						\
430 	memcpy(&nval, p, sizeof(tname));				\
431 	*val = ntoh(nval);						\
432 	return (0);							\
433 }									\
434 									\
435 int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
436 	uint8_t type, tname val)					\
437 {									\
438 	tname nval;							\
439 									\
440 	nval = hton(val);						\
441 	return radius_put_raw_attr(packet, type, &nval, sizeof(tname));	\
442 }									\
443 									\
444 int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
445 	uint32_t vendor, uint8_t vtype, tname val)			\
446 {									\
447 	tname nval;							\
448 									\
449 	nval = hton(val);						\
450 	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
451 			&nval, sizeof(tname));				\
452 }									\
453 									\
454 int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
455 	uint8_t type, tname val)					\
456 {									\
457 	tname nval;							\
458 									\
459 	nval = hton(val);						\
460 	return radius_set_raw_attr(packet, type, &nval, sizeof(tname));	\
461 }									\
462 									\
463 int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
464 	uint32_t vendor, uint8_t vtype, tname val)			\
465 {									\
466 	tname nval;							\
467 									\
468 	nval = hton(val);						\
469 	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
470 			&nval, sizeof(tname));				\
471 }
472 
473 #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ftname, tname) \
474 int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
475 	uint8_t type, tname *val)					\
476 {									\
477 	const void	*p;						\
478 	size_t		 len;						\
479 									\
480 	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
481 		return (-1);						\
482 	if (len != sizeof(tname))					\
483 		return (-1);						\
484 	memcpy(val, p, sizeof(tname));					\
485 	return (0);							\
486 }									\
487 									\
488 int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
489 	uint32_t vendor, uint8_t vtype, tname *val)			\
490 {									\
491 	const void	*p;						\
492 	size_t		 len;						\
493 									\
494 	if (radius_get_vs_raw_attr_ptr(packet,				\
495 			vendor, vtype, &p, &len) != 0)			\
496 		return (-1);						\
497 	if (len != sizeof(tname))					\
498 		return (-1);						\
499 	memcpy(val, p, sizeof(tname));					\
500 	return (0);							\
501 }									\
502 									\
503 int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
504 	uint8_t type, const tname *val)					\
505 {									\
506 	return radius_put_raw_attr(packet, type, val, sizeof(tname));	\
507 }									\
508 									\
509 int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
510 	uint32_t vendor, uint8_t vtype, const tname *val)		\
511 {									\
512 	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
513 			val, sizeof(tname));				\
514 }									\
515 									\
516 int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
517 	uint8_t type, const tname *val)					\
518 {									\
519 	return radius_set_raw_attr(packet, type, val, sizeof(tname));	\
520 }									\
521 									\
522 int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
523 	uint32_t vendor, uint8_t vtype, const tname *val)		\
524 {									\
525 	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
526 			val, sizeof(tname));				\
527 }
528 
529 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs)
530 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl)
531 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64)
532 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
533 DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)
534