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 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 malloc'd 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 == NULL) || !*request_ptr)
198 request = *request_ptr;
200 rad_assert(!request->in_request_hash);
202 rad_assert(!request->in_proxy_hash);
204 rad_assert(!request->ev);
207 rad_free(&request->packet);
211 rad_free(&request->proxy);
215 rad_free(&request->reply);
218 if (request->proxy_reply)
219 rad_free(&request->proxy_reply);
222 if (request->config_items)
223 pairfree(&request->config_items);
225 request->username = NULL;
226 request->password = NULL;
229 request_data_t *this, *next;
231 for (this = request->data; this != NULL; this = next) {
233 if (this->opaque && /* free it, if necessary */
235 this->free_opaque(this->opaque);
238 request->data = NULL;
242 (request->root->refcount > 0)) {
243 request->root->refcount--;
244 request->root = NULL;
249 request->coa->parent = NULL;
250 rad_assert(request->coa->ev == NULL);
251 request_free(&request->coa);
254 if (request->parent && (request->parent->coa == request)) {
255 request->parent->coa = NULL;
260 request->magic = 0x01020304; /* set the request to be nonsense */
262 request->client = NULL;
264 request->home_server = NULL;
272 * Check a filename for sanity.
274 * Allow only uppercase/lowercase letters, numbers, and '-_/.'
276 int rad_checkfilename(const char *filename)
278 if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
286 * Create possibly many directories.
288 * Note that the input directory name is NOT a constant!
289 * This is so that IF an error is returned, the 'directory' ptr
290 * points to the name of the file which caused the error.
292 int rad_mkdir(char *directory, int mode)
299 * If the directory exists, don't do anything.
301 if (stat(directory, &st) == 0) {
306 * Look for the LAST directory name. Try to create that,
307 * failing on any error.
309 p = strrchr(directory, FR_DIR_SEP);
312 rcode = rad_mkdir(directory, mode);
315 * On error, we leave the directory name as the
316 * one which caused the error.
323 * Reset the directory delimiter, and go ask
324 * the system to make the directory.
332 * Having done everything successfully, we do the
333 * system call to actually go create the directory.
335 return mkdir(directory, mode);
340 * Module malloc() call, which does stuff if the malloc fails.
342 * This call ALWAYS succeeds!
344 void *rad_malloc(size_t size)
346 void *ptr = malloc(size);
349 radlog(L_ERR|L_CONS, "no memory");
357 * Logs an error message and aborts the program
361 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
364 radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
370 * Create a new REQUEST data structure.
372 REQUEST *request_alloc(void)
376 request = rad_malloc(sizeof(REQUEST));
377 memset(request, 0, sizeof(REQUEST));
379 request->magic = REQUEST_MAGIC;
382 request->proxy = NULL;
384 request->reply = NULL;
386 request->proxy_reply = NULL;
388 request->config_items = NULL;
389 request->username = NULL;
390 request->password = NULL;
391 request->timestamp = time(NULL);
392 request->options = RAD_REQUEST_OPTION_NONE;
394 request->module = "";
395 request->component = "<core>";
396 if (debug_flag) request->radlog = radlog_request;
403 * Create a new REQUEST, based on an old one.
405 * This function allows modules to inject fake requests
406 * into the server, for tunneled protocols like TTLS & PEAP.
408 REQUEST *request_alloc_fake(REQUEST *request)
412 fake = request_alloc();
414 fake->number = request->number;
415 #ifdef HAVE_PTHREAD_H
416 fake->child_pid = request->child_pid;
418 fake->parent = request;
419 fake->root = request->root;
420 fake->client = request->client;
423 * For new server support.
425 * FIXME: Key instead off of a "virtual server" data structure.
427 * FIXME: Permit different servers for inner && outer sessions?
429 fake->server = request->server;
431 fake->packet = rad_alloc(0);
437 fake->reply = rad_alloc(0);
443 fake->master_state = REQUEST_ACTIVE;
444 fake->child_state = REQUEST_RUNNING;
447 * Fill in the fake request.
449 fake->packet->sockfd = -1;
450 fake->packet->src_ipaddr = request->packet->src_ipaddr;
451 fake->packet->src_port = request->packet->src_port;
452 fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
453 fake->packet->dst_port = 0;
456 * This isn't STRICTLY required, as the fake request MUST NEVER
457 * be put into the request list. However, it's still reasonable
460 fake->packet->id = fake->number & 0xff;
461 fake->packet->code = request->packet->code;
462 fake->timestamp = request->timestamp;
465 * Required for new identity support
467 fake->listener = request->listener;
470 * Fill in the fake reply, based on the fake request.
472 fake->reply->sockfd = fake->packet->sockfd;
473 fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
474 fake->reply->src_port = fake->packet->dst_port;
475 fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
476 fake->reply->dst_port = fake->packet->src_port;
477 fake->reply->id = fake->packet->id;
478 fake->reply->code = 0; /* UNKNOWN code */
481 * Copy debug information.
483 fake->options = request->options;
484 fake->radlog = request->radlog;
490 REQUEST *request_alloc_coa(REQUEST *request)
492 if (!request || request->coa) return NULL;
495 * Originate CoA requests only when necessary.
497 if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
498 (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
500 request->coa = request_alloc_fake(request);
501 if (!request->coa) return NULL;
503 request->coa->packet->code = 0; /* unknown, as of yet */
504 request->coa->child_state = REQUEST_RUNNING;
505 request->coa->proxy = rad_alloc(0);
506 if (!request->coa->proxy) {
507 request_free(&request->coa);
516 * Copy a quoted string.
518 int rad_copy_string(char *to, const char *from)
530 } while (*from && (*from != quote));
532 if (*from != quote) return -1; /* not properly quoted */
545 int rad_copy_variable(char *to, const char *from)
557 sublen = rad_copy_string(to, from);
558 if (sublen < 0) return sublen;
564 case '}': /* end of variable expansion */
568 return length; /* proper end of variable */
576 case '%': /* start of variable expansion */
577 if (from[1] == '{') {
581 sublen = rad_copy_variable(to, from);
582 if (sublen < 0) return sublen;
587 } /* else FIXME: catch %%{ ?*/
595 } /* loop over the input string */
598 * We ended the string before a trailing '}'