diff libfdcore/fdd.y @ 658:f198d16fa7f4

Initial commit for 1.1.0: * Restructuring: * libfreeDiameter: - renamed folder & binary into libfdproto - renamed libfD.h into fdproto-internal.h - removed signals management (replaced by triggers in libfdcore) * freeDiameter split into: - libfdcore (most contents) - renamed fD.h into fdcore-internal.h - added core.c for framework init/shutdown. - new triggers mechanism in events.c. - freeDiameterd (main, command line parsing, signals management) * tests: - now in top-level directory tests. * other changes: - fd_dict_new now returns 0 on duplicate identical entries. - fixes in dict_legacy_xml - fixes in some dictionaries - moved FD_DEFAULT_CONF_FILENAME definition to freeDiameter-host.h
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 14 Jan 2011 15:15:23 +0900
parents freeDiameter/fdd.y@7c9a00bfd115
children 2e94ef0515d7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfdcore/fdd.y	Fri Jan 14 15:15:23 2011 +0900
@@ -0,0 +1,600 @@
+/*********************************************************************************************************
+* 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.								 *
+*********************************************************************************************************/
+
+/* Yacc configuration parser.
+ *
+ * This file defines the grammar of the configuration file.
+ * Note that each extension has a separate independant configuration file.
+ *
+ * Note : This module is NOT thread-safe. All processing must be done from one thread only.
+ */
+
+/* For development only : */
+%debug 
+%error-verbose
+
+%parse-param {struct fd_config * conf}
+
+/* Keep track of location */
+%locations 
+%pure-parser
+
+%{
+#include "fdcore-internal.h"
+#include "fdd.tab.h"	/* bug : bison does not define the YYLTYPE before including this bloc, so... */
+
+/* The Lex parser prototype */
+int fddlex(YYSTYPE *lvalp, YYLTYPE *llocp);
+
+/* Function to report error */
+void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s)
+{
+	if (ploc->first_line != ploc->last_line)
+		fprintf(stderr, "%s:%d.%d-%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
+	else if (ploc->first_column != ploc->last_column)
+		fprintf(stderr, "%s:%d.%d-%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_column, s);
+	else
+		fprintf(stderr, "%s:%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, s);
+}
+
+int got_peer_noip = 0;
+int got_peer_noipv6 = 0;
+int got_peer_notcp = 0;
+int got_peer_nosctp = 0;
+
+struct peer_info fddpi;
+
+%}
+
+/* Values returned by lex for token */
+%union {
+	char 		 *string;	/* The string is allocated by strdup in lex.*/
+	int		  integer;	/* Store integer values */
+}
+
+/* In case of error in the lexical analysis */
+%token 		LEX_ERROR
+
+%token <string>	QSTRING
+%token <integer> INTEGER
+
+%type <string> 	extconf
+
+%token		IDENTITY
+%token		REALM
+%token		PORT
+%token		SECPORT
+%token		NOIP
+%token		NOIP6
+%token		NOTCP
+%token		NOSCTP
+%token		PREFERTCP
+%token		OLDTLS
+%token		NOTLS
+%token		SCTPSTREAMS
+%token		APPSERVTHREADS
+%token		LISTENON
+%token		TCTIMER
+%token		TWTIMER
+%token		NORELAY
+%token		LOADEXT
+%token		CONNPEER
+%token		CONNTO
+%token		TLS_CRED
+%token		TLS_CA
+%token		TLS_CRL
+%token		TLS_PRIO
+%token		TLS_DH_BITS
+%token		TLS_DH_FILE
+
+
+/* -------------------------------------- */
+%%
+
+	/* The grammar definition - Sections blocs. */
+conffile:		/* Empty is OK -- for simplicity here, we reject in daemon later */
+			| conffile identity
+			| conffile realm
+			| conffile tctimer
+			| conffile twtimer
+			| conffile port
+			| conffile secport
+			| conffile sctpstreams
+			| conffile listenon
+			| conffile norelay
+			| conffile appservthreads
+			| conffile noip
+			| conffile noip6
+			| conffile notcp
+			| conffile nosctp
+			| conffile prefertcp
+			| conffile oldtls
+			| conffile loadext
+			| conffile connpeer
+			| conffile tls_cred
+			| conffile tls_ca
+			| conffile tls_crl
+			| conffile tls_prio
+			| conffile tls_dh
+			| conffile errors
+			{
+				yyerror(&yylloc, conf, "An error occurred while parsing the configuration file");
+				return EINVAL;
+			}
+			;
+
+			/* Lexical or syntax error */
+errors:			LEX_ERROR
+			| error
+			;
+
+identity:		IDENTITY '=' QSTRING ';'
+			{
+				conf->cnf_diamid = $3;
+			}
+			;
+
+realm:			REALM '=' QSTRING ';'
+			{
+				conf->cnf_diamrlm = $3;
+			}
+			;
+
+tctimer:		TCTIMER '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 0),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_timer_tc = (unsigned int)$3;
+			}
+			;
+
+twtimer:		TWTIMER '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 5),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_timer_tw = (unsigned int)$3;
+			}
+			;
+
+port:			PORT '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_port = (uint16_t)$3;
+			}
+			;
+
+secport:		SECPORT '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_port_tls = (uint16_t)$3;
+			}
+			;
+
+sctpstreams:		SCTPSTREAMS '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_sctp_str = (uint16_t)$3;
+			}
+			;
+
+listenon:		LISTENON '=' QSTRING ';'
+			{
+				struct addrinfo hints, *ai;
+				int ret;
+				
+				memset(&hints, 0, sizeof(hints));
+				hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+				ret = getaddrinfo($3, NULL, &hints, &ai);
+				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
+				CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR );
+				freeaddrinfo(ai);
+				free($3);
+			}
+			;
+
+norelay:		NORELAY ';'
+			{
+				conf->cnf_flags.no_fwd = 1;
+			}
+			;
+
+appservthreads:		APPSERVTHREADS '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1024),
+					{ yyerror (&yylloc, conf, "Invalid value"); YYERROR; } );
+				conf->cnf_dispthr = (uint16_t)$3;
+			}
+			;
+
+noip:			NOIP ';'
+			{
+				if (got_peer_noipv6) { 
+					yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IPv6."); 
+					YYERROR; 
+				}
+				conf->cnf_flags.no_ip4 = 1;
+			}
+			;
+
+noip6:			NOIP6 ';'
+			{
+				if (got_peer_noip) { 
+					yyerror (&yylloc, conf, "No_IP conflicts with a ConnectPeer directive No_IP."); 
+					YYERROR; 
+				}
+				conf->cnf_flags.no_ip6 = 1;
+			}
+			;
+
+notcp:			NOTCP ';'
+			{
+				#ifdef DISABLE_SCTP
+				yyerror (&yylloc, conf, "No_TCP cannot be specified for daemon compiled with DISABLE_SCTP option."); 
+				YYERROR; 
+				#endif
+				if (conf->cnf_flags.no_sctp)
+				{
+					yyerror (&yylloc, conf, "No_TCP conflicts with No_SCTP directive." ); 
+					YYERROR; 
+				}
+				if (got_peer_nosctp) { 
+					yyerror (&yylloc, conf, "No_TCP conflicts with a ConnectPeer directive No_SCTP."); 
+					YYERROR; 
+				}
+				conf->cnf_flags.no_tcp = 1;
+			}
+			;
+
+nosctp:			NOSCTP ';'
+			{
+				if (conf->cnf_flags.no_tcp)
+				{
+					yyerror (&yylloc, conf, "No_SCTP conflicts with No_TCP directive." ); 
+					YYERROR; 
+				}
+				if (got_peer_notcp) { 
+					yyerror (&yylloc, conf, "No_SCTP conflicts with a ConnectPeer directive No_TCP.");
+					YYERROR;
+				}
+				conf->cnf_flags.no_sctp = 1;
+			}
+			;
+
+prefertcp:		PREFERTCP ';'
+			{
+				conf->cnf_flags.pr_tcp = 1;
+			}
+			;
+
+oldtls:			OLDTLS ';'
+			{
+				conf->cnf_flags.tls_alg = 1;
+			}
+			;
+
+loadext:		LOADEXT '=' QSTRING extconf ';'
+			{
+				char * fname;
+				char * cfname;
+				FILE * fd;
+				
+				/* Try and open the extension file */
+				fname = $3;
+				fd = fopen(fname, "r");
+				if ((fd == NULL) && (*fname != '/')) {
+					char * bkp = fname;
+					CHECK_MALLOC_DO( fname = malloc( strlen(bkp) + strlen(DEFAULT_EXTENSIONS_PATH) + 2 ),
+						{ yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
+					sprintf(fname, DEFAULT_EXTENSIONS_PATH "/%s", bkp);
+					free(bkp);
+					fd = fopen(fname, "r");
+				}
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open extension file %s for reading: %s\n", fname, strerror(ret));
+					yyerror (&yylloc, conf, "Error adding extension"); 
+					YYERROR;
+				}
+				fclose(fd);
+				
+				/* Try and open the configuration file (optional) */
+				cfname = $4;
+				if (cfname) {
+					fd = fopen(cfname, "r");
+					if ((fd == NULL) && (*cfname != '/')) {
+						char * test;
+						CHECK_MALLOC_DO( test = malloc( strlen(cfname) + strlen(DEFAULT_CONF_PATH) + 2 ),
+							{ yyerror (&yylloc, conf, "Not enough memory"); YYERROR; } );
+						sprintf(test, DEFAULT_CONF_PATH "/%s", cfname);
+						fd = fopen(test, "r");
+						if (fd) {
+							free(cfname);
+							cfname=test;
+						} else {
+							/* This is not an error, we allow an extension to wait for something else than a real conf file. */
+							free(test);
+						}
+					}
+					if (fd)
+						fclose(fd);
+				}
+				
+				CHECK_FCT_DO( fd_ext_add( fname, cfname ),
+					{ yyerror (&yylloc, conf, "Error adding extension"); YYERROR; } );
+			}
+			;
+			
+extconf:		/* empty */
+			{
+				$$ = NULL;
+			}
+			| ':' QSTRING
+			{
+				$$ = $2;
+			}
+			;
+			
+connpeer:		{
+				memset(&fddpi, 0, sizeof(fddpi));
+				fddpi.config.pic_flags.persist = PI_PRST_ALWAYS;
+				fd_list_init( &fddpi.pi_endpoints, NULL );
+			}
+			CONNPEER '=' QSTRING peerinfo ';'
+			{
+				fddpi.pi_diamid = $4;
+				CHECK_FCT_DO( fd_peer_add ( &fddpi, conf->cnf_file, NULL, NULL ),
+					{ yyerror (&yylloc, conf, "Error adding ConnectPeer information"); YYERROR; } );
+					
+				/* Now destroy any content in the structure */
+				free(fddpi.pi_diamid);
+				free(fddpi.config.pic_realm);
+				free(fddpi.config.pic_priority);
+				while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) {
+					struct fd_list * li = fddpi.pi_endpoints.next;
+					fd_list_unlink(li);
+					free(li);
+				}
+			}
+			;
+			
+peerinfo:		/* empty */
+			| '{' peerparams '}'
+			;
+			
+peerparams:		/* empty */
+			| peerparams NOIP ';'
+			{
+				if ((conf->cnf_flags.no_ip6) || (fddpi.config.pic_flags.pro3 == PI_P3_IP)) { 
+					yyerror (&yylloc, conf, "No_IP conflicts with a No_IPv6 directive.");
+					YYERROR;
+				}
+				got_peer_noip++;
+				fddpi.config.pic_flags.pro3 = PI_P3_IPv6;
+			}
+			| peerparams NOIP6 ';'
+			{
+				if ((conf->cnf_flags.no_ip4) || (fddpi.config.pic_flags.pro3 == PI_P3_IPv6)) { 
+					yyerror (&yylloc, conf, "No_IPv6 conflicts with a No_IP directive.");
+					YYERROR;
+				}
+				got_peer_noipv6++;
+				fddpi.config.pic_flags.pro3 = PI_P3_IP;
+			}
+			| peerparams NOTCP ';'
+			{
+				#ifdef DISABLE_SCTP
+					yyerror (&yylloc, conf, "No_TCP cannot be specified in daemon compiled with DISABLE_SCTP option.");
+					YYERROR;
+				#endif
+				if ((conf->cnf_flags.no_sctp) || (fddpi.config.pic_flags.pro4 == PI_P4_TCP)) { 
+					yyerror (&yylloc, conf, "No_TCP conflicts with a No_SCTP directive.");
+					YYERROR;
+				}
+				got_peer_notcp++;
+				fddpi.config.pic_flags.pro4 = PI_P4_SCTP;
+			}
+			| peerparams NOSCTP ';'
+			{
+				if ((conf->cnf_flags.no_tcp) || (fddpi.config.pic_flags.pro4 == PI_P4_SCTP)) { 
+					yyerror (&yylloc, conf, "No_SCTP conflicts with a No_TCP directive.");
+					YYERROR;
+				}
+				got_peer_nosctp++;
+				fddpi.config.pic_flags.pro4 = PI_P4_TCP;
+			}
+			| peerparams PREFERTCP ';'
+			{
+				fddpi.config.pic_flags.alg = PI_ALGPREF_TCP;
+			}
+			| peerparams OLDTLS ';'
+			{
+				fddpi.config.pic_flags.sec |= PI_SEC_TLS_OLD;
+			}
+			| peerparams NOTLS ';'
+			{
+				fddpi.config.pic_flags.sec |= PI_SEC_NONE;
+			}
+			| peerparams REALM '=' QSTRING ';'
+			{
+				fddpi.config.pic_realm = $4;
+			}
+			| peerparams PORT '=' INTEGER ';'
+			{
+				CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16),
+					{ yyerror (&yylloc, conf, "Invalid port value"); YYERROR; } );
+				fddpi.config.pic_port = (uint16_t)$4;
+			}
+			| peerparams TCTIMER '=' INTEGER ';'
+			{
+				fddpi.config.pic_tctimer = $4;
+			}
+			| peerparams TWTIMER '=' INTEGER ';'
+			{
+				fddpi.config.pic_twtimer = $4;
+			}
+			| peerparams TLS_PRIO '=' QSTRING ';'
+			{
+				fddpi.config.pic_priority = $4;
+			}
+			| peerparams CONNTO '=' QSTRING ';'
+			{
+				struct addrinfo hints, *ai;
+				int ret;
+				int disc = 0;
+				
+				memset(&hints, 0, sizeof(hints));
+				hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
+				ret = getaddrinfo($4, NULL, &hints, &ai);
+				if (ret == EAI_NONAME) {
+					/* The name was maybe not numeric, try again */
+					disc = EP_FL_DISC;
+					hints.ai_flags &= ~ AI_NUMERICHOST;
+					ret = getaddrinfo($4, NULL, &hints, &ai);
+				}
+				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
+				
+				CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR );
+				free($4);
+				freeaddrinfo(ai);
+			}
+			;
+
+tls_cred:		TLS_CRED '=' QSTRING ',' QSTRING ';'
+			{
+				FILE * fd;
+				fd = fopen($3, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open certificate file %s for reading: %s\n", $3, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+				fd = fopen($5, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open private key file %s for reading: %s\n", $5, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+				conf->cnf_sec_data.cert_file = $3;
+				conf->cnf_sec_data.key_file = $5;
+				
+				CHECK_GNUTLS_DO( gnutls_certificate_set_x509_key_file( 
+							conf->cnf_sec_data.credentials,
+							conf->cnf_sec_data.cert_file,
+							conf->cnf_sec_data.key_file,
+							GNUTLS_X509_FMT_PEM),
+						{ yyerror (&yylloc, conf, "Error opening certificate or private key file."); YYERROR; } );
+			}
+			;
+
+tls_ca:			TLS_CA '=' QSTRING ';'
+			{
+				FILE * fd;
+				fd = fopen($3, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open CA file %s for reading: %s\n", $3, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+				conf->cnf_sec_data.ca_file = $3;
+				CHECK_GNUTLS_DO( conf->cnf_sec_data.ca_file_nr += gnutls_certificate_set_x509_trust_file( 
+							conf->cnf_sec_data.credentials,
+							conf->cnf_sec_data.ca_file,
+							GNUTLS_X509_FMT_PEM),
+						{ yyerror (&yylloc, conf, "Error setting CA parameters."); YYERROR; } );
+			}
+			;
+			
+tls_crl:		TLS_CRL '=' QSTRING ';'
+			{
+				FILE * fd;
+				fd = fopen($3, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open CRL file %s for reading: %s\n", $3, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+				conf->cnf_sec_data.crl_file = $3;
+				CHECK_GNUTLS_DO( gnutls_certificate_set_x509_crl_file( 
+							conf->cnf_sec_data.credentials,
+							conf->cnf_sec_data.ca_file,
+							GNUTLS_X509_FMT_PEM),
+						{ yyerror (&yylloc, conf, "Error setting CRL parameters."); YYERROR; } );
+			}
+			;
+			
+tls_prio:		TLS_PRIO '=' QSTRING ';'
+			{
+				const char * err_pos = NULL;
+				conf->cnf_sec_data.prio_string = $3;
+				CHECK_GNUTLS_DO( gnutls_priority_init( 
+							&conf->cnf_sec_data.prio_cache,
+							conf->cnf_sec_data.prio_string,
+							&err_pos),
+						{ yyerror (&yylloc, conf, "Error setting Priority parameter.");
+						  fprintf(stderr, "Error at position : %s\n", err_pos);
+						  YYERROR; } );
+			}
+			;
+			
+tls_dh:			TLS_DH_BITS '=' INTEGER ';'
+			{
+				conf->cnf_sec_data.dh_bits = $3;
+			}
+			| TLS_DH_FILE '=' QSTRING ';'
+			{
+				FILE * fd;
+				free(conf->cnf_sec_data.dh_file);
+				conf->cnf_sec_data.dh_file = $3;
+				fd = fopen($3, "r");
+				if (fd == NULL) {
+					int ret = errno;
+					TRACE_DEBUG(INFO, "Unable to open DH file %s for reading: %s\n", $3, strerror(ret));
+					yyerror (&yylloc, conf, "Error on file name"); 
+					YYERROR;
+				}
+				fclose(fd);
+			}
+			;
"Welcome to our mercurial repository"