4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * Copyright 2000,2006 The FreeRADIUS server project
21 #include <freeradius-devel/ident.h>
24 #include <freeradius-devel/radiusd.h>
25 #include <freeradius-devel/modules.h>
30 * Room for at least 16 attributes.
32 #define BUFFERLEN 4096
34 typedef struct rlm_acct_unique_list_t {
36 struct rlm_acct_unique_list_t *next;
37 } rlm_acct_unique_list_t;
39 typedef struct rlm_acct_unique_t {
41 rlm_acct_unique_list_t *head;
44 static const CONF_PARSER module_config[] = {
45 { "key", PW_TYPE_STRING_PTR, offsetof(rlm_acct_unique_t,key), NULL, NULL },
46 { NULL, -1, 0, NULL, NULL } /* end the list */
50 * Add an attribute to the list.
52 static void unique_add_attr(rlm_acct_unique_t *inst, DICT_ATTR *dattr)
54 rlm_acct_unique_list_t *new;
56 new = rad_malloc(sizeof(*new));
57 memset(new, 0, sizeof(*new));
59 /* Assign the attr to our new structure */
62 new->next = inst->head;
69 static int unique_parse_key(rlm_acct_unique_t *inst, char *key)
71 char *ptr, *prev, *keyptr;
77 /* Let's remove spaces in the string */
79 if (isspace((int) *keyptr)) {
82 *(ptr++) = *(keyptr++);
92 if((a = dict_attrbyname(prev)) == NULL) {
93 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
98 unique_add_attr(inst, a);
101 if((a = dict_attrbyname(prev)) == NULL) {
102 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
105 unique_add_attr(inst, a);
119 * Needed before instantiate for cleanup.
121 static int unique_detach(void *instance)
123 rlm_acct_unique_t *inst = instance;
124 rlm_acct_unique_list_t *this, *next;
126 for (this = inst->head; this != NULL; this = next) {
135 static int unique_instantiate(CONF_SECTION *conf, void **instance)
137 rlm_acct_unique_t *inst;
140 * Set up a storage area for instance data
142 inst = rad_malloc(sizeof(*inst));
143 memset(inst, 0, sizeof(*inst));
145 if (cf_section_parse(conf, inst, module_config) < 0) {
151 * Check to see if 'key' has something in it
154 radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
160 * Go thru the list of keys and build attr_list;
162 if (unique_parse_key(inst, inst->key) < 0) {
163 unique_detach(inst); /* clean up memory */
173 * Create a (hopefully) unique Acct-Unique-Session-Id from
174 * attributes listed in 'key' from radiusd.conf
176 static int add_unique_id(void *instance, REQUEST *request)
178 char buffer[BUFFERLEN];
184 rlm_acct_unique_t *inst = instance;
185 rlm_acct_unique_list_t *cur;
187 /* initialize variables */
193 * A unique ID already exists: don't do anything.
195 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID, 0);
197 return RLM_MODULE_NOOP;
200 /* loop over items to create unique identifiers */
204 vp = pairfind(request->packet->vps, cur->dattr->attr);
207 * This was changed in 2.x, but it's still
210 if ((cur->dattr->attr == PW_CLIENT_IP_ADDRESS) &&
211 (request->packet->src_ipaddr.af == AF_INET)) {
212 memset(&hack, 0, sizeof(hack));
213 hack.name = cur->dattr->name;
214 hack.attribute = cur->dattr->attr;
215 hack.type = cur->dattr->type;
216 hack.operator = T_OP_EQ;
218 hack.lvalue = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
221 RDEBUG2("WARNING: Attribute %s was not found in request, unique ID MAY be inconsistent", cur->dattr->name);
224 length = vp_prints(p, left, vp);
225 left -= length + 1; /* account for ',' in between elements */
227 *(p++) = ','; /* ensure seperation of elements */
230 buffer[BUFFERLEN-left-1] = '\0';
232 RDEBUG2("Hashing '%s'", buffer);
233 /* calculate a 'unique' string based on the above information */
234 fr_md5_calc(md5_buf, (u_char *)buffer, (p - buffer));
235 sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x",
236 md5_buf[0], md5_buf[1], md5_buf[2], md5_buf[3],
237 md5_buf[4], md5_buf[5], md5_buf[6], md5_buf[7]);
239 RDEBUG2("Acct-Unique-Session-ID = \"%s\".", buffer);
241 vp = pairmake("Acct-Unique-Session-Id", buffer, 0);
243 radlog(L_ERR, "%s", fr_strerror());
244 return RLM_MODULE_FAIL;
247 /* add the (hopefully) unique session ID to the packet */
248 pairadd(&request->packet->vps, vp);
250 return RLM_MODULE_OK;
253 /* globally exported name */
254 module_t rlm_acct_unique = {
256 "Acct-Unique-Session-Id",
257 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
258 unique_instantiate, /* instantiation */
259 unique_detach, /* detach */
261 NULL, /* authentication */
262 add_unique_id, /* authorization */
263 add_unique_id, /* preaccounting */
264 add_unique_id, /* accounting */
265 NULL, /* checksimul */
266 NULL, /* pre-proxy */
267 NULL, /* post-proxy */