The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_dccallow.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 
00016 /* $ModDesc: Povides support for the /DCCALLOW command */
00017 
00018 static ConfigReader *Conf;
00019 
00020 class BannedFileList : public classbase
00021 {
00022  public:
00023         std::string filemask;
00024         std::string action;
00025 };
00026 
00027 class DCCAllow : public classbase
00028 {
00029  public:
00030         std::string nickname;
00031         std::string hostmask;
00032         time_t set_on;
00033         long length;
00034 
00035         DCCAllow() { }
00036 
00037         DCCAllow(const std::string &nick, const std::string &hm, const time_t so, const long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }
00038 };
00039 
00040 typedef std::vector<User *> userlist;
00041 userlist ul;
00042 typedef std::vector<DCCAllow> dccallowlist;
00043 dccallowlist* dl;
00044 typedef std::vector<BannedFileList> bannedfilelist;
00045 bannedfilelist bfl;
00046 
00047 class CommandDccallow : public Command
00048 {
00049  public:
00050         CommandDccallow(InspIRCd* Me) : Command(Me, "DCCALLOW", 0, 0)
00051         {
00052                 this->source = "m_dccallow.so";
00053                 syntax = "{[+|-]<nick> <time>|HELP|LIST}";
00054                 /* XXX we need to fix this so it can work with translation stuff (i.e. move +- into a seperate param */
00055         }
00056 
00057         CmdResult Handle(const std::vector<std::string> &parameters, User *user)
00058         {
00059                 /* syntax: DCCALLOW [+|-]<nick> (<time>) */
00060                 if (!parameters.size())
00061                 {
00062                         // display current DCCALLOW list
00063                         DisplayDCCAllowList(user);
00064                         return CMD_FAILURE;
00065                 }
00066                 else if (parameters.size() > 0)
00067                 {
00068                         char action = *parameters[0].c_str();
00069 
00070                         // if they didn't specify an action, this is probably a command
00071                         if (action != '+' && action != '-')
00072                         {
00073                                 if (!strcasecmp(parameters[0].c_str(), "LIST"))
00074                                 {
00075                                         // list current DCCALLOW list
00076                                         DisplayDCCAllowList(user);
00077                                         return CMD_FAILURE;
00078                                 }
00079                                 else if (!strcasecmp(parameters[0].c_str(), "HELP"))
00080                                 {
00081                                         // display help
00082                                         DisplayHelp(user);
00083                                         return CMD_FAILURE;
00084                                 }
00085                         }
00086 
00087                         std::string nick = parameters[0].substr(1);
00088                         User *target = ServerInstance->FindNick(nick);
00089 
00090                         if (target)
00091                         {
00092 
00093                                 if (action == '-')
00094                                 {
00095                                         // check if it contains any entries
00096                                         if (user->GetExt("dccallow_list", dl))
00097                                         {
00098                                                 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
00099                                                 {
00100                                                         // search through list
00101                                                         if (i->nickname == target->nick)
00102                                                         {
00103                                                                 dl->erase(i);
00104                                                                 user->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00105                                                                 break;
00106                                                         }
00107                                                 }
00108                                         }
00109                                         else
00110                                         {
00111                                                 delete  dl;
00112                                                 user->Shrink("dccallow_list");
00113 
00114                                                 // remove from userlist
00115                                                 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
00116                                                 {
00117                                                         User* u = (User*)(*j);
00118                                                         if (u == user)
00119                                                         {
00120                                                                 ul.erase(j);
00121                                                                 break;
00122                                                         }
00123                                                 }
00124                                         }
00125                                 }
00126                                 else if (action == '+')
00127                                 {
00128                                         if (!user->GetExt("dccallow_list", dl))
00129                                         {
00130                                                 dl = new dccallowlist;
00131                                                 user->Extend("dccallow_list", dl);
00132                                                 // add this user to the userlist
00133                                                 ul.push_back(user);
00134                                         }
00135                                         for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
00136                                         {
00137                                                 if (k->nickname == target->nick)
00138                                                 {
00139                                                         user->WriteNumeric(996, "%s %s :%s is already on your DCCALLOW list", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00140                                                         return CMD_FAILURE;
00141                                                 }
00142                                                 else if (InspIRCd::Match(user->GetFullHost(), k->hostmask))
00143                                                 {
00144                                                         user->WriteNumeric(996, "%s %s :You cannot add yourself to your own DCCALLOW list!", user->nick.c_str(), user->nick.c_str());
00145                                                         return CMD_FAILURE;
00146                                                 }
00147                                         }
00148 
00149                                         std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);
00150                                         std::string default_length = Conf->ReadValue("dccallow", "length", 0);
00151 
00152                                         long length;
00153                                         if (parameters.size() < 2)
00154                                         {
00155                                                 length = ServerInstance->Duration(default_length);
00156                                         }
00157                                         else if (!atoi(parameters[1].c_str()))
00158                                         {
00159                                                 length = 0;
00160                                         }
00161                                         else
00162                                         {
00163                                                 length = ServerInstance->Duration(parameters[1]);
00164                                         }
00165 
00166                                         if (!ServerInstance->IsValidMask(mask.c_str()))
00167                                         {
00168                                                 return CMD_FAILURE;
00169                                         }
00170 
00171                                         dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
00172 
00173                                         if (length > 0)
00174                                         {
00175                                                 user->WriteNumeric(993, "%s %s :Added %s to DCCALLOW list for %ld seconds", user->nick.c_str(), user->nick.c_str(), target->nick.c_str(), length);
00176                                         }
00177                                         else
00178                                         {
00179                                                 user->WriteNumeric(994, "%s %s :Added %s to DCCALLOW list for this session", user->nick.c_str(), user->nick.c_str(), target->nick.c_str());
00180                                         }
00181 
00182                                         /* route it. */
00183                                         return CMD_SUCCESS;
00184                                 }
00185                         }
00186                         else
00187                         {
00188                                 // nick doesn't exist
00189                                 user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), nick.c_str());
00190                                 return CMD_FAILURE;
00191                         }
00192                 }
00193                 return CMD_FAILURE;
00194         }
00195 
00196         void DisplayHelp(User* user)
00197         {
00198                 user->WriteNumeric(998, "%s :DCCALLOW [<+|->nick.c_str() [time]] [list] [help]", user->nick.c_str());
00199                 user->WriteNumeric(998, "%s :You may allow DCCs from specific users by specifying a", user->nick.c_str());
00200                 user->WriteNumeric(998, "%s :DCC allow for the user you want to receive DCCs from.", user->nick.c_str());
00201                 user->WriteNumeric(998, "%s :For example, to allow the user Brain to send you inspircd.exe", user->nick.c_str());
00202                 user->WriteNumeric(998, "%s :you would type:", user->nick.c_str());
00203                 user->WriteNumeric(998, "%s :/DCCALLOW +Brain", user->nick.c_str());
00204                 user->WriteNumeric(998, "%s :Brain would then be able to send you files. They would have to", user->nick.c_str());
00205                 user->WriteNumeric(998, "%s :resend the file again if the server gave them an error message", user->nick.c_str());
00206                 user->WriteNumeric(998, "%s :before you added them to your DCCALLOW list.", user->nick.c_str());
00207                 user->WriteNumeric(998, "%s :DCCALLOW entries will be temporary by default, if you want to add", user->nick.c_str());
00208                 user->WriteNumeric(998, "%s :them to your DCCALLOW list until you leave IRC, type:", user->nick.c_str());
00209                 user->WriteNumeric(998, "%s :/DCCALLOW +Brain 0", user->nick.c_str());
00210                 user->WriteNumeric(998, "%s :To remove the user from your DCCALLOW list, type:", user->nick.c_str());
00211                 user->WriteNumeric(998, "%s :/DCCALLOW -Brain", user->nick.c_str());
00212                 user->WriteNumeric(998, "%s :To see the users in your DCCALLOW list, type:", user->nick.c_str());
00213                 user->WriteNumeric(998, "%s :/DCCALLOW LIST", user->nick.c_str());
00214                 user->WriteNumeric(998, "%s :NOTE: If the user leaves IRC or changes their nickname", user->nick.c_str());
00215                 user->WriteNumeric(998, "%s :  they will be removed from your DCCALLOW list.", user->nick.c_str());
00216                 user->WriteNumeric(998, "%s :  your DCCALLOW list will be deleted when you leave IRC.", user->nick.c_str());
00217                 user->WriteNumeric(999, "%s :End of DCCALLOW HELP", user->nick.c_str());
00218         }
00219 
00220         void DisplayDCCAllowList(User* user)
00221         {
00222                  // display current DCCALLOW list
00223                 user->WriteNumeric(990, "%s :Users on your DCCALLOW list:", user->nick.c_str());
00224 
00225                 if (user->GetExt("dccallow_list", dl))
00226                 {
00227                         for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
00228                         {
00229                                 user->WriteNumeric(991, "%s %s :%s (%s)", user->nick.c_str(), user->nick.c_str(), c->nickname.c_str(), c->hostmask.c_str());
00230                         }
00231                 }
00232 
00233                 user->WriteNumeric(992, "%s :End of DCCALLOW list", user->nick.c_str());
00234         }
00235 
00236 };
00237 
00238 class ModuleDCCAllow : public Module
00239 {
00240         CommandDccallow* mycommand;
00241  public:
00242 
00243         ModuleDCCAllow(InspIRCd* Me)
00244                 : Module(Me)
00245         {
00246                 Conf = new ConfigReader(ServerInstance);
00247                 mycommand = new CommandDccallow(ServerInstance);
00248                 ServerInstance->AddCommand(mycommand);
00249                 ReadFileConf();
00250                 Implementation eventlist[] = { I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserQuit, I_OnUserPreNick, I_OnRehash };
00251                 ServerInstance->Modules->Attach(eventlist, this, 5);
00252         }
00253 
00254 
00255         virtual void OnRehash(User* user, const std::string &parameter)
00256         {
00257                 delete Conf;
00258                 Conf = new ConfigReader(ServerInstance);
00259         }
00260 
00261         virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
00262         {
00263                 dccallowlist* udl;
00264 
00265                 // remove their DCCALLOW list if they have one
00266                 if (user->GetExt("dccallow_list", udl))
00267                 {
00268                         delete udl;
00269                         user->Shrink("dccallow_list");
00270                         RemoveFromUserlist(user);
00271                 }
00272 
00273                 // remove them from any DCCALLOW lists
00274                 // they are currently on
00275                 RemoveNick(user);
00276         }
00277 
00278 
00279         virtual int OnUserPreNick(User* user, const std::string &newnick)
00280         {
00281                 RemoveNick(user);
00282                 return 0;
00283         }
00284 
00285         virtual int OnUserPreMessage(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
00286         {
00287                 return OnUserPreNotice(user, dest, target_type, text, status, exempt_list);
00288         }
00289 
00290         virtual int OnUserPreNotice(User* user, void* dest, int target_type, std::string &text, char status, CUList &exempt_list)
00291         {
00292                 if (!IS_LOCAL(user))
00293                         return 0;
00294 
00295                 if (target_type == TYPE_USER)
00296                 {
00297                         User* u = (User*)dest;
00298 
00299                         /* Always allow a user to dcc themselves (although... why?) */
00300                         if (user == u)
00301                                 return 0;
00302 
00303                         if ((text.length()) && (text[0] == '\1'))
00304                         {
00305                                 Expire();
00306 
00307                                 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
00308                                 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
00309 
00310                                 if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
00311                                 {
00312                                         if (u->GetExt("dccallow_list", dl) && dl->size())
00313                                         {
00314                                                 for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
00315                                                         if (InspIRCd::Match(user->GetFullHost(), iter->hostmask))
00316                                                                 return 0;
00317                                         }
00318 
00319                                         // tokenize
00320                                         std::stringstream ss(text);
00321                                         std::string buf;
00322                                         std::vector<std::string> tokens;
00323 
00324                                         while (ss >> buf)
00325                                                 tokens.push_back(buf);
00326 
00327                                         irc::string type = tokens[1].c_str();
00328 
00329                                         bool blockchat = Conf->ReadFlag("dccallow", "blockchat", 0);
00330 
00331                                         if (type == "SEND")
00332                                         {
00333                                                 std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
00334                                                 std::string filename = tokens[2];
00335 
00336                                                 if (defaultaction == "allow")
00337                                                         return 0;
00338 
00339                                                 for (unsigned int i = 0; i < bfl.size(); i++)
00340                                                 {
00341                                                         if (InspIRCd::Match(filename, bfl[i].filemask))
00342                                                         {
00343                                                                 if (bfl[i].action == "allow")
00344                                                                         return 0;
00345                                                         }
00346                                                         else
00347                                                         {
00348                                                                 if (defaultaction == "allow")
00349                                                                         return 0;
00350                                                         }
00351                                                         user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick.c_str(), u->nick.c_str(), filename.c_str());
00352                                                         u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str(), filename.c_str());
00353                                                         u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
00354                                                         return 1;
00355                                                 }
00356                                         }
00357                                         else if ((type == "CHAT") && (blockchat))
00358                                         {
00359                                                 user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick.c_str(), u->nick.c_str());
00360                                                 u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick.c_str(), user->nick.c_str(), user->ident.c_str(), user->dhost.c_str());
00361                                                 u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick.c_str(), user->nick.c_str());
00362                                                 return 1;
00363                                         }
00364                                 }
00365                         }
00366                 }
00367                 return 0;
00368         }
00369 
00370         void Expire()
00371         {
00372                 for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
00373                 {
00374                         User* u = (User*)(*iter);
00375                         if (u->GetExt("dccallow_list", dl))
00376                         {
00377                                 if (dl->size())
00378                                 {
00379                                         dccallowlist::iterator iter2 = dl->begin();
00380                                         while (iter2 != dl->end())
00381                                         {
00382                                                 if (iter2->length != 0 && (iter2->set_on + iter2->length) <= ServerInstance->Time())
00383                                                 {
00384                                                         u->WriteNumeric(997, "%s %s :DCCALLOW entry for %s has expired", u->nick.c_str(), u->nick.c_str(), iter2->nickname.c_str());
00385                                                         iter2 = dl->erase(iter2);
00386                                                 }
00387                                                 else
00388                                                 {
00389                                                         ++iter2;
00390                                                 }
00391                                         }
00392                                 }
00393                         }
00394                         else
00395                         {
00396                                 RemoveFromUserlist(u);
00397                         }
00398                 }
00399         }
00400 
00401         void RemoveNick(User* user)
00402         {
00403                 /* Iterate through all DCCALLOW lists and remove user */
00404                 for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
00405                 {
00406                         User *u = (User*)(*iter);
00407                         if (u->GetExt("dccallow_list", dl))
00408                         {
00409                                 if (dl->size())
00410                                 {
00411                                         for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
00412                                         {
00413                                                 if (i->nickname == user->nick)
00414                                                 {
00415 
00416                                                         u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick.c_str(), i->nickname.c_str());
00417                                                         u->WriteNumeric(995, "%s %s :Removed %s from your DCCALLOW list", u->nick.c_str(), u->nick.c_str(), i->nickname.c_str());
00418                                                         dl->erase(i);
00419                                                         break;
00420                                                 }
00421                                         }
00422                                 }
00423                         }
00424                         else
00425                         {
00426                                 RemoveFromUserlist(u);
00427                         }
00428                 }
00429         }
00430 
00431         void RemoveFromUserlist(User *user)
00432         {
00433                 // remove user from userlist
00434                 for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
00435                 {
00436                         User* u = (User*)(*j);
00437                         if (u == user)
00438                         {
00439                                 ul.erase(j);
00440                                 break;
00441                         }
00442                 }
00443         }
00444 
00445         void ReadFileConf()
00446         {
00447                 bfl.clear();
00448                 for (int i = 0; i < Conf->Enumerate("banfile"); i++)
00449                 {
00450                         BannedFileList bf;
00451                         std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
00452                         std::string action = Conf->ReadValue("banfile", "action", i);
00453                         bf.filemask = fileglob;
00454                         bf.action = action;
00455                         bfl.push_back(bf);
00456                 }
00457 
00458         }
00459 
00460         virtual ~ModuleDCCAllow()
00461         {
00462         }
00463 
00464         virtual Version GetVersion()
00465         {
00466                 return Version("$Id: m_dccallow.cpp 10291 2008-08-25 20:35:51Z w00t $", VF_COMMON | VF_VENDOR, API_VERSION);
00467         }
00468 };
00469 
00470 MODULE_INIT(ModuleDCCAllow)
00471