anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

ns_recover.cpp (8536B)

      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 #include "modules/ns_cert.h"
     14 
     15 static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
     16 
     17 typedef std::map<Anope::string, ChannelStatus> NSRecoverInfo;
     18 
     19 class NSRecoverSvsnick
     20 {
     21  public:
     22 	Reference<User> from;
     23 	Anope::string to;
     24 };
     25 
     26 class NSRecoverRequest : public IdentifyRequest
     27 {
     28 	CommandSource source;
     29 	Command *cmd;
     30 	Anope::string user;
     31 
     32  public:
     33 	NSRecoverRequest(Module *o, CommandSource &src, Command *c, const Anope::string &nick, const Anope::string &pass) : IdentifyRequest(o, nick, pass), source(src), cmd(c), user(nick) { }
     34 
     35 	void OnSuccess() anope_override
     36 	{
     37 		User *u = User::Find(user, true);
     38 		if (!source.GetUser() || !source.service)
     39 			return;
     40 
     41 		NickAlias *na = NickAlias::Find(user);
     42 		if (!na)
     43 			return;
     44 
     45 		Log(LOG_COMMAND, source, cmd) << "for " << na->nick;
     46 
     47 		/* Nick is being held by us, release it */
     48 		if (na->HasExt("HELD"))
     49 		{
     50 			nickserv->Release(na);
     51 			source.Reply(_("Service's hold on \002%s\002 has been released."), na->nick.c_str());
     52 		}
     53 		else if (!u)
     54 		{
     55 			source.Reply(_("No one is using your nick, and services are not holding it."));
     56 		}
     57 		// If the user being recovered is identified for the account of the nick then the user is the
     58 		// same person that is executing the command, so kill them off (old GHOST command).
     59 		else if (u->Account() == na->nc)
     60 		{
     61 			if (!source.GetAccount() && na->nc->HasExt("NS_SECURE"))
     62 			{
     63 				source.GetUser()->Login(u->Account());
     64 				Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << u->Account()->display;
     65 			}
     66 
     67 			if (Config->GetModule("ns_recover")->Get<bool>("restoreonrecover"))
     68 			{
     69 				if (!u->chans.empty())
     70 				{
     71 					NSRecoverInfo *ei = source.GetUser()->Extend<NSRecoverInfo>("recover");
     72 					for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it)
     73 						(*ei)[it->first->name] = it->second->status;
     74 				}
     75 			}
     76 
     77 			u->SendMessage(source.service, _("This nickname has been recovered by %s. If you did not do\n"
     78 							"this then %s may have your password, and you should change it."),
     79 							source.GetNick().c_str(), source.GetNick().c_str());
     80 
     81 			Anope::string buf = source.command.upper() + " command used by " + source.GetNick();
     82 			u->Kill(*source.service, buf);
     83 
     84 			source.Reply(_("Ghost with your nick has been killed."));
     85 
     86 			if (IRCD->CanSVSNick)
     87 				IRCD->SendForceNickChange(source.GetUser(), GetAccount(), Anope::CurTime);
     88 		}
     89 		/* User is not identified or not identified to the same account as the person using this command */
     90 		else
     91 		{
     92 			if (!source.GetAccount() && na->nc->HasExt("NS_SECURE"))
     93 			{
     94 				source.GetUser()->Login(na->nc); // Identify the user using the command if they arent identified
     95 				Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << na->nick << " (" << na->nc->display << ")";
     96 				source.Reply(_("You have been logged in as \002%s\002."), na->nc->display.c_str());
     97 			}
     98 
     99 			u->SendMessage(source.service, _("This nickname has been recovered by %s."), source.GetNick().c_str());
    100 
    101 			if (IRCD->CanSVSNick)
    102 			{
    103 				NSRecoverSvsnick *svs = u->Extend<NSRecoverSvsnick>("svsnick");
    104 				svs->from = source.GetUser();
    105 				svs->to = u->nick;
    106 			}
    107 
    108 			if (nickserv)
    109 				nickserv->Collide(u, na);
    110 
    111 			if (IRCD->CanSVSNick)
    112 			{
    113 				/* If we can svsnick then release our hold and svsnick the user using the command */
    114 				if (nickserv)
    115 					nickserv->Release(na);
    116 
    117 				source.Reply(_("You have regained control of \002%s\002."), u->nick.c_str());
    118 			}
    119 			else
    120 			{
    121 				source.Reply(_("The user with your nick has been removed. Use this command again\n"
    122 						"to release services's hold on your nick."));
    123 			}
    124 		}
    125 	}
    126 
    127 	void OnFail() anope_override
    128 	{
    129 		if (NickAlias::Find(GetAccount()) != NULL)
    130 		{
    131 			source.Reply(ACCESS_DENIED);
    132 			if (!GetPassword().empty())
    133 			{
    134 				Log(LOG_COMMAND, source, cmd) << "with an invalid password for " << GetAccount();
    135 				if (source.GetUser())
    136 					source.GetUser()->BadPassword();
    137 			}
    138 		}
    139 		else
    140 			source.Reply(NICK_X_NOT_REGISTERED, GetAccount().c_str());
    141 	}
    142 };
    143 
    144 class CommandNSRecover : public Command
    145 {
    146  public:
    147 	CommandNSRecover(Module *creator) : Command(creator, "nickserv/recover", 1, 2)
    148 	{
    149 		this->SetDesc(_("Regains control of your nick"));
    150 		this->SetSyntax(_("\037nickname\037 [\037password\037]"));
    151 		this->AllowUnregistered(true);
    152 	}
    153 
    154 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    155 	{
    156 		const Anope::string &nick = params[0];
    157 		const Anope::string &pass = params.size() > 1 ? params[1] : "";
    158 
    159 		User *user = User::Find(nick, true);
    160 
    161 		if (user && source.GetUser() == user)
    162 		{
    163 			source.Reply(_("You can't %s yourself!"), source.command.lower().c_str());
    164 			return;
    165 		}
    166 
    167 		const NickAlias *na = NickAlias::Find(nick);
    168 
    169 		if (!na)
    170 		{
    171 			source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
    172 			return;
    173 		}
    174 		else if (na->nc->HasExt("NS_SUSPENDED"))
    175 		{
    176 			source.Reply(NICK_X_SUSPENDED, na->nick.c_str());
    177 			return;
    178 		}
    179 
    180 		bool ok = false;
    181 		if (source.GetAccount() == na->nc)
    182 			ok = true;
    183 		else if (!na->nc->HasExt("NS_SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser()))
    184 			ok = true;
    185 
    186 		NSCertList *cl = na->nc->GetExt<NSCertList>("certificates");
    187 		if (source.GetUser() && !source.GetUser()->fingerprint.empty() && cl && cl->FindCert(source.GetUser()->fingerprint))
    188 			ok = true;
    189 
    190 		if (source.HasPriv("nickserv/recover"))
    191 			ok = true;
    192 
    193 		if (ok == false && !pass.empty())
    194 		{
    195 			NSRecoverRequest *req = new NSRecoverRequest(owner, source, this, na->nick, pass);
    196 			FOREACH_MOD(OnCheckAuthentication, (source.GetUser(), req));
    197 			req->Dispatch();
    198 		}
    199 		else
    200 		{
    201 			NSRecoverRequest req(owner, source, this, na->nick, pass);
    202 
    203 			if (ok)
    204 				req.OnSuccess();
    205 			else
    206 				req.OnFail();
    207 		}
    208 	}
    209 
    210 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    211 	{
    212 		this->SendSyntax(source);
    213 		source.Reply(" ");
    214 		source.Reply(_("Recovers your nick from another user or from services.\n"
    215 				"If services are currently holding your nick, the hold\n"
    216 				"will be released. If another user is holding your nick\n"
    217 				"and is identified they will be killed (similar to the old\n"
    218 				"GHOST command). If they are not identified they will be\n"
    219 				"forced off of the nick."));
    220 		return true;
    221 	}
    222 };
    223 
    224 class NSRecover : public Module
    225 {
    226 	CommandNSRecover commandnsrecover;
    227 	PrimitiveExtensibleItem<NSRecoverInfo> recover;
    228 	PrimitiveExtensibleItem<NSRecoverSvsnick> svsnick;
    229 
    230  public:
    231 	NSRecover(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    232 		commandnsrecover(this), recover(this, "recover"), svsnick(this, "svsnick")
    233 	{
    234 
    235 		if (Config->GetModule("nickserv")->Get<bool>("nonicknameownership"))
    236 			throw ModuleException(modname + " can not be used with options:nonicknameownership enabled");
    237 
    238 	}
    239 
    240 	void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override
    241 	{
    242 		if (Config->GetModule(this)->Get<bool>("restoreonrecover"))
    243 		{
    244 			NSRecoverInfo *ei = recover.Get(u);
    245 			BotInfo *NickServ = Config->GetClient("NickServ");
    246 
    247 			if (ei != NULL && NickServ != NULL)
    248 				for (NSRecoverInfo::iterator it = ei->begin(), it_end = ei->end(); it != it_end;)
    249 				{
    250 					Channel *c = Channel::Find(it->first);
    251 					const Anope::string &cname = it->first;
    252 					++it;
    253 
    254 					/* User might already be on the channel */
    255 					if (u->FindChannel(c))
    256 						this->OnJoinChannel(u, c);
    257 					else if (IRCD->CanSVSJoin)
    258 						IRCD->SendSVSJoin(NickServ, u, cname, "");
    259 				}
    260 		}
    261 
    262 		NSRecoverSvsnick *svs = svsnick.Get(u);
    263 		if (svs)
    264 		{
    265 			if (svs->from)
    266 			{
    267 				// svsnick from to to
    268 				IRCD->SendForceNickChange(svs->from, svs->to, Anope::CurTime);
    269 			}
    270 
    271 			svsnick.Unset(u);
    272 		}
    273 	}
    274 
    275 	void OnJoinChannel(User *u, Channel *c) anope_override
    276 	{
    277 		if (Config->GetModule(this)->Get<bool>("restoreonrecover"))
    278 		{
    279 			NSRecoverInfo *ei = recover.Get(u);
    280 
    281 			if (ei != NULL)
    282 			{
    283 				NSRecoverInfo::iterator it = ei->find(c->name);
    284 				if (it != ei->end())
    285 				{
    286 					for (size_t i = 0; i < it->second.Modes().length(); ++i)
    287 						c->SetMode(c->ci->WhoSends(), ModeManager::FindChannelModeByChar(it->second.Modes()[i]), u->GetUID());
    288 
    289 					ei->erase(it);
    290 					if (ei->empty())
    291 						recover.Unset(u);
    292 				}
    293 			}
    294 		}
    295 	}
    296 };
    297 
    298 MODULE_INIT(NSRecover)