The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_json.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: a5077140e5bd01897f1aee8cd018a0bd37e05e84 $
19  * @file rlm_json.c
20  * @brief Parses JSON responses
21  *
22  * @author Arran Cudbard-Bell
23  * @author Matthew Newton
24  *
25  * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26  * @copyright 2015,2020 Network RADIUS SAS (legal@networkradius.com)
27  * @copyright 2015 The FreeRADIUS Server Project
28  */
29 RCSID("$Id: a5077140e5bd01897f1aee8cd018a0bd37e05e84 $")
30 
31 #include <freeradius-devel/server/base.h>
32 #include <freeradius-devel/server/module_rlm.h>
33 #include <freeradius-devel/server/map_proc.h>
34 #include <freeradius-devel/util/base16.h>
35 #include <freeradius-devel/util/debug.h>
36 #include <freeradius-devel/util/sbuff.h>
37 #include <freeradius-devel/util/types.h>
38 #include <freeradius-devel/util/value.h>
39 #include <freeradius-devel/unlang/xlat_func.h>
40 #include <freeradius-devel/json/base.h>
41 
42 #include <ctype.h>
43 
44 #ifndef HAVE_JSON
45 # error "rlm_json should not be built unless json-c is available"
46 #endif
47 
48 static fr_sbuff_parse_rules_t const json_arg_parse_rules = {
49  .terminals = &FR_SBUFF_TERMS(
50  L("\t"),
51  L(" "),
52  L("!")
53  )
54 };
55 
56 /** rlm_json module instance
57  *
58  */
59 typedef struct {
61 } rlm_json_t;
62 
63 
64 static conf_parser_t const module_config[] = {
66  .subcs_size = sizeof(fr_json_format_t), .subcs_type = "fr_json_format_t" },
67 
69 };
70 
71 /** Forms a linked list of jpath head node pointers (a list of jpaths)
72  */
75  fr_jpath_node_t *jpath; //!< First node in jpath expression.
76  rlm_json_jpath_cache_t *next; //!< Next jpath cache entry.
77 };
78 
79 typedef struct {
81  json_object *root;
83 
85  { .type = FR_TYPE_VOID },
87 };
88 
89 static xlat_action_t json_escape(TALLOC_CTX *ctx, fr_dcursor_t *out,
90  UNUSED xlat_ctx_t const *xctx,
91  request_t *request, fr_value_box_list_t *in, bool quote)
92 {
93  fr_value_box_t *vb_out;
94  fr_value_box_t *in_head = fr_value_box_list_head(in);
95  fr_sbuff_t *agg;
96 
97  FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 1024, SIZE_MAX);
98 
99  if (fr_value_box_list_num_elements(&in_head->vb_group) == 0) {
100  MEM(vb_out = fr_value_box_alloc_null(ctx));
101  fr_value_box_strdup(vb_out, vb_out, NULL, "null", false);
102  fr_dcursor_append(out, vb_out);
103 
104  return XLAT_ACTION_DONE;
105  }
106 
107  fr_value_box_list_foreach(&in_head->vb_group, vb_in) {
108  MEM(vb_out = fr_value_box_alloc_null(ctx));
109  if (fr_json_str_from_value(agg, vb_in, quote) < 0) {
110  RPERROR("Failed creating escaped JSON value");
111  return XLAT_ACTION_FAIL;
112  }
113  if (fr_value_box_bstrndup(vb_out, vb_out, NULL, fr_sbuff_start(agg), fr_sbuff_used(agg), vb_in->tainted) < 0) {
114  RPERROR("Failed assigning escaped JSON value to output box");
115  return XLAT_ACTION_FAIL;
116  }
118  fr_dcursor_append(out, vb_out);
119  }
120 
121  return XLAT_ACTION_DONE;
122 }
123 /** Ensure contents are escaped correctly for a JSON document
124  *
125  * This allows values to be embedded inside JSON strings.
126  *
127  * @ingroup xlat_functions
128  *
129  */
131  xlat_ctx_t const *xctx,
132  request_t *request, fr_value_box_list_t *in)
133 {
134  return json_escape(ctx, out, xctx, request, in, false);
135 }
136 
138  { .required = true, .concat = true, .type = FR_TYPE_STRING },
140 };
141 
142 /** Ensure contents are quoted correctly for a JSON document
143  *
144  * This emits values with escaping, and appropriate quoting '"' depending on the
145  * type of values being produced. This lets boxed values be inserted directly
146  * as table values and array elements, without needing to determine if the
147  * expansion needs to be wrapped in quotes.
148  *
149  * @ingroup xlat_functions
150  *
151  */
153  xlat_ctx_t const *xctx,
154  request_t *request, fr_value_box_list_t *in)
155 {
156  return json_escape(ctx, out, xctx, request, in, true);
157 }
158 
159 /** Determine if a jpath expression is valid
160  *
161  * @ingroup xlat_functions
162  *
163  * Writes the output (in the format @verbatim<bytes parsed>[:error]@endverbatim).
164  */
166  UNUSED xlat_ctx_t const *xctx,
167  request_t *request, fr_value_box_list_t *in)
168 {
169  fr_value_box_t *path = fr_value_box_list_head(in);
171  ssize_t slen;
172  char *jpath_str;
173  fr_value_box_t *vb;
174 
175  MEM(vb = fr_value_box_alloc_null(ctx));
176 
177  slen = fr_jpath_parse(request, &head, path->vb_strvalue, path->vb_length);
178  if (slen <= 0) {
179  fr_value_box_asprintf(ctx, vb, NULL, false, "%zu:%s", -(slen), fr_strerror());
180  fr_dcursor_append(out, vb);
181  fr_assert(head == NULL);
182  return XLAT_ACTION_DONE;
183  }
184  fr_assert(talloc_get_type_abort(head, fr_jpath_node_t));
185 
186  jpath_str = fr_jpath_asprint(request, head);
187 
188  fr_value_box_asprintf(ctx, vb, NULL, false, "%zu:%s", (size_t) slen, jpath_str);
189  fr_dcursor_append(out, vb);
190  talloc_free(head);
191  talloc_free(jpath_str);
192 
193  return XLAT_ACTION_DONE;
194 }
195 
197  { .required = true, .concat = true, .type = FR_TYPE_STRING },
199 };
200 
201 /** Convert given attributes to a JSON document
202  *
203  * Usage is `%json.encode(attr tmpl list)`
204  *
205  * @ingroup xlat_functions
206  */
208  xlat_ctx_t const *xctx,
209  request_t *request, fr_value_box_list_t *in)
210 {
212  fr_json_format_t const *format = inst->format;
213 
214  ssize_t slen;
215  tmpl_t *vpt = NULL;
216  fr_pair_list_t json_vps, vps;
217  bool negate;
218  char *json_str = NULL;
219  fr_value_box_t *vb;
220  fr_sbuff_t sbuff;
221  fr_value_box_t *in_head = fr_value_box_list_head(in);
222 
223  fr_pair_list_init(&json_vps);
224  fr_pair_list_init(&vps);
225 
226  sbuff = FR_SBUFF_IN(in_head->vb_strvalue, in_head->vb_length);
227  fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL);
228 
229  /*
230  * Iterate through the list of attribute templates in the xlat. For each
231  * one we either add it to the list of attributes for the JSON document
232  * or, if prefixed with '!', remove from the JSON list.
233  */
234  while (fr_sbuff_extend(&sbuff)) {
235  negate = false;
236 
237  /* Check if we should be removing attributes */
238  if (fr_sbuff_next_if_char(&sbuff, '!')) negate = true;
239 
240  /* Decode next attr template */
241  slen = tmpl_afrom_attr_substr(ctx, NULL, &vpt,
242  &sbuff,
244  &(tmpl_rules_t){
245  .attr = {
246  .list_def = request_attr_request,
247  .allow_wildcard = true,
248  .dict_def = request->dict
249  }
250  });
251  if (slen <= 0) {
252  fr_sbuff_set(&sbuff, (size_t)(slen * -1));
253  REMARKER(fr_sbuff_start(&sbuff), fr_sbuff_used(&sbuff), "%s", fr_strerror());
254  error:
255  fr_pair_list_free(&json_vps);
256  talloc_free(vpt);
257  return XLAT_ACTION_FAIL;
258  }
259 
260  /*
261  * Get attributes from the template.
262  * Missing attribute isn't an error (so -1, not 0).
263  */
264  if (tmpl_copy_pairs(ctx, &vps, request, vpt) < -1) {
265  RPEDEBUG("Error copying attributes");
266  goto error;
267  }
268 
269  if (negate) {
270  /* Remove all template attributes from JSON list */
271  for (fr_pair_t *vp = fr_pair_list_head(&vps);
272  vp;
273  vp = fr_pair_list_next(&vps, vp)) {
274 
275  fr_pair_t *vpm = fr_pair_list_head(&json_vps);
276  while (vpm) {
277  if (vp->da == vpm->da) {
278  fr_pair_t *next = fr_pair_list_next(&json_vps, vpm);
279  fr_pair_delete(&json_vps, vpm);
280  vpm = next;
281  continue;
282  }
283  vpm = fr_pair_list_next(&json_vps, vpm);
284  }
285  }
286 
287  fr_pair_list_free(&vps);
288  } else {
289  /* Add template VPs to JSON list */
290  fr_pair_list_append(&json_vps, &vps);
291  }
292 
293  TALLOC_FREE(vpt);
294 
295  /* Jump forward to next attr */
296  fr_sbuff_adv_past_whitespace(&sbuff, SIZE_MAX, NULL);
297  }
298 
299  /*
300  * Given the list of attributes we now have in json_vps,
301  * convert them into a JSON document and append it to the
302  * return cursor.
303  */
304  MEM(vb = fr_value_box_alloc_null(ctx));
305 
306  json_str = fr_json_afrom_pair_list(vb, &json_vps, format);
307  if (!json_str) {
308  REDEBUG("Failed to generate JSON string");
309  goto error;
310  }
311  fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, json_str, false);
312 
313  fr_dcursor_append(out, vb);
314  fr_pair_list_free(&json_vps);
315 
316  return XLAT_ACTION_DONE;
317 }
318 
319 /** Pre-parse and validate literal jpath expressions for maps
320  *
321  * @param[in] cs #CONF_SECTION that defined the map instance.
322  * @param[in] mod_inst module instance (unused).
323  * @param[in] proc_inst the cache structure to fill.
324  * @param[in] src Where to get the JSON data from.
325  * @param[in] maps set of maps to translate to jpaths.
326  * @return
327  * - 0 on success.
328  * - -1 on failure.
329  */
330 static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, void *proc_inst,
331  tmpl_t const *src, map_list_t const *maps)
332 {
333  rlm_json_jpath_cache_t *cache_inst = proc_inst;
334  map_t const *map = NULL;
335  ssize_t slen;
336  rlm_json_jpath_cache_t *cache = cache_inst, **tail = &cache->next;
337 
338  if (!src) {
339  cf_log_err(cs, "Missing JSON source");
340 
341  return -1;
342  }
343 
344  while ((map = map_list_next(maps, map))) {
345  CONF_PAIR *cp = cf_item_to_pair(map->ci);
346  char const *p;
347 
348 #ifndef HAVE_JSON_OBJECT_GET_INT64
349  if (tmpl_is_attr(map->lhs) && (tmpl_attr_tail_da(map->lhs)->type == FR_TYPE_UINT64)) {
350  cf_log_err(cp, "64bit integers are not supported by linked json-c. "
351  "Upgrade to json-c >= 0.10 to use this feature");
352  return -1;
353  }
354 #endif
355 
356  switch (map->rhs->type) {
358  p = map->rhs->name;
359  slen = fr_jpath_parse(cache, &cache->jpath, p, map->rhs->len);
360  if (slen <= 0) {
361  error:
362  cf_canonicalize_error(cp, slen, "Syntax error", fr_strerror());
363  return -1;
364  }
365  break;
366 
367  case TMPL_TYPE_DATA:
368  if (tmpl_value_type(map->rhs) != FR_TYPE_STRING) {
369  cf_log_err(cp, "Right side of map must be a string");
370  return -1;
371  }
372  p = tmpl_value(map->rhs)->vb_strvalue;
373  slen = fr_jpath_parse(cache, &cache->jpath, p, tmpl_value_length(map->rhs));
374  if (slen <= 0) goto error;
375  break;
376 
377  default:
378  continue;
379  }
380 
381  /*
382  * Slightly weird... This is here because our first
383  * list member was pre-allocated and passed to the
384  * instantiation callback.
385  */
386  if (map_list_next(maps, map)) {
387  *tail = cache = talloc_zero(cache, rlm_json_jpath_cache_t);
388  tail = &cache->next;
389  }
390  }
391 
392  return 0;
393 }
394 
395 /** Converts a string value into a #fr_pair_t
396  *
397  * @param[in,out] ctx to allocate #fr_pair_t (s).
398  * @param[out] out where to write the resulting #fr_pair_t.
399  * @param[in] request The current request.
400  * @param[in] map to process.
401  * @param[in] uctx The json tree/jpath expression to evaluate.
402  * @return
403  * - 0 on success.
404  * - -1 on failure.
405  */
406 static int _json_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request,
407  map_t const *map, void *uctx)
408 {
409  fr_pair_t *vp;
410  rlm_json_jpath_to_eval_t *to_eval = uctx;
412  fr_value_box_list_t head;
413  int ret;
414 
416  fr_value_box_list_init(&head);
417 
418  ret = fr_jpath_evaluate_leaf(request, &head, tmpl_attr_tail_da(map->lhs)->type, tmpl_attr_tail_da(map->lhs),
419  to_eval->root, to_eval->jpath);
420  if (ret < 0) {
421  RPEDEBUG("Failed evaluating jpath");
422  return -1;
423  }
424  if (ret == 0) return 0;
425  fr_assert(!fr_value_box_list_empty(&head));
426 
427  for (value = fr_value_box_list_head(&head);
428  value;
429  fr_pair_append(out, vp), value = fr_value_box_list_next(&head, value)) {
431 
432  if (fr_value_box_steal(vp, &vp->data, value) < 0) {
433  RPEDEBUG("Copying data to attribute failed");
434  talloc_free(vp);
436  return -1;
437  }
438  }
439 
440  return 0;
441 }
442 
443 /** Parses a JSON string, and executes jpath queries against it to map values to attributes
444  *
445  * @param p_result Result of applying map:
446  * - #RLM_MODULE_NOOP no rows were returned or columns matched.
447  * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t.
448  * - #RLM_MODULE_FAIL if a fault occurred.
449  * @param mod_inst unused.
450  * @param proc_inst cached jpath sequences.
451  * @param request The current request.
452  * @param json JSON string to parse.
453  * @param maps Head of the map list.
454  * @return UNLANG_ACTION_CALCULATE_RESULT
455  */
456 static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void *mod_inst, void *proc_inst, request_t *request,
457  fr_value_box_list_t *json, map_list_t const *maps)
458 {
460  struct json_tokener *tok;
461 
462  rlm_json_jpath_cache_t *cache = proc_inst;
463  map_t const *map = NULL;
464 
465  rlm_json_jpath_to_eval_t to_eval;
466 
467  char const *json_str = NULL;
468  fr_value_box_t *json_head = fr_value_box_list_head(json);
469 
470  if (!json_head) {
471  REDEBUG("JSON map input cannot be (null)");
473  }
474 
476  json_head, json, FR_TYPE_STRING,
478  SIZE_MAX) < 0) {
479  REDEBUG("Failed concatenating input");
481  }
482  json_str = json_head->vb_strvalue;
483 
484  if ((talloc_array_length(json_str) - 1) == 0) {
485  REDEBUG("JSON map input length must be > 0");
487  }
488 
489  tok = json_tokener_new();
490  to_eval.root = json_tokener_parse_ex(tok, json_str, (int)(talloc_array_length(json_str) - 1));
491  if (!to_eval.root) {
492  REMARKER(json_str, tok->char_offset, "%s", json_tokener_error_desc(json_tokener_get_error(tok)));
493  rcode = RLM_MODULE_FAIL;
494  goto finish;
495  }
496 
497  while ((map = map_list_next(maps, map))) {
498  switch (map->rhs->type) {
499  /*
500  * Cached types
501  */
503  case TMPL_TYPE_DATA:
504  to_eval.jpath = cache->jpath;
505 
506  if (map_to_request(request, map, _json_map_proc_get_value, &to_eval) < 0) {
507  rcode = RLM_MODULE_FAIL;
508  goto finish;
509  }
510  cache = cache->next;
511  break;
512 
513  /*
514  * Dynamic types
515  */
516  default:
517  {
518  ssize_t slen;
519  fr_jpath_node_t *node;
520  char *to_parse;
521 
522  if (tmpl_aexpand(request, &to_parse, request, map->rhs, fr_jpath_escape_func, NULL) < 0) {
523  RPERROR("Failed getting jpath data");
524  rcode = RLM_MODULE_FAIL;
525  goto finish;
526  }
527  slen = fr_jpath_parse(request, &node, to_parse, talloc_array_length(to_parse) - 1);
528  if (slen <= 0) {
529  REMARKER(to_parse, -(slen), "%s", fr_strerror());
530  talloc_free(to_parse);
531  rcode = RLM_MODULE_FAIL;
532  goto finish;
533  }
534  to_eval.jpath = node;
535 
536  if (map_to_request(request, map, _json_map_proc_get_value, &to_eval) < 0) {
537  talloc_free(node);
538  talloc_free(to_parse);
539  rcode = RLM_MODULE_FAIL;
540  goto finish;
541  }
542  talloc_free(node);
543  }
544  break;
545  }
546  }
547 
548 
549 finish:
550  json_object_put(to_eval.root);
551  json_tokener_free(tok);
552 
553  RETURN_MODULE_RCODE(rcode);
554 }
555 
556 static int mod_bootstrap(module_inst_ctx_t const *mctx)
557 {
558  rlm_json_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_json_t);
559  CONF_SECTION *conf = mctx->inst->conf;
560  xlat_t *xlat;
561  fr_json_format_t *format = inst->format;
562 
565 
566  /*
567  * Check the output format type and warn on unused
568  * format options
569  */
570  format->output_mode = fr_table_value_by_str(fr_json_format_table, format->output_mode_str, JSON_MODE_UNSET);
571  if (format->output_mode == JSON_MODE_UNSET) {
572  cf_log_err(conf, "output_mode value \"%s\" is invalid", format->output_mode_str);
573  return -1;
574  }
576 
577  if (map_proc_register(inst, "json", mod_map_proc,
578  mod_map_proc_instantiate, sizeof(rlm_json_jpath_cache_t), 0) < 0) return -1;
579  return 0;
580 }
581 
582 static int mod_load(void)
583 {
584  xlat_t *xlat;
585 
587 
588  if (unlikely(!(xlat = xlat_func_register(NULL, "json.escape", json_escape_xlat, FR_TYPE_STRING)))) return -1;
590  if (unlikely(!(xlat = xlat_func_register(NULL, "json.quote", json_quote_xlat, FR_TYPE_STRING)))) return -1;
592  if (unlikely(!(xlat = xlat_func_register(NULL, "json.jpath_validate", json_jpath_validate_xlat, FR_TYPE_STRING)))) return -1;
594 
595  return 0;
596 }
597 
598 static void mod_unload(void)
599 {
600  xlat_func_unregister("json.escape");
601  xlat_func_unregister("json.quote");
602  xlat_func_unregister("json.jpath_validate");
603 }
604 
605 /*
606  * The module name should be the only globally exported symbol.
607  * That is, everything else should be 'static'.
608  *
609  * If the module needs to temporarily modify it's instantiation
610  * data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
611  * The server will then take care of ensuring that the module
612  * is single-threaded.
613  */
614 extern module_rlm_t rlm_json;
616  .common = {
617  .magic = MODULE_MAGIC_INIT,
618  .name = "json",
619  .flags = MODULE_TYPE_THREAD_SAFE,
620  .onload = mod_load,
621  .unload = mod_unload,
622  .config = module_config,
623  .inst_size = sizeof(rlm_json_t),
624  .bootstrap = mod_bootstrap
625  }
626 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition: cf_parse.h:297
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:629
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_canonicalize_error(_ci, _slen, _msg, _str)
Definition: cf_util.h:340
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static fr_slen_t in
Definition: dict.h:645
Test enumeration values.
Definition: dict_test.h:92
void *_CONST data
Module instance's parsed configuration.
Definition: dl_module.h:165
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
CONF_SECTION *_CONST conf
Module's instance configuration.
Definition: dl_module.h:166
static xlat_action_t json_quote_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Ensure contents are quoted correctly for a JSON document.
Definition: rlm_json.c:152
static xlat_action_t json_escape_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Ensure contents are escaped correctly for a JSON document.
Definition: rlm_json.c:130
static xlat_action_t json_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Convert given attributes to a JSON document.
Definition: rlm_json.c:207
static xlat_action_t json_jpath_validate_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Determine if a jpath expression is valid.
Definition: rlm_json.c:165
Node in a jpath selector sequence.
Definition: jpath.c:87
char * fr_jpath_asprint(TALLOC_CTX *ctx, fr_jpath_node_t const *head)
Print a node list to a string for debugging.
Definition: jpath.c:411
@ JSON_MODE_UNSET
Definition: base.h:58
size_t fr_jpath_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escapes special chars.
Definition: jpath.c:106
struct fr_json_format_s fr_json_format_t
Definition: base.h:231
fr_slen_t fr_json_str_from_value(fr_sbuff_t *out, fr_value_box_t *vb, bool include_quotes)
Print a value box as its equivalent JSON format without going via a struct json_object (in most cases...
Definition: json.c:279
conf_parser_t const fr_json_format_config[]
Definition: json.c:63
int fr_jpath_evaluate_leaf(TALLOC_CTX *ctx, fr_value_box_list_t *out, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, json_object *root, fr_jpath_node_t const *jpath)
Evaluate a parsed jpath expression against a json-c tree.
Definition: jpath.c:383
void fr_json_version_print(void)
Print JSON-C version.
Definition: json.c:459
fr_table_num_sorted_t const fr_json_format_table[]
Definition: json.c:36
bool fr_json_format_verify(fr_json_format_t const *format, bool verbose)
Verify that the options in fr_json_format_t are valid.
Definition: json.c:559
ssize_t fr_jpath_parse(TALLOC_CTX *ctx, fr_jpath_node_t **head, char const *in, size_t inlen)
Parse a jpath string.
Definition: jpath.c:813
char * fr_json_afrom_pair_list(TALLOC_CTX *ctx, fr_pair_list_t *vps, fr_json_format_t const *format)
Returns a JSON string of a list of value pairs.
Definition: json.c:1239
JSON document formatting options.
Definition: base.h:219
#define RPERROR(fmt,...)
Definition: log.h:302
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:498
#define RPEDEBUG(fmt,...)
Definition: log.h:376
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:1783
talloc_free(reap)
int map_proc_register(void *mod_inst, char const *name, map_proc_func_t evaluate, map_proc_instantiate_t instantiate, size_t inst_size, fr_value_box_safe_for_t literals_safe_for)
Register a map processor.
Definition: map_proc.c:111
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
long int ssize_t
Definition: merged_model.c:24
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:52
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
Temporary structure to hold arguments for instantiation calls.
Definition: module_ctx.h:51
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:278
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
fr_pair_t * fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition: pair.c:1819
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
#define REDEBUG(fmt,...)
Definition: radclient.h:52
static rs_t * conf
Definition: radsniff.c:53
#define RETURN_MODULE_RCODE(_rcode)
Definition: rcode.h:64
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
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
fr_json_format_t * format
Definition: rlm_json.c:60
fr_jpath_node_t * jpath
First node in jpath expression.
Definition: rlm_json.c:75
static xlat_arg_parser_t const json_escape_xlat_arg[]
Definition: rlm_json.c:84
static int mod_load(void)
Definition: rlm_json.c:582
json_object * root
Definition: rlm_json.c:81
static xlat_action_t json_escape(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in, bool quote)
Definition: rlm_json.c:89
static xlat_arg_parser_t const json_encode_xlat_arg[]
Definition: rlm_json.c:196
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition: rlm_json.c:556
static void mod_unload(void)
Definition: rlm_json.c:598
static int mod_map_proc_instantiate(CONF_SECTION *cs, UNUSED void *mod_inst, void *proc_inst, tmpl_t const *src, map_list_t const *maps)
Pre-parse and validate literal jpath expressions for maps.
Definition: rlm_json.c:330
rlm_json_jpath_cache_t * next
Next jpath cache entry.
Definition: rlm_json.c:76
static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void *mod_inst, void *proc_inst, request_t *request, fr_value_box_list_t *json, map_list_t const *maps)
Parses a JSON string, and executes jpath queries against it to map values to attributes.
Definition: rlm_json.c:456
fr_jpath_node_t const * jpath
Definition: rlm_json.c:80
static fr_sbuff_parse_rules_t const json_arg_parse_rules
Definition: rlm_json.c:48
static xlat_arg_parser_t const json_jpath_validate_xlat_arg[]
Definition: rlm_json.c:137
module_rlm_t rlm_json
Definition: rlm_json.c:615
static int _json_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, void *uctx)
Converts a string value into a fr_pair_t.
Definition: rlm_json.c:406
static conf_parser_t const module_config[]
Definition: rlm_json.c:64
rlm_json module instance
Definition: rlm_json.c:59
int fr_sbuff_reset_talloc(fr_sbuff_t *sbuff)
Reset a talloced buffer to its initial length, clearing any data stored.
Definition: sbuff.c:434
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition: sbuff.c:2047
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition: sbuff.h:167
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
@ MODULE_TYPE_THREAD_SAFE
Module is threadsafe.
Definition: module.h:49
#define tmpl_value_length(_tmpl)
Definition: tmpl.h:933
static fr_slen_t vpt
Definition: tmpl.h:1260
#define tmpl_value(_tmpl)
Definition: tmpl.h:932
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition: tmpl.h:796
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition: tmpl.h:183
int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt))
Copy pairs matching a tmpl_t in the current request_t.
Definition: tmpl_eval.c:796
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, fr_sbuff_t *name, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:934
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
Definition: tmpl.h:1054
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
fr_pair_t * vp
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
CONF_ITEM * ci
Config item that the map was created from.
Definition: map.h:85
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition: table.h:134
#define talloc_get_type_abort_const
Definition: talloc.h:270
fr_type_t type
Type to cast argument to.
Definition: xlat.h:153
bool required
Argument must be present, and non-empty.
Definition: xlat.h:146
static fr_slen_t head
Definition: xlat.h:408
#define XLAT_ARG_PARSER_TERMINATOR
Definition: xlat.h:166
xlat_action_t
Definition: xlat.h:35
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition: xlat.h:42
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition: xlat.h:41
Definition for a single argument consumend by an xlat function.
Definition: xlat.h:145
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
Definition: pair_inline.c:182
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
int fr_value_box_asprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt,...)
Print a formatted string using our internal printf wrapper and assign it to a value box.
Definition: value.c:3963
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition: value.c:3876
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition: value.c:3807
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition: value.c:4097
int fr_value_box_bstrdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a talloced buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:4202
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition: value.c:5725
@ FR_VALUE_BOX_LIST_FREE
Definition: value.h:214
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
#define fr_value_box_list_foreach(_list_head, _iter)
Definition: value.h:199
int format(printf, 5, 0))
static size_t char ** out
Definition: value.h:984
module_ctx_t const * mctx
Synthesised module calling ctx.
Definition: xlat_ctx.h:45
An xlat calling ctx.
Definition: xlat_ctx.h:42
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition: xlat_func.c:360
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition: xlat_func.c:195
int xlat_func_mono_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the argument of an xlat.
Definition: xlat_func.c:392
void xlat_func_unregister(char const *name)
Unregister an xlat function.
Definition: xlat_func.c:531
xlat_t * xlat_func_register_module(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function for a module.
Definition: xlat_func.c:274