blob: 53ab746d423b803a91180ba57034df2bbe465cdc [file] [log] [blame]
Brian Waters13d96012017-12-08 16:53:31 -06001/*********************************************************************************************************
2* Software License Agreement (BSD License) *
3* Author: Sebastien Decugis <sdecugis@freediameter.net> *
4* *
5* Copyright (c) 2013, WIDE Project and NICT *
6* All rights reserved. *
7* *
8* Redistribution and use of this software in source and binary forms, with or without modification, are *
9* permitted provided that the following conditions are met: *
10* *
11* * Redistributions of source code must retain the above *
12* copyright notice, this list of conditions and the *
13* following disclaimer. *
14* *
15* * Redistributions in binary form must reproduce the above *
16* copyright notice, this list of conditions and the *
17* following disclaimer in the documentation and/or other *
18* materials provided with the distribution. *
19* *
20* * Neither the name of the WIDE Project or NICT nor the *
21* names of its contributors may be used to endorse or *
22* promote products derived from this software without *
23* specific prior written permission of WIDE Project and *
24* NICT. *
25* *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34*********************************************************************************************************/
35
36/* Yacc extension's configuration parser.
37 * See doc/app_radgw.conf.sample for configuration file format
38 */
39
40/* For development only : */
41%debug
42%error-verbose
43
44/* The parser receives the configuration file filename as parameter */
45%parse-param {char * conffile}
46
47/* Keep track of location */
48%locations
49%pure-parser
50
51%{
52#include "rgw.h"
53#include "rgw_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */
54
55#include <sys/socket.h>
56#include <arpa/inet.h>
57#include <netdb.h>
58
59/* Forward declaration */
60int yyparse(char * conffile);
61
62/* Parse the configuration file */
63int rgw_conf_handle(char * conffile)
64{
65 extern FILE * rgw_confin;
66 int ret;
67
68 rgw_confin = fopen(conffile, "r");
69 if (rgw_confin == NULL) {
70 ret = errno;
71 fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret));
72 return ret;
73 }
74
75 ret = rgw_confparse(conffile);
76
77 fclose(rgw_confin);
78
79 if (ret != 0) {
80 return EINVAL;
81 }
82
83 return 0;
84}
85
86/* The Lex parser prototype */
87int rgw_conflex(YYSTYPE *lvalp, YYLTYPE *llocp);
88
89/* Function to report the errors */
90void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
91{
92 if (ploc->first_line != ploc->last_line)
93 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
94 else if (ploc->first_column != ploc->last_column)
95 fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s);
96 else
97 fd_log_debug("%s:%d.%d : %s", conffile, ploc->first_line, ploc->first_column, s);
98}
99
100/* Very simple byte stack management */
101static unsigned char * buf = NULL;
102static size_t buf_sz = 0;
103static size_t buf_rsz = 0;
104static inline int buf_add(unsigned char val) /* add a value in the array */
105{
106 buf_sz++;
107
108 if (buf_sz > buf_rsz) {
109 void * rez=NULL;
110 buf_rsz += 256;
111 rez = realloc(buf, buf_rsz);
112 if (rez == NULL) {
113 fd_log_debug("Error on memory allocation: %s", strerror(errno));
114 return 0;
115 }
116 buf = (unsigned char *)rez;
117 }
118 buf[buf_sz - 1] = val;
119 return 1;
120}
121static inline void buf_reinit(void)
122{
123 free(buf);
124 buf = NULL;
125 buf_sz = 0;
126 buf_rsz = 0;
127}
128
129static int port = 0;
130static char * plgconffile = NULL;
131
132%}
133
134/* Values returned by lex for token */
135%union {
136 char *string; /* The string is allocated by strdup in lex.*/
137 int integer; /* Store integer values */
138 struct sockaddr *ss; /* sockaddr to free after use (alloc in lex) */
139}
140
141/* typed data */
142%token <string> QSTRING
143%token <integer> INTEGER
144%token <ss> IP
145
146%type <string> FINDFILEEXT
147
148%token <integer> NAS_OR_PXY
149
150/* simple tokens */
151%token DISABLED
152%token AUTH
153%token ACCT
154
155%token PLG_PREFIX
156
157%token AUTH_ENABLE
158%token AUTH_PORT
159%token AUTH_IP4
160%token AUTH_IP6
161%token ACCT_ENABLE
162%token ACCT_PORT
163%token ACCT_IP4
164%token ACCT_IP6
165
166/* In case of error in the lexical analysis */
167%token LEX_ERROR
168
169
170/* -------------------------------------- */
171%%
172
173 /* The grammar definition */
174conffile: /* empty grammar is OK */
175 | conffile plugin
176 | conffile clientdef
177 | conffile authserv
178 | conffile acctserv
179 ;
180
181
182/* -------------------------------------- */
183FINDFILEEXT: QSTRING
184 {
185 char * fname = $1;
186 FILE * fd;
187
188 /* First, check if the file exists */
189 fd = fopen(fname, "r");
190 if ((fd == NULL) && (*fname != '/')) {
191 char * bkp = fname;
192 CHECK_MALLOC_DO( fname = malloc( strlen(bkp) + strlen(DEFAULT_EXTENSIONS_PATH) + 2 ),
193 { yyerror (&yylloc, conffile, "Not enough memory"); YYERROR; } );
194 sprintf(fname, DEFAULT_EXTENSIONS_PATH "/%s", bkp);
195 free(bkp);
196 fd = fopen(fname, "r");
197 }
198 if (fd == NULL) {
199 int ret = errno;
200 TRACE_DEBUG(INFO, "Unable to open file %s for reading: %s", fname, strerror(ret));
201 yyerror (&yylloc, conffile, "Error adding plugin");
202 YYERROR;
203 }
204 fclose(fd);
205
206 $$ = fname;
207 }
208 ;
209/* -------------------------------------- */
210plugin: {
211 /* Reset the parameters */
212 buf_reinit();
213 port = RGW_PLG_TYPE_AUTH | RGW_PLG_TYPE_ACCT ;
214 free(plgconffile); plgconffile = NULL;
215 }
216 PLG_PREFIX '=' FINDFILEEXT plg_attributes ';'
217 {
218 /* Add this extension in the list */
219 if ( rgw_plg_add( $4, plgconffile, port, &buf, buf_sz ) ) {
220 yyerror (&yylloc, conffile, "Error parsing / adding extension !");
221 YYERROR;
222 }
223
224 /* Free the array */
225 buf_reinit();
226
227 /* stop conffile from being freed here */
228 plgconffile = NULL;
229 }
230 ;
231
232plg_attributes: /* empty */
233 | plg_attributes ':' QSTRING
234 {
235 plgconffile = $3;
236 }
237 | plg_attributes ':' AUTH
238 {
239 port = RGW_PLG_TYPE_AUTH;
240 }
241 | plg_attributes ':' ACCT
242 {
243 port = RGW_PLG_TYPE_ACCT;
244 }
245 | plg_attributes ':' extcodes_list
246 ;
247
248extcodes_list: /* empty */
249 | extcodes_list INTEGER
250 {
251 if ($2 < 0 || $2 > 255) {
252 yyerror (&yylloc, conffile, "Invalid command code value!");
253 YYERROR;
254 }
255 if ( ! buf_add((unsigned char)$2) ) {
256 yyerror (&yylloc, conffile, "Error allocating memory!");
257 YYERROR;
258 }
259 }
260 ;
261
262/* -------------------------------------- */
263
264clientdef: {
265 buf_reinit();
266 }
267 NAS_OR_PXY '=' IP '/' clisecret_key ';'
268 {
269 /* Add this client */
270 if ( rgw_clients_add( $4, &buf, buf_sz, $2 ) ) {
271 yyerror (&yylloc, conffile, "Error parsing / adding client !");
272 YYERROR;
273 }
274
275 /* reinit the buffer */
276 buf_reinit();
277 }
278 ;
279
280clisecret_key: /* empty */
281 | clisecret_key QSTRING
282 {
283 int i;
284 size_t len = strlen($2);
285 for (i = 0; i < len; i++) {
286 if ( ! buf_add( $2 [i] ) ) {
287 yyerror (&yylloc, conffile, "Memory allocation error.");
288 YYERROR;
289 }
290 }
291
292 free($2);
293 }
294 | clisecret_key INTEGER
295 {
296 if ( $2 < 0 || $2 > 255 ) {
297 yyerror (&yylloc, conffile, "Invalid value in key.");
298 YYERROR;
299 }
300
301 if ( ! buf_add( $2 ) ) {
302 yyerror (&yylloc, conffile, "Memory allocation error.");
303 YYERROR;
304 }
305 }
306 ;
307
308/* -------------------------------------- */
309
310authserv: AUTH_ENABLE '=' INTEGER ';'
311 {
312 if ($3 == 0) {
313 rgw_servers.auth_serv.disabled = 1;
314 } else {
315 rgw_servers.auth_serv.disabled = 0;
316 }
317 }
318 | AUTH_PORT '=' INTEGER ';'
319 {
320 if ($3 <= 0 || $3 > 65535) {
321 yyerror (&yylloc, conffile, "Invalid port number !");
322 YYERROR;
323 }
324
325 rgw_servers.auth_serv.port = htons($3);
326 }
327 | AUTH_IP4 '=' DISABLED ';'
328 {
329 rgw_servers.auth_serv.ip_disabled = 1;
330 }
331 | AUTH_IP4 '=' IP ';'
332 {
333 if (((struct sockaddr *)($3))->sa_family != AF_INET) {
334 yyerror (&yylloc, conffile, "Invalid address specification !");
335 YYERROR;
336 }
337 memcpy( & rgw_servers.auth_serv.ip_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
338 free($3);
339 rgw_servers.auth_serv.ip_disabled = 0;
340 }
341 | AUTH_IP6 '=' DISABLED ';'
342 {
343 rgw_servers.auth_serv.ip6_disabled = 1;
344 }
345 | AUTH_IP6 '=' IP ';'
346 {
347 if (((struct sockaddr *)($3)) -> sa_family != AF_INET6) {
348 yyerror (&yylloc, conffile, "Invalid address specification !");
349 YYERROR;
350 }
351 memcpy( & rgw_servers.auth_serv.ip6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
352 free($3);
353 rgw_servers.auth_serv.ip6_disabled = 0;
354 }
355 ;
356
357/* -------------------------------------- */
358
359acctserv: ACCT_ENABLE '=' INTEGER ';'
360 {
361 if ($3 == 0) {
362 rgw_servers.acct_serv.disabled = 1;
363 } else {
364 rgw_servers.acct_serv.disabled = 0;
365 }
366 }
367 | ACCT_PORT '=' INTEGER ';'
368 {
369 if ($3 <= 0 || $3 > 65535) {
370 yyerror (&yylloc, conffile, "Invalid port number !");
371 YYERROR;
372 }
373
374 rgw_servers.acct_serv.port = htons($3);
375 }
376 | ACCT_IP4 '=' DISABLED ';'
377 {
378 rgw_servers.acct_serv.ip_disabled = 1;
379 }
380 | ACCT_IP4 '=' IP ';'
381 {
382 if (((struct sockaddr *)($3)) -> sa_family != AF_INET) {
383 yyerror (&yylloc, conffile, "Invalid address specification !");
384 YYERROR;
385 }
386 memcpy( & rgw_servers.auth_serv.ip_endpoint, &((struct sockaddr_in *)($3))->sin_addr, sizeof(struct in_addr) );
387 free($3);
388 rgw_servers.acct_serv.ip_disabled = 0;
389 }
390 | ACCT_IP6 '=' DISABLED ';'
391 {
392 rgw_servers.acct_serv.ip6_disabled = 1;
393 }
394 | ACCT_IP6 '=' IP ';'
395 {
396 if (((struct sockaddr *)($3)) -> sa_family != AF_INET6) {
397 yyerror (&yylloc, conffile, "Invalid address specification !");
398 YYERROR;
399 }
400 memcpy( & rgw_servers.auth_serv.ip6_endpoint, &((struct sockaddr_in6 *)($3))->sin6_addr, sizeof(struct in6_addr) );
401 free($3);
402 rgw_servers.acct_serv.ip6_disabled = 0;
403 }
404 ;