]> jfr.im git - irc/quakenet/newserv.git/blame - channel/channelbans.c
CHANNEL: Don't try and match IP addresses against bans with only numbers,
[irc/quakenet/newserv.git] / channel / channelbans.c
CommitLineData
c86edd1d
Q
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
795410dd 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
22int 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. */
a04aa32c 34 if (IsSetHost(np) && np->shident && *np->shident->content)
795410dd 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) {
3d417b1c 86 /* Only exact IP bans are valid */
795410dd 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;
795410dd 100 }
101 } else {
102 /* Hostname bans need to be checked against +x host, +h host (if set)
103 * and actual host. Note that the +x host is only generated (and checked) if it's
104 * possible for the ban to match a hidden host.. */
105
106 if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
107 sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
108
109 if ((bp->flags & CHANBAN_HOSTEXACT) &&
110 !ircd_strcmp(fakehost, bp->host->content))
111 return 1;
112
113 if ((bp->flags & CHANBAN_HOSTMASK) &&
114 match2strings(bp->host->content, fakehost))
115 return 1;
116 }
117
118 if (IsSetHost(np)) {
119 if ((bp->flags & CHANBAN_HOSTEXACT) &&
120 !ircd_strcmp(np->sethost->content, bp->host->content))
121 return 1;
122
123 if ((bp->flags & CHANBAN_HOSTMASK) &&
124 match2strings(bp->host->content, np->sethost->content))
125 return 1;
126 }
127
128 /* If the user is +h or +rx don't check their real host */
129 if (IsSetHost(np) || (IsHideHost(np) && IsAccount(np)))
130 return 0;
131
132 if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
133 return 1;
134
135 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content))
136 return 1;
137 }
138
139 return 0;
140}
141
c86edd1d
Q
142/*
143 * nickmatchban:
144 * Returns true iff the supplied nick* matches the supplied ban*
145 */
146
147int nickmatchban(nick *np, chanban *bp) {
148 const char *ipstring;
149 char fakehost[HOSTLEN+1];
150
151 /* nick/ident section: return 0 (no match) if they don't match */
152
153 if (bp->flags & CHANBAN_INVALID)
154 return 0;
155
156 if (bp->flags & CHANBAN_USEREXACT &&
157 ircd_strcmp(np->ident,bp->user->content) &&
158 (!IsSetHost(np) || !np->shident ||
159 ircd_strcmp(np->shident->content,bp->user->content)))
160 return 0;
161
162 if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content))
163 return 0;
164
165 if (bp->flags & CHANBAN_USERMASK &&
166 !match2strings(bp->user->content,np->ident) &&
167 (!IsSetHost(np) || !np->shident ||
168 !match2strings(bp->user->content, np->shident->content)))
169 return 0;
170
171 if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick))
172 return 0;
173
174 /* host section. Return 1 (match) if they do match
175 * Note that if user or ident was specified, they've already been checked
176 */
177
178 if (bp->flags & CHANBAN_HOSTANY)
179 return 1;
180
e340eee8 181 if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) {
182 unsigned int cip;
183 unsigned char *ch;
184
185 /* CIDR bans don't match IPv6 hosts */
186 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
187 return 0;
188
189 /* Extract the client's IP address into a usable format */
190 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
191 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
192
193 if ((cip & bp->mask) == bp->ipaddr)
c86edd1d
Q
194 return 1;
195
e340eee8 196 return 0; /* A CIDR ban won't match any other way */
197 }
198
199 if (bp->flags & CHANBAN_IP) {
200 if (bp->flags & CHANBAN_HOSTEXACT) {
3d417b1c 201 /* Only exact matches for IP bans */
e340eee8 202 unsigned int cip;
203 unsigned char *ch;
204
205 /* Well, it won't match if it's not an IPv4 host */
206 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
207 return 0;
208
209 /* Extract the client's IP address into a usable format */
210 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
211 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
212
213 if (cip==bp->ipaddr)
214 return 1;
e340eee8 215 }
c86edd1d
Q
216 } else {
217 /* Hostname bans need to be checked against +x host, +h host (if set)
218 * and actual host. Note that the +x host is only generated (and checked) if it's
219 * possible for the ban to match a hidden host.. */
220
221 if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
222 sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
223
224 if ((bp->flags & CHANBAN_HOSTEXACT) &&
225 !ircd_strcmp(fakehost, bp->host->content))
226 return 1;
227
228 if ((bp->flags & CHANBAN_HOSTMASK) &&
229 match2strings(bp->host->content, fakehost))
230 return 1;
231 }
232
233 if (IsSetHost(np)) {
234 if ((bp->flags & CHANBAN_HOSTEXACT) &&
235 !ircd_strcmp(np->sethost->content, bp->host->content))
236 return 1;
237
238 if ((bp->flags & CHANBAN_HOSTMASK) &&
239 match2strings(bp->host->content, np->sethost->content))
240 return 1;
241 }
242
243 if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
244 return 1;
245
246 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content))
247 return 1;
248 }
249
250 return 0;
251}
252
253/*
254 * nickbanned:
255 * Returns true iff the supplied nick* is banned on the supplied chan*
795410dd 256 *
257 * Also nickbanned_visible - doesn't violate privacy by checking hidden
258 * hosts and idents. Factored into one function to reduce copy&paste.
c86edd1d 259 */
795410dd 260static int nickbanned_real(nick *np, channel *cp, int (*cmpfunc)(nick *, chanban *)) {
c86edd1d
Q
261 chanban *cbp;
262
263 for (cbp=cp->bans;cbp;cbp=cbp->next) {
795410dd 264 if (cmpfunc(np,cbp))
c86edd1d
Q
265 return 1;
266 }
267
268 return 0;
269}
795410dd 270
271int nickbanned(nick *np, channel *cp) {
272 return nickbanned_real(np,cp,nickmatchban);
273}
274
275int nickbanned_visible(nick *np, channel *cp) {
276 return nickbanned_real(np,cp,nickmatchban_visible);
277}
c86edd1d
Q
278
279/*
280 * setban:
281 * Set the specified ban; if it completely encloses any existing bans
282 * then remove them.
11032584 283 *
284 * Returns 1 if the ban was set, or 0 if the ban was not set because an
285 * existing ban overlapped it.
c86edd1d
Q
286 */
287
11032584 288int setban(channel *cp, const char *ban) {
c86edd1d
Q
289 chanban **cbh,*cbp,*cbp2;
290
291 cbp=makeban(ban);
292
11032584 293 /* Don't set our ban if something encloses it */
294 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
295 if (banoverlap(cbp2, cbp)) {
296 /* This ban overlaps the one we are adding. Abort. */
297 freechanban(cbp);
298 return 0;
299 }
300 }
301
c86edd1d
Q
302 /* Remove enclosed bans first */
303 for (cbh=&(cp->bans);*cbh;) {
304 if (banoverlap(cbp,*cbh)) {
305 cbp2=(*cbh);
306 (*cbh)=cbp2->next;
307 freechanban(cbp2);
308 /* Break out of the loop if we just deleted the last ban */
309 if ((*cbh)==NULL) {
310 break;
311 }
312 } else {
313 cbh=(chanban **)&((*cbh)->next);
314 }
315 }
316
317 /* Now set the new ban */
318 cbp->next=(struct chanban *)cp->bans;
319 cp->bans=cbp;
11032584 320
321 return 1;
c86edd1d
Q
322}
323
324/*
325 * clearban:
326 * Remove the specified ban iff an exact match is found
327 * Returns 1 if the ban was cleared, 0 if the ban didn't exist.
328 * If "optional" is 0 and the ban didn't exist, flags an error
329 */
330
331int clearban(channel *cp, const char *ban, int optional) {
332 chanban **cbh,*cbp,*cbp2;
333 int found=0;
334 int i=0;
335
336 if (!cp)
337 return 0;
338
339 cbp=makeban(ban);
340
341 for (cbh=&(cp->bans);*cbh;cbh=(chanban **)&((*cbh)->next)) {
342 if (banequal(cbp,*cbh)) {
343 cbp2=(*cbh);
344 (*cbh)=cbp2->next;
345 freechanban(cbp2);
346 found=1;
347 break;
348 }
349 }
350
351 if (!found && !optional) {
352 Error("channel",ERR_DEBUG,"Couldn't remove ban %s from %s. Dumping banlist:",ban,cp->index->name->content);
353 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
354 Error("channel",ERR_DEBUG,"%s %d %s",cp->index->name->content, i++, bantostringdebug(cbp2));
355 }
356 }
357
358 freechanban(cbp);
359
360 return found;
361}
362
363/*
364 * clearallbans:
365 * Just free all the bans on the channel
366 */
367
368void clearallbans(channel *cp) {
369 chanban *cbp,*ncbp;
370
371 for (cbp=cp->bans;cbp;cbp=ncbp) {
372 ncbp=(chanban *)cbp->next;
373 freechanban(cbp);
374 }
375
376 cp->bans=NULL;
377}