2 * util.c Various utility functions.
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.
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.
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
20 * Copyright 2000,2006 The FreeRADIUS server project
25 #include <freeradius-devel/radiusd.h>
26 #include <freeradius-devel/rad_assert.h>
35 * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
36 * sa_flags, which causes grief if signal() is called in the
37 * handler before the cause of the signal has been cleared.
38 * (Infinite recursion).
40 * The same problem appears on HPUX, so we avoid it, if we can.
42 * Using sigaction() to reset the signal handler fixes the problem,
43 * so where available, we prefer that solution.
46 void (*reset_signal(int signo, void (*func)(int)))(int)
49 struct sigaction act, oact;
51 memset(&act, 0, sizeof(act));
52 act.sa_handler = func;
53 sigemptyset(&act.sa_mask);
55 #ifdef SA_INTERRUPT /* SunOS */
56 act.sa_flags |= SA_INTERRUPT;
58 if (sigaction(signo, &act, &oact) < 0)
60 return oact.sa_handler;
64 * re-set by calling the 'signal' function, which
65 * may cause infinite recursion and core dumps due to
68 * However, the system is too dumb to implement sigaction(),
69 * so we don't have a choice.
78 * Per-request data, added by modules...
80 struct request_data_t {
86 void (*free_opaque)(void *);
90 * Add opaque data (with a "free" function) to a REQUEST.
92 * The unique ptr is meant to be a module configuration,
93 * and the unique integer allows the caller to have multiple
94 * opaque data associated with a REQUEST.
96 int request_data_add(REQUEST *request,
97 void *unique_ptr, int unique_int,
98 void *opaque, void (*free_opaque)(void *))
100 request_data_t *this, **last, *next;
103 * Some simple sanity checks.
105 if (!request || !opaque) return -1;
108 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
109 if (((*last)->unique_ptr == unique_ptr) &&
110 ((*last)->unique_int == unique_int)) {
115 if (this->opaque && /* free it, if necessary */
117 this->free_opaque(this->opaque);
118 break; /* replace the existing entry */
122 if (!this) this = rad_malloc(sizeof(*this));
123 memset(this, 0, sizeof(*this));
126 this->unique_ptr = unique_ptr;
127 this->unique_int = unique_int;
128 this->opaque = opaque;
129 this->free_opaque = free_opaque;
138 * Get opaque data from a request.
140 void *request_data_get(REQUEST *request,
141 void *unique_ptr, int unique_int)
143 request_data_t **last;
145 if (!request) return NULL;
147 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
148 if (((*last)->unique_ptr == unique_ptr) &&
149 ((*last)->unique_int == unique_int)) {
150 request_data_t *this = *last;
151 void *ptr = this->opaque;
154 * Remove the entry from the list, and free it.
158 return ptr; /* don't free it, the caller does that */
162 return NULL; /* wasn't found, too bad... */
167 * Get opaque data from a request without removing it.
169 void *request_data_reference(REQUEST *request,
170 void *unique_ptr, int unique_int)
172 request_data_t **last;
174 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
175 if (((*last)->unique_ptr == unique_ptr) &&
176 ((*last)->unique_int == unique_int)) {
177 request_data_t *this = *last;
178 void *ptr = this->opaque;
184 return NULL; /* wasn't found, too bad... */
189 * Free a REQUEST struct.
191 void request_free(REQUEST **request_ptr)
195 if (!request_ptr || !*request_ptr) {
199 request = *request_ptr;
201 rad_assert(!request->in_request_hash);
203 rad_assert(!request->in_proxy_hash);
205 rad_assert(!request->ev);
208 rad_free(&request->packet);
212 rad_free(&request->proxy);
216 rad_free(&request->reply);
219 if (request->proxy_reply)
220 rad_free(&request->proxy_reply);
223 if (request->config_items)
224 pairfree(&request->config_items);
226 request->username = NULL;
227 request->password = NULL;
230 request_data_t *this, *next;
232 for (this = request->data; this != NULL; this = next) {
234 if (this->opaque && /* free it, if necessary */
236 this->free_opaque(this->opaque);
239 request->data = NULL;
243 (request->root->refcount > 0)) {
244 request->root->refcount--;
245 request->root = NULL;
250 request->coa->parent = NULL;
251 rad_assert(request->coa->ev == NULL);
252 request_free(&request->coa);
255 if (request->parent && (request->parent->coa == request)) {
256 request->parent->coa = NULL;
261 request->magic = 0x01020304; /* set the request to be nonsense */
263 request->client = NULL;
265 request->home_server = NULL;
267 talloc_free(request);
272 * Check a filename for sanity.
274 * Allow only uppercase/lowercase letters, numbers, and '-_/.'
276 int rad_checkfilename(char const *filename)
278 if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
285 /** Check if file exists
287 * @param filename to check.
288 * @return 0 if the file does not exist, 1 if the file exists, -1 if the file
289 * exists but there was an error opening it. errno value should be usable
290 * for error messages.
292 int rad_file_exists(char const *filename)
297 if ((des = open(filename, O_RDONLY)) == -1) {
298 if (errno == ENOENT) {
311 * Create possibly many directories.
313 * Note that the input directory name is NOT a constant!
314 * This is so that IF an error is returned, the 'directory' ptr
315 * points to the name of the file which caused the error.
317 int rad_mkdir(char *directory, mode_t mode)
324 * If the directory exists, don't do anything.
326 if (stat(directory, &st) == 0) {
331 * Look for the LAST directory name. Try to create that,
332 * failing on any error.
334 p = strrchr(directory, FR_DIR_SEP);
337 rcode = rad_mkdir(directory, mode);
340 * On error, we leave the directory name as the
341 * one which caused the error.
344 if (errno == EEXIST) return 0;
349 * Reset the directory delimiter, and go ask
350 * the system to make the directory.
358 * Having done everything successfully, we do the
359 * system call to actually go create the directory.
361 rcode = mkdir(directory, mode & 0777);
367 * Set things like sticky bits that aren't supported by
371 rcode = chmod(directory, mode);
379 * Allocate memory, or exit.
381 * This call ALWAYS succeeds!
383 void *rad_malloc(size_t size)
385 void *ptr = malloc(size);
396 void *rad_calloc(size_t size)
398 void *ptr = rad_malloc(size);
399 memset(ptr, 0, size);
403 void rad_const_free(void const *ptr)
408 memcpy(&tmp, &ptr, sizeof(tmp));
414 * Signature for free is dumb, and raises errors when we try
415 * to free const ptrs.
417 void rad_cfree(void const *ptr)
422 memcpy(&tmp, &ptr, sizeof(tmp));
427 * Logs an error message and aborts the program
431 void NEVER_RETURNS rad_assert_fail (char const *file, unsigned int line,
434 ERROR("ASSERT FAILED %s[%u]: %s", file, line, expr);
440 * Create a new REQUEST data structure.
442 REQUEST *request_alloc(void)
446 request = talloc_zero(NULL, REQUEST);
448 request->magic = REQUEST_MAGIC;
451 request->proxy = NULL;
453 request->reply = NULL;
455 request->proxy_reply = NULL;
457 request->config_items = NULL;
458 request->username = NULL;
459 request->password = NULL;
460 request->timestamp = time(NULL);
461 request->options = debug_flag; /* Default to global debug level */
463 request->module = "";
464 request->component = "<core>";
465 request->radlog = radlog_request;
472 * Create a new REQUEST, based on an old one.
474 * This function allows modules to inject fake requests
475 * into the server, for tunneled protocols like TTLS & PEAP.
477 REQUEST *request_alloc_fake(REQUEST *request)
481 fake = request_alloc();
483 fake->number = request->number;
484 #ifdef HAVE_PTHREAD_H
485 fake->child_pid = request->child_pid;
487 fake->parent = request;
488 fake->root = request->root;
489 fake->client = request->client;
492 * For new server support.
494 * FIXME: Key instead off of a "virtual server" data structure.
496 * FIXME: Permit different servers for inner && outer sessions?
498 fake->server = request->server;
500 fake->packet = rad_alloc(request, 1);
506 fake->reply = rad_alloc(request, 0);
512 fake->master_state = REQUEST_ACTIVE;
513 fake->child_state = REQUEST_RUNNING;
516 * Fill in the fake request.
518 fake->packet->sockfd = -1;
519 fake->packet->src_ipaddr = request->packet->src_ipaddr;
520 fake->packet->src_port = request->packet->src_port;
521 fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
522 fake->packet->dst_port = 0;
525 * This isn't STRICTLY required, as the fake request MUST NEVER
526 * be put into the request list. However, it's still reasonable
529 fake->packet->id = fake->number & 0xff;
530 fake->packet->code = request->packet->code;
531 fake->timestamp = request->timestamp;
534 * Required for new identity support
536 fake->listener = request->listener;
539 * Fill in the fake reply, based on the fake request.
541 fake->reply->sockfd = fake->packet->sockfd;
542 fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
543 fake->reply->src_port = fake->packet->dst_port;
544 fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
545 fake->reply->dst_port = fake->packet->src_port;
546 fake->reply->id = fake->packet->id;
547 fake->reply->code = 0; /* UNKNOWN code */
550 * Copy debug information.
552 fake->options = request->options;
553 fake->radlog = request->radlog;
559 REQUEST *request_alloc_coa(REQUEST *request)
561 if (!request || request->coa) return NULL;
564 * Originate CoA requests only when necessary.
566 if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
567 (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
569 request->coa = request_alloc_fake(request);
570 if (!request->coa) return NULL;
572 request->coa->packet->code = 0; /* unknown, as of yet */
573 request->coa->child_state = REQUEST_RUNNING;
574 request->coa->proxy = rad_alloc(request->coa, 0);
575 if (!request->coa->proxy) {
576 request_free(&request->coa);
585 * Copy a quoted string.
587 int rad_copy_string(char *to, char const *from)
599 } while (*from && (*from != quote));
601 if (*from != quote) return -1; /* not properly quoted */
611 * Copy a quoted string but without the quotes. The length
612 * returned is the number of chars written; the number of
613 * characters consumed is 2 more than this.
615 int rad_copy_string_bare(char *to, char const *from)
621 while (*from && (*from != quote)) {
630 if (*from != quote) return -1; /* not properly quoted */
641 int rad_copy_variable(char *to, char const *from)
653 sublen = rad_copy_string(to, from);
654 if (sublen < 0) return sublen;
660 case '}': /* end of variable expansion */
664 return length; /* proper end of variable */
672 case '%': /* start of variable expansion */
673 if (from[1] == '{') {
677 sublen = rad_copy_variable(to, from);
678 if (sublen < 0) return sublen;
683 } /* else FIXME: catch %%{ ?*/
691 } /* loop over the input string */
694 * We ended the string before a trailing '}'
704 int rad_pps(int *past, int *present, time_t *then, struct timeval *now)
708 if (*then != now->tv_sec) {
715 * Bootstrap PPS by looking at a percentage of
716 * the previous PPS. This lets us take a moving
717 * count, without doing a moving average. If
718 * we're a fraction "f" (0..1) into the current
719 * second, we can get a good guess for PPS by
722 * PPS = pps_now + pps_old * (1 - f)
724 * It's an instantaneous measurement, rather than
725 * a moving average. This will hopefully let it
726 * respond better to sudden spikes.
728 * Doing the calculations by thousands allows us
729 * to not overflow 2^32, AND to not underflow
730 * when we divide by USEC.
732 pps = USEC - now->tv_usec; /* useconds left in previous second */
733 pps /= 1000; /* scale to milliseconds */
734 pps *= *past; /* multiply by past count to get fraction */
735 pps /= 1000; /* scale to usec again */
736 pps += *present; /* add in current count */
741 /** Split string into words and expand each one
743 * @param request Current request.
744 * @param cmd string to split.
745 * @param max_argc the maximum number of arguments to split into.
746 * @param argv Where to write the pointers into argv_buf.
747 * @param can_fail If false, stop processing if any of the xlat expansions fail.
748 * @param argv_buflen size of argv_buf.
749 * @param argv_buf temporary buffer we used to mangle/expand cmd.
750 * Pointers to offsets of this buffer will be written to argv.
751 * @return argc or -1 on failure.
754 int rad_expand_xlat(REQUEST *request, char const *cmd,
755 int max_argc, char *argv[], bool can_fail,
756 size_t argv_buflen, char *argv_buf)
764 if (strlen(cmd) > (argv_buflen - 1)) {
765 ERROR("rad_expand_xlat: Command line is too long");
770 * Check for bad escapes.
772 if (cmd[strlen(cmd) - 1] == '\\') {
773 ERROR("rad_expand_xlat: Command line has final backslash, without a following character");
777 strlcpy(argv_buf, cmd, argv_buflen);
780 * Split the string into argv's BEFORE doing radius_xlat...
791 if ((*from == ' ') || (*from == '\t')) {
799 if (argc >= (max_argc - 1)) break;
802 * Copy the argv over to our buffer.
804 while (*from && (*from != ' ') && (*from != '\t')) {
805 if (to >= argv_buf + argv_buflen - 1) {
806 ERROR("rad_expand_xlat: Ran out of space in command line");
813 length = rad_copy_string_bare(to, from);
815 ERROR("rad_expand_xlat: Invalid string passed as argument");
823 if (from[1] == '{') {
826 length = rad_copy_variable(to, from);
828 ERROR("rad_expand_xlat: Invalid variable expansion passed as argument");
833 } else { /* FIXME: catch %%{ ? */
839 if (from[1] == ' ') from++;
845 } /* end of string, or found a space */
847 *(to++) = '\0'; /* terminate the string */
851 * We have to have SOMETHING, at least.
854 ERROR("rad_expand_xlat: Empty command line.");
859 * Expand each string, as appropriate.
861 left = argv_buf + argv_buflen - to;
862 for (i = 0; i < argc; i++) {
866 * Don't touch argv's which won't be translated.
868 if (strchr(argv[i], '%') == NULL) continue;
870 if (!request) continue;
872 sublen = radius_xlat(to, left - 1, request, argv[i], NULL, NULL);
876 * Fail to be backwards compatible.
878 * It's yucky, but it won't break anything,
879 * and it won't cause security problems.
883 ERROR("rad_expand_xlat: xlat failed");
895 ERROR("rad_expand_xlat: Ran out of space while expanding arguments.");
904 const FR_NAME_NUMBER pair_lists[] = {
905 { "request", PAIR_LIST_REQUEST },
906 { "reply", PAIR_LIST_REPLY },
907 { "config", PAIR_LIST_CONTROL },
908 { "control", PAIR_LIST_CONTROL },
910 { "proxy-request", PAIR_LIST_PROXY_REQUEST },
911 { "proxy-reply", PAIR_LIST_PROXY_REPLY },
914 { "coa", PAIR_LIST_COA },
915 { "coa-reply", PAIR_LIST_COA_REPLY },
916 { "disconnect", PAIR_LIST_DM },
917 { "disconnect-reply", PAIR_LIST_DM_REPLY },
922 const FR_NAME_NUMBER request_refs[] = {
923 { "outer", REQUEST_OUTER },
924 { "current", REQUEST_CURRENT },
925 { "parent", REQUEST_PARENT },
930 /** Resolve attribute name to a list.
932 * Check the name string for qualifiers that specify a list and return
933 * an pair_lists_t value for that list. This value may be passed to
934 * radius_list, along with the current request, to get a pointer to the
935 * actual list in the request.
937 * If qualifiers were consumed, write a new pointer into name to the
938 * char after the last qualifier to be consumed.
940 * radius_list_name should be called before passing a name string that
941 * may contain qualifiers to dict_attrbyname.
943 * @see dict_attrbyname
945 * @param[in,out] name of attribute.
946 * @param[in] unknown the list to return if no qualifiers were found.
947 * @return PAIR_LIST_UNKOWN if qualifiers couldn't be resolved to a list.
949 pair_lists_t radius_list_name(char const **name, pair_lists_t unknown)
951 char const *p = *name;
955 /* This should never be a NULL pointer or zero length string */
956 rad_assert(name && *name);
959 * We couldn't determine the list if:
961 * A colon delimiter was found, but the next char was a
962 * number, indicating a tag, not a list qualifier.
964 * No colon was found and the first char was upper case
965 * indicating an attribute.
969 if (((q && (q[1] >= '0') && (q[1] <= '9'))) ||
970 (!q && isupper((int) *p))) {
975 *name = (q + 1); /* Consume the list and delimiter */
976 return fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
979 q = (p + strlen(p)); /* Consume the entire string */
980 output = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
981 if (output != PAIR_LIST_UNKNOWN) {
990 /** Resolve attribute name to a request.
992 * Check the name string for qualifiers that reference a parent request and
993 * write the pointer to this request to 'request'.
995 * If qualifiers were consumed, write a new pointer into name to the
996 * char after the last qualifier to be consumed.
998 * radius_ref_request should be called before radius_list_name.
1000 * @see radius_list_name
1001 * @param[in,out] name of attribute.
1002 * @param[in] def default request ref to return if no request qualifier is present.
1003 * @return one of the REQUEST_* definitions or REQUEST_UNKOWN
1005 request_refs_t radius_request_name(char const **name, request_refs_t def)
1010 p = strchr(*name, '.');
1012 return REQUEST_CURRENT;
1016 * We may get passed "127.0.0.1".
1018 request = fr_substr2int(request_refs, *name, REQUEST_UNKNOWN,
1022 * If we get a VALID LIST, skip it.
1024 if (request != REQUEST_UNKNOWN) {
1030 * Otherwise leave it alone, and return the caller's
1036 /** Resolve request to a request.
1038 * Resolve name to a current request.
1041 * @param[in,out] context Base context to use, and to write the result back to.
1042 * @param[in] name (request) to resolve to.
1043 * @return 0 if request is valid in this context, else -1.
1045 int radius_request(REQUEST **context, request_refs_t name)
1047 REQUEST *request = *context;
1050 case REQUEST_CURRENT:
1053 case REQUEST_PARENT: /* for future use in request chaining */
1055 if (!request->parent) {
1056 RWDEBUG("Specified request \"%s\" is not available in this context",
1057 fr_int2str(request_refs, name, "¿unknown?"));
1061 *context = request->parent;
1065 case REQUEST_UNKNOWN: