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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Copyright 2000 The FreeRADIUS server project
22 #include "libradius.h"
32 * Room for at least 16 attributes.
34 #define BUFFERLEN 4096
36 static const char rcsid[] = "$Id$";
38 typedef struct rlm_acct_unique_list_t {
40 struct rlm_acct_unique_list_t *next;
41 } rlm_acct_unique_list_t;
43 typedef struct rlm_acct_unique_t {
45 rlm_acct_unique_list_t *head;
48 static CONF_PARSER module_config[] = {
49 { "key", PW_TYPE_STRING_PTR, offsetof(rlm_acct_unique_t,key), NULL, NULL },
50 { NULL, -1, 0, NULL, NULL } /* end the list */
54 * Add an attribute to the list.
56 static void unique_add_attr(rlm_acct_unique_t *inst, DICT_ATTR *dattr)
58 rlm_acct_unique_list_t *new;
60 new = rad_malloc(sizeof(*new));
61 memset(new, 0, sizeof(*new));
63 /* Assign the attr to our new structure */
66 new->next = inst->head;
73 static int unique_parse_key(rlm_acct_unique_t *inst, char *key)
75 char *ptr, *prev, *keyptr;
82 /* Let's remove spaces in the string */
90 if((a = dict_attrbyname(prev)) == NULL) {
91 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
96 unique_add_attr(inst, a);
99 if((a = dict_attrbyname(prev)) == NULL) {
100 radlog(L_ERR, "rlm_acct_unique: Cannot find attribute '%s' in dictionary", prev);
103 unique_add_attr(inst, a);
117 * Needed before instantiate for cleanup.
119 static int unique_detach(void *instance)
121 rlm_acct_unique_t *inst = instance;
122 rlm_acct_unique_list_t *this, *next;
125 for (this = inst->head; this != NULL; this = next) {
134 static int unique_instantiate(CONF_SECTION *conf, void **instance)
136 rlm_acct_unique_t *inst;
139 * Set up a storage area for instance data
141 inst = rad_malloc(sizeof(*inst));
142 memset(inst, 0, sizeof(*inst));
144 if (cf_section_parse(conf, inst, module_config) < 0) {
150 * Check to see if 'key' has something in it
153 radlog(L_ERR,"rlm_acct_unique: Cannot find value for 'key' in configuration.");
159 * Go thru the list of keys and build attr_list;
161 if (unique_parse_key(inst, inst->key) < 0) {
162 unique_detach(inst); /* clean up memory */
172 * Create a (hopefully) unique Acct-Unique-Session-Id from
173 * attributes listed in 'key' from radiusd.conf
175 static int add_unique_id(void *instance, REQUEST *request)
177 char buffer[BUFFERLEN];
183 rlm_acct_unique_t *inst = instance;
184 rlm_acct_unique_list_t *cur;
186 /* initialize variables */
193 * A unique ID already exists: don't do anything.
195 vp = pairfind(request->packet->vps, PW_ACCT_UNIQUE_SESSION_ID);
197 return RLM_MODULE_NOOP;
200 /* loop over items to create unique identifiers */
202 vp = pairfind(request->packet->vps, cur->dattr->attr);
204 DEBUG2("rlm_acct_unique: WARNING: Attribute %s was not found in request, unique ID MAY be inconsistent", cur->dattr->name);
206 length = vp_prints(p, left, vp);
207 left -= length + 1; /* account for ',' in between elements */
209 *(p++) = ','; /* ensure seperation of elements */
212 buffer[BUFFERLEN-left-1] = '\0';
214 DEBUG2("rlm_acct_unique: Hashing '%s'", buffer);
215 /* calculate a 'unique' string based on the above information */
216 librad_md5_calc(md5_buf, (u_char *)buffer, (p - buffer));
217 sprintf(buffer, "%02x%02x%02x%02x%02x%02x%02x%02x",
218 md5_buf[0], md5_buf[1], md5_buf[2], md5_buf[3],
219 md5_buf[4], md5_buf[5], md5_buf[6], md5_buf[7]);
221 DEBUG2("rlm_acct_unique: Acct-Unique-Session-ID = \"%s\".", buffer);
223 vp = pairmake("Acct-Unique-Session-Id", buffer, 0);
225 radlog(L_ERR, "%s", librad_errstr);
226 return RLM_MODULE_FAIL;
229 /* add the (hopefully) unique session ID to the packet */
230 pairadd(&request->packet->vps, vp);
232 return RLM_MODULE_OK;
235 /* globally exported name */
236 module_t rlm_acct_unique = {
237 "Acct-Unique-Session-Id",
238 0, /* type: reserved */
239 NULL, /* initialization */
240 unique_instantiate, /* instantiation */
242 NULL, /* authentication */
243 add_unique_id, /* authorization */
244 add_unique_id, /* preaccounting */
245 add_unique_id, /* accounting */
246 NULL, /* checksimul */
247 NULL, /* pre-proxy */
248 NULL, /* post-proxy */
251 unique_detach, /* detach */