anope

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

nickcore.cpp (7420B)

      1 /*
      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 "services.h"
     13 #include "modules.h"
     14 #include "account.h"
     15 #include "config.h"
     16 #include <climits>
     17 
     18 Serialize::Checker<nickcore_map> NickCoreList("NickCore");
     19 nickcoreid_map NickCoreIdList;
     20 
     21 NickCore::NickCore(const Anope::string &coredisplay, uint64_t coreid) : Serializable("NickCore"), chanaccess("ChannelInfo"), aliases("NickAlias")
     22 {
     23 	if (coredisplay.empty())
     24 		throw CoreException("Empty display passed to NickCore constructor");
     25 
     26 	this->o = NULL;
     27 	this->channelcount = 0;
     28 	this->lastmail = 0;
     29 
     30 	this->display = coredisplay;
     31 	this->id = coreid;
     32 
     33 	size_t old = NickCoreList->size();
     34 	(*NickCoreList)[this->display] = this;
     35 	if (old == NickCoreList->size())
     36 		Log(LOG_DEBUG) << "Duplicate account " << coredisplay << " in nickcore table?";
     37 
     38 	if (this->id)
     39 		NickCoreIdList[this->id] = this;
     40 
     41 	FOREACH_MOD(OnNickCoreCreate, (this));
     42 }
     43 
     44 NickCore::~NickCore()
     45 {
     46 	FOREACH_MOD(OnDelCore, (this));
     47 
     48 	UnsetExtensibles();
     49 
     50 	if (!this->chanaccess->empty())
     51 		Log(LOG_DEBUG) << "Non-empty chanaccess list in destructor!";
     52 
     53 	for (std::list<User *>::iterator it = this->users.begin(); it != this->users.end();)
     54 	{
     55 		User *user = *it++;
     56 		user->Logout();
     57 	}
     58 	this->users.clear();
     59 
     60 	NickCoreList->erase(this->display);
     61 	if (this->id)
     62 		NickCoreIdList.erase(this->id);
     63 
     64 	this->ClearAccess();
     65 
     66 	if (!this->memos.memos->empty())
     67 	{
     68 		for (unsigned i = 0, end = this->memos.memos->size(); i < end; ++i)
     69 			delete this->memos.GetMemo(i);
     70 		this->memos.memos->clear();
     71 	}
     72 }
     73 
     74 void NickCore::Serialize(Serialize::Data &data) const
     75 {
     76 	data["display"] << this->display;
     77 	data["uniqueid"] << this->id;
     78 	data["pass"] << this->pass;
     79 	data["email"] << this->email;
     80 	data["language"] << this->language;
     81 	for (unsigned i = 0; i < this->access.size(); ++i)
     82 		data["access"] << this->access[i] << " ";
     83 	data["memomax"] << this->memos.memomax;
     84 	for (unsigned i = 0; i < this->memos.ignores.size(); ++i)
     85 		data["memoignores"] << this->memos.ignores[i] << " ";
     86 	Extensible::ExtensibleSerialize(this, this, data);
     87 }
     88 
     89 Serializable* NickCore::Unserialize(Serializable *obj, Serialize::Data &data)
     90 {
     91 	NickCore *nc;
     92 
     93 	Anope::string sdisplay;
     94 	data["display"] >> sdisplay;
     95 
     96 	uint64_t sid = 0;
     97 	data["uniqueid"] >> sid;
     98 
     99 	if (obj)
    100 		nc = anope_dynamic_static_cast<NickCore *>(obj);
    101 	else
    102 		nc = new NickCore(sdisplay, sid);
    103 
    104 	data["pass"] >> nc->pass;
    105 	data["email"] >> nc->email;
    106 	data["language"] >> nc->language;
    107 	{
    108 		Anope::string buf;
    109 		data["access"] >> buf;
    110 		spacesepstream sep(buf);
    111 		nc->access.clear();
    112 		while (sep.GetToken(buf))
    113 			nc->access.push_back(buf);
    114 	}
    115 	data["memomax"] >> nc->memos.memomax;
    116 	{
    117 		Anope::string buf;
    118 		data["memoignores"] >> buf;
    119 		spacesepstream sep(buf);
    120 		nc->memos.ignores.clear();
    121 		while (sep.GetToken(buf))
    122 			nc->memos.ignores.push_back(buf);
    123 	}
    124 
    125 	Extensible::ExtensibleUnserialize(nc, nc, data);
    126 
    127 	/* compat */
    128 	bool b;
    129 	b = false;
    130 	data["extensible:SECURE"] >> b;
    131 	if (b)
    132 		nc->Extend<bool>("NS_SECURE");
    133 	b = false;
    134 	data["extensible:PRIVATE"] >> b;
    135 	if (b)
    136 		nc->Extend<bool>("NS_PRIVATE");
    137 	b = false;
    138 	data["extensible:AUTOOP"] >> b;
    139 	if (b)
    140 		nc->Extend<bool>("AUTOOP");
    141 	b = false;
    142 	data["extensible:HIDE_EMAIL"] >> b;
    143 	if (b)
    144 		nc->Extend<bool>("HIDE_EMAIL");
    145 	b = false;
    146 	data["extensible:HIDE_QUIT"] >> b;
    147 	if (b)
    148 		nc->Extend<bool>("HIDE_QUIT");
    149 	b = false;
    150 	data["extensible:MEMO_RECEIVE"] >> b;
    151 	if (b)
    152 		nc->Extend<bool>("MEMO_RECEIVE");
    153 	b = false;
    154 	data["extensible:MEMO_SIGNON"] >> b;
    155 	if (b)
    156 		nc->Extend<bool>("MEMO_SIGNON");
    157 	b = false;
    158 	data["extensible:KILLPROTECT"] >> b;
    159 	if (b)
    160 		nc->Extend<bool>("KILLPROTECT");
    161 	/* end compat */
    162 
    163 	return nc;
    164 }
    165 
    166 void NickCore::SetDisplay(const NickAlias *na)
    167 {
    168 	if (na->nc != this || na->nick == this->display)
    169 		return;
    170 
    171 	FOREACH_MOD(OnChangeCoreDisplay, (this, na->nick));
    172 
    173 	/* this affects the serialized aliases */
    174 	for (unsigned i = 0; i < aliases->size(); ++i)
    175 		aliases->at(i)->QueueUpdate();
    176 
    177 	/* Remove the core from the list */
    178 	NickCoreList->erase(this->display);
    179 
    180 	this->display = na->nick;
    181 
    182 	(*NickCoreList)[this->display] = this;
    183 }
    184 
    185 bool NickCore::IsServicesOper() const
    186 {
    187 	return this->o != NULL;
    188 }
    189 
    190 void NickCore::AddAccess(const Anope::string &entry)
    191 {
    192 	this->access.push_back(entry);
    193 	FOREACH_MOD(OnNickAddAccess, (this, entry));
    194 }
    195 
    196 Anope::string NickCore::GetAccess(unsigned entry) const
    197 {
    198 	if (this->access.empty() || entry >= this->access.size())
    199 		return "";
    200 	return this->access[entry];
    201 }
    202 
    203 unsigned NickCore::GetAccessCount() const
    204 {
    205 	return this->access.size();
    206 }
    207 
    208 bool NickCore::FindAccess(const Anope::string &entry)
    209 {
    210 	for (unsigned i = 0, end = this->access.size(); i < end; ++i)
    211 		if (this->access[i] == entry)
    212 			return true;
    213 
    214 	return false;
    215 }
    216 
    217 void NickCore::EraseAccess(const Anope::string &entry)
    218 {
    219 	for (unsigned i = 0, end = this->access.size(); i < end; ++i)
    220 		if (this->access[i] == entry)
    221 		{
    222 			FOREACH_MOD(OnNickEraseAccess, (this, entry));
    223 			this->access.erase(this->access.begin() + i);
    224 			break;
    225 		}
    226 }
    227 
    228 void NickCore::ClearAccess()
    229 {
    230 	FOREACH_MOD(OnNickClearAccess, (this));
    231 	this->access.clear();
    232 }
    233 
    234 bool NickCore::IsOnAccess(const User *u) const
    235 {
    236 	Anope::string buf = u->GetIdent() + "@" + u->host, buf2, buf3;
    237 	if (!u->vhost.empty())
    238 		buf2 = u->GetIdent() + "@" + u->vhost;
    239 	if (!u->GetCloakedHost().empty())
    240 		buf3 = u->GetIdent() + "@" + u->GetCloakedHost();
    241 
    242 	for (unsigned i = 0, end = this->access.size(); i < end; ++i)
    243 	{
    244 		Anope::string a = this->GetAccess(i);
    245 		if (Anope::Match(buf, a) || (!buf2.empty() && Anope::Match(buf2, a)) || (!buf3.empty() && Anope::Match(buf3, a)))
    246 			return true;
    247 	}
    248 	return false;
    249 }
    250 
    251 void NickCore::AddChannelReference(ChannelInfo *ci)
    252 {
    253 	++(*this->chanaccess)[ci];
    254 }
    255 
    256 void NickCore::RemoveChannelReference(ChannelInfo *ci)
    257 {
    258 	int& i = (*this->chanaccess)[ci];
    259 	if (--i <= 0)
    260 		this->chanaccess->erase(ci);
    261 }
    262 
    263 void NickCore::GetChannelReferences(std::deque<ChannelInfo *> &queue)
    264 {
    265 	queue.clear();
    266 	for (std::map<ChannelInfo *, int>::iterator it = this->chanaccess->begin(), it_end = this->chanaccess->end(); it != it_end; ++it)
    267 		queue.push_back(it->first);
    268 }
    269 
    270 NickCore* NickCore::Find(const Anope::string &nick)
    271 {
    272 	nickcore_map::const_iterator it = NickCoreList->find(nick);
    273 	if (it != NickCoreList->end())
    274 	{
    275 		it->second->QueueUpdate();
    276 		return it->second;
    277 	}
    278 
    279 	return NULL;
    280 }
    281 
    282 uint64_t NickCore::GetId()
    283 {
    284 	if (this->id)
    285 		return this->id;
    286 
    287 	NickAlias *na = NickAlias::Find(this->display);
    288 	if (!na)
    289 	{
    290 		Log(LOG_DEBUG) << "Unable to find the display NickAlias for NickCore: " << this->display;
    291 		return 0;
    292 	}
    293 
    294 	Anope::string secretid = this->display + "\0" + stringify(na->time_registered);
    295 
    296 	// Generate the account id. This should almost always only have one
    297 	// iteration but in the rare case that we generate a duplicate id we try
    298 	// again with a new key.
    299 	while (!this->id)
    300 	{
    301 		// Generate a random key for SipHash.
    302 		char key[16];
    303 		for (size_t i = 0; i < sizeof(key); ++i)
    304 			key[i] = rand() % CHAR_MAX;
    305 
    306 		uint64_t newid = Anope::SipHash24(secretid.c_str(), secretid.length(), key);
    307 		nickcoreid_map::const_iterator it = NickCoreIdList.find(newid);
    308 		if (it == NickCoreIdList.end())
    309 		{
    310 			this->id = newid;
    311 			NickCoreIdList[this->id] = this;
    312 			this->QueueUpdate();
    313 			break;
    314 		}
    315 	}
    316 
    317 	return this->id;
    318 }