All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_sqlippool.c
Go to the documentation of this file.
1 /*
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.
6  *
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.
11  *
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
15  */
16 
17 /**
18  * $Id: 5c24a61dec4bd03f8ea9c06b89f07c30b01b99e7 $
19  * @file rlm_sqlippool.c
20  * @brief Allocates an IPv4 address from pools stored in SQL.
21  *
22  * @copyright 2002 Globe.Net Communications Limited
23  * @copyright 2006 The FreeRADIUS server project
24  * @copyright 2006 Suntel Communications
25  */
26 RCSID("$Id: 5c24a61dec4bd03f8ea9c06b89f07c30b01b99e7 $")
27 
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/rad_assert.h>
30 
31 #include <ctype.h>
32 
33 #include <rlm_sql.h>
34 
35 #define MAX_QUERY_LEN 4096
36 
37 /*
38  * Define a structure for our module configuration.
39  */
40 typedef struct rlm_sqlippool_t {
41  char const *sql_instance_name;
42 
43  uint32_t lease_duration;
44 
46 
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
50 
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.
57 
58  char const *pool_check; //!< Query to check for the existence of the pool.
59 
60  /* Start sequence */
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.
64 
65  /* Alive sequence */
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.
69 
70  /* Stop sequence */
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.
74 
75  /* On sequence */
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.
79 
80  /* Off sequence */
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.
84 
85  /* Logging Section */
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.
91 
92  /* Reserved to handle 255.255.255.254 Requests */
93  char const *defaultpool; //!< Default Pool-Name if there is none in the check items.
94 
96 
98  { FR_CONF_OFFSET("exists", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_exists) },
99  { FR_CONF_OFFSET("success", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_success) },
100  { FR_CONF_OFFSET("clear", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_clear) },
101  { FR_CONF_OFFSET("failed", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_failed) },
102  { FR_CONF_OFFSET("nopool", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, log_nopool) },
104 };
105 
106 /*
107  * A mapping of configuration file names to internal variables.
108  *
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
113  * buffer over-flows.
114  */
116  { FR_CONF_OFFSET("sql_module_instance", PW_TYPE_STRING | PW_TYPE_REQUIRED, rlm_sqlippool_t, sql_instance_name), .dflt = "sql" },
117 
118  { FR_CONF_OFFSET("lease_duration", PW_TYPE_INTEGER, rlm_sqlippool_t, lease_duration), .dflt = "86400" },
119 
120  { FR_CONF_OFFSET("pool_name", PW_TYPE_STRING, rlm_sqlippool_t, pool_name), .dflt = "" },
121 
122  { FR_CONF_OFFSET("default_pool", PW_TYPE_STRING, rlm_sqlippool_t, defaultpool), .dflt = "main_pool" },
123 
124 
125  { FR_CONF_OFFSET("ipv6", PW_TYPE_BOOLEAN, rlm_sqlippool_t, ipv6) },
126 
127  { FR_CONF_OFFSET("allocate_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_begin), .dflt = "START TRANSACTION" },
128 
129  { FR_CONF_OFFSET("allocate_clear", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_clear), .dflt = "" },
130 
131  { FR_CONF_OFFSET("allocate_find", PW_TYPE_STRING | PW_TYPE_XLAT | PW_TYPE_REQUIRED, rlm_sqlippool_t, allocate_find), .dflt = "" },
132 
133  { FR_CONF_OFFSET("allocate_update", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, allocate_update), .dflt = "" },
134 
135  { FR_CONF_OFFSET("allocate_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, allocate_commit), .dflt = "COMMIT" },
136 
137 
138  { FR_CONF_OFFSET("pool_check", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, pool_check), .dflt = "" },
139 
140 
141  { FR_CONF_OFFSET("start_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_begin), .dflt = "START TRANSACTION" },
142 
143  { FR_CONF_OFFSET("start_update", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, start_update), .dflt = "" },
144 
145  { FR_CONF_OFFSET("start_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, start_commit), .dflt = "COMMIT" },
146 
147 
148  { FR_CONF_OFFSET("alive_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_begin), .dflt = "START TRANSACTION" },
149 
150  { FR_CONF_OFFSET("alive_update", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, alive_update), .dflt = "" },
151 
152  { FR_CONF_OFFSET("alive_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, alive_commit), .dflt = "COMMIT" },
153 
154 
155  { FR_CONF_OFFSET("stop_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_begin), .dflt = "START TRANSACTION" },
156 
157  { FR_CONF_OFFSET("stop_clear", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, stop_clear), .dflt = "" },
158 
159  { FR_CONF_OFFSET("stop_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, stop_commit), .dflt = "COMMIT" },
160 
161 
162  { FR_CONF_OFFSET("on_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_begin), .dflt = "START TRANSACTION" },
163 
164  { FR_CONF_OFFSET("on_clear", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, on_clear), .dflt = "" },
165 
166  { FR_CONF_OFFSET("on_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, on_commit), .dflt = "COMMIT" },
167 
168 
169  { FR_CONF_OFFSET("off_begin", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_begin), .dflt = "START TRANSACTION" },
170 
171  { FR_CONF_OFFSET("off_clear", PW_TYPE_STRING | PW_TYPE_XLAT , rlm_sqlippool_t, off_clear), .dflt = "" },
172 
173  { FR_CONF_OFFSET("off_commit", PW_TYPE_STRING | PW_TYPE_XLAT, rlm_sqlippool_t, off_commit), .dflt = "COMMIT" },
174 
175  { FR_CONF_POINTER("messages", PW_TYPE_SUBSECTION, NULL), .dflt = (void const *) message_config },
177 };
178 
179 /*
180  * Replace %<whatever> in a string.
181  *
182  * %P pool_name
183  * %I param
184  * %J lease_duration
185  *
186  */
187 static int sqlippool_expand(char * out, int outlen, char const * fmt,
188  rlm_sqlippool_t *data, char * param, int param_len)
189 {
190  char *q;
191  char const *p;
192  char tmp[40]; /* For temporary storing of integers */
193 
194  q = out;
195  for (p = fmt; *p ; p++) {
196  int freespace;
197  int c;
198 
199  /* Calculate freespace in output */
200  freespace = outlen - (q - out);
201  if (freespace <= 1)
202  break;
203 
204  c = *p;
205  if (c != '%') {
206  *q++ = *p;
207  continue;
208  }
209 
210  if (*++p == '\0') {
211  break;
212  }
213 
214  if (c == '%') {
215  switch (*p) {
216  case 'P': /* pool name */
217  strlcpy(q, data->pool_name, freespace);
218  q += strlen(q);
219  break;
220  case 'I': /* IP address */
221  if (param && param_len > 0) {
222  if (param_len > freespace) {
223  strlcpy(q, param, freespace);
224  q += strlen(q);
225  }
226  else {
227  memcpy(q, param, param_len);
228  q += param_len;
229  }
230  }
231  break;
232  case 'J': /* lease duration */
233  sprintf(tmp, "%d", data->lease_duration);
234  strlcpy(q, tmp, freespace);
235  q += strlen(q);
236  break;
237 
238  default:
239  *q++ = '%';
240  *q++ = *p;
241  break;
242  }
243  }
244  }
245  *q = '\0';
246 
247 #if 0
248  DEBUG2("sqlippool_expand: \"%s\"", out);
249 #endif
250 
251  return strlen(out);
252 }
253 
254 /** Perform a single sqlippool query
255  *
256  * Mostly wrapper around sql_query which does some special sqlippool sequence substitutions and expands
257  * the format string.
258  *
259  * @param fmt sql query to expand.
260  * @param handle sql connection handle.
261  * @param data Instance of rlm_sqlippool.
262  * @param request Current request.
263  * @param param ip address string.
264  * @param param_len ip address string len.
265  * @return
266  * - 0 on success.
267  * - < 0 on error.
268  */
269 static int sqlippool_command(char const * fmt, rlm_sql_handle_t * handle, rlm_sqlippool_t *data, REQUEST *request,
270  char *param, int param_len)
271 {
272  char query[MAX_QUERY_LEN];
273  char *expanded = NULL;
274 
275  int ret;
276 
277  /*
278  * If we don't have a command, do nothing.
279  */
280  if (!fmt || !*fmt) return 0;
281 
282  /*
283  * @todo this needs to die (should just be done in xlat expansion)
284  */
285  sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
286 
287  if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, handle) < 0) {
288  return -1;
289  }
290 
291  ret = data->sql_inst->sql_query(data->sql_inst, request, &handle, expanded);
292  if (ret < 0){
293  talloc_free(expanded);
294  return -1;
295  }
296  talloc_free(expanded);
297 
298  (data->sql_inst->module->sql_finish_query)(handle, data->sql_inst->config);
299  return 0;
300 }
301 
302 /*
303  * Don't repeat yourself
304  */
305 #undef DO
306 #define DO(_x) sqlippool_command(inst->_x, handle, inst, request, NULL, 0)
307 
308 /*
309  * Query the database expecting a single result row
310  */
311 static int CC_HINT(nonnull (1, 3, 4, 5)) sqlippool_query1(char *out, int outlen, char const *fmt,
313  REQUEST *request, char *param, int param_len)
314 {
315  char query[MAX_QUERY_LEN];
316  char *expanded = NULL;
317 
318  int rlen, retval;
319 
320  rlm_sql_row_t row;
321 
322  /*
323  * @todo this needs to die (should just be done in xlat expansion)
324  */
325  sqlippool_expand(query, sizeof(query), fmt, data, param, param_len);
326 
327  *out = '\0';
328 
329  /*
330  * Do an xlat on the provided string
331  */
332  if (radius_axlat(&expanded, request, query, data->sql_inst->sql_escape_func, handle) < 0) {
333  return 0;
334  }
335  retval = data->sql_inst->sql_select_query(data->sql_inst, request, &handle, expanded);
336  talloc_free(expanded);
337 
338  if (retval != 0){
339  REDEBUG("database query error on '%s'", query);
340  return 0;
341  }
342 
343  if (data->sql_inst->sql_fetch_row(&row, data->sql_inst, request, &handle) < 0) {
344  REDEBUG("Failed fetching query result");
345  goto finish;
346  }
347 
348  if (!row) {
349  REDEBUG("SQL query did not return any results");
350  goto finish;
351  }
352 
353  if (!row[0]) {
354  REDEBUG("The first column of the result was NULL");
355  goto finish;
356  }
357 
358  rlen = strlen(row[0]);
359  if (rlen >= outlen) {
360  RDEBUG("insufficient string space");
361  goto finish;
362  }
363 
364  strcpy(out, row[0]);
365  retval = rlen;
366 finish:
367  (data->sql_inst->module->sql_finish_select_query)(handle, data->sql_inst->config);
368 
369  return retval;
370 }
371 
372 /*
373  * Do any per-module initialization that is separate to each
374  * configured instance of the module. e.g. set up connections
375  * to external databases, read configuration files, set up
376  * dictionary entries, etc.
377  *
378  * If configuration information is given in the config section
379  * that must be referenced in later calls, store a handle to it
380  * in *instance otherwise put a null pointer there.
381  */
382 static int mod_instantiate(CONF_SECTION *conf, void *instance)
383 {
385  rlm_sqlippool_t *inst = instance;
386  char const *pool_name = NULL;
387 
388  pool_name = cf_section_name2(conf);
389  if (pool_name != NULL) {
390  inst->pool_name = talloc_typed_strdup(inst, pool_name);
391  } else {
392  inst->pool_name = talloc_typed_strdup(inst, "ippool");
393  }
395  inst->sql_instance_name);
396  if (!sql_inst) {
397  cf_log_err_cs(conf, "failed to find sql instance named %s",
398  inst->sql_instance_name);
399  return -1;
400  }
401 
402  if (!inst->ipv6) {
403  inst->framed_ip_address = PW_FRAMED_IP_ADDRESS;
404  } else {
405  inst->framed_ip_address = PW_FRAMED_IPV6_PREFIX;
406  }
407 
408  if (strcmp(sql_inst->entry->name, "rlm_sql") != 0) {
409  cf_log_err_cs(conf, "Module \"%s\""
410  " is not an instance of the rlm_sql module",
411  inst->sql_instance_name);
412  return -1;
413  }
414 
415  inst->sql_inst = (rlm_sql_t *) sql_inst->insthandle;
416  return 0;
417 }
418 
419 
420 /*
421  * If we have something to log, then we log it.
422  * Otherwise we return the retcode as soon as possible
423  */
424 static int do_logging(REQUEST *request, char const *str, int rcode)
425 {
426  char *expanded = NULL;
427 
428  if (!str || !*str) return rcode;
429 
430  if (radius_axlat(&expanded, request, str, NULL, NULL) < 0) {
431  return rcode;
432  }
433 
434  pair_make_config("Module-Success-Message", expanded, T_OP_SET);
435 
436  talloc_free(expanded);
437 
438  return rcode;
439 }
440 
441 
442 /*
443  * Allocate an IP number from the pool.
444  */
445 static rlm_rcode_t CC_HINT(nonnull) mod_post_auth(void *instance, REQUEST *request)
446 {
447  rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
448  char allocation[MAX_STRING_LEN];
449  int allocation_len;
450  VALUE_PAIR *vp;
451  rlm_sql_handle_t *handle;
452  time_t now;
453 
454  /*
455  * If there is a Framed-IP-Address attribute in the reply do nothing
456  */
457  if (fr_pair_find_by_num(request->reply->vps, 0, inst->framed_ip_address, TAG_ANY) != NULL) {
458  RDEBUG("Framed-IP-Address already exists");
459 
460  return do_logging(request, inst->log_exists, RLM_MODULE_NOOP);
461  }
462 
463  if (fr_pair_find_by_num(request->config, 0, PW_POOL_NAME, TAG_ANY) == NULL) {
464  RDEBUG("No Pool-Name defined");
465 
466  return do_logging(request, inst->log_nopool, RLM_MODULE_NOOP);
467  }
468 
469  handle = fr_connection_get(inst->sql_inst->pool);
470  if (!handle) {
471  REDEBUG("cannot get sql connection");
472  return RLM_MODULE_FAIL;
473  }
474 
475  if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
476  return RLM_MODULE_FAIL;
477  }
478 
479  /*
480  * Limit the number of clears we do. There are minor
481  * race conditions for the check, but so what. The
482  * actual work is protected by a transaction. The idea
483  * here is that if we're allocating 100 IPs a second,
484  * we're only do 1 CLEAR per second.
485  */
486  now = time(NULL);
487  if (inst->last_clear < now) {
488  inst->last_clear = now;
489 
490  DO(allocate_begin);
491  DO(allocate_clear);
492  DO(allocate_commit);
493  }
494 
495  DO(allocate_begin);
496 
497  allocation_len = sqlippool_query1(allocation, sizeof(allocation),
498  inst->allocate_find, handle,
499  inst, request, (char *) NULL, 0);
500 
501  /*
502  * Nothing found...
503  */
504  if (allocation_len == 0) {
505  DO(allocate_commit);
506 
507  /*
508  *Should we perform pool-check ?
509  */
510  if (inst->pool_check && *inst->pool_check) {
511 
512  /*
513  *Ok, so the allocate-find query found nothing ...
514  *Let's check if the pool exists at all
515  */
516  allocation_len = sqlippool_query1(allocation, sizeof(allocation),
517  inst->pool_check, handle, inst, request,
518  (char *) NULL, 0);
519 
520  fr_connection_release(inst->sql_inst->pool, handle);
521 
522  if (allocation_len) {
523 
524  /*
525  * Pool exists after all... So,
526  * the failure to allocate the IP
527  * address was most likely due to
528  * the depletion of the pool. In
529  * that case, we should return
530  * NOTFOUND
531  */
532  RDEBUG("pool appears to be full");
533  return do_logging(request, inst->log_failed, RLM_MODULE_NOTFOUND);
534 
535  }
536 
537  /*
538  * Pool doesn't exist in the table. It
539  * may be handled by some other instance of
540  * sqlippool, so we should just ignore this
541  * allocation failure and return NOOP
542  */
543  RDEBUG("IP address could not be allocated as no pool exists with that name");
544  return RLM_MODULE_NOOP;
545 
546  }
547 
548  fr_connection_release(inst->sql_inst->pool, handle);
549 
550  RDEBUG("IP address could not be allocated");
551  return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
552  }
553 
554  /*
555  * See if we can create the VP from the returned data. If not,
556  * error out. If so, add it to the list.
557  */
558  vp = fr_pair_afrom_num(request->reply, 0, inst->framed_ip_address);
559  if (fr_pair_value_from_str(vp, allocation, allocation_len) < 0) {
560  DO(allocate_commit);
561 
562  RDEBUG("Invalid IP number [%s] returned from instbase query.", allocation);
563  fr_connection_release(inst->sql_inst->pool, handle);
564  return do_logging(request, inst->log_failed, RLM_MODULE_NOOP);
565  }
566 
567  RDEBUG("Allocated IP %s", allocation);
568  fr_pair_add(&request->reply->vps, vp);
569 
570  /*
571  * UPDATE
572  */
573  sqlippool_command(inst->allocate_update, handle, inst, request,
574  allocation, allocation_len);
575 
576  DO(allocate_commit);
577 
578  fr_connection_release(inst->sql_inst->pool, handle);
579 
580  return do_logging(request, inst->log_success, RLM_MODULE_OK);
581 }
582 
584  rlm_sqlippool_t *inst, REQUEST *request)
585 {
586  DO(start_begin);
587  DO(start_update);
588  DO(start_commit);
589 
590  return RLM_MODULE_OK;
591 }
592 
594  rlm_sqlippool_t *inst, REQUEST *request)
595 {
596  DO(alive_begin);
597  DO(alive_update);
598  DO(alive_commit);
599  return RLM_MODULE_OK;
600 }
601 
603  rlm_sqlippool_t *inst, REQUEST *request)
604 {
605  DO(stop_begin);
606  DO(stop_clear);
607  DO(stop_commit);
608 
609  return do_logging(request, inst->log_clear, RLM_MODULE_OK);
610 }
611 
613  rlm_sqlippool_t *inst, REQUEST *request)
614 {
615  DO(on_begin);
616  DO(on_clear);
617  DO(on_commit);
618 
619  return RLM_MODULE_OK;
620 }
621 
623  rlm_sqlippool_t *inst, REQUEST *request)
624 {
625  DO(off_begin);
626  DO(off_clear);
627  DO(off_commit);
628 
629  return RLM_MODULE_OK;
630 }
631 
632 /*
633  * Check for an Accounting-Stop
634  * If we find one and we have allocated an IP to this nas/port
635  * combination, then deallocate it.
636  */
637 static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void *instance, REQUEST *request)
638 {
639  int rcode = RLM_MODULE_NOOP;
640  VALUE_PAIR *vp;
641  int acct_status_type;
642  rlm_sqlippool_t *inst = (rlm_sqlippool_t *) instance;
643  rlm_sql_handle_t *handle;
644 
645  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_ACCT_STATUS_TYPE, TAG_ANY);
646  if (!vp) {
647  RDEBUG("Could not find account status type in packet");
648  return RLM_MODULE_NOOP;
649  }
650  acct_status_type = vp->vp_integer;
651 
652  switch (acct_status_type) {
653  case PW_STATUS_START:
654  case PW_STATUS_ALIVE:
655  case PW_STATUS_STOP:
658  break; /* continue through to the next section */
659 
660  default:
661  /* We don't care about any other accounting packet */
662  return RLM_MODULE_NOOP;
663  }
664 
665  handle = fr_connection_get(inst->sql_inst->pool);
666  if (!handle) {
667  RDEBUG("Cannot allocate sql connection");
668  return RLM_MODULE_FAIL;
669  }
670 
671  if (inst->sql_inst->sql_set_user(inst->sql_inst, request, NULL) < 0) {
672  return RLM_MODULE_FAIL;
673  }
674 
675  switch (acct_status_type) {
676  case PW_STATUS_START:
677  rcode = mod_accounting_start(handle, inst, request);
678  break;
679 
680  case PW_STATUS_ALIVE:
681  rcode = mod_accounting_alive(handle, inst, request);
682  break;
683 
684  case PW_STATUS_STOP:
685  rcode = mod_accounting_stop(handle, inst, request);
686  break;
687 
689  rcode = mod_accounting_on(handle, inst, request);
690  break;
691 
693  rcode = mod_accounting_off(handle, inst, request);
694  break;
695  }
696 
697  fr_connection_release(inst->sql_inst->pool, handle);
698 
699  return rcode;
700 }
701 
702 /*
703  * The module name should be the only globally exported symbol.
704  * That is, everything else should be 'static'.
705  *
706  * If the module needs to temporarily modify it's instantiation
707  * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
708  * The server will then take care of ensuring that the module
709  * is single-threaded.
710  */
711 extern module_t rlm_sqlippool;
712 module_t rlm_sqlippool = {
714  .name = "sqlippool",
715  .type = RLM_TYPE_THREAD_SAFE,
716  .inst_size = sizeof(rlm_sqlippool_t),
717  .config = module_config,
718  .instantiate = mod_instantiate,
719  .methods = {
722  },
723 };
ssize_t ssize_t ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
#define MAX_QUERY_LEN
Definition: rlm_sqlippool.c:35
char const * off_begin
SQL query to begin.
Definition: rlm_sqlippool.c:81
static int mod_accounting_alive(rlm_sql_handle_t *handle, rlm_sqlippool_t *inst, REQUEST *request)
char const * start_begin
SQL query to begin.
Definition: rlm_sqlippool.c:61
char const * start_update
SQL query to update an IP entry.
Definition: rlm_sqlippool.c:62
Main server configuration.
Definition: radiusd.h:108
static rlm_rcode_t mod_accounting(void *instance, REQUEST *request)
Write accounting data to Couchbase documents.
Prototypes and functions for the SQL module.
The module is OK, continue.
Definition: radiusd.h:91
char ** rlm_sql_row_t
Definition: rlm_sql.h:59
module_entry_t * entry
Definition: modpriv.h:67
char const * sql_instance_name
Definition: rlm_sqlippool.c:41
static rlm_rcode_t mod_post_auth(void *instance, REQUEST *request) CC_HINT(nonnull)
Metadata exported by the module.
Definition: modules.h:134
char const * alive_begin
SQL query to begin.
Definition: rlm_sqlippool.c:66
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
char const * log_failed
Failed to allocate ip from the pool.
Definition: rlm_sqlippool.c:89
char const * allocate_begin
SQL query to begin.
Definition: rlm_sqlippool.c:52
char const * alive_update
SQL query to update an IP entry.
Definition: rlm_sqlippool.c:67
7 methods index for postauth section.
Definition: modules.h:48
char const * stop_clear
SQL query to clear an IP.
Definition: rlm_sqlippool.c:72
char const * on_clear
SQL query to clear an entire NAS.
Definition: rlm_sqlippool.c:77
#define RLM_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: modules.h:75
#define RLM_MODULE_INIT
Definition: modules.h:86
char const * allocate_clear
SQL query to clear an IP.
Definition: rlm_sqlippool.c:53
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
#define PW_STATUS_ALIVE
Definition: radius.h:193
static int sqlippool_expand(char *out, int outlen, char const *fmt, rlm_sqlippool_t *data, char *param, int param_len)
#define PW_STATUS_START
Definition: radius.h:191
#define inst
module_instance_t * module_instantiate(CONF_SECTION *modules, char const *askedname)
Load a module, and instantiate it.
Definition: modules.c:644
char const * allocate_update
SQL query to mark an IP as used.
Definition: rlm_sqlippool.c:55
char const * alive_commit
SQL query to commit.
Definition: rlm_sqlippool.c:68
#define PW_TYPE_SUBSECTION
Definition: conffile.h:188
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
char const * stop_commit
SQL query to commit.
Definition: rlm_sqlippool.c:73
rlm_sql_t * sql_inst
Definition: rlm_sqlippool.c:45
uint32_t lease_duration
Definition: rlm_sqlippool.c:43
char const * name
Definition: modpriv.h:53
static CONF_PARSER module_config[]
int(* sql_set_user)(rlm_sql_t const *inst, REQUEST *request, char const *username)
Definition: rlm_sql.h:231
static int mod_accounting_on(rlm_sql_handle_t *handle, rlm_sqlippool_t *inst, REQUEST *request)
char const * log_exists
There was an ip address already assigned.
Definition: rlm_sqlippool.c:86
#define pair_make_config(_a, _b, _c)
Definition: radiusd.h:547
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
#define DEBUG2(fmt,...)
Definition: log.h:176
#define PW_TYPE_XLAT
string will be dynamically expanded.
Definition: conffile.h:207
xlat_escape_t sql_escape_func
Definition: rlm_sql.h:232
3 methods index for accounting section.
Definition: modules.h:44
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
A truth value.
Definition: radius.h:56
rlm_sql_config_t * config
Definition: rlm_sql.h:221
char const * log_clear
We successfully deallocated ip address from pool.
Definition: rlm_sqlippool.c:88
Definition: token.h:45
32 Bit unsigned integer.
Definition: radius.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t len)
Convert string value to native attribute value.
Definition: pair.c:1840
static rs_t * conf
Definition: radsniff.c:46
char const * pool_check
Query to check for the existence of the pool.
Definition: rlm_sqlippool.c:58
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *, char const *name)
Find a sub-section in a section.
Definition: conffile.c:3708
struct rlm_sqlippool_t rlm_sqlippool_t
char const * allocate_commit
SQL query to commit.
Definition: rlm_sqlippool.c:56
Module succeeded without doing anything.
Definition: radiusd.h:96
static int do_logging(REQUEST *request, char const *str, int rcode)
uint8_t data[]
Definition: eap_pwd.h:625
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
CONF_SECTION * config
Root of the server config.
Definition: radiusd.h:110
void * insthandle
Definition: modpriv.h:68
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
static int CC_HINT(nonnull(1, 3, 4, 5))
char const * off_commit
SQL query to commit.
Definition: rlm_sqlippool.c:83
void * fr_connection_get(fr_connection_pool_t *pool)
Reserve a connection in the connection pool.
Definition: connection.c:1291
time_t last_clear
So we only do it once a second.
Definition: rlm_sqlippool.c:51
char const * log_nopool
There was no Framed-IP-Address but also no Pool-Name.
Definition: rlm_sqlippool.c:90
#define PW_STATUS_ACCOUNTING_ON
Definition: radius.h:194
module_t rlm_sqlippool
#define REDEBUG(fmt,...)
Definition: log.h:254
char const * off_clear
SQL query to clear an entire NAS.
Definition: rlm_sqlippool.c:82
static int mod_accounting_off(rlm_sql_handle_t *handle, rlm_sqlippool_t *inst, REQUEST *request)
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: conffile.h:200
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
bool ipv6
Whether or not we do IPv6 pools.
Definition: rlm_sqlippool.c:48
static CONF_PARSER message_config[]
Definition: rlm_sqlippool.c:97
#define PW_STATUS_STOP
Definition: radius.h:192
char const * stop_begin
SQL query to begin.
Definition: rlm_sqlippool.c:71
char const * start_commit
SQL query to commit.
Definition: rlm_sqlippool.c:63
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
sql_rcode_t(* sql_query)(rlm_sql_t const *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query)
Definition: rlm_sql.h:233
char const * defaultpool
Default Pool-Name if there is none in the check items.
Definition: rlm_sqlippool.c:93
sql_rcode_t(* sql_finish_query)(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
Definition: rlm_sql.h:212
void fr_connection_release(fr_connection_pool_t *pool, void *conn)
Release a connection.
Definition: connection.c:1305
char const * pool_name
Definition: rlm_sqlippool.c:47
char const * allocate_find
SQL query to find an unused IP.
Definition: rlm_sqlippool.c:54
#define MAX_STRING_LEN
Definition: libradius.h:120
String of printable characters.
Definition: radius.h:33
#define FR_CONF_POINTER(_n, _t, _p)
Definition: conffile.h:172
char const * log_success
We successfully allocated ip address from pool.
Definition: rlm_sqlippool.c:87
static int mod_accounting_stop(rlm_sql_handle_t *handle, rlm_sqlippool_t *inst, REQUEST *request)
User not found.
Definition: radiusd.h:95
#define RCSID(id)
Definition: build.h:135
rlm_sql_module_t * module
Definition: rlm_sql.h:229
#define DO(_x)
char const * on_commit
SQL query to commit.
Definition: rlm_sqlippool.c:78
int framed_ip_address
the attribute number for Framed-IP(v6)-Address
Definition: rlm_sqlippool.c:49
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
static int mod_accounting_start(rlm_sql_handle_t *handle, rlm_sqlippool_t *inst, REQUEST *request)
fr_connection_pool_t * pool
Definition: rlm_sql.h:220
#define PW_STATUS_ACCOUNTING_OFF
Definition: radius.h:195
#define RDEBUG(fmt,...)
Definition: log.h:243
char const * cf_section_name2(CONF_SECTION const *cs)
Definition: conffile.c:3601
static int sqlippool_command(char const *fmt, rlm_sql_handle_t *handle, rlm_sqlippool_t *data, REQUEST *request, char *param, int param_len)
Perform a single sqlippool query.
char const * on_begin
SQL query to begin.
Definition: rlm_sqlippool.c:76