8 #include <boost/thread/mutex.hpp>
10 // TODO: Fix this shit!
11 #include "../../../admins.h"
15 #include "config_thread.h"
16 #include "root_parser.h"
18 void DumpCrypto(const char * data, size_t size)
20 std::string dumpstr = "";
21 for (unsigned i = 0; i < size; ++i) {
23 strprintf(&ch, "%x", *(data + i));
26 printfd(__FILE__, "Crypto dump: '%s'\n", dumpstr.c_str());
29 CONFIG_THREAD::CONFIG_THREAD(ADMINS * a, TARIFFS * t, USERS * u, const SETTINGS * s)
39 /*printfd(__FILE__, "sizeof(REQ::HEADER) = %d\n", sizeof(REQ::HEADER));
40 printfd(__FILE__, "sizeof(REQ::CRYPTO_HEADER) = %d\n", sizeof(REQ::CRYPTO_HEADER));
41 printfd(__FILE__, "sizeof(RESP::HEADER) = %d\n", sizeof(RESP::HEADER));
42 printfd(__FILE__, "sizeof(RESP::CRYPTO_HEADER) = %d\n", sizeof(RESP::CRYPTO_HEADER));*/
43 assert(sizeof(REQ::HEADER) % 8 == 0);
44 assert(sizeof(REQ::CRYPTO_HEADER) % 8 == 0);
45 assert(sizeof(RESP::HEADER) % 8 == 0);
46 assert(sizeof(RESP::CRYPTO_HEADER) % 8 == 0);
48 iv = new unsigned char[8];
52 CONFIG_THREAD::CONFIG_THREAD(const CONFIG_THREAD & rvalue)
54 remoteAddr(rvalue.remoteAddr),
57 respCode(rvalue.respCode),
58 admins(rvalue.admins),
59 tariffs(rvalue.tariffs),
61 settings(rvalue.settings)
64 iv = new unsigned char[8];
65 memcpy(iv, rvalue.iv, 8);
68 CONFIG_THREAD & CONFIG_THREAD::operator=(const CONFIG_THREAD & rvalue)
70 assert(0 && "Never be here");
74 CONFIG_THREAD::~CONFIG_THREAD()
80 void CONFIG_THREAD::operator() ()
83 printfd(__FILE__, "CONFIG_THREAD::operator()() Invalid socket descriptor\n");
96 boost::mutex::scoped_lock lock(mutex);
101 bool CONFIG_THREAD::IsDone() const
103 boost::mutex::scoped_lock lock(mutex);
107 void CONFIG_THREAD::SetConnection(int sock, struct sockaddr_in sin)
113 bool CONFIG_THREAD::ReadBlock(void * dest, size_t & size, int timeout) const
115 unsigned readSize = 0;
116 char * ptr = static_cast<char *>(dest);
117 while (readSize < size) {
120 tv.tv_usec = timeout * 1000;
126 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
127 /* Don't rely on the value of tv now! */
130 printfd(__FILE__, "CONFIG_THREAD::ReadBlock() Select error: '%s'\n", strerror(errno));
140 res = read(sd, ptr + readSize, size - readSize);
142 if (res == 0) { // EOF
143 printfd(__FILE__, "CONFIG_THREAD::ReadBlock() EOF\n");
147 // Ignore 'Interrupted system call' errors
149 if (errno != EINTR) {
150 printfd(__FILE__, "CONFIG_THREAD::ReadBlock() Read error: '%s'\n", strerror(errno));
163 bool CONFIG_THREAD::WriteBlock(const void * source, size_t & size, int timeout) const
165 const char * ptr = static_cast<const char *>(source);
166 unsigned writeSize = 0;
167 while (writeSize < size) {
170 tv.tv_usec = timeout * 1000;
176 int res = select(sd + 1, NULL, &wfds, NULL, &tv);
177 /* Don't rely on the value of tv now! */
180 printfd(__FILE__, "CONFIG_THREAD::WriteBlock() Select error: '%s'\n", strerror(errno));
190 res = write(sd, ptr + writeSize, size - writeSize);
192 // Ignore 'Interrupted system call' errors
193 if (res < 0 && errno != EINTR) {
194 printfd(__FILE__, "CONFIG_THREAD::WriteBlock() Write error: '%s'\n", strerror(errno));
204 bool CONFIG_THREAD::ReadReq()
206 struct REQ::HEADER reqHeader;
208 size_t size = sizeof(reqHeader);
209 if (!ReadBlock(&reqHeader, size, 5000)) {
211 message = "No request header within 5 sec";
212 printfd(__FILE__, "CONFIG_THREAD::ReadReq() %s\n", message.c_str());
216 if (strncmp(reqHeader.magic, PROTO_MAGIC, sizeof(reqHeader.magic))) {
218 respCode = RESP::INVALID_MAGIC;
219 message = "Invalid magic code in header";
220 printfd(__FILE__, "CONFIG_THREAD::ReadReq() %s\n", message.c_str());
224 uint32_t version = ntohl(reqHeader.version);
225 if (version > (2 << 8 | 0)) {
227 respCode = RESP::UNSUPPORTED_VERSION;
228 message = "Unsupported version";
229 printfd(__FILE__, "CONFIG_THREAD::ReadReq() %s (wanted: %d, actual: %d)\n", message.c_str(), (2 << 8 | 0), version);
233 versionMinor = version & 0x0000FFFF;
234 versionMajor = (version >> 8) & 0x0000FFFF;
236 reqHeader.login[sizeof(reqHeader.login) - 1] = 0;
238 login = reqHeader.login;
240 if (!CheckLogin(login, password)) {
242 respCode = RESP::INVALID_CREDENTIALS;
243 message = "Unknown login";
244 printfd(__FILE__, "CONFIG_THREAD::ReadReq() %s\n", message.c_str());
248 return ReceiveData();
251 bool CONFIG_THREAD::ReceiveData()
253 unsigned char buffer[sizeof(struct REQ::CRYPTO_HEADER)];
254 //unsigned char iv[] = "00000000";
255 size_t size = sizeof(struct REQ::CRYPTO_HEADER);
257 if (!ReadBlock(buffer, size, 5000)) {
259 message = "No crypto header within 5 secs";
260 printfd(__FILE__, "CONFIG_THREAD::ReceiveData() %s\n", message.c_str());
264 BF_set_key(&key, password.length(), reinterpret_cast<const unsigned char *>(password.c_str()));
266 struct REQ::CRYPTO_HEADER reqCryptoHeader;
268 BF_cbc_encrypt(buffer, reinterpret_cast<unsigned char *>(&reqCryptoHeader), sizeof(struct REQ::CRYPTO_HEADER), &key, iv, BF_DECRYPT);
270 reqCryptoHeader.login[sizeof(reqCryptoHeader.login) - 1] = 0;
272 std::string cryptoLogin(reqCryptoHeader.login);
274 if (login != cryptoLogin) {
276 respCode = RESP::INVALID_CREDENTIALS;
277 message = "Password is invalid";
278 printfd(__FILE__, "CONFIG_THREAD::ReceiveData() %s\n", message.c_str());
282 //assert(reqCryptoHeader.dataSize % 8 == 0);
285 unsigned char cryptoBlock[1496];
287 uint32_t dataSize = ntohl(reqCryptoHeader.dataSize);
289 while (length < dataSize) {
290 size_t delta = dataSize - length;
291 if (delta > sizeof(cryptoBlock)) {
292 delta = sizeof(cryptoBlock);
295 ReadBlock(cryptoBlock, bs, 5000);
298 message = "No data within 5 secs";
299 printfd(__FILE__, "CONFIG_THREAD::ReceiveData() %s\n", message.c_str());
303 BF_cbc_encrypt(cryptoBlock, reinterpret_cast<unsigned char *>(block), bs, &key, iv, BF_DECRYPT);
305 xml.append(block, bs);
313 void CONFIG_THREAD::Process()
315 ROOT_PARSER parser(currAdmin, tariffs, users, settings);
319 p= XML_ParserCreate(NULL);
320 XML_SetElementHandler(p, &TagBegin, &TagEnd);
321 XML_SetUserData(p, &parser);
323 if (!XML_Parse(p, xml.c_str(), xml.length(), true)) {
324 printfd(__FILE__, "CONFIG_THREAD::Process() Error: '%s' at line %d\n", XML_ErrorString(XML_GetErrorCode(p)), XML_GetCurrentLineNumber(p));
330 xml = parser.GetResult();
333 void CONFIG_THREAD::WriteResp() const
335 RESP::HEADER respHeader;
337 strncpy(respHeader.magic, PROTO_MAGIC, sizeof(respHeader.magic));
338 respHeader.version = htonl(2 << 8 | 0);
339 respHeader.code = respCode;
341 RESP::CRYPTO_HEADER respCryptoHeader;
342 strncpy(respCryptoHeader.login, login.c_str(), sizeof(respCryptoHeader.login));
343 if (xml.size() % 8 == 0) {
344 respCryptoHeader.dataSize = htonl(xml.size());
346 respCryptoHeader.dataSize = htonl((xml.size() / 8 + 1) * 8);
349 size_t size = sizeof(respHeader);
350 if (!WriteBlock(&respHeader, size, 5000)) {
351 printfd(__FILE__, "CONFIG_THREAD::WriteResp() Failed to send answer header\n");
355 if (state != ST_ERROR) {
356 unsigned char buffer[sizeof(respCryptoHeader)];
357 size = sizeof(respCryptoHeader);
359 BF_cbc_encrypt(reinterpret_cast<unsigned char *>(&respCryptoHeader), buffer, size, &key, iv, BF_ENCRYPT);
361 if (!WriteBlock(buffer, size, 5000)) {
362 printfd(__FILE__, "CONFIG_THREAD::WriteResp() Failed to send answer crypto-header\n");
370 void CONFIG_THREAD::SendData() const
373 std::string data(xml);
374 if (data.size() % 8) {
375 size_t delta = (data.size() / 8 + 1) * 8 - data.size();
376 data.append(delta, ' ');
378 while (pos < data.size()) {
379 unsigned char source[1496];
380 unsigned char buffer[1496];
383 if (data.size() - pos > sizeof(source)) {
384 memcpy(source, data.c_str() + pos, sizeof(source));
385 size = sizeof(source);
387 memset(source, 0, sizeof(source));
388 memcpy(source, data.c_str() + pos, data.size() - pos);
389 size = data.size() - pos;
392 BF_cbc_encrypt(source, buffer, size, &key, iv, BF_ENCRYPT);
394 if (!WriteBlock(buffer, size, 5000)) {
395 printfd(__FILE__, "CONFIG_THREAD::SendData() Failed to write data block\n");
399 pos += size; // size?
405 bool CONFIG_THREAD::CheckLogin(const std::string & login, std::string & password)
407 currAdmin = admins->FindAdmin(login);
409 if (currAdmin == NULL) {
410 printfd(__FILE__, "CONFIG_THREAD::CheckLogin() Admin '%s' not found\n", login.c_str());
414 password = currAdmin->GetPassword();
419 void CONFIG_THREAD::TagBegin(void * userData, const char * name, const char ** attr)
421 ROOT_PARSER * self = static_cast<ROOT_PARSER *>(userData);
422 self->StartTag(name, attr);
425 void CONFIG_THREAD::TagEnd(void * userData, const char * name)
427 ROOT_PARSER * self = static_cast<ROOT_PARSER *>(userData);