From: Maxim Mamontov Date: Sat, 20 Jun 2015 09:32:23 +0000 (+0300) Subject: Merge branch 'stg-2.409' into stg-2.409-radius X-Git-Url: https://git.stg.codes/stg.git/commitdiff_plain/70f8adff2c970496bdc45717cad49ddec0405ae7?hp=1d95c81b71982af419d945a964cc657c44ef40b1 Merge branch 'stg-2.409' into stg-2.409-radius --- diff --git a/projects/rlm_stg/Makefile b/projects/rlm_stg/Makefile index 05c43d95..548232a8 100644 --- a/projects/rlm_stg/Makefile +++ b/projects/rlm_stg/Makefile @@ -13,7 +13,8 @@ SRCS = ./rlm_stg.c \ ./stg_client.cpp STGLIBS = crypto \ - common + common \ + sgcp STGLIBS_INCS = $(addprefix -I ../../stglibs/,$(addsuffix .lib/include,$(STGLIBS))) STGLIBS_LIBS = $(addprefix -L ../../stglibs/,$(addsuffix .lib,$(STGLIBS))) @@ -31,6 +32,7 @@ SEARCH_DIRS = -I ../../include OBJS = $(notdir $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS)))) +CFLAGS += -fPIC $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS) CXXFLAGS += -fPIC $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS) CFLAGS += $(DEFS) $(STGLIBS_INCS) $(SEARCH_DIRS) LDFLAGS += -shared -Wl,-rpath,$(PREFIX)/usr/lib/stg -Wl,-E $(STGLIBS_LIBS) diff --git a/projects/rlm_stg/build b/projects/rlm_stg/build index 179d5261..4894491a 100755 --- a/projects/rlm_stg/build +++ b/projects/rlm_stg/build @@ -61,7 +61,7 @@ printf "######################################################################## printf " Building rlm_stg for $sys $release\n" printf "#############################################################################\n" -STG_LIBS="crypto.lib common.lib" +STG_LIBS="crypto.lib common.lib sgcp.lib" if [ "$OS" = "linux" ] then diff --git a/projects/rlm_stg/event.h b/projects/rlm_stg/event.h deleted file mode 100644 index 83a72d01..00000000 --- a/projects/rlm_stg/event.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef FR_EVENT_H -#define FR_EVENT_H - -/* - * event.h Simple event queue - * - * Version: $Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * Copyright 2007 The FreeRADIUS server project - * Copyright 2007 Alan DeKok - */ - -//#include -//RCSIDH(event_h, "$Id: event.h,v 1.1 2010/08/14 04:13:52 faust Exp $") - -typedef struct fr_event_list_t fr_event_list_t; -typedef struct fr_event_t fr_event_t; - -typedef void (*fr_event_callback_t)(void *); -typedef void (*fr_event_status_t)(struct timeval *); -typedef void (*fr_event_fd_handler_t)(fr_event_list_t *el, int sock, void *ctx); - -fr_event_list_t *fr_event_list_create(fr_event_status_t status); -void fr_event_list_free(fr_event_list_t *el); - -int fr_event_list_num_elements(fr_event_list_t *el); - -int fr_event_insert(fr_event_list_t *el, - fr_event_callback_t callback, - void *ctx, struct timeval *when, fr_event_t **ev_p); -int fr_event_delete(fr_event_list_t *el, fr_event_t **ev_p); - -int fr_event_run(fr_event_list_t *el, struct timeval *when); - -int fr_event_now(fr_event_list_t *el, struct timeval *when); - -int fr_event_fd_insert(fr_event_list_t *el, int type, int fd, - fr_event_fd_handler_t handler, void *ctx); -int fr_event_fd_delete(fr_event_list_t *el, int type, int fd); -int fr_event_loop(fr_event_list_t *el); -void fr_event_loop_exit(fr_event_list_t *el, int code); - -#endif /* FR_HASH_H */ diff --git a/projects/rlm_stg/iface.cpp b/projects/rlm_stg/iface.cpp index a74f3259..485e9ef7 100644 --- a/projects/rlm_stg/iface.cpp +++ b/projects/rlm_stg/iface.cpp @@ -1,41 +1,111 @@ #include "iface.h" -#include "thriftclient.h" +#include "stg_client.h" -int stgInstantiateImpl(const char * server, uint16_t port, const char * password) +#include + +#include + +namespace { - if (STG_CLIENT_ST::Get().Configure(server, port, password)) - return 1; - return 0; +STG_PAIR* toSTGPairs(const PAIRS& source) +{ + STG_PAIR * pairs = new STG_PAIR[source.size() + 1]; + for (size_t pos = 0; pos < source.size(); ++pos) { + bzero(pairs[pos].key, sizeof(STG_PAIR::key)); + bzero(pairs[pos].value, sizeof(STG_PAIR::value)); + strncpy(pairs[pos].key, source[pos].first.c_str(), sizeof(STG_PAIR::key)); + strncpy(pairs[pos].value, source[pos].second.c_str(), sizeof(STG_PAIR::value)); + ++pos; + } + bzero(pairs[source.size()].key, sizeof(STG_PAIR::key)); + bzero(pairs[source.size()].value, sizeof(STG_PAIR::value)); + + return pairs; } -const STG_PAIR * stgAuthorizeImpl(const char * userName, const char * serviceType) +PAIRS fromSTGPairs(const STG_PAIR* pairs) { - return STG_CLIENT_ST::Get().Authorize(userName, serviceType); + const STG_PAIR* pair = pairs; + PAIRS res; + + while (!emptyPair(pair)) { + res.push_back(std::pair(pair->key, pair->value)); + ++pair; + } + + return res; } -const STG_PAIR * stgAuthenticateImpl(const char * userName, const char * serviceType) +STG_RESULT toResult(const RESULT& source) { - return STG_CLIENT_ST::Get().Authenticate(userName, serviceType); + STG_RESULT result; + result.modify = toSTGPairs(source.modify); + result.reply = toSTGPairs(source.reply); + return result; } -const STG_PAIR * stgPostAuthImpl(const char * userName, const char * serviceType) +STG_RESULT emptyResult() { - return STG_CLIENT_ST::Get().PostAuth(userName, serviceType); + STG_RESULT result = {NULL, NULL}; + return result; } -/*const STG_PAIR * stgPreAcctImpl(const char * userName, const char * serviceType) +std::string toString(const char* value) { - return STG_CLIENT_ST::Get().PreAcct(userName, serviceType); -}*/ + if (value == NULL) + return ""; + else + return value; +} + +STG_RESULT stgRequest(STG_CLIENT::TYPE type, const char* userName, const char* password, const STG_PAIR* pairs) +{ + STG_CLIENT* client = STG_CLIENT::get(); + if (client == NULL) { + // TODO: log "Not configured" + return emptyResult(); + } + try { + return toResult(client->request(type, toString(userName), toString(password), fromSTGPairs(pairs))); + } catch (const STG_CLIENT::Error& ex) { + // TODO: log error + return emptyResult(); + } +} + +} + +int stgInstantiateImpl(const char* address) +{ + if (STG_CLIENT::configure(toString(address))) + return 1; + + return 0; +} + +STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* pairs) +{ + return stgRequest(STG_CLIENT::AUTHORIZE, userName, password, pairs); +} + +STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* pairs) +{ + return stgRequest(STG_CLIENT::AUTHENTICATE, userName, password, pairs); +} + +STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* pairs) +{ + return stgRequest(STG_CLIENT::POST_AUTH, userName, password, pairs); +} -const STG_PAIR * stgAccountingImpl(const char * userName, const char * serviceType, const char * statusType, const char * sessionId) +STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* pairs) { - return STG_CLIENT_ST::Get().Account(userName, serviceType, statusType, sessionId); + return stgRequest(STG_CLIENT::PRE_ACCT, userName, password, pairs); } -void deletePairs(const STG_PAIR * pairs) +STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* pairs) { - delete[] pairs; + return stgRequest(STG_CLIENT::ACCOUNT, userName, password, pairs); } diff --git a/projects/rlm_stg/iface.h b/projects/rlm_stg/iface.h index 831c3123..e863e939 100644 --- a/projects/rlm_stg/iface.h +++ b/projects/rlm_stg/iface.h @@ -9,14 +9,12 @@ extern "C" { #endif -int stgInstantiateImpl(const char * server, uint16_t port, const char * password); -const STG_PAIR * stgAuthorizeImpl(const char * userName, const char * serviceType); -const STG_PAIR * stgAuthenticateImpl(const char * userName, const char * serviceType); -const STG_PAIR * stgPostAuthImpl(const char * userName, const char * serviceType); -/*const STG_PAIR * stgPreAcctImpl(const char * userName, const char * serviceType);*/ -const STG_PAIR * stgAccountingImpl(const char * userName, const char * serviceType, const char * statusType, const char * sessionId); - -void deletePairs(const STG_PAIR * pairs); +int stgInstantiateImpl(const char* address); +STG_RESULT stgAuthorizeImpl(const char* userName, const char* password, const STG_PAIR* vps); +STG_RESULT stgAuthenticateImpl(const char* userName, const char* password, const STG_PAIR* vps); +STG_RESULT stgPostAuthImpl(const char* userName, const char* password, const STG_PAIR* vps); +STG_RESULT stgPreAcctImpl(const char* userName, const char* password, const STG_PAIR* vps); +STG_RESULT stgAccountingImpl(const char* userName, const char* password, const STG_PAIR* vps); #ifdef __cplusplus } diff --git a/projects/rlm_stg/rlm_stg.c b/projects/rlm_stg/rlm_stg.c index e1caf575..0333fadc 100644 --- a/projects/rlm_stg/rlm_stg.c +++ b/projects/rlm_stg/rlm_stg.c @@ -26,6 +26,9 @@ * */ +#include "iface.h" +#include "stgpair.h" + #ifndef NDEBUG #define NDEBUG #include @@ -34,24 +37,79 @@ #undef NDEBUG #endif -#include "stgpair.h" -#include "iface.h" +#include // size_t typedef struct rlm_stg_t { - char * server; - uint16_t port; - char * password; + char* address; } rlm_stg_t; static const CONF_PARSER module_config[] = { - { "server", PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,server), NULL, "localhost"}, - { "port", PW_TYPE_INTEGER, offsetof(rlm_stg_t,port), NULL, "9091" }, - { "password", PW_TYPE_STRING_PTR, offsetof(rlm_stg_t,password), NULL, "123456"}, + { "address", PW_TYPE_STRING_PTR, offsetof(rlm_stg_t, address), NULL, "unix:/var/run/stg.sock"}, { NULL, -1, 0, NULL, NULL } /* end the list */ }; -int emptyPair(const STG_PAIR * pair); +static void deletePairs(STG_PAIR* pairs) +{ + free(pairs); +} + +static size_t toVPS(const STG_PAIR* pairs, VALUE_PAIR* vps) +{ + const STG_PAIR* pair = pairs; + size_t count = 0; + + while (!emptyPair(pair)) { + VALUE_PAIR* vp = pairmake(pair->key, pair->value, T_OP_SET); + pairadd(&vps, vp); + DEBUG("Adding pair '%s': '%s'", pair->key, pair->value); + ++pair; + ++count; + } + + return count; +} + +static size_t toReply(STG_RESULT result, REQUEST* request) +{ + size_t count = 0; + + count += toVPS(result.modify, request->config_items); + count += toVPS(result.reply, request->reply->vps); + + deletePairs(result.modify); + deletePairs(result.reply); + + return count; +} + +static int countVPS(const VALUE_PAIR* pairs) +{ + unsigned count = 0; + while (pairs != NULL) { + ++count; + pairs = pairs->next; + } + return count; +} + +static STG_PAIR* fromVPS(const VALUE_PAIR* pairs) +{ + unsigned size = countVPS(pairs); + STG_PAIR* res = (STG_PAIR*)malloc(sizeof(STG_PAIR) * (size + 1)); + size_t pos = 0; + while (pairs != NULL) { + bzero(res[pos].key, sizeof(res[0].key)); + bzero(res[pos].value, sizeof(res[0].value)); + strncpy(res[pos].key, pairs->name, sizeof(res[0].key)); + strncpy(res[pos].value, pairs->data.strvalue, sizeof(res[0].value)); + ++pos; + pairs = pairs->next; + } + bzero(res[pos].key, sizeof(res[0].key)); + bzero(res[pos].value, sizeof(res[0].value)); + return res; +} /* * Do any per-module initialization that is separate to each @@ -63,17 +121,17 @@ int emptyPair(const STG_PAIR * pair); * that must be referenced in later calls, store a handle to it * in *instance otherwise put a null pointer there. */ -static int stg_instantiate(CONF_SECTION *conf, void **instance) +static int stg_instantiate(CONF_SECTION* conf, void** instance) { - rlm_stg_t *data; + rlm_stg_t* data; /* * Set up a storage area for instance data */ data = rad_malloc(sizeof(*data)); - if (!data) { + if (!data) return -1; - } + memset(data, 0, sizeof(*data)); /* @@ -85,7 +143,7 @@ static int stg_instantiate(CONF_SECTION *conf, void **instance) return -1; } - if (!stgInstantiateImpl(data->server, data->port)) { + if (!stgInstantiateImpl(data->address)) { free(data); return -1; } @@ -101,45 +159,37 @@ static int stg_instantiate(CONF_SECTION *conf, void **instance) * from the database. The authentication code only needs to check * the password, the rest is done here. */ -static int stg_authorize(void *, REQUEST *request) +static int stg_authorize(void* instance, REQUEST* request) { - const STG_PAIR * pairs; - const STG_PAIR * pair; + STG_RESULT result; + STG_PAIR* pairs = fromVPS(request->packet->vps); size_t count = 0; + const char* username = NULL; + const char* password = NULL; instance = instance; DEBUG("rlm_stg: stg_authorize()"); if (request->username) { - DEBUG("rlm_stg: stg_authorize() request username field: '%s'", request->username->vp_strvalue); + username = request->username->data.strvalue; + DEBUG("rlm_stg: stg_authorize() request username field: '%s'", username); } + if (request->password) { - DEBUG("rlm_stg: stg_authorize() request password field: '%s'", request->password->vp_strvalue); + password = request->password->data.strvalue; + DEBUG("rlm_stg: stg_authorize() request password field: '%s'", password); } - // Here we need to define Framed-Protocol - VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); - if (svc) { - DEBUG("rlm_stg: stg_authorize() Service-Type defined as '%s'", svc->vp_strvalue); - pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue); - } else { - DEBUG("rlm_stg: stg_authorize() Service-Type undefined"); - pairs = stgAuthorizeImpl((const char *)request->username->vp_strvalue, ""); - } - if (!pairs) { + + result = stgAuthorizeImpl(username, password, pairs); + deletePairs(pairs); + + if (!result.modify && !result.reply) { DEBUG("rlm_stg: stg_authorize() failed."); return RLM_MODULE_REJECT; } - pair = pairs; - while (!emptyPair(pair)) { - VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); - pairadd(&request->config_items, pwd); - DEBUG("Adding pair '%s': '%s'", pair->key, pair->value); - ++pair; - ++count; - } - deletePairs(pairs); + count = toReply(result, request); if (count) return RLM_MODULE_UPDATED; @@ -150,37 +200,37 @@ static int stg_authorize(void *, REQUEST *request) /* * Authenticate the user with the given password. */ -static int stg_authenticate(void *, REQUEST *request) +static int stg_authenticate(void* instance, REQUEST* request) { - const STG_PAIR * pairs; - const STG_PAIR * pair; + STG_RESULT result; + STG_PAIR* pairs = fromVPS(request->packet->vps); size_t count = 0; + const char* username = NULL; + const char* password = NULL; instance = instance; DEBUG("rlm_stg: stg_authenticate()"); - VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); - if (svc) { - DEBUG("rlm_stg: stg_authenticate() Service-Type defined as '%s'", svc->vp_strvalue); - pairs = stgAuthenticateImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue); - } else { - DEBUG("rlm_stg: stg_authenticate() Service-Type undefined"); - pairs = stgAuthenticateImpl((const char *)request->username->vp_strvalue, ""); + if (request->username) { + username = request->username->data.strvalue; + DEBUG("rlm_stg: stg_authenticate() request username field: '%s'", username); + } + + if (request->password) { + password = request->password->data.strvalue; + DEBUG("rlm_stg: stg_authenticate() request password field: '%s'", password); } - if (!pairs) { + + result = stgAuthenticateImpl(username, password, pairs); + deletePairs(pairs); + + if (!result.modify && !result.reply) { DEBUG("rlm_stg: stg_authenticate() failed."); return RLM_MODULE_REJECT; } - pair = pairs; - while (!emptyPair(pair)) { - VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); - pairadd(&request->reply->vps, pwd); - ++pair; - ++count; - } - deletePairs(pairs); + count = toReply(result, request); if (count) return RLM_MODULE_UPDATED; @@ -191,63 +241,78 @@ static int stg_authenticate(void *, REQUEST *request) /* * Massage the request before recording it or proxying it */ -static int stg_preacct(void *, REQUEST *) +static int stg_preacct(void* instance, REQUEST* request) { + STG_RESULT result; + STG_PAIR* pairs = fromVPS(request->packet->vps); + size_t count = 0; + const char* username = NULL; + const char* password = NULL; + DEBUG("rlm_stg: stg_preacct()"); instance = instance; - return RLM_MODULE_OK; + if (request->username) { + username = request->username->data.strvalue; + DEBUG("rlm_stg: stg_preacct() request username field: '%s'", username); + } + + if (request->password) { + password = request->password->data.strvalue; + DEBUG("rlm_stg: stg_preacct() request password field: '%s'", password); + } + + result = stgPreAcctImpl(username, password, pairs); + deletePairs(pairs); + + if (!result.modify && !result.reply) { + DEBUG("rlm_stg: stg_preacct() failed."); + return RLM_MODULE_REJECT; + } + + count = toReply(result, request); + + if (count) + return RLM_MODULE_UPDATED; + + return RLM_MODULE_NOOP; } /* * Write accounting information to this modules database. */ -static int stg_accounting(void *, REQUEST * request) +static int stg_accounting(void* instance, REQUEST* request) { - const STG_PAIR * pairs; - const STG_PAIR * pair; + STG_RESULT result; + STG_PAIR* pairs = fromVPS(request->packet->vps); size_t count = 0; - - instance = instance; + const char* username = NULL; + const char* password = NULL; DEBUG("rlm_stg: stg_accounting()"); - VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); - VALUE_PAIR * sessid = pairfind(request->packet->vps, PW_ACCT_SESSION_ID); - VALUE_PAIR * sttype = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE); + instance = instance; - if (!sessid) { - DEBUG("rlm_stg: stg_accounting() Acct-Session-ID undefined"); - return RLM_MODULE_FAIL; + if (request->username) { + username = request->username->data.strvalue; + DEBUG("rlm_stg: stg_accounting() request username field: '%s'", username); } - if (sttype) { - DEBUG("Acct-Status-Type := %s", sttype->vp_strvalue); - if (svc) { - DEBUG("rlm_stg: stg_accounting() Service-Type defined as '%s'", svc->vp_strvalue); - pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue, (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue); - } else { - DEBUG("rlm_stg: stg_accounting() Service-Type undefined"); - pairs = stgAccountingImpl((const char *)request->username->vp_strvalue, "", (const char *)sttype->vp_strvalue, (const char *)sessid->vp_strvalue); - } - } else { - DEBUG("rlm_stg: stg_accounting() Acct-Status-Type := NULL"); - return RLM_MODULE_OK; + if (request->password) { + password = request->password->data.strvalue; + DEBUG("rlm_stg: stg_accounting() request password field: '%s'", password); } - if (!pairs) { + + result = stgAccountingImpl(username, password, pairs); + deletePairs(pairs); + + if (!result.modify && !result.reply) { DEBUG("rlm_stg: stg_accounting() failed."); return RLM_MODULE_REJECT; } - pair = pairs; - while (!emptyPair(pair)) { - VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); - pairadd(&request->reply->vps, pwd); - ++pair; - ++count; - } - deletePairs(pairs); + count = toReply(result, request); if (count) return RLM_MODULE_UPDATED; @@ -265,49 +330,48 @@ static int stg_accounting(void *, REQUEST * request) * max. number of logins, do a second pass and validate all * logins by querying the terminal server (using eg. SNMP). */ -static int stg_checksimul(void *, REQUEST *request) +static int stg_checksimul(void* instance, REQUEST* request) { DEBUG("rlm_stg: stg_checksimul()"); instance = instance; - request->simul_count=0; + request->simul_count = 0; return RLM_MODULE_OK; } -static int stg_postauth(void *, REQUEST *request) +static int stg_postauth(void* instance, REQUEST* request) { - const STG_PAIR * pairs; - const STG_PAIR * pair; + STG_RESULT result; + STG_PAIR* pairs = fromVPS(request->packet->vps); size_t count = 0; - - instance = instance; + const char* username = NULL; + const char* password = NULL; DEBUG("rlm_stg: stg_postauth()"); - VALUE_PAIR * svc = pairfind(request->packet->vps, PW_SERVICE_TYPE); + instance = instance; - if (svc) { - DEBUG("rlm_stg: stg_postauth() Service-Type defined as '%s'", svc->vp_strvalue); - pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, (const char *)svc->vp_strvalue); - } else { - DEBUG("rlm_stg: stg_postauth() Service-Type undefined"); - pairs = stgPostAuthImpl((const char *)request->username->vp_strvalue, ""); + if (request->username) { + username = request->username->data.strvalue; + DEBUG("rlm_stg: stg_postauth() request username field: '%s'", username); } - if (!pairs) { + + if (request->password) { + password = request->password->data.strvalue; + DEBUG("rlm_stg: stg_postauth() request password field: '%s'", password); + } + + result = stgPostAuthImpl(username, password, pairs); + deletePairs(pairs); + + if (!result.modify && !result.reply) { DEBUG("rlm_stg: stg_postauth() failed."); return RLM_MODULE_REJECT; } - pair = pairs; - while (!emptyPair(pair)) { - VALUE_PAIR * pwd = pairmake(pair->key, pair->value, T_OP_SET); - pairadd(&request->reply->vps, pwd); - ++pair; - ++count; - } - deletePairs(pairs); + count = toReply(result, request); if (count) return RLM_MODULE_UPDATED; @@ -315,9 +379,9 @@ static int stg_postauth(void *, REQUEST *request) return RLM_MODULE_NOOP; } -static int stg_detach(void *instance) +static int stg_detach(void* instance) { - free(((struct rlm_stg_t *)instance)->server); + free(((struct rlm_stg_t*)instance)->address); free(instance); return 0; } @@ -334,17 +398,17 @@ static int stg_detach(void *instance) module_t rlm_stg = { RLM_MODULE_INIT, "stg", - RLM_TYPE_THREAD_SAFE, /* type */ - stg_instantiate, /* instantiation */ - stg_detach, /* detach */ + RLM_TYPE_THREAD_SAFE, /* type */ + stg_instantiate, /* instantiation */ + stg_detach, /* detach */ { - stg_authenticate, /* authentication */ + stg_authenticate, /* authentication */ stg_authorize, /* authorization */ - stg_preacct, /* preaccounting */ - stg_accounting, /* accounting */ - stg_checksimul, /* checksimul */ - NULL, /* pre-proxy */ - NULL, /* post-proxy */ - stg_postauth /* post-auth */ + stg_preacct, /* preaccounting */ + stg_accounting, /* accounting */ + stg_checksimul, /* checksimul */ + NULL, /* pre-proxy */ + NULL, /* post-proxy */ + stg_postauth /* post-auth */ }, }; diff --git a/projects/rlm_stg/stg_client.cpp b/projects/rlm_stg/stg_client.cpp index 113e71c9..199aca90 100644 --- a/projects/rlm_stg/stg_client.cpp +++ b/projects/rlm_stg/stg_client.cpp @@ -18,278 +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 - -#include - #include "stg_client.h" -typedef std::vector > PAIRS; - -//----------------------------------------------------------------------------- +#include "stg/common.h" -STG_CLIENT::STG_CLIENT(const std::string & host, uint16_t port, uint16_t lp, const std::string & pass) - : 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() +unsigned fromType(STG_CLIENT::TYPE type) { -/*close(sock);*/ + return static_cast(type); } -int STG_CLIENT::PrepareNet() +STG::SGCP::TransportType toTransport(const std::string& value) { -return 0; + 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) +ChannelConfig::ChannelConfig(std::string addr) + : transport(STG::SGCP::TCP) { -/*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) - { - errorStr = "Error receiving data"; - return -1; + // 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."); } - -Decrypt(&ctx, (char *)packet, buf, res / 8); - -return 0;*/ -} - -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)) + if (transport == STG::SGCP::UNIX) { - errorStr = "Magic invalid. Wanted: '"; - errorStr += RAD_ID; - errorStr += "', got: '"; - errorStr += (char *)packet->magic; - errorStr += "'"; - return -1; + address = addr; + return; } - -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."); } -//----------------------------------------------------------------------------- - -const STG_PAIRS * STG_CLIENT::Authorize(const std::string & login, const std::string & svc) +STG_CLIENT::STG_CLIENT(const std::string& address) + : m_config(address), + m_proto(m_config.transport, m_config.key) { -/*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;*/ - -PAIRS pairs; -pairs.push_back(std::make_pair("Cleartext-Password", userPassword)); - -return ToSTGPairs(pairs); + try { + m_proto.connect(m_config.address, m_config.port); + } catch (const STG::SGCP::Proto::Error& ex) { + throw Error(ex.what()); + } } -const STG_PAIRS * STG_CLIENT::Authenticate(const std::string & login, const std::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;*/ - -PAIRS pairs; - -return ToSTGPairs(pairs); } -const STG_PAIRS * STG_CLIENT::PostAuth(const std::string & login, const std::string & svc) +RESULT STG_CLIENT::request(TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs) { -/*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;*/ - -PAIRS pairs; -pairs.push_back(std::make_pair("Framed-IP-Address", inet_ntostring(framedIP))); - -return ToSTGPairs(pairs); + m_writeHeader(type, userName, password); + m_writePairBlock(pairs); + RESULT result; + result.modify = m_readPairBlock(); + result.reply = m_readPairBlock(); + return result; } -const STG_PAIRS * STG_CLIENT::PreAcct(const std::string & login, const std::String & service) +STG_CLIENT* STG_CLIENT::get() { -PAIRS pairs; - -return ToSTGPairs(pairs); + return stgClient; } -const STG_PAIRS * STG_CLIENT::Account(const std::string & type, const std::string & login, const std::string & svc, const std::string & sessid) +bool STG_CLIENT::configure(const std::string& address) { -/*RAD_PACKET packet; - -userPassword = ""; -strncpy((char *)packet.sessid, sessid.c_str(), RAD_SESSID_LEN); - -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; + 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;*/ - -PAIRS pairs; - -return ToSTGPairs(pairs); + return false; } -//----------------------------------------------------------------------------- - -std::string STG_CLIENT_ST::m_host; -uint16_t STG_CLIENT_ST::m_port(6666); -std::string STG_CLIENT_ST::m_password; - -//----------------------------------------------------------------------------- - -STG_CLIENT * STG_CLIENT_ST::Get() +void STG_CLIENT::m_writeHeader(TYPE type, const std::string& userName, const std::string& password) { - static STG_CLIENT * stgClient = NULL; - if ( stgClient == NULL ) - stgClient = new STG_CLIENT(m_host, m_port, m_password); - return stgClient; + 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()); + } } -void STG_CLIENT_ST::Configure(const std::string & host, uint16_t port, const std::string & password) +void STG_CLIENT::m_writePairBlock(const PAIRS& pairs) { - m_host = host; - m_port = port; - m_password = password; + 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()); + } } -//----------------------------------------------------------------------------- - -const STG_PAIR * ToSTGPairs(const PAIRS & source) +PAIRS STG_CLIENT::m_readPairBlock() { - STG_PAIR * pairs = new STG_PAIR[source.size() + 1]; - for (size_t pos = 0; pos < source.size(); ++pos) { - bzero(pairs[pos].key, sizeof(STG_PAIR::key)); - bzero(pairs[pos].value, sizeof(STG_PAIR::value)); - strncpy(pairs[pos].key, source[pos].first.c_str(), sizeof(STG_PAIR::key)); - strncpy(pairs[pos].value, source[pos].second.c_str(), sizeof(STG_PAIR::value)); - ++pos; + 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()); } - bzero(pairs[sources.size()].key, sizeof(STG_PAIR::key)); - bzero(pairs[sources.size()].value, sizeof(STG_PAIR::value)); - - return pairs; } diff --git a/projects/rlm_stg/stg_client.h b/projects/rlm_stg/stg_client.h index 5ee000c7..6315a0a5 100644 --- a/projects/rlm_stg/stg_client.h +++ b/projects/rlm_stg/stg_client.h @@ -18,61 +18,67 @@ * Author : Maxim Mamontov */ -/* - * Header file for client part of data access via Stargazer for RADIUS - * - * $Revision: 1.4 $ - * $Date: 2010/04/16 12:30:02 $ - * - */ - #ifndef STG_CLIENT_H #define STG_CLIENT_H +#include "stg/sgcp_proto.h" // Proto +#include "stg/sgcp_types.h" // TransportType +#include "stg/os_int.h" + #include +#include +#include + +typedef std::vector > PAIRS; -#include -#include -#include // socklen_t +struct RESULT +{ + PAIRS modify; + PAIRS reply; +}; -#include "stg/blowfish.h" -#include "stg/rad_packets.h" +struct ChannelConfig { + struct Error : std::runtime_error { + Error(const std::string& message) : runtime_error(message) {} + }; -#include "stgpair.h" + ChannelConfig(std::string address); + + STG::SGCP::TransportType transport; + std::string key; + std::string address; + uint16_t port; +}; class STG_CLIENT { public: - STG_CLIENT(const std::string & host, uint16_t port, const std::string & password); + enum TYPE { + AUTHORIZE, + AUTHENTICATE, + POST_AUTH, + PRE_ACCT, + ACCOUNT + }; + struct Error : std::runtime_error { + Error(const std::string& message) : runtime_error(message) {} + }; + + STG_CLIENT(const std::string& address); ~STG_CLIENT(); - const STG_PAIR * Authorize(const std::string & login, const std::string & service); - const STG_PAIR * Authenticate(const std::string & login, const std::string & service); - const STG_PAIR * PostAuth(const std::string & login, const std::string & service); - const STG_PAIR * PreAcct(const std::string & login, const std::string & service); - const STG_PAIR * Account(const std::string & type, const std::string & login, const std::string & service, const std::string & sessionId); - -private: - std::string password; - - int PrepareNet(); + static STG_CLIENT* get(); + static bool configure(const std::string& address); - int Request(RAD_PACKET * packet, const std::string & login, const std::string & svc, uint8_t packetType); + RESULT request(TYPE type, const std::string& userName, const std::string& password, const PAIRS& pairs); - int RecvData(RAD_PACKET * packet); - int Send(const RAD_PACKET & packet); -}; +private: + ChannelConfig m_config; + STG::SGCP::Proto m_proto; -struct STG_CLIENT_ST -{ - public: - static void Configure(const std::string & host, uint16_t port, const std::string & password); - static STG_CLIENT * Get(); - - private: - static std::string m_host; - static uint16_t m_port; - static std::string m_password; + void m_writeHeader(TYPE type, const std::string& userName, const std::string& password); + void m_writePairBlock(const PAIRS& source); + PAIRS m_readPairBlock(); }; #endif diff --git a/projects/rlm_stg/stgpair.h b/projects/rlm_stg/stgpair.h index 19b42bc1..dba9e3eb 100644 --- a/projects/rlm_stg/stgpair.h +++ b/projects/rlm_stg/stgpair.h @@ -1,12 +1,33 @@ #ifndef __STG_STGPAIR_H__ #define __STG_STGPAIR_H__ +#include + #define STGPAIR_KEYLENGTH 64 #define STGPAIR_VALUELENGTH 256 +#ifdef __cplusplus +extern "C" { +#endif + typedef struct STG_PAIR { char key[STGPAIR_KEYLENGTH]; char value[STGPAIR_VALUELENGTH]; } STG_PAIR; +typedef struct STG_RESULT { + STG_PAIR* modify; + STG_PAIR* reply; +} STG_RESULT; + +inline +int emptyPair(const STG_PAIR* pair) +{ + return pair != NULL && pair->key[0] != '\0' && pair->value[0] != '\0'; +} + +#ifdef __cplusplus +} +#endif + #endif diff --git a/projects/stargazer/plugins/other/radius/Makefile b/projects/stargazer/plugins/other/radius/Makefile index 62a05183..dd736698 100644 --- a/projects/stargazer/plugins/other/radius/Makefile +++ b/projects/stargazer/plugins/other/radius/Makefile @@ -8,7 +8,8 @@ LIBS += $(LIB_THREAD) PROG = mod_radius.so -SRCS = ./radius.cpp +SRCS = radius.cpp \ + config.cpp STGLIBS = common \ crypto \ diff --git a/projects/stargazer/plugins/other/radius/config.cpp b/projects/stargazer/plugins/other/radius/config.cpp new file mode 100644 index 00000000..8a90567d --- /dev/null +++ b/projects/stargazer/plugins/other/radius/config.cpp @@ -0,0 +1,177 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "config.h" + +#include "stg/common.h" + +#include +#include + +#include // strncasecmp + +using STG::Config; + +namespace +{ + +struct ParserError : public std::runtime_error +{ + ParserError(size_t pos, const std::string& message) + : runtime_error("Parsing error at position " + x2str(pos) + ". " + message), + position(pos), + error(message) + {} + + size_t position; + std::string error; +}; + +size_t skipSpaces(const std::string& value, size_t start) +{ + while (start < value.length() && std::isspace(value[start])) + ++start; + return start; +} + +size_t checkChar(const std:string& value, size_t start, char ch) +{ + if (start >= value.length()) + throw ParserError(start, "Unexpected end of string. Expected '" + std::string(ch) + "'."); + if (value[start] != ch) + throw ParserError(start, "Expected '" + std::string(ch) + "', got '" + std::string(value[start]) + "'."); + return start + 1; +} + +std::pair readString(const std::string& value, size_t start) +{ + std::string dest; + while (start < value.length() && !std::isspace(value[start])) + dest.push_back(value[start++]); + if (dest.empty()) { + if (start == value.length()) + throw ParserError(start, "Unexpected end of string. Expected string."); + else + throw ParserError(start, "Unexpected whitespace. Expected string."); + } + return dest; +} + +Config::Pairs toPairs(const std::vector& values) +{ + if (values.empty()) + return Config::Pairs(); + std::string value(values[0]); + Config::Pairs res; + size_t start = 0; + while (start < value.size()) { + Config::Pair pair; + start = skipSpaces(value, start); + size_t pairStart = start; + start = checkChar(value, start, '('); + std::pair key = readString(value, start); + start = key.first; + pair.first = key.second; + start = skipSpaces(value, start); + start = checkChar(value, start, ',') + start = skipSpaces(value, start); + std::pair value = readString(value, start); + start = key.first; + pair.second = value.second; + start = skipSpaces(value, start); + start = checkChar(value, start, ')'); + if (res.find(pair.first) != res.end()) + throw ParserError(pairStart, "Duplicate field."); + res.insert(pair); + } + return res; +} + +bool toBool(const std::vector& values) +{ + if (values.empty()) + return false; + std::string value(values[0]); + return strncasecmp(value.c_str(), "yes", 3) == 0; +} + +std::string toString(const std::vector& values) +{ + if (values.empty()) + return ""; + return values[0]; +} + +template +T toInt(const std::vector& values) +{ + if (values.empty()) + return 0; + T res = 0; + if (srt2x(values[0], res) == 0) + return res; + return 0; +} + +Config::Pairs parseVector(const std::string& paramName, const MODULE_SETTINGS& params) +{ + for (size_t i = 0; i < params.moduleParams.size(); ++i) + if (params.moduleParams[i].first == paramName) + return toPairs(params.moduleParams[i].second); + return Config::Pairs(); +} + +bool parseBool(const std::string& paramName, const MODULE_SETTINGS& params) +{ + for (size_t i = 0; i < params.moduleParams.size(); ++i) + if (params.moduleParams[i].first == paramName) + return toBool(params.moduleParams[i].second); + return false; +} + +std::string parseString(const std::string& paramName, const MODULE_SETTINGS& params) +{ + for (size_t i = 0; i < params.moduleParams.size(); ++i) + if (params.moduleParams[i].first == paramName) + return toString(params.moduleParams[i].second); + return ""; +} + +template +T parseInt(const std::string& paramName, const MODULE_SETTINGS& params) +{ + for (size_t i = 0; i < params.moduleParams.size(); ++i) + if (params.moduleParams[i].first == paramName) + return toInt(params.moduleParams[i].second); + return 0; +} + +} // namespace anonymous + +Config::Config(const MODULE_SETTINGS& settings) + : match(parseVector("match", settings)), + modify(parseVector("modify", settings)), + reply(parseVector("reply", settings)), + verbose(parseBool("verbose", settings)), + bindAddress(parseString("bind_address", settings)), + port(parseInt("port", settings)), + key(parseString("key", settings)) +{ +} diff --git a/projects/stargazer/plugins/other/radius/config.h b/projects/stargazer/plugins/other/radius/config.h new file mode 100644 index 00000000..8e5055d8 --- /dev/null +++ b/projects/stargazer/plugins/other/radius/config.h @@ -0,0 +1,54 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_RADIUS_CONFIG_H__ +#define __STG_RADIUS_CONFIG_H__ + +#include "stg/module_settings.h" + +#include "stg/os_int.h" + +#include +#include + +namespace STG +{ + +struct Config +{ + typedef std::map Pairs; + typedef Pairs::value_type Pair; + + Config(const MODULE_SETTINGS& settings); + + Pairs match; + Pairs modify; + Pairs reply; + + bool verbose; + + std::string bindAddress; + uint16_t port; + std::string key; +}; + +} // namespace STG + +#endif diff --git a/projects/stargazer/plugins/other/radius/conn.cpp b/projects/stargazer/plugins/other/radius/conn.cpp new file mode 100644 index 00000000..223eb2cf --- /dev/null +++ b/projects/stargazer/plugins/other/radius/conn.cpp @@ -0,0 +1,63 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "conn.h" + +#include "config.h" + +#include "stg/users.h" +#include "stg/user.h" +#include "stg/logger.h" +#include "stg/common.h" + +#include +#include + +using STG::Conn; + +Conn::Conn(USERS& users, PLUGIN_LOGGER & logger, const Config& config) + : m_users(users), + m_logger(logger), + m_config(config) +{ +} + +Conn::~Conn() +{ +} + +bool Conn::read() +{ + ssize_t res = read(m_sock, m_buffer, m_bufferSize); + if (res < 0) + { + m_state = ERROR; + Log(__FILE__, "Failed to read data from " + inet_ntostring(IP()) + ":" + x2str(port()) + ". Reason: '" + strerror(errno) + "'"); + return false; + } + if (res == 0 && m_state != DATA) // EOF is ok for data. + { + m_state = ERROR; + Log(__FILE__, "Failed to read data from " + inet_ntostring(IP()) + ":" + x2str(port()) + ". Unexpected EOF."); + return false; + } + m_bufferSize -= res; + return HandleBuffer(res); +} diff --git a/projects/stargazer/plugins/other/radius/conn.h b/projects/stargazer/plugins/other/radius/conn.h new file mode 100644 index 00000000..31ebe1dd --- /dev/null +++ b/projects/stargazer/plugins/other/radius/conn.h @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONFIG_CONN_H__ +#define __STG_SGCONFIG_CONN_H__ + +#include "stg/os_int.h" + +#include +#include + +class USERS; + +namespace STG +{ + +class Conn +{ + public: + struct Error : public std::runtime_error + { + Error(const std::string& message) : runtime_error(message.c_str()) {} + }; + + Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config); + ~Conn(); + + int sock() const { return m_sock; } + + bool read(); + + private: + USERS& m_users; + PLUGIN_LOGGER& m_logger; + const Config& m_config; +}; + +} + +#endif diff --git a/projects/stargazer/plugins/other/radius/radius.cpp b/projects/stargazer/plugins/other/radius/radius.cpp index 8e52cdb4..fe989b28 100644 --- a/projects/stargazer/plugins/other/radius/radius.cpp +++ b/projects/stargazer/plugins/other/radius/radius.cpp @@ -18,586 +18,169 @@ * Author : Maxim Mamontov */ -/* - * This file contains a realization of radius data access plugin for Stargazer - * - * $Revision: 1.14 $ - * $Date: 2009/12/13 14:17:13 $ - * - */ - -#include -#include -#include +#include "radius.h" #include "stg/store.h" -#include "stg/common.h" -#include "stg/user_conf.h" -#include "stg/user_property.h" +#include "stg/users.h" #include "stg/plugin_creator.h" -#include "radius.h" -extern volatile time_t stgTime; +#include +#include +#include -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- namespace { -PLUGIN_CREATOR radc; -void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password); -void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8); -void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8); -} -extern "C" PLUGIN * GetPlugin(); -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -PLUGIN * GetPlugin() -{ -return radc.GetPlugin(); +PLUGIN_CREATOR creator; + } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -int RAD_SETTINGS::ParseServices(const std::vector & str, std::list * lst) + +extern "C" PLUGIN * GetPlugin() { -std::copy(str.begin(), str.end(), std::back_inserter(*lst)); -std::list::iterator it(std::find(lst->begin(), - lst->end(), - "empty")); -if (it != lst->end()) - *it = ""; - -return 0; + return creator.GetPlugin(); } -//----------------------------------------------------------------------------- -int RAD_SETTINGS::ParseSettings(const MODULE_SETTINGS & s) -{ -int p; -PARAM_VALUE pv; -std::vector::const_iterator pvi; -/////////////////////////// -pv.param = "Port"; -pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv); -if (pvi == s.moduleParams.end()) - { - errorStr = "Parameter \'Port\' not found."; - printfd(__FILE__, "Parameter 'Port' not found\n"); - return -1; - } -if (ParseIntInRange(pvi->value[0], 2, 65535, &p)) - { - errorStr = "Cannot parse parameter \'Port\': " + errorStr; - printfd(__FILE__, "Cannot parse parameter 'Port'\n"); - return -1; - } -port = static_cast(p); -/////////////////////////// -pv.param = "Password"; -pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv); -if (pvi == s.moduleParams.end()) - { - errorStr = "Parameter \'Password\' not found."; - printfd(__FILE__, "Parameter 'Password' not found\n"); - return -1; - } -password = pvi->value[0]; -/////////////////////////// -pv.param = "AuthServices"; -pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv); -if (pvi != s.moduleParams.end()) - { - ParseServices(pvi->value, &authServices); - } -/////////////////////////// -pv.param = "AcctServices"; -pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv); -if (pvi != s.moduleParams.end()) - { - ParseServices(pvi->value, &acctServices); - } -return 0; -} -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- RADIUS::RADIUS() - : ctx(), - errorStr(), - radSettings(), - settings(), - authServices(), - acctServices(), - sessions(), - nonstop(false), - isRunning(false), - users(NULL), - stgSettings(NULL), - store(NULL), - thread(), - mutex(), - sock(-1), - packet(), - logger(GetPluginLogger(GetStgLogger(), "radius")) + : m_running(false), + m_stopped(true), + m_users(NULL), + m_store(NULL), + m_logger(GetPluginLogger(GetStgLogger(), "radius")) { -InitEncrypt(&ctx, ""); } -//----------------------------------------------------------------------------- + int RADIUS::ParseSettings() { -int ret = radSettings.ParseSettings(settings); -if (ret) - errorStr = radSettings.GetStrError(); -return ret; -} -//----------------------------------------------------------------------------- -int RADIUS::PrepareNet() -{ -sock = socket(AF_INET, SOCK_DGRAM, 0); - -if (sock < 0) - { - errorStr = "Cannot create socket."; - logger("Cannot create a socket: %s", strerror(errno)); - printfd(__FILE__, "Cannot create socket\n"); - return -1; - } - -struct sockaddr_in inAddr; -inAddr.sin_family = AF_INET; -inAddr.sin_port = htons(radSettings.GetPort()); -inAddr.sin_addr.s_addr = inet_addr("0.0.0.0"); - -if (bind(sock, (struct sockaddr*)&inAddr, sizeof(inAddr)) < 0) - { - errorStr = "RADIUS: Bind failed."; - logger("Cannot bind the socket: %s", strerror(errno)); - printfd(__FILE__, "Cannot bind socket\n"); - return -1; + try { + m_config = STG::Config(m_settings); + return 0; + } catch (const std::runtime_error& ex) { + m_logger("Failed to parse settings. %s", ex.what()); + return -1; } - -return 0; } -//----------------------------------------------------------------------------- -int RADIUS::FinalizeNet() -{ -close(sock); -return 0; -} -//----------------------------------------------------------------------------- + int RADIUS::Start() { -std::string password(radSettings.GetPassword()); - -authServices = radSettings.GetAuthServices(); -acctServices = radSettings.GetAcctServices(); - -InitEncrypt(&ctx, password); + if (m_running) + return 0; -nonstop = true; + int res = pthread_create(&m_thread, NULL, run, this); + if (res == 0) + return 0; -if (PrepareNet()) - { + m_error = strerror(res); + m_logger("Failed to create thread: '" + m_error + "'."); return -1; - } - -if (!isRunning) - { - if (pthread_create(&thread, NULL, Run, this)) - { - errorStr = "Cannot create thread."; - logger("Cannot create thread."); - printfd(__FILE__, "Cannot create thread\n"); - return -1; - } - } - -errorStr = ""; -return 0; } -//----------------------------------------------------------------------------- + int RADIUS::Stop() { -if (!IsRunning()) - return 0; - -nonstop = false; - -std::map::iterator it; -for (it = sessions.begin(); it != sessions.end(); ++it) - { - USER_PTR ui; - if (users->FindByName(it->second.userName, &ui)) - { - users->Unauthorize(ui->GetLogin(), this); - } - } -sessions.erase(sessions.begin(), sessions.end()); + if (m_stopped) + return 0; -FinalizeNet(); + m_running = false; -if (isRunning) - { - //5 seconds to thread stops itself - for (int i = 0; i < 25 && isRunning; i++) - { + for (size_t i = 0; i < 25 && !m_stopped; i++) { struct timespec ts = {0, 200000000}; nanosleep(&ts, NULL); - } } -if (isRunning) - return -1; - -return 0; -} -//----------------------------------------------------------------------------- -void * RADIUS::Run(void * d) -{ -sigset_t signalSet; -sigfillset(&signalSet); -pthread_sigmask(SIG_BLOCK, &signalSet, NULL); - -RADIUS * rad = static_cast(d); -RAD_PACKET packet; - -rad->isRunning = true; - -while (rad->nonstop) - { - if (!WaitPackets(rad->sock)) - { - continue; - } - struct sockaddr_in outerAddr; - if (rad->RecvData(&packet, &outerAddr)) - { - printfd(__FILE__, "RADIUS::Run Error on RecvData\n"); - } - else - { - if (rad->ProcessData(&packet)) - { - packet.packetType = RAD_REJECT_PACKET; - } - rad->Send(packet, &outerAddr); - } + if (m_stopped) { + pthread_join(m_thread, NULL); + return 0; } -rad->isRunning = false; - -return NULL; -} -//----------------------------------------------------------------------------- -int RADIUS::RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr) -{ - int8_t buf[RAD_MAX_PACKET_LEN]; - socklen_t outerAddrLen = sizeof(struct sockaddr_in); - ssize_t dataLen = recvfrom(sock, buf, RAD_MAX_PACKET_LEN, 0, reinterpret_cast(outerAddr), &outerAddrLen); - if (dataLen < 0) - { - logger("recvfrom error: %s", strerror(errno)); - return -1; - } - if (dataLen == 0) - return -1; - - Decrypt(&ctx, (char *)packet, (const char *)buf, dataLen / 8); - - if (strncmp((char *)packet->magic, RAD_ID, RAD_MAGIC_LEN)) - { - printfd(__FILE__, "RADIUS::RecvData Error magic. Wanted: '%s', got: '%s'\n", RAD_ID, packet->magic); - return -1; - } - - return 0; -} -//----------------------------------------------------------------------------- -ssize_t RADIUS::Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr) -{ -size_t len = sizeof(RAD_PACKET); -char buf[1032]; - -Encrypt(&ctx, buf, (char *)&packet, len / 8); -ssize_t res = sendto(sock, buf, len, 0, reinterpret_cast(outerAddr), sizeof(struct sockaddr_in)); -if (res < 0) - logger("sendto error: %s", strerror(errno)); -return res; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessData(RAD_PACKET * packet) -{ -if (strncmp((const char *)packet->protoVer, "01", 2)) - { - printfd(__FILE__, "RADIUS::ProcessData packet.protoVer incorrect\n"); + m_error = "Failed to stop thread."; + m_logger(m_error); return -1; - } -switch (packet->packetType) - { - case RAD_AUTZ_PACKET: - return ProcessAutzPacket(packet); - case RAD_AUTH_PACKET: - return ProcessAuthPacket(packet); - case RAD_POST_AUTH_PACKET: - return ProcessPostAuthPacket(packet); - case RAD_ACCT_START_PACKET: - return ProcessAcctStartPacket(packet); - case RAD_ACCT_STOP_PACKET: - return ProcessAcctStopPacket(packet); - case RAD_ACCT_UPDATE_PACKET: - return ProcessAcctUpdatePacket(packet); - case RAD_ACCT_OTHER_PACKET: - return ProcessAcctOtherPacket(packet); - default: - printfd(__FILE__, "RADIUS::ProcessData Unsupported packet type: %d\n", packet->packetType); - return -1; - }; } //----------------------------------------------------------------------------- -int RADIUS::ProcessAutzPacket(RAD_PACKET * packet) +void* RADIUS::run(void* d) { -USER_CONF conf; - -if (!IsAllowedService((char *)packet->service)) - { - printfd(__FILE__, "RADIUS::ProcessAutzPacket service '%s' is not allowed to authorize\n", packet->service); - packet->packetType = RAD_REJECT_PACKET; - return 0; - } + sigset_t signalSet; + sigfillset(&signalSet); + pthread_sigmask(SIG_BLOCK, &signalSet, NULL); -if (store->RestoreUserConf(&conf, (char *)packet->login)) - { - packet->packetType = RAD_REJECT_PACKET; - printfd(__FILE__, "RADIUS::ProcessAutzPacket cannot restore conf for user '%s'\n", packet->login); - return 0; - } + static_cast(d)->runImpl(); -// At this point service can be authorized at least -// So we send a plain-text password - -packet->packetType = RAD_ACCEPT_PACKET; -strncpy((char *)packet->password, conf.password.c_str(), RAD_PASSWORD_LEN); - -return 0; + return NULL; } -//----------------------------------------------------------------------------- -int RADIUS::ProcessAuthPacket(RAD_PACKET * packet) -{ -USER_PTR ui; - -if (!CanAcctService((char *)packet->service)) - { - - // There are no sense to check for allowed service - // It has allready checked at previous stage (authorization) - - printfd(__FILE__, "RADIUS::ProcessAuthPacket service '%s' neednot stargazer authentication\n", (char *)packet->service); - packet->packetType = RAD_ACCEPT_PACKET; - return 0; - } -// At this point we have an accountable service -// All other services got a password if allowed or rejected - -if (!FindUser(&ui, (char *)packet->login)) - { - packet->packetType = RAD_REJECT_PACKET; - printfd(__FILE__, "RADIUS::ProcessAuthPacket user '%s' not found\n", (char *)packet->login); - return 0; - } - -if (ui->IsInetable()) - { - packet->packetType = RAD_ACCEPT_PACKET; - } -else - { - packet->packetType = RAD_REJECT_PACKET; - } - -packet->packetType = RAD_ACCEPT_PACKET; -return 0; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessPostAuthPacket(RAD_PACKET * packet) +void RADIUS::runImpl() { -USER_PTR ui; - -if (!CanAcctService((char *)packet->service)) - { + m_running = true; - // There are no sense to check for allowed service - // It has allready checked at previous stage (authorization) - - packet->packetType = RAD_ACCEPT_PACKET; - return 0; - } - -if (!FindUser(&ui, (char *)packet->login)) - { - packet->packetType = RAD_REJECT_PACKET; - printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", (char *)packet->login); - return 0; - } - -// I think that only Framed-User services has sense to be accountable -// So we have to supply a Framed-IP - -USER_IPS ips = ui->GetProperty().ips; -packet->packetType = RAD_ACCEPT_PACKET; - -// Additional checking for Framed-User service - -if (!strncmp((char *)packet->service, "Framed-User", RAD_SERVICE_LEN)) - packet->ip = ips[0].ip; -else - packet->ip = 0; - -return 0; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessAcctStartPacket(RAD_PACKET * packet) -{ -USER_PTR ui; + while (m_running) { + fd_set fds; -if (!FindUser(&ui, (char *)packet->login)) - { - packet->packetType = RAD_REJECT_PACKET; - printfd(__FILE__, "RADIUS::ProcessAcctStartPacket user '%s' not found\n", (char *)packet->login); - return 0; - } + buildFDSet(fds); -// At this point we have to unauthorize user only if it is an accountable service + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 500000; -if (CanAcctService((char *)packet->service)) - { - if (sessions.find((const char *)packet->sessid) != sessions.end()) + int res = select(maxFD() + 1, &fds, NULL, NULL, &tv); + if (res < 0) { - printfd(__FILE__, "RADIUS::ProcessAcctStartPacket session already started!\n"); - packet->packetType = RAD_REJECT_PACKET; - return -1; - } - USER_IPS ips = ui->GetProperty().ips; - if (!users->Authorize(ui->GetLogin(), ips[0].ip, 0xffFFffFF, this)) - { - printfd(__FILE__, "RADIUS::ProcessAcctStartPacket cannot authorize user '%s'\n", packet->login); - packet->packetType = RAD_REJECT_PACKET; - return -1; + m_error = std::string("'select' is failed: '") + strerror(errno) + "'."; + m_logger(m_error); + break; } - sessions[(const char *)packet->sessid].userName = (const char *)packet->login; - sessions[(const char *)packet->sessid].serviceType = (const char *)packet->service; - for_each(sessions.begin(), sessions.end(), SPrinter()); - } -else - { - printfd(__FILE__, "RADIUS::ProcessAcctStartPacket service '%s' can not be accounted\n", (char *)packet->service); - } - -packet->packetType = RAD_ACCEPT_PACKET; -return 0; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessAcctStopPacket(RAD_PACKET * packet) -{ -std::map::iterator sid; -if ((sid = sessions.find((const char *)packet->sessid)) == sessions.end()) - { - printfd(__FILE__, "RADIUS::ProcessAcctStopPacket session had not started yet\n"); - packet->packetType = RAD_REJECT_PACKET; - return -1; - } + if (!m_running) + break; -USER_PTR ui; + if (res > 0) + handleEvents(fds); -if (!FindUser(&ui, sid->second.userName)) - { - packet->packetType = RAD_REJECT_PACKET; - printfd(__FILE__, "RADIUS::ProcessPostAuthPacket user '%s' not found\n", sid->second.userName.c_str()); - return 0; + cleanupConns(); } -sessions.erase(sid); - -users->Unauthorize(ui->GetLogin(), this); - -packet->packetType = RAD_ACCEPT_PACKET; -return 0; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessAcctUpdatePacket(RAD_PACKET * packet) -{ -// Fake. May be use it later -packet->packetType = RAD_ACCEPT_PACKET; -return 0; -} -//----------------------------------------------------------------------------- -int RADIUS::ProcessAcctOtherPacket(RAD_PACKET * packet) -{ -// Fake. May be use it later -packet->packetType = RAD_ACCEPT_PACKET; -return 0; + m_stopped = true; } -//----------------------------------------------------------------------------- -bool RADIUS::FindUser(USER_PTR * ui, const std::string & login) const -{ -if (users->FindByName(login, ui)) - { - return false; - } -return true; -} -//----------------------------------------------------------------------------- -bool RADIUS::CanAuthService(const std::string & svc) const -{ -return find(authServices.begin(), authServices.end(), svc) != authServices.end(); -} -//----------------------------------------------------------------------------- -bool RADIUS::CanAcctService(const std::string & svc) const -{ -return find(acctServices.begin(), acctServices.end(), svc) != acctServices.end(); -} -//----------------------------------------------------------------------------- -bool RADIUS::IsAllowedService(const std::string & svc) const + +int RADIUS::maxFD() const { -return CanAuthService(svc) || CanAcctService(svc); + int maxFD = m_listenSocket; + std::deque::const_iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + if (maxFD < (*it)->sock()) + maxFD = (*it)->sock(); + return maxFD; } -//----------------------------------------------------------------------------- -namespace -{ -inline -void InitEncrypt(BLOWFISH_CTX * ctx, const std::string & password) +void RADIUS::buildFDSet(fd_set & fds) const { -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); + FD_ZERO(&fds); + FD_SET(m_listenSocket, &fds); + std::deque::const_iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + FD_SET((*it)->sock(), &fds); } -//----------------------------------------------------------------------------- -inline -void Encrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8) -{ -// len8 - длина в 8-ми байтовых блоках -if (dst != src) - memcpy(dst, src, len8 * 8); -for (size_t i = 0; i < len8; i++) - Blowfish_Encrypt(ctx, static_cast(dst) + i * 2, static_cast(dst) + i * 2 + 1); -} -//----------------------------------------------------------------------------- -inline -void Decrypt(BLOWFISH_CTX * ctx, void * dst, const void * src, unsigned long len8) +void RADIUS::cleanupConns() { -// len8 - длина в 8-ми байтовых блоках -if (dst != src) - memcpy(dst, src, len8 * 8); + std::deque::iterator pos; + for (pos = m_conns.begin(); pos != m_conns.end(); ++pos) + if (((*pos)->isDone() && !(*pos)->isKeepAlive()) || !(*pos)->isOk()) { + delete *pos; + *pos = NULL; + } -for (size_t i = 0; i < len8; i++) - Blowfish_Decrypt(ctx, static_cast(dst) + i * 2, static_cast(dst) + i * 2 + 1); + pos = std::remove(m_conns.begin(), m_conns.end(), static_cast(NULL)); + m_conns.erase(pos, m_conns.end()); } -} // namespace anonymous +void RADIUS::handleEvents(const fd_set & fds) +{ + if (FD_ISSET(m_listenSocket, &fds)) + acceptConnection(); + else + { + std::deque::iterator it; + for (it = m_conns.begin(); it != m_conns.end(); ++it) + if (FD_ISSET((*it)->sock(), &fds)) + (*it)->read(); + } +} diff --git a/projects/stargazer/plugins/other/radius/radius.h b/projects/stargazer/plugins/other/radius/radius.h index 8f5ba2a4..ff8ecf5e 100644 --- a/projects/stargazer/plugins/other/radius/radius.h +++ b/projects/stargazer/plugins/other/radius/radius.h @@ -18,154 +18,77 @@ * Author : Maxim Mamontov */ -/* - * Radius data access plugin for Stargazer - * - * $Revision: 1.10 $ - * $Date: 2009/12/13 14:17:13 $ - * - */ - -#ifndef RADIUS_H -#define RADIUS_H - -#include - -#include -#include -#include -#include -#include -#include +#ifndef __STG_RADIUS_H__ +#define __STG_RADIUS_H__ #include "stg/os_int.h" #include "stg/auth.h" #include "stg/module_settings.h" -#include "stg/notifer.h" -#include "stg/user_ips.h" -#include "stg/user.h" -#include "stg/users.h" -#include "stg/blowfish.h" -#include "stg/rad_packets.h" #include "stg/logger.h" -extern "C" PLUGIN * GetPlugin(); +#include -#define RAD_DEBUG (1) +#include +#include +#include +#include -class RADIUS; -//----------------------------------------------------------------------------- -class RAD_SETTINGS { -public: - RAD_SETTINGS() - : port(0), errorStr(), password(), - authServices(), acctServices() - {} - virtual ~RAD_SETTINGS() {} - const std::string & GetStrError() const { return errorStr; } - int ParseSettings(const MODULE_SETTINGS & s); - uint16_t GetPort() const { return port; } - const std::string & GetPassword() const { return password; } - const std::list & GetAuthServices() const { return authServices; } - const std::list & GetAcctServices() const { return acctServices; } +extern "C" PLUGIN * GetPlugin(); -private: - int ParseServices(const std::vector & str, std::list * lst); +class STORE; +class USERS; - uint16_t port; - std::string errorStr; - std::string password; - std::list authServices; - std::list acctServices; -}; -//----------------------------------------------------------------------------- -struct RAD_SESSION { - RAD_SESSION() : userName(), serviceType() {} - std::string userName; - std::string serviceType; -}; -//----------------------------------------------------------------------------- -class RADIUS :public AUTH { +class RADIUS : public AUTH { public: - RADIUS(); - virtual ~RADIUS() {} + RADIUS(); + virtual ~RADIUS() {} - void SetUsers(USERS * u) { users = u; } - void SetStore(STORE * s) { store = s; } - void SetStgSettings(const SETTINGS *) {} - void SetSettings(const MODULE_SETTINGS & s) { settings = s; } - int ParseSettings(); + void SetUsers(USERS* u) { users = u; } + void SetStore(STORE* s) { store = s; } + void SetStgSettings(const SETTINGS*) {} + void SetSettings(const MODULE_SETTINGS& s) { settings = s; } + int ParseSettings(); - int Start(); - int Stop(); - int Reload() { return 0; } - bool IsRunning() { return isRunning; } + int Start(); + int Stop(); + int Reload() { return 0; } + bool IsRunning() { return m_running; } - const std::string & GetStrError() const { return errorStr; } - std::string GetVersion() const { return "RADIUS data access plugin v 0.6"; } - uint16_t GetStartPosition() const { return 30; } - uint16_t GetStopPosition() const { return 30; } + const std::string& GetStrError() const { return m_error; } + std::string GetVersion() const { return "RADIUS data access plugin v 1.0"; } + uint16_t GetStartPosition() const { return 30; } + uint16_t GetStopPosition() const { return 30; } - int SendMessage(const STG_MSG &, uint32_t) const { return 0; } + int SendMessage(const STG_MSG&, uint32_t) const { return 0; } private: RADIUS(const RADIUS & rvalue); RADIUS & operator=(const RADIUS & rvalue); - static void * Run(void *); - int PrepareNet(); - int FinalizeNet(); - - ssize_t Send(const RAD_PACKET & packet, struct sockaddr_in * outerAddr); - int RecvData(RAD_PACKET * packet, struct sockaddr_in * outerAddr); - int ProcessData(RAD_PACKET * packet); - - int ProcessAutzPacket(RAD_PACKET * packet); - int ProcessAuthPacket(RAD_PACKET * packet); - int ProcessPostAuthPacket(RAD_PACKET * packet); - int ProcessAcctStartPacket(RAD_PACKET * packet); - int ProcessAcctStopPacket(RAD_PACKET * packet); - int ProcessAcctUpdatePacket(RAD_PACKET * packet); - int ProcessAcctOtherPacket(RAD_PACKET * packet); - - bool FindUser(USER_PTR * ui, const std::string & login) const; - bool CanAuthService(const std::string & svc) const; - bool CanAcctService(const std::string & svc) const; - bool IsAllowedService(const std::string & svc) const; - - struct SPrinter : public std::unary_function, void> - { - void operator()(const std::pair & it) - { - printfd("radius.cpp", "%s - ('%s', '%s')\n", it.first.c_str(), it.second.userName.c_str(), it.second.serviceType.c_str()); - } - }; - - BLOWFISH_CTX ctx; + static void* run(void*); - mutable std::string errorStr; - RAD_SETTINGS radSettings; - MODULE_SETTINGS settings; - std::list authServices; - std::list acctServices; - std::map sessions; + void rumImpl(); + int maxFD() const; + void buildFDSet(fd_set & fds) const; + void cleanupConns(); + void handleEvents(const fd_set & fds); + void acceptConnection(); - bool nonstop; - bool isRunning; + mutable std::string m_error; + STG::Config m_config; - USERS * users; - const SETTINGS * stgSettings; - const STORE * store; + MODULE_SETTINGS m_settings; - pthread_t thread; - pthread_mutex_t mutex; + bool m_running; + bool m_stopped; - int sock; + USERS* m_users; + const STORE* m_store; - RAD_PACKET packet; + pthread_t m_thread; + pthread_mutex_t m_mutex; - PLUGIN_LOGGER logger; + PLUGIN_LOGGER m_logger; }; -//----------------------------------------------------------------------------- #endif diff --git a/projects/stargazer/plugins/other/radius/reader.cpp b/projects/stargazer/plugins/other/radius/reader.cpp new file mode 100644 index 00000000..e7d3e2fa --- /dev/null +++ b/projects/stargazer/plugins/other/radius/reader.cpp @@ -0,0 +1,7 @@ +#include "reader.h" + +using STG::Reader; + +Reader::Reader() +{ +} diff --git a/projects/stargazer/plugins/other/radius/reader.h b/projects/stargazer/plugins/other/radius/reader.h new file mode 100644 index 00000000..3bc1f9e6 --- /dev/null +++ b/projects/stargazer/plugins/other/radius/reader.h @@ -0,0 +1,170 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#ifndef __STG_SGCONFIG_READER_H__ +#define __STG_SGCONFIG_READER_H__ + +#include +#include +#include + +namespace STG +{ + +struct BaseReader +{ + virtual ~BaseReader() {} + + virtual ssize_t read(TransportProto& proto) = 0; + virtual bool done() const = 0; +}; + +template +class Reader : public BaseReader +{ + public: + Reader(size_t size = sizeof(T)) : m_size(size), m_done(0) {} + + virtual ssize_t read(TransportProto& proto) + { + char* pos = static_cast(&m_dest); + pos += m_done; + ssize_t res = proto.read(pos, m_size - m_done); + if (res < 0) + return res; + if (res == 0) { + m_done = m_size; + return 0; + } + m_done += res; + return res; + } + + virtual bool done() const { return m_done == m_size; } + + T get() const { return ntoh(m_dest); } + + private: + T m_dest; + size_t m_size; + size_t m_done; + +}; + +template <> +class Reader > : public BaseReader +{ + public: + Reader(const std::vector& readers) : m_size(readers.size()), m_done(0) {} + + virtual ssize_t read(TransportProto& proto) + { + if (m_size == 0) + return 0; + size_t res = m_dest[m_done]->read(proto); + if (res < 0) + return res; + if (res == 0) { + m_done = m_size; + return 0; + } + if (m_dest[m_done].done()) + ++m_dest; + return res; + } + + virtual bool done() const { return m_done == m_size; } + + const T& get() const { return m_dest; } + + private: + T m_dest; + size_t m_size; + size_t m_done; + +}; + +template <> +class Reader > : public BaseReader +{ + public: + Reader(size_t size ) : m_dest(size), m_size(size), m_done(0) {} + + virtual ssize_t read(TransportProto& proto) + { + char* pos = static_cast(m_dest.data()); + pos += m_done; + ssize_t res = proto.read(pos, m_size - m_done); + if (res < 0) + return res; + if (res == 0) { + m_done = m_size; + return 0; + } + m_done += res; + return res; + } + + virtual bool done() const { return m_done == m_size; } + + const std::vector& get() const { return m_dest; } + + private: + std::vector m_dest; + size_t m_size; + size_t m_done; + +}; + +template <> +class Reader +{ + public: + Reader() : m_dest(Reader::initDest()) {} + + virtual ssize_t read(TransportProto& proto) + { + if (m_size == 0) + return 0; + size_t res = m_dest[m_done]->read(proto); + if (res < 0) + return res; + if (res == 0) { + m_done = m_size; + return 0; + } + if (m_dest[m_done].done()) + ++m_dest; + return res; + } + + virtual bool done() const { return m_done == m_size; } + + const T& get() const { return m_dest; } + + private: + T m_dest; + size_t m_size; + size_t m_done; +}; + +} // namespace STG + +#endif diff --git a/stglibs/common.lib/Makefile b/stglibs/common.lib/Makefile index 1f662c25..932e2709 100644 --- a/stglibs/common.lib/Makefile +++ b/stglibs/common.lib/Makefile @@ -7,9 +7,11 @@ include ../../Makefile.conf LIB_NAME = stgcommon SRCS = common.cpp \ - strptime.cpp + strptime.cpp \ + blockio.cpp -INCS = common.h +INCS = common.h \ + blockio.h LIBS += $(LIBICONV) diff --git a/stglibs/common.lib/blockio.cpp b/stglibs/common.lib/blockio.cpp new file mode 100644 index 00000000..04fd1d81 --- /dev/null +++ b/stglibs/common.lib/blockio.cpp @@ -0,0 +1,102 @@ +#include "stg/blockio.h" + +namespace +{ + +void* adjust(void* base, size_t shift) +{ + char* ptr = static_cast(base); + return ptr + shift; +} + +} // namspace anonymous + +using STG::BlockReader; +using STG::BlockWriter; + +BlockReader::BlockReader(const IOVec& ioVec) + : m_dest(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_dest.size(); ++i) + m_remainder += m_dest[i].iov_len; +} + +bool BlockReader::read(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_dest.size() - 1; + size_t toRead = m_remainder; + while (offset > 0) { + if (toRead < m_dest[offset].iov_len) + break; + toRead -= m_dest[offset].iov_len; + --offset; + } + + IOVec dest(m_dest.size() - offset); + for (size_t i = 0; i < dest.size(); ++i) { + if (i == 0) { + dest[0].iov_len = toRead; + dest[0].iov_base = adjust(m_dest[offset].iov_base, m_dest[offset].iov_len - toRead); + } else { + dest[i] = m_dest[offset + i]; + } + } + + ssize_t res = readv(socket, dest.data(), dest.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +} + +BlockWriter::BlockWriter(const IOVec& ioVec) + : m_source(ioVec), + m_remainder(0) +{ + for (size_t i = 0; i < m_source.size(); ++i) + m_remainder += m_source[i].iov_len; +} + +bool BlockWriter::write(int socket) +{ + if (m_remainder == 0) + return true; + + size_t offset = m_source.size() - 1; + size_t toWrite = m_remainder; + while (offset > 0) { + if (toWrite < m_source[offset].iov_len) + break; + toWrite -= m_source[offset].iov_len; + --offset; + } + + IOVec source(m_source.size() - offset); + for (size_t i = 0; i < source.size(); ++i) { + if (i == 0) { + source[0].iov_len = toWrite; + source[0].iov_base = adjust(m_source[offset].iov_base, m_source[offset].iov_len - toWrite); + } else { + source[i] = m_source[offset + i]; + } + } + ssize_t res = writev(socket, source.data(), source.size()); + if (res < 0) + return false; + if (res == 0) + return m_remainder == 0; + if (res < static_cast(m_remainder)) + m_remainder -= res; + else + m_remainder = 0; + return true; +} diff --git a/stglibs/common.lib/include/stg/blockio.h b/stglibs/common.lib/include/stg/blockio.h new file mode 100644 index 00000000..3879e39e --- /dev/null +++ b/stglibs/common.lib/include/stg/blockio.h @@ -0,0 +1,43 @@ +#ifndef __STG_STGLIBS_BLOCK_IO_H__ +#define __STG_STGLIBS_BLOCK_IO_H__ + +#include + +#include + +namespace STG +{ + +typedef std::vector IOVec; + +class BlockReader +{ + public: + BlockReader(const IOVec& ioVec); + + bool read(int socket); + bool done() const { return m_remainder == 0; } + size_t remainder() const { return m_remainder; } + + private: + IOVec m_dest; + size_t m_remainder; +}; + +class BlockWriter +{ + public: + BlockWriter(const IOVec& ioVec); + + bool write(int socket); + bool done() const { return m_remainder == 0; } + size_t remainder() const { return m_remainder; } + + private: + IOVec m_source; + size_t m_remainder; +}; + +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/Makefile b/stglibs/sgcp.lib/Makefile new file mode 100644 index 00000000..01ec3373 --- /dev/null +++ b/stglibs/sgcp.lib/Makefile @@ -0,0 +1,16 @@ +include ../../Makefile.conf + +LIB_NAME = stgsgcp + +SRCS = proto.cpp \ + transport.cpp \ + unix.cpp \ + udp.cpp \ + tcp.cpp \ + crypto.cpp + +INCS = sgcp_proto.h \ + sgcp_types.h \ + sgcp_transport.h + +include ../Makefile.in diff --git a/stglibs/sgcp.lib/crypto.cpp b/stglibs/sgcp.lib/crypto.cpp new file mode 100644 index 00000000..2b2bb8f3 --- /dev/null +++ b/stglibs/sgcp.lib/crypto.cpp @@ -0,0 +1,30 @@ +#include "crypto.h" + +using STG::SGCP::CryptoProto; + +CryptoProto::CryptoProto(const std::string& key, TransportProto* underlying) + : m_underlying(underlying) +{ +} + +CryptoProto::~CryptoProto() +{ + delete m_underlying; +} + +void CryptoProto::connect(const std::string& address, uint16_t port) +{ + m_underlying->connect(address, port); +} + +ssize_t CryptoProto::write(const void* buf, size_t size) +{ + // TODO: to implement + return m_underlying->write(buf, size); +} + +ssize_t CryptoProto::read(void* buf, size_t size) +{ + // TODO: to implement + return m_underlying->read(buf, size); +} diff --git a/stglibs/sgcp.lib/crypto.h b/stglibs/sgcp.lib/crypto.h new file mode 100644 index 00000000..5f720d04 --- /dev/null +++ b/stglibs/sgcp.lib/crypto.h @@ -0,0 +1,54 @@ +#ifndef __STG_SGCP_CRYPTO_H__ +#define __STG_SGCP_CRYPTO_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/sgcp_transport.h" + +#include "stg/os_int.h" + +#include + +#include // ssize_t + +namespace STG +{ +namespace SGCP +{ + +class CryptoProto : public TransportProto +{ + public: + CryptoProto(const std::string& key, TransportProto* underlying); + virtual ~CryptoProto(); + + virtual void connect(const std::string& address, uint16_t port); + virtual ssize_t write(const void* buf, size_t size); + virtual ssize_t read(void* buf, size_t size); + + private: + TransportProto* m_underlying; +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/include/stg/sgcp_proto.h b/stglibs/sgcp.lib/include/stg/sgcp_proto.h new file mode 100644 index 00000000..3cc35b19 --- /dev/null +++ b/stglibs/sgcp.lib/include/stg/sgcp_proto.h @@ -0,0 +1,108 @@ +#ifndef __STG_SGCP_PROTO_H__ +#define __STG_SGCP_PROTO_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "sgcp_types.h" // TransportType +#include "sgcp_utils.h" // hton/ntoh + +#include "stg/os_int.h" + +#include +#include +#include + +namespace STG +{ +namespace SGCP +{ + +class TransportProto; + +class Proto +{ + public: + struct Error : public std::runtime_error + { + Error(const std::string& mesage); + Error(); + }; + + Proto(TransportType transport, const std::string& key); + ~Proto(); + + void connect(const std::string& address, uint16_t port); + + void writeAllBuf(const void* buf, size_t size); + void readAllBuf(void* buf, size_t size); + + template + void writeAll(const T& value); + + template + T readAll(); + + private: + TransportProto* m_transport; +}; + +template <> +inline +void Proto::writeAll(const uint64_t& value) +{ + uint64_t temp = hton(value); + writeAllBuf(&temp, sizeof(temp)); +} + +template <> +inline +void Proto::writeAll(const std::string& value) +{ + uint64_t size = hton(value.size()); + writeAllBuf(&size, sizeof(size)); + writeAllBuf(value.c_str(), value.size()); +} + +template <> +inline +uint64_t Proto::readAll() +{ + uint64_t temp = 0; + readAllBuf(&temp, sizeof(temp)); + return ntoh(temp); +} + +template <> +inline +std::string Proto::readAll() +{ + uint64_t size = 0; + readAllBuf(&size, sizeof(size)); + size = ntoh(size); + std::vector res(size); + readAllBuf(res.data(), res.size()); + return res.data(); +} + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/include/stg/sgcp_transport.h b/stglibs/sgcp.lib/include/stg/sgcp_transport.h new file mode 100644 index 00000000..88a7d0c4 --- /dev/null +++ b/stglibs/sgcp.lib/include/stg/sgcp_transport.h @@ -0,0 +1,58 @@ +#ifndef __STG_SGCP_TRANSPORT_H__ +#define __STG_SGCP_TRANSPORT_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/sgcp_types.h" + +#include "stg/os_int.h" + +#include +#include + +#include // ssize_t + +namespace STG +{ +namespace SGCP +{ + +class TransportProto +{ + public: + struct Error : public std::runtime_error { + Error(const std::string& message) : runtime_error(message) {} + }; + + static TransportProto* create(TransportType transport, const std::string& key); + static TransportProto* create(TransportType transport); + + virtual ~TransportProto() {} + + virtual void connect(const std::string& address, uint16_t port) = 0; + virtual ssize_t write(const void* buf, size_t size) = 0; + virtual ssize_t read(void* buf, size_t size) = 0; +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/include/stg/sgcp_types.h b/stglibs/sgcp.lib/include/stg/sgcp_types.h new file mode 100644 index 00000000..47920077 --- /dev/null +++ b/stglibs/sgcp.lib/include/stg/sgcp_types.h @@ -0,0 +1,39 @@ +#ifndef __STG_SGCP_TYPES_H__ +#define __STG_SGCP_TYPES_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +namespace STG +{ +namespace SGCP +{ + +enum TransportType +{ + UNIX, + UDP, + TCP +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/include/stg/sgcp_utils.h b/stglibs/sgcp.lib/include/stg/sgcp_utils.h new file mode 100644 index 00000000..7e5004c1 --- /dev/null +++ b/stglibs/sgcp.lib/include/stg/sgcp_utils.h @@ -0,0 +1,67 @@ +#ifndef __STG_SGCP_UTILS_H__ +#define __STG_SGCP_UTILS_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/os_int.h" + +#include +#include + +#include // hton* +#include // in_addr + +namespace STG +{ +namespace SGCP +{ + +template inline T hton(T value) { return value; } +template inline T ntoh(T value) { return hton(value); } + +template <> inline uint16_t hton(uint16_t value) { return htons(value); } +template <> inline int16_t hton(int16_t value) { return htons(value); } + +template <> inline uint32_t hton(uint32_t value) { return htonl(value); } +template <> inline int32_t hton(int32_t value) { return htonl(value); } + +inline +uint64_t htonll(uint64_t value) +{ +#ifdef ARCH_LE + const uint32_t high_part = htonl(static_cast(value >> 32)); + const uint32_t low_part = htonl(static_cast(value & 0xFFFFFFFFLL)); + + return (static_cast(low_part) << 32) | high_part; +#else + return value; +#endif +} + +template <> inline uint64_t hton(uint64_t value) { return htonll(value); } +template <> inline int64_t hton(int64_t value) { return htonll(value); } + +std::vector resolve(const std::string& address); + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/proto.cpp b/stglibs/sgcp.lib/proto.cpp new file mode 100644 index 00000000..96b6285b --- /dev/null +++ b/stglibs/sgcp.lib/proto.cpp @@ -0,0 +1,63 @@ +#include "stg/sgcp_proto.h" + +#include "stg/sgcp_transport.h" + +#include +#include + +using STG::SGCP::Proto; + +Proto::Error::Error(const std::string& message) + : runtime_error(message) +{} + +Proto::Error::Error() + : runtime_error(strerror(errno)) +{} + +Proto::Proto(TransportType transport, const std::string& key) + : m_transport(TransportProto::create(transport, key)) +{ +} + +Proto::~Proto() +{ + delete m_transport; +} + +void Proto::connect(const std::string& address, uint16_t port) +{ + try { + m_transport->connect(address, port); + } catch (const TransportProto::Error& ex) { + throw Error(ex.what()); + } +} + +void Proto::writeAllBuf(const void* buf, size_t size) +{ + const char* pos = static_cast(buf); + while (size > 0) { + ssize_t res = m_transport->write(pos, size); + if (res < 0) + throw Error(); + if (res == 0) + return; + size -= res; + pos += res; + } +} + +void Proto::readAllBuf(void* buf, size_t size) +{ + char* pos = static_cast(buf); + while (size > 0) { + ssize_t res = m_transport->read(pos, size); + if (res < 0) + throw Error(); + if (res == 0) + return; + size -= res; + pos += res; + } +} diff --git a/stglibs/sgcp.lib/tcp.cpp b/stglibs/sgcp.lib/tcp.cpp new file mode 100644 index 00000000..414d5ec8 --- /dev/null +++ b/stglibs/sgcp.lib/tcp.cpp @@ -0,0 +1,52 @@ +#include "tcp.h" + +#include "stg/sgcp_utils.h" + +#include +#include + +#include +#include +#include +#include + +using STG::SGCP::TCPProto; + +TCPProto::TCPProto() + : m_sock(socket(AF_INET, SOCK_STREAM, 0)) +{ +} + +TCPProto::~TCPProto() +{ + close(m_sock); +} + +void TCPProto::connect(const std::string& address, uint16_t port) +{ + std::vector addrs = resolve(address); + + for (size_t i = 0; i < addrs.size(); ++i) { + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = hton(port); + addr.sin_addr = addrs[i]; + + if (::connect(m_sock, reinterpret_cast(&addr), sizeof(addr)) == 0) + return; + + close(m_sock); + m_sock = socket(AF_INET, SOCK_STREAM, 0); + } + throw Error("No more addresses to connect to."); +} + +ssize_t TCPProto::write(const void* buf, size_t size) +{ + return ::write(m_sock, buf, size); +} + +ssize_t TCPProto::read(void* buf, size_t size) +{ + return ::read(m_sock, buf, size); +} diff --git a/stglibs/sgcp.lib/tcp.h b/stglibs/sgcp.lib/tcp.h new file mode 100644 index 00000000..8afa0b5e --- /dev/null +++ b/stglibs/sgcp.lib/tcp.h @@ -0,0 +1,54 @@ +#ifndef __STG_SGCP_TCP_H__ +#define __STG_SGCP_TCP_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/sgcp_transport.h" + +#include "stg/os_int.h" + +#include + +#include // ssize_t + +namespace STG +{ +namespace SGCP +{ + +class TCPProto : public TransportProto +{ + public: + TCPProto(); + virtual ~TCPProto(); + + virtual void connect(const std::string& address, uint16_t port); + virtual ssize_t write(const void* buf, size_t size); + virtual ssize_t read(void* buf, size_t size); + + private: + int m_sock; +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/transport.cpp b/stglibs/sgcp.lib/transport.cpp new file mode 100644 index 00000000..1e94fa58 --- /dev/null +++ b/stglibs/sgcp.lib/transport.cpp @@ -0,0 +1,27 @@ +#include "stg/sgcp_transport.h" + +#include "crypto.h" +#include "unix.h" +#include "udp.h" +#include "tcp.h" + +using STG::SGCP::TransportProto; + +TransportProto* TransportProto::create(TransportType transport, const std::string& key) +{ + TransportProto* underlying = create(transport); + if (key.empty()) + return underlying; + else + return new CryptoProto(key, underlying); +} + +TransportProto* TransportProto::create(TransportType transport) +{ + switch (transport) { + case UNIX: return new UnixProto; + case UDP: return new UDPProto; + case TCP: return new TCPProto; + }; + return NULL; +} diff --git a/stglibs/sgcp.lib/udp.cpp b/stglibs/sgcp.lib/udp.cpp new file mode 100644 index 00000000..ebbb98e6 --- /dev/null +++ b/stglibs/sgcp.lib/udp.cpp @@ -0,0 +1,52 @@ +#include "udp.h" + +#include "stg/sgcp_utils.h" + +#include +#include + +#include +#include +#include +#include + +using STG::SGCP::UDPProto; + +UDPProto::UDPProto() + : m_sock(socket(AF_INET, SOCK_DGRAM, 0)) +{ +} + +UDPProto::~UDPProto() +{ + close(m_sock); +} + +void UDPProto::connect(const std::string& address, uint16_t port) +{ + std::vector addrs = resolve(address); + + for (size_t i = 0; i < addrs.size(); ++i) { + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = hton(port); + addr.sin_addr = addrs[i]; + + if (::connect(m_sock, reinterpret_cast(&addr), sizeof(addr)) == 0) + return; + + close(m_sock); + m_sock = socket(AF_INET, SOCK_DGRAM, 0); + } + throw Error("No more addresses to connect to."); +} + +ssize_t UDPProto::write(const void* buf, size_t size) +{ + return ::write(m_sock, buf, size); +} + +ssize_t UDPProto::read(void* buf, size_t size) +{ + return ::read(m_sock, buf, size); +} diff --git a/stglibs/sgcp.lib/udp.h b/stglibs/sgcp.lib/udp.h new file mode 100644 index 00000000..b08978b4 --- /dev/null +++ b/stglibs/sgcp.lib/udp.h @@ -0,0 +1,54 @@ +#ifndef __STG_SGCP_UDP_H__ +#define __STG_SGCP_UDP_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/sgcp_transport.h" + +#include "stg/os_int.h" + +#include + +#include // ssize_t + +namespace STG +{ +namespace SGCP +{ + +class UDPProto : public TransportProto +{ + public: + UDPProto(); + virtual ~UDPProto(); + + virtual void connect(const std::string& address, uint16_t port); + virtual ssize_t write(const void* buf, size_t size); + virtual ssize_t read(void* buf, size_t size); + + private: + int m_sock; +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/unix.cpp b/stglibs/sgcp.lib/unix.cpp new file mode 100644 index 00000000..15002e5e --- /dev/null +++ b/stglibs/sgcp.lib/unix.cpp @@ -0,0 +1,41 @@ +#include "unix.h" + +#include +#include + +#include +#include +#include + +using STG::SGCP::UnixProto; + +UnixProto::UnixProto() + : m_sock(socket(AF_UNIX, SOCK_STREAM, 0)) +{ +} + +UnixProto::~UnixProto() +{ + close(m_sock); +} + +void UnixProto::connect(const std::string& address, uint16_t /*port*/) +{ + sockaddr_un addr; + addr.sun_family = AF_UNIX; + size_t max = sizeof(addr.sun_path); + strncpy(addr.sun_path, address.c_str(), max - 1); + addr.sun_path[max - 1] = 0; // Just in case. + if (::connect(m_sock, reinterpret_cast(&addr), sizeof(addr)) < 0) + throw Error(strerror(errno)); +} + +ssize_t UnixProto::write(const void* buf, size_t size) +{ + return ::write(m_sock, buf, size); +} + +ssize_t UnixProto::read(void* buf, size_t size) +{ + return ::read(m_sock, buf, size); +} diff --git a/stglibs/sgcp.lib/unix.h b/stglibs/sgcp.lib/unix.h new file mode 100644 index 00000000..e5b645f2 --- /dev/null +++ b/stglibs/sgcp.lib/unix.h @@ -0,0 +1,54 @@ +#ifndef __STG_SGCP_UNIX_H__ +#define __STG_SGCP_UNIX_H__ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Author : Maxim Mamontov + */ + +#include "stg/sgcp_transport.h" + +#include "stg/os_int.h" + +#include + +#include // ssize_t + +namespace STG +{ +namespace SGCP +{ + +class UnixProto : public TransportProto +{ + public: + UnixProto(); + virtual ~UnixProto(); + + virtual void connect(const std::string& address, uint16_t /*port*/); + virtual ssize_t write(const void* buf, size_t size); + virtual ssize_t read(void* buf, size_t size); + + private: + int m_sock; +}; + +} // namespace SGCP +} // namespace STG + +#endif diff --git a/stglibs/sgcp.lib/utils.cpp b/stglibs/sgcp.lib/utils.cpp new file mode 100644 index 00000000..4c33e42f --- /dev/null +++ b/stglibs/sgcp.lib/utils.cpp @@ -0,0 +1,30 @@ +#include "stg/sgcp_utils.h" + +#include +#include +#include + +std::vector STG::SGCP::resolve(const std::string& address) +{ + addrinfo* result = NULL; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; /* Allow IPv4 */ + hints.ai_socktype = 0; /* Datagram socket */ + hints.ai_flags = 0; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + int res = getaddrinfo(address.c_str(), NULL, &hints, &result); + if (res != 0) + throw TransportProto::Error(gai_error(res)); + + std::vector as; + for (const addrinfo* p = result; p != NULL; p = p->next) + as.push_back(p->ai_addr.sin_addr); + return as; +}