Make ircd.conf accept "*" as vhost like .11 did. Fix comment in channel.c.
[ircu2.10.12-pk.git] / ircd / ircd_parser.y
index e02f4ba8a65bee44d3b1f68251f3ca9e79079f27..2ce1b6c79cf129c07cfdc7551b6965bdbaafbba6 100644 (file)
@@ -68,7 +68,7 @@
 
   int yylex(void);
   /* Now all the globals we need :/... */
-  int tping, tconn, maxlinks, sendq, port, invert, stringno;
+  int tping, tconn, maxlinks, sendq, port, invert, stringno, flags;
   char *name, *pass, *host, *ip, *username, *origin, *hub_limit;
   char *stringlist[MAX_STRINGS];
   struct ConnectionClass *c_class;
@@ -155,6 +155,7 @@ static void parse_error(char *pattern,...) {
 %token IAUTH
 %token TIMEOUT
 %token FAST
+%token AUTOCONNECT
 /* and now a lot of privileges... */
 %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN
 %token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE
@@ -181,7 +182,7 @@ blocks: blocks block | block;
 block: adminblock | generalblock | classblock | connectblock |
        uworldblock | operblock | portblock | jupeblock | clientblock |
        killblock | cruleblock | motdblock | featuresblock | quarantineblock |
-       pseudoblock | iauthblock | error;
+       pseudoblock | iauthblock | error ';';
 
 /* The timespec, sizespec and expr was ripped straight from
  * ircd-hybrid-7. */
@@ -255,22 +256,26 @@ expr: NUMBER
 
 jupeblock: JUPE '{' jupeitems '}' ';' ;
 jupeitems: jupeitem jupeitems | jupeitem;
-jupeitem: jupenick | error;
-jupenick: NICK '=' QSTRING
+jupeitem: jupenick;
+jupenick: NICK '=' QSTRING ';'
 {
   addNickJupes($3);
   MyFree($3);
-} ';';
+};
 
-generalblock: GENERAL '{' generalitems '}'
+generalblock: GENERAL
 {
+    /* Zero out the vhost addresses, in case they were removed. */
+    memset(&VirtualHost_v4.addr, 0, sizeof(VirtualHost_v4.addr));
+    memset(&VirtualHost_v6.addr, 0, sizeof(VirtualHost_v6.addr));
+} '{' generalitems '}' ';' {
   if (localConf.name == NULL)
     parse_error("Your General block must contain a name.");
   if (localConf.numeric == 0)
     parse_error("Your General block must contain a numeric (between 1 and 4095).");
-} ';' ;
+};
 generalitems: generalitem generalitems | generalitem;
-generalitem: generalnumeric | generalname | generalvhost | generaldesc | error;
+generalitem: generalnumeric | generalname | generalvhost | generaldesc;
 generalnumeric: NUMERIC '=' NUMBER ';'
 {
   if (localConf.numeric == 0)
@@ -302,8 +307,11 @@ generaldesc: DESCRIPTION '=' QSTRING ';'
 generalvhost: VHOST '=' QSTRING ';'
 {
   struct irc_in_addr addr;
-  if (!ircd_aton(&addr, $3))
-      parse_error("Invalid virtual host '%s'.", $3);
+  if (!strcmp($3, "*")) {
+    /* This traditionally meant bind to all interfaces and connect
+     * from the default. */
+  } else if (!ircd_aton(&addr, $3))
+    parse_error("Invalid virtual host '%s'.", $3);
   else if (irc_in_addr_is_ipv4(&addr))
     memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr));
   else
@@ -311,7 +319,7 @@ generalvhost: VHOST '=' QSTRING ';'
   MyFree($3);
 };
 
-adminblock: ADMIN '{' adminitems '}'
+adminblock: ADMIN '{' adminitems '}' ';'
 {
   if (localConf.location1 == NULL)
     DupString(localConf.location1, "");
@@ -319,9 +327,9 @@ adminblock: ADMIN '{' adminitems '}'
     DupString(localConf.location2, "");
   if (localConf.contact == NULL)
     DupString(localConf.contact, "");
-} ';';
+};
 adminitems: adminitems adminitem | adminitem;
