2
* hostapd / RADIUS message processing
3
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
2
* RADIUS message processing
3
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
5
5
* This program is free software; you can redistribute it and/or modify
6
6
* it under the terms of the GNU General Public License version 2 as
12
12
* See README and COPYING for more details.
15
#include "utils/includes.h"
17
#include "utils/common.h"
18
#include "utils/wpabuf.h"
19
#include "crypto/md5.h"
20
#include "crypto/crypto.h"
18
21
#include "radius.h"
25
* struct radius_msg - RADIUS message structure for new and parsed messages
29
* buf - Allocated buffer for RADIUS message
34
* hdr - Pointer to the RADIUS header in buf
36
struct radius_hdr *hdr;
39
* attr_pos - Array of indexes to attributes
41
* The values are number of bytes from buf to the beginning of
42
* struct radius_attr_hdr.
47
* attr_size - Total size of the attribute pointer array
52
* attr_used - Total number of attributes in the array
58
struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
64
struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
23
70
static struct radius_attr_hdr *
24
71
radius_get_attr_hdr(struct radius_msg *msg, int idx)
26
return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
30
struct radius_msg *radius_msg_new(u8 code, u8 identifier)
32
struct radius_msg *msg;
34
msg = os_malloc(sizeof(*msg));
38
if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
43
radius_msg_set_hdr(msg, code, identifier);
49
int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
51
if (msg == NULL || init_len < sizeof(struct radius_hdr))
54
os_memset(msg, 0, sizeof(*msg));
55
msg->buf = os_zalloc(init_len);
59
msg->buf_size = init_len;
60
msg->hdr = (struct radius_hdr *) msg->buf;
61
msg->buf_used = sizeof(*msg->hdr);
73
return (struct radius_attr_hdr *)
74
(wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
78
static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
80
msg->hdr->code = code;
81
msg->hdr->identifier = identifier;
85
static int radius_msg_initialize(struct radius_msg *msg)
64
88
os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
65
if (msg->attr_pos == NULL) {
89
if (msg->attr_pos == NULL)
72
92
msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
73
93
msg->attr_used = 0;
79
void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
100
* radius_msg_new - Create a new RADIUS message
101
* @code: Code for RADIUS header
102
* @identifier: Identifier for RADIUS header
103
* Returns: Context for RADIUS message or %NULL on failure
105
* The caller is responsible for freeing the returned data with
108
struct radius_msg * radius_msg_new(u8 code, u8 identifier)
81
msg->hdr->code = code;
82
msg->hdr->identifier = identifier;
110
struct radius_msg *msg;
112
msg = os_zalloc(sizeof(*msg));
116
msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
117
if (msg->buf == NULL || radius_msg_initialize(msg)) {
118
radius_msg_free(msg);
121
msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
123
radius_msg_set_hdr(msg, code, identifier);
130
* radius_msg_free - Free a RADIUS message
131
* @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
86
133
void radius_msg_free(struct radius_msg *msg)
91
msg->buf_size = msg->buf_used = 0;
138
wpabuf_free(msg->buf);
93
139
os_free(msg->attr_pos);
95
msg->attr_size = msg->attr_used = 0;
305
350
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
306
351
auth, MD5_MAC_LEN);
307
352
if (attr == NULL) {
308
printf("WARNING: Could not add "
309
"Message-Authenticator\n");
353
wpa_printf(MSG_WARNING, "RADIUS: Could not add "
354
"Message-Authenticator");
312
msg->hdr->length = htons(msg->buf_used);
313
hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
357
msg->hdr->length = htons(wpabuf_len(msg->buf));
358
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
359
wpabuf_len(msg->buf), (u8 *) (attr + 1));
316
msg->hdr->length = htons(msg->buf_used);
361
msg->hdr->length = htons(wpabuf_len(msg->buf));
318
if (msg->buf_used > 0xffff) {
319
printf("WARNING: too long RADIUS message (%lu)\n",
320
(unsigned long) msg->buf_used);
363
if (wpabuf_len(msg->buf) > 0xffff) {
364
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
365
(unsigned long) wpabuf_len(msg->buf));
339
384
printf("WARNING: Could not add Message-Authenticator\n");
342
msg->hdr->length = htons(msg->buf_used);
387
msg->hdr->length = htons(wpabuf_len(msg->buf));
343
388
os_memcpy(msg->hdr->authenticator, req_authenticator,
344
389
sizeof(msg->hdr->authenticator));
345
hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
390
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
391
wpabuf_len(msg->buf), (u8 *) (attr + 1));
348
393
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
349
394
addr[0] = (u8 *) msg->hdr;
350
395
len[0] = 1 + 1 + 2;
351
396
addr[1] = req_authenticator;
352
397
len[1] = MD5_MAC_LEN;
353
addr[2] = (u8 *) (msg->hdr + 1);
354
len[2] = msg->buf_used - sizeof(*msg->hdr);
398
addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
399
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
355
400
addr[3] = secret;
356
401
len[3] = secret_len;
357
402
md5_vector(4, addr, len, msg->hdr->authenticator);
359
if (msg->buf_used > 0xffff) {
360
printf("WARNING: too long RADIUS message (%lu)\n",
361
(unsigned long) msg->buf_used);
404
if (wpabuf_len(msg->buf) > 0xffff) {
405
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
406
(unsigned long) wpabuf_len(msg->buf));
371
416
const u8 *addr[2];
374
msg->hdr->length = htons(msg->buf_used);
419
msg->hdr->length = htons(wpabuf_len(msg->buf));
375
420
os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
377
len[0] = msg->buf_used;
421
addr[0] = wpabuf_head(msg->buf);
422
len[0] = wpabuf_len(msg->buf);
378
423
addr[1] = secret;
379
424
len[1] = secret_len;
380
425
md5_vector(2, addr, len, msg->hdr->authenticator);
382
if (msg->buf_used > 0xffff) {
383
printf("WARNING: too long RADIUS messages (%lu)\n",
384
(unsigned long) msg->buf_used);
427
if (wpabuf_len(msg->buf) > 0xffff) {
428
wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
429
(unsigned long) wpabuf_len(msg->buf));
423
buf_needed = msg->buf_used + sizeof(*attr) + data_len;
469
buf_needed = sizeof(*attr) + data_len;
425
if (msg->buf_size < buf_needed) {
471
if (wpabuf_tailroom(msg->buf) < buf_needed) {
426
472
/* allocate more space for message buffer */
428
size_t nlen = msg->buf_size;
430
while (nlen < buf_needed)
432
nbuf = os_realloc(msg->buf, nlen);
473
if (wpabuf_resize(&msg->buf, buf_needed) < 0)
436
msg->hdr = (struct radius_hdr *) msg->buf;
437
os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
438
msg->buf_size = nlen;
475
msg->hdr = wpabuf_mhead(msg->buf);
441
attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
478
attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
442
479
attr->type = type;
443
480
attr->length = sizeof(*attr) + data_len;
445
os_memcpy(attr + 1, data, data_len);
447
msg->buf_used += sizeof(*attr) + data_len;
481
wpabuf_put_data(msg->buf, data, data_len);
449
483
if (radius_msg_add_attr_to_array(msg, attr))
456
struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
491
* radius_msg_parse - Parse a RADIUS message
492
* @data: RADIUS message to be parsed
493
* @len: Length of data buffer in octets
494
* Returns: Parsed RADIUS message or %NULL on failure
496
* This parses a RADIUS message and makes a copy of its data. The caller is
497
* responsible for freeing the returned data with radius_msg_free().
499
struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
458
501
struct radius_msg *msg;
459
502
struct radius_hdr *hdr;
469
512
msg_len = ntohs(hdr->length);
470
513
if (msg_len < sizeof(*hdr) || msg_len > len) {
471
printf("Invalid RADIUS message length\n");
514
wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
475
518
if (msg_len < len) {
476
printf("Ignored %lu extra bytes after RADIUS message\n",
477
(unsigned long) len - msg_len);
519
wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
520
"RADIUS message", (unsigned long) len - msg_len);
480
msg = os_malloc(sizeof(*msg));
523
msg = os_zalloc(sizeof(*msg));
484
if (radius_msg_initialize(msg, msg_len)) {
527
msg->buf = wpabuf_alloc_copy(data, msg_len);
528
if (msg->buf == NULL || radius_msg_initialize(msg)) {
529
radius_msg_free(msg);
489
os_memcpy(msg->buf, data, msg_len);
490
msg->buf_size = msg->buf_used = msg_len;
532
msg->hdr = wpabuf_mhead(msg->buf);
492
534
/* parse attributes */
493
pos = (unsigned char *) (msg->hdr + 1);
494
end = msg->buf + msg->buf_used;
535
pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
536
end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
495
537
while (pos < end) {
496
538
if ((size_t) (end - pos) < sizeof(*attr))
615
656
os_memcpy(msg->hdr->authenticator, req_auth,
616
657
sizeof(msg->hdr->authenticator));
618
hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
659
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
660
wpabuf_len(msg->buf), auth);
619
661
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
621
663
os_memcpy(msg->hdr->authenticator, orig_authenticator,
654
696
len[0] = 1 + 1 + 2;
655
697
addr[1] = sent_msg->hdr->authenticator;
656
698
len[1] = MD5_MAC_LEN;
657
addr[2] = (u8 *) (msg->hdr + 1);
658
len[2] = msg->buf_used - sizeof(*msg->hdr);
699
addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
700
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
659
701
addr[3] = secret;
660
702
len[3] = secret_len;
661
703
md5_vector(4, addr, len, hash);
1279
void radius_free_class(struct radius_class_data *c)
1284
for (i = 0; i < c->count; i++)
1285
os_free(c->attr[i].data);
1292
int radius_copy_class(struct radius_class_data *dst,
1293
const struct radius_class_data *src)
1297
if (src->attr == NULL)
1300
dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
1301
if (dst->attr == NULL)
1306
for (i = 0; i < src->count; i++) {
1307
dst->attr[i].data = os_malloc(src->attr[i].len);
1308
if (dst->attr[i].data == NULL)
1311
os_memcpy(dst->attr[i].data, src->attr[i].data,
1313
dst->attr[i].len = src->attr[i].len;