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 $
 
  36 extern volatile const time_t stgTime;
 
  38 void InitEncrypt(BLOWFISH_CTX * ctx, const string & password);
 
  39 void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
 
  40 void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8);
 
  42 //-----------------------------------------------------------------------------
 
  43 //-----------------------------------------------------------------------------
 
  44 //-----------------------------------------------------------------------------
 
  65 //-----------------------------------------------------------------------------
 
  66 //-----------------------------------------------------------------------------
 
  67 //-----------------------------------------------------------------------------
 
  69 //-----------------------------------------------------------------------------
 
  70 //-----------------------------------------------------------------------------
 
  71 //-----------------------------------------------------------------------------
 
  72 BASE_PLUGIN * GetPlugin()
 
  74 return radc.GetPlugin();
 
  76 //-----------------------------------------------------------------------------
 
  77 //-----------------------------------------------------------------------------
 
  78 //-----------------------------------------------------------------------------
 
  79 int RAD_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
 
  81 if (str2x(str.c_str(), *val))
 
  83     errorStr = "Incorrect value \'" + str + "\'.";
 
  86 if (*val < min || *val > max)
 
  88     errorStr = "Value \'" + str + "\' out of range.";
 
  93 //-----------------------------------------------------------------------------
 
  94 int RAD_SETTINGS::ParseServices(const vector<string> & str, list<string> * lst)
 
  96     copy(str.begin(), str.end(), back_inserter(*lst));
 
  97     list<string>::iterator it(find(lst->begin(),
 
 100     if (it != lst->end())
 
 105 //-----------------------------------------------------------------------------
 
 106 int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
 
 110 vector<PARAM_VALUE>::const_iterator pvi;
 
 111 ///////////////////////////
 
 113 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 114 if (pvi == s.moduleParams.end())
 
 116     errorStr = "Parameter \'Port\' not found.";
 
 117     printfd(__FILE__, "Parameter 'Port' not found\n");
 
 120 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
 
 122     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
 
 123     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
 
 127 ///////////////////////////
 
 128 pv.param = "Password";
 
 129 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 130 if (pvi == s.moduleParams.end())
 
 132     errorStr = "Parameter \'Password\' not found.";
 
 133     printfd(__FILE__, "Parameter 'Password' not found\n");
 
 136 password = pvi->value[0];
 
 137 ///////////////////////////
 
 138 pv.param = "AuthServices";
 
 139 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 140 if (pvi != s.moduleParams.end())
 
 142     ParseServices(pvi->value, &authServices);
 
 144 ///////////////////////////
 
 145 pv.param = "AcctServices";
 
 146 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
 
 147 if (pvi != s.moduleParams.end())
 
 149     ParseServices(pvi->value, &acctServices);
 
 154 //-----------------------------------------------------------------------------
 
 155 //-----------------------------------------------------------------------------
 
 156 //-----------------------------------------------------------------------------
 
 165 InitEncrypt(&ctx, "");
 
 167 //-----------------------------------------------------------------------------
 
 168 void RADIUS::SetUsers(USERS * u)
 
 172 //-----------------------------------------------------------------------------
 
 173 void RADIUS::SetStgSettings(const SETTINGS * s)
 
 177 //-----------------------------------------------------------------------------
 
 178 void RADIUS::SetSettings(const MODULE_SETTINGS & s)
 
 182 //-----------------------------------------------------------------------------
 
 183 void RADIUS::SetStore(BASE_STORE * s)
 
 187 //-----------------------------------------------------------------------------
 
 188 int RADIUS::ParseSettings()
 
 190 int ret = radSettings.ParseSettings(settings);
 
 192     errorStr = radSettings.GetStrError();
 
 195 //-----------------------------------------------------------------------------
 
 196 bool RADIUS::IsRunning()
 
 200 //-----------------------------------------------------------------------------
 
 201 const string RADIUS::GetVersion() const
 
 203 return "RADIUS data access plugin v 0.6";
 
 205 //-----------------------------------------------------------------------------
 
 206 uint16_t RADIUS::GetStartPosition() const
 
 208 // Start before any authorizers!!!
 
 211 //-----------------------------------------------------------------------------
 
 212 uint16_t RADIUS::GetStopPosition() const
 
 216 //-----------------------------------------------------------------------------
 
 217 int RADIUS::PrepareNet()
 
 219 sock = socket(AF_INET, SOCK_DGRAM, 0);
 
 223     errorStr = "Cannot create socket.";
 
 224     printfd(__FILE__, "Cannot create socket\n");
 
 228 struct sockaddr_in inAddr;
 
 229 inAddr.sin_family = AF_INET;
 
 230 inAddr.sin_port = htons(radSettings.GetPort());
 
 231 inAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
 
 233 if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0)
 
 235     errorStr = "RADIUS: Bind failed.";
 
 236     printfd(__FILE__, "Cannot bind socket\n");
 
 242 //-----------------------------------------------------------------------------
 
 243 int RADIUS::FinalizeNet()
 
 248 //-----------------------------------------------------------------------------
 
 251 string password(radSettings.GetPassword());
 
 253 authServices = radSettings.GetAuthServices();
 
 254 acctServices = radSettings.GetAcctServices();
 
 256 InitEncrypt(&ctx, password);
 
 267     if (pthread_create(&thread, NULL, Run, this))
 
 269         errorStr = "Cannot create thread.";
 
 270         printfd(__FILE__, "Cannot create thread\n");
 
 278 //-----------------------------------------------------------------------------
 
 286 map<string, RAD_SESSION>::iterator it;
 
 287 for (it = sessions.begin(); it != sessions.end(); ++it)
 
 290     if (users->FindByName(it->second.userName, &ui))
 
 292         ui->Unauthorize(this);
 
 295 sessions.erase(sessions.begin(), sessions.end());
 
 301     //5 seconds to thread stops itself
 
 302     for (int i = 0; i < 25 && isRunning; i++)
 
 307     //after 5 seconds waiting thread still running. now killing it
 
 310         if (pthread_kill(thread, SIGINT))
 
 312             errorStr = "Cannot kill thread.";
 
 313             printfd(__FILE__, "Cannot kill thread\n");
 
 316         printfd(__FILE__, "RADIUS::Stop killed Run\n");
 
 322 //-----------------------------------------------------------------------------
 
 323 void * RADIUS::Run(void * d)
 
 325 RADIUS * rad = (RADIUS *)d;
 
 328 rad->isRunning = true;
 
 332     if (!rad->WaitPackets(rad->sock))
 
 336     struct sockaddr_in outerAddr;
 
 337     if (rad->RecvData(&packet, &outerAddr))
 
 339         printfd(__FILE__, "RADIUS::Run Error on RecvData\n");
 
 343         if (rad->ProcessData(&packet))
 
 345             packet.packetType = RAD_REJECT_PACKET;
 
 347         rad->Send(packet, &outerAddr);
 
 351 rad->isRunning = false;
 
 355 //-----------------------------------------------------------------------------
 
 356 int RADIUS::RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr)
 
 358     int8_t buf[RAD_MAX_PACKET_LEN];
 
 359     socklen_t outerAddrLen = sizeof(struct sockaddr_in);
 
 360     int dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast<struct sockaddr *>(outerAddr), &outerAddrLen);
 
 362         Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8);
 
 364     if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN))
 
 366         printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic);
 
 371 //-----------------------------------------------------------------------------
 
 372 int RADIUS::Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr)
 
 374 size_t len = sizeof(RAD_PACKET);
 
 377 Encrypt(&ctx, buf, (char *)&packet, len / 8);
 
 378 return sendto(sock, buf, len, 0, reinterpret_cast<struct sockaddr *>(outerAddr), sizeof(struct sockaddr_in));
 
 380 //-----------------------------------------------------------------------------
 
 381 int RADIUS::ProcessData(RAD_PACKET * packet)
 
 383 if (strncmp((const char *)packet->protoVer, "01", 2))
 
 385     printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n");
 
 388 switch (packet->packetType)
 
 390     case RAD_AUTZ_PACKET:
 
 391         return ProcessAutzPacket(packet);
 
 392     case RAD_AUTH_PACKET:
 
 393         return ProcessAuthPacket(packet);
 
 394     case RAD_POST_AUTH_PACKET:
 
 395         return ProcessPostAuthPacket(packet);
 
 396     case RAD_ACCT_START_PACKET:
 
 397         return ProcessAcctStartPacket(packet);
 
 398     case RAD_ACCT_STOP_PACKET:
 
 399         return ProcessAcctStopPacket(packet);
 
 400     case RAD_ACCT_UPDATE_PACKET:
 
 401         return ProcessAcctUpdatePacket(packet);
 
 402     case RAD_ACCT_OTHER_PACKET:
 
 403         return ProcessAcctOtherPacket(packet);
 
 405         printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType);
 
 410 //-----------------------------------------------------------------------------
 
 411 int RADIUS::ProcessAutzPacket(RAD_PACKET * packet)
 
 415 if (!IsAllowedService((char *)packet->service))
 
 417     printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service);
 
 418     packet->packetType = RAD_REJECT_PACKET;
 
 422 if (store->RestoreUserConf(&conf, (char *)packet->login))
 
 424     packet->packetType = RAD_REJECT_PACKET;
 
 425     printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login);
 
 429 // At this point service can be authorized at least
 
 430 // So we send a plain-text password
 
 432 packet->packetType = RAD_ACCEPT_PACKET;
 
 433 strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN);
 
 437 //-----------------------------------------------------------------------------
 
 438 int RADIUS::ProcessAuthPacket(RAD_PACKET * packet)
 
 442 if (!CanAcctService((char *)packet->service))
 
 445     // There are no sense to check for allowed service
 
 446     // It has allready checked at previous stage (authorization)
 
 448     printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service);
 
 449     packet->packetType = RAD_ACCEPT_PACKET;
 
 453 // At this point we have an accountable service
 
 454 // All other services got a password if allowed or rejected
 
 456 if (!FindUser(&ui, (char *)packet->login))
 
 458     packet->packetType = RAD_REJECT_PACKET;
 
 459     printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login);
 
 463 if (ui->IsInetable())
 
 465     packet->packetType = RAD_ACCEPT_PACKET;
 
 469     packet->packetType = RAD_REJECT_PACKET;
 
 472 packet->packetType = RAD_ACCEPT_PACKET;
 
 475 //-----------------------------------------------------------------------------
 
 476 int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet)
 
 480 if (!CanAcctService((char *)packet->service))
 
 483     // There are no sense to check for allowed service
 
 484     // It has allready checked at previous stage (authorization)
 
 486     packet->packetType = RAD_ACCEPT_PACKET;
 
 490 if (!FindUser(&ui, (char *)packet->login))
 
 492     packet->packetType = RAD_REJECT_PACKET;
 
 493     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login);
 
 497 // I think that only Framed-User services has sense to be accountable
 
 498 // So we have to supply a Framed-IP
 
 500 USER_IPS ips = ui->property.ips;
 
 501 packet->packetType = RAD_ACCEPT_PACKET;
 
 503 // Additional checking for Framed-User service
 
 505 if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN))
 
 506     packet->ip = ips[0].ip;
 
 512 //-----------------------------------------------------------------------------
 
 513 int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet)
 
 517 if (!FindUser(&ui, (char *)packet->login))
 
 519     packet->packetType = RAD_REJECT_PACKET;
 
 520     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login);
 
 524 // At this point we have to unauthorize user only if it is an accountable service
 
 526 if (CanAcctService((char *)packet->service))
 
 528     if (sessions.find((const char *)packet->sessid) != sessions.end())
 
 530         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n");
 
 531         packet->packetType = RAD_REJECT_PACKET;
 
 534     USER_IPS ips = ui->property.ips;
 
 535     if (ui->Authorize(ips[0].ip, "", 0xffFFffFF, this))
 
 537         printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login);
 
 538         packet->packetType = RAD_REJECT_PACKET;
 
 541     sessions[(const char *)packet->sessid].userName = (const char *)packet->login;
 
 542     sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service;
 
 543     for_each(sessions.begin(), sessions.end(), SPrinter());
 
 547     printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service);
 
 550 packet->packetType = RAD_ACCEPT_PACKET;
 
 553 //-----------------------------------------------------------------------------
 
 554 int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet)
 
 556 map<string, RAD_SESSION>::iterator sid;
 
 558 if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end())
 
 560     printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n");
 
 561     packet->packetType = RAD_REJECT_PACKET;
 
 567 if (!FindUser(&ui, sid->second.userName))
 
 569     packet->packetType = RAD_REJECT_PACKET;
 
 570     printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str());
 
 576 ui->Unauthorize(this);
 
 578 packet->packetType = RAD_ACCEPT_PACKET;
 
 581 //-----------------------------------------------------------------------------
 
 582 int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet)
 
 584 // Fake. May be use it later
 
 585 packet->packetType = RAD_ACCEPT_PACKET;
 
 588 //-----------------------------------------------------------------------------
 
 589 int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet)
 
 591 // Fake. May be use it later
 
 592 packet->packetType = RAD_ACCEPT_PACKET;
 
 595 //-----------------------------------------------------------------------------
 
 596 void RADIUS::PrintServices(const list<string> & svcs)
 
 598     for_each(svcs.begin(), svcs.end(), Printer());
 
 600 //-----------------------------------------------------------------------------
 
 601 bool RADIUS::FindUser(user_iter * ui, const std::string & login) const
 
 603 if (users->FindByName(login, ui))
 
 609 //-----------------------------------------------------------------------------
 
 610 bool RADIUS::CanAuthService(const std::string & svc) const
 
 612     return find(authServices.begin(), authServices.end(), svc) != authServices.end();
 
 614 //-----------------------------------------------------------------------------
 
 615 bool RADIUS::CanAcctService(const std::string & svc) const
 
 617     return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end();
 
 619 //-----------------------------------------------------------------------------
 
 620 bool RADIUS::IsAllowedService(const std::string & svc) const
 
 622     return CanAuthService(svc) || CanAcctService(svc);
 
 624 //-----------------------------------------------------------------------------
 
 625 bool RADIUS::WaitPackets(int sd) const
 
 635 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
 
 636 if (res == -1) // Error
 
 640         printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
 
 645 if (res == 0) // Timeout
 
 652 //-----------------------------------------------------------------------------
 
 654 void InitEncrypt(BLOWFISH_CTX * ctx, const string & password)
 
 656 unsigned char keyL[RAD_PASSWORD_LEN];  // Пароль для шифровки
 
 657 memset(keyL, 0, RAD_PASSWORD_LEN);
 
 658 strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN);
 
 659 Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN);
 
 661 //-----------------------------------------------------------------------------
 
 663 void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
 
 665 // len8 - длина в 8-ми байтовых блоках
 
 667     memcpy(dst, src, len8 * 8);
 
 669 for (int i = 0; i < len8; i++)
 
 670     Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));
 
 672 //-----------------------------------------------------------------------------
 
 674 void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8)
 
 676 // len8 - длина в 8-ми байтовых блоках
 
 678     memcpy(dst, src, len8 * 8);
 
 680 for (int i = 0; i < len8; i++)
 
 681     Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4));