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/autoconf.h>
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/modules.h>
35 * Room for at least 16 attributes.
37 #define BUFFERLEN 4096
39 typedef struct rlm_acct_unique_list_t {
41 struct rlm_acct_unique_list_t *next;
42 } rlm_acct_unique_list_t;
44 typedef struct rlm_acct_unique_t {
46 rlm_acct_unique_list_t *head;
49 static const CONF_PARSER module_config[] = {
50 { "key", PW_TYPE_STRING_PTR, offsetof(rlm_acct_unique_t,key), NULL, NULL },
51 { NULL, -1, 0, NULL, NULL } /* end the list */
55 * Add an attribute to the list.
57 static void unique_add_attr(rlm_acct_unique_t *inst, DICT_ATTR *dattr)
59 rlm_acct_unique_list_t *new;
61 new = rad_malloc(sizeof(*new));
62 memset(new, 0, sizeof(*new));
64 /* Assign the attr to our new structure */
67 new->next = inst->head;
74 static int unique_parse_key(rlm_acct_unique_t *inst, char *key)
76 char *ptr, *prev, *keyptr;
82 /* Let's remove spaces in the string */
84 if (isspace((int) *keyptr)) {
87 *(ptr++) = *(keyptr++);
98 if((a = dict_attrbyname(prev)) == NULL) {
99 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
104 unique_add_attr(inst, a);
107 if((a = dict_attrbyname(prev)) == NULL) {
108 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
111 unique_add_attr(inst, a);
125 * Needed before instantiate for cleanup.
127 static int unique_detach(void *instance)
129 rlm_acct_unique_t *inst = instance;
130 rlm_acct_unique_list_t *this, *next;
133 for (this = inst->head; this != NULL; this = next) {
142 static int unique_instantiate(CONF_SECTION *conf, void **instance)
144 rlm_acct_unique_t *inst;
147 * Set up a storage area for instance data
149 inst = rad_malloc(sizeof(*inst));
150 memset(inst, 0, sizeof(*inst));
152 if (cf_section_parse(conf, inst, module_config) < 0) {
158 * Check to see if 'key' has something in it
161 radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
167 * Go thru the list of keys and build attr_list;
169 if (unique_parse_key(inst, inst->key) < 0) {
170 unique_detach(inst); /* clean up memory */
180 * Create a (hopefully) unique Acct-Unique-Session-Id from
181 * attributes listed in 'key' from radiusd.conf
183 static int add_unique_id(void *instance, REQUEST *request)
185 char buffer[BUFFERLEN];
191 rlm_acct_unique_t *inst = instance;
192 rlm_acct_unique_list_t *cur;
194 /* initialize variables */
201 * A unique ID already exists: don't do anything.
203 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
205 return RLM_MODULE_NOOP;
208 /* loop over items to create unique identifiers */
210 vp = pairfind(request->packet->vps, cur->dattr->attr);
212 DEBUG2("rlm_acct_unique: WARNING: Attribute %s was not found in request, unique ID MAY be inconsistent", cur->dattr->name);
214 length = vp_prints(p, left, vp);
215 left -= length + 1; /* account for ',' in between elements */
217 *(p++) = ','; /* ensure seperation of elements */
220 buffer[BUFFERLEN-left-1] = '\0';
222 DEBUG2("rlm_acct_unique: Hashing '%s'", buffer);
223 /* calculate a 'unique' string based on the above information */
224 librad_md5_calc(md5_buf, (u_char *)buffer, (p - buffer));
225 sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x",
226 md5_buf[0], md5_buf[1], md5_buf[2], md5_buf[3],
227 md5_buf[4], md5_buf[5], md5_buf[6], md5_buf[7]);
229 DEBUG2("rlm_acct_unique: Acct-Unique-Session-ID = \"%s\".", buffer);
231 vp = pairmake("Acct-Unique-Session-Id", buffer, 0);
233 radlog(L_ERR, "%s", librad_errstr);
234 return RLM_MODULE_FAIL;
237 /* add the (hopefully) unique session ID to the packet */
238 pairadd(&request->packet->vps, vp);
240 return RLM_MODULE_OK;
243 /* globally exported name */
244 module_t rlm_acct_unique = {
246 "Acct-Unique-Session-Id",
247 0, /* type: reserved */
248 unique_instantiate, /* instantiation */
249 unique_detach, /* detach */
251 NULL, /* authentication */
252 add_unique_id, /* authorization */
253 add_unique_id, /* preaccounting */
254 add_unique_id, /* accounting */
255 NULL, /* checksimul */
256 NULL, /* pre-proxy */
257 NULL, /* post-proxy */