#include <freeradius-devel/ident.h>
RCSID("$Id$")
#include <freeradius-devel/radiusd.h>
#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
void (*reset_signal(int signo, void (*func)(int)))(int)
{
#ifdef HAVE_SIGACTION
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return oact.sa_handler;
#else
signal(signo, func);
return NULL;
#endif
}
struct request_data_t {
request_data_t *next;
void *unique_ptr;
int unique_int;
void *opaque;
void (*free_opaque)(void *);
};
int request_data_add(REQUEST *request,
void *unique_ptr, int unique_int,
void *opaque, void (*free_opaque)(void *))
{
request_data_t *this, **last, *next;
if (!request || !opaque) return -1;
this = next = NULL;
for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
if (((*last)->unique_ptr == unique_ptr) &&
((*last)->unique_int == unique_int)) {
this = *last;
next = this->next;
if (this->opaque &&
this->free_opaque)
this->free_opaque(this->opaque);
break;
}
}
if (!this) this = rad_malloc(sizeof(*this));
memset(this, 0, sizeof(*this));
this->next = next;
this->unique_ptr = unique_ptr;
this->unique_int = unique_int;
this->opaque = opaque;
this->free_opaque = free_opaque;
*last = this;
return 0;
}
void *request_data_get(REQUEST *request,
void *unique_ptr, int unique_int)
{
request_data_t **last;
if (!request) return NULL;
for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
if (((*last)->unique_ptr == unique_ptr) &&
((*last)->unique_int == unique_int)) {
request_data_t *this = *last;
void *ptr = this->opaque;
*last = this->next;
free(this);
return ptr;
}
}
return NULL;
}
void *request_data_reference(REQUEST *request,
void *unique_ptr, int unique_int)
{
request_data_t **last;
for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
if (((*last)->unique_ptr == unique_ptr) &&
((*last)->unique_int == unique_int)) {
request_data_t *this = *last;
void *ptr = this->opaque;
return ptr;
}
}
return NULL;
}
void request_free(REQUEST **request_ptr)
{
REQUEST *request;
if ((request_ptr == NULL) || !*request_ptr)
return;
request = *request_ptr;
rad_assert(!request->in_request_hash);
#ifdef WITH_PROXY
rad_assert(!request->in_proxy_hash);
#endif
rad_assert(!request->ev);
if (request->packet)
rad_free(&request->packet);
#ifdef WITH_PROXY
if (request->proxy)
rad_free(&request->proxy);
#endif
if (request->reply)
rad_free(&request->reply);
#ifdef WITH_PROXY
if (request->proxy_reply)
rad_free(&request->proxy_reply);
#endif
if (request->config_items)
pairfree(&request->config_items);
request->username = NULL;
request->password = NULL;
if (request->data) {
request_data_t *this, *next;
for (this = request->data; this != NULL; this = next) {
next = this->next;
if (this->opaque &&
this->free_opaque)
this->free_opaque(this->opaque);
free(this);
}
request->data = NULL;
}
if (request->root &&
(request->root->refcount > 0)) {
request->root->refcount--;
request->root = NULL;
}
#ifdef WITH_COA
if (request->coa) {
request->coa->parent = NULL;
rad_assert(request->coa->ev == NULL);
request_free(&request->coa);
}
if (request->parent && (request->parent->coa == request)) {
request->parent->coa = NULL;
}
#endif
#ifndef NDEBUG
request->magic = 0x01020304;
#endif
request->client = NULL;
#ifdef WITH_PROXY
request->home_server = NULL;
#endif
free(request);
*request_ptr = NULL;
}
int rad_checkfilename(const char *filename)
{
if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
return 0;
}
return -1;
}
int rad_mkdir(char *directory, int mode)
{
int rcode;
char *p;
struct stat st;
if (stat(directory, &st) == 0) {
return 0;
}
p = strrchr(directory, FR_DIR_SEP);
if (p != NULL) {
*p = '\0';
rcode = rad_mkdir(directory, mode);
if (rcode < 0) {
return rcode;
}
*p = FR_DIR_SEP;
} else {
return 0;
}
return mkdir(directory, mode);
}
void *rad_malloc(size_t size)
{
void *ptr = malloc(size);
if (ptr == NULL) {
radlog(L_ERR|L_CONS, "no memory");
exit(1);
}
return ptr;
}
void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
const char *expr)
{
radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
abort();
}
REQUEST *request_alloc(void)
{
REQUEST *request;
request = rad_malloc(sizeof(REQUEST));
memset(request, 0, sizeof(REQUEST));
#ifndef NDEBUG
request->magic = REQUEST_MAGIC;
#endif
#ifdef WITH_PROXY
request->proxy = NULL;
#endif
request->reply = NULL;
#ifdef WITH_PROXY
request->proxy_reply = NULL;
#endif
request->config_items = NULL;
request->username = NULL;
request->password = NULL;
request->timestamp = time(NULL);
request->options = RAD_REQUEST_OPTION_NONE;
request->module = "";
request->component = "<core>";
if (debug_flag) request->radlog = radlog_request;
return request;
}
REQUEST *request_alloc_fake(REQUEST *request)
{
REQUEST *fake;
fake = request_alloc();
fake->number = request->number;
#ifdef HAVE_PTHREAD_H
fake->child_pid = request->child_pid;
#endif
fake->parent = request;
fake->root = request->root;
fake->client = request->client;
fake->server = request->server;
fake->packet = rad_alloc(0);
if (!fake->packet) {
request_free(&fake);
return NULL;
}
fake->reply = rad_alloc(0);
if (!fake->reply) {
request_free(&fake);
return NULL;
}
fake->master_state = REQUEST_ACTIVE;
fake->child_state = REQUEST_RUNNING;
fake->packet->sockfd = -1;
fake->packet->src_ipaddr = request->packet->src_ipaddr;
fake->packet->src_port = request->packet->src_port;
fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
fake->packet->dst_port = 0;
fake->packet->id = fake->number & 0xff;
fake->packet->code = request->packet->code;
fake->timestamp = request->timestamp;
fake->listener = request->listener;
fake->reply->sockfd = fake->packet->sockfd;
fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
fake->reply->src_port = fake->packet->dst_port;
fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
fake->reply->dst_port = fake->packet->src_port;
fake->reply->id = fake->packet->id;
fake->reply->code = 0;
fake->options = request->options;
fake->radlog = request->radlog;
return fake;
}
#ifdef WITH_COA
REQUEST *request_alloc_coa(REQUEST *request)
{
if (!request || request->coa) return NULL;
if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
(request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
request->coa = request_alloc_fake(request);
request->coa->packet->code = 0;
request->coa->child_state = REQUEST_RUNNING;
request->coa->proxy = rad_alloc(0);
return request->coa;
}
#endif
int rad_copy_string(char *to, const char *from)
{
int length = 0;
char quote = *from;
do {
if (*from == '\\') {
*(to++) = *(from++);
length++;
}
*(to++) = *(from++);
length++;
} while (*from && (*from != quote));
if (*from != quote) return -1;
*(to++) = quote;
length++;
*to = '\0';
return length;
}
int rad_copy_variable(char *to, const char *from)
{
int length = 0;
int sublen;
*(to++) = *(from++);
length++;
while (*from) {
switch (*from) {
case '"':
case '\'':
sublen = rad_copy_string(to, from);
if (sublen < 0) return sublen;
from += sublen;
to += sublen;
length += sublen;
break;
case '}':
*(to++) = *(from++);
*to = '\0';
length++;
return length;
case '\\':
*(to++) = *(from++);
*(to++) = *(from++);
length += 2;
break;
case '%':
if (from[1] == '{') {
*(to++) = *(from++);
length++;
sublen = rad_copy_variable(to, from);
if (sublen < 0) return sublen;
from += sublen;
to += sublen;
length += sublen;
break;
}
default:
*(to++) = *(from++);
length++;
break;
}
}
return -1;
}