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++);
93 if((a = dict_attrbyname(prev)) == NULL) {
94 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
99 unique_add_attr(inst, a);
102 if((a = dict_attrbyname(prev)) == NULL) {
103 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
106 unique_add_attr(inst, a);
120 * Needed before instantiate for cleanup.
122 static int unique_detach(void *instance)
124 rlm_acct_unique_t *inst = instance;
125 rlm_acct_unique_list_t *this, *next;
127 for (this = inst->head; this != NULL; this = next) {
136 static int unique_instantiate(CONF_SECTION *conf, void **instance)
138 rlm_acct_unique_t *inst;
141 * Set up a storage area for instance data
143 inst = rad_malloc(sizeof(*inst));
144 memset(inst, 0, sizeof(*inst));
146 if (cf_section_parse(conf, inst, module_config) < 0) {
152 * Check to see if 'key' has something in it
155 radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
161 * Go thru the list of keys and build attr_list;
163 if (unique_parse_key(inst, inst->key) < 0) {
164 unique_detach(inst); /* clean up memory */
174 * Create a (hopefully) unique Acct-Unique-Session-Id from
175 * attributes listed in 'key' from radiusd.conf
177 static int add_unique_id(void *instance, REQUEST *request)
179 char buffer[BUFFERLEN];
185 rlm_acct_unique_t *inst = instance;
186 rlm_acct_unique_list_t *cur;
188 /* initialize variables */
195 * A unique ID already exists: don't do anything.
197 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
199 return RLM_MODULE_NOOP;
202 /* loop over items to create unique identifiers */
204 vp = pairfind(request->packet->vps, cur->dattr->attr);
206 DEBUG2("rlm_acct_unique: WARNING: Attribute %s was not found in request, unique ID MAY be inconsistent", cur->dattr->name);
208 length = vp_prints(p, left, vp);
209 left -= length + 1; /* account for ',' in between elements */
211 *(p++) = ','; /* ensure seperation of elements */
214 buffer[BUFFERLEN-left-1] = '\0';
216 DEBUG2("rlm_acct_unique: Hashing '%s'", buffer);
217 /* calculate a 'unique' string based on the above information */
218 librad_md5_calc(md5_buf, (u_char *)buffer, (p - buffer));
219 sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x",
220 md5_buf[0], md5_buf[1], md5_buf[2], md5_buf[3],
221 md5_buf[4], md5_buf[5], md5_buf[6], md5_buf[7]);
223 DEBUG2("rlm_acct_unique: Acct-Unique-Session-ID = \"%s\".", buffer);
225 vp = pairmake("Acct-Unique-Session-Id", buffer, 0);
227 radlog(L_ERR, "%s", librad_errstr);
228 return RLM_MODULE_FAIL;
231 /* add the (hopefully) unique session ID to the packet */
232 pairadd(&request->packet->vps, vp);
234 return RLM_MODULE_OK;
237 /* globally exported name */
238 module_t rlm_acct_unique = {
240 "Acct-Unique-Session-Id",
241 RLM_TYPE_CHECK_CONFIG_SAFE, /* type */
242 unique_instantiate, /* instantiation */
243 unique_detach, /* detach */
245 NULL, /* authentication */
246 add_unique_id, /* authorization */
247 add_unique_id, /* preaccounting */
248 add_unique_id, /* accounting */
249 NULL, /* checksimul */
250 NULL, /* pre-proxy */
251 NULL, /* post-proxy */