Mercurial > hg > freeDiameter
diff extensions/app_radgw/radius.c @ 550:4c935aecee6c
Hide and automate the Proxy-State attributes management in RADIUS gateway
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Wed, 15 Sep 2010 14:24:45 +0900 |
parents | 23736ebcbfbb |
children | d2be88628747 |
line wrap: on
line diff
--- a/extensions/app_radgw/radius.c Wed Sep 15 10:44:46 2010 +0900 +++ b/extensions/app_radgw/radius.c Wed Sep 15 14:24:45 2010 +0900 @@ -1,18 +1,44 @@ -/*********************************************************************************/ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2010, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + /* freeDiameter author note: - * The content from this file comes directly from the hostap project. + * The content from this file comes for the main part from the hostap project. * It is redistributed under the terms of the BSD license, as allowed * by the original copyright reproduced bellow. - * In addition to this notice, the following changes have been done: - * - created the radius_msg_dump_attr_val function + * The modifications to this file are placed under the copyright of the freeDiameter project. */ -#include "rgw_common.h" - -/* Overwrite printf */ -#define printf(args...) fd_log_debug(args) - -/*********************************************************************************/ - /* * hostapd / RADIUS message processing @@ -28,6 +54,13 @@ * See README and COPYING for more details. */ +/*********************************************************************************/ +#include "rgw.h" + +/* Overwrite printf */ +#define printf(args...) fd_log_debug(args) + + static struct radius_attr_hdr * radius_get_attr_hdr(struct radius_msg *msg, int idx) { @@ -103,24 +136,19 @@ msg->attr_size = msg->attr_used = 0; } - -static const char *radius_code_string(u8 code) +/* Destroy a message */ +void rgw_msg_free(struct rgw_radius_msg_meta ** msg) { - switch (code) { - case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request"; - case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept"; - case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject"; - case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request"; - case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response"; - case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge"; - case RADIUS_CODE_STATUS_SERVER: return "Status-Server"; - case RADIUS_CODE_STATUS_CLIENT: return "Status-Client"; - case RADIUS_CODE_RESERVED: return "Reserved"; - default: return "?Unknown?"; - } + if (!msg || !*msg) + return; + + radius_msg_free(&(*msg)->radius); + free(*msg); + *msg = NULL; } + struct radius_attr_type { u8 type; char *name; @@ -218,7 +246,7 @@ } -void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr) +static void radius_msg_dump_attr_val(struct radius_attr_hdr *hdr) { struct radius_attr_type *attr; int i, len; @@ -281,31 +309,36 @@ } } -static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) +/* Dump a message -- can be used safely with a struct radius_msg as parameter (we don't dump the metadata) */ +void rgw_msg_dump(struct rgw_radius_msg_meta * msg) { - struct radius_attr_type *attr; - - attr = radius_get_attr_type(hdr->type); - - printf(" Attribute %d (%s) length=%d\n", - hdr->type, attr ? attr->name : "?Unknown?", hdr->length); + unsigned char *auth; + size_t i; + if (! TRACE_BOOL(FULL) ) + return; + + auth = &(msg->radius.hdr->authenticator[0]); - radius_msg_dump_attr_val(hdr); -} - - -void radius_msg_dump(struct radius_msg *msg) -{ - size_t i; - - printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n", - msg->hdr->code, radius_code_string(msg->hdr->code), - msg->hdr->identifier, ntohs(msg->hdr->length)); - - for (i = 0; i < msg->attr_used; i++) { - struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i); - radius_msg_dump_attr(attr); + fd_log_debug("------ RADIUS msg dump -------\n"); + fd_log_debug(" id : 0x%02hhx, code : %hhd (%s), length : %d\n", msg->radius.hdr->identifier, msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code), ntohs(msg->radius.hdr->length)); + fd_log_debug(" auth: %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", + auth[0], auth[1], auth[2], auth[3], auth[4], auth[5], auth[6], auth[7]); + fd_log_debug(" %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n", + auth[8], auth[9], auth[10], auth[11], auth[12], auth[13], auth[14], auth[15]); + for (i = 0; i < msg->radius.attr_used; i++) { + struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]); + fd_log_debug(" - Type: 0x%02hhx (%s)\n Len: %-3hhu", attr->type, rgw_msg_attrtype_str(attr->type), attr->length); + radius_msg_dump_attr_val(attr); } + if (msg->ps_nb) { + fd_log_debug("---- hidden attributes:\n"); + for (i = msg->ps_first; i < msg->ps_first + msg->ps_nb; i++) { + struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[i]); + fd_log_debug(" - Type: 0x%02hhx (%s)\n Len: %-3hhu", attr->type, rgw_msg_attrtype_str(attr->type), attr->length); + radius_msg_dump_attr_val(attr); + } + } + fd_log_debug("-----------------------------\n"); } @@ -406,7 +439,7 @@ } -static int radius_msg_add_attr_to_array(struct radius_msg *msg, +int radius_msg_add_attr_to_array(struct radius_msg *msg, struct radius_attr_hdr *attr) { if (msg->attr_used >= msg->attr_size) { @@ -473,69 +506,114 @@ } -struct radius_msg *radius_msg_parse(const u8 *data, size_t len) +/* Modified version of radius_msg_parse */ +int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg) { - struct radius_msg *msg; + struct rgw_radius_msg_meta * temp_msg = NULL; struct radius_hdr *hdr; struct radius_attr_hdr *attr; size_t msg_len; unsigned char *pos, *end; - - if (data == NULL || len < sizeof(*hdr)) - return NULL; - - hdr = (struct radius_hdr *) data; - + int ret = 0; + + TRACE_ENTRY("%p %g %p", buf, len, msg); + + CHECK_PARAMS( buf && len >= sizeof(*hdr) && msg ); + + *msg = NULL; + + /* Parse the RADIUS message */ + hdr = (struct radius_hdr *) buf; msg_len = ntohs(hdr->length); if (msg_len < sizeof(*hdr) || msg_len > len) { - printf("Invalid RADIUS message length\n"); - return NULL; + TRACE_DEBUG(INFO, "Invalid RADIUS message length\n"); + return EINVAL; } if (msg_len < len) { - printf("Ignored %lu extra bytes after RADIUS message\n", + TRACE_DEBUG(INFO, "Ignored %lu extra bytes after RADIUS message\n", (unsigned long) len - msg_len); } - msg = os_malloc(sizeof(*msg)); - if (msg == NULL) - return NULL; - - if (radius_msg_initialize(msg, msg_len)) { - os_free(msg); - return NULL; + CHECK_MALLOC( temp_msg = malloc(sizeof(struct rgw_radius_msg_meta)) ); + memset(temp_msg, 0, sizeof(struct rgw_radius_msg_meta)); + + if (radius_msg_initialize(&temp_msg->radius, msg_len)) { + TRACE_DEBUG(INFO, "Error in radius_msg_initialize, returning ENOMEM."); + free(temp_msg); + return ENOMEM; } - - os_memcpy(msg->buf, data, msg_len); - msg->buf_size = msg->buf_used = msg_len; - + + /* Store the received data in the alloc'd buffer */ + memcpy(temp_msg->radius.buf, buf, msg_len); + temp_msg->radius.buf_size = temp_msg->radius.buf_used = msg_len; + /* parse attributes */ - pos = (unsigned char *) (msg->hdr + 1); - end = msg->buf + msg->buf_used; + pos = (unsigned char *) (temp_msg->radius.hdr + 1); + end = temp_msg->radius.buf + temp_msg->radius.buf_used; + while (pos < end) { - if ((size_t) (end - pos) < sizeof(*attr)) - goto fail; - + if ((size_t) (end - pos) < sizeof(*attr)) { + TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); + ret = EINVAL; + break; + } + attr = (struct radius_attr_hdr *) pos; + + if (pos + attr->length > end || attr->length < sizeof(*attr)) { + TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); + ret = EINVAL; + break; + } - if (pos + attr->length > end || attr->length < sizeof(*attr)) - goto fail; - - /* TODO: check that attr->length is suitable for attr->type */ - - if (radius_msg_add_attr_to_array(msg, attr)) - goto fail; + if (radius_msg_add_attr_to_array(&temp_msg->radius, attr)) { + TRACE_DEBUG(INFO, "Error in radius_msg_add_attr_to_array, ENOMEM"); + ret = ENOMEM; + break; + } + + if (attr->type == RADIUS_ATTR_PROXY_STATE) + temp_msg->ps_nb += 1; pos += attr->length; } - - return msg; + + if (ret != 0) { + radius_msg_free(&temp_msg->radius); + free(temp_msg); + return ret; + } + + /* Now move all the proxy-state attributes at the end of the attr_pos array */ + if (temp_msg->ps_nb) { + size_t *temp_ps = NULL; + int n, new_n = 0, p = 0; + + CHECK_MALLOC( temp_ps = calloc(temp_msg->ps_nb, sizeof(size_t *)) ); + + /* Move all the Proxy-State attributes into the temp_ps array */ + for (n=0; n < temp_msg->radius.attr_used; n++) { + struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(temp_msg->radius.buf + temp_msg->radius.attr_pos[n]); + + if (attr->type == RADIUS_ATTR_PROXY_STATE) { + temp_ps[p++] = temp_msg->radius.attr_pos[n]; + } else { + temp_msg->radius.attr_pos[new_n++] = temp_msg->radius.attr_pos[n]; + } + } + temp_msg->radius.attr_used = new_n; /* hide the proxy-state to other modules */ + temp_msg->ps_first = new_n; + + /* And back into the array */ + memcpy(temp_msg->radius.attr_pos + new_n, temp_ps, p * sizeof(size_t *)); + free(temp_ps); + } + + *msg = temp_msg; + return 0; +} - fail: - radius_msg_free(msg); - os_free(msg); - return NULL; -} int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)