+++ /dev/null
-.\" # DS - begin display
-.de DS
-.RS
-.nf
-.sp
-..
-.\" # DE - end display
-.de DE
-.fi
-.RE
-.sp
-..
-.TH rlm_acct_unique 5 "3 February 2004" "" "FreeRADIUS Module"
-.SH NAME
-rlm_acct_unique \- FreeRADIUS Module
-.SH DESCRIPTION
-The \fIrlm_acct_unique\fP module creates a unique accounting session
-Id.
-.PP
-Many NAS vendors have their equipment supply an Acct-Session-Id
-attribute which is not unique over reboots. This makes accounting
-difficult, as there will be many independent sessions with the same
-Acct-Session-Id attribute. This module uses the Acct-Session-Id
-attribute, along with other attributes in the request, to create a
-more unique session ID, called Acct-Unique-Session-Id.
-.PP
-The main configuration items to be aware of are:
-.IP key
-A list of the attributes used in calculating an MD5 hash which is used
-as the value for the unique session id.
-.SH CONFIGURATION
-.DS
-modules {
- ...
-.br
- acct_unique {
-.br
- key = "User-Name, Acct-Session-Id, NAS-IP-Address, NAS-Port"
-.br
- }
-.br
- ...
-.br
-}
-.br
- ...
-.br
-preacct {
- ...
-.br
- acct_unique
- ...
-.br
-}
-.DE
-.PP
-After generating the MD5 hash, the module adds it to the accounting
-request packet received from the client. It will look something like
-this in your detail file:
-.PP
-.DS
- Acct-Unique-Session-Id = "c66ef57e480b9d26"
-.DE
-.PP
-NOTE: Any attribute you specify that is not found in the 'dictionary'
-file will cause the server to fail and exit with an error.
-.PP
-NOTE: If you want the Acct-Unique-Session-Id of the Start and the
-Stop packet of a particular session to match, you must use values for
-the key that will stay the same for the Start and Stop. The above
-example is a good start. Adding 'Acct-Session-Time', for example, would
-cause a mismatch because that value is not the same on the Start and
-Stop accounting packets.
-.PP
-.SH SECTIONS
-.BR authorization,
-.BR pre-accounting,
-.BR accounting
-.PP
-.SH FILES
-.I /etc/raddb/radiusd.conf
-.PP
-.SH "SEE ALSO"
-.BR radiusd (8),
-.BR radiusd.conf (5)
-.SH AUTHORS
-Chris Parker, cparker@segv.org
+++ /dev/null
-/*
- * rlm_acct_unique.c
- *
- * 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 2000,2006 The FreeRADIUS server project
- */
-
-#include <freeradius-devel/ident.h>
-RCSID("$Id$")
-
-#include <freeradius-devel/radiusd.h>
-#include <freeradius-devel/modules.h>
-
-#include <ctype.h>
-
-/*
- * Room for at least 16 attributes.
- */
-#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 } /* end the list */
-};
-
-/*
- * Add an attribute to the list.
- */
-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));
-
- /* Assign the attr to our new structure */
- new->dattr = dattr;
-
- new->next = inst->head;
- inst->head = new;
-}
-
-/*
- * Parse a key.
- */
-static int unique_parse_key(rlm_acct_unique_t *inst, char *key)
-{
- char *ptr, *prev, *keyptr;
- DICT_ATTR *a;
-
- prev = key;
- keyptr = ptr = key;
-
- /* Let's remove spaces in the string */
- 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;
-}
-
-/*
- * Needed before instantiate for cleanup.
- */
-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;
-
- /*
- * Set up a storage area for instance data
- */
- inst = rad_malloc(sizeof(*inst));
- memset(inst, 0, sizeof(*inst));
-
- if (cf_section_parse(conf, inst, module_config) < 0) {
- free(inst);
- return -1;
- }
-
- /*
- * Check to see if 'key' has something in it
- */
- if (!inst->key) {
- radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
- free(inst);
- return -1;
- }
-
- /*
- * Go thru the list of keys and build attr_list;
- */
- if (unique_parse_key(inst, inst->key) < 0) {
- unique_detach(inst); /* clean up memory */
- return -1;
- };
-
- *instance = inst;
-
- return 0;
-}
-
-/*
- * Create a (hopefully) unique Acct-Unique-Session-Id from
- * attributes listed in 'key' from radiusd.conf
- */
-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;
-
- /* initialize variables */
- p = buffer;
- left = BUFFERLEN;
- cur = inst->head;
-
- /*
- * A unique ID already exists: don't do anything.
- */
- vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0);
- if (vp) {
- return RLM_MODULE_NOOP;
- }
-
- /* loop over items to create unique identifiers */
- while (cur) {
- VALUE_PAIR hack;
-
- vp = pairfind(request->packet->vps, cur->dattr->attr, cur->dattr->vendor);
- if (!vp) {
- /*
- * This was changed in 2.x, but it's still
- * useful.
- */
- 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.vp_ipaddr = 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; /* account for ',' in between elements */
- p += length;
- *(p++) = ','; /* ensure seperation of elements */
- cur = cur->next;
- }
- buffer[BUFFERLEN-left-1] = '\0';
-
- RDEBUG2("Hashing '%s'", buffer);
- /* calculate a 'unique' string based on the above information */
- 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;
- }
-
- /* add the (hopefully) unique session ID to the packet */
- pairadd(&request->packet->vps, vp);
-
- return RLM_MODULE_OK;
-}
-
-/* globally exported name */
-module_t rlm_acct_unique = {
- RLM_MODULE_INIT,
- "Acct-Unique-Session-Id",
- RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
- unique_instantiate, /* instantiation */
- unique_detach, /* detach */
- {
- NULL, /* authentication */
- add_unique_id, /* authorization */
- add_unique_id, /* preaccounting */
- add_unique_id, /* accounting */
- NULL, /* checksimul */
- NULL, /* pre-proxy */
- NULL, /* post-proxy */
- NULL /* post-auth */
- },
-};