# HG changeset patch # User Sebastien Decugis # Date 1241774921 -32400 # Node ID 6d22078428a54dd282f0f089e303b53e4887d0b3 # Parent 932ed12e182198bee06a3807dda43141f0096c19 Wrote initial conf parser for radius_gw ... to debug diff -r 932ed12e1821 -r 6d22078428a5 doc/radius_gw.conf.sample --- a/doc/radius_gw.conf.sample Thu May 07 11:01:46 2009 +0900 +++ b/doc/radius_gw.conf.sample Fri May 08 18:28:41 2009 +0900 @@ -18,22 +18,23 @@ # Extensions are registered either for every message, or by port (auth or acct), or by port and code. # The general format is: -# extension [: conf_file [: port] [: code(s)]] ; +# ext = extension [: conf_file] [: port] [: code(s)] ; # Where: -# extension is the file name (relative or absolute) of the extension to load. -# conf_file is optional and the name of the configuration file. -# port is optional, either "auth" or "acct". +# extension is the quoted file name (relative or absolute) of the extension to load. +# conf_file is optional and the quoted name of the configuration file. +# port is optional, either auth or acct. # If not specified, extension is called for messages incoming on both ports -# code(s): coma-separated list of command codes for which this extension must be called. +# code(s): space-separated list of command codes for which this extension must be called. # If not specified, the extension is called for all incoming messages. +# The values are interpreted as hexadecimal. # # The extensions are called in the order they appear in this file. # Here are some explained examples: -# 3579.so; Load this extension and call it for all messages. No configuration file. -# 3579.so : 3579.conf; Same as previous but with a configuration file specified. -# 3579.so : : auth; No configuration file, but called only for messages on authentication port. -# 3579.so : : 4, 8, 11; Called for messages with command code 4, 8, or 11 only. -# 3579.so : 3579.conf : auth : 4, 8, 11; All parameters combined. +# ext = "3579.so"; Load this extension and call it for all messages. No configuration file. +# ext = "3579.so" : "3579.conf"; Same as previous but with a configuration file specified. +# ext = "3579.so" : auth; No configuration file, but called only for messages on authentication port. +# ext = "3579.so" : 4 8 b; Called for messages with command code 4, 8, or 11 only. +# ext = "3579.so" : "3579.conf" : auth : 4 8 b; All parameters combined. # Once the list of extensions for an incoming message has been called (or empty list), # if some of the attributes have not been handled, an error is loggued. @@ -43,17 +44,14 @@ # RADIUS Clients # ################## -# Each RADIUS client must be declared in the form: IP = shared-secret ; +# Each RADIUS client must be declared in the form: cli = IP / shared-secret ; # IP can be ipv4 or ipv6 +# port can be additionaly restricted with brackets: IP[port] (ex: 192.168.0.1[1812]) # shared-secret can be a quoted string, or a list of hexadecimal values. # examples: -# 192.168.100.1 = "secret key" ; # the shared secret buffer is 0x736563726574206b6579 (length 10 bytes) -# fe00::1 = 73 65 63 72 65 74 20 6b 65 79; # same shared secret as previously +# cli = 192.168.100.1 / "secret key" ; # the shared secret buffer is 0x736563726574206b6579 (length 10 bytes) +# cli = fe00::1 / 73 65 63 72 65 74 20 6b 65 79; # same shared secret as previously # When a packet is received from an IP not declared here, it is silently discarded. -# -# Alternatively, a separate file can be specified in the form: -# radius_client_file = "/path/to/file"; -# The format of this file in that case is yet to be defined (option not supported fully yet) #################### @@ -71,7 +69,7 @@ # auth_server_ip4 = 0.0.0.0; # The IPv6 address to which the server is bound, or "disable" -# auth_server_ipv6 = :: ; +# auth_server_ip6 = :: ; ################ @@ -88,4 +86,4 @@ # acct_server_ip4 = 0.0.0.0; # The IPv6 address to which the server is bound, or "disable" -# acct_server_ipv6 = :: ; +# acct_server_ip6 = :: ; diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/CMakeLists.txt --- a/extensions/radius_gw/CMakeLists.txt Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/CMakeLists.txt Fri May 08 18:28:41 2009 +0900 @@ -12,6 +12,7 @@ lex.radius_gw.c radius_gw.tab.c radius_gw.tab.h + radius_msg.c ) SET( RGW_DEFAULT_HEADER diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/notes.txt --- a/extensions/radius_gw/notes.txt Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/notes.txt Fri May 08 18:28:41 2009 +0900 @@ -44,3 +44,10 @@ - Diameter answer (with linked Diameter Request inside) - When all extensions have been called, the RADIUS answer is generated, with appropriate authenticator and all, and sent to the RADIUS client. + +*** About sessions *** + +The session is created the first time an Access-Request is received. +Then a State attribute in the form "Diameter/..." is used to store the information. +More details in http://tools.ietf.org/html/rfc4005#section-9 + diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_gw.c --- a/extensions/radius_gw/radius_gw.c Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_gw.c Fri May 08 18:28:41 2009 +0900 @@ -32,3 +32,44 @@ * 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. * *********************************************************************************************************/ +/* + * Main file of the radius_gw extension. + */ + +#define DECLARE_API_POINTERS +#include "radius_gw_internal.h" + +static int rgw_init(void) +{ + rgw_conf_init(); +} + +static int rgw_entry(char * conffile) +{ + int ret = 0; + + ret = rgw_init(); + if (ret != 0) { + log_error("Error in extension initialization: %s\n", strerror(ret)); + return ret; + } + + ret = rgw_conf_handle(conffile); + if (ret != 0) { + log_error("Error while parsin the configuration: %s\n", strerror(ret)); + return ret; + } + + + rgw_dump_conf(); + + return ret; +} + +/* Unload */ +void waaad_ext_fini(void) +{ + ; +} + +EXTENSION_API_INIT( API_MODULE_ALL, rgw_entry, "radius_gw" ); diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_gw.h --- a/extensions/radius_gw/radius_gw.h Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_gw.h Fri May 08 18:28:41 2009 +0900 @@ -40,6 +40,7 @@ #define _RADIUS_GW_H /* This file extends definitions from the standard waaad API */ +#define IN_EXTENSION #include /* This type is used for all lists in this extension */ diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_gw.l --- a/extensions/radius_gw/radius_gw.l Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_gw.l Fri May 08 18:28:41 2009 +0900 @@ -32,3 +32,253 @@ * 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. * *********************************************************************************************************/ +/* Lex configuration parser for radius_gw extension. + * + */ + +%{ +#include "radius_gw_internal.h" +#include "radius_gw.tab.h" + +/* Update the column information */ +#ifdef DEBUG_LEX +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ + log_debug("(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n",\ + yylloc->first_line, yylloc->first_column, \ + yylloc->last_line, yylloc->last_column, \ + yy_act, yyleng, yytext); \ +} +#else /* DEBUG_LEX */ +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ +} +#endif + +/* %option noinput ? */ +#define YY_NO_INPUT +%} + +%option bison-bridge bison-locations +%option noyywrap +%option nounput + +/* Use the following start condition to parse an URI */ +%x IN_EXT +%x IN_CLI1 +%x IN_CLI2 +%x EXPECT_IP4 +%x EXPECT_IP6 +%x EXPECT_DECINT + +/* Quoted string. Multilines do not match. */ +qstring \"[^\"\n]*\" + +/* Used to match IP, IP6, and port */ +IP4 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} +IP6 [[:xdigit:]]*:[[:xdigit:]]*:[[:xdigit:].:]* +BR_PORT [[][0-9]+[]] + + +%% + + /* All sections */ +<*>\n { + /* Update the line count */ + yylloc->first_line++; + yylloc->last_line++; + yylloc->last_column=0; + } + +<*>([[:space:]]{-}[\n])+ ; /* Eat all spaces, not new lines */ +<*>#.*$ ; /* Eat all comments */ + +<*>{qstring} { + /* First copy the string without the quotes for use in the yacc parser */ + yylval->string = strdup(yytext+1); + if (yylval->string == NULL) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + yylval->string[yyleng-2] = '\0'; + + /* the yacc parser will check the string is valid */ + return QSTRING; + } + + + /* Extension section */ +(?i:"ext") { BEGIN(IN_EXT); return EXT_PREFIX; } + +(?i:"auth") { return AUTH; } +(?i:"acct") { return ACCT; } + +[[:xdigit:]]+ { + /* Convert this to an integer value */ + int ret = sscanf(yytext, "%x", &yylval->integer); + if (ret != 1) { + /* No matching: an error occurred */ + log_error("Unable to convert the value '%s' to a valid number: %s\n", yytext, strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + /* Maybe we could REJECT instead of failing here? */ + } + return INTEGER; + } + + /* Client section */ +(?i:"cli") { BEGIN(IN_CLI1); return CLI_PREFIX; } + + /* Match an IP (4 or 6) and optional port */ +({IP4}|{IP6}){BR_PORT}? { + char * work; + char * port; + unsigned short p = 0; + + work = strdup(yytext); + if ( work == NULL ) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + if (port = strchr(work, '[')) { + *port = '\0'; + port++; + if (sscanf(port, "%hu]", &p) != 1) { + log_error("'%s' is not a valid port: %s\n", port, strerror(errno)); + free(work); + return LEX_ERROR; /* trig an error in yacc parser */ + } + } + + /* Do we have an IP or IPv6? Let's check if we have ':' char somewhere in the beginning */ + if (memchr(work, ':', 5) != NULL) { + struct sockaddr_in6 * sin6 = NULL; + + sin6 = malloc(sizeof(struct sockaddr_in6)); + if (sin6 == NULL) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + free(work); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + memset(sin6, 0, sizeof(struct sockaddr_in6)); + sin6->sin6_family = AF_INET6; + if (inet_pton(AF_INET6, work, &sin6->sin6_addr) != 1) { + log_error("'%s' is not a valid IPv6 address: %s\n", work, strerror(errno)); + free(work); + free(sin6); + return LEX_ERROR; /* trig an error in yacc parser */ + } + sin6->sin6_port = htons(p); + yylval->ss = (struct sockaddr *)sin6; + } else { + struct sockaddr_in * sin = NULL; + + sin = malloc(sizeof(struct sockaddr_in)); + if (sin == NULL) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + free(work); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + memset(sin, 0, sizeof(struct sockaddr_in)); + sin->sin_family = AF_INET; + if (inet_pton(AF_INET, work, &sin->sin_addr) != 1) { + log_error("'%s' is not a valid IP address: %s\n", work, strerror(errno)); + free(work); + free(sin); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + sin->sin_port = htons(p); + yylval->ss = (struct sockaddr *)sin; + } + free(work); + return IP; + } + + +"/" { BEGIN(IN_CLI2); return '/'; } + + + /* Servers section */ +(?i:"auth_server_enable") { return AUTH_ENABLE; } +(?i:"auth_server_port") { BEGIN(EXPECT_DECINT); return AUTH_PORT; } +(?i:"auth_server_ip4") { BEGIN(EXPECT_IP4); return AUTH_IP4; } +(?i:"auth_server_ip6") { BEGIN(EXPECT_IP6); return AUTH_IP6; } +(?i:"acct_server_enable") { return ACCT_ENABLE; } +(?i:"acct_server_port") { BEGIN(EXPECT_DECINT); return ACCT_PORT; } +(?i:"acct_server_ip4") { BEGIN(EXPECT_IP4); return ACCT_IP4; } +(?i:"acct_server_ip6") { BEGIN(EXPECT_IP6); return ACCT_IP6; } + +[[:digit:]]+ { + /* Match an integer (not hexa) */ + int ret = sscanf(yytext, "%d", &yylval->integer); + if (ret != 1) { + /* No matching: an error occurred */ + log_error("Unable to convert the value '%s' to a valid number: %s\n", yytext, strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + /* Maybe we could REJECT instead of failing here? */ + } + return INTEGER; + } + +(?i:"disable") { return DISABLED; } + +{IP4} { + struct sockaddr_in * sin = NULL; + + sin = malloc(sizeof(struct sockaddr_in)); + if (sin == NULL) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + memset(sin, 0, sizeof(struct sockaddr_in)); + sin->sin_family = AF_INET; + if (inet_pton(AF_INET, yytext, &sin->sin_addr) != 1) { + log_error("'%s' is not a valid IP address: %s\n", yytext, strerror(errno)); + free(sin); + return LEX_ERROR; /* trig an error in yacc parser */ + } + yylval->ss = (struct sockaddr *)sin; + return IP; + } + +{IP6} { + struct sockaddr_in6 * sin6 = NULL; + + sin6 = malloc(sizeof(struct sockaddr_in6)); + if (sin6 == NULL) { + log_error("Unable to allocate memory: %s\n", strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + } + + memset(sin6, 0, sizeof(struct sockaddr_in6)); + sin6->sin6_family = AF_INET6; + if (inet_pton(AF_INET6, yytext, &sin6->sin6_addr) != 1) { + log_error("'%s' is not a valid IPv6 address: %s\n", yytext, strerror(errno)); + free(sin6); + return LEX_ERROR; /* trig an error in yacc parser */ + } + yylval->ss = (struct sockaddr *)sin6; + return IP; + } + + + /* Valid single characters for yyparse in all contexts */ +<*>[=] { return yytext[0]; } +<*>[;] { BEGIN(INITIAL); return yytext[0]; } + + /* Unrecognized token */ +<*>[[:alnum:]]+ | /* This rule is only useful to print a complete token in error messages */ + /* Unrecognized character */ +<*>. { + log_error("Unrecognized text on line %d col %d: '%s'.\n", yylloc->first_line, yylloc->first_column, yytext); + return LEX_ERROR; + } + +%% diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_gw.y --- a/extensions/radius_gw/radius_gw.y Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_gw.y Fri May 08 18:28:41 2009 +0900 @@ -32,3 +32,431 @@ * 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. * *********************************************************************************************************/ + +/* Yacc extension's configuration parser. + * See doc/radius_gw.conf.sample for configuration file format + */ + +/* For development only : */ +%debug +%error-verbose + +/* The parser receives the configuration file filename as parameter */ +%parse-param {char * conffile} + +/* Keep track of location */ +%locations +%pure-parser + +/* Not very sure if the two shift/reduce conflicts are normal... well... */ +%expect 2 + +%{ +#include "radius_gw_internal.h" +#include "radius_gw.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ + +#include +#include +#include +#include +#include +#include +#include + +/* Forward declaration */ +int yyparse(char * conffile); + +/* Declare the rgw_servers */ +struct rgw_servs rgw_servers; + +/* Parse the configuration file */ +int rgw_conf_handle(char * conffile) +{ + extern FILE * rgw_confin; + int ret; + + rgw_confin = fopen(conffile, "r"); + if (rgw_confin == NULL) { + ret = errno; + log_error("Unable to open extension configuration file %s for reading: %s\n", conffile, strerror(ret)); + return ret; + } + + ret = radius_gwparse(conffile); + + fclose(rgw_confin); + + if (ret != 0) { + return EINVAL; + } + + return 0; +} + +void rgw_dump_conf(void) +{ + char ipstr[INET6_ADDRSTRLEN]; + + log_normal("-------------------------\n"); + + log_normal(" auth server:\n"); + log_normal(" disabled..... : %s\n", rgw_servers.auth_serv.disabled ? "TRUE":"false"); + log_normal(" IP disabled.. : %s\n", rgw_servers.auth_serv.ipv4_disabled ? "TRUE":"false"); + log_normal(" IPv6 disabled : %s\n", rgw_servers.auth_serv.ipv6_disabled ? "TRUE":"false"); + log_normal(" port......... : %hu\n", ntohs(rgw_servers.auth_serv.port)); + inet_ntop(AF_INET, &rgw_servers.auth_serv.ipv4_endpoint,ipstr,sizeof(ipstr)); + log_normal(" IP bind...... : %s\n", ipstr); + inet_ntop(AF_INET6, &rgw_servers.auth_serv.ipv6_endpoint,ipstr,sizeof(ipstr)); + log_normal(" IPv6 bind.... : %s\n", ipstr); + + log_normal(" acct server:\n"); + log_normal(" disabled..... : %s\n", rgw_servers.acct_serv.disabled ? "TRUE":"false"); + log_normal(" IP disabled.. : %s\n", rgw_servers.acct_serv.ipv4_disabled ? "TRUE":"false"); + log_normal(" IPv6 disabled : %s\n", rgw_servers.acct_serv.ipv6_disabled ? "TRUE":"false"); + log_normal(" port......... : %hu\n", ntohs(rgw_servers.acct_serv.port)); + inet_ntop(AF_INET, &rgw_servers.acct_serv.ipv4_endpoint,ipstr,sizeof(ipstr)); + log_normal(" IP bind...... : %s\n", ipstr); + inet_ntop(AF_INET6, &rgw_servers.acct_serv.ipv6_endpoint,ipstr,sizeof(ipstr)); + log_normal(" IPv6 bind.... : %s\n", ipstr); + + log_normal("-------------------------\n"); +} + +void rgw_conf_init(void) +{ + memset(&rgw_servers, 0, sizeof(rgw_servers)); + + rgw_servers.auth_serv.port = htons(1812); + rgw_servers.auth_serv.ipv4_endpoint.s_addr = INADDR_ANY; + memcpy(&rgw_servers.auth_serv.ipv6_endpoint, &in6addr_any, sizeof(struct in6_addr)); + + rgw_servers.acct_serv.port = htons(1813); + rgw_servers.acct_serv.ipv4_endpoint.s_addr = INADDR_ANY; + memcpy(&rgw_servers.acct_serv.ipv6_endpoint, &in6addr_any, sizeof(struct in6_addr)); +} + + +/* The Lex parser prototype */ +int radius_gwlex(YYSTYPE *lvalp, YYLTYPE *llocp); + +/* Function to report the errors */ +void yyerror (YYLTYPE *ploc, char * conffile, char const *s) +{ + if (ploc->first_line != ploc->last_line) + log_error("%s:%d.%d-%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); + else if (ploc->first_column != ploc->last_column) + log_error("%s:%d.%d-%d : %s\n", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s); + else + log_error("%s:%d.%d : %s\n", conffile, ploc->first_line, ploc->first_column, s); +} + +/* This function checks a string value is a valid filename */ +static int is_valid_file( char * candidate ) +{ + int ret; + struct stat buffer; + + ret = stat(candidate, &buffer); + if (ret != 0) { + log_error("Error on file '%s': %s.\n", candidate, strerror(errno)); + return 0; + } + + /* Ok this candidate is valid */ + return 1; +} + +/* Very simple byte stack management */ +static unsigned char * buf = NULL; +static size_t buf_sz = 0; +static size_t buf_rsz = 0; +static inline int buf_add(unsigned char val) /* add a value in the array */ +{ + buf_sz++; + + if (buf_sz > buf_rsz) { + void * rez=NULL; + buf_rsz += 256; + rez = realloc(buf, buf_rsz); + if (rez == NULL) { + log_error("Error on memory allocation: %s\n", strerror(errno)); + return 0; + } + buf = (unsigned char *)rez; + } + buf[buf_sz - 1] = val; + return 1; +} +static inline void buf_reinit(void) +{ + free(buf); + buf = NULL; + buf_sz = 0; + buf_rsz = 0; +} + + +%} + +/* Values returned by lex for token */ +%union { + char *string; /* The string is allocated by strdup in lex.*/ + int integer; /* Store integer values */ + struct sockaddr *ss; /* sockaddr to free after use (alloc in lex) */ +} + +/* typed data */ +%token QSTRING +%token INTEGER +%token IP + +%type FILENAME +%type extconf +%type extport + +/* simple tokens */ +%token DISABLED +%token AUTH +%token ACCT + +%token EXT_PREFIX +%token CLI_PREFIX + +%token AUTH_ENABLE +%token AUTH_PORT +%token AUTH_IP4 +%token AUTH_IP6 +%token ACCT_ENABLE +%token ACCT_PORT +%token ACCT_IP4 +%token ACCT_IP6 + +/* In case of error in the lexical analysis */ +%token LEX_ERROR + + +/* -------------------------------------- */ +%% + + /* The grammar definition */ +conffile: /* empty grammar is OK */ + | conffile extension + | conffile clientdef + | conffile authserv + | conffile acctserv + ; + + +/* -------------------------------------- */ +FILENAME: QSTRING + { + /* Verify this is a valid file */ + if (!is_valid_file($1)) { + yyerror (&yylloc, conffile, "Error on file name, aborting..."); + YYERROR; + } + $$ = $1; + } + ; +/* -------------------------------------- */ + +extension: { + buf_reinit(); + } + EXT_PREFIX '=' FILENAME extconf extport extcodes ';' + { + /* Add this extension in the list */ + if ( rgw_add_extension( $4, $5, $6, buf, buf_sz ) ) { + yyerror (&yylloc, conffile, "Error parsing / adding extension !"); + YYERROR; + } + + /* Free the array */ + buf_reinit(); + } + ; + +extconf: /* empty */ + { + $$ = NULL; + } + | ':' QSTRING + { + $$ = $2; + } + ; + +extport: /* empty */ + { + $$ = RGW_EXT_PORT_AUTH | RGW_EXT_PORT_ACCT ; + } + | ':' AUTH + { + $$ = RGW_EXT_PORT_AUTH; + } + | ':' ACCT + { + $$ = RGW_EXT_PORT_ACCT; + } + +extcodes: /* empty */ + | ':' extcodes_list + ; + +extcodes_list: /* empty */ + | extcodes_list INTEGER + { + if ($2 < 0 || $2 > 255) { + yyerror (&yylloc, conffile, "Invalid command code value!"); + YYERROR; + } + if ( ! buf_add((unsigned char)$2) ) { + yyerror (&yylloc, conffile, "Error allocating memory!"); + YYERROR; + } + } + ; + +/* -------------------------------------- */ + +clientdef: { + buf_reinit(); + } + CLI_PREFIX '=' IP '/' clisecret_key ';' + { + /* Add this client */ + if ( rgw_add_client( $4, buf, buf_sz ) ) { + yyerror (&yylloc, conffile, "Error parsing / adding client !"); + YYERROR; + } + + /* reinit the buffer */ + buf_reinit(); + } + ; + +clisecret_key: /* empty */ + | clisecret_key QSTRING + { + int i; + size_t len = strlen($2); + for (i = 0; i < len; i++) { + if ( ! buf_add( $2 [i] ) ) { + yyerror (&yylloc, conffile, "Memory allocation error."); + YYERROR; + } + } + + free($2); + } + | clisecret_key INTEGER + { + if ( $2 < 0 || $2 > 255 ) { + yyerror (&yylloc, conffile, "Invalid value in key."); + YYERROR; + } + + if ( ! buf_add( $2 ) ) { + yyerror (&yylloc, conffile, "Memory allocation error."); + YYERROR; + } + } + ; + +/* -------------------------------------- */ + +authserv: AUTH_ENABLE '=' INTEGER ';' + { + if ($3 == 0) { + rgw_servers.auth_serv.disabled = 1; + } else { + rgw_servers.auth_serv.disabled = 0; + } + } + | AUTH_PORT '=' INTEGER ';' + { + if ($3 <= 0 || $3 > 65535) { + yyerror (&yylloc, conffile, "Invalid port number !"); + YYERROR; + } + + rgw_servers.auth_serv.port = htons($3); + } + | AUTH_IP4 '=' DISABLED ';' + { + rgw_servers.auth_serv.ipv4_disabled = 1; + } + | AUTH_IP4 '=' IP ';' + { + if (((struct sockaddr *)($3))->sa_family != AF_INET) { + yyerror (&yylloc, conffile, "Invalid address specification !"); + YYERROR; + } + memcpy( & rgw_servers.auth_serv.ipv4_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) ); + free($3); + rgw_servers.auth_serv.ipv4_disabled = 0; + } + | AUTH_IP6 '=' DISABLED ';' + { + rgw_servers.auth_serv.ipv6_disabled = 1; + } + | AUTH_IP6 '=' IP ';' + { + if (((struct sockaddr *)($3)) -> sa_family != AF_INET6) { + yyerror (&yylloc, conffile, "Invalid address specification !"); + YYERROR; + } + memcpy( & rgw_servers.auth_serv.ipv6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) ); + free($3); + rgw_servers.auth_serv.ipv6_disabled = 0; + } + ; + +/* -------------------------------------- */ + +acctserv: ACCT_ENABLE '=' INTEGER ';' + { + if ($3 == 0) { + rgw_servers.acct_serv.disabled = 1; + } else { + rgw_servers.acct_serv.disabled = 0; + } + } + | ACCT_PORT '=' INTEGER ';' + { + if ($3 <= 0 || $3 > 65535) { + yyerror (&yylloc, conffile, "Invalid port number !"); + YYERROR; + } + + rgw_servers.acct_serv.port = htons($3); + } + | ACCT_IP4 '=' DISABLED ';' + { + rgw_servers.acct_serv.ipv4_disabled = 1; + } + | ACCT_IP4 '=' IP ';' + { + if (((struct sockaddr *)($3)) -> sa_family != AF_INET) { + yyerror (&yylloc, conffile, "Invalid address specification !"); + YYERROR; + } + memcpy( & rgw_servers.auth_serv.ipv4_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) ); + free($3); + rgw_servers.acct_serv.ipv4_disabled = 0; + } + | ACCT_IP6 '=' DISABLED ';' + { + rgw_servers.acct_serv.ipv6_disabled = 1; + } + | ACCT_IP6 '=' IP ';' + { + if (((struct sockaddr *)($3)) -> sa_family != AF_INET6) { + yyerror (&yylloc, conffile, "Invalid address specification !"); + YYERROR; + } + memcpy( & rgw_servers.auth_serv.ipv6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) ); + free($3); + rgw_servers.acct_serv.ipv6_disabled = 0; + } + ; diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_gw_internal.h --- a/extensions/radius_gw/radius_gw_internal.h Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_gw_internal.h Fri May 08 18:28:41 2009 +0900 @@ -44,9 +44,11 @@ /* The content of this file is mainly used to declare interfaces between lex/yacc files and the main extension file. */ -int rgw_add_extension( /* file, conffile, port(s), code_array, code_len */ ); +#define RGW_EXT_PORT_AUTH 1 +#define RGW_EXT_PORT_ACCT 2 +int rgw_add_extension( char * extfile, char * conffile, int port, unsigned char * codes_array, size_t codes_sz ); -int rgw_add_client(/* ip, key, keylen */); +int rgw_add_client( struct sockaddr * ip_port, unsigned char * key, size_t keylen ); struct rgw_serv { unsigned disabled :1; @@ -56,15 +58,21 @@ uint16_t port; /* stored in network byte order */ - struct sockaddr_in ipv4_endpoint; - struct sockaddr_in6 ipv6_endpoint; + struct in_addr ipv4_endpoint; + struct in6_addr ipv6_endpoint; }; -struct { +extern struct rgw_servs { struct rgw_serv auth_serv; struct rgw_serv acct_serv; } rgw_servers; +void rgw_conf_init(void); +int rgw_conf_handle(char * conffile); + +void rgw_dump_conf(void); +void rgw_dump_extensions(void); +void rgw_dump_clients(void); #endif /* _RADIUS_GW_INTERNAL_H */ diff -r 932ed12e1821 -r 6d22078428a5 extensions/radius_gw/radius_msg.c --- a/extensions/radius_gw/radius_msg.c Thu May 07 11:01:46 2009 +0900 +++ b/extensions/radius_gw/radius_msg.c Fri May 08 18:28:41 2009 +0900 @@ -41,6 +41,7 @@ modules do not need to "know" the actual representation of RADIUS messages on the network. They only receive the logical view as exposed in the radius_gw.h file. */ +#include "radius_gw_internal.h" /* To ensure packed structures with some common compilers */ #ifdef __GNUC__ @@ -53,22 +54,22 @@ #endif /* _MSC_VER */ struct radius_hdr { - u8 code; - u8 identifier; - u16 length; /* including this header */ - u8 authenticator[16]; + uint8_t code; + uint8_t identifier; + uint16_t length; /* including this header */ + uint8_t authenticator[16]; /* followed by length-20 octets of attributes */ } STRUCT_PACKED; struct radius_attr_hdr { - u8 type; - u8 length; /* including this header */ + uint8_t type; + uint8_t length; /* including this header */ /* followed by length-2 octets of attribute value */ } STRUCT_PACKED; struct radius_attr_vendor { - u8 vendor_type; - u8 vendor_length; + uint8_t vendor_type; + uint8_t vendor_length; } STRUCT_PACKED; #ifdef _MSC_VER