summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/radius/radius.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/src/radius/radius.c')
-rw-r--r--contrib/wpa/src/radius/radius.c293
1 files changed, 188 insertions, 105 deletions
diff --git a/contrib/wpa/src/radius/radius.c b/contrib/wpa/src/radius/radius.c
index 71bbfb5..70754ef 100644
--- a/contrib/wpa/src/radius/radius.c
+++ b/contrib/wpa/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
- * hostapd / RADIUS message processing
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * RADIUS message processing
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,62 +12,82 @@
* See README and COPYING for more details.
*/
-#include "includes.h"
+#include "utils/includes.h"
-#include "common.h"
+#include "utils/common.h"
+#include "utils/wpabuf.h"
+#include "crypto/md5.h"
+#include "crypto/crypto.h"
#include "radius.h"
-#include "md5.h"
-#include "crypto.h"
-static struct radius_attr_hdr *
-radius_get_attr_hdr(struct radius_msg *msg, int idx)
-{
- return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
-}
+/**
+ * struct radius_msg - RADIUS message structure for new and parsed messages
+ */
+struct radius_msg {
+ /**
+ * buf - Allocated buffer for RADIUS message
+ */
+ struct wpabuf *buf;
+
+ /**
+ * hdr - Pointer to the RADIUS header in buf
+ */
+ struct radius_hdr *hdr;
+ /**
+ * attr_pos - Array of indexes to attributes
+ *
+ * The values are number of bytes from buf to the beginning of
+ * struct radius_attr_hdr.
+ */
+ size_t *attr_pos;
+
+ /**
+ * attr_size - Total size of the attribute pointer array
+ */
+ size_t attr_size;
+
+ /**
+ * attr_used - Total number of attributes in the array
+ */
+ size_t attr_used;
+};
-struct radius_msg *radius_msg_new(u8 code, u8 identifier)
+
+struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
{
- struct radius_msg *msg;
+ return msg->hdr;
+}
- msg = os_malloc(sizeof(*msg));
- if (msg == NULL)
- return NULL;
- if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
- os_free(msg);
- return NULL;
- }
+struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
+{
+ return msg->buf;
+}
- radius_msg_set_hdr(msg, code, identifier);
- return msg;
+static struct radius_attr_hdr *
+radius_get_attr_hdr(struct radius_msg *msg, int idx)
+{
+ return (struct radius_attr_hdr *)
+ (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
}
-int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
+static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
{
- if (msg == NULL || init_len < sizeof(struct radius_hdr))
- return -1;
-
- os_memset(msg, 0, sizeof(*msg));
- msg->buf = os_zalloc(init_len);
- if (msg->buf == NULL)
- return -1;
+ msg->hdr->code = code;
+ msg->hdr->identifier = identifier;
+}
- msg->buf_size = init_len;
- msg->hdr = (struct radius_hdr *) msg->buf;
- msg->buf_used = sizeof(*msg->hdr);
+static int radius_msg_initialize(struct radius_msg *msg)
+{
msg->attr_pos =
os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
- if (msg->attr_pos == NULL) {
- os_free(msg->buf);
- msg->buf = NULL;
- msg->hdr = NULL;
+ if (msg->attr_pos == NULL)
return -1;
- }
msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
msg->attr_used = 0;
@@ -76,23 +96,48 @@ int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
}
-void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
+/**
+ * radius_msg_new - Create a new RADIUS message
+ * @code: Code for RADIUS header
+ * @identifier: Identifier for RADIUS header
+ * Returns: Context for RADIUS message or %NULL on failure
+ *
+ * The caller is responsible for freeing the returned data with
+ * radius_msg_free().
+ */
+struct radius_msg * radius_msg_new(u8 code, u8 identifier)
{
- msg->hdr->code = code;
- msg->hdr->identifier = identifier;
+ struct radius_msg *msg;
+
+ msg = os_zalloc(sizeof(*msg));
+ if (msg == NULL)
+ return NULL;
+
+ msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
+ if (msg->buf == NULL || radius_msg_initialize(msg)) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
+
+ radius_msg_set_hdr(msg, code, identifier);
+
+ return msg;
}
+/**
+ * radius_msg_free - Free a RADIUS message
+ * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
+ */
void radius_msg_free(struct radius_msg *msg)
{
- os_free(msg->buf);
- msg->buf = NULL;
- msg->hdr = NULL;
- msg->buf_size = msg->buf_used = 0;
+ if (msg == NULL)
+ return;
+ wpabuf_free(msg->buf);
os_free(msg->attr_pos);
- msg->attr_pos = NULL;
- msg->attr_size = msg->attr_used = 0;
+ os_free(msg);
}
@@ -305,19 +350,19 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
if (attr == NULL) {
- printf("WARNING: Could not add "
- "Message-Authenticator\n");
+ wpa_printf(MSG_WARNING, "RADIUS: Could not add "
+ "Message-Authenticator");
return -1;
}
- msg->hdr->length = htons(msg->buf_used);
- hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
- (u8 *) (attr + 1));
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), (u8 *) (attr + 1));
} else
- msg->hdr->length = htons(msg->buf_used);
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
- if (msg->buf_used > 0xffff) {
- printf("WARNING: too long RADIUS message (%lu)\n",
- (unsigned long) msg->buf_used);
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
return -1;
}
return 0;
@@ -339,26 +384,26 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
printf("WARNING: Could not add Message-Authenticator\n");
return -1;
}
- msg->hdr->length = htons(msg->buf_used);
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_authenticator,
sizeof(msg->hdr->authenticator));
- hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
- (u8 *) (attr + 1));
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), (u8 *) (attr + 1));
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
addr[0] = (u8 *) msg->hdr;
len[0] = 1 + 1 + 2;
addr[1] = req_authenticator;
len[1] = MD5_MAC_LEN;
- addr[2] = (u8 *) (msg->hdr + 1);
- len[2] = msg->buf_used - sizeof(*msg->hdr);
+ addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, msg->hdr->authenticator);
- if (msg->buf_used > 0xffff) {
- printf("WARNING: too long RADIUS message (%lu)\n",
- (unsigned long) msg->buf_used);
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
return -1;
}
return 0;
@@ -371,17 +416,17 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
const u8 *addr[2];
size_t len[2];
- msg->hdr->length = htons(msg->buf_used);
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
- addr[0] = msg->buf;
- len[0] = msg->buf_used;
+ addr[0] = wpabuf_head(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
addr[1] = secret;
len[1] = secret_len;
md5_vector(2, addr, len, msg->hdr->authenticator);
- if (msg->buf_used > 0xffff) {
- printf("WARNING: too long RADIUS messages (%lu)\n",
- (unsigned long) msg->buf_used);
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
}
}
@@ -402,7 +447,8 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
msg->attr_size = nlen;
}
- msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;
+ msg->attr_pos[msg->attr_used++] =
+ (unsigned char *) attr - wpabuf_head_u8(msg->buf);
return 0;
}
@@ -420,31 +466,19 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
return NULL;
}
- buf_needed = msg->buf_used + sizeof(*attr) + data_len;
+ buf_needed = sizeof(*attr) + data_len;
- if (msg->buf_size < buf_needed) {
+ if (wpabuf_tailroom(msg->buf) < buf_needed) {
/* allocate more space for message buffer */
- unsigned char *nbuf;
- size_t nlen = msg->buf_size;
-
- while (nlen < buf_needed)
- nlen *= 2;
- nbuf = os_realloc(msg->buf, nlen);
- if (nbuf == NULL)
+ if (wpabuf_resize(&msg->buf, buf_needed) < 0)
return NULL;
- msg->buf = nbuf;
- msg->hdr = (struct radius_hdr *) msg->buf;
- os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
- msg->buf_size = nlen;
+ msg->hdr = wpabuf_mhead(msg->buf);
}
- attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
+ attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
attr->type = type;
attr->length = sizeof(*attr) + data_len;
- if (data_len > 0)
- os_memcpy(attr + 1, data, data_len);
-
- msg->buf_used += sizeof(*attr) + data_len;
+ wpabuf_put_data(msg->buf, data, data_len);
if (radius_msg_add_attr_to_array(msg, attr))
return NULL;
@@ -453,7 +487,16 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
}
-struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
+/**
+ * radius_msg_parse - Parse a RADIUS message
+ * @data: RADIUS message to be parsed
+ * @len: Length of data buffer in octets
+ * Returns: Parsed RADIUS message or %NULL on failure
+ *
+ * This parses a RADIUS message and makes a copy of its data. The caller is
+ * responsible for freeing the returned data with radius_msg_free().
+ */
+struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
{
struct radius_msg *msg;
struct radius_hdr *hdr;
@@ -468,30 +511,29 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
msg_len = ntohs(hdr->length);
if (msg_len < sizeof(*hdr) || msg_len > len) {
- printf("Invalid RADIUS message length\n");
+ wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
return NULL;
}
if (msg_len < len) {
- printf("Ignored %lu extra bytes after RADIUS message\n",
- (unsigned long) len - msg_len);
+ wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
+ "RADIUS message", (unsigned long) len - msg_len);
}
- msg = os_malloc(sizeof(*msg));
+ msg = os_zalloc(sizeof(*msg));
if (msg == NULL)
return NULL;
- if (radius_msg_initialize(msg, msg_len)) {
- os_free(msg);
+ msg->buf = wpabuf_alloc_copy(data, msg_len);
+ if (msg->buf == NULL || radius_msg_initialize(msg)) {
+ radius_msg_free(msg);
return NULL;
}
-
- os_memcpy(msg->buf, data, msg_len);
- msg->buf_size = msg->buf_used = msg_len;
+ msg->hdr = wpabuf_mhead(msg->buf);
/* parse attributes */
- pos = (unsigned char *) (msg->hdr + 1);
- end = msg->buf + msg->buf_used;
+ pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
+ end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
while (pos < end) {
if ((size_t) (end - pos) < sizeof(*attr))
goto fail;
@@ -513,7 +555,6 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
fail:
radius_msg_free(msg);
- os_free(msg);
return NULL;
}
@@ -615,7 +656,8 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
os_memcpy(msg->hdr->authenticator, req_auth,
sizeof(msg->hdr->authenticator));
}
- hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth);
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -654,8 +696,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
len[0] = 1 + 1 + 2;
addr[1] = sent_msg->hdr->authenticator;
len[1] = MD5_MAC_LEN;
- addr[2] = (u8 *) (msg->hdr + 1);
- len[2] = msg->buf_used - sizeof(*msg->hdr);
+ addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
@@ -1232,3 +1274,44 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
return -1;
}
+
+
+void radius_free_class(struct radius_class_data *c)
+{
+ size_t i;
+ if (c == NULL)
+ return;
+ for (i = 0; i < c->count; i++)
+ os_free(c->attr[i].data);
+ os_free(c->attr);
+ c->attr = NULL;
+ c->count = 0;
+}
+
+
+int radius_copy_class(struct radius_class_data *dst,
+ const struct radius_class_data *src)
+{
+ size_t i;
+
+ if (src->attr == NULL)
+ return 0;
+
+ dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+ if (dst->attr == NULL)
+ return -1;
+
+ dst->count = 0;
+
+ for (i = 0; i < src->count; i++) {
+ dst->attr[i].data = os_malloc(src->attr[i].len);
+ if (dst->attr[i].data == NULL)
+ break;
+ dst->count++;
+ os_memcpy(dst->attr[i].data, src->attr[i].data,
+ src->attr[i].len);
+ dst->attr[i].len = src->attr[i].len;
+ }
+
+ return 0;
+}
OpenPOWER on IntegriCloud