00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "module.h"
00015
00016 struct NSRecoverExtensibleInfo : ExtensibleItem, std::map<Anope::string, ChannelStatus> { };
00017
00018 class NSRecoverRequest : public IdentifyRequest
00019 {
00020 CommandSource source;
00021 Command *cmd;
00022 Anope::string user;
00023
00024 public:
00025 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) { }
00026
00027 void OnSuccess() anope_override
00028 {
00029 User *u = User::Find(user, true);
00030 if (!source.GetUser() || !source.service)
00031 return;
00032
00033 NickAlias *na = NickAlias::Find(user);
00034 if (!na)
00035 return;
00036
00037 Log(LOG_COMMAND, source, cmd) << "for " << na->nick;
00038
00039
00040 if (na->HasExt("HELD"))
00041 {
00042 na->Release();
00043 source.Reply(_("Service's hold on \002%s\002 has been released."), na->nick.c_str());
00044 }
00045 else if (!u)
00046 {
00047 source.Reply(_("No one is using your nick, and services are not holding it."));
00048 }
00049
00050
00051 else if (u->Account() == na->nc)
00052 {
00053 if (!source.GetAccount() && na->nc->HasExt("SECURE"))
00054 {
00055 source.GetUser()->Login(u->Account());
00056 Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << u->Account()->display;
00057 }
00058
00059 if (Config->NSRestoreOnRecover)
00060 {
00061 if (!u->chans.empty())
00062 {
00063 NSRecoverExtensibleInfo *ei = new NSRecoverExtensibleInfo;
00064 for (User::ChanUserList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it)
00065 (*ei)[(*it)->chan->name] = (*it)->status;
00066
00067 source.GetUser()->Extend("ns_recover_info", ei);
00068 }
00069 }
00070
00071 u->SendMessage(NickServ, _("This nickname has been recovered by %s. If you did not do\n"
00072 "this then %s may have your password, and you should change it.\n"),
00073 source.GetNick().c_str(), source.GetNick().c_str());
00074
00075 Anope::string buf = source.command.upper() + " command used by " + source.GetNick();
00076 u->Kill(source.service->nick, buf);
00077
00078 source.Reply(_("Ghost with your nick has been killed."));
00079
00080 if (IRCD->CanSVSNick)
00081 IRCD->SendForceNickChange(source.GetUser(), GetAccount(), Anope::CurTime);
00082 }
00083
00084 else
00085 {
00086 if (!source.GetAccount() && na->nc->HasExt("SECURE"))
00087 {
00088 source.GetUser()->Login(na->nc);
00089 Log(LOG_COMMAND, source, cmd) << "and was automatically identified to " << na->nick << " (" << na->nc->display << ")";
00090 }
00091
00092 u->SendMessage(NickServ, _("This nickname has been recovered by %s."), source.GetNick().c_str());
00093 u->Collide(na);
00094
00095 if (IRCD->CanSVSNick)
00096 {
00097
00098 na->Release();
00099 IRCD->SendForceNickChange(source.GetUser(), GetAccount(), Anope::CurTime);
00100 }
00101 else
00102 source.Reply(_("The user with your nick has been removed. Use this command again\n"
00103 "to release services's hold on your nick."));
00104 }
00105 }
00106
00107 void OnFail() anope_override
00108 {
00109 if (NickAlias::Find(GetAccount()) != NULL)
00110 {
00111 source.Reply(ACCESS_DENIED);
00112 if (!GetPassword().empty())
00113 {
00114 Log(LOG_COMMAND, source, cmd) << "with an invalid password for " << GetAccount();
00115 if (source.GetUser())
00116 source.GetUser()->BadPassword();
00117 }
00118 }
00119 else
00120 source.Reply(NICK_X_NOT_REGISTERED, GetAccount().c_str());
00121 }
00122 };
00123
00124 class CommandNSRecover : public Command
00125 {
00126 public:
00127 CommandNSRecover(Module *creator) : Command(creator, "nickserv/recover", 1, 2)
00128 {
00129 this->SetDesc(_("Regains control of your nick"));
00130 this->SetSyntax("\037nickname\037 [\037password\037]");
00131 this->AllowUnregistered(true);
00132 }
00133
00134 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
00135 {
00136 const Anope::string &nick = params[0];
00137 const Anope::string &pass = params.size() > 1 ? params[1] : "";
00138
00139 User *user = User::Find(nick, true);
00140
00141 if (user && source.GetUser() == user)
00142 {
00143 source.Reply(_("You can't %s yourself!"), source.command.lower().c_str());
00144 return;
00145 }
00146
00147 const NickAlias *na = NickAlias::Find(nick);
00148
00149 if (!na)
00150 {
00151 source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
00152 return;
00153 }
00154 else if (na->nc->HasExt("SUSPENDED"))
00155 {
00156 source.Reply(NICK_X_SUSPENDED, na->nick.c_str());
00157 return;
00158 }
00159
00160 bool ok = false;
00161 if (source.GetAccount() == na->nc)
00162 ok = true;
00163 else if (!na->nc->HasExt("SECURE") && source.GetUser() && na->nc->IsOnAccess(source.GetUser()))
00164 ok = true;
00165 else if (source.GetUser() && !source.GetUser()->fingerprint.empty() && na->nc->FindCert(source.GetUser()->fingerprint))
00166 ok = true;
00167
00168 if (ok == false && !pass.empty())
00169 {
00170 NSRecoverRequest *req = new NSRecoverRequest(owner, source, this, na->nick, pass);
00171 FOREACH_MOD(I_OnCheckAuthentication, OnCheckAuthentication(source.GetUser(), req));
00172 req->Dispatch();
00173 }
00174 else
00175 {
00176 NSRecoverRequest req(owner, source, this, na->nick, pass);
00177
00178 if (ok)
00179 req.OnSuccess();
00180 else
00181 req.OnFail();
00182 }
00183 }
00184
00185 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00186 {
00187 this->SendSyntax(source);
00188 source.Reply(" ");
00189 source.Reply(_("Recovers your nick from another user or from services.\n"
00190 "If services are currently holding your nick, the hold\n"
00191 "will be released. If another user is holding your nick\n"
00192 "and is identified they will be killed (similar to the old\n"
00193 "GHOST command). If they are not identified they will be\n"
00194 "forced off of the nick."));
00195 return true;
00196 }
00197 };
00198
00199 class NSRecover : public Module
00200 {
00201 CommandNSRecover commandnsrecover;
00202
00203 public:
00204 NSRecover(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00205 commandnsrecover(this)
00206 {
00207 this->SetAuthor("Anope");
00208
00209 if (Config->NoNicknameOwnership)
00210 throw ModuleException(modname + " can not be used with options:nonicknameownership enabled");
00211
00212 Implementation i[] = { I_OnUserNickChange, I_OnJoinChannel, I_OnShutdown, I_OnRestart };
00213 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00214 }
00215
00216 ~NSRecover()
00217 {
00218 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
00219 it->second->Shrink("ns_recover_info");
00220
00221 OnShutdown();
00222 }
00223
00224 void OnShutdown() anope_override
00225 {
00226
00227
00228
00229 for (nickalias_map::const_iterator it = NickAliasList->begin(); it != NickAliasList->end(); ++it)
00230 it->second->Release();
00231 }
00232
00233 void OnRestart() anope_override { OnShutdown(); }
00234
00235 void OnUserNickChange(User *u, const Anope::string &oldnick) anope_override
00236 {
00237 if (Config->NSRestoreOnRecover)
00238 {
00239 NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info");
00240
00241 if (ei != NULL)
00242 for (std::map<Anope::string, ChannelStatus>::iterator it = ei->begin(), it_end = ei->end(); it != it_end;)
00243 {
00244 Channel *c = Channel::Find(it->first);
00245 const Anope::string &cname = it->first;
00246 ++it;
00247
00248
00249 if (u->FindChannel(c))
00250 this->OnJoinChannel(u, c);
00251 else if (IRCD->CanSVSJoin)
00252 IRCD->SendSVSJoin(NickServ, u, cname, "");
00253 }
00254 }
00255 }
00256
00257 void OnJoinChannel(User *u, Channel *c) anope_override
00258 {
00259 if (Config->NSRestoreOnRecover)
00260 {
00261 NSRecoverExtensibleInfo *ei = u->GetExt<NSRecoverExtensibleInfo *>("ns_recover_info");
00262
00263 if (ei != NULL)
00264 {
00265 std::map<Anope::string, ChannelStatus>::iterator it = ei->find(c->name);
00266 if (it != ei->end())
00267 {
00268 for (std::set<Anope::string>::iterator it2 = it->second.modes.begin(), it2_end = it->second.modes.end(); it2 != it2_end; ++it2)
00269 c->SetMode(c->ci->WhoSends(), ModeManager::FindChannelModeByName(*it2), u->GetUID());
00270
00271 ei->erase(it);
00272 if (ei->empty())
00273 u->Shrink("ns_recover_info");
00274 }
00275 }
00276 }
00277 }
00278 };
00279
00280 MODULE_INIT(NSRecover)