From: Chris Porter Date: Sat, 20 Feb 2010 19:21:28 +0000 (+0000) Subject: Merge. X-Git-Url: https://jfr.im/git/irc/quakenet/newserv.git/commitdiff_plain/6a7c5b7fc2ab7fa46c8d0fade5cfa9dc7f4077e1?hp=7a91c1d0c9a2be9d1a0bbee6e289d86f656af751 Merge. --- diff --git a/bans/bans.c b/bans/bans.c index 13730863..65b5db9f 100644 --- a/bans/bans.c +++ b/bans/bans.c @@ -69,10 +69,7 @@ void freechanban(chanban *cbp) { chanban *makeban(const char *mask) { int len; int foundat=-1,foundbang=-1; - int dotcount=0; - int notip=0; int foundwild=0; - int foundslash=0; int i; int checklen; chanban *cbp; @@ -112,38 +109,15 @@ chanban *makeban(const char *mask) { /* Special case: "@*" */ cbp->flags |= CHANBAN_HOSTANY; cbp->host=NULL; - } else if (foundslash) { - /* If we found a slash (/), this can only be a CIDR ban */ - /* However, it might be broken, so we need to retain the exact string - * to track it accurately */ - cbp->host=getsstring(&mask[i+1],HOSTLEN); - if ((notip || dotcount!=3) && !foundwild) { - cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTEXACT); - } else if (foundwild) { - cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTMASK); - } else { - unsigned int a,b,c,d,l; - /* CIDR bans have to match this pattern. */ - if ((sscanf(&mask[i+1], "%u.%u.%u.%u/%u",&a,&b,&c,&d,&l) != 5) || - (a>255) || (b>255) || (c>255) || (d>255) || (l>32) ) { - cbp->flags |= (CHANBAN_HOSTEXACT | CHANBAN_INVALID); - } else { - /* Save the IP address and mask for later */ - cbp->ipaddr=(a<<24)|(b<<16)|(c<<8)|d; - cbp->mask=0xffffffff; - if (l==0) { - cbp->mask=0; - } else if (l<32) { - cbp->mask<<=(32-l); - } - /* pre-AND the IP with the mask here. */ - cbp->ipaddr &= cbp->mask; - cbp->flags |= (CHANBAN_HOSTEXACT | CHANBAN_CIDR); - } - } } else { /* We have some string with between 1 and HOSTLEN characters.. */ cbp->host=getsstring(&mask[i+1],HOSTLEN); + + /* If it matches an IP address, flag it as such */ + if (ipmask_parse(cbp->host->content, &(cbp->ipaddr), &(cbp->prefixlen))) { + cbp->flags |= CHANBAN_IP; + } + if (foundwild) { /* We check all characters after the last wildcard (if any).. if they match * the corresponding bits of the hidden host string we mark it accordingly */ @@ -160,38 +134,20 @@ chanban *makeban(const char *mask) { } } cbp->flags |= CHANBAN_HOSTMASK; - if (!notip && dotcount<=3) - cbp->flags |= CHANBAN_IP; } else { /* Exact host: see if it ends with the "hidden host" string */ cbp->flags |= CHANBAN_HOSTEXACT; if ((cbp->host->length > (strlen(HIS_HIDDENHOST)+1)) && !ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST)) { cbp->flags |= CHANBAN_HIDDENHOST; - } else if (!notip && dotcount==3) { - unsigned int a,b,c,d; - if ((sscanf(&mask[i+1], "%u.%u.%u.%u",&a,&b,&c,&d) != 4) || - (a > 255) || (b > 255) || (c > 255) || (d > 255) ) { - /* Something with only numbers and exactly 3 dots that isn't an IP address can't match anything. */ - cbp->flags |= CHANBAN_INVALID; - } else { - cbp->ipaddr=(a<<24)|(b<<16)|(c<<8)|d; - cbp->flags |= CHANBAN_IP; - } } } } foundat=i; break; - } else if (mask[i]=='/') { - foundslash=1; - } else if (mask[i]=='.') { - dotcount++; } else if (mask[i]=='?' || mask[i]=='*') { if (!foundwild) /* Mark last wildcard in string */ foundwild=i; - } else if (mask[i]<'0' || mask[i]>'9') { - notip=1; } } diff --git a/bans/bans.h b/bans/bans.h index 1336e60e..3ae1ff1a 100644 --- a/bans/bans.h +++ b/bans/bans.h @@ -3,6 +3,7 @@ #include "../lib/flags.h" #include "../lib/sstring.h" +#include "../lib/irc_ipv6.h" #include #define CHANBAN_NICKEXACT 0x0001 /* Ban includes an exact nick (no wildcards) */ @@ -29,8 +30,8 @@ typedef struct chanban { sstring *user; sstring *host; time_t timeset; - unsigned int ipaddr; - unsigned int mask; + struct irc_in_addr ipaddr; + unsigned char prefixlen; struct chanban *next; } chanban; diff --git a/channel/channel.h b/channel/channel.h index cc4d1656..6c5da84a 100644 --- a/channel/channel.h +++ b/channel/channel.h @@ -167,10 +167,8 @@ void freechanuserhash(chanuserhash *cuhp); int setban(channel *cp, const char *ban); int clearban(channel *cp, const char *ban, int optional); void clearallbans(channel *cp); -int nickmatchban(nick *np, chanban *bp); -int nickbanned(nick *np, channel *cp); -int nickmatchban_visible(nick *np, chanban *bp); -int nickbanned_visible(nick *np, channel *cp); +int nickmatchban(nick *np, chanban *bp, int visibleonly); +int nickbanned(nick *np, channel *cp, int visibleonly); /* functions from channelindex.c */ void initchannelindex(); diff --git a/channel/channelbans.c b/channel/channelbans.c index 57af8bbf..fc86bc76 100644 --- a/channel/channelbans.c +++ b/channel/channelbans.c @@ -9,44 +9,45 @@ #include "../lib/irc_string.h" #include "../irc/irc_config.h" #include "../irc/irc.h" +#include "../lib/irc_ipv6.h" /* - * nickmatchban_visible: + * nickmatchban: * Returns true iff the supplied nick* matches the supplied ban* - * Doesn't check "invisible" things like true hosts and IPs for - * +x/+h users. * - * copy & pasted this, touch and go whether this was a good idea. + * "visibleonly" flag indicates that we shouldn't check against the real + * host if it's masked. */ -int nickmatchban_visible(nick *np, chanban *bp) { - const char *ipstring; +int nickmatchban(nick *np, chanban *bp, int visibleonly) { char fakehost[HOSTLEN+1]; - char *visibleident; + char *ident; - /* Don't waste time on invalid bans */ + /* If it's not valid, don't bother */ if (bp->flags & CHANBAN_INVALID) return 0; /* nick/ident section: return 0 (no match) if they don't match */ - /* Determine the visible ident for sethost users. Don't test the real one. */ - if (IsSetHost(np) && np->shident && *np->shident->content) - visibleident=np->shident->content; - else - visibleident=np->ident; + /* Pick up the visible username. If a sethost username is set, the real + * username is not checked. */ + ident=np->ident; + if (IsSetHost(np) && np->shident) + ident=np->shident->content; - if (bp->flags & CHANBAN_USEREXACT && ircd_strcmp(visibleident,bp->user->content)) + if (bp->flags & CHANBAN_USEREXACT && + ircd_strcmp(ident,bp->user->content)) return 0; if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content)) return 0; - if (bp->flags & CHANBAN_USERMASK && !match2strings(bp->user->content,visibleident)) + if (bp->flags & CHANBAN_USERMASK && + !match2strings(bp->user->content,ident)) return 0; if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick)) - return 0; + return 0; /* host section. Return 1 (match) if they do match * Note that if user or ident was specified, they've already been checked @@ -54,210 +55,57 @@ int nickmatchban_visible(nick *np, chanban *bp) { if (bp->flags & CHANBAN_HOSTANY) return 1; - - if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) { - unsigned int cip; - unsigned char *ch; - - /* CIDR bans don't visibly match sethosted users */ - if (IsSetHost(np) || (IsAccount(np) && IsHideHost(np))) - return 0; - - /* CIDR bans don't match IPv6 hosts */ - if (!irc_in_addr_is_ipv4(&(np->p_ipaddr))) - return 0; - - /* Extract the client's IP address into a usable format */ - ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]); - cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]); - if ((cip & bp->mask) == bp->ipaddr) + /* "visibleonly" means don't check IP/realhost if they are sethosted/+x. + * We change this to mean "Don't check IP/realhost unconditionally" - by + * clearing it to 0 if the user isn't sethosted or +x. Simplifies logic + * later. */ + + if (!(IsSetHost(np) || (IsAccount(np) && IsHideHost(np)))) + visibleonly=0; + + if ((bp->flags & CHANBAN_IP) && !visibleonly) { + if (ipmask_check(&(np->ipnode->prefix->sin), &(bp->ipaddr), bp->prefixlen)) return 1; - - return 0; /* A CIDR ban won't match any other way */ } - if (bp->flags & CHANBAN_IP) { - /* IP bans don't match sethosted users */ - if (IsSetHost(np) || (IsAccount(np) && IsHideHost(np))) - return 0; - - if (bp->flags & CHANBAN_HOSTEXACT) { - /* If it's an exact IP ban we can compare it numerically */ - unsigned int cip; - unsigned char *ch; - - /* Well, it won't match if it's not an IPv4 host */ - if (!irc_in_addr_is_ipv4(&(np->p_ipaddr))) - return 0; - - /* Extract the client's IP address into a usable format */ - ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]); - cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]); + /* Hostname bans need to be checked against +x host, +h host (if set) + * and actual host. Note that the +x host is only generated (and checked) if it's + * possible for the ban to match a hidden host. And it's checked regardless + * of whether the user is actually +x. */ - if (cip==bp->ipaddr) - return 1; - } else { - /* It's not an exact IP ban so let's generate the string */ - ipstring=IPtostr(np->p_ipaddr); - - if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,ipstring)) - return 1; - } - } else { - /* Hostname bans need to be checked against +x host, +h host (if set) - * and actual host. Note that the +x host is only generated (and checked) if it's - * possible for the ban to match a hidden host.. */ + if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) { + sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST); + + if ((bp->flags & CHANBAN_HOSTEXACT) && + !ircd_strcmp(fakehost, bp->host->content)) + return 1; - if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) { - sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST); - - if ((bp->flags & CHANBAN_HOSTEXACT) && - !ircd_strcmp(fakehost, bp->host->content)) - return 1; - - if ((bp->flags & CHANBAN_HOSTMASK) && - match2strings(bp->host->content, fakehost)) - return 1; - } + if ((bp->flags & CHANBAN_HOSTMASK) && + match2strings(bp->host->content, fakehost)) + return 1; + } - if (IsSetHost(np)) { - if ((bp->flags & CHANBAN_HOSTEXACT) && + if (IsSetHost(np)) { + if ((bp->flags & CHANBAN_HOSTEXACT) && !ircd_strcmp(np->sethost->content, bp->host->content)) - return 1; + return 1; - if ((bp->flags & CHANBAN_HOSTMASK) && + if ((bp->flags & CHANBAN_HOSTMASK) && match2strings(bp->host->content, np->sethost->content)) - return 1; - } - - /* If the user is +h or +rx don't check their real host */ - if (IsSetHost(np) || (IsHideHost(np) && IsAccount(np))) - return 0; - - if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content)) - return 1; - - if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content)) return 1; } - return 0; -} - -/* - * nickmatchban: - * Returns true iff the supplied nick* matches the supplied ban* - */ - -int nickmatchban(nick *np, chanban *bp) { - const char *ipstring; - char fakehost[HOSTLEN+1]; - - /* nick/ident section: return 0 (no match) if they don't match */ - - if (bp->flags & CHANBAN_INVALID) - return 0; - - if (bp->flags & CHANBAN_USEREXACT && - ircd_strcmp(np->ident,bp->user->content) && - (!IsSetHost(np) || !np->shident || - ircd_strcmp(np->shident->content,bp->user->content))) - return 0; - - if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content)) - return 0; - - if (bp->flags & CHANBAN_USERMASK && - !match2strings(bp->user->content,np->ident) && - (!IsSetHost(np) || !np->shident || - !match2strings(bp->user->content, np->shident->content))) + /* If we are only checking visible host and the host is somehow masked, don't check + * against the real one. */ + if (visibleonly) return 0; - if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick)) - return 0; - - /* host section. Return 1 (match) if they do match - * Note that if user or ident was specified, they've already been checked - */ - - if (bp->flags & CHANBAN_HOSTANY) + if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content)) return 1; - - if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) { - unsigned int cip; - unsigned char *ch; - - /* CIDR bans don't match IPv6 hosts */ - if (!irc_in_addr_is_ipv4(&(np->p_ipaddr))) - return 0; - - /* Extract the client's IP address into a usable format */ - ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]); - cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]); - - if ((cip & bp->mask) == bp->ipaddr) - return 1; - - return 0; /* A CIDR ban won't match any other way */ - } - if (bp->flags & CHANBAN_IP) { - if (bp->flags & CHANBAN_HOSTEXACT) { - /* If it's an exact IP ban we can compare it numerically */ - unsigned int cip; - unsigned char *ch; - - /* Well, it won't match if it's not an IPv4 host */ - if (!irc_in_addr_is_ipv4(&(np->p_ipaddr))) - return 0; - - /* Extract the client's IP address into a usable format */ - ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]); - cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]); - - if (cip==bp->ipaddr) - return 1; - } else { - /* It's not an exact IP ban so let's generate the string */ - ipstring=IPtostr(np->p_ipaddr); - - if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,ipstring)) - return 1; - } - } else { - /* Hostname bans need to be checked against +x host, +h host (if set) - * and actual host. Note that the +x host is only generated (and checked) if it's - * possible for the ban to match a hidden host.. */ - - if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) { - sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST); - - if ((bp->flags & CHANBAN_HOSTEXACT) && - !ircd_strcmp(fakehost, bp->host->content)) - return 1; - - if ((bp->flags & CHANBAN_HOSTMASK) && - match2strings(bp->host->content, fakehost)) - return 1; - } - - if (IsSetHost(np)) { - if ((bp->flags & CHANBAN_HOSTEXACT) && - !ircd_strcmp(np->sethost->content, bp->host->content)) - return 1; - - if ((bp->flags & CHANBAN_HOSTMASK) && - match2strings(bp->host->content, np->sethost->content)) - return 1; - } - - if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content)) - return 1; - - if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content)) - return 1; - } + if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content)) + return 1; return 0; } @@ -266,27 +114,18 @@ int nickmatchban(nick *np, chanban *bp) { * nickbanned: * Returns true iff the supplied nick* is banned on the supplied chan* * - * Also nickbanned_visible - doesn't violate privacy by checking hidden - * hosts and idents. Factored into one function to reduce copy&paste. + * Pass the visibleonly flag on to nickbanned(). */ -static int nickbanned_real(nick *np, channel *cp, int (*cmpfunc)(nick *, chanban *)) { +int nickbanned(nick *np, channel *cp, int visibleonly) { chanban *cbp; for (cbp=cp->bans;cbp;cbp=cbp->next) { - if (cmpfunc(np,cbp)) + if (nickmatchban(np,cbp,visibleonly)) return 1; } return 0; } - -int nickbanned(nick *np, channel *cp) { - return nickbanned_real(np,cp,nickmatchban); -} - -int nickbanned_visible(nick *np, channel *cp) { - return nickbanned_real(np,cp,nickmatchban_visible); -} /* * setban: diff --git a/chanserv/authcmds/authhistory.c b/chanserv/authcmds/authhistory.c index 3621657d..ac3f8fd9 100644 --- a/chanserv/authcmds/authhistory.c +++ b/chanserv/authcmds/authhistory.c @@ -114,15 +114,28 @@ int csa_doauthhistory(void *source, int cargc, char **cargv) { if (!(trup=findreguser(sender, cargv[0]))) return CMD_ERROR; - /* don't allow non-opers to view oper auth history, but allow helpers to view non-oper history */ - if ((trup != rup) && ((UHasOperPriv(trup) && !UHasOperPriv(rup)) || !UHasHelperPriv(rup))) { - chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[0]); - return CMD_ERROR; + /* if target != command issuer */ + if (trup != rup) { + /* only opers and helpers can view authhistory of other users */ + if (!UHasHelperPriv(rup)) { + chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[0]); + return CMD_ERROR; + } + + /* and only opers can view opers history */ + if (UHasOperPriv(trup) && !UHasOperPriv(rup)) { + chanservwallmessage("%s (%s) just FAILED using AUTHHISTORY on %s", sender->nick, rup->username, trup->username); + chanservstdmessage(sender, QM_NOACCESSONUSER, "authhistory", cargv[0]); + return CMD_ERROR; + } + + /* checks passed */ + + chanservwallmessage("%s (%s) used AUTHHISTORY on %s", sender->nick, rup->username, trup->username); } } else { trup=rup; } - csdb_retreiveauthhistory(sender, trup, 10); return CMD_OK; diff --git a/chanserv/chancmds/cleartopic.c b/chanserv/chancmds/cleartopic.c new file mode 100644 index 00000000..3cc8035c --- /dev/null +++ b/chanserv/chancmds/cleartopic.c @@ -0,0 +1,53 @@ +/* + * CMDNAME: cleartopic + * CMDLEVEL: QCMD_AUTHED + * CMDARGS: 2 + * CMDDESC: Clears the topic on a channel. + * CMDFUNC: csc_docleartopic + * CMDPROTO: int csc_docleartopic(void *source, int cargc, char **cargv); + * CMDHELP: Usage: CLEARTOPIC + * CMDHELP: Clears the topic on a channel, where: + * CMDHELP: channel - channel to use + * CMDHELP: CLEARTOPIC requires topic (+t) or master (+m) access on the named channel. + */ + +#include "../chanserv.h" +#include "../../nick/nick.h" +#include "../../lib/flags.h" +#include "../../lib/irc_string.h" +#include "../../channel/channel.h" +#include "../../parser/parser.h" +#include "../../irc/irc.h" +#include "../../localuser/localuserchannel.h" +#include +#include + +int csc_docleartopic(void *source, int cargc, char **cargv) { + nick *sender=source; + chanindex *cip; + regchan *rcp; + + if (cargc<1) { + chanservstdmessage(sender, QM_NOTENOUGHPARAMS, "cleartopic"); + return CMD_ERROR; + } + + if (!(cip=cs_checkaccess(sender, cargv[0], CA_TOPICPRIV, + NULL, "cleartopic", 0, 0))) + return CMD_ERROR; + + rcp=cip->exts[chanservext]; + + if (rcp->topic) + freesstring(rcp->topic); + + rcp->topic=NULL; + + if (cip->channel) { + localsettopic(chanservnick, cip->channel, ""); + } + + chanservstdmessage(sender, QM_DONE); + csdb_updatechannel(rcp); + return CMD_OK; +} diff --git a/chanserv/chanservnetevents.c b/chanserv/chanservnetevents.c index 0320b00b..6a419e11 100644 --- a/chanserv/chanservnetevents.c +++ b/chanserv/chanservnetevents.c @@ -185,7 +185,7 @@ void cs_handlejoin(int hooknum, void *arg) { } /* Check for other ban lurking on channel which we are enforcing */ - if (CIsEnforce(rcp) && nickbanned_visible(np,cp)) { + if (CIsEnforce(rcp) && nickbanned(np,cp,1)) { localkickuser(chanservnick,cp,np,"Banned."); return; } @@ -409,7 +409,7 @@ void cs_handlenewban(int hooknum, void *arg) { Error("chanserv",ERR_WARNING,"Found user on channel %s who doesn't exist!",cp->index->name->content); continue; } - if (!IsService(np) && nickmatchban_visible(np,cbp)) { + if (!IsService(np) && nickmatchban(np,cbp,1)) { localkickuser(chanservnick,cp,np,"Banned."); } } @@ -430,10 +430,8 @@ void cs_handletopicchange(int hooknum, void *arg) { return; if (CIsForceTopic(rcp)) { - if (rcp->topic) { - /* Forced topic: change it back */ - localsettopic(chanservnick, cp, rcp->topic->content); - } + /* Forced topic: change it back even if blank */ + localsettopic(chanservnick, cp, (rcp->topic)?rcp->topic->content:""); } else if (CIsTopicSave(rcp)) { if (rcp->topic) { freesstring(rcp->topic); diff --git a/chanserv/chanservprivs.c b/chanserv/chanservprivs.c index cd0976e7..d3e03e95 100644 --- a/chanserv/chanservprivs.c +++ b/chanserv/chanservprivs.c @@ -81,7 +81,7 @@ chanindex *cs_checkaccess(nick *np, const char *chan, unsigned int flags, if (!cs_privcheck(priv,np)) { if ((flags & CA_VOICEPRIV) && !(rcp && (CIsVoiceAll(rcp)) && - !(cip->channel && (nickbanned_visible(np, cip->channel) || IsInviteOnly(cip->channel)))) && + !(cip->channel && (nickbanned(np, cip->channel, 1) || IsInviteOnly(cip->channel)))) && !(rcup && (CUHasVoicePriv(rcup)))) { if (!quiet) chanservstdmessage(np, QM_NOACCESSONCHAN, cip->name->content, cmdname); return NULL; diff --git a/chanserv/chanservuser.c b/chanserv/chanservuser.c index 584e1788..8e6a2ef5 100644 --- a/chanserv/chanservuser.c +++ b/chanserv/chanservuser.c @@ -768,6 +768,14 @@ void cs_doallautomodes(nick *np) { if ((lp=getnumerichandlefromchanhash(rcup->chan->index->channel->users, np->numeric))) { /* User is on channel.. */ + /* Update last use time. Do early in case of ban. */ + rcup->usetime=getnettime(); + + if (CUIsBanned(rcup)) { + cs_banuser(NULL, rcup->chan->index, np, NULL); + continue; + } + if (CUKnown(rcup) && rcup->chan->index->channel->users->totalusers >= 3) { /* This meets the channel use criteria, update. */ rcup->chan->lastactive=time(NULL); @@ -779,8 +787,6 @@ void cs_doallautomodes(nick *np) { } } - /* Update last use time */ - rcup->usetime=getnettime(); localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick); if (*lp & CUMODE_OP) { @@ -828,7 +834,7 @@ void cs_checknickbans(nick *np) { for (j=0;jindex->exts[chanservext]) && !CIsSuspended(rcp) && - CIsEnforce(rcp) && nickbanned_visible(np, ca[j])) + CIsEnforce(rcp) && nickbanned(np, ca[j], 1)) localkickuser(chanservnick, ca[j], np, "Banned."); } @@ -869,8 +875,8 @@ void cs_checkbans(channel *cp) { for (rbp=rcp->bans;rbp;rbp=rbp->next) { if (((!rbp->expiry) || (rbp->expiry <= now)) && - nickmatchban_visible(np, rbp->cbp)) { - if (!nickbanned_visible(np, cp)) { + nickmatchban(np, rbp->cbp, 1)) { + if (!nickbanned(np, cp, 1)) { localdosetmode_ban(&changes, bantostring(rbp->cbp), MCB_ADD); } localkickuser(chanservnick,cp,np,rbp->reason?rbp->reason->content:"Banned."); @@ -883,7 +889,7 @@ void cs_checkbans(channel *cp) { if (CIsEnforce(rcp)) { for (cbp=cp->bans;cbp;cbp=cbp->next) { - if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban_visible(np, cbp)) + if ((cbp->timeset>=rcp->lastbancheck) && nickmatchban(np, cbp, 1)) localkickuser(chanservnick,cp,np,"Banned."); } rcp->lastbancheck=time(NULL); @@ -1166,9 +1172,9 @@ int cs_bancheck(nick *np, channel *cp) { freesstring(rbp->reason); freechanban(rbp->cbp); freeregban(rbp); - } else if (nickmatchban_visible(np,(*rbh)->cbp)) { + } else if (nickmatchban(np,(*rbh)->cbp,1)) { /* This user matches this ban.. */ - if (!nickbanned_visible(np,cp)) { + if (!nickbanned(np,cp,1)) { /* Only bother putting the ban on the channel if they're not banned already */ /* (might be covered by this ban or a different one.. doesn't really matter */ localsetmodeinit(&changes, cp, chanservnick); @@ -1202,7 +1208,7 @@ void cs_setregban(chanindex *cip, regban *rbp) { if (cip->channel->users->content[i]!=nouser && (np=getnickbynumeric(cip->channel->users->content[i])) && !IsService(np) && !IsOper(np) && !IsXOper(np) && - nickmatchban_visible(np, rbp->cbp)) + nickmatchban(np, rbp->cbp, 1)) localkickuser(chanservnick, cip->channel, np, rbp->reason ? rbp->reason->content : "Banned."); } @@ -1216,7 +1222,7 @@ void cs_banuser(modechanges *changes, chanindex *cip, nick *np, const char *reas if (!cip->channel) return; - if (nickbanned_visible(np, cip->channel)) { + if (nickbanned(np, cip->channel, 1)) { localkickuser(chanservnick, cip->channel, np, reason?reason:"Banned."); return; } diff --git a/control/control.c b/control/control.c index d29f9387..43e584be 100644 --- a/control/control.c +++ b/control/control.c @@ -267,6 +267,10 @@ int controlwhois(void *sender, int cargc, char **cargv) { } } + if (target->away) { + controlreply((nick *)sender, "Away : %s",target->away->content); + } + hooknick=(nick *)sender; registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois); triggerhook(HOOK_CONTROL_WHOISREQUEST,target); diff --git a/helpmod2/hban.c b/helpmod2/hban.c index 496271a6..848c2bf5 100644 --- a/helpmod2/hban.c +++ b/helpmod2/hban.c @@ -40,7 +40,7 @@ hban *hban_add(const char* pat, const char* rsn, time_t exp, int now) { /* additional logic here */ huser* tmpu; for (tmpu = husers;tmpu;tmpu = tmpu->next) - if (nickmatchban(tmpu->real_user, tmp) && !IsOper(tmpu->real_user)) + if (nickmatchban(tmpu->real_user, tmp, 0) && !IsOper(tmpu->real_user)) { hchannel *assert_hchan = NULL; while (tmpu->hchannels) @@ -114,7 +114,7 @@ hban *hban_check(nick *nck) { hban *ptr = hbans; for (;ptr;ptr = ptr->next) - if (nickmatchban(nck, ptr->real_ban)) + if (nickmatchban(nck, ptr->real_ban, 0)) return ptr; return NULL; } diff --git a/helpmod2/hcommands.c b/helpmod2/hcommands.c index 050bed42..0204e853 100644 --- a/helpmod2/hcommands.c +++ b/helpmod2/hcommands.c @@ -2300,7 +2300,7 @@ static void helpmod_cmd_invite (huser *sender, channel *returntype, char* arg, i return; } - if (nickbanned(sender->real_user, hchan->real_channel)) + if (nickbanned(sender->real_user, hchan->real_channel, 0)) { helpmod_reply(sender, returntype, "Cannot invite: You are banned from channel %s", argv[0]); return; diff --git a/irc/irc_config.h b/irc/irc_config.h index 4d8202d0..4f7f254b 100644 --- a/irc/irc_config.h +++ b/irc/irc_config.h @@ -10,6 +10,7 @@ #define TOPICLEN 250 #define CHANNELLEN 200 #define KEYLEN 23 +#define AWAYLEN 160 #define MAXSERVERS 4096 diff --git a/lib/irc_ipv6.c b/lib/irc_ipv6.c index 638db74c..82d56726 100644 --- a/lib/irc_ipv6.c +++ b/lib/irc_ipv6.c @@ -464,3 +464,24 @@ void base64toip(const char* input, struct irc_in_addr* addr) } } +/** Test whether an address matches the most significant bits of a mask. + * @param[in] addr Address to test. + * @param[in] mask Address to test against. + * @param[in] bits Number of bits to test. + * @return 0 on mismatch, 1 if bits < 128 and all bits match; -1 if + * bits == 128 and all bits match. + */ +int ipmask_check(const struct irc_in_addr *addr, const struct irc_in_addr *mask, unsigned char bits) +{ + int k; + + for (k = 0; k < 8; k++) { + if (bits < 16) + return !(htons(addr->in6_16[k] ^ mask->in6_16[k]) >> (16-bits)); + if (addr->in6_16[k] != mask->in6_16[k]) + return 0; + if (!(bits -= 16)) + return 1; + } + return -1; +} diff --git a/lib/irc_ipv6.h b/lib/irc_ipv6.h index f5fb361a..4c51f86f 100644 --- a/lib/irc_ipv6.h +++ b/lib/irc_ipv6.h @@ -62,6 +62,7 @@ extern const char* ircd_ntoa(const struct irc_in_addr* addr); extern const char* ircd_ntoa_r(char* buf, const struct irc_in_addr* addr); #define ircd_aton(ADDR, STR) ipmask_parse((STR), (ADDR), NULL) extern int ipmask_parse(const char *in, struct irc_in_addr *mask, unsigned char *bits_ptr); +extern int ipmask_check(const struct irc_in_addr *, const struct irc_in_addr *, unsigned char); #define IPtostr(ipaddr) ircd_ntoa(&(ipaddr)) #define irc_in_addr_v4_to_int(ADDR) ((ntohs((ADDR)->in6_16[6]) << 16) | ntohs((ADDR)->in6_16[7])) diff --git a/localuser/localuser.c b/localuser/localuser.c index c7db7cb1..dd11918b 100644 --- a/localuser/localuser.c +++ b/localuser/localuser.c @@ -114,6 +114,7 @@ nick *registerlocaluserflags(char *nickname, char *ident, char *host, char *real newuser->timestamp=getnettime(); newuser->shident=NULL; newuser->sethost=NULL; + newuser->away=NULL; newuser->marker=0; memset(newuser->exts, 0, MAXNICKEXTS * sizeof(void *)); diff --git a/newsearch/Makefile.in b/newsearch/Makefile.in index 2fdf3ff3..726323f0 100644 --- a/newsearch/Makefile.in +++ b/newsearch/Makefile.in @@ -6,7 +6,7 @@ LDFLAGS+=$(LIBPCRE) .PHONY: all clean distclean all: newsearch.so -NSCOMMANDS=ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-cumodecount.o ns-cumodepct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o ns-nickiter.o ns-ipv6.o +NSCOMMANDS=ns-not.o ns-and.o ns-or.o ns-eq.o ns-match.o ns-hostmask.o ns-realname.o ns-away.o ns-modes.o ns-nick.o ns-ident.o ns-regex.o ns-host.o ns-channel.o ns-lt.o ns-gt.o ns-timestamp.o ns-country.o ns-authname.o ns-ip.o ns-kill.o ns-gline.o ns-exists.o ns-services.o ns-size.o ns-name.o ns-topic.o ns-oppct.o ns-cumodecount.o ns-cumodepct.o ns-hostpct.o ns-authedpct.o ns-length.o ns-kick.o ns-authts.o ns-channels.o ns-server.o ns-authid.o ns-notice.o newsearch_ast.o ns-any.o ns-channeliter.o ns-var.o ns-all.o ns-cumodes.o ns-cidr.o ns-nickiter.o ns-ipv6.o @ifeq@${NEWSEARCH_NEWPARSER}@ifeqsep@1@ifeqend@ CFLAGS+=-DNEWSEARCH_NEWPARSER=1 diff --git a/newsearch/newsearch.c b/newsearch/newsearch.c index 51867073..d4531b4c 100644 --- a/newsearch/newsearch.c +++ b/newsearch/newsearch.c @@ -178,6 +178,7 @@ void _init() { /* Nickname operations */ registersearchterm(reg_nicksearch, "hostmask",hostmask_parse, 0, "The user's nick!user@host; \"hostmask real\" returns nick!user@host\rreal"); /* nick only */ registersearchterm(reg_nicksearch, "realname",realname_parse, 0, "User's current realname"); /* nick only */ + registersearchterm(reg_nicksearch, "away",away_parse, 0, "User's current away message"); /* nick only */ registersearchterm(reg_nicksearch, "authname",authname_parse, 0, "User's current authname or false"); /* nick only */ registersearchterm(reg_nicksearch, "authts",authts_parse, 0, "User's Auth timestamp"); /* nick only */ registersearchterm(reg_nicksearch, "ident",ident_parse, 0, "User's current ident"); /* nick only */ @@ -399,6 +400,10 @@ int parseopts(int cargc, char **cargv, int *arg, int *limit, void **subset, void break; case 's': + if (subset == NULL) { + reply(sender,"Error: -s switch not supported for this search."); + return CMD_ERROR; + } if (cargc<*arg) { reply(sender,"Error: -s switch requires an argument (for help, see help )"); return CMD_ERROR; diff --git a/newsearch/newsearch.h b/newsearch/newsearch.h index 9b4a26e9..727886a0 100644 --- a/newsearch/newsearch.h +++ b/newsearch/newsearch.h @@ -126,6 +126,7 @@ struct searchNode *modes_parse(searchCtx *ctx, int argc, char **argv); /* Nick functions (various types) */ struct searchNode *hostmask_parse(searchCtx *ctx, int argc, char **argv); struct searchNode *realname_parse(searchCtx *ctx, int argc, char **argv); +struct searchNode *away_parse(searchCtx *ctx, int argc, char **argv); struct searchNode *authname_parse(searchCtx *ctx, int argc, char **argv); struct searchNode *authts_parse(searchCtx *ctx, int argc, char **argv); struct searchNode *ident_parse(searchCtx *ctx, int argc, char **argv); diff --git a/newsearch/ns-away.c b/newsearch/ns-away.c new file mode 100644 index 00000000..fb09e78c --- /dev/null +++ b/newsearch/ns-away.c @@ -0,0 +1,38 @@ +/* + * AWAY functionality + */ + +#include "newsearch.h" + +#include +#include + +void *away_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput); +void away_free(searchCtx *ctx, struct searchNode *thenode); + +struct searchNode *away_parse(searchCtx *ctx, int argc, char **argv) { + struct searchNode *thenode; + + if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) { + parseError = "malloc: could not allocate memory for this search."; + return NULL; + } + + thenode->returntype = RETURNTYPE_STRING; + thenode->localdata = NULL; + thenode->exe = away_exe; + thenode->free = away_free; + + return thenode; +} + +void *away_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) { + nick *np = (nick *)theinput; + + return (np->away) ? np->away->content : ""; +} + +void away_free(searchCtx *ctx, struct searchNode *thenode) { + free(thenode); +} + diff --git a/nick/nick.c b/nick/nick.c index c43a87e0..3b9dead2 100644 --- a/nick/nick.c +++ b/nick/nick.c @@ -91,6 +91,7 @@ void _init() { registerserverhandler("AC",&handleaccountmsg,4); registerserverhandler("R",&handlestatsmsg,2); registerserverhandler("P",&handleprivmsg,2); + registerserverhandler("A",&handleawaymsg,1); /* Fake the addition of our own server */ handleserverchange(HOOK_SERVER_NEWSERVER,(void *)numerictolong(mynumeric->content,2)); @@ -128,6 +129,7 @@ void _fini() { deregisterserverhandler("AC",&handleaccountmsg); deregisterserverhandler("R",&handlestatsmsg); deregisterserverhandler("P",&handleprivmsg); + deregisterserverhandler("A",&handleawaymsg); } /* diff --git a/nick/nick.h b/nick/nick.h index 8fbe01e4..004aa4b1 100644 --- a/nick/nick.h +++ b/nick/nick.h @@ -140,6 +140,7 @@ typedef struct nick { authname *auth; /* This requires User ID numbers to work */ time_t timestamp; time_t accountts; + sstring *away; patricia_node_t *ipnode; unsigned int marker; struct nick *next; @@ -207,6 +208,7 @@ int handlewhoismsg(void *source, int cargc, char **cargv); int handleaccountmsg(void *source, int cargc, char **cargv); int handlestatsmsg(void *source, int cargc, char **cargv); int handleprivmsg(void *source, int cargc, char **cargv); +int handleawaymsg(void *source, int cargc, char **cargv); /* These functions have been replaced by macros nick **gethandlebynumeric(long numeric); diff --git a/nick/nickhandlers.c b/nick/nickhandlers.c index 86c35905..282139f3 100644 --- a/nick/nickhandlers.c +++ b/nick/nickhandlers.c @@ -143,6 +143,7 @@ int handlenickmsg(void *source, int cargc, char **cargv) { np->ipnode = refnode(iptree, &ipaddress, PATRICIA_MAXBITS); node_increment_usercount(np->ipnode); + np->away=NULL; np->shident=NULL; np->sethost=NULL; np->opername=NULL; @@ -527,3 +528,22 @@ int handleprivmsg(void *source, int cargc, char **cargv) { return CMD_OK; } +int handleawaymsg(void *source, int cargc, char **cargv) { + nick *sender; + + /* Check source is a valid user */ + if (!(sender=getnickbynumericstr(source))) { + return CMD_OK; + } + + /* Done with the old away message either way */ + freesstring(sender->away); + sender->away=NULL; + + /* If we have an arg and it isn't an empty string, this sets a new message */ + if (cargc > 0 && *(cargv[0])) { + sender->away=getsstring(cargv[0], AWAYLEN); + } + + return CMD_OK; +} diff --git a/regexgline/regexgline.c b/regexgline/regexgline.c index 3ae6a69a..5398612a 100644 --- a/regexgline/regexgline.c +++ b/regexgline/regexgline.c @@ -57,6 +57,8 @@ void rg_dodelay(void *arg); void rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char *matched); void rg_flush_schedule(void *arg); +static char *gvhost(nick *np); + static DBModuleIdentifier dbid; static unsigned long highestid = 0; static int attached = 0, started = 0; @@ -259,11 +261,7 @@ void rg_dodelay(void *arg) { } if ((delay->reason->type == DELAYED_KILL) || (usercount > rg_max_per_gline)) { - if (IsAccount(delay->np)) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed kill regex %08lx (class: %s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed kill regex %08lx (class: %s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class); - } + controlwall(NO_OPER, NL_HITS, "%s matched delayed kill regex %08lx (class: %s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class); rg_shadowserver(delay->np, delay->reason, DELAYED_KILL); killuser(NULL, delay->np, "%s (ID: %08lx)", delay->reason->reason->content, delay->reason->glineid); @@ -271,17 +269,9 @@ void rg_dodelay(void *arg) { } if (delay->reason->type == DELAYED_IDENT_GLINE) { - if (IsAccount(delay->np)) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); - } + controlwall(NO_OPER, NL_HITS, "%s matched delayed user@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); } else if (delay->reason->type == DELAYED_HOST_GLINE) { - if (IsAccount(delay->np)) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->np->authname, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", delay->np->nick, delay->np->ident, delay->np->host->name->content, delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); - } + controlwall(NO_OPER, NL_HITS, "%s matched delayed *@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(delay->np), delay->reason->glineid, delay->reason->class, usercount, (usercount!=1)?"s":""); } else { return; } @@ -301,11 +291,7 @@ void rg_flushglines(struct rg_glinelist *gll) { for(nn=gll->start;nn;nn=pn) { pn = nn->next; if(nn->punish == INSTANT_KILL) { - if ( IsAccount(nn->np) ) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched kill regex %08lx (class: %s)", nn->np->nick, nn->np->ident, nn->np->host->name->content, nn->np->authname, nn->reason->glineid, nn->reason->class); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched kill regex %08lx (class: %s)", nn->np->nick, nn->np->ident, nn->np->host->name->content, nn->reason->glineid, nn->reason->class); - } + controlwall(NO_OPER, NL_HITS, "%s matched kill regex %08lx (class: %s)", gvhost(nn->np), nn->reason->glineid, nn->reason->class); rg_shadowserver(nn->np, nn->reason, nn->punish); killuser(NULL, nn->np, "%s (ID: %08lx)", nn->reason->reason->content, nn->reason->glineid); @@ -1098,17 +1084,9 @@ int __rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char } if (rp->type == INSTANT_IDENT_GLINE) { - if (IsAccount(np)) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, np->authname, rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); - } + controlwall(NO_OPER, NL_HITS, "%s matched user@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(np), rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); } else if(rp->type == INSTANT_HOST_GLINE) { - if (IsAccount(np)) { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s/%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, np->authname, rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); - } else { - controlwall(NO_OPER, NL_HITS, "%s!%s@%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", np->nick, np->ident, np->host->name->content, rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); - } + controlwall(NO_OPER, NL_HITS, "%s matched *@host gline regex %08lx (class: %s, hit %d user%s)", gvhost(np), rp->glineid, rp->class, usercount, (usercount!=1)?"s":""); } else { return 0; } @@ -1118,6 +1096,18 @@ int __rg_dogline(struct rg_glinelist *gll, nick *np, struct rg_struct *rp, char return usercount; } +static char *gvhost(nick *np) { + static char buf[NICKLEN+1+USERLEN+1+HOSTLEN+1+ACCOUNTLEN+4+REALLEN+1+10]; + + if(IsAccount(np)) { + snprintf(buf, sizeof(buf), "%s!%s@%s/%s r(%s)", np->nick, np->ident, np->host->name->content, np->authname, np->realname->name->content); + } else { + snprintf(buf, sizeof(buf), "%s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content); + } + + return buf; +} + static int floodprotection = 0; static int lastfloodspam = 0; diff --git a/trojanscan/trojanscan.c b/trojanscan/trojanscan.c index 971f79c4..1813d1fc 100644 --- a/trojanscan/trojanscan.c +++ b/trojanscan/trojanscan.c @@ -1098,7 +1098,7 @@ int trojanscan_nickbanned(trojanscan_clones *np, channel *cp) { np->clone->ipnode = np->fakeipnode; - ret = nickbanned(np->clone, cp); + ret = nickbanned(np->clone, cp, 0); np->clone->ipnode = realipnode;