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