2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 if the
4 * License as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * @file rlm_sqlippool.c
19 * @brief Allocates an IPv4 address from pools stored in SQL.
21 * @copyright 2002 Globe.Net Communications Limited
22 * @copyright 2006 The FreeRADIUS server project
23 * @copyright 2006 Suntel Communications
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
34 #define MAX_QUERY_LEN 4096
37 * Define a structure for our module configuration.
39 typedef struct rlm_sqlippool_t {
40 char *sql_instance_name;
48 /* We ended up removing the init
49 queries so that its up to user
50 to create the db structure and put the required
53 /* Allocation sequence */
54 time_t last_clear; /* so we only do it once a second */
55 char *allocate_begin; /* SQL query to begin */
56 char *allocate_clear; /* SQL query to clear an IP */
57 char *allocate_find; /* SQL query to find an unused IP */
58 char *allocate_update; /* SQL query to mark an IP as used */
59 char *allocate_commit; /* SQL query to commit */
61 char *pool_check; /* Query to check for the existence of the pool */
64 char *start_begin; /* SQL query to begin */
65 char *start_update; /* SQL query to update an IP entry */
66 char *start_commit; /* SQL query to commit */
69 char *alive_begin; /* SQL query to begin */
70 char *alive_update; /* SQL query to update an IP entry */
71 char *alive_commit; /* SQL query to commit */
74 char *stop_begin; /* SQL query to begin */
75 char *stop_clear; /* SQL query to clear an IP */
76 char *stop_commit; /* SQL query to commit */
79 char *on_begin; /* SQL query to begin */
80 char *on_clear; /* SQL query to clear an entire NAS */
81 char *on_commit; /* SQL query to commit */
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 */
89 char *log_exists; /* There was an ip address already assigned */
90 char *log_success; /* We successfully allocated ip address from pool */
91 char *log_clear; /* We successfully deallocated ip address from pool */
92 char *log_failed; /* Failed to allocate ip from the pool */
93 char *log_nopool; /* There was no Framed-IP-Address but also no Pool-Name */
95 /* Reserved to handle 255.255.255.254 Requests */
96 char *defaultpool; /* Default Pool-Name if there is none in the check items */
100 static CONF_PARSER message_config[] = {
101 { "exists", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_exists), NULL, NULL },
102 { "success", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_success), NULL, NULL },
103 { "clear", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_clear), NULL, NULL },
104 { "failed", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_failed), NULL, NULL },
105 { "nopool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, log_nopool), NULL, NULL },
107 { NULL, -1, 0, NULL, NULL }
111 * A mapping of configuration file names to internal variables.
113 * Note that the string is dynamically allocated, so it MUST
114 * be freed. When the configuration file parse re-reads the string,
115 * it free's the old one, and strdup's the new one, placing the pointer
116 * to the strdup'd string into 'config.string'. This gets around
119 static CONF_PARSER module_config[] = {
120 {"sql-instance-name",PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
121 offsetof(rlm_sqlippool_t,sql_instance_name), NULL, NULL},
122 {"sql_module_instance",PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
123 offsetof(rlm_sqlippool_t,sql_instance_name), NULL, "sql"},
125 { "lease-duration", PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,lease_duration), NULL, NULL},
126 { "lease_duration", PW_TYPE_INTEGER, offsetof(rlm_sqlippool_t,lease_duration), NULL, "86400"},
128 { "pool-name", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t, pool_name), NULL, NULL},
129 { "pool_name", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, pool_name), NULL, ""},
131 { "default-pool", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t, defaultpool), NULL, NULL },
132 { "default_pool", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t, defaultpool), NULL, "main_pool" },
135 { "allocate-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
136 offsetof(rlm_sqlippool_t,allocate_begin), NULL, NULL},
137 { "allocate_begin", PW_TYPE_STRING_PTR,
138 offsetof(rlm_sqlippool_t,allocate_begin), NULL, "START TRANSACTION" },
140 { "allocate-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
141 offsetof(rlm_sqlippool_t,allocate_clear), NULL, NULL},
142 { "allocate_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
143 offsetof(rlm_sqlippool_t,allocate_clear), NULL, "" },
145 { "allocate-find", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
146 offsetof(rlm_sqlippool_t,allocate_find), NULL, NULL},
147 { "allocate_find", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
148 offsetof(rlm_sqlippool_t,allocate_find), NULL, "" },
150 { "allocate-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
151 offsetof(rlm_sqlippool_t,allocate_update), NULL, NULL },
152 { "allocate_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED,
153 offsetof(rlm_sqlippool_t,allocate_update), NULL, "" },
155 { "allocate-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED,
156 offsetof(rlm_sqlippool_t,allocate_commit), NULL, NULL },
157 { "allocate_commit", PW_TYPE_STRING_PTR,
158 offsetof(rlm_sqlippool_t,allocate_commit), NULL, "COMMIT" },
161 { "pool-check", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,pool_check), NULL, NULL },
162 { "pool_check", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,pool_check), NULL, "" },
165 { "start-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_begin), NULL, NULL },
166 { "start_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_begin), NULL, "START TRANSACTION" },
168 { "start-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_update), NULL, NULL },
169 { "start_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,start_update), NULL, "" },
171 { "start-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,start_commit), NULL, NULL },
172 { "start_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,start_commit), NULL, "COMMIT" },
175 { "alive-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_begin), NULL, NULL },
176 { "alive_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_begin), NULL, "START TRANSACTION" },
178 { "alive-update", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_update), NULL, NULL },
179 { "alive_update", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,alive_update), NULL, "" },
181 { "alive-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,alive_commit), NULL, NULL },
182 { "alive_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,alive_commit), NULL, "COMMIT" },
185 { "stop-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_begin), NULL, NULL },
186 { "stop_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_begin), NULL, "START TRANSACTION" },
188 { "stop-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_clear), NULL, NULL },
189 { "stop_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,stop_clear), NULL, "" },
191 { "stop-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,stop_commit), NULL, NULL },
192 { "stop_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,stop_commit), NULL, "COMMIT" },
195 { "on-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_begin), NULL, NULL },
196 { "on_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_begin), NULL, "START TRANSACTION" },
198 { "on-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_clear), NULL, NULL },
199 { "on_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,on_clear), NULL, "" },
201 { "on-commit", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,on_commit), NULL, NULL },
202 { "on_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,on_commit), NULL, "COMMIT" },
205 { "off-begin", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_begin), NULL, NULL },
206 { "off_begin", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_begin), NULL, "START TRANSACTION" },
208 { "off-clear", PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_clear), NULL, NULL },
209 { "off_clear", PW_TYPE_STRING_PTR | PW_TYPE_REQUIRED, offsetof(rlm_sqlippool_t,off_clear), NULL, "" },
211 { "off-commit",PW_TYPE_STRING_PTR | PW_TYPE_DEPRECATED, offsetof(rlm_sqlippool_t,off_commit), NULL, NULL },
212 { "off_commit", PW_TYPE_STRING_PTR, offsetof(rlm_sqlippool_t,off_commit), NULL, "COMMIT" },
214 { "messages", PW_TYPE_SUBSECTION, 0, NULL, (void const *) message_config },
216 { NULL, -1, 0, NULL, NULL }
220 * Replace %<whatever> in a string.
227 static int sqlippool_expand(char * out, int outlen, char const * fmt,
228 rlm_sqlippool_t *data, char * param, int param_len)
232 char tmp[40]; /* For temporary storing of integers */
235 for (p = fmt; *p ; p++) {
239 /* Calculate freespace in output */
240 freespace = outlen - (q - out);
245 if (c != '%' && c != '$' && c != '\\') {
275 case 'P': /* pool name */
276 strlcpy(q, data->pool_name, freespace);
279 case 'I': /* IP address */
280 if (param && param_len > 0) {
281 if (param_len > freespace) {
282 strlcpy(q, param, freespace);
286 memcpy(q, param, param_len);
291 case 'J': /* lease duration */
292 sprintf(tmp, "%d", data->lease_duration);
293 strlcpy(q, tmp, freespace);
306 DEBUG2("sqlippool_expand: \"%s\"", out);
312 /** Perform a single sqlippool query
314 * Mostly wrapper around sql_query which does some special sqlippool sequence substitutions and expands
317 * @param fmt sql query to expand.
318 * @param handle sql connection handle.
319 * @param data Instance of rlm_sqlippool.
320 * @param request Current request.
321 * @param param ip address string.
322 * @param param_len ip address string len.
323 * @return 0 on success or < 0 on error.
325 static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sqlippool_t *data, REQUEST *request,
326 char *param, int param_len)
328 char query[MAX_QUERY_LEN];
329 char *expanded = NULL;
334 * If we don't have a command, do nothing.
339 * @todo this needs to die (should just be done in xlat expansion)
341 sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
343 if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
347 ret = data->sql_inst->sql_query(&handle, data->sql_inst, expanded);
349 talloc_free(expanded);
352 talloc_free(expanded);
354 (data->sql_inst->module->sql_finish_query)(handle, data->sql_inst->config);
359 * Don't repeat yourself
362 #define DO(_x) sqlippool_command(inst->_x, handle, inst, request, NULL, 0)
365 * Query the database expecting a single result row
367 static int sqlippool_query1(char *out, int outlen, char const *fmt,
368 rlm_sql_handle_t *handle, rlm_sqlippool_t *data,
369 REQUEST *request, char *param, int param_len)
371 char query[MAX_QUERY_LEN];
372 char *expanded = NULL;
377 * @todo this needs to die (should just be done in xlat expansion)
379 sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
381 rad_assert(request != NULL);
386 * Do an xlat on the provided string
388 if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
391 retval = data->sql_inst->sql_select_query(&handle, data->sql_inst, expanded);
392 talloc_free(expanded);
395 REDEBUG("database query error on '%s'", query);
399 if (data->sql_inst->sql_fetch_row(&handle, data->sql_inst) < 0) {
400 REDEBUG("Failed fetching query result");
405 REDEBUG("SQL query did not return any results");
409 if (!handle->row[0]) {
410 REDEBUG("The first column of the result was NULL");
414 rlen = strlen(handle->row[0]);
415 if (rlen >= outlen) {
416 RDEBUG("insufficient string space");
420 strcpy(out, handle->row[0]);
423 (data->sql_inst->module->sql_finish_select_query)(handle, data->sql_inst->config);
429 * Do any per-module initialization that is separate to each
430 * configured instance of the module. e.g. set up connections
431 * to external databases, read configuration files, set up
432 * dictionary entries, etc.
434 * If configuration information is given in the config section
435 * that must be referenced in later calls, store a handle to it
436 * in *instance otherwise put a null pointer there.
438 static int mod_instantiate(CONF_SECTION *conf, void *instance)
440 module_instance_t *sqlinst;
441 rlm_sqlippool_t *inst = instance;
442 char const *pool_name = NULL;
444 pool_name = cf_section_name2(conf);
445 if (pool_name != NULL)
446 inst->pool_name = talloc_strdup(inst, pool_name);
448 inst->pool_name = talloc_strdup(inst, "ippool");
450 sqlinst = find_module_instance(cf_section_find("modules"),
451 inst->sql_instance_name, 1);
453 cf_log_err_cs(conf, "failed to find sql instance named %s",
454 inst->sql_instance_name);
458 if (strcmp(sqlinst->entry->name, "rlm_sql") != 0) {
459 cf_log_err_cs(conf, "Module \"%s\""
460 " is not an instance of the rlm_sql module",
461 inst->sql_instance_name);
465 inst->sql_inst = (rlm_sql_t *) sqlinst->insthandle;
471 * If we have something to log, then we log it.
472 * Otherwise we return the retcode as soon as possible
474 static int do_logging(REQUEST *request, char *str, int rcode)
476 char *expanded = NULL;
478 if (!str || !*str) return rcode;
480 if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) {
484 pairmake_config("Module-Success-Message", expanded, T_OP_SET);
486 talloc_free(expanded);
493 * Allocate an IP number from the pool.
495 static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request)
497 rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
498 char allocation[MAX_STRING_LEN];
500 uint32_t ip_allocation;
502 rlm_sql_handle_t *handle;
507 * If there is a Framed-IP-Address attribute in the reply do nothing
509 if (pairfind(request->reply->vps, PW_FRAMED_IP_ADDRESS, 0, TAG_ANY) != NULL) {
510 RDEBUG("Framed-IP-Address already exists");
512 return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
515 if (pairfind(request->config_items, PW_POOL_NAME, 0, TAG_ANY) == NULL) {
516 RDEBUG("No Pool-Name defined.");
518 return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
521 handle = inst->sql_inst->sql_get_socket(inst->sql_inst);
523 REDEBUG("cannot get sql connection");
524 return RLM_MODULE_FAIL;
527 if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
528 return RLM_MODULE_FAIL;
532 * Limit the number of clears we do. There are minor
533 * race conditions for the check, but so what. The
534 * actual work is protected by a transaction. The idea
535 * here is that if we're allocating 100 IPs a second,
536 * we're only do 1 CLEAR per second.
539 if (inst->last_clear < now) {
540 inst->last_clear = now;
549 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
550 inst->allocate_find, handle,
551 inst, request, (char *) NULL, 0);
556 if (allocation_len == 0) {
560 *Should we perform pool-check ?
562 if (inst->pool_check && *inst->pool_check) {
565 *Ok, so the allocate-find query found nothing ...
566 *Let's check if the pool exists at all
568 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
569 inst->pool_check, handle, inst, request,
572 inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
574 if (allocation_len) {
577 * Pool exists after all... So,
578 * the failure to allocate the IP
579 * address was most likely due to
580 * the depletion of the pool. In
581 * that case, we should return
584 RDEBUG("pool appears to be full");
585 return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);
590 * Pool doesn't exist in the table. It
591 * may be handled by some other instance of
592 * sqlippool, so we should just ignore this
593 * allocation failure and return NOOP
595 RDEBUG("IP address could not be allocated as no pool exists with that name.");
596 return RLM_MODULE_NOOP;
600 inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
602 RDEBUG("IP address could not be allocated.");
603 return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
607 * FIXME: Make it work with the ipv6 addresses
609 if ((ip_hton(allocation, AF_INET, &ipaddr) < 0) ||
610 ((ip_allocation = ipaddr.ipaddr.ip4addr.s_addr) == INADDR_NONE)) {
613 RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
614 inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
615 return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
621 sqlippool_command(inst->allocate_update, handle, inst, request,
622 allocation, allocation_len);
624 RDEBUG("Allocated IP %s [%08x]", allocation, ip_allocation);
626 vp = radius_paircreate(request, &request->reply->vps,
627 PW_FRAMED_IP_ADDRESS, 0);
628 vp->vp_ipaddr = ip_allocation;
633 inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
635 return do_logging(request, inst->log_success, RLM_MODULE_OK);
638 static int mod_accounting_start(rlm_sql_handle_t *handle,
639 rlm_sqlippool_t *inst, REQUEST *request)
645 return RLM_MODULE_OK;
648 static int mod_accounting_alive(rlm_sql_handle_t *handle,
649 rlm_sqlippool_t *inst, REQUEST *request)
654 return RLM_MODULE_OK;
657 static int mod_accounting_stop(rlm_sql_handle_t *handle,
658 rlm_sqlippool_t *inst, REQUEST *request)
664 return do_logging(request, inst->log_clear, RLM_MODULE_OK);
667 static int mod_accounting_on(rlm_sql_handle_t *handle,
668 rlm_sqlippool_t *inst, REQUEST *request)
674 return RLM_MODULE_OK;
677 static int mod_accounting_off(rlm_sql_handle_t *handle,
678 rlm_sqlippool_t *inst, REQUEST *request)
684 return RLM_MODULE_OK;
688 * Check for an Accounting-Stop
689 * If we find one and we have allocated an IP to this nas/port
690 * combination, then deallocate it.
692 static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
694 int rcode = RLM_MODULE_NOOP;
696 int acct_status_type;
697 rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
698 rlm_sql_handle_t *handle;
700 vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
702 RDEBUG("Could not find account status type in packet.");
703 return RLM_MODULE_NOOP;
705 acct_status_type = vp->vp_integer;
707 switch (acct_status_type) {
708 case PW_STATUS_START:
709 case PW_STATUS_ALIVE:
711 case PW_STATUS_ACCOUNTING_ON:
712 case PW_STATUS_ACCOUNTING_OFF:
713 break; /* continue through to the next section */
716 /* We don't care about any other accounting packet */
717 return RLM_MODULE_NOOP;
720 handle = inst->sql_inst->sql_get_socket(inst->sql_inst);
722 RDEBUG("Cannot allocate sql connection");
723 return RLM_MODULE_FAIL;
726 if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
727 return RLM_MODULE_FAIL;
730 switch (acct_status_type) {
731 case PW_STATUS_START:
732 rcode = mod_accounting_start(handle, inst, request);
735 case PW_STATUS_ALIVE:
736 rcode = mod_accounting_alive(handle, inst, request);
740 rcode = mod_accounting_stop(handle, inst, request);
743 case PW_STATUS_ACCOUNTING_ON:
744 rcode = mod_accounting_on(handle, inst, request);
747 case PW_STATUS_ACCOUNTING_OFF:
748 rcode = mod_accounting_off(handle, inst, request);
752 inst->sql_inst->sql_release_socket(inst->sql_inst, handle);
758 * The module name should be the only globally exported symbol.
759 * That is, everything else should be 'static'.
761 * If the module needs to temporarily modify it's instantiation
762 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
763 * The server will then take care of ensuring that the module
764 * is single-threaded.
766 module_t rlm_sqlippool = {
769 RLM_TYPE_THREAD_SAFE, /* type */
770 sizeof(rlm_sqlippool_t),
772 mod_instantiate, /* instantiation */
775 NULL, /* authentication */
776 NULL, /* authorization */
777 NULL, /* preaccounting */
778 mod_accounting, /* accounting */
779 NULL, /* checksimul */
780 NULL, /* pre-proxy */
781 NULL, /* post-proxy */
782 mod_post_auth /* post-auth */