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