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