--- /dev/null
+
+.PHONY: all
+all: bans.so
+
+bans.so: bans.o
+ ld -shared -Bdynamic -o $@ $^
--- /dev/null
+/* channelbans.c */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include "bans.h"
+
+#include "../nick/nick.h"
+#include "../lib/irc_string.h"
+#include "../irc/irc_config.h"
+#include "../core/nsmalloc.h"
+#include "../lib/flags.h"
+
+#define ALLOCUNIT 100
+
+chanban *freebans;
+
+void _init() {
+ freebans=NULL;
+}
+
+void _fini() {
+ nsfreeall(POOL_BANS);
+}
+
+chanban *getchanban() {
+ int i;
+ chanban *cbp;
+
+ if (freebans==NULL) {
+ freebans=(chanban *)nsmalloc(POOL_BANS, ALLOCUNIT*sizeof(chanban));
+ for (i=0;i<ALLOCUNIT-1;i++) {
+ freebans[i].next=(struct chanban *)&(freebans[i+1]);
+ }
+ freebans[ALLOCUNIT-1].next=NULL;
+ }
+
+ cbp=freebans;
+ freebans=cbp->next;
+
+ cbp->nick=NULL;
+ cbp->user=NULL;
+ cbp->host=NULL;
+
+ return cbp;
+}
+
+void freechanban(chanban *cbp) {
+ cbp->next=(struct chanban *)freebans;
+
+ if (cbp->nick)
+ freesstring(cbp->nick);
+ if (cbp->user)
+ freesstring(cbp->user);
+ if (cbp->host)
+ freesstring(cbp->host);
+
+ freebans=cbp;
+}
+
+/*
+ * makeban:
+ * Converts the specified ban into a ban structure
+ */
+
+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;
+
+ cbp=getchanban();
+ len=strlen(mask);
+
+ cbp->flags=0;
+
+ /* Let's catch a silly case first */
+ if (!strcmp(mask,"*")) {
+ cbp->flags=CHANBAN_HOSTANY | CHANBAN_USERANY | CHANBAN_NICKANY;
+ cbp->nick=NULL;
+ cbp->user=NULL;
+ cbp->host=NULL;
+ cbp->timeset=time(NULL);
+ return cbp;
+ }
+
+ for (i=(len-1);i>=0;i--) {
+ if (mask[i]=='@') {
+ /* Got @ sign: everything after here is host */
+ if ((len-i)-1 > HOSTLEN) {
+ /* This is too long, we need to truncate it */
+ cbp->host=getsstring(&mask[len-HOSTLEN],HOSTLEN);
+ cbp->host->content[0]='*';
+ cbp->flags |= CHANBAN_HOSTMASK;
+ } else if (i==(len-1)) {
+ /* Ban ending with @, just mark it invalid */
+ /* Note that "moo@*" overrides "moo@", so mark it as having a host too */
+ cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTNULL);
+ cbp->host=NULL;
+ } else if (i==(len-2) && mask[i+1]=='*') {
+ /* 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);
+ }
+ if (foundwild) {
+ cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTMASK);
+ }
+ 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 (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 */
+ if (!(checklen=len-foundwild-1)) { /* Ban ends in *, mark it anyway.. */
+ cbp->flags |= CHANBAN_HIDDENHOST;
+ } else {
+ if (checklen>=strlen(HIS_HIDDENHOST)) {
+ if (!ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
+ cbp->flags |= CHANBAN_HIDDENHOST;
+ } else {
+ if (!ircd_strcmp(cbp->host->content+(cbp->host->length-checklen),
+ (HIS_HIDDENHOST)+strlen(HIS_HIDDENHOST)-checklen))
+ cbp->flags |= CHANBAN_HIDDENHOST;
+ }
+ }
+ 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)
+ 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;
+ }
+ }
+
+ if (foundat<0) {
+ /* If there wasn't an @, this ban matches any host */
+ cbp->host=NULL;
+ cbp->flags |= CHANBAN_HOSTANY;
+ }
+
+ foundwild=0;
+
+ for (i=0;i<foundat;i++) {
+ if (mask[i]=='!') {
+ if (i==0) {
+ /* Invalid mask: nick is empty */
+ cbp->flags |= CHANBAN_NICKNULL;
+ cbp->nick=NULL;
+ } else if (i==1 && mask[0]=='*') {
+ /* matches any nick */
+ cbp->flags |= CHANBAN_NICKANY;
+ cbp->nick=NULL;
+ } else {
+ if (i>NICKLEN) {
+ /* too long: just take the first NICKLEN chars */
+ cbp->nick=getsstring(mask,NICKLEN);
+ } else {
+ cbp->nick=getsstring(mask,i);
+ }
+ if (foundwild)
+ cbp->flags |= CHANBAN_NICKMASK;
+ else
+ cbp->flags |= CHANBAN_NICKEXACT;
+ }
+ foundbang=i;
+ break;
+ } else if (mask[i]=='?' || mask[i]=='*') {
+ if (i<NICKLEN) {
+ foundwild=1;
+ }
+ }
+ }
+
+ if (foundbang<0) {
+ /* We didn't find a !, what we do now depends on what happened
+ * with the @ */
+ if (foundat<0) {
+ /* A ban with no ! or @ is treated as a nick ban only */
+ /* Note that we've special-cased "*" at the top, so we can only
+ * hit the MASK or EXACT case here. */
+ if (len>NICKLEN)
+ cbp->nick=getsstring(mask,NICKLEN);
+ else
+ cbp->nick=getsstring(mask,len);
+
+ if (foundwild)
+ cbp->flags |= CHANBAN_NICKMASK;
+ else
+ cbp->flags |= CHANBAN_NICKEXACT;
+
+ cbp->flags |= (CHANBAN_USERANY | CHANBAN_HOSTANY);
+ cbp->host=NULL;
+ cbp->user=NULL;
+ } else {
+ /* A ban with @ only is treated as user@host */
+ cbp->nick=NULL;
+ cbp->flags |= CHANBAN_NICKANY;
+ }
+ }
+
+ if (foundat>=0) {
+ /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
+ /* This is true even if there was no !.. */
+ if (foundat==(foundbang+1)) {
+ /* empty ident matches nothing */
+ cbp->flags |= (CHANBAN_INVALID | CHANBAN_USERNULL);
+ cbp->user=NULL;
+ } else if (foundat - foundbang - 1 > USERLEN) {
+ /* It's too long.. */
+ cbp->user=getsstring(&mask[foundat-USERLEN],USERLEN);
+ cbp->user->content[0]='*';
+ cbp->flags |= CHANBAN_USERMASK;
+ } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
+ cbp->user=NULL;
+ cbp->flags |= CHANBAN_USERANY;
+ } else {
+ cbp->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1));
+ if (strchr(cbp->user->content,'*') || strchr(cbp->user->content,'?'))
+ cbp->flags |= CHANBAN_USERMASK;
+ else
+ cbp->flags |= CHANBAN_USEREXACT;
+ }
+ }
+
+ assert(cbp->flags & (CHANBAN_USEREXACT | CHANBAN_USERMASK | CHANBAN_USERANY | CHANBAN_USERNULL));
+ assert(cbp->flags & (CHANBAN_NICKEXACT | CHANBAN_NICKMASK | CHANBAN_NICKANY | CHANBAN_NICKNULL));
+ assert(cbp->flags & (CHANBAN_HOSTEXACT | CHANBAN_HOSTMASK | CHANBAN_HOSTANY | CHANBAN_HOSTNULL));
+
+ cbp->timeset=time(NULL);
+
+ return cbp;
+}
+
+/* banoverlap:
+ * Returns nonzero iff bana is a SUPERSET of banb
+ */
+
+int banoverlap(const chanban *bana, const chanban *banb) {
+ /* This function works by looking for cases where bana DOESN'T overlap banb */
+
+ /* NICK section */
+ /* If bana has CHANBAN_NICKANY then it clearly overlaps
+ * in the nick section so there are no checks */
+
+ if ((bana->flags & CHANBAN_NICKNULL) && !(banb->flags & CHANBAN_NICKNULL)) {
+ return 0;
+ }
+
+ if (bana->flags & CHANBAN_NICKMASK) {
+ if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKNULL)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_NICKMASK) && !match2patterns(bana->nick->content, banb->nick->content)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_NICKEXACT) && !match2strings(bana->nick->content, banb->nick->content)) {
+ return 0;
+ }
+ }
+
+ if (bana->flags & CHANBAN_NICKEXACT) {
+ if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKMASK | CHANBAN_NICKNULL)) {
+ return 0;
+ }
+ if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick)) {
+ return 0;
+ }
+ if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content)) {
+ return 0;
+ }
+ }
+
+ /* USER section */
+ /* If bana has CHANBAN_USERANY then it clearly overlaps
+ * in the user section so there are no checks */
+
+ if ((bana->flags & CHANBAN_USERNULL) && !(banb->flags & CHANBAN_USERNULL)) {
+ return 0;
+ }
+
+ if (bana->flags & CHANBAN_USERMASK) {
+ if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERNULL)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_USERMASK) && !match2patterns(bana->user->content, banb->user->content)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_USEREXACT) && !match2strings(bana->user->content, banb->user->content)) {
+ return 0;
+ }
+ }
+
+ if (bana->flags & CHANBAN_USEREXACT) {
+ if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERMASK | CHANBAN_USERNULL)) {
+ return 0;
+ }
+ if ((!bana->user && banb->user) || (bana->user && !banb->user)) {
+ return 0;
+ }
+ if (bana->user && ircd_strcmp(bana->user->content,banb->user->content)) {
+ return 0;
+ }
+ }
+
+ /* HOST section */
+ /* If bana has CHANBAN_HOSTANY then it clearly overlaps
+ * in the host section so there are no checks */
+
+ if ((bana->flags & CHANBAN_HOSTNULL) && !(banb->flags & CHANBAN_HOSTNULL)) {
+ return 0;
+ }
+
+ if (bana->flags & CHANBAN_HOSTMASK) {
+ if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTNULL)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_HOSTMASK) && !match2patterns(bana->host->content, banb->host->content)) {
+ return 0;
+ }
+ if ((banb->flags & CHANBAN_HOSTEXACT) && !match2strings(bana->host->content, banb->host->content)) {
+ return 0;
+ }
+ }
+
+ if (bana->flags & CHANBAN_HOSTEXACT) {
+ if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTMASK | CHANBAN_HOSTNULL)) {
+ return 0;
+ }
+ if ((!bana->host && banb->host) || (bana->host && !banb->host)) {
+ return 0;
+ }
+ if (bana->host && ircd_strcmp(bana->host->content,banb->host->content)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * banequal:
+ * Returns nonzero iff the bans are EXACTLY the same
+ */
+
+int banequal(chanban *bana, chanban *banb) {
+ if (bana->flags != banb->flags)
+ return 0;
+
+ if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick))
+ return 0;
+
+ if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content))
+ return 0;
+
+ if ((!bana->user && banb->user) || (bana->user && !banb->user))
+ return 0;
+
+ if (bana->user && ircd_strcmp(bana->user->content,banb->user->content))
+ return 0;
+
+ if ((!bana->host && banb->host) || (bana->host && !banb->host))
+ return 0;
+
+ if (bana->host && ircd_strcmp(bana->host->content,banb->host->content))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * bantostring:
+ * Convert the specified ban to a string
+ */
+
+char *bantostring(chanban *bp) {
+ static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
+ int strpos=0;
+
+ if (bp->flags & CHANBAN_NICKANY) {
+ strpos += sprintf(outstring+strpos,"*");
+ } else if (bp->nick) {
+ strpos += sprintf(outstring+strpos,"%s",bp->nick->content);
+ }
+
+ strpos += sprintf(outstring+strpos,"!");
+
+ if (bp->flags & CHANBAN_USERANY) {
+ strpos += sprintf(outstring+strpos,"*");
+ } else if (bp->user) {
+ strpos += sprintf(outstring+strpos,"%s",bp->user->content);
+ }
+
+ strpos += sprintf(outstring+strpos,"@");
+
+ if (bp->flags & CHANBAN_HOSTANY) {
+ strpos += sprintf(outstring+strpos,"*");
+ } else if (bp->host) {
+ strpos += sprintf(outstring+strpos,"%s",bp->host->content);
+ }
+
+ return outstring;
+}
+
+/*
+ * bantostringdebug:
+ * Convert the specified ban to a string (debugging version)
+ */
+
+char *bantostringdebug(chanban *bp) {
+ static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
+ int strpos=0;
+
+ strpos += sprintf(outstring+strpos, "flags=%04x ",bp->flags);
+
+ if (bp->nick) {
+ strpos += sprintf(outstring+strpos, "nick=%s ",bp->nick->content);
+ } else {
+ strpos += sprintf(outstring+strpos, "nonick ");
+ }
+
+ if (bp->user) {
+ strpos += sprintf(outstring+strpos, "user=%s ",bp->user->content);
+ } else {
+ strpos += sprintf(outstring+strpos, "nouser ");
+ }
+
+ if (bp->host) {
+ strpos += sprintf(outstring+strpos, "host=%s ",bp->host->content);
+ } else {
+ strpos += sprintf(outstring+strpos, "nohost ");
+ }
+
+
+ return outstring;
+}
+
--- /dev/null
+#ifndef _BANS_H
+#define _BANS_H
+
+#include "../lib/flags.h"
+#include "../lib/sstring.h"
+#include <time.h>
+
+#define CHANBAN_NICKEXACT 0x0001 /* Ban includes an exact nick (no wildcards) */
+#define CHANBAN_NICKMASK 0x0002 /* Ban includes a nick mask with wildcards */
+#define CHANBAN_NICKANY 0x0004 /* Ban is *!.. */
+#define CHANBAN_NICKNULL 0x0008 /* Ban has no nick */
+#define CHANBAN_USEREXACT 0x0010 /* Ban includes an exact user (no wildcards) */
+#define CHANBAN_USERMASK 0x0020 /* Ban includes a user mask with wildcards */
+#define CHANBAN_USERANY 0x0040 /* Ban is ..!*@.. */
+#define CHANBAN_USERNULL 0x0080 /* Ban has no user */
+#define CHANBAN_HOSTEXACT 0x0100 /* Ban includes an exact host */
+#define CHANBAN_HOSTMASK 0x0200 /* Ban includes a host mask */
+#define CHANBAN_HOSTANY 0x0400 /* Ban is ..@* */
+#define CHANBAN_HOSTNULL 0x0800 /* Ban has no host */
+#define CHANBAN_IP 0x1000 /* Ban could match against IP address */
+#define CHANBAN_CIDR 0x2000 /* Ban includes a CIDR mask (e.g. 192.168.0.0/16 ) */
+#define CHANBAN_INVALID 0x4000 /* Ban is nonsensical, i.e. has at least one really NULL component*/
+#define CHANBAN_HIDDENHOST 0x8000 /* Ban could possibly match hidden host */
+
+
+typedef struct chanban {
+ flag_t flags;
+ sstring *nick;
+ sstring *user;
+ sstring *host;
+ time_t timeset;
+ struct chanban *next;
+} chanban;
+
+chanban *getchanban();
+void freechanban(chanban *cbp);
+
+chanban *makeban(const char *mask);
+
+int banoverlap(const chanban *bana, const chanban *banb);
+int banequal(chanban *bana, chanban *banb);
+char *bantostring(chanban *bp);
+char *bantostringdebug(chanban *bp);
+
+
+#endif
#include "../irc/irc.h"
#include "../lib/base64.h"
#include "../lib/version.h"
+#include "../core/nsmalloc.h"
#include <stdio.h>
#include <string.h>
}
void _fini() {
+ unsigned int i;
+ struct channel *cp;
+ struct chanindex *cip, *ncip;
+ nick *np;
+
deregisterserverhandler("B",&handleburstmsg);
deregisterserverhandler("J",&handlejoinmsg);
deregisterserverhandler("C",&handlecreatemsg);
deregisterhook(HOOK_CORE_STATSREQUEST,&channelstats);
deregisterhook(HOOK_IRC_SENDBURSTBURSTS,&sendchanburst);
deregisterhook(HOOK_NICK_WHOISCHANNELS,&handlewhoischannels);
+
+ /* Free all the channels */
+ for(i=0;i<CHANNELHASHSIZE;i++) {
+ for (cip=chantable[i];cip;cip=ncip) {
+ ncip=cip->next;
+ if (!(cp=cip->channel))
+ continue;
+
+ delchannel(cp);
+ }
+ }
+
+ /* We also need to remove the channels array from each user */
+ for (i=0;i<NICKHASHSIZE;i++) {
+ for (np=nicktable[i];np;np=np->next) {
+ array_free(np->channels);
+ free(np->channels);
+ }
+ }
+
+ nsfreeall(POOL_CHANNEL);
}
int addnicktochannel(channel *cp, long numeric) {
return count;
}
+
#include "../core/error.h"
#include "../nick/nick.h"
#include "../chanindex/chanindex.h"
+#include "../bans/bans.h"
#include <time.h>
#include <stdlib.h>
#define CHANMODE_ALL 0xFFFF
-#define CHANBAN_NICKEXACT 0x0001 /* Ban includes an exact nick (no wildcards) */
-#define CHANBAN_NICKMASK 0x0002 /* Ban includes a nick mask with wildcards */
-#define CHANBAN_NICKANY 0x0004 /* Ban is *!.. */
-#define CHANBAN_NICKNULL 0x0008 /* Ban has no nick */
-#define CHANBAN_USEREXACT 0x0010 /* Ban includes an exact user (no wildcards) */
-#define CHANBAN_USERMASK 0x0020 /* Ban includes a user mask with wildcards */
-#define CHANBAN_USERANY 0x0040 /* Ban is ..!*@.. */
-#define CHANBAN_USERNULL 0x0080 /* Ban has no user */
-#define CHANBAN_HOSTEXACT 0x0100 /* Ban includes an exact host */
-#define CHANBAN_HOSTMASK 0x0200 /* Ban includes a host mask */
-#define CHANBAN_HOSTANY 0x0400 /* Ban is ..@* */
-#define CHANBAN_HOSTNULL 0x0800 /* Ban has no host */
-#define CHANBAN_IP 0x1000 /* Ban could match against IP address */
-#define CHANBAN_CIDR 0x2000 /* Ban includes a CIDR mask (e.g. 192.168.0.0/16 ) */
-#define CHANBAN_INVALID 0x4000 /* Ban is nonsensical, i.e. has at least one really NULL component*/
-#define CHANBAN_HIDDENHOST 0x8000 /* Ban could possibly match hidden host */
-
#define IsNoExtMsg(x) ((x)->flags & CHANMODE_NOEXTMSG)
#define IsTopicLimit(x) ((x)->flags & CHANMODE_TOPICLIMIT)
#define IsSecret(x) ((x)->flags & CHANMODE_SECRET)
#define MODECHANGE_USERS 0x00000002
#define MODECHANGE_BANS 0x00000004
-typedef struct chanban {
- flag_t flags;
- sstring *nick;
- sstring *user;
- sstring *host;
- time_t timeset;
- struct chanban *next;
-} chanban;
-
typedef struct chanuserhash {
unsigned short hashsize;
unsigned short totalusers;
void freechan(channel *cp);
chanuserhash *newchanuserhash(int numbuckets);
void freechanuserhash(chanuserhash *cuhp);
-chanban *getchanban();
-void freechanban(chanban *cbp);
/* functions from channelbans.c */
-chanban *makeban(const char *mask);
-int banoverlap(const chanban *bana, const chanban *banb);
-int banequal(chanban *bana, chanban *banb);
-char *bantostring(chanban *bp);
-char *bantostringdebug(chanban *bp);
-void setban(channel *cp, const char *ban);
+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);
#include <stdlib.h>
#include "channel.h"
#include <assert.h>
+#include "../core/nsmalloc.h"
#define ALLOCUNIT 100
channel *freechans;
chanuserhash *freehash;
-chanban *freebans;
void initchannelalloc() {
freechans=NULL;
freehash=NULL;
- freebans=NULL;
}
/* channel records don't have next pointers.
channel *cp;
if (freechans==NULL) {
- freechans=(channel *)malloc(ALLOCUNIT*sizeof(channel));
+ freechans=(channel *)nsmalloc(POOL_CHANNEL,ALLOCUNIT*sizeof(channel));
for (i=0;i<(ALLOCUNIT-1);i++) {
freechans[i].index=(struct chanindex *)&(freechans[i+1]);
}
chanuserhash *cuhp;
if (freehash==NULL) {
- freehash=(chanuserhash *)malloc(ALLOCUNIT*sizeof(chanuserhash));
+ freehash=(chanuserhash *)nsmalloc(POOL_CHANNEL,ALLOCUNIT*sizeof(chanuserhash));
for (i=0;i<(ALLOCUNIT-1);i++) {
freehash[i].content=(unsigned long *)&(freehash[i+1]);
}
cuhp=freehash;
freehash=(chanuserhash *)cuhp->content;
-
+ /* Don't use nsmalloc() here since we will free this in freechanuserhash() */
cuhp->content=(unsigned long *)malloc(hashsize*sizeof(unsigned long));
for (i=0;i<hashsize;i++) {
cuhp->content[i]=nouser;
cuhp->content=(unsigned long *)freehash;
freehash=cuhp;
}
-
-chanban *getchanban() {
- int i;
- chanban *cbp;
-
- if (freebans==NULL) {
- freebans=(chanban *)malloc(ALLOCUNIT*sizeof(chanban));
- for (i=0;i<ALLOCUNIT-1;i++) {
- freebans[i].next=(struct chanban *)&(freebans[i+1]);
- }
- freebans[ALLOCUNIT-1].next=NULL;
- }
-
- cbp=freebans;
- freebans=cbp->next;
-
- cbp->nick=NULL;
- cbp->user=NULL;
- cbp->host=NULL;
-
- return cbp;
-}
-
-void freechanban(chanban *cbp) {
- cbp->next=(struct chanban *)freebans;
-
- if (cbp->nick)
- freesstring(cbp->nick);
- if (cbp->user)
- freesstring(cbp->user);
- if (cbp->host)
- freesstring(cbp->host);
-
- freebans=cbp;
-}
-
#include "../irc/irc_config.h"
#include "../irc/irc.h"
-/*
- * makeban:
- * Converts the specified ban into a ban structure
- */
-
-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;
-
- cbp=getchanban();
- len=strlen(mask);
-
- cbp->flags=0;
-
- /* Let's catch a silly case first */
- if (!strcmp(mask,"*")) {
- cbp->flags=CHANBAN_HOSTANY | CHANBAN_USERANY | CHANBAN_NICKANY;
- cbp->nick=NULL;
- cbp->user=NULL;
- cbp->host=NULL;
- cbp->timeset=time(NULL);
- return cbp;
- }
-
- for (i=(len-1);i>=0;i--) {
- if (mask[i]=='@') {
- /* Got @ sign: everything after here is host */
- if ((len-i)-1 > HOSTLEN) {
- /* This is too long, we need to truncate it */
- cbp->host=getsstring(&mask[len-HOSTLEN],HOSTLEN);
- cbp->host->content[0]='*';
- cbp->flags |= CHANBAN_HOSTMASK;
- } else if (i==(len-1)) {
- /* Ban ending with @, just mark it invalid */
- /* Note that "moo@*" overrides "moo@", so mark it as having a host too */
- cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTNULL);
- cbp->host=NULL;
- } else if (i==(len-2) && mask[i+1]=='*') {
- /* 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);
- }
- if (foundwild) {
- cbp->flags |= (CHANBAN_INVALID | CHANBAN_HOSTMASK);
- }
- 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 (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 */
- if (!(checklen=len-foundwild-1)) { /* Ban ends in *, mark it anyway.. */
- cbp->flags |= CHANBAN_HIDDENHOST;
- } else {
- if (checklen>=strlen(HIS_HIDDENHOST)) {
- if (!ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST))
- cbp->flags |= CHANBAN_HIDDENHOST;
- } else {
- if (!ircd_strcmp(cbp->host->content+(cbp->host->length-checklen),
- (HIS_HIDDENHOST)+strlen(HIS_HIDDENHOST)-checklen))
- cbp->flags |= CHANBAN_HIDDENHOST;
- }
- }
- 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)
- 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;
- }
- }
-
- if (foundat<0) {
- /* If there wasn't an @, this ban matches any host */
- cbp->host=NULL;
- cbp->flags |= CHANBAN_HOSTANY;
- }
-
- foundwild=0;
-
- for (i=0;i<foundat;i++) {
- if (mask[i]=='!') {
- if (i==0) {
- /* Invalid mask: nick is empty */
- cbp->flags |= CHANBAN_NICKNULL;
- cbp->nick=NULL;
- } else if (i==1 && mask[0]=='*') {
- /* matches any nick */
- cbp->flags |= CHANBAN_NICKANY;
- cbp->nick=NULL;
- } else {
- if (i>NICKLEN) {
- /* too long: just take the first NICKLEN chars */
- cbp->nick=getsstring(mask,NICKLEN);
- } else {
- cbp->nick=getsstring(mask,i);
- }
- if (foundwild)
- cbp->flags |= CHANBAN_NICKMASK;
- else
- cbp->flags |= CHANBAN_NICKEXACT;
- }
- foundbang=i;
- break;
- } else if (mask[i]=='?' || mask[i]=='*') {
- if (i<NICKLEN) {
- foundwild=1;
- }
- }
- }
-
- if (foundbang<0) {
- /* We didn't find a !, what we do now depends on what happened
- * with the @ */
- if (foundat<0) {
- /* A ban with no ! or @ is treated as a nick ban only */
- /* Note that we've special-cased "*" at the top, so we can only
- * hit the MASK or EXACT case here. */
- if (len>NICKLEN)
- cbp->nick=getsstring(mask,NICKLEN);
- else
- cbp->nick=getsstring(mask,len);
-
- if (foundwild)
- cbp->flags |= CHANBAN_NICKMASK;
- else
- cbp->flags |= CHANBAN_NICKEXACT;
-
- cbp->flags |= (CHANBAN_USERANY | CHANBAN_HOSTANY);
- cbp->host=NULL;
- cbp->user=NULL;
- } else {
- /* A ban with @ only is treated as user@host */
- cbp->nick=NULL;
- cbp->flags |= CHANBAN_NICKANY;
- }
- }
-
- if (foundat>=0) {
- /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
- /* This is true even if there was no !.. */
- if (foundat==(foundbang+1)) {
- /* empty ident matches nothing */
- cbp->flags |= (CHANBAN_INVALID | CHANBAN_USERNULL);
- cbp->user=NULL;
- } else if (foundat - foundbang - 1 > USERLEN) {
- /* It's too long.. */
- cbp->user=getsstring(&mask[foundat-USERLEN],USERLEN);
- cbp->user->content[0]='*';
- cbp->flags |= CHANBAN_USERMASK;
- } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
- cbp->user=NULL;
- cbp->flags |= CHANBAN_USERANY;
- } else {
- cbp->user=getsstring(&mask[foundbang+1],(foundat-foundbang-1));
- if (strchr(cbp->user->content,'*') || strchr(cbp->user->content,'?'))
- cbp->flags |= CHANBAN_USERMASK;
- else
- cbp->flags |= CHANBAN_USEREXACT;
- }
- }
-
- assert(cbp->flags & (CHANBAN_USEREXACT | CHANBAN_USERMASK | CHANBAN_USERANY | CHANBAN_USERNULL));
- assert(cbp->flags & (CHANBAN_NICKEXACT | CHANBAN_NICKMASK | CHANBAN_NICKANY | CHANBAN_NICKNULL));
- assert(cbp->flags & (CHANBAN_HOSTEXACT | CHANBAN_HOSTMASK | CHANBAN_HOSTANY | CHANBAN_HOSTNULL));
-
- cbp->timeset=time(NULL);
-
- return cbp;
-}
-
-/* banoverlap:
- * Returns nonzero iff bana is a SUPERSET of banb
- */
-
-int banoverlap(const chanban *bana, const chanban *banb) {
- /* This function works by looking for cases where bana DOESN'T overlap banb */
-
- /* NICK section */
- /* If bana has CHANBAN_NICKANY then it clearly overlaps
- * in the nick section so there are no checks */
-
- if ((bana->flags & CHANBAN_NICKNULL) && !(banb->flags & CHANBAN_NICKNULL)) {
- return 0;
- }
-
- if (bana->flags & CHANBAN_NICKMASK) {
- if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKNULL)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_NICKMASK) && !match2patterns(bana->nick->content, banb->nick->content)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_NICKEXACT) && !match2strings(bana->nick->content, banb->nick->content)) {
- return 0;
- }
- }
-
- if (bana->flags & CHANBAN_NICKEXACT) {
- if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKMASK | CHANBAN_NICKNULL)) {
- return 0;
- }
- if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick)) {
- return 0;
- }
- if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content)) {
- return 0;
- }
- }
-
- /* USER section */
- /* If bana has CHANBAN_USERANY then it clearly overlaps
- * in the user section so there are no checks */
-
- if ((bana->flags & CHANBAN_USERNULL) && !(banb->flags & CHANBAN_USERNULL)) {
- return 0;
- }
-
- if (bana->flags & CHANBAN_USERMASK) {
- if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERNULL)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_USERMASK) && !match2patterns(bana->user->content, banb->user->content)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_USEREXACT) && !match2strings(bana->user->content, banb->user->content)) {
- return 0;
- }
- }
-
- if (bana->flags & CHANBAN_USEREXACT) {
- if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERMASK | CHANBAN_USERNULL)) {
- return 0;
- }
- if ((!bana->user && banb->user) || (bana->user && !banb->user)) {
- return 0;
- }
- if (bana->user && ircd_strcmp(bana->user->content,banb->user->content)) {
- return 0;
- }
- }
-
- /* HOST section */
- /* If bana has CHANBAN_HOSTANY then it clearly overlaps
- * in the host section so there are no checks */
-
- if ((bana->flags & CHANBAN_HOSTNULL) && !(banb->flags & CHANBAN_HOSTNULL)) {
- return 0;
- }
-
- if (bana->flags & CHANBAN_HOSTMASK) {
- if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTNULL)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_HOSTMASK) && !match2patterns(bana->host->content, banb->host->content)) {
- return 0;
- }
- if ((banb->flags & CHANBAN_HOSTEXACT) && !match2strings(bana->host->content, banb->host->content)) {
- return 0;
- }
- }
-
- if (bana->flags & CHANBAN_HOSTEXACT) {
- if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTMASK | CHANBAN_HOSTNULL)) {
- return 0;
- }
- if ((!bana->host && banb->host) || (bana->host && !banb->host)) {
- return 0;
- }
- if (bana->host && ircd_strcmp(bana->host->content,banb->host->content)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * banequal:
- * Returns nonzero iff the bans are EXACTLY the same
- */
-
-int banequal(chanban *bana, chanban *banb) {
- if (bana->flags != banb->flags)
- return 0;
-
- if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick))
- return 0;
-
- if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content))
- return 0;
-
- if ((!bana->user && banb->user) || (bana->user && !banb->user))
- return 0;
-
- if (bana->user && ircd_strcmp(bana->user->content,banb->user->content))
- return 0;
-
- if ((!bana->host && banb->host) || (bana->host && !banb->host))
- return 0;
-
- if (bana->host && ircd_strcmp(bana->host->content,banb->host->content))
- return 0;
-
- return 1;
-}
-
-/*
- * bantostring:
- * Convert the specified ban to a string
- */
-
-char *bantostring(chanban *bp) {
- static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
- int strpos=0;
-
- if (bp->flags & CHANBAN_NICKANY) {
- strpos += sprintf(outstring+strpos,"*");
- } else if (bp->nick) {
- strpos += sprintf(outstring+strpos,"%s",bp->nick->content);
- }
-
- strpos += sprintf(outstring+strpos,"!");
-
- if (bp->flags & CHANBAN_USERANY) {
- strpos += sprintf(outstring+strpos,"*");
- } else if (bp->user) {
- strpos += sprintf(outstring+strpos,"%s",bp->user->content);
- }
-
- strpos += sprintf(outstring+strpos,"@");
-
- if (bp->flags & CHANBAN_HOSTANY) {
- strpos += sprintf(outstring+strpos,"*");
- } else if (bp->host) {
- strpos += sprintf(outstring+strpos,"%s",bp->host->content);
- }
-
- return outstring;
-}
-
-/*
- * bantostringdebug:
- * Convert the specified ban to a string (debugging version)
- */
-
-char *bantostringdebug(chanban *bp) {
- static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
- int strpos=0;
-
- strpos += sprintf(outstring+strpos, "flags=%04x ",bp->flags);
-
- if (bp->nick) {
- strpos += sprintf(outstring+strpos, "nick=%s ",bp->nick->content);
- } else {
- strpos += sprintf(outstring+strpos, "nonick ");
- }
-
- if (bp->user) {
- strpos += sprintf(outstring+strpos, "user=%s ",bp->user->content);
- } else {
- strpos += sprintf(outstring+strpos, "nouser ");
- }
-
- if (bp->host) {
- strpos += sprintf(outstring+strpos, "host=%s ",bp->host->content);
- } else {
- strpos += sprintf(outstring+strpos, "nohost ");
- }
-
-
- return outstring;
-}
-
/*
* nickmatchban:
* Returns true iff the supplied nick* matches the supplied ban*
* setban:
* Set the specified ban; if it completely encloses any existing bans
* then remove them.
+ *
+ * Returns 1 if the ban was set, or 0 if the ban was not set because an
+ * existing ban overlapped it.
*/
-void setban(channel *cp, const char *ban) {
+int setban(channel *cp, const char *ban) {
chanban **cbh,*cbp,*cbp2;
cbp=makeban(ban);
+ /* Don't set our ban if something encloses it */
+ for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
+ if (banoverlap(cbp2, cbp)) {
+ /* This ban overlaps the one we are adding. Abort. */
+ freechanban(cbp);
+ return 0;
+ }
+ }
+
/* Remove enclosed bans first */
for (cbh=&(cp->bans);*cbh;) {
if (banoverlap(cbp,*cbh)) {
/* Now set the new ban */
cbp->next=(struct chanban *)cp->bans;
cp->bans=cbp;
+
+ return 1;
}
/*