]> jfr.im git - irc/quakenet/newserv.git/blob - channel/channelbans.c
attempt 2
[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:
15 * Returns true iff the supplied nick* matches the supplied ban*
16 */
17
18 int nickmatchban(nick *np, chanban *bp) {
19 const char *ipstring;
20 char fakehost[HOSTLEN+1];
21
22 /* nick/ident section: return 0 (no match) if they don't match */
23
24 if (bp->flags & CHANBAN_INVALID)
25 return 0;
26
27 if (bp->flags & CHANBAN_USEREXACT &&
28 ircd_strcmp(np->ident,bp->user->content) &&
29 (!IsSetHost(np) || !np->shident ||
30 ircd_strcmp(np->shident->content,bp->user->content)))
31 return 0;
32
33 if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content))
34 return 0;
35
36 if (bp->flags & CHANBAN_USERMASK &&
37 !match2strings(bp->user->content,np->ident) &&
38 (!IsSetHost(np) || !np->shident ||
39 !match2strings(bp->user->content, np->shident->content)))
40 return 0;
41
42 if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick))
43 return 0;
44
45 /* host section. Return 1 (match) if they do match
46 * Note that if user or ident was specified, they've already been checked
47 */
48
49 if (bp->flags & CHANBAN_HOSTANY)
50 return 1;
51
52 if ((bp->flags & CHANBAN_CIDR) && (bp->flags & CHANBAN_HOSTEXACT)) {
53 unsigned int cip;
54 unsigned char *ch;
55
56 /* CIDR bans don't match IPv6 hosts */
57 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
58 return 0;
59
60 /* Extract the client's IP address into a usable format */
61 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
62 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
63
64 if ((cip & bp->mask) == bp->ipaddr)
65 return 1;
66
67 return 0; /* A CIDR ban won't match any other way */
68 }
69
70 if (bp->flags & CHANBAN_IP) {
71 if (bp->flags & CHANBAN_HOSTEXACT) {
72 /* If it's an exact IP ban we can compare it numerically */
73 unsigned int cip;
74 unsigned char *ch;
75
76 /* Well, it won't match if it's not an IPv4 host */
77 if (!irc_in_addr_is_ipv4(&(np->p_ipaddr)))
78 return 0;
79
80 /* Extract the client's IP address into a usable format */
81 ch=(unsigned char *)&(np->p_ipaddr.in6_16[6]);
82 cip=(ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | (ch[3]);
83
84 if (cip==bp->ipaddr)
85 return 1;
86 } else {
87 /* It's not an exact IP ban so let's generate the string */
88 ipstring=IPtostr(np->p_ipaddr);
89
90 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,ipstring))
91 return 1;
92 }
93 } else {
94 /* Hostname bans need to be checked against +x host, +h host (if set)
95 * and actual host. Note that the +x host is only generated (and checked) if it's
96 * possible for the ban to match a hidden host.. */
97
98 if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) {
99 sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST);
100
101 if ((bp->flags & CHANBAN_HOSTEXACT) &&
102 !ircd_strcmp(fakehost, bp->host->content))
103 return 1;
104
105 if ((bp->flags & CHANBAN_HOSTMASK) &&
106 match2strings(bp->host->content, fakehost))
107 return 1;
108 }
109
110 if (IsSetHost(np)) {
111 if ((bp->flags & CHANBAN_HOSTEXACT) &&
112 !ircd_strcmp(np->sethost->content, bp->host->content))
113 return 1;
114
115 if ((bp->flags & CHANBAN_HOSTMASK) &&
116 match2strings(bp->host->content, np->sethost->content))
117 return 1;
118 }
119
120 if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content))
121 return 1;
122
123 if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content))
124 return 1;
125 }
126
127 return 0;
128 }
129
130 /*
131 * nickbanned:
132 * Returns true iff the supplied nick* is banned on the supplied chan*
133 */
134
135 int nickbanned(nick *np, channel *cp) {
136 chanban *cbp;
137
138 for (cbp=cp->bans;cbp;cbp=cbp->next) {
139 if (nickmatchban(np,cbp))
140 return 1;
141 }
142
143 return 0;
144 }
145
146 /*
147 * setban:
148 * Set the specified ban; if it completely encloses any existing bans
149 * then remove them.
150 *
151 * Returns 1 if the ban was set, or 0 if the ban was not set because an
152 * existing ban overlapped it.
153 */
154
155 int setban(channel *cp, const char *ban) {
156 chanban **cbh,*cbp,*cbp2;
157
158 cbp=makeban(ban);
159
160 /* Don't set our ban if something encloses it */
161 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
162 if (banoverlap(cbp2, cbp)) {
163 /* This ban overlaps the one we are adding. Abort. */
164 freechanban(cbp);
165 return 0;
166 }
167 }
168
169 /* Remove enclosed bans first */
170 for (cbh=&(cp->bans);*cbh;) {
171 if (banoverlap(cbp,*cbh)) {
172 cbp2=(*cbh);
173 (*cbh)=cbp2->next;
174 freechanban(cbp2);
175 /* Break out of the loop if we just deleted the last ban */
176 if ((*cbh)==NULL) {
177 break;
178 }
179 } else {
180 cbh=(chanban **)&((*cbh)->next);
181 }
182 }
183
184 /* Now set the new ban */
185 cbp->next=(struct chanban *)cp->bans;
186 cp->bans=cbp;
187
188 return 1;
189 }
190
191 /*
192 * clearban:
193 * Remove the specified ban iff an exact match is found
194 * Returns 1 if the ban was cleared, 0 if the ban didn't exist.
195 * If "optional" is 0 and the ban didn't exist, flags an error
196 */
197
198 int clearban(channel *cp, const char *ban, int optional) {
199 chanban **cbh,*cbp,*cbp2;
200 int found=0;
201 int i=0;
202
203 if (!cp)
204 return 0;
205
206 cbp=makeban(ban);
207
208 for (cbh=&(cp->bans);*cbh;cbh=(chanban **)&((*cbh)->next)) {
209 if (banequal(cbp,*cbh)) {
210 cbp2=(*cbh);
211 (*cbh)=cbp2->next;
212 freechanban(cbp2);
213 found=1;
214 break;
215 }
216 }
217
218 if (!found && !optional) {
219 Error("channel",ERR_DEBUG,"Couldn't remove ban %s from %s. Dumping banlist:",ban,cp->index->name->content);
220 for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) {
221 Error("channel",ERR_DEBUG,"%s %d %s",cp->index->name->content, i++, bantostringdebug(cbp2));
222 }
223 }
224
225 freechanban(cbp);
226
227 return found;
228 }
229
230 /*
231 * clearallbans:
232 * Just free all the bans on the channel
233 */
234
235 void clearallbans(channel *cp) {
236 chanban *cbp,*ncbp;
237
238 for (cbp=cp->bans;cbp;cbp=ncbp) {
239 ncbp=(chanban *)cbp->next;
240 freechanban(cbp);
241 }
242
243 cp->bans=NULL;
244 }