]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_check.cpp
Merge pull request #998 from SaberUK/master+fix-clang-builds
[user/henk/code/inspircd.git] / src / modules / m_check.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
6  *   Copyright (C) 2006-2007 Robin Burchell <robin+git@viroteck.net>
7  *   Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "listmode.h"
25
26 /** Handle /CHECK
27  */
28 class CommandCheck : public Command
29 {
30         UserModeReference snomaskmode;
31
32         std::string GetSnomasks(User* user)
33         {
34                 std::string ret;
35                 if (snomaskmode)
36                         ret = snomaskmode->GetUserParameter(user);
37
38                 if (ret.empty())
39                         ret = "+";
40                 return ret;
41         }
42
43         static void dumpListMode(User* user, const std::string& checkstr, const ListModeBase::ModeList* list)
44         {
45                 if (!list)
46                         return;
47
48                 std::string buf = checkstr + " modelist";
49                 const std::string::size_type headlen = buf.length();
50                 const size_t maxline = ServerInstance->Config->Limits.MaxLine;
51                 for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
52                 {
53                         if (buf.size() + i->mask.size() + 1 > maxline)
54                         {
55                                 user->SendText(buf);
56                                 buf.erase(headlen);
57                         }
58                         buf.append(" ").append(i->mask);
59                 }
60                 if (buf.length() > headlen)
61                         user->SendText(buf);
62         }
63
64  public:
65         CommandCheck(Module* parent)
66                 : Command(parent,"CHECK", 1)
67                 , snomaskmode(parent, "snomask")
68         {
69                 flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>";
70         }
71
72         std::string timestring(time_t time)
73         {
74                 char timebuf[60];
75                 struct tm *mytime = gmtime(&time);
76                 strftime(timebuf, 59, "%Y-%m-%d %H:%M:%S UTC (%s)", mytime);
77                 return std::string(timebuf);
78         }
79
80         void dumpExt(User* user, const std::string& checkstr, Extensible* ext)
81         {
82                 std::stringstream dumpkeys;
83                 for(Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++)
84                 {
85                         ExtensionItem* item = i->first;
86                         std::string value = item->serialize(FORMAT_USER, ext, i->second);
87                         if (!value.empty())
88                                 user->SendText(checkstr + " meta:" + item->name + " " + value);
89                         else if (!item->name.empty())
90                                 dumpkeys << " " << item->name;
91                 }
92                 if (!dumpkeys.str().empty())
93                         user->SendText(checkstr + " metadata", dumpkeys);
94         }
95
96         CmdResult Handle (const std::vector<std::string> &parameters, User *user)
97         {
98                 if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName.c_str())
99                         return CMD_SUCCESS;
100
101                 User *targuser;
102                 Channel *targchan;
103                 std::string checkstr;
104                 std::string chliststr;
105
106                 checkstr = ":" + ServerInstance->Config->ServerName + " 304 " + user->nick + " :CHECK";
107
108                 targuser = ServerInstance->FindNick(parameters[0]);
109                 targchan = ServerInstance->FindChan(parameters[0]);
110
111                 /*
112                  * Syntax of a /check reply:
113                  *  :server.name 304 target :CHECK START <target>
114                  *  :server.name 304 target :CHECK <field> <value>
115                  *  :server.name 304 target :CHECK END
116                  */
117
118                 user->SendText(checkstr + " START " + parameters[0]);
119
120                 if (targuser)
121                 {
122                         LocalUser* loctarg = IS_LOCAL(targuser);
123                         /* /check on a user */
124                         user->SendText(checkstr + " nuh " + targuser->GetFullHost());
125                         user->SendText(checkstr + " realnuh " + targuser->GetFullRealHost());
126                         user->SendText(checkstr + " realname " + targuser->fullname);
127                         user->SendText(checkstr + " modes +" + targuser->FormatModes());
128                         user->SendText(checkstr + " snomasks " + GetSnomasks(targuser));
129                         user->SendText(checkstr + " server " + targuser->server->GetName());
130                         user->SendText(checkstr + " uid " + targuser->uuid);
131                         user->SendText(checkstr + " signon " + timestring(targuser->signon));
132                         user->SendText(checkstr + " nickts " + timestring(targuser->age));
133                         if (loctarg)
134                                 user->SendText(checkstr + " lastmsg " + timestring(loctarg->idle_lastmsg));
135
136                         if (targuser->IsAway())
137                         {
138                                 /* user is away */
139                                 user->SendText(checkstr + " awaytime " + timestring(targuser->awaytime));
140                                 user->SendText(checkstr + " awaymsg " + targuser->awaymsg);
141                         }
142
143                         if (targuser->IsOper())
144                         {
145                                 OperInfo* oper = targuser->oper;
146                                 /* user is an oper of type ____ */
147                                 user->SendText(checkstr + " opertype " + oper->name);
148                                 if (loctarg)
149                                 {
150                                         std::string umodes;
151                                         std::string cmodes;
152                                         for(char c='A'; c <= 'z'; c++)
153                                         {
154                                                 ModeHandler* mh = ServerInstance->Modes->FindMode(c, MODETYPE_USER);
155                                                 if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_USER))
156                                                         umodes.push_back(c);
157                                                 mh = ServerInstance->Modes->FindMode(c, MODETYPE_CHANNEL);
158                                                 if (mh && mh->NeedsOper() && loctarg->HasModePermission(c, MODETYPE_CHANNEL))
159                                                         cmodes.push_back(c);
160                                         }
161                                         user->SendText(checkstr + " modeperms user=" + umodes + " channel=" + cmodes);
162                                         std::string opcmds;
163                                         for (OperInfo::PrivSet::const_iterator i = oper->AllowedOperCommands.begin(); i != oper->AllowedOperCommands.end(); ++i)
164                                         {
165                                                 opcmds.push_back(' ');
166                                                 opcmds.append(*i);
167                                         }
168                                         std::stringstream opcmddump(opcmds);
169                                         user->SendText(checkstr + " commandperms", opcmddump);
170                                         std::string privs;
171                                         for (OperInfo::PrivSet::const_iterator i = oper->AllowedPrivs.begin(); i != oper->AllowedPrivs.end(); ++i)
172                                         {
173                                                 privs.push_back(' ');
174                                                 privs.append(*i);
175                                         }
176                                         std::stringstream privdump(privs);
177                                         user->SendText(checkstr + " permissions", privdump);
178                                 }
179                         }
180
181                         if (loctarg)
182                         {
183                                 user->SendText(checkstr + " clientaddr " + loctarg->client_sa.str());
184                                 user->SendText(checkstr + " serveraddr " + loctarg->server_sa.str());
185
186                                 std::string classname = loctarg->GetClass()->name;
187                                 if (!classname.empty())
188                                         user->SendText(checkstr + " connectclass " + classname);
189                         }
190                         else
191                                 user->SendText(checkstr + " onip " + targuser->GetIPString());
192
193                         for (User::ChanList::iterator i = targuser->chans.begin(); i != targuser->chans.end(); i++)
194                         {
195                                 Membership* memb = *i;
196                                 Channel* c = memb->chan;
197                                 char prefix = memb->GetPrefixChar();
198                                 if (prefix)
199                                         chliststr.push_back(prefix);
200                                 chliststr.append(c->name).push_back(' ');
201                         }
202
203                         std::stringstream dump(chliststr);
204
205                         user->SendText(checkstr + " onchans", dump);
206
207                         dumpExt(user, checkstr, targuser);
208                 }
209                 else if (targchan)
210                 {
211                         /* /check on a channel */
212                         user->SendText(checkstr + " timestamp " + timestring(targchan->age));
213
214                         if (targchan->topic[0] != 0)
215                         {
216                                 /* there is a topic, assume topic related information exists */
217                                 user->SendText(checkstr + " topic " + targchan->topic);
218                                 user->SendText(checkstr + " topic_setby " + targchan->setby);
219                                 user->SendText(checkstr + " topic_setat " + timestring(targchan->topicset));
220                         }
221
222                         user->SendText(checkstr + " modes " + targchan->ChanModes(true));
223                         user->SendText(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));
224
225                         /* now the ugly bit, spool current members of a channel. :| */
226
227                         const Channel::MemberMap& ulist = targchan->GetUsers();
228
229                         /* note that unlike /names, we do NOT check +i vs in the channel */
230                         for (Channel::MemberMap::const_iterator i = ulist.begin(); i != ulist.end(); ++i)
231                         {
232                                 /*
233                                  * Unlike Asuka, I define a clone as coming from the same host. --w00t
234                                  */
235                                 const UserManager::CloneCounts& clonecount = ServerInstance->Users->GetCloneCounts(i->first);
236                                 user->SendText("%s member %-3u %s%s (%s@%s) %s ",
237                                         checkstr.c_str(), clonecount.global,
238                                         i->second->GetAllPrefixChars(), i->first->nick.c_str(),
239                                         i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str());
240                         }
241
242                         const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
243                         for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i)
244                                 dumpListMode(user, checkstr, (*i)->GetList(targchan));
245
246                         dumpExt(user, checkstr, targchan);
247                 }
248                 else
249                 {
250                         /*  /check on an IP address, or something that doesn't exist */
251                         long x = 0;
252
253                         /* hostname or other */
254                         const user_hash& users = ServerInstance->Users->GetUsers();
255                         for (user_hash::const_iterator a = users.begin(); a != users.end(); ++a)
256                         {
257                                 if (InspIRCd::Match(a->second->host, parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->dhost, parameters[0], ascii_case_insensitive_map))
258                                 {
259                                         /* host or vhost matches mask */
260                                         user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
261                                 }
262                                 /* IP address */
263                                 else if (InspIRCd::MatchCIDR(a->second->GetIPString(), parameters[0]))
264                                 {
265                                         /* same IP. */
266                                         user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
267                                 }
268                         }
269
270                         user->SendText(checkstr + " matches " + ConvToStr(x));
271                 }
272
273                 user->SendText(checkstr + " END " + parameters[0]);
274
275                 return CMD_SUCCESS;
276         }
277
278         RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
279         {
280                 if (parameters.size() > 1)
281                         return ROUTE_OPT_UCAST(parameters[1]);
282                 return ROUTE_LOCALONLY;
283         }
284 };
285
286 class ModuleCheck : public Module
287 {
288         CommandCheck mycommand;
289  public:
290         ModuleCheck() : mycommand(this)
291         {
292         }
293
294         Version GetVersion() CXX11_OVERRIDE
295         {
296                 return Version("CHECK command, view user, channel, IP address or hostname information", VF_VENDOR|VF_OPTCOMMON);
297         }
298 };
299
300 MODULE_INIT(ModuleCheck)