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