Author: A1kmm
[ircu2.10.12-pk.git] / ircd / ircd_parser.y
1 /*
2  * ircd_parser.y: A yacc/bison parser for ircd config files.
3  * This is part of ircu, an Internet Relay Chat server.
4  * The contents of this file are Copyright(C) 2001 by Andrew Miller, the
5  * ircd-hybrid team and the ircu team.
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  *  USA.
20  * $Id$
21  */
22 %{
23
24 #include "config.h"
25 #include "s_conf.h"
26 #include "class.h"
27 #include "client.h"
28 #include "crule.h"
29 #include "ircd_features.h"
30 #include "fileio.h"
31 #include "gline.h"
32 #include "hash.h"
33 #include "ircd.h"
34 #include "ircd_alloc.h"
35 #include "ircd_chattr.h"
36 #include "ircd_log.h"
37 #include "ircd_reply.h"
38 #include "ircd_snprintf.h"
39 #include "ircd_string.h"
40 #include "list.h"
41 #include "listener.h"
42 #include "match.h"
43 #include "motd.h"
44 #include "numeric.h"
45 #include "numnicks.h"
46 #include "opercmds.h"
47 #include "parse.h"
48 #include "res.h"
49 #include "s_bsd.h"
50 #include "s_debug.h"
51 #include "s_misc.h"
52 #include "send.h"
53 #include "struct.h"
54 #include "support.h"
55 #include "sys.h"
56 #include <stdlib.h>
57 #include <string.h>
58 #include <arpa/inet.h>
59 #define MAX_STRINGS 80 /* Maximum number of feature params. */
60   extern struct LocalConf   localConf;
61   extern struct DenyConf*   denyConfList;
62   extern struct CRuleConf*  cruleConfList;
63   extern struct ServerConf* serverConfList;
64
65   int yylex(void);
66   /* Now all the globals we need :/... */
67   int tping, tconn, maxlinks, sendq, port;
68   int stringno;
69   char *name, *pass, *host;
70   char *stringlist[MAX_STRINGS];
71   struct ConnectionClass *class;
72   struct ConfItem *aconf;
73   struct DenyConf *dconf;
74   struct ServerConf *sconf;
75 %}
76
77 %token <text> QSTRING
78 %token <num> NUMBER
79 %token <text> FNAME
80
81 %token GENERAL
82 %token ADMIN
83 %token LOCATION
84 %token CONTACT
85 %token CONNECT
86 %token CLASS
87 %token PINGFREQ
88 %token CONNECTFREQ
89 %token MAXLINKS
90 %token SENDQ
91 %token NAME
92 %token HOST
93 %token PASS
94 %token LOCAL
95 %token SECONDS
96 %token MINUTES
97 %token HOURS
98 %token DAYS
99 %token WEEKS
100 %token MONTHS
101 %token YEARS
102 %token DECADES
103 %token BYTES
104 %token KBYTES
105 %token MBYTES
106 %token GBYTES
107 %token TBYTES
108 %token SERVER
109 %token PORT
110 %token MASK
111 %token HUB
112 %token LEAF
113 %token UWORLD
114 %token YES
115 %token NO
116 %token OPER
117 %token PORT
118 %token VHOST
119 %token MASK
120 %token HIDDEN
121 %token MOTD
122 %token JUPE
123 %token NICK
124 %token NUMERIC
125 %token DESCRIPTION
126 %token CLIENT
127 %token KILL
128 %token CRULE
129 %token REAL
130 %token REASON
131 %token TFILE
132 %token RULE
133 %token ALL
134 %token IP
135 %token FEATURES
136 %type <num> sizespec
137 %type <num> timespec, timefactor, factoredtimes, factoredtime
138 %type <num> expr
139 %left '+' '-'
140 %left '*' '/'
141
142 %union{
143  char *text;
144  int num;
145 }
146
147 %%
148 /* Blocks in the config file... */
149 blocks: blocks block | block;
150 block: adminblock | generalblock | classblock | connectblock |
151        serverblock | operblock | portblock | jupeblock | clientblock |
152        killblock | cruleblock | motdblock | featuresblock;
153
154 /* The timespec, sizespec and expr was ripped straight from
155  * ircd-hybrid-7. */
156 timespec: expr | factoredtimes;
157
158 factoredtimes: factoredtimes factoredtime
159 {
160   $$ = $1 + $2;
161 } | factoredtime;
162
163 factoredtime: expr timefactor
164 {
165   $$ = $1 * $2;
166 };
167
168 timefactor: SECONDS { $$ = 1; }
169 | MINUTES { $$ = 60; }
170 | HOURS { $$ = 60 * 60; }
171 | DAYS { $$ = 60 * 60 * 24; }
172 | WEEKS { $$ = 60 * 60 * 24 * 7; }
173 | MONTHS { $$ = 60 * 60 * 24 * 7 * 4; }
174 | YEARS { $$ = 60 * 60 * 24 * 365; }
175 | DECADES { $$ = 60 * 60 * 24 * 365 * 10; };
176
177
178 sizespec:       expr    
179                 = {
180                         $$ = $1;
181                 }
182                 | expr BYTES
183                 = { 
184                         $$ = $1;
185                 }
186                 | expr KBYTES
187                 = {
188                         $$ = $1 * 1024;
189                 }
190                 | expr MBYTES
191                 = {
192                         $$ = $1 * 1024 * 1024;
193                 }
194                 | expr GBYTES
195                 = {
196                         $$ = $1 * 1024 * 1024 * 1024;
197                 }
198                 | expr TBYTES
199                 = {
200                         $$ = $1 * 1024 * 1024 * 1024;
201                 }
202                 ;
203
204 /* this is an arithmatic expression */
205 expr: NUMBER
206                 = { 
207                         $$ = $1;
208                 }
209                 | expr '+' expr
210                 = { 
211                         $$ = $1 + $3;
212                 }
213                 | expr '-' expr
214                 = { 
215                         $$ = $1 - $3;
216                 }
217                 | expr '*' expr
218                 = { 
219                         $$ = $1 * $3;
220                 }
221                 | expr '/' expr
222                 = { 
223                         $$ = $1 / $3;
224                 }
225 /* leave this out until we find why it makes BSD yacc dump core -larne
226                 | '-' expr  %prec NEG
227                 = {
228                         $$ = -$2;
229                 } */
230                 | '(' expr ')'
231                 = {
232                         $$ = $2;
233                 }
234                 ;
235
236 jupeblock: JUPE '{' jupeitems '}' ';' ;
237 jupeitems: jupeitem jupeitems | jupeitem;
238 jupeitem: jupenick;
239 jupenick: NICK '=' QSTRING
240 {
241   addNickJupes(yylval.text);
242 } ';';
243
244 generalblock: GENERAL '{' generalitems '}' ';' ;
245 generalitems: generalitem generalitems | generalitem;
246 generalitem: generalnumeric | generalname | generalvhost | generaldesc;
247 generalnumeric: NUMERIC '=' NUMBER ';'
248 {
249   if (localConf.numeric == 0)
250     localConf.numeric = yylval.num;
251 };
252
253 generalname: NAME '=' QSTRING ';'
254 {
255   if (localConf.name == NULL)
256     DupString(localConf.name, yylval.text);
257 };
258
259 generaldesc: DESCRIPTION '=' QSTRING ';'
260 {
261   MyFree(localConf.description);
262   DupString(localConf.description, yylval.text);
263 };
264
265 generalvhost: VHOST '=' QSTRING ';'
266 {
267   if (INADDR_NONE ==
268       (localConf.vhost_address.s_addr = inet_addr(yylval.text)))
269     localConf.vhost_address.s_addr = INADDR_ANY;
270 };
271
272 adminblock: ADMIN '{' adminitems '}'
273 {
274   if (localConf.location1 == NULL)
275     DupString(localConf.location1, "");
276   if (localConf.location2 == NULL)
277     DupString(localConf.location2, "");
278   if (localConf.contact == NULL)
279     DupString(localConf.contact, "");
280 } ';';
281 adminitems: adminitems adminitem | adminitem;
282 adminitem: adminlocation | admincontact;
283 adminlocation: LOCATION '=' QSTRING ';'
284 {
285  if (localConf.location1 == NULL)
286   DupString(localConf.location1, yylval.text);
287  else if (localConf.location2 == NULL)
288   DupString(localConf.location2, yylval.text);
289  /* Otherwise just drop it. -A1kmm */
290 };
291 admincontact: CONTACT '=' QSTRING ';'
292 {
293  if (localConf.contact != NULL)
294   free(localConf.contact);
295  DupString(localConf.contact, yylval.text);
296 };
297
298 classblock: CLASS {
299  name = NULL;
300  tping = 90;
301  tconn = 0;
302  maxlinks = 0;
303  sendq = 0;
304 } '{' classitems '}'
305 {
306  if (name != NULL)
307  {
308   add_class(name, tping, tconn, maxlinks, sendq);
309  }
310 } ';';
311 classitems: classitem classitems | classitem;
312 classitem: classname | classpingfreq | classconnfreq | classmaxlinks |
313            classsendq;
314 classname: NAME '=' QSTRING ';'
315 {
316  MyFree(name);
317  DupString(name, yylval.text);
318 };
319 classpingfreq: PINGFREQ '=' timespec ';'
320 {
321  tping = yylval.num;
322 };
323 classconnfreq: CONNECTFREQ '=' timespec ';'
324 {
325  tconn = yylval.num;
326 };
327 classmaxlinks: MAXLINKS '=' expr ';'
328 {
329  maxlinks = yylval.num;
330 };
331 classsendq: SENDQ '=' sizespec ';'
332 {
333  sendq = yylval.num;
334 };
335
336 connectblock: CONNECT
337 {
338  name = pass = host = NULL;
339  class = NULL;
340  port = 0;
341 } '{' connectitems '}'
342 {
343  if (name != NULL && pass != NULL && host != NULL && class != NULL && 
344      /*ccount < MAXCONFLINKS &&*/ !strchr(host, '*') &&
345      !strchr(host, '?'))
346  {
347   aconf = MyMalloc(sizeof(*aconf));
348   aconf->status = CONF_SERVER;
349   aconf->name = name;
350   aconf->passwd = pass;
351   aconf->conn_class = class;
352   aconf->port = port;
353   aconf->status = CONF_SERVER;
354   aconf->host = host;
355   aconf->next = GlobalConfList;
356   GlobalConfList = aconf;
357   printf("Server added: %s\n", name);
358   /* ccount++; -- XXX fixme --- A1kmm */
359  }
360  else
361  {
362   MyFree(name);
363   MyFree(pass);
364   MyFree(host);
365   name = pass = host = NULL;
366  }
367 }';';
368 connectitems: connectitem connectitems | connectitem;
369 connectitem: connectname | connectpass | connectclass | connecthost
370               | connectport;
371 connectname: NAME '=' QSTRING ';'
372 {
373  MyFree(name);
374  DupString(name, yylval.text);
375 };
376 connectpass: PASS '=' QSTRING ';'
377 {
378  MyFree(pass);
379  DupString(pass, yylval.text);
380 };
381 connectclass: CLASS '=' QSTRING ';'
382 {
383  class = find_class(yylval.text);
384 };
385 connecthost: HOST '=' QSTRING ';'
386 {
387  MyFree(host);
388  DupString(host, yylval.text);
389 };
390 connectport: PORT '=' NUMBER ';'
391 {
392  port = yylval.num;
393 };
394
395 serverblock: SERVER
396 {
397  aconf = MyMalloc(sizeof(*aconf));
398  memset(aconf, 0, sizeof(*aconf));
399 } '{' serveritems '}'
400 {
401  if (aconf->status == 0)
402  {
403    MyFree(aconf->host);
404    MyFree(aconf->name);
405    MyFree(aconf);
406    aconf = NULL;
407  }
408  else
409  {
410    aconf->next = GlobalConfList;
411    GlobalConfList = aconf;
412  }
413 } ';';
414 serveritems: serveritem serveritems | serveritem;
415 serveritem: servername | servermask | serverhub | serverleaf |
416              serveruworld;
417 servername: NAME '=' QSTRING
418 {
419  MyFree(aconf->name);
420  DupString(aconf->name, yylval.text);
421 } ';' ;
422 servermask: MASK '=' QSTRING
423 {
424  MyFree(aconf->host);
425  DupString(aconf->host, yylval.text);
426 } ';' ;
427 /* XXX - perhaps we should do this the hybrid way in connect blocks
428  * instead -A1kmm. */
429 serverhub: HUB '=' YES ';'
430 {
431  aconf->status |= CONF_HUB;
432  aconf->status &= ~CONF_LEAF;
433 }
434 | HUB '=' NO
435 {
436  aconf->status &= ~CONF_HUB;
437 } ';'; 
438 serverleaf: LEAF '=' YES ';'
439 {
440  if (!(aconf->status & CONF_HUB && aconf->status & CONF_UWORLD))
441   aconf->status |= CONF_LEAF;
442 }
443 | LEAF '=' NO ';'
444 {
445  aconf->status &= ~CONF_LEAF;
446 };
447 serveruworld: UWORLD '=' YES ';'
448 {
449  aconf->status |= CONF_UWORLD;
450  aconf->status &= ~CONF_LEAF;
451 }
452 | UWORLD '=' NO ';'
453 {
454   aconf->status &= ~CONF_UWORLD;
455 };
456
457 operblock: OPER
458 {
459   aconf = MyMalloc(sizeof(*aconf));
460   memset(aconf, 0, sizeof(*aconf));
461   aconf->status = CONF_OPERATOR;
462 } '{' operitems '}' ';'
463 {
464   if (aconf->name != NULL && aconf->passwd != NULL && aconf->host != NULL)
465   {
466    aconf->next = GlobalConfList;
467    GlobalConfList = aconf;
468   }
469   else
470   {
471    MyFree(aconf->name);
472    MyFree(aconf->passwd);
473    MyFree(aconf->host);
474    MyFree(aconf);
475    aconf = NULL;
476   }
477 };
478 operitems: operitem | operitems operitem;
479 operitem: opername | operpass | operlocal | operhost | operclass;
480
481 opername: NAME '=' QSTRING ';'
482 {
483   MyFree(aconf->name);
484   DupString(aconf->name, yylval.text);
485 };
486
487 operpass: PASS '=' QSTRING ';'
488 {
489   MyFree(aconf->passwd);
490   DupString(aconf->passwd, yylval.text);
491 };
492
493 operlocal: LOCAL '=' YES ';'
494 {
495   /* XXX it would be good to get rid of local operators and add same
496    * permission values here. But for now, I am just going with local 
497    * opers... */
498   aconf->status = CONF_LOCOP;
499 } | LOCAL '=' NO ';'
500 {
501   aconf->status = CONF_OPERATOR;
502 };
503
504 operhost: HOST '=' QSTRING ';'
505 {
506  MyFree(aconf->host);
507  if (!strchr(yylval.text, '@'))
508  {
509    int uh_len;
510    char *b = MyMalloc((uh_len = strlen(yylval.text)+3));
511    ircd_snprintf(0, b, uh_len, "*@%s", yylval.text);
512    aconf->host = b;
513  }
514  else
515    DupString(aconf->host, yylval.text);
516 };
517
518 operclass: CLASS '=' QSTRING ';'
519 {
520  aconf->conn_class = find_class(yylval.text);
521 };
522
523 /* The port block... */
524 portblock: PORT {
525   port = 0;
526   host = NULL;
527   /* Hijack these for is_server, is_hidden to cut down on globals... */
528   tconn = 0;
529   tping = 0;
530   /* and this for mask... */
531   pass = NULL;
532 } '{' portitems '}' ';'
533 {
534   if (port > 0 && port <= 0xFFFF)
535   {
536     add_listener(port, host, pass, tconn, tping);
537     host = pass = NULL;
538   }
539   else
540   {
541     MyFree(host);
542     MyFree(pass);
543   }
544 };
545 portitems: portitem portitems | portitem;
546 portitem: portnumber | portvhost | portmask | portserver | porthidden;
547 portnumber: PORT '=' NUMBER ';'
548 {
549   port = yylval.num;
550 };
551
552 portvhost: VHOST '=' QSTRING ';'
553 {
554   MyFree(host);
555   DupString(host, yylval.text);
556 };
557
558 portmask: MASK '=' QSTRING ';'
559 {
560   MyFree(pass);
561   DupString(pass, yylval.text);
562 };
563
564 portserver: SERVER '=' YES ';'
565 {
566   tconn = -1;
567 } | SERVER '=' NO ';'
568 {
569   tconn = 0;
570 };
571
572 porthidden: HIDDEN '=' YES ';'
573 {
574   tping = -1;
575 } | HIDDEN '=' NO ';'
576 {
577   tping = 0;
578 };
579
580 clientblock: CLIENT
581 {
582   aconf = MyMalloc(sizeof(*aconf));
583   memset(aconf, 0, sizeof(*aconf));
584   aconf->status = CONF_CLIENT;
585 } '{' clientitems '}'
586 {
587   if ((aconf->host != NULL || aconf->name!=NULL))
588   {
589     if (aconf->host == NULL)
590       DupString(aconf->host, "");
591     if (aconf->name == NULL)
592       DupString(aconf->name, "");
593     if (aconf->conn_class == NULL)
594       aconf->conn_class = find_class("default");
595     aconf->next = GlobalConfList;
596     GlobalConfList = aconf;
597     aconf = NULL;
598   }
599   else
600   {
601    MyFree(aconf->host);
602    MyFree(aconf->passwd);
603    MyFree(aconf);
604    aconf = NULL;
605   }
606 } ';';
607 clientitems: clientitem clientitems | clientitem;
608 clientitem: clienthost | clientclass | clientpass | clientip;
609 clientip: IP '=' QSTRING ';'
610 {
611   MyFree(aconf->host);
612   DupString(aconf->host, yylval.text);
613 };
614
615 clienthost: HOST '=' QSTRING ';'
616 {
617   MyFree(aconf->name);
618   DupString(aconf->name, yylval.text);
619 };
620
621 clientclass: CLASS '=' QSTRING ';'
622 {
623   aconf->conn_class = find_class(yylval.text);
624 };
625
626 clientpass: PASS '=' QSTRING ';'
627 {
628   MyFree(aconf->passwd);
629   DupString(aconf->passwd, yylval.text);
630 };
631
632 killblock: KILL
633 {
634   dconf = MyMalloc(sizeof(*dconf));
635   memset(dconf, 0, sizeof(*dconf));
636 } '{' killitems '}'
637 {
638   if (dconf->hostmask != NULL)
639   {
640     if (dconf->usermask == NULL)
641       DupString(dconf->usermask, "*");
642     dconf->next = denyConfList;
643     denyConfList = dconf;
644     dconf = NULL;
645   }
646   else
647   {
648     MyFree(dconf->hostmask);
649     MyFree(dconf->message);
650     MyFree(dconf);
651     dconf = NULL;
652   }
653 } ';';
654 killitems: killitem killitems | killitem;
655 killitem: killuhost | killreal | killreasonfile | killreason;
656 killuhost: HOST '=' QSTRING ';'
657 {
658   char *u, *h;
659   dconf->flags &= ~DENY_FLAGS_REALNAME;
660   MyFree(dconf->hostmask);
661   MyFree(dconf->usermask);
662   if ((h = strchr(yylval.text, '@')) == NULL)
663   {
664     u = "*";
665     h = yylval.text;
666   }
667   else
668   {
669     u = yylval.text;
670     h++;
671   }
672   DupString(dconf->hostmask, h);
673   DupString(dconf->usermask, u);
674   if (strchr(yylval.text, '.'))
675   {
676     int  c_class;
677     char ipname[16];
678     int  ad[4] = { 0 };
679     int  bits2 = 0;
680     dconf->flags |= DENY_FLAGS_IP;
681     c_class = sscanf(dconf->hostmask, "%d.%d.%d.%d/%d",
682                      &ad[0], &ad[1], &ad[2], &ad[3], &bits2);
683     if (c_class != 5) {
684       dconf->bits = c_class * 8;
685     }
686     else {
687       dconf->bits = bits2;
688     }
689     ircd_snprintf(0, ipname, sizeof(ipname), "%d.%d.%d.%d", ad[0], ad[1],
690                   ad[2], ad[3]);
691     dconf->address = inet_addr(ipname);
692   }
693 };
694
695 killreal: REAL '=' QSTRING ';'
696 {
697  dconf->flags &= ~DENY_FLAGS_IP;
698  dconf->flags |= DENY_FLAGS_REALNAME;
699  MyFree(dconf->hostmask);
700  /* Leave usermask so you can specify user and real... */
701  DupString(dconf->hostmask, yylval.text);
702 };
703
704 killreason: REASON '=' QSTRING ';'
705 {
706  dconf->flags &= DENY_FLAGS_FILE;
707  MyFree(dconf->message);
708  DupString(dconf->message, yylval.text);
709 };
710
711 killreasonfile: TFILE '=' QSTRING ';'
712 {
713  dconf->flags |= DENY_FLAGS_FILE;
714  MyFree(dconf->message);
715  DupString(dconf->message, yylval.text);
716 };
717
718 cruleblock: CRULE
719 {
720   host = pass = NULL;
721   tconn = CRULE_AUTO;
722 } '{' cruleitems '}'
723 {
724   struct CRuleNode *node;
725   if (host != NULL && pass != NULL && (node=crule_parse(pass)) != NULL)
726   {
727     struct CRuleConf *p = MyMalloc(sizeof(*p));
728     p->hostmask = host;
729     p->rule = pass;
730     p->type = tconn;
731     p->node = node;
732     p->next = cruleConfList;
733     cruleConfList = p;
734   }
735   else
736   {
737     MyFree(host);
738     MyFree(pass);
739   }
740 } ';';
741
742 cruleitems: cruleitem cruleitems | cruleitem;
743 cruleitem: cruleserver | crulerule | cruleall;
744
745 cruleserver: SERVER '=' QSTRING ';'
746 {
747   MyFree(host);
748   collapse(yylval.text);
749   DupString(host, yylval.text);
750 };
751
752 crulerule: RULE '=' QSTRING ';'
753 {
754  MyFree(pass);
755  DupString(pass, yylval.text);
756 };
757
758 cruleall: ALL '=' YES ';'
759 {
760  tconn = CRULE_ALL;
761 } | ALL '=' NO ';'
762 {
763  tconn = CRULE_AUTO;
764 };
765
766 motdblock: MOTD {
767  pass = host = NULL;
768 } '{' motditems '}'
769 {
770   if (host != NULL && pass != NULL)
771     motd_add(host, pass);
772   MyFree(host);
773   MyFree(pass);
774   host = pass = NULL;
775 } ';';
776
777 motditems: motditem motditems | motditem;
778 motditem: motdhost | motdfile;
779 motdhost: HOST '=' QSTRING ';'
780 {
781   DupString(host, yylval.text);
782 };
783
784 motdfile: TFILE '=' QSTRING ';'
785 {
786   DupString(pass, yylval.text);
787 };
788
789 featuresblock: FEATURES '{' featureitems '}' ';';
790 featureitems: featureitems featureitem | featureitem;
791
792 featureitem: QSTRING
793 {
794   stringno = 0;
795 } '=' stringlist ';';
796
797 stringlist: QSTRING
798 {
799   stringlist[0] = $1;
800   stringno = 1;
801 } posextrastrings
802 {
803   feature_set(NULL, (const char * const *)stringlist, stringno);
804 };
805 posextrastrings: /* empty */ | extrastrings;
806 extrastrings: extrastrings extrastring | extrastring;
807 extrastring: QSTRING
808 {
809   if (stringno < MAX_STRINGS)
810     stringlist[stringno++] = $1;
811 };