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: cbf993c0768de18dfcebacd279738fcfe7f8fe4f $
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: cbf993c0768de18dfcebacd279738fcfe7f8fe4f $")
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 out Output buffer.
85 * @param in string to escape.
86 * @param len Size of the output buffer.
87 */
88static ssize_t rad_filename_make_safe(char *out, char const *in, size_t len)
89{
90 char const *q, *end;
91 char *p = out;
92
93 q = in;
94 end = in + len;
95
96 /*
97 * Escape '.foo', as it could be used to either read the local directory, walk back up the
98 * directory hierarchy, or else to create "dot" files.
99 */
100 if (len > 1) {
101 if (*q == '.') {
102 *(p++) = '_';
103 q++;
104 }
105 }
106
107 while (q < end) {
108 if (*q < ' ') {
109 *(p++) = '_';
110 q++;
111 continue;
112 }
113
114 if (*q != '/') {
115 *(p++) = *(q++);
116 continue;
117 }
118
119 /*
120 * Mash slashes, too.
121 */
122 *(p++) = '_';
123 q++;
124 continue;
125 }
126 *p = '\0';
127
128 return (p - out);
129}
130
132{
133 char *escaped;
134 size_t len;
135
136 if (vb->vb_length == 0) return 0;
137
139
140 /*
141 * Allocate an output buffer, only ever the same or shorter than the input
142 */
143 MEM(escaped = talloc_array(vb, char, vb->vb_length + 1));
144
145 len = rad_filename_make_safe(escaped, vb->vb_strvalue, vb->vb_length);
146
147 fr_value_box_strdup_shallow_replace(vb, escaped, len);
148
150
151 return 1;
152}
153
154/** Escapes the raw string such that it should be safe to use as part of a file path
155 *
156 * This function is designed to produce a string that's still readable but portable
157 * across the majority of file systems.
158 *
159 * For security reasons it cannot remove characters from the name, and must not allow
160 * collisions to occur between different strings.
161 *
162 * With that in mind '-' has been chosen as the escape character, and will be double
163 * escaped '-' -> '--' to avoid collisions.
164 *
165 * Escaping should be reversible if the original string needs to be extracted.
166 *
167 * @note function takes additional arguments so that it may be used as an xlat escape
168 * function but it's fine to call it directly.
169 *
170 * @note OSX/Unix/NTFS/VFAT have a max filename size of 255 bytes.
171 *
172 * @param request Current request (may be NULL).
173 * @param out Output buffer.
174 * @param outlen Size of the output buffer.
175 * @param in string to escape.
176 * @param arg Context arguments (unused, should be NULL).
177 */
178ssize_t rad_filename_escape(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
179{
180 size_t freespace = outlen;
181
182 while (*in != '\0') {
183 size_t utf8_len;
184
185 /*
186 * Encode multibyte UTF8 chars
187 */
188 utf8_len = fr_utf8_char((uint8_t const *) in, -1);
189 if (utf8_len > 1) {
190 if (freespace <= (utf8_len * 3)) break;
191
192 switch (utf8_len) {
193 case 2:
194 snprintf(out, freespace, "-%02x-%02x", (uint8_t)in[0], (uint8_t)in[1]);
195 break;
196
197 case 3:
198 snprintf(out, freespace, "-%02x-%02x-%02x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2]);
199 break;
200
201 case 4:
202 snprintf(out, freespace, "-%02x-%02x-%02x-%02x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2], (uint8_t)in[3]);
203 break;
204 }
205
206 freespace -= (utf8_len * 3);
207 out += (utf8_len * 3);
208 in += utf8_len;
209
210 continue;
211 }
212
213 /*
214 * Safe chars
215 */
216 if (((*in >= 'A') && (*in <= 'Z')) ||
217 ((*in >= 'a') && (*in <= 'z')) ||
218 ((*in >= '0') && (*in <= '9')) ||
219 (*in == '_')) {
220 if (freespace <= 1) break;
221
222 *out++ = *in++;
223 freespace--;
224 continue;
225 }
226 if (freespace <= 2) break;
227
228 /*
229 * Double escape '-' (like \\‍)
230 */
231 if (*in == '-') {
232 *out++ = '-';
233 *out++ = '-';
234
235 freespace -= 2;
236 in++;
237 continue;
238 }
239
240 /*
241 * Unsafe chars get escaped as -XX.
242 */
243 snprintf(out, freespace, "-%02x", (uint8_t) in[0]);
244 in++;
245 out += 3;
246 freespace -= 3;
247 }
248 *out = '\0';
249
250 return outlen - freespace;
251}
252
254{
255 char *escaped;
256 size_t len;
257
258 if (vb->vb_length == 0) return 0;
259
261
262 /*
263 * Allocate an output buffer, if every character is escaped,
264 * it will be 3 times the input
265 */
266 MEM(escaped = talloc_array(vb, char, vb->vb_length * 3 + 1));
267
268 len = rad_filename_escape(NULL, escaped, (vb->vb_length * 3 + 1), vb->vb_strvalue, NULL);
269
270 /*
271 * If the escaped length == input length, no changes were done.
272 */
273 if (len == vb->vb_length) {
274 talloc_free(escaped);
275 return 0;
276 }
277
278 fr_value_box_strdup_shallow_replace(vb, escaped, len);
279
280 return 0;
281}
282
283
284/*
285 * Copy a quoted string.
286 */
287static int rad_copy_string(char *to, char const *from)
288{
289 int length = 0;
290 char quote = *from;
291
292 do {
293 if (*from == '\\') {
294 *(to++) = *(from++);
295 length++;
296 }
297 *(to++) = *(from++);
298 length++;
299 } while (*from && (*from != quote));
300
301 if (*from != quote) return -1; /* not properly quoted */
302
303 *(to++) = quote;
304 length++;
305 *to = '\0';
306
307 return length;
308}
309
310/*
311 * Copy a quoted string but without the quotes. The length
312 * returned is the number of chars written; the number of
313 * characters consumed is 2 more than this.
314 */
315static int rad_copy_string_bare(char *to, char const *from)
316{
317 int length = 0;
318 char quote = *from;
319
320 from++;
321 while (*from && (*from != quote)) {
322 if (*from == '\\') {
323 *(to++) = *(from++);
324 length++;
325 }
326 *(to++) = *(from++);
327 length++;
328 }
329
330 if (*from != quote) return -1; /* not properly quoted */
331
332 *to = '\0';
333
334 return length;
335}
336
337
338/*
339 * Copy a %{} string.
340 */
341static int rad_copy_variable(char *to, char const *from)
342{
343 int length = 0;
344 int sublen;
345
346 *(to++) = *(from++);
347 length++;
348
349 while (*from) {
350 switch (*from) {
351 case '"':
352 case '\'':
353 sublen = rad_copy_string(to, from);
354 if (sublen < 0) return sublen;
355 from += sublen;
356 to += sublen;
357 length += sublen;
358 break;
359
360 case '}': /* end of variable expansion */
361 *(to++) = *(from++);
362 *to = '\0';
363 length++;
364 return length; /* proper end of variable */
365
366 case '\\':
367 *(to++) = *(from++);
368 *(to++) = *(from++);
369 length += 2;
370 break;
371
372 case '%': /* start of variable expansion */
373 if (from[1] == '{') {
374 *(to++) = *(from++);
375 length++;
376
377 sublen = rad_copy_variable(to, from);
378 if (sublen < 0) return sublen;
379 from += sublen;
380 to += sublen;
381 length += sublen;
382 break;
383 } /* else FIXME: catch %%{ ?*/
384
386 default:
387 *(to++) = *(from++);
388 length++;
389 break;
390 }
391 } /* loop over the input string */
392
393 /*
394 * We ended the string before a trailing '}'
395 */
396
397 return -1;
398}
399
400uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
401{
402 uint32_t pps;
403
404 if (*then != now->tv_sec) {
405 *then = now->tv_sec;
406 *past = *present;
407 *present = 0;
408 }
409
410 /*
411 * Bootstrap PPS by looking at a percentage of
412 * the previous PPS. This lets us take a moving
413 * count, without doing a moving average. If
414 * we're a fraction "f" (0..1) into the current
415 * second, we can get a good guess for PPS by
416 * doing:
417 *
418 * PPS = pps_now + pps_old * (1 - f)
419 *
420 * It's an instantaneous measurement, rather than
421 * a moving average. This will hopefully let it
422 * respond better to sudden spikes.
423 *
424 * Doing the calculations by thousands allows us
425 * to not overflow 2^32, AND to not underflow
426 * when we divide by USEC.
427 */
428 pps = USEC - now->tv_usec; /* useconds left in previous second */
429 pps /= 1000; /* scale to milliseconds */
430 pps *= *past; /* multiply by past count to get fraction */
431 pps /= 1000; /* scale to usec again */
432 pps += *present; /* add in current count */
433
434 return pps;
435}
436
437/** Split string into words and expand each one
438 *
439 * @param request Current request.
440 * @param cmd string to split.
441 * @param max_argc the maximum number of arguments to split into.
442 * @param argv Where to write the pointers into argv_buf.
443 * @param can_fail If false, stop processing if any of the xlat expansions fail.
444 * @param argv_buflen size of argv_buf.
445 * @param argv_buf temporary buffer we used to mangle/expand cmd.
446 * Pointers to offsets of this buffer will be written to argv.
447 * @return argc or -1 on failure.
448 */
449
450int rad_expand_xlat(request_t *request, char const *cmd,
451 int max_argc, char const *argv[], bool can_fail,
452 size_t argv_buflen, char *argv_buf)
453{
454 char const *from;
455 char *to;
456 int argc = -1;
457 int i;
458 int left;
459 size_t len = strlen(cmd);
460
461 if (len > (argv_buflen - 1)) {
462 fr_strerror_const("Expansion string is too long for output buffer");
463 return -1;
464 }
465
466 /*
467 * Check for bad escapes.
468 */
469 if ((len > 0) && (cmd[len - 1] == '\\')) {
470 fr_strerror_const("Expansion string ends with a trailing backslash - invalid escape sequence");
471 return -1;
472 }
473
474 strlcpy(argv_buf, cmd, argv_buflen);
475
476 /*
477 * Split the string into argv's BEFORE doing xlat_eval...
478 */
479 from = cmd;
480 to = argv_buf;
481 argc = 0;
482 while (*from) {
483 int length;
484
485 fr_skip_whitespace(from);
486
487 argv[argc] = to;
488 argc++;
489
490 if (argc >= (max_argc - 1)) break;
491
492 /*
493 * Copy the argv over to our buffer.
494 */
495 while (*from && (*from != ' ') && (*from != '\t')) {
496 if (to >= argv_buf + argv_buflen - 1) {
497 fr_strerror_const("Expansion string is too long for output buffer");
498 return -1;
499 }
500
501 switch (*from) {
502 case '"':
503 case '\'':
504 length = rad_copy_string_bare(to, from);
505 if (length < 0) {
506 fr_strerror_const("Invalid quoted string in expansion");
507 return -1;
508 }
509 from += length+2;
510 to += length;
511 break;
512
513 case '%':
514 if (from[1] == '{') {
515 *(to++) = *(from++);
516
517 length = rad_copy_variable(to, from);
518 if (length < 0) {
519 fr_strerror_const("Invalid variable in expansion");
520 return -1;
521 }
522 from += length;
523 to += length;
524 } else { /* FIXME: catch %%{ ? */
525 *(to++) = *(from++);
526 }
527 break;
528
529 case '\\':
530 if (from[1] == ' ') from++;
532
533 default:
534 *(to++) = *(from++);
535 }
536 } /* end of string, or found a space */
537
538 *(to++) = '\0'; /* terminate the string */
539 }
540
541 /*
542 * We have to have SOMETHING, at least.
543 */
544 if (argc <= 0) {
545 fr_strerror_const("Expansion string is empty");
546 return -1;
547 }
548
549 /*
550 * Expand each string, as appropriate.
551 */
552 left = argv_buf + argv_buflen - to;
553 for (i = 0; i < argc; i++) {
554 int sublen;
555
556 /*
557 * Don't touch argv's which won't be translated.
558 */
559 if (strchr(argv[i], '%') == NULL) continue;
560
561 if (!request) continue;
562
563 sublen = xlat_eval(to, left - 1, request, argv[i], NULL, NULL);
564 if (sublen <= 0) {
565 if (can_fail) {
566 /*
567 * Fail to be backwards compatible.
568 *
569 * It's yucky, but it won't break anything,
570 * and it won't cause security problems.
571 */
572 sublen = 0;
573 } else {
574 fr_strerror_const("Failed expanding substring");
575 return -1;
576 }
577 }
578
579 argv[i] = to;
580 to += sublen;
581 *(to++) = '\0';
582 left -= sublen;
583 left--;
584
585 if (left <= 0) {
586 fr_strerror_const("Ran out of space while expanding arguments");
587 return -1;
588 }
589 }
590 argv[argc] = NULL;
591
592 return argc;
593}
594
595#ifdef HAVE_SETUID
596static bool doing_setuid = false;
597static uid_t suid_down_uid = (uid_t)-1;
598
599/** Set the uid and gid used when dropping privileges
600 *
601 * @note if this function hasn't been called, rad_suid_down will have no effect.
602 *
603 * @param uid to drop down to.
604 */
605void rad_suid_set_down_uid(uid_t uid)
606{
607 suid_down_uid = uid;
608 doing_setuid = true;
609}
610
611# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
612void rad_suid_up(void)
613{
614 uid_t ruid, euid, suid;
615
616 if (getresuid(&ruid, &euid, &suid) < 0) {
617 ERROR("Failed getting saved UID's");
618 fr_exit_now(EXIT_FAILURE);
619 }
620
621 if (setresuid(-1, suid, -1) < 0) {
622 ERROR("Failed switching to privileged user");
623 fr_exit_now(EXIT_FAILURE);
624 }
625
626 if (geteuid() != suid) {
627 ERROR("Switched to unknown UID");
628 fr_exit_now(EXIT_FAILURE);
629 }
630}
631
632void rad_suid_down(void)
633{
634 if (!doing_setuid) return;
635
636 if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
637 struct passwd *passwd;
638 char const *name;
639
640 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
641 ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno));
642 talloc_free(passwd);
643 fr_exit_now(EXIT_FAILURE);
644 }
645
646 if (geteuid() != suid_down_uid) {
647 ERROR("Failed switching uid: UID is incorrect");
648 fr_exit_now(EXIT_FAILURE);
649 }
650
652}
653
655{
656 if (!doing_setuid) return;
657
658 if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
659 struct passwd *passwd;
660 char const *name;
661
662 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
663 ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno));
664 talloc_free(passwd);
665 fr_exit_now(EXIT_FAILURE);
666 }
667
668 if (geteuid() != suid_down_uid) {
669 ERROR("Switched to unknown uid");
670 fr_exit_now(EXIT_FAILURE);
671 }
672
673 /*
674 * Shut down most of the interesting things which might get abused.
675 */
679 ERROR("Failed disabling CAP_SUID");
680 fr_exit_now(EXIT_FAILURE);
681 }
682
683#ifdef HAVE_GRP_H
687 ERROR("Failed disabling CAP_SGID");
688 fr_exit_now(EXIT_FAILURE);
689 }
690#endif
691
693
694 suid_down_permanent = true;
695}
696# else
697/*
698 * Much less secure...
699 */
700void rad_suid_up(void)
701{
702 if (!doing_setuid) return;
703
704 if (seteuid(0) < 0) {
705 ERROR("Failed switching up to euid 0: %s", fr_syserror(errno));
706 fr_exit_now(EXIT_FAILURE);
707 }
708
709}
710
711void rad_suid_down(void)
712{
713 if (!doing_setuid) return;
714
715 if (geteuid() == suid_down_uid) return;
716
717 if (seteuid(suid_down_uid) < 0) {
718 struct passwd *passwd;
719 char const *name;
720
721 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
722 ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno));
723 talloc_free(passwd);
724 fr_exit_now(EXIT_FAILURE);
725 }
726
728}
729
731{
732 if (!doing_setuid) return;
733
734 /*
735 * Already done. Don't do anything else.
736 */
737 if (getuid() == suid_down_uid) return;
738
739 /*
740 * We're root, but running as a normal user. Fix that,
741 * so we can call setuid().
742 */
743 if (geteuid() == suid_down_uid) {
744 rad_suid_up();
745 }
746
747 if (setuid(suid_down_uid) < 0) {
748 struct passwd *passwd;
749 char const *name;
750
751 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
752 ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno));
753 talloc_free(passwd);
754 fr_exit_now(EXIT_FAILURE);
755 }
756
758
759 suid_down_permanent = true;
760}
761# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
762#else /* HAVE_SETUID */
764{
765}
766
767void rad_suid_up(void)
768{
769}
770
772{
774}
775
777{
779}
780#endif /* HAVE_SETUID */
781
782/** Return whether we've permanently dropped root privileges
783 *
784 * @return
785 * - true if root privileges have been dropped.
786 * - false if root privileges have not been dropped.
787 */
789{
790 return suid_down_permanent;
791}
792
793/** Alter the effective user id
794 *
795 * @param uid to set
796 * @return
797 * - 0 on success.
798 * - -1 on failure.
799 */
800int rad_seuid(uid_t uid)
801{
802 if (seteuid(uid) < 0) {
803 int sete_errno = errno; /* errno sets overwritten by fr_perm_getpwuid */
804 struct passwd *passwd;
805
806 if (fr_perm_getpwuid(NULL, &passwd, uid) < 0) return -1;
807 fr_strerror_printf("%s", fr_syserror(sete_errno));
808 talloc_free(passwd);
809
810 return -1;
811 }
812 return 0;
813}
814
815/** Alter the effective user id
816 *
817 * @param gid to set
818 * @return
819 * - 0 on success.
820 * - -1 on failure.
821 */
822int rad_segid(gid_t gid)
823{
824 if (setegid(gid) < 0) {
825 int sete_errno = errno; /* errno sets overwritten by fr_perm_getgrgid */
826 struct group *group;
827
828 if (fr_perm_getgrgid(NULL, &group, gid) < 0) return -1;
829 fr_strerror_printf("%s", fr_syserror(sete_errno));
830 talloc_free(group);
831
832 return -1;
833 }
834 return 0;
835}
#define RCSID(id)
Definition build.h:506
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define UNUSED
Definition build.h:336
#define CAP_SETGID
Definition cap.h:53
#define CAP_PERMITTED
Definition cap.h:50
#define CAP_SETUID
Definition cap.h:52
#define CAP_EFFECTIVE
Definition cap.h:48
#define fr_cap_disable(_x, _y)
Definition cap.h:56
#define CAP_INHERITABLE
Definition cap.h:49
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:743
#define MEM(x)
Definition debug.h:46
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:236
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static fr_slen_t in
Definition dict.h:882
talloc_free(hp)
void rad_suid_up(void)
Definition util.c:767
bool rad_suid_is_down_permanent(void)
Return whether we've permanently dropped root privileges.
Definition util.c:788
static int rad_copy_string(char *to, char const *from)
Definition util.c:287
static int rad_copy_variable(char *to, char const *from)
Definition util.c:341
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:822
uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
Definition util.c:400
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.
Definition util.c:88
int rad_filename_box_escape(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:253
static bool suid_down_permanent
Record whether we've permanently dropped privilledges.
Definition util.c:35
void rad_suid_down(void)
Definition util.c:771
int rad_filename_box_make_safe(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:131
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:450
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:178
void rad_suid_down_permanent(void)
Definition util.c:776
static int rad_copy_string_bare(char *to, char const *from)
Definition util.c:315
int rad_seuid(uid_t uid)
Alter the effective user id.
Definition util.c:800
void rad_suid_set_down_uid(uid_t uid)
Definition util.c:763
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:331
int fr_perm_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
Resolve a uid to a passwd entry.
Definition perm.c:205
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:37
static char const * name
#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:4730
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1093
#define fr_value_box_is_safe_for(_box, _safe_for)
Definition value.h:1100
static size_t char ** out
Definition value.h:1030