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