]> jfr.im git - irc/quakenet/newserv.git/blame - bans/bans.c
LOCALUSER: Changed "localinvite" to take a chanindex * to identify the
[irc/quakenet/newserv.git] / bans / bans.c
CommitLineData
11032584 1/* channelbans.c */
2
3#include <assert.h>
4#include <string.h>
5#include <stdio.h>
6#include "bans.h"
7
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"
240bbd21
CP
13#include "../lib/version.h"
14
15MODULE_VERSION("")
11032584 16
17#define ALLOCUNIT 100
18
19chanban *freebans;
20
21void _init() {
22 freebans=NULL;
23}
24
25void _fini() {
26 nsfreeall(POOL_BANS);
27}
28
29chanban *getchanban() {
30 int i;
31 chanban *cbp;
32
33 if (freebans==NULL) {
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]);
37 }
38 freebans[ALLOCUNIT-1].next=NULL;
39 }
40
41 cbp=freebans;
42 freebans=cbp->next;
43
44 cbp->nick=NULL;
45 cbp->user=NULL;
46 cbp->host=NULL;
47
48 return cbp;
49}
50
51void freechanban(chanban *cbp) {
52 cbp->next=(struct chanban *)freebans;
53
54 if (cbp->nick)
55 freesstring(cbp->nick);
56 if (cbp->user)
57 freesstring(cbp->user);
58 if (cbp->host)
59 freesstring(cbp->host);
60
61 freebans=cbp;
62}
63
64/*
65 * makeban:
66 * Converts the specified ban into a ban structure
67 */
68
69chanban *makeban(const char *mask) {
70 int len;
71 int foundat=-1,foundbang=-1;
11032584 72 int foundwild=0;
11032584 73 int i;
74 int checklen;
75 chanban *cbp;
281f454f 76 char tmpbuf[512];
11032584 77
78 cbp=getchanban();
79 len=strlen(mask);
80
81 cbp->flags=0;
82
83 /* Let's catch a silly case first */
84 if (!strcmp(mask,"*")) {
85 cbp->flags=CHANBAN_HOSTANY | CHANBAN_USERANY | CHANBAN_NICKANY;
86 cbp->nick=NULL;
87 cbp->user=NULL;
88 cbp->host=NULL;
89 cbp->timeset=time(NULL);
90 return cbp;
91 }
92
93 for (i=(len-1);i>=0;i--) {
94 if (mask[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 */
281f454f 98 strncpy(tmpbuf,&mask[len-HOSTLEN],HOSTLEN);
99 tmpbuf[HOSTLEN]='\0';
100 tmpbuf[0]='*';
101 cbp->host=getsstring(tmpbuf,HOSTLEN);
11032584 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);
107 cbp->host=NULL;
108 } else if (i==(len-2) && mask[i+1]=='*') {
109 /* Special case: "@*" */
110 cbp->flags |= CHANBAN_HOSTANY;
111 cbp->host=NULL;
11032584 112 } else {
113 /* We have some string with between 1 and HOSTLEN characters.. */
114 cbp->host=getsstring(&mask[i+1],HOSTLEN);
873f4217 115
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;
119 }
120
11032584 121 if (foundwild) {
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;
126 } else {
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;
130 } else {
131 if (!ircd_strcmp(cbp->host->content+(cbp->host->length-checklen),
132 (HIS_HIDDENHOST)+strlen(HIS_HIDDENHOST)-checklen))
133 cbp->flags |= CHANBAN_HIDDENHOST;
134 }
135 }
136 cbp->flags |= CHANBAN_HOSTMASK;
11032584 137 } else {
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)) &&
e340eee8 141 !ircd_strcmp(cbp->host->content+(cbp->host->length-strlen(HIS_HIDDENHOST)), HIS_HIDDENHOST)) {
11032584 142 cbp->flags |= CHANBAN_HIDDENHOST;
e340eee8 143 }
11032584 144 }
145 }
146 foundat=i;
147 break;
11032584 148 } else if (mask[i]=='?' || mask[i]=='*') {
149 if (!foundwild) /* Mark last wildcard in string */
150 foundwild=i;
11032584 151 }
152 }
153
154 if (foundat<0) {
155 /* If there wasn't an @, this ban matches any host */
156 cbp->host=NULL;
157 cbp->flags |= CHANBAN_HOSTANY;
158 }
159
160 foundwild=0;
161
162 for (i=0;i<foundat;i++) {
163 if (mask[i]=='!') {
164 if (i==0) {
165 /* Invalid mask: nick is empty */
166 cbp->flags |= CHANBAN_NICKNULL;
167 cbp->nick=NULL;
168 } else if (i==1 && mask[0]=='*') {
169 /* matches any nick */
170 cbp->flags |= CHANBAN_NICKANY;
171 cbp->nick=NULL;
172 } else {
173 if (i>NICKLEN) {
174 /* too long: just take the first NICKLEN chars */
175 cbp->nick=getsstring(mask,NICKLEN);
176 } else {
177 cbp->nick=getsstring(mask,i);
178 }
179 if (foundwild)
180 cbp->flags |= CHANBAN_NICKMASK;
181 else
182 cbp->flags |= CHANBAN_NICKEXACT;
183 }
184 foundbang=i;
185 break;
186 } else if (mask[i]=='?' || mask[i]=='*') {
187 if (i<NICKLEN) {
188 foundwild=1;
189 }
190 }
191 }
192
193 if (foundbang<0) {
194 /* We didn't find a !, what we do now depends on what happened
195 * with the @ */
196 if (foundat<0) {
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. */
200 if (len>NICKLEN)
201 cbp->nick=getsstring(mask,NICKLEN);
202 else
203 cbp->nick=getsstring(mask,len);
204
205 if (foundwild)
206 cbp->flags |= CHANBAN_NICKMASK;
207 else
208 cbp->flags |= CHANBAN_NICKEXACT;
209
210 cbp->flags |= (CHANBAN_USERANY | CHANBAN_HOSTANY);
211 cbp->host=NULL;
212 cbp->user=NULL;
213 } else {
214 /* A ban with @ only is treated as user@host */
215 cbp->nick=NULL;
216 cbp->flags |= CHANBAN_NICKANY;
217 }
218 }
219
220 if (foundat>=0) {
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);
226 cbp->user=NULL;
227 } else if (foundat - foundbang - 1 > USERLEN) {
228 /* It's too long.. */
281f454f 229 strncpy(tmpbuf,&mask[foundat-USERLEN],USERLEN);
230 tmpbuf[USERLEN]='\0';
231 tmpbuf[0]='*';
232 cbp->user=getsstring(tmpbuf,USERLEN);
11032584 233 cbp->flags |= CHANBAN_USERMASK;
234 } else if ((foundat - foundbang - 1 == 1) && mask[foundbang+1]=='*') {
235 cbp->user=NULL;
236 cbp->flags |= CHANBAN_USERANY;
237 } else {
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;
241 else
242 cbp->flags |= CHANBAN_USEREXACT;
243 }
281f454f 244 /* Username part can't contain an @ */
245 if (cbp->user && strchr(cbp->user->content,'@')) {
246 cbp->flags |= CHANBAN_INVALID;
247 }
11032584 248 }
249
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));
253
254 cbp->timeset=time(NULL);
255
e340eee8 256 cbp->next=NULL;
257
11032584 258 return cbp;
259}
260
261/* banoverlap:
262 * Returns nonzero iff bana is a SUPERSET of banb
263 */
264
265int banoverlap(const chanban *bana, const chanban *banb) {
266 /* This function works by looking for cases where bana DOESN'T overlap banb */
267
268 /* NICK section */
269 /* If bana has CHANBAN_NICKANY then it clearly overlaps
270 * in the nick section so there are no checks */
271
272 if ((bana->flags & CHANBAN_NICKNULL) && !(banb->flags & CHANBAN_NICKNULL)) {
273 return 0;
274 }
275
276 if (bana->flags & CHANBAN_NICKMASK) {
277 if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKNULL)) {
278 return 0;
279 }
280 if ((banb->flags & CHANBAN_NICKMASK) && !match2patterns(bana->nick->content, banb->nick->content)) {
281 return 0;
282 }
283 if ((banb->flags & CHANBAN_NICKEXACT) && !match2strings(bana->nick->content, banb->nick->content)) {
284 return 0;
285 }
286 }
287
288 if (bana->flags & CHANBAN_NICKEXACT) {
289 if (banb->flags & (CHANBAN_NICKANY | CHANBAN_NICKMASK | CHANBAN_NICKNULL)) {
290 return 0;
291 }
292 if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick)) {
293 return 0;
294 }
295 if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content)) {
296 return 0;
297 }
298 }
299
300 /* USER section */
301 /* If bana has CHANBAN_USERANY then it clearly overlaps
302 * in the user section so there are no checks */
303
304 if ((bana->flags & CHANBAN_USERNULL) && !(banb->flags & CHANBAN_USERNULL)) {
305 return 0;
306 }
307
308 if (bana->flags & CHANBAN_USERMASK) {
309 if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERNULL)) {
310 return 0;
311 }
312 if ((banb->flags & CHANBAN_USERMASK) && !match2patterns(bana->user->content, banb->user->content)) {
313 return 0;
314 }
315 if ((banb->flags & CHANBAN_USEREXACT) && !match2strings(bana->user->content, banb->user->content)) {
316 return 0;
317 }
318 }
319
320 if (bana->flags & CHANBAN_USEREXACT) {
321 if (banb->flags & (CHANBAN_USERANY | CHANBAN_USERMASK | CHANBAN_USERNULL)) {
322 return 0;
323 }
324 if ((!bana->user && banb->user) || (bana->user && !banb->user)) {
325 return 0;
326 }
327 if (bana->user && ircd_strcmp(bana->user->content,banb->user->content)) {
328 return 0;
329 }
330 }
331
332 /* HOST section */
333 /* If bana has CHANBAN_HOSTANY then it clearly overlaps
334 * in the host section so there are no checks */
335
336 if ((bana->flags & CHANBAN_HOSTNULL) && !(banb->flags & CHANBAN_HOSTNULL)) {
337 return 0;
338 }
339
340 if (bana->flags & CHANBAN_HOSTMASK) {
341 if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTNULL)) {
342 return 0;
343 }
344 if ((banb->flags & CHANBAN_HOSTMASK) && !match2patterns(bana->host->content, banb->host->content)) {
345 return 0;
346 }
347 if ((banb->flags & CHANBAN_HOSTEXACT) && !match2strings(bana->host->content, banb->host->content)) {
348 return 0;
349 }
350 }
351
352 if (bana->flags & CHANBAN_HOSTEXACT) {
353 if (banb->flags & (CHANBAN_HOSTANY | CHANBAN_HOSTMASK | CHANBAN_HOSTNULL)) {
354 return 0;
355 }
356 if ((!bana->host && banb->host) || (bana->host && !banb->host)) {
357 return 0;
358 }
359 if (bana->host && ircd_strcmp(bana->host->content,banb->host->content)) {
360 return 0;
361 }
362 }
363
364 return 1;
365}
366
367/*
368 * banequal:
369 * Returns nonzero iff the bans are EXACTLY the same
370 */
371
372int banequal(chanban *bana, chanban *banb) {
373 if (bana->flags != banb->flags)
374 return 0;
375
376 if ((!bana->nick && banb->nick) || (bana->nick && !banb->nick))
377 return 0;
378
379 if (bana->nick && ircd_strcmp(bana->nick->content,banb->nick->content))
380 return 0;
381
382 if ((!bana->user && banb->user) || (bana->user && !banb->user))
383 return 0;
384
385 if (bana->user && ircd_strcmp(bana->user->content,banb->user->content))
386 return 0;
387
388 if ((!bana->host && banb->host) || (bana->host && !banb->host))
389 return 0;
390
391 if (bana->host && ircd_strcmp(bana->host->content,banb->host->content))
392 return 0;
393
394 return 1;
395}
396
397/*
398 * bantostring:
399 * Convert the specified ban to a string
400 */
401
402char *bantostring(chanban *bp) {
403 static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
404 int strpos=0;
405
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);
410 }
411
412 strpos += sprintf(outstring+strpos,"!");
413
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);
418 }
419
420 strpos += sprintf(outstring+strpos,"@");
421
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);
426 }
427
428 return outstring;
429}
430
431/*
432 * bantostringdebug:
433 * Convert the specified ban to a string (debugging version)
434 */
435
436char *bantostringdebug(chanban *bp) {
437 static char outstring[NICKLEN+USERLEN+HOSTLEN+5];
438 int strpos=0;
439
440 strpos += sprintf(outstring+strpos, "flags=%04x ",bp->flags);
441
442 if (bp->nick) {
443 strpos += sprintf(outstring+strpos, "nick=%s ",bp->nick->content);
444 } else {
445 strpos += sprintf(outstring+strpos, "nonick ");
446 }
447
448 if (bp->user) {
449 strpos += sprintf(outstring+strpos, "user=%s ",bp->user->content);
450 } else {
451 strpos += sprintf(outstring+strpos, "nouser ");
452 }
453
454 if (bp->host) {
455 strpos += sprintf(outstring+strpos, "host=%s ",bp->host->content);
456 } else {
457 strpos += sprintf(outstring+strpos, "nohost ");
458 }
459
460
461 return outstring;
462}
463