The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
exec.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: c32377b47d41e19fd92ea59479c6839c11b98b90 $
19 *
20 * @file src/lib/server/exec.c
21 * @brief Execute external programs.
22 *
23 * @copyright 2022-2023 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2000-2004,2006 The FreeRADIUS server project
25 */
26RCSID("$Id: c32377b47d41e19fd92ea59479c6839c11b98b90 $")
27
28#include <stdint.h>
29
30#include <freeradius-devel/server/log.h>
31#include <freeradius-devel/server/exec.h>
32#include <freeradius-devel/server/exec_priv.h>
33#include <freeradius-devel/server/request.h>
34#include <freeradius-devel/server/util.h>
35#include <freeradius-devel/util/debug.h>
36
37#define MAX_ENVP 1024
38
39static _Thread_local char *env_exec_arr[MAX_ENVP]; /* Avoid allocing 8k on the stack */
40
41/** Flatten a list into individual "char *" argv-style array
42 *
43 * @param[in] ctx to allocate boxes in.
44 * @param[out] argv_p where output strings go
45 * @param[in] in boxes to flatten
46 * @return
47 * - >= 0 number of array elements in argv
48 * - <0 on error
49 */
50int fr_exec_value_box_list_to_argv(TALLOC_CTX *ctx, char ***argv_p, fr_value_box_list_t const *in)
51{
52 char **argv;
53 unsigned int i = 0;
54 size_t argc = fr_value_box_list_num_elements(in);
55 fr_value_box_t const *first;
56
57 /*
58 * Check that we're not trying to run a program from
59 * a tainted source.
60 */
61 first = fr_value_box_list_head(in);
62 if (first->type == FR_TYPE_GROUP) first = fr_value_box_list_head(&first->vb_group);
63 if (first->tainted) {
64 fr_strerror_printf("Program to run comes from tainted source - %pV", first);
65 return -1;
66 }
67
68 argv = talloc_zero_array(ctx, char *, argc + 1);
69 if (!argv) return -1;
70
72 /*
73 * Print the children of each group into the argv array.
74 */
75 argv[i] = fr_value_box_list_aprint(argv, &vb->vb_group, NULL, NULL);
76 if (!argv[i]) {
77 talloc_free(argv);
78 return -1;
79 }
80 i++;
81 }
82
83 *argv_p = argv;
84
85 return argc;
86}
87
88/** Print debug information showing the arguments and environment for a process
89 *
90 * @param[in] request The current request, may be NULL.
91 * @param[in] argv_in arguments to pass to process.
92 * @param[in] env_in environment to pass to process.
93 * @param[in] env_inherit print debug for the environment from the environment.
94 */
95static inline CC_HINT(always_inline) void exec_debug(request_t *request, char **argv_in, char **env_in, bool env_inherit)
96{
97 char **p;
98
99 if (argv_in) for (p = argv_in; *p; p++) ROPTIONAL(RDEBUG3, DEBUG3, "arg[%d] %s", (unsigned int)(p - argv_in), *p);
100 if (env_in) for (p = env_in; *p; p++) ROPTIONAL(RDEBUG3, DEBUG3, "export %s", *p);
101 if (env_inherit) for (p = environ; *p; p++) ROPTIONAL(RDEBUG3, DEBUG3, "export %s", *p);
102}
103
104/** Convert pairs from a request and a list of pairs into environmental variables
105 *
106 * @param[out] env_p Where to write an array of \0 terminated strings.
107 * @param[in] env_len Length of env_p.
108 * @param[out] env_sbuff To write environmental variables too. Each variable
109 * will be written to the buffer, and separated with
110 * a '\0'.
111 * @param[in] env_m an array of markers of the same length as env_len.
112 * @param[in] request Will look for &control.Exec-Export items to convert to
113 * env vars.
114 * @param[in] env_pairs Other items to convert to environmental variables.
115 * The dictionary attribute name will be converted to
116 * uppercase, and all '-' converted to '_' and will form
117 * the variable name.
118 * @param[in] env_escape Wrap string values in double quotes, and apply doublequote
119 * escaping to all environmental variable values.
120 * @return
121 * - The number of environmental variables created.
122 * - -1 on failure.
123 */
124static inline CC_HINT(nonnull(1,3,4,5)) CC_HINT(always_inline)
125int exec_pair_to_env(char **env_p, size_t env_len,
126 fr_sbuff_t *env_sbuff, fr_sbuff_marker_t env_m[],
127 request_t *request, fr_pair_list_t *env_pairs, bool env_escape)
128{
129 char *p;
130 size_t i, j;
131 fr_dcursor_t cursor;
132 fr_dict_attr_t const *da;
133 fr_sbuff_t sbuff = FR_SBUFF_BIND_CURRENT(env_sbuff);
134
135 if (!env_pairs) {
136 env_p[0] = NULL;
137 return 0;
138 }
139
140 /*
141 * Set up the environment variables in the
142 * parent, so we don't call libc functions that
143 * hold mutexes. They might be locked when we fork,
144 * and will remain locked in the child.
145 */
146 i = 0;
147 fr_pair_list_foreach_leaf(env_pairs, vp) {
148 fr_sbuff_marker(&env_m[i], &sbuff);
149
150 if (fr_sbuff_in_strcpy(&sbuff, vp->da->name) <= 0) {
151 fr_strerror_printf("Out of buffer space adding attribute name");
152 return -1;
153 }
154
155 /*
156 * POSIX only allows names to contain
157 * uppercase chars, digits, and
158 * underscores. Digits are not allowed
159 * for the first char.
160 */
161 p = fr_sbuff_current(&env_m[i]);
162 if (isdigit((uint8_t)*p)) *p++ = '_';
163 for (; p < fr_sbuff_current(&sbuff); p++) {
164 if (isalpha((uint8_t)*p)) *p = toupper((uint8_t) *p);
165 else if (*p == '-') *p = '_';
166 else if (isdigit((uint8_t)*p)) goto next;
167 else *p = '_';
168 }
169
170 if (fr_sbuff_in_char(&sbuff, '=') <= 0) {
171 fr_strerror_printf("Out of buffer space");
172 return -1;
173 }
174
175 if (env_escape) {
176 if (fr_value_box_print_quoted(&sbuff, &vp->data, T_DOUBLE_QUOTED_STRING) < 0) {
177 fr_strerror_printf("Out of buffer space adding attribute value for %pV", &vp->data);
178 return -1;
179 }
180 } else {
181 /*
182 * This can be zero length for empty strings
183 *
184 * Note we don't do double quote escaping here,
185 * we just escape unprintable chars.
186 *
187 * Environmental variable values are not
188 * restricted we likely wouldn't need to do
189 * any escaping if we weren't dealing with C
190 * strings.
191 *
192 * If we end up passing binary data through
193 * then the user can unescape the octal
194 * sequences on the other side.
195 *
196 * We unfortunately still need to escape '\'
197 * because of this.
198 */
199 if (fr_value_box_print(&sbuff, &vp->data, &fr_value_escape_unprintables) < 0) {
200 fr_strerror_printf("Out of buffer space adding attribute value for %pV", &vp->data);
201 return -1;
202 }
203 }
204 if (fr_sbuff_in_char(&sbuff, '\0') <= 0) {
205 fr_strerror_printf("Out of buffer space");
206 return -1;
207 }
208
209 next:
210 i++;
211 if (i == (env_len - 1)) break;
212 }
213
214 /*
215 * Do this as a separate step so that if env_sbuff
216 * is extended at any point during the conversion
217 * the sbuff we use is the final one.
218 */
219 for (j = 0; j < i; j++) {
220 env_p[j] = fr_sbuff_current(&env_m[j]);
221 }
222
224 if (da) {
225 fr_pair_t *vp;
226
227 for (vp = fr_pair_dcursor_by_da_init(&cursor, &request->control_pairs, da);
228 vp;
229 vp = fr_dcursor_next(&cursor)) {
230 env_p[i++] = UNCONST(char *, vp->vp_strvalue);
231 }
232 }
233
234 if (unlikely(i == (env_len - 1))) {
235 fr_strerror_printf("Out of space for environmental variables");
236 return -1;
237 }
238
239 /*
240 * NULL terminate for execve
241 */
242 env_p[i] = NULL;
243
244 return i;
245}
246
247/** Convert env_pairs into an array of environmental variables using thread local buffers
248 *
249 * @param[in] request Will be searched for control.Exec-Export pairs.
250 * @param[in] env_pairs env_pairs to put into into the environment. May be NULL.
251 * @param[in] env_escape Wrap string values in double quotes, and apply doublequote
252 * escaping to all environmental variable values.
253 * @return
254 * - An array of environmental variable definitions, valid until the next call
255 * to fr_exec_pair_to_env within the same thread.
256 * - NULL on error. Error retrievable fr_strerror().
257 */
258char **fr_exec_pair_to_env(request_t *request, fr_pair_list_t *env_pairs, bool env_escape)
259{
260 static _Thread_local char *env_arr[MAX_ENVP]; /* Avoid allocing 8k on the stack */
261 static _Thread_local char env_buff[NUM_ELEMENTS(env_arr) * 128]; /* Avoid allocing 128k on the stack */
262 static _Thread_local fr_sbuff_marker_t env_m[NUM_ELEMENTS(env_arr)];
263
264 if (exec_pair_to_env(env_arr, NUM_ELEMENTS(env_arr),
265 &FR_SBUFF_OUT(env_buff, sizeof(env_buff)), env_m,
266 request, env_pairs, env_escape) < 0) return NULL;
267
268 return env_arr;
269}
270
271/** Start a child process
272 *
273 * We try to be fail-safe here. So if ANYTHING goes wrong, we exit with status 1.
274 *
275 * @param[in] argv array of arguments to pass to child.
276 * @param[in] envp array of environment variables in form `<attr>=<val>`
277 * @param[in] exec_wait if true, redirect child process' stdin, stdout, stderr
278 * to the pipes provided, redirecting any to /dev/null
279 * where no pipe was provided. If false redirect
280 * stdin, and stdout to /dev/null.
281 * @param[in] debug If true, and !exec_wait, don't molest stderr.
282 * @param[in] stdin_pipe the pipe used to write data to the process. STDIN will
283 * be set to stdin_pipe[0], stdin_pipe[1] will be closed.
284 * @param[in] stdout_pipe the pipe used to read data from the process.
285 * STDOUT will be set to stdout_pipe[1], stdout_pipe[0]
286 * will be closed.
287 * @param[in] stderr_pipe the pipe used to read error text from the process.
288 * STDERR will be set to stderr_pipe[1], stderr_pip[0]
289 * will be closed.
290 */
291static NEVER_RETURNS void exec_child(char **argv, char **envp,
292 bool exec_wait, bool debug,
293 int stdin_pipe[static 2], int stdout_pipe[static 2], int stderr_pipe[static 2])
294{
295 int devnull;
296
297 /*
298 * Open STDIN to /dev/null
299 */
300 devnull = open("/dev/null", O_RDWR);
301 if (devnull < 0) {
302 fprintf(stderr, "Failed opening /dev/null: %s\n", fr_syserror(errno));
303
304 /*
305 * Where the status code is interpreted as a module rcode
306 * one is subtracted from it, to allow 0 to equal success
307 *
308 * 2 is RLM_MODULE_FAIL + 1
309 */
310 exit(2);
311 }
312
313 /*
314 * Only massage the pipe handles if the parent
315 * has created them.
316 */
317 if (exec_wait) {
318 if (stdin_pipe[1] >= 0) {
319 close(stdin_pipe[1]);
320 dup2(stdin_pipe[0], STDIN_FILENO);
321 } else {
322 dup2(devnull, STDIN_FILENO);
323 }
324
325 if (stdout_pipe[1] >= 0) {
326 close(stdout_pipe[0]);
327 dup2(stdout_pipe[1], STDOUT_FILENO);
328 } else {
329 dup2(devnull, STDOUT_FILENO);
330 }
331
332 if (stderr_pipe[1] >= 0) {
333 close(stderr_pipe[0]);
334 dup2(stderr_pipe[1], STDERR_FILENO);
335 } else {
336 dup2(devnull, STDERR_FILENO);
337 }
338 } else { /* no pipe, STDOUT should be /dev/null */
339 dup2(devnull, STDIN_FILENO);
340 dup2(devnull, STDOUT_FILENO);
341
342 /*
343 * If we're not debugging, then we can't do
344 * anything with the error messages, so we throw
345 * them away.
346 *
347 * If we are debugging, then we want the error
348 * messages to go to the STDERR of the server.
349 */
350 if (!debug) dup2(devnull, STDERR_FILENO);
351 }
352
353 close(devnull);
354
355 /*
356 * The server may have MANY FD's open. We don't
357 * want to leave dangling FD's for the child process
358 * to play funky games with, so we close them.
359 */
360 fr_closefrom(STDERR_FILENO + 1);
361
362 /*
363 * Disarm the thread local destructors
364 *
365 * It's not safe to free memory between fork and exec.
366 */
368
369 /*
370 * Disarm the global destructors for the same reason
371 */
373
374 /*
375 * I swear the signature for execve is wrong and should
376 * take 'char const * const argv[]'.
377 *
378 * Note: execve(), unlike system(), treats all the space
379 * delimited arguments as literals, so there's no need
380 * to perform additional escaping.
381 */
382 execve(argv[0], argv, envp);
383 printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */
384
385 /*
386 * Where the status code is interpreted as a module rcode
387 * one is subtracted from it, to allow 0 to equal success
388 *
389 * 2 is RLM_MODULE_FAIL + 1
390 */
391 exit(2);
392}
393
394/** Merge extra environmental variables and potentially the inherited environment
395 *
396 * @param[in] env_in to merge.
397 * @param[in] env_inherit inherite environment from radiusd.
398 * @return merged environmental variables.
399 */
400static
401char **exec_build_env(char **env_in, bool env_inherit)
402{
403 size_t num_in, num_environ;
404
405 /*
406 * Not inheriting the radiusd environment, just return whatever we were given.
407 */
408 if (!env_inherit) {
409 return env_in;
410 }
411
412 /*
413 * No additional environment variables, just return the ones from radiusd.
414 */
415 if (!env_in) return environ;
416
417 for (num_environ = 0; environ[num_environ] != NULL; num_environ++) {
418 /* nothing */
419 }
420
421 /*
422 * No room to copy anything after the environment variables.
423 */
424 if (((num_environ + 1) == NUM_ELEMENTS(env_exec_arr))) {
425 return environ;
426 }
427
428 /*
429 * Copy the radiusd environment to the local array
430 */
431 memcpy(env_exec_arr, environ, num_environ + 1);
432
433 for (num_in = 0; env_in[num_in] != NULL; num_in++) {
434 if ((num_environ + num_in + 1) >= NUM_ELEMENTS(env_exec_arr)) break;
435 }
436
437 memcpy(env_exec_arr + num_environ, env_in, num_in);
438 env_exec_arr[num_environ + num_in] = NULL;
439
440 return env_exec_arr;
441}
442
443/** Execute a program without waiting for the program to finish.
444 *
445 * @param[in] el event list to insert reaper child into.
446 * @param[in] argv_in arg[0] is the path to the program, arg[...] are arguments
447 * to pass to the program.
448 * @param[in] env_in any additional environmental variables to pass to the program.
449 * @param[in] env_inherit Inherit the environment from the current process.
450 * This will be merged with any variables from env_pairs.
451 * @param[in] debug If true, STDERR will be left open and pointing to the stderr
452 * descriptor of the parent.
453 * @return
454 * - <0 on error. Error retrievable fr_strerror().
455 * - 0 on success
456 *
457 * @todo - maybe take an fr_dcursor_t instead of env_pairs? That
458 * would allow finer-grained control over the attributes to put into
459 * the environment.
460 */
461int fr_exec_fork_nowait(fr_event_list_t *el, char **argv_in, char **env_in, bool env_inherit, bool debug)
462{
463 char **env;
464 pid_t pid;
465
466 env = exec_build_env(env_in, env_inherit);
467 pid = fork();
468 /*
469 * The child never returns from calling exec_child();
470 */
471 if (pid == 0) {
472 int unused[2] = { -1, -1 };
473
474 exec_child(argv_in, env, false, debug, unused, unused, unused);
475 }
476
477 if (pid < 0) {
478 fr_strerror_printf("Couldn't fork %s", argv_in[0]);
479 error:
480 return -1;
481 }
482
483 /*
484 * Ensure that we can clean up any child processes. We
485 * don't want them left over as zombies.
486 */
487 if (fr_event_pid_reap(el, pid, NULL, NULL) < 0) {
488 int status;
489
490 /*
491 * Try and cleanup... really we have
492 * no idea what state things are in.
493 */
494 kill(pid, SIGKILL);
495 waitpid(pid, &status, WNOHANG);
496 goto error;
497 }
498
499 return 0;
500}
501
502/** Execute a program assuming that the caller waits for it to finish.
503 *
504 * The caller takes responsibility for calling waitpid() on the returned PID.
505 *
506 * The caller takes responsibility for reading from the returned FD,
507 * and closing it.
508 *
509 * @param[out] pid_p The PID of the child
510 * @param[out] stdin_fd The stdin FD of the child.
511 * @param[out] stdout_fd The stdout FD of the child.
512 * @param[out] stderr_fd The stderr FD of the child.
513 * @param[in] argv_in arg[0] is the path to the program, arg[...] are arguments
514 * to pass to the program.
515 * @param[in] env_in Environmental variables to pass to the program.
516 * @param[in] env_inherit Inherit the environment from the current process.
517 * This will be merged with any variables from env_pairs.
518 * @param[in] debug If true, STDERR will be left open and pointing to the stderr
519 * descriptor of the parent, if no stderr_fd pointer is provided.
520 * @return
521 * - <0 on error. Error retrievable fr_strerror().
522 * - 0 on success.
523 *
524 * @todo - maybe take an fr_dcursor_t instead of env_pairs? That
525 * would allow finer-grained control over the attributes to put into
526 * the environment.
527 */
528int fr_exec_fork_wait(pid_t *pid_p,
529 int *stdin_fd, int *stdout_fd, int *stderr_fd,
530 char **argv_in, char **env_in, bool env_inherit, bool debug)
531{
532 char **env;
533 pid_t pid;
534 int stdin_pipe[2] = {-1, -1};
535 int stderr_pipe[2] = {-1, -1};
536 int stdout_pipe[2] = {-1, -1};
537
538 if (stdin_fd) {
539 if (pipe(stdin_pipe) < 0) {
540 fr_strerror_const("Failed opening pipe to write to child");
541
542 error1:
543 return -1;
544 }
545 if (fr_nonblock(stdin_pipe[1]) < 0) fr_strerror_const("Error setting stdin to nonblock");
546 }
547
548 if (stdout_fd) {
549 if (pipe(stdout_pipe) < 0) {
550 fr_strerror_const("Failed opening pipe to read from child");
551
552 error2:
553 close(stdin_pipe[0]);
554 close(stdin_pipe[1]);
555 goto error1;
556 }
557 if (fr_nonblock(stdout_pipe[0]) < 0) fr_strerror_const("Error setting stdout to nonblock");
558 }
559
560 if (stderr_fd) {
561 if (pipe(stderr_pipe) < 0) {
562 fr_strerror_const("Failed opening pipe to read from child");
563
564 error3:
565 close(stdout_pipe[0]);
566 close(stdout_pipe[1]);
567 goto error2;
568 }
569 if (fr_nonblock(stderr_pipe[0]) < 0) fr_strerror_const("Error setting stderr to nonblock");
570 }
571
572 env = exec_build_env(env_in, env_inherit);
573 pid = fork();
574
575 /*
576 * The child never returns from calling exec_child();
577 */
578 if (pid == 0) exec_child(argv_in, env, true, debug, stdin_pipe, stdout_pipe, stderr_pipe);
579 if (pid < 0) {
580 fr_strerror_printf("Couldn't fork %s", argv_in[0]);
581 *pid_p = -1; /* Ensure the PID is set even if the caller didn't check the return code */
582 goto error3;
583 }
584
585 /*
586 * Tell the caller the childs PID, and the FD to read from.
587 */
588 *pid_p = pid;
589
590 if (stdin_fd) {
591 *stdin_fd = stdin_pipe[1];
592 close(stdin_pipe[0]);
593 }
594
595 if (stdout_fd) {
597 close(stdout_pipe[1]);
598 }
599
600 if (stderr_fd) {
602 close(stderr_pipe[1]);
603 }
604
605 return 0;
606}
607
608/** Similar to fr_exec_oneshot, but does not attempt to parse output
609 *
610 * @param[in] request currently being processed, may be NULL.
611 * @param[in] args to call as a fr_value_box_list_t. Program will
612 * be the first box and arguments in the subsequent boxes.
613 * @param[in] env_pairs list of pairs to be presented as environment variables
614 * to the child.
615 * @param[in] env_escape Wrap string values in double quotes, and apply doublequote
616 * escaping to all environmental variable values.
617 * @param[in] env_inherit Inherit the environment from the current process.
618 * This will be merged with any variables from env_pairs.
619 * @return
620 * - 0 on success.
621 * - -1 on error.
622 */
624 fr_value_box_list_t *args, fr_pair_list_t *env_pairs,
625 bool env_escape, bool env_inherit)
626{
627 char **argv = NULL;
628 char **env = NULL;
629 int ret;
630
632 RPEDEBUG("Failed converting boxes to argument strings");
633 return -1;
634 }
635
636 if (env_pairs) {
637 env = fr_exec_pair_to_env(request, env_pairs, env_escape);
638 if (unlikely(env == NULL)) {
639 RPEDEBUG("Failed creating environment pairs");
640 return -1;
641 }
642 }
643
644 if (RDEBUG_ENABLED3) exec_debug(request, argv, env, env_inherit);
645 ret = fr_exec_fork_nowait(unlang_interpret_event_list(request), argv, env,
647 talloc_free(argv);
648 if (unlikely(ret < 0)) RPEDEBUG("Failed executing program");
649
650 return ret;
651}
652
653/** Cleans up an exec'd process on error
654 *
655 * This function is intended to be called at any point after a successful
656 * #fr_exec_oneshot call in order to release resources and cleanup
657 * zombie processes.
658 *
659 * @param[in] exec state to cleanup.
660 * @param[in] signal If non-zero, and we think the process is still
661 * running, send it a signal to cause it to exit.
662 * The PID reaper we insert here will cleanup its
663 * state so it doesn't become a zombie.
664 *
665 */
667{
668 request_t *request = exec->request;
670
671 if (exec->pid >= 0) {
672 RDEBUG3("Cleaning up exec state for PID %u", exec->pid);
673 } else {
674 RDEBUG3("Cleaning up failed exec");
675 }
676
677 /*
678 * There's still an EV_PROC event installed
679 * for the PID remove it (there's a destructor).
680 */
681 if (exec->ev_pid) {
683 fr_assert(!exec->ev_pid); /* Should be NULLified by destructor */
684 }
685
686 if (exec->stdout_fd >= 0) {
688 RPERROR("Failed removing stdout handler");
689 }
690 close(exec->stdout_fd);
691 exec->stdout_fd = -1;
692 }
693
694 if (exec->stderr_fd >= 0) {
696 RPERROR("Failed removing stderr handler");
697 }
698 close(exec->stderr_fd);
699 exec->stderr_fd = -1;
700 }
701
702 if (exec->pid >= 0) {
703 if (signal > 0) kill(exec->pid, signal);
704
705 if (unlikely(fr_event_pid_reap(el, exec->pid, NULL, NULL) < 0)) {
706 int status;
707
708 RPERROR("Failed setting up async PID reaper, PID %u may now be a zombie", exec->pid);
709
710 /*
711 * Try and cleanup... really we have
712 * no idea what state things are in.
713 */
714 kill(exec->pid, SIGKILL);
715 waitpid(exec->pid, &status, WNOHANG);
716 }
717 exec->pid = -1;
718 }
719
720 if (exec->ev) fr_event_timer_delete(&exec->ev);
721}
722
723/*
724 * Callback when exec has completed. Record the status and tidy up.
725 */
726static void exec_reap(fr_event_list_t *el, pid_t pid, int status, void *uctx)
727{
728 fr_exec_state_t *exec = uctx; /* may not be talloced */
729 request_t *request = exec->request;
730 int wait_status = 0;
731 int ret;
732
733 if (!fr_cond_assert(pid == exec->pid)) RWDEBUG("Event PID %u and exec->pid %u do not match", pid, exec->pid);
734
735 /*
736 * Reap the process. This is needed so the processes
737 * don't stick around indefinitely. libkqueue/kqueue
738 * does not do this for us!
739 */
740 ret = waitpid(exec->pid, &wait_status, WNOHANG);
741 if (ret < 0) {
742 RWDEBUG("Failed reaping PID %i: %s", exec->pid, fr_syserror(errno));
743 /*
744 * Either something cleaned up the process before us
745 * (bad!), or the notification system is broken
746 * (also bad!)
747 *
748 * This could be caused by 3rd party libraries.
749 */
750 } else if (ret == 0) {
751 RWDEBUG("Something reaped PID %d before us!", exec->pid);
752 wait_status = status;
753 }
754
755 /*
756 * kevent should be returning an identical status value
757 * to waitpid.
758 */
759 if (wait_status != status) RWDEBUG("Exit status from waitpid (%d) and kevent (%d) disagree",
760 wait_status, status);
761
762 if (WIFEXITED(wait_status)) {
763 RDEBUG("Program exited with status code %d", WEXITSTATUS(wait_status));
764 exec->status = WEXITSTATUS(wait_status);
765 } else if (WIFSIGNALED(wait_status)) {
766 RDEBUG("Program exited due to signal with status code %d", WTERMSIG(wait_status));
767 exec->status = -WTERMSIG(wait_status);
768 } else {
769 RDEBUG("Program exited due to unknown status %d", wait_status);
770 exec->status = -wait_status;
771 }
772 exec->pid = -1; /* pid_t is signed */
773
774 if (exec->ev) fr_event_timer_delete(&exec->ev);
775
776 /*
777 * Process exit notifications (EV_PROC) and file
778 * descriptor read events (EV_READ) can race.
779 *
780 * So... If the process has exited, trigger the IO
781 * handlers manually.
782 *
783 * This is icky, but the only other option is to
784 * enhance our event loop so we can look for
785 * pending events associated with file
786 * descriptors...
787 *
788 * Even then we might get the file readable
789 * notification and the process exited notification
790 * in different kevent() calls on busy systems.
791 */
792 if (exec->stdout_fd >= 0) {
793 fr_event_fd_t *ef;
795
797 if (!fr_cond_assert_msg(ef, "no event associated with processes's stdout fd (%i)",
798 exec->stdout_fd)) goto close_stdout;
799
800 cb = fr_event_fd_cb(ef, EVFILT_READ, 0);
801 if (!fr_cond_assert_msg(cb, "no read callback associated with processes's stdout_fd (%i)",
802 exec->stdout_fd)) goto close_stdout;
803
804 /*
805 * Call the original read callback that
806 * was setup here to ensure that there's
807 * no pending data.
808 */
809 cb(el, exec->stdout_fd, 0, fr_event_fd_uctx(ef));
810
811 /*
812 * ...and delete the event from the event
813 * loop. This should also suppress the
814 * EVFILT_READ event if there was one.
815 */
817 close_stdout:
818 close(exec->stdout_fd);
819 exec->stdout_fd = -1;
820 }
821
822 if (exec->stderr_fd >= 0) {
823 fr_event_fd_t *ef;
825
827 if (!fr_cond_assert_msg(ef, "no event associated with processes's stderr fd (%i)",
828 exec->stderr_fd)) goto close_stderr;
829
830 cb = fr_event_fd_cb(ef, EVFILT_READ, 0);
831 if (!fr_cond_assert_msg(cb, "no read callback associated with processes's stderr_fd (%i)",
832 exec->stderr_fd)) goto close_stderr;
833
834 cb(el, exec->stderr_fd, 0, fr_event_fd_uctx(ef));
836 close_stderr:
837 close(exec->stderr_fd);
838 exec->stderr_fd = -1;
839 }
840
842}
843
844/*
845 * Callback when an exec times out.
846 */
847static void exec_timeout(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
848{
849 fr_exec_state_t *exec = uctx; /* may not be talloced */
850 bool exit_timeout;
851
852 /*
853 * Some race conditions cause fr_exec_oneshot_cleanup to insert
854 * a new event, which calls fr_strerror_clear(), resulting in
855 * inconsistent error messages.
856 * Recording the condition to drive the error message here and
857 * then setting after tidying up keeps things consistent.
858 */
859 exit_timeout = (exec->stdout_fd < 0);
860
862 fr_exec_oneshot_cleanup(exec, SIGKILL);
863
864 if (exit_timeout) {
865 fr_strerror_const("Timeout waiting for program to exit");
866 } else {
867 fr_strerror_const("Timeout running program");
868 }
869
871}
872
873/*
874 * Callback to read stdout from an exec into the pre-prepared extensible sbuff
875 */
876static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, int flags, void *uctx) {
877 fr_exec_state_t *exec = uctx;
878 request_t *request = exec->request;
879 ssize_t data_len, remaining;
880 fr_sbuff_marker_t start_m;
881
882 fr_sbuff_marker(&start_m, &exec->stdout_buff);
883
884 do {
885 /*
886 * Read in 128 byte chunks
887 */
888 remaining = fr_sbuff_extend_lowat(NULL, &exec->stdout_buff, 128);
889
890 /*
891 * Ran out of buffer space.
892 */
893 if (unlikely(!remaining)) {
894 REDEBUG("Too much output from program - killing it and failing the request");
895
896 error:
898 fr_exec_oneshot_cleanup(exec, SIGKILL);
899 break;
900 }
901
902 data_len = read(fd, fr_sbuff_current(&exec->stdout_buff), remaining);
903 if (data_len < 0) {
904 if (errno == EINTR) continue;
905
906 /*
907 * This can happen when the callback is called
908 * manually when we're reaping the process.
909 *
910 * It's pretty much an identical condition to
911 * data_len == 0.
912 */
913 if (errno == EWOULDBLOCK) break;
914
915 REDEBUG("Error reading from child program - %s", fr_syserror(errno));
916 goto error;
917 }
918
919 /*
920 * Even if we get 0 now the process may write more data later
921 * before it completes, so we leave the fd handlers in place.
922 */
923 if (data_len == 0) break;
924
925 fr_sbuff_advance(&exec->stdout_buff, data_len);
926 } while (remaining == data_len); /* If process returned maximum output, loop again */
927
928 if (flags & EV_EOF) {
929 /*
930 * We've received EOF - so the process has finished writing
931 * Remove event and tidy up
932 */
934 close(fd);
935 exec->stdout_fd = -1;
936
937 if (exec->pid < 0) {
938 /*
939 * Child has already exited - unlang can resume
940 */
941 if (exec->ev) fr_event_timer_delete(&exec->ev);
943 }
944 }
945
946 /*
947 * Only print if we got additional data
948 */
949 if (RDEBUG_ENABLED2 && fr_sbuff_behind(&start_m)) {
950 RDEBUG2("pid %u (stdout) - %pV", exec->pid,
952 }
953
954 fr_sbuff_marker_release(&start_m);
955}
956
957/** Call an child program, optionally reading it's output
958 *
959 * @note If the caller set need_stdin = true, it is the caller's
960 * responsibility to close exec->std_in and remove it from any event loops
961 * if this function returns 0 (success).
962 *
963 * @param[in] ctx to allocate events in.
964 * @param[in,out] exec structure holding the state of the external call.
965 * @param[in] request currently being processed, may be NULL.
966 * @param[in] args to call as a fr_value_box_list_t. Program will
967 * be the first box and arguments in the subsequent boxes.
968 * @param[in] env_pairs list of pairs to be presented as environment variables
969 * to the child.
970 * @param[in] env_escape Wrap string values in double quotes, and apply doublequote
971 * escaping to all environmental variable values.
972 * @param[in] env_inherit Inherit the environment from the current process.
973 * This will be merged with any variables from env_pairs.
974 * @param[in] need_stdin If true, allocate a pipe that will allow us to send data to the
975 * process.
976 * @param[in] store_stdout if true keep a copy of stdout in addition to logging
977 * it if RDEBUG_ENABLED2.
978 * @param[in] stdout_ctx ctx to alloc stdout data in.
979 * @param[in] timeout to wait for child to complete.
980 * @return
981 * - 0 on success
982 * - -1 on failure
983 */
984int fr_exec_oneshot(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request,
985 fr_value_box_list_t *args,
986 fr_pair_list_t *env_pairs, bool env_escape, bool env_inherit,
987 bool need_stdin,
988 bool store_stdout, TALLOC_CTX *stdout_ctx,
989 fr_time_delta_t timeout)
990{
991 int *stdout_fd = (store_stdout || RDEBUG_ENABLED2) ? &exec->stdout_fd : NULL;
993 char **env = NULL;
994 char **argv;
995 int ret;
996
998 RPEDEBUG("Failed converting boxes to argument strings");
999 return -1;
1000 }
1001
1002 if (env_pairs) {
1003 env = fr_exec_pair_to_env(request, env_pairs, env_escape);
1004 if (unlikely(!env)) {
1005 RPEDEBUG("Failed creating environment pairs");
1006 return -1;
1007 }
1008 }
1009
1010 if (RDEBUG_ENABLED3) exec_debug(request, argv, env, env_inherit);
1011 *exec = (fr_exec_state_t){
1012 .request = request,
1013 .env_pairs = env_pairs,
1014 .pid = -1,
1015 .stdout_fd = -1,
1016 .stderr_fd = -1,
1017 .stdin_fd = -1,
1018 .status = -1, /* default to program didn't work */
1019 .stdin_used = need_stdin,
1020 .stdout_used = store_stdout,
1021 .stdout_ctx = stdout_ctx
1022 };
1023 ret = fr_exec_fork_wait(&exec->pid,
1024 exec->stdin_used ? &exec->stdin_fd : NULL,
1025 stdout_fd, &exec->stderr_fd,
1026 argv, env,
1028 talloc_free(argv);
1029 if (ret < 0) {
1030 fail:
1031 RPEDEBUG("Failed executing program");
1032
1033 /*
1034 * Not done in fr_exec_oneshot_cleanup as it's
1035 * usually the caller's responsibility.
1036 */
1037 if (exec->stdin_fd >= 0) {
1038 close(exec->stdin_fd);
1039 exec->stdin_fd = -1;
1040 }
1041 fr_exec_oneshot_cleanup(exec, 0);
1042 return -1;
1043 }
1044
1045 /*
1046 * First setup I/O events for the child process. This needs
1047 * to be done before we call fr_event_pid_wait, as it may
1048 * immediately trigger the PID callback if there's a race
1049 * between kevent and the child exiting, and that callback
1050 * will expect file descriptor events to have been created.
1051 */
1052
1053 /*
1054 * If we need to parse stdout, insert a special IO handler that
1055 * aggregates all stdout data into an expandable buffer.
1056 */
1057 if (exec->stdout_used) {
1058 /*
1059 * Accept a maximum of 32k of data from the process.
1060 */
1061 fr_sbuff_init_talloc(exec->stdout_ctx, &exec->stdout_buff, &exec->stdout_tctx, 128, 32 * 1024);
1062 if (fr_event_fd_insert(ctx, NULL, el, exec->stdout_fd, exec_stdout_read, NULL, NULL, exec) < 0) {
1063 RPEDEBUG("Failed adding event listening to stdout");
1064 goto fail_and_close;
1065 }
1066
1067 /*
1068 * If the caller doesn't want the output box, we still want to copy stdout
1069 * into the request log if we're logging at a high enough level of verbosity.
1070 */
1071 } else if (RDEBUG_ENABLED2) {
1072 snprintf(exec->stdout_prefix, sizeof(exec->stdout_prefix), "pid %u (stdout)", exec->pid);
1074 .type = L_DBG,
1075 .lvl = L_DBG_LVL_2,
1076 .request = request,
1077 .prefix = exec->stdout_prefix
1078 };
1079
1080 if (fr_event_fd_insert(ctx, NULL, el, exec->stdout_fd, log_request_fd_event,
1081 NULL, NULL, &exec->stdout_uctx) < 0){
1082 RPEDEBUG("Failed adding event listening to stdout");
1083 goto fail_and_close;
1084 }
1085 }
1086
1087 /*
1088 * Send stderr to the request log as error messages with a custom prefix
1089 */
1090 snprintf(exec->stderr_prefix, sizeof(exec->stderr_prefix), "pid %u (stderr)", exec->pid);
1092 .type = L_DBG_ERR,
1093 .lvl = L_DBG_LVL_1,
1094 .request = request,
1095 .prefix = exec->stderr_prefix
1096 };
1097
1098 if (fr_event_fd_insert(ctx, NULL, el, exec->stderr_fd, log_request_fd_event,
1099 NULL, NULL, &exec->stderr_uctx) < 0) {
1100 RPEDEBUG("Failed adding event listening to stderr");
1101 close(exec->stderr_fd);
1102 exec->stderr_fd = -1;
1103 goto fail;
1104 }
1105
1106 /*
1107 * Tell the event loop that it needs to wait for this PID
1108 */
1109 if (fr_event_pid_wait(ctx, el, &exec->ev_pid, exec->pid, exec_reap, exec) < 0) {
1110 exec->pid = -1;
1111 RPEDEBUG("Failed adding watcher for child process");
1112
1113 fail_and_close:
1114 /*
1115 * Avoid spurious errors in fr_exec_oneshot_cleanup
1116 * when it tries to remove FDs from the
1117 * event loop that were never added.
1118 */
1119 if (exec->stdout_fd >= 0) {
1120 close(exec->stdout_fd);
1121 exec->stdout_fd = -1;
1122 }
1123
1124 if (exec->stderr_fd >= 0) {
1125 close(exec->stderr_fd);
1126 exec->stderr_fd = -1;
1127 }
1128
1129 goto fail;
1130 }
1131
1132 /*
1133 * Setup event to kill the child process after a period of time.
1134 */
1135 if (fr_time_delta_ispos(timeout) &&
1136 (fr_event_timer_in(ctx, el, &exec->ev, timeout, exec_timeout, exec) < 0)) goto fail_and_close;
1137
1138 return 0;
1139}
va_list args
Definition acutest.h:770
void fr_atexit_global_disarm_all(void)
Remove all global destructors (without executing them)
Definition atexit.c:259
#define fr_atexit_thread_local_disarm_all(...)
Definition atexit.h:232
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2400
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4610
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3328
static fr_slen_t in
Definition dict.h:824
#define fr_event_fd_insert(...)
Definition event.h:232
void(* fr_event_fd_cb_t)(fr_event_list_t *el, int fd, int flags, void *uctx)
Called when an IO event occurs on a file descriptor.
Definition event.h:137
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
#define fr_event_pid_reap(...)
Definition event.h:271
#define fr_event_pid_wait(...)
Definition event.h:265
#define fr_event_timer_in(...)
Definition event.h:255
int fr_exec_fork_wait(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_fd, char **argv_in, char **env_in, bool env_inherit, bool debug)
Execute a program assuming that the caller waits for it to finish.
Definition exec.c:528
static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, int flags, void *uctx)
Definition exec.c:876
int fr_exec_oneshot(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request, fr_value_box_list_t *args, fr_pair_list_t *env_pairs, bool env_escape, bool env_inherit, bool need_stdin, bool store_stdout, TALLOC_CTX *stdout_ctx, fr_time_delta_t timeout)
Call an child program, optionally reading it's output.
Definition exec.c:984
static int exec_pair_to_env(char **env_p, size_t env_len, fr_sbuff_t *env_sbuff, fr_sbuff_marker_t env_m[], request_t *request, fr_pair_list_t *env_pairs, bool env_escape)
Convert pairs from a request and a list of pairs into environmental variables.
Definition exec.c:125
static void exec_reap(fr_event_list_t *el, pid_t pid, int status, void *uctx)
Definition exec.c:726
int fr_exec_oneshot_nowait(request_t *request, fr_value_box_list_t *args, fr_pair_list_t *env_pairs, bool env_escape, bool env_inherit)
Similar to fr_exec_oneshot, but does not attempt to parse output.
Definition exec.c:623
static void exec_debug(request_t *request, char **argv_in, char **env_in, bool env_inherit)
Print debug information showing the arguments and environment for a process.
Definition exec.c:95
#define MAX_ENVP
Definition exec.c:37
static char ** exec_build_env(char **env_in, bool env_inherit)
Merge extra environmental variables and potentially the inherited environment.
Definition exec.c:401
static NEVER_RETURNS void exec_child(char **argv, char **envp, bool exec_wait, bool debug, int stdin_pipe[static 2], int stdout_pipe[static 2], int stderr_pipe[static 2])
Start a child process.
Definition exec.c:291
int fr_exec_fork_nowait(fr_event_list_t *el, char **argv_in, char **env_in, bool env_inherit, bool debug)
Execute a program without waiting for the program to finish.
Definition exec.c:461
int fr_exec_value_box_list_to_argv(TALLOC_CTX *ctx, char ***argv_p, fr_value_box_list_t const *in)
Flatten a list into individual "char *" argv-style array.
Definition exec.c:50
void fr_exec_oneshot_cleanup(fr_exec_state_t *exec, int signal)
Cleans up an exec'd process on error.
Definition exec.c:666
static _Thread_local char * env_exec_arr[MAX_ENVP]
Definition exec.c:39
static void exec_timeout(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Definition exec.c:847
char ** fr_exec_pair_to_env(request_t *request, fr_pair_list_t *env_pairs, bool env_escape)
Convert env_pairs into an array of environmental variables using thread local buffers.
Definition exec.c:258
fr_event_pid_t const * ev_pid
for cleaning up the process
Definition exec.h:73
request_t * request
request this exec is related to
Definition exec.h:82
char stderr_prefix[sizeof("pid -9223372036854775808 (stderr)")]
Definition exec.h:60
log_fd_event_ctx_t stdout_uctx
Config for the stdout logger.
Definition exec.h:57
int stderr_fd
for producing error messages.
Definition exec.h:70
log_fd_event_ctx_t stderr_uctx
Config for the stderr logger.
Definition exec.h:58
TALLOC_CTX * stdout_ctx
ctx to allocate output buffers
Definition exec.h:68
int stdout_fd
for reading from the child.
Definition exec.h:65
int stdin_fd
for writing to the child.
Definition exec.h:63
@ FR_EXEC_FAIL_TOO_MUCH_DATA
Definition exec.h:49
@ FR_EXEC_FAIL_TIMEOUT
Definition exec.h:50
char stdout_prefix[sizeof("pid -9223372036854775808 (stdout)")]
Definition exec.h:59
fr_sbuff_t stdout_buff
Expandable buffer to store process output.
Definition exec.h:54
pid_t pid
child PID
Definition exec.h:62
bool stdout_used
use stdout fd?
Definition exec.h:67
fr_sbuff_uctx_talloc_t stdout_tctx
sbuff talloc ctx data.
Definition exec.h:55
int status
return code of the program
Definition exec.h:76
bool stdin_used
use stdin fd?
Definition exec.h:64
fr_exec_fail_t failed
what kind of failure
Definition exec.h:74
fr_event_timer_t const * ev
for timing out the child
Definition exec.h:72
#define fr_closefrom
Definition exec_priv.h:81
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1359
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
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1764
void log_request_fd_event(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Function to provide as the readable callback to the event loop.
Definition log.c:956
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition log.h:258
#define DEBUG3(_fmt,...)
Definition log.h:266
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:528
#define RWDEBUG(fmt,...)
Definition log.h:361
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:335
#define RDEBUG3(fmt,...)
Definition log.h:343
#define ROPTIONAL_ENABLED(_e_request, _e_global)
Check if a debug level is set by the request (if !NULL) or by the global log.
Definition log.h:542
#define RPERROR(fmt,...)
Definition log.h:302
#define RPEDEBUG(fmt,...)
Definition log.h:376
fr_log_type_t type
What type of log message it is.
Definition log.h:84
Context structure for the log fd event function.
Definition log.h:83
waitpid(reap->pid_ev->pid, &status, 0)
fr_event_fd_cb_t fr_event_fd_cb(fr_event_fd_t *ef, int kq_filter, int kq_fflags)
Returns the appropriate callback function for a given event.
Definition event.c:1318
talloc_free(reap)
void * fr_event_fd_uctx(fr_event_fd_t *ef)
Returns the uctx associated with an fr_event_fd_t handle.
Definition event.c:1326
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition event.c:1611
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1260
fr_event_fd_t * fr_event_fd_handle(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Get the opaque event handle from a file descriptor.
Definition event.c:1296
A file descriptor/filter event.
Definition event.c:294
Stores all information relating to an event list.
Definition event.c:411
static FILE * devnull
File handle for /dev/null.
Definition log.c:59
static int stdout_fd
The original unmolested stdout file descriptor.
Definition log.c:51
static int stdout_pipe[2]
Pipe we use to transport stdout data.
Definition log.c:56
static int stderr_pipe[2]
Pipe we use to transport stderr data.
Definition log.c:57
static fr_log_fd_event_ctx_t stdout_ctx
Logging ctx for stdout.
Definition log.c:53
static int stderr_fd
The original unmolested stderr file descriptor.
Definition log.c:50
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition log.h:70
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:71
@ L_DBG_ERR
Error only displayed when debugging is enabled.
Definition log.h:62
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
int fr_nonblock(UNUSED int fd)
Definition misc.c:293
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define WIFEXITED(stat_val)
Definition radiusd.c:72
#define WEXITSTATUS(stat_val)
Definition radiusd.c:69
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1454
#define FR_SBUFF_BIND_CURRENT(_sbuff_or_marker)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_sbuff_behind(_sbuff_or_marker)
#define fr_sbuff_extend_lowat(_status, _sbuff_or_marker, _lowat)
#define fr_sbuff_in_char(_sbuff,...)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_pair_t * vp
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
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:224
#define fr_time_delta_ispos(_a)
Definition time.h:290
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
@ T_DOUBLE_QUOTED_STRING
Definition token.h:121
close(uq->fd)
static fr_event_list_t * el
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition pair.h:628
#define fr_pair_list_foreach_leaf(_list_head, _iter)
Iterate over the leaf nodes of a fr_pair_list_t.
Definition pair.h:272
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition value.c:5352
char * fr_value_box_list_aprint(TALLOC_CTX *ctx, fr_value_box_list_t const *list, char const *delim, fr_sbuff_escape_rules_t const *e_rules)
Concatenate the string representations of a list of value boxes together.
Definition value.c:6028
ssize_t fr_value_box_print_quoted(fr_sbuff_t *out, fr_value_box_t const *data, fr_token_t quote)
Print one boxed value to a string with quotes (where needed)
Definition value.c:5540
fr_sbuff_escape_rules_t fr_value_escape_unprintables
Definition value.c:455
#define fr_box_strvalue_len(_val, _len)
Definition value.h:286
int nonnull(2, 5))
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:206