]>
jfr.im git - irc/quakenet/newserv.git/blob - bans/bans.c
8 #include "../nick/nick.h"
9 #include "../lib/irc_string.h"
10 #include "../irc/irc_config.h"
11 #include "../core/nsmalloc.h"
12 #include "../lib/flags.h"
26 chanban
*getchanban() {
31 freebans
=(chanban
*)nsmalloc(POOL_BANS
, ALLOCUNIT
*sizeof(chanban
));
32 for (i
=0;i
<ALLOCUNIT
-1;i
++) {
33 freebans
[i
].next
=(struct chanban
*)&(freebans
[i
+1]);
35 freebans
[ALLOCUNIT
-1].next
=NULL
;
48 void freechanban(chanban
*cbp
) {
49 cbp
->next
=(struct chanban
*)freebans
;
52 freesstring(cbp
->nick
);
54 freesstring(cbp
->user
);
56 freesstring(cbp
->host
);
63 * Converts the specified ban into a ban structure
66 chanban
*makeban(const char *mask
) {
68 int foundat
=-1,foundbang
=-1;
83 /* Let's catch a silly case first */
84 if (!strcmp(mask
,"*")) {
85 cbp
->flags
=CHANBAN_HOSTANY
| CHANBAN_USERANY
| CHANBAN_NICKANY
;
89 cbp
->timeset
=time(NULL
);
93 for (i
=(len
-1);i
>=0;i
--) {
95 /* Got @ sign: everything after here is host */
96 if ((len
-i
)-1 > HOSTLEN
) {
97 /* This is too long, we need to truncate it */
98 strncpy(tmpbuf
,&mask
[len
-HOSTLEN
],HOSTLEN
);
101 cbp
->host
=getsstring(tmpbuf
,HOSTLEN
);
102 cbp
->flags
|= CHANBAN_HOSTMASK
;
103 } else if (i
==(len
-1)) {
104 /* Ban ending with @, just mark it invalid */
105 /* Note that "moo@*" overrides "moo@", so mark it as having a host too */
106 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTNULL
);
108 } else if (i
==(len
-2) && mask
[i
+1]=='*') {
109 /* Special case: "@*" */
110 cbp
->flags
|= CHANBAN_HOSTANY
;
112 } else if (foundslash
) {
113 /* If we found a slash (/), this can only be a CIDR ban */
114 /* However, it might be broken, so we need to retain the exact string
115 * to track it accurately */
116 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
117 if ((notip
|| dotcount
!=3) && !foundwild
) {
118 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTEXACT
);
119 } else if (foundwild
) {
120 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTMASK
);
122 unsigned int a
,b
,c
,d
,l
;
123 /* CIDR bans have to match this pattern. */
124 if ((sscanf(&mask
[i
+1], "%u.%u.%u.%u/%u",&a
,&b
,&c
,&d
,&l
) != 5) ||
125 (a
>255) || (b
>255) || (c
>255) || (d
>255) || (l
>32) ) {
126 cbp
->flags
|= (CHANBAN_HOSTEXACT
| CHANBAN_INVALID
);
128 /* Save the IP address and mask for later */
129 cbp
->ipaddr
=(a
<<24)|(b
<<16)|(c
<<8)|d
;
130 cbp
->mask
=0xffffffff;
136 /* pre-AND the IP with the mask here. */
137 cbp
->ipaddr
&= cbp
->mask
;
138 cbp
->flags
|= (CHANBAN_HOSTEXACT
| CHANBAN_CIDR
);
142 /* We have some string with between 1 and HOSTLEN characters.. */
143 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
145 /* We check all characters after the last wildcard (if any).. if they match
146 * the corresponding bits of the hidden host string we mark it accordingly */
147 if (!(checklen
=len
-foundwild
-1)) { /* Ban ends in *, mark it anyway.. */
148 cbp
->flags
|= CHANBAN_HIDDENHOST
;
150 if (checklen
>=strlen(HIS_HIDDENHOST
)) {
151 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
))
152 cbp
->flags
|= CHANBAN_HIDDENHOST
;
154 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-checklen
),
155 (HIS_HIDDENHOST
)+strlen(HIS_HIDDENHOST
)-checklen
))
156 cbp
->flags
|= CHANBAN_HIDDENHOST
;
159 cbp
->flags
|= CHANBAN_HOSTMASK
;
160 if (!notip
&& dotcount
<=3)
161 cbp
->flags
|= CHANBAN_IP
;
163 /* Exact host: see if it ends with the "hidden host" string */
164 cbp
->flags
|= CHANBAN_HOSTEXACT
;
165 if ((cbp
->host
->length
> (strlen(HIS_HIDDENHOST
)+1)) &&
166 !ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
)) {
167 cbp
->flags
|= CHANBAN_HIDDENHOST
;
168 } else if (!notip
&& dotcount
==3) {
169 unsigned int a
,b
,c
,d
;
170 if ((sscanf(&mask
[i
+1], "%u.%u.%u.%u",&a
,&b
,&c
,&d
) != 4) ||
171 (a
> 255) || (b
> 255) || (c
> 255) || (d
> 255) ) {
172 /* Something with only numbers and exactly 3 dots that isn't an IP address can't match anything. */
173 cbp
->flags
|= CHANBAN_INVALID
;
175 cbp
->ipaddr
=(a
<<24)|(b
<<16)|(c
<<8)|d
;
176 cbp
->flags
|= CHANBAN_IP
;
183 } else if (mask
[i
]=='/') {
185 } else if (mask
[i
]=='.') {
187 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
188 if (!foundwild
) /* Mark last wildcard in string */
190 } else if (mask
[i
]<'0' || mask
[i
]>'9') {
196 /* If there wasn't an @, this ban matches any host */
198 cbp
->flags
|= CHANBAN_HOSTANY
;
203 for (i
=0;i
<foundat
;i
++) {
206 /* Invalid mask: nick is empty */
207 cbp
->flags
|= CHANBAN_NICKNULL
;
209 } else if (i
==1 && mask
[0]=='*') {
210 /* matches any nick */
211 cbp
->flags
|= CHANBAN_NICKANY
;
215 /* too long: just take the first NICKLEN chars */
216 cbp
->nick
=getsstring(mask
,NICKLEN
);
218 cbp
->nick
=getsstring(mask
,i
);
221 cbp
->flags
|= CHANBAN_NICKMASK
;
223 cbp
->flags
|= CHANBAN_NICKEXACT
;
227 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
235 /* We didn't find a !, what we do now depends on what happened
238 /* A ban with no ! or @ is treated as a nick ban only */
239 /* Note that we've special-cased "*" at the top, so we can only
240 * hit the MASK or EXACT case here. */
242 cbp
->nick
=getsstring(mask
,NICKLEN
);
244 cbp
->nick
=getsstring(mask
,len
);
247 cbp
->flags
|= CHANBAN_NICKMASK
;
249 cbp
->flags
|= CHANBAN_NICKEXACT
;
251 cbp
->flags
|= (CHANBAN_USERANY
| CHANBAN_HOSTANY
);
255 /* A ban with @ only is treated as user@host */
257 cbp
->flags
|= CHANBAN_NICKANY
;
262 /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
263 /* This is true even if there was no !.. */
264 if (foundat
==(foundbang
+1)) {
265 /* empty ident matches nothing */
266 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_USERNULL
);
268 } else if (foundat
- foundbang
- 1 > USERLEN
) {
269 /* It's too long.. */
270 strncpy(tmpbuf
,&mask
[foundat
-USERLEN
],USERLEN
);
271 tmpbuf
[USERLEN
]='\0';
273 cbp
->user
=getsstring(tmpbuf
,USERLEN
);
274 cbp
->flags
|= CHANBAN_USERMASK
;
275 } else if ((foundat
- foundbang
- 1 == 1) && mask
[foundbang
+1]=='*') {
277 cbp
->flags
|= CHANBAN_USERANY
;
279 cbp
->user
=getsstring(&mask
[foundbang
+1],(foundat
-foundbang
-1));
280 if (strchr(cbp
->user
->content
,'*') || strchr(cbp
->user
->content
,'?'))
281 cbp
->flags
|= CHANBAN_USERMASK
;
283 cbp
->flags
|= CHANBAN_USEREXACT
;
285 /* Username part can't contain an @ */
286 if (cbp
->user
&& strchr(cbp
->user
->content
,'@')) {
287 cbp
->flags
|= CHANBAN_INVALID
;
291 assert(cbp
->flags
& (CHANBAN_USEREXACT
| CHANBAN_USERMASK
| CHANBAN_USERANY
| CHANBAN_USERNULL
));
292 assert(cbp
->flags
& (CHANBAN_NICKEXACT
| CHANBAN_NICKMASK
| CHANBAN_NICKANY
| CHANBAN_NICKNULL
));
293 assert(cbp
->flags
& (CHANBAN_HOSTEXACT
| CHANBAN_HOSTMASK
| CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
));
295 cbp
->timeset
=time(NULL
);
303 * Returns nonzero iff bana is a SUPERSET of banb
306 int banoverlap(const chanban
*bana
, const chanban
*banb
) {
307 /* This function works by looking for cases where bana DOESN'T overlap banb */
310 /* If bana has CHANBAN_NICKANY then it clearly overlaps
311 * in the nick section so there are no checks */
313 if ((bana
->flags
& CHANBAN_NICKNULL
) && !(banb
->flags
& CHANBAN_NICKNULL
)) {
317 if (bana
->flags
& CHANBAN_NICKMASK
) {
318 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKNULL
)) {
321 if ((banb
->flags
& CHANBAN_NICKMASK
) && !match2patterns(bana
->nick
->content
, banb
->nick
->content
)) {
324 if ((banb
->flags
& CHANBAN_NICKEXACT
) && !match2strings(bana
->nick
->content
, banb
->nick
->content
)) {
329 if (bana
->flags
& CHANBAN_NICKEXACT
) {
330 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKMASK
| CHANBAN_NICKNULL
)) {
333 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
)) {
336 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
)) {
342 /* If bana has CHANBAN_USERANY then it clearly overlaps
343 * in the user section so there are no checks */
345 if ((bana
->flags
& CHANBAN_USERNULL
) && !(banb
->flags
& CHANBAN_USERNULL
)) {
349 if (bana
->flags
& CHANBAN_USERMASK
) {
350 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERNULL
)) {
353 if ((banb
->flags
& CHANBAN_USERMASK
) && !match2patterns(bana
->user
->content
, banb
->user
->content
)) {
356 if ((banb
->flags
& CHANBAN_USEREXACT
) && !match2strings(bana
->user
->content
, banb
->user
->content
)) {
361 if (bana
->flags
& CHANBAN_USEREXACT
) {
362 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERMASK
| CHANBAN_USERNULL
)) {
365 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
)) {
368 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
)) {
374 /* If bana has CHANBAN_HOSTANY then it clearly overlaps
375 * in the host section so there are no checks */
377 if ((bana
->flags
& CHANBAN_HOSTNULL
) && !(banb
->flags
& CHANBAN_HOSTNULL
)) {
381 if (bana
->flags
& CHANBAN_HOSTMASK
) {
382 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
)) {
385 if ((banb
->flags
& CHANBAN_HOSTMASK
) && !match2patterns(bana
->host
->content
, banb
->host
->content
)) {
388 if ((banb
->flags
& CHANBAN_HOSTEXACT
) && !match2strings(bana
->host
->content
, banb
->host
->content
)) {
393 if (bana
->flags
& CHANBAN_HOSTEXACT
) {
394 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTMASK
| CHANBAN_HOSTNULL
)) {
397 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
)) {
400 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
)) {
410 * Returns nonzero iff the bans are EXACTLY the same
413 int banequal(chanban
*bana
, chanban
*banb
) {
414 if (bana
->flags
!= banb
->flags
)
417 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
))
420 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
))
423 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
))
426 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
))
429 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
))
432 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
))
440 * Convert the specified ban to a string
443 char *bantostring(chanban
*bp
) {
444 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
447 if (bp
->flags
& CHANBAN_NICKANY
) {
448 strpos
+= sprintf(outstring
+strpos
,"*");
449 } else if (bp
->nick
) {
450 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->nick
->content
);
453 strpos
+= sprintf(outstring
+strpos
,"!");
455 if (bp
->flags
& CHANBAN_USERANY
) {
456 strpos
+= sprintf(outstring
+strpos
,"*");
457 } else if (bp
->user
) {
458 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->user
->content
);
461 strpos
+= sprintf(outstring
+strpos
,"@");
463 if (bp
->flags
& CHANBAN_HOSTANY
) {
464 strpos
+= sprintf(outstring
+strpos
,"*");
465 } else if (bp
->host
) {
466 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->host
->content
);
474 * Convert the specified ban to a string (debugging version)
477 char *bantostringdebug(chanban
*bp
) {
478 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
481 strpos
+= sprintf(outstring
+strpos
, "flags=%04x ",bp
->flags
);
484 strpos
+= sprintf(outstring
+strpos
, "nick=%s ",bp
->nick
->content
);
486 strpos
+= sprintf(outstring
+strpos
, "nonick ");
490 strpos
+= sprintf(outstring
+strpos
, "user=%s ",bp
->user
->content
);
492 strpos
+= sprintf(outstring
+strpos
, "nouser ");
496 strpos
+= sprintf(outstring
+strpos
, "host=%s ",bp
->host
->content
);
498 strpos
+= sprintf(outstring
+strpos
, "nohost ");