2 * rlm_sqlippool.c rlm_sqlippool - FreeRADIUS SQL IP Pool Module
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.
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.
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
20 * Copyright 2002 Globe.Net Communications Limited
21 * Copyright 2006 The FreeRADIUS server project
22 * Copyright 2006 Suntel Communications
26 #include "libradius.h"
32 #include <netinet/in.h>
41 static const char rcsid[] = "$Id$";
46 * Define a structure for our module configuration.
48 typedef struct rlm_sqlippool_t {
49 char *sql_instance_name;
57 /* We ended up removing the init
58 queries so that its up to user
59 to create the db structure and put the required
62 /* Allocation sequence */
63 char *allocate_begin; /* SQL query to begin */
64 char *allocate_clear; /* SQL query to clear an IP */
65 char *allocate_find; /* SQL query to find an unused IP */
66 char *allocate_update; /* SQL query to mark an IP as used */
67 char *allocate_commit; /* SQL query to commit */
68 char *allocate_rollback; /* SQL query to rollback */
71 char *start_begin; /* SQL query to begin */
72 char *start_update; /* SQL query to update an IP entry */
73 char *start_commit; /* SQL query to commit */
74 char *start_rollback; /* SQL query to rollback */
77 char *alive_begin; /* SQL query to begin */
78 char *alive_update; /* SQL query to update an IP entry */
79 char *alive_commit; /* SQL query to commit */
80 char *alive_rollback; /* SQL query to rollback */
83 char *stop_begin; /* SQL query to begin */
84 char *stop_clear; /* SQL query to clear an IP */
85 char *stop_commit; /* SQL query to commit */
86 char *stop_rollback; /* SQL query to rollback */
89 char *on_begin; /* SQL query to begin */
90 char *on_clear; /* SQL query to clear an entire NAS */
91 char *on_commit; /* SQL query to commit */
92 char *on_rollback; /* SQL query to rollback */
95 char *off_begin; /* SQL query to begin */
96 char *off_clear; /* SQL query to clear an entire NAS */
97 char *off_commit; /* SQL query to commit */
98 char *off_rollback; /* SQL query to rollback */
100 #ifdef HAVE_PTHREAD_H
101 pthread_mutex_t dlock;
107 #ifndef HAVE_PTHREAD_H
109 * This is easier than ifdef's throughout the code.
111 #define pthread_mutex_init(_x, _y)
112 #define pthread_mutex_destroy(_x)
113 #define pthread_mutex_lock(_x)
114 #define pthread_mutex_unlock(_x)
119 * A mapping of configuration file names to internal variables.
121 * Note that the string is dynamically allocated, so it MUST
122 * be freed. When the configuration file parse re-reads the string,
123 * it free's the old one, and strdup's the new one, placing the pointer
124 * to the strdup'd string into 'config.string'. This gets around
127 static CONF_PARSER module_config[] = {
128 {"sql-instance-name",PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,sql_instance_name), NULL, "sql"},
130 { "lease-duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
132 { "pool-name" , PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, pool_name), NULL, ""},
134 { "allocate-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_begin), NULL, "BEGIN" },
135 { "allocate-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
136 { "allocate-find", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
137 { "allocate-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
138 { "allocate-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
139 { "allocate-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_rollback), NULL, "ROLLBACK" },
141 { "start-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "BEGIN" },
142 { "start-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
143 { "start-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_commit), NULL, "COMMIT" },
144 { "start-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_rollback), NULL, "ROLLBACK" },
146 { "alive-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "BEGIN" },
147 { "alive-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
148 { "alive-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
149 { "alive-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_rollback), NULL, "ROLLBACK" },
151 { "stop-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "BEGIN" },
152 { "stop-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
153 { "stop-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_commit), NULL, "COMMIT" },
154 { "stop-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_rollback), NULL, "ROLLBACK" },
156 { "on-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "BEGIN" },
157 { "on-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
158 { "on-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
159 { "on-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_rollback), NULL, "ROLLBACK" },
161 { "off-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "BEGIN" },
162 { "off-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
163 { "off-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
164 { "off-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_rollback), NULL, "ROLLBACK" },
166 { NULL, -1, 0, NULL, NULL }
170 * Replace %<whatever> in a string.
177 static int sqlippool_expand(char * out, int outlen, const char * fmt, void * instance, char * param, int param_len)
179 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
182 char tmp[40]; /* For temporary storing of integers */
187 for (p = fmt; *p ; p++) {
191 /* Calculate freespace in output */
192 freespace = outlen - (q - out);
197 if (c != '%' && c != '$' && c != '\\') {
199 * We check if we're inside an open brace. If we are
200 * then we assume this brace is NOT literal, but is
201 * a closing brace and apply it
203 if((c == '}') && openbraces) {
236 case 'P': /* pool name */
237 strNcpy(q, data->pool_name, freespace);
240 case 'I': /* IP address */
241 if (param && param_len > 0) {
242 if (param_len > freespace) {
243 strNcpy(q, param, freespace);
247 memcpy(q, param, param_len);
252 case 'J': /* lease duration */
253 sprintf(tmp, "%d", data->lease_duration);
254 strNcpy(q, tmp, freespace);
267 DEBUG2("sqlippool_expand: '%s'", out);
274 * Query the database executing a command with no result rows
276 static int sqlippool_command(const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
278 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
279 char expansion[MAX_STRING_LEN * 4];
280 char query[MAX_STRING_LEN * 4];
282 sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
285 * Do an xlat on the provided string
288 if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
289 radlog(L_ERR, "sqlippool_command: xlat failed.");
294 strcpy(query, expansion);
298 DEBUG2("sqlippool_command: '%s'", query);
300 if (rlm_sql_query(sqlsocket, data->sql_inst, query)){
301 radlog(L_ERR, "sqlippool_command: database query error");
305 (data->sql_inst->module->sql_finish_query)(sqlsocket, data->sql_inst->config);
310 * Query the database expecting a single result row
312 static int sqlippool_query1(char * out, int outlen, const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
314 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
315 char expansion[MAX_STRING_LEN * 4];
316 char query[MAX_STRING_LEN * 4];
320 sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
323 * Do an xlat on the provided string
326 if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
327 radlog(L_ERR, "sqlippool_command: xlat failed.");
333 strcpy(query, expansion);
337 DEBUG2("sqlippool_query1: '%s'", query);
339 if (rlm_sql_select_query(sqlsocket, data->sql_inst, query)){
340 radlog(L_ERR, "sqlippool_query1: database query error");
345 r = rlm_sql_fetch_row(sqlsocket, data->sql_inst);
346 (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config);
349 DEBUG("sqlippool_query1: SQL query did not succeed");
354 row = sqlsocket->row;
356 DEBUG("sqlippool_query1: SQL query did not return any results");
362 DEBUG("sqlippool_query1: row[0] returned NULL");
369 DEBUG("sqlippool_query1: insufficient string space");
374 strncpy(out, row[0], r);
380 static int sqlippool_initialize_sql(void * instance)
383 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
387 sqlsocket = sql_get_socket(data->sql_inst);
388 if (sqlsocket == NULL) {
389 DEBUG("rlm_sqlippool: cannot allocate sql connection for initialization sequence");
397 * Do any per-module initialization that is separate to each
398 * configured instance of the module. e.g. set up connections
399 * to external databases, read configuration files, set up
400 * dictionary entries, etc.
402 * If configuration information is given in the config section
403 * that must be referenced in later calls, store a handle to it
404 * in *instance otherwise put a null pointer there.
406 static int sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
408 rlm_sqlippool_t * data;
409 char * pool_name = NULL;
412 * Set up a storage area for instance data
414 data = rad_malloc(sizeof(*data));
415 memset(data, 0, sizeof(*data));
418 * If the configuration parameters can't be parsed, then
421 if (cf_section_parse(conf, data, module_config) < 0) {
426 if (data->sql_instance_name == NULL || strlen(data->sql_instance_name) == 0) {
427 radlog(L_ERR, "rlm_sqlippool: the 'sql-instance-name' variable must be set.");
433 * Check that all the queries are in place
436 if (data->allocate_clear == NULL || strlen(data->allocate_clear) == 0) {
437 radlog(L_ERR, "rlm_sqlippool: the 'allocate-clear' statement must be set.");
442 if (data->allocate_find == NULL || strlen(data->allocate_find) == 0) {
443 radlog(L_ERR, "rlm_sqlippool: the 'allocate_find' statement must be set.");
448 if (data->allocate_update == NULL || strlen(data->allocate_update) == 0) {
449 radlog(L_ERR, "rlm_sqlippool: the 'allocate_update' statement must be set.");
454 if (data->start_update == NULL || strlen(data->start_update) == 0) {
455 radlog(L_ERR, "rlm_sqlippool: the 'start-update' statement must be set.");
460 if (data->alive_update == NULL || strlen(data->alive_update) == 0) {
461 radlog(L_ERR, "rlm_sqlippool: the 'alive-update' statement must be set.");
466 if (data->stop_clear == NULL || strlen(data->stop_clear) == 0) {
467 radlog(L_ERR, "rlm_sqlippool: the 'stop-clear' statement must be set.");
472 if (data->on_clear == NULL || strlen(data->on_clear) == 0) {
473 radlog(L_ERR, "rlm_sqlippool: the 'on-clear' statement must be set.");
478 if (data->off_clear == NULL || strlen(data->off_clear) == 0) {
479 radlog(L_ERR, "rlm_sqlippool: the 'off-clear' statement must be set.");
484 pool_name = cf_section_name2(conf);
485 if (pool_name != NULL)
486 data->pool_name = strdup(pool_name);
488 data->pool_name = strdup("ippool");
490 if ( !(data->sql_inst = (SQL_INST *) (find_module_instance(data->sql_instance_name))->insthandle) )
492 radlog(L_ERR, "sqlippool_instantiate: failed to find sql instance named %s", data->sql_instance_name);
497 sqlippool_initialize_sql(data);
498 pthread_mutex_init(&data->dlock, NULL);
504 * Allocate an IP number from the pool.
506 static int sqlippool_postauth(void *instance, REQUEST * request)
508 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
509 char allocation[MAX_STRING_LEN];
511 uint32_t ip_allocation;
514 long self = (long) pthread_self();
517 * If there is a Framed-IP-Address attribute in the reply do nothing
519 if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) {
520 DEBUG("rlm_sqlippool: Framed-IP-Address already exists");
521 return RLM_MODULE_NOOP;
524 if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL) {
525 DEBUG("Value Of the Pool-Name is [%s] and its [%i] Chars \n", vp->strvalue, vp->length);
526 pthread_mutex_lock(&data->dlock);
527 strNcpy(data->pool_name, vp->strvalue, (vp->length + 1));
528 pthread_mutex_unlock(&data->dlock);
531 DEBUG("rlm_sqlippool: missing pool_name");
532 return RLM_MODULE_NOOP;
535 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
536 DEBUG("rlm_sqlippool: unknown NAS-IP-Address");
537 return RLM_MODULE_NOOP;
540 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
541 DEBUG("rlm_sqlippool: unknown NAS-Port");
542 return RLM_MODULE_NOOP;
545 sqlsocket = sql_get_socket(data->sql_inst);
546 if (sqlsocket == NULL) {
547 DEBUG("rlm_sqlippool: cannot allocate sql connection");
548 return RLM_MODULE_NOOP;
554 sqlippool_command(data->allocate_begin, sqlsocket, instance, request,
560 sqlippool_command(data->allocate_clear, sqlsocket, instance, request,
566 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
567 data->allocate_find, sqlsocket, instance, request,
569 radlog(L_INFO,"rlm_sqlippool: ip=[%s] len=%d", allocation, allocation_len);
571 if (allocation_len == 0)
576 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
579 DEBUG("rlm_sqlippool: IP number could not be allocated.");
580 sql_release_socket(data->sql_inst, sqlsocket);
581 return RLM_MODULE_NOOP;
584 ip_allocation = ip_addr(allocation);
585 if (ip_allocation == INADDR_NONE)
590 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
593 DEBUG("rlm_sqlippool: Invalid IP number [%s] returned from database query.", allocation);
594 sql_release_socket(data->sql_inst, sqlsocket);
595 return RLM_MODULE_NOOP;
601 sqlippool_command(data->allocate_update, sqlsocket, instance, request,
602 allocation, allocation_len);
604 DEBUG("rlm_sqlippool: Allocated IP %s [%08x]", allocation, ip_allocation);
606 if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
607 radlog(L_ERR|L_CONS, "no memory");
608 sql_release_socket(data->sql_inst, sqlsocket);
609 return RLM_MODULE_NOOP;
611 vp->lvalue = ip_allocation;
612 pairadd(&request->reply->vps, vp);
617 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
620 sql_release_socket(data->sql_inst, sqlsocket);
621 return RLM_MODULE_OK;
624 static int sqlippool_accounting_start(void * instance, REQUEST * request)
626 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
629 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
630 DEBUG("rlm_ippool: Could not find port number in packet.");
631 return RLM_MODULE_NOOP;
634 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
635 DEBUG("rlm_ippool: Could not find nas information in packet.");
636 return RLM_MODULE_NOOP;
639 sqlsocket = sql_get_socket(data->sql_inst);
640 if (sqlsocket == NULL) {
641 DEBUG("rlm_sqlippool: cannot allocate sql connection");
642 return RLM_MODULE_NOOP;
648 sqlippool_command(data->start_begin, sqlsocket, instance, request,
654 sqlippool_command(data->start_update, sqlsocket, instance, request,
660 sqlippool_command(data->start_commit, sqlsocket, instance, request,
663 sql_release_socket(data->sql_inst, sqlsocket);
665 return RLM_MODULE_OK;
668 static int sqlippool_accounting_alive(void * instance, REQUEST * request)
670 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
673 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
674 DEBUG("rlm_ippool: Could not find port number in packet.");
675 return RLM_MODULE_NOOP;
678 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
679 DEBUG("rlm_ippool: Could not find nas information in packet.");
680 return RLM_MODULE_NOOP;
683 sqlsocket = sql_get_socket(data->sql_inst);
684 if (sqlsocket == NULL) {
685 DEBUG("rlm_sqlippool: cannot allocate sql connection");
686 return RLM_MODULE_NOOP;
692 sqlippool_command(data->alive_begin, sqlsocket, instance, request,
698 sqlippool_command(data->alive_update, sqlsocket, instance, request,
704 sqlippool_command(data->alive_commit, sqlsocket, instance, request,
707 sql_release_socket(data->sql_inst, sqlsocket);
709 return RLM_MODULE_OK;
712 static int sqlippool_accounting_stop(void * instance, REQUEST * request)
714 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
717 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
718 DEBUG("rlm_ippool: Could not find port number in packet.");
719 return RLM_MODULE_NOOP;
722 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
723 DEBUG("rlm_ippool: Could not find nas information in packet.");
724 return RLM_MODULE_NOOP;
727 sqlsocket = sql_get_socket(data->sql_inst);
728 if (sqlsocket == NULL) {
729 DEBUG("rlm_sqlippool: cannot allocate sql connection");
730 return RLM_MODULE_NOOP;
736 sqlippool_command(data->stop_begin, sqlsocket, instance, request,
742 sqlippool_command(data->stop_clear, sqlsocket, instance, request,
748 sqlippool_command(data->stop_commit, sqlsocket, instance, request,
751 sql_release_socket(data->sql_inst, sqlsocket);
753 return RLM_MODULE_OK;
756 static int sqlippool_accounting_on(void * instance, REQUEST * request)
758 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
761 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
762 DEBUG("rlm_ippool: Could not find nas information in packet.");
763 return RLM_MODULE_NOOP;
766 sqlsocket = sql_get_socket(data->sql_inst);
767 if (sqlsocket == NULL) {
768 DEBUG("rlm_sqlippool: cannot allocate sql connection");
769 return RLM_MODULE_NOOP;
775 sqlippool_command(data->on_begin, sqlsocket, instance, request,
781 sqlippool_command(data->on_clear, sqlsocket, instance, request,
787 sqlippool_command(data->on_commit, sqlsocket, instance, request,
790 sql_release_socket(data->sql_inst, sqlsocket);
792 return RLM_MODULE_OK;
795 static int sqlippool_accounting_off(void * instance, REQUEST * request)
797 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
800 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
801 DEBUG("rlm_ippool: Could not find nas information in packet.");
802 return RLM_MODULE_NOOP;
805 sqlsocket = sql_get_socket(data->sql_inst);
806 if (sqlsocket == NULL) {
807 DEBUG("rlm_sqlippool: cannot allocate sql connection");
808 return RLM_MODULE_NOOP;
814 sqlippool_command(data->off_begin, sqlsocket, instance, request,
820 sqlippool_command(data->off_clear, sqlsocket, instance, request,
826 sqlippool_command(data->off_commit, sqlsocket, instance, request,
829 sql_release_socket(data->sql_inst, sqlsocket);
831 return RLM_MODULE_OK;
835 * Check for an Accounting-Stop
836 * If we find one and we have allocated an IP to this nas/port combination, deallocate it.
838 static int sqlippool_accounting(void * instance, REQUEST * request)
841 int acct_status_type;
843 vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
845 DEBUG("rlm_sqlippool: Could not find account status type in packet.");
846 return RLM_MODULE_NOOP;
848 acct_status_type = vp->lvalue;
850 switch (acct_status_type) {
851 case PW_STATUS_START:
852 return sqlippool_accounting_start(instance, request);
854 case PW_STATUS_ALIVE:
855 return sqlippool_accounting_alive(instance, request);
858 return sqlippool_accounting_stop(instance, request);
860 case PW_STATUS_ACCOUNTING_ON:
861 return sqlippool_accounting_on(instance, request);
863 case PW_STATUS_ACCOUNTING_OFF:
864 return sqlippool_accounting_off(instance, request);
867 /* We don't care about any other accounting packet */
868 return RLM_MODULE_NOOP;
872 static int sqlippool_detach(void *instance)
874 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
876 free(data->sql_instance_name);
877 free(data->pool_name);
879 free(data->allocate_begin);
880 free(data->allocate_clear);
881 free(data->allocate_find);
882 free(data->allocate_update);
883 free(data->allocate_commit);
884 free(data->allocate_rollback);
886 free(data->start_begin);
887 free(data->start_update);
888 free(data->start_commit);
889 free(data->start_rollback);
891 free(data->alive_begin);
892 free(data->alive_update);
893 free(data->alive_commit);
894 free(data->alive_rollback);
896 free(data->stop_begin);
897 free(data->stop_clear);
898 free(data->stop_commit);
899 free(data->stop_rollback);
901 free(data->on_begin);
902 free(data->on_clear);
903 free(data->on_commit);
904 free(data->on_rollback);
906 free(data->off_begin);
907 free(data->off_clear);
908 free(data->off_commit);
909 free(data->off_rollback);
915 * The module name should be the only globally exported symbol.
916 * That is, everything else should be 'static'.
918 * If the module needs to temporarily modify it's instantiation
919 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
920 * The server will then take care of ensuring that the module
921 * is single-threaded.
923 module_t rlm_sqlippool = {
925 RLM_TYPE_THREAD_SAFE, /* type */
926 NULL, /* initialization */
927 sqlippool_instantiate, /* instantiation */
929 NULL, /* authentication */
930 NULL, /* authorization */
931 NULL, /* preaccounting */
932 sqlippool_accounting, /* accounting */
933 NULL, /* checksimul */
934 NULL, /* pre-proxy */
935 NULL, /* post-proxy */
936 sqlippool_postauth /* post-auth */
938 sqlippool_detach, /* detach */