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