]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_check.cpp
d7cfe74bd50bf2ff4505aae97b6e426070c9f3a7
[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(std::set<std::string>::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(std::set<std::string>::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 (UCListIter i = targuser->chans.begin(); i != targuser->chans.end(); i++)
194                         {
195                                 Membership* memb = *i;
196                                 Channel* c = memb->chan;
197                                 chliststr.push_back(memb->GetPrefixChar());
198                                 chliststr.append(c->name).push_back(' ');
199                         }
200
201                         std::stringstream dump(chliststr);
202
203                         user->SendText(checkstr + " onchans", dump);
204
205                         dumpExt(user, checkstr, targuser);
206                 }
207                 else if (targchan)
208                 {
209                         /* /check on a channel */
210                         user->SendText(checkstr + " timestamp " + timestring(targchan->age));
211
212                         if (targchan->topic[0] != 0)
213                         {
214                                 /* there is a topic, assume topic related information exists */
215                                 user->SendText(checkstr + " topic " + targchan->topic);
216                                 user->SendText(checkstr + " topic_setby " + targchan->setby);
217                                 user->SendText(checkstr + " topic_setat " + timestring(targchan->topicset));
218                         }
219
220                         user->SendText(checkstr + " modes " + targchan->ChanModes(true));
221                         user->SendText(checkstr + " membercount " + ConvToStr(targchan->GetUserCounter()));
222
223                         /* now the ugly bit, spool current members of a channel. :| */
224
225                         const UserMembList *ulist= targchan->GetUsers();
226
227                         /* note that unlike /names, we do NOT check +i vs in the channel */
228                         for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++)
229                         {
230                                 /*
231                                  * Unlike Asuka, I define a clone as coming from the same host. --w00t
232                                  */
233                                 user->SendText("%s member %-3lu %s%s (%s@%s) %s ",
234                                         checkstr.c_str(), ServerInstance->Users->GlobalCloneCount(i->first),
235                                         i->second->GetAllPrefixChars(), i->first->nick.c_str(),
236                                         i->first->ident.c_str(), i->first->dhost.c_str(), i->first->fullname.c_str());
237                         }
238
239                         const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
240                         for (ModeParser::ListModeList::const_iterator i = listmodes.begin(); i != listmodes.end(); ++i)
241                                 dumpListMode(user, checkstr, (*i)->GetList(targchan));
242
243                         dumpExt(user, checkstr, targchan);
244                 }
245                 else
246                 {
247                         /*  /check on an IP address, or something that doesn't exist */
248                         long x = 0;
249
250                         /* hostname or other */
251                         const user_hash& users = ServerInstance->Users->GetUsers();
252                         for (user_hash::const_iterator a = users.begin(); a != users.end(); ++a)
253                         {
254                                 if (InspIRCd::Match(a->second->host, parameters[0], ascii_case_insensitive_map) || InspIRCd::Match(a->second->dhost, parameters[0], ascii_case_insensitive_map))
255                                 {
256                                         /* host or vhost matches mask */
257                                         user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
258                                 }
259                                 /* IP address */
260                                 else if (InspIRCd::MatchCIDR(a->second->GetIPString(), parameters[0]))
261                                 {
262                                         /* same IP. */
263                                         user->SendText(checkstr + " match " + ConvToStr(++x) + " " + a->second->GetFullRealHost() + " " + a->second->GetIPString() + " " + a->second->fullname);
264                                 }
265                         }
266
267                         user->SendText(checkstr + " matches " + ConvToStr(x));
268                 }
269
270                 user->SendText(checkstr + " END " + parameters[0]);
271
272                 return CMD_SUCCESS;
273         }
274
275         RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
276         {
277                 if (parameters.size() > 1)
278                         return ROUTE_OPT_UCAST(parameters[1]);
279                 return ROUTE_LOCALONLY;
280         }
281 };
282
283 class ModuleCheck : public Module
284 {
285         CommandCheck mycommand;
286  public:
287         ModuleCheck() : mycommand(this)
288         {
289         }
290
291         Version GetVersion() CXX11_OVERRIDE
292         {
293                 return Version("CHECK command, view user, channel, IP address or hostname information", VF_VENDOR|VF_OPTCOMMON);
294         }
295 };
296
297 MODULE_INIT(ModuleCheck)