23 RCSID(
"$Id: 6f73aefec22b48883c3198e421c6ef3030b187aa $")
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/rad_assert.h>
48 struct sigaction act, oact;
50 memset(&act, 0,
sizeof(act));
51 act.sa_handler = func;
52 sigemptyset(&act.sa_mask);
55 act.sa_flags |= SA_INTERRUPT;
57 if (sigaction(signo, &act, &oact) < 0)
59 return oact.sa_handler;
90 int rad_mkdir(
char *dir, mode_t mode, uid_t uid, gid_t gid)
106 rcode = mkdir(dir, 0700);
126 p = strrchr(dir, FR_DIR_SEP);
127 if (!p || (p == dir))
return -1;
131 if (rcode < 0)
return rcode;
138 rcode = mkdir(dir, 0700);
139 if (rcode < 0)
return rcode;
146 fd = open(dir, O_DIRECTORY);
147 if (fd < 0)
return -1;
149 rcode = fchmod(fd, mode);
155 if ((uid != (uid_t)-1) || (gid != (gid_t)-1)) {
157 rcode = fchown(fd, uid, gid);
179 size_t left = outlen;
234 if ((q[0] ==
'.') && (q[1] ==
'.') &&
271 size_t freespace = outlen;
273 while (*in !=
'\0') {
281 if (freespace <= (utf8_len * 3))
break;
285 snprintf(out, freespace,
"-%x-%x", in[0], in[1]);
289 snprintf(out, freespace,
"-%x-%x-%x", in[0], in[1], in[2]);
293 snprintf(out, freespace,
"-%x-%x-%x-%x", in[0], in[1], in[2], in[3]);
297 freespace -= (utf8_len * 3);
298 out += (utf8_len * 3);
307 if (((*in >=
'A') && (*in <=
'Z')) ||
308 ((*in >=
'a') && (*in <=
'z')) ||
309 ((*in >=
'0') && (*in <=
'9')) ||
311 if (freespace <= 1)
break;
317 if (freespace <= 2)
break;
341 return outlen - freespace;
356 char const *p, *end = in + inlen;
357 size_t freespace = outlen;
359 for (p = in; p < end; p++) {
360 if (freespace <= 1)
break;
362 if (((*p >=
'A') && (*p <=
'Z')) ||
363 ((*p >=
'a') && (*p <=
'z')) ||
364 ((*p >=
'0') && (*p <=
'9')) ||
376 if ((end - p) < 2)
return in - p;
388 if ((end - p) < 3)
return in - p;
393 if (
fr_hex2bin((uint8_t *) out, 1, in, 1) == 0)
return in - (p + 1);
403 return outlen - freespace;
413 void *ptr = malloc(size);
429 memcpy(&tmp, &ptr,
sizeof(tmp));
441 char *
rad_ajoin(TALLOC_CTX *ctx,
char const **argv,
int argc,
char c)
445 size_t total = 0, freespace;
451 for (i = 0; i < argc; i++) total += (strlen(argv[i]) + ((c ==
'\0') ? 0 : 1));
454 return talloc_zero_array(ctx,
char, 1);
457 if (c ==
'\0') total++;
460 buff = p = talloc_array(ctx,
char, total);
461 for (i = 0; i < argc; i++) {
464 len =
strlcpy(p, argv[i], freespace);
483 ERROR(
"ASSERT FAILED %s[%u]: %s", file, line, expr);
503 }
while (*from && (*from != quote));
505 if (*from != quote)
return -1;
525 while (*from && (*from != quote)) {
534 if (*from != quote)
return -1;
558 if (sublen < 0)
return sublen;
577 if (from[1] ==
'{') {
582 if (sublen < 0)
return sublen;
608 uint32_t
rad_pps(uint32_t *past, uint32_t *present, time_t *then,
struct timeval *now)
612 if (*then != now->tv_sec) {
636 pps =
USEC - now->tv_usec;
659 int max_argc,
char const *argv[],
bool can_fail,
660 size_t argv_buflen,
char *argv_buf)
668 if (strlen(cmd) > (argv_buflen - 1)) {
669 ERROR(
"rad_expand_xlat: Command line is too long");
676 if (cmd[strlen(cmd) - 1] ==
'\\') {
677 ERROR(
"rad_expand_xlat: Command line has final backslash, without a following character");
681 strlcpy(argv_buf, cmd, argv_buflen);
695 if ((*from ==
' ') || (*from ==
'\t')) {
703 if (argc >= (max_argc - 1))
break;
708 while (*from && (*from !=
' ') && (*from !=
'\t')) {
709 if (to >= argv_buf + argv_buflen - 1) {
710 ERROR(
"rad_expand_xlat: Ran out of space in command line");
719 ERROR(
"rad_expand_xlat: Invalid string passed as argument");
727 if (from[1] ==
'{') {
732 ERROR(
"rad_expand_xlat: Invalid variable expansion passed as argument");
743 if (from[1] ==
' ') from++;
758 ERROR(
"rad_expand_xlat: Empty command line");
765 left = argv_buf + argv_buflen - to;
766 for (i = 0; i < argc; i++) {
772 if (strchr(argv[i],
'%') == NULL)
continue;
774 if (!request)
continue;
776 sublen =
radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
787 ERROR(
"rad_expand_xlat: xlat failed");
799 ERROR(
"rad_expand_xlat: Ran out of space while expanding arguments");
877 fprintf(stderr,
"CONSISTENCY CHECK FAILED %s[%i]: RADIUS_PACKET %s pointer was NULL", file, line, type);
882 parent = talloc_parent(packet);
883 if (parent != request) {
884 ERROR(
"CONSISTENCY CHECK FAILED %s[%i]: Expected RADIUS_PACKET %s to be parented by %p (%s), "
885 "but parented by %p (%s)", file, line, type, request, talloc_get_name(request),
886 parent, parent ? talloc_get_name(parent) :
"NULL");
896 if (!packet->
vps)
return;
898 #ifdef WITH_VERIFY_PTR
899 fr_pair_list_verify(file, line, packet, packet->
vps);
908 fprintf(stderr,
"CONSISTENCY CHECK FAILED %s[%i]: REQUEST pointer was NULL", file, line);
913 (void) talloc_get_type_abort(request,
REQUEST);
915 #ifdef WITH_VERIFY_PTR
916 fr_pair_list_verify(file, line, request, request->
config);
917 fr_pair_list_verify(file, line, request->
state_ctx, request->
state);
931 (void) talloc_get_type_abort(request->
coa,
REQUEST);
932 parent = talloc_parent(request->
coa);
951 static char const *rwx[] = {
"---",
"--x",
"-w-",
"-wx",
"r--",
"r-x",
"rw-",
"rwx"};
953 strcpy(&out[0], rwx[(mode >> 6) & 0x07]);
954 strcpy(&out[3], rwx[(mode >> 3) & 0x07]);
955 strcpy(&out[6], rwx[(mode & 7)]);
956 if (mode & S_ISUID) out[2] = (mode & 0100) ?
's' :
'S';
957 if (mode & S_ISGID) out[5] = (mode & 0010) ?
's' :
'l';
958 if (mode & S_ISVTX) out[8] = (mode & 0100) ?
't' :
'T';
964 out[0] =
'0' + ((mode >> 9) & 0x07);
965 out[1] =
'0' + ((mode >> 6) & 0x07);
966 out[2] =
'0' + ((mode >> 3) & 0x07);
967 out[3] =
'0' + (mode & 0x07);
998 #ifdef _SC_GETPW_R_SIZE_MAX
1001 sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
1002 if (sc_len <= 0) sc_len = 1024;
1003 len = (size_t)sc_len;
1009 buff = talloc_array(ctx, uint8_t,
sizeof(
struct passwd) + len);
1010 if (!buff)
return -1;
1016 while ((ret = getpwuid_r(uid, (
struct passwd *)buff, (
char *)(buff +
sizeof(
struct passwd)),
1017 talloc_array_length(buff) -
sizeof(
struct passwd), out)) == ERANGE) {
1018 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1025 if ((ret != 0) || !*out) {
1032 talloc_set_type(buff,
struct passwd);
1033 *out = (
struct passwd *)buff;
1065 #ifdef _SC_GETPW_R_SIZE_MAX
1068 sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
1069 if (sc_len <= 0) sc_len = 1024;
1070 len = (size_t)sc_len;
1076 buff = talloc_array(ctx, uint8_t,
sizeof(
struct passwd) + len);
1077 if (!buff)
return -1;
1083 while ((ret = getpwnam_r(name, (
struct passwd *)buff, (
char *)(buff +
sizeof(
struct passwd)),
1084 talloc_array_length(buff) -
sizeof(
struct passwd), out)) == ERANGE) {
1085 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1092 if ((ret != 0) || !*out) {
1099 talloc_set_type(buff,
struct passwd);
1100 *out = (
struct passwd *)buff;
1132 #ifdef _SC_GETGR_R_SIZE_MAX
1135 sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1136 if (sc_len <= 0) sc_len = 1024;
1137 len = (size_t)sc_len;
1143 buff = talloc_array(ctx, uint8_t,
sizeof(
struct group) + len);
1144 if (!buff)
return -1;
1150 while ((ret = getgrgid_r(gid, (
struct group *)buff, (
char *)(buff +
sizeof(
struct group)),
1151 talloc_array_length(buff) -
sizeof(
struct group), out)) == ERANGE) {
1152 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1159 if ((ret != 0) || !*out) {
1166 talloc_set_type(buff,
struct group);
1167 *out = (
struct group *)buff;
1199 #ifdef _SC_GETGR_R_SIZE_MAX
1202 sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1203 if (sc_len <= 0) sc_len = 1024;
1204 len = (size_t)sc_len;
1210 buff = talloc_array(ctx, uint8_t,
sizeof(
struct group) + len);
1211 if (!buff)
return -1;
1217 while ((ret = getgrnam_r(name, (
struct group *)buff, (
char *)(buff +
sizeof(
struct group)),
1218 talloc_array_length(buff) -
sizeof(
struct group), out)) == ERANGE) {
1219 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1226 if ((ret != 0) || !*out) {
1233 talloc_set_type(buff,
struct group);
1234 *out = (
struct group *)buff;
1251 struct group *result;
1254 if (ret < 0)
return -1;
1256 *out = result->gr_gid;
1257 talloc_free(result);
1271 struct passwd *result;
1275 out = talloc_strdup(ctx, result->pw_name);
1276 talloc_free(result);
1290 struct group *result;
1294 out = talloc_strdup(ctx, result->gr_name);
1295 talloc_free(result);
1309 struct passwd *user = NULL;
1310 struct group *group = NULL;
1314 if (
rad_getpwuid(NULL, &user, geteuid()) < 0)
goto finish;
1315 if (
rad_getgrgid(NULL, &group, getegid()) < 0)
goto finish;
1317 fr_strerror_printf(
"Effective user/group %s:%s: %s", user->pw_name, group->gr_name, error);
1324 static bool doing_setuid =
false;
1325 static uid_t suid_down_uid = (uid_t)-1;
1335 suid_down_uid = uid;
1336 doing_setuid =
true;
1339 # if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
1342 uid_t ruid, euid, suid;
1344 if (getresuid(&ruid, &euid, &suid) < 0) {
1345 ERROR(
"Failed getting saved UID's");
1349 if (setresuid(-1, suid, -1) < 0) {
1350 ERROR(
"Failed switching to privileged user");
1354 if (geteuid() != suid) {
1355 ERROR(
"Switched to unknown UID");
1362 if (!doing_setuid)
return;
1364 if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
1365 struct passwd *passwd;
1368 name = (
rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ?
"unknown" : passwd->pw_name;
1370 talloc_free(passwd);
1374 if (geteuid() != suid_down_uid) {
1375 ERROR(
"Failed switching uid: UID is incorrect");
1384 if (!doing_setuid)
return;
1386 if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
1387 struct passwd *passwd;
1390 name = (
rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ?
"unknown" : passwd->pw_name;
1391 ERROR(
"Failed in permanent switch to uid %s: %s", name,
fr_syserror(errno));
1392 talloc_free(passwd);
1396 if (geteuid() != suid_down_uid) {
1397 ERROR(
"Switched to unknown uid");
1409 if (!doing_setuid)
return;
1411 if (seteuid(0) < 0) {
1420 if (!doing_setuid)
return;
1422 if (geteuid() == suid_down_uid)
return;
1424 if (seteuid(suid_down_uid) < 0) {
1425 struct passwd *passwd;
1428 name = (
rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ?
"unknown": passwd->pw_name;
1430 talloc_free(passwd);
1439 if (!doing_setuid)
return;
1444 if (getuid() == suid_down_uid)
return;
1450 if (geteuid() == suid_down_uid) {
1454 if (setuid(suid_down_uid) < 0) {
1455 struct passwd *passwd;
1458 name = (
rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ?
"unknown": passwd->pw_name;
1459 ERROR(
"Failed switching permanently to uid %s: %s", name,
fr_syserror(errno));
1460 talloc_free(passwd);
1493 if (seteuid(uid) < 0) {
1494 struct passwd *passwd;
1498 talloc_free(passwd);
1514 if (setegid(gid) < 0) {
1515 struct group *group;
char const * rad_radacct_dir(void)
Return the default radacct dir.
char * rad_asprint_gid(TALLOC_CTX *ctx, uid_t gid)
Print gid to a string.
void rad_mode_to_str(char out[10], mode_t mode)
Convert mode_t into humanly readable permissions flags.
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
int rad_expand_xlat(REQUEST *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.
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
Resolve a group name to a group database entry.
size_t rad_filename_escape(UNUSED REQUEST *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. ...
char const * rad_default_lib_dir(void)
Return the default lib dir.
void rad_suid_down_permanent(void)
int rad_copy_string_bare(char *to, char const *from)
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
int rad_segid(gid_t gid)
Alter the effective user id.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
int fr_log_talloc_report(TALLOC_CTX *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
int rad_copy_string(char *to, char const *from)
char const * rad_default_raddb_dir(void)
Return the default raddb dir.
char const * rad_default_sbin_dir(void)
Return the default sbin dir.
RADIUS_PACKET * proxy
Outgoing request to proxy server.
void rad_suid_set_down_uid(uid_t uid)
void verify_request(char const *file, int line, REQUEST *request)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
int rad_copy_variable(char *to, char const *from)
int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
Resolve a gid to a group database entry.
char * rad_asprint_uid(TALLOC_CTX *ctx, uid_t uid)
Print uid to a string.
void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
void fr_fault(int sig)
Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
Convert hex strings to binary data.
REQUEST * coa
CoA request originated by this request.
TALLOC_CTX * state_ctx
for request->state
uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
void * rad_malloc(size_t size)
int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
Resolve a group name to a GID.
RADIUS_PACKET * reply
Outgoing response.
char const * rad_default_log_dir(void)
Return the default log dir.
#define VERIFY_PACKET(_x)
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
char const * rad_default_run_dir(void)
Return the default run dir.
ssize_t rad_filename_unescape(char *out, size_t outlen, char const *in, size_t inlen)
Converts data stored in a file name back to its original form.
int rad_mkdir(char *dir, mode_t mode, uid_t uid, gid_t gid)
Create possibly many directories.
void rad_mode_to_oct(char out[5], mode_t mode)
char * rad_ajoin(TALLOC_CTX *ctx, char const **argv, int argc, char c)
talloc a buffer to hold the concatenated value of all elements of argv
int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
static void verify_packet(char const *file, int line, REQUEST *request, RADIUS_PACKET *packet, char const *type)
VALUE_PAIR * state
VALUE_PAIR (s) available over the lifetime of the authentication attempt.
size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Ensures that a filename cannot walk up the directory structure.
int rad_seuid(uid_t uid)
Alter the effective user id.
RADIUS_PACKET * packet
Incoming request.
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
void rad_const_free(void const *ptr)
void(*)(int) reset_signal(int signo, void(*func)(int))
size_t strlcpy(char *dst, char const *src, size_t siz)
int 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.
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
void rad_file_error(int num)
Write a file access error to the fr_strerror buffer, including euid/egid.