]>
Commit | Line | Data |
---|---|---|
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" | |
873f4217 | 12 | #include "../lib/irc_ipv6.h" |
c86edd1d | 13 | |
795410dd | 14 | /* |
873f4217 | 15 | * nickmatchban: |
795410dd | 16 | * Returns true iff the supplied nick* matches the supplied ban* |
795410dd | 17 | * |
873f4217 | 18 | * "visibleonly" flag indicates that we shouldn't check against the real |
19 | * host if it's masked. | |
795410dd | 20 | */ |
21 | ||
873f4217 | 22 | int nickmatchban(nick *np, chanban *bp, int visibleonly) { |
795410dd | 23 | char fakehost[HOSTLEN+1]; |
873f4217 | 24 | char *ident; |
795410dd | 25 | |
e831c619 | 26 | /* If it's not valid, don't bother */ |
795410dd | 27 | if (bp->flags & CHANBAN_INVALID) |
28 | return 0; | |
29 | ||
e831c619 | 30 | /* nick/ident section: return 0 (no match) if they don't match */ |
31 | ||
873f4217 | 32 | /* Pick up the visible username. If a sethost username is set, the real |
33 | * username is not checked. */ | |
34 | ident=np->ident; | |
35 | if (IsSetHost(np) && np->shident) | |
36 | ident=np->shident->content; | |
795410dd | 37 | |
873f4217 | 38 | if (bp->flags & CHANBAN_USEREXACT && |
39 | ircd_strcmp(ident,bp->user->content)) | |
795410dd | 40 | return 0; |
41 | ||
42 | if (bp->flags & CHANBAN_NICKEXACT && ircd_strcmp(np->nick,bp->nick->content)) | |
43 | return 0; | |
44 | ||
873f4217 | 45 | if (bp->flags & CHANBAN_USERMASK && |
46 | !match2strings(bp->user->content,ident)) | |
795410dd | 47 | return 0; |
48 | ||
49 | if (bp->flags & CHANBAN_NICKMASK && !match2strings(bp->nick->content,np->nick)) | |
873f4217 | 50 | return 0; |
795410dd | 51 | |
52 | /* host section. Return 1 (match) if they do match | |
53 | * Note that if user or ident was specified, they've already been checked | |
54 | */ | |
55 | ||
56 | if (bp->flags & CHANBAN_HOSTANY) | |
57 | return 1; | |
e831c619 | 58 | |
59 | /* "visibleonly" means don't check IP/realhost if they are sethosted/+x. | |
60 | * We change this to mean "Don't check IP/realhost unconditionally" - by | |
61 | * clearing it to 0 if the user isn't sethosted or +x. Simplifies logic | |
62 | * later. */ | |
63 | ||
7c2d4ae7 | 64 | if (!(IsSetHost(np) || (IsAccount(np) && IsHideHost(np)))) |
e831c619 | 65 | visibleonly=0; |
795410dd | 66 | |
e831c619 | 67 | if ((bp->flags & CHANBAN_IP) && !visibleonly) { |
873f4217 | 68 | if (ipmask_check(&(np->ipnode->prefix->sin), &(bp->ipaddr), bp->prefixlen)) |
795410dd | 69 | return 1; |
795410dd | 70 | } |
71 | ||
873f4217 | 72 | /* Hostname bans need to be checked against +x host, +h host (if set) |
73 | * and actual host. Note that the +x host is only generated (and checked) if it's | |
e831c619 | 74 | * possible for the ban to match a hidden host. And it's checked regardless |
75 | * of whether the user is actually +x. */ | |
795410dd | 76 | |
873f4217 | 77 | if ((bp->flags & CHANBAN_HIDDENHOST) && IsAccount(np)) { |
78 | sprintf(fakehost,"%s.%s",np->authname, HIS_HIDDENHOST); | |
79 | ||
80 | if ((bp->flags & CHANBAN_HOSTEXACT) && | |
81 | !ircd_strcmp(fakehost, bp->host->content)) | |
82 | return 1; | |
795410dd | 83 | |
873f4217 | 84 | if ((bp->flags & CHANBAN_HOSTMASK) && |
85 | match2strings(bp->host->content, fakehost)) | |
86 | return 1; | |
87 | } | |
795410dd | 88 | |
873f4217 | 89 | if (IsSetHost(np)) { |
90 | if ((bp->flags & CHANBAN_HOSTEXACT) && | |
795410dd | 91 | !ircd_strcmp(np->sethost->content, bp->host->content)) |
873f4217 | 92 | return 1; |
795410dd | 93 | |
873f4217 | 94 | if ((bp->flags & CHANBAN_HOSTMASK) && |
795410dd | 95 | match2strings(bp->host->content, np->sethost->content)) |
795410dd | 96 | return 1; |
97 | } | |
98 | ||
873f4217 | 99 | /* If we are only checking visible host and the host is somehow masked, don't check |
100 | * against the real one. */ | |
e831c619 | 101 | if (visibleonly) |
c86edd1d Q |
102 | return 0; |
103 | ||
873f4217 | 104 | if (bp->flags & CHANBAN_HOSTEXACT && !ircd_strcmp(np->host->name->content,bp->host->content)) |
c86edd1d | 105 | return 1; |
e340eee8 | 106 | |
873f4217 | 107 | if (bp->flags & CHANBAN_HOSTMASK && match2strings(bp->host->content,np->host->name->content)) |
108 | return 1; | |
c86edd1d Q |
109 | |
110 | return 0; | |
111 | } | |
112 | ||
113 | /* | |
114 | * nickbanned: | |
115 | * Returns true iff the supplied nick* is banned on the supplied chan* | |
795410dd | 116 | * |
873f4217 | 117 | * Pass the visibleonly flag on to nickbanned(). |
c86edd1d | 118 | */ |
873f4217 | 119 | int nickbanned(nick *np, channel *cp, int visibleonly) { |
c86edd1d Q |
120 | chanban *cbp; |
121 | ||
122 | for (cbp=cp->bans;cbp;cbp=cbp->next) { | |
873f4217 | 123 | if (nickmatchban(np,cbp,visibleonly)) |
c86edd1d Q |
124 | return 1; |
125 | } | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | /* | |
131 | * setban: | |
132 | * Set the specified ban; if it completely encloses any existing bans | |
133 | * then remove them. | |
11032584 | 134 | * |
135 | * Returns 1 if the ban was set, or 0 if the ban was not set because an | |
136 | * existing ban overlapped it. | |
c86edd1d Q |
137 | */ |
138 | ||
11032584 | 139 | int setban(channel *cp, const char *ban) { |
c86edd1d Q |
140 | chanban **cbh,*cbp,*cbp2; |
141 | ||
142 | cbp=makeban(ban); | |
143 | ||
11032584 | 144 | /* Don't set our ban if something encloses it */ |
145 | for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) { | |
146 | if (banoverlap(cbp2, cbp)) { | |
147 | /* This ban overlaps the one we are adding. Abort. */ | |
148 | freechanban(cbp); | |
149 | return 0; | |
150 | } | |
151 | } | |
152 | ||
c86edd1d Q |
153 | /* Remove enclosed bans first */ |
154 | for (cbh=&(cp->bans);*cbh;) { | |
155 | if (banoverlap(cbp,*cbh)) { | |
156 | cbp2=(*cbh); | |
157 | (*cbh)=cbp2->next; | |
158 | freechanban(cbp2); | |
159 | /* Break out of the loop if we just deleted the last ban */ | |
160 | if ((*cbh)==NULL) { | |
161 | break; | |
162 | } | |
163 | } else { | |
164 | cbh=(chanban **)&((*cbh)->next); | |
165 | } | |
166 | } | |
167 | ||
168 | /* Now set the new ban */ | |
169 | cbp->next=(struct chanban *)cp->bans; | |
170 | cp->bans=cbp; | |
11032584 | 171 | |
172 | return 1; | |
c86edd1d Q |
173 | } |
174 | ||
175 | /* | |
176 | * clearban: | |
177 | * Remove the specified ban iff an exact match is found | |
178 | * Returns 1 if the ban was cleared, 0 if the ban didn't exist. | |
179 | * If "optional" is 0 and the ban didn't exist, flags an error | |
180 | */ | |
181 | ||
182 | int clearban(channel *cp, const char *ban, int optional) { | |
183 | chanban **cbh,*cbp,*cbp2; | |
184 | int found=0; | |
185 | int i=0; | |
186 | ||
187 | if (!cp) | |
188 | return 0; | |
189 | ||
190 | cbp=makeban(ban); | |
191 | ||
192 | for (cbh=&(cp->bans);*cbh;cbh=(chanban **)&((*cbh)->next)) { | |
193 | if (banequal(cbp,*cbh)) { | |
194 | cbp2=(*cbh); | |
195 | (*cbh)=cbp2->next; | |
196 | freechanban(cbp2); | |
197 | found=1; | |
198 | break; | |
199 | } | |
200 | } | |
201 | ||
202 | if (!found && !optional) { | |
203 | Error("channel",ERR_DEBUG,"Couldn't remove ban %s from %s. Dumping banlist:",ban,cp->index->name->content); | |
204 | for (cbp2=cp->bans;cbp2;cbp2=cbp2->next) { | |
205 | Error("channel",ERR_DEBUG,"%s %d %s",cp->index->name->content, i++, bantostringdebug(cbp2)); | |
206 | } | |
207 | } | |
208 | ||
209 | freechanban(cbp); | |
210 | ||
211 | return found; | |
212 | } | |
213 | ||
214 | /* | |
215 | * clearallbans: | |
216 | * Just free all the bans on the channel | |
217 | */ | |
218 | ||
219 | void clearallbans(channel *cp) { | |
220 | chanban *cbp,*ncbp; | |
221 | ||
222 | for (cbp=cp->bans;cbp;cbp=ncbp) { | |
223 | ncbp=(chanban *)cbp->next; | |
224 | freechanban(cbp); | |
225 | } | |
226 | ||
227 | cp->bans=NULL; | |
228 | } |