1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2019 Sadie Powell <sadie@witchery.services>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 #include "inspircd.h"
21 
Load(const std::string & key,std::string & out)22 Serializable::Data& Serializable::Data::Load(const std::string& key, std::string& out)
23 {
24 	EntryMap::iterator iter = this->entries.find(key);
25 	if (iter == this->entries.end())
26 	{
27 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Unable to load missing kv %s!", key.c_str());
28 	}
29 	else
30 	{
31 		out = iter->second;
32 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Loaded kv %s: %s", key.c_str(), out.c_str());
33 	}
34 	return *this;
35 }
36 
Load(const std::string & key,Serializable::Data & out)37 Serializable::Data& Serializable::Data::Load(const std::string& key, Serializable::Data& out)
38 {
39 	ChildMap::iterator iter = this->children.find(key);
40 	if (iter == this->children.end())
41 	{
42 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Unable to load missing data %s!", key.c_str());
43 	}
44 	else
45 	{
46 		out = iter->second;
47 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Loaded data: %s", key.c_str());
48 	}
49 	return *this;
50 }
51 
Store(const std::string & key,const std::string & value)52 Serializable::Data& Serializable::Data::Store(const std::string& key, const std::string& value)
53 {
54 	ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Stored kv %s: %s", key.c_str(), value.c_str());
55 	this->entries[key] = value;
56 	return *this;
57 }
58 
Store(const std::string & key,const Serializable::Data & value)59 Serializable::Data& Serializable::Data::Store(const std::string& key, const Serializable::Data& value)
60 {
61 	ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Stored data: %s", key.c_str());
62 	this->children[key] = value;
63 	return *this;
64 }
65 
Deserialize(Serializable::Data & data)66 bool Extensible::Deserialize(Serializable::Data& data)
67 {
68 	// If the extensible has been culled then it shouldn't be deserialized.
69 	if (culled)
70 		return false;
71 
72 	const Serializable::Data::EntryMap& entries = data.GetEntries();
73 	for (Serializable::Data::EntryMap::const_iterator iter = entries.begin(); iter != entries.end(); ++iter)
74 	{
75 		const std::string& name = iter->first;
76 		ExtensionItem* item = ServerInstance->Extensions.GetItem(name);
77 		if (item)
78 		{
79 			item->FromInternal(this, iter->second);
80 			continue;
81 		}
82 
83 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize the %s extension item but it doesn't exist",
84 			name.c_str());
85 	}
86 	return true;
87 }
88 
Serialize(Serializable::Data & data)89 bool Extensible::Serialize(Serializable::Data& data)
90 {
91 	// If the extensible has been culled then it shouldn't be serialized.
92 	if (culled)
93 	{
94 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to serialize an extensible which has been culled");
95 		return false;
96 	}
97 
98 	for (Extensible::ExtensibleStore::const_iterator iter = extensions.begin(); iter != extensions.end(); ++iter)
99 	{
100 		ExtensionItem* item = iter->first;
101 		const std::string value = item->ToInternal(this, iter->second);
102 		if (!value.empty())
103 			data.Store(item->name, value);
104 	}
105 	return true;
106 }
107 
Deserialize(Serializable::Data & data)108 bool User::Deserialize(Serializable::Data& data)
109 {
110 	// If the user is quitting they shouldn't be deserialized.
111 	if (quitting)
112 	{
113 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s who is in the process of quitting",
114 			uuid.c_str());
115 		return false;
116 	}
117 
118 	// Check we're actually deserialising data for this user.
119 	std::string client_uuid;
120 	data.Load("uuid", client_uuid);
121 	if (!client_uuid.empty() && client_uuid != uuid)
122 	{
123 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to deserialize %s into %s",
124 			client_uuid.c_str(), uuid.c_str());
125 		return false;
126 	}
127 
128 	// Deserialize the extensions first.
129 	Serializable::Data exts;
130 	data.Load("extensions", exts);
131 	if (!Extensible::Deserialize(exts))
132 		return false;
133 
134 	long client_port;
135 	std::string client_addr;
136 	std::string user_modes;
137 	std::string user_oper;
138 	std::string user_snomasks;
139 
140 	// Apply the members which can be applied directly.
141 	data.Load("age", age)
142 		.Load("awaymsg", awaymsg)
143 		.Load("awaytime", awaytime)
144 		.Load("client_sa.addr", client_addr)
145 		.Load("client_sa.port", client_port)
146 		.Load("displayhost", displayhost)
147 		.Load("ident", ident)
148 		.Load("modes", user_modes)
149 		.Load("nick", nick)
150 		.Load("oper", user_oper)
151 		.Load("realhost", realhost)
152 		.Load("realname", realname)
153 		.Load("signon", signon)
154 		.Load("snomasks", user_snomasks);
155 
156 	// Apply the rest of the members.
157 	modes = std::bitset<ModeParser::MODEID_MAX>(user_modes);
158 	snomasks = std::bitset<64>(user_snomasks);
159 
160 	ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(user_oper);
161 	if (iter != ServerInstance->Config->OperTypes.end())
162 		oper = iter->second;
163 	else
164 		oper = new OperInfo(user_oper);
165 
166 	irc::sockets::sockaddrs sa;
167 	if (irc::sockets::aptosa(client_addr, client_port, sa) || irc::sockets::untosa(client_addr, sa))
168 		client_sa = sa;
169 
170 	InvalidateCache();
171 	return true;
172 }
173 
Serialize(Serializable::Data & data)174 bool User::Serialize(Serializable::Data& data)
175 {
176 	// If the user is quitting they shouldn't be serialized.
177 	if (quitting)
178 	{
179 		ServerInstance->Logs->Log("SERIALIZE", LOG_DEBUG, "Tried to serialize %s who is in the process of quitting",
180 			uuid.c_str());
181 		return false;
182 	}
183 
184 	// If the user is unregistered they shouldn't be serialised.
185 	if (registered != REG_ALL)
186 		return false;
187 
188 	// Serialize the extensions first.
189 	Serializable::Data exts;
190 	if (!Extensible::Serialize(exts))
191 		return false;
192 	data.Store("extensions", exts);
193 
194 	// The following member variables not checked above are not serialised:
195 	// * cached_fullhost (serialising cache variables is unnecessary)
196 	// * cached_fullrealhost (serialising cache variables is unnecessary)
197 	// * cached_hostip (serialising cache variables is unnecessary)
198 	// * cached_makehost (serialising cache variables is unnecessary)
199 	// * cachedip (serialising cache variables is unnecessary)
200 	// * server (specific to the origin server)
201 	// * usertype (can't be networked reliably)
202 	data.Store("age", age)
203 		.Store("awaymsg", awaymsg)
204 		.Store("awaytime", awaytime)
205 		.Store("client_sa.addr", client_sa.addr())
206 		.Store("client_sa.port", client_sa.port())
207 		.Store("displayhost", displayhost)
208 		.Store("ident", ident)
209 		.Store("modes", modes.to_string())
210 		.Store("nick", nick)
211 		.Store("oper", oper ? oper->name : "")
212 		.Store("realhost", realhost)
213 		.Store("realname", realname)
214 		.Store("signon", signon)
215 		.Store("snomasks", snomasks.to_string())
216 		.Store("uuid", uuid);
217 
218 	return true;
219 }
220 
Deserialize(Serializable::Data & data)221 bool LocalUser::Deserialize(Serializable::Data& data)
222 {
223 
224 	// Deserialize the base class first.
225 	if (!User::Deserialize(data))
226 		return false;
227 
228 	bool user_exempt;
229 	bool user_lastping;
230 	long server_port;
231 	std::string server_addr;
232 
233 	// Apply the members which can be applied directly.
234 	data.Load("bytes_in", bytes_in)
235 		.Load("bytes_out", bytes_out)
236 		.Load("cmds_in", cmds_in)
237 		.Load("cmds_out", cmds_out)
238 		.Load("CommandFloodPenalty", CommandFloodPenalty)
239 		.Load("exempt", user_exempt)
240 		.Load("idle_lastmsg", idle_lastmsg)
241 		.Load("lastping", user_lastping)
242 		.Load("nextping", nextping)
243 		.Load("password", password)
244 		.Load("server_sa.addr", server_addr)
245 		.Load("server_sa.port", server_port);
246 
247 	// Apply the rest of the members.
248 	irc::sockets::sockaddrs sa;
249 	if (irc::sockets::aptosa(server_addr, server_port, sa) || irc::sockets::untosa(server_addr, sa))
250 		server_sa = sa;
251 
252 	// These are bitfields so we need to ensure they only get the appropriate bits.
253 	exempt = user_exempt ? 1 : 0;
254 	lastping = user_lastping ? 1 : 0;
255 	return true;
256 }
257 
Serialize(Serializable::Data & data)258 bool LocalUser::Serialize(Serializable::Data& data)
259 {
260 	// Serialize the base class first.
261 	if (!User::Serialize(data))
262 		return false;
263 
264 	// The following member variables not checked above are not serialised:
265 	// * already_sent (can't be networked reliably)
266 	// * eh (shouldn't be networked)
267 	// * MyClass (might not be the same on a different server)
268 	// * serializer (might not be the same on a different connection)
269 	data.Store("bytes_in", bytes_in)
270 		.Store("bytes_out", bytes_out)
271 		.Store("cmds_in", cmds_in)
272 		.Store("cmds_out", cmds_out)
273 		.Store("CommandFloodPenalty", CommandFloodPenalty)
274 		.Store("exempt", exempt)
275 		.Store("idle_lastmsg", idle_lastmsg)
276 		.Store("lastping", lastping)
277 		.Store("nextping", nextping)
278 		.Store("password", password)
279 		.Store("server_sa.addr", server_sa.addr())
280 		.Store("server_sa.port", server_sa.port());
281 	return true;
282 }
283