anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
os_forbid.cpp (15667B)
1 /* OperServ core functions 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "module.h" 13 #include "modules/os_forbid.h" 14 15 static ServiceReference<NickServService> nickserv("NickServService", "NickServ"); 16 17 struct ForbidDataImpl : ForbidData, Serializable 18 { 19 ForbidDataImpl() : Serializable("ForbidData") { } 20 void Serialize(Serialize::Data &data) const anope_override; 21 static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); 22 }; 23 24 void ForbidDataImpl::Serialize(Serialize::Data &data) const 25 { 26 data["mask"] << this->mask; 27 data["creator"] << this->creator; 28 data["reason"] << this->reason; 29 data["created"] << this->created; 30 data["expires"] << this->expires; 31 data["type"] << this->type; 32 } 33 34 Serializable* ForbidDataImpl::Unserialize(Serializable *obj, Serialize::Data &data) 35 { 36 if (!forbid_service) 37 return NULL; 38 39 ForbidDataImpl *fb; 40 if (obj) 41 fb = anope_dynamic_static_cast<ForbidDataImpl *>(obj); 42 else 43 fb = new ForbidDataImpl(); 44 45 data["mask"] >> fb->mask; 46 data["creator"] >> fb->creator; 47 data["reason"] >> fb->reason; 48 data["created"] >> fb->created; 49 data["expires"] >> fb->expires; 50 unsigned int t; 51 data["type"] >> t; 52 fb->type = static_cast<ForbidType>(t); 53 54 if (t > FT_SIZE - 1) 55 return NULL; 56 57 if (!obj) 58 forbid_service->AddForbid(fb); 59 return fb; 60 } 61 62 class MyForbidService : public ForbidService 63 { 64 Serialize::Checker<std::vector<ForbidData *>[FT_SIZE - 1]> forbid_data; 65 66 inline std::vector<ForbidData *>& forbids(unsigned t) { return (*this->forbid_data)[t - 1]; } 67 68 public: 69 MyForbidService(Module *m) : ForbidService(m), forbid_data("ForbidData") { } 70 71 ~MyForbidService() 72 { 73 std::vector<ForbidData *> f = GetForbids(); 74 for (unsigned i = 0; i < f.size(); ++i) 75 delete f[i]; 76 } 77 78 void AddForbid(ForbidData *d) anope_override 79 { 80 this->forbids(d->type).push_back(d); 81 } 82 83 void RemoveForbid(ForbidData *d) anope_override 84 { 85 std::vector<ForbidData *>::iterator it = std::find(this->forbids(d->type).begin(), this->forbids(d->type).end(), d); 86 if (it != this->forbids(d->type).end()) 87 this->forbids(d->type).erase(it); 88 delete d; 89 } 90 91 ForbidData *CreateForbid() anope_override 92 { 93 return new ForbidDataImpl(); 94 } 95 96 ForbidData *FindForbid(const Anope::string &mask, ForbidType ftype) anope_override 97 { 98 for (unsigned i = this->forbids(ftype).size(); i > 0; --i) 99 { 100 ForbidData *d = this->forbids(ftype)[i - 1]; 101 102 if (Anope::Match(mask, d->mask, false, true)) 103 return d; 104 } 105 return NULL; 106 } 107 108 ForbidData *FindForbidExact(const Anope::string &mask, ForbidType ftype) anope_override 109 { 110 for (unsigned i = this->forbids(ftype).size(); i > 0; --i) 111 { 112 ForbidData *d = this->forbids(ftype)[i - 1]; 113 114 if (d->mask.equals_ci(mask)) 115 return d; 116 } 117 return NULL; 118 } 119 120 std::vector<ForbidData *> GetForbids() anope_override 121 { 122 std::vector<ForbidData *> f; 123 for (unsigned j = FT_NICK; j < FT_SIZE; ++j) 124 for (unsigned i = this->forbids(j).size(); i > 0; --i) 125 { 126 ForbidData *d = this->forbids(j).at(i - 1); 127 128 if (d->expires && !Anope::NoExpire && Anope::CurTime >= d->expires) 129 { 130 Anope::string ftype = "none"; 131 if (d->type == FT_NICK) 132 ftype = "nick"; 133 else if (d->type == FT_CHAN) 134 ftype = "chan"; 135 else if (d->type == FT_EMAIL) 136 ftype = "email"; 137 138 Log(LOG_NORMAL, "expire/forbid", Config->GetClient("OperServ")) << "Expiring forbid for " << d->mask << " type " << ftype; 139 this->forbids(j).erase(this->forbids(j).begin() + i - 1); 140 delete d; 141 } 142 else 143 f.push_back(d); 144 } 145 146 return f; 147 } 148 }; 149 150 class CommandOSForbid : public Command 151 { 152 ServiceReference<ForbidService> fs; 153 public: 154 CommandOSForbid(Module *creator) : Command(creator, "operserv/forbid", 1, 5), fs("ForbidService", "forbid") 155 { 156 this->SetDesc(_("Forbid usage of nicknames, channels, and emails")); 157 this->SetSyntax(_("ADD {NICK|CHAN|EMAIL|REGISTER} [+\037expiry\037] \037entry\037 \037reason\037")); 158 this->SetSyntax(_("DEL {NICK|CHAN|EMAIL|REGISTER} \037entry\037")); 159 this->SetSyntax("LIST [NICK|CHAN|EMAIL|REGISTER]"); 160 } 161 162 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 163 { 164 if (!this->fs) 165 return; 166 167 const Anope::string &command = params[0]; 168 const Anope::string &subcommand = params.size() > 1 ? params[1] : ""; 169 170 ForbidType ftype = FT_SIZE; 171 if (subcommand.equals_ci("NICK")) 172 ftype = FT_NICK; 173 else if (subcommand.equals_ci("CHAN")) 174 ftype = FT_CHAN; 175 else if (subcommand.equals_ci("EMAIL")) 176 ftype = FT_EMAIL; 177 else if (subcommand.equals_ci("REGISTER")) 178 ftype = FT_REGISTER; 179 180 if (command.equals_ci("ADD") && params.size() > 3 && ftype != FT_SIZE) 181 { 182 const Anope::string &expiry = params[2][0] == '+' ? params[2] : ""; 183 const Anope::string &entry = !expiry.empty() ? params[3] : params[2]; 184 Anope::string reason; 185 if (expiry.empty()) 186 reason = params[3] + " "; 187 if (params.size() > 4) 188 reason += params[4]; 189 reason.trim(); 190 191 if (entry.replace_all_cs("?*", "").empty()) 192 { 193 source.Reply(_("The mask must contain at least one non wildcard character.")); 194 return; 195 } 196 197 time_t expiryt = 0; 198 199 if (!expiry.empty()) 200 { 201 expiryt = Anope::DoTime(expiry); 202 if (expiryt < 0) 203 { 204 source.Reply(BAD_EXPIRY_TIME); 205 return; 206 } 207 else if (expiryt) 208 expiryt += Anope::CurTime; 209 } 210 211 NickAlias *target = NickAlias::Find(entry); 212 if (target != NULL && Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && target->nc->IsServicesOper()) 213 { 214 source.Reply(ACCESS_DENIED); 215 return; 216 } 217 218 ForbidData *d = this->fs->FindForbidExact(entry, ftype); 219 bool created = false; 220 if (d == NULL) 221 { 222 d = new ForbidDataImpl(); 223 created = true; 224 } 225 226 d->mask = entry; 227 d->creator = source.GetNick(); 228 d->reason = reason; 229 d->created = Anope::CurTime; 230 d->expires = expiryt; 231 d->type = ftype; 232 if (created) 233 this->fs->AddForbid(d); 234 235 if (Anope::ReadOnly) 236 source.Reply(READ_ONLY_MODE); 237 238 Log(LOG_ADMIN, source, this) << "to add a forbid on " << entry << " of type " << subcommand; 239 source.Reply(_("Added a forbid on %s of type %s to expire on %s."), entry.c_str(), subcommand.lower().c_str(), d->expires ? Anope::strftime(d->expires, source.GetAccount()).c_str() : "never"); 240 241 /* apply forbid */ 242 switch (ftype) 243 { 244 case FT_NICK: 245 { 246 int na_matches = 0; 247 248 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) 249 module->OnUserNickChange(it->second, ""); 250 251 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end;) 252 { 253 NickAlias *na = it->second; 254 ++it; 255 256 d = this->fs->FindForbid(na->nick, FT_NICK); 257 if (d == NULL) 258 continue; 259 260 ++na_matches; 261 262 delete na; 263 } 264 265 source.Reply(_("\002%d\002 nickname(s) dropped."), na_matches); 266 break; 267 } 268 case FT_CHAN: 269 { 270 int chan_matches = 0, ci_matches = 0; 271 272 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end;) 273 { 274 Channel *c = it->second; 275 ++it; 276 277 d = this->fs->FindForbid(c->name, FT_CHAN); 278 if (d == NULL) 279 continue; 280 281 ServiceReference<ChanServService> chanserv("ChanServService", "ChanServ"); 282 BotInfo *OperServ = Config->GetClient("OperServ"); 283 if (IRCD->CanSQLineChannel && OperServ) 284 { 285 time_t inhabit = Config->GetModule("chanserv")->Get<time_t>("inhabit", "15s"); 286 XLine x(c->name, OperServ->nick, Anope::CurTime + inhabit, d->reason); 287 IRCD->SendSQLine(NULL, &x); 288 } 289 else if (chanserv) 290 { 291 chanserv->Hold(c); 292 } 293 294 ++chan_matches; 295 296 for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end;) 297 { 298 User *u = cit->first; 299 ++cit; 300 301 if (u->server == Me || u->HasMode("OPER")) 302 continue; 303 304 reason = Anope::printf(Language::Translate(u, _("This channel has been forbidden: %s")), d->reason.c_str()); 305 306 c->Kick(source.service, u, "%s", reason.c_str()); 307 } 308 } 309 310 for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(); it != RegisteredChannelList->end();) 311 { 312 ChannelInfo *ci = it->second; 313 ++it; 314 315 d = this->fs->FindForbid(ci->name, FT_CHAN); 316 if (d == NULL) 317 continue; 318 319 ++ci_matches; 320 321 delete ci; 322 } 323 324 source.Reply(_("\002%d\002 channel(s) cleared, and \002%d\002 channel(s) dropped."), chan_matches, ci_matches); 325 326 break; 327 } 328 default: 329 break; 330 } 331 332 } 333 else if (command.equals_ci("DEL") && params.size() > 2 && ftype != FT_SIZE) 334 { 335 const Anope::string &entry = params[2]; 336 337 ForbidData *d = this->fs->FindForbidExact(entry, ftype); 338 if (d != NULL) 339 { 340 if (Anope::ReadOnly) 341 source.Reply(READ_ONLY_MODE); 342 343 Log(LOG_ADMIN, source, this) << "to remove forbid on " << d->mask << " of type " << subcommand; 344 source.Reply(_("%s deleted from the %s forbid list."), d->mask.c_str(), subcommand.c_str()); 345 this->fs->RemoveForbid(d); 346 } 347 else 348 source.Reply(_("Forbid on %s was not found."), entry.c_str()); 349 } 350 else if (command.equals_ci("LIST")) 351 { 352 const std::vector<ForbidData *> &forbids = this->fs->GetForbids(); 353 if (forbids.empty()) 354 source.Reply(_("Forbid list is empty.")); 355 else 356 { 357 ListFormatter list(source.GetAccount()); 358 list.AddColumn(_("Mask")).AddColumn(_("Type")).AddColumn(_("Creator")).AddColumn(_("Expires")).AddColumn(_("Reason")); 359 360 unsigned shown = 0; 361 for (unsigned i = 0; i < forbids.size(); ++i) 362 { 363 ForbidData *d = forbids[i]; 364 365 if (ftype != FT_SIZE && ftype != d->type) 366 continue; 367 368 Anope::string stype; 369 if (d->type == FT_NICK) 370 stype = "NICK"; 371 else if (d->type == FT_CHAN) 372 stype = "CHAN"; 373 else if (d->type == FT_EMAIL) 374 stype = "EMAIL"; 375 else if (d->type == FT_REGISTER) 376 stype = "REGISTER"; 377 else 378 continue; 379 380 ListFormatter::ListEntry entry; 381 entry["Mask"] = d->mask; 382 entry["Type"] = stype; 383 entry["Creator"] = d->creator; 384 entry["Expires"] = d->expires ? Anope::strftime(d->expires, NULL, true).c_str() : Language::Translate(source.GetAccount(), _("Never")); 385 entry["Reason"] = d->reason; 386 list.AddEntry(entry); 387 ++shown; 388 } 389 390 if (!shown) 391 { 392 source.Reply(_("There are no forbids of type %s."), subcommand.upper().c_str()); 393 } 394 else 395 { 396 source.Reply(_("Forbid list:")); 397 398 std::vector<Anope::string> replies; 399 list.Process(replies); 400 401 for (unsigned i = 0; i < replies.size(); ++i) 402 source.Reply(replies[i]); 403 404 if (shown >= forbids.size()) 405 source.Reply(_("End of forbid list.")); 406 else 407 source.Reply(_("End of forbid list - %d/%d entries shown."), shown, forbids.size()); 408 } 409 } 410 } 411 else 412 this->OnSyntaxError(source, command); 413 414 return; 415 } 416 417 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 418 { 419 this->SendSyntax(source); 420 source.Reply(" "); 421 source.Reply(_("Forbid allows you to forbid usage of certain nicknames, channels,\n" 422 "and email addresses. Wildcards are accepted for all entries.")); 423 424 const Anope::string ®exengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine"); 425 if (!regexengine.empty()) 426 { 427 source.Reply(" "); 428 source.Reply(_("Regex matches are also supported using the %s engine.\n" 429 "Enclose your pattern in // if this is desired."), regexengine.c_str()); 430 } 431 432 return true; 433 } 434 }; 435 436 class OSForbid : public Module 437 { 438 MyForbidService forbidService; 439 Serialize::Type forbiddata_type; 440 CommandOSForbid commandosforbid; 441 442 public: 443 OSForbid(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 444 forbidService(this), forbiddata_type("ForbidData", ForbidDataImpl::Unserialize), commandosforbid(this) 445 { 446 447 } 448 449 void OnUserConnect(User *u, bool &exempt) anope_override 450 { 451 if (u->Quitting() || exempt) 452 return; 453 454 this->OnUserNickChange(u, ""); 455 } 456 457 void OnUserNickChange(User *u, const Anope::string &) anope_override 458 { 459 if (u->HasMode("OPER")) 460 return; 461 462 ForbidData *d = this->forbidService.FindForbid(u->nick, FT_NICK); 463 if (d != NULL) 464 { 465 BotInfo *bi = Config->GetClient("NickServ"); 466 if (!bi) 467 bi = Config->GetClient("OperServ"); 468 if (bi) 469 u->SendMessage(bi, _("This nickname has been forbidden: %s"), d->reason.c_str()); 470 if (nickserv) 471 nickserv->Collide(u, NULL); 472 } 473 } 474 475 EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override 476 { 477 BotInfo *OperServ = Config->GetClient("OperServ"); 478 if (u->HasMode("OPER") || !OperServ) 479 return EVENT_CONTINUE; 480 481 ForbidData *d = this->forbidService.FindForbid(c->name, FT_CHAN); 482 if (d != NULL) 483 { 484 ServiceReference<ChanServService> chanserv("ChanServService", "ChanServ"); 485 if (IRCD->CanSQLineChannel) 486 { 487 time_t inhabit = Config->GetModule("chanserv")->Get<time_t>("inhabit", "15s"); 488 XLine x(c->name, OperServ->nick, Anope::CurTime + inhabit, d->reason); 489 IRCD->SendSQLine(NULL, &x); 490 } 491 else if (chanserv) 492 { 493 chanserv->Hold(c); 494 } 495 496 reason = Anope::printf(Language::Translate(u, _("This channel has been forbidden: %s")), d->reason.c_str()); 497 498 return EVENT_STOP; 499 } 500 501 return EVENT_CONTINUE; 502 } 503 504 EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> ¶ms) anope_override 505 { 506 if (command->name == "nickserv/info" && params.size() > 0) 507 { 508 ForbidData *d = this->forbidService.FindForbid(params[0], FT_NICK); 509 if (d != NULL) 510 { 511 if (source.IsOper()) 512 source.Reply(_("Nick \002%s\002 is forbidden by %s: %s"), params[0].c_str(), d->creator.c_str(), d->reason.c_str()); 513 else 514 source.Reply(_("Nick \002%s\002 is forbidden."), params[0].c_str()); 515 return EVENT_STOP; 516 } 517 } 518 else if (command->name == "chanserv/info" && params.size() > 0) 519 { 520 ForbidData *d = this->forbidService.FindForbid(params[0], FT_CHAN); 521 if (d != NULL) 522 { 523 if (source.IsOper()) 524 source.Reply(_("Channel \002%s\002 is forbidden by %s: %s"), params[0].c_str(), d->creator.c_str(), d->reason.c_str()); 525 else 526 source.Reply(_("Channel \002%s\002 is forbidden."), params[0].c_str()); 527 return EVENT_STOP; 528 } 529 } 530 else if (source.IsOper()) 531 return EVENT_CONTINUE; 532 else if (command->name == "nickserv/register" && params.size() > 1) 533 { 534 ForbidData *d = this->forbidService.FindForbid(source.GetNick(), FT_REGISTER); 535 if (d != NULL) 536 { 537 source.Reply(NICK_CANNOT_BE_REGISTERED, source.GetNick().c_str()); 538 return EVENT_STOP; 539 } 540 541 d = this->forbidService.FindForbid(params[1], FT_EMAIL); 542 if (d != NULL) 543 { 544 source.Reply(_("Your email address is not allowed, choose a different one.")); 545 return EVENT_STOP; 546 } 547 } 548 else if (command->name == "nickserv/set/email" && params.size() > 0) 549 { 550 ForbidData *d = this->forbidService.FindForbid(params[0], FT_EMAIL); 551 if (d != NULL) 552 { 553 source.Reply(_("Your email address is not allowed, choose a different one.")); 554 return EVENT_STOP; 555 } 556 } 557 else if (command->name == "chanserv/register" && !params.empty()) 558 { 559 ForbidData *d = this->forbidService.FindForbid(params[0], FT_REGISTER); 560 if (d != NULL) 561 { 562 source.Reply(CHAN_X_INVALID, params[0].c_str()); 563 return EVENT_STOP; 564 } 565 } 566 567 return EVENT_CONTINUE; 568 } 569 }; 570 571 MODULE_INIT(OSForbid)