]>
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;
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
;
113 /* We have some string with between 1 and HOSTLEN characters.. */
114 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
116 /* If it matches an IP address, flag it as such */
117 if (ipmask_parse(cbp
->host
->content
, &(cbp
->ipaddr
), &(cbp
->prefixlen
))) {
118 cbp
->flags
|= CHANBAN_IP
;
122 /* We check all characters after the last wildcard (if any).. if they match
123 * the corresponding bits of the hidden host string we mark it accordingly */
124 if (!(checklen
=len
-foundwild
-1)) { /* Ban ends in *, mark it anyway.. */
125 cbp
->flags
|= CHANBAN_HIDDENHOST
;
127 if (checklen
>=strlen(HIS_HIDDENHOST
)) {
128 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
))
129 cbp
->flags
|= CHANBAN_HIDDENHOST
;
131 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-checklen
),
132 (HIS_HIDDENHOST
)+strlen(HIS_HIDDENHOST
)-checklen
))
133 cbp
->flags
|= CHANBAN_HIDDENHOST
;
136 cbp
->flags
|= CHANBAN_HOSTMASK
;
138 /* Exact host: see if it ends with the "hidden host" string */
139 cbp
->flags
|= CHANBAN_HOSTEXACT
;
140 if ((cbp
->host
->length
> (strlen(HIS_HIDDENHOST
)+1)) &&
141 !ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
)) {
142 cbp
->flags
|= CHANBAN_HIDDENHOST
;
148 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
149 if (!foundwild
) /* Mark last wildcard in string */
155 /* If there wasn't an @, this ban matches any host */
157 cbp
->flags
|= CHANBAN_HOSTANY
;
162 for (i
=0;i
<foundat
;i
++) {
165 /* Invalid mask: nick is empty */
166 cbp
->flags
|= CHANBAN_NICKNULL
;
168 } else if (i
==1 && mask
[0]=='*') {
169 /* matches any nick */
170 cbp
->flags
|= CHANBAN_NICKANY
;
174 /* too long: just take the first NICKLEN chars */
175 cbp
->nick
=getsstring(mask
,NICKLEN
);
177 cbp
->nick
=getsstring(mask
,i
);
180 cbp
->flags
|= CHANBAN_NICKMASK
;
182 cbp
->flags
|= CHANBAN_NICKEXACT
;
186 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
194 /* We didn't find a !, what we do now depends on what happened
197 /* A ban with no ! or @ is treated as a nick ban only */
198 /* Note that we've special-cased "*" at the top, so we can only
199 * hit the MASK or EXACT case here. */
201 cbp
->nick
=getsstring(mask
,NICKLEN
);
203 cbp
->nick
=getsstring(mask
,len
);
206 cbp
->flags
|= CHANBAN_NICKMASK
;
208 cbp
->flags
|= CHANBAN_NICKEXACT
;
210 cbp
->flags
|= (CHANBAN_USERANY
| CHANBAN_HOSTANY
);
214 /* A ban with @ only is treated as user@host */
216 cbp
->flags
|= CHANBAN_NICKANY
;
221 /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
222 /* This is true even if there was no !.. */
223 if (foundat
==(foundbang
+1)) {
224 /* empty ident matches nothing */
225 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_USERNULL
);
227 } else if (foundat
- foundbang
- 1 > USERLEN
) {
228 /* It's too long.. */
229 strncpy(tmpbuf
,&mask
[foundat
-USERLEN
],USERLEN
);
230 tmpbuf
[USERLEN
]='\0';
232 cbp
->user
=getsstring(tmpbuf
,USERLEN
);
233 cbp
->flags
|= CHANBAN_USERMASK
;
234 } else if ((foundat
- foundbang
- 1 == 1) && mask
[foundbang
+1]=='*') {
236 cbp
->flags
|= CHANBAN_USERANY
;
238 cbp
->user
=getsstring(&mask
[foundbang
+1],(foundat
-foundbang
-1));
239 if (strchr(cbp
->user
->content
,'*') || strchr(cbp
->user
->content
,'?'))
240 cbp
->flags
|= CHANBAN_USERMASK
;
242 cbp
->flags
|= CHANBAN_USEREXACT
;
244 /* Username part can't contain an @ */
245 if (cbp
->user
&& strchr(cbp
->user
->content
,'@')) {
246 cbp
->flags
|= CHANBAN_INVALID
;
250 assert(cbp
->flags
& (CHANBAN_USEREXACT
| CHANBAN_USERMASK
| CHANBAN_USERANY
| CHANBAN_USERNULL
));
251 assert(cbp
->flags
& (CHANBAN_NICKEXACT
| CHANBAN_NICKMASK
| CHANBAN_NICKANY
| CHANBAN_NICKNULL
));
252 assert(cbp
->flags
& (CHANBAN_HOSTEXACT
| CHANBAN_HOSTMASK
| CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
));
254 cbp
->timeset
=time(NULL
);
262 * Returns nonzero iff bana is a SUPERSET of banb
265 int banoverlap(const chanban
*bana
, const chanban
*banb
) {
266 /* This function works by looking for cases where bana DOESN'T overlap banb */
269 /* If bana has CHANBAN_NICKANY then it clearly overlaps
270 * in the nick section so there are no checks */
272 if ((bana
->flags
& CHANBAN_NICKNULL
) && !(banb
->flags
& CHANBAN_NICKNULL
)) {
276 if (bana
->flags
& CHANBAN_NICKMASK
) {
277 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKNULL
)) {
280 if ((banb
->flags
& CHANBAN_NICKMASK
) && !match2patterns(bana
->nick
->content
, banb
->nick
->content
)) {
283 if ((banb
->flags
& CHANBAN_NICKEXACT
) && !match2strings(bana
->nick
->content
, banb
->nick
->content
)) {
288 if (bana
->flags
& CHANBAN_NICKEXACT
) {
289 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKMASK
| CHANBAN_NICKNULL
)) {
292 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
)) {
295 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
)) {
301 /* If bana has CHANBAN_USERANY then it clearly overlaps
302 * in the user section so there are no checks */
304 if ((bana
->flags
& CHANBAN_USERNULL
) && !(banb
->flags
& CHANBAN_USERNULL
)) {
308 if (bana
->flags
& CHANBAN_USERMASK
) {
309 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERNULL
)) {
312 if ((banb
->flags
& CHANBAN_USERMASK
) && !match2patterns(bana
->user
->content
, banb
->user
->content
)) {
315 if ((banb
->flags
& CHANBAN_USEREXACT
) && !match2strings(bana
->user
->content
, banb
->user
->content
)) {
320 if (bana
->flags
& CHANBAN_USEREXACT
) {
321 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERMASK
| CHANBAN_USERNULL
)) {
324 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
)) {
327 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
)) {
333 /* If bana has CHANBAN_HOSTANY then it clearly overlaps
334 * in the host section so there are no checks */
336 if ((bana
->flags
& CHANBAN_HOSTNULL
) && !(banb
->flags
& CHANBAN_HOSTNULL
)) {
340 if (bana
->flags
& CHANBAN_HOSTMASK
) {
341 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
)) {
344 if ((banb
->flags
& CHANBAN_HOSTMASK
) && !match2patterns(bana
->host
->content
, banb
->host
->content
)) {
347 if ((banb
->flags
& CHANBAN_HOSTEXACT
) && !match2strings(bana
->host
->content
, banb
->host
->content
)) {
352 if (bana
->flags
& CHANBAN_HOSTEXACT
) {
353 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTMASK
| CHANBAN_HOSTNULL
)) {
356 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
)) {
359 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
)) {
369 * Returns nonzero iff the bans are EXACTLY the same
372 int banequal(chanban
*bana
, chanban
*banb
) {
373 if (bana
->flags
!= banb
->flags
)
376 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
))
379 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
))
382 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
))
385 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
))
388 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
))
391 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
))
399 * Convert the specified ban to a string
402 char *bantostring(chanban
*bp
) {
403 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
406 if (bp
->flags
& CHANBAN_NICKANY
) {
407 strpos
+= sprintf(outstring
+strpos
,"*");
408 } else if (bp
->nick
) {
409 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->nick
->content
);
412 strpos
+= sprintf(outstring
+strpos
,"!");
414 if (bp
->flags
& CHANBAN_USERANY
) {
415 strpos
+= sprintf(outstring
+strpos
,"*");
416 } else if (bp
->user
) {
417 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->user
->content
);
420 strpos
+= sprintf(outstring
+strpos
,"@");
422 if (bp
->flags
& CHANBAN_HOSTANY
) {
423 strpos
+= sprintf(outstring
+strpos
,"*");
424 } else if (bp
->host
) {
425 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->host
->content
);
433 * Convert the specified ban to a string (debugging version)
436 char *bantostringdebug(chanban
*bp
) {
437 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
440 strpos
+= sprintf(outstring
+strpos
, "flags=%04x ",bp
->flags
);
443 strpos
+= sprintf(outstring
+strpos
, "nick=%s ",bp
->nick
->content
);
445 strpos
+= sprintf(outstring
+strpos
, "nonick ");
449 strpos
+= sprintf(outstring
+strpos
, "user=%s ",bp
->user
->content
);
451 strpos
+= sprintf(outstring
+strpos
, "nouser ");
455 strpos
+= sprintf(outstring
+strpos
, "host=%s ",bp
->host
->content
);
457 strpos
+= sprintf(outstring
+strpos
, "nohost ");