diff options
Diffstat (limited to 'contrib/wpa/src/radius/radius.c')
-rw-r--r-- | contrib/wpa/src/radius/radius.c | 293 |
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; +} |