The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
subrequest.c
Go to the documentation of this file.
1/*
2 * This program 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
5 * (at 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: 2dbbf1abc4ac573dc07271331ecef2d2d9fcb34f $
19 *
20 * @file unlang/subrequest.c
21 * @brief Unlang "subrequest" and "detach" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25
26RCSID("$Id: 2dbbf1abc4ac573dc07271331ecef2d2d9fcb34f $")
27
28#include <freeradius-devel/server/state.h>
29#include <freeradius-devel/server/tmpl_dcursor.h>
30#include "unlang_priv.h"
31#include "interpret_priv.h"
32#include "subrequest_priv.h"
33#include "child_request_priv.h"
34
35/** Send a signal from parent request to subrequest
36 *
37 */
39{
40 unlang_child_request_t *cr = talloc_get_type_abort(frame->state, unlang_child_request_t);
41 request_t *child = talloc_get_type_abort(cr->request, request_t);
42
43 switch (cr->state) {
44 case CHILD_DETACHED:
45 RDEBUG3("subrequest detached during its execution - Not sending signal to child");
46 return;
47
48 case CHILD_CANCELLED:
49 RDEBUG3("subrequest is cancelled - Not sending signal to child");
50 return;
51
52 case CHILD_RUNNABLE:
53 fr_assert_msg(!unlang_request_is_scheduled(request), "Parent cannot be runnable if child has not completed");
54 break;
55
56 default:
57 break;
58 }
59
60 /*
61 * Parent should never receive a detach
62 * signal whilst the child is running.
63 *
64 * Only the child receives a detach
65 * signal when the detach keyword is used.
66 */
67 fr_assert(action != FR_SIGNAL_DETACH);
68
69 /*
70 * If the server is stopped, inside a breakpoint,
71 * whilst processing a child, on resumption both
72 * requests (parent and child) may need to be
73 * cancelled as they've both hit max request_time.
74 *
75 * Sometimes the child will run to completion before
76 * the cancellation is processed, but the parent
77 * will still be cancelled.
78 *
79 * When the parent is cancelled this function is
80 * executed, which will signal an already stopped
81 * child to cancel itself.
82 *
83 * This triggers asserts in the time tracking code.
84 *
85 * ...so we check to see if the child is done before
86 * sending a signal.
87 */
88 if (unlang_request_is_done(child)) return;
89
90 /*
91 * Forward other signals to the child
92 */
93 unlang_interpret_signal(child, action);
94}
95
96/** Parent being resumed after a child completes
97 *
98 */
101{
103 unlang_child_request_t *cr = talloc_get_type_abort(frame->state, unlang_child_request_t);
104 request_t *child = cr->request;
106
107 /*
108 * Child detached
109 */
110 if (cr->state == CHILD_DETACHED) {
111 RDEBUG3("subrequest detached during its execution - Not updating rcode or reply attributes");
112
113 /*
114 * If the child detached the subrequest section
115 * should become entirely transparent, and
116 * should not update the section rcode.
117 */
119 }
120
121 RDEBUG3("subrequest completed with rcode %s",
123
124 /*
125 * If there's a no destination tmpl, we're done.
126 */
127 if (!child->reply) {
130 }
131
132 /*
133 * Otherwise... copy reply attributes into the
134 * specified destination.
135 */
137 if (gext->dst) {
138 fr_pair_t *vp = NULL;
140 fr_dcursor_t cursor;
141
142 /*
143 * Use callback to build missing destination container.
144 */
145 vp = tmpl_dcursor_build_init(NULL, request, &cc, &cursor, request, gext->dst, tmpl_dcursor_pair_build, NULL);
146 if (!vp) {
147 RPDEBUG("Discarding subrequest attributes - Failed allocating groups");
149 return UNLANG_ACTION_FAIL;
150 }
151
152 MEM(fr_pair_list_copy(vp, &vp->vp_group, &child->reply_pairs) >= 0);
153
155 }
156
159}
160
161/** Allocates a new subrequest and initialises it
162 *
163 */
165{
166 unlang_child_request_t *cr = talloc_get_type_abort(frame->state, unlang_child_request_t);
167 request_t *child;
168 fr_pair_t *vp;
169
172
173 /*
174 * This should only be set for manually pushed subrequests
175 */
176 fr_assert(!cr->config.free_child);
177
178 /*
179 * Initialize the state
180 */
182 if (unlang_list_empty(&g->children)) RETURN_UNLANG_NOOP;
183
186 if (!child) {
187 fail:
188 talloc_free(child);
189 return UNLANG_ACTION_FAIL;
190 }
191 /*
192 * Set the packet type.
193 */
194 MEM(vp = fr_pair_afrom_da(child->request_ctx, gext->attr_packet_type));
195 if (gext->type_enum) {
196 child->packet->code = vp->vp_uint32 = gext->type_enum->value->vb_uint32;
197 } else {
198 fr_dict_enum_value_t const *type_enum;
199 fr_pair_t *attr;
200
201 if (tmpl_find_vp(&attr, request, gext->vpt) < 0) {
202 RDEBUG("Failed finding attribute %s", gext->vpt->name);
203 goto fail;
204 }
205
206 if (tmpl_attr_tail_da(gext->vpt)->type == FR_TYPE_STRING) {
207 type_enum = fr_dict_enum_by_name(gext->attr_packet_type, attr->vp_strvalue, attr->vp_length);
208 if (!type_enum) {
209 RDEBUG("Unknown Packet-Type %pV", &attr->data);
210 goto fail;
211 }
212
213 child->packet->code = vp->vp_uint32 = type_enum->value->vb_uint32;
214 } else {
215 fr_value_box_t box;
216
217 fr_value_box_init(&box, FR_TYPE_UINT32, NULL, false);
218 if (fr_value_box_cast(request, &box, FR_TYPE_UINT32, NULL, &attr->data) < 0) {
219 RDEBUG("Failed casting value from %pV to data type uint32", &attr->data);
220 goto fail;
221 }
222
223 /*
224 * Check that the value is known to the server.
225 *
226 * If it isn't known, then there's no
227 * "recv foo" section for it and we can't
228 * do anything with this packet.
229 */
230 type_enum = fr_dict_enum_by_value(gext->attr_packet_type, &box);
231 if (!type_enum) {
232 RDEBUG("Invalid value %pV for Packet-Type", &box);
233 goto fail;
234 }
235
236 child->packet->code = vp->vp_uint32 = box.vb_uint32;
237 }
238
239 }
240 fr_pair_append(&child->request_pairs, vp);
241
242 if ((gext->src) && (tmpl_copy_pair_children(child->request_ctx, &child->request_pairs, request, gext->src) < -1)) {
243 RPEDEBUG("Failed copying source attributes into subrequest");
244 goto fail;
245 }
246
247 /*
248 * Setup the child so it'll inform us when
249 * it resumes, or if it detaches.
250 *
251 * frame->instruction should be consistent
252 * as it's allocated by the unlang compiler.
253 */
254 if (unlang_child_request_init(cr, cr, child, p_result, NULL, frame->instruction, false) < 0) goto fail;
255
256 /*
257 * Push the first instruction the child's
258 * going to run.
259 */
260 if (unlang_interpret_push(NULL, child, unlang_list_head(&g->children),
262 UNLANG_NEXT_SIBLING) < 0) goto fail;
263
264 /*
265 * Finally, setup the function that will be
266 * called when the child indicates the
267 * parent should be resumed.
268 */
270
271 /*
272 * This is a common function, either pushed
273 * onto the parent's stack, or called directly
274 * from the subrequest instruction..
275 */
276 return unlang_subrequest_child_run(p_result, request, frame); /* returns UNLANG_ACTION_YIELD */
277}
278
279/** Free a child request, detaching it from its parent and freeing allocated memory
280 *
281 * @param[in] child to free.
282 */
284{
285 request_t *request = *child;
286
287 /*
288 * The interpeter is told about this subrequest via interpret_child_init() in
289 * unlang_subrequest_child_push_and_detach() etc. The subrequest is managed by the interpreter,
290 * and we therefore have to remove it from the interpreter. Otherwise, simply calling
291 * talloc_free() will leave a dangling pointer in the interpreter scheduler.
292 *
293 * If the request is detached, then the interpreter sees that it's done, and de-schedules it.
294 *
295 * unlang_interpret_request_done() isn't idempotent, so we have to check for the DONE state
296 * before calling it again. unlang_interpret_request_done() then calls the "done_internal"
297 * callback, which informs the application of that fact.
298 */
299 if (!request_is_detached(request) && (request->master_state != REQUEST_DONE)) {
301 }
302
305 *child = NULL;
306}
307
308/** Allocate a subrequest to run through a virtual server at some point in the future
309 *
310 * @param[in] parent to hang sub request off of.
311 * @param[in] namespace the child will operate in.
312 * @return
313 * - A new child request.
314 * - NULL on failure.
315 */
320
321
322/** Function to run in the context of the parent on resumption
323 *
324 * @note Only executes if unlang_subrequest_child_push was called, not with the normal subrequest keyword.
325 */
328{
329 unlang_child_request_t *cr = talloc_get_type_abort(frame->state, unlang_child_request_t);
330
331 /*
332 * Default to NOOP
333 */
334 if (cr->result.rcode == RLM_MODULE_NOT_SET) {
336 if (cr->p_result) {
337 *cr->p_result = cr->result;
338 } else {
339 *p_result = cr->result;
340 }
341 }
342
343 /*
344 * We can free the child here as we're its parent
345 */
346 if (cr->config.free_child) {
349 } else {
350 TALLOC_FREE(cr->request);
351 }
352 }
353
355}
356
357/** Function called by the unlang interpreter, or manually to start the child running
358 *
359 * The reason why we do this on the unlang stack is so that _this_ frame
360 * is marked as resumable in the parent, not whatever frame was previously
361 * being processed by the interpreter when the parent was called.
362 *
363 * i.e. after calling unlang_subrequest_child_push, the code in the parent
364 * can call UNLANG_ACTION_PUSHED_CHILD, which will result in _this_ frame
365 * being executed, and _this_ frame can yield.
366 *
367 * @note Called from the parent to start a child running.
368 */
371{
372 unlang_child_request_t *cr = talloc_get_type_abort(frame->state, unlang_child_request_t);
373 request_t *child = cr->request;
374
375 /*
376 * No parent means this is a pre-detached child
377 * so the parent should continue executing.
378 */
379 if (!child || !child->parent) return UNLANG_ACTION_CALCULATE_RESULT;
380
381
382 /*
383 * Ensure we restore the session state information
384 * into the child.
385 */
386 if (cr->config.session_unique_ptr) fr_state_restore_from_parent(child,
387 cr->config.session_unique_ptr,
388 cr->num);
389 /*
390 * Ensures the child is setup correctly and adds
391 * it into the runnable queue of whatever owns
392 * the interpreter.
393 */
395
396 /*
397 * This function is being called by something
398 * other than the subrequest keyword.
399 *
400 * Set a different resumption function that
401 * just writes the final rcode out.
402 */
403 if (frame->process == unlang_subrequest_child_run) {
405 }
406
407 cr->state = CHILD_RUNNABLE;
408
409 return UNLANG_ACTION_YIELD;
410}
411
412/** Push a pre-existing child back onto the stack as a subrequest
413 *
414 * The child *MUST* have been allocated with unlang_io_subrequest_alloc, or something
415 * that calls it.
416 *
417 * After the child is no longer required it *MUST* be freed with #unlang_subrequest_detach_and_free.
418 * It's not enough to free it with talloc_free.
419 *
420 * This function should be called _before_ pushing any additional frames onto the child's
421 * stack for it to execute.
422 *
423 * The parent should return UNLANG_ACTION_PUSHED_CHILD, when it's done setting up the
424 * child request. It should NOT return UNLANG_ACTION_YIELD.
425 *
426 * @param[in] p_result Where to write the result of the subrequest.
427 * @param[in] child to push.
428 * @param[in] unique_session_ptr Unique identifier for child's session data.
429 * @param[in] free_child automatically free the child when it's finished executing.
430 * This is useful if extracting the result from the child is
431 * done using the child's stack, and so the parent never needs
432 * to access it.
433 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
434 * Set to UNLANG_SUB_FRAME if the interpreter should continue.
435 * @return
436 * - 0 on success.
437 * - -1 on failure.
438 */
439
440int unlang_subrequest_child_push(unlang_result_t *p_result, request_t *child, void const *unique_session_ptr, bool free_child, bool top_frame)
441{
444
445 static unlang_t subrequest_instruction = {
447 .name = "subrequest",
448 .debug_name = "subrequest",
449 .actions = DEFAULT_MOD_ACTIONS,
450 };
451
452 fr_assert_msg(free_child || child->parent, "Child's request pointer must not be NULL when calling subrequest_child_push");
453
455 "Child stack depth must be 0 (not %d), when calling subrequest_child_push",
456 stack_depth_current(child))) return -1;
457
458 /*
459 * Push a new subrequest frame onto the stack
460 * of the parent.
461 *
462 * This allocates memory for the frame state
463 * which we fill in below.
464 *
465 * This frame executes once the subrequest has
466 * completed.
467 */
468 if (unlang_interpret_push(NULL, child->parent, &subrequest_instruction,
470 return -1;
471 }
472
473 frame = frame_current(child->parent);
475
476 /*
477 * Setup the state for the subrequest
478 */
479 cr = talloc_get_type_abort(frame_current(child->parent)->state, unlang_child_request_t);
480
481 /*
482 * Initialise our frame state, and push the first
483 * instruction onto the child's stack.
484 *
485 * This instruction will mark the parent as runnable
486 * when it executed.
487 */
488 if (unlang_child_request_init(cr, cr, child, p_result, NULL, unique_session_ptr, free_child) < 0) {
489 unwind_set(frame);
490 return -1;
491 }
492
493 return 0;
494}
495
496/** Add a child request to the runnable queue
497 *
498 * @param[in] request to add to the runnable queue.
499 * @return
500 * - 0 on success.
501 * - -1 on failure.
502 */
504{
505 /*
506 * Ensures the child is setup correctly and adds
507 * it into the runnable queue of whatever owns
508 * the interpreter.
509 */
511
512 if (request_detach(request) < 0) {
513 RPEDEBUG("Failed detaching request");
514 return -1;
515 }
516
517 return 0;
518}
519
521{
523 char const *name2;
524
525 unlang_t *c;
526
529
530 unlang_compile_ctx_t unlang_ctx2;
531
532 tmpl_rules_t t_rules;
533 fr_dict_autoload_talloc_t *dict_ref = NULL;
534
535 fr_dict_t const *dict;
536 fr_dict_attr_t const *attr_packet_type = NULL;
537 fr_dict_enum_value_t const *type_enum = NULL;
538
539 fr_slen_t slen;
540 char *namespace = NULL;
541 char const *packet_name = NULL;
542
543 tmpl_t *vpt = NULL, *src_vpt = NULL, *dst_vpt = NULL;
544
545 if (!cf_item_next(cs, NULL)) return UNLANG_IGNORE;
546
547 /*
548 * subrequest { ... }
549 *
550 * Create a subrequest which is of the same dictionary
551 * and packet type as the current request.
552 *
553 * We assume that the Packet-Type attribute exists.
554 */
555 name2 = cf_section_name2(cs);
556 if (!name2) {
557 dict = unlang_ctx->rules->attr.dict_def;
558 packet_name = name2 = unlang_ctx->section_name2;
560 goto get_packet_type;
561 }
562
564 cf_log_err(cs, "The arguments to 'subrequest' must be a name or an attribute reference");
565 print_url:
566 cf_log_err(ci, DOC_KEYWORD_REF(subrequest));
567 return NULL;
568 }
569
570 dict = unlang_ctx->rules->attr.dict_def;
571
572 /*
573 * @foo is "dictionary foo", as with references in the dictionaries.
574 *
575 * @foo::bar is "dictionary foo, Packet-Type = ::bar"
576 *
577 * foo::bar is "dictionary foo, Packet-Type = ::bar"
578 *
579 * ::bar is "this dictionary, Packet-Type = ::bar", BUT
580 * we don't try to parse the new dictionary name, as it
581 * doesn't exist.
582 */
583 if ((name2[0] == '@') ||
584 ((name2[0] != ':') && (name2[0] != '&') && (strchr(name2 + 1, ':') != NULL))) {
585 char *q;
586
587 /*
588 * This is a different protocol dictionary. We reset the packet type.
589 *
590 * @todo - the packet type should really be stored in #fr_dict_protocol_t.
591 */
592 if (name2[0] == '@') {
593 attr_packet_type = NULL;
594 name2++;
595 }
596
597 MEM(namespace = talloc_strdup(parent, name2));
598 q = namespace;
599
600 while (fr_dict_attr_allowed_chars[(uint8_t) *q]) {
601 q++;
602 }
603 *q = '\0';
604
605 dict = fr_dict_by_protocol_name(namespace);
606 if (!dict) {
607 dict_ref = fr_dict_autoload_talloc(NULL, &dict, namespace);
608 if (!dict_ref) {
609 cf_log_err(cs, "Unknown namespace in '%s'", name2);
610 talloc_free(namespace);
611 return NULL;
612 }
613 }
614
615 /*
616 * Skip the dictionary name, and go to the thing
617 * right after it.
618 */
619 name2 += (q - namespace);
620 TALLOC_FREE(namespace);
621 }
622
623 /*
624 * @dict::enum is "other dictionary, Packet-Type = ::enum"
625 * ::enum is this dictionary, "Packet-Type = ::enum"
626 */
627 if ((name2[0] == ':') && (name2[1] == ':')) {
628 packet_name = name2;
629 goto get_packet_type;
630 }
631
632 /*
633 * Can't do foo.bar.baz::foo, the enums are only used for Packet-Type.
634 */
635 if (strchr(name2, ':') != NULL) {
636 cf_log_err(cs, "Reference cannot contain enum value in '%s'", name2);
637 return NULL;
638 }
639
640 /*
641 * Bare words are attribute references.
642 */
643 slen = tmpl_afrom_attr_substr(parent, NULL, &vpt,
644 &FR_SBUFF_IN(name2, talloc_strlen(name2)),
645 NULL, unlang_ctx->rules);
646 if (slen <= 0) {
647 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing packet-type");
648 goto print_url;
649 }
650
652
653 /*
654 * Anything resembling an integer or string is
655 * OK. Nothing else makes sense.
656 */
657 switch (tmpl_attr_tail_da(vpt)->type) {
659 case FR_TYPE_STRING:
660 break;
661
662 default:
664 cf_log_err(cs, "Invalid data type for attribute %s. "
665 "Must be an integer type or string", name2 + 1);
666 goto print_url;
667 }
668
669 dict = unlang_ctx->rules->attr.dict_def;
670 packet_name = NULL;
671
672get_packet_type:
673 /*
674 * Local attributes cannot be used in a subrequest. They belong to the parent. Local attributes
675 * are NOT copied to the subrequest.
676 *
677 * @todo - maybe we want to copy local variables, too? But there may be multiple nested local
678 * variables, each with their own dictionary.
679 */
681
682 /*
683 * We're switching virtual servers, find the packet type by name.
684 */
685 if (!attr_packet_type) {
687 if (!attr_packet_type) {
688 cf_log_err(cs, "No such attribute 'Packet-Type' in namespace '%s'", fr_dict_root(dict)->name);
689 error:
690 talloc_free(namespace);
692 talloc_free(dict_ref);
693 goto print_url;
694 }
695 }
696
697 if (packet_name) {
698 /*
699 * Allow ::enum-name for packet types
700 */
701 if ((packet_name[0] == ':') && (packet_name[1] == ':')) packet_name += 2;
702
704 if (!type_enum) {
705 cf_log_err(cs, "No such value '%s' for attribute '%s' in namespace '%s'",
707 goto error;
708 }
709 }
710
711 /*
712 * No longer needed
713 */
714 talloc_free(namespace);
715
716 /*
717 * Source and destination arguments
718 */
719 {
720 char const *dst, *src;
721
722 src = cf_section_argv(cs, 0);
723 if (src) {
724 RULES_VERIFY(unlang_ctx->rules);
725
726 (void) tmpl_afrom_substr(parent, &src_vpt,
727 &FR_SBUFF_IN(src, talloc_strlen(src)),
728 cf_section_argv_quote(cs, 0), NULL, unlang_ctx->rules);
729 if (!src_vpt) {
730 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing src");
731 goto error;
732 }
733
734 if (!tmpl_contains_attr(src_vpt)) {
735 cf_log_err(cs, "Invalid argument to 'subrequest' src must be an attr or list, got %s",
736 tmpl_type_to_str(src_vpt->type));
737 talloc_free(src_vpt);
738 goto error;
739 }
740
741 dst = cf_section_argv(cs, 1);
742 if (dst) {
743 RULES_VERIFY(unlang_ctx->rules);
744
745 (void) tmpl_afrom_substr(parent, &dst_vpt,
746 &FR_SBUFF_IN(dst, talloc_strlen(dst)),
747 cf_section_argv_quote(cs, 1), NULL, unlang_ctx->rules);
748 if (!dst_vpt) {
749 cf_log_perr(cs, "Invalid argument to 'subrequest', failed parsing dst");
750 goto error;
751 }
752
753 if (!tmpl_contains_attr(dst_vpt)) {
754 cf_log_err(cs, "Invalid argument to 'subrequest' dst must be an "
755 "attr or list, got %s",
756 tmpl_type_to_str(dst_vpt->type));
757 talloc_free(src_vpt);
758 talloc_free(dst_vpt);
759 goto error;
760 }
761 }
762 }
763 }
764
765 if (!cf_item_next(cs, NULL)) {
767 talloc_free(src_vpt);
768 talloc_free(dst_vpt);
769 return UNLANG_IGNORE;
770 }
771
772 t_rules = *unlang_ctx->rules;
773 t_rules.parent = unlang_ctx->rules;
774 t_rules.attr.dict_def = dict;
775 t_rules.attr.allow_foreign = false;
776
777 /*
778 * Copy over the compilation context. This is mostly
779 * just to ensure that retry is handled correctly.
780 * i.e. reset.
781 */
782 unlang_compile_ctx_copy(&unlang_ctx2, unlang_ctx);
783
784 /*
785 * Then over-write the new compilation context.
786 */
787 unlang_ctx2.section_name1 = "subrequest";
788 unlang_ctx2.section_name2 = name2;
789 unlang_ctx2.rules = &t_rules;
790
791 /*
792 * Compile the subsection with a *different* default dictionary.
793 */
795 if (!c) return NULL;
796
797 /*
798 * Set the dictionary and packet information, which tells
799 * unlang_subrequest() how to process the request.
800 */
803
804 if (dict_ref) {
805 /*
806 * Parent the dictionary reference correctly now that we
807 * have the section with the dependency. This should
808 * be fast as dict_ref has no siblings.
809 */
810 talloc_steal(gext, dict_ref);
811 }
812 if (vpt) gext->vpt = talloc_steal(gext, vpt);
813
814 gext->dict = dict;
816 gext->type_enum = type_enum;
817 gext->src = src_vpt;
818 gext->dst = dst_vpt;
819
820 return c;
821}
822
823
824/** Initialise subrequest ops
825 *
826 */
828{
830 .name = "subrequest",
832
833 /*
834 * Frame can't be cancelled, because children need to
835 * write out status to the parent. If we don't do this,
836 * then all children must be detachable and must detach
837 * so they don't try and write out status to a "done"
838 * parent.
839 *
840 * It's easier to allow the child/parent relationship
841 * to end normally so that non-detachable requests are
842 * guaranteed the parent still exists.
843 */
845
846 .compile = unlang_compile_subrequest,
847 .interpret = unlang_subrequest_init,
848 .signal = unlang_subrequest_signal,
849
850 .unlang_size = sizeof(unlang_subrequest_t),
851 .unlang_name = "unlang_subrequest_t",
852 .pool_headers = (TMPL_POOL_DEF_HEADERS * 3),
853 .pool_len = (TMPL_POOL_DEF_LEN * 3),
854
855 .frame_state_size = sizeof(unlang_child_request_t),
856 .frame_state_type = "unlang_child_request_t",
857 });
858
859 if (unlang_child_request_op_init() < 0) return -1;
860
861 return 0;
862}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:38
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:42
static uint8_t request[4]
#define RCSID(id)
Definition build.h:603
#define UNUSED
Definition build.h:415
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
fr_token_t cf_section_argv_quote(CONF_SECTION const *cs, int argc)
Return the quoting for one of the variadic arguments.
Definition cf_util.c:1468
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:671
char const * cf_section_argv(CONF_SECTION const *cs, int argc)
Return variadic argument at the specified index.
Definition cf_util.c:1433
fr_token_t cf_section_name2_quote(CONF_SECTION const *cs)
Return the quoting of the name2 identifier.
Definition cf_util.c:1450
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_item_next(_parent, _curr)
Definition cf_util.h:91
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
int unlang_child_request_op_init(void)
int unlang_child_request_init(TALLOC_CTX *ctx, unlang_child_request_t *out, request_t *child, unlang_result_t *p_result, unsigned int *sibling_count, void const *unique_session_ptr, bool free_child)
Initialize a child request.
request_t * request
Child request. The actual request the child will run.
unlang_result_t result
The result of the child request.
unlang_child_request_state_t state
State of the child.
struct unlang_child_request_t::@118 config
unlang_result_t * p_result
Pointer to the result of the child request.
@ CHILD_RUNNABLE
Running/runnable.
@ CHILD_DETACHED
Child has detached, we can't signal it or communicate with it anymore.
@ CHILD_CANCELLED
Child was cancelled.
int num
The child number.
Each child has a state, a number, a request, and a count of their siblings.
fr_dict_t * dict
Definition common.c:31
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1522
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:67
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:248
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:194
#define MEM(x)
Definition debug.h:38
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:88
#define fr_dict_autoload_talloc(_ctx, _dict_out, _proto)
Definition dict.h:940
bool const fr_dict_attr_allowed_chars[SBUFF_CHAR_CLASS]
Characters allowed in a single dictionary attribute name.
Definition dict_util.c:54
fr_dict_t const * fr_dict_proto_dict(fr_dict_t const *dict)
Definition dict_util.c:5413
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_attr_err_t *err, fr_dict_attr_t const *parent, char const *attr))
Locate a fr_dict_attr_t by its name.
Definition dict_util.c:3600
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2717
fr_value_box_t const * value
Enum value (what name maps to).
Definition dict.h:281
fr_dict_enum_value_t const * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition dict_util.c:3729
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
Definition dict_util.c:2906
fr_dict_enum_value_t const * fr_dict_enum_by_name(fr_dict_attr_t const *da, char const *name, ssize_t len)
Definition dict_util.c:3778
Value of an enumerated attribute.
Definition dict.h:277
Structure used to managed the lifetime of a dictionary.
Definition dict_util.c:4654
talloc_free(hp)
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1978
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1630
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1961
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1789
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:622
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:158
#define UNLANG_SUB_FRAME
Definition interpret.h:37
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:140
Private declarations for the unlang interpreter.
static void interpret_child_init(request_t *request)
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RPDEBUG(fmt,...)
Definition log.h:363
#define RPEDEBUG(fmt,...)
Definition log.h:393
static TALLOC_CTX * unlang_ctx
Definition base.c:71
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
request_t * unlang_io_subrequest_alloc(request_t *parent, fr_dict_t const *namespace, bool detachable)
Allocate a child request based on the parent.
Definition io.c:39
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unsigned char uint8_t
ssize_t fr_slen_t
#define DEFAULT_MOD_ACTIONS
Definition mod_action.h:73
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2303
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:1297
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:284
static const char * packet_name[]
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RDEBUG(fmt,...)
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:45
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:54
#define RETURN_UNLANG_NOOP
Definition rcode.h:75
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:560
#define request_is_detached(_x)
Definition request.h:187
#define request_is_detachable(_x)
Definition request.h:188
@ REQUEST_DONE
Request has completed.
Definition request.h:91
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
void fr_state_restore_from_parent(request_t *child, void const *unique_ptr, int unique_int)
Restore subrequest data from a parent request.
Definition state.c:987
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt))
Returns the first VP matching a tmpl_t.
Definition tmpl_eval.c:777
static char const * tmpl_type_to_str(tmpl_type_t type)
Return a static string containing the type name.
Definition tmpl.h:661
#define tmpl_is_attr(vpt)
Definition tmpl.h:215
tmpl_rules_t const * parent
for parent / child relationships
Definition tmpl.h:344
#define tmpl_contains_attr(vpt)
Definition tmpl.h:232
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.
fr_slen_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.
static fr_slen_t vpt
Definition tmpl.h:1300
#define TMPL_POOL_DEF_HEADERS
Define manipulation functions for the attribute reference list.
Definition tmpl.h:513
#define TMPL_POOL_DEF_LEN
How many additional bytes to allocate in a pool for a tmpl_t.
Definition tmpl.h:518
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:346
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:826
int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt))
Copy children of pairs matching a tmpl_t in the current request_t.
Definition tmpl_eval.c:729
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:343
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_DETACH
Request is being detached from its parent.
Definition signal.h:45
fr_aka_sim_id_type_t type
fr_pair_t * vp
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:280
unsigned int allow_foreign
Allow arguments not found in dict_def.
Definition tmpl.h:321
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
static void unlang_subrequest_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Send a signal from parent request to subrequest.
Definition subrequest.c:38
static unlang_action_t unlang_subrequest_parent_resume(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Parent being resumed after a child completes.
Definition subrequest.c:99
static unlang_action_t unlang_subrequest_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Allocates a new subrequest and initialises it.
Definition subrequest.c:164
int unlang_subrequest_op_init(void)
Initialise subrequest ops.
Definition subrequest.c:827
int unlang_subrequest_child_push_and_detach(request_t *request)
Add a child request to the runnable queue.
Definition subrequest.c:503
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
Definition subrequest.c:316
void unlang_subrequest_detach_and_free(request_t **child)
Free a child request, detaching it from its parent and freeing allocated memory.
Definition subrequest.c:283
static unlang_action_t unlang_subrequest_child_done(unlang_result_t *p_result, UNUSED request_t *request, unlang_stack_frame_t *frame)
Function to run in the context of the parent on resumption.
Definition subrequest.c:326
static unlang_t * unlang_compile_subrequest(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
Definition subrequest.c:520
int unlang_subrequest_child_push(unlang_result_t *p_result, request_t *child, void const *unique_session_ptr, bool free_child, bool top_frame)
Push a pre-existing child back onto the stack as a subrequest.
Definition subrequest.c:440
unlang_action_t unlang_subrequest_child_run(UNUSED unlang_result_t *p_result, UNUSED request_t *request, unlang_stack_frame_t *frame)
Function called by the unlang interpreter, or manually to start the child running.
Definition subrequest.c:369
static unlang_subrequest_t * unlang_group_to_subrequest(unlang_group_t *g)
Cast a group structure to the subrequest keyword extension.
tmpl_t * vpt
Value to expand to find the value to place into the packet-type attribute.
fr_dict_attr_t const * attr_packet_type
Packet-type attribute in the subrequest protocol.
tmpl_t * src
Pairs to copy into the subrequest request list.
fr_dict_t const * dict
Dictionary of the subrequest protocol.
tmpl_t * dst
Where to copy pairs from the reply list in the subrequest to.
fr_dict_enum_value_t const * type_enum
Static enumeration value for attr_packet_type.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
fr_pair_t * tmpl_dcursor_pair_build(fr_pair_t *parent, fr_dcursor_t *cursor, fr_dict_attr_t const *da, UNUSED void *uctx)
Simple pair building callback for use with tmpl_dcursors.
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_build_init(_err, _ctx, _cc, _cursor, _request, _vpt, _build, _uctx)
Maintains state between cursor calls.
@ T_BARE_WORD
Definition token.h:118
Private interpreter structures and functions.
#define UNLANG_NORMAL_CHILD
#define UNLANG_DETACHABLE
#define RULES_VERIFY(_rules)
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:99
void * state
Stack frame specialisations.
tmpl_rules_t const * rules
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:98
static void unwind_set(unlang_stack_frame_t *frame)
static void unlang_compile_ctx_copy(unlang_compile_ctx_t *dst, unlang_compile_ctx_t const *src)
#define UNLANG_IGNORE
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
char const * section_name1
static unlang_stack_frame_t * frame_current(request_t *request)
unlang_list_t children
static int stack_depth_current(request_t *request)
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
Definition unlang_priv.h:67
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
char const * section_name2
unlang_op_flag_t
@ UNLANG_OP_FLAG_NO_FORCE_UNWIND
Must not be cancelled.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
static fr_slen_t parent
Definition pair.h:864
#define FR_TYPE_INTEGER_EXCEPT_BOOL
Definition types.h:303
#define DOC_KEYWORD_REF(_x)
Definition version.h:89
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:4071
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:634
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
fr_dict_attr_t const * virtual_server_packet_type_by_cs(CONF_SECTION const *server_cs)
Return the packet type attribute for a virtual server specified by a config section.