]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp
WaitPackets moved to common.lib
[stg.git] / projects / stargazer / plugins / configuration / sgconfig / rsconf.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*******************************************************************
18 *
19 *    DESCRIPTION: æÁÊÌ Ó ÏÓÎÏ×ÎÙÍÉ ÆÕÎËÃÉÑÍÉ ÄÌÑ ÓÅÔÅ×ÏÇÏ ÏÂÍÅÎÁ ÄÁÎÎÙÍÉ
20 *    Ó ÍÅÎÅÄÖÅÒÏÍ ËÌÉÅÎÔÏ×. ðÒÉÅÍ, ÐÅÒÅÄÁÞÁ É ÛÉÆÒÏ×ÁÎÉÅ ÓÏÏÂÝÅÎÉÊ.
21 *
22 *    AUTHOR: Boris Mikhailenko <stg34@stargazer.dp.ua>
23 *
24 *    $Revision: 1.24 $
25 *    $Date: 2010/10/04 20:24:54 $
26 *
27 *******************************************************************/
28
29 #include <unistd.h> // cloase, usleep
30
31 #include <cerrno>
32 #include <csignal>
33 #include <cstdio> // snprintf
34
35 #include "stg/blowfish.h"
36 #include "configproto.h"
37
38 #ifndef ENODATA
39 // FreeBSD 4.* - suxx
40 #define ENODATA -1
41 #endif
42
43 enum CONF_STATE
44     {
45     confHdr,
46     confLogin,
47     confLoginCipher,
48     confData
49     };
50
51 enum
52     {
53     ans_ok = 0,
54     ans_err
55     };
56
57 //-----------------------------------------------------------------------------
58 int CONFIGPROTO::Prepare()
59 {
60 list<string> ansList; //óÀÄÁ ÂÕÄÅÔ ÐÏÍÅÝÅΠÏÔ×ÅÔ ÄÌÑ ÍÅÎÅÄÖÅÒÁ ËÌÉÅÎÔÏ×
61 int res;
62 struct sockaddr_in listenAddr;
63
64 sigset_t sigmask, oldmask;
65 sigemptyset(&sigmask);
66 sigaddset(&sigmask, SIGINT);
67 sigaddset(&sigmask, SIGTERM);
68 sigaddset(&sigmask, SIGUSR1);
69 sigaddset(&sigmask, SIGHUP);
70 pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
71
72 listenSocket = socket(PF_INET, SOCK_STREAM, 0);
73
74 if (listenSocket < 0)
75     {
76     errorStr = "Create NET_CONFIGURATOR socket failed.";
77     return -1;
78     }
79
80 listenAddr.sin_family = PF_INET;
81 listenAddr.sin_port = htons(port);
82 listenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
83
84 int lng = 1;
85
86 if (0 != setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &lng, 4))
87     {
88     errorStr = "Setsockopt failed. " + string(strerror(errno));
89     return -1;
90     }
91
92 res = bind(listenSocket, (struct sockaddr*)&listenAddr, sizeof(listenAddr));
93
94 if (res == -1)
95     {
96     errorStr = "Bind admin socket failed";
97     return -1;
98     }
99
100 res = listen(listenSocket, 0);
101 if (res == -1)
102     {
103     errorStr = "Listen admin socket failed";
104     return -1;
105     }
106
107 errorStr = "";
108 nonstop = true;
109 return 0;
110 }
111 //-----------------------------------------------------------------------------
112 int CONFIGPROTO::Stop()
113 {
114 nonstop = false;
115 close(listenSocket);
116 //TODO: Idiotism
117 int                 sock;
118 struct sockaddr_in  addr;
119 socklen_t           addrLen;
120 addr.sin_family = PF_INET;
121 addr.sin_port = htons(port);
122 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
123
124 addrLen = sizeof(addr);
125 sock = socket(PF_INET, SOCK_STREAM, 0);
126 connect(sock, (sockaddr*)&addr, addrLen);
127 close(sock);
128 //Idiotism end
129 return 0;
130 }
131 //-----------------------------------------------------------------------------
132 void CONFIGPROTO::Run()
133 {
134 state = confHdr;
135
136 while (nonstop)
137     {
138     state = confHdr;
139     struct sockaddr_in outerAddr;
140     socklen_t outerAddrLen(sizeof(outerAddr));
141     int outerSocket = accept(listenSocket,
142                              (struct sockaddr*)(&outerAddr),
143                              &outerAddrLen);
144
145     if (!nonstop)
146         {
147         break;
148         }
149
150     if (outerSocket == -1)
151         {
152         printfd(__FILE__, "accept failed\n");
153         continue;
154         }
155
156     adminIP = *(unsigned int*)&(outerAddr.sin_addr);
157
158     printfd(__FILE__, "Connection accepted from %s\n", inet_ntostring(outerAddr.sin_addr.s_addr).c_str());
159
160     if (state == confHdr)
161         {
162         if (RecvHdr(outerSocket) < 0)
163             {
164             close(outerSocket);
165             continue;
166             }
167         if (state == confLogin)
168             {
169             if (SendHdrAnswer(outerSocket, ans_ok) < 0)
170                 {
171                 close(outerSocket);
172                 continue;
173                 }
174             if (RecvLogin(outerSocket) < 0)
175                 {
176                 close(outerSocket);
177                 continue;
178                 }
179             if (state == confLoginCipher)
180                 {
181                 if (SendLoginAnswer(outerSocket) < 0)
182                     {
183                     close(outerSocket);
184                     continue;
185                     }
186                 if (RecvLoginS(outerSocket) < 0)
187                     {
188                     close(outerSocket);
189                     continue;
190                     }
191                 if (state == confData)
192                     {
193                     if (SendLoginSAnswer(outerSocket, ans_ok) < 0)
194                         {
195                         close(outerSocket);
196                         continue;
197                         }
198                     if (RecvData(outerSocket) < 0)
199                         {
200                         close(outerSocket);
201                         continue;
202                         }
203                     state = confHdr;
204                     }
205                 else
206                     {
207                     if (SendLoginSAnswer(outerSocket, ans_err) < 0)
208                         {
209                         close(outerSocket);
210                         continue;
211                         }
212                     WriteLogAccessFailed(adminIP);
213                     }
214                 }
215             else
216                 {
217                 WriteLogAccessFailed(adminIP);
218                 }
219             }
220         else
221             {
222             WriteLogAccessFailed(adminIP);
223             if (SendHdrAnswer(outerSocket, ans_err) < 0)
224                 {
225                 close(outerSocket);
226                 continue;
227                 }
228             }
229         }
230     else
231         {
232         WriteLogAccessFailed(adminIP);
233         }
234     close(outerSocket);
235     }
236 }
237 //-----------------------------------------------------------------------------
238 int CONFIGPROTO::RecvHdr(int sock)
239 {
240 char buf[sizeof(STG_HEADER)];
241 memset(buf, 0, sizeof(STG_HEADER));
242 int ret;
243 size_t stgHdrLen = sizeof(STG_HEADER) - 1; // Without 0-char
244 for (size_t i = 0; i < stgHdrLen; i++)
245     {
246     ret = recv(sock, &buf[i], 1, 0);
247     if (ret <= 0)
248         {
249         state = confHdr;
250         return -1;
251         }
252     }
253
254 if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
255     {
256     state = confLogin;
257     return 0;
258     }
259 else
260     {
261     SendError("Bad request");
262     }
263
264 state = confHdr;
265 return -1;
266 }
267 //-----------------------------------------------------------------------------
268 int CONFIGPROTO::SendHdrAnswer(int sock, int err)
269 {
270 int ret;
271
272 if (err)
273     {
274     ret = send(sock, ERR_HEADER, sizeof(ERR_HEADER) - 1, 0);
275     if (ret < 0)
276         {
277         WriteServLog("send ERR_HEADER error in SendHdrAnswer.");
278         return -1;
279         }
280     }
281 else
282     {
283     ret = send(sock, OK_HEADER, sizeof(OK_HEADER) - 1, 0);
284     if (ret < 0)
285         {
286         WriteServLog("send OK_HEADER error in SendHdrAnswer.");
287         return -1;
288         }
289     }
290
291 return 0;
292 }
293 //-----------------------------------------------------------------------------
294 int CONFIGPROTO::RecvLogin(int sock)
295 {
296 char login[ADM_LOGIN_LEN + 1];
297 int ret;
298
299 memset(login, 0, ADM_LOGIN_LEN + 1);
300
301 ret = recv(sock, login, ADM_LOGIN_LEN, 0);
302
303 if (ret < 0)
304     {
305     // Error in network
306     state = confHdr;
307     return ENODATA;
308     }
309
310 if (ret < ADM_LOGIN_LEN)
311     {
312     // Error in protocol
313     state = confHdr;
314     return ENODATA;
315     }
316
317 if (admins->Find(login, &currAdmin))
318     {
319     // Admin not found
320     state = confHdr;
321     return ENODATA;
322     }
323 currAdmin->SetIP(adminIP);
324 adminLogin = login;
325 state = confLoginCipher;
326 return 0;
327 }
328 //-----------------------------------------------------------------------------
329 int CONFIGPROTO::SendLoginAnswer(int sock)
330 {
331 int ret;
332
333 ret = send(sock, OK_LOGIN, sizeof(OK_LOGIN) - 1, 0);
334 if (ret < 0)
335     {
336     WriteServLog("Send OK_LOGIN error in SendLoginAnswer.");
337     return -1;
338     }
339 return 0;
340 }
341 //-----------------------------------------------------------------------------
342 int CONFIGPROTO::RecvLoginS(int sock)
343 {
344 char loginS[ADM_LOGIN_LEN + 1];
345 char login[ADM_LOGIN_LEN + 1];
346 BLOWFISH_CTX ctx;
347 memset(loginS, 0, ADM_LOGIN_LEN + 1);
348
349 int total = 0;
350
351 while (total < ADM_LOGIN_LEN)
352     {
353     int ret = recv(sock, &loginS[total], ADM_LOGIN_LEN - total, 0);
354
355     if (ret < 0)
356         {
357         // Network error
358         printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
359         state = confHdr;
360         return ENODATA;
361         }
362
363     total += ret;
364     }
365
366 if (currAdmin->GetLogin().empty())
367     {
368     state = confHdr;
369     return ENODATA;
370     }
371
372 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
373
374 for (int i = 0; i < ADM_LOGIN_LEN / 8; i++)
375     {
376     DecodeString(login + i * 8, loginS + i * 8, &ctx);
377     }
378
379 if (currAdmin == admins->GetNoAdmin())
380     {
381     // If there are no admins registered in the system - give access with any password
382     state = confData;
383     return 0;
384     }
385
386 if (strncmp(currAdmin->GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
387     {
388     state = confHdr;
389     return ENODATA;
390     }
391
392 state = confData;
393 return 0;
394 }
395 //-----------------------------------------------------------------------------
396 int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
397 {
398 if (err)
399     {
400     int ret = send(sock, ERR_LOGINS, sizeof(ERR_LOGINS) - 1, 0);
401     if (ret < 0)
402         {
403         WriteServLog("send ERR_LOGIN error in SendLoginAnswer.");
404         return -1;
405         }
406     }
407 else
408     {
409     int ret = send(sock, OK_LOGINS, sizeof(OK_LOGINS) - 1, 0);
410     if (ret < 0)
411         {
412         WriteServLog("send OK_LOGINS error in SendLoginSAnswer.");
413         return -1;
414         }
415     }
416 return 0;
417 }
418 //-----------------------------------------------------------------------------
419 int CONFIGPROTO::RecvData(int sock)
420 {
421 char bufferS[8];
422 char buffer[9];
423
424 buffer[8] = 0;
425
426 requestList.clear();
427 BLOWFISH_CTX ctx;
428
429 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
430
431 while (1)
432     {
433     int total = 0;
434     bool done = false;
435     while (total < 8)
436         {
437         int ret = recv(sock, &bufferS[total], 8 - total, 0);
438         if (ret < 0)
439             {
440             // Network error
441             return -1;
442             }
443
444         if (ret == 0)
445             {
446             done = true;
447             break;
448             }
449
450         total += ret;
451         }
452
453     DecodeString(buffer, bufferS, &ctx);
454     requestList.push_back(std::string(buffer, total));
455
456     if (done || memchr(buffer, 0, total) != NULL)
457         {
458         // ëÏÎÅàÐÏÓÙÌËÉ
459         if (ParseCommand())
460             {
461             SendError("Bad command");
462             }
463         return SendDataAnswer(sock);
464         }
465     }
466 return 0;
467 }
468 //-----------------------------------------------------------------------------
469 int CONFIGPROTO::SendDataAnswer(int sock)
470 {
471 list<string>::iterator li;
472 li = answerList.begin();
473
474 BLOWFISH_CTX ctx;
475
476 char buff[8];
477 char buffS[8];
478 int n = 0;
479 int k = 0;
480
481 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
482
483 while (li != answerList.end())
484     {
485     while ((*li).c_str()[k])
486         {
487         buff[n % 8] = (*li).c_str()[k];
488         n++;
489         k++;
490
491         if (n % 8 == 0)
492             {
493             EncodeString(buffS, buff, &ctx);
494             int ret = send(sock, buffS, 8, 0);
495             if (ret < 0)
496                 {
497                 return -1;
498                 }
499             }
500         }
501     k = 0;// new node
502     ++li;
503     }
504
505 if (answerList.empty()) {
506     return 0;
507 }
508
509 buff[n % 8] = 0;
510 EncodeString(buffS, buff, &ctx);
511
512 answerList.clear();
513
514 return send(sock, buffS, 8, 0);
515 }
516 //-----------------------------------------------------------------------------
517 void CONFIGPROTO::SendError(const char * text)
518 {
519 char s[255];
520 answerList.clear();
521 snprintf(s, 255, "<Error value=\"%s\"/>", text);
522 answerList.push_back(s);
523 }
524 //-----------------------------------------------------------------------------
525 void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
526 {
527 WriteServLog("Admin's connect failed. IP %s", inet_ntostring(ip).c_str());
528 }
529 //-----------------------------------------------------------------------------