Set request->radlog if debugging
[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         if (request->packet)
201                 rad_free(&request->packet);
202
203 #ifdef WITH_PROXY
204         if (request->proxy)
205                 rad_free(&request->proxy);
206 #endif
207
208         if (request->reply)
209                 rad_free(&request->reply);
210
211 #ifdef WITH_PROXY
212         if (request->proxy_reply)
213                 rad_free(&request->proxy_reply);
214 #endif
215
216         if (request->config_items)
217                 pairfree(&request->config_items);
218
219         request->username = NULL;
220         request->password = NULL;
221
222         if (request->data) {
223                 request_data_t *this, *next;
224
225                 for (this = request->data; this != NULL; this = next) {
226                         next = this->next;
227                         if (this->opaque && /* free it, if necessary */
228                             this->free_opaque)
229                                 this->free_opaque(this->opaque);
230                         free(this);
231                 }
232                 request->data = NULL;
233         }
234
235         if (request->root &&
236             (request->root->refcount > 0)) {
237                 request->root->refcount--;
238                 request->root = NULL;
239         }
240
241 #ifndef NDEBUG
242         request->magic = 0x01020304;    /* set the request to be nonsense */
243 #endif
244         request->client = NULL;
245 #ifdef WITH_PROXY
246         request->home_server = NULL;
247 #endif
248         free(request);
249
250         *request_ptr = NULL;
251 }
252
253 /*
254  *      Check a filename for sanity.
255  *
256  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
257  */
258 int rad_checkfilename(const char *filename)
259 {
260         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
261                 return 0;
262         }
263
264         return -1;
265 }
266
267 /*
268  *      Create possibly many directories.
269  *
270  *      Note that the input directory name is NOT a constant!
271  *      This is so that IF an error is returned, the 'directory' ptr
272  *      points to the name of the file which caused the error.
273  */
274 int rad_mkdir(char *directory, int mode)
275 {
276         int rcode;
277         char *p;
278         struct stat st;
279
280         /*
281          *      If the directory exists, don't do anything.
282          */
283         if (stat(directory, &st) == 0) {
284                 return 0;
285         }
286
287         /*
288          *      Look for the LAST directory name.  Try to create that,
289          *      failing on any error.
290          */
291         p = strrchr(directory, FR_DIR_SEP);
292         if (p != NULL) {
293                 *p = '\0';
294                 rcode = rad_mkdir(directory, mode);
295
296                 /*
297                  *      On error, we leave the directory name as the
298                  *      one which caused the error.
299                  */
300                 if (rcode < 0) {
301                         return rcode;
302                 }
303
304                 /*
305                  *      Reset the directory delimiter, and go ask
306                  *      the system to make the directory.
307                  */
308                 *p = FR_DIR_SEP;
309         } else {
310                 return 0;
311         }
312
313         /*
314          *      Having done everything successfully, we do the
315          *      system call to actually go create the directory.
316          */
317         return mkdir(directory, mode);
318 }
319
320
321 /*
322  *      Module malloc() call, which does stuff if the malloc fails.
323  *
324  *      This call ALWAYS succeeds!
325  */
326 void *rad_malloc(size_t size)
327 {
328         void *ptr = malloc(size);
329
330         if (ptr == NULL) {
331                 radlog(L_ERR|L_CONS, "no memory");
332                 exit(1);
333         }
334
335         return ptr;
336 }
337
338 /*
339  *      Logs an error message and aborts the program
340  *
341  */
342
343 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
344                                     const char *expr)
345 {
346         radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
347         abort();
348 }
349
350
351 /*
352  *      Create a new REQUEST data structure.
353  */
354 REQUEST *request_alloc(void)
355 {
356         REQUEST *request;
357
358         request = rad_malloc(sizeof(REQUEST));
359         memset(request, 0, sizeof(REQUEST));
360 #ifndef NDEBUG
361         request->magic = REQUEST_MAGIC;
362 #endif
363 #ifdef WITH_PROXY
364         request->proxy = NULL;
365 #endif
366         request->reply = NULL;
367 #ifdef WITH_PROXY
368         request->proxy_reply = NULL;
369 #endif
370         request->config_items = NULL;
371         request->username = NULL;
372         request->password = NULL;
373         request->timestamp = time(NULL);
374 #ifdef HAVE_PTHREAD_H
375         request->child_pid = NO_SUCH_CHILD_PID;
376 #endif
377         request->options = RAD_REQUEST_OPTION_NONE;
378
379         request->module = "";
380         request->component = "";
381         if (debug_flag) request->radlog = radlog_request;
382
383         return request;
384 }
385
386
387 /*
388  *      Create a new REQUEST, based on an old one.
389  *
390  *      This function allows modules to inject fake requests
391  *      into the server, for tunneled protocols like TTLS & PEAP.
392  */
393 REQUEST *request_alloc_fake(REQUEST *request)
394 {
395   REQUEST *fake;
396
397   fake = request_alloc();
398
399   fake->number = request->number;
400 #ifdef HAVE_PTHREAD_H
401   fake->child_pid = NO_SUCH_CHILD_PID;
402 #endif
403   fake->parent = request;
404   fake->root = request->root;
405   fake->client = request->client;
406
407   /*
408    *    For new server support.
409    *
410    *    FIXME: Key instead off of a "virtual server" data structure.
411    *
412    *    FIXME: Permit different servers for inner && outer sessions?
413    */
414   fake->server = request->server;
415
416   fake->packet = rad_alloc(0);
417   if (!fake->packet) {
418           request_free(&fake);
419           return NULL;
420   }
421
422   fake->reply = rad_alloc(0);
423   if (!fake->reply) {
424           request_free(&fake);
425           return NULL;
426   }
427
428   fake->master_state = REQUEST_ACTIVE;
429   fake->child_state = REQUEST_RUNNING;
430
431   /*
432    *    Fill in the fake request.
433    */
434   fake->packet->sockfd = -1;
435   fake->packet->src_ipaddr = request->packet->src_ipaddr;
436   fake->packet->src_port = request->packet->src_port;
437   fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
438   fake->packet->dst_port = 0;
439
440   /*
441    *    This isn't STRICTLY required, as the fake request MUST NEVER
442    *    be put into the request list.  However, it's still reasonable
443    *    practice.
444    */
445   fake->packet->id = fake->number & 0xff;
446   fake->packet->code = request->packet->code;
447   fake->timestamp = request->timestamp;
448  
449   /*
450    *    Required for new identity support
451    */
452   fake->listener = request->listener;
453
454   /*
455    *    Fill in the fake reply, based on the fake request.
456    */
457   fake->reply->sockfd = fake->packet->sockfd;
458   fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
459   fake->reply->src_port = fake->packet->dst_port;
460   fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
461   fake->reply->dst_port = fake->packet->src_port;
462   fake->reply->id = fake->packet->id;
463   fake->reply->code = 0; /* UNKNOWN code */
464
465   return fake;
466 }
467
468
469 /*
470  *      Copy a quoted string.
471  */
472 int rad_copy_string(char *to, const char *from)
473 {
474         int length = 0;
475         char quote = *from;
476
477         do {
478                 if (*from == '\\') {
479                         *(to++) = *(from++);
480                         length++;
481                 }
482                 *(to++) = *(from++);
483                 length++;
484         } while (*from && (*from != quote));
485
486         if (*from != quote) return -1; /* not properly quoted */
487
488         *(to++) = quote;
489         length++;
490         *to = '\0';
491
492         return length;
493 }
494
495
496 /*
497  *      Copy a %{} string.
498  */
499 int rad_copy_variable(char *to, const char *from)
500 {
501         int length = 0;
502         int sublen;
503
504         *(to++) = *(from++);
505         length++;
506
507         while (*from) {
508                 switch (*from) {
509                 case '"':
510                 case '\'':
511                         sublen = rad_copy_string(to, from);
512                         if (sublen < 0) return sublen;
513                         from += sublen;
514                         to += sublen;
515                         break;
516
517                 case '}':       /* end of variable expansion */
518                         *(to++) = *(from++);
519                         *to = '\0';
520                         length++;
521                         return length; /* proper end of variable */
522
523                 case '\\':
524                         *(to++) = *(from++);
525                         *(to++) = *(from++);
526                         length += 2;
527                         break;
528
529                 case '%':       /* start of variable expansion */
530                         if (from[1] == '{') {
531                                 *(to++) = *(from++);
532                                 length++;
533
534                                 sublen = rad_copy_variable(to, from);
535                                 if (sublen < 0) return sublen;
536                                 from += sublen;
537                                 to += sublen;
538                                 length += sublen;
539                         } /* else FIXME: catch %%{ ?*/
540
541                         /* FALL-THROUGH */
542                         break;
543
544                 default:
545                         *(to++) = *(from++);
546                         length++;
547                         break;
548                 }
549         } /* loop over the input string */
550
551         /*
552          *      We ended the string before a trailing '}'
553          */
554
555         return -1;
556 }
557