Remove redundant file from freeradius-abfab list.
[freeradius.git] / src / main / util.c
1 /*
2  * util.c       Various utility functions.
3  *
4  * Version:     $Id$
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  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/rad_assert.h>
27
28 #include <ctype.h>
29
30 #include <sys/stat.h>
31 #include <fcntl.h>
32
33 /*
34  *      The signal() function in Solaris 2.5.1 sets SA_NODEFER in
35  *      sa_flags, which causes grief if signal() is called in the
36  *      handler before the cause of the signal has been cleared.
37  *      (Infinite recursion).
38  *
39  *      The same problem appears on HPUX, so we avoid it, if we can.
40  *
41  *      Using sigaction() to reset the signal handler fixes the problem,
42  *      so where available, we prefer that solution.
43  */
44
45 void (*reset_signal(int signo, void (*func)(int)))(int)
46 {
47 #ifdef HAVE_SIGACTION
48         struct sigaction act, oact;
49
50         memset(&act, 0, sizeof(act));
51         act.sa_handler = func;
52         sigemptyset(&act.sa_mask);
53         act.sa_flags = 0;
54 #ifdef  SA_INTERRUPT            /* SunOS */
55         act.sa_flags |= SA_INTERRUPT;
56 #endif
57         if (sigaction(signo, &act, &oact) < 0)
58                 return SIG_ERR;
59         return oact.sa_handler;
60 #else
61
62         /*
63          *      re-set by calling the 'signal' function, which
64          *      may cause infinite recursion and core dumps due to
65          *      stack growth.
66          *
67          *      However, the system is too dumb to implement sigaction(),
68          *      so we don't have a choice.
69          */
70         signal(signo, func);
71
72         return NULL;
73 #endif
74 }
75
76 /*
77  *      Per-request data, added by modules...
78  */
79 struct request_data_t {
80         request_data_t  *next;
81
82         void            *unique_ptr;
83         int             unique_int;
84         void            *opaque;
85         bool            free_opaque;
86 };
87
88 /*
89  *      Add opaque data (with a "free" function) to a REQUEST.
90  *
91  *      The unique ptr is meant to be a module configuration,
92  *      and the unique integer allows the caller to have multiple
93  *      opaque data associated with a REQUEST.
94  */
95 int request_data_add(REQUEST *request, void *unique_ptr, int unique_int, void *opaque, bool free_opaque)
96 {
97         request_data_t *this, **last, *next;
98
99         /*
100          *      Some simple sanity checks.
101          */
102         if (!request || !opaque) return -1;
103
104         this = next = NULL;
105         for (last = &(request->data);
106              *last != NULL;
107              last = &((*last)->next)) {
108                 if (((*last)->unique_ptr == unique_ptr) &&
109                     ((*last)->unique_int == unique_int)) {
110                         this = *last;
111                         next = this->next;
112
113                         /*
114                          *      If caller requires custom behaviour on free
115                          *      they must set a destructor.
116                          */
117                         if (this->opaque && this->free_opaque) talloc_free(this->opaque);
118
119                         break;  /* replace the existing entry */
120                 }
121         }
122
123         /*
124          *      Only alloc new memory if we're not replacing
125          *      an existing entry.
126          */
127         if (!this) this = talloc_zero(request, request_data_t);
128         if (!this) return -1;
129
130         this->next = next;
131         this->unique_ptr = unique_ptr;
132         this->unique_int = unique_int;
133         this->opaque = opaque;
134         this->free_opaque = free_opaque;
135
136         *last = this;
137
138         return 0;
139 }
140
141 /*
142  *      Get opaque data from a request.
143  */
144 void *request_data_get(REQUEST *request, void *unique_ptr, int unique_int)
145 {
146         request_data_t **last;
147
148         if (!request) return NULL;
149
150         for (last = &(request->data);
151              *last != NULL;
152              last = &((*last)->next)) {
153                 if (((*last)->unique_ptr == unique_ptr) &&
154                     ((*last)->unique_int == unique_int)) {
155                         request_data_t *this;
156                         void *ptr;
157
158                         this = *last;
159                         ptr = this->opaque;
160
161                         /*
162                          *      Remove the entry from the list, and free it.
163                          */
164                         *last = this->next;
165                         talloc_free(this);
166
167                         return ptr;             /* don't free it, the caller does that */
168                 }
169         }
170
171         return NULL;            /* wasn't found, too bad... */
172 }
173
174 /*
175  *      Get opaque data from a request without removing it.
176  */
177 void *request_data_reference(REQUEST *request, void *unique_ptr, int unique_int)
178 {
179         request_data_t **last;
180
181         for (last = &(request->data);
182              *last != NULL;
183              last = &((*last)->next)) {
184                 if (((*last)->unique_ptr == unique_ptr) &&
185                     ((*last)->unique_int == unique_int)) {
186                         return (*last)->opaque;
187                 }
188         }
189
190         return NULL;            /* wasn't found, too bad... */
191 }
192
193 /** Create possibly many directories.
194  *
195  * @note that the input directory name is NOT treated as a constant. This is so that
196  *       if an error is returned, the 'directory' ptr points to the name of the file
197  *       which caused the error.
198  *
199  * @param dir path to directory to create.
200  * @param mode for new directories.
201  * @param uid to set on new directories, may be -1 to use effective uid.
202  * @param gid to set on new directories, may be -1 to use effective gid.
203  * @return 0 on success, -1 on error. Error available as errno.
204  */
205 int rad_mkdir(char *dir, mode_t mode, uid_t uid, gid_t gid)
206 {
207         int rcode, fd;
208         char *p;
209
210         /*
211          *      Try to make the dir.  If it exists, chmod it.
212          *      If a path doesn't exist, that's OK.  Otherwise
213          *      return with an error.
214          *
215          *      Directories permissions are initially set so
216          *      that only we should have access. This prevents
217          *      an attacker removing them and swapping them
218          *      out for a link to somewhere else.
219          *      We change them to the correct permissions later.
220          */
221         rcode = mkdir(dir, 0700);
222         if (rcode < 0) {
223                 switch (errno) {
224                 case EEXIST:
225                         return 0; /* don't change permissions */
226
227                 case ENOENT:
228                         break;
229
230                 default:
231                         return rcode;
232                 }
233
234                 /*
235                  *      A component in the dir path doesn't
236                  *      exist.  Look for the LAST dir name.  Try
237                  *      to create that.  If there's an error, we leave
238                  *      the dir path as the one at which the
239                  *      error occured.
240                  */
241                 p = strrchr(dir, FR_DIR_SEP);
242                 if (!p || (p == dir)) return -1;
243
244                 *p = '\0';
245                 rcode = rad_mkdir(dir, mode, uid, gid);
246                 if (rcode < 0) return rcode;
247
248                 /*
249                  *      Reset the dir path, and try again to
250                  *      make the dir.
251                  */
252                 *p = FR_DIR_SEP;
253                 rcode = mkdir(dir, 0700);
254                 if (rcode < 0) return rcode;
255         } /* else we successfully created the dir */
256
257         /*
258          *      Set the permissions on the directory we created
259          *      this should never fail unless there's a race.
260          */
261         fd = open(dir, O_DIRECTORY);
262         if (fd < 0) return -1;
263
264         rcode = fchmod(fd, mode);
265         if (rcode < 0) {
266                 close(fd);
267                 return rcode;
268         }
269
270         if ((uid != (uid_t)-1) || (gid != (gid_t)-1)) {
271                 rad_suid_up();
272                 rcode = fchown(fd, uid, gid);
273                 rad_suid_down();
274         }
275         close(fd);
276
277         return rcode;
278 }
279
280 /** Ensures that a filename cannot walk up the directory structure
281  *
282  * Also sanitizes control chars.
283  *
284  * @param request Current request (may be NULL).
285  * @param out Output buffer.
286  * @param outlen Size of the output buffer.
287  * @param in string to escape.
288  * @param arg Context arguments (unused, should be NULL).
289  */
290 size_t rad_filename_make_safe(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
291 {
292         char const *q = in;
293         char *p = out;
294         size_t left = outlen;
295
296         while (*q) {
297                 if (*q != '/') {
298                         if (left < 2) break;
299
300                         /*
301                          *      Smash control characters and spaces to
302                          *      something simpler.
303                          */
304                         if (*q < ' ') {
305                                 *(p++) = '_';
306                                 continue;
307                         }
308
309                         *(p++) = *(q++);
310                         left--;
311                         continue;
312                 }
313
314                 /*
315                  *      For now, allow slashes in the expanded
316                  *      filename.  This allows the admin to set
317                  *      attributes which create sub-directories.
318                  *      Unfortunately, it also allows users to send
319                  *      attributes which *may* end up creating
320                  *      sub-directories.
321                  */
322                 if (left < 2) break;
323                 *(p++) = *(q++);
324
325                 /*
326                  *      Get rid of ////../.././///.///..//
327                  */
328         redo:
329                 /*
330                  *      Get rid of ////
331                  */
332                 if (*q == '/') {
333                         q++;
334                         goto redo;
335                 }
336
337                 /*
338                  *      Get rid of /./././
339                  */
340                 if ((q[0] == '.') &&
341                     (q[1] == '/')) {
342                         q += 2;
343                         goto redo;
344                 }
345
346                 /*
347                  *      Get rid of /../../../
348                  */
349                 if ((q[0] == '.') && (q[1] == '.') &&
350                     (q[2] == '/')) {
351                         q += 3;
352                         goto redo;
353                 }
354         }
355         *p = '\0';
356
357         return (p - out);
358 }
359
360 /** Escapes the raw string such that it should be safe to use as part of a file path
361  *
362  * This function is designed to produce a string that's still readable but portable
363  * across the majority of file systems.
364  *
365  * For security reasons it cannot remove characters from the name, and must not allow
366  * collisions to occur between different strings.
367  *
368  * With that in mind '-' has been chosen as the escape character, and will be double
369  * escaped '-' -> '--' to avoid collisions.
370  *
371  * Escaping should be reversible if the original string needs to be extracted.
372  *
373  * @note function takes additional arguments so that it may be used as an xlat escape
374  *      function but it's fine to call it directly.
375  *
376  * @note OSX/Unix/NTFS/VFAT have a max filename size of 255 bytes.
377  *
378  * @param request Current request (may be NULL).
379  * @param out Output buffer.
380  * @param outlen Size of the output buffer.
381  * @param in string to escape.
382  * @param arg Context arguments (unused, should be NULL).
383  */
384 size_t rad_filename_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
385 {
386         size_t freespace = outlen;
387
388         while (*in != '\0') {
389                 size_t utf8_len;
390
391                 /*
392                  *      Encode multibyte UTF8 chars
393                  */
394                 utf8_len = fr_utf8_char((uint8_t const *) in, -1);
395                 if (utf8_len > 1) {
396                         if (freespace <= (utf8_len * 3)) break;
397
398                         switch (utf8_len) {
399                         case 2:
400                                 snprintf(out, freespace, "-%x-%x", in[0], in[1]);
401                                 break;
402
403                         case 3:
404                                 snprintf(out, freespace, "-%x-%x-%x", in[0], in[1], in[2]);
405                                 break;
406
407                         case 4:
408                                 snprintf(out, freespace, "-%x-%x-%x-%x", in[0], in[1], in[2], in[3]);
409                                 break;
410                         }
411
412                         freespace -= (utf8_len * 3);
413                         out += (utf8_len * 3);
414                         in += utf8_len;
415
416                         continue;
417                 }
418
419                 /*
420                  *      Safe chars
421                  */
422                 if (((*in >= 'A') && (*in <= 'Z')) ||
423                     ((*in >= 'a') && (*in <= 'z')) ||
424                     ((*in >= '0') && (*in <= '9')) ||
425                     (*in == '_')) {
426                         if (freespace <= 1) break;
427
428                         *out++ = *in++;
429                         freespace--;
430                         continue;
431                 }
432                 if (freespace <= 2) break;
433
434                 /*
435                  *      Double escape '-' (like \\)
436                  */
437                 if (*in == '-') {
438                         *out++ = '-';
439                         *out++ = '-';
440
441                         freespace -= 2;
442                         in++;
443                         continue;
444                 }
445
446                 /*
447                  *      Unsafe chars
448                  */
449                 *out++ = '-';
450                 fr_bin2hex(out, (uint8_t const *)in++, 1);
451                 out += 2;
452                 freespace -= 3;
453         }
454         *out = '\0';
455
456         return outlen - freespace;
457 }
458
459 /** Converts data stored in a file name back to its original form
460  *
461  * @param out Where to write the unescaped string (may be the same as in).
462  * @param outlen Length of the output buffer.
463  * @param in Input filename.
464  * @param inlen Length of input.
465  * @return number of bytes written to output buffer, or offset where parse error
466  *      occurred on failure.
467  */
468 ssize_t rad_filename_unescape(char *out, size_t outlen, char const *in, size_t inlen)
469 {
470         char const *p, *end = in + inlen;
471         size_t freespace = outlen;
472
473         for (p = in; p < end; p++) {
474                 if (freespace <= 1) break;
475
476                 if (((*p >= 'A') && (*p <= 'Z')) ||
477                     ((*p >= 'a') && (*p <= 'z')) ||
478                     ((*p >= '0') && (*p <= '9')) ||
479                     (*p == '_')) {
480                         *out++ = *p;
481                         freespace--;
482                         continue;
483                 }
484
485                 if (p[0] == '-') {
486                         /*
487                          *      End of input, '-' needs at least one extra char after
488                          *      it to be valid.
489                          */
490                         if ((end - p) < 2) return in - p;
491                         if (p[1] == '-') {
492                                 p++;
493                                 *out++ = '-';
494                                 freespace--;
495                                 continue;
496                         }
497
498                         /*
499                          *      End of input, '-' must be followed by <hex><hex>
500                          *      but there aren't enough chars left
501                          */
502                         if ((end - p) < 3) return in - p;
503
504                         /*
505                          *      If hex2bin returns 0 the next two chars weren't hexits.
506                          */
507                         if (fr_hex2bin((uint8_t *) out, 1, in, 1) == 0) return in - (p + 1);
508                         in += 2;
509                         out++;
510                         freespace--;
511                 }
512
513                 return in - p; /* offset we found the bad char at */
514         }
515         *out = '\0';
516
517         return outlen - freespace;      /* how many bytes were written */
518 }
519
520 /*
521  *      Allocate memory, or exit.
522  *
523  *      This call ALWAYS succeeds!
524  */
525 void *rad_malloc(size_t size)
526 {
527         void *ptr = malloc(size);
528
529         if (ptr == NULL) {
530                 ERROR("no memory");
531                 fr_exit(1);
532         }
533
534         return ptr;
535 }
536
537
538 void rad_const_free(void const *ptr)
539 {
540         void *tmp;
541         if (!ptr) return;
542
543         memcpy(&tmp, &ptr, sizeof(tmp));
544         talloc_free(tmp);
545 }
546
547
548 /*
549  *      Logs an error message and aborts the program
550  *
551  */
552
553 void NEVER_RETURNS rad_assert_fail(char const *file, unsigned int line, char const *expr)
554 {
555         ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
556         fr_fault(SIGABRT);
557         fr_exit_now(1);
558 }
559
560 /*
561  *      Free a REQUEST struct.
562  */
563 static int _request_free(REQUEST *request)
564 {
565         rad_assert(!request->in_request_hash);
566 #ifdef WITH_PROXY
567         rad_assert(!request->in_proxy_hash);
568 #endif
569         rad_assert(!request->ev);
570
571 #ifdef WITH_COA
572         rad_assert(request->coa == NULL);
573 #endif
574
575 #ifndef NDEBUG
576         request->magic = 0x01020304;    /* set the request to be nonsense */
577 #endif
578         request->client = NULL;
579 #ifdef WITH_PROXY
580         request->home_server = NULL;
581 #endif
582
583         return 0;
584 }
585
586 /*
587  *      Create a new REQUEST data structure.
588  */
589 REQUEST *request_alloc(TALLOC_CTX *ctx)
590 {
591         REQUEST *request;
592
593         request = talloc_zero(ctx, REQUEST);
594         if (!request) return NULL;
595         talloc_set_destructor(request, _request_free);
596 #ifndef NDEBUG
597         request->magic = REQUEST_MAGIC;
598 #endif
599 #ifdef WITH_PROXY
600         request->proxy = NULL;
601 #endif
602         request->reply = NULL;
603 #ifdef WITH_PROXY
604         request->proxy_reply = NULL;
605 #endif
606         request->config = NULL;
607         request->username = NULL;
608         request->password = NULL;
609         request->timestamp = time(NULL);
610         request->log.lvl = rad_debug_lvl; /* Default to global debug level */
611
612         request->module = "";
613         request->component = "<core>";
614         request->log.func = vradlog_request;
615
616         return request;
617 }
618
619
620 /*
621  *      Create a new REQUEST, based on an old one.
622  *
623  *      This function allows modules to inject fake requests
624  *      into the server, for tunneled protocols like TTLS & PEAP.
625  */
626 REQUEST *request_alloc_fake(REQUEST *request)
627 {
628         REQUEST *fake;
629
630         fake = request_alloc(request);
631         if (!fake) return NULL;
632
633         fake->number = request->number;
634 #ifdef HAVE_PTHREAD_H
635         fake->child_pid = request->child_pid;
636 #endif
637         fake->parent = request;
638         fake->root = request->root;
639         fake->client = request->client;
640
641         /*
642          *      For new server support.
643          *
644          *      FIXME: Key instead off of a "virtual server" data structure.
645          *
646          *      FIXME: Permit different servers for inner && outer sessions?
647          */
648         fake->server = request->server;
649
650         fake->packet = rad_alloc(fake, true);
651         if (!fake->packet) {
652                 talloc_free(fake);
653                 return NULL;
654         }
655
656         fake->reply = rad_alloc(fake, false);
657         if (!fake->reply) {
658                 talloc_free(fake);
659                 return NULL;
660         }
661
662         fake->master_state = REQUEST_ACTIVE;
663         fake->child_state = REQUEST_RUNNING;
664
665         /*
666          *      Fill in the fake request.
667          */
668         fake->packet->sockfd = -1;
669         fake->packet->src_ipaddr = request->packet->src_ipaddr;
670         fake->packet->src_port = request->packet->src_port;
671         fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
672         fake->packet->dst_port = 0;
673
674         /*
675          *      This isn't STRICTLY required, as the fake request MUST NEVER
676          *      be put into the request list.  However, it's still reasonable
677          *      practice.
678          */
679         fake->packet->id = fake->number & 0xff;
680         fake->packet->code = request->packet->code;
681         fake->timestamp = request->timestamp;
682         fake->packet->timestamp = request->packet->timestamp;
683
684         /*
685          *      Required for new identity support
686          */
687         fake->listener = request->listener;
688
689         /*
690          *      Fill in the fake reply, based on the fake request.
691          */
692         fake->reply->sockfd = fake->packet->sockfd;
693         fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
694         fake->reply->src_port = fake->packet->dst_port;
695         fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
696         fake->reply->dst_port = fake->packet->src_port;
697         fake->reply->id = fake->packet->id;
698         fake->reply->code = 0; /* UNKNOWN code */
699
700         /*
701          *      Copy debug information.
702          */
703         memcpy(&(fake->log), &(request->log), sizeof(fake->log));
704         fake->log.indent = 0;   /* Apart from the indent which we reset */
705
706         return fake;
707 }
708
709 #ifdef WITH_COA
710 REQUEST *request_alloc_coa(REQUEST *request)
711 {
712         if (!request || request->coa) return NULL;
713
714         /*
715          *      Originate CoA requests only when necessary.
716          */
717         if ((request->packet->code != PW_CODE_ACCESS_REQUEST) &&
718             (request->packet->code != PW_CODE_ACCOUNTING_REQUEST)) return NULL;
719
720         request->coa = request_alloc_fake(request);
721         if (!request->coa) return NULL;
722
723         request->coa->options = RAD_REQUEST_OPTION_COA; /* is a CoA packet */
724         request->coa->packet->code = 0; /* unknown, as of yet */
725         request->coa->child_state = REQUEST_RUNNING;
726         request->coa->proxy = rad_alloc(request->coa, false);
727         if (!request->coa->proxy) {
728                 TALLOC_FREE(request->coa);
729                 return NULL;
730         }
731
732         return request->coa;
733 }
734 #endif
735
736 /*
737  *      Copy a quoted string.
738  */
739 int rad_copy_string(char *to, char const *from)
740 {
741         int length = 0;
742         char quote = *from;
743
744         do {
745                 if (*from == '\\') {
746                         *(to++) = *(from++);
747                         length++;
748                 }
749                 *(to++) = *(from++);
750                 length++;
751         } while (*from && (*from != quote));
752
753         if (*from != quote) return -1; /* not properly quoted */
754
755         *(to++) = quote;
756         length++;
757         *to = '\0';
758
759         return length;
760 }
761
762 /*
763  *      Copy a quoted string but without the quotes. The length
764  *      returned is the number of chars written; the number of
765  *      characters consumed is 2 more than this.
766  */
767 int rad_copy_string_bare(char *to, char const *from)
768 {
769         int length = 0;
770         char quote = *from;
771
772         from++;
773         while (*from && (*from != quote)) {
774                 if (*from == '\\') {
775                         *(to++) = *(from++);
776                         length++;
777                 }
778                 *(to++) = *(from++);
779                 length++;
780         }
781
782         if (*from != quote) return -1; /* not properly quoted */
783
784         *to = '\0';
785
786         return length;
787 }
788
789
790 /*
791  *      Copy a %{} string.
792  */
793 int rad_copy_variable(char *to, char const *from)
794 {
795         int length = 0;
796         int sublen;
797
798         *(to++) = *(from++);
799         length++;
800
801         while (*from) {
802                 switch (*from) {
803                 case '"':
804                 case '\'':
805                         sublen = rad_copy_string(to, from);
806                         if (sublen < 0) return sublen;
807                         from += sublen;
808                         to += sublen;
809                         length += sublen;
810                         break;
811
812                 case '}':       /* end of variable expansion */
813                         *(to++) = *(from++);
814                         *to = '\0';
815                         length++;
816                         return length; /* proper end of variable */
817
818                 case '\\':
819                         *(to++) = *(from++);
820                         *(to++) = *(from++);
821                         length += 2;
822                         break;
823
824                 case '%':       /* start of variable expansion */
825                         if (from[1] == '{') {
826                                 *(to++) = *(from++);
827                                 length++;
828
829                                 sublen = rad_copy_variable(to, from);
830                                 if (sublen < 0) return sublen;
831                                 from += sublen;
832                                 to += sublen;
833                                 length += sublen;
834                                 break;
835                         } /* else FIXME: catch %%{ ?*/
836
837                         /* FALL-THROUGH */
838                 default:
839                         *(to++) = *(from++);
840                         length++;
841                         break;
842                 }
843         } /* loop over the input string */
844
845         /*
846          *      We ended the string before a trailing '}'
847          */
848
849         return -1;
850 }
851
852 #ifndef USEC
853 #define USEC 1000000
854 #endif
855
856 uint32_t rad_pps(uint32_t *past, uint32_t *present, time_t *then, struct timeval *now)
857 {
858         uint32_t pps;
859
860         if (*then != now->tv_sec) {
861                 *then = now->tv_sec;
862                 *past = *present;
863                 *present = 0;
864         }
865
866         /*
867          *      Bootstrap PPS by looking at a percentage of
868          *      the previous PPS.  This lets us take a moving
869          *      count, without doing a moving average.  If
870          *      we're a fraction "f" (0..1) into the current
871          *      second, we can get a good guess for PPS by
872          *      doing:
873          *
874          *      PPS = pps_now + pps_old * (1 - f)
875          *
876          *      It's an instantaneous measurement, rather than
877          *      a moving average.  This will hopefully let it
878          *      respond better to sudden spikes.
879          *
880          *      Doing the calculations by thousands allows us
881          *      to not overflow 2^32, AND to not underflow
882          *      when we divide by USEC.
883          */
884         pps = USEC - now->tv_usec; /* useconds left in previous second */
885         pps /= 1000;               /* scale to milliseconds */
886         pps *= *past;              /* multiply by past count to get fraction */
887         pps /= 1000;               /* scale to usec again */
888         pps += *present;           /* add in current count */
889
890         return pps;
891 }
892
893 /** Split string into words and expand each one
894  *
895  * @param request Current request.
896  * @param cmd string to split.
897  * @param max_argc the maximum number of arguments to split into.
898  * @param argv Where to write the pointers into argv_buf.
899  * @param can_fail If false, stop processing if any of the xlat expansions fail.
900  * @param argv_buflen size of argv_buf.
901  * @param argv_buf temporary buffer we used to mangle/expand cmd.
902  *      Pointers to offsets of this buffer will be written to argv.
903  * @return argc or -1 on failure.
904  */
905
906 int rad_expand_xlat(REQUEST *request, char const *cmd,
907                     int max_argc, char const *argv[], bool can_fail,
908                     size_t argv_buflen, char *argv_buf)
909 {
910         char const *from;
911         char *to;
912         int argc = -1;
913         int i;
914         int left;
915
916         if (strlen(cmd) > (argv_buflen - 1)) {
917                 ERROR("rad_expand_xlat: Command line is too long");
918                 return -1;
919         }
920
921         /*
922          *      Check for bad escapes.
923          */
924         if (cmd[strlen(cmd) - 1] == '\\') {
925                 ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
926                 return -1;
927         }
928
929         strlcpy(argv_buf, cmd, argv_buflen);
930
931         /*
932          *      Split the string into argv's BEFORE doing radius_xlat...
933          */
934         from = cmd;
935         to = argv_buf;
936         argc = 0;
937         while (*from) {
938                 int length;
939
940                 /*
941                  *      Skip spaces.
942                  */
943                 if ((*from == ' ') || (*from == '\t')) {
944                         from++;
945                         continue;
946                 }
947
948                 argv[argc] = to;
949                 argc++;
950
951                 if (argc >= (max_argc - 1)) break;
952
953                 /*
954                  *      Copy the argv over to our buffer.
955                  */
956                 while (*from && (*from != ' ') && (*from != '\t')) {
957                         if (to >= argv_buf + argv_buflen - 1) {
958                                 ERROR("rad_expand_xlat: Ran out of space in command line");
959                                 return -1;
960                         }
961
962                         switch (*from) {
963                         case '"':
964                         case '\'':
965                                 length = rad_copy_string_bare(to, from);
966                                 if (length < 0) {
967                                         ERROR("rad_expand_xlat: Invalid string passed as argument");
968                                         return -1;
969                                 }
970                                 from += length+2;
971                                 to += length;
972                                 break;
973
974                         case '%':
975                                 if (from[1] == '{') {
976                                         *(to++) = *(from++);
977
978                                         length = rad_copy_variable(to, from);
979                                         if (length < 0) {
980                                                 ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
981                                                 return -1;
982                                         }
983                                         from += length;
984                                         to += length;
985                                 } else { /* FIXME: catch %%{ ? */
986                                         *(to++) = *(from++);
987                                 }
988                                 break;
989
990                         case '\\':
991                                 if (from[1] == ' ') from++;
992                                 /* FALL-THROUGH */
993
994                         default:
995                                 *(to++) = *(from++);
996                         }
997                 } /* end of string, or found a space */
998
999                 *(to++) = '\0'; /* terminate the string */
1000         }
1001
1002         /*
1003          *      We have to have SOMETHING, at least.
1004          */
1005         if (argc <= 0) {
1006                 ERROR("rad_expand_xlat: Empty command line");
1007                 return -1;
1008         }
1009
1010         /*
1011          *      Expand each string, as appropriate.
1012          */
1013         left = argv_buf + argv_buflen - to;
1014         for (i = 0; i < argc; i++) {
1015                 int sublen;
1016
1017                 /*
1018                  *      Don't touch argv's which won't be translated.
1019                  */
1020                 if (strchr(argv[i], '%') == NULL) continue;
1021
1022                 if (!request) continue;
1023
1024                 sublen = radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
1025                 if (sublen <= 0) {
1026                         if (can_fail) {
1027                                 /*
1028                                  *      Fail to be backwards compatible.
1029                                  *
1030                                  *      It's yucky, but it won't break anything,
1031                                  *      and it won't cause security problems.
1032                                  */
1033                                 sublen = 0;
1034                         } else {
1035                                 ERROR("rad_expand_xlat: xlat failed");
1036                                 return -1;
1037                         }
1038                 }
1039
1040                 argv[i] = to;
1041                 to += sublen;
1042                 *(to++) = '\0';
1043                 left -= sublen;
1044                 left--;
1045
1046                 if (left <= 0) {
1047                         ERROR("rad_expand_xlat: Ran out of space while expanding arguments");
1048                         return -1;
1049                 }
1050         }
1051         argv[argc] = NULL;
1052
1053         return argc;
1054 }
1055
1056 #ifndef NDEBUG
1057 /*
1058  *      Verify a packet.
1059  */
1060 static void verify_packet(char const *file, int line, REQUEST *request, RADIUS_PACKET *packet, char const *type)
1061 {
1062         TALLOC_CTX *parent;
1063
1064         if (!packet) {
1065                 fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%i]: RADIUS_PACKET %s pointer was NULL", file, line, type);
1066                 fr_assert(0);
1067                 fr_exit_now(0);
1068         }
1069
1070         parent = talloc_parent(packet);
1071         if (parent != request) {
1072                 ERROR("CONSISTENCY CHECK FAILED %s[%i]: Expected RADIUS_PACKET %s to be parented by %p (%s), "
1073                       "but parented by %p (%s)", file, line, type, request, talloc_get_name(request),
1074                       parent, parent ? talloc_get_name(parent) : "NULL");
1075
1076                 fr_log_talloc_report(packet);
1077                 if (parent) fr_log_talloc_report(parent);
1078
1079                 rad_assert(0);
1080         }
1081
1082         VERIFY_PACKET(packet);
1083
1084         if (!packet->vps) return;
1085
1086 #ifdef WITH_VERIFY_PTR
1087         fr_pair_list_verify(file, line, packet, packet->vps);
1088 #endif
1089 }
1090 /*
1091  *      Catch horrible talloc errors.
1092  */
1093 void verify_request(char const *file, int line, REQUEST *request)
1094 {
1095         if (!request) {
1096                 fprintf(stderr, "CONSISTENCY CHECK FAILED %s[%i]: REQUEST pointer was NULL", file, line);
1097                 fr_assert(0);
1098                 fr_exit_now(0);
1099         }
1100
1101         (void) talloc_get_type_abort(request, REQUEST);
1102
1103 #ifdef WITH_VERIFY_PTR
1104         fr_pair_list_verify(file, line, request, request->config);
1105         fr_pair_list_verify(file, line, request, request->state);
1106 #endif
1107
1108         if (request->packet) verify_packet(file, line, request, request->packet, "request");
1109         if (request->reply) verify_packet(file, line, request, request->reply, "reply");
1110 #ifdef WITH_PROXY
1111         if (request->proxy) verify_packet(file, line, request, request->proxy, "proxy-request");
1112         if (request->proxy_reply) verify_packet(file, line, request, request->proxy_reply, "proxy-reply");
1113 #endif
1114
1115 #ifdef WITH_COA
1116         if (request->coa) {
1117                 void *parent;
1118
1119                 (void) talloc_get_type_abort(request->coa, REQUEST);
1120                 parent = talloc_parent(request->coa);
1121
1122                 rad_assert(parent == request);
1123
1124                 verify_request(file, line, request->coa);
1125         }
1126 #endif
1127 }
1128 #endif
1129
1130 /** Convert mode_t into humanly readable permissions flags
1131  *
1132  * @author Jonathan Leffler.
1133  *
1134  * @param mode to convert.
1135  * @param out Where to write the string to, must be exactly 10 bytes long.
1136  */
1137 void rad_mode_to_str(char out[10], mode_t mode)
1138 {
1139     static char const *rwx[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
1140
1141     strcpy(&out[0], rwx[(mode >> 6) & 0x07]);
1142     strcpy(&out[3], rwx[(mode >> 3) & 0x07]);
1143     strcpy(&out[6], rwx[(mode & 7)]);
1144     if (mode & S_ISUID) out[2] = (mode & 0100) ? 's' : 'S';
1145     if (mode & S_ISGID) out[5] = (mode & 0010) ? 's' : 'l';
1146     if (mode & S_ISVTX) out[8] = (mode & 0100) ? 't' : 'T';
1147     out[9] = '\0';
1148 }
1149
1150 void rad_mode_to_oct(char out[5], mode_t mode)
1151 {
1152         out[0] = '0' + ((mode >> 9) & 0x07);
1153         out[1] = '0' + ((mode >> 6) & 0x07);
1154         out[2] = '0' + ((mode >> 3) & 0x07);
1155         out[3] = '0' + (mode & 0x07);
1156         out[4] = '\0';
1157 }
1158
1159 /** Resolve a uid to a passwd entry
1160  *
1161  * Resolves a uid to a passwd entry. The memory to hold the
1162  * passwd entry is talloced under ctx, and must be freed when no
1163  * longer required.
1164  *
1165  * @param ctx to allocate passwd entry in.
1166  * @param out Where to write pointer to entry.
1167  * @param uid to resolve.
1168  * @return 0 on success, -1 on error.
1169  */
1170 int rad_getpwuid(TALLOC_CTX *ctx, struct passwd **out, uid_t uid)
1171 {
1172         static size_t len;
1173         uint8_t *buff;
1174         int ret;
1175
1176         *out = NULL;
1177
1178         /*
1179          *      We assume this won't change between calls,
1180          *      and that the value is the same, so races don't
1181          *      matter.
1182          */
1183         if (len == 0) {
1184 #ifdef _SC_GETPW_R_SIZE_MAX
1185                 long int sc_len;
1186
1187                 sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
1188                 if (sc_len <= 0) sc_len = 1024;
1189                 len = (size_t)sc_len;
1190 #else
1191                 len = 1024;
1192 #endif
1193         }
1194
1195         buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
1196         if (!buff) return -1;
1197
1198         /*
1199          *      In some cases we may need to dynamically
1200          *      grow the string buffer.
1201          */
1202         while ((ret = getpwuid_r(uid, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
1203                                  talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
1204                 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1205                 if (!buff) {
1206                         talloc_free(buff);
1207                         return -1;
1208                 }
1209         }
1210
1211         if ((ret != 0) || !*out) {
1212                 fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
1213                 talloc_free(buff);
1214                 errno = ret;
1215                 return -1;
1216         }
1217
1218         talloc_set_type(buff, struct passwd);
1219         *out = (struct passwd *)buff;
1220
1221         return 0;
1222 }
1223
1224 /** Resolve a username to a passwd entry
1225  *
1226  * Resolves a username to a passwd entry. The memory to hold the
1227  * passwd entry is talloced under ctx, and must be freed when no
1228  * longer required.
1229  *
1230  * @param ctx to allocate passwd entry in.
1231  * @param out Where to write pointer to entry.
1232  * @param name to resolve.
1233  * @return 0 on success, -1 on error.
1234  */
1235 int rad_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
1236 {
1237         static size_t len;
1238         uint8_t *buff;
1239         int ret;
1240
1241         *out = NULL;
1242
1243         /*
1244          *      We assume this won't change between calls,
1245          *      and that the value is the same, so races don't
1246          *      matter.
1247          */
1248         if (len == 0) {
1249 #ifdef _SC_GETPW_R_SIZE_MAX
1250                 long int sc_len;
1251
1252                 sc_len = sysconf(_SC_GETPW_R_SIZE_MAX);
1253                 if (sc_len <= 0) sc_len = 1024;
1254                 len = (size_t)sc_len;
1255 #else
1256                 sc_len = 1024;
1257 #endif
1258         }
1259
1260         buff = talloc_array(ctx, uint8_t, sizeof(struct passwd) + len);
1261         if (!buff) return -1;
1262
1263         /*
1264          *      In some cases we may need to dynamically
1265          *      grow the string buffer.
1266          */
1267         while ((ret = getpwnam_r(name, (struct passwd *)buff, (char *)(buff + sizeof(struct passwd)),
1268                                  talloc_array_length(buff) - sizeof(struct passwd), out)) == ERANGE) {
1269                 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1270                 if (!buff) {
1271                         talloc_free(buff);
1272                         return -1;
1273                 }
1274         }
1275
1276         if ((ret != 0) || !*out) {
1277                 fr_strerror_printf("Failed resolving UID: %s", fr_syserror(ret));
1278                 talloc_free(buff);
1279                 errno = ret;
1280                 return -1;
1281         }
1282
1283         talloc_set_type(buff, struct passwd);
1284         *out = (struct passwd *)buff;
1285
1286         return 0;
1287 }
1288
1289 /** Resolve a gid to a group database entry
1290  *
1291  * Resolves a gid to a group database entry. The memory to hold the
1292  * group entry is talloced under ctx, and must be freed when no
1293  * longer required.
1294  *
1295  * @param ctx to allocate passwd entry in.
1296  * @param out Where to write pointer to entry.
1297  * @param gid to resolve.
1298  * @return 0 on success, -1 on error.
1299  */
1300 int rad_getgrgid(TALLOC_CTX *ctx, struct group **out, gid_t gid)
1301 {
1302         static size_t len;
1303         uint8_t *buff;
1304         int ret;
1305
1306         *out = NULL;
1307
1308         /*
1309          *      We assume this won't change between calls,
1310          *      and that the value is the same, so races don't
1311          *      matter.
1312          */
1313         if (len == 0) {
1314 #ifdef _SC_GETGR_R_SIZE_MAX
1315                 long int sc_len;
1316
1317                 sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1318                 if (sc_len <= 0) sc_len = 1024;
1319                 len = (size_t)sc_len;
1320 #else
1321                 sc_len = 1024;
1322 #endif
1323         }
1324
1325         buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
1326         if (!buff) return -1;
1327
1328         /*
1329          *      In some cases we may need to dynamically
1330          *      grow the string buffer.
1331          */
1332         while ((ret = getgrgid_r(gid, (struct group *)buff, (char *)(buff + sizeof(struct group)),
1333                                  talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
1334                 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1335                 if (!buff) {
1336                         talloc_free(buff);
1337                         return -1;
1338                 }
1339         }
1340
1341         if ((ret != 0) || !*out) {
1342                 fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
1343                 talloc_free(buff);
1344                 errno = ret;
1345                 return -1;
1346         }
1347
1348         talloc_set_type(buff, struct group);
1349         *out = (struct group *)buff;
1350
1351         return 0;
1352 }
1353
1354 /** Resolve a group name to a group database entry
1355  *
1356  * Resolves a group name to a group database entry.
1357  * The memory to hold the group entry is talloced under ctx,
1358  * and must be freed when no longer required.
1359  *
1360  * @param ctx to allocate passwd entry in.
1361  * @param out Where to write pointer to entry.
1362  * @param name to resolve.
1363  * @return 0 on success, -1 on error.
1364  */
1365 int rad_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
1366 {
1367         static size_t len;
1368         uint8_t *buff;
1369         int ret;
1370
1371         *out = NULL;
1372
1373         /*
1374          *      We assume this won't change between calls,
1375          *      and that the value is the same, so races don't
1376          *      matter.
1377          */
1378         if (len == 0) {
1379 #ifdef _SC_GETGR_R_SIZE_MAX
1380                 long int sc_len;
1381
1382                 sc_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1383                 if (sc_len <= 0) sc_len = 1024;
1384                 len = (size_t)sc_len;
1385 #else
1386                 len = 1024;
1387 #endif
1388         }
1389
1390         buff = talloc_array(ctx, uint8_t, sizeof(struct group) + len);
1391         if (!buff) return -1;
1392
1393         /*
1394          *      In some cases we may need to dynamically
1395          *      grow the string buffer.
1396          */
1397         while ((ret = getgrnam_r(name, (struct group *)buff, (char *)(buff + sizeof(struct group)),
1398                                  talloc_array_length(buff) - sizeof(struct group), out)) == ERANGE) {
1399                 buff = talloc_realloc_size(ctx, buff, talloc_array_length(buff) * 2);
1400                 if (!buff) {
1401                         talloc_free(buff);
1402                         return -1;
1403                 }
1404         }
1405
1406         if ((ret != 0) || !*out) {
1407                 fr_strerror_printf("Failed resolving GID: %s", fr_syserror(ret));
1408                 talloc_free(buff);
1409                 errno = ret;
1410                 return -1;
1411         }
1412
1413         talloc_set_type(buff, struct group);
1414         *out = (struct group *)buff;
1415
1416         return 0;
1417 }
1418
1419 /** Resolve a group name to a GID
1420  *
1421  * @param ctx TALLOC_CTX for temporary allocations.
1422  * @param name of group.
1423  * @param out where to write gid.
1424  * @return 0 on success, -1 on error;
1425  */
1426 int rad_getgid(TALLOC_CTX *ctx, gid_t *out, char const *name)
1427 {
1428         int ret;
1429         struct group *result;
1430
1431         ret = rad_getgrnam(ctx, &result, name);
1432         if (ret < 0) return -1;
1433
1434         *out = result->gr_gid;
1435         talloc_free(result);
1436         return 0;
1437 }
1438
1439 /** Print uid to a string
1440  *
1441  * @note The reason for taking a fixed buffer is pure laziness.
1442  *       It means the caller doesn't have to free the string.
1443  *
1444  * @note Will always \0 terminate the buffer, even on error.
1445  *
1446  * @param ctx TALLOC_CTX for temporary allocations.
1447  * @param out Where to write the uid string.
1448  * @param outlen length of output buffer.
1449  * @param uid to resolve.
1450  * @return 0 on success, -1 on failure.
1451  */
1452 int rad_prints_uid(TALLOC_CTX *ctx, char *out, size_t outlen, uid_t uid)
1453 {
1454         struct passwd *result;
1455
1456         rad_assert(outlen > 0);
1457
1458         *out = '\0';
1459
1460         if (rad_getpwuid(ctx, &result, uid) < 0) return -1;
1461         strlcpy(out, result->pw_name, outlen);
1462         talloc_free(result);
1463
1464         return 0;
1465 }
1466
1467 /** Print gid to a string
1468  *
1469  * @note The reason for taking a fixed buffer is pure laziness.
1470  *       It means the caller doesn't have to free the string.
1471  *
1472  * @note Will always \0 terminate the buffer, even on error.
1473  *
1474  * @param ctx TALLOC_CTX for temporary allocations.
1475  * @param out Where to write the uid string.
1476  * @param outlen length of output buffer.
1477  * @param gid to resolve.
1478  * @return 0 on success, -1 on failure.
1479  */
1480 int rad_prints_gid(TALLOC_CTX *ctx, char *out, size_t outlen, gid_t gid)
1481 {
1482         struct group *result;
1483
1484         rad_assert(outlen > 0);
1485
1486         *out = '\0';
1487
1488         if (rad_getgrgid(ctx, &result, gid) < 0) return -1;
1489         strlcpy(out, result->gr_name, outlen);
1490         talloc_free(result);
1491
1492         return 0;
1493 }
1494
1495 #ifdef HAVE_SETUID
1496 static bool doing_setuid = false;
1497 static uid_t suid_down_uid = (uid_t)-1;
1498
1499 /** Set the uid and gid used when dropping privileges
1500  *
1501  * @note if this function hasn't been called, rad_suid_down will have no effect.
1502  *
1503  * @param uid to drop down to.
1504  */
1505 void rad_suid_set_down_uid(uid_t uid)
1506 {
1507         suid_down_uid = uid;
1508         doing_setuid = true;
1509 }
1510
1511 #  if defined(HAVE_SETRESUID) && defined (HAVE_GETRESUID)
1512 void rad_suid_up(void)
1513 {
1514         uid_t ruid, euid, suid;
1515
1516         if (getresuid(&ruid, &euid, &suid) < 0) {
1517                 ERROR("Failed getting saved UID's");
1518                 fr_exit_now(1);
1519         }
1520
1521         if (setresuid(-1, suid, -1) < 0) {
1522                 ERROR("Failed switching to privileged user");
1523                 fr_exit_now(1);
1524         }
1525
1526         if (geteuid() != suid) {
1527                 ERROR("Switched to unknown UID");
1528                 fr_exit_now(1);
1529         }
1530 }
1531
1532 void rad_suid_down(void)
1533 {
1534         if (!doing_setuid) return;
1535
1536         if (setresuid(-1, suid_down_uid, geteuid()) < 0) {
1537                 struct passwd *passwd;
1538                 char const *name;
1539
1540                 name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
1541                 ERROR("Failed switching to uid %s: %s", name, fr_syserror(errno));
1542                 talloc_free(passwd);
1543                 fr_exit_now(1);
1544         }
1545
1546         if (geteuid() != suid_down_uid) {
1547                 ERROR("Failed switching uid: UID is incorrect");
1548                 fr_exit_now(1);
1549         }
1550
1551         fr_reset_dumpable();
1552 }
1553
1554 void rad_suid_down_permanent(void)
1555 {
1556         if (!doing_setuid) return;
1557
1558         if (setresuid(suid_down_uid, suid_down_uid, suid_down_uid) < 0) {
1559                 struct passwd *passwd;
1560                 char const *name;
1561
1562                 name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown" : passwd->pw_name;
1563                 ERROR("Failed in permanent switch to uid %s: %s", name, fr_syserror(errno));
1564                 talloc_free(passwd);
1565                 fr_exit_now(1);
1566         }
1567
1568         if (geteuid() != suid_down_uid) {
1569                 ERROR("Switched to unknown uid");
1570                 fr_exit_now(1);
1571         }
1572
1573         fr_reset_dumpable();
1574 }
1575 #  else
1576 /*
1577  *      Much less secure...
1578  */
1579 void rad_suid_up(void)
1580 {
1581         if (!doing_setuid) return;
1582
1583         if (seteuid(0) < 0) {
1584                 ERROR("Failed switching up to euid 0: %s", fr_syserror(errno));
1585                 fr_exit_now(1);
1586         }
1587
1588 }
1589
1590 void rad_suid_down(void)
1591 {
1592         if (!doing_setuid) return;
1593
1594         if (geteuid() == suid_down_uid) return;
1595
1596         if (seteuid(suid_down_uid) < 0) {
1597                 struct passwd *passwd;
1598                 char const *name;
1599
1600                 name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
1601                 ERROR("Failed switching to euid %s: %s", name, fr_syserror(errno));
1602                 talloc_free(passwd);
1603                 fr_exit_now(1);
1604         }
1605
1606         fr_reset_dumpable();
1607 }
1608
1609 void rad_suid_down_permanent(void)
1610 {
1611         if (!doing_setuid) return;
1612
1613         /*
1614          *      Already done.  Don't do anything else.
1615          */
1616         if (getuid() == suid_down_uid) return;
1617
1618         /*
1619          *      We're root, but running as a normal user.  Fix that,
1620          *      so we can call setuid().
1621          */
1622         if (geteuid() == suid_down_uid) {
1623                 rad_suid_up();
1624         }
1625
1626         if (setuid(suid_down_uid) < 0) {
1627                 struct passwd *passwd;
1628                 char const *name;
1629
1630                 name = (rad_getpwuid(NULL, &passwd, suid_down_uid) < 0) ? "unknown": passwd->pw_name;
1631                 ERROR("Failed switching permanently to uid %s: %s", name, fr_syserror(errno));
1632                 talloc_free(passwd);
1633                 fr_exit_now(1);
1634         }
1635
1636         fr_reset_dumpable();
1637 }
1638 #  endif /* HAVE_SETRESUID && HAVE_GETRESUID */
1639 #else  /* HAVE_SETUID */
1640 void rad_suid_set_down_uid(uid_t uid)
1641 {
1642 }
1643 void rad_suid_up(void)
1644 {
1645 }
1646 void rad_suid_down(void)
1647 {
1648         fr_reset_dumpable();
1649 }
1650 void rad_suid_down_permanent(void)
1651 {
1652         fr_reset_dumpable();
1653 }
1654 #endif /* HAVE_SETUID */
1655
1656 /** Alter the effective user id
1657  *
1658  * @param uid to set
1659  * @return 0 on success -1 on failure.
1660  */
1661 int rad_seuid(uid_t uid)
1662 {
1663         if (seteuid(uid) < 0) {
1664                 struct passwd *passwd;
1665
1666                 if (rad_getpwuid(NULL, &passwd, uid) < 0) return -1;
1667                 fr_strerror_printf("Failed setting euid to %s", passwd->pw_name);
1668                 talloc_free(passwd);
1669
1670                 return -1;
1671         }
1672         return 0;
1673 }
1674
1675 /** Alter the effective user id
1676  *
1677  * @param gid to set
1678  * @return 0 on success -1 on failure.
1679  */
1680 int rad_segid(gid_t gid)
1681 {
1682         if (setegid(gid) < 0) {
1683                 struct group *group;
1684
1685                 if (rad_getgrgid(NULL, &group, gid) < 0) return -1;
1686                 fr_strerror_printf("Failed setting egid to %s", group->gr_name);
1687                 talloc_free(group);
1688
1689                 return -1;
1690         }
1691         return 0;
1692 }