]> jfr.im git - solanum.git/blame - modules/core/m_kill.c
Kill Travis
[solanum.git] / modules / core / m_kill.c
CommitLineData
212380e3
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_kill.c: Kills a user.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
212380e3
AC
23 */
24
25#include "stdinc.h"
26#include "client.h"
27#include "hash.h" /* for find_client() */
28#include "ircd.h"
29#include "numeric.h"
4016731b 30#include "logger.h"
212380e3
AC
31#include "s_serv.h"
32#include "s_conf.h"
33#include "send.h"
34#include "whowas.h"
4562c604 35#include "match.h"
212380e3
AC
36#include "msg.h"
37#include "parse.h"
38#include "modules.h"
39#include "s_newconf.h"
40
eeabf33a
EM
41static const char kill_desc[] = "Provides the KILL command to remove a user from the network";
42
9d745dbd 43static int h_can_kill;
212380e3
AC
44static char buf[BUFSIZE];
45
3c7d6fcc
EM
46static void ms_kill(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void mo_kill(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
212380e3
AC
48static void relay_kill(struct Client *, struct Client *, struct Client *,
49 const char *, const char *);
50
51struct Message kill_msgtab = {
7baa37a9 52 "KILL", 0, 0, 0, 0,
212380e3
AC
53 {mg_unreg, mg_not_oper, {ms_kill, 2}, {ms_kill, 2}, mg_ignore, {mo_kill, 2}}
54};
55
56mapi_clist_av1 kill_clist[] = { &kill_msgtab, NULL };
57
9d745dbd
EM
58mapi_hlist_av1 kill_hlist[] = {
59 { "can_kill", &h_can_kill },
60 { NULL, NULL},
61};
62
ac1b809c 63DECLARE_MODULE_AV2(kill, NULL, NULL, kill_clist, kill_hlist, NULL, NULL, NULL, kill_desc);
212380e3
AC
64
65/*
66** mo_kill
212380e3
AC
67** parv[1] = kill victim
68** parv[2] = kill path
69*/
3c7d6fcc 70static void
428ca87b 71mo_kill(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
72{
73 struct Client *target_p;
74 const char *inpath = client_p->name;
75 const char *user;
76 const char *reason;
9d745dbd 77 hook_data_client_approval moduledata;
212380e3
AC
78
79 user = parv[1];
80
7d84719d 81 if(!IsOperKill(source_p))
212380e3 82 {
7d84719d 83 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "kill");
3c7d6fcc 84 return;
212380e3
AC
85 }
86
87 if(!EmptyString(parv[2]))
88 {
89 char *s;
90 s = LOCAL_COPY(parv[2]);
91 if(strlen(s) > (size_t) KILLLEN)
92 s[KILLLEN] = '\0';
93 reason = s;
94 }
95 else
96 reason = "<No reason given>";
97
98 if((target_p = find_named_person(user)) == NULL)
99 {
100 /*
101 ** If the user has recently changed nick, automatically
102 ** rewrite the KILL for this new nickname--this keeps
103 ** servers in synch when nick change and kill collide
104 */
b47f8a4f 105 if((target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
212380e3
AC
106 {
107 if (strchr(user, '.'))
108 sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
109 else
110 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
111 form_str(ERR_NOSUCHNICK), user);
3c7d6fcc 112 return;
212380e3 113 }
5366977b 114 sendto_one_notice(source_p, ":KILL changed from %s to %s", user, target_p->name);
212380e3
AC
115 }
116
9d745dbd
EM
117 /* Last chance to stop the kill */
118 moduledata.client = source_p;
119 moduledata.target = target_p;
120 moduledata.approved = 1;
121 call_hook(h_can_kill, &moduledata);
122
123 if (moduledata.approved == 0)
373a0439 124 /* The callee should have sent a message. */
3c7d6fcc 125 return;
9d745dbd 126
212380e3
AC
127 if(MyConnect(target_p))
128 sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
129 source_p->name, source_p->username, source_p->host,
130 target_p->name, reason);
131
132 /* Do not change the format of this message. There's no point in changing messages
133 * that have been around for ever, for no reason.. */
134 sendto_realops_snomask(SNO_GENERAL, L_ALL,
8d090389 135 "Received KILL message for %s!%s@%s. From %s Path: %s (%s)",
55abcbb2 136 target_p->name, target_p->username, target_p->orighost,
3dfaa671 137 source_p->name, me.name, reason);
212380e3
AC
138
139 ilog(L_KILL, "%c %s %s!%s@%s %s %s",
140 MyConnect(target_p) ? 'L' : 'G', get_oper_name(source_p),
c88cdb00 141 target_p->name, target_p->username, target_p->host, target_p->servptr->name, reason);
212380e3
AC
142
143 /*
144 ** And pass on the message to other servers. Note, that if KILL
145 ** was changed, the message has to be sent to all links, also
146 ** back.
147 ** Suicide kills are NOT passed on --SRB
148 */
149 if(!MyConnect(target_p))
150 {
151 relay_kill(client_p, source_p, target_p, inpath, reason);
152 /*
153 ** Set FLAGS_KILLED. This prevents exit_one_client from sending
154 ** the unnecessary QUIT for this. (This flag should never be
155 ** set in any other place)
156 */
157 target_p->flags |= FLAGS_KILLED;
158 }
159
5203cba5 160 sprintf(buf, "Killed (%s (%s))", source_p->name, reason);
212380e3
AC
161
162 exit_client(client_p, target_p, source_p, buf);
212380e3
AC
163}
164
165/*
166 * ms_kill
212380e3
AC
167 * parv[1] = kill victim
168 * parv[2] = kill path and reason
169 */
3c7d6fcc 170static void
428ca87b 171ms_kill(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
172{
173 struct Client *target_p;
174 const char *user;
175 const char *reason;
176 char default_reason[] = "<No reason given>";
177 const char *path;
212380e3
AC
178
179 *buf = '\0';
180
181 user = parv[1];
182
183 if(EmptyString(parv[2]))
184 {
185 reason = default_reason;
186
187 /* hyb6 takes the nick of the killer from the path *sigh* --fl_ */
188 path = source_p->name;
189 }
190 else
191 {
192 char *s = LOCAL_COPY(parv[2]), *t;
193 t = strchr(s, ' ');
194
195 if(t)
196 {
197 *t = '\0';
198 t++;
199 reason = t;
200 }
201 else
202 reason = default_reason;
203
204 path = s;
205 }
206
207 if((target_p = find_person(user)) == NULL)
208 {
209 /*
55abcbb2 210 * If the user has recently changed nick, but only if its
212380e3
AC
211 * not an uid, automatically rewrite the KILL for this new nickname.
212 * --this keeps servers in synch when nick change and kill collide
213 */
b47f8a4f 214 if(IsDigit(*user) || (!(target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT))))
212380e3
AC
215 {
216 sendto_one_numeric(source_p, ERR_NOSUCHNICK,
217 form_str(ERR_NOSUCHNICK), IsDigit(*user) ? "*" : user);
3c7d6fcc 218 return;
212380e3
AC
219 }
220 sendto_one_notice(source_p, ":KILL changed from %s to %s", user, target_p->name);
212380e3
AC
221 }
222
223 if(IsServer(target_p) || IsMe(target_p))
224 {
225 sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
3c7d6fcc 226 return;
212380e3
AC
227 }
228
229 if(MyConnect(target_p))
230 {
231 if(IsServer(source_p))
232 {
233 sendto_one(target_p, ":%s KILL %s :%s",
234 source_p->name, target_p->name, reason);
235 }
236 else
237 sendto_one(target_p, ":%s!%s@%s KILL %s :%s",
238 source_p->name, source_p->username, source_p->host,
239 target_p->name, reason);
240 }
241
242 /* Be warned, this message must be From %s, or it confuses clients
243 * so dont change it to From: or the case or anything! -- fl -- db */
244 /* path must contain at least 2 !'s, or bitchx falsely declares it
245 * local --fl
246 */
247 if(IsOper(source_p)) /* send it normally */
248 {
249 sendto_realops_snomask(IsService(source_p) ? SNO_SKILL : SNO_GENERAL, L_ALL,
8d090389 250 "Received KILL message for %s!%s@%s. From %s Path: %s!%s!%s!%s %s",
55abcbb2 251 target_p->name, target_p->username, target_p->orighost, source_p->name,
c88cdb00 252 source_p->servptr->name, source_p->host, source_p->username,
5366977b 253 source_p->name, reason);
212380e3
AC
254
255 ilog(L_KILL, "%c %s %s!%s@%s %s %s",
256 MyConnect(target_p) ? 'O' : 'R', get_oper_name(source_p),
257 target_p->name, target_p->username, target_p->host,
c88cdb00 258 target_p->servptr->name, reason);
212380e3
AC
259 }
260 else
261 {
262 sendto_realops_snomask(SNO_SKILL, L_ALL,
8d090389 263 "Received KILL message for %s!%s@%s. From %s %s",
d1d0629f 264 target_p->name, target_p->username, target_p->orighost,
3dfaa671 265 source_p->name, reason);
212380e3
AC
266
267 ilog(L_KILL, "S %s %s!%s@%s %s %s",
268 source_p->name, target_p->name, target_p->username,
c88cdb00 269 target_p->host, target_p->servptr->name, reason);
212380e3
AC
270 }
271
272 relay_kill(client_p, source_p, target_p, path, reason);
273
274 /* FLAGS_KILLED prevents a quit being sent out */
275 target_p->flags |= FLAGS_KILLED;
276
5203cba5 277 sprintf(buf, "Killed (%s %s)", source_p->name, reason);
212380e3
AC
278
279 exit_client(client_p, target_p, source_p, buf);
212380e3
AC
280}
281
282static void
283relay_kill(struct Client *one, struct Client *source_p,
284 struct Client *target_p, const char *inpath, const char *reason)
285{
286 struct Client *client_p;
5b96d9a6 287 rb_dlink_node *ptr;
212380e3
AC
288 char buffer[BUFSIZE];
289
290 if(MyClient(source_p))
5203cba5 291 snprintf(buffer, sizeof(buffer),
212380e3
AC
292 "%s!%s!%s!%s (%s)",
293 me.name, source_p->host, source_p->username, source_p->name, reason);
294 else
5203cba5 295 snprintf(buffer, sizeof(buffer), "%s %s", inpath, reason);
212380e3 296
5b96d9a6 297 RB_DLINK_FOREACH(ptr, serv_list.head)
212380e3
AC
298 {
299 client_p = ptr->data;
300
301 if(!client_p || client_p == one)
302 continue;
303
304 sendto_one(client_p, ":%s KILL %s :%s",
305 get_id(source_p, client_p), get_id(target_p, client_p), buffer);
306 }
307}