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