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