#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/modules.h>
#include <ctype.h>
#define BUFFERLEN 4096
typedef struct rlm_acct_unique_list_t {
DICT_ATTR *dattr;
struct rlm_acct_unique_list_t *next;
} rlm_acct_unique_list_t;
typedef struct rlm_acct_unique_t {
char *key;
rlm_acct_unique_list_t *head;
} rlm_acct_unique_t;
static const CONF_PARSER module_config[] = {
{ "key", PW_TYPE_STRING_PTR, offsetof(rlm_acct_unique_t,key), NULL, NULL },
{ NULL, -1, 0, NULL, NULL }
};
static void unique_add_attr(rlm_acct_unique_t *inst, DICT_ATTR *dattr)
{
rlm_acct_unique_list_t *new;
new = rad_malloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->dattr = dattr;
new->next = inst->head;
inst->head = new;
}
static int unique_parse_key(rlm_acct_unique_t *inst, char *key)
{
char *ptr, *prev, *keyptr;
DICT_ATTR *a;
prev = key;
keyptr = ptr = key;
while (*keyptr) {
if (isspace((int) *keyptr)) {
keyptr++;
} else {
*(ptr++) = *(keyptr++);
}
}
*ptr = '\0';
ptr = key;
while(ptr) {
switch(*ptr) {
case ',':
*ptr = '\0';
if((a = dict_attrbyname(prev)) == NULL) {
radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
return -1;
}
*ptr = ',';
prev = ptr+1;
unique_add_attr(inst, a);
break;
case '\0':
if((a = dict_attrbyname(prev)) == NULL) {
radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
return -1;
}
unique_add_attr(inst, a);
return 0;
break;
case ' ':
continue;
break;
}
ptr++;
}
return 0;
}
static int unique_detach(void *instance)
{
rlm_acct_unique_t *inst = instance;
rlm_acct_unique_list_t *this, *next;
for (this = inst->head; this != NULL; this = next) {
next = this->next;
free(this);
}
free(inst);
return 0;
}
static int unique_instantiate(CONF_SECTION *conf, void **instance)
{
rlm_acct_unique_t *inst;
inst = rad_malloc(sizeof(*inst));
memset(inst, 0, sizeof(*inst));
if (cf_section_parse(conf, inst, module_config) < 0) {
free(inst);
return -1;
}
if (!inst->key) {
radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
free(inst);
return -1;
}
if (unique_parse_key(inst, inst->key) < 0) {
unique_detach(inst);
return -1;
};
*instance = inst;
return 0;
}
static int add_unique_id(void *instance, REQUEST *request)
{
char buffer[BUFFERLEN];
u_char md5_buf[16];
VALUE_PAIR *vp;
char *p;
int length, left;
rlm_acct_unique_t *inst = instance;
rlm_acct_unique_list_t *cur;
p = buffer;
left = BUFFERLEN;
cur = inst->head;
vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
if (vp) {
return RLM_MODULE_NOOP;
}
while (cur) {
VALUE_PAIR hack;
vp = pairfind(request->packet->vps, cur->dattr->attr);
if (!vp) {
if ((cur->dattr->attr == PW_CLIENT_IP_ADDRESS) &&
(request->packet->src_ipaddr.af == AF_INET)) {
memset(&hack, 0, sizeof(hack));
hack.name = cur->dattr->name;
hack.attribute = cur->dattr->attr;
hack.type = cur->dattr->type;
hack.operator = T_OP_EQ;
hack.length = 4;
hack.lvalue = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
vp = &hack;
} else {
RDEBUG2("WARNING: Attribute %s was not found in request, unique ID MAY be inconsistent", cur->dattr->name);
}
}
length = vp_prints(p, left, vp);
left -= length + 1;
p += length;
*(p++) = ',';
cur = cur->next;
}
buffer[BUFFERLEN-left-1] = '\0';
RDEBUG2("Hashing '%s'", buffer);
fr_md5_calc(md5_buf, (u_char *)buffer, (p - buffer));
sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x",
md5_buf[0], md5_buf[1], md5_buf[2], md5_buf[3],
md5_buf[4], md5_buf[5], md5_buf[6], md5_buf[7]);
RDEBUG2("Acct-Unique-Session-ID = \"%s\".", buffer);
vp = pairmake("Acct-Unique-Session-Id", buffer, 0);
if (!vp) {
radlog(L_ERR, "%s", fr_strerror());
return RLM_MODULE_FAIL;
}
pairadd(&request->packet->vps, vp);
return RLM_MODULE_OK;
}
module_t rlm_acct_unique = {
RLM_MODULE_INIT,
"Acct-Unique-Session-Id",
RLM_TYPE_CHECK_CONFIG_SAFE,
unique_instantiate,
unique_detach,
{
NULL,
add_unique_id,
add_unique_id,
add_unique_id,
NULL,
NULL,
NULL,
NULL
},
};