6 * Copyright 2002 Globe.Net Communications Limited
10 #include <freeradius-devel/autoconf.h>
11 #include <freeradius-devel/libradius.h>
17 #include <netinet/in.h>
19 #include <freeradius-devel/radiusd.h>
20 #include <freeradius-devel/modules.h>
21 #include <freeradius-devel/modpriv.h>
26 static const char rcsid[] = "$Id$";
29 * Define a structure for our module configuration.
31 typedef struct rlm_sqlippool_t {
32 char *sql_instance_name;
43 /* Initialization sequence */
44 char *init_begin; /* SQL query to begin */
45 char *init_query; /* SQL query to select records */
46 char *init_delete; /* SQL query to delete records */
47 char *init_insert; /* SQL query to insert records */
48 char *init_commit; /* SQL query to commit */
49 char *init_rollback; /* SQL query to rollback */
51 /* Allocation sequence */
52 char *allocate_begin; /* SQL query to begin */
53 char *allocate_clear; /* SQL query to clear an IP */
54 char *allocate_find; /* SQL query to find an unused IP */
55 char *allocate_update; /* SQL query to mark an IP as used */
56 char *allocate_commit; /* SQL query to commit */
57 char *allocate_rollback; /* SQL query to rollback */
60 char *start_begin; /* SQL query to begin */
61 char *start_update; /* SQL query to update an IP entry */
62 char *start_commit; /* SQL query to commit */
63 char *start_rollback; /* SQL query to rollback */
66 char *alive_begin; /* SQL query to begin */
67 char *alive_update; /* SQL query to update an IP entry */
68 char *alive_commit; /* SQL query to commit */
69 char *alive_rollback; /* SQL query to rollback */
72 char *stop_begin; /* SQL query to begin */
73 char *stop_clear; /* SQL query to clear an IP */
74 char *stop_commit; /* SQL query to commit */
75 char *stop_rollback; /* SQL query to rollback */
78 char *on_begin; /* SQL query to begin */
79 char *on_clear; /* SQL query to clear an entire NAS */
80 char *on_commit; /* SQL query to commit */
81 char *on_rollback; /* SQL query to rollback */
84 char *off_begin; /* SQL query to begin */
85 char *off_clear; /* SQL query to clear an entire NAS */
86 char *off_commit; /* SQL query to commit */
87 char *off_rollback; /* SQL query to rollback */
91 * A mapping of configuration file names to internal variables.
93 * Note that the string is dynamically allocated, so it MUST
94 * be freed. When the configuration file parse re-reads the string,
95 * it free's the old one, and strdup's the new one, placing the pointer
96 * to the strdup'd string into 'config.string'. This gets around
99 static CONF_PARSER module_config[] = {
100 {"sql-instance-name",PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,sql_instance_name), NULL, "sql"},
102 { "range-start", PW_TYPE_IPADDR, offsetof(rlm_sqlippool_t,range_start), NULL, "0" },
103 { "range-stop", PW_TYPE_IPADDR, offsetof(rlm_sqlippool_t,range_stop), NULL, "0" },
104 { "netmask", PW_TYPE_IPADDR, offsetof(rlm_sqlippool_t,netmask), NULL, "0" },
105 { "lease-duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
107 { "init-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_begin), NULL, "BEGIN" },
108 { "init-query", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_query), NULL, "" },
109 { "init-delete", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_delete), NULL, "" },
110 { "init-insert", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_insert), NULL, "" },
111 { "init-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_commit), NULL, "COMMIT" },
112 { "init-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,init_rollback), NULL, "ROLLBACK" },
114 { "allocate-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_begin), NULL, "BEGIN" },
115 { "allocate-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
116 { "allocate-find", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
117 { "allocate-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
118 { "allocate-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
119 { "allocate-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,allocate_rollback), NULL, "ROLLBACK" },
121 { "start-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "BEGIN" },
122 { "start-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
123 { "start-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_commit), NULL, "COMMIT" },
124 { "start-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_rollback), NULL, "ROLLBACK" },
126 { "alive-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "BEGIN" },
127 { "alive-update", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
128 { "alive-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
129 { "alive-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_rollback), NULL, "ROLLBACK" },
131 { "stop-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "BEGIN" },
132 { "stop-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
133 { "stop-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_commit), NULL, "COMMIT" },
134 { "stop-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_rollback), NULL, "ROLLBACK" },
136 { "on-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "BEGIN" },
137 { "on-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
138 { "on-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
139 { "on-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_rollback), NULL, "ROLLBACK" },
141 { "off-begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "BEGIN" },
142 { "off-clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
143 { "off-commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
144 { "off-rollback", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_rollback), NULL, "ROLLBACK" },
146 { NULL, -1, 0, NULL, NULL }
150 * Replace %<whatever> in a string.
157 static int sqlippool_expand(char * out, int outlen, const char * fmt, void * instance, char * param, int param_len)
159 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
162 char tmp[40]; /* For temporary storing of integers */
167 for (p = fmt; *p ; p++) {
171 /* Calculate freespace in output */
172 freespace = outlen - (q - out);
177 if (c != '%' && c != '$' && c != '\\') {
179 * We check if we're inside an open brace. If we are
180 * then we assume this brace is NOT literal, but is
181 * a closing brace and apply it
183 if((c == '}') && openbraces) {
216 case 'P': /* pool name */
217 strNcpy(q, data->pool_name, freespace);
220 case 'I': /* IP address */
221 if (param && param_len > 0) {
222 if (param_len > freespace) {
223 strNcpy(q, param, freespace);
227 memcpy(q, param, param_len);
232 case 'J': /* lease duration */
233 sprintf(tmp, "%d", data->lease_duration);
234 strNcpy(q, tmp, freespace);
247 DEBUG2("sqlippool_expand: '%s'", out);
254 * Query the database executing a command with no result rows
256 static int sqlippool_command(const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
258 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
259 char expansion[MAX_STRING_LEN * 4];
260 char query[MAX_STRING_LEN * 4];
262 sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
265 * Do an xlat on the provided string
268 if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
269 radlog(L_ERR, "sqlippool_command: xlat failed.");
274 strcpy(query, expansion);
278 DEBUG2("sqlippool_command: '%s'", query);
281 if (rlm_sql_query(sqlsocket, data->sql_inst, query)){
282 radlog(L_ERR, "sqlippool_command: database query error");
286 (data->sql_inst->module->sql_finish_query)(sqlsocket, data->sql_inst->config);
292 * Query the database expecting a single result row
294 static int sqlippool_query1(char * out, int outlen, const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
296 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
297 char expansion[MAX_STRING_LEN * 4];
298 char query[MAX_STRING_LEN * 4];
302 sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
305 * Do an xlat on the provided string
308 if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
309 radlog(L_ERR, "sqlippool_command: xlat failed.");
315 strcpy(query, expansion);
319 DEBUG2("sqlippool_query1: '%s'", query);
322 if (rlm_sql_select_query(sqlsocket, data->sql_inst, query)){
323 radlog(L_ERR, "sqlippool_query1: database query error");
328 r = rlm_sql_fetch_row(sqlsocket, data->sql_inst);
329 (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config);
332 DEBUG("sqlippool_query1: SQL query did not succeed");
337 row = sqlsocket->row;
339 DEBUG("sqlippool_query1: SQL query did not return any results");
345 DEBUG("sqlippool_query1: row[0] returned NULL");
352 DEBUG("sqlippool_query1: insufficient string space");
357 strncpy(out, row[0], r);
364 * Start the database query expecting multiple result rows
366 static int sqlippool_queryn(const char * fmt, SQLSOCK * sqlsocket, void * instance, REQUEST * request, char * param, int param_len)
368 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
369 char expansion[MAX_STRING_LEN * 4];
370 char query[MAX_STRING_LEN * 4];
372 sqlippool_expand(expansion, sizeof(expansion), fmt, instance, param, param_len);
375 * Do an xlat on the provided string
378 if (!radius_xlat(query, sizeof(query), expansion, request, NULL)) {
379 radlog(L_ERR, "sqlippool_command: xlat failed.");
384 strcpy(query, expansion);
388 DEBUG2("sqlippool_queryn: '%s'", query);
391 if (rlm_sql_select_query(sqlsocket, data->sql_inst, query)){
392 radlog(L_ERR, "sqlippool_query1: database query error");
400 * Fetch the next record from the multiple result set
402 static int sqlippool_queryn_fetch(char * out, int outlen, SQLSOCK * sqlsocket, void * instance)
404 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
408 r = rlm_sql_fetch_row(sqlsocket, data->sql_inst);
411 DEBUG("sqlippool_queryn: SQL query did not succeed");
416 row = sqlsocket->row;
423 DEBUG("sqlippool_queryn: row[0] returned NULL");
430 DEBUG("sqlippool_queryn: insufficient string space");
435 strncpy(out, row[0], r);
442 * Query the database expecting a multiple result rows
444 static int sqlippool_queryn_end(SQLSOCK * sqlsocket, void * instance)
446 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
448 (data->sql_inst->module->sql_finish_select_query)(sqlsocket, data->sql_inst->config);
453 static int sqlippool_initialize_range(void * instance)
455 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
458 char ip_buffer[MAX_STRING_LEN];
461 uint32_t h_start; /* start in host order */
462 uint32_t h_stop; /* stop in host order */
463 uint32_t h_netmask; /* netmask in host order */
465 h_start = ntohl(data->range_start);
466 h_stop = ntohl(data->range_stop);
467 h_netmask = ntohl(data->netmask);
469 ip_set_initialize(&ips);
472 * Now run the initialization sequence
474 sqlsocket = sql_get_socket(data->sql_inst);
475 if (sqlsocket == NULL) {
476 DEBUG("rlm_sqlippool: cannot allocate sql connection for initialization sequence");
483 sqlippool_command(data->init_begin, sqlsocket, instance, NULL,
489 sqlippool_queryn(data->init_query, sqlsocket, instance, NULL,
495 uint32_t h_ip; /* ip in host order */
496 lrad_ipaddr_t ipaddr;
498 ip_buffer_len = sqlippool_queryn_fetch(ip_buffer, sizeof(ip_buffer),
499 sqlsocket, instance);
500 if (ip_buffer_len == 0)
504 if (ip_hton(ip_buffer, AF_INET, &ipaddr) < 0) {
505 radlog(L_ERR, "sqlippool_initialize_range: invalid IP number in pool");
506 /* XXX store and delete */
509 ip = ipaddr.ipaddr.ip4addr.s_addr;
512 ip_set_add(&ips, h_ip);
515 sqlippool_queryn_end(sqlsocket, data);
520 DEBUG(" len = %d, allocated = %d", ips.length, ips.allocated);
521 for (i = 0; i < ips.length; i++) {
522 DEBUG(" %d: %08x-%08x",
524 ips.ranges[i].h_start,
525 ips.ranges[i].h_finish);
530 * Loop over the rows and delete any entries are not in the pool
537 for (i = 0; i < ips.length; i++) {
538 for (h_ip = ips.ranges[i].h_start; h_ip <= ips.ranges[i].h_finish; h_ip++) {
541 else if (h_ip > h_stop)
544 or_result = h_ip | h_netmask;
545 if (or_result == h_netmask || or_result == 0xffffffff)
551 ip_ntoa(ip_buffer, htonl(h_ip));
556 sqlippool_command(data->init_delete, sqlsocket, instance, NULL,
557 ip_buffer, strlen(ip_buffer));
563 * Loop over the range and insert any entries are not in the database
566 uint32_t h_ip; /* ip in host order */
569 h_start = ntohl(data->range_start);
570 h_stop = ntohl(data->range_stop);
571 h_netmask = ntohl(data->netmask);
573 for (h_ip = h_start; h_ip <= h_stop; h_ip++) {
575 * Network and broadcast addresses are excluded
577 or_result = h_ip | h_netmask;
578 if (or_result == h_netmask || or_result == 0xffffffff) {
582 if (ip_set_test(&ips, h_ip))
585 ip_ntoa(ip_buffer, htonl(h_ip));
590 sqlippool_command(data->init_insert, sqlsocket, instance, NULL,
591 ip_buffer, strlen(ip_buffer));
598 sqlippool_command(data->init_commit, sqlsocket, instance, NULL,
601 sql_release_socket(data->sql_inst, sqlsocket);
609 * Do any per-module initialization that is separate to each
610 * configured instance of the module. e.g. set up connections
611 * to external databases, read configuration files, set up
612 * dictionary entries, etc.
614 * If configuration information is given in the config section
615 * that must be referenced in later calls, store a handle to it
616 * in *instance otherwise put a null pointer there.
618 static int sqlippool_instantiate(CONF_SECTION * conf, void ** instance)
620 rlm_sqlippool_t * data;
621 char * pool_name = NULL;
624 * Set up a storage area for instance data
626 data = rad_malloc(sizeof(*data));
627 memset(data, 0, sizeof(*data));
630 * If the configuration parameters can't be parsed, then
633 if (cf_section_parse(conf, data, module_config) < 0) {
638 if (data->sql_instance_name == NULL || strlen(data->sql_instance_name) == 0) {
639 radlog(L_ERR, "rlm_sqlippool: the 'sql-instance-name' variable must be set.");
645 * Check that all the queries are in place
647 if (data->init_query == NULL || strlen(data->init_query) == 0) {
648 radlog(L_ERR, "rlm_sqlippool: the 'init-query' statement must be set.");
653 if (data->init_delete == NULL || strlen(data->init_delete) == 0) {
654 radlog(L_ERR, "rlm_sqlippool: the 'init-delete' statement must be set.");
659 if (data->init_insert == NULL || strlen(data->init_insert) == 0) {
660 radlog(L_ERR, "rlm_sqlippool: the 'init-insert' statement must be set.");
665 if (data->allocate_clear == NULL || strlen(data->allocate_clear) == 0) {
666 radlog(L_ERR, "rlm_sqlippool: the 'allocate-clear' statement must be set.");
671 if (data->allocate_find == NULL || strlen(data->allocate_find) == 0) {
672 radlog(L_ERR, "rlm_sqlippool: the 'allocate_find' statement must be set.");
677 if (data->allocate_update == NULL || strlen(data->allocate_update) == 0) {
678 radlog(L_ERR, "rlm_sqlippool: the 'allocate_update' statement must be set.");
683 if (data->start_update == NULL || strlen(data->start_update) == 0) {
684 radlog(L_ERR, "rlm_sqlippool: the 'start-update' statement must be set.");
689 if (data->alive_update == NULL || strlen(data->alive_update) == 0) {
690 radlog(L_ERR, "rlm_sqlippool: the 'alive-update' statement must be set.");
695 if (data->stop_clear == NULL || strlen(data->stop_clear) == 0) {
696 radlog(L_ERR, "rlm_sqlippool: the 'stop-clear' statement must be set.");
701 if (data->on_clear == NULL || strlen(data->on_clear) == 0) {
702 radlog(L_ERR, "rlm_sqlippool: the 'on-clear' statement must be set.");
707 if (data->off_clear == NULL || strlen(data->off_clear) == 0) {
708 radlog(L_ERR, "rlm_sqlippool: the 'off-clear' statement must be set.");
713 pool_name = cf_section_name2(conf);
714 if (pool_name != NULL)
715 data->pool_name = strdup(pool_name);
717 data->pool_name = strdup("ippool");
719 data->sql_inst = (SQL_INST *)(find_module_instance(cf_section_find("modules"), data->sql_instance_name))->insthandle;
720 if (data->sql_inst == NULL) {
721 radlog(L_ERR, "sqlippool_instantiate: failed to find sql instance named %s", data->sql_instance_name);
726 sqlippool_initialize_range(data);
733 * Allocate an IP number from the pool.
735 static int sqlippool_postauth(void *instance, REQUEST * request)
737 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
738 char allocation[MAX_STRING_LEN];
740 lrad_ipaddr_t ipaddr;
741 uint32_t ip_allocation;
746 * If there is a Framed-IP-Address attribute in the reply do nothing
748 if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS) != NULL) {
749 DEBUG("rlm_sqlippool: Framed-IP-Address already exists");
750 return RLM_MODULE_NOOP;
754 * Check if Pool-Name attribute exists. If it exists check our name and
755 * run only if they match
757 if ((vp = pairfind(request->config_items, PW_POOL_NAME)) != NULL) {
758 if (data->pool_name == NULL || strcmp(data->pool_name, vp->vp_strvalue) != 0) {
759 DEBUG("rlm_sqlippool: pool_name does not match");
760 return RLM_MODULE_NOOP;
764 DEBUG("rlm_sqlippool: missing pool_name");
765 return RLM_MODULE_NOOP;
768 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
769 DEBUG("rlm_sqlippool: unknown NAS-IP-Address");
770 return RLM_MODULE_NOOP;
773 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
774 DEBUG("rlm_sqlippool: unknown NAS-Port");
775 return RLM_MODULE_NOOP;
778 sqlsocket = sql_get_socket(data->sql_inst);
779 if (sqlsocket == NULL) {
780 DEBUG("rlm_sqlippool: cannot allocate sql connection");
781 return RLM_MODULE_NOOP;
787 sqlippool_command(data->allocate_begin, sqlsocket, instance, request,
793 sqlippool_command(data->allocate_clear, sqlsocket, instance, request,
799 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
800 data->allocate_find, sqlsocket, instance, request,
802 DEBUG("rlm_sqlippool: ip=[%s] len=%d", allocation, allocation_len);
804 if (allocation_len == 0)
809 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
812 DEBUG("rlm_sqlippool: IP number could not be allocated.");
813 sql_release_socket(data->sql_inst, sqlsocket);
814 return RLM_MODULE_NOOP;
817 if (ip_hton(allocation, AF_INET, &ipaddr) < 0)
820 * Invalid IP number - run INIT-DELETE and complain
826 sqlippool_command(data->init_delete, sqlsocket, instance, NULL,
827 allocation, allocation_len);
832 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
835 DEBUG("rlm_sqlippool: Invalid IP number [%s] returned from database query.", allocation);
836 sql_release_socket(data->sql_inst, sqlsocket);
837 return RLM_MODULE_NOOP;
839 ip_allocation = ipaddr.ipaddr.ip4addr.s_addr;
844 sqlippool_command(data->allocate_update, sqlsocket, instance, request,
845 allocation, allocation_len);
847 DEBUG("rlm_sqlippool: Allocated IP %s [%08x]", allocation, ip_allocation);
849 if ((vp = paircreate(PW_FRAMED_IP_ADDRESS, PW_TYPE_IPADDR)) == NULL) {
850 radlog(L_ERR|L_CONS, "no memory");
851 sql_release_socket(data->sql_inst, sqlsocket);
852 return RLM_MODULE_NOOP;
854 vp->lvalue = ip_allocation;
855 pairadd(&request->reply->vps, vp);
860 sqlippool_command(data->allocate_commit, sqlsocket, instance, request,
863 sql_release_socket(data->sql_inst, sqlsocket);
864 return RLM_MODULE_OK;
867 static int sqlippool_accounting_start(void * instance, REQUEST * request)
869 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
872 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
873 DEBUG("rlm_ippool: Could not find port number in packet.");
874 return RLM_MODULE_NOOP;
877 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
878 DEBUG("rlm_ippool: Could not find nas information in packet.");
879 return RLM_MODULE_NOOP;
882 sqlsocket = sql_get_socket(data->sql_inst);
883 if (sqlsocket == NULL) {
884 DEBUG("rlm_sqlippool: cannot allocate sql connection");
885 return RLM_MODULE_NOOP;
891 sqlippool_command(data->start_begin, sqlsocket, instance, request,
897 sqlippool_command(data->start_update, sqlsocket, instance, request,
903 sqlippool_command(data->start_commit, sqlsocket, instance, request,
906 sql_release_socket(data->sql_inst, sqlsocket);
908 return RLM_MODULE_OK;
911 static int sqlippool_accounting_alive(void * instance, REQUEST * request)
913 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
916 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
917 DEBUG("rlm_ippool: Could not find port number in packet.");
918 return RLM_MODULE_NOOP;
921 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
922 DEBUG("rlm_ippool: Could not find nas information in packet.");
923 return RLM_MODULE_NOOP;
926 sqlsocket = sql_get_socket(data->sql_inst);
927 if (sqlsocket == NULL) {
928 DEBUG("rlm_sqlippool: cannot allocate sql connection");
929 return RLM_MODULE_NOOP;
935 sqlippool_command(data->alive_begin, sqlsocket, instance, request,
941 sqlippool_command(data->alive_update, sqlsocket, instance, request,
947 sqlippool_command(data->alive_commit, sqlsocket, instance, request,
950 sql_release_socket(data->sql_inst, sqlsocket);
952 return RLM_MODULE_OK;
955 static int sqlippool_accounting_stop(void * instance, REQUEST * request)
957 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
960 if (pairfind(request->packet->vps, PW_NAS_PORT) == NULL) {
961 DEBUG("rlm_ippool: Could not find port number in packet.");
962 return RLM_MODULE_NOOP;
965 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
966 DEBUG("rlm_ippool: Could not find nas information in packet.");
967 return RLM_MODULE_NOOP;
970 sqlsocket = sql_get_socket(data->sql_inst);
971 if (sqlsocket == NULL) {
972 DEBUG("rlm_sqlippool: cannot allocate sql connection");
973 return RLM_MODULE_NOOP;
979 sqlippool_command(data->stop_begin, sqlsocket, instance, request,
985 sqlippool_command(data->stop_clear, sqlsocket, instance, request,
991 sqlippool_command(data->stop_commit, sqlsocket, instance, request,
994 sql_release_socket(data->sql_inst, sqlsocket);
996 return RLM_MODULE_OK;
999 static int sqlippool_accounting_on(void * instance, REQUEST * request)
1001 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
1002 SQLSOCK * sqlsocket;
1004 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
1005 DEBUG("rlm_ippool: Could not find nas information in packet.");
1006 return RLM_MODULE_NOOP;
1009 sqlsocket = sql_get_socket(data->sql_inst);
1010 if (sqlsocket == NULL) {
1011 DEBUG("rlm_sqlippool: cannot allocate sql connection");
1012 return RLM_MODULE_NOOP;
1018 sqlippool_command(data->on_begin, sqlsocket, instance, request,
1024 sqlippool_command(data->on_clear, sqlsocket, instance, request,
1030 sqlippool_command(data->on_commit, sqlsocket, instance, request,
1033 sql_release_socket(data->sql_inst, sqlsocket);
1035 return RLM_MODULE_OK;
1038 static int sqlippool_accounting_off(void * instance, REQUEST * request)
1040 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
1041 SQLSOCK * sqlsocket;
1043 if (pairfind(request->packet->vps, PW_NAS_IP_ADDRESS) == NULL) {
1044 DEBUG("rlm_ippool: Could not find nas information in packet.");
1045 return RLM_MODULE_NOOP;
1048 sqlsocket = sql_get_socket(data->sql_inst);
1049 if (sqlsocket == NULL) {
1050 DEBUG("rlm_sqlippool: cannot allocate sql connection");
1051 return RLM_MODULE_NOOP;
1057 sqlippool_command(data->off_begin, sqlsocket, instance, request,
1063 sqlippool_command(data->off_clear, sqlsocket, instance, request,
1069 sqlippool_command(data->off_commit, sqlsocket, instance, request,
1072 sql_release_socket(data->sql_inst, sqlsocket);
1074 return RLM_MODULE_OK;
1078 * Check for an Accounting-Stop
1079 * If we find one and we have allocated an IP to this nas/port combination, deallocate it.
1081 static int sqlippool_accounting(void * instance, REQUEST * request)
1084 int acct_status_type;
1086 vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE);
1088 DEBUG("rlm_sqlippool: Could not find account status type in packet.");
1089 return RLM_MODULE_NOOP;
1091 acct_status_type = vp->lvalue;
1093 switch (acct_status_type) {
1094 case PW_STATUS_START:
1095 return sqlippool_accounting_start(instance, request);
1097 case PW_STATUS_ALIVE:
1098 return sqlippool_accounting_alive(instance, request);
1100 case PW_STATUS_STOP:
1101 return sqlippool_accounting_stop(instance, request);
1103 case PW_STATUS_ACCOUNTING_ON:
1104 return sqlippool_accounting_on(instance, request);
1106 case PW_STATUS_ACCOUNTING_OFF:
1107 return sqlippool_accounting_off(instance, request);
1110 /* We don't care about any other accounting packet */
1111 return RLM_MODULE_NOOP;
1115 static int sqlippool_detach(void *instance)
1117 rlm_sqlippool_t * data = (rlm_sqlippool_t *) instance;
1119 free(data->sql_instance_name);
1120 free(data->pool_name);
1122 free(data->init_begin);
1123 free(data->init_query);
1124 free(data->init_delete);
1125 free(data->init_insert);
1126 free(data->init_commit);
1127 free(data->init_rollback);
1129 free(data->allocate_begin);
1130 free(data->allocate_clear);
1131 free(data->allocate_find);
1132 free(data->allocate_update);
1133 free(data->allocate_commit);
1134 free(data->allocate_rollback);
1136 free(data->start_begin);
1137 free(data->start_update);
1138 free(data->start_commit);
1139 free(data->start_rollback);
1141 free(data->alive_begin);
1142 free(data->alive_update);
1143 free(data->alive_commit);
1144 free(data->alive_rollback);
1146 free(data->stop_begin);
1147 free(data->stop_clear);
1148 free(data->stop_commit);
1149 free(data->stop_rollback);
1151 free(data->on_begin);
1152 free(data->on_clear);
1153 free(data->on_commit);
1154 free(data->on_rollback);
1156 free(data->off_begin);
1157 free(data->off_clear);
1158 free(data->off_commit);
1159 free(data->off_rollback);
1165 * The module name should be the only globally exported symbol.
1166 * That is, everything else should be 'static'.
1168 * If the module needs to temporarily modify it's instantiation
1169 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
1170 * The server will then take care of ensuring that the module
1171 * is single-threaded.
1173 module_t rlm_sqlippool = {
1176 RLM_TYPE_THREAD_SAFE, /* type */
1177 sqlippool_instantiate, /* instantiation */
1178 sqlippool_detach, /* detach */
1180 NULL, /* authentication */
1181 NULL, /* authorization */
1182 NULL, /* preaccounting */
1183 sqlippool_accounting, /* accounting */
1184 NULL, /* checksimul */
1185 NULL, /* pre-proxy */
1186 NULL, /* post-proxy */
1187 sqlippool_postauth /* post-auth */