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
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/rad_assert.h>
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).
41 * The same problem appears on HPUX, so we avoid it, if we can.
43 * Using sigaction() to reset the signal handler fixes the problem,
44 * so where available, we prefer that solution.
47 void (*reset_signal(int signo, void (*func)(int)))(int)
50 struct sigaction act, oact;
52 memset(&act, 0, sizeof(act));
53 act.sa_handler = func;
54 sigemptyset(&act.sa_mask);
56 #ifdef SA_INTERRUPT /* SunOS */
57 act.sa_flags |= SA_INTERRUPT;
59 if (sigaction(signo, &act, &oact) < 0)
61 return oact.sa_handler;
65 * re-set by calling the 'signal' function, which
66 * may cause infinite recursion and core dumps due to
69 * However, the system is too dumb to implement sigaction(),
70 * so we don't have a choice.
79 * Per-request data, added by modules...
81 struct request_data_t {
87 void (*free_opaque)(void *);
91 * Add opaque data (with a "free" function) to a REQUEST.
93 * The unique ptr is meant to be a module configuration,
94 * and the unique integer allows the caller to have multiple
95 * opaque data associated with a REQUEST.
97 int request_data_add(REQUEST *request,
98 void *unique_ptr, int unique_int,
99 void *opaque, void (*free_opaque)(void *))
101 request_data_t *this, **last, *next;
104 * Some simple sanity checks.
106 if (!request || !opaque) return -1;
109 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
110 if (((*last)->unique_ptr == unique_ptr) &&
111 ((*last)->unique_int == unique_int)) {
116 if (this->opaque && /* free it, if necessary */
118 this->free_opaque(this->opaque);
119 break; /* replace the existing entry */
123 if (!this) this = rad_malloc(sizeof(*this));
124 memset(this, 0, sizeof(*this));
127 this->unique_ptr = unique_ptr;
128 this->unique_int = unique_int;
129 this->opaque = opaque;
130 this->free_opaque = free_opaque;
139 * Get opaque data from a request.
141 void *request_data_get(REQUEST *request,
142 void *unique_ptr, int unique_int)
144 request_data_t **last;
146 if (!request) return NULL;
148 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
149 if (((*last)->unique_ptr == unique_ptr) &&
150 ((*last)->unique_int == unique_int)) {
151 request_data_t *this = *last;
152 void *ptr = this->opaque;
155 * Remove the entry from the list, and free it.
159 return ptr; /* don't free it, the caller does that */
163 return NULL; /* wasn't found, too bad... */
168 * Get opaque data from a request without removing it.
170 void *request_data_reference(REQUEST *request,
171 void *unique_ptr, int unique_int)
173 request_data_t **last;
175 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
176 if (((*last)->unique_ptr == unique_ptr) &&
177 ((*last)->unique_int == unique_int)) {
178 request_data_t *this = *last;
179 void *ptr = this->opaque;
185 return NULL; /* wasn't found, too bad... */
190 * Free a REQUEST struct.
192 void request_free(REQUEST **request_ptr)
196 if (!request_ptr || !*request_ptr) {
200 request = *request_ptr;
202 rad_assert(!request->in_request_hash);
204 rad_assert(!request->in_proxy_hash);
206 rad_assert(!request->ev);
209 rad_free(&request->packet);
213 rad_free(&request->proxy);
217 rad_free(&request->reply);
220 if (request->proxy_reply)
221 rad_free(&request->proxy_reply);
224 if (request->config_items)
225 pairfree(&request->config_items);
227 request->username = NULL;
228 request->password = NULL;
231 request_data_t *this, *next;
233 for (this = request->data; this != NULL; this = next) {
235 if (this->opaque && /* free it, if necessary */
237 this->free_opaque(this->opaque);
240 request->data = NULL;
244 (request->root->refcount > 0)) {
245 request->root->refcount--;
246 request->root = NULL;
251 request->coa->parent = NULL;
252 rad_assert(request->coa->ev == NULL);
253 request_free(&request->coa);
256 if (request->parent && (request->parent->coa == request)) {
257 request->parent->coa = NULL;
262 request->magic = 0x01020304; /* set the request to be nonsense */
264 request->client = NULL;
266 request->home_server = NULL;
268 talloc_free(request);
273 * Check a filename for sanity.
275 * Allow only uppercase/lowercase letters, numbers, and '-_/.'
277 int rad_checkfilename(const char *filename)
279 if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
286 /** Check if file exists
288 * @param filename to check.
289 * @return 0 if the file does not exist, 1 if the file exists, -1 if the file
290 * exists but there was an error opening it. errno value should be usable
291 * for error messages.
293 int rad_file_exists(const char *filename)
298 if ((des = open(filename, O_RDONLY)) == -1) {
299 if (errno == ENOENT) {
312 * Create possibly many directories.
314 * Note that the input directory name is NOT a constant!
315 * This is so that IF an error is returned, the 'directory' ptr
316 * points to the name of the file which caused the error.
318 int rad_mkdir(char *directory, mode_t mode)
325 * If the directory exists, don't do anything.
327 if (stat(directory, &st) == 0) {
332 * Look for the LAST directory name. Try to create that,
333 * failing on any error.
335 p = strrchr(directory, FR_DIR_SEP);
338 rcode = rad_mkdir(directory, mode);
341 * On error, we leave the directory name as the
342 * one which caused the error.
345 if (errno == EEXIST) return 0;
350 * Reset the directory delimiter, and go ask
351 * the system to make the directory.
359 * Having done everything successfully, we do the
360 * system call to actually go create the directory.
362 rcode = mkdir(directory, mode & 0777);
368 * Set things like sticky bits that aren't supported by
372 rcode = chmod(directory, mode);
380 * Allocate memory, or exit.
382 * This call ALWAYS succeeds!
384 void *rad_malloc(size_t size)
386 void *ptr = malloc(size);
389 radlog(L_ERR, "no memory");
397 void *rad_calloc(size_t size)
399 void *ptr = rad_malloc(size);
400 memset(ptr, 0, size);
404 void rad_const_free(const void *ptr)
409 memcpy(&tmp, &ptr, sizeof(tmp));
415 * Signature for free is dumb, and raises errors when we try
416 * to free const ptrs.
418 void rad_cfree(const void *ptr)
423 memcpy(&tmp, &ptr, sizeof(tmp));
428 * Logs an error message and aborts the program
432 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
435 radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
441 * Create a new REQUEST data structure.
443 REQUEST *request_alloc(void)
447 request = talloc_zero(NULL, REQUEST);
449 request->magic = REQUEST_MAGIC;
452 request->proxy = NULL;
454 request->reply = NULL;
456 request->proxy_reply = NULL;
458 request->config_items = NULL;
459 request->username = NULL;
460 request->password = NULL;
461 request->timestamp = time(NULL);
462 request->options = debug_flag; /* Default to global debug level */
464 request->module = "";
465 request->component = "<core>";
466 if (debug_flag) request->radlog = radlog_request;
473 * Create a new REQUEST, based on an old one.
475 * This function allows modules to inject fake requests
476 * into the server, for tunneled protocols like TTLS & PEAP.
478 REQUEST *request_alloc_fake(REQUEST *request)
482 fake = request_alloc();
484 fake->number = request->number;
485 #ifdef HAVE_PTHREAD_H
486 fake->child_pid = request->child_pid;
488 fake->parent = request;
489 fake->root = request->root;
490 fake->client = request->client;
493 * For new server support.
495 * FIXME: Key instead off of a "virtual server" data structure.
497 * FIXME: Permit different servers for inner && outer sessions?
499 fake->server = request->server;
501 fake->packet = rad_alloc(request, 1);
507 fake->reply = rad_alloc(request, 0);
513 fake->master_state = REQUEST_ACTIVE;
514 fake->child_state = REQUEST_RUNNING;
517 * Fill in the fake request.
519 fake->packet->sockfd = -1;
520 fake->packet->src_ipaddr = request->packet->src_ipaddr;
521 fake->packet->src_port = request->packet->src_port;
522 fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
523 fake->packet->dst_port = 0;
526 * This isn't STRICTLY required, as the fake request MUST NEVER
527 * be put into the request list. However, it's still reasonable
530 fake->packet->id = fake->number & 0xff;
531 fake->packet->code = request->packet->code;
532 fake->timestamp = request->timestamp;
535 * Required for new identity support
537 fake->listener = request->listener;
540 * Fill in the fake reply, based on the fake request.
542 fake->reply->sockfd = fake->packet->sockfd;
543 fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
544 fake->reply->src_port = fake->packet->dst_port;
545 fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
546 fake->reply->dst_port = fake->packet->src_port;
547 fake->reply->id = fake->packet->id;
548 fake->reply->code = 0; /* UNKNOWN code */
551 * Copy debug information.
553 fake->options = request->options;
554 fake->radlog = request->radlog;
560 REQUEST *request_alloc_coa(REQUEST *request)
562 if (!request || request->coa) return NULL;
565 * Originate CoA requests only when necessary.
567 if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
568 (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
570 request->coa = request_alloc_fake(request);
571 if (!request->coa) return NULL;
573 request->coa->packet->code = 0; /* unknown, as of yet */
574 request->coa->child_state = REQUEST_RUNNING;
575 request->coa->proxy = rad_alloc(request->coa, 0);
576 if (!request->coa->proxy) {
577 request_free(&request->coa);
586 * Copy a quoted string.
588 int rad_copy_string(char *to, const char *from)
600 } while (*from && (*from != quote));
602 if (*from != quote) return -1; /* not properly quoted */
612 * Copy a quoted string but without the quotes. The length
613 * returned is the number of chars written; the number of
614 * characters consumed is 2 more than this.
616 int rad_copy_string_bare(char *to, const char *from)
622 while (*from && (*from != quote)) {
631 if (*from != quote) return -1; /* not properly quoted */
642 int rad_copy_variable(char *to, const char *from)
654 sublen = rad_copy_string(to, from);
655 if (sublen < 0) return sublen;
661 case '}': /* end of variable expansion */
665 return length; /* proper end of variable */
673 case '%': /* start of variable expansion */
674 if (from[1] == '{') {
678 sublen = rad_copy_variable(to, from);
679 if (sublen < 0) return sublen;
684 } /* else FIXME: catch %%{ ?*/
692 } /* loop over the input string */
695 * We ended the string before a trailing '}'
705 int rad_pps(int *past, int *present, time_t *then, struct timeval *now)
709 if (*then != now->tv_sec) {
716 * Bootstrap PPS by looking at a percentage of
717 * the previous PPS. This lets us take a moving
718 * count, without doing a moving average. If
719 * we're a fraction "f" (0..1) into the current
720 * second, we can get a good guess for PPS by
723 * PPS = pps_now + pps_old * (1 - f)
725 * It's an instantaneous measurement, rather than
726 * a moving average. This will hopefully let it
727 * respond better to sudden spikes.
729 * Doing the calculations by thousands allows us
730 * to not overflow 2^32, AND to not underflow
731 * when we divide by USEC.
733 pps = USEC - now->tv_usec; /* useconds left in previous second */
734 pps /= 1000; /* scale to milliseconds */
735 pps *= *past; /* multiply by past count to get fraction */
736 pps /= 1000; /* scale to usec again */
737 pps += *present; /* add in current count */
743 * Split a string into words, xlat each one and write into argv array.
744 * Return argc or -1 on failure.
747 int rad_expand_xlat(REQUEST *request, const char *cmd,
748 int max_argc, const char *argv[], int can_fail,
749 size_t argv_buflen, char *argv_buf)
757 if (strlen(cmd) > (argv_buflen - 1)) {
758 radlog(L_ERR, "rad_expand_xlat: Command line is too long");
763 * Check for bad escapes.
765 if (cmd[strlen(cmd) - 1] == '\\') {
766 radlog(L_ERR, "rad_expand_xlat: Command line has final backslash, without a following character");
770 strlcpy(argv_buf, cmd, argv_buflen);
773 * Split the string into argv's BEFORE doing radius_xlat...
784 if ((*from == ' ') || (*from == '\t')) {
792 if (argc >= (max_argc - 1)) break;
795 * Copy the argv over to our buffer.
797 while (*from && (*from != ' ') && (*from != '\t')) {
798 if (to >= argv_buf + argv_buflen - 1) {
799 radlog(L_ERR, "rad_expand_xlat: Ran out of space in command line");
806 length = rad_copy_string_bare(to, from);
808 radlog(L_ERR, "rad_expand_xlat: Invalid string passed as argument");
816 if (from[1] == '{') {
819 length = rad_copy_variable(to, from);
821 radlog(L_ERR, "rad_expand_xlat: Invalid variable expansion passed as argument");
826 } else { /* FIXME: catch %%{ ? */
832 if (from[1] == ' ') from++;
838 } /* end of string, or found a space */
840 *(to++) = '\0'; /* terminate the string */
844 * We have to have SOMETHING, at least.
847 radlog(L_ERR, "rad_expand_xlat: Empty command line.");
852 * Expand each string, as appropriate.
854 left = argv_buf + argv_buflen - to;
855 for (i = 0; i < argc; i++) {
859 * Don't touch argv's which won't be translated.
861 if (strchr(argv[i], '%') == NULL) continue;
863 if (!request) continue;
865 sublen = radius_xlat(to, left - 1, argv[i], request, NULL, NULL);
869 * Fail to be backwards compatible.
871 * It's yucky, but it won't break anything,
872 * and it won't cause security problems.
876 radlog(L_ERR, "rad_expand_xlat: xlat failed");
888 radlog(L_ERR, "rad_expand_xlat: Ran out of space while expanding arguments.");