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