/* * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd) * * Copyright (c) 2000-2014 ircd-hybrid development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /*! \file ircd_lexer.l * \brief Scans the ircd configuration file for tokens. * \version $Id$ */ %option case-insensitive %option noyywrap %option nounput %option never-interactive %{ #include "stdinc.h" #include "irc_string.h" #include "conf.h" #include "conf_parser.h" /* autogenerated header file */ #include "log.h" #undef YY_INPUT #define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg) #define YY_INPUT(buf,result,max_size) \ if (!(result = conf_yy_input(buf, max_size))) \ YY_FATAL_ERROR("input in flex scanner failed"); #define MAX_INCLUDE_DEPTH 10 unsigned int lineno = 1; char linebuf[IRCD_BUFSIZE]; char conffilebuf[IRCD_BUFSIZE]; static int include_stack_ptr = 0; static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; static FILE *inc_fbfile_in[MAX_INCLUDE_DEPTH]; static char conffile_stack[MAX_INCLUDE_DEPTH][IRCD_BUFSIZE]; static void ccomment(void); static void cinclude(void); static int ieof(void); static int conf_yy_input(char *lbuf, unsigned int max_size) { return !fgets(lbuf, max_size, conf_parser_ctx.conf_file) ? 0 : strlen(lbuf); } static int conf_yy_fatal_error(const char *msg) { return 0; } %} WS [[:blank:]]* DIGIT [[:digit:]]+ COMMENT ("//"|"#").* qstring \"[^\"\n]*[\"\n] include \.include{WS}(\<.*\>|\".*\") %% {include} { cinclude(); } "/*" { ccomment(); } \n.* { strlcpy(linebuf, yytext+1, sizeof(linebuf)); ++lineno; yyless(1); } {WS} ; {COMMENT} ; {DIGIT} { yylval.number = atoi(yytext); return NUMBER; } {qstring} { if (yytext[yyleng-2] == '\\') { yyless(yyleng-1); /* return last quote */ yymore(); /* append next string */ } else { yylval.string = yytext+1; if(yylval.string[yyleng-2] != '"') ilog(LOG_TYPE_IRCD, "Unterminated character string"); else { int i,j; yylval.string[yyleng-2] = '\0'; /* remove close * quote */ for (j=i=0 ;yylval.string[i] != '\0'; i++,j++) { if (yylval.string[i] != '\\') { yylval.string[j] = yylval.string[i]; } else { i++; if (yylval.string[i] == '\0') /* XXX * should not * happen */ { ilog(LOG_TYPE_IRCD, "Unterminated character string"); break; } yylval.string[j] = yylval.string[i]; } } yylval.string[j] = '\0'; return QSTRING; } } } accept_password { return ACCEPT_PASSWORD; } admin { return ADMIN; } administrator { return ADMIN; } aftype { return AFTYPE; } all { return T_ALL; } anti_nick_flood { return ANTI_NICK_FLOOD; } anti_spam_exit_message_time { return ANTI_SPAM_EXIT_MESSAGE_TIME; } auth { return IRCD_AUTH; } autoconn { return AUTOCONN; } bots { return T_BOTS; } caller_id_wait { return CALLER_ID_WAIT; } callerid { return T_CALLERID; } can_flood { return CAN_FLOOD; } cconn { return T_CCONN; } channel { return CHANNEL; } cidr_bitlen_ipv4 { return CIDR_BITLEN_IPV4; } cidr_bitlen_ipv6 { return CIDR_BITLEN_IPV6; } class { return CLASS; } cluster { return T_CLUSTER; } connect { return CONNECT; } connectfreq { return CONNECTFREQ; } cycle_on_host_change { return CYCLE_ON_HOST_CHANGE; } deaf { return T_DEAF; } debug { return T_DEBUG; } default_floodcount { return DEFAULT_FLOODCOUNT; } default_split_server_count { return DEFAULT_SPLIT_SERVER_COUNT; } default_split_user_count { return DEFAULT_SPLIT_USER_COUNT; } deny { return DENY; } description { return DESCRIPTION; } die { return DIE; } disable_auth { return DISABLE_AUTH; } disable_fake_channels { return DISABLE_FAKE_CHANNELS; } disable_remote_commands { return DISABLE_REMOTE_COMMANDS; } dline { return T_DLINE; } dots_in_ident { return DOTS_IN_IDENT; } egdpool_path { return EGDPOOL_PATH; } email { return EMAIL; } encrypted { return ENCRYPTED; } exceed_limit { return EXCEED_LIMIT; } exempt { return EXEMPT; } external { return T_EXTERNAL; } failed_oper_notice { return FAILED_OPER_NOTICE; } farconnect { return T_FARCONNECT; } file { return T_FILE; } flags { return IRCD_FLAGS; } flatten_links { return FLATTEN_LINKS; } full { return T_FULL; } gecos { return GECOS; } general { return GENERAL; } gline { return GLINE; } gline_duration { return GLINE_DURATION; } gline_enable { return GLINE_ENABLE; } gline_exempt { return GLINE_EXEMPT; } gline_min_cidr { return GLINE_MIN_CIDR; } gline_min_cidr6 { return GLINE_MIN_CIDR6; } gline_request_duration { return GLINE_REQUEST_DURATION; } global_kill { return GLOBAL_KILL; } globops { return T_GLOBOPS; } have_ident { return NEED_IDENT; } havent_read_conf { return HAVENT_READ_CONF; } hidden { return HIDDEN; } hidden_name { return HIDDEN_NAME; } hide_idle_from_opers { return HIDE_IDLE_FROM_OPERS; } hide_server_ips { return HIDE_SERVER_IPS; } hide_servers { return HIDE_SERVERS; } hide_services { return HIDE_SERVICES; } hide_spoof_ips { return HIDE_SPOOF_IPS; } host { return HOST; } hub { return HUB; } hub_mask { return HUB_MASK; } ignore_bogus_ts { return IGNORE_BOGUS_TS; } invisible { return T_INVISIBLE; } invisible_on_connect { return INVISIBLE_ON_CONNECT; } ip { return IP; } ipv4 { return T_IPV4; } ipv6 { return T_IPV6; } join_flood_count { return JOIN_FLOOD_COUNT; } join_flood_time { return JOIN_FLOOD_TIME; } kill { return KILL; } kill_chase_time_limit { return KILL_CHASE_TIME_LIMIT; } kline { return KLINE; } kline_exempt { return KLINE_EXEMPT; } knock_delay { return KNOCK_DELAY; } knock_delay_channel { return KNOCK_DELAY_CHANNEL; } leaf_mask { return LEAF_MASK; } links_delay { return LINKS_DELAY; } listen { return LISTEN; } locops { return T_LOCOPS; } log { return T_LOG; } mask { return MASK; } masked { return TMASKED; } max_accept { return MAX_ACCEPT; } max_bans { return MAX_BANS; } max_chans_per_oper { return MAX_CHANS_PER_OPER; } max_chans_per_user { return MAX_CHANS_PER_USER; } max_clients { return T_MAX_CLIENTS; } max_global { return MAX_GLOBAL; } max_ident { return MAX_IDENT; } max_idle { return MAX_IDLE; } max_local { return MAX_LOCAL; } max_nick_changes { return MAX_NICK_CHANGES; } max_nick_length { return MAX_NICK_LENGTH; } max_nick_time { return MAX_NICK_TIME; } max_number { return MAX_NUMBER; } max_targets { return MAX_TARGETS; } max_topic_length { return MAX_TOPIC_LENGTH; } max_watch { return MAX_WATCH; } min_idle { return MIN_IDLE; } min_nonwildcard { return MIN_NONWILDCARD; } min_nonwildcard_simple { return MIN_NONWILDCARD_SIMPLE; } module { return MODULE; } modules { return MODULES; } motd { return MOTD; } name { return NAME; } nchange { return T_NCHANGE; } need_ident { return NEED_IDENT; } need_password { return NEED_PASSWORD; } network_desc { return NETWORK_DESC; } network_name { return NETWORK_NAME; } nick { return NICK; } no_create_on_split { return NO_CREATE_ON_SPLIT; } no_join_on_split { return NO_JOIN_ON_SPLIT; } no_oper_flood { return NO_OPER_FLOOD; } no_tilde { return NO_TILDE; } nononreg { return T_NONONREG; } number_per_cidr { return NUMBER_PER_CIDR; } number_per_ip { return NUMBER_PER_IP; } oper { return OPERATOR; } oper_only_umodes { return OPER_ONLY_UMODES; } oper_pass_resv { return OPER_PASS_RESV; } oper_umodes { return OPER_UMODES; } operator { return OPERATOR; } opers_bypass_callerid { return OPERS_BYPASS_CALLERID; } operwall { return T_OPERWALL; } pace_wait { return PACE_WAIT; } pace_wait_simple { return PACE_WAIT_SIMPLE; } passwd { return PASSWORD; } password { return PASSWORD; } path { return PATH; } ping_cookie { return PING_COOKIE; } ping_time { return PING_TIME; } port { return PORT; } quarantine { return RESV; } random_idle { return RANDOM_IDLE; } reason { return REASON; } recvq { return T_RECVQ; } redirport { return REDIRPORT; } redirserv { return REDIRSERV; } rehash { return REHASH; } rej { return T_REJ; } remote { return REMOTE; } remoteban { return REMOTEBAN; } restart { return T_RESTART; } resv { return RESV; } resv_exempt { return RESV_EXEMPT; } rsa_private_key_file { return RSA_PRIVATE_KEY_FILE; } rsa_public_key_file { return RSA_PUBLIC_KEY_FILE; } send_password { return SEND_PASSWORD; } sendq { return SENDQ; } server { return T_SERVER; } serverhide { return SERVERHIDE; } serverinfo { return SERVERINFO; } service { return T_SERVICE; } services_name { return T_SERVICES_NAME; } servnotice { return T_SERVNOTICE; } set { return T_SET; } shared { return T_SHARED; } short_motd { return SHORT_MOTD; } sid { return IRCD_SID; } size { return T_SIZE; } skill { return T_SKILL; } softcallerid { return T_SOFTCALLERID; } spoof { return SPOOF; } spoof_notice { return SPOOF_NOTICE; } spy { return T_SPY; } squit { return SQUIT; } ssl { return T_SSL; } ssl_certificate_file { return SSL_CERTIFICATE_FILE; } ssl_certificate_fingerprint { return SSL_CERTIFICATE_FINGERPRINT; } ssl_cipher_list { return T_SSL_CIPHER_LIST; } ssl_client_method { return T_SSL_CLIENT_METHOD; } ssl_connection_required { return SSL_CONNECTION_REQUIRED; } ssl_dh_param_file { return SSL_DH_PARAM_FILE; } ssl_server_method { return T_SSL_SERVER_METHOD; } sslv3 { return T_SSLV3; } stats_e_disabled { return STATS_E_DISABLED; } stats_i_oper_only { return STATS_I_OPER_ONLY; } stats_k_oper_only { return STATS_K_OPER_ONLY; } stats_o_oper_only { return STATS_O_OPER_ONLY; } stats_P_oper_only { return STATS_P_OPER_ONLY; } stats_u_oper_only { return STATS_U_OPER_ONLY; } throttle_time { return THROTTLE_TIME; } tkline_expire_notices { return TKLINE_EXPIRE_NOTICES; } tlsv1 { return T_TLSV1; } true_no_oper_flood { return TRUE_NO_OPER_FLOOD; } ts_max_delta { return TS_MAX_DELTA; } ts_warn_delta { return TS_WARN_DELTA; } type { return TYPE; } umodes { return T_UMODES; } unauth { return T_UNAUTH; } undline { return T_UNDLINE; } unkline { return UNKLINE; } unlimited { return T_UNLIMITED; } unresv { return T_UNRESV; } unxline { return T_UNXLINE; } use_egd { return USE_EGD; } use_logging { return USE_LOGGING; } user { return USER; } vhost { return VHOST; } vhost6 { return VHOST6; } wallop { return T_WALLOP; } wallops { return T_WALLOPS; } warn_no_nline { return WARN_NO_NLINE; } webirc { return T_WEBIRC; } xline { return XLINE; } yes { yylval.number = 1; return TBOOL; } no { yylval.number = 0; return TBOOL; } years { return YEARS; } year { return YEARS; } months { return MONTHS; } month { return MONTHS; } weeks { return WEEKS; } week { return WEEKS; } days { return DAYS; } day { return DAYS; } hours { return HOURS; } hour { return HOURS; } minutes { return MINUTES; } minute { return MINUTES; } seconds { return SECONDS; } second { return SECONDS; } bytes { return BYTES; } byte { return BYTES; } kilobytes { return KBYTES; } kilobyte { return KBYTES; } kbytes { return KBYTES; } kbyte { return KBYTES; } kb { return KBYTES; } megabytes { return MBYTES; } megabyte { return MBYTES; } mbytes { return MBYTES; } mbyte { return MBYTES; } mb { return MBYTES; } \.\. { return TWODOTS; } . { return yytext[0]; } <> { if (ieof()) yyterminate(); } %% /* C-comment ignoring routine -kre*/ static void ccomment(void) { int c = 0; /* log(L_NOTICE, "got comment"); */ while (1) { while ((c = input()) != '*' && c != EOF) if (c == '\n') ++lineno; if (c == '*') { while ((c = input()) == '*') /* Nothing */ ; if (c == '/') break; else if (c == '\n') ++lineno; } if (c == EOF) { YY_FATAL_ERROR("EOF in comment"); /* XXX hack alert this disables * the stupid unused function warning * gcc generates */ if (1 == 0) yy_fatal_error("EOF in comment"); break; } } } /* C-style .includes. This function will properly swap input conf buffers, * and lineno -kre */ static void cinclude(void) { char *p = NULL; if ((p = strchr(yytext, '<')) == NULL) *strchr(p = strchr(yytext, '"') + 1, '"') = '\0'; else *strchr(++p, '>') = '\0'; /* log(L_NOTICE, "got include %s!", c); */ /* do stacking and co. */ if (include_stack_ptr >= MAX_INCLUDE_DEPTH) ilog(LOG_TYPE_IRCD, "Includes nested too deep in %s", p); else { FILE *tmp_fbfile_in = NULL; char filenamebuf[IRCD_BUFSIZE]; if (*p == '/') /* if it is an absolute path */ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p); else snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", ETCPATH, p); tmp_fbfile_in = fopen(filenamebuf, "r"); if (tmp_fbfile_in == NULL) { ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s", filenamebuf, strerror(errno)); return; } lineno_stack[include_stack_ptr] = lineno; lineno = 1; inc_fbfile_in[include_stack_ptr] = conf_parser_ctx.conf_file; strlcpy(conffile_stack[include_stack_ptr], conffilebuf, IRCD_BUFSIZE); include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; conf_parser_ctx.conf_file = tmp_fbfile_in; snprintf(conffilebuf, sizeof(conffilebuf), "%s", filenamebuf); yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); } } /* This is function that will be called on EOF in conf file. It will * apropriately close conf if it not main conf and swap input buffers -kre * */ static int ieof(void) { /* log(L_NOTICE, "return from include stack!"); */ if (include_stack_ptr) fclose(conf_parser_ctx.conf_file); if (--include_stack_ptr < 0) { /* log(L_NOTICE, "terminating lexer"); */ /* We will now exit the lexer - restore init values if we get /rehash * later and reenter lexer -kre */ include_stack_ptr = 0; lineno = 1; return 1; } /* switch buffer */ /* log(L_NOTICE, "deleting include_stack_ptr=%d", include_stack_ptr); */ yy_delete_buffer(YY_CURRENT_BUFFER); lineno = lineno_stack[include_stack_ptr]; conf_parser_ctx.conf_file = inc_fbfile_in[include_stack_ptr]; strlcpy(conffilebuf, conffile_stack[include_stack_ptr], sizeof(conffilebuf)); yy_switch_to_buffer(include_stack[include_stack_ptr]); return 0; }