]>
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"
21 chanban
*getchanban() {
24 cbp
= nsmalloc(POOL_BANS
, sizeof(chanban
));
35 void freechanban(chanban
*cbp
) {
36 freesstring(cbp
->nick
);
37 freesstring(cbp
->user
);
38 freesstring(cbp
->host
);
40 nsfree(POOL_BANS
, cbp
);
45 * Converts the specified ban into a ban structure
48 chanban
*makeban(const char *mask
) {
50 int foundat
=-1,foundbang
=-1;
62 /* Let's catch a silly case first */
63 if (!strcmp(mask
,"*")) {
64 cbp
->flags
=CHANBAN_HOSTANY
| CHANBAN_USERANY
| CHANBAN_NICKANY
;
68 cbp
->timeset
=time(NULL
);
72 for (i
=(len
-1);i
>=0;i
--) {
74 /* Got @ sign: everything after here is host */
75 if ((len
-i
)-1 > HOSTLEN
) {
76 /* This is too long, we need to truncate it */
77 strncpy(tmpbuf
,&mask
[len
-HOSTLEN
],HOSTLEN
);
80 cbp
->host
=getsstring(tmpbuf
,HOSTLEN
);
81 cbp
->flags
|= CHANBAN_HOSTMASK
;
82 } else if (i
==(len
-1)) {
83 /* Ban ending with @, just mark it invalid */
84 /* Note that "moo@*" overrides "moo@", so mark it as having a host too */
85 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_HOSTNULL
);
87 } else if (i
==(len
-2) && mask
[i
+1]=='*') {
88 /* Special case: "@*" */
89 cbp
->flags
|= CHANBAN_HOSTANY
;
92 /* We have some string with between 1 and HOSTLEN characters.. */
93 cbp
->host
=getsstring(&mask
[i
+1],HOSTLEN
);
95 /* If it matches an IP address, flag it as such */
96 if (ipmask_parse(cbp
->host
->content
, &(cbp
->ipaddr
), &(cbp
->prefixlen
))) {
97 cbp
->flags
|= CHANBAN_IP
;
101 /* We check all characters after the last wildcard (if any).. if they match
102 * the corresponding bits of the hidden host string we mark it accordingly */
103 if (!(checklen
=len
-foundwild
-1)) { /* Ban ends in *, mark it anyway.. */
104 cbp
->flags
|= CHANBAN_HIDDENHOST
;
106 if (checklen
>=strlen(HIS_HIDDENHOST
)) {
107 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
))
108 cbp
->flags
|= CHANBAN_HIDDENHOST
;
110 if (!ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-checklen
),
111 (HIS_HIDDENHOST
)+strlen(HIS_HIDDENHOST
)-checklen
))
112 cbp
->flags
|= CHANBAN_HIDDENHOST
;
115 cbp
->flags
|= CHANBAN_HOSTMASK
;
117 /* Exact host: see if it ends with the "hidden host" string */
118 cbp
->flags
|= CHANBAN_HOSTEXACT
;
119 if ((cbp
->host
->length
> (strlen(HIS_HIDDENHOST
)+1)) &&
120 !ircd_strcmp(cbp
->host
->content
+(cbp
->host
->length
-strlen(HIS_HIDDENHOST
)), HIS_HIDDENHOST
)) {
121 cbp
->flags
|= CHANBAN_HIDDENHOST
;
127 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
128 if (!foundwild
) /* Mark last wildcard in string */
134 /* If there wasn't an @, this ban matches any host */
136 cbp
->flags
|= CHANBAN_HOSTANY
;
141 for (i
=0;i
<foundat
;i
++) {
144 /* Invalid mask: nick is empty */
145 cbp
->flags
|= CHANBAN_NICKNULL
;
147 } else if (i
==1 && mask
[0]=='*') {
148 /* matches any nick */
149 cbp
->flags
|= CHANBAN_NICKANY
;
153 /* too long: just take the first NICKLEN chars */
154 cbp
->nick
=getsstring(mask
,NICKLEN
);
156 cbp
->nick
=getsstring(mask
,i
);
159 cbp
->flags
|= CHANBAN_NICKMASK
;
161 cbp
->flags
|= CHANBAN_NICKEXACT
;
165 } else if (mask
[i
]=='?' || mask
[i
]=='*') {
173 /* We didn't find a !, what we do now depends on what happened
176 /* A ban with no ! or @ is treated as a nick ban only */
177 /* Note that we've special-cased "*" at the top, so we can only
178 * hit the MASK or EXACT case here. */
180 cbp
->nick
=getsstring(mask
,NICKLEN
);
182 cbp
->nick
=getsstring(mask
,len
);
185 cbp
->flags
|= CHANBAN_NICKMASK
;
187 cbp
->flags
|= CHANBAN_NICKEXACT
;
189 cbp
->flags
|= (CHANBAN_USERANY
| CHANBAN_HOSTANY
);
193 /* A ban with @ only is treated as user@host */
195 cbp
->flags
|= CHANBAN_NICKANY
;
200 /* We found an @, so everything between foundbang+1 and foundat-1 is supposed to be ident */
201 /* This is true even if there was no !.. */
202 if (foundat
==(foundbang
+1)) {
203 /* empty ident matches nothing */
204 cbp
->flags
|= (CHANBAN_INVALID
| CHANBAN_USERNULL
);
206 } else if (foundat
- foundbang
- 1 > USERLEN
) {
207 /* It's too long.. */
208 strncpy(tmpbuf
,&mask
[foundat
-USERLEN
],USERLEN
);
209 tmpbuf
[USERLEN
]='\0';
211 cbp
->user
=getsstring(tmpbuf
,USERLEN
);
212 cbp
->flags
|= CHANBAN_USERMASK
;
213 } else if ((foundat
- foundbang
- 1 == 1) && mask
[foundbang
+1]=='*') {
215 cbp
->flags
|= CHANBAN_USERANY
;
217 cbp
->user
=getsstring(&mask
[foundbang
+1],(foundat
-foundbang
-1));
218 if (strchr(cbp
->user
->content
,'*') || strchr(cbp
->user
->content
,'?'))
219 cbp
->flags
|= CHANBAN_USERMASK
;
221 cbp
->flags
|= CHANBAN_USEREXACT
;
223 /* Username part can't contain an @ */
224 if (cbp
->user
&& strchr(cbp
->user
->content
,'@')) {
225 cbp
->flags
|= CHANBAN_INVALID
;
229 assert(cbp
->flags
& (CHANBAN_USEREXACT
| CHANBAN_USERMASK
| CHANBAN_USERANY
| CHANBAN_USERNULL
));
230 assert(cbp
->flags
& (CHANBAN_NICKEXACT
| CHANBAN_NICKMASK
| CHANBAN_NICKANY
| CHANBAN_NICKNULL
));
231 assert(cbp
->flags
& (CHANBAN_HOSTEXACT
| CHANBAN_HOSTMASK
| CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
));
233 cbp
->timeset
=time(NULL
);
241 * Returns nonzero iff bana is a SUPERSET of banb
244 int banoverlap(const chanban
*bana
, const chanban
*banb
) {
245 /* This function works by looking for cases where bana DOESN'T overlap banb */
248 /* If bana has CHANBAN_NICKANY then it clearly overlaps
249 * in the nick section so there are no checks */
251 if ((bana
->flags
& CHANBAN_NICKNULL
) && !(banb
->flags
& CHANBAN_NICKNULL
)) {
255 if (bana
->flags
& CHANBAN_NICKMASK
) {
256 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKNULL
)) {
259 if ((banb
->flags
& CHANBAN_NICKMASK
) && !match2patterns(bana
->nick
->content
, banb
->nick
->content
)) {
262 if ((banb
->flags
& CHANBAN_NICKEXACT
) && !match2strings(bana
->nick
->content
, banb
->nick
->content
)) {
267 if (bana
->flags
& CHANBAN_NICKEXACT
) {
268 if (banb
->flags
& (CHANBAN_NICKANY
| CHANBAN_NICKMASK
| CHANBAN_NICKNULL
)) {
271 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
)) {
274 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
)) {
280 /* If bana has CHANBAN_USERANY then it clearly overlaps
281 * in the user section so there are no checks */
283 if ((bana
->flags
& CHANBAN_USERNULL
) && !(banb
->flags
& CHANBAN_USERNULL
)) {
287 if (bana
->flags
& CHANBAN_USERMASK
) {
288 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERNULL
)) {
291 if ((banb
->flags
& CHANBAN_USERMASK
) && !match2patterns(bana
->user
->content
, banb
->user
->content
)) {
294 if ((banb
->flags
& CHANBAN_USEREXACT
) && !match2strings(bana
->user
->content
, banb
->user
->content
)) {
299 if (bana
->flags
& CHANBAN_USEREXACT
) {
300 if (banb
->flags
& (CHANBAN_USERANY
| CHANBAN_USERMASK
| CHANBAN_USERNULL
)) {
303 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
)) {
306 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
)) {
312 /* If bana has CHANBAN_HOSTANY then it clearly overlaps
313 * in the host section so there are no checks */
315 if ((bana
->flags
& CHANBAN_HOSTNULL
) && !(banb
->flags
& CHANBAN_HOSTNULL
)) {
319 if (bana
->flags
& CHANBAN_HOSTMASK
) {
320 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTNULL
)) {
323 if ((banb
->flags
& CHANBAN_HOSTMASK
) && !match2patterns(bana
->host
->content
, banb
->host
->content
)) {
326 if ((banb
->flags
& CHANBAN_HOSTEXACT
) && !match2strings(bana
->host
->content
, banb
->host
->content
)) {
331 if (bana
->flags
& CHANBAN_HOSTEXACT
) {
332 if (banb
->flags
& (CHANBAN_HOSTANY
| CHANBAN_HOSTMASK
| CHANBAN_HOSTNULL
)) {
335 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
)) {
338 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
)) {
348 * Returns nonzero iff the bans are EXACTLY the same
351 int banequal(chanban
*bana
, chanban
*banb
) {
352 if (bana
->flags
!= banb
->flags
)
355 if ((!bana
->nick
&& banb
->nick
) || (bana
->nick
&& !banb
->nick
))
358 if (bana
->nick
&& ircd_strcmp(bana
->nick
->content
,banb
->nick
->content
))
361 if ((!bana
->user
&& banb
->user
) || (bana
->user
&& !banb
->user
))
364 if (bana
->user
&& ircd_strcmp(bana
->user
->content
,banb
->user
->content
))
367 if ((!bana
->host
&& banb
->host
) || (bana
->host
&& !banb
->host
))
370 if (bana
->host
&& ircd_strcmp(bana
->host
->content
,banb
->host
->content
))
378 * Convert the specified ban to a string
381 char *bantostring(chanban
*bp
) {
382 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
385 if (bp
->flags
& CHANBAN_NICKANY
) {
386 strpos
+= sprintf(outstring
+strpos
,"*");
387 } else if (bp
->nick
) {
388 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->nick
->content
);
391 strpos
+= sprintf(outstring
+strpos
,"!");
393 if (bp
->flags
& CHANBAN_USERANY
) {
394 strpos
+= sprintf(outstring
+strpos
,"*");
395 } else if (bp
->user
) {
396 strpos
+= sprintf(outstring
+strpos
,"%s",bp
->user
->content
);
399 strpos
+= sprintf(outstring
+strpos
,"@");
401 if (bp
->flags
& CHANBAN_HOSTANY
) {
402 sprintf(outstring
+strpos
,"*");
403 } else if (bp
->host
) {
404 sprintf(outstring
+strpos
,"%s",bp
->host
->content
);
412 * Convert the specified ban to a string (debugging version)
415 char *bantostringdebug(chanban
*bp
) {
416 static char outstring
[NICKLEN
+USERLEN
+HOSTLEN
+5];
419 strpos
+= sprintf(outstring
+strpos
, "flags=%04x ",bp
->flags
);
422 strpos
+= sprintf(outstring
+strpos
, "nick=%s ",bp
->nick
->content
);
424 strpos
+= sprintf(outstring
+strpos
, "nonick ");
428 strpos
+= sprintf(outstring
+strpos
, "user=%s ",bp
->user
->content
);
430 strpos
+= sprintf(outstring
+strpos
, "nouser ");
434 sprintf(outstring
+strpos
, "host=%s ",bp
->host
->content
);
436 sprintf(outstring
+strpos
, "nohost ");