]> jfr.im git - irc/quakenet/newserv.git/blob - channel/channelbans.c
fix makefile of jupe module
[irc/quakenet/newserv.git] / channel / channelbans.c
1 /* channelbans.c */
2
3 #include <assert.h>
4 #include <string.h>
5 #include <stdio.h>
6
7 #include "channel.h"
8 #include "../nick/nick.h"
9 #include "../lib/irc_string.h"
10 #include "../irc/irc_config.h"
11 #include "../irc/irc.h"
12
13 /*
14 * nickmatchban_visible:
15 * Returns true iff the supplied nick* matches the supplied ban*
16 * Doesn't check "invisible" things like true hosts and IPs for
17 * +x/+h users.
18 *
19 * copy & pasted this, touch and go whether this was a good idea.
20 */
21
22 int nickmatchban_visible(nick *np, chanban *bp) {
23 const char *ipstring;
24 char fakehost[HOSTLEN+1];
25 char *visibleident;
26
27 /* Don't waste time on invalid bans */
28 if (bp->flags & CHANBAN_INVALID)
29 return 0;
30
31 /* nick/ident section: return 0 (no match) if they don't match */
32
33 /* Determine the visible ident for sethost users. Don't test the real one. */
34 if (IsSetHost(np) && np->shident && *np->shident->content)
35 visibleident=np->shident->content;
36 else
37 visibleident=np->ident;
38
39 if (bp->flags & CHANBAN_USEREXACT && ircd_strcmp(visibleident,bp->user->content))
40 return 0;
41
42 if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content))
43 return 0;
44
45 if (bp->flags & CHANBAN_USERMASK && !match2strings(bp->user->content,visibleident))
46 return 0;
47
48 if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick))
49 return 0;
50
51 /* host section. Return 1 (match) if they do match
52 * Note that if user or ident was specified, they've already been checked
53 */
54
55 if (bp->flags & CHANBAN_HOSTANY)
56 return 1;
57
58 if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) {
59 unsigned int cip;
60 unsigned char *ch;
61
62 /* CIDR bans don't visibly match sethosted users */
63 if (IsSetHost(np) || (IsAccount(np) && IsHideHost(np)))
64 return 0;
65
66 /* CIDR bans don't match IPv6 hosts */
67 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
68 return 0;
69
70 /* Extract the client's IP address into a usable format */
71 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
72 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
73
74 if ((cip & bp->mask) == bp->ipaddr)
75 return 1;
76
77 return 0; /* A CIDR ban won't match any other way */
78 }
79
80 if (bp->flags & CHANBAN_IP) {
81 /* IP bans don't match sethosted users */
82 if (IsSetHost(np) || (IsAccount(np) && IsHideHost(np)))
83 return 0;
84
85 if (bp->flags & CHANBAN_HOSTEXACT) {
86 /* If it's an exact IP ban we can compare it numerically */
87 unsigned int cip;
88 unsigned char *ch;
89
90 /* Well, it won't match if it's not an IPv4 host */
91 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
92 return 0;
93
94 /* Extract the client's IP address into a usable format */
95 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
96 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
97
98 if (cip==bp->ipaddr)
99 return 1;
100 } else {
101 /* It's not an exact IP ban so let's generate the string */
102 ipstring=IPtostr(np->p_ipaddr);
103
104 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,ipstring))
105 return 1;
106 }
107 } else {
108 /* Hostname bans need to be checked against +x host, +h host (if set)
109 * and actual host. Note that the +x host is only generated (and checked) if it's
110 * possible for the ban to match a hidden host.. */
111
112 if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
113 sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
114
115 if ((bp->flags & CHANBAN_HOSTEXACT) &&
116 !ircd_strcmp(fakehost, bp->host->content))
117 return 1;
118
119 if ((bp->flags & CHANBAN_HOSTMASK) &&
120 match2strings(bp->host->content, fakehost))
121 return 1;
122 }
123
124 if (IsSetHost(np)) {
125 if ((bp->flags & CHANBAN_HOSTEXACT) &&
126 !ircd_strcmp(np->sethost->content, bp->host->content))
127 return 1;
128
129 if ((bp->flags & CHANBAN_HOSTMASK) &&
130 match2strings(bp->host->content, np->sethost->content))
131 return 1;
132 }
133
134 /* If the user is +h or +rx don't check their real host */
135 if (IsSetHost(np) || (IsHideHost(np) && IsAccount(np)))
136 return 0;
137
138 if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
139 return 1;
140
141 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content))
142 return 1;
143 }
144
145 return 0;
146 }
147
148 /*
149 * nickmatchban:
150 * Returns true iff the supplied nick* matches the supplied ban*
151 */
152
153 int nickmatchban(nick *np, chanban *bp) {
154 const char *ipstring;
155 char fakehost[HOSTLEN+1];
156
157 /* nick/ident section: return 0 (no match) if they don't match */
158
159 if (bp->flags & CHANBAN_INVALID)
160 return 0;
161
162 if (bp->flags & CHANBAN_USEREXACT &&
163 ircd_strcmp(np->ident,bp->user->content) &&
164 (!IsSetHost(np) || !np->shident ||
165 ircd_strcmp(np->shident->content,bp->user->content)))
166 return 0;
167
168 if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content))
169 return 0;
170
171 if (bp->flags & CHANBAN_USERMASK &&
172 !match2strings(bp->user->content,np->ident) &&
173 (!IsSetHost(np) || !np->shident ||
174 !match2strings(bp->user->content, np->shident->content)))
175 return 0;
176
177 if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick))
178 return 0;
179
180 /* host section. Return 1 (match) if they do match
181 * Note that if user or ident was specified, they've already been checked
182 */
183
184 if (bp->flags & CHANBAN_HOSTANY)
185 return 1;
186
187 if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) {
188 unsigned int cip;
189 unsigned char *ch;
190
191 /* CIDR bans don't match IPv6 hosts */
192 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
193 return 0;
194
195 /* Extract the client's IP address into a usable format */
196 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
197 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
198
199 if ((cip & bp->mask) == bp->ipaddr)
200 return 1;
201
202 return 0; /* A CIDR ban won't match any other way */
203 }
204
205 if (bp->flags & CHANBAN_IP) {
206 if (bp->flags & CHANBAN_HOSTEXACT) {
207 /* If it's an exact IP ban we can compare it numerically */
208 unsigned int cip;
209 unsigned char *ch;
210
211 /* Well, it won't match if it's not an IPv4 host */
212 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
213 return 0;
214
215 /* Extract the client's IP address into a usable format */
216 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
217 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
218
219 if (cip==bp->ipaddr)
220 return 1;
221 } else {
222 /* It's not an exact IP ban so let's generate the string */
223 ipstring=IPtostr(np->p_ipaddr);
224
225 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,ipstring))
226 return 1;
227 }
228 } else {
229 /* Hostname bans need to be checked against +x host, +h host (if set)
230 * and actual host. Note that the +x host is only generated (and checked) if it's
231 * possible for the ban to match a hidden host.. */
232
233 if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
234 sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
235
236 if ((bp->flags & CHANBAN_HOSTEXACT) &&
237 !ircd_strcmp(fakehost, bp->host->content))
238 return 1;
239
240 if ((bp->flags & CHANBAN_HOSTMASK) &&
241 match2strings(bp->host->content, fakehost))
242 return 1;
243 }
244
245 if (IsSetHost(np)) {
246 if ((bp->flags & CHANBAN_HOSTEXACT) &&
247 !ircd_strcmp(np->sethost->content, bp->host->content))
248 return 1;
249
250 if ((bp->flags & CHANBAN_HOSTMASK) &&
251 match2strings(bp->host->content, np->sethost->content))
252 return 1;
253 }
254
255 if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
256 return 1;
257
258 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content))
259 return 1;
260 }
261
262 return 0;
263 }
264
265 /*
266 * nickbanned:
267 * Returns true iff the supplied nick* is banned on the supplied chan*
268 *
269 * Also nickbanned_visible - doesn't violate privacy by checking hidden
270 * hosts and idents. Factored into one function to reduce copy&paste.
271 */
272 static int nickbanned_real(nick *np, channel *cp, int (*cmpfunc)(nick *, chanban *)) {
273 chanban *cbp;
274
275 for (cbp=cp->bans;cbp;cbp=cbp->next) {
276 if (cmpfunc(np,cbp))
277 return 1;
278 }
279
280 return 0;
281 }
282
283 int nickbanned(nick *np, channel *cp) {
284 return nickbanned_real(np,cp,nickmatchban);
285 }
286
287 int nickbanned_visible(nick *np, channel *cp) {
288 return nickbanned_real(np,cp,nickmatchban_visible);
289 }
290
291 /*
292 * setban:
293 * Set the specified ban; if it completely encloses any existing bans
294 * then remove them.
295 *
296 * Returns 1 if the ban was set, or 0 if the ban was not set because an
297 * existing ban overlapped it.
298 */
299
300 int setban(channel *cp, const char *ban) {
301 chanban **cbh,*cbp,*cbp2;
302
303 cbp=makeban(ban);
304
305 /* Don't set our ban if something encloses it */
306 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
307 if (banoverlap(cbp2, cbp)) {
308 /* This ban overlaps the one we are adding. Abort. */
309 freechanban(cbp);
310 return 0;
311 }
312 }
313
314 /* Remove enclosed bans first */
315 for (cbh=&(cp->bans);*cbh;) {
316 if (banoverlap(cbp,*cbh)) {
317 cbp2=(*cbh);
318 (*cbh)=cbp2->next;
319 freechanban(cbp2);
320 /* Break out of the loop if we just deleted the last ban */
321 if ((*cbh)==NULL) {
322 break;
323 }
324 } else {
325 cbh=(chanban **)&((*cbh)->next);
326 }
327 }
328
329 /* Now set the new ban */
330 cbp->next=(struct chanban *)cp->bans;
331 cp->bans=cbp;
332
333 return 1;
334 }
335
336 /*
337 * clearban:
338 * Remove the specified ban iff an exact match is found
339 * Returns 1 if the ban was cleared, 0 if the ban didn't exist.
340 * If "optional" is 0 and the ban didn't exist, flags an error
341 */
342
343 int clearban(channel *cp, const char *ban, int optional) {
344 chanban **cbh,*cbp,*cbp2;
345 int found=0;
346 int i=0;
347
348 if (!cp)
349 return 0;
350
351 cbp=makeban(ban);
352
353 for (cbh=&(cp->bans);*cbh;cbh=(chanban **)&((*cbh)->next)) {
354 if (banequal(cbp,*cbh)) {
355 cbp2=(*cbh);
356 (*cbh)=cbp2->next;
357 freechanban(cbp2);
358 found=1;
359 break;
360 }
361 }
362
363 if (!found && !optional) {
364 Error("channel",ERR_DEBUG,"Couldn't remove ban %s from %s. Dumping banlist:",ban,cp->index->name->content);
365 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
366 Error("channel",ERR_DEBUG,"%s %d %s",cp->index->name->content, i++, bantostringdebug(cbp2));
367 }
368 }
369
370 freechanban(cbp);
371
372 return found;
373 }
374
375 /*
376 * clearallbans:
377 * Just free all the bans on the channel
378 */
379
380 void clearallbans(channel *cp) {
381 chanban *cbp,*ncbp;
382
383 for (cbp=cp->bans;cbp;cbp=ncbp) {
384 ncbp=(chanban *)cbp->next;
385 freechanban(cbp);
386 }
387
388 cp->bans=NULL;
389 }