/* * Copyright (c) 2002 Erik Fears * Copyright (c) 2014-2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ %option case-insensitive %option noyywrap %option noinput %option nounput %option never-interactive %x IN_COMMENT %{ #include #include #include "compat.h" #include "config.h" #include "config-parser.h" /* autogenerated header file */ #include "log.h" /* libopm includes */ #include "libopm/src/opm_types.h" #undef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) conf_yy_fatal_error(msg) #undef YY_INPUT #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[512]; char conffilebuf[512]; static struct included_file { YY_BUFFER_STATE state; unsigned int lineno; FILE *file; char conffile[512]; } include_stack[MAX_INCLUDE_DEPTH]; static unsigned int include_stack_ptr; static void conf_include(void); static int conf_eof(void); static int conf_yy_input(char *lbuf, unsigned int max_size) { return fgets(lbuf, max_size, conf_file) == NULL ? 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}(\<.*\>|\".*\") %% "/*" { BEGIN IN_COMMENT; } "*/" { BEGIN INITIAL; } . ; /* Eat everything but a newline */ \n { ++lineno; } <> { BEGIN INITIAL; if (conf_eof()) yyterminate(); } {include} { conf_include(); } \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] != '"') log_printf("CONFIG ->Unterminated character string"); else { unsigned int i = 0, j = 0; yylval.string[yyleng - 2] = '\0'; /* Remove close quote */ for (; 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 */ { log_printf("CONFIG -> Unterminated character string"); break; } yylval.string[j] = yylval.string[i]; } } yylval.string[j] = '\0'; return STRING; } } } ADDRESS_FAMILY { return ADDRESS_FAMILY; } AWAY { return AWAY; } BAN_UNKNOWN { return BAN_UNKNOWN; } BLACKLIST { return BLACKLIST; } CHANNEL { return CHANNEL; } COMMAND_INTERVAL { return COMMAND_INTERVAL; } COMMAND_QUEUE_SIZE { return COMMAND_QUEUE_SIZE; } COMMAND_TIMEOUT { return COMMAND_TIMEOUT; } CONNREGEX { return CONNREGEX; } DNS_FDLIMIT { return DNS_FDLIMIT; } DNS_TIMEOUT { return DNS_TIMEOUT; } DNSBL_FROM { return DNSBL_FROM; } DNSBL_TO { return DNSBL_TO; } EXEMPT { return EXEMPT; } FD { return FD; } INVITE { return INVITE; } IPV4 { return IPV4; } IPV6 { return IPV6; } IRC { return IRC; } KLINE { return KLINE; } KEY { return KEY; } MASK { return MASK; } MAX_READ { return MAX_READ; } MODE { return MODE; } NAME { return NAME; } NEGCACHE { return NEGCACHE; } NEGCACHE_REBUILD { return NEGCACHE_REBUILD; } NICK { return NICK; } NICKSERV { return NICKSERV; } NOTICE { return NOTICE; } OPER { return OPER; } OPM { return OPM; } OPTIONS { return OPTIONS; } PASSWORD { return PASSWORD; } PERFORM { return PERFORM; } PIDFILE { return PIDFILE; } PORT { return PORT; } PROTOCOL { return PROTOCOL; } READTIMEOUT { return READTIMEOUT; } REALNAME { return REALNAME; } RECONNECTINTERVAL { return RECONNECTINTERVAL; } REPLY { return REPLY; } SCANLOG { return SCANLOG; } SCANNER { return SCANNER; } SENDMAIL { return SENDMAIL; } SERVER { return SERVER; } TARGET_IP { return TARGET_IP; } TARGET_PORT { return TARGET_PORT; } TARGET_STRING { return TARGET_STRING;} TIMEOUT { return TIMEOUT; } TYPE { return TYPE; } USER { return USER; } USERNAME { return USERNAME; } VHOST { return VHOST; } 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; } HTTP { yylval.number = OPM_TYPE_HTTP; return PROTOCOLTYPE; } HTTPPOST { yylval.number = OPM_TYPE_HTTPPOST; return PROTOCOLTYPE; } HTTPS { yylval.number = OPM_TYPE_HTTPS; return PROTOCOLTYPE; } HTTPSPOST { yylval.number = OPM_TYPE_HTTPSPOST; return PROTOCOLTYPE; } SOCKS4 { yylval.number = OPM_TYPE_SOCKS4; return PROTOCOLTYPE; } SOCKS5 { yylval.number = OPM_TYPE_SOCKS5; return PROTOCOLTYPE; } WINGATE { yylval.number = OPM_TYPE_WINGATE; return PROTOCOLTYPE; } ROUTER { yylval.number = OPM_TYPE_ROUTER; return PROTOCOLTYPE; } DREAMBOX { yylval.number = OPM_TYPE_DREAMBOX; return PROTOCOLTYPE; } SSH { yylval.number = OPM_TYPE_SSH; return PROTOCOLTYPE; } TRUE { yylval.number=1; return NUMBER; } YES { yylval.number=1; return NUMBER; } ON { yylval.number=1; return NUMBER; } FALSE { yylval.number=0; return NUMBER; } NO { yylval.number=0; return NUMBER; } OFF { yylval.number=0; return NUMBER; } . { return yytext[0]; } <> { if (conf_eof()) yyterminate(); } %% static void conf_include(void) { char *p = NULL; char filenamebuf[512]; if ((p = strchr(yytext, '<')) == NULL) *strchr(p = strchr(yytext, '"') + 1, '"') = '\0'; else *strchr(++p, '>') = '\0'; /* do stacking and co. */ if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { log_printf("CONFIG -> Includes nested too deep in %s", p); return; } if (*p == '/') /* if it is an absolute path */ snprintf(filenamebuf, sizeof(filenamebuf), "%s", p); else snprintf(filenamebuf, sizeof(filenamebuf), "%s/%s", HOPM_ETCDIR, p); FILE *tmp_fbfile_in = fopen(filenamebuf, "r"); if (!tmp_fbfile_in) { log_printf("CONFIG -> Unable to read configuration file '%s': %s", filenamebuf, strerror(errno)); return; } struct included_file *file = &include_stack[include_stack_ptr++]; file->lineno = lineno; file->file = conf_file; file->state = YY_CURRENT_BUFFER; strlcpy(file->conffile, conffilebuf, sizeof(file->conffile)); lineno = 1; conf_file = tmp_fbfile_in; strlcpy(conffilebuf, filenamebuf, sizeof(conffilebuf)); yy_switch_to_buffer(yy_create_buffer(NULL, YY_BUF_SIZE)); } static int conf_eof(void) { if (include_stack_ptr == 0) return 1; /* switch buffer */ struct included_file *file = &include_stack[--include_stack_ptr]; /* close current file */ fclose(conf_file); /* switch buffers */ yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(file->state); /* switch lineno */ lineno = file->lineno; /* switch file */ conf_file = file->file; strlcpy(conffilebuf, file->conffile, sizeof(conffilebuf)); return 0; }