diff options
Diffstat (limited to 'src/nickserv.cpp')
-rw-r--r-- | src/nickserv.cpp | 507 |
1 files changed, 507 insertions, 0 deletions
diff --git a/src/nickserv.cpp b/src/nickserv.cpp new file mode 100644 index 000000000..c14de6ae6 --- /dev/null +++ b/src/nickserv.cpp @@ -0,0 +1,507 @@ + +/* NickServ functions. + * + * (C) 2003-2010 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * + */ + +#include "services.h" +#include "modules.h" +#include "language.h" + +nickalias_map NickAliasList; +nickcore_map NickCoreList; +nickrequest_map NickRequestList; + +static std::map<std::string, NickServCollide *> NickServCollides; +static std::map<std::string, NickServRelease *> NickServReleases; + +NickServCollide::NickServCollide(const std::string &_nick, time_t delay) : Timer(delay), nick(_nick) +{ + /* Erase the current collide and use the new one */ + std::map<std::string, NickServCollide *>::iterator nit = NickServCollides.find(nick); + if (nit != NickServCollides.end()) + { + delete nit->second; + } + + NickServCollides.insert(std::make_pair(nick, this)); +} + +NickServCollide::~NickServCollide() +{ + NickServCollides.erase(nick); +} + +void NickServCollide::Tick(time_t ctime) +{ + /* If they identified or don't exist anymore, don't kill them. */ + User *u = finduser(nick); + NickAlias *na = findnick(nick); + if (!u || !na || u->Account() == na->nc || u->my_signon > this->GetSetTime()) + return; + + u->Collide(na); +} + +NickServRelease::NickServRelease(const std::string &_nick, const std::string &_uid, time_t delay) : Timer(delay), nick(_nick), uid(_uid) +{ + /* Erase the current release timer and use the new one */ + std::map<std::string, NickServRelease *>::iterator nit = NickServReleases.find(nick); + if (nit != NickServReleases.end()) + { + delete nit->second; + } + + NickServReleases.insert(std::make_pair(nick, this)); +} + +NickServRelease::~NickServRelease() +{ + NickServReleases.erase(nick); +} + +void NickServRelease::Tick(time_t ctime) +{ + NickAlias *na = findnick(nick); + + if (na) + na->Release(); +} + +/*************************************************************************/ +/* *INDENT-OFF* */ +void moduleAddNickServCmds() +{ + ModuleManager::LoadModuleList(Config.NickServCoreModules); +} +/* *INDENT-ON* */ +/*************************************************************************/ + +/* Return information on memory use. Assumes pointers are valid. */ + +void get_aliases_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + + for (nickalias_map::const_iterator it = NickAliasList.begin(); it != NickAliasList.end(); ++it) + { + NickAlias *na = it->second; + + count++; + mem += sizeof(*na); + if (na->nick) + mem += strlen(na->nick) + 1; + if (na->last_usermask) + mem += strlen(na->last_usermask) + 1; + if (na->last_realname) + mem += strlen(na->last_realname) + 1; + if (na->last_quit) + mem += strlen(na->last_quit) + 1; + } + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ + +/* Return information on memory use. Assumes pointers are valid. */ + +void get_core_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + unsigned j; + + for (nickcore_map::const_iterator it = NickCoreList.begin(); it != NickCoreList.end(); ++it) + { + NickCore *nc = it->second; + + count++; + mem += sizeof(*nc); + + if (nc->display) + mem += strlen(nc->display) + 1; + if (!nc->pass.empty()) + mem += (nc->pass.capacity() + (2 * sizeof(size_t)) + (2 * sizeof(void*))); + if (nc->url) + mem += strlen(nc->url) + 1; + if (nc->email) + mem += strlen(nc->email) + 1; + if (nc->greet) + mem += strlen(nc->greet) + 1; + + mem += sizeof(std::string) * nc->access.size(); + for (j = 0; j < nc->access.size(); ++j) + mem += nc->GetAccess(j).length() + 1; + + mem += nc->memos.memos.size() * sizeof(Memo); + for (j = 0; j < nc->memos.memos.size(); j++) + { + if (nc->memos.memos[j]->text) + mem += strlen(nc->memos.memos[j]->text) + 1; + } + + mem += sizeof(NickAlias *) * nc->aliases.size(); + } + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ +/*************************************************************************/ + +/* NickServ initialization. */ + +void ns_init() +{ + moduleAddNickServCmds(); +} + +/*************************************************************************/ + +/* Main NickServ routine. */ + +void nickserv(User *u, const std::string &buf) +{ + if (!u || buf.empty()) + return; + + if (buf.find("\1PING ", 0, 6) != std::string::npos && buf[buf.length() - 1] == '\1') + { + std::string command = buf; + command.erase(command.begin()); + command.erase(command.end()); + ircdproto->SendCTCP(NickServ, u->nick.c_str(), "%s", command.c_str()); + } + else + { + mod_run_cmd(NickServ, u, buf); + } + +} + +/*************************************************************************/ + +/* Check whether a user is on the access list of the nick they're using If + * not, send warnings as appropriate. If so (and not NI_SECURE), update + * last seen info. + * Return 1 if the user is valid and recognized, 0 otherwise (note + * that this means an NI_SECURE nick will return 0 from here). + * If the user's nick is not registered, 0 is returned. + */ + +int validate_user(User * u) +{ + NickAlias *na; + NickRequest *nr; + + if ((nr = findrequestnick(u->nick))) + { + notice_lang(Config.s_NickServ, u, NICK_IS_PREREG); + return 0; + } + + if (!(na = findnick(u->nick))) + return 0; + + if (na->HasFlag(NS_FORBIDDEN)) + { + notice_lang(Config.s_NickServ, u, NICK_MAY_NOT_BE_USED); + u->Collide(na); + return 0; + } + + if (na->nc->HasFlag(NI_SUSPENDED)) + { + notice_lang(Config.s_NickServ, u, NICK_X_SUSPENDED, u->nick.c_str()); + u->Collide(na); + return 0; + } + + if (!na->nc->HasFlag(NI_SECURE) && u->IsRecognized()) + { + na->last_seen = time(NULL); + if (na->last_usermask) + delete [] na->last_usermask; + std::string last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); + na->last_usermask = sstrdup(last_usermask.c_str()); + if (na->last_realname) + delete [] na->last_realname; + na->last_realname = sstrdup(u->realname); + + check_memos(u); + + return 1; + } + + if (u->IsRecognized() || !na->nc->HasFlag(NI_KILL_IMMED)) + { + if (na->nc->HasFlag(NI_SECURE)) + notice_lang(Config.s_NickServ, u, NICK_IS_SECURE, Config.s_NickServ); + else + notice_lang(Config.s_NickServ, u, NICK_IS_REGISTERED, Config.s_NickServ); + } + + if (na->nc->HasFlag(NI_KILLPROTECT) && !u->IsRecognized()) + { + if (na->nc->HasFlag(NI_KILL_IMMED)) + { + notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_NOW); + u->Collide(na); + } + else if (na->nc->HasFlag(NI_KILL_QUICK)) + { + notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_20_SECONDS); + new NickServCollide(na->nick, 20); + } + else + { + notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_1_MINUTE); + new NickServCollide(na->nick, 60); + } + } + + return 0; +} + +/*************************************************************************/ + +/* Remove all nicks which have expired. Also update last-seen time for all + * nicks. + */ + +void expire_nicks() +{ + time_t now = time(NULL); + + for (nickalias_map::const_iterator it = NickAliasList.begin(); it != NickAliasList.end();) + { + NickAlias *na = it->second; + ++it; + + User *u = finduser(na->nick); + if (u && (na->nc->HasFlag(NI_SECURE) ? u->IsIdentified() : u->IsRecognized())) + { + Alog(LOG_DEBUG_2) << "NickServ: updating last seen time for " << na->nick; + na->last_seen = now; + continue; + } + + if (Config.NSExpire && now - na->last_seen >= Config.NSExpire + && !na->HasFlag(NS_FORBIDDEN) && !na->HasFlag(NS_NO_EXPIRE) + && !na->nc->HasFlag(NI_SUSPENDED)) + { + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreNickExpire, OnPreNickExpire(na)); + if (MOD_RESULT == EVENT_STOP) + continue; + Alog() << "Expiring nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " + << (na->nc->email ? na->nc->email : "none") << ")"; + FOREACH_MOD(I_OnNickExpire, OnNickExpire(na)); + delete na; + } + } +} + +void expire_requests() +{ + time_t now = time(NULL); + + for (nickrequest_map::const_iterator it = NickRequestList.begin(); it != NickRequestList.end(); ++it) + { + NickRequest *nr = it->second; + + if (Config.NSRExpire && now - nr->requested >= Config.NSRExpire) + { + Alog() << "Request for nick " << nr->nick << " expiring"; + delete nr; + } + } +} + +/*************************************************************************/ + +NickRequest *findrequestnick(const char *nick) +{ + return findrequestnick(ci::string(nick)); +} + +NickRequest *findrequestnick(const std::string &nick) +{ + return findrequestnick(ci::string(nick.c_str())); +} + +NickRequest *findrequestnick(const ci::string &nick) +{ + nickrequest_map::const_iterator it = NickRequestList.find(nick); + + if (it != NickRequestList.end()) + return it->second; + return NULL; +} + +NickAlias *findnick(const char *nick) +{ + return findnick(ci::string(nick)); +} + +NickAlias *findnick(const std::string &nick) +{ + return findnick(ci::string(nick.c_str())); +} + +NickAlias *findnick(const ci::string &nick) +{ + nickalias_map::const_iterator it = NickAliasList.find(nick); + + if (it != NickAliasList.end()) + return it->second; + return NULL; +} + +/*************************************************************************/ + +NickCore *findcore(const char *nick) +{ + return findcore(ci::string(nick)); +} + +NickCore *findcore(const std::string &nick) +{ + return findcore(ci::string(nick.c_str())); +} + +NickCore *findcore(const ci::string &nick) +{ + nickcore_map::const_iterator it = NickCoreList.find(nick); + + if (it != NickCoreList.end()) + return it->second; + return NULL; +} + +/*************************************************************************/ +/*********************** NickServ private routines ***********************/ +/*************************************************************************/ + +/** Is the user's address on the nickcores access list? + * @param u The user + * @param nc The nickcore + * @return true or false + */ +bool is_on_access(User *u, NickCore *nc) +{ + unsigned i; + char *buf; + char *buf2 = NULL; + char *buf3 = NULL; + std::string tmp_buf; + + if (!u || !nc || nc->access.empty()) + return false; + + tmp_buf = u->GetIdent() + "@" + u->host; + buf = sstrdup(tmp_buf.c_str()); + if (ircd->vhost) + { + if (u->vhost) + { + tmp_buf = u->GetIdent() + "@" + u->vhost; + buf2 = sstrdup(tmp_buf.c_str()); + } + if (!u->GetCloakedHost().empty()) + { + tmp_buf = u->GetIdent() + "@" + u->GetCloakedHost(); + buf3 = sstrdup(tmp_buf.c_str()); + } + } + + for (i = 0; i < nc->access.size(); i++) + { + std::string access = nc->GetAccess(i); + if (Anope::Match(buf, access, false) || (buf2 && Anope::Match(buf2, access, false)) || (buf3 && Anope::Match(buf3, access, false))) + { + delete [] buf; + if (ircd->vhost) + { + if (u->vhost) + { + delete [] buf2; + } + if (!u->GetCloakedHost().empty()) + { + delete [] buf3; + } + } + return true; + } + } + delete [] buf; + if (ircd->vhost) + { + if (buf2) + delete [] buf2; + if (buf3) + delete [] buf3; + } + return false; +} + +/*************************************************************************/ + +/* Sets nc->display to newdisplay. If newdisplay is NULL, it will change + * it to the first alias in the list. + */ + + +void change_core_display(NickCore * nc, const char *newdisplay) +{ + /* Log ... */ + FOREACH_MOD(I_OnChangeCoreDisplay, OnChangeCoreDisplay(nc, newdisplay)); + Alog() << Config.s_NickServ << ": changing " << nc->display << " nickname group display to " << newdisplay; + + /* Remove the core from the list */ + NickCoreList.erase(nc->display); + + delete [] nc->display; + nc->display = sstrdup(newdisplay); + + NickCoreList[nc->display] = nc; +} + +void change_core_display(NickCore * nc) +{ + NickAlias *na; + if (nc->aliases.empty()) + return; + na = nc->aliases.front(); + change_core_display(nc,na->nick); +} + + +/*************************************************************************/ +/*********************** NickServ command routines ***********************/ +/*************************************************************************/ + +int do_setmodes(User * u) +{ + Channel *c; + + /* Walk users current channels */ + for (UChannelList::iterator it = u->chans.begin(); it != u->chans.end(); ++it) + { + ChannelContainer *cc = *it; + + if ((c = cc->chan)) + chan_set_correct_modes(u, c, 1); + } + return MOD_CONT; +} + |