Mercurial > hg > waaad
view extensions/radius_gw/sub_echo_drop.c @ 374:883330e610e1
Progress on the echo_drop sub extension
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 26 May 2009 11:37:32 +0900 |
parents | 0cb02e490017 |
children | 98806d0e175f |
line wrap: on
line source
/********************************************************************************************************* * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@nict.go.jp> * * * * Copyright (c) 2009, 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. * *********************************************************************************************************/ /* See sub_echo_drop.h for details */ #define DECLARE_API_POINTERS #include "sub_echo_drop.h" int sub_echo_drop_verbosity = SUB_ECHO_DROP_VERBO; /* Create the configuration and state structure */ static struct rga_conf_state * sed_cs_create(char * conffile) { struct rga_conf_state * cs = NULL; TRACE_ENTRY("%p", conffile); if ( ! conffile ) { log_error("No configuration file specified for extension sub_echo_drop!\n"); return NULL; } /* Create a new storage for extension state */ CHECK_MALLOC_DO( cs = malloc(sizeof(struct rga_conf_state)), return NULL ); memset(cs, 0, sizeof(struct rga_conf_state)); rg_list_init(&cs->conf); /* Initialize the session handler, to store "echo" attributes */ CHECK_FCT_DO( sess_regext( &cs->sess_hdl ), { free(cs); return NULL; } ); /* Parse the configuration file with the yacc parser */ cs->conffile = conffile; CHECK_FCT_DO( sed_conf_parse(cs), { sess_deregext(cs->sess_hdl); free(cs); return NULL; } ); TRACE_DEBUG(INFO, "Extension Echo/Drop initialized with configuration: '%s'", cs->conffile); if (TRACE_BOOL(FULL)) { struct rg_list * li; for (li = cs->conf.next; li != &cs->conf; li = li->next) { struct sed_conf_item * sci = (struct sed_conf_item *)li; char * act = (sci->action == ACT_ECHO) ? "ECHO" : "DROP"; if (sci->ext) { log_debug(" %s Code: %hhu, Vendor: %u, Ext-Type: %hu\n", act, sci->code, sci->vendor_id, sci->extype); continue; } if (sci->tlv) { log_debug(" %s Code: %hhu, Vendor: %u, Type: %hhu\n", act, sci->code, sci->vendor_id, sci->type); continue; } if (sci->vsa) { log_debug(" %s Code: %hhu, Vendor: %u\n", act, sci->code, sci->vendor_id); continue; } log_debug(" %s Code: %hhu\n", act, sci->code); } } /* We're done */ return cs; } /* Destroy the state */ static void sed_cs_destroy(struct rga_conf_state * cs) { TRACE_ENTRY("%p", cs); CHECK_PARAMS_DO( cs, ); while (! rg_list_is_empty(&cs->conf) ) { struct rg_list * li = cs->conf.next; rg_list_unlink(li); free(li); } CHECK_FCT_DO( sess_deregext( cs->sess_hdl ), ); free(cs); return; } /* Destroy a list of attributes saved in a session */ static void ssi_cleanup(void * ptr) { TRACE_ENTRY("%p", ptr); CHECK_PARAMS_DO( ptr , return ); struct rg_list *list = (struct rg_list *)ptr; while (! rg_list_is_empty(list) ) { struct sed_saved_item * ssi = (struct sed_saved_item *)(list->next); rg_list_unlink(&ssi->chain); free(ssi); } free(list); } /* Handle attributes from a RADIUS request as specified in the configuration */ static int sed_rad_req(struct rga_conf_state * cs, sess_id_t ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, msg_t ** diam_fw ) { size_t *nattr_pos; size_t nattr_used = 0; int idx; struct rg_list echo_list; struct rg_list *li; TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw); CHECK_PARAMS(cs && rad_req); rg_list_init(&echo_list); CHECK_MALLOC( nattr_pos = malloc(rad_req->attr_size * sizeof(size_t)) ); /* For each attribute in the original message */ for (idx = 0; idx < rad_req->attr_used; idx++) { int action = 0; struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(rad_req->buf + rad_req->attr_pos[idx]); /* Look if we have a matching attribute in our configuration */ for (li = cs->conf.next; li != &cs->conf; li = li->next) { struct sed_conf_item * sci = (struct sed_conf_item *)li; uint32_t vid; unsigned char * ptr; if (sci->code < attr->type) continue; if (sci->code > attr->type) break; /* matching code */ if (! sci->vsa) { action = sci->action; break; } if (attr->length < 8) continue; ptr = (unsigned char *)(attr + 1); /* since attr is not aligned, we cannot access *(attr+1) directly */ memcpy(&vid, ptr, sizeof(uint32_t)); if (sci->vendor_id < ntohl(vid)) continue; if (sci->vendor_id > ntohl(vid)) break; /* Matching vendor */ if ( ! sci->tlv && ! sci->ext ) { action = sci->action; break; } if (attr->length < 10) continue; if (sci->tlv) { struct radius_attr_vendor * tl = (struct radius_attr_vendor *)(ptr + sizeof(uint32_t)); if (tl->vendor_type == sci->type) { action = sci->action; break; } continue; } if (sci->ext) { /* To be done */ ASSERT(0); } } switch (action) { case ACT_DROP: TRACE_DEBUG(FULL, "Dropping attribute with code %hhd", attr->type); break; case ACT_ECHO: { struct sed_saved_item * sav = NULL; TRACE_DEBUG(FULL, "Saving attribute with code %hhd", attr->type); CHECK_MALLOC( sav = malloc(sizeof(struct sed_saved_item) + attr->length - sizeof(struct radius_attr_hdr)) ); rg_list_init(&sav->chain); memcpy(&sav->attr, attr, attr->length); rg_list_insert_before(&echo_list, &sav->chain); } break; case 0: /* Attribute was not specified in the configuration */ default: /* unknown action value */ /* We just keep the attribute in the RADIUS message */ nattr_pos[nattr_used++] = rad_req->attr_pos[idx]; } } /* Save the echoed values in the session, if any */ if (!rg_list_is_empty(&echo_list)) { CHECK_PARAMS(session && *session); CHECK_MALLOC( li = malloc(sizeof(struct rg_list)) ); memcpy(li, &echo_list, sizeof(struct rg_list)); /* Check that we have no previous data stored for this session, for debug */ ASSERT( sess_data_dereg(*session, cs->sess_hdl, NULL) == ENOENT ); /* Save the list in the session */ CHECK_FCT( sess_data_reg(*session, cs->sess_hdl, li, ssi_cleanup) ); } /* Finally update the radius message to remove all handled attributes */ free(rad_req->attr_pos); rad_req->attr_pos = nattr_pos; rad_req->attr_used = nattr_used; return 0; } /* Process an answer: add back the ECHO attributes, if any */ static int sed_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw ) { int ret; struct rg_list * list = NULL; TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw); CHECK_PARAMS(cs); /* If there is no session associated, just give up */ if (! session || ! *session) { TRACE_DEBUG(FULL, "No session associated with the message, nothing to do here..."); return 0; } /* No try and retrieve any data from the session */ ret = sess_data_dereg( *session, cs->sess_hdl, (void *)&list ); if (ret == ENOENT) { TRACE_DEBUG(FULL, "No data saved in the session, no attribute to add back"); return 0; } CHECK_FCT(ret); /* Return if another error occurred */ /* From this point on, we have a list of attributes to add to the radius message */ CHECK_PARAMS( rad_fw ); if ( *rad_fw == NULL ) { /* Will implement this when main extension is complete */ ASSERT(0); return ENOTSUP; } while (! rg_list_is_empty(list) ) { struct sed_saved_item * ssi = (struct sed_saved_item *)(list->next); struct radius_attr_hdr * rc; rg_list_unlink(&ssi->chain); TRACE_DEBUG(FULL, "Echo attribute in the RADIUS answer: type %hhu, len: %hhu", ssi->attr.type, ssi->attr.length); /* Add this attribute in the RADIUS message */ CHECK_MALLOC( radius_msg_add_attr(*rad_fw, ssi->attr.type, (unsigned char *)(ssi + 1), ssi->attr.length - sizeof(struct radius_attr_hdr)) ); free(ssi); } free(list); return 0; } int rga_register(int version, waaad_api_t * waaad_api, struct radius_gw_api * api) { TRACE_ENTRY("%d %p %p", version, waaad_api, api); CHECK_PARAMS( waaad_api && api ); if (version != RADIUS_GW_API_VER) { log_error("ABI version mismatch, please recompile this extension (%s)\n", __FILE__); return EINVAL; } /* Required to use the waaad api from this sub-extension: */ EXTENSION_API_INIT_INTERN( API_MODULE_ALL, "sub_echo_drop", waaad_api ); /* Initialize the radius_gw api callbacks */ api->rga_conf_parse_cb = sed_cs_create; api->rga_conf_free_cb = sed_cs_destroy; api->rga_rad_req_cb = sed_rad_req; api->rga_diam_ans_cb = sed_diam_ans; /* We're done, we must not initialize any state here since the extension must be re-entrant, but in sample_conf_parse */ return 0; }