#include <arpa/inet.h>
#define MAX_STRINGS 80 /* Maximum number of feature params. */
-#define USE_IPV4 (1 << 0)
-#define USE_IPV6 (1 << 1)
+#define USE_IPV4 (1 << 16)
+#define USE_IPV6 (1 << 17)
extern struct LocalConf localConf;
extern struct DenyConf* denyConfList;
/* 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;
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 <text> QSTRING
%token PROGRAM
%token TOK_IPV4 TOK_IPV6
%token DNS
+%token SSL
+%token CERTFILE
+%token KEYFILE
+%token CAFILE
/* 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
%token TPRIV_GLINE TPRIV_LOCAL_GLINE TPRIV_LOCAL_JUPE TPRIV_LOCAL_BADCHAN
%token TPRIV_LOCAL_OPMODE TPRIV_OPMODE TPRIV_SET TPRIV_WHOX TPRIV_BADCHAN
%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
+%token TPRIV_UNLIMIT_QUERY TPRIV_UNLIMIT_FLOOD TPRIV_DISPLAY TPRIV_SEE_OPERS
+%token TPRIV_WIDE_GLINE TPRIV_FORCE_OPMODE TPRIV_FORCE_LOCAL_OPMODE
+%token TPRIV_APASS_OPMODE TPRIV_LIST_CHAN
/* and some types... */
%type <num> sizespec
%type <num> timespec timefactor factoredtimes factoredtime
%%
/* Blocks in the config file... */
blocks: blocks block | block;
-block: adminblock | generalblock | classblock | connectblock |
+block: adminblock | generalblock | classblock | connectblock | sslblock |
uworldblock | operblock | portblock | jupeblock | clientblock |
killblock | cruleblock | motdblock | featuresblock | quarantineblock |
pseudoblock | iauthblock | error ';';
localConf.contact = $3;
};
+sslblock: SSL
+{
+ MyFree(localConf.sslcertfile);
+ MyFree(localConf.sslkeyfile);
+ MyFree(localConf.sslcafile);
+ localConf.sslcertfile = localConf.sslkeyfile = localConf.sslcafile = NULL;
+}
+'{' sslitems '}' ';'
+{
+ if (localConf.sslcertfile == NULL)
+ DupString(localConf.sslcertfile, "");
+ if (localConf.sslkeyfile == NULL)
+ DupString(localConf.sslkeyfile, "");
+ if (localConf.sslcafile == NULL)
+ DupString(localConf.sslcafile, "");
+};
+sslitems: sslitems sslitem | sslitem;
+sslitem: sslcertfile | sslkeyfile | sslcafile;
+sslcertfile: CERTFILE '=' QSTRING ';'
+{
+ MyFree(localConf.sslcertfile);
+ localConf.sslcertfile = $3;
+};
+sslkeyfile: KEYFILE '=' QSTRING ';'
+{
+ MyFree(localConf.sslkeyfile);
+ localConf.sslkeyfile = $3;
+};
+sslcafile: CAFILE '=' QSTRING ';'
+{
+ MyFree(localConf.sslcafile);
+ localConf.sslcafile = $3;
+};
+
classblock: CLASS {
tping = 90;
} '{' classitems '}' ';'
connectblock: CONNECT
{
- maxlinks = 65535;
flags = CONF_AUTOCONNECT;
} '{' connectitems '}' ';'
{
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);
}
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
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");
/* Do not check password length because it may be crypted. */
- else if (host == NULL)
- parse_error("Missing host in operator block");
+ 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 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 {
+ 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 (!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));
};
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 ';'
{
TPRIV_SHOW_ALL_INVIS { $$ = PRIV_SHOW_ALL_INVIS; } |
TPRIV_PROPAGATE { $$ = PRIV_PROPAGATE; } |
TPRIV_UNLIMIT_QUERY { $$ = PRIV_UNLIMIT_QUERY; } |
+ TPRIV_UNLIMIT_FLOOD { $$ = PRIV_UNLIMIT_FLOOD; } |
TPRIV_DISPLAY { $$ = PRIV_DISPLAY; } |
TPRIV_SEE_OPERS { $$ = PRIV_SEE_OPERS; } |
TPRIV_WIDE_GLINE { $$ = PRIV_WIDE_GLINE; } |
;
/* The port block... */
-portblock: PORT '{' portitems '}' ';'
-{
- if (!FlagHas(&listen_flags, LISTEN_IPV4)
- && !FlagHas(&listen_flags, LISTEN_IPV6))
- {
- FlagSet(&listen_flags, LISTEN_IPV4);
- FlagSet(&listen_flags, LISTEN_IPV6);
+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;
}
- if (port > 0 && port <= 0xFFFF)
- add_listener(port, host, pass, &listen_flags);
- else
- parse_error("Port %d is out of range", port);
- MyFree(host);
+ 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);
memset(&listen_flags, 0, sizeof(listen_flags));
- host = pass = NULL;
+ pass = NULL;
port = 0;
};
portitems: portitem portitems | portitem;
-portitem: portnumber | portvhost | portmask | portserver | porthidden;
+portitem: portnumber | portvhost | portvhostnumber | portmask | portserver | portssl | porthidden;
portnumber: PORT '=' address_family NUMBER ';'
{
- int families = $3;
- if (families & USE_IPV4)
- FlagSet(&listen_flags, LISTEN_IPV4);
- else if (families & USE_IPV6)
- FlagSet(&listen_flags, LISTEN_IPV6);
- port = $4;
+ 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 '=' address_family QSTRING ';'
{
- int families = $3;
- if (families & USE_IPV4)
- FlagSet(&listen_flags, LISTEN_IPV4);
- else if (families & USE_IPV6)
- FlagSet(&listen_flags, LISTEN_IPV6);
- MyFree(host);
- host = $4;
+ 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 ';'
FlagClr(&listen_flags, LISTEN_SERVER);
};
+portssl: SSL '=' YES ';'
+{
+ FlagSet(&listen_flags, LISTEN_SSL);
+} | SSL '=' NO ';'
+{
+ FlagClr(&listen_flags, LISTEN_SSL);
+};
+
porthidden: HIDDEN '=' YES ';'
{
FlagSet(&listen_flags, LISTEN_HIDDEN);
host = NULL;
username = NULL;
c_class = NULL;
+ maxlinks = 0;
ip = NULL;
pass = NULL;
port = 0;
} '{' 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;
};
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 ';'
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;
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;
};
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))
{
auth_spawn(stringno, stringlist);
while (stringno > 0)
- MyFree(stringlist[--stringno]);
+ {
+ --stringno;
+ MyFree(stringlist[stringno]);
+ }
};
iauthitems: iauthitem iauthitems | iauthitem;
iauthprogram: PROGRAM '='
{
while (stringno > 0)
- MyFree(stringlist[--stringno]);
+ {
+ --stringno;
+ MyFree(stringlist[stringno]);
+ }
} stringlist ';';