-adminitem: adminlocation | admincontact | error;
+adminitem: adminlocation | admincontact;
 adminlocation: LOCATION '=' QSTRING ';'
 {
   if (localConf.location1 == NULL)
@@ -339,7 +347,7 @@ admincontact: CONTACT '=' QSTRING ';'
 
 classblock: CLASS {
   tping = 90;
-} '{' classitems '}'
+} '{' classitems '}' ';'
 {
   if (name != NULL)
   {
@@ -361,10 +369,10 @@ classblock: CLASS {
   sendq = 0;
   memset(&privs, 0, sizeof(privs));
   memset(&privs_dirty, 0, sizeof(privs_dirty));
-} ';';
+};
 classitems: classitem classitems | classitem;
 classitem: classname | classpingfreq | classconnfreq | classmaxlinks |
-           classsendq | classusermode | priv | error;
+           classsendq | classusermode | priv;
 classname: NAME '=' QSTRING ';'
 {
   MyFree(name);
@@ -395,7 +403,8 @@ classusermode: USERMODE '=' QSTRING ';'
 connectblock: CONNECT
 {
  maxlinks = 65535;
-} '{' connectitems '}'
+ flags = CONF_AUTOCONNECT;
+} '{' connectitems '}' ';'
 {
  struct ConfItem *aconf = NULL;
  if (name == NULL)
@@ -407,7 +416,7 @@ connectblock: CONNECT
  else if (strchr(host, '*') || strchr(host, '?'))
   parse_error("Invalid host '%s' in connect block", host);
  else if (c_class == NULL)
-  parse_error("Missing class in connect block");
+  parse_error("Missing or non-existent class in connect block");
  else {
    aconf = make_conf(CONF_SERVER);
    aconf->name = name;
@@ -418,6 +427,7 @@ connectblock: CONNECT
    aconf->host = host;
    aconf->maximum = maxlinks;
    aconf->hub_limit = hub_limit;
+   aconf->flags = flags;
    lookup_confhost(aconf);
  }
  if (!aconf) {
@@ -429,12 +439,12 @@ connectblock: CONNECT
  }
  name = pass = host = origin = hub_limit = NULL;
  c_class = NULL;
- port = 0;
-}';';
+ port = flags = 0;
+};
 connectitems: connectitem connectitems | connectitem;
 connectitem: connectname | connectpass | connectclass | connecthost
               | connectport | connectvhost | connectleaf | connecthub
