]> jfr.im git - solanum.git/blob - modules/core/m_ban.c
Unify oper:{global,local}_kill
[solanum.git] / modules / core / m_ban.c
1 /*
2 * Solanum: a slightly advanced ircd
3 * m_ban.c: Propagates network bans across servers.
4 *
5 * Copyright (C) 2010 Jilles Tjoelker
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * 1.Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2.Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "stdinc.h"
31 #include "send.h"
32 #include "channel.h"
33 #include "client.h"
34 #include "defaults.h"
35 #include "ircd.h"
36 #include "match.h"
37 #include "s_conf.h"
38 #include "s_newconf.h"
39 #include "msg.h"
40 #include "modules.h"
41 #include "hash.h"
42 #include "s_serv.h"
43 #include "operhash.h"
44 #include "reject.h"
45 #include "hostmask.h"
46 #include "logger.h"
47
48 static const char ban_desc[] = "Provides the TS6 BAN command for propagating network-wide bans";
49
50 static void m_ban(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
51 static void ms_ban(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
52
53 struct Message ban_msgtab = {
54 "BAN", 0, 0, 0, 0,
55 {mg_unreg, {m_ban, 0}, {ms_ban, 9}, {ms_ban, 9}, mg_ignore, {m_ban, 0}}
56 };
57
58 mapi_clist_av1 ban_clist[] = { &ban_msgtab, NULL };
59
60 DECLARE_MODULE_AV2(ban, NULL, NULL, ban_clist, NULL, NULL, NULL, NULL, ban_desc);
61
62 static void
63 m_ban(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
64 {
65 sendto_one_notice(source_p, ":The BAN command is not user-accessible.");
66 sendto_one_notice(source_p, ":To ban a user from a channel, see /QUOTE HELP CMODE");
67 if (IsOperGeneral(source_p))
68 sendto_one_notice(source_p, ":To ban a user from a server or from the network, see /QUOTE HELP KLINE");
69 }
70
71 /* ms_ban()
72 *
73 * parv[1] - type
74 * parv[2] - username mask or *
75 * parv[3] - hostname mask
76 * parv[4] - creation TS
77 * parv[5] - duration (relative to creation)
78 * parv[6] - lifetime (relative to creation)
79 * parv[7] - oper or *
80 * parv[8] - reason (possibly with |operreason)
81 */
82 static void
83 ms_ban(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
84 {
85 rb_dlink_node *ptr;
86 struct ConfItem *aconf;
87 unsigned int ntype;
88 const char *oper, *stype;
89 time_t now, created, hold, lifetime;
90 char *p;
91 int act;
92 int valid;
93
94 now = rb_current_time();
95 if (strlen(parv[1]) != 1)
96 {
97 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
98 "Unknown BAN type %s from %s",
99 parv[1], source_p->name);
100 return;
101 }
102 switch (parv[1][0])
103 {
104 case 'K':
105 ntype = CONF_KILL;
106 stype = "K-Line";
107 break;
108 case 'X':
109 ntype = CONF_XLINE;
110 stype = "X-Line";
111 break;
112 case 'R':
113 ntype = IsChannelName(parv[3]) ? CONF_RESV_CHANNEL :
114 CONF_RESV_NICK;
115 stype = "RESV";
116 break;
117 default:
118 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
119 "Unknown BAN type %s from %s",
120 parv[1], source_p->name);
121 return;
122 }
123 created = atol(parv[4]);
124 hold = created + atoi(parv[5]);
125 lifetime = created + atoi(parv[6]);
126 if (!strcmp(parv[7], "*"))
127 oper = IsServer(source_p) ? source_p->name : get_oper_name(source_p);
128 else
129 oper = parv[7];
130 ptr = find_prop_ban(ntype, parv[2], parv[3]);
131 if (ptr != NULL)
132 {
133 /* We already know about this ban mask. */
134 aconf = ptr->data;
135 if (aconf->created > created ||
136 (aconf->created == created &&
137 aconf->lifetime >= lifetime))
138 {
139 if (IsPerson(source_p))
140 sendto_one_notice(source_p,
141 ":Your %s [%s%s%s] has been superseded",
142 stype,
143 aconf->user ? aconf->user : "",
144 aconf->user ? "@" : "",
145 aconf->host);
146 return;
147 }
148 /* act indicates if something happened (from the oper's
149 * point of view). This is the case if the ban was
150 * previously active (not deleted) or if the new ban
151 * is not a removal and not already expired.
152 */
153 act = !(aconf->status & CONF_ILLEGAL) || (hold != created &&
154 hold > now);
155 if (lifetime > aconf->lifetime)
156 aconf->lifetime = lifetime;
157 /* already expired, hmm */
158 if (aconf->lifetime <= now)
159 return;
160 /* Deactivate, it will be reactivated later if appropriate. */
161 deactivate_conf(aconf, ptr, now);
162 rb_free(aconf->user);
163 aconf->user = NULL;
164 rb_free(aconf->host);
165 aconf->host = NULL;
166 operhash_delete(aconf->info.oper);
167 aconf->info.oper = NULL;
168 rb_free(aconf->passwd);
169 aconf->passwd = NULL;
170 rb_free(aconf->spasswd);
171 aconf->spasswd = NULL;
172 }
173 else
174 {
175 /* New ban mask. */
176 aconf = make_conf();
177 aconf->status = CONF_ILLEGAL | ntype;
178 aconf->lifetime = lifetime;
179 rb_dlinkAddAlloc(aconf, &prop_bans);
180 act = hold != created && hold > now;
181 }
182 aconf->flags &= ~CONF_FLAGS_MYOPER;
183 aconf->flags |= CONF_FLAGS_TEMPORARY;
184 aconf->user = ntype == CONF_KILL ? rb_strdup(parv[2]) : NULL;
185 aconf->host = rb_strdup(parv[3]);
186 aconf->info.oper = operhash_add(oper);
187 aconf->created = created;
188 aconf->hold = hold;
189 if (ntype != CONF_KILL || (p = strchr(parv[parc - 1], '|')) == NULL)
190 aconf->passwd = rb_strdup(parv[parc - 1]);
191 else
192 {
193 aconf->passwd = rb_strndup(parv[parc - 1], p - parv[parc - 1] + 1);
194 aconf->spasswd = rb_strdup(p + 1);
195 }
196 /* The ban is fully filled in and in the prop_bans list
197 * but still deactivated. Now determine if it should be activated
198 * and send the server notices.
199 */
200 /* We only reject *@* and the like here.
201 * Otherwise malformed bans are fairly harmless and can be removed.
202 */
203 switch (ntype)
204 {
205 case CONF_KILL:
206 valid = valid_wild_card(aconf->user, aconf->host);
207 break;
208 case CONF_RESV_CHANNEL:
209 valid = 1;
210 break;
211 default:
212 valid = valid_wild_card_simple(aconf->host);
213 break;
214 }
215 if (act && hold != created && !valid)
216 {
217 sendto_realops_snomask(SNO_GENERAL, L_ALL,
218 "Ignoring global %d min. %s from %s%s%s for [%s%s%s]: too few non-wildcard characters",
219 (int)((hold - now) / 60),
220 stype,
221 IsServer(source_p) ? source_p->name : get_oper_name(source_p),
222 strcmp(parv[7], "*") ? " on behalf of " : "",
223 strcmp(parv[7], "*") ? parv[7] : "",
224 aconf->user ? aconf->user : "",
225 aconf->user ? "@" : "",
226 aconf->host);
227 if(IsPerson(source_p))
228 sendto_one_notice(source_p,
229 ":Your %s [%s%s%s] has too few non-wildcard characters",
230 stype,
231 aconf->user ? aconf->user : "",
232 aconf->user ? "@" : "",
233 aconf->host);
234 /* Propagate it, but do not apply it locally. */
235 }
236 else if (act && hold != created)
237 {
238 /* Keep the notices in sync with modules/m_kline.c etc. */
239 sendto_realops_snomask(SNO_GENERAL, L_ALL,
240 "%s added global %d min. %s%s%s for [%s%s%s] [%s]",
241 IsServer(source_p) ? source_p->name : get_oper_name(source_p),
242 (int)((hold - now) / 60),
243 stype,
244 strcmp(parv[7], "*") ? " from " : "",
245 strcmp(parv[7], "*") ? parv[7] : "",
246 aconf->user ? aconf->user : "",
247 aconf->user ? "@" : "",
248 aconf->host,
249 parv[parc - 1]);
250 ilog(L_KLINE, "%s %s %d %s%s%s %s", parv[1],
251 IsServer(source_p) ? source_p->name : get_oper_name(source_p),
252 (int)((hold - now) / 60),
253 aconf->user ? aconf->user : "",
254 aconf->user ? " " : "",
255 aconf->host,
256 parv[parc - 1]);
257 aconf->status &= ~CONF_ILLEGAL;
258 }
259 else if (act)
260 {
261 sendto_realops_snomask(SNO_GENERAL, L_ALL,
262 "%s has removed the global %s for: [%s%s%s]%s%s",
263 IsServer(source_p) ? source_p->name : get_oper_name(source_p),
264 stype,
265 aconf->user ? aconf->user : "",
266 aconf->user ? "@" : "",
267 aconf->host,
268 strcmp(parv[7], "*") ? " on behalf of " : "",
269 strcmp(parv[7], "*") ? parv[7] : "");
270 ilog(L_KLINE, "U%s %s %s%s %s", parv[1],
271 IsServer(source_p) ? source_p->name : get_oper_name(source_p),
272 aconf->user ? aconf->user : "",
273 aconf->user ? " " : "",
274 aconf->host);
275 }
276 /* If CONF_ILLEGAL is still set at this point, remove entries from the
277 * reject cache (for klines and xlines).
278 * If CONF_ILLEGAL is not set, add the ban to the type-specific data
279 * structure and take action on matched clients/channels.
280 */
281 switch (ntype)
282 {
283 case CONF_KILL:
284 if (aconf->status & CONF_ILLEGAL)
285 remove_reject_mask(aconf->user, aconf->host);
286 else
287 {
288 add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf);
289 check_one_kline(aconf);
290 }
291 break;
292 case CONF_XLINE:
293 if (aconf->status & CONF_ILLEGAL)
294 remove_reject_mask(aconf->host, NULL);
295 else
296 {
297 rb_dlinkAddAlloc(aconf, &xline_conf_list);
298 check_xlines();
299 }
300 break;
301 case CONF_RESV_CHANNEL:
302 if (!(aconf->status & CONF_ILLEGAL))
303 {
304 add_to_resv_hash(aconf->host, aconf);
305 resv_chan_forcepart(aconf->host, aconf->passwd, hold - now);
306 }
307 break;
308 case CONF_RESV_NICK:
309 if (!(aconf->status & CONF_ILLEGAL))
310 rb_dlinkAddAlloc(aconf, &resv_conf_list);
311 break;
312 }
313 sendto_server(client_p, NULL, CAP_BAN|CAP_TS6, NOCAPS,
314 ":%s BAN %s %s %s %s %s %s %s :%s",
315 source_p->id,
316 parv[1],
317 parv[2],
318 parv[3],
319 parv[4],
320 parv[5],
321 parv[6],
322 parv[7],
323 parv[parc - 1]);
324 }