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