From: Perry Lorier Date: Tue, 2 Apr 2002 01:02:59 +0000 (+0000) Subject: Author: A1kmm X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=commitdiff_plain;h=d46ac9a03ae4645fd26a4721d58b045eede64a4f Author: A1kmm Log message: I missed adding some files, oops. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@694 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l new file mode 100644 index 0000000..ea9ccb8 --- /dev/null +++ b/ircd/ircd_lexer.l @@ -0,0 +1,115 @@ +/* + * ircd_parser.y: A yacc/bison parser for ircd config files. + * This is part of ircu, an Internet Relay Chat server. + * The contents of this file are Copyright(C) 2001 by Andrew Miller, the + * ircd-hybrid team and the ircu 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. + * $Id$ + */ + +%{ +extern int conf_fd, lineno; +#include +#include "y.tab.h" +#undef YY_INPUT +/* Just stop the lexer at EOF or error. */ +#define YY_INPUT(buf,result,max_size) \ + if ((result = read(conf_fd, buf, max_size)) <= 0) \ + result = 0; +%} +%option noyywrap +%option case-insensitive +%option nounput + +WHITE [ \t\r]+ +SHCOMMENT #[^\n]* +NUMBER [0-9]+ +QSTRING \"[^"\n]+[\"\n] +%% + +{QSTRING} {yytext[yyleng-1] = 0; yylval.text = yytext+1; return QSTRING;} +{NUMBER} {yylval.num = strtoul(yytext, NULL, 10); return NUMBER;} +{WHITE} ; +{SHCOMMENT} ; + +admin return ADMIN; +administrator return ADMIN; +general return GENERAL; +location return LOCATION; +contact return CONTACT; +connect return CONNECT; +class return CLASS; +pingfreq return PINGFREQ; +connectfreq return CONNECTFREQ; +maxlinks return MAXLINKS; +sendq return SENDQ; +name return NAME; +host return HOST; +password return PASS; +pass return PASS; +seconds return SECONDS; +minutes return MINUTES; +hours return HOURS; +days return DAYS; +weeks return WEEKS; +months return MONTHS; +years return YEARS; +decades return DECADES; +bytes return BYTES; +b return BYTES; +kbytes return KBYTES; +kilobytes return KBYTES; +kb return KBYTES; +mbytes return MBYTES; +megabytes return MBYTES; +mb return MBYTES; +gbytes return GBYTES; +gigabytes return GBYTES; +gb return GBYTES; +tbytes return TBYTES; +terabytes return TBYTES; +tb return TBYTES; +port return PORT; +server return SERVER; +yes return YES; +no return NO; +hub return HUB; +leaf return LEAF; +uworld return UWORLD; +operator return OPER; +oper return OPER; +local return LOCAL; +vhost return VHOST; +mask return MASK; +hidden return HIDDEN; +motd return MOTD; +numeric return NUMERIC; +nick return NICK; +jupe return JUPE; +description return DESCRIPTION; +client return CLIENT; +real return REAL; +realname return REAL; +reason return REASON; +file return TFILE; +rule return RULE; +all return ALL; +ip return IP; +crule return CRULE; +kill return KILL; +features return FEATURES; +\n lineno++; +. return yytext[0]; diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y new file mode 100644 index 0000000..d49ab33 --- /dev/null +++ b/ircd/ircd_parser.y @@ -0,0 +1,811 @@ +/* + * ircd_parser.y: A yacc/bison parser for ircd config files. + * This is part of ircu, an Internet Relay Chat server. + * The contents of this file are Copyright(C) 2001 by Andrew Miller, the + * ircd-hybrid team and the ircu 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. + * $Id$ + */ +%{ + +#include "config.h" +#include "s_conf.h" +#include "class.h" +#include "client.h" +#include "crule.h" +#include "ircd_features.h" +#include "fileio.h" +#include "gline.h" +#include "hash.h" +#include "ircd.h" +#include "ircd_alloc.h" +#include "ircd_chattr.h" +#include "ircd_log.h" +#include "ircd_reply.h" +#include "ircd_snprintf.h" +#include "ircd_string.h" +#include "list.h" +#include "listener.h" +#include "match.h" +#include "motd.h" +#include "numeric.h" +#include "numnicks.h" +#include "opercmds.h" +#include "parse.h" +#include "res.h" +#include "s_bsd.h" +#include "s_debug.h" +#include "s_misc.h" +#include "send.h" +#include "struct.h" +#include "support.h" +#include "sys.h" +#include +#include +#include +#define MAX_STRINGS 80 /* Maximum number of feature params. */ + extern struct LocalConf localConf; + extern struct DenyConf* denyConfList; + extern struct CRuleConf* cruleConfList; + extern struct ServerConf* serverConfList; + + int yylex(void); + /* Now all the globals we need :/... */ + int tping, tconn, maxlinks, sendq, port; + int stringno; + char *name, *pass, *host; + char *stringlist[MAX_STRINGS]; + struct ConnectionClass *class; + struct ConfItem *aconf; + struct DenyConf *dconf; + struct ServerConf *sconf; +%} + +%token QSTRING +%token NUMBER +%token FNAME + +%token GENERAL +%token ADMIN +%token LOCATION +%token CONTACT +%token CONNECT +%token CLASS +%token PINGFREQ +%token CONNECTFREQ +%token MAXLINKS +%token SENDQ +%token NAME +%token HOST +%token PASS +%token LOCAL +%token SECONDS +%token MINUTES +%token HOURS +%token DAYS +%token WEEKS +%token MONTHS +%token YEARS +%token DECADES +%token BYTES +%token KBYTES +%token MBYTES +%token GBYTES +%token TBYTES +%token SERVER +%token PORT +%token MASK +%token HUB +%token LEAF +%token UWORLD +%token YES +%token NO +%token OPER +%token PORT +%token VHOST +%token MASK +%token HIDDEN +%token MOTD +%token JUPE +%token NICK +%token NUMERIC +%token DESCRIPTION +%token CLIENT +%token KILL +%token CRULE +%token REAL +%token REASON +%token TFILE +%token RULE +%token ALL +%token IP +%token FEATURES +%type sizespec +%type timespec, timefactor, factoredtimes, factoredtime +%type expr +%left '+' '-' +%left '*' '/' + +%union{ + char *text; + int num; +} + +%% +/* Blocks in the config file... */ +blocks: blocks block | block; +block: adminblock | generalblock | classblock | connectblock | + serverblock | operblock | portblock | jupeblock | clientblock | + killblock | cruleblock | motdblock | featuresblock; + +/* The timespec, sizespec and expr was ripped straight from + * ircd-hybrid-7. */ +timespec: expr | factoredtimes; + +factoredtimes: factoredtimes factoredtime +{ + $$ = $1 + $2; +} | factoredtime; + +factoredtime: expr timefactor +{ + $$ = $1 * $2; +}; + +timefactor: SECONDS { $$ = 1; } +| MINUTES { $$ = 60; } +| HOURS { $$ = 60 * 60; } +| DAYS { $$ = 60 * 60 * 24; } +| WEEKS { $$ = 60 * 60 * 24 * 7; } +| MONTHS { $$ = 60 * 60 * 24 * 7 * 4; } +| YEARS { $$ = 60 * 60 * 24 * 365; } +| DECADES { $$ = 60 * 60 * 24 * 365 * 10; }; + + +sizespec: expr + = { + $$ = $1; + } + | expr BYTES + = { + $$ = $1; + } + | expr KBYTES + = { + $$ = $1 * 1024; + } + | expr MBYTES + = { + $$ = $1 * 1024 * 1024; + } + | expr GBYTES + = { + $$ = $1 * 1024 * 1024 * 1024; + } + | expr TBYTES + = { + $$ = $1 * 1024 * 1024 * 1024; + } + ; + +/* this is an arithmatic expression */ +expr: NUMBER + = { + $$ = $1; + } + | expr '+' expr + = { + $$ = $1 + $3; + } + | expr '-' expr + = { + $$ = $1 - $3; + } + | expr '*' expr + = { + $$ = $1 * $3; + } + | expr '/' expr + = { + $$ = $1 / $3; + } +/* leave this out until we find why it makes BSD yacc dump core -larne + | '-' expr %prec NEG + = { + $$ = -$2; + } */ + | '(' expr ')' + = { + $$ = $2; + } + ; + +jupeblock: JUPE '{' jupeitems '}' ';' ; +jupeitems: jupeitem jupeitems | jupeitem; +jupeitem: jupenick; +jupenick: NICK '=' QSTRING +{ + addNickJupes(yylval.text); +} ';'; + +generalblock: GENERAL '{' generalitems '}' ';' ; +generalitems: generalitem generalitems | generalitem; +generalitem: generalnumeric | generalname | generalvhost | generaldesc; +generalnumeric: NUMERIC '=' NUMBER ';' +{ + if (localConf.numeric == 0) + localConf.numeric = yylval.num; +}; + +generalname: NAME '=' QSTRING ';' +{ + if (localConf.name == NULL) + DupString(localConf.name, yylval.text); +}; + +generaldesc: DESCRIPTION '=' QSTRING ';' +{ + MyFree(localConf.description); + DupString(localConf.description, yylval.text); +}; + +generalvhost: VHOST '=' QSTRING ';' +{ + if (INADDR_NONE == + (localConf.vhost_address.s_addr = inet_addr(yylval.text))) + localConf.vhost_address.s_addr = INADDR_ANY; +}; + +adminblock: ADMIN '{' adminitems '}' +{ + if (localConf.location1 == NULL) + DupString(localConf.location1, ""); + if (localConf.location2 == NULL) + DupString(localConf.location2, ""); + if (localConf.contact == NULL) + DupString(localConf.contact, ""); +} ';'; +adminitems: adminitems adminitem | adminitem; +adminitem: adminlocation | admincontact; +adminlocation: LOCATION '=' QSTRING ';' +{ + if (localConf.location1 == NULL) + DupString(localConf.location1, yylval.text); + else if (localConf.location2 == NULL) + DupString(localConf.location2, yylval.text); + /* Otherwise just drop it. -A1kmm */ +}; +admincontact: CONTACT '=' QSTRING ';' +{ + if (localConf.contact != NULL) + free(localConf.contact); + DupString(localConf.contact, yylval.text); +}; + +classblock: CLASS { + name = NULL; + tping = 90; + tconn = 0; + maxlinks = 0; + sendq = 0; +} '{' classitems '}' +{ + if (name != NULL) + { + add_class(name, tping, tconn, maxlinks, sendq); + } +} ';'; +classitems: classitem classitems | classitem; +classitem: classname | classpingfreq | classconnfreq | classmaxlinks | + classsendq; +classname: NAME '=' QSTRING ';' +{ + MyFree(name); + DupString(name, yylval.text); +}; +classpingfreq: PINGFREQ '=' timespec ';' +{ + tping = yylval.num; +}; +classconnfreq: CONNECTFREQ '=' timespec ';' +{ + tconn = yylval.num; +}; +classmaxlinks: MAXLINKS '=' expr ';' +{ + maxlinks = yylval.num; +}; +classsendq: SENDQ '=' sizespec ';' +{ + sendq = yylval.num; +}; + +connectblock: CONNECT +{ + name = pass = host = NULL; + class = NULL; + port = 0; +} '{' connectitems '}' +{ + if (name != NULL && pass != NULL && host != NULL && class != NULL && + /*ccount < MAXCONFLINKS &&*/ !strchr(host, '*') && + !strchr(host, '?')) + { + aconf = MyMalloc(sizeof(*aconf)); + aconf->status = CONF_SERVER; + aconf->name = name; + aconf->passwd = pass; + aconf->conn_class = class; + aconf->port = port; + aconf->status = CONF_SERVER; + aconf->host = host; + aconf->next = GlobalConfList; + GlobalConfList = aconf; + printf("Server added: %s\n", name); + /* ccount++; -- XXX fixme --- A1kmm */ + } + else + { + MyFree(name); + MyFree(pass); + MyFree(host); + name = pass = host = NULL; + } +}';'; +connectitems: connectitem connectitems | connectitem; +connectitem: connectname | connectpass | connectclass | connecthost + | connectport; +connectname: NAME '=' QSTRING ';' +{ + MyFree(name); + DupString(name, yylval.text); +}; +connectpass: PASS '=' QSTRING ';' +{ + MyFree(pass); + DupString(pass, yylval.text); +}; +connectclass: CLASS '=' QSTRING ';' +{ + class = find_class(yylval.text); +}; +connecthost: HOST '=' QSTRING ';' +{ + MyFree(host); + DupString(host, yylval.text); +}; +connectport: PORT '=' NUMBER ';' +{ + port = yylval.num; +}; + +serverblock: SERVER +{ + aconf = MyMalloc(sizeof(*aconf)); + memset(aconf, 0, sizeof(*aconf)); +} '{' serveritems '}' +{ + if (aconf->status == 0) + { + MyFree(aconf->host); + MyFree(aconf->name); + MyFree(aconf); + aconf = NULL; + } + else + { + aconf->next = GlobalConfList; + GlobalConfList = aconf; + } +} ';'; +serveritems: serveritem serveritems | serveritem; +serveritem: servername | servermask | serverhub | serverleaf | + serveruworld; +servername: NAME '=' QSTRING +{ + MyFree(aconf->name); + DupString(aconf->name, yylval.text); +} ';' ; +servermask: MASK '=' QSTRING +{ + MyFree(aconf->host); + DupString(aconf->host, yylval.text); +} ';' ; +/* XXX - perhaps we should do this the hybrid way in connect blocks + * instead -A1kmm. */ +serverhub: HUB '=' YES ';' +{ + aconf->status |= CONF_HUB; + aconf->status &= ~CONF_LEAF; +} +| HUB '=' NO +{ + aconf->status &= ~CONF_HUB; +} ';'; +serverleaf: LEAF '=' YES ';' +{ + if (!(aconf->status & CONF_HUB && aconf->status & CONF_UWORLD)) + aconf->status |= CONF_LEAF; +} +| LEAF '=' NO ';' +{ + aconf->status &= ~CONF_LEAF; +}; +serveruworld: UWORLD '=' YES ';' +{ + aconf->status |= CONF_UWORLD; + aconf->status &= ~CONF_LEAF; +} +| UWORLD '=' NO ';' +{ + aconf->status &= ~CONF_UWORLD; +}; + +operblock: OPER +{ + aconf = MyMalloc(sizeof(*aconf)); + memset(aconf, 0, sizeof(*aconf)); + aconf->status = CONF_OPERATOR; +} '{' operitems '}' ';' +{ + if (aconf->name != NULL && aconf->passwd != NULL && aconf->host != NULL) + { + aconf->next = GlobalConfList; + GlobalConfList = aconf; + } + else + { + MyFree(aconf->name); + MyFree(aconf->passwd); + MyFree(aconf->host); + MyFree(aconf); + aconf = NULL; + } +}; +operitems: operitem | operitems operitem; +operitem: opername | operpass | operlocal | operhost | operclass; + +opername: NAME '=' QSTRING ';' +{ + MyFree(aconf->name); + DupString(aconf->name, yylval.text); +}; + +operpass: PASS '=' QSTRING ';' +{ + MyFree(aconf->passwd); + DupString(aconf->passwd, yylval.text); +}; + +operlocal: LOCAL '=' YES ';' +{ + /* XXX it would be good to get rid of local operators and add same + * permission values here. But for now, I am just going with local + * opers... */ + aconf->status = CONF_LOCOP; +} | LOCAL '=' NO ';' +{ + aconf->status = CONF_OPERATOR; +}; + +operhost: HOST '=' QSTRING ';' +{ + MyFree(aconf->host); + if (!strchr(yylval.text, '@')) + { + int uh_len; + char *b = MyMalloc((uh_len = strlen(yylval.text)+3)); + ircd_snprintf(0, b, uh_len, "*@%s", yylval.text); + aconf->host = b; + } + else + DupString(aconf->host, yylval.text); +}; + +operclass: CLASS '=' QSTRING ';' +{ + aconf->conn_class = find_class(yylval.text); +}; + +/* The port block... */ +portblock: PORT { + port = 0; + host = NULL; + /* Hijack these for is_server, is_hidden to cut down on globals... */ + tconn = 0; + tping = 0; + /* and this for mask... */ + pass = NULL; +} '{' portitems '}' ';' +{ + if (port > 0 && port <= 0xFFFF) + { + add_listener(port, host, pass, tconn, tping); + host = pass = NULL; + } + else + { + MyFree(host); + MyFree(pass); + } +}; +portitems: portitem portitems | portitem; +portitem: portnumber | portvhost | portmask | portserver | porthidden; +portnumber: PORT '=' NUMBER ';' +{ + port = yylval.num; +}; + +portvhost: VHOST '=' QSTRING ';' +{ + MyFree(host); + DupString(host, yylval.text); +}; + +portmask: MASK '=' QSTRING ';' +{ + MyFree(pass); + DupString(pass, yylval.text); +}; + +portserver: SERVER '=' YES ';' +{ + tconn = -1; +} | SERVER '=' NO ';' +{ + tconn = 0; +}; + +porthidden: HIDDEN '=' YES ';' +{ + tping = -1; +} | HIDDEN '=' NO ';' +{ + tping = 0; +}; + +clientblock: CLIENT +{ + aconf = MyMalloc(sizeof(*aconf)); + memset(aconf, 0, sizeof(*aconf)); + aconf->status = CONF_CLIENT; +} '{' clientitems '}' +{ + if ((aconf->host != NULL || aconf->name!=NULL)) + { + if (aconf->host == NULL) + DupString(aconf->host, ""); + if (aconf->name == NULL) + DupString(aconf->name, ""); + if (aconf->conn_class == NULL) + aconf->conn_class = find_class("default"); + aconf->next = GlobalConfList; + GlobalConfList = aconf; + aconf = NULL; + } + else + { + MyFree(aconf->host); + MyFree(aconf->passwd); + MyFree(aconf); + aconf = NULL; + } +} ';'; +clientitems: clientitem clientitems | clientitem; +clientitem: clienthost | clientclass | clientpass | clientip; +clientip: IP '=' QSTRING ';' +{ + MyFree(aconf->host); + DupString(aconf->host, yylval.text); +}; + +clienthost: HOST '=' QSTRING ';' +{ + MyFree(aconf->name); + DupString(aconf->name, yylval.text); +}; + +clientclass: CLASS '=' QSTRING ';' +{ + aconf->conn_class = find_class(yylval.text); +}; + +clientpass: PASS '=' QSTRING ';' +{ + MyFree(aconf->passwd); + DupString(aconf->passwd, yylval.text); +}; + +killblock: KILL +{ + dconf = MyMalloc(sizeof(*dconf)); + memset(dconf, 0, sizeof(*dconf)); +} '{' killitems '}' +{ + if (dconf->hostmask != NULL) + { + if (dconf->usermask == NULL) + DupString(dconf->usermask, "*"); + dconf->next = denyConfList; + denyConfList = dconf; + dconf = NULL; + } + else + { + MyFree(dconf->hostmask); + MyFree(dconf->message); + MyFree(dconf); + dconf = NULL; + } +} ';'; +killitems: killitem killitems | killitem; +killitem: killuhost | killreal | killreasonfile | killreason; +killuhost: HOST '=' QSTRING ';' +{ + char *u, *h; + dconf->flags &= ~DENY_FLAGS_REALNAME; + MyFree(dconf->hostmask); + MyFree(dconf->usermask); + if ((h = strchr(yylval.text, '@')) == NULL) + { + u = "*"; + h = yylval.text; + } + else + { + u = yylval.text; + h++; + } + DupString(dconf->hostmask, h); + DupString(dconf->usermask, u); + if (strchr(yylval.text, '.')) + { + int c_class; + char ipname[16]; + int ad[4] = { 0 }; + int bits2 = 0; + dconf->flags |= DENY_FLAGS_IP; + c_class = sscanf(dconf->hostmask, "%d.%d.%d.%d/%d", + &ad[0], &ad[1], &ad[2], &ad[3], &bits2); + if (c_class != 5) { + dconf->bits = c_class * 8; + } + else { + dconf->bits = bits2; + } + ircd_snprintf(0, ipname, sizeof(ipname), "%d.%d.%d.%d", ad[0], ad[1], + ad[2], ad[3]); + dconf->address = inet_addr(ipname); + } +}; + +killreal: REAL '=' QSTRING ';' +{ + dconf->flags &= ~DENY_FLAGS_IP; + dconf->flags |= DENY_FLAGS_REALNAME; + MyFree(dconf->hostmask); + /* Leave usermask so you can specify user and real... */ + DupString(dconf->hostmask, yylval.text); +}; + +killreason: REASON '=' QSTRING ';' +{ + dconf->flags &= DENY_FLAGS_FILE; + MyFree(dconf->message); + DupString(dconf->message, yylval.text); +}; + +killreasonfile: TFILE '=' QSTRING ';' +{ + dconf->flags |= DENY_FLAGS_FILE; + MyFree(dconf->message); + DupString(dconf->message, yylval.text); +}; + +cruleblock: CRULE +{ + host = pass = NULL; + tconn = CRULE_AUTO; +} '{' cruleitems '}' +{ + struct CRuleNode *node; + if (host != NULL && pass != NULL && (node=crule_parse(pass)) != NULL) + { + struct CRuleConf *p = MyMalloc(sizeof(*p)); + p->hostmask = host; + p->rule = pass; + p->type = tconn; + p->node = node; + p->next = cruleConfList; + cruleConfList = p; + } + else + { + MyFree(host); + MyFree(pass); + } +} ';'; + +cruleitems: cruleitem cruleitems | cruleitem; +cruleitem: cruleserver | crulerule | cruleall; + +cruleserver: SERVER '=' QSTRING ';' +{ + MyFree(host); + collapse(yylval.text); + DupString(host, yylval.text); +}; + +crulerule: RULE '=' QSTRING ';' +{ + MyFree(pass); + DupString(pass, yylval.text); +}; + +cruleall: ALL '=' YES ';' +{ + tconn = CRULE_ALL; +} | ALL '=' NO ';' +{ + tconn = CRULE_AUTO; +}; + +motdblock: MOTD { + pass = host = NULL; +} '{' motditems '}' +{ + if (host != NULL && pass != NULL) + motd_add(host, pass); + MyFree(host); + MyFree(pass); + host = pass = NULL; +} ';'; + +motditems: motditem motditems | motditem; +motditem: motdhost | motdfile; +motdhost: HOST '=' QSTRING ';' +{ + DupString(host, yylval.text); +}; + +motdfile: TFILE '=' QSTRING ';' +{ + DupString(pass, yylval.text); +}; + +featuresblock: FEATURES '{' featureitems '}' ';'; +featureitems: featureitems featureitem | featureitem; + +featureitem: QSTRING +{ + stringno = 0; +} '=' stringlist ';'; + +stringlist: QSTRING +{ + stringlist[0] = $1; + stringno = 1; +} posextrastrings +{ + feature_set(NULL, (const char * const *)stringlist, stringno); +}; +posextrastrings: /* empty */ | extrastrings; +extrastrings: extrastrings extrastring | extrastring; +extrastring: QSTRING +{ + if (stringno < MAX_STRINGS) + stringlist[stringno++] = $1; +};