]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/configuration/sgconfig/rsconf.cpp
Replace deprecated usleep with POSIX-compliant nanosleep
[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> // close
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 size_t stgHdrLen = sizeof(STG_HEADER) - 1; // Without 0-char
243 size_t pos = 0;
244 while (pos < stgHdrLen)
245     {
246     if (!WaitPackets(sock))
247         {
248         state = confHdr;
249         SendError("Bad request");
250         return -1;
251         }
252     int ret = recv(sock, &buf[pos], stgHdrLen - pos, 0);
253     if (ret < 0)
254         {
255         state = confHdr;
256         return -1;
257         }
258     pos += ret;
259     }
260
261 if (0 == strncmp(buf, STG_HEADER, strlen(STG_HEADER)))
262     {
263     state = confLogin;
264     return 0;
265     }
266 else
267     {
268     SendError("Bad request");
269     }
270
271 state = confHdr;
272 return -1;
273 }
274 //-----------------------------------------------------------------------------
275 int CONFIGPROTO::SendHdrAnswer(int sock, int err)
276 {
277 if (err)
278     {
279     if (send(sock, ERR_HEADER, sizeof(ERR_HEADER) - 1, 0) < 0)
280         {
281         WriteServLog("send ERR_HEADER error in SendHdrAnswer.");
282         return -1;
283         }
284     }
285 else
286     {
287     if (send(sock, OK_HEADER, sizeof(OK_HEADER) - 1, 0) < 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
301 memset(login, 0, ADM_LOGIN_LEN + 1);
302
303 size_t pos = 0;
304 while (pos < ADM_LOGIN_LEN) {
305     if (!WaitPackets(sock))
306         {
307         state = confHdr;
308         return ENODATA;
309         }
310
311     int ret = recv(sock, &login[pos], ADM_LOGIN_LEN - pos, 0);
312
313     if (ret < 0)
314         {
315         // Error in network
316         state = confHdr;
317         return ENODATA;
318         }
319
320     pos += ret;
321 }
322
323 if (admins->Find(login, &currAdmin))
324     {
325     // Admin not found
326     state = confHdr;
327     return ENODATA;
328     }
329
330 currAdmin->SetIP(adminIP);
331 adminLogin = login;
332 state = confLoginCipher;
333 return 0;
334 }
335 //-----------------------------------------------------------------------------
336 int CONFIGPROTO::SendLoginAnswer(int sock)
337 {
338 if (send(sock, OK_LOGIN, sizeof(OK_LOGIN) - 1, 0) < 0)
339     {
340     WriteServLog("Send OK_LOGIN error in SendLoginAnswer.");
341     return -1;
342     }
343 return 0;
344 }
345 //-----------------------------------------------------------------------------
346 int CONFIGPROTO::RecvLoginS(int sock)
347 {
348 char loginS[ADM_LOGIN_LEN + 1];
349 memset(loginS, 0, ADM_LOGIN_LEN + 1);
350
351 size_t pos = 0;
352 while (pos < ADM_LOGIN_LEN)
353     {
354     if (!WaitPackets(sock))
355         {
356         state = confHdr;
357         return ENODATA;
358         }
359
360     int ret = recv(sock, &loginS[pos], ADM_LOGIN_LEN - pos, 0);
361
362     if (ret < 0)
363         {
364         // Network error
365         printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
366         state = confHdr;
367         return ENODATA;
368         }
369
370     pos += ret;
371     }
372
373 if (currAdmin->GetLogin().empty())
374     {
375     state = confHdr;
376     return ENODATA;
377     }
378
379 BLOWFISH_CTX ctx;
380 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
381
382 char login[ADM_LOGIN_LEN + 1];
383 for (size_t i = 0; i < ADM_LOGIN_LEN / 8; i++)
384     {
385     DecodeString(login + i * 8, loginS + i * 8, &ctx);
386     }
387
388 if (currAdmin == admins->GetNoAdmin())
389     {
390     // If there are no admins registered in the system - give access with any password
391     state = confData;
392     return 0;
393     }
394
395 if (strncmp(currAdmin->GetLogin().c_str(), login, ADM_LOGIN_LEN) != 0)
396     {
397     state = confHdr;
398     return ENODATA;
399     }
400
401 state = confData;
402 return 0;
403 }
404 //-----------------------------------------------------------------------------
405 int CONFIGPROTO::SendLoginSAnswer(int sock, int err)
406 {
407 if (err)
408     {
409     if (send(sock, ERR_LOGINS, sizeof(ERR_LOGINS) - 1, 0) < 0)
410         {
411         WriteServLog("send ERR_LOGIN error in SendLoginAnswer.");
412         return -1;
413         }
414     }
415 else
416     {
417     if (send(sock, OK_LOGINS, sizeof(OK_LOGINS) - 1, 0) < 0)
418         {
419         WriteServLog("send OK_LOGINS error in SendLoginSAnswer.");
420         return -1;
421         }
422     }
423 return 0;
424 }
425 //-----------------------------------------------------------------------------
426 int CONFIGPROTO::RecvData(int sock)
427 {
428 requestList.clear();
429 BLOWFISH_CTX ctx;
430
431 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
432
433 while (1)
434     {
435     bool done = false;
436     char bufferS[8];
437     size_t pos = 0;
438     while (pos < sizeof(bufferS))
439         {
440         if (!WaitPackets(sock))
441             {
442             done = true;
443             break;
444             }
445
446         int ret = recv(sock, &bufferS[pos], sizeof(bufferS) - pos, 0);
447         if (ret < 0)
448             {
449             // Network error
450             printfd(__FILE__, "recv error: '%s'\n", strerror(errno));
451             return -1;
452             }
453
454         if (ret == 0)
455             {
456             done = true;
457             break;
458             }
459
460         pos += ret;
461         }
462
463     char buffer[8];
464     buffer[7] = 0;
465
466     DecodeString(buffer, bufferS, &ctx);
467     requestList.push_back(std::string(buffer, pos));
468
469     if (done || memchr(buffer, 0, pos) != NULL)
470         {
471         // End of data
472         if (ParseCommand())
473             {
474             SendError("Bad command");
475             }
476         return SendDataAnswer(sock);
477         }
478     }
479 return 0;
480 }
481 //-----------------------------------------------------------------------------
482 int CONFIGPROTO::SendDataAnswer(int sock)
483 {
484 list<string>::iterator li;
485 li = answerList.begin();
486
487 BLOWFISH_CTX ctx;
488
489 char buff[8];
490 char buffS[8];
491 int n = 0;
492 int k = 0;
493
494 EnDecodeInit(currAdmin->GetPassword().c_str(), ADM_PASSWD_LEN, &ctx);
495
496 while (li != answerList.end())
497     {
498     while ((*li).c_str()[k])
499         {
500         buff[n % 8] = (*li).c_str()[k];
501         n++;
502         k++;
503
504         if (n % 8 == 0)
505             {
506             EncodeString(buffS, buff, &ctx);
507             int ret = send(sock, buffS, 8, 0);
508             if (ret < 0)
509                 {
510                 return -1;
511                 }
512             }
513         }
514     k = 0;// new node
515     ++li;
516     }
517
518 if (answerList.empty()) {
519     return 0;
520 }
521
522 buff[n % 8] = 0;
523 EncodeString(buffS, buff, &ctx);
524
525 answerList.clear();
526
527 return send(sock, buffS, 8, 0);
528 }
529 //-----------------------------------------------------------------------------
530 void CONFIGPROTO::SendError(const char * text)
531 {
532 char s[255];
533 answerList.clear();
534 snprintf(s, 255, "<Error value=\"%s\"/>", text);
535 answerList.push_back(s);
536 }
537 //-----------------------------------------------------------------------------
538 void CONFIGPROTO::WriteLogAccessFailed(uint32_t ip)
539 {
540 WriteServLog("Admin's connect failed. IP %s", inet_ntostring(ip).c_str());
541 }
542 //-----------------------------------------------------------------------------