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