]>
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"
13 #include "../lib/version.h"
29 chanban
*getchanban() {
34 freebans
=(chanban
*)nsmalloc(POOL_BANS
, ALLOCUNIT
*sizeof(chanban
));
35 for (i
=0;i
<ALLOCUNIT
-1;i
++) {
36 freebans
[i
].next
=(struct chanban
*)&(freebans
[i
+1]);
38 freebans
[ALLOCUNIT
-1].next
=NULL
;
51 void freechanban(chanban
*cbp
) {
52 cbp
->next
=(struct chanban
*)freebans
;
55 freesstring(cbp
->nick
);
57 freesstring(cbp
->user
);
59 freesstring(cbp
->host
);
66 * Converts the specified ban into a ban structure
69 chanban
*makeban(const char *mask
) {
71 int foundat
=-1,foundbang
=-1;
86 /* Let's catch a silly case first */
87 if (!strcmp(mask
,"*")) {
88 cbp
->flags
=CHANBAN_HOSTANY
| CHANBAN_USERANY
| CHANBAN_NICKANY
;
92 cbp
->timeset
=time(NULL
);
96 for (i
=(len
-1);i
>=0;i
--) {
98 /* Got @ sign: everything after here is host */
99 if ((len
-i
)-1 > HOSTLEN
) {
100 /* This is too long, we need to truncate it */
101 strncpy(tmpbuf
,&mask
[len
-HOSTLEN
],HOSTLEN
);
102 tmpbuf
[HOSTLEN
]='\0';
104 cbp
->host
=getsstring(tmpbuf
,HOSTLEN
);
105 cbp
->flags
|= CHANBAN_HOSTMASK
;
106 } else if (i
==(len
-1)) {
107 /* Ban ending with @, just mark it invalid */
108 /* Note that "moo@*" overrides "moo@", so mark it as having a host too */
109 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTNULL
);
111 } else if (i
==(len
-2) && mask
[i
+1]=='*') {
112 /* Special case: "@*" */
113 cbp
->flags
|= CHANBAN_HOSTANY
;
115 } else if (foundslash
) {
116 /* If we found a slash (/), this can only be a CIDR ban */
117 /* However, it might be broken, so we need to retain the exact string
118 * to track it accurately */
119 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
120 if ((notip
|| dotcount
!=3) && !foundwild
) {
121 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTEXACT
);
122 } else if (foundwild
) {
123 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTMASK
);
125 unsigned int a
,b
,c
,d
,l
;
126 /* CIDR bans have to match this pattern. */
127 if ((sscanf(&mask
[i
+1], "%u.%u.%u.%u/%u",&a
,&b
,&c
,&d
,&l
) != 5) ||
128 (a
>255) || (b
>255) || (c
>255) || (d
>255) || (l
>32) ) {
129 cbp
->flags
|= (CHANBAN_HOSTEXACT
| CHANBAN_INVALID
);
131 /* Save the IP address and mask for later */
132 cbp
->ipaddr
=(a
<<24)|(b
<<16)|(c
<<8)|d
;
133 cbp
->mask
=0xffffffff;
139 /* pre-AND the IP with the mask here. */
140 cbp
->ipaddr
&= cbp
->mask
;
141 cbp
->flags
|= (CHANBAN_HOSTEXACT
| CHANBAN_CIDR
);
145 /* We have some string with between 1 and HOSTLEN characters.. */
146 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
148 /* We check all characters after the last wildcard (if any).. if they match
149 * the corresponding bits of the hidden host string we mark it accordingly */
150 if (!(checklen
=len
-foundwild
-1)) { /* Ban ends in *, mark it anyway.. */
151 cbp
->flags
|= CHANBAN_HIDDENHOST
;
153 if (checklen
>=strlen(HIS_HIDDENHOST
)) {
154 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
))
155 cbp
->flags
|= CHANBAN_HIDDENHOST
;
157 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-checklen
),
158 (HIS_HIDDENHOST
)+strlen(HIS_HIDDENHOST
)-checklen
))
159 cbp
->flags
|= CHANBAN_HIDDENHOST
;
162 cbp
->flags
|= CHANBAN_HOSTMASK
;
163 if (!notip
&& dotcount
<=3)
164 cbp
->flags
|= CHANBAN_IP
;
166 /* Exact host: see if it ends with the "hidden host" string */
167 cbp
->flags
|= CHANBAN_HOSTEXACT
;
168 if ((cbp
->host
->length
> (strlen(HIS_HIDDENHOST
)+1)) &&
169 !ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
)) {
170 cbp
->flags
|= CHANBAN_HIDDENHOST
;
171 } else if (!notip
&& dotcount
==3) {
172 unsigned int a
,b
,c
,d
;
173 if ((sscanf(&mask
[i
+1], "%u.%u.%u.%u",&a
,&b
,&c
,&d
) != 4) ||
174 (a
> 255) || (b
> 255) || (c
> 255) || (d
> 255) ) {
175 /* Something with only numbers and exactly 3 dots that isn't an IP address can't match anything. */
176 cbp
->flags
|= CHANBAN_INVALID
;
178 cbp
->ipaddr
=(a
<<24)|(b
<<16)|(c
<<8)|d
;
179 cbp
->flags
|= CHANBAN_IP
;
186 } else if (mask
[i
]=='/') {
188 } else if (mask
[i
]=='.') {
190 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
191 if (!foundwild
) /* Mark last wildcard in string */
193 } else if (mask
[i
]<'0' || mask
[i
]>'9') {
199 /* If there wasn't an @, this ban matches any host */
201 cbp
->flags
|= CHANBAN_HOSTANY
;
206 for (i
=0;i
<foundat
;i
++) {
209 /* Invalid mask: nick is empty */
210 cbp
->flags
|= CHANBAN_NICKNULL
;
212 } else if (i
==1 && mask
[0]=='*') {
213 /* matches any nick */
214 cbp
->flags
|= CHANBAN_NICKANY
;
218 /* too long: just take the first NICKLEN chars */
219 cbp
->nick
=getsstring(mask
,NICKLEN
);
221 cbp
->nick
=getsstring(mask
,i
);
224 cbp
->flags
|= CHANBAN_NICKMASK
;
226 cbp
->flags
|= CHANBAN_NICKEXACT
;
230 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
238 /* We didn't find a !, what we do now depends on what happened
241 /* A ban with no ! or @ is treated as a nick ban only */
242 /* Note that we've special-cased "*" at the top, so we can only
243 * hit the MASK or EXACT case here. */
245 cbp
->nick
=getsstring(mask
,NICKLEN
);
247 cbp
->nick
=getsstring(mask
,len
);
250 cbp
->flags
|= CHANBAN_NICKMASK
;
252 cbp
->flags
|= CHANBAN_NICKEXACT
;
254 cbp
->flags
|= (CHANBAN_USERANY
| CHANBAN_HOSTANY
);
258 /* A ban with @ only is treated as user@host */
260 cbp
->flags
|= CHANBAN_NICKANY
;
265 /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
266 /* This is true even if there was no !.. */
267 if (foundat
==(foundbang
+1)) {
268 /* empty ident matches nothing */
269 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_USERNULL
);
271 } else if (foundat
- foundbang
- 1 > USERLEN
) {
272 /* It's too long.. */
273 strncpy(tmpbuf
,&mask
[foundat
-USERLEN
],USERLEN
);
274 tmpbuf
[USERLEN
]='\0';
276 cbp
->user
=getsstring(tmpbuf
,USERLEN
);
277 cbp
->flags
|= CHANBAN_USERMASK
;
278 } else if ((foundat
- foundbang
- 1 == 1) && mask
[foundbang
+1]=='*') {
280 cbp
->flags
|= CHANBAN_USERANY
;
282 cbp
->user
=getsstring(&mask
[foundbang
+1],(foundat
-foundbang
-1));
283 if (strchr(cbp
->user
->content
,'*') || strchr(cbp
->user
->content
,'?'))
284 cbp
->flags
|= CHANBAN_USERMASK
;
286 cbp
->flags
|= CHANBAN_USEREXACT
;
288 /* Username part can't contain an @ */
289 if (cbp
->user
&& strchr(cbp
->user
->content
,'@')) {
290 cbp
->flags
|= CHANBAN_INVALID
;
294 assert(cbp
->flags
& (CHANBAN_USEREXACT
| CHANBAN_USERMASK
| CHANBAN_USERANY
| CHANBAN_USERNULL
));
295 assert(cbp
->flags
& (CHANBAN_NICKEXACT
| CHANBAN_NICKMASK
| CHANBAN_NICKANY
| CHANBAN_NICKNULL
));
296 assert(cbp
->flags
& (CHANBAN_HOSTEXACT
| CHANBAN_HOSTMASK
| CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
));
298 cbp
->timeset
=time(NULL
);
306 * Returns nonzero iff bana is a SUPERSET of banb
309 int banoverlap(const chanban
*bana
, const chanban
*banb
) {
310 /* This function works by looking for cases where bana DOESN'T overlap banb */
313 /* If bana has CHANBAN_NICKANY then it clearly overlaps
314 * in the nick section so there are no checks */
316 if ((bana
->flags
& CHANBAN_NICKNULL
) && !(banb
->flags
& CHANBAN_NICKNULL
)) {
320 if (bana
->flags
& CHANBAN_NICKMASK
) {
321 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKNULL
)) {
324 if ((banb
->flags
& CHANBAN_NICKMASK
) && !match2patterns(bana
->nick
->content
, banb
->nick
->content
)) {
327 if ((banb
->flags
& CHANBAN_NICKEXACT
) && !match2strings(bana
->nick
->content
, banb
->nick
->content
)) {
332 if (bana
->flags
& CHANBAN_NICKEXACT
) {
333 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKMASK
| CHANBAN_NICKNULL
)) {
336 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
)) {
339 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
)) {
345 /* If bana has CHANBAN_USERANY then it clearly overlaps
346 * in the user section so there are no checks */
348 if ((bana
->flags
& CHANBAN_USERNULL
) && !(banb
->flags
& CHANBAN_USERNULL
)) {
352 if (bana
->flags
& CHANBAN_USERMASK
) {
353 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERNULL
)) {
356 if ((banb
->flags
& CHANBAN_USERMASK
) && !match2patterns(bana
->user
->content
, banb
->user
->content
)) {
359 if ((banb
->flags
& CHANBAN_USEREXACT
) && !match2strings(bana
->user
->content
, banb
->user
->content
)) {
364 if (bana
->flags
& CHANBAN_USEREXACT
) {
365 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERMASK
| CHANBAN_USERNULL
)) {
368 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
)) {
371 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
)) {
377 /* If bana has CHANBAN_HOSTANY then it clearly overlaps
378 * in the host section so there are no checks */
380 if ((bana
->flags
& CHANBAN_HOSTNULL
) && !(banb
->flags
& CHANBAN_HOSTNULL
)) {
384 if (bana
->flags
& CHANBAN_HOSTMASK
) {
385 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
)) {
388 if ((banb
->flags
& CHANBAN_HOSTMASK
) && !match2patterns(bana
->host
->content
, banb
->host
->content
)) {
391 if ((banb
->flags
& CHANBAN_HOSTEXACT
) && !match2strings(bana
->host
->content
, banb
->host
->content
)) {
396 if (bana
->flags
& CHANBAN_HOSTEXACT
) {
397 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTMASK
| CHANBAN_HOSTNULL
)) {
400 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
)) {
403 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
)) {
413 * Returns nonzero iff the bans are EXACTLY the same
416 int banequal(chanban
*bana
, chanban
*banb
) {
417 if (bana
->flags
!= banb
->flags
)
420 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
))
423 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
))
426 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
))
429 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
))
432 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
))
435 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
))
443 * Convert the specified ban to a string
446 char *bantostring(chanban
*bp
) {
447 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
450 if (bp
->flags
& CHANBAN_NICKANY
) {
451 strpos
+= sprintf(outstring
+strpos
,"*");
452 } else if (bp
->nick
) {
453 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->nick
->content
);
456 strpos
+= sprintf(outstring
+strpos
,"!");
458 if (bp
->flags
& CHANBAN_USERANY
) {
459 strpos
+= sprintf(outstring
+strpos
,"*");
460 } else if (bp
->user
) {
461 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->user
->content
);
464 strpos
+= sprintf(outstring
+strpos
,"@");
466 if (bp
->flags
& CHANBAN_HOSTANY
) {
467 strpos
+= sprintf(outstring
+strpos
,"*");
468 } else if (bp
->host
) {
469 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->host
->content
);
477 * Convert the specified ban to a string (debugging version)
480 char *bantostringdebug(chanban
*bp
) {
481 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
484 strpos
+= sprintf(outstring
+strpos
, "flags=%04x ",bp
->flags
);
487 strpos
+= sprintf(outstring
+strpos
, "nick=%s ",bp
->nick
->content
);
489 strpos
+= sprintf(outstring
+strpos
, "nonick ");
493 strpos
+= sprintf(outstring
+strpos
, "user=%s ",bp
->user
->content
);
495 strpos
+= sprintf(outstring
+strpos
, "nouser ");
499 strpos
+= sprintf(outstring
+strpos
, "host=%s ",bp
->host
->content
);
501 strpos
+= sprintf(outstring
+strpos
, "nohost ");