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.
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.
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
18 * Author : Maxim Mamontov <faust@stargazer.dp.ua>
22 * This file contains a realization of radius data access plugin for Stargazer
25 * $Date: 2009/12/13 14:17:13 $
35 extern volatile const time_t stgTime;
37 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
67 BASE_PLUGIN * GetPlugin()
69 return radc.GetPlugin();
71 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
74 uint16_t RAD_SETTINGS::GetPort() const
78 //-----------------------------------------------------------------------------
79 int RAD_SETTINGS::GetPassword(string * password) const
81 *password = RAD_SETTINGS::password;
84 //-----------------------------------------------------------------------------
85 int RAD_SETTINGS::GetAuthServices(list<string> * svcs) const
90 //-----------------------------------------------------------------------------
91 int RAD_SETTINGS::GetAcctServices(list<string> * svcs) const
96 //-----------------------------------------------------------------------------
97 int RAD_SETTINGS::ParseIP(const string & str, uint32_t * IP)
99 *IP = inet_addr(str.c_str());
100 return *IP == INADDR_NONE ? -1 : 0;
102 //-----------------------------------------------------------------------------
103 int RAD_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
105 if (str2x(str.c_str(), *val))
107 errorStr = "Incorrect value \'" + str + "\'.";
110 if (*val < min || *val > max)
112 errorStr = "Value \'" + str + "\' out of range.";
117 //-----------------------------------------------------------------------------
118 int RAD_SETTINGS::ParseServices(const vector<string> & str, list<string> * lst)
120 copy(str.begin(), str.end(), back_inserter(*lst));
121 list<string>::iterator it(find(lst->begin(),
124 if (it != lst->end())
129 //-----------------------------------------------------------------------------
130 int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
134 vector<PARAM_VALUE>::const_iterator pvi;
135 ///////////////////////////
137 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
138 if (pvi == s.moduleParams.end())
140 errorStr = "Parameter \'Port\' not found.";
141 printfd(__FILE__, "Parameter 'Port' not found\n");
144 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
146 errorStr = "Cannot parse parameter \'Port\': " + errorStr;
147 printfd(__FILE__, "Cannot parse parameter 'Port'\n");
151 ///////////////////////////
152 pv.param = "Password";
153 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
154 if (pvi == s.moduleParams.end())
156 errorStr = "Parameter \'Password\' not found.";
157 printfd(__FILE__, "Parameter 'Password' not found\n");
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())
166 ParseServices(pvi->value, &authServices);
168 ///////////////////////////
169 pv.param = "AcctServices";
170 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
171 if (pvi != s.moduleParams.end())
173 ParseServices(pvi->value, &acctServices);
178 //-----------------------------------------------------------------------------
179 //-----------------------------------------------------------------------------
180 //-----------------------------------------------------------------------------
190 //-----------------------------------------------------------------------------
191 void RADIUS::SetUsers(USERS * u)
195 //-----------------------------------------------------------------------------
196 void RADIUS::SetStgSettings(const SETTINGS * s)
200 //-----------------------------------------------------------------------------
201 void RADIUS::SetSettings(const MODULE_SETTINGS & s)
205 //-----------------------------------------------------------------------------
206 void RADIUS::SetStore(BASE_STORE * s)
210 //-----------------------------------------------------------------------------
211 int RADIUS::ParseSettings()
213 int ret = radSettings.ParseSettings(settings);
215 errorStr = radSettings.GetStrError();
218 //-----------------------------------------------------------------------------
219 bool RADIUS::IsRunning()
223 //-----------------------------------------------------------------------------
224 const string RADIUS::GetVersion() const
226 return "RADIUS data access plugin v 0.6";
228 //-----------------------------------------------------------------------------
229 uint16_t RADIUS::GetStartPosition() const
231 // Start before any authorizers!!!
234 //-----------------------------------------------------------------------------
235 uint16_t RADIUS::GetStopPosition() const
239 //-----------------------------------------------------------------------------
240 void RADIUS::SetUserNotifier(user_iter)
243 //-----------------------------------------------------------------------------
244 void RADIUS::UnSetUserNotifier(user_iter)
247 //-----------------------------------------------------------------------------
248 int RADIUS::PrepareNet()
250 sock = socket(AF_INET, SOCK_DGRAM, 0);
254 errorStr = "Cannot create socket.";
255 printfd(__FILE__, "Cannot create socket\n");
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");
264 if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
266 errorStr = "RADIUS: Bind failed.";
267 printfd(__FILE__, "Cannot bind socket\n");
273 //-----------------------------------------------------------------------------
274 int RADIUS::FinalizeNet()
279 //-----------------------------------------------------------------------------
284 radSettings.GetPassword(&password);
285 radSettings.GetAuthServices(&authServices);
286 radSettings.GetAcctServices(&acctServices);
288 InitEncrypt(&ctx, password);
299 if (pthread_create(&thread, NULL, Run, this))
301 errorStr = "Cannot create thread.";
302 printfd(__FILE__, "Cannot create thread\n");
310 //-----------------------------------------------------------------------------
318 map<string, RAD_SESSION>::iterator it;
319 for (it = sessions.begin(); it != sessions.end(); ++it)
322 if (users->FindByName(it->second.userName, &ui))
324 ui->Unauthorize(this);
327 sessions.erase(sessions.begin(), sessions.end());
333 //5 seconds to thread stops itself
334 for (int i = 0; i < 25 && isRunning; i++)
339 //after 5 seconds waiting thread still running. now killing it
342 if (pthread_kill(thread, SIGINT))
344 errorStr = "Cannot kill thread.";
345 printfd(__FILE__, "Cannot kill thread\n");
348 printfd(__FILE__, "RADIUS::Stop killed Run\n");
354 //-----------------------------------------------------------------------------
355 void * RADIUS::Run(void * d)
357 RADIUS * rad = (RADIUS *)d;
360 rad->isRunning = true;
364 if (!rad->WaitPackets(rad->sock))
368 struct sockaddr_in outerAddr;
369 if (rad->RecvData(&packet, &outerAddr))
371 printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
375 if (rad->ProcessData(&packet))
377 packet.packetType = RAD_REJECT_PACKET;
379 rad->Send(packet, &outerAddr);
383 rad->isRunning = false;
387 //-----------------------------------------------------------------------------
388 int RADIUS::RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr)
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);
394 Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
396 if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
398 printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
403 //-----------------------------------------------------------------------------
404 int RADIUS::Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr)
406 size_t len = sizeof(RAD_PACKET);
409 Encrypt(&ctx, buf, (char *)&packet, len / 8);
410 return sendto(sock, buf, len, 0, reinterpret_cast<struct sockaddr *>(outerAddr), sizeof(struct sockaddr_in));
412 //-----------------------------------------------------------------------------
413 int RADIUS::ProcessData(RAD_PACKET * packet)
415 if (strncmp((const char *)packet->protoVer, "01", 2))
417 printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
420 switch (packet->packetType)
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);
437 printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
442 //-----------------------------------------------------------------------------
443 int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
447 if (!IsAllowedService((char *)packet->service))
449 printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
450 packet->packetType = RAD_REJECT_PACKET;
454 if (store->RestoreUserConf(&conf, (char *)packet->login))
456 packet->packetType = RAD_REJECT_PACKET;
457 printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
461 // At this point service can be authorized at least
462 // So we send a plain-text password
464 packet->packetType = RAD_ACCEPT_PACKET;
465 strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
469 //-----------------------------------------------------------------------------
470 int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
474 if (!CanAcctService((char *)packet->service))
477 // There are no sense to check for allowed service
478 // It has allready checked at previous stage (authorization)
480 printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
481 packet->packetType = RAD_ACCEPT_PACKET;
485 // At this point we have an accountable service
486 // All other services got a password if allowed or rejected
488 if (!FindUser(&ui, (char *)packet->login))
490 packet->packetType = RAD_REJECT_PACKET;
491 printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
495 if (ui->IsInetable())
497 packet->packetType = RAD_ACCEPT_PACKET;
501 packet->packetType = RAD_REJECT_PACKET;
504 packet->packetType = RAD_ACCEPT_PACKET;
507 //-----------------------------------------------------------------------------
508 int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
512 if (!CanAcctService((char *)packet->service))
515 // There are no sense to check for allowed service
516 // It has allready checked at previous stage (authorization)
518 packet->packetType = RAD_ACCEPT_PACKET;
522 if (!FindUser(&ui, (char *)packet->login))
524 packet->packetType = RAD_REJECT_PACKET;
525 printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
529 // I think that only Framed-User services has sense to be accountable
530 // So we have to supply a Framed-IP
532 USER_IPS ips = ui->property.ips;
533 packet->packetType = RAD_ACCEPT_PACKET;
535 // Additional checking for Framed-User service
537 if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
538 packet->ip = ips[0].ip;
544 //-----------------------------------------------------------------------------
545 int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
549 if (!FindUser(&ui, (char *)packet->login))
551 packet->packetType = RAD_REJECT_PACKET;
552 printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
556 // At this point we have to unauthorize user only if it is an accountable service
558 if (CanAcctService((char *)packet->service))
560 if (sessions.find((const char *)packet->sessid) != sessions.end())
562 printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
563 packet->packetType = RAD_REJECT_PACKET;
566 USER_IPS ips = ui->property.ips;
567 if (ui->Authorize(ips[0].ip, "", 0xffFFffFF, this))
569 printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
570 packet->packetType = RAD_REJECT_PACKET;
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());
579 printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
582 packet->packetType = RAD_ACCEPT_PACKET;
585 //-----------------------------------------------------------------------------
586 int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
588 map<string, RAD_SESSION>::iterator sid;
590 if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
592 printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
593 packet->packetType = RAD_REJECT_PACKET;
599 if (!FindUser(&ui, sid->second.userName))
601 packet->packetType = RAD_REJECT_PACKET;
602 printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
608 ui->Unauthorize(this);
610 packet->packetType = RAD_ACCEPT_PACKET;
613 //-----------------------------------------------------------------------------
614 int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
616 // Fake. May be use it later
617 packet->packetType = RAD_ACCEPT_PACKET;
620 //-----------------------------------------------------------------------------
621 int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
623 // Fake. May be use it later
624 packet->packetType = RAD_ACCEPT_PACKET;
627 //-----------------------------------------------------------------------------
628 void RADIUS::InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
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);
635 //-----------------------------------------------------------------------------
636 void RADIUS::Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
638 // len8 - длина в 8-ми байтовых блоках
640 memcpy(dst, src, len8 * 8);
642 for (int i = 0; i < len8; i++)
643 Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
645 //-----------------------------------------------------------------------------
646 void RADIUS::Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
648 // len8 - длина в 8-ми байтовых блоках
650 memcpy(dst, src, len8 * 8);
652 for (int i = 0; i < len8; i++)
653 Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
655 //-----------------------------------------------------------------------------
656 void RADIUS::PrintServices(const list<string> & svcs)
658 for_each(svcs.begin(), svcs.end(), Printer());
660 //-----------------------------------------------------------------------------
661 bool RADIUS::FindUser(user_iter * ui, const std::string & login) const
663 if (users->FindByName(login, ui))
669 //-----------------------------------------------------------------------------
670 bool RADIUS::CanAuthService(const std::string & svc) const
672 return find(authServices.begin(), authServices.end(), svc) != authServices.end();
674 //-----------------------------------------------------------------------------
675 bool RADIUS::CanAcctService(const std::string & svc) const
677 return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
679 //-----------------------------------------------------------------------------
680 bool RADIUS::IsAllowedService(const std::string & svc) const
682 return CanAuthService(svc) || CanAcctService(svc);
684 //-----------------------------------------------------------------------------
685 bool RADIUS::WaitPackets(int sd) const
695 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
696 if (res == -1) // Error
700 printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
705 if (res == 0) // Timeout