The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: b4e42b572f49276313b43c8d47b54a7d6cf4ccda $
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: b4e42b572f49276313b43c8d47b54a7d6cf4ccda $")
27 
28 #define LOG_PREFIX inst->name
29 
30 #include <rlm_sql.h>
31 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/radius/radius.h>
33 #include <freeradius-devel/unlang/function.h>
34 
35 #include <ctype.h>
36 
37 /*
38  * Define a structure for our module configuration.
39  */
40 typedef struct {
41  char const *name;
42  char const *sql_name;
43 
44  rlm_sql_t const *sql;
46 
47 /** Call environment used by module alloc method
48  */
49 typedef struct {
50  fr_value_box_t pool_name; //!< Name of pool address will be allocated from.
51  tmpl_t *pool_name_tmpl; //!< Tmpl used to expand pool_name
52  fr_value_box_t requested_address; //!< IP address being requested by client.
53  tmpl_t *allocated_address_attr; //!< Attribute to populate with allocated IP.
54  fr_value_box_t allocated_address; //!< Existing value for allocated IP.
55  fr_value_box_t begin; //!< SQL query to begin transaction.
56  tmpl_t *existing; //!< tmpl to expand as query for finding the existing IP.
57  tmpl_t *requested; //!< tmpl to expand as query for finding the requested IP.
58  tmpl_t *find; //!< tmpl to expand as query for finding an unused IP.
59  tmpl_t *update; //!< tmpl to expand as query for updating the found IP.
60  tmpl_t *pool_check; //!< tmpl to expand as query for checking for existence of the pool.
61  fr_value_box_t commit; //!< SQL query to commit transaction.
63 
64 /** Call environment used by all other module methods
65  */
66 typedef struct {
67  fr_value_box_t free; //!< SQL query to clear other offered IPs. Only used in "update" method.
68  fr_value_box_t update; //!< SQL query to update an IP record.
70 
71 /** Current step in IP allocation state machine
72  */
73 typedef enum {
74  IPPOOL_ALLOC_BEGIN_RUN, //!< Run the "begin" query
75  IPPOOL_ALLOC_EXISTING, //!< Expanding the "existing" query
76  IPPOOL_ALLOC_EXISTING_RUN, //!< Run the "existing" query
77  IPPOOL_ALLOC_REQUESTED, //!< Expanding the "requested" query
78  IPPOOL_ALLOC_REQUESTED_RUN, //!< Run the "requested" query
79  IPPOOL_ALLOC_FIND, //!< Expanding the "find" query
80  IPPOOL_ALLOC_FIND_RUN, //!< Run the "find" query
81  IPPOOL_ALLOC_NO_ADDRESS, //!< No address was found
82  IPPOOL_ALLOC_POOL_CHECK, //!< Expanding the "pool_check" query
83  IPPOOL_ALLOC_POOL_CHECK_RUN, //!< Run the "pool_check" query
84  IPPOOL_ALLOC_MAKE_PAIR, //!< Make the pair.
85  IPPOOL_ALLOC_UPDATE, //!< Expanding the "update" query
86  IPPOOL_ALLOC_UPDATE_RUN, //!< Run the "update" query
87  IPPOOL_ALLOC_COMMIT_RUN, //!< RUn the "commit" query
89 
90 /** Resume context for IP allocation
91  */
92 typedef struct {
93  request_t *request; //!< Current request.
94  ippool_alloc_status_t status; //!< Status of the allocation.
95  ippool_alloc_call_env_t *env; //!< Call environment for the allocation.
96  rlm_sql_handle_t *handle; //!< SQL handle being used for queries.
97  trunk_t *trunk; //!< Trunk connection for queries.
98  rlm_sql_t const *sql; //!< SQL module instance.
99  fr_value_box_list_t values; //!< Where to put the expanded queries ready for execution.
100  fr_value_box_t *query; //!< Current query being run.
101  fr_sql_query_t *query_ctx; //!< Query context for allocation queries.
102  rlm_rcode_t rcode; //!< Result code to return after running "commit".
104 
105 /** Resume context for IP update / release
106  */
107 typedef struct {
108  request_t *request; //!< Current request.
109  ippool_common_call_env_t *env; //!< Call environment for the update.
110  rlm_sql_handle_t *handle; //!< SQL handle being used for queries.
111  rlm_sql_t const *sql; //!< SQL module instance.
112  fr_sql_query_t *query_ctx; //!< Query context for allocation queries.
114 
116  { FR_CONF_OFFSET("sql_module_instance", rlm_sqlippool_t, sql_name), .dflt = "sql" },
117 
119 };
120 
121 static int _sql_escape_uxtx_free(void *uctx)
122 {
123  return talloc_free(uctx);
124 }
125 
126 static void *sql_escape_uctx_alloc(request_t *request, void const *uctx)
127 {
128  static _Thread_local rlm_sql_escape_uctx_t *t_ctx;
129 
130  if (unlikely(t_ctx == NULL)) {
132 
133  MEM(ctx = talloc_zero(NULL, rlm_sql_escape_uctx_t));
135  }
136  t_ctx->sql = uctx;
137  t_ctx->handle = request_data_reference(request, (void *)sql_escape_uctx_alloc, 0);
138 
139  return t_ctx;
140 }
141 
142 /*
143  * Don't repeat yourself
144  */
145 #define RESERVE_CONNECTION(_handle, _sql, _request) if (!_sql->driver->uses_trunks) { \
146  handle = fr_pool_connection_get(_sql->pool, _request); \
147  if (!_handle) { \
148  REDEBUG("Failed reserving SQL connection"); \
149  RETURN_MODULE_FAIL; \
150  } \
151 }
152 
153 
154 /*
155  * Process the results of an SQL query expected to return a single row
156  */
157 static int sqlippool_result_process(char *out, int outlen, fr_sql_query_t *query_ctx)
158 {
159  rlm_rcode_t p_result;
160  int rlen, retval = 0;
161  rlm_sql_row_t row;
162  request_t *request = query_ctx->request;
163 
164  *out = '\0';
165 
166  query_ctx->inst->fetch_row(&p_result, NULL, query_ctx->request, query_ctx);
167  if (query_ctx->rcode < 0) {
168  REDEBUG("Failed fetching query_result");
169  goto finish;
170  }
171 
172  row = query_ctx->row;
173  if (!row) {
174  RDEBUG2("SQL query did not return any results");
175  goto finish;
176  }
177 
178  if (!row[0]) {
179  REDEBUG("The first column of the result was NULL");
180  goto finish;
181  }
182 
183  rlen = strlen(row[0]);
184  if (rlen >= outlen) {
185  REDEBUG("The first column of the result was too long (%d)", rlen);
186  goto finish;
187  }
188 
189  strcpy(out, row[0]);
190  retval = rlen;
191 
192 finish:
193  query_ctx->inst->driver->sql_finish_select_query(query_ctx, &query_ctx->inst->config);
194  return retval;
195 }
196 
197 /*
198  * Do any per-module initialization that is separate to each
199  * configured instance of the module. e.g. set up connections
200  * to external databases, read configuration files, set up
201  * dictionary entries, etc.
202  *
203  * If configuration information is given in the config section
204  * that must be referenced in later calls, store a handle to it
205  * in *instance otherwise put a null pointer there.
206  */
207 static int mod_instantiate(module_inst_ctx_t const *mctx)
208 {
209  module_instance_t *sql;
210  rlm_sqlippool_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlippool_t);
211  CONF_SECTION *conf = mctx->mi->conf;
212 
213  inst->name = talloc_asprintf(inst, "%s - %s", mctx->mi->name, inst->sql_name);
214 
215  sql = module_rlm_static_by_name(NULL, inst->sql_name);
216  if (!sql) {
217  cf_log_err(conf, "failed to find sql instance named %s",
218  inst->sql_name);
219  return -1;
220  }
221 
222  inst->sql = (rlm_sql_t *) sql->data;
223 
224  if (strcmp(talloc_get_name(inst->sql), "rlm_sql_t") != 0) {
225  cf_log_err(conf, "Module \"%s\" is not an instance of the rlm_sql module",
226  inst->sql_name);
227  return -1;
228  }
229 
230  return 0;
231 }
232 
233 /** Release SQL pool connections when alloc context is freed.
234  */
236 {
237  if (!to_free->sql->sql_escape_arg) (void) request_data_get(to_free->request, (void *)sql_escape_uctx_alloc, 0);
238  if (to_free->handle) fr_pool_connection_release(to_free->sql->pool, to_free->request, to_free->handle);
239  return 0;
240 }
241 
242 #define REPEAT_MOD_ALLOC_RESUME if (unlang_function_repeat_set(request, mod_alloc_resume) < 0) RETURN_MODULE_FAIL
243 #define SUBMIT_QUERY(_query_str, _new_status, _type, _function) do { \
244  alloc_ctx->status = _new_status; \
245  REPEAT_MOD_ALLOC_RESUME; \
246  query_ctx->query_str = _query_str; \
247  query_ctx->type = _type; \
248  query_ctx->status = SQL_QUERY_PREPARED; \
249  alloc_ctx->query = query; \
250  return unlang_function_push(request, sql->_function, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx); \
251 } while (0)
252 
253 /** Resume function called after each IP allocation query is expanded
254  *
255  * Executes the query and, if appropriate, pushes the next tmpl for expansion
256  *
257  * Following the final (successful) query, the destination attribute is populated.
258  *
259  * @param p_result Result of IP allocation.
260  * @param priority Unused.
261  * @param request Current request.
262  * @param uctx Current allocation context.
263  * @return One of the UNLANG_ACTION_* values.
264  */
265 static unlang_action_t mod_alloc_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
266 {
267  ippool_alloc_ctx_t *alloc_ctx = talloc_get_type_abort(uctx, ippool_alloc_ctx_t);
268  ippool_alloc_call_env_t *env = alloc_ctx->env;
269  int allocation_len = 0;
270  char allocation[FR_MAX_STRING_LEN];
271  rlm_sql_t const *sql = alloc_ctx->sql;
272  fr_value_box_t *query = fr_value_box_list_pop_head(&alloc_ctx->values);
273  fr_sql_query_t *query_ctx = alloc_ctx->query_ctx;
274 
275  /*
276  * If a previous async call returned one of the "failure" results just return.
277  */
278  switch (*p_result) {
281 
282  default:
283  break;
284  }
285 
286  switch (alloc_ctx->status) {
288  if ((env->begin.type == FR_TYPE_STRING) &&
289  env->begin.vb_length) sql->driver->sql_finish_query(query_ctx, &query_ctx->inst->config);
290 
291  /*
292  * The first call of this function will always land here, whether or not a "begin" query is actually run.
293  *
294  * Having (possibly) run the "begin" query, establish which tmpl needs expanding
295  *
296  * If there is a query for finding the existing IP expand that first
297  */
298  if (env->existing) {
299  alloc_ctx->status = IPPOOL_ALLOC_EXISTING;
301  if (unlang_tmpl_push(alloc_ctx, &alloc_ctx->values, request, env->existing, NULL) < 0) {
302  error:
303  talloc_free(alloc_ctx);
305  }
307  }
308  goto expand_requested;
309 
311  if (query && query->vb_length) SUBMIT_QUERY(query->vb_strvalue, IPPOOL_ALLOC_EXISTING_RUN, SQL_QUERY_SELECT, select);
312  goto expand_requested;
313 
315  TALLOC_FREE(alloc_ctx->query);
316  if (query_ctx->rcode != RLM_SQL_OK) goto error;
317 
318  allocation_len = sqlippool_result_process(allocation, sizeof(allocation), query_ctx);
319  if (allocation_len > 0) goto make_pair;
320 
321  /*
322  * If there's a requested address and associated query, expand that
323  */
324  expand_requested:
325  if (env->requested && (env->requested_address.type != FR_TYPE_NULL)) {
326  alloc_ctx->status = IPPOOL_ALLOC_REQUESTED;
328  if (unlang_tmpl_push(alloc_ctx, &alloc_ctx->values, request, env->requested, NULL) < 0) goto error;
330  }
331  goto expand_find;
332 
334  if (query && query->vb_length) SUBMIT_QUERY(query->vb_strvalue, IPPOOL_ALLOC_REQUESTED_RUN, SQL_QUERY_SELECT, select);
335 
336  goto expand_find;
337 
339  TALLOC_FREE(alloc_ctx->query);
340  if (query_ctx->rcode != RLM_SQL_OK) goto error;
341 
342  allocation_len = sqlippool_result_process(allocation, sizeof(allocation), query_ctx);
343  if (allocation_len > 0) goto make_pair;
344 
345  expand_find:
346  /*
347  * Neither "existing" nor "requested" found an address, expand "find" query
348  */
349  alloc_ctx->status = IPPOOL_ALLOC_FIND;
351  if (unlang_tmpl_push(alloc_ctx, &alloc_ctx->values, request, env->find, NULL) < 0) goto error;
353 
354  case IPPOOL_ALLOC_FIND:
355  SUBMIT_QUERY(query->vb_strvalue, IPPOOL_ALLOC_FIND_RUN, SQL_QUERY_SELECT, select);
356 
358  TALLOC_FREE(alloc_ctx->query);
359  if (query_ctx->rcode != RLM_SQL_OK) goto error;
360 
361  allocation_len = sqlippool_result_process(allocation, sizeof(allocation), query_ctx);
362 
363  if (allocation_len > 0) goto make_pair;
364 
365  /*
366  * Nothing found
367  */
368  if ((env->commit.type == FR_TYPE_STRING) &&
369  env->commit.vb_length) SUBMIT_QUERY(env->commit.vb_strvalue, IPPOOL_ALLOC_NO_ADDRESS, SQL_QUERY_OTHER, query);
370  FALL_THROUGH;
371 
373  if ((env->commit.type == FR_TYPE_STRING) &&
374  env->commit.vb_length) sql->driver->sql_finish_query(query_ctx, &query_ctx->inst->config);
375 
376  /*
377  * Should we perform pool-check?
378  */
379  if (env->pool_check) {
380  alloc_ctx->status = IPPOOL_ALLOC_POOL_CHECK;
382  if (unlang_tmpl_push(alloc_ctx, &alloc_ctx->values, request, env->pool_check, NULL) < 0) goto error;
384  }
385  no_address:
386  RWDEBUG("IP address could not be allocated");
388 
390  {
391  tmpl_t ip_rhs;
392  map_t ip_map;
393 
394  make_pair:
395  /*
396  * See if we can create the VP from the returned data. If not,
397  * error out. If so, add it to the list.
398  */
399  ip_map = (map_t) {
400  .lhs = env->allocated_address_attr,
401  .op = T_OP_SET,
402  .rhs = &ip_rhs
403  };
404 
405  tmpl_init_shallow(&ip_rhs, TMPL_TYPE_DATA, T_BARE_WORD, "", 0, NULL);
406  fr_value_box_bstrndup_shallow(&ip_map.rhs->data.literal, NULL, allocation, allocation_len, false);
407  if (map_to_request(request, &ip_map, map_to_vp, NULL) < 0) {
408  alloc_ctx->rcode = RLM_MODULE_FAIL;
409 
410  REDEBUG("Invalid IP address [%s] returned from database query.", allocation);
411  goto finish;
412  }
413 
414  RDEBUG2("Allocated IP %s", allocation);
415  alloc_ctx->rcode = RLM_MODULE_UPDATED;
416 
417  /*
418  * If we have an update query expand it
419  */
420  if (env->update) {
421  alloc_ctx->status = IPPOOL_ALLOC_UPDATE;
423  if (unlang_tmpl_push(alloc_ctx, &alloc_ctx->values, request, env->update, NULL) < 0) goto error;
425  }
426 
427  goto finish;
428  }
429 
431  /*
432  * Ok, so the allocate-find query found nothing ...
433  * Let's check if the pool exists at all
434  */
435  if (query && query->vb_length) SUBMIT_QUERY(query->vb_strvalue, IPPOOL_ALLOC_POOL_CHECK_RUN, SQL_QUERY_SELECT, select);
436  goto no_address;
437 
439  TALLOC_FREE(alloc_ctx->query);
440  allocation_len = sqlippool_result_process(allocation, sizeof(allocation), query_ctx);
441 
442  if (allocation_len) {
443  /*
444  * Pool exists after all... So,
445  * the failure to allocate the IP
446  * address was most likely due to
447  * the depletion of the pool. In
448  * that case, we should return
449  * NOTFOUND
450  */
451  RWDEBUG("Pool \"%pV\" appears to be full", &env->pool_name);
453  }
454 
455  /*
456  * Pool doesn't exist in the table. It
457  * may be handled by some other instance of
458  * sqlippool, so we should just ignore this
459  * allocation failure and return NOOP
460  */
461  RWDEBUG("IP address could not be allocated as no pool exists with the name \"%pV\"",
462  &env->pool_name);
464 
465  case IPPOOL_ALLOC_UPDATE:
466  if (query && query->vb_length) SUBMIT_QUERY(query->vb_strvalue, IPPOOL_ALLOC_UPDATE_RUN, SQL_QUERY_OTHER, query);
467 
468  goto finish;
469 
471  TALLOC_FREE(alloc_ctx->query);
472  if (env->update) sql->driver->sql_finish_query(query_ctx, &query_ctx->inst->config);
473 
474  finish:
475  if ((env->commit.type == FR_TYPE_STRING) &&
476  env->commit.vb_length) SUBMIT_QUERY(env->commit.vb_strvalue, IPPOOL_ALLOC_COMMIT_RUN, SQL_QUERY_OTHER, query);
477 
478  FALL_THROUGH;
479 
481  {
482  rlm_rcode_t rcode = alloc_ctx->rcode;
483  talloc_free(alloc_ctx);
484  RETURN_MODULE_RCODE(rcode);
485  }
486  }
487 
488  /*
489  * All return paths are handled within the switch statement.
490  */
491  fr_assert(0);
493 }
494 
495 /** Initiate the allocation of an IP address from the pool.
496  *
497  * Based on configured queries and attributes which exist, determines the first
498  * query tmpl to expand.
499  *
500  * @param p_result Result of the allocation (if it fails).
501  * @param mctx Module context.
502  * @param request Current request.
503  * @return One of the UNLANG_ACTION_* values.
504  */
505 static unlang_action_t CC_HINT(nonnull) mod_alloc(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
506 {
507  rlm_sqlippool_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlippool_t);
508  ippool_alloc_call_env_t *env = talloc_get_type_abort(mctx->env_data, ippool_alloc_call_env_t);
509  rlm_sql_t const *sql = inst->sql;
510  rlm_sql_handle_t *handle = NULL;
511  ippool_alloc_ctx_t *alloc_ctx = NULL;
512  rlm_sql_thread_t *thread = talloc_get_type_abort(module_thread(sql->mi)->data, rlm_sql_thread_t);
513 
514  /*
515  * If the allocated IP attribute already exists, do nothing
516  */
517  if (env->allocated_address.type) {
518  RDEBUG2("%s already exists (%pV)", env->allocated_address_attr->name, &env->allocated_address);
520  }
521 
522  if (env->pool_name.type == FR_TYPE_NULL) {
523  RDEBUG2("No %s defined", env->pool_name_tmpl->name);
525  }
526 
527  RESERVE_CONNECTION(handle, inst->sql, request);
528  if (!sql->sql_escape_arg && !thread->sql_escape_arg && handle)
529  request_data_add(request, (void *)sql_escape_uctx_alloc, 0, handle, false, false, false);
530 
531  MEM(alloc_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ippool_alloc_ctx_t));
532  *alloc_ctx = (ippool_alloc_ctx_t) {
533  .env = env,
534  .handle = handle,
535  .trunk = thread->trunk,
536  .sql = inst->sql,
537  .request = request,
538  };
539  talloc_set_destructor(alloc_ctx, sqlippool_alloc_ctx_free);
540 
541  /*
542  * Allocate a query_ctx which will be used for all queries in the allocation.
543  * Since they typically form an SQL transaction, they all need to be on the same
544  * connection, and use the same trunk request if using trunks.
545  */
546  MEM(alloc_ctx->query_ctx = sql->query_alloc(alloc_ctx, sql, request, handle, thread->trunk, "", SQL_QUERY_OTHER));
547 
548  fr_value_box_list_init(&alloc_ctx->values);
549  if (unlang_function_push(request, NULL, mod_alloc_resume, NULL, 0, UNLANG_SUB_FRAME, alloc_ctx) < 0 ) {
550  talloc_free(alloc_ctx);
552  }
553 
554  if ((env->begin.type == FR_TYPE_STRING) && env->begin.vb_length) {
555  alloc_ctx->query_ctx->query_str = env->begin.vb_strvalue;
556  return unlang_function_push(request, sql->query, NULL, NULL, 0, UNLANG_SUB_FRAME, alloc_ctx->query_ctx);
557  }
558 
560 }
561 
562 /** Resume function called after mod_common "update" query has completed
563  */
564 static unlang_action_t mod_common_update_resume(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
565 {
566  ippool_common_ctx_t *common_ctx = talloc_get_type_abort(uctx, ippool_common_ctx_t);
567  fr_sql_query_t *query_ctx = common_ctx->query_ctx;
568  rlm_sql_t const *sql = common_ctx->sql;
569  int affected = 0;
570 
571  switch (*p_result) {
574 
575  default:
576  break;
577  }
578 
579  affected = sql->driver->sql_affected_rows(query_ctx, &sql->config);
580 
581  talloc_free(common_ctx);
582 
583  if (affected > 0) RETURN_MODULE_UPDATED;
585 }
586 
587 /** Resume function called after mod_common "free" query has completed
588  */
589 static unlang_action_t mod_common_free_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
590 {
591  ippool_common_ctx_t *common_ctx = talloc_get_type_abort(uctx, ippool_common_ctx_t);
592  fr_sql_query_t *query_ctx = common_ctx->query_ctx;
593  rlm_sql_t const *sql = common_ctx->sql;
594 
595  switch (*p_result) {
598 
599  default:
600  break;
601  }
602  if (common_ctx->env->update.type != FR_TYPE_STRING) RETURN_MODULE_NOOP;
603 
604  sql->driver->sql_finish_query(query_ctx, &sql->config);
605 
606  if (unlang_function_push(request, NULL, mod_common_update_resume, NULL, 0, UNLANG_SUB_FRAME, common_ctx) < 0) {
607  talloc_free(common_ctx);
609  }
610 
611  common_ctx->query_ctx->query_str = common_ctx->env->update.vb_strvalue;
612  query_ctx->status = SQL_QUERY_PREPARED;
613  return unlang_function_push(request, sql->query, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx);
614 }
615 
616 /** Return connection to pool when mod_common context is freed.
617  */
619 {
620  if (to_free->handle) fr_pool_connection_release(to_free->sql->pool, to_free->request, to_free->handle);
621  return 0;
622 }
623 
624 /** Common function used by module methods which perform an optional "free" then "update"
625  * - update
626  * - release
627  * - bulk_release
628  * - mark
629  */
630 static unlang_action_t CC_HINT(nonnull) mod_common(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
631 {
632  rlm_sqlippool_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_sqlippool_t);
633  ippool_common_call_env_t *env = talloc_get_type_abort(mctx->env_data, ippool_common_call_env_t);
634  rlm_sql_t const *sql = inst->sql;
635  rlm_sql_thread_t *thread = talloc_get_type_abort(module_thread(sql->mi)->data, rlm_sql_thread_t);
636  rlm_sql_handle_t *handle = NULL;
637  ippool_common_ctx_t *common_ctx = NULL;
638 
639  if ((env->free.type != FR_TYPE_STRING) && (env->update.type != FR_TYPE_STRING)) RETURN_MODULE_NOOP;
640 
641  RESERVE_CONNECTION(handle, inst->sql, request);
642  MEM(common_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ippool_common_ctx_t));
643  *common_ctx = (ippool_common_ctx_t) {
644  .request = request,
645  .env = env,
646  .handle = handle,
647  .sql = sql,
648  };
649  talloc_set_destructor(common_ctx, sqlippool_common_ctx_free);
650 
651  MEM(common_ctx->query_ctx = sql->query_alloc(common_ctx, sql, request, handle, thread->trunk, "", SQL_QUERY_OTHER));
652 
653  /*
654  * An optional query which can be used to tidy up before updates
655  * primarily intended for multi-server setups sharing a common database
656  * allowing for tidy up of multiple offered addresses in a DHCP context.
657  */
658  if (env->free.type == FR_TYPE_STRING) {
659  common_ctx->query_ctx->query_str = env->free.vb_strvalue;
660  if (unlang_function_push(request, NULL, mod_common_free_resume, NULL, 0, UNLANG_SUB_FRAME, common_ctx) < 0) {
661  talloc_free(common_ctx);
663  }
664  return unlang_function_push(request, sql->query, NULL, NULL, 0, UNLANG_SUB_FRAME, common_ctx->query_ctx);
665  }
666 
667  common_ctx->query_ctx->query_str = env->update.vb_strvalue;
668  if (unlang_function_push(request, NULL, mod_common_update_resume, NULL, 0, UNLANG_SUB_FRAME, common_ctx) < 0) {
669  talloc_free(common_ctx);
671  }
672  return unlang_function_push(request, sql->query, NULL, NULL, 0, UNLANG_SUB_FRAME, common_ctx->query_ctx);
673 }
674 
675 /** Call SQL module box_escape_func to escape tainted values
676  */
677 static int sqlippool_box_escape(fr_value_box_t *vb, void *uctx) {
678  rlm_sql_escape_uctx_t *ctx = talloc_get_type_abort(uctx, rlm_sql_escape_uctx_t);
679 
680  return ctx->sql->box_escape_func(vb, uctx);
681 }
682 
683 /** Custom parser for sqlippool call env
684  *
685  * Needed as the escape function needs to reference
686  * the correct instance of the SQL module since escaping functions
687  * are dependent on the driver used by a given module instance.
688  */
689 static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
690  call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
691 {
694  rlm_sql_t const *sql;
695  tmpl_t *parsed_tmpl;
696  CONF_PAIR const *to_parse = cf_item_to_pair(ci);
697  tmpl_rules_t our_rules = *t_rules;
698 
699  /*
700  * Lookup the sql module instance.
701  */
702  sql_inst = module_rlm_static_by_name(NULL, inst->sql_name);
703  if (!sql_inst) return -1;
704  sql = talloc_get_type_abort(sql_inst->data, rlm_sql_t);
705 
706  /*
707  * Set the sql module instance data as the uctx for escaping
708  * and use the same "safe_for" as the sql module.
709  */
710  our_rules.escape.uctx.func.uctx = sql;
711  our_rules.escape.safe_for = (fr_value_box_safe_for_t)sql->driver;
713 
714  if (tmpl_afrom_substr(ctx, &parsed_tmpl,
715  &FR_SBUFF_IN(cf_pair_value(to_parse), talloc_array_length(cf_pair_value(to_parse)) - 1),
717  &our_rules) < 0) return -1;
718  *(void **)out = parsed_tmpl;
719  return 0;
720 }
721 
722 #define QUERY_ESCAPE .pair.escape = { \
723  .func = sqlippool_box_escape, \
724  .mode = TMPL_ESCAPE_PRE_CONCAT, \
725  .uctx = { .func = { .alloc = sql_escape_uctx_alloc }, .type = TMPL_ESCAPE_UCTX_ALLOC_FUNC }, \
726 }, .pair.func = call_env_parse
727 
730  .env = (call_env_parser_t[]) {
732  ippool_alloc_call_env_t, pool_name, pool_name_tmpl),
733  .pair.dflt = "&control.IP-Pool.Name", .pair.dflt_quote = T_BARE_WORD },
735  ippool_alloc_call_env_t, requested_address) },
736  { FR_CALL_ENV_PARSE_OFFSET("allocated_address_attr", FR_TYPE_VOID,
738  ippool_alloc_call_env_t, allocated_address, allocated_address_attr) },
741  .pair.dflt = "START TRANSACTION", .pair.dflt_quote = T_SINGLE_QUOTED_STRING },
745  ippool_alloc_call_env_t, requested), QUERY_ESCAPE },
751  ippool_alloc_call_env_t, pool_check), QUERY_ESCAPE },
754  .pair.dflt = "COMMIT", .pair.dflt_quote = T_SINGLE_QUOTED_STRING },
756  }
757 };
758 
761  .env = (call_env_parser_t[]) {
767  }
768 };
769 
772  .env = (call_env_parser_t[]) {
776  }
777 };
778 
781  .env = (call_env_parser_t[]) {
785  }
786 };
787 
790  .env = (call_env_parser_t[]) {
794  }
795 };
796 
797 /*
798  * The module name should be the only globally exported symbol.
799  * That is, everything else should be 'static'.
800  *
801  * If the module needs to temporarily modify it's instantiation
802  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
803  * The server will then take care of ensuring that the module
804  * is single-threaded.
805  */
808  .common = {
809  .magic = MODULE_MAGIC_INIT,
810  .name = "sqlippool",
811  .inst_size = sizeof(rlm_sqlippool_t),
814  },
815  .method_group = {
816  .bindings = (module_method_binding_t[]){
817  /*
818  * RADIUS specific
819  */
820  { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_alloc, .method_env = &sqlippool_alloc_method_env },
821  { .section = SECTION_NAME("accounting", "Start"), .method = mod_common, .method_env = &sqlippool_update_method_env },
822  { .section = SECTION_NAME("accounting", "Alive"), .method = mod_common, .method_env = &sqlippool_update_method_env },
823  { .section = SECTION_NAME("accounting", "Stop"), .method = mod_common, .method_env = &sqlippool_release_method_env },
824  { .section = SECTION_NAME("accounting", "Accounting-On"), .method = mod_common, .method_env = &sqlippool_bulk_release_method_env },
825  { .section = SECTION_NAME("accounting", "Accounting-Off"), .method = mod_common, .method_env = &sqlippool_bulk_release_method_env },
826 
827  /*
828  * DHCPv4
829  */
830  { .section = SECTION_NAME("recv", "Discover"), .method = mod_alloc, .method_env = &sqlippool_alloc_method_env },
831  { .section = SECTION_NAME("recv", "Request"), .method = mod_common, .method_env = &sqlippool_update_method_env },
832  { .section = SECTION_NAME("recv", "Confirm"), .method = mod_common, .method_env = &sqlippool_update_method_env },
833  { .section = SECTION_NAME("recv", "Rebind"), .method = mod_common, .method_env = &sqlippool_update_method_env },
834  { .section = SECTION_NAME("recv", "Renew"), .method = mod_common, .method_env = &sqlippool_update_method_env },
835  { .section = SECTION_NAME("recv", "Release"), .method = mod_common, .method_env = &sqlippool_release_method_env },
836  { .section = SECTION_NAME("recv", "Decline"), .method = mod_common, .method_env = &sqlippool_mark_method_env },
837 
838  /*
839  * Generic
840  */
841  { .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_common, .method_env = &sqlippool_update_method_env },
842  { .section = SECTION_NAME("send", CF_IDENT_ANY),.method = mod_alloc, .method_env = &sqlippool_alloc_method_env },
843 
844  /*
845  * Named methods matching module operations
846  */
847  { .section = SECTION_NAME("allocate", NULL), .method = mod_alloc, .method_env = &sqlippool_alloc_method_env },
848  { .section = SECTION_NAME("update", NULL), .method = mod_common, .method_env = &sqlippool_update_method_env },
849  { .section = SECTION_NAME("renew", NULL), .method = mod_common, .method_env = &sqlippool_update_method_env },
850  { .section = SECTION_NAME("release", NULL), .method = mod_common, .method_env = &sqlippool_release_method_env },
851  { .section = SECTION_NAME("bulk-release", NULL), .method = mod_common, .method_env = &sqlippool_bulk_release_method_env },
852  { .section = SECTION_NAME("mark", NULL),.method = mod_common,.method_env = &sqlippool_mark_method_env },
853 
855  }
856  }
857 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition: action.h:39
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition: action.h:37
strcpy(log_entry->msg, buffer)
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition: atexit.h:221
#define RCSID(id)
Definition: build.h:481
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
#define CALL_ENV_TERMINATOR
Definition: call_env.h:231
#define FR_CALL_ENV_PARSE_OFFSET(_name, _cast_type, _flags, _struct, _field, _parse_field)
Specify a call_env_parser_t which writes out runtime results and the result of the parsing phase to t...
Definition: call_env.h:360
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
Definition: call_env.h:235
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
Definition: call_env.h:76
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl must contain an attribute reference.
Definition: call_env.h:86
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition: call_env.h:85
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition: call_env.h:75
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
Definition: call_env.h:80
module_instance_t const * mi
Module instance that the callenv is registered to.
Definition: call_env.h:224
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
Definition: call_env.h:335
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
Definition: call_env.h:384
Per method call config.
Definition: call_env.h:175
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:664
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition: cf_util.c:1638
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define CF_IDENT_ANY
Definition: cf_util.h:78
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
if(rcode > 0)
Definition: fd_read.h:9
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition: function.h:111
free(array)
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition: interpret.c:1403
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
#define RWDEBUG(fmt,...)
Definition: log.h:361
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
Definition: map.c:1487
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
Definition: map.c:1781
talloc_free(reap)
struct map_s map_t
Definition: map.h:33
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
void * env_data
Per call environment data.
Definition: module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition: module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:50
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition: module_rlm.c:828
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
void fr_pool_connection_release(fr_pool_t *pool, request_t *request, void *conn)
Release a connection.
Definition: pool.c:1407
static const conf_parser_t config[]
Definition: base.c:183
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
#define RLM_MODULE_USER_SECTION_REJECT
Rcodes that translate to a user configurable section failing overall.
Definition: rcode.h:72
#define RETURN_MODULE_UPDATED
Definition: rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition: rcode.h:42
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition: rcode.h:49
#define RETURN_MODULE_NOTFOUND
Definition: rcode.h:61
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
Definition: request_data.c:292
void * request_data_reference(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request without removing it.
Definition: request_data.c:339
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
Definition: request_data.h:59
static int instantiate(module_inst_ctx_t const *mctx)
Definition: rlm_rest.c:1302
Prototypes and functions for the SQL module.
trunk_t * trunk
Trunk connection for this thread.
Definition: rlm_sql.h:108
fr_sql_query_status_t status
Status of the query.
Definition: rlm_sql.h:146
rlm_sql_t const * inst
Module instance for this query.
Definition: rlm_sql.h:138
char const * query_str
Query string to run.
Definition: rlm_sql.h:144
request_t * request
Request this query relates to.
Definition: rlm_sql.h:139
@ RLM_SQL_OK
Success.
Definition: rlm_sql.h:47
@ SQL_QUERY_SELECT
Definition: rlm_sql.h:121
@ SQL_QUERY_OTHER
Definition: rlm_sql.h:122
void * sql_escape_arg
Thread specific argument to be passed to escape function.
Definition: rlm_sql.h:110
char ** rlm_sql_row_t
Definition: rlm_sql.h:59
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:148
sql_rcode_t rcode
Result code.
Definition: rlm_sql.h:147
rlm_sql_t const * sql
Definition: rlm_sql.h:199
@ SQL_QUERY_PREPARED
Ready to submit.
Definition: rlm_sql.h:129
static void * sql_escape_uctx_alloc(request_t *request, void const *uctx)
fr_value_box_t requested_address
IP address being requested by client.
Definition: rlm_sqlippool.c:52
#define REPEAT_MOD_ALLOC_RESUME
tmpl_t * pool_check
tmpl to expand as query for checking for existence of the pool.
Definition: rlm_sqlippool.c:60
static unlang_action_t mod_common_free_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Resume function called after mod_common "free" query has completed.
#define QUERY_ESCAPE
rlm_sql_handle_t * handle
SQL handle being used for queries.
Definition: rlm_sqlippool.c:96
static const call_env_method_t sqlippool_bulk_release_method_env
static int _sql_escape_uxtx_free(void *uctx)
fr_value_box_t allocated_address
Existing value for allocated IP.
Definition: rlm_sqlippool.c:54
rlm_sql_t const * sql
Definition: rlm_sqlippool.c:44
fr_sql_query_t * query_ctx
Query context for allocation queries.
fr_value_box_t free
SQL query to clear other offered IPs. Only used in "update" method.
Definition: rlm_sqlippool.c:67
fr_value_box_list_t values
Where to put the expanded queries ready for execution.
Definition: rlm_sqlippool.c:99
static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Custom parser for sqlippool call env.
static const call_env_method_t sqlippool_release_method_env
rlm_rcode_t rcode
Result code to return after running "commit".
trunk_t * trunk
Trunk connection for queries.
Definition: rlm_sqlippool.c:97
static const call_env_method_t sqlippool_update_method_env
rlm_sql_t const * sql
SQL module instance.
#define RESERVE_CONNECTION(_handle, _sql, _request)
static int sqlippool_result_process(char *out, int outlen, fr_sql_query_t *query_ctx)
static unlang_action_t mod_alloc(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Initiate the allocation of an IP address from the pool.
char const * sql_name
Definition: rlm_sqlippool.c:42
request_t * request
Current request.
ippool_alloc_call_env_t * env
Call environment for the allocation.
Definition: rlm_sqlippool.c:95
ippool_common_call_env_t * env
Call environment for the update.
static const call_env_method_t sqlippool_alloc_method_env
fr_value_box_t * query
Current query being run.
request_t * request
Current request.
Definition: rlm_sqlippool.c:93
static unlang_action_t mod_common(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Common function used by module methods which perform an optional "free" then "update".
static const call_env_method_t sqlippool_mark_method_env
char const * name
Definition: rlm_sqlippool.c:41
rlm_sql_handle_t * handle
SQL handle being used for queries.
static unlang_action_t mod_alloc_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Resume function called after each IP allocation query is expanded.
static int sqlippool_box_escape(fr_value_box_t *vb, void *uctx)
Call SQL module box_escape_func to escape tainted values.
tmpl_t * pool_name_tmpl
Tmpl used to expand pool_name.
Definition: rlm_sqlippool.c:51
static unlang_action_t mod_common_update_resume(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
Resume function called after mod_common "update" query has completed.
fr_sql_query_t * query_ctx
Query context for allocation queries.
fr_value_box_t commit
SQL query to commit transaction.
Definition: rlm_sqlippool.c:61
tmpl_t * existing
tmpl to expand as query for finding the existing IP.
Definition: rlm_sqlippool.c:56
#define SUBMIT_QUERY(_query_str, _new_status, _type, _function)
tmpl_t * requested
tmpl to expand as query for finding the requested IP.
Definition: rlm_sqlippool.c:57
fr_value_box_t pool_name
Name of pool address will be allocated from.
Definition: rlm_sqlippool.c:50
static int sqlippool_common_ctx_free(ippool_common_ctx_t *to_free)
Return connection to pool when mod_common context is freed.
static int sqlippool_alloc_ctx_free(ippool_alloc_ctx_t *to_free)
Release SQL pool connections when alloc context is freed.
fr_value_box_t update
SQL query to update an IP record.
Definition: rlm_sqlippool.c:68
fr_value_box_t begin
SQL query to begin transaction.
Definition: rlm_sqlippool.c:55
tmpl_t * find
tmpl to expand as query for finding an unused IP.
Definition: rlm_sqlippool.c:58
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
Definition: rlm_sqlippool.c:53
ippool_alloc_status_t status
Status of the allocation.
Definition: rlm_sqlippool.c:94
module_rlm_t rlm_sqlippool
ippool_alloc_status_t
Current step in IP allocation state machine.
Definition: rlm_sqlippool.c:73
@ IPPOOL_ALLOC_POOL_CHECK_RUN
Run the "pool_check" query.
Definition: rlm_sqlippool.c:83
@ IPPOOL_ALLOC_FIND_RUN
Run the "find" query.
Definition: rlm_sqlippool.c:80
@ IPPOOL_ALLOC_MAKE_PAIR
Make the pair.
Definition: rlm_sqlippool.c:84
@ IPPOOL_ALLOC_POOL_CHECK
Expanding the "pool_check" query.
Definition: rlm_sqlippool.c:82
@ IPPOOL_ALLOC_REQUESTED
Expanding the "requested" query.
Definition: rlm_sqlippool.c:77
@ IPPOOL_ALLOC_COMMIT_RUN
RUn the "commit" query.
Definition: rlm_sqlippool.c:87
@ IPPOOL_ALLOC_REQUESTED_RUN
Run the "requested" query.
Definition: rlm_sqlippool.c:78
@ IPPOOL_ALLOC_EXISTING_RUN
Run the "existing" query.
Definition: rlm_sqlippool.c:76
@ IPPOOL_ALLOC_UPDATE_RUN
Run the "update" query.
Definition: rlm_sqlippool.c:86
@ IPPOOL_ALLOC_FIND
Expanding the "find" query.
Definition: rlm_sqlippool.c:79
@ IPPOOL_ALLOC_EXISTING
Expanding the "existing" query.
Definition: rlm_sqlippool.c:75
@ IPPOOL_ALLOC_UPDATE
Expanding the "update" query.
Definition: rlm_sqlippool.c:85
@ IPPOOL_ALLOC_NO_ADDRESS
No address was found.
Definition: rlm_sqlippool.c:81
@ IPPOOL_ALLOC_BEGIN_RUN
Run the "begin" query.
Definition: rlm_sqlippool.c:74
static int mod_instantiate(module_inst_ctx_t const *mctx)
static conf_parser_t module_config[]
tmpl_t * update
tmpl to expand as query for updating the found IP.
Definition: rlm_sqlippool.c:59
rlm_sql_t const * sql
SQL module instance.
Definition: rlm_sqlippool.c:98
Call environment used by module alloc method.
Definition: rlm_sqlippool.c:49
Resume context for IP allocation.
Definition: rlm_sqlippool.c:92
Call environment used by all other module methods.
Definition: rlm_sqlippool.c:66
Resume context for IP update / release.
#define FR_SBUFF_IN(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
char const * name
Instance name e.g. user_database.
Definition: module.h:335
static module_thread_instance_t * module_thread(module_instance_t const *mi)
Retrieve module/thread specific instance for a module.
Definition: module.h:481
CONF_SECTION * conf
Module's instance configuration.
Definition: module.h:329
void * data
Module's instance data.
Definition: module.h:271
void * data
Thread specific instance data.
Definition: module.h:352
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Module instance data.
Definition: module.h:265
Named methods exported by a module.
Definition: module.h:173
tmpl_escape_t escape
How escaping should be handled during evaluation.
Definition: tmpl.h:358
fr_value_box_safe_for_t literals_safe_for
safe_for value assigned to literal values in xlats, execs, and data.
Definition: tmpl.h:356
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules))
Initialise a tmpl without copying the input name string.
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
Value pair map.
Definition: map.h:77
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:79
int(* sql_affected_rows)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition: rlm_sql.h:218
sql_rcode_t(* sql_finish_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition: rlm_sql.h:226
sql_rcode_t(* sql_finish_select_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition: rlm_sql.h:227
unlang_function_t fetch_row
Definition: rlm_sql.h:253
unlang_function_t query
Definition: rlm_sql.h:251
fr_pool_t * pool
Definition: rlm_sql.h:239
fr_value_box_escape_t box_escape_func
Definition: rlm_sql.h:249
rlm_sql_config_t config
Definition: rlm_sql.h:238
rlm_sql_driver_t const * driver
Driver's exported interface.
Definition: rlm_sql.h:246
fr_sql_query_t *(* query_alloc)(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, rlm_sql_handle_t *handle, trunk_t *trunk, char const *query_str, fr_sql_query_type_t type)
Definition: rlm_sql.h:254
module_instance_t const * mi
Module instance data for thread lookups.
Definition: rlm_sql.h:258
void * sql_escape_arg
Instance specific argument to be passed to escape function.
Definition: rlm_sql.h:250
#define talloc_get_type_abort_const
Definition: talloc.h:282
int unlang_tmpl_push(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args)
Push a tmpl onto the stack for evaluation.
Definition: tmpl.c:259
fr_value_box_escape_t func
How to escape when returned from evaluation.
Definition: tmpl_escape.h:81
struct tmpl_escape_t::@74 uctx
fr_value_box_safe_for_t safe_for
Value to set on boxes which have been escaped by the fr_value_box_escape_t function.
Definition: tmpl_escape.h:83
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_SET
Definition: token.h:84
Main trunk management handle.
Definition: trunk.c:195
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition: value.c:606
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition: value.c:4232
#define FR_MAX_STRING_LEN
Definition: value.h:30
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition: value.h:155
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:997