]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/radius/radius.cpp
Синхронизирую исходники мертвых проектов клиента юзерской статистики и
[stg.git] / projects / stargazer / plugins / other / radius / radius.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  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 /*
22  *  This file contains a realization of radius data access plugin for Stargazer
23  *
24  *  $Revision: 1.14 $
25  *  $Date: 2009/12/13 14:17:13 $
26  *
27  */
28
29 #include <algorithm>
30 #include <signal.h>
31
32 #include "radius.h"
33 #include "common.h"
34
35 extern volatile const time_t stgTime;
36
37 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
40 class RAD_CREATOR
41 {
42 private:
43     RADIUS * rad;
44
45 public:
46     RAD_CREATOR()
47         : rad(new RADIUS())
48         {
49         };
50     ~RAD_CREATOR()
51         {
52         delete rad;
53         };
54
55     RADIUS * GetPlugin()
56         {
57         return rad;
58         };
59 };
60 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
63 RAD_CREATOR radc;
64 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
67 BASE_PLUGIN * GetPlugin()
68 {
69 return radc.GetPlugin();
70 }
71 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
74 uint16_t RAD_SETTINGS::GetPort() const
75 {
76 return port;
77 }
78 //-----------------------------------------------------------------------------
79 uint32_t RAD_SETTINGS::GetServerIP() const
80 {
81 return serverIP;
82 }
83 //-----------------------------------------------------------------------------
84 int RAD_SETTINGS::GetPassword(string * password) const
85 {
86 *password = RAD_SETTINGS::password;
87 return 0;
88 }
89 //-----------------------------------------------------------------------------
90 int RAD_SETTINGS::GetAuthServices(list<string> * svcs) const
91 {
92 *svcs = authServices;
93 return 0;
94 }
95 //-----------------------------------------------------------------------------
96 int RAD_SETTINGS::GetAcctServices(list<string> * svcs) const
97 {
98 *svcs = acctServices;
99 return 0;
100 }
101 //-----------------------------------------------------------------------------
102 int RAD_SETTINGS::ParseIP(const string & str, uint32_t * IP)
103 {
104 *IP = inet_addr(str.c_str());
105 return *IP == INADDR_NONE ? -1 : 0;
106 }
107 //-----------------------------------------------------------------------------
108 int RAD_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
109 {
110 if (str2x(str.c_str(), *val))
111     {
112     errorStr = "Incorrect value \'" + str + "\'.";
113     return -1;
114     }
115 if (*val < min || *val > max)
116     {
117     errorStr = "Value \'" + str + "\' out of range.";
118     return -1;
119     }
120 return 0;
121 }
122 //-----------------------------------------------------------------------------
123 int RAD_SETTINGS::ParseServices(const vector<string> & str, list<string> * lst)
124 {
125     copy(str.begin(), str.end(), back_inserter(*lst));
126     list<string>::iterator it(find(lst->begin(),
127                                    lst->end(),
128                                    "empty"));
129     if (it != lst->end())
130         *it = "";
131
132     return 0;
133 }
134 //-----------------------------------------------------------------------------
135 int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
136 {
137 int p;
138 PARAM_VALUE pv;
139 vector<PARAM_VALUE>::const_iterator pvi;
140 ///////////////////////////
141 pv.param = "Port";
142 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
143 if (pvi == s.moduleParams.end())
144     {
145     errorStr = "Parameter \'Port\' not found.";
146     printfd(__FILE__, "Parameter 'Port' not found\n");
147     return -1;
148     }
149 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
150     {
151     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
152     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
153     return -1;
154     }
155 port = p;
156 ///////////////////////////
157 pv.param = "ServerIP";
158 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
159 if (pvi == s.moduleParams.end())
160     {
161     serverIP = 0;
162     }
163 else
164     {
165     if (ParseIP(pvi->value[0], &serverIP))
166         {
167         serverIP = 0;
168         }
169     }
170 ///////////////////////////
171 pv.param = "Password";
172 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
173 if (pvi == s.moduleParams.end())
174     {
175     errorStr = "Parameter \'Password\' not found.";
176     printfd(__FILE__, "Parameter 'Password' not found\n");
177     return -1;
178     }
179 password = pvi->value[0];
180 ///////////////////////////
181 pv.param = "AuthServices";
182 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
183 if (pvi != s.moduleParams.end())
184     {
185     ParseServices(pvi->value, &authServices);
186     }
187 ///////////////////////////
188 pv.param = "AcctServices";
189 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
190 if (pvi != s.moduleParams.end())
191     {
192     ParseServices(pvi->value, &acctServices);
193     }
194
195 return 0;
196 }
197 //-----------------------------------------------------------------------------
198 //-----------------------------------------------------------------------------
199 //-----------------------------------------------------------------------------
200 RADIUS::RADIUS()
201 {
202 isRunning = false;
203 }
204 //-----------------------------------------------------------------------------
205 void RADIUS::SetUsers(USERS * u)
206 {
207 users = u;
208 }
209 //-----------------------------------------------------------------------------
210 void RADIUS::SetStgSettings(const SETTINGS * s)
211 {
212 stgSettings = s;
213 }
214 //-----------------------------------------------------------------------------
215 void RADIUS::SetSettings(const MODULE_SETTINGS & s)
216 {
217 settings = s;
218 }
219 //-----------------------------------------------------------------------------
220 void RADIUS::SetStore(BASE_STORE * s)
221 {
222 store = s;
223 }
224 //-----------------------------------------------------------------------------
225 int RADIUS::ParseSettings()
226 {
227 int ret = radSettings.ParseSettings(settings);
228 if (ret)
229     errorStr = radSettings.GetStrError();
230 return ret;
231 }
232 //-----------------------------------------------------------------------------
233 bool RADIUS::IsRunning()
234 {
235 return isRunning;
236 }
237 //-----------------------------------------------------------------------------
238 const string RADIUS::GetVersion() const
239 {
240 return "RADIUS data access plugin v 0.6";
241 }
242 //-----------------------------------------------------------------------------
243 uint16_t RADIUS::GetStartPosition() const
244 {
245 // Start before any authorizers!!!
246 return 20;
247 }
248 //-----------------------------------------------------------------------------
249 uint16_t RADIUS::GetStopPosition() const
250 {
251 return 20;
252 }
253 //-----------------------------------------------------------------------------
254 void RADIUS::SetUserNotifier(user_iter)
255 {
256 }
257 //-----------------------------------------------------------------------------
258 void RADIUS::UnSetUserNotifier(user_iter)
259 {
260 }
261 //-----------------------------------------------------------------------------
262 int RADIUS::PrepareNet()
263 {
264 sock = socket(AF_INET, SOCK_DGRAM, 0);
265
266 if (sock < 0)
267     {
268     errorStr = "Cannot create socket.";
269     printfd(__FILE__, "Cannot create socket\n");
270     return -1;
271     }
272
273 inAddr.sin_family = AF_INET;
274 inAddr.sin_port = htons(port);
275 inAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
276
277 if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
278     {
279     errorStr = "RADIUS: Bind failed.";
280     printfd(__FILE__, "Cannot bind socket\n");
281     return -1;
282     }
283
284 return 0;
285 }
286 //-----------------------------------------------------------------------------
287 int RADIUS::FinalizeNet()
288 {
289 close(sock);
290 return 0;
291 }
292 //-----------------------------------------------------------------------------
293 int RADIUS::Start()
294 {
295 string password;
296
297 radSettings.GetPassword(&password);
298 port = radSettings.GetPort();
299 serverIP = radSettings.GetServerIP();
300 radSettings.GetAuthServices(&authServices);
301 radSettings.GetAcctServices(&acctServices);
302
303 InitEncrypt(&ctx, password);
304
305 nonstop = true;
306
307 if (PrepareNet())
308     {
309     return -1;
310     }
311
312 if (!isRunning)
313     {
314     if (pthread_create(&thread, NULL, Run, this))
315         {
316         errorStr = "Cannot create thread.";
317         printfd(__FILE__, "Cannot create thread\n");
318         return -1;
319         }
320     }
321
322 errorStr = "";
323 return 0;
324 }
325 //-----------------------------------------------------------------------------
326 int RADIUS::Stop()
327 {
328 if (!IsRunning())
329     return 0;
330
331 nonstop = false;
332
333 map<string, RAD_SESSION>::iterator it;
334 for (it = sessions.begin(); it != sessions.end(); ++it)
335     {
336     user_iter ui;
337     if (users->FindByName(it->second.userName, &ui))
338         {
339         ui->Unauthorize(this);
340         }
341     }
342 sessions.erase(sessions.begin(), sessions.end());
343
344 FinalizeNet();
345
346 if (isRunning)
347     {
348     //5 seconds to thread stops itself
349     for (int i = 0; i < 25 && isRunning; i++)
350         {
351         usleep(200000);
352         }
353
354     //after 5 seconds waiting thread still running. now killing it
355     if (isRunning)
356         {
357         if (pthread_kill(thread, SIGINT))
358             {
359             errorStr = "Cannot kill thread.";
360             printfd(__FILE__, "Cannot kill thread\n");
361             return -1;
362             }
363         printfd(__FILE__, "RADIUS::Stop killed Run\n");
364         }
365     }
366
367 return 0;
368 }
369 //-----------------------------------------------------------------------------
370 void * RADIUS::Run(void * d)
371 {
372 RADIUS * rad = (RADIUS *)d;
373 RAD_PACKET packet;
374
375 rad->isRunning = true;
376
377 while (rad->nonstop)
378     {
379     if (!rad->WaitPackets(rad->sock))
380         {
381         continue;
382         }
383     if (rad->RecvData(&packet))
384         {
385         printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
386         }
387     else
388         {
389         if (rad->ProcessData(&packet))
390             {
391             packet.packetType = RAD_REJECT_PACKET;
392             }
393         rad->Send(packet);
394         }
395     }
396
397 rad->isRunning = false;
398
399 return NULL;
400 }
401 //-----------------------------------------------------------------------------
402 int RADIUS::RecvData(RAD_PACKET * packet)
403 {
404     int8_t buf[RAD_MAX_PACKET_LEN];
405     outerAddrLen = sizeof(struct sockaddr_in);
406     int dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, (struct sockaddr *)&outerAddr, &outerAddrLen);
407     if (dataLen > 0) {
408         Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
409     }
410     if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
411         {
412         printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
413         return -1;
414         }
415     return 0;
416 }
417 //-----------------------------------------------------------------------------
418 int RADIUS::Send(const RAD_PACKET & packet)
419 {
420 int res, len = sizeof(RAD_PACKET);
421 char buf[1032];
422
423 Encrypt(&ctx, buf, (char *)&packet, len / 8);
424 res = sendto(sock, buf, len, 0, (struct sockaddr *)&outerAddr, outerAddrLen);
425
426 return 0;
427 }
428 //-----------------------------------------------------------------------------
429 int RADIUS::ProcessData(RAD_PACKET * packet)
430 {
431 //struct in_addr addr = {packet->ip};
432 if (strncmp((const char *)packet->protoVer, "01", 2))
433     {
434     printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
435     return -1;
436     }
437 switch (packet->packetType)
438     {
439     case RAD_AUTZ_PACKET:
440         return ProcessAutzPacket(packet);
441     case RAD_AUTH_PACKET:
442         return ProcessAuthPacket(packet);
443     case RAD_POST_AUTH_PACKET:
444         return ProcessPostAuthPacket(packet);
445     case RAD_ACCT_START_PACKET:
446         return ProcessAcctStartPacket(packet);
447     case RAD_ACCT_STOP_PACKET:
448         return ProcessAcctStopPacket(packet);
449     case RAD_ACCT_UPDATE_PACKET:
450         return ProcessAcctUpdatePacket(packet);
451     case RAD_ACCT_OTHER_PACKET:
452         return ProcessAcctOtherPacket(packet);
453     default:
454         printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
455         return -1;
456     };
457 return 0;
458 }
459 //-----------------------------------------------------------------------------
460 int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
461 {
462 USER_CONF conf;
463
464 if (!IsAllowedService((char *)packet->service))
465     {
466     printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
467     packet->packetType = RAD_REJECT_PACKET;
468     return 0;
469     }
470
471 if (store->RestoreUserConf(&conf, (char *)packet->login))
472     {
473     packet->packetType = RAD_REJECT_PACKET;
474     printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
475     return 0;
476     }
477
478 // At this point service can be authorized at least
479 // So we send a plain-text password
480
481 packet->packetType = RAD_ACCEPT_PACKET;
482 strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
483
484 return 0;
485 }
486 //-----------------------------------------------------------------------------
487 int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
488 {
489 user_iter ui;
490
491 if (!CanAcctService((char *)packet->service))
492     {
493
494     // There are no sense to check for allowed service
495     // It has allready checked at previous stage (authorization)
496
497     printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
498     packet->packetType = RAD_ACCEPT_PACKET;
499     return 0;
500     }
501
502 // At this point we have an accountable service
503 // All other services got a password if allowed or rejected
504
505 if (!FindUser(&ui, (char *)packet->login))
506     {
507     packet->packetType = RAD_REJECT_PACKET;
508     printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
509     return 0;
510     }
511
512 if (ui->IsInetable())
513     {
514     packet->packetType = RAD_ACCEPT_PACKET;
515     }
516 else
517     {
518     packet->packetType = RAD_REJECT_PACKET;
519     }
520
521 packet->packetType = RAD_ACCEPT_PACKET;
522 return 0;
523 }
524 //-----------------------------------------------------------------------------
525 int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
526 {
527 user_iter ui;
528
529 if (!CanAcctService((char *)packet->service))
530     {
531
532     // There are no sense to check for allowed service
533     // It has allready checked at previous stage (authorization)
534
535     packet->packetType = RAD_ACCEPT_PACKET;
536     return 0;
537     }
538
539 if (!FindUser(&ui, (char *)packet->login))
540     {
541     packet->packetType = RAD_REJECT_PACKET;
542     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
543     return 0;
544     }
545
546 // I think that only Framed-User services has sense to be accountable
547 // So we have to supply a Framed-IP
548
549 USER_IPS ips = ui->property.ips;
550 packet->packetType = RAD_ACCEPT_PACKET;
551
552 // Additional checking for Framed-User service
553
554 if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
555     packet->ip = ips[0].ip;
556 else
557     packet->ip = 0;
558
559 return 0;
560 }
561 //-----------------------------------------------------------------------------
562 int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
563 {
564 user_iter ui;
565
566 if (!FindUser(&ui, (char *)packet->login))
567     {
568     packet->packetType = RAD_REJECT_PACKET;
569     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
570     return 0;
571     }
572
573 // At this point we have to unauthorize user only if it is an accountable service
574
575 if (CanAcctService((char *)packet->service))
576     {
577     if (sessions.find((const char *)packet->sessid) != sessions.end())
578         {
579         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
580         packet->packetType = RAD_REJECT_PACKET;
581         return -1;
582         }
583     USER_IPS ips = ui->property.ips;
584     if (ui->Authorize(ips[0].ip, "", 0xffFFffFF, this))
585         {
586         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
587         packet->packetType = RAD_REJECT_PACKET;
588         return -1;
589         }
590     sessions[(const char *)packet->sessid].userName = (const char *)packet->login;
591     sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service;
592     for_each(sessions.begin(), sessions.end(), SPrinter());
593     }
594 else
595     {
596     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
597     }
598
599 packet->packetType = RAD_ACCEPT_PACKET;
600 return 0;
601 }
602 //-----------------------------------------------------------------------------
603 int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
604 {
605 map<string, RAD_SESSION>::iterator sid;
606
607 if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
608     {
609     printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
610     packet->packetType = RAD_REJECT_PACKET;
611     return -1;
612     }
613
614 user_iter ui;
615
616 if (!FindUser(&ui, sid->second.userName))
617     {
618     packet->packetType = RAD_REJECT_PACKET;
619     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
620     return 0;
621     }
622
623 sessions.erase(sid);
624
625 ui->Unauthorize(this);
626
627 packet->packetType = RAD_ACCEPT_PACKET;
628 return 0;
629 }
630 //-----------------------------------------------------------------------------
631 int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
632 {
633 // Fake. May be used later
634 packet->packetType = RAD_ACCEPT_PACKET;
635 return 0;
636 }
637 //-----------------------------------------------------------------------------
638 int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
639 {
640 // Fake. May be used later
641 packet->packetType = RAD_ACCEPT_PACKET;
642 return 0;
643 }
644 //-----------------------------------------------------------------------------
645 void RADIUS::InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
646 {
647 unsigned char keyL[RAD_PASSWORD_LEN];  // Пароль для шифровки
648 memset(keyL, 0, RAD_PASSWORD_LEN);
649 strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
650 Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
651 }
652 //-----------------------------------------------------------------------------
653 void RADIUS::Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
654 {
655 // len8 - длина в 8-ми байтовых блоках
656 if (dst != src)
657     memcpy(dst, src, len8 * 8);
658
659 for (int i = 0; i < len8; i++)
660     Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
661 }
662 //-----------------------------------------------------------------------------
663 void RADIUS::Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
664 {
665 // len8 - длина в 8-ми байтовых блоках
666 if (dst != src)
667     memcpy(dst, src, len8 * 8);
668
669 for (int i = 0; i < len8; i++)
670     Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
671 }
672 //-----------------------------------------------------------------------------
673 void RADIUS::PrintServices(const list<string> & svcs)
674 {
675     for_each(svcs.begin(), svcs.end(), Printer());
676 }
677 //-----------------------------------------------------------------------------
678 bool RADIUS::FindUser(user_iter * ui, const std::string & login) const
679 {
680 if (users->FindByName(login, ui))
681     {
682     return false;
683     }
684 return true;
685 }
686 //-----------------------------------------------------------------------------
687 bool RADIUS::CanAuthService(const std::string & svc) const
688 {
689     return find(authServices.begin(), authServices.end(), svc) != authServices.end();
690 }
691 //-----------------------------------------------------------------------------
692 bool RADIUS::CanAcctService(const std::string & svc) const
693 {
694     return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
695 }
696 //-----------------------------------------------------------------------------
697 bool RADIUS::IsAllowedService(const std::string & svc) const
698 {
699     return CanAuthService(svc) || CanAcctService(svc);
700 }
701 //-----------------------------------------------------------------------------
702 bool RADIUS::WaitPackets(int sd) const
703 {
704 fd_set rfds;
705 FD_ZERO(&rfds);
706 FD_SET(sd, &rfds);
707
708 struct timeval tv;
709 tv.tv_sec = 0;
710 tv.tv_usec = 500000;
711
712 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
713 if (res == -1) // Error
714     {
715     if (errno != EINTR)
716         {
717         printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
718         }
719     return false;
720     }
721
722 if (res == 0) // Timeout
723     {
724     return false;
725     }
726
727 return true;
728 }