Added event wrapper around request_free
[freeradius.git] / src / main / util.c
1 /*
2  * util.c       Various utility functions.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/rad_assert.h>
28
29 #include <ctype.h>
30 #include <signal.h>
31
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 /*
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).
40  *
41  *      The same problem appears on HPUX, so we avoid it, if we can.
42  *
43  *      Using sigaction() to reset the signal handler fixes the problem,
44  *      so where available, we prefer that solution.
45  */
46
47 void (*reset_signal(int signo, void (*func)(int)))(int)
48 {
49 #ifdef HAVE_SIGACTION
50         struct sigaction act, oact;
51
52         act.sa_handler = func;
53         sigemptyset(&act.sa_mask);
54         act.sa_flags = 0;
55 #ifdef  SA_INTERRUPT            /* SunOS */
56         act.sa_flags |= SA_INTERRUPT;
57 #endif
58         if (sigaction(signo, &act, &oact) < 0)
59                 return SIG_ERR;
60         return oact.sa_handler;
61 #else
62
63         /*
64          *      re-set by calling the 'signal' function, which
65          *      may cause infinite recursion and core dumps due to
66          *      stack growth.
67          *
68          *      However, the system is too dumb to implement sigaction(),
69          *      so we don't have a choice.
70          */
71         signal(signo, func);
72
73         return NULL;
74 #endif
75 }
76
77 /*
78  *      Per-request data, added by modules...
79  */
80 struct request_data_t {
81         request_data_t  *next;
82
83         void            *unique_ptr;
84         int             unique_int;
85         void            *opaque;
86         void            (*free_opaque)(void *);
87 };
88
89 /*
90  *      Add opaque data (with a "free" function) to a REQUEST.
91  *
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.
95  */
96 int request_data_add(REQUEST *request,
97                      void *unique_ptr, int unique_int,
98                      void *opaque, void (*free_opaque)(void *))
99 {
100         request_data_t *this, **last, *next;
101
102         /*
103          *      Some simple sanity checks.
104          */
105         if (!request || !opaque) return -1;
106
107         this = next = NULL;
108         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
109                 if (((*last)->unique_ptr == unique_ptr) &&
110                     ((*last)->unique_int == unique_int)) {
111                         this = *last;
112
113                         next = this->next;
114
115                         if (this->opaque && /* free it, if necessary */
116                             this->free_opaque)
117                                 this->free_opaque(this->opaque);
118                         break;  /* replace the existing entry */
119                 }
120         }
121
122         if (!this) this = rad_malloc(sizeof(*this));
123         memset(this, 0, sizeof(*this));
124
125         this->next = next;
126         this->unique_ptr = unique_ptr;
127         this->unique_int = unique_int;
128         this->opaque = opaque;
129         this->free_opaque = free_opaque;
130
131         *last = this;
132
133         return 0;
134 }
135
136
137 /*
138  *      Get opaque data from a request.
139  */
140 void *request_data_get(REQUEST *request,
141                        void *unique_ptr, int unique_int)
142 {
143         request_data_t **last;
144
145         if (!request) return NULL;
146
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;
152
153                         /*
154                          *      Remove the entry from the list, and free it.
155                          */
156                         *last = this->next;
157                         free(this);
158                         return ptr; /* don't free it, the caller does that */
159                 }
160         }
161
162         return NULL;            /* wasn't found, too bad... */
163 }
164
165
166 /*
167  *      Get opaque data from a request without removing it.
168  */
169 void *request_data_reference(REQUEST *request,
170                        void *unique_ptr, int unique_int)
171 {
172         request_data_t **last;
173
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;
179
180                         return ptr;
181                 }
182         }
183
184         return NULL;            /* wasn't found, too bad... */
185 }
186
187
188 /*
189  *      Free a REQUEST struct.
190  */
191 void request_free(REQUEST **request_ptr)
192 {
193         REQUEST *request;
194
195         if ((request_ptr == NULL) || !*request_ptr)
196                 return;
197
198         request = *request_ptr;
199
200         rad_assert(!request->in_request_hash);
201         rad_assert(!request->in_proxy_hash);
202         rad_assert(!request->ev);
203
204         if (request->packet)
205                 rad_free(&request->packet);
206
207 #ifdef WITH_PROXY
208         if (request->proxy)
209                 rad_free(&request->proxy);
210 #endif
211
212         if (request->reply)
213                 rad_free(&request->reply);
214
215 #ifdef WITH_PROXY
216         if (request->proxy_reply)
217                 rad_free(&request->proxy_reply);
218 #endif
219
220         if (request->config_items)
221                 pairfree(&request->config_items);
222
223         request->username = NULL;
224         request->password = NULL;
225
226         if (request->data) {
227                 request_data_t *this, *next;
228
229                 for (this = request->data; this != NULL; this = next) {
230                         next = this->next;
231                         if (this->opaque && /* free it, if necessary */
232                             this->free_opaque)
233                                 this->free_opaque(this->opaque);
234                         free(this);
235                 }
236                 request->data = NULL;
237         }
238
239         if (request->root &&
240             (request->root->refcount > 0)) {
241                 request->root->refcount--;
242                 request->root = NULL;
243         }
244
245 #ifdef WITH_COA
246         if (request->coa) {
247                 request->coa->parent = NULL;
248                 rad_assert(request->coa->ev == NULL);
249                 request_free(&request->coa);
250         }
251
252         if (request->parent && (request->parent->coa == request)) {
253                 request->parent->coa = NULL;
254         }
255 #endif
256
257 #ifndef NDEBUG
258         request->magic = 0x01020304;    /* set the request to be nonsense */
259 #endif
260         request->client = NULL;
261 #ifdef WITH_PROXY
262         request->home_server = NULL;
263 #endif
264         free(request);
265
266         *request_ptr = NULL;
267 }
268
269 /*
270  *      Check a filename for sanity.
271  *
272  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
273  */
274 int rad_checkfilename(const char *filename)
275 {
276         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
277                 return 0;
278         }
279
280         return -1;
281 }
282
283 /*
284  *      Create possibly many directories.
285  *
286  *      Note that the input directory name is NOT a constant!
287  *      This is so that IF an error is returned, the 'directory' ptr
288  *      points to the name of the file which caused the error.
289  */
290 int rad_mkdir(char *directory, int mode)
291 {
292         int rcode;
293         char *p;
294         struct stat st;
295
296         /*
297          *      If the directory exists, don't do anything.
298          */
299         if (stat(directory, &st) == 0) {
300                 return 0;
301         }
302
303         /*
304          *      Look for the LAST directory name.  Try to create that,
305          *      failing on any error.
306          */
307         p = strrchr(directory, FR_DIR_SEP);
308         if (p != NULL) {
309                 *p = '\0';
310                 rcode = rad_mkdir(directory, mode);
311
312                 /*
313                  *      On error, we leave the directory name as the
314                  *      one which caused the error.
315                  */
316                 if (rcode < 0) {
317                         return rcode;
318                 }
319
320                 /*
321                  *      Reset the directory delimiter, and go ask
322                  *      the system to make the directory.
323                  */
324                 *p = FR_DIR_SEP;
325         } else {
326                 return 0;
327         }
328
329         /*
330          *      Having done everything successfully, we do the
331          *      system call to actually go create the directory.
332          */
333         return mkdir(directory, mode);
334 }
335
336
337 /*
338  *      Module malloc() call, which does stuff if the malloc fails.
339  *
340  *      This call ALWAYS succeeds!
341  */
342 void *rad_malloc(size_t size)
343 {
344         void *ptr = malloc(size);
345
346         if (ptr == NULL) {
347                 radlog(L_ERR|L_CONS, "no memory");
348                 exit(1);
349         }
350
351         return ptr;
352 }
353
354 /*
355  *      Logs an error message and aborts the program
356  *
357  */
358
359 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
360                                     const char *expr)
361 {
362         radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
363         abort();
364 }
365
366
367 /*
368  *      Create a new REQUEST data structure.
369  */
370 REQUEST *request_alloc(void)
371 {
372         REQUEST *request;
373
374         request = rad_malloc(sizeof(REQUEST));
375         memset(request, 0, sizeof(REQUEST));
376 #ifndef NDEBUG
377         request->magic = REQUEST_MAGIC;
378 #endif
379 #ifdef WITH_PROXY
380         request->proxy = NULL;
381 #endif
382         request->reply = NULL;
383 #ifdef WITH_PROXY
384         request->proxy_reply = NULL;
385 #endif
386         request->config_items = NULL;
387         request->username = NULL;
388         request->password = NULL;
389         request->timestamp = time(NULL);
390         request->options = RAD_REQUEST_OPTION_NONE;
391
392         request->module = "";
393         request->component = "";
394         if (debug_flag) request->radlog = radlog_request;
395
396         return request;
397 }
398
399
400 /*
401  *      Create a new REQUEST, based on an old one.
402  *
403  *      This function allows modules to inject fake requests
404  *      into the server, for tunneled protocols like TTLS & PEAP.
405  */
406 REQUEST *request_alloc_fake(REQUEST *request)
407 {
408   REQUEST *fake;
409
410   fake = request_alloc();
411
412   fake->number = request->number;
413 #ifdef HAVE_PTHREAD_H
414   fake->child_pid = request->child_pid;
415 #endif
416   fake->parent = request;
417   fake->root = request->root;
418   fake->client = request->client;
419   fake->process = request->process;
420
421   /*
422    *    For new server support.
423    *
424    *    FIXME: Key instead off of a "virtual server" data structure.
425    *
426    *    FIXME: Permit different servers for inner && outer sessions?
427    */
428   fake->server = request->server;
429
430   fake->packet = rad_alloc(0);
431   if (!fake->packet) {
432           request_free(&fake);
433           return NULL;
434   }
435
436   fake->reply = rad_alloc(0);
437   if (!fake->reply) {
438           request_free(&fake);
439           return NULL;
440   }
441
442   fake->master_state = REQUEST_ACTIVE;
443   fake->child_state = REQUEST_RUNNING;
444
445   /*
446    *    Fill in the fake request.
447    */
448   fake->packet->sockfd = -1;
449   fake->packet->src_ipaddr = request->packet->src_ipaddr;
450   fake->packet->src_port = request->packet->src_port;
451   fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
452   fake->packet->dst_port = 0;
453
454   /*
455    *    This isn't STRICTLY required, as the fake request MUST NEVER
456    *    be put into the request list.  However, it's still reasonable
457    *    practice.
458    */
459   fake->packet->id = fake->number & 0xff;
460   fake->packet->code = request->packet->code;
461   fake->timestamp = request->timestamp;
462  
463   /*
464    *    Required for new identity support
465    */
466   fake->listener = request->listener;
467
468   /*
469    *    Fill in the fake reply, based on the fake request.
470    */
471   fake->reply->sockfd = fake->packet->sockfd;
472   fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
473   fake->reply->src_port = fake->packet->dst_port;
474   fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
475   fake->reply->dst_port = fake->packet->src_port;
476   fake->reply->id = fake->packet->id;
477   fake->reply->code = 0; /* UNKNOWN code */
478
479   /*
480    *    Copy debug information.
481    */
482   fake->options = request->options;
483   fake->radlog = request->radlog;
484
485   return fake;
486 }
487
488 #ifdef WITH_COA
489 REQUEST *request_alloc_coa(REQUEST *request)
490 {
491         if (!request || request->coa) return NULL;
492
493         request->coa = request_alloc_fake(request);
494         request->coa->packet->code = 0; /* unknown, as of yet */
495         request->coa->child_state = REQUEST_RUNNING;
496         request->coa->proxy = rad_alloc(0);
497
498         return request->coa;
499 }
500 #endif
501
502 /*
503  *      Copy a quoted string.
504  */
505 int rad_copy_string(char *to, const char *from)
506 {
507         int length = 0;
508         char quote = *from;
509
510         do {
511                 if (*from == '\\') {
512                         *(to++) = *(from++);
513                         length++;
514                 }
515                 *(to++) = *(from++);
516                 length++;
517         } while (*from && (*from != quote));
518
519         if (*from != quote) return -1; /* not properly quoted */
520
521         *(to++) = quote;
522         length++;
523         *to = '\0';
524
525         return length;
526 }
527
528
529 /*
530  *      Copy a %{} string.
531  */
532 int rad_copy_variable(char *to, const char *from)
533 {
534         int length = 0;
535         int sublen;
536
537         *(to++) = *(from++);
538         length++;
539
540         while (*from) {
541                 switch (*from) {
542                 case '"':
543                 case '\'':
544                         sublen = rad_copy_string(to, from);
545                         if (sublen < 0) return sublen;
546                         from += sublen;
547                         to += sublen;
548                         break;
549
550                 case '}':       /* end of variable expansion */
551                         *(to++) = *(from++);
552                         *to = '\0';
553                         length++;
554                         return length; /* proper end of variable */
555
556                 case '\\':
557                         *(to++) = *(from++);
558                         *(to++) = *(from++);
559                         length += 2;
560                         break;
561
562                 case '%':       /* start of variable expansion */
563                         if (from[1] == '{') {
564                                 *(to++) = *(from++);
565                                 length++;
566
567                                 sublen = rad_copy_variable(to, from);
568                                 if (sublen < 0) return sublen;
569                                 from += sublen;
570                                 to += sublen;
571                                 length += sublen;
572                         } /* else FIXME: catch %%{ ?*/
573
574                         /* FALL-THROUGH */
575                         break;
576
577                 default:
578                         *(to++) = *(from++);
579                         length++;
580                         break;
581                 }
582         } /* loop over the input string */
583
584         /*
585          *      We ended the string before a trailing '}'
586          */
587
588         return -1;
589 }
590