./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)))
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)
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
+++ /dev/null
-#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 <aland@deployingradius.com>
- */
-
-//#include <freeradius/ident.h>
-//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 */
#include "iface.h"
-#include "thriftclient.h"
+#include "stg_client.h"
-int stgInstantiateImpl(const char * server, uint16_t port, const char * password)
+#include <cstring>
+
+#include <strings.h>
+
+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<std::string, std::string>(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);
}
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
}
*
*/
+#include "iface.h"
+#include "stgpair.h"
+
#ifndef NDEBUG
#define NDEBUG
#include <freeradius/ident.h>
#undef NDEBUG
#endif
-#include "stgpair.h"
-#include "iface.h"
+#include <stddef.h> // 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
* 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));
/*
return -1;
}
- if (!stgInstantiateImpl(data->server, data->port)) {
+ if (!stgInstantiateImpl(data->address)) {
free(data);
return -1;
}
* 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;
/*
* 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;
/*
* 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;
* 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;
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;
}
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 */
},
};
* Author : Maxim Mamontov <faust@stargazer.dp.ua>
*/
-/*
- * Realization of data access via Stargazer for RADIUS
- *
- * $Revision: 1.8 $
- * $Date: 2010/04/16 12:30:02 $
- *
- */
-
-#include <netdb.h>
-#include <sys/types.h>
-#include <unistd.h> // close
-
-#include <cerrno>
-#include <cstring>
-#include <vector>
-#include <utility>
-
-#include <stdexcept>
-
#include "stg_client.h"
-typedef std::vector<std::pair<std::string, std::string> > 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 <stdexcept>
-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<unsigned>(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<struct sockaddr *>(&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<uint64_t>(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<uint64_t>(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<uint64_t>();
+ if (count == 0)
+ return PAIRS();
+ PAIRS res(count);
+ for (size_t i = 0; i < count; ++i) {
+ res[i].first = m_proto.readAll<std::string>();
+ res[i].second = m_proto.readAll<std::string>();
+ }
+ 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;
}
* Author : Maxim Mamontov <faust@stargazer.dp.ua>
*/
-/*
- * 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 <string>
+#include <vector>
+#include <utility>
+
+typedef std::vector<std::pair<std::string, std::string> > PAIRS;
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h> // 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
#ifndef __STG_STGPAIR_H__
#define __STG_STGPAIR_H__
+#include <stddef.h>
+
#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
PROG = mod_radius.so
-SRCS = ./radius.cpp
+SRCS = radius.cpp \
+ config.cpp
STGLIBS = common \
crypto \
--- /dev/null
+/*
+ * 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 <faust@stargazer.dp.ua>
+ */
+
+#include "config.h"
+
+#include "stg/common.h"
+
+#include <vector>
+#include <stdexcept>
+
+#include <strings.h> // 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<size_t, std::string> 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<std::string>& 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<size_t, std::string> 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<size_t, std::string> 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<std::string>& 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<std::string>& values)
+{
+ if (values.empty())
+ return "";
+ return values[0];
+}
+
+template <typename T>
+T toInt(const std::vector<std::string>& 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 <typename T>
+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<T>(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<uint16_t>("port", settings)),
+ key(parseString("key", settings))
+{
+}
--- /dev/null
+/*
+ * 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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_RADIUS_CONFIG_H__
+#define __STG_RADIUS_CONFIG_H__
+
+#include "stg/module_settings.h"
+
+#include "stg/os_int.h"
+
+#include <map>
+#include <string>
+
+namespace STG
+{
+
+struct Config
+{
+ typedef std::map<std::string, std::string> 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
--- /dev/null
+/*
+ * 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 <faust@stargazer.dp.ua>
+ */
+
+#include "conn.h"
+
+#include "config.h"
+
+#include "stg/users.h"
+#include "stg/user.h"
+#include "stg/logger.h"
+#include "stg/common.h"
+
+#include <cstring>
+#include <cerrno>
+
+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);
+}
--- /dev/null
+/*
+ * 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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONFIG_CONN_H__
+#define __STG_SGCONFIG_CONN_H__
+
+#include "stg/os_int.h"
+
+#include <stdexcept>
+#include <string>
+
+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
* Author : Maxim Mamontov <faust@stargazer.dp.ua>
*/
-/*
- * This file contains a realization of radius data access plugin for Stargazer
- *
- * $Revision: 1.14 $
- * $Date: 2009/12/13 14:17:13 $
- *
- */
-
-#include <csignal>
-#include <cerrno>
-#include <algorithm>
+#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 <csignal>
+#include <cerror>
+#include <cstring>
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
namespace
{
-PLUGIN_CREATOR<RADIUS> 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<RADIUS> creator;
+
}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-int RAD_SETTINGS::ParseServices(const std::vector<std::string> & str, std::list<std::string> * lst)
+
+extern "C" PLUGIN * GetPlugin()
{
-std::copy(str.begin(), str.end(), std::back_inserter(*lst));
-std::list<std::string>::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<PARAM_VALUE>::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<uint16_t>(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<std::string, RAD_SESSION>::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<RADIUS *>(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<struct sockaddr *>(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<struct sockaddr *>(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<RADIUS *>(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<std::string, RAD_SESSION>::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<STG::Conn *>::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<STG::Conn *>::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<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(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<STG::Conn *>::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<uint32_t *>(dst) + i * 2, static_cast<uint32_t *>(dst) + i * 2 + 1);
+ pos = std::remove(m_conns.begin(), m_conns.end(), static_cast<STG::Conn *>(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<STG::Conn *>::iterator it;
+ for (it = m_conns.begin(); it != m_conns.end(); ++it)
+ if (FD_ISSET((*it)->sock(), &fds))
+ (*it)->read();
+ }
+}
* Author : Maxim Mamontov <faust@stargazer.dp.ua>
*/
-/*
- * Radius data access plugin for Stargazer
- *
- * $Revision: 1.10 $
- * $Date: 2009/12/13 14:17:13 $
- *
- */
-
-#ifndef RADIUS_H
-#define RADIUS_H
-
-#include <pthread.h>
-
-#include <cstring>
-#include <cstdlib>
-#include <string>
-#include <list>
-#include <map>
-#include <vector>
+#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 <string>
-#define RAD_DEBUG (1)
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
-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<std::string> & GetAuthServices() const { return authServices; }
- const std::list<std::string> & GetAcctServices() const { return acctServices; }
+extern "C" PLUGIN * GetPlugin();
-private:
- int ParseServices(const std::vector<std::string> & str, std::list<std::string> * lst);
+class STORE;
+class USERS;
- uint16_t port;
- std::string errorStr;
- std::string password;
- std::list<std::string> authServices;
- std::list<std::string> 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<std::pair<std::string, RAD_SESSION>, void>
- {
- void operator()(const std::pair<std::string, RAD_SESSION> & 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<std::string> authServices;
- std::list<std::string> acctServices;
- std::map<std::string, RAD_SESSION> 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
--- /dev/null
+#include "reader.h"
+
+using STG::Reader;
+
+Reader::Reader()
+{
+}
--- /dev/null
+/*
+ * 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 <faust@stargazer.dp.ua>
+ */
+
+#ifndef __STG_SGCONFIG_READER_H__
+#define __STG_SGCONFIG_READER_H__
+
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace STG
+{
+
+struct BaseReader
+{
+ virtual ~BaseReader() {}
+
+ virtual ssize_t read(TransportProto& proto) = 0;
+ virtual bool done() const = 0;
+};
+
+template <typename T>
+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<void*>(&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<std::vector<Reader*> > : public BaseReader
+{
+ public:
+ Reader(const std::vector<Reader*>& 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<std::vector<char> > : 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<void*>(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<char>& get() const { return m_dest; }
+
+ private:
+ std::vector<char> m_dest;
+ size_t m_size;
+ size_t m_done;
+
+};
+
+template <>
+class Reader<std::string>
+{
+ public:
+ Reader() : m_dest(Reader<std::string>::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
LIB_NAME = stgcommon
SRCS = common.cpp \
- strptime.cpp
+ strptime.cpp \
+ blockio.cpp
-INCS = common.h
+INCS = common.h \
+ blockio.h
LIBS += $(LIBICONV)
--- /dev/null
+#include "stg/blockio.h"
+
+namespace
+{
+
+void* adjust(void* base, size_t shift)
+{
+ char* ptr = static_cast<char*>(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<ssize_t>(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<ssize_t>(m_remainder))
+ m_remainder -= res;
+ else
+ m_remainder = 0;
+ return true;
+}
--- /dev/null
+#ifndef __STG_STGLIBS_BLOCK_IO_H__
+#define __STG_STGLIBS_BLOCK_IO_H__
+
+#include <vector>
+
+#include <sys/uio.h>
+
+namespace STG
+{
+
+typedef std::vector<iovec> 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
--- /dev/null
+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
--- /dev/null
+#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);
+}
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // 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
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "sgcp_types.h" // TransportType
+#include "sgcp_utils.h" // hton/ntoh
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+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 <typename T>
+ void writeAll(const T& value);
+
+ template <typename T>
+ T readAll();
+
+ private:
+ TransportProto* m_transport;
+};
+
+template <>
+inline
+void Proto::writeAll<uint64_t>(const uint64_t& value)
+{
+ uint64_t temp = hton(value);
+ writeAllBuf(&temp, sizeof(temp));
+}
+
+template <>
+inline
+void Proto::writeAll<std::string>(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>()
+{
+ uint64_t temp = 0;
+ readAllBuf(&temp, sizeof(temp));
+ return ntoh(temp);
+}
+
+template <>
+inline
+std::string Proto::readAll<std::string>()
+{
+ uint64_t size = 0;
+ readAllBuf(&size, sizeof(size));
+ size = ntoh(size);
+ std::vector<char> res(size);
+ readAllBuf(res.data(), res.size());
+ return res.data();
+}
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_types.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <stdexcept>
+
+#include <unistd.h> // 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
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+namespace STG
+{
+namespace SGCP
+{
+
+enum TransportType
+{
+ UNIX,
+ UDP,
+ TCP
+};
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/os_int.h"
+
+#include <string>
+#include <vector>
+
+#include <arpa/inet.h> // hton*
+#include <netinet/in.h> // in_addr
+
+namespace STG
+{
+namespace SGCP
+{
+
+template <typename T> inline T hton(T value) { return value; }
+template <typename T> 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<uint32_t>(value >> 32));
+ const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));
+
+ return (static_cast<uint64_t>(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<in_addr> resolve(const std::string& address);
+
+} // namespace SGCP
+} // namespace STG
+
+#endif
--- /dev/null
+#include "stg/sgcp_proto.h"
+
+#include "stg/sgcp_transport.h"
+
+#include <cstring>
+#include <cerrno>
+
+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<const char*>(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<char*>(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;
+ }
+}
--- /dev/null
+#include "tcp.h"
+
+#include "stg/sgcp_utils.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+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<in_addr> 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<const sockaddr*>(&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);
+}
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // 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
--- /dev/null
+#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;
+}
--- /dev/null
+#include "udp.h"
+
+#include "stg/sgcp_utils.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/udp.h>
+
+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<in_addr> 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<const sockaddr*>(&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);
+}
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // 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
--- /dev/null
+#include "unix.h"
+
+#include <cerrno>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+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<const sockaddr*>(&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);
+}
--- /dev/null
+#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 <faust@stargazer.dp.ua>
+ */
+
+#include "stg/sgcp_transport.h"
+
+#include "stg/os_int.h"
+
+#include <string>
+
+#include <unistd.h> // 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
--- /dev/null
+#include "stg/sgcp_utils.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+std::vector<in_addr> 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;
+}