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 $
 
  33 #include "stg/store.h"
 
  34 #include "stg/common.h"
 
  35 #include "stg/user_conf.h"
 
  36 #include "stg/user_property.h"
 
  37 #include "stg/plugin_creator.h"
 
  40 extern volatile time_t stgTime;
 
  42 //-----------------------------------------------------------------------------
 
  43 //-----------------------------------------------------------------------------
 
  44 //-----------------------------------------------------------------------------
 
  47 PLUGIN_CREATOR<RADIUS> radc;
 
  49 void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password);
 
  50 void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8);
 
  51 void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8);
 
  53 extern "C" PLUGIN * GetPlugin();
 
  54 //-----------------------------------------------------------------------------
 
  55 //-----------------------------------------------------------------------------
 
  56 //-----------------------------------------------------------------------------
 
  59 return radc.GetPlugin();
 
  61 //-----------------------------------------------------------------------------
 
  62 //-----------------------------------------------------------------------------
 
  63 //-----------------------------------------------------------------------------
 
  64 int RAD_SETTINGS::ParseServices(const std::vector<std::string> & str, std::list<std::string> * lst)
 
  66 std::copy(str.begin(), str.end(), std::back_inserter(*lst));
 
  67 std::list<std::string>::iterator it(std::find(lst->begin(),
 
  75 //-----------------------------------------------------------------------------
 
  76 int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
 
  80 std::vector<PARAM_VALUE>::const_iterator pvi;
 
  81 ///////////////////////////
 
  83 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
  84 if (pvi == s.moduleParams.end())
 
  86     errorStr = "Parameter \'Port\' not found.";
 
  87     printfd(__FILE__, "Parameter 'Port' not found\n");
 
  90 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
 
  92     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
 
  93     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
 
  96 port = static_cast<uint16_t>(p);
 
  97 ///////////////////////////
 
  98 pv.param = "Password";
 
  99 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 100 if (pvi == s.moduleParams.end())
 
 102     errorStr = "Parameter \'Password\' not found.";
 
 103     printfd(__FILE__, "Parameter 'Password' not found\n");
 
 106 password = pvi->value[0];
 
 107 ///////////////////////////
 
 108 pv.param = "AuthServices";
 
 109 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 110 if (pvi != s.moduleParams.end())
 
 112     ParseServices(pvi->value, &authServices);
 
 114 ///////////////////////////
 
 115 pv.param = "AcctServices";
 
 116 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 117 if (pvi != s.moduleParams.end())
 
 119     ParseServices(pvi->value, &acctServices);
 
 124 //-----------------------------------------------------------------------------
 
 125 //-----------------------------------------------------------------------------
 
 126 //-----------------------------------------------------------------------------
 
 144       logger(GetPluginLogger(GetStgLogger(), "radius"))
 
 146 InitEncrypt(&ctx, "");
 
 148 //-----------------------------------------------------------------------------
 
 149 int RADIUS::ParseSettings()
 
 151 int ret = radSettings.ParseSettings(settings);
 
 153     errorStr = radSettings.GetStrError();
 
 156 //-----------------------------------------------------------------------------
 
 157 int RADIUS::PrepareNet()
 
 159 sock = socket(AF_INET, SOCK_DGRAM, 0);
 
 163     errorStr = "Cannot create socket.";
 
 164     logger("Cannot create a socket: %s", strerror(errno));
 
 165     printfd(__FILE__, "Cannot create socket\n");
 
 169 struct sockaddr_in inAddr;
 
 170 inAddr.sin_family = AF_INET;
 
 171 inAddr.sin_port = htons(radSettings.GetPort());
 
 172 inAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
 
 174 if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
 
 176     errorStr = "RADIUS: Bind failed.";
 
 177     logger("Cannot bind the socket: %s", strerror(errno));
 
 178     printfd(__FILE__, "Cannot bind socket\n");
 
 184 //-----------------------------------------------------------------------------
 
 185 int RADIUS::FinalizeNet()
 
 190 //-----------------------------------------------------------------------------
 
 193 std::string password(radSettings.GetPassword());
 
 195 authServices = radSettings.GetAuthServices();
 
 196 acctServices = radSettings.GetAcctServices();
 
 198 InitEncrypt(&ctx, password);
 
 209     if (pthread_create(&thread, NULL, Run, this))
 
 211         errorStr = "Cannot create thread.";
 
 212         logger("Cannot create thread.");
 
 213         printfd(__FILE__, "Cannot create thread\n");
 
 221 //-----------------------------------------------------------------------------
 
 229 std::map<std::string, RAD_SESSION>::iterator it;
 
 230 for (it = sessions.begin(); it != sessions.end(); ++it)
 
 233     if (users->FindByName(it->second.userName, &ui))
 
 235         users->Unauthorize(ui->GetLogin(), this);
 
 238 sessions.erase(sessions.begin(), sessions.end());
 
 244     //5 seconds to thread stops itself
 
 245     for (int i = 0; i < 25 && isRunning; i++)
 
 247         struct timespec ts = {0, 200000000};
 
 248         nanosleep(&ts, NULL);
 
 257 //-----------------------------------------------------------------------------
 
 258 void * RADIUS::Run(void * d)
 
 261 sigfillset(&signalSet);
 
 262 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
 
 264 RADIUS * rad = (RADIUS *)d;
 
 267 rad->isRunning = true;
 
 271     if (!WaitPackets(rad->sock))
 
 275     struct sockaddr_in outerAddr;
 
 276     if (rad->RecvData(&packet, &outerAddr))
 
 278         printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
 
 282         if (rad->ProcessData(&packet))
 
 284             packet.packetType = RAD_REJECT_PACKET;
 
 286         rad->Send(packet, &outerAddr);
 
 290 rad->isRunning = false;
 
 294 //-----------------------------------------------------------------------------
 
 295 int RADIUS::RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr)
 
 297     int8_t buf[RAD_MAX_PACKET_LEN];
 
 298     socklen_t outerAddrLen = sizeof(struct sockaddr_in);
 
 299     ssize_t dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast<struct sockaddr *>(outerAddr), &outerAddrLen);
 
 302         logger("recvfrom error: %s", strerror(errno));
 
 308     Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
 
 310     if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
 
 312         printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
 
 318 //-----------------------------------------------------------------------------
 
 319 ssize_t RADIUS::Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr)
 
 321 size_t len = sizeof(RAD_PACKET);
 
 324 Encrypt(&ctx, buf, (char *)&packet, len / 8);
 
 325 ssize_t res = sendto(sock, buf, len, 0, reinterpret_cast<struct sockaddr *>(outerAddr), sizeof(struct sockaddr_in));
 
 327     logger("sendto error: %s", strerror(errno));
 
 330 //-----------------------------------------------------------------------------
 
 331 int RADIUS::ProcessData(RAD_PACKET * packet)
 
 333 if (strncmp((const char *)packet->protoVer, "01", 2))
 
 335     printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
 
 338 switch (packet->packetType)
 
 340     case RAD_AUTZ_PACKET:
 
 341         return ProcessAutzPacket(packet);
 
 342     case RAD_AUTH_PACKET:
 
 343         return ProcessAuthPacket(packet);
 
 344     case RAD_POST_AUTH_PACKET:
 
 345         return ProcessPostAuthPacket(packet);
 
 346     case RAD_ACCT_START_PACKET:
 
 347         return ProcessAcctStartPacket(packet);
 
 348     case RAD_ACCT_STOP_PACKET:
 
 349         return ProcessAcctStopPacket(packet);
 
 350     case RAD_ACCT_UPDATE_PACKET:
 
 351         return ProcessAcctUpdatePacket(packet);
 
 352     case RAD_ACCT_OTHER_PACKET:
 
 353         return ProcessAcctOtherPacket(packet);
 
 355         printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
 
 359 //-----------------------------------------------------------------------------
 
 360 int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
 
 364 if (!IsAllowedService((char *)packet->service))
 
 366     printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
 
 367     packet->packetType = RAD_REJECT_PACKET;
 
 371 if (store->RestoreUserConf(&conf, (char *)packet->login))
 
 373     packet->packetType = RAD_REJECT_PACKET;
 
 374     printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
 
 378 // At this point service can be authorized at least
 
 379 // So we send a plain-text password
 
 381 packet->packetType = RAD_ACCEPT_PACKET;
 
 382 strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
 
 386 //-----------------------------------------------------------------------------
 
 387 int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
 
 391 if (!CanAcctService((char *)packet->service))
 
 394     // There are no sense to check for allowed service
 
 395     // It has allready checked at previous stage (authorization)
 
 397     printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
 
 398     packet->packetType = RAD_ACCEPT_PACKET;
 
 402 // At this point we have an accountable service
 
 403 // All other services got a password if allowed or rejected
 
 405 if (!FindUser(&ui, (char *)packet->login))
 
 407     packet->packetType = RAD_REJECT_PACKET;
 
 408     printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
 
 412 if (ui->IsInetable())
 
 414     packet->packetType = RAD_ACCEPT_PACKET;
 
 418     packet->packetType = RAD_REJECT_PACKET;
 
 421 packet->packetType = RAD_ACCEPT_PACKET;
 
 424 //-----------------------------------------------------------------------------
 
 425 int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
 
 429 if (!CanAcctService((char *)packet->service))
 
 432     // There are no sense to check for allowed service
 
 433     // It has allready checked at previous stage (authorization)
 
 435     packet->packetType = RAD_ACCEPT_PACKET;
 
 439 if (!FindUser(&ui, (char *)packet->login))
 
 441     packet->packetType = RAD_REJECT_PACKET;
 
 442     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
 
 446 // I think that only Framed-User services has sense to be accountable
 
 447 // So we have to supply a Framed-IP
 
 449 USER_IPS ips = ui->GetProperty().ips;
 
 450 packet->packetType = RAD_ACCEPT_PACKET;
 
 452 // Additional checking for Framed-User service
 
 454 if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
 
 455     packet->ip = ips[0].ip;
 
 461 //-----------------------------------------------------------------------------
 
 462 int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
 
 466 if (!FindUser(&ui, (char *)packet->login))
 
 468     packet->packetType = RAD_REJECT_PACKET;
 
 469     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
 
 473 // At this point we have to unauthorize user only if it is an accountable service
 
 475 if (CanAcctService((char *)packet->service))
 
 477     if (sessions.find((const char *)packet->sessid) != sessions.end())
 
 479         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
 
 480         packet->packetType = RAD_REJECT_PACKET;
 
 483     USER_IPS ips = ui->GetProperty().ips;
 
 484     if (!users->Authorize(ui->GetLogin(), ips[0].ip, 0xffFFffFF, this))
 
 486         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
 
 487         packet->packetType = RAD_REJECT_PACKET;
 
 490     sessions[(const char *)packet->sessid].userName = (const char *)packet->login;
 
 491     sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service;
 
 492     for_each(sessions.begin(), sessions.end(), SPrinter());
 
 496     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
 
 499 packet->packetType = RAD_ACCEPT_PACKET;
 
 502 //-----------------------------------------------------------------------------
 
 503 int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
 
 505 std::map<std::string, RAD_SESSION>::iterator sid;
 
 507 if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
 
 509     printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
 
 510     packet->packetType = RAD_REJECT_PACKET;
 
 516 if (!FindUser(&ui, sid->second.userName))
 
 518     packet->packetType = RAD_REJECT_PACKET;
 
 519     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
 
 525 users->Unauthorize(ui->GetLogin(), this);
 
 527 packet->packetType = RAD_ACCEPT_PACKET;
 
 530 //-----------------------------------------------------------------------------
 
 531 int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
 
 533 // Fake. May be use it later
 
 534 packet->packetType = RAD_ACCEPT_PACKET;
 
 537 //-----------------------------------------------------------------------------
 
 538 int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
 
 540 // Fake. May be use it later
 
 541 packet->packetType = RAD_ACCEPT_PACKET;
 
 544 //-----------------------------------------------------------------------------
 
 545 void RADIUS::PrintServices(const std::list<std::string> & svcs)
 
 547 for_each(svcs.begin(), svcs.end(), Printer());
 
 549 //-----------------------------------------------------------------------------
 
 550 bool RADIUS::FindUser(USER_PTR * ui, const std::string & login) const
 
 552 if (users->FindByName(login, ui))
 
 558 //-----------------------------------------------------------------------------
 
 559 bool RADIUS::CanAuthService(const std::string & svc) const
 
 561 return find(authServices.begin(), authServices.end(), svc) != authServices.end();
 
 563 //-----------------------------------------------------------------------------
 
 564 bool RADIUS::CanAcctService(const std::string & svc) const
 
 566 return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
 
 568 //-----------------------------------------------------------------------------
 
 569 bool RADIUS::IsAllowedService(const std::string & svc) const
 
 571 return CanAuthService(svc) || CanAcctService(svc);
 
 573 //-----------------------------------------------------------------------------
 
 578 void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password)
 
 580 unsigned char keyL[RAD_PASSWORD_LEN];  // Пароль для шифровки
 
 581 memset(keyL, 0, RAD_PASSWORD_LEN);
 
 582 strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
 
 583 Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
 
 585 //-----------------------------------------------------------------------------
 
 587 void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8)
 
 589 // len8 - длина в 8-ми байтовых блоках
 
 591     memcpy(dst, src, len8 * 8);
 
 593 for (size_t i = 0; i < len8; i++)
 
 594     Blowfish_Encrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
 
 596 //-----------------------------------------------------------------------------
 
 598 void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8)
 
 600 // len8 - длина в 8-ми байтовых блоках
 
 602     memcpy(dst, src, len8 * 8);
 
 604 for (size_t i = 0; i < len8; i++)
 
 605     Blowfish_Decrypt(ctx, static_cast<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
 
 608 } // namespace anonymous