00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "inspircd.h"
00017 #include "xline.h"
00018 #include "socketengine.h"
00019 #include "socket.h"
00020 #include "command_parse.h"
00021 #include "exitcodes.h"
00022
00023
00024 #ifndef WIN32
00025 #include <dirent.h>
00026 #include <dlfcn.h>
00027 #endif
00028
00029 int InspIRCd::PassCompare(Extensible* ex, const std::string &data, const std::string &input, const std::string &hashtype)
00030 {
00031 int MOD_RESULT = 0;
00032 FOREACH_RESULT_I(this,I_OnPassCompare,OnPassCompare(ex, data, input, hashtype))
00033 if (MOD_RESULT == 1)
00034 return 0;
00035 if (MOD_RESULT == -1)
00036 return 1;
00037 return data != input;
00038 }
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 int CommandParser::LoopCall(User* user, Command* CommandObj, const std::vector<std::string>& parameters, unsigned int splithere, unsigned int extra)
00051 {
00052 if (splithere >= parameters.size())
00053 return 0;
00054
00055
00056
00057
00058 if (parameters[splithere].find(',') == std::string::npos)
00059 return 0;
00060
00065 std::map<irc::string, bool> dupes;
00066
00067
00068
00069 irc::commasepstream items1(parameters[splithere]);
00070 irc::commasepstream items2(parameters[extra]);
00071 std::string extrastuff;
00072 std::string item;
00073 unsigned int max = 0;
00074
00075
00076
00077
00078
00079 while (items1.GetToken(item) && (max++ < ServerInstance->Config->MaxTargets))
00080 {
00081 if (dupes.find(item.c_str()) == dupes.end())
00082 {
00083 std::vector<std::string> new_parameters;
00084
00085 for (unsigned int t = 0; (t < parameters.size()) && (t < MAXPARAMETERS); t++)
00086 new_parameters.push_back(parameters[t]);
00087
00088 if (!items2.GetToken(extrastuff))
00089 extrastuff = "";
00090
00091 new_parameters[splithere] = item.c_str();
00092 new_parameters[extra] = extrastuff.c_str();
00093
00094 CommandObj->Handle(new_parameters, user);
00095
00096 dupes[item.c_str()] = true;
00097 }
00098 }
00099 return 1;
00100 }
00101
00102 int CommandParser::LoopCall(User* user, Command* CommandObj, const std::vector<std::string>& parameters, unsigned int splithere)
00103 {
00104 if (splithere >= parameters.size())
00105 return 0;
00106
00107
00108
00109
00110 if (parameters[splithere].find(',') == std::string::npos)
00111 return 0;
00112
00113 std::map<irc::string, bool> dupes;
00114
00115
00116 irc::commasepstream items1(parameters[splithere]);
00117 std::string item;
00118 unsigned int max = 0;
00119
00120
00121
00122
00123
00124 while (items1.GetToken(item) && (max++ < ServerInstance->Config->MaxTargets))
00125 {
00126 if (dupes.find(item.c_str()) == dupes.end())
00127 {
00128 std::vector<std::string> new_parameters;
00129
00130 for (unsigned int t = 0; (t < parameters.size()) && (t < MAXPARAMETERS); t++)
00131 new_parameters.push_back(parameters[t]);
00132
00133 new_parameters[splithere] = item.c_str();
00134
00135
00136 CommandObj->Handle(new_parameters, user);
00137
00138 dupes[item.c_str()] = true;
00139 }
00140 }
00141
00142
00143
00144
00145 return 1;
00146 }
00147
00148 bool CommandParser::IsValidCommand(const std::string &commandname, unsigned int pcnt, User * user)
00149 {
00150 Commandtable::iterator n = cmdlist.find(commandname);
00151
00152 if (n != cmdlist.end())
00153 {
00154 if ((pcnt >= n->second->min_params) && (n->second->source != "<core>"))
00155 {
00156 if (IS_LOCAL(user) && n->second->flags_needed)
00157 {
00158 if (user->IsModeSet(n->second->flags_needed))
00159 {
00160 return (user->HasPermission(commandname));
00161 }
00162 }
00163 else
00164 {
00165 return true;
00166 }
00167 }
00168 }
00169 return false;
00170 }
00171
00172 Command* CommandParser::GetHandler(const std::string &commandname)
00173 {
00174 Commandtable::iterator n = cmdlist.find(commandname);
00175 if (n != cmdlist.end())
00176 return n->second;
00177
00178 return NULL;
00179 }
00180
00181
00182
00183 CmdResult CommandParser::CallHandler(const std::string &commandname, const std::vector<std::string>& parameters, User *user)
00184 {
00185 Commandtable::iterator n = cmdlist.find(commandname);
00186
00187 if (n != cmdlist.end())
00188 {
00189 if (parameters.size() >= n->second->min_params)
00190 {
00191 bool bOkay = false;
00192
00193 if (IS_LOCAL(user) && n->second->flags_needed)
00194 {
00195
00196
00197 if (user->IsModeSet(n->second->flags_needed))
00198 {
00199
00200 if (user->HasPermission(commandname))
00201 bOkay = true;
00202 }
00203 }
00204 else
00205 {
00206
00207 bOkay = true;
00208 }
00209
00210 if (bOkay)
00211 {
00212 return n->second->Handle(parameters,user);
00213 }
00214 }
00215 }
00216 return CMD_INVALID;
00217 }
00218
00219 void CommandParser::DoLines(User* current, bool one_only)
00220 {
00221
00222 unsigned int floodlines = 0;
00223
00224 while (current->BufferIsReady())
00225 {
00226 if (current->MyClass)
00227 {
00228 if (ServerInstance->Time() > current->reset_due)
00229 {
00230 current->reset_due = ServerInstance->Time() + current->MyClass->GetThreshold();
00231 current->lines_in = 0;
00232 }
00233
00234 if (++current->lines_in > current->MyClass->GetFlood() && current->MyClass->GetFlood())
00235 {
00236 ServerInstance->FloodQuitUser(current);
00237 return;
00238 }
00239
00240 if ((++floodlines > current->MyClass->GetFlood()) && (current->MyClass->GetFlood() != 0))
00241 {
00242 ServerInstance->FloodQuitUser(current);
00243 return;
00244 }
00245 }
00246
00247
00248 std::string single_line = current->GetBuffer();
00249 current->bytes_in += single_line.length();
00250 current->cmds_in++;
00251 if (single_line.length() > MAXBUF - 2)
00252 single_line.resize(MAXBUF - 2);
00253
00254
00255 if (!ServerInstance->Parser->ProcessBuffer(single_line, current) || one_only)
00256 break;
00257 }
00258 }
00259
00260 bool CommandParser::ProcessCommand(User *user, std::string &cmd)
00261 {
00262 std::vector<std::string> command_p;
00263 irc::tokenstream tokens(cmd);
00264 std::string command, token;
00265 tokens.GetToken(command);
00266
00267
00268
00269
00270
00271
00272 if (command[0] == ':')
00273 tokens.GetToken(command);
00274
00275 while (tokens.GetToken(token) && (command_p.size() <= MAXPARAMETERS))
00276 command_p.push_back(token);
00277
00278 std::transform(command.begin(), command.end(), command.begin(), ::toupper);
00279
00280 int MOD_RESULT = 0;
00281 FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command, command_p, user, false, cmd));
00282 if (MOD_RESULT == 1) {
00283 return true;
00284 }
00285
00286
00287 Commandtable::iterator cm = cmdlist.find(command);
00288
00289 if (cm == cmdlist.end())
00290 {
00291 if (user->registered == REG_ALL)
00292 {
00293 user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str());
00294 }
00295 ServerInstance->stats->statsUnknown++;
00296 return true;
00297 }
00298
00299
00300 bool do_more = true;
00301 if (!user->ExemptFromPenalty)
00302 {
00303 user->IncreasePenalty(cm->second->Penalty);
00304 do_more = (user->Penalty < 10);
00305 if (!do_more)
00306 user->OverPenalty = true;
00307 }
00308
00309
00310 if (user->MyClass)
00311 user->nping = ServerInstance->Time() + user->MyClass->GetPingTime();
00312
00313 if (cm->second->flags_needed)
00314 {
00315 if (!user->IsModeSet(cm->second->flags_needed))
00316 {
00317 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - You do not have the required operator privileges",user->nick.c_str());
00318 return do_more;
00319 }
00320 if (!user->HasPermission(command))
00321 {
00322 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to command %s",user->nick.c_str(),user->oper.c_str(),command.c_str());
00323 return do_more;
00324 }
00325 }
00326 if ((user->registered == REG_ALL) && (!IS_OPER(user)) && (cm->second->IsDisabled()))
00327 {
00328
00329 if (ServerInstance->Config->DisabledDontExist)
00330 {
00331 user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :Unknown command",user->nick.c_str(),command.c_str());
00332 }
00333 else
00334 {
00335 user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s %s :This command has been disabled.",
00336 user->nick.c_str(), command.c_str());
00337 }
00338
00339 ServerInstance->SNO->WriteToSnoMask('d', "%s denied for %s (%s@%s)",
00340 command.c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str());
00341 return do_more;
00342 }
00343 if (command_p.size() < cm->second->min_params)
00344 {
00345 user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s %s :Not enough parameters.", user->nick.c_str(), command.c_str());
00346 if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (cm->second->syntax.length()))
00347 user->WriteNumeric(RPL_SYNTAX, "%s :SYNTAX %s %s", user->nick.c_str(), cm->second->command.c_str(), cm->second->syntax.c_str());
00348 return do_more;
00349 }
00350 if ((user->registered != REG_ALL) && (!cm->second->WorksBeforeReg()))
00351 {
00352 user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str());
00353 return do_more;
00354 }
00355 else
00356 {
00357
00358 cm->second->use_count++;
00359 cm->second->total_bytes += cmd.length();
00360
00361
00362 MOD_RESULT = 0;
00363 FOREACH_RESULT(I_OnPreCommand,OnPreCommand(command, command_p, user, true, cmd));
00364 if (MOD_RESULT == 1)
00365 return do_more;
00366
00367
00368
00369
00370 CmdResult result = cm->second->Handle(command_p, user);
00371
00372 FOREACH_MOD(I_OnPostCommand,OnPostCommand(command, command_p, user, result,cmd));
00373 return do_more;
00374 }
00375 }
00376
00377 void CommandParser::RemoveCommands(const char* source)
00378 {
00379 Commandtable::iterator i,safei;
00380 for (i = cmdlist.begin(); i != cmdlist.end();)
00381 {
00382 safei = i;
00383 i++;
00384 RemoveCommand(safei, source);
00385 }
00386 }
00387
00388 void CommandParser::RemoveCommand(Commandtable::iterator safei, const char* source)
00389 {
00390 Command* x = safei->second;
00391 if (x->source == std::string(source))
00392 {
00393 cmdlist.erase(safei);
00394 delete x;
00395 }
00396 }
00397
00398 bool CommandParser::ProcessBuffer(std::string &buffer,User *user)
00399 {
00400 std::string::size_type a;
00401
00402 if (!user)
00403 return true;
00404
00405 while ((a = buffer.rfind("\n")) != std::string::npos)
00406 buffer.erase(a);
00407 while ((a = buffer.rfind("\r")) != std::string::npos)
00408 buffer.erase(a);
00409
00410 if (buffer.length())
00411 {
00412 ServerInstance->Logs->Log("USERINPUT", DEBUG,"C[%d] I :%s %s",user->GetFd(), user->nick.c_str(), buffer.c_str());
00413 return this->ProcessCommand(user,buffer);
00414 }
00415
00416 return true;
00417 }
00418
00419 bool CommandParser::CreateCommand(Command *f, void* so_handle)
00420 {
00421 if (so_handle)
00422 {
00423 if (RFCCommands.find(f->command) == RFCCommands.end())
00424 RFCCommands[f->command] = so_handle;
00425 else
00426 {
00427 ServerInstance->Logs->Log("COMMAND",DEFAULT,"ERK! Somehow, we loaded a cmd_*.so file twice! Only the first instance is being recorded.");
00428 return false;
00429 }
00430 }
00431
00432
00433 if (cmdlist.find(f->command) == cmdlist.end())
00434 {
00435 cmdlist[f->command] = f;
00436 return true;
00437 }
00438 else return false;
00439 }
00440
00441 CommandParser::CommandParser(InspIRCd* Instance) : ServerInstance(Instance)
00442 {
00443 para.resize(128);
00444 }
00445
00446 bool CommandParser::FindSym(void** v, void* h, const std::string &name)
00447 {
00448 *v = dlsym(h, "init_command");
00449 const char* err = dlerror();
00450 if (err && !(*v))
00451 {
00452 ServerInstance->Logs->Log("COMMAND",SPARSE, "Error loading core command %s: %s\n", name.c_str(), err);
00453 return false;
00454 }
00455 return true;
00456 }
00457
00458 bool CommandParser::ReloadCommand(std::string cmd, User* user)
00459 {
00460 char filename[MAXBUF];
00461 std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
00462
00463 SharedObjectList::iterator command = RFCCommands.find(cmd);
00464
00465 if (command != RFCCommands.end())
00466 {
00467 Command* cmdptr = cmdlist.find(cmd)->second;
00468 cmdlist.erase(cmdlist.find(cmd));
00469
00470 RFCCommands.erase(cmd);
00471 std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::tolower);
00472 delete cmdptr;
00473 dlclose(command->second);
00474
00475 snprintf(filename, MAXBUF, "cmd_%s.so", cmd.c_str());
00476 const char* err = this->LoadCommand(filename);
00477 if (err)
00478 {
00479 if (user)
00480 user->WriteServ("NOTICE %s :*** Error loading 'cmd_%s.so': %s", user->nick.c_str(), cmd.c_str(), err);
00481 return false;
00482 }
00483
00484 return true;
00485 }
00486
00487 return false;
00488 }
00489
00490 CmdResult cmd_reload::Handle(const std::vector<std::string>& parameters, User *user)
00491 {
00492 if (parameters.size() < 1)
00493 return CMD_FAILURE;
00494
00495 user->WriteServ("NOTICE %s :*** Reloading command '%s'",user->nick.c_str(), parameters[0].c_str());
00496 if (ServerInstance->Parser->ReloadCommand(parameters[0], user))
00497 {
00498 user->WriteServ("NOTICE %s :*** Successfully reloaded command '%s'", user->nick.c_str(), parameters[0].c_str());
00499 ServerInstance->SNO->WriteToSnoMask('A', "RELOAD: %s reloaded the '%s' command.", user->nick.c_str(), parameters[0].c_str());
00500 return CMD_SUCCESS;
00501 }
00502 else
00503 {
00504 user->WriteServ("NOTICE %s :*** Could not reload command '%s' -- fix this problem, then /REHASH as soon as possible!", user->nick.c_str(), parameters[0].c_str());
00505 return CMD_FAILURE;
00506 }
00507 }
00508
00509 const char* CommandParser::LoadCommand(const char* name)
00510 {
00511 char filename[MAXBUF];
00512 void* h;
00513 Command* (*cmd_factory_func)(InspIRCd*);
00514
00515
00516 if (RFCCommands.find(name) != RFCCommands.end())
00517 {
00518 ServerInstance->Logs->Log("COMMAND",DEBUG,"Not reloading command %s/%s, it already exists", LIBRARYDIR, name);
00519 return NULL;
00520 }
00521
00522 snprintf(filename, MAXBUF, "%s/%s", LIBRARYDIR, name);
00523 h = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
00524
00525 if (!h)
00526 {
00527 const char* n = dlerror();
00528 ServerInstance->Logs->Log("COMMAND",SPARSE, "Error loading core command %s: %s", name, n);
00529 return n;
00530 }
00531
00532 if (this->FindSym((void **)&cmd_factory_func, h, name))
00533 {
00534 Command* newcommand = cmd_factory_func(ServerInstance);
00535 this->CreateCommand(newcommand, h);
00536 }
00537 return NULL;
00538 }
00539
00540 void CommandParser::SetupCommandTable(User* user)
00541 {
00542 RFCCommands.clear();
00543
00544 if (!user)
00545 {
00546 printf("\nLoading core commands");
00547 fflush(stdout);
00548 }
00549
00550 DIR* library = opendir(LIBRARYDIR);
00551 if (library)
00552 {
00553 dirent* entry = NULL;
00554 while (0 != (entry = readdir(library)))
00555 {
00556 if (InspIRCd::Match(entry->d_name, "cmd_*.so"))
00557 {
00558 if (!user)
00559 {
00560 printf(".");
00561 fflush(stdout);
00562 }
00563 const char* err = this->LoadCommand(entry->d_name);
00564 if (err)
00565 {
00566 if (user)
00567 {
00568 user->WriteServ("NOTICE %s :*** Failed to load core command %s: %s", user->nick.c_str(), entry->d_name, err);
00569 }
00570 else
00571 {
00572 printf("Error loading %s: %s", entry->d_name, err);
00573 exit(EXIT_STATUS_BADHANDLER);
00574 }
00575 }
00576 }
00577 }
00578 closedir(library);
00579 if (!user)
00580 printf("\n");
00581 }
00582
00583 if (cmdlist.find("RELOAD") == cmdlist.end())
00584 this->CreateCommand(new cmd_reload(ServerInstance));
00585 }
00586
00587 int CommandParser::TranslateUIDs(TranslateType to, const std::string &source, std::string &dest)
00588 {
00589 User* user = NULL;
00590 std::string item;
00591 int translations = 0;
00592 dest.clear();
00593
00594 switch (to)
00595 {
00596 case TR_NICK:
00597
00598 user = ServerInstance->FindNick(source);
00599 if (user)
00600 {
00601 dest = user->uuid;
00602 translations++;
00603 }
00604 else
00605 dest = source;
00606 break;
00607 case TR_NICKLIST:
00608 {
00609
00610 irc::commasepstream items(source);
00611 while (items.GetToken(item))
00612 {
00613 user = ServerInstance->FindNick(item);
00614 if (user)
00615 {
00616 dest.append(user->uuid);
00617 translations++;
00618 }
00619 else
00620 dest.append(item);
00621 dest.append(",");
00622 }
00623 if (!dest.empty())
00624 dest.erase(dest.end() - 1);
00625 }
00626 break;
00627 case TR_SPACENICKLIST:
00628 {
00629
00630 irc::spacesepstream items(source);
00631 while (items.GetToken(item))
00632 {
00633 user = ServerInstance->FindNick(item);
00634 if (user)
00635 {
00636 dest.append(user->uuid);
00637 translations++;
00638 }
00639 else
00640 dest.append(item);
00641 dest.append(" ");
00642 }
00643 if (!dest.empty())
00644 dest.erase(dest.end() - 1);
00645 }
00646 break;
00647 case TR_END:
00648 case TR_TEXT:
00649 default:
00650
00651 dest = source;
00652 break;
00653 }
00654
00655 return translations;
00656 }
00657
00658