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: 52b111adacb297a27e1dc27dd37770b4c74bedf2 $
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: 52b111adacb297a27e1dc27dd37770b4c74bedf2 $")
24
25#include <freeradius-devel/server/base.h>
26#include <freeradius-devel/server/stats.h>
27#include <freeradius-devel/server/util.h>
28
29#include <freeradius-devel/util/debug.h>
30#include <freeradius-devel/util/base16.h>
31#include <freeradius-devel/util/misc.h>
32#include <freeradius-devel/util/perm.h>
33#include <freeradius-devel/util/syserror.h>
34
35#include <freeradius-devel/unlang/xlat.h>
36
37#include <fcntl.h>
38#include <signal.h>
39#include <sys/stat.h>
40
41static bool suid_down_permanent = false; //!< Record whether we've permanently dropped privilledges
42
43/*
44 * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
45 * sa_flags, which causes grief if signal() is called in the
46 * handler before the cause of the signal has been cleared.
47 * (Infinite recursion).
48 *
49 * The same problem appears on HPUX, so we avoid it, if we can.
50 *
51 * Using sigaction() to reset the signal handler fixes the problem,
52 * so where available, we prefer that solution.
53 */
54
55void (*reset_signal(int signo, void (*func)(int)))(int)
56{
57#ifdef HAVE_SIGACTION
58 struct sigaction act, oact;
59
60 memset(&act, 0, sizeof(act));
61 act.sa_handler = func;
62 sigemptyset(&act.sa_mask);
63 act.sa_flags = 0;
64#ifdef SA_INTERRUPT /* SunOS */
65 act.sa_flags |= SA_INTERRUPT;
66#endif
67 if (sigaction(signo, &act, &oact) < 0)
68 return SIG_ERR;
69 return oact.sa_handler;
70#else
71
72 /*
73 * re-set by calling the 'signal' function, which
74 * may cause infinite recursion and core dumps due to
75 * stack growth.
76 *
77 * However, the system is too dumb to implement sigaction(),
78 * so we don't have a choice.
79 */
80 signal(signo, func);
81
82 return NULL;
83#endif
84}
85
86/** Ensures that a filename cannot walk up the directory structure
87 *
88 * Also sanitizes control chars.
89 *
90 * @param request Current request (may be NULL).
91 * @param out Output buffer.
92 * @param outlen Size of the output buffer.
93 * @param in string to escape.
94 * @param arg Context arguments (unused, should be NULL).
95 */
96ssize_t rad_filename_make_safe(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
97{
98 char const *q = in;
99 char *p = out;
100 size_t left = outlen;
101
102 while (*q) {
103 if (*q != '/') {
104 if (left < 2) break;
105
106 /*
107 * Smash control characters and spaces to
108 * something simpler.
109 */
110 if (*q < ' ') {
111 *(p++) = '_';
112 q++;
113 continue;
114 }
115
116 *(p++) = *(q++);
117 left--;
118 continue;
119 }
120
121 /*
122 * For now, allow slashes in the expanded
123 * filename. This allows the admin to set
124 * attributes which create sub-directories.
125 * Unfortunately, it also allows users to send
126 * attributes which *may* end up creating
127 * sub-directories.
128 */
129 if (left < 2) break;
130 *(p++) = *(q++);
131
132 /*
133 * Get rid of ////../.././///.///..//
134 */
135 redo:
136 /*
137 * Get rid of ////
138 */
139 if (*q == '/') {
140 q++;
141 goto redo;
142 }
143
144 /*
145 * Get rid of /./././
146 */
147 if ((q[0] == '.') &&
148 (q[1] == '/')) {
149 q += 2;
150 goto redo;
151 }
152
153 /*
154 * Get rid of /../../../
155 */
156 if ((q[0] == '.') && (q[1] == '.') &&
157 (q[2] == '/')) {
158 q += 3;
159 goto redo;
160 }
161 }
162 *p = '\0';
163
164 return (p - out);
165}
166
168{
169 char *escaped;
170 size_t len;
171 fr_value_box_entry_t entry;
172
173 if (vb->vb_length == 0) return 0;
174 if (vb->safe_for == (fr_value_box_safe_for_t)rad_filename_box_make_safe) return 0;
175
176 /*
177 * Allocate an output buffer, only ever the same or shorter than the input
178 */
179 MEM(escaped = talloc_array(vb, char, vb->vb_length + 1));
180
181 len = rad_filename_make_safe(NULL, escaped, (vb->vb_length + 1), vb->vb_strvalue, NULL);
182
183 entry = vb->entry;
185 fr_value_box_bstrndup(vb, vb, NULL, escaped, len, false);
186 vb->entry = entry;
187 talloc_free(escaped);
188
189 return 0;
190}
191
192/** Escapes the raw string such that it should be safe to use as part of a file path
193 *
194 * This function is designed to produce a string that's still readable but portable
195 * across the majority of file systems.
196 *
197 * For security reasons it cannot remove characters from the name, and must not allow
198 * collisions to occur between different strings.
199 *
200 * With that in mind '-' has been chosen as the escape character, and will be double
201 * escaped '-' -> '--' to avoid collisions.
202 *
203 * Escaping should be reversible if the original string needs to be extracted.
204 *
205 * @note function takes additional arguments so that it may be used as an xlat escape
206 * function but it's fine to call it directly.
207 *
208 * @note OSX/Unix/NTFS/VFAT have a max filename size of 255 bytes.
209 *
210 * @param request Current request (may be NULL).
211 * @param out Output buffer.
212 * @param outlen Size of the output buffer.
213 * @param in string to escape.
214 * @param arg Context arguments (unused, should be NULL).
215 */
216ssize_t rad_filename_escape(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
217{
218 size_t freespace = outlen;
219
220 while (*in != '\0') {
221 size_t utf8_len;
222
223 /*
224 * Encode multibyte UTF8 chars
225 */
226 utf8_len = fr_utf8_char((uint8_t const *) in, -1);
227 if (utf8_len > 1) {
228 if (freespace <= (utf8_len * 3)) break;
229
230 switch (utf8_len) {
231 case 2:
232 snprintf(out, freespace, "-%x-%x", (uint8_t)in[0], (uint8_t)in[1]);
233 break;
234
235 case 3:
236 snprintf(out, freespace, "-%x-%x-%x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2]);
237 break;
238
239 case 4:
240 snprintf(out, freespace, "-%x-%x-%x-%x", (uint8_t)in[0], (uint8_t)in[1], (uint8_t)in[2], (uint8_t)in[3]);
241 break;
242 }
243
244 freespace -= (utf8_len * 3);
245 out += (utf8_len * 3);
246 in += utf8_len;
247
248 continue;
249 }
250
251 /*
252 * Safe chars
253 */
254 if (((*in >= 'A') && (*in <= 'Z')) ||
255 ((*in >= 'a') && (*in <= 'z')) ||
256 ((*in >= '0') && (*in <= '9')) ||
257 (*in == '_')) {
258 if (freespace <= 1) break;
259
260 *out++ = *in++;
261 freespace--;
262 continue;
263 }
264 if (freespace <= 2) break;
265
266 /*
267 * Double escape '-' (like \\‍)
268 */
269 if (*in == '-') {
270 *out++ = '-';
271 *out++ = '-';
272
273 freespace -= 2;
274 in++;
275 continue;
276 }
277
278 /*
279 * Unsafe chars
280 */
281 *out++ = '-';
282 fr_base16_encode(&FR_SBUFF_OUT(out, freespace), &FR_DBUFF_TMP((uint8_t const *)in, 1));
283 in++;
284 out += 2;
285 freespace -= 3;
286 }
287 *out = '\0';
288
289 return outlen - freespace;
290}
291
293{
294 char *escaped;
295 size_t len;
296 fr_value_box_entry_t entry;
297
298 if (vb->vb_length == 0) return 0;
299 if (vb->safe_for == (fr_value_box_safe_for_t)rad_filename_box_escape) return 0;
300
301 /*
302 * Allocate an output buffer, if every character is escaped,
303 * it will be 3 times the input
304 */
305 MEM(escaped = talloc_array(vb, char, vb->vb_length * 3 + 1));
306
307 len = rad_filename_escape(NULL, escaped, (vb->vb_length * 3 + 1), vb->vb_strvalue, NULL);
308
309 /*
310 * If the escaped length == input length, no changes were done.
311 */
312 if (len == vb->vb_length) {
313 talloc_free(escaped);
314 return 0;
315 }
316
317 entry = vb->entry;
319 fr_value_box_bstrndup(vb, vb, NULL, escaped, len, false);
320 vb->entry = entry;
321 talloc_free(escaped);
322
323 return 0;
324}
325
326/** Converts data stored in a file name back to its original form
327 *
328 * @param out Where to write the unescaped string (may be the same as in).
329 * @param outlen Length of the output buffer.
330 * @param in Input filename.
331 * @param inlen Length of input.
332 * @return
333 * - Number of bytes written to output buffer
334 * - offset where parse error occurred on failure.
335 */
336ssize_t rad_filename_unescape(char *out, size_t outlen, char const *in, size_t inlen)
337{
338 char const *p, *end = in + inlen;
339 size_t freespace = outlen;
340
341 for (p = in; p < end; p++) {
342 if (freespace <= 1) break;
343
344 if (((*p >= 'A') && (*p <= 'Z')) ||
345 ((*p >= 'a') && (*p <= 'z')) ||
346 ((*p >= '0') && (*p <= '9')) ||
347 (*p == '_')) {
348 *out++ = *p;
349 freespace--;
350 continue;
351 }
352
353 if (p[0] == '-') {
354 /*
355 * End of input, '-' needs at least one extra char after
356 * it to be valid.
357 */
358 if ((end - p) < 2) return in - p;
359 if (p[1] == '-') {
360 p++;
361 *out++ = '-';
362 freespace--;
363 continue;
364 }
365
366 /*
367 * End of input, '-' must be followed by <hex><hex>
368 * but there aren't enough chars left
369 */
370 if ((end - p) < 3) return in - p;
371
372 /*
373 * If hex2bin returns 0 the next two chars weren't hexits.
374 */
375 if (fr_base16_decode(NULL,
376 &FR_DBUFF_TMP((uint8_t *) out, 1),
377 &FR_SBUFF_IN(in, 1), false) == 0) return in - (p + 1);
378 in += 2;
379 out++;
380 freespace--;
381 }
382
383 return in - p; /* offset we found the bad char at */
384 }
385 *out = '\0';
386
387 return outlen - freespace; /* how many bytes were written */
388}
389
390/** talloc a buffer to hold the concatenated value of all elements of argv
391 *
392 * @param ctx to allocate buffer in.
393 * @param argv array of substrings.
394 * @param argc length of array.
395 * @param c separation character. Optional, may be '\0' for no separator.
396 * @return the concatenation of the elements of argv, separated by c.
397 */
398char *rad_ajoin(TALLOC_CTX *ctx, char const **argv, int argc, char c)
399{
400 char *buff, *p;
401 int i;
402 size_t total = 0, freespace;
403
404 if (!*argv) {
405 goto null;
406 }
407
408 for (i = 0; i < argc; i++) total += (strlen(argv[i]) + ((c == '\0') ? 0 : 1));
409 if (!total) {
410 null:
411 return talloc_zero_array(ctx, char, 1);
412 }
413
414 if (c == '\0') total++;
415
416 freespace = total;
417 buff = p = talloc_array(ctx, char, total);
418 for (i = 0; i < argc; i++) {
419 size_t len;
420
421 len = strlcpy(p, argv[i], freespace);
422 p += len;
423 freespace -= len;
424
425 *p++ = c;
426 freespace--;
427 }
428 buff[total] = '\0';
429
430 return buff;
431}
432
433/*
434 * Copy a quoted string.
435 */
436static int rad_copy_string(char *to, char const *from)
437{
438 int length = 0;
439 char quote = *from;
440
441 do {
442 if (*from == '\\') {
443 *(to++) = *(from++);
444 length++;
445 }
446 *(to++) = *(from++);
447 length++;
448 } while (*from && (*from != quote));
449
450 if (*from != quote) return -1; /* not properly quoted */
451
452 *(to++) = quote;
453 length++;
454 *to = '\0';
455
456 return length;
457}
458
459/*
460 * Copy a quoted string but without the quotes. The length
461 * returned is the number of chars written; the number of
462 * characters consumed is 2 more than this.
463 */
464static int rad_copy_string_bare(char *to, char const *from)
465{
466 int length = 0;
467 char quote = *from;
468
469 from++;
470 while (*from && (*from != quote)) {
471 if (*from == '\\') {
472 *(to++) = *(from++);
473 length++;
474 }
475 *(to++) = *(from++);
476 length++;
477 }
478
479 if (*from != quote) return -1; /* not properly quoted */
480
481 *to = '\0';
482
483 return length;
484}
485
486
487/*
488 * Copy a %{} string.
489 */
490static int rad_copy_variable(char *to, char const *from)
491{
492 int length = 0;
493 int sublen;
494
495 *(to++) = *(from++);
496 length++;
497
498 while (*from) {
499 switch (*from) {
500 case '"':
501 case '\'':
502 sublen = rad_copy_string(to, from);
503 if (sublen < 0) return sublen;
504 from += sublen;
505 to += sublen;
506 length += sublen;
507 break;
508
509 case '}': /* end of variable expansion */
510 *(to++) = *(from++);
511 *to = '\0';
512 length++;
513 return length; /* proper end of variable */
514
515 case '\\':
516 *(to++) = *(from++);
517 *(to++) = *(from++);
518 length += 2;
519 break;
520
521 case '%': /* start of variable expansion */
522 if (from[1] == '{') {
523 *(to++) = *(from++);
524 length++;
525
526 sublen = rad_copy_variable(to, from);
527 if (sublen < 0) return sublen;
528 from += sublen;
529 to += sublen;
530 length += sublen;
531 break;
532 } /* else FIXME: catch %%{ ?*/
533
535 default:
536 *(to++) = *(from++);
537 length++;
538 break;
539 }
540 } /* loop over the input string */
541
542 /*
543 * We ended the string before a trailing '}'
544 */
545
546 return -1;
547}
548
549uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
550{
551 uint32_t pps;
552
553 if (*then != now->tv_sec) {
554 *then = now->tv_sec;
555 *past = *present;
556 *present = 0;
557 }
558
559 /*
560 * Bootstrap PPS by looking at a percentage of
561 * the previous PPS. This lets us take a moving
562 * count, without doing a moving average. If
563 * we're a fraction "f" (0..1) into the current
564 * second, we can get a good guess for PPS by
565 * doing:
566 *
567 * PPS = pps_now + pps_old * (1 - f)
568 *
569 * It's an instantaneous measurement, rather than
570 * a moving average. This will hopefully let it
571 * respond better to sudden spikes.
572 *
573 * Doing the calculations by thousands allows us
574 * to not overflow 2^32, AND to not underflow
575 * when we divide by USEC.
576 */
577 pps = USEC - now->tv_usec; /* useconds left in previous second */
578 pps /= 1000; /* scale to milliseconds */
579 pps *= *past; /* multiply by past count to get fraction */
580 pps /= 1000; /* scale to usec again */
581 pps += *present; /* add in current count */
582
583 return pps;
584}
585
586/** Split string into words and expand each one
587 *
588 * @param request Current request.
589 * @param cmd string to split.
590 * @param max_argc the maximum number of arguments to split into.
591 * @param argv Where to write the pointers into argv_buf.
592 * @param can_fail If false, stop processing if any of the xlat expansions fail.
593 * @param argv_buflen size of argv_buf.
594 * @param argv_buf temporary buffer we used to mangle/expand cmd.
595 * Pointers to offsets of this buffer will be written to argv.
596 * @return argc or -1 on failure.
597 */
598
599int rad_expand_xlat(request_t *request, char const *cmd,
600 int max_argc, char const *argv[], bool can_fail,
601 size_t argv_buflen, char *argv_buf)
602{
603 char const *from;
604 char *to;
605 int argc = -1;
606 int i;
607 int left;
608
609 if (strlen(cmd) > (argv_buflen - 1)) {
610 fr_strerror_const("Expansion string is too long for output buffer");
611 return -1;
612 }
613
614 /*
615 * Check for bad escapes.
616 */
617 if (cmd[strlen(cmd) - 1] == '\\') {
618 fr_strerror_const("Expansion string ends with a trailing backslash - invalid escape sequence");
619 return -1;
620 }
621
622 strlcpy(argv_buf, cmd, argv_buflen);
623
624 /*
625 * Split the string into argv's BEFORE doing xlat_eval...
626 */
627 from = cmd;
628 to = argv_buf;
629 argc = 0;
630 while (*from) {
631 int length;
632
633 fr_skip_whitespace(from);
634
635 argv[argc] = to;
636 argc++;
637
638 if (argc >= (max_argc - 1)) break;
639
640 /*
641 * Copy the argv over to our buffer.
642 */
643 while (*from && (*from != ' ') && (*from != '\t')) {
644 if (to >= argv_buf + argv_buflen - 1) {
645 fr_strerror_const("Expansion string is too long for output buffer");
646 return -1;
647 }
648
649 switch (*from) {
650 case '"':
651 case '\'':
652 length = rad_copy_string_bare(to, from);
653 if (length < 0) {
654 fr_strerror_const("Invalid quoted string in expansion");
655 return -1;
656 }
657 from += length+2;
658 to += length;
659 break;
660
661 case '%':
662 if (from[1] == '{') {
663 *(to++) = *(from++);
664
665 length = rad_copy_variable(to, from);
666 if (length < 0) {
667 fr_strerror_const("Invalid variable in expansion");
668 return -1;
669 }
670 from += length;
671 to += length;
672 } else { /* FIXME: catch %%{ ? */
673 *(to++) = *(from++);
674 }
675 break;
676
677 case '\\':
678 if (from[1] == ' ') from++;
680
681 default:
682 *(to++) = *(from++);
683 }
684 } /* end of string, or found a space */
685
686 *(to++) = '\0'; /* terminate the string */
687 }
688
689 /*
690 * We have to have SOMETHING, at least.
691 */
692 if (argc <= 0) {
693 fr_strerror_const("Expansion string is empty");
694 return -1;
695 }
696
697 /*
698 * Expand each string, as appropriate.
699 */
700 left = argv_buf + argv_buflen - to;
701 for (i = 0; i < argc; i++) {
702 int sublen;
703
704 /*
705 * Don't touch argv's which won't be translated.
706 */
707 if (strchr(argv[i], '%') == NULL) continue;
708
709 if (!request) continue;
710
711 sublen = xlat_eval(to, left - 1, request, argv[i], NULL, NULL);
712 if (sublen <= 0) {
713 if (can_fail) {
714 /*
715 * Fail to be backwards compatible.
716 *
717 * It's yucky, but it won't break anything,
718 * and it won't cause security problems.
719 */
720 sublen = 0;
721 } else {
722 fr_strerror_const("Failed expanding substring");
723 return -1;
724 }
725 }
726
727 argv[i] = to;
728 to += sublen;
729 *(to++) = '\0';
730 left -= sublen;
731 left--;
732
733 if (left <= 0) {
734 fr_strerror_const("Ran out of space while expanding arguments");
735 return -1;
736 }
737 }
738 argv[argc] = NULL;
739
740 return argc;
741}
742
743#ifdef HAVE_SETUID
744static bool doing_setuid = false;
745static uid_t suid_down_uid = (uid_t)-1;
746
747/** Set the uid and gid used when dropping privileges
748 *
749 * @note if this function hasn't been called, rad_suid_down will have no effect.
750 *
751 * @param uid to drop down to.
752 */
753void rad_suid_set_down_uid(uid_t uid)
754{
755 suid_down_uid = uid;
756 doing_setuid = true;
757}
758
759# if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
760void rad_suid_up(void)
761{
762 uid_t ruid, euid, suid;
763
764 if (getresuid(&ruid, &euid, &suid) < 0) {
765 ERROR("Failed getting saved UID's");
766 fr_exit_now(EXIT_FAILURE);
767 }
768
769 if (setresuid(-1, suid, -1) < 0) {
770 ERROR("Failed switching to privileged user");
771 fr_exit_now(EXIT_FAILURE);
772 }
773
774 if (geteuid() != suid) {
775 ERROR("Switched to unknown UID");
776 fr_exit_now(EXIT_FAILURE);
777 }
778}
779
780void rad_suid_down(void)
781{
782 if (!doing_setuid) return;
783
784 if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
785 struct passwd *passwd;
786 char const *name;
787
788 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
789 ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno));
790 talloc_free(passwd);
791 fr_exit_now(EXIT_FAILURE);
792 }
793
794 if (geteuid() != suid_down_uid) {
795 ERROR("Failed switching uid: UID is incorrect");
796 fr_exit_now(EXIT_FAILURE);
797 }
798
800}
801
803{
804 if (!doing_setuid) return;
805
806 if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
807 struct passwd *passwd;
808 char const *name;
809
810 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
811 ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno));
812 talloc_free(passwd);
813 fr_exit_now(EXIT_FAILURE);
814 }
815
816 if (geteuid() != suid_down_uid) {
817 ERROR("Switched to unknown uid");
818 fr_exit_now(EXIT_FAILURE);
819 }
820
822
823 suid_down_permanent = true;
824}
825# else
826/*
827 * Much less secure...
828 */
829void rad_suid_up(void)
830{
831 if (!doing_setuid) return;
832
833 if (seteuid(0) < 0) {
834 ERROR("Failed switching up to euid 0: %s", fr_syserror(errno));
835 fr_exit_now(EXIT_FAILURE);
836 }
837
838}
839
840void rad_suid_down(void)
841{
842 if (!doing_setuid) return;
843
844 if (geteuid() == suid_down_uid) return;
845
846 if (seteuid(suid_down_uid) < 0) {
847 struct passwd *passwd;
848 char const *name;
849
850 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
851 ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno));
852 talloc_free(passwd);
853 fr_exit_now(EXIT_FAILURE);
854 }
855
857}
858
860{
861 if (!doing_setuid) return;
862
863 /*
864 * Already done. Don't do anything else.
865 */
866 if (getuid() == suid_down_uid) return;
867
868 /*
869 * We're root, but running as a normal user. Fix that,
870 * so we can call setuid().
871 */
872 if (geteuid() == suid_down_uid) {
873 rad_suid_up();
874 }
875
876 if (setuid(suid_down_uid) < 0) {
877 struct passwd *passwd;
878 char const *name;
879
880 name = (fr_perm_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
881 ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno));
882 talloc_free(passwd);
883 fr_exit_now(EXIT_FAILURE);
884 }
885
887
888 suid_down_permanent = true;
889}
890# endif /* HAVE_SETRESUID && HAVE_GETRESUID */
891#else /* HAVE_SETUID */
893{
894}
895
896void rad_suid_up(void)
897{
898}
899
901{
903}
904
906{
908}
909#endif /* HAVE_SETUID */
910
911/** Return whether we've permanently dropped root privileges
912 *
913 * @return
914 * - true if root privileges have been dropped.
915 * - false if root privileges have not been dropped.
916 */
918{
919 return suid_down_permanent;
920}
921
922/** Alter the effective user id
923 *
924 * @param uid to set
925 * @return
926 * - 0 on success.
927 * - -1 on failure.
928 */
929int rad_seuid(uid_t uid)
930{
931 if (seteuid(uid) < 0) {
932 int sete_errno = errno; /* errno sets overwritten by fr_perm_getpwuid */
933 struct passwd *passwd;
934
935 if (fr_perm_getpwuid(NULL, &passwd, uid) < 0) return -1;
936 fr_strerror_printf("%s", fr_syserror(sete_errno));
937 talloc_free(passwd);
938
939 return -1;
940 }
941 return 0;
942}
943
944/** Alter the effective user id
945 *
946 * @param gid to set
947 * @return
948 * - 0 on success.
949 * - -1 on failure.
950 */
951int rad_segid(gid_t gid)
952{
953 if (setegid(gid) < 0) {
954 int sete_errno = errno; /* errno sets overwritten by fr_perm_getgrgid */
955 struct group *group;
956
957 if (fr_perm_getgrgid(NULL, &group, gid) < 0) return -1;
958 fr_strerror_printf("%s", fr_syserror(sete_errno));
959 talloc_free(group);
960
961 return -1;
962 }
963 return 0;
964}
#define fr_base16_encode(_out, _in)
Definition base16.h:57
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition base16.h:95
#define RCSID(id)
Definition build.h:483
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define UNUSED
Definition build.h:315
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:514
int fr_reset_dumpable(void)
Reset dumpable state to previously configured value.
Definition debug.c:890
#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:234
#define ERROR(fmt,...)
Definition dhcpclient.c:41
static fr_slen_t in
Definition dict.h:824
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:96
void rad_suid_up(void)
Definition util.c:896
bool rad_suid_is_down_permanent(void)
Return whether we've permanently dropped root privileges.
Definition util.c:917
static int rad_copy_string(char *to, char const *from)
Definition util.c:436
static int rad_copy_variable(char *to, char const *from)
Definition util.c:490
void(*)(int) reset_signal(int signo, void(*func)(int))
Definition util.c:55
int rad_segid(gid_t gid)
Alter the effective user id.
Definition util.c:951
uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
Definition util.c:549
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
Definition util.c:398
int rad_filename_box_escape(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:292
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.
Definition util.c:336
static bool suid_down_permanent
Record whether we've permanently dropped privilledges.
Definition util.c:41
void rad_suid_down(void)
Definition util.c:900
int rad_filename_box_make_safe(fr_value_box_t *vb, UNUSED void *uxtc)
Definition util.c:167
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:599
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:216
void rad_suid_down_permanent(void)
Definition util.c:905
static int rad_copy_string_bare(char *to, char const *from)
Definition util.c:464
int rad_seuid(uid_t uid)
Alter the effective user id.
Definition util.c:929
void rad_suid_set_down_uid(uid_t uid)
Definition util.c:892
talloc_free(reap)
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
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition misc.h:59
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
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
Signals that can be sent to a request.
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:41
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_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3681
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4148
static size_t char fr_sbuff_t size_t inlen
Definition value.h:997
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:155
static size_t char ** out
Definition value.h:997