The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
util.c
Go to the documentation of this file.
1/*
2 * util.c Various utility functions.
3 *
4 * Version: $Id: be4a9c72971af73cbe419ba9c261ee267312856e $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20
21 */
22
23RCSID("$Id: be4a9c72971af73cbe419ba9c261ee267312856e $")
24
25#include <freeradius-devel/server/base.h>
26
27#include <freeradius-devel/util/base16.h>
28#include <freeradius-devel/util/skip.h>
29#include <freeradius-devel/util/perm.h>
30#include <freeradius-devel/util/cap.h>
31
32
33#include <fcntl.h>
34
35static bool suid_down_permanent = false; //!< Record whether we've permanently dropped privilledges
36
37/*
38 * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
39 * sa_flags, which causes grief if signal() is called in the
40 * handler before the cause of the signal has been cleared.
41 * (Infinite recursion).
42 *
43 * The same problem appears on HPUX, so we avoid it, if we can.
44 *
45 * Using sigaction() to reset the signal handler fixes the problem,
46 * so where available, we prefer that solution.
47 */
48
49void (*reset_signal(int signo, void (*func)(int)))(int)
50{
51#ifdef HAVE_SIGACTION
52 struct sigaction act, oact;
53
54 memset(&act, 0, sizeof(act));
55 act.sa_handler = func;
56 sigemptyset(&act.sa_mask);
57 act.sa_flags = 0;
58#ifdef SA_INTERRUPT /* SunOS */
59 act.sa_flags |= SA_INTERRUPT;
60#endif
61 if (sigaction(signo, &act, &oact) < 0)
62 return SIG_ERR;
63 return oact.sa_handler;
64#else
65
66 /*
67 * re-set by calling the 'signal' function, which
68 * may cause infinite recursion and core dumps due to
69 * stack growth.
70 *
71 * However, the system is too dumb to implement sigaction(),
72 * so we don't have a choice.
73 */
74 signal(signo, func);
75
76 return NULL;
77#endif
78}
79
80/** Ensures that a filename cannot walk up the directory structure
81 *
82 * Also sanitizes control chars.
83 *
84 * @param request Current request (may be NULL).
85 * @param out Output buffer.
86 * @param outlen Size of the output buffer.
87 * @param in string to escape.
88 * @param arg Context arguments (unused, should be NULL).
89 */
90ssize_t rad_filename_make_safe(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
91{
92 char const *q = in;
93 char *p = out, *end;
94
95 end = out + outlen;
96
97 while (*q) {
98 if (*q != '/') {
99 if ((size_t) (end - p) < 2) break;
100
101 /*
102 * Smash control characters and spaces to
103 * something simpler.
104 */
105 if (*q < ' ') {
106 *(p++) = '_';
107 q++;
108 continue;
109 }
110
111 *(p++) = *(q++);
112 continue;
113 }
114
115 /*
116 * For now, allow slashes in the expanded
117 * filename. This allows the admin to set
118 * attributes which create sub-directories.
119 * Unfortunately, it also allows users to send
120 * attributes which *may* end up creating
121 * sub-directories.
122 */
123 if ((size_t) (end - p) < 2) break;
124 *(p++) = *(q++);
125
126 /*
127 * Get rid of ////../.././///.///..//
128 */
129 redo:
130 /*
131 * Get rid of ////
132 */
133 if (*q == '/') {
134 q++;
135 goto redo;
136 }
137
138 /*
139 * Get rid of /./././
140 */
141 if ((q[0] == '.') &&
142 (q[1] == '/')) {
143 q += 2;
144 goto redo;
145 }
146
147 /*
148 * Get rid of /../../../
149 */
150 if ((q[0] == '.') && (q[1] == '.') &&
151 (q[2] == '/')) {
152 q += 3;
153 goto redo;
154 }
155 }
156 *p = '\0';
157
158 return (p - out);
159}
160
162{
163 char *escaped;
164 size_t len;
165
166 if (vb->vb_length == 0) return 0;
167
169
170 /*
171 * Allocate an output buffer, only ever the same or shorter than the input
172 */
173 MEM(escaped = talloc_array(vb, char, vb->vb_length + 1));
174
175 len = rad_filename_make_safe(NULL, escaped, (vb->vb_length + 1), vb->vb_strvalue, NULL);
176
177 fr_value_box_strdup_shallow_replace(vb, escaped, len);
178
179 return 0;
180}
181
182/** Escapes the raw string such that it should be safe to use as part of a file path
183 *
184 * This function is designed to produce a string that's still readable but portable
185 * across the majority of file systems.
186 *
187 * For security reasons it cannot remove characters from the name, and must not allow
188 * collisions to occur between different strings.
189 *
190 * With that in mind '-' has been chosen as the escape character, and will be double
191 * escaped '-' -> '--' to avoid collisions.
192 *
193 * Escaping should be reversible if the original string needs to be extracted.
194 *
195 * @note function takes additional arguments so that it may be used as an xlat escape
196 * function but it's fine to call it directly.
197 *
198 * @note OSX/Unix/NTFS/VFAT have a max filename size of 255 bytes.
199 *
200 * @param request Current request (may be NULL).
201 * @param out Output buffer.
202 * @param outlen Size of the output buffer.
203 * @param in string to escape.
204 * @param arg Context arguments (unused, should be NULL).
205 */
206ssize_t rad_filename_escape(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
207{
208 size_t freespace = outlen;
209
210 while (*in != '\0') {
211 size_t utf8_len;
212
213 /*
214 * Encode multibyte UTF8 chars
215 */
216 utf8_len = fr_utf8_char((uint8_t const *) in, -1);
217 if (utf8_len > 1) {
218 if (freespace <= (utf8_len * 3)) break;
219
220 switch (utf8_len) {
221 case 2:
222 snprintf(out, freespace, "-%x-%x", (uint8_t)in[0], (uint8_t)in[1]);
223 break;
224
225 case 3:
226 snprintf(out, freespace, "-%x-%x-%x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2]);
227 break;
228
229 case 4:
230 snprintf(out, freespace, "-%x-%x-%x-%x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2], (uint8_t)in[3]);
231 break;
232 }
233
234 freespace -= (utf8_len * 3);
235 out += (utf8_len * 3);
236 in += utf8_len;
237
238 continue;
239 }
240
241 /*
242 * Safe chars
243 */
244 if (((*in >= 'A') && (*in <= 'Z')) ||
245 ((*in >= 'a') && (*in <= 'z')) ||
246 ((*in >= '0') && (*in <= '9')) ||
247 (*in == '_')) {
248 if (freespace <= 1) break;
249
250 *out++ = *in++;
251 freespace--;
252 continue;
253 }
254 if (freespace <= 2) break;
255
256 /*
257 * Double escape '-' (like \\‍)
258 */
259 if (*in == '-') {
260 *out++ = '-';
261 *out++ = '-';
262
263 freespace -= 2;
264 in++;
265 continue;
266 }
267
268 /*
269 * Unsafe chars
270 */
271 *out++ = '-';
272 fr_base16_encode(&FR_SBUFF_OUT(out, freespace), &FR_DBUFF_TMP((uint8_t const *)in, 1));
273 in++;
274 out += 2;
275 freespace -= 3;
276 }
277 *out = '\0';
278
279 return outlen - freespace;
280}
281
283{
284 char *escaped;
285 size_t len;
286
287 if (vb->vb_length == 0) return 0;
288
290
291 /*
292 * Allocate an output buffer, if every character is escaped,
293 * it will be 3 times the input
294 */
295 MEM(escaped = talloc_array(vb, char, vb->vb_length * 3 + 1));
296
297 len = rad_filename_escape(NULL, escaped, (vb->vb_length * 3 + 1), vb->vb_strvalue, NULL);
298
299 /*
300 * If the escaped length == input length, no changes were done.
301 */
302 if (len == vb->vb_length) {
303 talloc_free(escaped);
304 return 0;
305 }
306
307 fr_value_box_strdup_shallow_replace(vb, escaped, len);
308
309 return 0;
310}
311
312
313/*
314 * Copy a quoted string.
315 */
316static int rad_copy_string(char *to, char const *from)
317{
318 int length = 0;
319 char quote = *from;
320
321 do {
322 if (*from == '\\') {
323 *(to++) = *(from++);
324 length++;
325 }
326 *(to++) = *(from++);
327 length++;
328 } while (*from && (*from != quote));
329
330 if (*from != quote) return -1; /* not properly quoted */
331
332 *(to++) = quote;
333 length++;
334 *to = '\0';
335
336 return length;
337}
338
339/*
340 * Copy a quoted string but without the quotes. The length
341 * returned is the number of chars written; the number of
342 * characters consumed is 2 more than this.
343 */
344static int rad_copy_string_bare(char *to, char const *from)
345{
346 int length = 0;
347 char quote = *from;
348
349 from++;
350 while (*from && (*from != quote)) {
351 if (*from == '\\') {
352 *(to++) = *(from++);
353 length++;
354 }
355 *(to++) = *(from++);
356 length++;
357 }
358
359 if (*from != quote) return -1; /* not properly quoted */
360
361 *to = '\0';
362
363 return length;
364}
365
366
367/*
368 * Copy a %{} string.
369 */
370static int rad_copy_variable(char *to, char const *from)
371{
372 int length = 0;
373 int sublen;
374
375 *(to++) = *(from++);
376 length++;
377
378 while (*from) {
379 switch (*from) {
380 case '"':
381 case '\'':
382 sublen = rad_copy_string(to, from);
383 if (sublen < 0) return sublen;
384 from += sublen;
385 to += sublen;
386 length += sublen;
387 break;
388
389 case '}': /* end of variable expansion */
390 *(to++) = *(from++);
391 *to = '\0';
392 length++;
393 return length; /* proper end of variable */
394
395 case '\\':
396 *(to++) = *(from++);
397 *(to++) = *(from++);
398 length += 2;
399 break;
400
401 case '%': /* start of variable expansion */
402 if (from[1] == '{') {
403 *(to++) = *(from++);
404 length++;
405
406 sublen = rad_copy_variable(to, from);
407 if (sublen < 0) return sublen;
408 from += sublen;
409 to += sublen;
410 length += sublen;
411 break;
412 } /* else FIXME: catch %%{ ?*/
413
415 default:
416 *(to++) = *(from++);
417 length++;
418 break;
419 }
420 } /* loop over the input string */
421
422 /*
423 * We ended the string before a trailing '}'
424 */
425
426 return -1;
427}
428
429uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
430{
431 uint32_t pps;
432
433 if (*then != now->tv_sec) {
434 *then = now->tv_sec;
435 *past = *present;
436 *present = 0;
437 }
438
439 /*
440 * Bootstrap PPS by looking at a percentage of
441 * the previous PPS. This lets us take a moving
442 * count, without doing a moving average. If
443 * we're a fraction "f" (0..1) into the current
444 * second, we can get a good guess for PPS by
445 * doing:
446 *
447 * PPS = pps_now + pps_old * (1 - f)
448 *
449 * It's an instantaneous measurement, rather than
450 * a moving average. This will hopefully let it
451 * respond better to sudden spikes.
452 *
453 * Doing the calculations by thousands allows us
454 * to not overflow 2^32, AND to not underflow
455 * when we divide by USEC.
456 */
457 pps = USEC - now->tv_usec; /* useconds left in previous second */
458 pps /= 1000; /* scale to milliseconds */
459 pps *= *past; /* multiply by past count to get fraction */
460 pps /= 1000; /* scale to usec again */
461 pps += *present; /* add in current count */
462
463 return pps;
464}
465
466/** Split string into words and expand each one
467 *
468 * @param request Current request.
469 * @param cmd string to split.
470 * @param max_argc the maximum number of arguments to split into.
471 * @param argv Where to write the pointers into argv_buf.
472 * @param can_fail If false, stop processing if any of the xlat expansions fail.
473 * @param argv_buflen size of argv_buf.
474 * @param argv_buf temporary buffer we used to mangle/expand cmd.
475 * Pointers to offsets of this buffer will be written to argv.
476 * @return argc or -1 on failure.
477 */
478
479int rad_expand_xlat(request_t *request, char const *cmd,
480 int max_argc, char const *argv[], bool can_fail,
481 size_t argv_buflen, char *argv_buf)
482{
483 char const *from;
484 char *to;
485 int argc = -1;
486 int i;
487 int left;
488 size_t len = strlen(cmd);
489
490 if (len > (argv_buflen - 1)) {
491 fr_strerror_const("Expansion string is too long for output buffer");
492 return -1;
493 }
494
495 /*
496 * Check for bad escapes.
497 */
498 if ((len > 0) && (cmd[len - 1] == '\\')) {
499 fr_strerror_const("Expansion string ends with a trailing backslash - invalid escape sequence");
500 return -1;
501 }
502
503 strlcpy(argv_buf, cmd, argv_buflen);
504
505 /*
506 * Split the string into argv's BEFORE doing xlat_eval...
507 */
508 from = cmd;
509 to = argv_buf;
510 argc = 0;
511 while (*from) {
512 int length;
513
514 fr_skip_whitespace(from);
515
516 argv[argc] = to;
517 argc++;
518
519 if (argc >= (max_argc - 1)) break;
520
521 /*
522 * Copy the argv over to our buffer.
523 */
524 while (*from && (*from != ' ') && (*from != '\t')) {
525 if (to >= argv_buf + argv_buflen - 1) {
526 fr_strerror_const("Expansion string is too long for output buffer");
527 return -1;
528 }
529
530 switch (*from) {
531 case '"':
532 case '\'':
533 length = rad_copy_string_bare(to, from);
534 if (length < 0) {
535 fr_strerror_const("Invalid quoted string in expansion");
536 return -1;
537 }
538 from += length+2;
539 to += length;
540 break;
541
542 case '%':
543 if (from[1] == '{') {
544 *(to++) = *(from++);
545
546 length = rad_copy_variable(to, from);
547 if (length < 0) {
548 fr_strerror_const("Invalid variable in expansion");
549 return -1;
550 }
551 from += length;
552 to += length;
553 } else { /* FIXME: catch %%{ ? */
554 *(to++) = *(from++);
555 }
556 break;
557
558 case '\\':
559 if (from[1] == ' ') from++;
561
562 default:
563 *(to++) = *(from++);
564 }
565 } /* end of string, or found a space */
566
567 *(to++) = '\0'; /* terminate the string */
568 }
569
570 /*
571 * We have to have SOMETHING, at least.
572 */
573 if (argc <= 0) {
574 fr_strerror_const("Expansion string is empty");
575 return -1;
576 }
577
578 /*
579 * Expand each string, as appropriate.
580 */
581 left = argv_buf + argv_buflen - to;
582 for (i = 0; i < argc; i++) {
583 int sublen;
584
585 /*
586 * Don't touch argv's which won't be translated.
587 */
588 if (strchr(argv[i], '%') == NULL) continue;
589
590 if (!request) continue;
591
592 sublen = xlat_eval(to, left - 1, request, argv[i], NULL, NULL);
593 if (sublen <= 0) {
594 if (can_fail) {
595 /*
596 * Fail to be backwards compatible.
597 *
598 * It's yucky, but it won't break anything,
599 * and it won't cause security problems.
600 */
601 sublen = 0;
602 } else {
603 fr_strerror_const("Failed expanding substring");
604 return -1;
605 }
606 }
607
608 argv[i] = to;
609 to += sublen;
610 *(to++) = '\0';
611 left -= sublen;
612 left--;
613
614 if (left <= 0) {
615 fr_strerror_const("Ran out of space while expanding arguments");
616 return -1;
617 }
618 }
619 argv[argc] = NULL;
620
621 return argc;
622}
623
624#ifdef HAVE_SETUID
625static bool doing_setuid = false;
626static uid_t suid_down_uid = (uid_t)-1;
627
628/** Set the uid and gid used when dropping privileges
629 *
630 * @note if this function hasn't been called, rad_suid_down will have no effect.
631 *
632 * @param uid to drop down to.
633 */
634void rad_suid_set_down_uid(uid_t uid)
635{
636 suid_down_uid = uid;
637 doing_setuid = true;
638}
639
640# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
641void rad_suid_up(void)
642{
643 uid_t ruid, euid, suid;
644
645 if (getresuid(&ruid, &euid, &suid) < 0) {
646 ERROR("Failed getting saved UID's");
647 fr_exit_now(EXIT_FAILURE);
648 }
649
650 if (setresuid(-1, suid, -1) < 0) {
651 ERROR("Failed switching to privileged user");
652 fr_exit_now(EXIT_FAILURE);
653 }
654
655 if (geteuid() != suid) {
656 ERROR("Switched to unknown UID");
657 fr_exit_now(EXIT_FAILURE);
658 }
659}
660
661void rad_suid_down(void)
662{
663 if (!doing_setuid) return;
664
665 if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
666 struct passwd *passwd;
667 char const *name;
668
669 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
670 ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno));
671 talloc_free(passwd);
672 fr_exit_now(EXIT_FAILURE);
673 }
674
675 if (geteuid() != suid_down_uid) {
676 ERROR("Failed switching uid: UID is incorrect");
677 fr_exit_now(EXIT_FAILURE);
678 }
679
681}
682
684{
685 if (!doing_setuid) return;
686
687 if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
688 struct passwd *passwd;
689 char const *name;
690
691 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
692 ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno));
693 talloc_free(passwd);
694 fr_exit_now(EXIT_FAILURE);
695 }
696
697 if (geteuid() != suid_down_uid) {
698 ERROR("Switched to unknown uid");
699 fr_exit_now(EXIT_FAILURE);
700 }
701
702 /*
703 * Shut down most of the interesting things which might get abused.
704 */
708 ERROR("Failed disabling CAP_SUID");
709 fr_exit_now(EXIT_FAILURE);
710 }
711
712#ifdef HAVE_GRP_H
716 ERROR("Failed disabling CAP_SGID");
717 fr_exit_now(EXIT_FAILURE);
718 }
719#endif
720
722
723 suid_down_permanent = true;
724}
725# else
726/*
727 * Much less secure...
728 */
729void rad_suid_up(void)
730{
731 if (!doing_setuid) return;
732
733 if (seteuid(0) < 0) {
734 ERROR("Failed switching up to euid 0: %s", fr_syserror(errno));
735 fr_exit_now(EXIT_FAILURE);
736 }
737
738}
739
740void rad_suid_down(void)
741{
742 if (!doing_setuid) return;
743
744 if (geteuid() == suid_down_uid) return;
745
746 if (seteuid(suid_down_uid) < 0) {
747 struct passwd *passwd;
748 char const *name;
749
750 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
751 ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno));
752 talloc_free(passwd);
753 fr_exit_now(EXIT_FAILURE);
754 }
755
757}
758
760{
761 if (!doing_setuid) return;
762
763 /*
764 * Already done. Don't do anything else.
765 */
766 if (getuid() == suid_down_uid) return;
767
768 /*
769 * We're root, but running as a normal user. Fix that,
770 * so we can call setuid().
771 */
772 if (geteuid() == suid_down_uid) {
773 rad_suid_up();
774 }
775
776 if (setuid(suid_down_uid) < 0) {
777 struct passwd *passwd;
778 char const *name;
779
780 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
781 ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno));
782 talloc_free(passwd);
783 fr_exit_now(EXIT_FAILURE);
784 }
785
787
788 suid_down_permanent = true;
789}
790# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
791#else /* HAVE_SETUID */
793{
794}
795
796void rad_suid_up(void)
797{
798}
799
801{
803}
804
806{
808}
809#endif /* HAVE_SETUID */
810
811/** Return whether we've permanently dropped root privileges
812 *
813 * @return
814 * - true if root privileges have been dropped.
815 * - false if root privileges have not been dropped.
816 */
818{
819 return suid_down_permanent;
820}
821
822/** Alter the effective user id
823 *
824 * @param uid to set
825 * @return
826 * - 0 on success.
827 * - -1 on failure.
828 */
829int rad_seuid(uid_t uid)
830{
831 if (seteuid(uid) < 0) {
832 int sete_errno = errno; /* errno sets overwritten by fr_perm_getpwuid */
833 struct passwd *passwd;
834
835 if (fr_perm_getpwuid(NULL, &passwd, uid) < 0) return -1;
836 fr_strerror_printf("%s", fr_syserror(sete_errno));
837 talloc_free(passwd);
838
839 return -1;
840 }
841 return 0;
842}
843
844/** Alter the effective user id
845 *
846 * @param gid to set
847 * @return
848 * - 0 on success.
849 * - -1 on failure.
850 */
851int rad_segid(gid_t gid)
852{
853 if (setegid(gid) < 0) {
854 int sete_errno = errno; /* errno sets overwritten by fr_perm_getgrgid */
855 struct group *group;
856
857 if (fr_perm_getgrgid(NULL, &group, gid) < 0) return -1;
858 fr_strerror_printf("%s", fr_syserror(sete_errno));
859 talloc_free(group);
860
861 return -1;
862 }
863 return 0;
864}
#define fr_base16_encode(_out, _in)
Definition base16.h:57
#define RCSID(id)
Definition build.h:487
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define UNUSED
Definition build.h:317
#define CAP_SETGID
Definition cap.h:54
#define CAP_PERMITTED
Definition cap.h:51
#define CAP_SETUID
Definition cap.h:53
#define CAP_EFFECTIVE
Definition cap.h:49
#define fr_cap_disable(_x, _y)
Definition cap.h:57
#define CAP_INHERITABLE
Definition cap.h:50
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:743
#define MEM(x)
Definition debug.h:36
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:226
#define ERROR(fmt,...)
Definition dhcpclient.c:41
static fr_slen_t in
Definition dict.h:884
talloc_free(hp)
ssize_t rad_filename_make_safe(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Ensures that a filename cannot walk up the directory structure.
Definition util.c:90
void rad_suid_up(void)
Definition util.c:796
bool rad_suid_is_down_permanent(void)
Return whether we've permanently dropped root privileges.
Definition util.c:817
static int rad_copy_string(char *to, char const *from)
Definition util.c:316
static int rad_copy_variable(char *to, char const *from)
Definition util.c:370
void(*)(int) reset_signal(int signo, void(*func)(int))
Definition util.c:49
int rad_segid(gid_t gid)
Alter the effective user id.
Definition util.c:851
uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
Definition util.c:429
int rad_filename_box_escape(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:282
static bool suid_down_permanent
Record whether we've permanently dropped privilledges.
Definition util.c:35
void rad_suid_down(void)
Definition util.c:800
int rad_filename_box_make_safe(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:161
int rad_expand_xlat(request_t *request, char const *cmd, int max_argc, char const *argv[], bool can_fail, size_t argv_buflen, char *argv_buf)
Split string into words and expand each one.
Definition util.c:479
ssize_t rad_filename_escape(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escapes the raw string such that it should be safe to use as part of a file path.
Definition util.c:206
void rad_suid_down_permanent(void)
Definition util.c:805
static int rad_copy_string_bare(char *to, char const *from)
Definition util.c:344
int rad_seuid(uid_t uid)
Alter the effective user id.
Definition util.c:829
void rad_suid_set_down_uid(uid_t uid)
Definition util.c:792
unsigned int uint32_t
long int ssize_t
ssize_t xlat_eval(char *out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
unsigned char uint8_t
int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
Resolve a gid to a group database entry.
Definition perm.c:329
int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
Definition perm.c:203
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
Definition print.c:39
#define fr_assert(_expr)
Definition rad_assert.h:38
static char const * name
#define FR_SBUFF_OUT(_start, _len_or_end)
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:36
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition strlcpy.c:34
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define USEC
Definition time.h:380
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
void fr_value_box_strdup_shallow_replace(fr_value_box_t *vb, char const *src, ssize_t len)
Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one.
Definition value.c:4760
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1094
static size_t char ** out
Definition value.h:1024