diff options
author | Adam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864> | 2010-05-22 07:40:22 +0000 |
---|---|---|
committer | Adam- <Adam-@5417fbe8-f217-4b02-8779-1006273d7864> | 2010-05-22 07:40:22 +0000 |
commit | d5f036017510dad134fd9c8d471135f774f1fe17 (patch) | |
tree | ee037c32da9ad223cd660af9f5ed36133a517bec | |
parent | fae2710ba7e068edb68baf26f901af564741e5bf (diff) |
Rewrote the nick colliding/releaseing/canceling system, fixes many many bugs on IRCds without svsnick and/or svshold
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2975 5417fbe8-f217-4b02-8779-1006273d7864
-rw-r--r-- | include/account.h | 27 | ||||
-rw-r--r-- | include/extern.h | 5 | ||||
-rw-r--r-- | include/services.h | 39 | ||||
-rw-r--r-- | include/users.h | 7 | ||||
-rw-r--r-- | src/bots.cpp | 3 | ||||
-rw-r--r-- | src/core/bs_bot.c | 1 | ||||
-rw-r--r-- | src/core/ns_forbid.c | 2 | ||||
-rw-r--r-- | src/core/ns_identify.c | 7 | ||||
-rw-r--r-- | src/core/ns_logout.c | 8 | ||||
-rw-r--r-- | src/core/ns_recover.c | 4 | ||||
-rw-r--r-- | src/core/ns_release.c | 6 | ||||
-rw-r--r-- | src/core/ns_suspend.c | 7 | ||||
-rw-r--r-- | src/init.c | 3 | ||||
-rw-r--r-- | src/messages.c | 2 | ||||
-rw-r--r-- | src/nickalias.cpp | 50 | ||||
-rw-r--r-- | src/nickserv.c | 215 | ||||
-rw-r--r-- | src/protocol/bahamut.c | 1 | ||||
-rw-r--r-- | src/protocol/ratbox.c | 1 | ||||
-rw-r--r-- | src/protocol/unreal32.c | 3 | ||||
-rw-r--r-- | src/users.c | 133 |
20 files changed, 237 insertions, 287 deletions
diff --git a/include/account.h b/include/account.h index 25c3ff87d..004760699 100644 --- a/include/account.h +++ b/include/account.h @@ -11,11 +11,16 @@ enum NickNameFlag NS_FORBIDDEN, /* Nick never expires */ NS_NO_EXPIRE, - /* Nick is being held after a kill */ - NS_KILL_HELD, - /* SVSNICK has been sent but nick has not yet changed. - * An enforcer will be introduced when it does change. */ - NS_GUESTED, + /* This nick is being held after a kill by an enforcer client + * or is being SVSHeld. Used by ns_release to determin if something + * should be allowed to be released + */ + NS_HELD, + /* We are taking over this nick, either by SVSNICK or KILL. + * We are waiting for the confirmation of either of these actions to + * proceed. This is checked in NickAlias::OnCancel + */ + NS_COLLIDED, NS_END }; @@ -106,6 +111,18 @@ class CoreExport NickAlias : public Extensible, public Flags<NickNameFlag> time_t last_seen; /* When it was seen online for the last time */ NickCore *nc; /* I'm an alias of this */ HostInfo hostinfo; + + /** Release a nick + * See the comment in users.cpp + */ + void Release(); + + /** This function is called when a user on this nick either disconnects or changes nick. + * Note that the user isnt necessarially identified to this nick + * See the comment in users.cpp + * @param u The user + */ + void OnCancel(User *u); }; class CoreExport NickCore : public Extensible, public Flags<NickCoreFlag> diff --git a/include/extern.h b/include/extern.h index 4194338e9..f3b295bb8 100644 --- a/include/extern.h +++ b/include/extern.h @@ -371,23 +371,18 @@ E NickAlias *nalists[1024]; E NickCore *nclists[1024]; E NickRequest *nrlists[1024]; E NickRequest *findrequestnick(const char *nick); -E unsigned int guestnum; E void insert_requestnick(NickRequest * nr); E void alpha_insert_alias(NickAlias * na); E void insert_core(NickCore * nc); E void get_aliases_stats(long *nrec, long *memuse); E void get_core_stats(long *nrec, long *memuse); -E void collide(NickAlias * na, int from_timeout); -E void del_ns_timeout(NickAlias * na, int type); E void change_core_display(NickCore * nc); E void change_core_display(NickCore * nc, const char *newdisplay); -E void release(NickAlias * na, int from_timeout); E int do_setmodes(User * u); E void ns_init(); E void nickserv(User * u, char *buf); E int validate_user(User * u); -E void cancel_user(User * u); E void expire_nicks(); E void expire_requests(); E NickAlias *findnick(const char *nick); diff --git a/include/services.h b/include/services.h index 2807c49c8..1eb644c52 100644 --- a/include/services.h +++ b/include/services.h @@ -1159,65 +1159,52 @@ class CoreExport Anope */ class NickServCollide : public Timer { - public: - /* NickAlias of the nick who were kicking off */ - NickAlias *na; - /* Return for the std::map::insert */ - std::pair<std::map<NickAlias *, NickServCollide *>::iterator, bool> it; + /* The nick */ + std::string nick; + public: /** Default constructor - * @param nickalias The nick alias were kicking off + * @param _nick The nick were colliding * @param delay How long to delay before kicking the user off the nick */ - NickServCollide(NickAlias *nickalias, time_t delay); + NickServCollide(const std::string &_nick, time_t delay); /** Default destructor */ - ~NickServCollide(); + virtual ~NickServCollide(); /** Called when the delay is up * @param t The current time */ void Tick(time_t t); - - /** Clear all timers for a nick - * @param na The nick to remove the timers for - */ - static void ClearTimers(NickAlias *na); }; /** Timers for releasing nicks to be available for use */ class NickServRelease : public Timer { - public: /* The nick */ - NickAlias *na; + std::string nick; + + public: /* The uid of the services enforcer client (used for TS6 ircds) */ std::string uid; - /* Return for std::map::insert */ - std::pair<std::map<NickAlias *, NickServRelease *>::iterator, bool> it; /** Default constructor - * @param nickalias The nick + * @param _nick The nick + * @param _uid the uid of the enforcer, if any * @param delay The delay before the nick is released */ - NickServRelease(NickAlias *nickalias, time_t delay); + NickServRelease(const std::string &_nick, const std::string &_uid, time_t delay); /** Default destructor */ - ~NickServRelease(); + virtual ~NickServRelease(); /** Called when the delay is up * @param t The current time */ void Tick(time_t t); - - /** Clear all timers for a nick - * @param na The nick to remove the timers for - * @param dorelase true to actually call release(), false to just remove the timers - */ - static void ClearTimers(NickAlias *na, bool dorelease = false); }; /** A timer used to keep the BotServ bot/ChanServ in the channel diff --git a/include/users.h b/include/users.h index 0d701f839..ff7c74622 100644 --- a/include/users.h +++ b/include/users.h @@ -130,6 +130,7 @@ class CoreExport User : public Extensible /** Get the full mask ( nick!ident@realhost ) of a user */ const std::string GetMask(); + /** Updates the realname of the user record. */ void SetRealname(const std::string &realname); @@ -143,6 +144,12 @@ class CoreExport User : public Extensible virtual void SendMessage(const std::string &source, const char *fmt, ...); virtual void SendMessage(const std::string &source, const std::string &msg); + /** Collide a nick + * See the comment in users.cpp + * @param na The nick + */ + void Collide(NickAlias *na); + /** Check if the user should become identified because * their svid matches the one stored in their nickcore * @param svid Services id diff --git a/src/bots.cpp b/src/bots.cpp index e9b72f3e8..316f7c23a 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -64,7 +64,10 @@ BotInfo::BotInfo(const std::string &nnick, const std::string &nuser, const std:: // If we're synchronised with the uplink already, call introduce_user() for this bot. if (serv_uplink && serv_uplink->sync == SSYNC_DONE) + { ircdproto->SendClientIntroduction(this->nick, this->user, this->host, this->real, ircd->pseudoclient_mode, this->uid); + ircdproto->SendSQLine(this->nick, "Reserved for services"); + } } BotInfo::~BotInfo() diff --git a/src/core/bs_bot.c b/src/core/bs_bot.c index 9c7ce4854..09463a77b 100644 --- a/src/core/bs_bot.c +++ b/src/core/bs_bot.c @@ -274,6 +274,7 @@ class CommandBSBot : public Command bi->uid = ts6_uid_retrieve(); } ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real, ircd->pseudoclient_mode, bi->uid); + ircdproto->SendSQLine(bi->nick, "Reserved for services"); bi->RejoinAll(); } diff --git a/src/core/ns_forbid.c b/src/core/ns_forbid.c index 18f3bf2aa..7ddaec68a 100644 --- a/src/core/ns_forbid.c +++ b/src/core/ns_forbid.c @@ -65,7 +65,7 @@ class CommandNSForbid : public Command if (curr) { notice_lang(Config.s_NickServ, curr, FORCENICKCHANGE_NOW); - collide(na, 0); + curr->Collide(na); } diff --git a/src/core/ns_identify.c b/src/core/ns_identify.c index f16b5e84c..1b829179c 100644 --- a/src/core/ns_identify.c +++ b/src/core/ns_identify.c @@ -15,9 +15,6 @@ #include "module.h" -#define TO_COLLIDE 0 /* Collide the user with this nick */ -#define TO_RELEASE 1 /* Release a collided nick */ - class CommandNSIdentify : public Command { public: @@ -94,10 +91,6 @@ class CommandNSIdentify : public Command if (u->IsIdentified()) check_memos(u); - - /* Clear any timers */ - if (na->nc->HasFlag(NI_KILLPROTECT)) - del_ns_timeout(na, TO_COLLIDE); } return MOD_CONT; } diff --git a/src/core/ns_logout.c b/src/core/ns_logout.c index fcb14fb8e..7e16dc8f5 100644 --- a/src/core/ns_logout.c +++ b/src/core/ns_logout.c @@ -15,9 +15,6 @@ #include "module.h" -#define TO_COLLIDE 0 /* Collide the user with this nick */ -#define TO_RELEASE 1 /* Release a collided nick */ - class CommandNSLogout : public Command { public: @@ -44,7 +41,6 @@ class CommandNSLogout : public Command if (nick && !param.empty() && param == "REVALIDATE") { - cancel_user(u2); validate_user(u2); } @@ -57,10 +53,6 @@ class CommandNSLogout : public Command else notice_lang(Config.s_NickServ, u, NICK_LOGOUT_SUCCEEDED); - /* Clear any timers again */ - if (na && u->Account()->HasFlag(NI_KILLPROTECT)) - del_ns_timeout(na, TO_COLLIDE); - ircdproto->SendAccountLogout(u2, u2->Account()); ircdproto->SendUnregisteredNick(u2); diff --git a/src/core/ns_recover.c b/src/core/ns_recover.c index 23b284e46..99b5e34f1 100644 --- a/src/core/ns_recover.c +++ b/src/core/ns_recover.c @@ -49,7 +49,7 @@ class CommandNSRecover : public Command char relstr[192]; notice_lang(Config.s_NickServ, u2, FORCENICKCHANGE_NOW); - collide(na, 0); + u2->Collide(na); /* Convert Config.NSReleaseTimeout seconds to string format */ duration(na->nc, relstr, sizeof(relstr), Config.NSReleaseTimeout); @@ -74,7 +74,7 @@ class CommandNSRecover : public Command char relstr[192]; notice_lang(Config.s_NickServ, u2, FORCENICKCHANGE_NOW); - collide(na, 0); + u2->Collide(na); /* Convert Config.NSReleaseTimeout seconds to string format */ duration(na->nc, relstr, sizeof(relstr), Config.NSReleaseTimeout); diff --git a/src/core/ns_release.c b/src/core/ns_release.c index a4169ecda..6f360e942 100644 --- a/src/core/ns_release.c +++ b/src/core/ns_release.c @@ -35,14 +35,14 @@ class CommandNSRelease : public Command notice_lang(Config.s_NickServ, u, NICK_X_FORBIDDEN, na->nick); else if (na->nc->HasFlag(NI_SUSPENDED)) notice_lang(Config.s_NickServ, u, NICK_X_SUSPENDED, na->nick); - else if (!(na->HasFlag(NS_KILL_HELD))) + else if (!(na->HasFlag(NS_HELD))) notice_lang(Config.s_NickServ, u, NICK_RELEASE_NOT_HELD, nick); else if (!pass.empty()) { int res = enc_check_password(pass, na->nc->pass); if (res == 1) { - release(na, 0); + na->Release(); notice_lang(Config.s_NickServ, u, NICK_RELEASED); } else @@ -60,7 +60,7 @@ class CommandNSRelease : public Command { if (u->Account() == na->nc || (!(na->nc->HasFlag(NI_SECURE)) && is_on_access(u, na->nc))) { - release(na, 0); + na->Release(); notice_lang(Config.s_NickServ, u, NICK_RELEASED); } else diff --git a/src/core/ns_suspend.c b/src/core/ns_suspend.c index 7c3dd0ca9..2354fe66b 100644 --- a/src/core/ns_suspend.c +++ b/src/core/ns_suspend.c @@ -70,11 +70,12 @@ class CommandNSSuspend : public Command if (na2->last_quit) delete [] na2->last_quit; na2->last_quit = sstrdup(reason); - /* removes nicktracking */ + if ((u2 = finduser(na2->nick))) + { u2->Logout(); - /* force guestnick */ - collide(na2, 0); + u2->Collide(na2); + } } } diff --git a/src/init.c b/src/init.c index cafb30ada..b551325bb 100644 --- a/src/init.c +++ b/src/init.c @@ -43,7 +43,10 @@ void introduce_user(const std::string &user) { ci::string ci_bi_nick(bi->nick.c_str()); if (user.empty() || ci_bi_nick == user) + { ircdproto->SendClientIntroduction(bi->nick, bi->user, bi->host, bi->real, ircd->pseudoclient_mode, bi->uid); + ircdproto->SendSQLine(bi->nick, "Reserved for services"); + } } } } diff --git a/src/messages.c b/src/messages.c index 212174939..5e97dfc71 100644 --- a/src/messages.c +++ b/src/messages.c @@ -300,7 +300,7 @@ int m_whois(const char *source, const char *who) ircdproto->SendNumeric(Config.ServerName, 317, source, "%s %ld %ld :seconds idle, signon time", bi->nick.c_str(), time(NULL) - bi->lastmsg, start_time); ircdproto->SendNumeric(Config.ServerName, 318, source, "%s :End of /WHOIS list.", who); } - else if (!ircd->svshold && (na = findnick(who)) && na->HasFlag(NS_KILL_HELD)) + else if (!ircd->svshold && (na = findnick(who)) && na->HasFlag(NS_HELD)) { /* We have a nick enforcer client here that we need to respond to. * We can't just say it doesn't exist here, even tho it does for diff --git a/src/nickalias.cpp b/src/nickalias.cpp index 12e656668..afd40ccd7 100644 --- a/src/nickalias.cpp +++ b/src/nickalias.cpp @@ -80,10 +80,6 @@ NickAlias::~NickAlias() { User *u = NULL; - /* First thing to do: remove any timeout belonging to the nick we're deleting */ - NickServCollide::ClearTimers(this); - NickServRelease::ClearTimers(this, true); - FOREACH_MOD(I_OnDelNick, OnDelNick(this)); /* Second thing to do: look for an user using the alias @@ -130,3 +126,49 @@ NickAlias::~NickAlias() delete [] this->last_quit; } +/** Release a nick from being held. This can be called from the core (ns_release) + * or from a timer used when forcing clients off of nicks. Note that if this is called + * from a timer, ircd->svshold is NEVER true + */ +void NickAlias::Release() +{ + if (this->HasFlag(NS_HELD)) + { + if (ircd->svshold) + { + ircdproto->SendSVSHoldDel(this->nick); + } + else + { + ircdproto->SendQuit(this->nick, NULL); + } + + this->UnsetFlag(NS_HELD); + } +} + +/** Called when a user gets off this nick + * See the comment in users.cpp for User::Collide() + * @param u The user + */ +void NickAlias::OnCancel(User *) +{ + if (this->HasFlag(NS_COLLIDED)) + { + this->SetFlag(NS_HELD); + this->UnsetFlag(NS_COLLIDED); + + if (ircd->svshold) + { + ircdproto->SendSVSHold(this->nick); + } + else + { + std::string uid = (ircd->ts6 ? ts6_uid_retrieve() : ""); + + ircdproto->SendClientIntroduction(this->nick, Config.NSEnforcerUser, Config.NSEnforcerHost, "Services Enforcer", "+", uid); + new NickServRelease(this->nick, uid, Config.NSReleaseTimeout); + } + } +} + diff --git a/src/nickserv.c b/src/nickserv.c index aef24eecf..c9f2e2ffb 100644 --- a/src/nickserv.c +++ b/src/nickserv.c @@ -24,106 +24,60 @@ NickAlias *nalists[1024]; NickCore *nclists[1024]; NickRequest *nrlists[1024]; -unsigned int guestnum; /* Current guest number */ +static std::map<std::string, NickServCollide *> NickServCollides; +static std::map<std::string, NickServRelease *> NickServReleases; -#define TO_COLLIDE 0 /* Collide the user with this nick */ -#define TO_RELEASE 1 /* Release a collided nick */ - -/*************************************************************************/ - -static std::map<NickAlias *, NickServCollide *> NickServCollides; -static std::map<NickAlias *, NickServRelease *> NickServReleases; - -NickServCollide::NickServCollide(NickAlias *nickalias, time_t delay) : Timer(delay), na(nickalias) +NickServCollide::NickServCollide(const std::string &_nick, time_t delay) : Timer(delay), nick(_nick) { /* Erase the current collide and use the new one */ - std::map<NickAlias *, NickServCollide *>::iterator nit = NickServCollides.find(nickalias); + std::map<std::string, NickServCollide *>::iterator nit = NickServCollides.find(nick); if (nit != NickServCollides.end()) { delete nit->second; } - it = NickServCollides.insert(std::make_pair(nickalias, this)); + NickServCollides.insert(std::make_pair(nick, this)); } NickServCollide::~NickServCollide() { - if (it.second) - { - NickServCollides.erase(it.first); - } + NickServCollides.erase(nick); } void NickServCollide::Tick(time_t ctime) { /* If they identified or don't exist anymore, don't kill them. */ - User *u = finduser(na->nick); - if (!u || u->Account() == na->nc || u->my_signon > this->GetSetTime()) + User *u = finduser(nick); + NickAlias *na = findnick(nick); + if (!u || !na || u->Account() == na->nc || u->my_signon > this->GetSetTime()) return; - - /* The RELEASE timeout will always add to the beginning of the - * list, so we won't see it. Which is fine because it can't be - * triggered yet anyway. */ - collide(na, 1); + + u->Collide(na); } -void NickServCollide::ClearTimers(NickAlias *na) -{ - std::map<NickAlias *, NickServCollide *>::iterator i = NickServCollides.find(na); - - if (i != NickServCollides.end()) - { - delete i->second; - } -} - -NickServRelease::NickServRelease(NickAlias *nickalias, time_t delay) : Timer(delay), na(nickalias) +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<NickAlias *, NickServRelease *>::iterator nit = NickServReleases.find(nickalias); + std::map<std::string, NickServRelease *>::iterator nit = NickServReleases.find(nick); if (nit != NickServReleases.end()) { delete nit->second; } - it = NickServReleases.insert(std::make_pair(nickalias, this)); + NickServReleases.insert(std::make_pair(nick, this)); } NickServRelease::~NickServRelease() { - if (it.second) - { - NickServReleases.erase(it.first); - } + NickServReleases.erase(nick); } void NickServRelease::Tick(time_t ctime) { - if (ircd->svshold) - { - ircdproto->SendSVSHoldDel(na->nick); - } - else - { - if (ircd->ts6 && !uid.empty()) - ircdproto->SendQuit(uid.c_str(), NULL); - else - ircdproto->SendQuit(na->nick, NULL); - } - na->UnsetFlag(NS_KILL_HELD); -} - -void NickServRelease::ClearTimers(NickAlias *na, bool dorelease) -{ - std::map<NickAlias *, NickServRelease *>::iterator i = NickServReleases.find(na); - - if (i != NickServReleases.end()) - { - if (dorelease) - release(na, 1); + NickAlias *na = findnick(nick); - delete i->second; - } + if (na) + na->Release(); } /*************************************************************************/ @@ -217,9 +171,6 @@ void get_core_stats(long *nrec, long *memuse) void ns_init() { moduleAddNickServCmds(); - guestnum = time(NULL); - while (guestnum > 9999999) - guestnum -= 10000000; } /*************************************************************************/ @@ -265,11 +216,11 @@ int validate_user(User * u) { NickAlias *na; NickRequest *nr; - NickServCollide *t; if ((nr = findrequestnick(u->nick.c_str()))) { notice_lang(Config.s_NickServ, u, NICK_IS_PREREG); + return 0; } if (!(na = findnick(u->nick))) @@ -278,14 +229,14 @@ int validate_user(User * u) if (na->HasFlag(NS_FORBIDDEN)) { notice_lang(Config.s_NickServ, u, NICK_MAY_NOT_BE_USED); - collide(na, 0); + u->Collide(na); return 0; } if (na->nc->HasFlag(NI_SUSPENDED)) { notice_lang(Config.s_NickServ, u, NICK_X_SUSPENDED, u->nick.c_str()); - collide(na, 0); + u->Collide(na); return 0; } @@ -315,17 +266,17 @@ int validate_user(User * u) if (na->nc->HasFlag(NI_KILL_IMMED)) { notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_NOW); - collide(na, 0); + u->Collide(na); } else if (na->nc->HasFlag(NI_KILL_QUICK)) { notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_20_SECONDS); - t = new NickServCollide(na, 20); + new NickServCollide(na->nick, 20); } else { notice_lang(Config.s_NickServ, u, FORCENICKCHANGE_IN_1_MINUTE); - t = new NickServCollide(na, 60); + new NickServCollide(na->nick, 60); } } @@ -334,44 +285,6 @@ int validate_user(User * u) /*************************************************************************/ -/* Cancel validation flags for a nick (i.e. when the user with that nick - * signs off or changes nicks). Also cancels any impending collide. */ - -void cancel_user(User * u) -{ - NickAlias *na = findnick(u->nick); - NickServRelease *t; - std::string uid; - - if (na) - { - if (na->HasFlag(NS_GUESTED)) - { - if (ircd->svshold) - { - ircdproto->SendSVSHold(na->nick); - } - else if (ircd->svsnick) - { - uid = ts6_uid_retrieve(); - ircdproto->SendClientIntroduction(u->nick, Config.NSEnforcerUser, Config.NSEnforcerHost, "Services Enforcer", "+", uid); - t = new NickServRelease(na, Config.NSReleaseTimeout); - t->uid = uid; - } - else - { - ircdproto->SendSVSKill(findbot(Config.s_NickServ), u, "Please do not use a registered nickname without identifying"); - } - na->SetFlag(NS_KILL_HELD); - na->UnsetFlag(NS_GUESTED); - } - - NickServCollide::ClearTimers(na); - } -} - -/*************************************************************************/ - /* Remove all nicks which have expired. Also update last-seen time for all * nicks. */ @@ -700,86 +613,6 @@ void change_core_display(NickCore * nc) /*************************************************************************/ - -/* Collide a nick. - * - * When connected to a network using DALnet servers, version 4.4.15 and above, - * Services is now able to force a nick change instead of killing the user. - * The new nick takes the form "Guest######". If a nick change is forced, we - * do not introduce the enforcer nick until the user's nick actually changes. - * This is watched for and done in cancel_user(). -TheShadow - */ - -void collide(NickAlias * na, int from_timeout) -{ - if (!from_timeout) - NickServCollide::ClearTimers(na); - - /* Old system was unsure since there can be more than one collide - * per second. So let use another safer method. - * --lara - */ - /* So you should check the length of Config.NSGUestNickPrefix, eh Lara? - * --Certus - */ - - if (ircd->svsnick) - { - User *u = finduser(na->nick); - if (!u) - return; - - std::string guestnick; - /* We need to make sure the guestnick is free -- heinz */ - do - { - char randbuf[17]; - snprintf(randbuf, sizeof(randbuf), "%d", getrandom16()); - guestnick = Config.NSGuestNickPrefix; - guestnick += randbuf; - } - while (finduser(guestnick.c_str())); - notice_lang(Config.s_NickServ, finduser(na->nick), FORCENICKCHANGE_CHANGING, guestnick.c_str()); - ircdproto->SendForceNickChange(u, guestnick.c_str(), time(NULL)); - na->SetFlag(NS_GUESTED); - } - else - { - kill_user(Config.s_NickServ, na->nick, "Services nickname-enforcer kill"); - } -} - -/*************************************************************************/ - -/* Release hold on a nick. */ - -void release(NickAlias * na, int from_timeout) -{ - if (!from_timeout) - NickServRelease::ClearTimers(na); - - if (ircd->svshold) - { - ircdproto->SendSVSHoldDel(na->nick); - } - else - { - ircdproto->SendQuit(na->nick, NULL); - } - na->UnsetFlag(NS_KILL_HELD); -} - -/*************************************************************************/ - -void del_ns_timeout(NickAlias * na, int type) -{ - if (type == TO_COLLIDE) - NickServCollide::ClearTimers(na); - else if (type == TO_RELEASE) - NickServRelease::ClearTimers(na); -} - -/*************************************************************************/ /*********************** NickServ command routines ***********************/ /*************************************************************************/ diff --git a/src/protocol/bahamut.c b/src/protocol/bahamut.c index 01462708c..a813a4b6c 100644 --- a/src/protocol/bahamut.c +++ b/src/protocol/bahamut.c @@ -261,7 +261,6 @@ class BahamutIRCdProto : public IRCDProto { EnforceQlinedNick(nick, Config.s_BotServ); send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick.c_str(), static_cast<long>(time(NULL)), modes, user.c_str(), host.c_str(), Config.ServerName, real.c_str()); - SendSQLine(nick, "Reserved for services"); } /* SVSMODE +d */ diff --git a/src/protocol/ratbox.c b/src/protocol/ratbox.c index 116042992..f1c2f3b3b 100644 --- a/src/protocol/ratbox.c +++ b/src/protocol/ratbox.c @@ -209,7 +209,6 @@ class RatboxProto : public IRCDTS6Proto { EnforceQlinedNick(nick, NULL); send_cmd(TS6SID, "UID %s 1 %ld %s %s %s 0 %s :%s", nick.c_str(), static_cast<long>(time(NULL)), modes, user.c_str(), host.c_str(), uid.c_str(), real.c_str()); - SendSQLine(nick, "Reserved for services"); } void SendPartInternal(BotInfo *bi, const char *chan, const char *buf) diff --git a/src/protocol/unreal32.c b/src/protocol/unreal32.c index e1b673c25..d36a5db20 100644 --- a/src/protocol/unreal32.c +++ b/src/protocol/unreal32.c @@ -197,9 +197,8 @@ class UnrealIRCdProto : public IRCDProto void SendClientIntroduction(const std::string &nick, const std::string &user, const std::string &host, const std::string &real, const char *modes, const std::string &uid) { - EnforceQlinedNick(nick, Config.s_BotServ); + EnforceQlinedNick(nick, Config.ServerName); send_cmd(NULL, "& %s 1 %ld %s %s %s 0 %s %s%s :%s", nick.c_str(), static_cast<long>(time(NULL)), user.c_str(), host.c_str(), Config.ServerName, modes, host.c_str(), myIrcd->nickip ? " *" : " ", real.c_str()); - SendSQLine(nick, "Reserved for services"); } void SendKickInternal(BotInfo *source, Channel *chan, User *user, const char *buf) diff --git a/src/users.c b/src/users.c index c1532bc27..26e50a40d 100644 --- a/src/users.c +++ b/src/users.c @@ -14,6 +14,7 @@ #include "services.h" #include "modules.h" +#include "language.h" #define HASH(nick) (((nick)[0]&31)<<5 | ((nick)[1]&31)) User *userlist[1024]; @@ -223,13 +224,11 @@ void User::SetRealname(const std::string &srealname) User::~User() { - char *srealname; - Alog(LOG_DEBUG_2) << "User::~User() called"; if (Config.LogUsers) { - srealname = normalizeBuffer(this->realname); + const char *srealname = normalizeBuffer(this->realname); Alog() << "LOGUSERS: " << this->GetMask() << (ircd->vhost ? " => " : " ") << (ircd->vhost ? this->GetDisplayedHost() : "") @@ -244,6 +243,22 @@ User::~User() if (is_oper(this)) opcnt--; + + while (!this->chans.empty()) + { + this->chans.front()->chan->DeleteUser(this); + } + + if (this->prev) + this->prev->next = this->next; + else + userlist[HASH(this->nick)] = this->next; + if (this->next) + this->next->prev = this->prev; + + NickAlias *na = findnick(this->nick); + if (na) + na->OnCancel(this); Alog(LOG_DEBUG_2) << "User::~User(): free user data"; @@ -257,26 +272,6 @@ User::~User() if (this->hostip) delete [] this->hostip; - Alog(LOG_DEBUG_2) << "User::~User(): remove from channels"; - - while (!this->chans.empty()) - { - this->chans.front()->chan->DeleteUser(this); - } - - /* Cancel pending nickname enforcers, etc */ - cancel_user(this); - - Alog(LOG_DEBUG_2) << "User::~User(): delete from list"; - - if (this->prev) - this->prev->next = this->next; - else - userlist[HASH(this->nick)] = this->next; - - if (this->next) - this->next->prev = this->prev; - Alog(LOG_DEBUG_2) << "User::~User() done"; } @@ -315,6 +310,88 @@ void User::SendMessage(const std::string &source, const std::string &msg) } } +/** Collides a nick. + * + * First, it marks the nick (if the user is on a registered nick, we don't use it without but it could be) + * as COLLIDED, this is checked in NickAlias::OnCancel. + * + * Then it does one of two things. + * + * 1. This will force change the users nick to the guest nick. This gets processed by the IRCd and comes + * back to call do_nick. do_nick changes the nick of the use to the new one, then calls NickAlias::OnCancel + * with the users old nick's nickalias (if there is one). + * + * 2. Calls kill_user, which will either delete the user immediatly or kill them, wait for the QUIT, + * then delete the user then. Users destructor then calls NickAlias::OnCancel + * + * NickAlias::OnCancel checks for NS_COLLIDED, it then does one of two things. + * + * 1. If supported, we send a SVSHold for the user. We are done here, the IRCds expires this at the time we give it. + * + * 2. We create a new client with SendClientIntroduction(). Note that is it important that this is called either after the + * user has been removed from our internal list of user or after the users nick has been updated completely internally. + * This is beacuse SendClientIntroduction will destroy any users we think are currently on the nickname (which causes a + * lot of problems, eg, deleting the user which recalls OnCancel), whether they really are or not. We then create a + * release timer for this new client that waits and later on sends a QUIT for the client. Release timers are never used + * for SVSHolds. Ever. + * + * + * Note that now for the timers we only store the users name, not the NickAlias* pointer. We never remove timers when + * a user changes nick or a nick is deleted, the timers must assume that either of these may have happend. + * + * Storing NickAlias* pointers caused quite a problem, some of which are: + * + * Having a valid timer alive that calls User::Collide would either: + * + * 1. Kill the user, causing users destructor to cancel all timers for the nick (as it should, it has no way of knowing + * if we are in a timer or not) which would delete the currently active timer while it was running, causing TimerManager + * to explode. + * + * 2. Force a user off of their nick, this would call NickAlias::Cancel before updating the user internally (to cancel the + * current nicks timers, granted we could have easially saved this and called it after) which could possibly try to + * introduce an enforcer nick. We would then check to see if the nick is already in use (it is, internally) and send + * a kill for that nick. That may in turn delete the user immediatly, calling users destructor, which would attempt to + * delete the timer, causing TimerManager to explode. + * + * Additionally, if we marked the timer as "in use" so that calling the ClearTimer function wouldn't delete them, users + * destructor would then call NickAlias::OnCancel, which would (at this point, it was unsetting GUESTED after introducing + * the new client) introduce the same new client again, without actually deleting the originial user, causing an infinite + * loop. + * + * This is why we remove NS_GUESTED first in NickAlias::OnCancel before introducing a new client, although this should + * not happen anymore. If I must emphasize this again, users need to be GONE from the internal list before calling + * NickAlias::OnCancel. NickAlias::OnCancel intentionally reffers to this->nick, not the user passed to it. They *can* + * (but not always) be different, depending if the user changed nicks or disconnected. + * + * + * Adam + */ +void User::Collide(NickAlias *na) +{ + if (na) + na->SetFlag(NS_COLLIDED); + + if (ircd->svsnick) + { + std::string guestnick; + + do + { + char randbuf[17]; + snprintf(randbuf, sizeof(randbuf), "%d", getrandom16()); + guestnick = std::string(Config.NSGuestNickPrefix) + std::string(randbuf); + } + while (finduser(guestnick.c_str())); + + notice_lang(Config.s_NickServ, this, FORCENICKCHANGE_CHANGING, guestnick.c_str()); + ircdproto->SendForceNickChange(this, guestnick.c_str(), time(NULL)); + } + else + { + kill_user(Config.s_NickServ, this->nick, "Services nickname-enforcer kill"); + } +} + /** Check if the user should become identified because * their svid matches the one stored in their nickcore * @param svid Services id @@ -749,7 +826,6 @@ User *do_nick(const char *source, const char *nick, const char *username, const NickAlias *old_na; /* Old nick rec */ int nc_changed = 1; /* Did nick core change? */ char *logrealname; - std::string oldnick; /* stores the old nick of the user, so we can pass it to OnUserNickChange */ if (!*source) { char ipbuf[16]; @@ -875,16 +951,19 @@ User *do_nick(const char *source, const char *nick, const char *username, const user->my_signon = time(NULL); old_na = findnick(user->nick); - if (old_na) { + if (old_na) + { if (user->IsRecognized()) old_na->last_seen = time(NULL); - cancel_user(user); } - oldnick = user->nick; + std::string oldnick = user->nick; user->SetNewNick(nick); FOREACH_MOD(I_OnUserNickChange, OnUserNickChange(user, oldnick.c_str())); + if (old_na) + old_na->OnCancel(user); + if ((old_na ? old_na->nc : NULL) == user->Account()) nc_changed = 0; |