1 /*
2 * IRC - Internet Relay Chat, src/modules/m_kick.c
3 * (C) 2004 The UnrealIRCd Team
4 *
5 * See file AUTHORS in IRC package for additional names of
6 * the programmers.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 #include "config.h"
23 #include "struct.h"
24 #include "common.h"
25 #include "sys.h"
26 #include "numeric.h"
27 #include "msg.h"
28 #include "proto.h"
29 #include "channel.h"
30 #include <time.h>
31 #include <sys/stat.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #ifdef _WIN32
36 #include <io.h>
37 #endif
38 #include <fcntl.h>
39 #include "h.h"
40 #ifdef STRIPBADWORDS
41 #include "badwords.h"
42 #endif
43 #ifdef _WIN32
44 #include "version.h"
45 #endif
46
47 DLLFUNC int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[]);
48
49 #define MSG_KICK "KICK"
50 #define TOK_KICK "H"
51
52 ModuleHeader MOD_HEADER(m_kick)
53 = {
54 "m_kick",
55 "$Id$",
56 "command /kick",
57 "3.2-b8-1",
58 NULL
59 };
60
MOD_INIT(m_kick)61 DLLFUNC int MOD_INIT(m_kick)(ModuleInfo *modinfo)
62 {
63 add_Command(MSG_KICK, TOK_KICK, m_kick, 3);
64 MARK_AS_OFFICIAL_MODULE(modinfo);
65 return MOD_SUCCESS;
66 }
67
MOD_LOAD(m_kick)68 DLLFUNC int MOD_LOAD(m_kick)(int module_load)
69 {
70 return MOD_SUCCESS;
71 }
72
MOD_UNLOAD(m_kick)73 DLLFUNC int MOD_UNLOAD(m_kick)(int module_unload)
74 {
75 if (del_Command(MSG_KICK, TOK_KICK, m_kick) < 0)
76 {
77 sendto_realops("Failed to delete commands when unloading %s",
78 MOD_HEADER(m_kick).name);
79 }
80 return MOD_SUCCESS;
81 }
82
83 /*
84 ** m_kick
85 ** parv[0] = sender prefix
86 ** parv[1] = channel
87 ** parv[2] = client to kick
88 ** parv[3] = kick comment
89 */
90
91 #ifdef PREFIX_AQ
92 #define CHFL_ISOP (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP)
93 #else
94 #define CHFL_ISOP (CHFL_CHANOP)
95 #endif
96
CMD_FUNC(m_kick)97 CMD_FUNC(m_kick)
98 {
99 aClient *who;
100 aChannel *chptr;
101 int chasing = 0;
102 char *comment, *name, *p = NULL, *user, *p2 = NULL;
103 Membership *lp;
104
105 if (parc < 3 || *parv[1] == '\0')
106 {
107 sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
108 me.name, parv[0], "KICK");
109 return 0;
110 }
111
112 comment = (BadPtr(parv[3])) ? parv[0] : parv[3];
113
114 if (strlen(comment) > (size_t)TOPICLEN)
115 comment[TOPICLEN] = '\0';
116
117 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
118 {
119 long sptr_flags = 0;
120 chptr = get_channel(sptr, name, !CREATE);
121 if (!chptr)
122 {
123 sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
124 me.name, parv[0], name);
125 continue;
126 }
127 if (check_channelmask(sptr, cptr, name))
128 continue;
129 /* Store "sptr" access flags */
130 if (IsPerson(sptr))
131 sptr_flags = get_access(sptr, chptr);
132 if (!IsServer(cptr) && !IsULine(sptr) && !op_can_override(sptr)
133 && !(sptr_flags & CHFL_ISOP) && !(sptr_flags & CHFL_HALFOP))
134 {
135 sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
136 me.name, parv[0], chptr->chname);
137 continue;
138 }
139
140 for (; (user = strtoken(&p2, parv[2], ",")); parv[2] = NULL)
141 {
142 long who_flags;
143 if (!(who = find_chasing(sptr, user, &chasing)))
144 continue; /* No such user left! */
145 if (!who->user)
146 continue;
147 if ((lp = find_membership_link(who->user->channel, chptr)))
148 {
149 if (IsULine(sptr) || IsServer(sptr))
150 goto attack;
151
152 /* Note for coders regarding oper override:
153 * always let a remote kick (=from a user on another server) through or
154 * else we will get desynched. In short this means all the denying should
155 * always contain a && MyClient(sptr) [or sptr!=cptr] and at the end
156 * a remote kick should always be allowed (pass through). -- Syzop
157 */
158
159 /* applies to everyone (well except remote/ulines :p) */
160 if (IsKix(who) && !IsULine(sptr) && MyClient(sptr))
161 {
162 if (!IsNetAdmin(sptr))
163 {
164 char errbuf[NICKLEN+10];
165 ircsprintf(errbuf, "%s is +q", who->name);
166 sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND),
167 me.name, sptr->name, "KICK",
168 errbuf);
169 sendto_one(who,
170 ":%s %s %s :*** q: %s tried to kick you from channel %s (%s)",
171 me.name, IsWebTV(who) ? "PRIVMSG" : "NOTICE", who->name,
172 parv[0],
173 chptr->chname, comment);
174 goto deny;
175 }
176 }
177
178 if (chptr->mode.mode & MODE_NOKICKS)
179 {
180 if (!op_can_override(sptr))
181 {
182 if (!MyClient(sptr))
183 goto attack; /* lag? yes.. kick crossing +Q... allow */
184 sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND),
185 me.name, sptr->name, "KICK",
186 "channel is +Q");
187 goto deny;
188 }
189 sendto_snomask(SNO_EYES,
190 "*** OperOverride -- %s (%s@%s) KICK %s %s (%s)",
191 sptr->name, sptr->user->username, sptr->user->realhost,
192 chptr->chname, who->name, comment);
193 ircd_log(LOG_OVERRIDE,"OVERRIDE: %s (%s@%s) KICK %s %s (%s)",
194 sptr->name, sptr->user->username, sptr->user->realhost,
195 chptr->chname, who->name, comment);
196 goto attack; /* No reason to continue.. */
197 }
198 /* Store "who" access flags */
199 who_flags = get_access(who, chptr);
200 /* we are neither +o nor +h, OR..
201 * we are +h but victim is +o, OR...
202 * we are +h and victim is +h
203 */
204 if (op_can_override(sptr))
205 {
206 if ((!(sptr_flags & CHFL_ISOP) && !(sptr_flags & CHFL_HALFOP)) ||
207 ((sptr_flags & CHFL_HALFOP) && (who_flags & CHFL_ISOP)) ||
208 ((sptr_flags & CHFL_HALFOP) && (who_flags & CHFL_HALFOP)))
209 {
210 sendto_snomask(SNO_EYES,
211 "*** OperOverride -- %s (%s@%s) KICK %s %s (%s)",
212 sptr->name, sptr->user->username, sptr->user->realhost,
213 chptr->chname, who->name, comment);
214
215 /* Logging Implementation added by XeRXeS */
216 ircd_log(LOG_OVERRIDE,"OVERRIDE: %s (%s@%s) KICK %s %s (%s)",
217 sptr->name, sptr->user->username, sptr->user->realhost,
218 chptr->chname, who->name, comment);
219
220 goto attack;
221 } /* is_chan_op */
222
223 }
224 /* victim is +a or +q, we are not +q */
225 if ((who_flags & (CHFL_CHANOWNER|CHFL_CHANPROT) || IsServices(who))
226 && !(sptr_flags & CHFL_CHANOWNER)) {
227 if (sptr == who)
228 goto attack; /* kicking self == ok */
229 if (op_can_override(sptr)) /* (and f*ck local ops) */
230 { /* IRCop kicking owner/prot */
231 sendto_snomask(SNO_EYES,
232 "*** OperOverride -- %s (%s@%s) KICK %s %s (%s)",
233 sptr->name, sptr->user->username, sptr->user->realhost,
234 chptr->chname, who->name, comment);
235
236 /* Logging Implementation added by XeRXeS */
237 ircd_log(LOG_OVERRIDE,"OVERRIDE: %s (%s@%s) KICK %s %s (%s)",
238 sptr->name, sptr->user->username, sptr->user->realhost,
239 chptr->chname, who->name, comment);
240
241 goto attack;
242 }
243 else if (!IsULine(sptr) && (who != sptr) && MyClient(sptr))
244 {
245 char errbuf[NICKLEN+25];
246 if (who_flags & CHFL_CHANOWNER)
247 ircsprintf(errbuf, "%s is a channel owner",
248 who->name);
249 else
250 ircsprintf(errbuf, "%s is a channel admin",
251 who->name);
252 sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND),
253 me.name, sptr->name, "KICK",
254 errbuf);
255 goto deny;
256 continue;
257 } /* chanprot/chanowner */
258 }
259
260 /* victim is +o, we are +h [operoverride is already taken care of 2 blocks above] */
261 if ((who_flags & CHFL_ISOP) && (sptr_flags & CHFL_HALFOP)
262 && !(sptr_flags & CHFL_ISOP) && !IsULine(sptr) && MyClient(sptr))
263 {
264 char errbuf[NICKLEN+30];
265 ircsprintf(errbuf, "%s is a channel operator", who->name);
266 sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND),
267 me.name, sptr->name, "KICK",
268 errbuf);
269 goto deny;
270 }
271
272 /* victim is +h, we are +h [operoverride is already taken care of 3 blocks above] */
273 if ((who_flags & CHFL_HALFOP) && (sptr_flags & CHFL_HALFOP)
274 && !(sptr_flags & CHFL_ISOP) && MyClient(sptr))
275 {
276 char errbuf[NICKLEN+15];
277 ircsprintf(errbuf, "%s is a halfop", who->name);
278 sendto_one(sptr, err_str(ERR_CANNOTDOCOMMAND),
279 me.name, sptr->name, "KICK",
280 errbuf);
281 goto deny;
282 } /* halfop */
283
284 /* allowed (either coz access granted or a remote kick), so attack! */
285 goto attack;
286
287 deny:
288 continue;
289
290 attack:
291 if (MyConnect(sptr)) {
292 int breakit = 0;
293 Hook *h;
294 for (h = Hooks[HOOKTYPE_PRE_LOCAL_KICK]; h; h = h->next) {
295 if((*(h->func.intfunc))(sptr,who,chptr,comment) > 0) {
296 breakit = 1;
297 break;
298 }
299 }
300 if (breakit)
301 continue;
302 RunHook5(HOOKTYPE_LOCAL_KICK, cptr,sptr,who,chptr,comment);
303 } else {
304 RunHook5(HOOKTYPE_REMOTE_KICK, cptr, sptr, who, chptr, comment);
305 }
306 if (lp)
307 {
308 if ((chptr->mode.mode & MODE_AUDITORIUM) &&
309 !(lp->flags & (CHFL_CHANOP|CHFL_CHANPROT|CHFL_CHANOWNER)))
310 {
311 /* Send it only to chanops & victim */
312 if (IsPerson(sptr))
313 sendto_chanops_butone(who, chptr, ":%s!%s@%s KICK %s %s :%s",
314 sptr->name, sptr->user->username, GetHost(sptr),
315 chptr->chname, who->name, comment);
316 else
317 sendto_chanops_butone(who, chptr, ":%s KICK %s %s :%s",
318 sptr->name, chptr->chname, who->name, comment);
319
320 if (MyClient(who))
321 sendto_prefix_one(who, sptr, ":%s KICK %s %s :%s",
322 sptr->name, chptr->chname, who->name, comment);
323 } else {
324 /* NORMAL */
325 sendto_channel_butserv(chptr,
326 sptr, ":%s KICK %s %s :%s",
327 parv[0], chptr->chname, who->name, comment);
328 }
329 }
330 sendto_serv_butone_token(cptr, parv[0],
331 MSG_KICK, TOK_KICK, "%s %s :%s",
332 chptr->chname, who->name, comment);
333 if (lp)
334 {
335 remove_user_from_channel(who, chptr);
336 }
337 }
338 else if (MyClient(sptr))
339 sendto_one(sptr,
340 err_str(ERR_USERNOTINCHANNEL),
341 me.name, parv[0], user, name);
342 if (MyClient(cptr))
343 break;
344 } /* loop on parv[2] */
345 if (MyClient(cptr))
346 break;
347 } /* loop on parv[1] */
348
349 return 0;
350 }
351