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;
/* 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 */
}
}
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;
}
}
#include "../lib/flags.h"
#include "../lib/sstring.h"
+#include "../lib/irc_ipv6.h"
#include <time.h>
#define CHANBAN_NICKEXACT 0x0001 /* Ban includes an exact nick (no wildcards) */
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;
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();
#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
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;
}
* 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:
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;
--- /dev/null
+/*
+ * 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 <channel>
+ * 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 <string.h>
+#include <stdio.h>
+
+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;
+}
}
/* 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;
}
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.");
}
}
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);
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;
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);
}
}
- /* Update last use time */
- rcup->usetime=getnettime();
localsetmodeinit(&changes, rcup->chan->index->channel, chanservnick);
if (*lp & CUMODE_OP) {
for (j=0;j<i;j++) {
if ((rcp=ca[j]->index->exts[chanservext]) && !CIsSuspended(rcp) &&
- CIsEnforce(rcp) && nickbanned_visible(np, ca[j]))
+ CIsEnforce(rcp) && nickbanned(np, ca[j], 1))
localkickuser(chanservnick, ca[j], np, "Banned.");
}
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.");
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);
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);
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.");
}
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;
}
}
}
+ if (target->away) {
+ controlreply((nick *)sender, "Away : %s",target->away->content);
+ }
+
hooknick=(nick *)sender;
registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
{ /* 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)
{
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;
}
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;
#define TOPICLEN 250
#define CHANNELLEN 200
#define KEYLEN 23
+#define AWAYLEN 160
#define MAXSERVERS 4096
}
}
+/** 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;
+}
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]))
newuser->timestamp=getnettime();
newuser->shident=NULL;
newuser->sethost=NULL;
+ newuser->away=NULL;
newuser->marker=0;
memset(newuser->exts, 0, MAXNICKEXTS * sizeof(void *));
.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
/* 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 */
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 <searchcmd>)");
return CMD_ERROR;
/* 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);
--- /dev/null
+/*
+ * AWAY functionality
+ */
+
+#include "newsearch.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+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);
+}
+
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));
deregisterserverhandler("AC",&handleaccountmsg);
deregisterserverhandler("R",&handlestatsmsg);
deregisterserverhandler("P",&handleprivmsg);
+ deregisterserverhandler("A",&handleawaymsg);
}
/*
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;
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);
np->ipnode = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
node_increment_usercount(np->ipnode);
+ np->away=NULL;
np->shident=NULL;
np->sethost=NULL;
np->opername=NULL;
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;
+}
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;
}
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);
}
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;
}
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);
}
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;
}
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;
np->clone->ipnode = np->fakeipnode;
- ret = nickbanned(np->clone, cp);
+ ret = nickbanned(np->clone, cp, 0);
np->clone->ipnode = realipnode;