X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/9ff5d2bf8c72ad82b68761b920475ac8175791c6..a8690e044055da20e4cf7d7d7e51d182b5e09154:/projects/rlm_stg/stg_client.cpp diff --git a/projects/rlm_stg/stg_client.cpp b/projects/rlm_stg/stg_client.cpp index 834f19c4..199aca90 100644 --- a/projects/rlm_stg/stg_client.cpp +++ b/projects/rlm_stg/stg_client.cpp @@ -18,277 +18,146 @@ * Author : Maxim Mamontov */ -/* - * Realization of data access via Stargazer for RADIUS - * - * $Revision: 1.8 $ - * $Date: 2010/04/16 12:30:02 $ - * - */ - -#include -#include -#include // close - -#include -#include - -#include - #include "stg_client.h" -using namespace std; +#include "stg/common.h" -void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password); -void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8); -void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8); - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -STG_CLIENT::STG_CLIENT(const std::string & host, uint16_t port, uint16_t lp, const std::string & pass) - : localPort(lp), - password(pass), - framedIP(0) -{ -sock = socket(AF_INET, SOCK_DGRAM, 0); -if (sock == -1) - { - std::string message = strerror(errno); - message = "Socket create error: '" + message + "'"; - throw std::runtime_error(message); - } - -struct hostent * he = NULL; -he = gethostbyname(host.c_str()); -if (he == NULL) - { - throw std::runtime_error("gethostbyname error"); - } +#include -outerAddr.sin_family = AF_INET; -outerAddr.sin_port = htons(port); -outerAddr.sin_addr.s_addr = *(uint32_t *)he->h_addr; +namespace { -InitEncrypt(&ctx, password); +STG_CLIENT* stgClient = NULL; -PrepareNet(); -} -//----------------------------------------------------------------------------- -STG_CLIENT::~STG_CLIENT() -{ -close(sock); -} -//----------------------------------------------------------------------------- -uint32_t STG_CLIENT::GetFramedIP() const +unsigned fromType(STG_CLIENT::TYPE type) { -return framedIP; + return static_cast(type); } -//----------------------------------------------------------------------------- -int STG_CLIENT::PrepareNet() -{ -if (localPort != 0) - { - struct sockaddr_in localAddr; - localAddr.sin_family = AF_INET; - localAddr.sin_port = htons(localPort); - localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");; - if (bind(sock, (struct sockaddr *)&localAddr, sizeof(localAddr))) - { - errorStr = "Bind failed"; - return -1; - } - } -return 0; -} -//----------------------------------------------------------------------------- -string STG_CLIENT::GetUserPassword() const +STG::SGCP::TransportType toTransport(const std::string& value) { -return userPassword; + std::string type = ToLower(value); + if (type == "unix") return STG::SGCP::UNIX; + else if (type == "udp") return STG::SGCP::UDP; + else if (type == "tcp") return STG::SGCP::TCP; + throw ChannelConfig::Error("Invalid transport type. Should be 'unix', 'udp' or 'tcp'."); } -//----------------------------------------------------------------------------- -int STG_CLIENT::Send(const RAD_PACKET & packet) -{ -char buf[RAD_MAX_PACKET_LEN]; - -Encrypt(&ctx, buf, (char *)&packet, sizeof(RAD_PACKET) / 8); - -int res = sendto(sock, buf, sizeof(RAD_PACKET), 0, (struct sockaddr *)&outerAddr, sizeof(outerAddr)); - -if (res == -1) - errorStr = "Error sending data"; -return res; } -//----------------------------------------------------------------------------- -int STG_CLIENT::RecvData(RAD_PACKET * packet) -{ -char buf[RAD_MAX_PACKET_LEN]; -int res; - -struct sockaddr_in addr; -socklen_t len = sizeof(struct sockaddr_in); -res = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast(&addr), &len); -if (res == -1) +ChannelConfig::ChannelConfig(std::string addr) + : transport(STG::SGCP::TCP) +{ + // unix:pass@/var/run/stg.sock + // tcp:secret@192.168.0.1:12345 + // udp:key@isp.com.ua:54321 + + size_t pos = addr.find_first_of(':'); + if (pos == std::string::npos) + throw Error("Missing transport name."); + transport = toTransport(addr.substr(0, pos)); + addr = addr.substr(pos + 1); + if (addr.empty()) + throw Error("Missing address to connect to."); + pos = addr.find_first_of('@'); + if (pos != std::string::npos) { + key = addr.substr(0, pos); + addr = addr.substr(pos + 1); + if (addr.empty()) + throw Error("Missing address to connect to."); + } + if (transport == STG::SGCP::UNIX) { - errorStr = "Error receiving data"; - return -1; + address = addr; + return; } - -Decrypt(&ctx, (char *)packet, buf, res / 8); - -return 0; + pos = addr.find_first_of(':'); + if (pos == std::string::npos) + throw Error("Missing port."); + address = addr.substr(0, pos); + if (str2x(addr.substr(pos + 1), port)) + throw Error("Invalid port value."); } -//----------------------------------------------------------------------------- -int STG_CLIENT::Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType) -{ -int res; -memcpy((void *)&packet->magic, (void *)RAD_ID, RAD_MAGIC_LEN); -packet->protoVer[0] = '0'; -packet->protoVer[1] = '1'; -packet->packetType = packetType; -packet->ip = 0; -strncpy((char *)packet->login, login.c_str(), RAD_LOGIN_LEN); -strncpy((char *)packet->service, svc.c_str(), RAD_SERVICE_LEN); - -res = Send(*packet); -if (res == -1) - return -1; - -res = RecvData(packet); -if (res == -1) - return -1; - -if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN)) - { - errorStr = "Magic invalid. Wanted: '"; - errorStr += RAD_ID; - errorStr += "', got: '"; - errorStr += (char *)packet->magic; - errorStr += "'"; - return -1; +STG_CLIENT::STG_CLIENT(const std::string& address) + : m_config(address), + m_proto(m_config.transport, m_config.key) +{ + try { + m_proto.connect(m_config.address, m_config.port); + } catch (const STG::SGCP::Proto::Error& ex) { + throw Error(ex.what()); } - -return 0; } -//----------------------------------------------------------------------------- -int STG_CLIENT::Authorize(const string & login, const string & svc) -{ -RAD_PACKET packet; - -userPassword = ""; - -if (Request(&packet, login, svc, RAD_AUTZ_PACKET)) - return -1; - -if (packet.packetType != RAD_ACCEPT_PACKET) - return -1; -userPassword = (char *)packet.password; - -return 0; -} -//----------------------------------------------------------------------------- -int STG_CLIENT::Authenticate(const string & login, const string & svc) +STG_CLIENT::~STG_CLIENT() { -RAD_PACKET packet; - -userPassword = ""; - -if (Request(&packet, login, svc, RAD_AUTH_PACKET)) - return -1; - -if (packet.packetType != RAD_ACCEPT_PACKET) - return -1; - -return 0; } -//----------------------------------------------------------------------------- -int STG_CLIENT::PostAuthenticate(const string & login, const string & svc) -{ -RAD_PACKET packet; - -userPassword = ""; - -if (Request(&packet, login, svc, RAD_POST_AUTH_PACKET)) - return -1; -if (packet.packetType != RAD_ACCEPT_PACKET) - return -1; - -if (svc == "Framed-User") - framedIP = packet.ip; -else - framedIP = 0; - -return 0; -} -//----------------------------------------------------------------------------- -int STG_CLIENT::Account(const std::string & type, const string & login, const string & svc, const string & sessid) +RESULT STG_CLIENT::request(TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) { -RAD_PACKET packet; + m_writeHeader(type, userName, password); + m_writePairBlock(pairs); + RESULT result; + result.modify = m_readPairBlock(); + result.reply = m_readPairBlock(); + return result; +} -userPassword = ""; -strncpy((char *)packet.sessid, sessid.c_str(), RAD_SESSID_LEN); +STG_CLIENT* STG_CLIENT::get() +{ + return stgClient; +} -if (type == "Start") - { - if (Request(&packet, login, svc, RAD_ACCT_START_PACKET)) - return -1; - } -else if (type == "Stop") - { - if (Request(&packet, login, svc, RAD_ACCT_STOP_PACKET)) - return -1; - } -else if (type == "Interim-Update") - { - if (Request(&packet, login, svc, RAD_ACCT_UPDATE_PACKET)) - return -1; - } -else - { - if (Request(&packet, login, svc, RAD_ACCT_OTHER_PACKET)) - return -1; +bool STG_CLIENT::configure(const std::string& address) +{ + if ( stgClient != NULL ) + delete stgClient; + try { + stgClient = new STG_CLIENT(address); + return true; + } catch (const ChannelConfig::Error& ex) { + // TODO: Log it } - -if (packet.packetType != RAD_ACCEPT_PACKET) - return -1; - -return 0; + return false; } -//----------------------------------------------------------------------------- -inline -void Encrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8) + +void STG_CLIENT::m_writeHeader(TYPE type, const std::string& userName, const std::string& password) { -// len8 - длина в 8-ми байтовых блоках -if (dst != src) - memcpy(dst, src, len8 * 8); - -for (int i = 0; i < len8; i++) - Blowfish_Encrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4)); + try { + m_proto.writeAll(fromType(type)); + m_proto.writeAll(userName); + m_proto.writeAll(password); + } catch (const STG::SGCP::Proto::Error& ex) { + throw Error(ex.what()); + } } -//----------------------------------------------------------------------------- -inline -void Decrypt(BLOWFISH_CTX * ctx, char * dst, const char * src, int len8) -{ -// len8 - длина в 8-ми байтовых блоках -if (dst != src) - memcpy(dst, src, len8 * 8); -for (int i = 0; i < len8; i++) - Blowfish_Decrypt(ctx, (uint32_t *)(dst + i*8), (uint32_t *)(dst + i*8 + 4)); +void STG_CLIENT::m_writePairBlock(const PAIRS& pairs) +{ + try { + m_proto.writeAll(pairs.size()); + for (size_t i = 0; i < pairs.size(); ++i) { + m_proto.writeAll(pairs[i].first); + m_proto.writeAll(pairs[i].second); + } + } catch (const STG::SGCP::Proto::Error& ex) { + throw Error(ex.what()); + } } -//----------------------------------------------------------------------------- -inline -void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) + +PAIRS STG_CLIENT::m_readPairBlock() { -unsigned char keyL[RAD_PASSWORD_LEN]; -memset(keyL, 0, RAD_PASSWORD_LEN); -strncpy((char *)keyL, password.c_str(), RAD_PASSWORD_LEN); -Blowfish_Init(ctx, keyL, RAD_PASSWORD_LEN); + try { + size_t count = m_proto.readAll(); + if (count == 0) + return PAIRS(); + PAIRS res(count); + for (size_t i = 0; i < count; ++i) { + res[i].first = m_proto.readAll(); + res[i].second = m_proto.readAll(); + } + return res; + } catch (const STG::SGCP::Proto::Error& ex) { + throw Error(ex.what()); + } } -//-----------------------------------------------------------------------------