GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libradius/radius_attr.c Lines: 150 161 93.2 %
Date: 2017-11-07 Branches: 135 162 83.3 %

Line Branch Exec Source
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

660
	FIND_ATTRIBUTE_BEGIN(const,) {
91
60
		*length = attr->length - 2;
92
60
		*ptr = attr->data;
93
60
		return (0);
94
	} FIND_ATTRIBUTE_END;
95
96
4
	return (-1);
97
64
}
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


1140
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
104
60
		*length = attr->vlength - 2;
105
60
		*ptr = attr->vdata;
106
60
		return (0);
107
	} FIND_VS_ATTRIBUTE_END;
108
109
8
	return (-1);
110
68
}
111
112
int
113
radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf,
114
    size_t * length)
115
{
116

288
	FIND_ATTRIBUTE_BEGIN(const,) {
117
108
		*length = MINIMUM(attr->length - 2, *length);
118
36
		memcpy(buf, attr->data, *length);
119
36
		return (0);
120
	} FIND_ATTRIBUTE_END;
121
122
4
	return (-1);
123
40
}
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


456
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
130
84
		*length = MINIMUM(attr->vlength - 2, *length);
131
28
		memcpy(buf, attr->vdata, *length);
132
28
		return (0);
133
	} FIND_VS_ATTRIBUTE_END;
134
135
8
	return (-1);
136
36
}
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

216
	FIND_ATTRIBUTE_BEGIN(const,) {
145
20
		if (buf != NULL) {
146
20
			if (off + attr->length - 2 <= *length)
147
40
				memcpy((char *)buf + off, attr->data,
148
20
				    attr->length - 2);
149
			else
150
				return (-1);
151
20
		}
152
20
		off += attr->length - 2;
153
20
	} FIND_ATTRIBUTE_END;
154
155
8
	*length = off;
156
157
8
	return (0);
158
8
}
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


132
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
167
12
		if (buf != NULL) {
168
12
			if (off + attr->vlength - 2 <= *length)
169
24
				memcpy((char *)buf + off, attr->vdata,
170
12
				    attr->vlength - 2);
171
			else
172
				return (-1);
173
12
		}
174
12
		off += attr->vlength - 2;
175
12
	} FIND_VS_ATTRIBUTE_END;
176
177
4
	*length = off;
178
179
4
	return (0);
180
4
}
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
248
	if (length > 255 - 2)
189
		return (-1);
190
191
124
	if (radius_ensure_add_capacity(packet, length + 2) != 0)
192
		return (-1);
193
194
124
	newattr = ATTRS_END(packet->pdata);
195
124
	newattr->type = type;
196
124
	newattr->length = length + 2;
197
124
	memcpy(newattr->data, buf, length);
198
124
	packet->pdata->length = htons(radius_get_length(packet) + length + 2);
199
200
124
	return (0);
201
124
}
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
168
	if (length > 255 - 8)
210
		return (-1);
211
84
	if ((vendor & 0xff000000U) != 0)
212
		return (-1);
213
214
84
	if (radius_ensure_add_capacity(packet, length + 8) != 0)
215
		return (-1);
216
217
84
	newattr = ATTRS_END(packet->pdata);
218
84
	newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
219
84
	newattr->length = length + 8;
220
84
	newattr->vendor = htonl(vendor);
221
84
	newattr->vtype = vtype;
222
84
	newattr->vlength = length + 2;
223
84
	memcpy(newattr->vdata, buf, length);
224
84
	packet->pdata->length = htons(radius_get_length(packet) + length + 8);
225
226
84
	return (0);
227
84
}
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
36
	while (off < length) {
237
28
		len0 = MINIMUM(length - off, 255 - 2);
238
239
36
		if (radius_put_raw_attr(packet, type, (const char *)buf + off,
240
24
		    len0) != 0)
241
			return (-1);
242
243
12
		off += len0;
244
	}
245
246
4
	return (0);
