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 as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @file rlm_sqlippool.c
20 * @brief Allocates an IPv4 address from pools stored in SQL.
22 * @copyright 2002 Globe.Net Communications Limited
23 * @copyright 2006 The FreeRADIUS server project
24 * @copyright 2006 Suntel Communications
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/rad_assert.h>
35 #define MAX_QUERY_LEN 4096
38 * Define a structure for our module configuration.
40 typedef struct rlm_sqlippool_t {
41 char const *sql_instance_name;
43 uint32_t lease_duration;
47 char const *pool_name;
48 bool ipv6; //!< Whether or not we do IPv6 pools.
49 int framed_ip_address; //!< the attribute number for Framed-IP(v6)-Address
51 time_t last_clear; //!< So we only do it once a second.
52 char const *allocate_begin; //!< SQL query to begin.
53 char const *allocate_clear; //!< SQL query to clear an IP.
54 char const *allocate_find; //!< SQL query to find an unused IP.
55 char const *allocate_update; //!< SQL query to mark an IP as used.
56 char const *allocate_commit; //!< SQL query to commit.
58 char const *pool_check; //!< Query to check for the existence of the pool.
61 char const *start_begin; //!< SQL query to begin.
62 char const *start_update; //!< SQL query to update an IP entry.
63 char const *start_commit; //!< SQL query to commit.
66 char const *alive_begin; //!< SQL query to begin.
67 char const *alive_update; //!< SQL query to update an IP entry.
68 char const *alive_commit; //!< SQL query to commit.
71 char const *stop_begin; //!< SQL query to begin.
72 char const *stop_clear; //!< SQL query to clear an IP.
73 char const *stop_commit; //!< SQL query to commit.
76 char const *on_begin; //!< SQL query to begin.
77 char const *on_clear; //!< SQL query to clear an entire NAS.
78 char const *on_commit; //!< SQL query to commit.
81 char const *off_begin; //!< SQL query to begin.
82 char const *off_clear; //!< SQL query to clear an entire NAS.
83 char const *off_commit; //!< SQL query to commit.
86 char const *log_exists; //!< There was an ip address already assigned.
87 char const *log_success; //!< We successfully allocated ip address from pool.
88 char const *log_clear; //!< We successfully deallocated ip address from pool.
89 char const *log_failed; //!< Failed to allocate ip from the pool.
90 char const *log_nopool; //!< There was no Framed-IP-Address but also no Pool-Name.
92 /* Reserved to handle 255.255.255.254 Requests */
93 char const *defaultpool; //!< Default Pool-Name if there is none in the check items.
97 static CONF_PARSER message_config[] = {
98 { "exists", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_exists), NULL },
99 { "success", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_success), NULL },
100 { "clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_clear), NULL },
101 { "failed", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_failed), NULL },
102 { "nopool", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_nopool), NULL },
103 CONF_PARSER_TERMINATOR
107 * A mapping of configuration file names to internal variables.
109 * Note that the string is dynamically allocated, so it MUST
110 * be freed. When the configuration file parse re-reads the string,
111 * it free's the old one, and strdup's the new one, placing the pointer
112 * to the strdup'd string into 'config.string'. This gets around
115 static CONF_PARSER module_config[] = {
116 { "sql-instance-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, sql_instance_name), NULL },
117 { "sql_module_instance", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, sql_instance_name), "sql" },
119 { "lease-duration", FR_CONF_OFFSET(PW_TYPE_INTEGER | PW_TYPE_DEPRECATED, rlm_sqlippool_t, lease_duration), NULL },
120 { "lease_duration", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_sqlippool_t, lease_duration), "86400" },
122 { "pool-name", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_name), NULL },
123 { "pool_name", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, pool_name), "" },
125 { "default-pool", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_DEPRECATED, rlm_sqlippool_t, defaultpool), NULL },
126 { "default_pool", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_sqlippool_t, defaultpool), "main_pool" },
129 { "ipv6", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_sqlippool_t, ipv6), NULL},
131 { "allocate-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_begin), NULL },
132 { "allocate_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_begin), "START TRANSACTION" },
134 { "allocate-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_clear), NULL },
135 { "allocate_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_clear), "" },
137 { "allocate-find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_find), NULL },
138 { "allocate_find", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_find), "" },
140 { "allocate-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_update), NULL },
141 { "allocate_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_update), "" },
143 { "allocate-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, allocate_commit), NULL },
144 { "allocate_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_commit), "COMMIT" },
147 { "pool-check", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, pool_check), NULL },
148 { "pool_check", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, pool_check), "" },
151 { "start-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_begin), NULL },
152 { "start_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_begin), "START TRANSACTION" },
154 { "start-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_update), NULL },
155 { "start_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, start_update), "" },
157 { "start-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, start_commit), NULL },
158 { "start_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_commit), "COMMIT" },
161 { "alive-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_begin), NULL },
162 { "alive_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_begin), "START TRANSACTION" },
164 { "alive-update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_update), NULL },
165 { "alive_update", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, alive_update), "" },
167 { "alive-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, alive_commit), NULL },
168 { "alive_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_commit), "COMMIT" },
171 { "stop-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_begin), NULL },
172 { "stop_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_begin), "START TRANSACTION" },
174 { "stop-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_clear), NULL },
175 { "stop_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, stop_clear), "" },
177 { "stop-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, stop_commit), NULL },
178 { "stop_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_commit), "COMMIT" },
181 { "on-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_begin), NULL },
182 { "on_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_begin), "START TRANSACTION" },
184 { "on-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_clear), NULL },
185 { "on_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, on_clear), "" },
187 { "on-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, on_commit), NULL },
188 { "on_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_commit), "COMMIT" },
191 { "off-begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_begin), NULL },
192 { "off_begin", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_begin), "START TRANSACTION" },
194 { "off-clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_clear), NULL },
195 { "off_clear", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, off_clear), "" },
197 { "off-commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_DEPRECATED, rlm_sqlippool_t, off_commit), NULL },
198 { "off_commit", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_commit), "COMMIT" },
200 { "messages", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) message_config },
201 CONF_PARSER_TERMINATOR
205 * Replace %<whatever> in a string.
212 static int sqlippool_expand(char * out, int outlen, char const * fmt,
213 rlm_sqlippool_t *data, char * param, int param_len)
217 char tmp[40]; /* For temporary storing of integers */
220 for (p = fmt; *p ; p++) {
224 /* Calculate freespace in output */
225 freespace = outlen - (q - out);
241 case 'P': /* pool name */
242 strlcpy(q, data->pool_name, freespace);
245 case 'I': /* IP address */
246 if (param && param_len > 0) {
247 if (param_len > freespace) {
248 strlcpy(q, param, freespace);
252 memcpy(q, param, param_len);
257 case 'J': /* lease duration */
258 sprintf(tmp, "%d", data->lease_duration);
259 strlcpy(q, tmp, freespace);
273 DEBUG2("sqlippool_expand: \"%s\"", out);
279 /** Perform a single sqlippool query
281 * Mostly wrapper around sql_query which does some special sqlippool sequence substitutions and expands
284 * @param fmt sql query to expand.
285 * @param handle sql connection handle.
286 * @param data Instance of rlm_sqlippool.
287 * @param request Current request.
288 * @param param ip address string.
289 * @param param_len ip address string len.
290 * @return 0 on success or < 0 on error.
292 static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sqlippool_t *data, REQUEST *request,
293 char *param, int param_len)
295 char query[MAX_QUERY_LEN];
296 char *expanded = NULL;
301 * If we don't have a command, do nothing.
303 if (!fmt || !*fmt) return 0;
306 * @todo this needs to die (should just be done in xlat expansion)
308 sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
310 if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
314 ret = data->sql_inst->sql_query(data->sql_inst, request, &handle, expanded);
316 talloc_free(expanded);
319 talloc_free(expanded);
321 (data->sql_inst->module->sql_finish_query)(handle, data->sql_inst->config);
326 * Don't repeat yourself
329 #define DO(_x) sqlippool_command(inst->_x, handle, inst, request, NULL, 0)
332 * Query the database expecting a single result row
334 static int CC_HINT(nonnull (1, 3, 4, 5)) sqlippool_query1(char *out, int outlen, char const *fmt,
335 rlm_sql_handle_t *handle, rlm_sqlippool_t *data,
336 REQUEST *request, char *param, int param_len)
338 char query[MAX_QUERY_LEN];
339 char *expanded = NULL;
344 * @todo this needs to die (should just be done in xlat expansion)
346 sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
351 * Do an xlat on the provided string
353 if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, data->sql_inst) < 0) {
356 retval = data->sql_inst->sql_select_query(data->sql_inst, request, &handle, expanded);
357 talloc_free(expanded);
360 REDEBUG("database query error on '%s'", query);
364 if (data->sql_inst->sql_fetch_row(data->sql_inst, request, &handle) < 0) {
365 REDEBUG("Failed fetching query result");
370 REDEBUG("SQL query did not return any results");
374 if (!handle->row[0]) {
375 REDEBUG("The first column of the result was NULL");
379 rlen = strlen(handle->row[0]);
380 if (rlen >= outlen) {
381 RDEBUG("insufficient string space");
385 strcpy(out, handle->row[0]);
388 (data->sql_inst->module->sql_finish_select_query)(handle, data->sql_inst->config);
394 * Do any per-module initialization that is separate to each
395 * configured instance of the module. e.g. set up connections
396 * to external databases, read configuration files, set up
397 * dictionary entries, etc.
399 * If configuration information is given in the config section
400 * that must be referenced in later calls, store a handle to it
401 * in *instance otherwise put a null pointer there.
403 static int mod_instantiate(CONF_SECTION *conf, void *instance)
405 module_instance_t *sql_inst;
406 rlm_sqlippool_t *inst = instance;
407 char const *pool_name = NULL;
409 pool_name = cf_section_name2(conf);
410 if (pool_name != NULL) {
411 inst->pool_name = talloc_typed_strdup(inst, pool_name);
413 inst->pool_name = talloc_typed_strdup(inst, "ippool");
415 sql_inst = module_instantiate(cf_section_find("modules"),
416 inst->sql_instance_name);
418 cf_log_err_cs(conf, "failed to find sql instance named %s",
419 inst->sql_instance_name);
424 inst->framed_ip_address = PW_FRAMED_IP_ADDRESS;
426 inst->framed_ip_address = PW_FRAMED_IPV6_PREFIX;
429 if (strcmp(sql_inst->entry->name, "rlm_sql") != 0) {
430 cf_log_err_cs(conf, "Module \"%s\""
431 " is not an instance of the rlm_sql module",
432 inst->sql_instance_name);
436 inst->sql_inst = (rlm_sql_t *) sql_inst->insthandle;
442 * If we have something to log, then we log it.
443 * Otherwise we return the retcode as soon as possible
445 static int do_logging(REQUEST *request, char const *str, int rcode)
447 char *expanded = NULL;
449 if (!str || !*str) return rcode;
451 if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) {
455 pair_make_config("Module-Success-Message", expanded, T_OP_SET);
457 talloc_free(expanded);
464 * Allocate an IP number from the pool.
466 static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
468 rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
469 char allocation[MAX_STRING_LEN];
472 rlm_sql_handle_t *handle;
476 * If there is a Framed-IP-Address attribute in the reply do nothing
478 if (fr_pair_find_by_num(request->reply->vps, inst->framed_ip_address, 0, TAG_ANY) != NULL) {
479 RDEBUG("Framed-IP-Address already exists");
481 return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
484 if (fr_pair_find_by_num(request->config, PW_POOL_NAME, 0, TAG_ANY) == NULL) {
485 RDEBUG("No Pool-Name defined");
487 return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
490 handle = fr_connection_get(inst->sql_inst->pool);
492 REDEBUG("cannot get sql connection");
493 return RLM_MODULE_FAIL;
496 if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
497 return RLM_MODULE_FAIL;
501 * Limit the number of clears we do. There are minor
502 * race conditions for the check, but so what. The
503 * actual work is protected by a transaction. The idea
504 * here is that if we're allocating 100 IPs a second,
505 * we're only do 1 CLEAR per second.
508 if (inst->last_clear < now) {
509 inst->last_clear = now;
518 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
519 inst->allocate_find, handle,
520 inst, request, (char *) NULL, 0);
525 if (allocation_len == 0) {
529 *Should we perform pool-check ?
531 if (inst->pool_check && *inst->pool_check) {
534 *Ok, so the allocate-find query found nothing ...
535 *Let's check if the pool exists at all
537 allocation_len = sqlippool_query1(allocation, sizeof(allocation),
538 inst->pool_check, handle, inst, request,
541 fr_connection_release(inst->sql_inst->pool, handle);
543 if (allocation_len) {
546 * Pool exists after all... So,
547 * the failure to allocate the IP
548 * address was most likely due to
549 * the depletion of the pool. In
550 * that case, we should return
553 RDEBUG("pool appears to be full");
554 return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);
559 * Pool doesn't exist in the table. It
560 * may be handled by some other instance of
561 * sqlippool, so we should just ignore this
562 * allocation failure and return NOOP
564 RDEBUG("IP address could not be allocated as no pool exists with that name");
565 return RLM_MODULE_NOOP;
569 fr_connection_release(inst->sql_inst->pool, handle);
571 RDEBUG("IP address could not be allocated");
572 return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
576 * See if we can create the VP from the returned data. If not,
577 * error out. If so, add it to the list.
579 vp = fr_pair_afrom_num(request->reply, inst->framed_ip_address, 0);
580 if (fr_pair_value_from_str(vp, allocation, allocation_len) < 0) {
583 RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
584 fr_connection_release(inst->sql_inst->pool, handle);
585 return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
588 RDEBUG("Allocated IP %s", allocation);
589 fr_pair_add(&request->reply->vps, vp);
594 sqlippool_command(inst->allocate_update, handle, inst, request,
595 allocation, allocation_len);
599 fr_connection_release(inst->sql_inst->pool, handle);
601 return do_logging(request, inst->log_success, RLM_MODULE_OK);
604 static int mod_accounting_start(rlm_sql_handle_t *handle,
605 rlm_sqlippool_t *inst, REQUEST *request)
611 return RLM_MODULE_OK;
614 static int mod_accounting_alive(rlm_sql_handle_t *handle,
615 rlm_sqlippool_t *inst, REQUEST *request)
620 return RLM_MODULE_OK;
623 static int mod_accounting_stop(rlm_sql_handle_t *handle,
624 rlm_sqlippool_t *inst, REQUEST *request)
630 return do_logging(request, inst->log_clear, RLM_MODULE_OK);
633 static int mod_accounting_on(rlm_sql_handle_t *handle,
634 rlm_sqlippool_t *inst, REQUEST *request)
640 return RLM_MODULE_OK;
643 static int mod_accounting_off(rlm_sql_handle_t *handle,
644 rlm_sqlippool_t *inst, REQUEST *request)
650 return RLM_MODULE_OK;
654 * Check for an Accounting-Stop
655 * If we find one and we have allocated an IP to this nas/port
656 * combination, then deallocate it.
658 static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
660 int rcode = RLM_MODULE_NOOP;
662 int acct_status_type;
663 rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
664 rlm_sql_handle_t *handle;
666 vp = fr_pair_find_by_num(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY);
668 RDEBUG("Could not find account status type in packet");
669 return RLM_MODULE_NOOP;
671 acct_status_type = vp->vp_integer;
673 switch (acct_status_type) {
674 case PW_STATUS_START:
675 case PW_STATUS_ALIVE:
677 case PW_STATUS_ACCOUNTING_ON:
678 case PW_STATUS_ACCOUNTING_OFF:
679 break; /* continue through to the next section */
682 /* We don't care about any other accounting packet */
683 return RLM_MODULE_NOOP;
686 handle = fr_connection_get(inst->sql_inst->pool);
688 RDEBUG("Cannot allocate sql connection");
689 return RLM_MODULE_FAIL;
692 if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
693 return RLM_MODULE_FAIL;
696 switch (acct_status_type) {
697 case PW_STATUS_START:
698 rcode = mod_accounting_start(handle, inst, request);
701 case PW_STATUS_ALIVE:
702 rcode = mod_accounting_alive(handle, inst, request);
706 rcode = mod_accounting_stop(handle, inst, request);
709 case PW_STATUS_ACCOUNTING_ON:
710 rcode = mod_accounting_on(handle, inst, request);
713 case PW_STATUS_ACCOUNTING_OFF:
714 rcode = mod_accounting_off(handle, inst, request);
718 fr_connection_release(inst->sql_inst->pool, handle);
724 * The module name should be the only globally exported symbol.
725 * That is, everything else should be 'static'.
727 * If the module needs to temporarily modify it's instantiation
728 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
729 * The server will then take care of ensuring that the module
730 * is single-threaded.
732 extern module_t rlm_sqlippool;
733 module_t rlm_sqlippool = {
734 .magic = RLM_MODULE_INIT,
736 .type = RLM_TYPE_THREAD_SAFE,
737 .inst_size = sizeof(rlm_sqlippool_t),
738 .config = module_config,
739 .instantiate = mod_instantiate,
741 [MOD_ACCOUNTING] = mod_accounting,
742 [MOD_POST_AUTH] = mod_post_auth