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/autoconf.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
45 #include <freeradius-devel/radiusd.h>
46 #include <freeradius-devel/rad_assert.h>
49 * The signal() function in Solaris 2.5.1 sets SA_NODEFER in
50 * sa_flags, which causes grief if signal() is called in the
51 * handler before the cause of the signal has been cleared.
52 * (Infinite recursion).
54 * The same problem appears on HPUX, so we avoid it, if we can.
56 * Using sigaction() to reset the signal handler fixes the problem,
57 * so where available, we prefer that solution.
59 void (*reset_signal(int signo, void (*func)(int)))(int)
62 struct sigaction act, oact;
64 act.sa_handler = func;
65 sigemptyset(&act.sa_mask);
67 #ifdef SA_INTERRUPT /* SunOS */
68 act.sa_flags |= SA_INTERRUPT;
70 if (sigaction(signo, &act, &oact) < 0)
72 return oact.sa_handler;
76 * re-set by calling the 'signal' function, which
77 * may cause infinite recursion and core dumps due to
80 * However, the system is too dumb to implement sigaction(),
81 * so we don't have a choice.
88 * Per-request data, added by modules...
90 struct request_data_t {
96 void (*free_opaque)(void *);
100 * Add opaque data (with a "free" function) to a REQUEST.
102 * The unique ptr is meant to be a malloc'd module configuration,
103 * and the unique integer allows the caller to have multiple
104 * opaque data associated with a REQUEST.
106 int request_data_add(REQUEST *request,
107 void *unique_ptr, int unique_int,
108 void *opaque, void (*free_opaque)(void *))
110 request_data_t *this, **last, *next;
113 * Some simple sanity checks.
115 if (!request || !opaque) return -1;
118 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
119 if (((*last)->unique_ptr == unique_ptr) &&
120 ((*last)->unique_int == unique_int)) {
125 if (this->opaque && /* free it, if necessary */
127 this->free_opaque(this->opaque);
128 break; /* replace the existing entry */
132 if (!this) this = rad_malloc(sizeof(*this));
133 memset(this, 0, sizeof(*this));
136 this->unique_ptr = unique_ptr;
137 this->unique_int = unique_int;
138 this->opaque = opaque;
139 this->free_opaque = free_opaque;
148 * Get opaque data from a request.
150 void *request_data_get(REQUEST *request,
151 void *unique_ptr, int unique_int)
153 request_data_t **last;
155 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
156 if (((*last)->unique_ptr == unique_ptr) &&
157 ((*last)->unique_int == unique_int)) {
158 request_data_t *this = *last;
159 void *ptr = this->opaque;
162 * Remove the entry from the list, and free it.
166 return ptr; /* don't free it, the caller does that */
170 return NULL; /* wasn't found, too bad... */
175 * Get opaque data from a request without removing it.
177 void *request_data_reference(REQUEST *request,
178 void *unique_ptr, int unique_int)
180 request_data_t **last;
182 for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
183 if (((*last)->unique_ptr == unique_ptr) &&
184 ((*last)->unique_int == unique_int)) {
185 request_data_t *this = *last;
186 void *ptr = this->opaque;
192 return NULL; /* wasn't found, too bad... */
197 * Free a REQUEST struct.
199 void request_free(REQUEST **request_ptr)
203 if ((request_ptr == NULL) || !*request_ptr)
206 request = *request_ptr;
209 * If there's a thread currently active on this request,
212 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
215 rad_free(&request->packet);
218 rad_free(&request->proxy);
221 rad_free(&request->reply);
223 if (request->proxy_reply)
224 rad_free(&request->proxy_reply);
226 if (request->config_items)
227 pairfree(&request->config_items);
229 request->username = NULL;
230 request->password = NULL;
233 request_data_t *this, *next;
235 for (this = request->data; this != NULL; this = next) {
237 if (this->opaque && /* free it, if necessary */
239 this->free_opaque(this->opaque);
242 request->data = NULL;
246 request->magic = 0x01020304; /* set the request to be nonsense */
247 strcpy(request->secret, "REQUEST-DELETED");
248 strcpy(request->proxysecret, "REQUEST-DELETED");
256 * Check a filename for sanity.
258 * Allow only uppercase/lowercase letters, numbers, and '-_/.'
260 int rad_checkfilename(const char *filename)
262 if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
270 * Create possibly many directories.
272 * Note that the input directory name is NOT a constant!
273 * This is so that IF an error is returned, the 'directory' ptr
274 * points to the name of the file which caused the error.
276 int rad_mkdir(char *directory, int mode)
283 * If the directory exists, don't do anything.
285 if (stat(directory, &st) == 0) {
290 * Look for the LAST directory name. Try to create that,
291 * failing on any error.
293 p = strrchr(directory, '/');
296 rcode = rad_mkdir(directory, mode);
299 * On error, we leave the directory name as the
300 * one which caused the error.
307 * Reset the directory delimiter, and go ask
308 * the system to make the directory.
316 * Having done everything successfully, we do the
317 * system call to actually go create the directory.
319 return mkdir(directory, mode);
324 * Module malloc() call, which does stuff if the malloc fails.
326 * This call ALWAYS succeeds!
328 void *rad_malloc(size_t size)
330 void *ptr = malloc(size);
333 radlog(L_ERR|L_CONS, "no memory");
341 * Logs an error message and aborts the program
345 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line)
347 radlog(L_ERR|L_CONS, "Assertion failed in %s, line %u", file, line);
353 * Create a new REQUEST data structure.
355 REQUEST *request_alloc(void)
359 request = rad_malloc(sizeof(REQUEST));
360 memset(request, 0, sizeof(REQUEST));
362 request->magic = REQUEST_MAGIC;
364 request->proxy = NULL;
365 request->reply = NULL;
366 request->proxy_reply = NULL;
367 request->config_items = NULL;
368 request->username = NULL;
369 request->password = NULL;
370 request->timestamp = time(NULL);
371 request->child_pid = NO_SUCH_CHILD_PID;
372 request->container = NULL;
373 request->options = RAD_REQUEST_OPTION_NONE;
380 * Create a new REQUEST, based on an old one.
382 * This function allows modules to inject fake requests
383 * into the server, for tunneled protocols like TTLS & PEAP.
385 REQUEST *request_alloc_fake(REQUEST *oldreq)
389 request = request_alloc();
391 request->number = oldreq->number;
392 request->child_pid = NO_SUCH_CHILD_PID;
393 request->options = RAD_REQUEST_OPTION_FAKE_REQUEST;
395 request->packet = rad_alloc(0);
396 rad_assert(request->packet != NULL);
398 request->reply = rad_alloc(0);
399 rad_assert(request->reply != NULL);
402 * Fill in the fake request packet.
404 request->packet->sockfd = -1;
405 request->packet->src_ipaddr.af = AF_INET;
406 request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
407 request->packet->dst_ipaddr = request->packet->src_ipaddr;
408 request->packet->src_port = request->number >> 8;
409 request->packet->dst_port = 0;
412 * This isn't STRICTLY required, as the fake request SHOULD NEVER
413 * be put into the request list. However, it's still reasonable
416 request->packet->id = request->number & 0xff;
417 request->packet->code = oldreq->packet->code;
418 request->timestamp = oldreq->timestamp;
421 * Fill in the fake reply, based on the fake request.
423 request->reply->sockfd = request->packet->sockfd;
424 request->reply->dst_ipaddr = request->packet->src_ipaddr;
425 request->reply->dst_port = request->packet->src_port;
426 request->reply->id = request->packet->id;
427 request->reply->code = 0; /* UNKNOWN code */
434 * Copy a quoted string.
436 int rad_copy_string(char *to, const char *from)
448 } while (*from && (*from != quote));
450 if (*from != quote) return -1; /* not properly quoted */
463 int rad_copy_variable(char *to, const char *from)
475 sublen = rad_copy_string(to, from);
476 if (sublen < 0) return sublen;
481 case '}': /* end of variable expansion */
485 return length; /* proper end of variable */
493 case '%': /* start of variable expansion */
494 if (from[1] == '{') {
498 sublen = rad_copy_variable(to, from);
499 if (sublen < 0) return sublen;
503 } /* else FIXME: catch %%{ ?*/
513 } /* loop over the input string */
516 * We ended the string before a trailing '}'