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