From 2c7a3f2e6646e18d85e8260eb1950a93f339f855 Mon Sep 17 00:00:00 2001 From: aquanight Date: Sun, 13 May 2007 23:09:24 +0000 Subject: [PATCH] Chained extbans support. --- Changes | 19 ++++++++ Config | 34 ++++++++++++++ configure | 11 +++++ include/h.h | 5 ++ include/setup.h.in | 3 ++ src/channel.c | 53 ++++++++++++++++++++- src/extbans.c | 113 ++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 236 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 65170ce08..642276034 100644 --- a/Changes +++ b/Changes @@ -1669,3 +1669,22 @@ MOTDs - Removed class.h and minor references to aClass. Patched by WolfSage - Changed all references to 'class' to 'cclass' (connection class) - to avoid some keyword confusion and other wacky ideas +- Added support for "chained" extbans. Put simply this allows extban combinations + such as ~q:~c:#test to only silence users on #test, for example. This feature + is enabled by default, but can be disabled during ./Config -advanced. Module + support for this feature must note the following: + - For is_ok function, the extban can either assign extban_is_ok_nuh_extban, which + will deal checking a chained extban (including checking for restricted extbans), + or it can call that function from its own is_ok routine. For the latter case, + remember to pass only the mask part of your ban format (ie, don't just pass para as + otherwise it'll just call your is_ok again). + - For conv_param function, the extban can either assign extban_conv_param_nuh_or_extban, + which will automatically call conv_param for a chained extban, or pretty up a n!u@h mask. + - For is_banned, the extban should call ban_check_mask with the mask part of the parameter. + This will automatically call is_banned for a stacked extban, or match against a n!u@h. n!u@h + is checked against the current user (ie, with the info in the globals ban_ip, etc), so things + can get weird if you call this outside a normal ban check. + Modules must keep in mind that chained extban support is not available (and neither are the three + functions above) if DISABLE_STACKED_EXTBANS is #defined (this is controled by Config). Modules will + not compile/load if they try to use them anyway. + This change should not break extban modules, and should need some more extensive testing. diff --git a/Config b/Config index 125750377..93d78e72e 100755 --- a/Config +++ b/Config @@ -41,6 +41,9 @@ fi if [ "$OPEROVERRIDEVERIFY" = "1" ] ; then ARG="$ARG--with-operoverride-verify " fi +if [ "$DISABLEEXTBANSTACKING" = "1" ]; then + ARG="$ARG--with-disable-extendedban-stacking "; +fi fi if [ "$NOSPOOF" = "1" ] ; then ARG="$ARG--enable-nospoof " @@ -274,6 +277,35 @@ while [ -z "$TEST" ] ; do esac done +TEST="" +while [ -z "$TEST" ] ; do + if [ "$DISABLEEXTBANSTACKING" = "1" ] ; then + TEST="Yes" + else + TEST="No" + fi + echo "" + echo "Do you want to disable extended ban stacking (~q:~c:#test, etc) support?" + echo $n "[$TEST] -> $c" + read cc + if [ -z "$cc" ] ; then + cc=$TEST + fi + case "$cc" in + [Yy]*) + DISABLEEXTBANSTACKING="1" + ;; + [Nn]*) + DISABLEEXTBANSTACKING="0" + ;; + *) + echo "" + echo "You must enter either Yes or No" + TEST="" + ;; + esac +done + } c="" n="" @@ -302,6 +334,7 @@ SHUNNOTICES="" NOOPEROVERRIDE="" DISABLEUSERMOD="" OPEROVERRIDEVERIFY="" +DISABLEEXTBANSTACKING="" EXTRAPARA="" if [ "`eval echo -n 'a'`" = "-n a" ] ; then c="\c" @@ -838,6 +871,7 @@ SHUNNOTICES="$SHUNNOTICES" NOOPEROVERRIDE="$NOOPEROVERRIDE" DISABLEUSERMOD="$DISABLEUSERMOD" OPEROVERRIDEVERIFY="$OPEROVERRIDEVERIFY" +DISABLEEXTBANSTACKING="$DISABLEEXTBANSTACKING" EXTRAPARA="$EXTRAPARA" ADVANCED="$ADVANCED" __EOF__ diff --git a/configure b/configure index f62686076..b7da1dd0f 100755 --- a/configure +++ b/configure @@ -874,6 +874,8 @@ Optional Packages: --with-disableusermod Disable /set* and /chg* --with-operoverride-verify Require opers to invite themselves to +s/+p channels + --with-disable-extendedban-stacking + Disable extended ban stacking (~q:~c:#chan) support Some influential environment variables: CC C compiler command @@ -12025,6 +12027,15 @@ _ACEOF fi; +# Check whether --with-disable-extendedban-stacking or --without-disable-extendedban-stacking was given. +if test "${with_disable_extendedban_stacking+set}" = set; then + withval="$with_disable_extendedban_stacking" + cat >>confdefs.h <<\_ACEOF +#define DISABLE_STACKED_EXTBANS 1 +_ACEOF + +fi; + # Check whether --enable-ssl or --disable-ssl was given. if test "${enable_ssl+set}" = set; then enableval="$enable_ssl" diff --git a/include/h.h b/include/h.h index 240cb8d02..63f86a1e4 100644 --- a/include/h.h +++ b/include/h.h @@ -186,6 +186,11 @@ extern long get_access(aClient *, aChannel *); extern int is_chan_op(aClient *, aChannel *); extern int has_voice(aClient *, aChannel *); extern int is_chanowner(aClient *, aChannel *); +#ifndef DISABLE_EXTBAN_STACKING +extern int ban_check_mask(aClient *, aChannel *, char *, int, int); +extern int extban_is_ok_nuh_extban(aClient *, aChannel *, char *, int, int, int); +extern char* extban_conv_param_nuh_extban(char *); +#endif extern Ban *is_banned(aClient *, aChannel *, int); extern Ban *is_banned_with_nick(aClient *, aChannel *, int, char *); extern int parse_help(aClient *, char *, char *); diff --git a/include/setup.h.in b/include/setup.h.in index 78c843390..9f9837c9f 100644 --- a/include/setup.h.in +++ b/include/setup.h.in @@ -240,6 +240,9 @@ /* Define if you want to disable /set* and /chg* */ #undef DISABLE_USERMOD +/* Define to disable extended ban stacking (~q:~c:#chan, etc) */ +#undef DISABLE_STACKED_EXTBANS + /* Define if your system prepends an underscore to symbols */ #undef UNDERSCORE diff --git a/src/channel.c b/src/channel.c index 06fc75198..234cc7432 100644 --- a/src/channel.c +++ b/src/channel.c @@ -447,6 +447,46 @@ inline Ban *is_banned(aClient *sptr, aChannel *chptr, int type) return is_banned_with_nick(sptr, chptr, type, sptr->name); } +#ifndef DISABLE_STACKED_EXTBANS +/** ban_check_mask - Checks if the current user in ban checking (ban_ip, etc) matches the specified n!u@h mask -or- run an extended ban. + * @param sptr Client to check (can be remote client) + * @param chptr Channel to check + * @param banstr Mask string to check user + * @param type Type of ban to check for (BANCHK_*) + * @param no_extbans 0 to check extbans, nonzero to disable extban checking. + * @returns Nonzero if the mask/extban succeeds. Zero if it doesn't. + * @comments This is basically extracting the mask and extban check from is_banned_with_nick, but with being a bit more strict in what an extban is. + * Strange things could happen if this is called outside standard ban checking. + */ +inline int ban_check_mask(aClient* sptr, aChannel* chptr, char* banstr, int type, int no_extbans) +{ + Extban *extban = NULL; + if (!no_extbans && banstr[0] == '~' && banstr[1] != '\0' && banstr[2] == ':') + { + /* Is an extended ban. */ + extban = findmod_by_bantype(banstr[1]); + if (!extban) + { + return 0; + } + else + { + return extban->is_banned(sptr, chptr, banstr, type); + } + } + else + { + /* Is a n!u@h mask. */ + return ( + (match(banstr, ban_realhost) == 0) || /* nick!user@realhost */ + (!BadPtr(ban_virthost) && (match(banstr, ban_virthost) == 0)) || /* nick!user@virthost - if he's been sethost/chghost/vhost */ + (!BadPtr(ban_ip) && (match(banstr, ban_ip) == 0)) || /* nick!user@IP (1.2.3.4, 1234:5678::90AB:CDEF, ::ffff:1.2.3.4, etc) */ + (!BadPtr(ban_cloakhost) && (match(banstr, ban_cloakhost) == 0)) /* nick!user@cloakhost - if +x */ + ); + } +} +#endif + /** is_banned_with_nick - Check if a user is banned on a channel. * @param sptr Client to check (can be remote client) * @param chptr Channel to check @@ -470,7 +510,8 @@ Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick) ban_realhost = realhost; ban_ip = ban_virthost = ban_cloakhost = NULL; - + + /* Might it be possible in the future to include the possiblity for SupportNICKIP(sptr->from), SupportCLK(sptr->from)? -- aquanight */ if (MyConnect(sptr)) { mine = 1; @@ -495,6 +536,7 @@ Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick) */ for (tmp = chptr->banlist; tmp; tmp = tmp->next) { +#ifdef DISABLE_STACKED_EXTBANS if (*tmp->banstr == '~') { extban = findmod_by_bantype(tmp->banstr[1]); @@ -512,10 +554,15 @@ Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick) } else continue; } +#else + if (!ban_check_mask(sptr, chptr, tmp->banstr, type, 0)) + continue; +#endif /* Ban found, now check for +e */ for (tmp2 = chptr->exlist; tmp2; tmp2 = tmp2->next) { +#ifdef DISABLE_STACKED_EXTBANS if (*tmp2->banstr == '~') { extban = findmod_by_bantype(tmp2->banstr[1]); @@ -530,6 +577,10 @@ Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick) (mine && (match(tmp2->banstr, cloakhost) == 0)) ) return NULL; } +#else + if (!ban_check_mask(sptr, chptr, tmp2->banstr, type, 0)) + return NULL; +#endif } break; /* ban found and not on except */ } diff --git a/src/extbans.c b/src/extbans.c index 57ab770e6..6ca587951 100644 --- a/src/extbans.c +++ b/src/extbans.c @@ -251,7 +251,11 @@ char *ban = banin + 3; if (type != BANCHK_MSG) return 0; +#ifdef DISABLE_STACKED_EXTBANS return extban_is_banned_helper(ban); +#else + return ban_check_mask(sptr, chptr, ban, type, 0); +#endif } int extban_moden_is_banned(aClient *sptr, aChannel *chptr, char *banin, int type) @@ -263,8 +267,12 @@ char *ban = banin + 3; if (has_voice(sptr, chptr)) return 0; - + +#ifdef DISABLE_STACKED_EXTBANS return extban_is_banned_helper(ban); +#else + return ban_check_mask(sptr, chptr, ban, type, 0); +#endif } int extban_modej_is_banned(aClient* sptr, aChannel* chptr, char* banin, int type) @@ -274,9 +282,52 @@ char* ban = banin + 3; if (type != BANCHK_JOIN) return 0; +#ifdef DISABLE_STACKED_EXTBANS return extban_is_banned_helper(ban); +#else + return ban_check_mask(sptr, chptr, ban, type, 0); +#endif } +#ifndef DISABLE_STACKED_EXTBANS +/** General is_ok for n!u@h stuff that also deals with recursive extbans. + */ +int extban_is_ok_nuh_extban(aClient* sptr, aChannel* chptr, char* para, int checkt, int what, int what2) +{ + char* mask = (para + 3); + Extban* p = NULL; + + /* Mostly copied from clean_ban_mask - but note MyClient checks aren't needed here: extban->is_ok() according to m_mode isn't called for nonlocal. */ + if ((*mask == '~') && mask[1] && (mask[2] == ':')) + { + /* We can be sure RESTRICT_EXTENDEDBANS is not *. Else this extended ban wouldn't be happening at all. */ + if (what == EXBCHK_PARAM && RESTRICT_EXTENDEDBANS && !IsAnOper(sptr)) + { + if (strchr(RESTRICT_EXTENDEDBANS, mask[1])) + { + sendnotice(sptr, "Setting/removing of extended bantypes '%s' has been disabled.", RESTRICT_EXTENDEDBANS); + return 0; /* Fail */ + } + } + p = findmod_by_bantype(mask[1]); + if (!p) + { + if (what == MODE_DEL) + { + return 1; /* Always allow killing unknowns. */ + } + return 0; /* Don't add unknown extbans. */ + } + /* Now we have to ask the stacked extban if it's ok. */ + if (p->is_ok) + { + return p->is_ok(sptr, chptr, mask, checkt, what, what2); + } + } + return 1; /* Either not an extban, or extban has NULL is_ok. Good to go. */ +} +#endif + /** Some kind of general conv_param routine, * to ensure the parameter is nick!user@host. * most of the code is just copied from clean_ban_mask. @@ -311,6 +362,51 @@ char pfix[8]; return retbuf; } +#ifndef DISABLE_STACKED_EXTBANS +/** conv_param to deal with stacked extbans. + */ +char* extban_conv_param_nuh_or_extban(char* para) +{ +static char retbuf[USERLEN + NICKLEN + HOSTLEN + 32]; + char* mask; + char tmpbuf[USERLEN + NICKLEN + HOSTLEN + 32]; + char bantype = para[1]; + char* ret = NULL; + Extban* p = NULL; + + if (para[3] == '~' && para[4] && para[5] == ':') + { + strncpyzt(tmpbuf, para, sizeof(tmpbuf)); + mask = tmpbuf + 3; + /* Already did restrict-extended bans check. */ + p = findmod_by_bantype(mask[1]); + if (!p) + { + /* Handling unknown bantypes in is_ok. Assume that it's ok here. */ + return para; + } + if (p->conv_param) + { + if (ret = p->conv_param(mask)) + { + ircsprintf(retbuf, "~%c:%s", bantype, ret); /* Make sure our extban prefix sticks. */ + return retbuf; + } + else + { + return NULL; /* Fail. */ + } + } + /* I honestly don't know what the deal is with the 80 char cap in clean_ban_mask is about. So I'm leaving it out here. */ + return para; + } + else + { + return extban_conv_param_nuh(para); + } +} +#endif + /** Realname bans - conv_param */ char *extban_moder_conv_param(char *para) { @@ -345,19 +441,34 @@ void extban_init(void) memset(&req, 0, sizeof(ExtbanInfo)); req.flag = 'q'; +#ifdef DISABLE_STACKED_EXTBANS req.conv_param = extban_conv_param_nuh; +#else + req.is_ok = extban_is_ok_nuh_extban; + req.conv_param = extban_conv_param_nuh_or_extban; +#endif req.is_banned = extban_modeq_is_banned; ExtbanAdd(NULL, req); memset(&req, 0, sizeof(ExtbanInfo)); req.flag = 'n'; +#ifdef DISABLE_STACKED_EXTBANS req.conv_param = extban_conv_param_nuh; +#else + req.is_ok = extban_is_ok_nuh_extban; + req.conv_param = extban_conv_param_nuh_or_extban; +#endif req.is_banned = extban_moden_is_banned; ExtbanAdd(NULL, req); memset(&req, 0, sizeof(ExtbanInfo)); req.flag = 'j'; +#ifdef DISABLE_STACKED_EXTBANS req.conv_param = extban_conv_param_nuh; +#else + req.is_ok = extban_is_ok_nuh_extban; + req.conv_param = extban_conv_param_nuh_or_extban; +#endif req.is_banned = extban_modej_is_banned; ExtbanAdd(NULL, req);