Move from authorize to post-auth
[freeradius.git] / src / modules / rlm_ippool / rlm_ippool.c
1 /*
2  * rlm_ippool.c
3  *
4  * Version:  $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2001  The FreeRADIUS server project
21  * Copyright 2002  Kostas Kalevras <kkalev@noc.ntua.gr>
22  * 
23  * March 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
24  * - Initial release
25  * April 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
26  * - Add support for the Pool-Name attribute
27  * May 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
28  * - Check the return value of a gdbm_fetch() we didn't check
29  * - Change the nas entry in the ippool_key structure from uint32 to string[64]
30  *   That should allow us to also use the NAS-Identifier attribute
31  * Sep 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
32  * - Move from authorize to post-auth
33  */
34
35 #include "config.h"
36 #include "autoconf.h"
37 #include "libradius.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #include "radiusd.h"
45 #include "modules.h"
46 #include "conffile.h"
47
48 #include <gdbm.h>
49 #include <time.h>
50 #include <netinet/in.h>
51
52 #ifdef NEEDS_GDBM_SYNC
53 #       define GDBM_SYNCOPT GDBM_SYNC
54 #else
55 #       define GDBM_SYNCOPT 0
56 #endif
57
58 #ifdef GDBM_NOLOCK
59 #define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT | GDBM_NOLOCK)
60 #else
61 #define GDBM_IPPOOL_OPTS (GDBM_SYNCOPT)
62 #endif
63
64 #ifndef HAVE_GDBM_FDESC
65 #define gdbm_fdesc(foo) (-1)
66 #endif
67
68 #define ALL_ONES 4294967295
69 #define MAX_NAS_NAME_SIZE 64
70
71 static const char rcsid[] = "$Id$";
72
73 /*
74  *      Define a structure for our module configuration.
75  *
76  *      These variables do not need to be in a structure, but it's
77  *      a lot cleaner to do so, and a pointer to the structure can
78  *      be used as the instance handle.
79  */
80 typedef struct rlm_ippool_t {
81         char *session_db;
82         char *ip_index;
83         char *name;
84         uint32_t range_start;
85         uint32_t range_stop;
86         uint32_t netmask;
87         int cache_size;
88         GDBM_FILE gdbm;
89         GDBM_FILE ip;
90         int fd;
91         int ip_fd;
92 } rlm_ippool_t;
93
94 typedef struct ippool_info {
95         uint32_t        ipaddr;
96         char            active;
97         char            cli[32];
98 } ippool_info;
99
100 typedef struct ippool_key {
101         char nas[MAX_NAS_NAME_SIZE];
102         int port;
103 } ippool_key;
104
105 /*
106  *      A mapping of configuration file names to internal variables.
107  *
108  *      Note that the string is dynamically allocated, so it MUST
109  *      be freed.  When the configuration file parse re-reads the string,
110  *      it free's the old one, and strdup's the new one, placing the pointer
111  *      to the strdup'd string into 'config.string'.  This gets around
112  *      buffer over-flows.
113  */
114 static CONF_PARSER module_config[] = {
115   { "session-db", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,session_db), NULL, NULL },
116   { "ip-index", PW_TYPE_STRING_PTR, offsetof(rlm_ippool_t,ip_index), NULL, NULL },
117   { "range-start", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_start), NULL, "0" },
118   { "range-stop", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,range_stop), NULL, "0" },
119   { "netmask", PW_TYPE_IPADDR, offsetof(rlm_ippool_t,netmask), NULL, "0" },
120   { "cache-size", PW_TYPE_INTEGER, offsetof(rlm_ippool_t,cache_size), NULL, "1000" },
121   { NULL, -1, 0, NULL, NULL }
122 };
123
124
125 /*
126  *      Do any per-module initialization that is separate to each
127  *      configured instance of the module.  e.g. set up connections
128  *      to external databases, read configuration files, set up
129  *      dictionary entries, etc.
130  *
131  *      If configuration information is given in the config section
132  *      that must be referenced in later calls, store a handle to it
133  *      in *instance otherwise put a null pointer there.
134  */
135 static int ippool_instantiate(CONF_SECTION *conf, void **instance)
136 {
137         rlm_ippool_t *data;
138         int cache_size;
139         ippool_info entry;
140         ippool_key key;
141         datum key_datum;
142         datum data_datum;
143         int i,j;
144         const char *cli = "0";
145         char *pool_name = NULL;
146         
147         /*
148          *      Set up a storage area for instance data
149          */
150         data = rad_malloc(sizeof(*data));
151
152         /*
153          *      If the configuration parameters can't be parsed, then
154          *      fail.
155          */
156         if (cf_section_parse(conf, data, module_config) < 0) {
157                 free(data);
158                 return -1;
159         }
160         cache_size = data->cache_size;
161
162         if (data->session_db == NULL) {
163                 radlog(L_ERR, "rlm_ippool: 'session-db' must be set.");
164                 free(data);
165                 return -1;
166         }
167         if (data->ip_index == NULL) {
168                 radlog(L_ERR, "rlm_ippool: 'ip-index' must be set.");
169                 free(data);
170                 return -1;
171         }
172         data->range_start = htonl(data->range_start);
173         data->range_stop = htonl(data->range_stop);
174         data->netmask = htonl(data->netmask);
175         if (data->range_start == 0 || data->range_stop == 0 || \
176                          data->range_start >= data->range_stop ) {
177                 radlog(L_ERR, "rlm_ippool: Invalid configuration data given.");
178                 free(data);
179                 return -1;
180         }
181         data->gdbm = gdbm_open(data->session_db, sizeof(int),
182                         GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
183         if (data->gdbm == NULL) {
184                 radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",
185                                 data->session_db, strerror(errno));
186                 return -1;
187         }
188         if (data->fd >= 0) data->fd = gdbm_fdesc(data->gdbm);
189
190         data->ip = gdbm_open(data->ip_index, sizeof(int),
191                         GDBM_WRCREAT | GDBM_IPPOOL_OPTS, 0600, NULL);
192         if (data->ip == NULL) {
193                 radlog(L_ERR, "rlm_ippool: Failed to open file %s: %s",
194                                 data->ip_index, strerror(errno));
195                 return -1;
196         }
197         if (data->ip_fd >= 0) data->ip_fd = gdbm_fdesc(data->ip);
198
199         if (gdbm_setopt(data->gdbm, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
200                 radlog(L_ERR, "rlm_ippool: Failed to set cache size");
201         if (gdbm_setopt(data->ip, GDBM_CACHESIZE, &cache_size, sizeof(int)) == -1)
202                 radlog(L_ERR, "rlm_ippool: Failed to set cache size");
203
204         if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
205         key_datum = gdbm_firstkey(data->gdbm);
206         if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
207         if (key_datum.dptr == NULL){
208                         /*
209                          * If the database does not exist initialize it.
210                          * We set the nas/port pairs to not existent values and
211                          * active = 0
212                          */
213                 int rcode;
214                 uint32_t or_result;
215                 char str[32];
216                 const char *nas_init = "NOT_EXIST";
217
218                 DEBUG("rlm_ippool: Initializing database");
219                 for(i=data->range_start,j=-1;i<=data->range_stop;i++,j--){
220
221                         /*
222                          * Net and Broadcast addresses are excluded
223                          */
224                         or_result = i | data->netmask;
225                         if (or_result == data->netmask || or_result == ALL_ONES){
226                                 DEBUG("rlm_ippool: IP %s exlcluded",ip_ntoa(str,ntohl(i)));
227                                 continue;
228                         }
229                         
230                         strcpy(key.nas, nas_init);
231                         key.port = j;
232                         key_datum.dptr = (ippool_key *) &key;
233                         key_datum.dsize = sizeof(ippool_key);
234
235                         entry.ipaddr = ntohl(i);
236                         entry.active = 0;
237                         strcpy(entry.cli,cli);
238
239                         data_datum.dptr = (ippool_info *) &entry;
240                         data_datum.dsize = sizeof(ippool_info);
241
242                         if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
243                         rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
244                         if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
245                         if (rcode < 0) {
246                                 radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
247                                                 data->session_db, gdbm_strerror(gdbm_errno));
248                                 free(data);
249                                 gdbm_close(data->gdbm);
250                                 gdbm_close(data->ip);
251                                 return -1;
252                         }
253                 }
254         }
255         else
256                 free(key_datum.dptr);
257
258         /* Add the ip pool name */
259         data->name = NULL;
260         pool_name = cf_section_name2(conf);
261         if (pool_name != NULL)
262                 data->name = strdup(pool_name);
263
264         *instance = data;
265         
266         return 0;
267 }
268
269
270 /*
271  *      Check for an Accounting-Stop
272  *      If we find one and we have allocated an IP to this nas/port combination, deallocate it. 
273  */
274 static int ippool_accounting(void *instance, REQUEST *request)
275 {
276         rlm_ippool_t *data = (rlm_ippool_t *)instance;
277         datum key_datum;
278         datum data_datum;
279         int acctstatustype = 0;
280         int port = -1;
281         int rcode;
282         char nas[MAX_NAS_NAME_SIZE];
283         ippool_info entry;
284         ippool_key key;
285         int num = 0;
286         VALUE_PAIR *vp;
287         char str[32];
288
289
290         if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) != NULL)
291                 acctstatustype = vp->lvalue;
292         else {
293                 DEBUG("rlm_ippool: Could not find account status type in packet.");
294                 return RLM_MODULE_NOOP;
295         }
296         switch(acctstatustype){
297                 case PW_STATUS_STOP:
298                         if ((vp = pairfind(request->packet->vps, PW_NAS_PORT_ID)) != NULL)
299                                 port = vp->lvalue;
300                         else {
301                                 DEBUG("rlm_ippool: Could not find port number in packet.");
302                                 return RLM_MODULE_NOOP;
303                         }
304                         if ((vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS)) != NULL)
305                                 strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1);
306                         else {
307                                 if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL)
308                                         strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1);
309                                 else {
310                                         DEBUG("rlm_ippool: Could not find nas information in packet.");
311                                         return RLM_MODULE_NOOP;
312                                 }
313                         }
314                         break;
315                 default:
316                         /* We don't care about any other accounting packet */
317
318                         return RLM_MODULE_NOOP;
319         }
320
321         strncpy(key.nas,nas,MAX_NAS_NAME_SIZE - 1);
322         key.port = port;
323         key_datum.dptr = (ippool_key *) &key;
324         key_datum.dsize = sizeof(ippool_key);
325
326         if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
327         data_datum = gdbm_fetch(data->gdbm, key_datum);
328         if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
329         if (data_datum.dptr != NULL){
330
331                 /*
332                  * If the entry was found set active to zero
333                  */
334                 memcpy(&entry, data_datum.dptr, sizeof(int));
335                 free(data_datum.dptr);
336                 DEBUG("rlm_ippool: Deallocated entry for ip/port: %s/%d",ip_ntoa(str,entry.ipaddr),port);
337                 entry.active = 0;
338
339                 data_datum.dptr = (ippool_info *) &entry;
340                 data_datum.dsize = sizeof(ippool_info);
341
342                 if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
343                 rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
344                 if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
345                 if (rcode < 0) {
346                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
347                                         data->session_db, gdbm_strerror(gdbm_errno));
348                         return RLM_MODULE_FAIL;
349                 }
350
351                 /*
352                  * Decrease allocated count from the ip index
353                  */
354                 key_datum.dptr = (uint32_t *) &entry.ipaddr;
355                 key_datum.dsize = sizeof(uint32_t);
356                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
357                 data_datum = gdbm_fetch(data->ip, key_datum);
358                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
359                 if (data_datum.dptr != NULL){
360                         memcpy(&num, data_datum.dptr, sizeof(int));
361                         free(data_datum.dptr);
362                         if (num >0){
363                                 num--;
364                                 DEBUG("rlm_ippool: num: %d",num);
365                                 data_datum.dptr = (int *) &num;
366                                 data_datum.dsize = sizeof(int);
367                                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
368                                 rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
369                                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
370                                 if (rcode < 0) {
371                                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
372                                                         data->ip_index, gdbm_strerror(gdbm_errno));
373                                         return RLM_MODULE_FAIL;
374                                 }
375                         }
376                 }
377         }
378
379         return RLM_MODULE_OK;
380 }
381
382 static int ippool_postauth(void *instance, REQUEST *request)
383 {
384         rlm_ippool_t *data = (rlm_ippool_t *) instance;
385         int port = 0;
386         int delete = 0;
387         int rcode;
388         int num = 0;
389         char nas[MAX_NAS_NAME_SIZE];
390         datum key_datum;
391         datum nextkey;
392         datum data_datum;
393         ippool_key key;
394         ippool_info entry;
395         VALUE_PAIR *vp;
396         char *cli = NULL;
397         char str[32];
398
399
400         /* quiet the compiler */
401         instance = instance;
402         request = request;
403
404         /* Check if Pool-Name attribute exists. If it exists check our name and
405          * run only if they match
406          */
407         if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL){
408                 if (data->name == NULL || strcmp(data->name,vp->strvalue))
409                         return RLM_MODULE_NOOP;
410         } else {
411                 DEBUG("rlm_ippool: Could not find Pool-Name attribute.");
412                 return RLM_MODULE_NOOP;
413         }
414
415         /*
416          * Get the nas ip address
417          */
418         if ((vp = pairfind(request->packet->vps, PW_NAS_IP_ADDRESS)) != NULL)
419                 strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1);
420         else{
421                 if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL)
422                         strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1);
423                 else{
424                         DEBUG("rlm_ippool: Could not find nas information.");
425                         return RLM_MODULE_NOOP;
426                 }
427         }
428
429         /*
430          * Find the caller id
431          */
432         if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)
433                 cli = vp->strvalue;
434
435         /*
436          * Find the port
437          */
438         if ((vp = pairfind(request->packet->vps, PW_NAS_PORT_ID)) != NULL){
439                 port = vp->lvalue;
440
441                 strncpy(key.nas,nas,MAX_NAS_NAME_SIZE -1 );
442                 key.port = port;        
443                 DEBUG("rlm_ippool: Searching for an entry for nas/port: %s/%d",nas,port);
444                 key_datum.dptr = (ippool_key *) &key;
445                 key_datum.dsize = sizeof(ippool_key);
446
447                 if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
448                 data_datum = gdbm_fetch(data->gdbm, key_datum);
449                 if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
450                 if (data_datum.dptr != NULL){
451                         /*
452                          * If there is a corresponding entry in the database with active=1 it is stale.
453                          * Set active to zero
454                          */
455                         memcpy(&entry, data_datum.dptr, sizeof(ippool_info));
456                         free(data_datum.dptr);
457                         if (entry.active){
458                                 DEBUG("rlm_ippool: Found a stale entry for ip/port: %s/%d",ip_ntoa(str,entry.ipaddr),port);
459                                 entry.active = 0;
460
461                                 data_datum.dptr = (ippool_info *) &entry;
462                                 data_datum.dsize = sizeof(ippool_info);
463
464                                 if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
465                                 rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
466                                 if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
467                                 if (rcode < 0) {
468                                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
469                                                 data->session_db, gdbm_strerror(gdbm_errno));
470                                         return RLM_MODULE_FAIL;
471                                 }
472                                 /* Decrease allocated count from the ip index */
473
474                                 key_datum.dptr = (uint32_t *) &entry.ipaddr;
475                                 key_datum.dsize = sizeof(uint32_t);
476                                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
477                                 data_datum = gdbm_fetch(data->ip, key_datum);
478                                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
479                                 if (data_datum.dptr != NULL){
480                                         memcpy(&num, data_datum.dptr, sizeof(int));
481                                         free(data_datum.dptr);
482                                         if (num >0){
483                                                 num--;
484                                                 DEBUG("rlm_ippool: num: %d",num);
485                                                 data_datum.dptr = (int *) &num;
486                                                 data_datum.dsize = sizeof(int);
487                                                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
488                                                 rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
489                                                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
490                                                 if (rcode < 0) {
491                                                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
492                                                                         data->ip_index, gdbm_strerror(gdbm_errno));
493                                                         return RLM_MODULE_FAIL;
494                                                 }
495                                         }
496                                 }
497                         }
498                 }
499         }
500         /*
501          * If there is a Framed-IP-Address attribute in the reply do nothing
502          */
503         if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL)
504                 return RLM_MODULE_NOOP;
505
506         /*
507          * Walk through the database searching for an active=0 entry.
508          */
509
510         if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
511         key_datum = gdbm_firstkey(data->gdbm);
512         while(key_datum.dptr){
513                 data_datum = gdbm_fetch(data->gdbm, key_datum);
514                 if (data_datum.dptr){
515                         memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
516                         free(data_datum.dptr);  
517                         /*
518                         * If we find an entry for the same caller-id and nas with active=1
519                         * then we use that for multilink (MPPP) to work properly.
520                         */
521                         if (cli != NULL && strcmp(entry.cli,cli) == 0 && entry.active){
522                                 memcpy(&key,key_datum.dptr,sizeof(ippool_key));
523                                 if (!strcmp(key.nas,nas))
524                                         break;
525                         }
526                         if (entry.active == 0){
527                                 datum tmp;              
528
529                                 tmp.dptr = (uint32_t *) &entry.ipaddr;
530                                 tmp.dsize = sizeof(uint32_t);
531                                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
532                                 data_datum = gdbm_fetch(data->ip, tmp);
533                                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
534
535                                 /*
536                                  * If we find an entry in the ip index and the number is zero (meaning
537                                  * that we haven't allocated the same ip address to another nas/port pair)
538                                  * or if we don't find an entry then delete the session entry so
539                                  * that we can change the key (nas/port)
540                                  * Else we don't delete the session entry since we haven't yet deallocated the
541                                  * corresponding ip address and we continue our search.
542                                  */
543
544                                 if (data_datum.dptr){
545                                         memcpy(&num,data_datum.dptr, sizeof(int));
546                                         free(data_datum.dptr);
547                                         if (num == 0){
548                                                 delete = 1;
549                                                 break;
550                                         }
551                                 }
552                                 else{
553                                         delete = 1;
554                                         break;
555                                 }
556                         }
557                 }
558                 nextkey = gdbm_nextkey(data->gdbm, key_datum);
559                 free(key_datum.dptr);
560                 key_datum = nextkey;
561         }
562         if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
563         /*
564          * If we have found a free entry set active to 1 then add a Framed-IP-Address attribute to
565          * the reply
566          */
567         if (key_datum.dptr){
568                 entry.active = 1;
569                 data_datum.dptr = (ippool_info *) &entry;
570                 data_datum.dsize = sizeof(ippool_info);
571
572                 if (delete){
573                         /*
574                          * Delete the entry so that we can change the key
575                          */
576                         if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
577                         gdbm_delete(data->gdbm, key_datum);
578                         if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
579                 }
580                 free(key_datum.dptr);
581                 strncpy(key.nas,nas,MAX_NAS_NAME_SIZE - 1);
582                 key.port = port;
583                 key_datum.dptr = (ippool_key *) &key;
584                 key_datum.dsize = sizeof(ippool_key);
585                 
586                 if (data->fd >= 0) rad_lockfd(data->fd, sizeof(int));
587                 rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
588                 if (data->fd >= 0) rad_unlockfd(data->fd, sizeof(int));
589                 if (rcode < 0) {
590                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
591                                 data->session_db, gdbm_strerror(gdbm_errno));
592                         return RLM_MODULE_FAIL;
593                 }
594
595                 /* Increase the ip index count */
596                 key_datum.dptr = (uint32_t *) &entry.ipaddr;
597                 key_datum.dsize = sizeof(uint32_t);     
598                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
599                 data_datum = gdbm_fetch(data->ip, key_datum);
600                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
601                 if (data_datum.dptr){
602                         memcpy(&num,data_datum.dptr,sizeof(int));
603                         free(data_datum.dptr);
604                 }
605                 num++;
606                 DEBUG("rlm_ippool: num: %d",num);
607                 data_datum.dptr = (int *) &num;
608                 data_datum.dsize = sizeof(int);
609                 if (data->ip_fd >= 0) rad_lockfd(data->ip_fd, sizeof(int));
610                 rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
611                 if (data->ip_fd >= 0) rad_unlockfd(data->ip_fd, sizeof(int));
612                 if (rcode < 0) {
613                         radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
614                                 data->ip_index, gdbm_strerror(gdbm_errno));
615                         return RLM_MODULE_FAIL;
616                 }
617                         
618
619                 DEBUG("rlm_ippool: Allocated ip %s to client on nas %s,port %d",ip_ntoa(str,entry.ipaddr),
620                                 key.nas,port);
621                 if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
622                         radlog(L_ERR|L_CONS, "no memory");
623                         return RLM_MODULE_NOOP;
624                 }
625                 vp->lvalue = entry.ipaddr;
626                 pairadd(&request->reply->vps, vp);
627         }
628         else{
629                 DEBUG("rlm_ippool: No available ip addresses in pool.");
630                 return RLM_MODULE_NOOP;
631         }
632
633         return RLM_MODULE_OK;
634 }
635
636 static int ippool_detach(void *instance)
637 {
638         rlm_ippool_t *data = (rlm_ippool_t *) instance;
639
640         gdbm_close(data->gdbm);
641         gdbm_close(data->ip);
642         free(data->session_db);
643         free(data->ip_index);
644
645         free(instance);
646         return 0;
647 }
648
649 /*
650  *      The module name should be the only globally exported symbol.
651  *      That is, everything else should be 'static'.
652  *
653  *      If the module needs to temporarily modify it's instantiation
654  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
655  *      The server will then take care of ensuring that the module
656  *      is single-threaded.
657  */
658 module_t rlm_ippool = {
659         "IPPOOL",       
660         RLM_TYPE_THREAD_SAFE,           /* type */
661         NULL,                           /* initialization */
662         ippool_instantiate,             /* instantiation */
663         {
664                 NULL,                   /* authentication */
665                 NULL,                   /* authorization */
666                 NULL,                   /* preaccounting */
667                 ippool_accounting,      /* accounting */
668                 NULL,                   /* checksimul */
669                 NULL,                   /* pre-proxy */
670                 NULL,                   /* post-proxy */
671                 ippool_postauth         /* post-auth */
672         },
673         ippool_detach,                  /* detach */
674         NULL,                           /* destroy */
675 };