/** 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; int isok; static int extban_is_ok_recursion = 0; /* 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] == ':')) { if (extban_is_ok_recursion) return 0; /* Fail: more than one stacked extban */ /* 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) { extban_is_ok_recursion++; isok = p->is_ok(sptr, chptr, mask, checkt, what, what2); extban_is_ok_recursion--; return isok; } } return 1; /* Either not an extban, or extban has NULL is_ok. Good to go. */ }
/** 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 extban_is_banned_helper(banstr); } }
/** 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 * @param type Type of ban to check for (BANCHK_*) * @param nick Nick of the user * @returns A pointer to the ban struct if banned, otherwise NULL. */ Ban *is_banned_with_nick(aClient *sptr, aChannel *chptr, int type, char *nick) { Ban *tmp, *tmp2; char *s; static char realhost[NICKLEN + USERLEN + HOSTLEN + 24]; static char cloakhost[NICKLEN + USERLEN + HOSTLEN + 24]; static char virthost[NICKLEN + USERLEN + HOSTLEN + 24]; static char nuip[NICKLEN + USERLEN + HOSTLEN + 24]; int dovirt = 0, mine = 0; Extban *extban; if (!IsPerson(sptr) || !chptr->banlist) return NULL; ban_realhost = realhost; ban_ip = ban_virthost = ban_cloakhost = NULL; if (MyConnect(sptr)) { mine = 1; make_nick_user_host_r(nuip, nick, sptr->user->username, GetIP(sptr)); ban_ip = nuip; make_nick_user_host_r(cloakhost, nick, sptr->user->username, sptr->user->cloakedhost); ban_cloakhost = cloakhost; } if (IsSetHost(sptr) && strcmp(sptr->user->realhost, sptr->user->virthost)) { dovirt = 1; make_nick_user_host_r(virthost, nick, sptr->user->username, sptr->user->virthost); ban_virthost = virthost; } make_nick_user_host_r(realhost, nick, sptr->user->username, sptr->user->realhost); /* We now check +b first, if a +b is found we then see if there is a +e. * If a +e was found we return NULL, if not, we return the ban. */ for (tmp = chptr->banlist; tmp; tmp = tmp->next) { if (*tmp->banstr == '~') { extban = findmod_by_bantype(tmp->banstr[1]); if (!extban) continue; if (!extban->is_banned(sptr, chptr, tmp->banstr, type)) continue; } else { if ((match(tmp->banstr, realhost) == 0) || (dovirt && (match(tmp->banstr, virthost) == 0)) || (mine && (match(tmp->banstr, nuip) == 0)) || (mine && (match(tmp->banstr, cloakhost) == 0)) ) { /* matches.. do nothing */ } else continue; } /* Ban found, now check for +e */ for (tmp2 = chptr->exlist; tmp2; tmp2 = tmp2->next) { if (*tmp2->banstr == '~') { extban = findmod_by_bantype(tmp2->banstr[1]); if (!extban) continue; if (extban->is_banned(sptr, chptr, tmp2->banstr, type)) return NULL; } else { if ((match(tmp2->banstr, realhost) == 0) || (dovirt && (match(tmp2->banstr, virthost) == 0)) || (mine && (match(tmp2->banstr, nuip) == 0)) || (mine && (match(tmp2->banstr, cloakhost) == 0)) ) return NULL; } } break; /* ban found and not on except */ } return (tmp); }
/* clean_ban_mask: makes a proper banmask * RETURNS: pointer to correct banmask or NULL in case of error * NOTES: * - A pointer is returned to a static buffer, which is overwritten * on next clean_ban_mask or make_nick_user_host call. * - mask is fragged in some cases, this could be bad. */ char *clean_ban_mask(char *mask, int what, aClient *cptr) { char *cp; char *user; char *host; Extban *p; cp = index(mask, ' '); if (cp) *cp = '\0'; /* Strip any ':' at beginning coz that desynchs clients/banlists */ for (; (*mask && (*mask == ':')); mask++); if (!*mask) return NULL; /* Extended ban? */ if ((*mask == '~') && mask[1] && (mask[2] == ':')) { if (RESTRICT_EXTENDEDBANS && MyClient(cptr) && !IsAnOper(cptr)) { if (!strcmp(RESTRICT_EXTENDEDBANS, "*")) { sendnotice(cptr, "Setting/removing of extended bans has been disabled"); return NULL; } if (strchr(RESTRICT_EXTENDEDBANS, mask[1])) { sendnotice(cptr, "Setting/removing of extended bantypes '%s' has been disabled", RESTRICT_EXTENDEDBANS); return NULL; } } p = findmod_by_bantype(mask[1]); if (!p) { /* extended bantype not supported, what to do? * Here are the rules: * - if from a remote client/server: allow it (easy upgrading, * no desynch) * - if from a local client trying to REMOVE the extban, * allow it too (so you don't get "unremovable" extbans). */ if (!MyClient(cptr) || (what == MODE_DEL)) return mask; /* allow it */ return NULL; /* reject */ } if (p->conv_param) return p->conv_param(mask); /* else, do some basic sanity checks and cut it off at 80 bytes */ if ((cp[1] != ':') || (cp[2] == '\0')) return NULL; /* require a ":<char>" after extban type */ if (strlen(mask) > 80) mask[80] = '\0'; return mask; } if ((*mask == '~') && !strchr(mask, '@')) return NULL; /* not an extended ban and not a ~user@host ban either. */ if ((user = index((cp = mask), '!'))) *user++ = '\0'; if ((host = rindex(user ? user : cp, '@'))) { *host++ = '\0'; if (!user) return make_nick_user_host(NULL, trim_str(cp,USERLEN), trim_str(host,HOSTLEN)); } else if (!user && index(cp, '.')) return make_nick_user_host(NULL, NULL, trim_str(cp,HOSTLEN)); return make_nick_user_host(trim_str(cp,NICKLEN), trim_str(user,USERLEN), trim_str(host,HOSTLEN)); }
/** conv_param to deal with stacked extbans. */ char* extban_conv_param_nuh_or_extban(char* para) { #if (USERLEN + NICKLEN + HOSTLEN + 32) > 256 #error "wtf?" #endif static char retbuf[256]; static char printbuf[256]; char *mask; char tmpbuf[USERLEN + NICKLEN + HOSTLEN + 32]; char bantype = para[1]; char *ret = NULL; Extban *p = NULL; static int extban_recursion = 0; if (para[3] == '~' && para[4] && para[5] == ':') { /* We're dealing with a stacked extended ban. * Rules: * 1) You can only stack once, so: ~x:~y:something and not ~x:~y:~z... * 2) The first item must be an action modifier, such as ~q/~n/~j * 3) The second item may never be an action modifier, nor have the * EXTBOPT_NOSTACKCHILD flag set (for things like a textban). */ /* Rule #1. Yes the recursion check is also in extban_is_ok_nuh_extban, * but it's possible to get here without the is_ok() function ever * being called (think: non-local client). And no, don't delete it * there either. It needs to be in BOTH places. -- Syzop */ if (extban_recursion) return NULL; /* Rule #2 */ p = findmod_by_bantype(para[1]); if (p && !(p->options & EXTBOPT_ACTMODIFIER)) { /* Rule #2 violation */ return NULL; } 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->options & EXTBOPT_ACTMODIFIER) || (p->options & EXTBOPT_NOSTACKCHILD)) { /* Rule #3 violation */ return NULL; } if (p->conv_param) { extban_recursion++; ret = p->conv_param(mask); extban_recursion--; if (ret) { /* * If bans are stacked, then we have to use two buffers * to prevent ircsprintf() from going into a loop. */ ircsprintf(printbuf, "~%c:%s", bantype, ret); /* Make sure our extban prefix sticks. */ memcpy(retbuf, printbuf, sizeof(retbuf)); 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. -- aquanight */ /* I don't know why it's 80, but I like a limit anyway. A ban of 500 characters can never be good... -- Syzop */ if (strlen(para) > 80) { strlcpy(retbuf, para, 128); return retbuf; } return para; } else { return extban_conv_param_nuh(para); } }