GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libradius/radius_attr.c Lines: 150 161 93.2 %
Date: 2017-11-13 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

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


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

216
	FIND_ATTRIBUTE_BEGIN(const,) {
117
81
		*length = MINIMUM(attr->length - 2, *length);
118
27
		memcpy(buf, attr->data, *length);
119
27
		return (0);
120
	} FIND_ATTRIBUTE_END;
121
122
3
	return (-1);
123
30
}
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


342
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
130
63
		*length = MINIMUM(attr->vlength - 2, *length);
131
21
		memcpy(buf, attr->vdata, *length);
132
21
		return (0);
133
	} FIND_VS_ATTRIBUTE_END;
134
135
6
	return (-1);
136
27
}
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

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


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

381
	FIND_ATTRIBUTE_BEGIN(,) {
274
48
		if (length != attr->length - 2)
275
6
			return (-1);
276
42
		memcpy(attr->data, buf, length);
277
42
		return (0);
278
	} FIND_ATTRIBUTE_END;
279
280
3
	return (-1);
281
51
}
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


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

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


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

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


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


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


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


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


84
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
533


84
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)