247
4
}
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
36
	while (off < length) {
257
28
		len0 = MINIMUM(length - off, 255 - 8);
258
259
24
		if (radius_put_vs_raw_attr(packet, vendor, vtype,
260
24
		    (const char *)buf + off, len0) != 0)
261
			return (-1);
262
263
12
		off += len0;
264
	}
265
266
4
	return (0);
267
4
}
268
269
int
270
radius_set_raw_attr(RADIUS_PACKET * packet,
271
    uint8_t type, const void *buf, size_t length)
272
{
273

508
	FIND_ATTRIBUTE_BEGIN(,) {
274
64
		if (length != attr->length - 2)
275
8
			return (-1);
276
56
		memcpy(attr->data, buf, length);
277
56
		return (0);
278
	} FIND_ATTRIBUTE_END;
279
280
4
	return (-1);
281
68
}
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


564
	FIND_VS_ATTRIBUTE_BEGIN(,) {
288
32
		if (length != attr->vlength - 2)
289
8
			return (-1);
290
24
		memcpy(attr->vdata, buf, length);
291
24
		return (0);
292
	} FIND_VS_ATTRIBUTE_END;
293
294
4
	return (-1);
295
36
}
296
297
int
298
radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type)
299
{
300

192
	FIND_ATTRIBUTE_BEGIN(, redo:) {
301
8
		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
302
8
		packet->pdata->length =
303
8
		    htons(ntohs(packet->pdata->length) - attr->length);
304
8
		memmove(attr, next, ((char *)end) - ((char *)next));
305
8
		end = ATTRS_END(packet->pdata);
306
		goto redo;
307
	} FIND_ATTRIBUTE_END;
308
309
8
	return (0);
310
}
311
312
int
313
radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
314
{
315


184
	FIND_VS_ATTRIBUTE_BEGIN(, redo:) {
316
12
		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
317
12
		packet->pdata->length =
318
12
		    htons(ntohs(packet->pdata->length) - attr->length);
319
12
		memmove(attr, next, ((char *)end) - ((char *)next));
320
12
		end = ATTRS_END(packet->pdata);
321
		goto redo;
322
	} FIND_VS_ATTRIBUTE_END;
323
324
8
	return (0);
325
}
326
327
bool
328
radius_has_attr(const RADIUS_PACKET * packet, uint8_t type)
329
{
330

140
	FIND_ATTRIBUTE_BEGIN(const,) {
331
8
		return (true);
332
	} FIND_VS_ATTRIBUTE_END;
333
334
8
	return (false);
335
16
}
336
337
bool
338
radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
339
{
340


312
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
341
8
		return (true);
342
	} FIND_VS_ATTRIBUTE_END;
343
344
8
	return (false);
345
16
}
346
347
int
348
radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str,
349
    size_t len)
350
{
351
32
	const void	*p;
352
16
	size_t		 origlen;
353
354
16
	if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0)
355
		return (-1);
356
16
	if (memchr(p, 0, origlen) != NULL)
357
4
		return (-1);
358
12
	if (len >= 1) {
359
8
		len = MINIMUM(origlen, len - 1);
360
8
		memcpy(str, (const char *)p, len);
361
8
		str[len] = '\0';
362
8
	}
363
12
	return (0);
364
16
}
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
32
	const void *p;
371
16
	size_t origlen;
372
373
32
	if (radius_get_vs_raw_attr_ptr(packet,
374
16
		vendor, vtype, &p, &origlen) != 0)
375
		return (-1);
376
16
	if (memchr(p, 0, origlen) != NULL)
377
4
		return (-1);
378
12
	if (len >= 1) {
379
8
		len = MINIMUM(origlen, len - 1);
380
8
		memcpy(str, (const char *)p, len);
381
8
		str[len] = '\0';
382
8
	}
383
384
12
	return (0);
385
16
}
386
387
int
388
radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str)
389
{
390
40
	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
8
	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


112
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs)
530


120
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl)
531


112
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64)
532


112
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
533


112
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)