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