diff --git a/include/h.h b/include/h.h index 815c69328..9fcaa4ed0 100644 --- a/include/h.h +++ b/include/h.h @@ -660,6 +660,7 @@ extern MODVAR void (*send_md_member)(ModDataInfo *mdi, aChannel *chptr, Member * extern MODVAR void (*send_md_membership)(ModDataInfo *mdi, aClient *acptr, Membership *m, ModData *md); extern MODVAR int (*check_banned)(aClient *cptr); extern MODVAR void (*introduce_user)(aClient *to, aClient *acptr); +extern MODVAR int (*check_deny_version)(aClient *cptr, char *version_string, int protocol, char *flags); /* /Efuncs */ extern MODVAR aMotdFile opermotd, svsmotd, motd, botmotd, smotd, rules; diff --git a/include/modules.h b/include/modules.h index 9cc3a53de..e85f6d2bf 100644 --- a/include/modules.h +++ b/include/modules.h @@ -824,6 +824,7 @@ extern char *moddata_client_get(aClient *acptr, char *varname); #define EFUNC_SEND_MD_MEMBERSHIP 41 #define EFUNC_CHECK_BANNED 42 #define EFUNC_INTRODUCE_USER 43 +#define EFUNC_CHECK_DENY_VERSION 44 /* Module flags */ #define MODFLAG_NONE 0x0000 diff --git a/src/modules.c b/src/modules.c index ba6d09448..300aa471c 100644 --- a/src/modules.c +++ b/src/modules.c @@ -122,6 +122,7 @@ void (*send_md_channel)(ModDataInfo *mdi, aChannel *chptr, ModData *md); void (*send_md_member)(ModDataInfo *mdi, aChannel *chptr, Member *m, ModData *md); void (*send_md_membership)(ModDataInfo *mdi, aClient *acptr, Membership *m, ModData *md); int (*check_banned)(aClient *cptr); +int (*check_deny_version)(aClient *cptr, char *version_string, int protocol, char *flags); static const EfunctionsList efunction_table[MAXEFUNCTIONS] = { /* 00 */ {NULL, NULL}, @@ -168,7 +169,8 @@ static const EfunctionsList efunction_table[MAXEFUNCTIONS] = { /* 41 */ {"send_md_membership", (void *)&send_md_membership}, /* 42 */ {"check_banned", (void *)&check_banned}, /* 43 */ {"introduce_user", (void *)&introduce_user}, -/* 44 */ {NULL, NULL} +/* 44 */ {"check_deny_version", (void *)&check_deny_version}, +/* 45 */ {NULL, NULL} }; #ifdef UNDERSCORE diff --git a/src/modules/m_protoctl.c b/src/modules/m_protoctl.c index d890bdd44..fe2f5aff1 100644 --- a/src/modules/m_protoctl.c +++ b/src/modules/m_protoctl.c @@ -301,35 +301,25 @@ CMD_FUNC(m_protoctl) } else if ((strncmp(s, "EAUTH=", 6) == 0) && NEW_LINKING_PROTOCOL) { - /* Early authorization: EAUTH=servername[,options] */ + /* Early authorization: EAUTH=servername,protocol,flags,versiontext + * (Only servername is mandatory, rest is optional) + */ int ret; - int protocol = 0; - char *servername = s+6, *p; + char *p; + char *servername = NULL, *protocol = NULL, *flags = NULL, *versiontext = NULL; + char buf[512]; ConfigItem_link *aconf = NULL; - - if (strlen(servername) > HOSTLEN) - servername[HOSTLEN] = '\0'; - for (p = servername; *p; p ++) + strlcpy(buf, s+6, sizeof(buf)); + p = strchr(buf, ' '); + if (p) { - if (*p == ',') - { - char *x; - - *p = '\0'; - - /* upwards compatible */ - x = strchr(p+1, ','); - if (x) - *x = '\0'; - protocol = atoi(p+1); - break; - } - if (*p <= ' ' || *p > '~') - break; + *p = '\0'; + p = NULL; } - - if (*p || !index(servername, '.')) + + servername = strtoken(&p, buf, ","); + if (!servername || (strlen(servername) > HOSTLEN) || !index(servername, '.')) { sendto_one(sptr, "ERROR :Bogus server name in EAUTH (%s)", servername); sendto_snomask @@ -339,14 +329,31 @@ CMD_FUNC(m_protoctl) return exit_client(cptr, sptr, &me, "Bogus server name"); } + + + protocol = strtoken(&p, NULL, ","); + if (protocol) + { + flags = strtoken(&p, NULL, ","); + if (flags) + { + versiontext = strtoken(&p, NULL, ","); + } + } + + ret = verify_link(cptr, sptr, servername, &aconf); + if (ret < 0) + return ret; /* FLUSH_BUFFER */ - ret = verify_link(cptr, sptr, s+6, &aconf); + /* note: versiontext, protocol and flags may be NULL */ + ret = check_deny_version(sptr, versiontext, protocol ? atoi(protocol) : 0, flags); if (ret < 0) return ret; /* FLUSH_BUFFER */ SetEAuth(cptr); make_server(cptr); /* allocate and set cptr->serv */ - cptr->serv->features.protocol = protocol; + if (protocol) + cptr->serv->features.protocol = atoi(protocol); if (!IsHandshake(cptr) && aconf) /* Send PASS early... */ sendto_one(sptr, "PASS :%s", (aconf->auth->type == AUTHTYPE_PLAINTEXT) ? aconf->auth->data : "*"); } diff --git a/src/modules/m_server.c b/src/modules/m_server.c index 663e9a49f..63991b1b8 100644 --- a/src/modules/m_server.c +++ b/src/modules/m_server.c @@ -48,6 +48,7 @@ int _verify_link(aClient *cptr, aClient *sptr, char *servername, ConfigItem_link void _send_protoctl_servers(aClient *sptr, int response); void _send_server_message(aClient *sptr); void _introduce_user(aClient *to, aClient *acptr); +int _check_deny_version(aClient *cptr, char *version_string, int protocol, char *flags); static char buf[BUFSIZE]; @@ -70,6 +71,7 @@ MOD_TEST(m_server) EfunctionAddVoid(modinfo->handle, EFUNC_SEND_SERVER_MESSAGE, _send_server_message); EfunctionAdd(modinfo->handle, EFUNC_VERIFY_LINK, _verify_link); EfunctionAddVoid(modinfo->handle, EFUNC_INTRODUCE_USER, _introduce_user); + EfunctionAdd(modinfo->handle, EFUNC_CHECK_DENY_VERSION, _check_deny_version); return MOD_SUCCESS; } @@ -95,6 +97,87 @@ MOD_UNLOAD(m_server) int m_server_synch(aClient *cptr, ConfigItem_link *conf); +/** Check deny version { } blocks. + * NOTE: cptr will always be valid, but all the other values may be NULL or 0 !!! + */ +int _check_deny_version(aClient *cptr, char *version_string, int protocol, char *flags) +{ + ConfigItem_deny_version *vlines; + + for (vlines = conf_deny_version; vlines; vlines = (ConfigItem_deny_version *) vlines->next) + { + if (!match(vlines->mask, cptr->name)) + break; + } + + if (vlines) + { + char *proto = vlines->version; + char *vflags = vlines->flags; + int result = 0, i; + switch (*proto) + { + case '<': + proto++; + if (protocol < atoi(proto)) + result = 1; + break; + case '>': + proto++; + if (protocol > atoi(proto)) + result = 1; + break; + case '=': + proto++; + if (protocol == atoi(proto)) + result = 1; + break; + case '!': + proto++; + if (protocol != atoi(proto)) + result = 1; + break; + default: + if (protocol == atoi(proto)) + result = 1; + break; + } + if (protocol == 0 || *proto == '*') + result = 0; + + if (result) + return exit_client(cptr, cptr, cptr, "Denied by deny version { } block"); + + if (flags) + { + for (i = 0; vflags[i]; i++) + { + if (vflags[i] == '!') + { + i++; + if (strchr(flags, vflags[i])) { + result = 1; + break; + } + } + else if (!strchr(flags, vflags[i])) + { + result = 1; + break; + } + } + + if (*vflags == '*' || !strcmp(flags, "0")) + result = 0; + } + + if (result) + return exit_client(cptr, cptr, cptr, "Denied by deny version { } block"); + } + + return 0; +} + /** Send our PROTOCTL SERVERS=x,x,x,x stuff. * When response is set, it will be PROTOCTL SERVERS=*x,x,x (mind the asterisk). */ @@ -106,8 +189,10 @@ void _send_protoctl_servers(aClient *sptr, int response) if (!NEW_LINKING_PROTOCOL) return; - ircsnprintf(buf, sizeof(buf), "PROTOCTL EAUTH=%s,%d SERVERS=%s", - me.name, UnrealProtocol, response ? "*" : ""); + sendto_one(sptr, "PROTOCTL EAUTH=%s,%d,%s%s,%s", + me.name, UnrealProtocol, serveropts, extraflags ? extraflags : "", version); + + ircsnprintf(buf, sizeof(buf), "PROTOCTL SERVERS=%s", response ? "*" : ""); list_for_each_entry(acptr, &global_server_list, client_node) { @@ -126,7 +211,7 @@ void _send_protoctl_servers(aClient *sptr, int response) void _send_server_message(aClient *sptr) { - if (sptr->serv->flags.server_sent) + if (sptr->serv && sptr->serv->flags.server_sent) { #ifdef DEBUGMODE abort(); @@ -134,9 +219,17 @@ void _send_server_message(aClient *sptr) return; } - sendto_one(sptr, "SERVER %s 1 :%s", - me.name, me.info); - sptr->serv->flags.server_sent = 1; + if (1) /* SupportVL(sptr)) -- always send like 3.2.x for now. */ + { + sendto_one(sptr, "SERVER %s 1 :U%d-%s %s", + me.name, UnrealProtocol, serveropts, me.info); + } else { + sendto_one(sptr, "SERVER %s 1 :%s", + me.name, me.info); + } + + if (sptr->serv) + sptr->serv->flags.server_sent = 1; } @@ -391,7 +484,6 @@ CMD_FUNC(m_server) /* we also have a fail safe incase they say they are sending * VL stuff and don't -- codemastr */ - ConfigItem_deny_version *vlines; inf = NULL; protocol = NULL; flags = NULL; @@ -403,83 +495,24 @@ CMD_FUNC(m_server) num = (char *)strtok((char *)NULL, " "); if (num) inf = (char *)strtok((char *)NULL, ""); - if (inf) { - strlcpy(cptr->info, inf[0] ? inf : me.name, - sizeof(cptr->info)); - - for (vlines = conf_deny_version; vlines; vlines = (ConfigItem_deny_version *) vlines->next) { - if (!match(vlines->mask, cptr->name)) - break; - } - if (vlines) { - char *proto = vlines->version; - char *vflags = vlines->flags; - int version, result = 0, i; - protocol++; - version = atoi(protocol); - switch (*proto) { - case '<': - proto++; - if (version < atoi(proto)) - result = 1; - break; - case '>': - proto++; - if (version > atoi(proto)) - result = 1; - break; - case '=': - proto++; - if (version == atoi(proto)) - result = 1; - break; - case '!': - proto++; - if (version != atoi(proto)) - result = 1; - break; - default: - if (version == atoi(proto)) - result = 1; - break; - } - if (version == 0 || *proto == '*') - result = 0; - - if (result) - return exit_client(cptr, cptr, cptr, - "Denied by V:line"); - - for (i = 0; vflags[i]; i++) { - if (vflags[i] == '!') { - i++; - if (strchr(flags, vflags[i])) { - result = 1; - break; - } - } - else if (!strchr(flags, vflags[i])) { - result = 1; - break; - } - } - if (*vflags == '*' || !strcmp(flags, "0")) - result = 0; - if (result) - return exit_client(cptr, cptr, cptr, - "Denied by V:line"); - } + if (inf) + { + int ret; + + strlcpy(cptr->info, inf[0] ? inf : me.name, sizeof(cptr->info)); /* set real description */ + + ret = _check_deny_version(cptr, NULL, atoi(protocol), flags); + if (ret < 0) + return ret; + } else { + strlcpy(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); } - else - strlcpy(cptr->info, info[0] ? info : me.name, - sizeof(cptr->info)); - + } else { + strlcpy(cptr->info, info[0] ? info : me.name, sizeof(cptr->info)); } - else - strlcpy(cptr->info, info[0] ? info : me.name, - sizeof(cptr->info)); - for (deny = conf_deny_link; deny; deny = (ConfigItem_deny_link *) deny->next) { + for (deny = conf_deny_link; deny; deny = (ConfigItem_deny_link *) deny->next) + { if (deny->flag.type == CRULE_ALL && !match(deny->mask, servername) && crule_eval(deny->rule)) { sendto_ops("Refused connection from %s.", @@ -686,8 +719,7 @@ int m_server_synch(aClient *cptr, ConfigItem_link *aconf) sendto_one(cptr, "PASS :%s", (aconf->auth->type == AUTHTYPE_PLAINTEXT) ? aconf->auth->data : "*"); send_proto(cptr, aconf); - sendto_one(cptr, "SERVER %s 1 :%s", - me.name, me.info); + send_server_message(cptr); } /* Set up server structure */