anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
nickserv.cpp (17073B)
1 /* NickServ 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 14 class NickServCollide; 15 static std::set<NickServCollide *> collides; 16 17 /** Timer for colliding nicks to force people off of nicknames 18 */ 19 class NickServCollide : public Timer 20 { 21 NickServService *service; 22 Reference<User> u; 23 time_t ts; 24 Reference<NickAlias> na; 25 26 public: 27 NickServCollide(Module *me, NickServService *nss, User *user, NickAlias *nick, time_t delay) : Timer(me, delay), service(nss), u(user), ts(user->timestamp), na(nick) 28 { 29 collides.insert(this); 30 } 31 32 ~NickServCollide() 33 { 34 collides.erase(this); 35 } 36 37 User *GetUser() 38 { 39 return u; 40 } 41 42 NickAlias *GetNick() 43 { 44 return na; 45 } 46 47 void Tick(time_t t) anope_override 48 { 49 if (!u || !na) 50 return; 51 /* If they identified or don't exist anymore, don't kill them. */ 52 if (u->Account() == na->nc || u->timestamp > ts) 53 return; 54 55 service->Collide(u, na); 56 } 57 }; 58 59 /** Timer for removing HELD status from nicks. 60 */ 61 class NickServHeld : public Timer 62 { 63 Reference<NickAlias> na; 64 Anope::string nick; 65 public: 66 NickServHeld(Module *me, NickAlias *n, long l) : Timer(me, l), na(n), nick(na->nick) 67 { 68 n->Extend<bool>("HELD"); 69 } 70 71 void Tick(time_t) 72 { 73 if (na) 74 na->Shrink<bool>("HELD"); 75 } 76 }; 77 78 class NickServRelease; 79 static Anope::map<NickServRelease *> NickServReleases; 80 81 /** Timer for releasing nicks to be available for use 82 */ 83 class NickServRelease : public User, public Timer 84 { 85 Anope::string nick; 86 87 public: 88 NickServRelease(Module *me, NickAlias *na, time_t delay) : User(na->nick, Config->GetModule("nickserv")->Get<const Anope::string>("enforceruser", "user"), 89 Config->GetModule("nickserv")->Get<const Anope::string>("enforcerhost", Me->GetName()), "", "", Me, "Services Enforcer", Anope::CurTime, "", IRCD->UID_Retrieve(), NULL), Timer(me, delay), nick(na->nick) 90 { 91 /* Erase the current release timer and use the new one */ 92 Anope::map<NickServRelease *>::iterator nit = NickServReleases.find(this->nick); 93 if (nit != NickServReleases.end()) 94 { 95 IRCD->SendQuit(nit->second, ""); 96 delete nit->second; 97 } 98 99 NickServReleases.insert(std::make_pair(this->nick, this)); 100 101 IRCD->SendClientIntroduction(this); 102 } 103 104 ~NickServRelease() 105 { 106 IRCD->SendQuit(this, ""); 107 NickServReleases.erase(this->nick); 108 } 109 110 void Tick(time_t t) anope_override { } 111 }; 112 113 class NickServCore : public Module, public NickServService 114 { 115 Reference<BotInfo> NickServ; 116 std::vector<Anope::string> defaults; 117 ExtensibleItem<bool> held, collided; 118 119 void OnCancel(User *u, NickAlias *na) 120 { 121 if (collided.HasExt(na)) 122 { 123 collided.Unset(na); 124 125 new NickServHeld(this, na, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m")); 126 127 if (IRCD->CanSVSHold) 128 IRCD->SendSVSHold(na->nick, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m")); 129 else 130 new NickServRelease(this, na, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m")); 131 } 132 } 133 134 public: 135 NickServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), 136 NickServService(this), held(this, "HELD"), collided(this, "COLLIDED") 137 { 138 } 139 140 ~NickServCore() 141 { 142 OnShutdown(); 143 } 144 145 void OnShutdown() anope_override 146 { 147 /* On shutdown, restart, or mod unload, remove all of our holds for nicks (svshold or qlines) 148 * because some IRCds do not allow us to have these automatically expire 149 */ 150 for (nickalias_map::const_iterator it = NickAliasList->begin(); it != NickAliasList->end(); ++it) 151 this->Release(it->second); 152 } 153 154 void OnRestart() anope_override 155 { 156 OnShutdown(); 157 } 158 159 void Validate(User *u) anope_override 160 { 161 NickAlias *na = NickAlias::Find(u->nick); 162 if (!na) 163 return; 164 165 EventReturn MOD_RESULT; 166 FOREACH_RESULT(OnNickValidate, MOD_RESULT, (u, na)); 167 if (MOD_RESULT == EVENT_STOP) 168 { 169 this->Collide(u, na); 170 return; 171 } 172 else if (MOD_RESULT == EVENT_ALLOW) 173 return; 174 175 if (!na->nc->HasExt("NS_SECURE") && u->IsRecognized()) 176 { 177 na->last_seen = Anope::CurTime; 178 na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); 179 na->last_realname = u->realname; 180 return; 181 } 182 183 if (Config->GetModule("nickserv")->Get<bool>("nonicknameownership")) 184 return; 185 186 bool on_access = u->IsRecognized(false); 187 188 if (on_access || !na->nc->HasExt("KILL_IMMED")) 189 { 190 if (na->nc->HasExt("NS_SECURE")) 191 u->SendMessage(NickServ, NICK_IS_SECURE, Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); 192 else 193 u->SendMessage(NickServ, NICK_IS_REGISTERED, Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); 194 } 195 if (na->nc->HasExt("KILLPROTECT") && !on_access) 196 { 197 if (na->nc->HasExt("KILL_IMMED")) 198 { 199 u->SendMessage(NickServ, FORCENICKCHANGE_NOW); 200 this->Collide(u, na); 201 } 202 else if (na->nc->HasExt("KILL_QUICK")) 203 { 204 time_t killquick = Config->GetModule("nickserv")->Get<time_t>("killquick", "20s"); 205 u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."), Anope::Duration(killquick, u->Account()).c_str()); 206 new NickServCollide(this, this, u, na, killquick); 207 } 208 else 209 { 210 time_t kill = Config->GetModule("nickserv")->Get<time_t>("kill", "60s"); 211 u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."), Anope::Duration(kill, u->Account()).c_str()); 212 new NickServCollide(this, this, u, na, kill); 213 } 214 } 215 216 } 217 218 void OnUserLogin(User *u) anope_override 219 { 220 NickAlias *na = NickAlias::Find(u->nick); 221 if (na && *na->nc == u->Account() && !Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && !na->nc->HasExt("UNCONFIRMED")) 222 u->SetMode(NickServ, "REGISTERED"); 223 224 const Anope::string &modesonid = Config->GetModule(this)->Get<Anope::string>("modesonid"); 225 if (!modesonid.empty()) 226 u->SetModes(NickServ, "%s", modesonid.c_str()); 227 } 228 229 void Collide(User *u, NickAlias *na) anope_override 230 { 231 if (na) 232 collided.Set(na); 233 234 if (IRCD->CanSVSNick) 235 { 236 unsigned nicklen = Config->GetBlock("networkinfo")->Get<unsigned>("nicklen"); 237 const Anope::string &guestprefix = Config->GetModule("nickserv")->Get<const Anope::string>("guestnickprefix", "Guest"); 238 239 Anope::string guestnick; 240 241 int i = 0; 242 do 243 { 244 guestnick = guestprefix + stringify(static_cast<uint16_t>(rand())); 245 if (guestnick.length() > nicklen) 246 guestnick = guestnick.substr(0, nicklen); 247 } 248 while (User::Find(guestnick) && i++ < 10); 249 250 if (i == 11) 251 u->Kill(*NickServ, "Services nickname-enforcer kill"); 252 else 253 { 254 u->SendMessage(*NickServ, _("Your nickname is now being changed to \002%s\002"), guestnick.c_str()); 255 IRCD->SendForceNickChange(u, guestnick, Anope::CurTime); 256 } 257 } 258 else 259 u->Kill(*NickServ, "Services nickname-enforcer kill"); 260 } 261 262 void Release(NickAlias *na) anope_override 263 { 264 if (held.HasExt(na)) 265 { 266 if (IRCD->CanSVSHold) 267 IRCD->SendSVSHoldDel(na->nick); 268 else 269 { 270 User *u = User::Find(na->nick); 271 if (u && u->server == Me) 272 { 273 u->Quit(); 274 } 275 } 276 277 held.Unset(na); 278 } 279 collided.Unset(na); /* clear pending collide */ 280 } 281 282 void OnReload(Configuration::Conf *conf) anope_override 283 { 284 const Anope::string &nsnick = conf->GetModule(this)->Get<const Anope::string>("client"); 285 286 if (nsnick.empty()) 287 throw ConfigException(Module::name + ": <client> must be defined"); 288 289 BotInfo *bi = BotInfo::Find(nsnick, true); 290 if (!bi) 291 throw ConfigException(Module::name + ": no bot named " + nsnick); 292 293 NickServ = bi; 294 295 spacesepstream(conf->GetModule(this)->Get<const Anope::string>("defaults", "ns_secure memo_signon memo_receive")).GetTokens(defaults); 296 if (defaults.empty()) 297 { 298 defaults.push_back("NS_SECURE"); 299 defaults.push_back("MEMO_SIGNON"); 300 defaults.push_back("MEMO_RECEIVE"); 301 } 302 else if (defaults[0].equals_ci("none")) 303 defaults.clear(); 304 } 305 306 void OnDelNick(NickAlias *na) anope_override 307 { 308 User *u = User::Find(na->nick); 309 if (u && u->Account() == na->nc) 310 { 311 IRCD->SendLogout(u); 312 u->RemoveMode(NickServ, "REGISTERED"); 313 u->Logout(); 314 } 315 } 316 317 void OnDelCore(NickCore *nc) anope_override 318 { 319 Log(NickServ, "nick") << "Deleting nickname group " << nc->display; 320 321 /* Clean up this nick core from any users online */ 322 for (std::list<User *>::iterator it = nc->users.begin(); it != nc->users.end();) 323 { 324 User *user = *it++; 325 IRCD->SendLogout(user); 326 user->RemoveMode(NickServ, "REGISTERED"); 327 user->Logout(); 328 FOREACH_MOD(OnNickLogout, (user)); 329 } 330 nc->users.clear(); 331 } 332 333 void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) anope_override 334 { 335 Log(LOG_NORMAL, "nick", NickServ) << "Changing " << nc->display << " nickname group display to " << newdisplay; 336 } 337 338 void OnNickIdentify(User *u) anope_override 339 { 340 Configuration::Block *block = Config->GetModule(this); 341 342 if (block->Get<bool>("modeonid", "yes")) 343 344 for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) 345 { 346 ChanUserContainer *cc = it->second; 347 Channel *c = cc->chan; 348 if (c) 349 c->SetCorrectModes(u, true); 350 } 351 352 const Anope::string &modesonid = block->Get<const Anope::string>("modesonid"); 353 if (!modesonid.empty()) 354 u->SetModes(NickServ, "%s", modesonid.c_str()); 355 356 if (block->Get<bool>("forceemail", "yes") && u->Account()->email.empty()) 357 { 358 u->SendMessage(NickServ, _("You must now supply an e-mail for your nick.\n" 359 "This e-mail will allow you to retrieve your password in\n" 360 "case you forget it.")); 361 u->SendMessage(NickServ, _("Type \002%s%s SET EMAIL \037e-mail\037\002 in order to set your e-mail.\n" 362 "Your privacy is respected; this e-mail won't be given to\n" 363 "any third-party person."), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str()); 364 } 365 366 for (std::set<NickServCollide *>::iterator it = collides.begin(); it != collides.end(); ++it) 367 { 368 NickServCollide *c = *it; 369 if (c->GetUser() == u && c->GetNick() && c->GetNick()->nc == u->Account()) 370 { 371 delete c; 372 break; 373 } 374 } 375 } 376 377 void OnNickGroup(User *u, NickAlias *target) anope_override 378 { 379 if (!target->nc->HasExt("UNCONFIRMED")) 380 u->SetMode(NickServ, "REGISTERED"); 381 } 382 383 void OnNickUpdate(User *u) anope_override 384 { 385 for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) 386 { 387 ChanUserContainer *cc = it->second; 388 Channel *c = cc->chan; 389 if (c) 390 c->SetCorrectModes(u, true); 391 } 392 } 393 394 void OnUserConnect(User *u, bool &exempt) anope_override 395 { 396 if (u->Quitting() || !u->server->IsSynced() || u->server->IsULined()) 397 return; 398 399 const NickAlias *na = NickAlias::Find(u->nick); 400 401 const Anope::string &unregistered_notice = Config->GetModule(this)->Get<const Anope::string>("unregistered_notice"); 402 if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && !unregistered_notice.empty() && !na && !u->Account()) 403 u->SendMessage(NickServ, unregistered_notice.replace_all_cs("%n", u->nick)); 404 else if (na && !u->IsIdentified(true)) 405 this->Validate(u); 406 } 407 408 void OnPostUserLogoff(User *u) anope_override 409 { 410 NickAlias *na = NickAlias::Find(u->nick); 411 if (na) 412 OnCancel(u, na); 413 } 414 415 void OnServerSync(Server *s) anope_override 416 { 417 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it) 418 { 419 User *u = it->second; 420 421 if (u->server == s) 422 { 423 if (u->HasMode("REGISTERED") && !u->IsIdentified(true)) 424 u->RemoveMode(NickServ, "REGISTERED"); 425 if (!u->IsIdentified()) 426 this->Validate(u); 427 } 428 } 429 } 430 431 void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override 432 { 433 NickAlias *old_na = NickAlias::Find(oldnick), *na = NickAlias::Find(u->nick); 434 /* If the new nick isn't registered or it's registered and not yours */ 435 if (!na || na->nc != u->Account()) 436 { 437 /* Remove +r, but keep an account associated with the user */ 438 u->RemoveMode(NickServ, "REGISTERED"); 439 440 this->Validate(u); 441 } 442 else 443 { 444 /* Reset +r and re-send account (even though it really should be set at this point) */ 445 IRCD->SendLogin(u, na); 446 if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && na->nc == u->Account() && !na->nc->HasExt("UNCONFIRMED")) 447 u->SetMode(NickServ, "REGISTERED"); 448 Log(u, "", NickServ) << u->GetMask() << " automatically identified for group " << u->Account()->display; 449 } 450 451 if (!u->nick.equals_ci(oldnick) && old_na) 452 OnCancel(u, old_na); 453 } 454 455 void OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname) anope_override 456 { 457 if (u->server->IsSynced() && mname == "REGISTERED" && !u->IsIdentified(true)) 458 u->RemoveMode(NickServ, mname); 459 } 460 461 EventReturn OnPreHelp(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 462 { 463 if (!params.empty() || source.c || source.service != *NickServ) 464 return EVENT_CONTINUE; 465 if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership")) 466 source.Reply(_("\002%s\002 allows you to register a nickname and\n" 467 "prevent others from using it. The following\n" 468 "commands allow for registration and maintenance of\n" 469 "nicknames; to use them, type \002%s%s \037command\037\002.\n" 470 "For more information on a specific command, type\n" 471 "\002%s%s %s \037command\037\002.\n"), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), source.command.c_str()); 472 else 473 source.Reply(_("\002%s\002 allows you to register an account.\n" 474 "The following commands allow for registration and maintenance of\n" 475 "accounts; to use them, type \002%s%s \037command\037\002.\n" 476 "For more information on a specific command, type\n" 477 "\002%s%s %s \037command\037\002.\n"), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), source.command.c_str()); 478 return EVENT_CONTINUE; 479 } 480 481 void OnPostHelp(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 482 { 483 if (!params.empty() || source.c || source.service != *NickServ) 484 return; 485 if (source.IsServicesOper()) 486 source.Reply(_(" \n" 487 "Services Operators can also drop any nickname without needing\n" 488 "to identify for the nick, and may view the access list for\n" 489 "any nickname.")); 490 time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "21d"); 491 if (nickserv_expire >= 86400) 492 source.Reply(_(" \n" 493 "Accounts that are not used anymore are subject to\n" 494 "the automatic expiration, i.e. they will be deleted\n" 495 "after %d days if not used."), nickserv_expire / 86400); 496 } 497 498 void OnNickCoreCreate(NickCore *nc) anope_override 499 { 500 /* Set default flags */ 501 for (unsigned i = 0; i < defaults.size(); ++i) 502 nc->Extend<bool>(defaults[i].upper()); 503 } 504 505 void OnUserQuit(User *u, const Anope::string &msg) anope_override 506 { 507 if (u->server && !u->server->GetQuitReason().empty() && Config->GetModule(this)->Get<bool>("hidenetsplitquit")) 508 return; 509 510 /* Update last quit and last seen for the user */ 511 NickAlias *na = NickAlias::Find(u->nick); 512 if (na && !na->nc->HasExt("NS_SUSPENDED") && (u->IsRecognized() || u->IsIdentified(true))) 513 { 514 na->last_seen = Anope::CurTime; 515 na->last_quit = msg; 516 } 517 } 518 519 void OnExpireTick() anope_override 520 { 521 if (Anope::NoExpire || Anope::ReadOnly) 522 return; 523 524 time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "21d"); 525 526 for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ) 527 { 528 NickAlias *na = it->second; 529 ++it; 530 531 User *u = User::Find(na->nick, true); 532 if (u && (u->IsIdentified(true) || u->IsRecognized())) 533 na->last_seen = Anope::CurTime; 534 535 bool expire = false; 536 537 if (nickserv_expire && Anope::CurTime - na->last_seen >= nickserv_expire) 538 expire = true; 539 540 FOREACH_MOD(OnPreNickExpire, (na, expire)); 541 542 if (expire) 543 { 544 Log(LOG_NORMAL, "nickserv/expire", NickServ) << "Expiring nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")"; 545 FOREACH_MOD(OnNickExpire, (na)); 546 delete na; 547 } 548 } 549 } 550 551 void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) anope_override 552 { 553 if (!na->nc->HasExt("UNCONFIRMED")) 554 { 555 time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "21d"); 556 if (!na->HasExt("NS_NO_EXPIRE") && nickserv_expire && !Anope::NoExpire && (source.HasPriv("nickserv/auspex") || na->last_seen != Anope::CurTime)) 557 info[_("Expires")] = Anope::strftime(na->last_seen + nickserv_expire, source.GetAccount()); 558 } 559 else 560 { 561 time_t unconfirmed_expire = Config->GetModule("ns_register")->Get<time_t>("unconfirmedexpire", "1d"); 562 info[_("Expires")] = Anope::strftime(na->time_registered + unconfirmed_expire, source.GetAccount()); 563 } 564 } 565 }; 566 567 MODULE_INIT(NickServCore)