-              | connecthublimit | connectmaxhops | error;
+              | connecthublimit | connectmaxhops | connectauto;
 connectname: NAME '=' QSTRING ';'
 {
  MyFree(name);
@@ -448,6 +458,8 @@ connectpass: PASS '=' QSTRING ';'
 connectclass: CLASS '=' QSTRING ';'
 {
  c_class = find_class($3);
+ if (!c_class)
+  parse_error("No such connection class '%s' for Connect block", $3);
  MyFree($3);
 };
 connecthost: HOST '=' QSTRING ';'
@@ -482,10 +494,12 @@ connectmaxhops: MAXHOPS '=' expr ';'
 {
   maxlinks = $3;
 };
+connectauto: AUTOCONNECT '=' YES ';' { flags |= CONF_AUTOCONNECT; }
+ | AUTOCONNECT '=' NO ';' { flags &= ~CONF_AUTOCONNECT; };
 
 uworldblock: UWORLD '{' uworlditems '}' ';';
 uworlditems: uworlditem uworlditems | uworlditem;
-uworlditem: uworldname | error;
+uworlditem: uworldname;
 uworldname: NAME '=' QSTRING ';'
 {
   make_conf(CONF_UWORLD)->host = $3;
@@ -501,7 +515,7 @@ operblock: OPER '{' operitems '}' ';'
   else if (host == NULL)
     parse_error("Missing host in operator block");
   else if (c_class == NULL)
-    parse_error("Missing class in operator block");
+    parse_error("Invalid or missing class in operator block");
   else {
     aconf = make_conf(CONF_OPERATOR);
     aconf->name = name;
@@ -525,7 +539,7 @@ operblock: OPER '{' operitems '}' ';'
   memset(&privs_dirty, 0, sizeof(privs_dirty));
 };
 operitems: operitem | operitems operitem;
-operitem: opername | operpass | operhost | operclass | priv | error;
+operitem: opername | operpass | operhost | operclass | priv;
 opername: NAME '=' QSTRING ';'
 {
   MyFree(name);
@@ -552,6 +566,8 @@ operhost: HOST '=' QSTRING ';'
 operclass: CLASS '=' QSTRING ';'
 {
  c_class = find_class($3);
+ if (!c_class)
+  parse_error("No such connection class '%s' for Operator block", $3);
  MyFree($3);
 };
 
@@ -612,7 +628,7 @@ portblock: PORT '{' portitems '}' ';'
   port = tconn = tping = 0;
 };
 portitems: portitem portitems | portitem;
-portitem: portnumber | portvhost | portmask | portserver | porthidden | error;
+portitem: portnumber | portvhost | portmask | portserver | porthidden;
 portnumber: PORT '=' NUMBER ';'
 {
   port = $3;
@@ -652,17 +668,16 @@ clientblock: CLIENT
 }
 '{' clientitems '}' ';'
 {
+  struct ConfItem *aconf = 0;
   struct irc_in_addr addr;
   unsigned char addrbits = 0;
 
-  if (ip && !ipmask_parse(ip, &addr, &addrbits)) {
-    parse_error("Invalid IP address %s in block", ip);
-    MyFree(username);
-    MyFree(host);
-    MyFree(ip);
-    MyFree(pass);
-  } else {
-    struct ConfItem *aconf = make_conf(CONF_CLIENT);
+  if (!c_class)
+    parse_error("Invalid or missing class in Client block");
+  else if (ip && !ipmask_parse(ip, &addr, &addrbits))
+    parse_error("Invalid IP address %s in Client block", ip);
+  else {
+    aconf = make_conf(CONF_CLIENT);
     aconf->username = username;
     aconf->host = host;
     if (ip)
@@ -671,10 +686,16 @@ clientblock: CLIENT
       memset(&aconf->address.addr, 0, sizeof(aconf->address.addr));
     aconf->addrbits = addrbits;
     aconf->name = ip;
-    aconf->conn_class = c_class ? c_class : find_class("default");
+    aconf->conn_class = c_class;
     aconf->maximum = maxlinks;
     aconf->passwd = pass;
   }
+  if (!aconf) {
+    MyFree(username);
+    MyFree(host);
+    MyFree(ip);
+    MyFree(pass);
+  }
   host = NULL;
   username = NULL;
   c_class = NULL;
@@ -682,7 +703,7 @@ clientblock: CLIENT
   pass = NULL;
 };
 clientitems: clientitem clientitems | clientitem;
-clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks | error;
+clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks;
 clienthost: HOST '=' QSTRING ';'
 {
   char *sep = strchr($3, '@');
@@ -718,6 +739,8 @@ clientusername: USERNAME '=' QSTRING ';'
 clientclass: CLASS '=' QSTRING ';'
 {
   c_class = find_class($3);
+  if (!c_class)
+    parse_error("No such connection class '%s' for Class block", $3);
   MyFree($3);
 };
 clientpass: PASS '=' QSTRING ';'
@@ -733,7 +756,7 @@ clientmaxlinks: MAXLINKS '=' expr ';'
 killblock: KILL
 {
   dconf = (struct DenyConf*) MyCalloc(1, sizeof(*dconf));
-} '{' killitems '}'
+} '{' killitems '}' ';'
 {
   if (dconf->usermask || dconf->hostmask ||dconf->realmask) {
     dconf->next = denyConfList;
@@ -749,9 +772,9 @@ killblock: KILL
     parse_error("Kill block must match on at least one of username, host or realname");
   }
   dconf = NULL;
-} ';';
+};
 killitems: killitem killitems | killitem;
-killitem: killuhost | killreal | killusername | killreasonfile | killreason | error;
+killitem: killuhost | killreal | killusername | killreasonfile | killreason;
 killuhost: HOST '=' QSTRING ';'
 {
   char *h;
@@ -829,7 +852,7 @@ cruleblock: CRULE
 };
 
 cruleitems: cruleitem cruleitems | cruleitem;
-cruleitem: cruleserver | crulerule | cruleall | error;
+cruleitem: cruleserver | crulerule | cruleall;
 
 cruleserver: SERVER '=' QSTRING ';'
 {
@@ -862,7 +885,7 @@ motdblock: MOTD '{' motditems '}' ';'
 };
 
 motditems: motditem motditems | motditem;
-motditem: motdhost | motdfile | error;
+motditem: motdhost | motdfile;
 motdhost: HOST '=' QSTRING ';'
 {
   host = $3;
@@ -951,7 +974,7 @@ pseudoitems '}' ';'
 };
 
 pseudoitems: pseudoitem pseudoitems | pseudoitem;
-pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags | error;
+pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags;
 pseudoname: NAME '=' QSTRING ';'
 {
   MyFree(smap->name);
@@ -1000,7 +1023,7 @@ iauthblock: IAUTH '{'
 };
 
 iauthitems: iauthitem iauthitems | iauthitem;
-iauthitem: iauthpass | iauthhost | iauthport | iauthconnfreq | iauthtimeout | error;
+iauthitem: iauthpass | iauthhost | iauthport | iauthconnfreq | iauthtimeout;
 iauthpass: PASS '=' QSTRING ';'
 {
   MyFree(pass);