23RCSID(
"$Id: cbf993c0768de18dfcebacd279738fcfe7f8fe4f $")
25#include <freeradius-devel/server/base.h>
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>
52 struct sigaction act, oact;
54 memset(&act, 0,
sizeof(act));
55 act.sa_handler = func;
56 sigemptyset(&act.sa_mask);
59 act.sa_flags |= SA_INTERRUPT;
61 if (sigaction(signo, &act, &oact) < 0)
63 return oact.sa_handler;
136 if (vb->vb_length == 0)
return 0;
143 MEM(escaped = talloc_array(vb,
char, vb->vb_length + 1));
180 size_t freespace = outlen;
182 while (*
in !=
'\0') {
190 if (freespace <= (utf8_len * 3))
break;
206 freespace -= (utf8_len * 3);
207 out += (utf8_len * 3);
216 if (((*
in >=
'A') && (*
in <=
'Z')) ||
217 ((*
in >=
'a') && (*
in <=
'z')) ||
218 ((*
in >=
'0') && (*
in <=
'9')) ||
220 if (freespace <= 1)
break;
226 if (freespace <= 2)
break;
250 return outlen - freespace;
258 if (vb->vb_length == 0)
return 0;
266 MEM(escaped = talloc_array(vb,
char, vb->vb_length * 3 + 1));
273 if (len == vb->vb_length) {
299 }
while (*from && (*from != quote));
301 if (*from != quote)
return -1;
321 while (*from && (*from != quote)) {
330 if (*from != quote)
return -1;
354 if (sublen < 0)
return sublen;
373 if (from[1] ==
'{') {
378 if (sublen < 0)
return sublen;
404 if (*then != now->tv_sec) {
428 pps =
USEC - now->tv_usec;
451 int max_argc,
char const *argv[],
bool can_fail,
452 size_t argv_buflen,
char *argv_buf)
459 size_t len = strlen(cmd);
461 if (len > (argv_buflen - 1)) {
469 if ((len > 0) && (cmd[len - 1] ==
'\\')) {
470 fr_strerror_const(
"Expansion string ends with a trailing backslash - invalid escape sequence");
474 strlcpy(argv_buf, cmd, argv_buflen);
490 if (argc >= (max_argc - 1))
break;
495 while (*from && (*from !=
' ') && (*from !=
'\t')) {
496 if (to >= argv_buf + argv_buflen - 1) {
514 if (from[1] ==
'{') {
530 if (from[1] ==
' ') from++;
552 left = argv_buf + argv_buflen - to;
553 for (i = 0; i < argc; i++) {
559 if (strchr(argv[i],
'%') == NULL)
continue;
561 if (!request)
continue;
563 sublen =
xlat_eval(to, left - 1, request, argv[i], NULL, NULL);
596static bool doing_setuid =
false;
597static uid_t suid_down_uid = (uid_t)-1;
611# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
614 uid_t ruid, euid, suid;
616 if (getresuid(&ruid, &euid, &suid) < 0) {
617 ERROR(
"Failed getting saved UID's");
621 if (setresuid(-1, suid, -1) < 0) {
622 ERROR(
"Failed switching to privileged user");
626 if (geteuid() != suid) {
627 ERROR(
"Switched to unknown UID");
634 if (!doing_setuid)
return;
636 if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
637 struct passwd *passwd;
646 if (geteuid() != suid_down_uid) {
647 ERROR(
"Failed switching uid: UID is incorrect");
656 if (!doing_setuid)
return;
658 if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
659 struct passwd *passwd;
668 if (geteuid() != suid_down_uid) {
669 ERROR(
"Switched to unknown uid");
679 ERROR(
"Failed disabling CAP_SUID");
687 ERROR(
"Failed disabling CAP_SGID");
702 if (!doing_setuid)
return;
704 if (seteuid(0) < 0) {
713 if (!doing_setuid)
return;
715 if (geteuid() == suid_down_uid)
return;
717 if (seteuid(suid_down_uid) < 0) {
718 struct passwd *passwd;
732 if (!doing_setuid)
return;
737 if (getuid() == suid_down_uid)
return;
743 if (geteuid() == suid_down_uid) {
747 if (setuid(suid_down_uid) < 0) {
748 struct passwd *passwd;
802 if (seteuid(uid) < 0) {
803 int sete_errno = errno;
804 struct passwd *passwd;
824 if (setegid(gid) < 0) {
825 int sete_errno = errno;
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define fr_cap_disable(_x, _y)
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
bool rad_suid_is_down_permanent(void)
Return whether we've permanently dropped root privileges.
static int rad_copy_string(char *to, char const *from)
static int rad_copy_variable(char *to, char const *from)
void(*)(int) reset_signal(int signo, void(*func)(int))
int rad_segid(gid_t gid)
Alter the effective user id.
uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
static ssize_t rad_filename_make_safe(char *out, char const *in, size_t len)
Ensures that a filename cannot walk up the directory structure.
int rad_filename_box_escape(fr_value_box_t *vb, UNUSED void *uxtc)
static bool suid_down_permanent
Record whether we've permanently dropped privilledges.
int rad_filename_box_make_safe(fr_value_box_t *vb, UNUSED void *uxtc)
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.
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.
void rad_suid_down_permanent(void)
static int rad_copy_string_bare(char *to, char const *from)
int rad_seuid(uid_t uid)
Alter the effective user id.
void rad_suid_set_down_uid(uid_t uid)
ssize_t xlat_eval(char *out, size_t outlen, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx)
int fr_perm_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
Resolve a gid to a group database entry.
int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
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.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
size_t strlcpy(char *dst, char const *src, size_t siz)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
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.
#define fr_value_box_mark_safe_for(_box, _safe_for)
#define fr_value_box_is_safe_for(_box, _safe_for)
static size_t char ** out