Pull fix from branch_1_1, so proxied EAP replies work
[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/autoconf.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <signal.h>
33
34 #include <sys/stat.h>
35 #include <fcntl.h>
36
37 #ifdef HAVE_UNISTD_H
38 #       include <unistd.h>
39 #endif
40
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
44
45 #include <freeradius-devel/radiusd.h>
46 #include <freeradius-devel/rad_assert.h>
47
48 /*
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).
53  *
54  *      The same problem appears on HPUX, so we avoid it, if we can.
55  *
56  *      Using sigaction() to reset the signal handler fixes the problem,
57  *      so where available, we prefer that solution.
58  */
59 void (*reset_signal(int signo, void (*func)(int)))(int)
60 {
61 #ifdef HAVE_SIGACTION
62         struct sigaction act, oact;
63
64         act.sa_handler = func;
65         sigemptyset(&act.sa_mask);
66         act.sa_flags = 0;
67 #ifdef  SA_INTERRUPT            /* SunOS */
68         act.sa_flags |= SA_INTERRUPT;
69 #endif
70         if (sigaction(signo, &act, &oact) < 0)
71                 return SIG_ERR;
72         return oact.sa_handler;
73 #else
74
75         /*
76          *      re-set by calling the 'signal' function, which
77          *      may cause infinite recursion and core dumps due to
78          *      stack growth.
79          *
80          *      However, the system is too dumb to implement sigaction(),
81          *      so we don't have a choice.
82          */
83         signal(signo, func);
84 #endif
85 }
86
87 /*
88  *      Per-request data, added by modules...
89  */
90 struct request_data_t {
91         request_data_t  *next;
92
93         void            *unique_ptr;
94         int             unique_int;
95         void            *opaque;
96         void            (*free_opaque)(void *);
97 };
98
99 /*
100  *      Add opaque data (with a "free" function) to a REQUEST.
101  *
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.
105  */
106 int request_data_add(REQUEST *request,
107                      void *unique_ptr, int unique_int,
108                      void *opaque, void (*free_opaque)(void *))
109 {
110         request_data_t *this, **last, *next;
111
112         /*
113          *      Some simple sanity checks.
114          */
115         if (!request || !opaque) return -1;
116
117         this = next = NULL;
118         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
119                 if (((*last)->unique_ptr == unique_ptr) &&
120                     ((*last)->unique_int == unique_int)) {
121                         this = *last;
122
123                         next = this->next;
124
125                         if (this->opaque && /* free it, if necessary */
126                             this->free_opaque)
127                                 this->free_opaque(this->opaque);
128                         break;  /* replace the existing entry */
129                 }
130         }
131
132         if (!this) this = rad_malloc(sizeof(*this));
133         memset(this, 0, sizeof(*this));
134
135         this->next = next;
136         this->unique_ptr = unique_ptr;
137         this->unique_int = unique_int;
138         this->opaque = opaque;
139         this->free_opaque = free_opaque;
140
141         *last = this;
142
143         return 0;
144 }
145
146
147 /*
148  *      Get opaque data from a request.
149  */
150 void *request_data_get(REQUEST *request,
151                        void *unique_ptr, int unique_int)
152 {
153         request_data_t **last;
154
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;
160
161                         /*
162                          *      Remove the entry from the list, and free it.
163                          */
164                         *last = this->next;
165                         free(this);
166                         return ptr; /* don't free it, the caller does that */
167                 }
168         }
169
170         return NULL;            /* wasn't found, too bad... */
171 }
172
173
174 /*
175  *      Get opaque data from a request without removing it.
176  */
177 void *request_data_reference(REQUEST *request,
178                        void *unique_ptr, int unique_int)
179 {
180         request_data_t **last;
181
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;
187
188                         return ptr;
189                 }
190         }
191
192         return NULL;            /* wasn't found, too bad... */
193 }
194
195
196 /*
197  *      Free a REQUEST struct.
198  */
199 void request_free(REQUEST **request_ptr)
200 {
201         REQUEST *request;
202
203         if ((request_ptr == NULL) || !*request_ptr)
204                 return;
205
206         request = *request_ptr;
207
208         /*
209          *      If there's a thread currently active on this request,
210          *      blow up!
211          */
212         rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
213
214         if (request->packet)
215                 rad_free(&request->packet);
216
217         if (request->proxy)
218                 rad_free(&request->proxy);
219
220         if (request->reply)
221                 rad_free(&request->reply);
222
223         if (request->proxy_reply)
224                 rad_free(&request->proxy_reply);
225
226         if (request->config_items)
227                 pairfree(&request->config_items);
228
229         request->username = NULL;
230         request->password = NULL;
231
232         if (request->data) {
233                 request_data_t *this, *next;
234
235                 for (this = request->data; this != NULL; this = next) {
236                         next = this->next;
237                         if (this->opaque && /* free it, if necessary */
238                             this->free_opaque)
239                                 this->free_opaque(this->opaque);
240                         free(this);
241                 }
242                 request->data = NULL;
243         }
244
245 #ifndef NDEBUG
246         request->magic = 0x01020304;    /* set the request to be nonsense */
247         strcpy(request->secret, "REQUEST-DELETED");
248         strcpy(request->proxysecret, "REQUEST-DELETED");
249 #endif
250         free(request);
251
252         *request_ptr = NULL;
253 }
254
255 /*
256  *      Check a filename for sanity.
257  *
258  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
259  */
260 int rad_checkfilename(const char *filename)
261 {
262         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
263                 return 0;
264         }
265
266         return -1;
267 }
268
269 /*
270  *      Create possibly many directories.
271  *
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.
275  */
276 int rad_mkdir(char *directory, int mode)
277 {
278         int rcode;
279         char *p;
280         struct stat st;
281
282         /*
283          *      If the directory exists, don't do anything.
284          */
285         if (stat(directory, &st) == 0) {
286                 return 0;
287         }
288
289         /*
290          *      Look for the LAST directory name.  Try to create that,
291          *      failing on any error.
292          */
293         p = strrchr(directory, '/');
294         if (p != NULL) {
295                 *p = '\0';
296                 rcode = rad_mkdir(directory, mode);
297
298                 /*
299                  *      On error, we leave the directory name as the
300                  *      one which caused the error.
301                  */
302                 if (rcode < 0) {
303                         return rcode;
304                 }
305
306                 /*
307                  *      Reset the directory delimiter, and go ask
308                  *      the system to make the directory.
309                  */
310                 *p = '/';
311         } else {
312                 return 0;
313         }
314
315         /*
316          *      Having done everything successfully, we do the
317          *      system call to actually go create the directory.
318          */
319         return mkdir(directory, mode);
320 }
321
322
323 /*
324  *      Module malloc() call, which does stuff if the malloc fails.
325  *
326  *      This call ALWAYS succeeds!
327  */
328 void *rad_malloc(size_t size)
329 {
330         void *ptr = malloc(size);
331
332         if (ptr == NULL) {
333                 radlog(L_ERR|L_CONS, "no memory");
334                 exit(1);
335         }
336
337         return ptr;
338 }
339
340 /*
341  *      Logs an error message and aborts the program
342  *
343  */
344
345 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line)
346 {
347         radlog(L_ERR|L_CONS, "Assertion failed in %s, line %u", file, line);
348         abort();
349 }
350
351
352 /*
353  *      Create a new REQUEST data structure.
354  */
355 REQUEST *request_alloc(void)
356 {
357         REQUEST *request;
358
359         request = rad_malloc(sizeof(REQUEST));
360         memset(request, 0, sizeof(REQUEST));
361 #ifndef NDEBUG
362         request->magic = REQUEST_MAGIC;
363 #endif
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;
374
375         return request;
376 }
377
378
379 /*
380  *      Create a new REQUEST, based on an old one.
381  *
382  *      This function allows modules to inject fake requests
383  *      into the server, for tunneled protocols like TTLS & PEAP.
384  */
385 REQUEST *request_alloc_fake(REQUEST *oldreq)
386 {
387   REQUEST *request;
388
389   request = request_alloc();
390
391   request->number = oldreq->number;
392   request->child_pid = NO_SUCH_CHILD_PID;
393   request->options = RAD_REQUEST_OPTION_FAKE_REQUEST;
394
395   request->packet = rad_alloc(0);
396   rad_assert(request->packet != NULL);
397
398   request->reply = rad_alloc(0);
399   rad_assert(request->reply != NULL);
400
401   /*
402    *    Fill in the fake request packet.
403    */
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;
410
411   /*
412    *    This isn't STRICTLY required, as the fake request SHOULD NEVER
413    *    be put into the request list.  However, it's still reasonable
414    *    practice.
415    */
416   request->packet->id = request->number & 0xff;
417   request->packet->code = oldreq->packet->code;
418   request->timestamp = oldreq->timestamp;
419
420   /*
421    *    Fill in the fake reply, based on the fake request.
422    */
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 */
428
429   return request;
430 }
431
432
433 /*
434  *      Copy a quoted string.
435  */
436 int rad_copy_string(char *to, const char *from)
437 {
438         int length = 0;
439         char quote = *from;
440
441         do {
442                 if (*from == '\\') {
443                         *(to++) = *(from++);
444                         length++;
445                 }
446                 *(to++) = *(from++);
447                 length++;
448         } while (*from && (*from != quote));
449
450         if (*from != quote) return -1; /* not properly quoted */
451
452         *(to++) = quote;
453         length++;
454         *to = '\0';
455
456         return length;
457 }
458
459
460 /*
461  *      Copy a %{} string.
462  */
463 int rad_copy_variable(char *to, const char *from)
464 {
465         int length = 0;
466         int sublen;
467
468         *(to++) = *(from++);
469         length++;
470
471         while (*from) {
472                 switch (*from) {
473                 case '"':
474                 case '\'':
475                         sublen = rad_copy_string(to, from);
476                         if (sublen < 0) return sublen;
477                         from += sublen;
478                         to += sublen;
479                         break;
480
481                 case '}':       /* end of variable expansion */
482                         *(to++) = *(from++);
483                         *to = '\0';
484                         length++;
485                         return length; /* proper end of variable */
486
487                 case '\\':
488                         *(to++) = *(from++);
489                         *(to++) = *(from++);
490                         length += 2;
491                         break;
492
493                 case '%':       /* start of variable expansion */
494                         if (from[1] == '{') {
495                                 *(to++) = *(from++);
496                                 length++;
497                                 
498                                 sublen = rad_copy_variable(to, from);
499                                 if (sublen < 0) return sublen;
500                                 from += sublen;
501                                 to += sublen;
502                                 length += sublen;
503                         } /* else FIXME: catch %%{ ?*/
504
505                         /* FALL-THROUGH */
506                         break;
507
508                 default:
509                         *(to++) = *(from++);
510                         length++;
511                         break;
512                 }
513         } /* loop over the input string */
514
515         /*
516          *      We ended the string before a trailing '}'
517          */
518
519         return -1;
520 }
521