]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp
209ea3b2d25349de6e0aff08393338b4a0352f05
[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
175             if (RecvLogin(outerSocket) < 0)
176                 {
177                 close(outerSocket);
178                 continue;
179                 }
180
181             if (state == confLoginCipher)
182                 {
183                 if (SendLoginAnswer(outerSocket) < 0)
184                     {
185                     close(outerSocket);
186                     continue;
187                     }
188                 if (RecvLoginS(outerSocket) < 0)
189                     {
190                     close(outerSocket);
191                     continue;
192                     }
193
194                 if (state == confData)
195                     {
196                     if (SendLoginSAnswer(outerSocket, ans_ok) < 0)
197                         {
198                         close(outerSocket);
199                         continue;
200                         }
201                     if (RecvData(outerSocket) < 0)
202                         {
203                         close(outerSocket);
204                         continue;
205                         }
206                     state = confHdr;
207                     }
208                 else
209                     {
210                     if (SendLoginSAnswer(outerSocket, ans_err) < 0)
211                         {
212                         close(outerSocket);
213                         continue;
214                         }
215                     WriteLogAccessFailed(adminIP);
216                     }
217                 }
218             else
219                 {
220                 WriteLogAccessFailed(adminIP);
221                 }
222             }
223         else
224             {
225             WriteLogAccessFailed(adminIP);
226             if (SendHdrAnswer(outerSocket, ans_err) < 0)
227                 {
228                 close(outerSocket);
229                 continue;
230                 }
231             }
232         }
233     else
234         {
235         WriteLogAccessFailed(adminIP);
236         }
237     close(outerSocket);
238     }
239 }
240 //-----------------------------------------------------------------------------
241 int CONFIGPROTO::RecvHdr(int sock)
242 {
243 char buf[sizeof(STG_HEADER)];
244 memset(buf, 0, sizeof(STG_HEADER));
245 int ret;
246 size_t stgHdrLen = sizeof(STG_HEADER);
247 for (size_t i = 0; i < stgHdrLen; i++)
248     {
249     ret = recv(sock, &buf[i], 1, 0);
250     if (ret <= 0)
251         {
252         state = confHdr;
253         return -1;
254         }
255     }
256
257 if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
258     {
259     state = confLogin;
260     return 0;
261     }
262 else
263     {
264     SendError("Bad request");
265     }
266
267 state = confHdr;
268 return -1;
269 }
270 //-----------------------------------------------------------------------------
271 int CONFIGPROTO::SendHdrAnswer(int sock, int err)
272 {
273 int ret;
274
275 if (err)
276     {
277     ret = send(sock, ERR_HEADER, sizeof(ERR_HEADER) - 1, 0);
278     if (ret < 0)
279         {
280         WriteServLog("send ERR_HEADER error in SendHdrAnswer.");
281         return -1;
282         }
283     }
284 else
285     {
286     ret = send(sock, OK_HEADER, sizeof(OK_HEADER) - 1, 0);
287     if (ret < 0)
288         {
289         WriteServLog("send OK_HEADER error in SendHdrAnswer.");
290         return -1;
291         }
292     }
293
294 return 0;
295 }
296 //-----------------------------------------------------------------------------
297 int CONFIGPROTO::RecvLogin(int sock)
298 {
299 char login[ADM_LOGIN_LEN + 1];
300 int ret;
301
302 memset(login, 0, ADM_LOGIN_LEN + 1);
303
304 ret = recv(sock, login, ADM_LOGIN_LEN, 0);
305
306 if (ret < 0)
307     {
308     // Error in network
309     state = confHdr;
310     return ENODATA;
311     }
312
313 if (ret < ADM_LOGIN_LEN)
314     {
315     // Error in protocol
316     state = confHdr;
317     return ENODATA;
318     }
319
320 if (admins->Find(login, &currAdmin))
321     {
322     // Admin not found
323     state = confHdr;
324     return ENODATA;
325     }
326 currAdmin->SetIP(adminIP);
327 adminLogin = login;
328 state = confLoginCipher;
329 return 0;
330 }
331 //-----------------------------------------------------------------------------
332 int CONFIGPROTO::SendLoginAnswer(int sock)
333 {
334 int ret;
335
336 ret = send(sock, OK_LOGIN, sizeof(OK_LOGIN) - 1, 0);
337 if (ret < 0)
338     {
339     WriteServLog("Send OK_LOGIN error in SendLoginAnswer.");
340     return -1;
341     }
342 return 0;
343 }
344 //-----------------------------------------------------------------------------
345 int CONFIGPROTO::RecvLoginS(int sock)
346 {
347 char loginS[ADM_LOGIN_LEN + 1];
348 char login[ADM_LOGIN_LEN + 1];
349 BLOWFISH_CTX ctx;
350 memset(loginS, 0, ADM_LOGIN_LEN + 1);
351
352 int total = 0;
353
354 while (total < ADM_LOGIN_LEN)
355     {
356     int ret = recv(sock, &loginS[total], ADM_LOGIN_LEN - total, 0);
357
358     if (ret < 0)
359         {
360         // Network error
361         printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
362         state = confHdr;
363         return ENODATA;
364         }
365
366     total += ret;
367     }
368
369 if (currAdmin->GetLogin().empty())
370     {
371     state = confHdr;
372     return ENODATA;
373     }
374
375 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
376
377 for (int i = 0; i < ADM_LOGIN_LEN / 8; i++)
378     {
379     DecodeString(login + i * 8, loginS + i * 8, &ctx);
380     }
381
382 if (currAdmin == admins->GetNoAdmin())
383     {
384     // If there are no admins registered in the system - give access with any password
385     state = confData;
386     return 0;
387     }
388
389 if (strncmp(currAdmin->GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
390     {
391     state = confHdr;
392     return ENODATA;
393     }
394
395 state = confData;
396 return 0;
397 }
398 //-----------------------------------------------------------------------------
399 int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
400 {
401 if (err)
402     {
403     int ret = send(sock, ERR_LOGINS, sizeof(ERR_LOGINS) - 1, 0);
404     if (ret < 0)
405         {
406         WriteServLog("send ERR_LOGIN error in SendLoginAnswer.");
407         return -1;
408         }
409     }
410 else
411     {
412     int ret = send(sock, OK_LOGINS, sizeof(OK_LOGINS) - 1, 0);
413     if (ret < 0)
414         {
415         WriteServLog("send OK_LOGINS error in SendLoginSAnswer.");
416         return -1;
417         }
418     }
419 return 0;
420 }
421 //-----------------------------------------------------------------------------
422 int CONFIGPROTO::RecvData(int sock)
423 {
424 char bufferS[8];
425 char buffer[9];
426
427 buffer[8] = 0;
428
429 requestList.clear();
430 BLOWFISH_CTX ctx;
431
432 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
433
434 while (1)
435     {
436     int total = 0;
437     bool done = false;
438     while (total < 8)
439         {
440         int ret = recv(sock, &bufferS[total], 8 - total, 0);
441         if (ret < 0)
442             {
443             // Network error
444             return -1;
445             }
446
447         if (ret == 0)
448             {
449             done = true;
450             break;
451             }
452
453         total += ret;
454         }
455
456     DecodeString(buffer, bufferS, &ctx);
457     requestList.push_back(std::string(buffer, total));
458
459     if (done || memchr(buffer, 0, total) != NULL)
460         {
461         // ëÏÎÅàÐÏÓÙÌËÉ
462         if (ParseCommand())
463             {
464             SendError("Bad command");
465             }
466         return SendDataAnswer(sock);
467         }
468     }
469 return 0;
470 }
471 //-----------------------------------------------------------------------------
472 int CONFIGPROTO::SendDataAnswer(int sock)
473 {
474 list<string>::iterator li;
475 li = answerList.begin();
476
477 BLOWFISH_CTX ctx;
478
479 char buff[8];
480 char buffS[8];
481 int n = 0;
482 int k = 0;
483
484 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
485
486 while (li != answerList.end())
487     {
488     while ((*li).c_str()[k])
489         {
490         buff[n % 8] = (*li).c_str()[k];
491         n++;
492         k++;
493
494         if (n % 8 == 0)
495             {
496             EncodeString(buffS, buff, &ctx);
497             int ret = send(sock, buffS, 8, 0);
498             if (ret < 0)
499                 {
500                 return -1;
501                 }
502             }
503         }
504     k = 0;// new node
505     ++li;
506     }
507
508 if (answerList.empty()) {
509     return 0;
510 }
511
512 buff[n % 8] = 0;
513 EncodeString(buffS, buff, &ctx);
514
515 answerList.clear();
516
517 return send(sock, buffS, 8, 0);
518 }
519 //-----------------------------------------------------------------------------
520 void CONFIGPROTO::SendError(const char * text)
521 {
522 char s[255];
523 answerList.clear();
524 snprintf(s, 255, "<Error value=\"%s\"/>", text);
525 answerList.push_back(s);
526 }
527 //-----------------------------------------------------------------------------
528 void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
529 {
530 WriteServLog("Admin's connect failed. IP %s", inet_ntostring(ip).c_str());
531 }
532 //-----------------------------------------------------------------------------