X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fircd_parser.y;h=a43b9446cd7619768bafb7e301ea67525065901f;hb=7fbb742f7d849cb57b23f2a76d90950174094719;hp=13c881bd4d5191bf31d9f5bfe5a8725fee841f9e;hpb=6cdd22d4d1c70a45d9ea26c2f1ded2c2eccc8548;p=ircu2.10.12-pk.git diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 13c881b..a43b944 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -32,7 +32,6 @@ #include "hash.h" #include "ircd.h" #include "ircd_alloc.h" -#include "ircd_auth.h" #include "ircd_chattr.h" #include "ircd_log.h" #include "ircd_reply.h" @@ -47,6 +46,7 @@ #include "opercmds.h" #include "parse.h" #include "res.h" +#include "s_auth.h" #include "s_bsd.h" #include "s_conf.h" #include "s_debug.h" @@ -58,7 +58,11 @@ #include #include #include + #define MAX_STRINGS 80 /* Maximum number of feature params. */ +#define USE_IPV4 (1 << 16) +#define USE_IPV6 (1 << 17) + extern struct LocalConf localConf; extern struct DenyConf* denyConfList; extern struct CRuleConf* cruleConfList; @@ -70,7 +74,9 @@ /* Now all the globals we need :/... */ int tping, tconn, maxlinks, sendq, port, invert, stringno, flags; char *name, *pass, *host, *ip, *username, *origin, *hub_limit; + struct SLink *hosts; char *stringlist[MAX_STRINGS]; + struct ListenerFlags listen_flags; struct ConnectionClass *c_class; struct DenyConf *dconf; struct ServerConf *sconf; @@ -87,6 +93,16 @@ static void parse_error(char *pattern,...) { yyerror(error_buffer); } +static void free_slist(struct SLink **link) { + struct SLink *next; + while (*link != NULL) { + next = (*link)->next; + MyFree((*link)->value.cp); + free_link(*link); + *link = next; + } +} + %} %token QSTRING @@ -156,6 +172,9 @@ static void parse_error(char *pattern,...) { %token TIMEOUT %token FAST %token AUTOCONNECT +%token PROGRAM +%token TOK_IPV4 TOK_IPV6 +%token DNS /* 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 @@ -164,10 +183,11 @@ static void parse_error(char *pattern,...) { %token TPRIV_SEE_CHAN TPRIV_SHOW_INVIS TPRIV_SHOW_ALL_INVIS TPRIV_PROPAGATE %token TPRIV_UNLIMIT_QUERY TPRIV_DISPLAY TPRIV_SEE_OPERS TPRIV_WIDE_GLINE %token TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE TPRIV_APASS_OPMODE +%token TPRIV_LIST_CHAN /* and some types... */ %type sizespec %type timespec timefactor factoredtimes factoredtime -%type expr yesorno privtype +%type expr yesorno privtype address_family %left '+' '-' %left '*' '/' @@ -182,7 +202,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. */ @@ -256,22 +276,28 @@ 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 + | generaldnsvhost | generaldnsserver; + generalnumeric: NUMERIC '=' NUMBER ';' { if (localConf.numeric == 0) @@ -303,16 +329,58 @@ generaldesc: DESCRIPTION '=' QSTRING ';' generalvhost: VHOST '=' QSTRING ';' { struct irc_in_addr addr; - if (!ircd_aton(&addr, $3)) - parse_error("Invalid virtual host '%s'.", $3); + char *vhost = $3; + + if (!strcmp(vhost, "*")) { + /* This traditionally meant bind to all interfaces and connect + * from the default. */ + } else if (!ircd_aton(&addr, vhost)) + parse_error("Invalid virtual host '%s'.", vhost); else if (irc_in_addr_is_ipv4(&addr)) memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr)); else memcpy(&VirtualHost_v6.addr, &addr, sizeof(addr)); - MyFree($3); + MyFree(vhost); }; -adminblock: ADMIN '{' adminitems '}' +generaldnsvhost: DNS VHOST '=' address_family QSTRING ';' +{ + struct irc_in_addr addr; + int families = $4; + char *vhost = $5; + + if (!strcmp(vhost, "*")) { + /* Let the operating system assign the default. */ + } else if (!ircd_aton(&addr, vhost)) + parse_error("Invalid DNS virtual host '%s'.", vhost); + else + { + if ((families & USE_IPV4) + || (!families && irc_in_addr_is_ipv4(&addr))) + memcpy(&VirtualHost_dns_v4.addr, &addr, sizeof(addr)); + if ((families & USE_IPV6) + || (!families && !irc_in_addr_is_ipv4(&addr))) + memcpy(&VirtualHost_dns_v6.addr, &addr, sizeof(addr)); + } + MyFree(vhost); +}; + +generaldnsserver: DNS SERVER '=' QSTRING ';' +{ + char *server = $4; + + add_nameserver(server); + MyFree(server); +}; + +adminblock: ADMIN +{ + MyFree(localConf.location1); + MyFree(localConf.location2); + MyFree(localConf.contact); + localConf.location1 = localConf.location2 = localConf.contact = NULL; +} +'{' adminitems '}' ';' { if (localConf.location1 == NULL) DupString(localConf.location1, ""); @@ -320,9 +388,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) @@ -340,7 +408,7 @@ admincontact: CONTACT '=' QSTRING ';' classblock: CLASS { tping = 90; -} '{' classitems '}' +} '{' classitems '}' ';' { if (name != NULL) { @@ -362,10 +430,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,15 +463,16 @@ classusermode: USERMODE '=' QSTRING ';' connectblock: CONNECT { - maxlinks = 65535; flags = CONF_AUTOCONNECT; -} '{' connectitems '}' +} '{' connectitems '}' ';' { struct ConfItem *aconf = NULL; if (name == NULL) parse_error("Missing name in connect block"); else if (pass == NULL) parse_error("Missing password in connect block"); + else if (strlen(pass) > PASSWDLEN) + parse_error("Password too long in connect block"); else if (host == NULL) parse_error("Missing host in connect block"); else if (strchr(host, '*') || strchr(host, '?')) @@ -418,7 +487,10 @@ connectblock: CONNECT aconf->conn_class = c_class; aconf->address.port = port; aconf->host = host; - aconf->maximum = maxlinks; + /* If the user specified a hub allowance, but not maximum links, + * allow an effectively unlimited number of hops. + */ + aconf->maximum = (hub_limit != NULL && maxlinks == 0) ? 65535 : maxlinks; aconf->hub_limit = hub_limit; aconf->flags = flags; lookup_confhost(aconf); @@ -432,12 +504,12 @@ connectblock: CONNECT } name = pass = host = origin = hub_limit = NULL; c_class = NULL; - port = flags = 0; -}';'; + port = flags = maxlinks = 0; +}; connectitems: connectitem connectitems | connectitem; connectitem: connectname | connectpass | connectclass | connecthost | connectport | connectvhost | connectleaf | connecthub - | connecthublimit | connectmaxhops | connectauto | error; + | connecthublimit | connectmaxhops | connectauto; connectname: NAME '=' QSTRING ';' { MyFree(name); @@ -492,7 +564,7 @@ connectauto: AUTOCONNECT '=' YES ';' { 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,38 +573,39 @@ uworldname: NAME '=' QSTRING ';' operblock: OPER '{' operitems '}' ';' { struct ConfItem *aconf = NULL; + struct SLink *link; + if (name == NULL) parse_error("Missing name in operator block"); else if (pass == NULL) parse_error("Missing password in operator block"); - else if (host == NULL) - parse_error("Missing host in operator block"); + /* Do not check password length because it may be crypted. */ + else if (hosts == NULL) + parse_error("Missing host(s) in operator block"); else if (c_class == NULL) parse_error("Invalid or missing class in operator block"); - else { + else if (!FlagHas(&privs_dirty, PRIV_PROPAGATE) + && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE)) + parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name); + else for (link = hosts; link != NULL; link = link->next) { aconf = make_conf(CONF_OPERATOR); - aconf->name = name; - aconf->passwd = pass; - conf_parse_userhost(aconf, host); + DupString(aconf->name, name); + DupString(aconf->passwd, pass); + conf_parse_userhost(aconf, link->value.cp); aconf->conn_class = c_class; memcpy(&aconf->privs, &privs, sizeof(aconf->privs)); memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty)); - if (!FlagHas(&privs_dirty, PRIV_PROPAGATE) - && !FlagHas(&c_class->privs_dirty, PRIV_PROPAGATE)) - parse_error("Operator block for %s and class %s have no LOCAL setting", name, c_class->cc_name); - } - if (!aconf) { - MyFree(name); - MyFree(pass); - MyFree(host); } - name = pass = host = NULL; + MyFree(name); + MyFree(pass); + free_slist(&hosts); + name = pass = NULL; c_class = NULL; memset(&privs, 0, sizeof(privs)); 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); @@ -545,16 +618,19 @@ operpass: PASS '=' QSTRING ';' }; operhost: HOST '=' QSTRING ';' { - MyFree(host); + struct SLink *link; + link = make_link(); if (!strchr($3, '@')) { int uh_len; - host = (char*) MyMalloc((uh_len = strlen($3)+3)); - ircd_snprintf(0, host, uh_len, "*@%s", $3); - MyFree($3); + link->value.cp = (char*) MyMalloc((uh_len = strlen($3)+3)); + ircd_snprintf(0, link->value.cp, uh_len, "*@%s", $3); } else - host = $3; + DupString(link->value.cp, $3); + MyFree($3); + link->next = hosts; + hosts = link; }; operclass: CLASS '=' QSTRING ';' { @@ -601,6 +677,7 @@ privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | TPRIV_DISPLAY { $$ = PRIV_DISPLAY; } | TPRIV_SEE_OPERS { $$ = PRIV_SEE_OPERS; } | TPRIV_WIDE_GLINE { $$ = PRIV_WIDE_GLINE; } | + TPRIV_LIST_CHAN { $$ = PRIV_LIST_CHAN; } | LOCAL { $$ = PRIV_PROPAGATE; invert = 1; } | TPRIV_FORCE_OPMODE { $$ = PRIV_FORCE_OPMODE; } | TPRIV_FORCE_LOCAL_OPMODE { $$ = PRIV_FORCE_LOCAL_OPMODE; } | @@ -608,29 +685,88 @@ privtype: TPRIV_CHAN_LIMIT { $$ = PRIV_CHAN_LIMIT; } | yesorno: YES { $$ = 1; } | NO { $$ = 0; }; +/* not a recursive definition because some pedant will just come along + * and whine that the parser accepts "ipv4 ipv4 ipv4 ipv4" + */ +address_family: + { $$ = 0; } + | TOK_IPV4 { $$ = USE_IPV4; } + | TOK_IPV6 { $$ = USE_IPV6; } + | TOK_IPV4 TOK_IPV6 { $$ = USE_IPV4 | USE_IPV6; } + | TOK_IPV6 TOK_IPV4 { $$ = USE_IPV6 | USE_IPV4; } + ; + /* The port block... */ -portblock: PORT '{' portitems '}' ';' -{ - if (port > 0 && port <= 0xFFFF) - add_listener(port, host, pass, tconn, tping); - else - parse_error("Port %d is out of range", port); - MyFree(host); +portblock: PORT '{' portitems '}' ';' { + struct ListenerFlags flags_here; + struct SLink *link; + if (hosts == NULL) { + struct SLink *link; + link = make_link(); + DupString(link->value.cp, "*"); + link->flags = 0; + link->next = hosts; + hosts = link; + } + for (link = hosts; link != NULL; link = link->next) { + memcpy(&flags_here, &listen_flags, sizeof(&flags_here)); + switch (link->flags & (USE_IPV4 | USE_IPV6)) { + case USE_IPV4: + FlagSet(&flags_here, LISTEN_IPV4); + break; + case USE_IPV6: + FlagSet(&flags_here, LISTEN_IPV6); + break; + default: /* 0 or USE_IPV4|USE_IPV6 */ + FlagSet(&flags_here, LISTEN_IPV4); + FlagSet(&flags_here, LISTEN_IPV6); + break; + } + if (link->flags & 65535) + port = link->flags & 65535; + add_listener(port, link->value.cp, pass, &flags_here); + } + free_slist(&hosts); MyFree(pass); - host = pass = NULL; - port = tconn = tping = 0; + memset(&listen_flags, 0, sizeof(listen_flags)); + pass = NULL; + port = 0; }; portitems: portitem portitems | portitem; -portitem: portnumber | portvhost | portmask | portserver | porthidden | error; -portnumber: PORT '=' NUMBER ';' +portitem: portnumber | portvhost | portvhostnumber | portmask | portserver | porthidden; +portnumber: PORT '=' address_family NUMBER ';' { - port = $3; + if ($4 < 1 || $4 > 65535) { + parse_error("Port %d is out of range", port); + } else { + port = $3 | $4; + if (hosts && (0 == (hosts->flags & 65535))) + hosts->flags = (hosts->flags & ~65535) | port; + } }; -portvhost: VHOST '=' QSTRING ';' +portvhost: VHOST '=' address_family QSTRING ';' { - MyFree(host); - host = $3; + struct SLink *link; + link = make_link(); + link->value.cp = $4; + link->flags = $3 | port; + link->next = hosts; + hosts = link; +}; + +portvhostnumber: VHOST '=' address_family QSTRING NUMBER ';' +{ + if ($5 < 1 || $5 > 65535) { + parse_error("Port %d is out of range", port); + } else { + struct SLink *link; + link = make_link(); + link->value.cp = $4; + link->flags = $3 | $5; + link->next = hosts; + hosts = link; + } }; portmask: MASK '=' QSTRING ';' @@ -641,23 +777,24 @@ portmask: MASK '=' QSTRING ';' portserver: SERVER '=' YES ';' { - tconn = -1; + FlagSet(&listen_flags, LISTEN_SERVER); } | SERVER '=' NO ';' { - tconn = 0; + FlagClr(&listen_flags, LISTEN_SERVER); }; porthidden: HIDDEN '=' YES ';' { - tping = -1; + FlagSet(&listen_flags, LISTEN_HIDDEN); } | HIDDEN '=' NO ';' { - tping = 0; + FlagClr(&listen_flags, LISTEN_HIDDEN); }; clientblock: CLIENT { maxlinks = 65535; + port = 0; } '{' clientitems '}' ';' { @@ -667,6 +804,8 @@ clientblock: CLIENT if (!c_class) parse_error("Invalid or missing class in Client block"); + else if (pass && strlen(pass) > PASSWDLEN) + parse_error("Password too long in connect block"); else if (ip && !ipmask_parse(ip, &addr, &addrbits)) parse_error("Invalid IP address %s in Client block", ip); else { @@ -677,6 +816,7 @@ clientblock: CLIENT memcpy(&aconf->address.addr, &addr, sizeof(aconf->address.addr)); else memset(&aconf->address.addr, 0, sizeof(aconf->address.addr)); + aconf->address.port = port; aconf->addrbits = addrbits; aconf->name = ip; aconf->conn_class = c_class; @@ -692,11 +832,13 @@ clientblock: CLIENT host = NULL; username = NULL; c_class = NULL; + maxlinks = 0; ip = NULL; pass = NULL; + port = 0; }; clientitems: clientitem clientitems | clientitem; -clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks | error; +clientitem: clienthost | clientip | clientusername | clientclass | clientpass | clientmaxlinks | clientport; clienthost: HOST '=' QSTRING ';' { char *sep = strchr($3, '@'); @@ -733,7 +875,7 @@ clientclass: CLASS '=' QSTRING ';' { c_class = find_class($3); if (!c_class) - parse_error("No such connection class '%s' for Class block", $3); + parse_error("No such connection class '%s' for Client block", $3); MyFree($3); }; clientpass: PASS '=' QSTRING ';' @@ -745,11 +887,15 @@ clientmaxlinks: MAXLINKS '=' expr ';' { maxlinks = $3; }; +clientport: PORT '=' expr ';' +{ + port = $3; +}; killblock: KILL { dconf = (struct DenyConf*) MyCalloc(1, sizeof(*dconf)); -} '{' killitems '}' +} '{' killitems '}' ';' { if (dconf->usermask || dconf->hostmask ||dconf->realmask) { dconf->next = denyConfList; @@ -765,9 +911,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; @@ -819,39 +965,43 @@ cruleblock: CRULE } '{' cruleitems '}' ';' { struct CRuleNode *node = NULL; - if (host == NULL) - parse_error("Missing host in crule block"); + struct SLink *link; + + if (hosts == NULL) + parse_error("Missing server(s) in crule block"); else if (pass == NULL) parse_error("Missing rule in crule block"); else if ((node = crule_parse(pass)) == NULL) parse_error("Invalid rule '%s' in crule block", pass); - else + else for (link = hosts; link != NULL; link = link->next) { struct CRuleConf *p = (struct CRuleConf*) MyMalloc(sizeof(*p)); - p->hostmask = host; - p->rule = pass; + if (node == NULL) + node = crule_parse(pass); + DupString(p->hostmask, link->value.cp); + DupString(p->rule, pass); p->type = tconn; p->node = node; + node = NULL; p->next = cruleConfList; cruleConfList = p; } - if (!node) - { - MyFree(host); - MyFree(pass); - } - host = pass = NULL; + free_slist(&hosts); + MyFree(pass); + pass = NULL; tconn = 0; }; cruleitems: cruleitem cruleitems | cruleitem; -cruleitem: cruleserver | crulerule | cruleall | error; +cruleitem: cruleserver | crulerule | cruleall; cruleserver: SERVER '=' QSTRING ';' { - MyFree(host); - collapse($3); - host = $3; + struct SLink *link; + link = make_link(); + link->value.cp = $3; + link->next = hosts; + hosts = link; }; crulerule: RULE '=' QSTRING ';' @@ -870,22 +1020,29 @@ cruleall: ALL '=' YES ';' motdblock: MOTD '{' motditems '}' ';' { - if (host != NULL && pass != NULL) - motd_add(host, pass); - MyFree(host); + struct SLink *link; + if (pass != NULL) + for (link = hosts; link != NULL; link = link->next) + motd_add(link->value.cp, pass); + free_slist(&hosts); MyFree(pass); - host = pass = NULL; + pass = NULL; }; motditems: motditem motditems | motditem; -motditem: motdhost | motdfile | error; +motditem: motdhost | motdfile; motdhost: HOST '=' QSTRING ';' { - host = $3; + struct SLink *link; + link = make_link(); + link->value.cp = $3; + link->next = hosts; + hosts = link; }; motdfile: TFILE '=' QSTRING ';' { + MyFree(pass); pass = $3; }; @@ -896,21 +1053,14 @@ featureitem: QSTRING { stringlist[0] = $1; stringno = 1; -} '=' stringlist ';'; - -stringlist: QSTRING -{ - stringlist[1] = $1; - stringno = 2; -} posextrastrings -{ +} '=' stringlist ';' { unsigned int ii; feature_set(NULL, (const char * const *)stringlist, stringno); for (ii = 0; ii < stringno; ++ii) MyFree(stringlist[ii]); }; -posextrastrings: /* empty */ | extrastrings; -extrastrings: extrastrings extrastring | extrastring; + +stringlist: stringlist extrastring | extrastring; extrastring: QSTRING { if (stringno < MAX_STRINGS) @@ -943,6 +1093,8 @@ pseudoitems '}' ';' parse_error("Missing name in pseudo %s block", smap->command); else if (!smap->services) parse_error("Missing nick in pseudo %s block", smap->command); + else if (!strIsAlpha(smap->command)) + parse_error("Pseudo command %s invalid: must all be letters", smap->command); else valid = 1; if (valid && register_mapping(smap)) @@ -952,22 +1104,13 @@ pseudoitems '}' ';' } else { - struct nick_host *nh, *next; - for (nh = smap->services; nh; nh = next) - { - next = nh->next; - MyFree(nh); - } - MyFree(smap->name); - MyFree(smap->command); - MyFree(smap->prepend); - MyFree(smap); + free_mapping(smap); } smap = NULL; }; pseudoitems: pseudoitem pseudoitems | pseudoitem; -pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags | error; +pseudoitem: pseudoname | pseudoprepend | pseudonick | pseudoflags; pseudoname: NAME '=' QSTRING ';' { MyFree(smap->name); @@ -997,45 +1140,23 @@ pseudoflags: FAST ';' smap->flags |= SMAP_FAST; }; -iauthblock: IAUTH '{' -{ - tconn = 60; - tping = 60; -} iauthitems '}' ';' +iauthblock: IAUTH '{' iauthitems '}' ';' { - if (!host) - parse_error("Missing host in iauth block"); - else if (!port) - parse_error("Missing port in iauth block"); - else - iauth_connect(host, port, pass, tconn, tping); - MyFree(pass); - MyFree(host); - pass = host = NULL; - port = tconn = tping = 0; + auth_spawn(stringno, stringlist); + while (stringno > 0) + { + --stringno; + MyFree(stringlist[stringno]); + } }; iauthitems: iauthitem iauthitems | iauthitem; -iauthitem: iauthpass | iauthhost | iauthport | iauthconnfreq | iauthtimeout | error; -iauthpass: PASS '=' QSTRING ';' -{ - MyFree(pass); - pass = $3; -}; -iauthhost: HOST '=' QSTRING ';' +iauthitem: iauthprogram; +iauthprogram: PROGRAM '=' { - MyFree(host); - host = $3; -}; -iauthport: PORT '=' NUMBER ';' -{ - port = $3; -}; -iauthconnfreq: CONNECTFREQ '=' timespec ';' -{ - tconn = $3; -}; -iauthtimeout: TIMEOUT '=' timespec ';' -{ - tping = $3; -}; + while (stringno > 0) + { + --stringno; + MyFree(stringlist[stringno]); + } +} stringlist ';';