Initialize the structure
[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         memset(&act, 0, sizeof(act));
53         act.sa_handler = func;
54         sigemptyset(&act.sa_mask);
55         act.sa_flags = 0;
56 #ifdef  SA_INTERRUPT            /* SunOS */
57         act.sa_flags |= SA_INTERRUPT;
58 #endif
59         if (sigaction(signo, &act, &oact) < 0)
60                 return SIG_ERR;
61         return oact.sa_handler;
62 #else
63
64         /*
65          *      re-set by calling the 'signal' function, which
66          *      may cause infinite recursion and core dumps due to
67          *      stack growth.
68          *
69          *      However, the system is too dumb to implement sigaction(),
70          *      so we don't have a choice.
71          */
72         signal(signo, func);
73
74         return NULL;
75 #endif
76 }
77
78 /*
79  *      Per-request data, added by modules...
80  */
81 struct request_data_t {
82         request_data_t  *next;
83
84         void            *unique_ptr;
85         int             unique_int;
86         void            *opaque;
87         void            (*free_opaque)(void *);
88 };
89
90 /*
91  *      Add opaque data (with a "free" function) to a REQUEST.
92  *
93  *      The unique ptr is meant to be a malloc'd module configuration,
94  *      and the unique integer allows the caller to have multiple
95  *      opaque data associated with a REQUEST.
96  */
97 int request_data_add(REQUEST *request,
98                      void *unique_ptr, int unique_int,
99                      void *opaque, void (*free_opaque)(void *))
100 {
101         request_data_t *this, **last, *next;
102
103         /*
104          *      Some simple sanity checks.
105          */
106         if (!request || !opaque) return -1;
107
108         this = next = NULL;
109         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
110                 if (((*last)->unique_ptr == unique_ptr) &&
111                     ((*last)->unique_int == unique_int)) {
112                         this = *last;
113
114                         next = this->next;
115
116                         if (this->opaque && /* free it, if necessary */
117                             this->free_opaque)
118                                 this->free_opaque(this->opaque);
119                         break;  /* replace the existing entry */
120                 }
121         }
122
123         if (!this) this = rad_malloc(sizeof(*this));
124         memset(this, 0, sizeof(*this));
125
126         this->next = next;
127         this->unique_ptr = unique_ptr;
128         this->unique_int = unique_int;
129         this->opaque = opaque;
130         this->free_opaque = free_opaque;
131
132         *last = this;
133
134         return 0;
135 }
136
137
138 /*
139  *      Get opaque data from a request.
140  */
141 void *request_data_get(REQUEST *request,
142                        void *unique_ptr, int unique_int)
143 {
144         request_data_t **last;
145
146         if (!request) return NULL;
147
148         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
149                 if (((*last)->unique_ptr == unique_ptr) &&
150                     ((*last)->unique_int == unique_int)) {
151                         request_data_t *this = *last;
152                         void *ptr = this->opaque;
153
154                         /*
155                          *      Remove the entry from the list, and free it.
156                          */
157                         *last = this->next;
158                         free(this);
159                         return ptr; /* don't free it, the caller does that */
160                 }
161         }
162
163         return NULL;            /* wasn't found, too bad... */
164 }
165
166
167 /*
168  *      Get opaque data from a request without removing it.
169  */
170 void *request_data_reference(REQUEST *request,
171                        void *unique_ptr, int unique_int)
172 {
173         request_data_t **last;
174
175         for (last = &(request->data); *last != NULL; last = &((*last)->next)) {
176                 if (((*last)->unique_ptr == unique_ptr) &&
177                     ((*last)->unique_int == unique_int)) {
178                         request_data_t *this = *last;
179                         void *ptr = this->opaque;
180
181                         return ptr;
182                 }
183         }
184
185         return NULL;            /* wasn't found, too bad... */
186 }
187
188
189 /*
190  *      Free a REQUEST struct.
191  */
192 void request_free(REQUEST **request_ptr)
193 {
194         REQUEST *request;
195
196         if ((request_ptr == NULL) || !*request_ptr)
197                 return;
198
199         request = *request_ptr;
200
201         rad_assert(!request->in_request_hash);
202 #ifdef WITH_PROXY
203         rad_assert(!request->in_proxy_hash);
204 #endif
205         rad_assert(!request->ev);
206
207         if (request->packet)
208                 rad_free(&request->packet);
209
210 #ifdef WITH_PROXY
211         if (request->proxy)
212                 rad_free(&request->proxy);
213 #endif
214
215         if (request->reply)
216                 rad_free(&request->reply);
217
218 #ifdef WITH_PROXY
219         if (request->proxy_reply)
220                 rad_free(&request->proxy_reply);
221 #endif
222
223         if (request->config_items)
224                 pairfree(&request->config_items);
225
226         request->username = NULL;
227         request->password = NULL;
228
229         if (request->data) {
230                 request_data_t *this, *next;
231
232                 for (this = request->data; this != NULL; this = next) {
233                         next = this->next;
234                         if (this->opaque && /* free it, if necessary */
235                             this->free_opaque)
236                                 this->free_opaque(this->opaque);
237                         free(this);
238                 }
239                 request->data = NULL;
240         }
241
242         if (request->root &&
243             (request->root->refcount > 0)) {
244                 request->root->refcount--;
245                 request->root = NULL;
246         }
247
248 #ifdef WITH_COA
249         if (request->coa) {
250                 request->coa->parent = NULL;
251                 rad_assert(request->coa->ev == NULL);
252                 request_free(&request->coa);
253         }
254
255         if (request->parent && (request->parent->coa == request)) {
256                 request->parent->coa = NULL;
257         }
258 #endif
259
260 #ifndef NDEBUG
261         request->magic = 0x01020304;    /* set the request to be nonsense */
262 #endif
263         request->client = NULL;
264 #ifdef WITH_PROXY
265         request->home_server = NULL;
266 #endif
267         free(request);
268
269         *request_ptr = NULL;
270 }
271
272 /*
273  *      Check a filename for sanity.
274  *
275  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
276  */
277 int rad_checkfilename(const char *filename)
278 {
279         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
280                 return 0;
281         }
282
283         return -1;
284 }
285
286 /*
287  *      Create possibly many directories.
288  *
289  *      Note that the input directory name is NOT a constant!
290  *      This is so that IF an error is returned, the 'directory' ptr
291  *      points to the name of the file which caused the error.
292  */
293 int rad_mkdir(char *directory, int mode)
294 {
295         int rcode;
296         char *p;
297         struct stat st;
298
299         /*
300          *      If the directory exists, don't do anything.
301          */
302         if (stat(directory, &st) == 0) {
303                 return 0;
304         }
305
306         /*
307          *      Look for the LAST directory name.  Try to create that,
308          *      failing on any error.
309          */
310         p = strrchr(directory, FR_DIR_SEP);
311         if (p != NULL) {
312                 *p = '\0';
313                 rcode = rad_mkdir(directory, mode);
314
315                 /*
316                  *      On error, we leave the directory name as the
317                  *      one which caused the error.
318                  */
319                 if (rcode < 0) {
320                         return rcode;
321                 }
322
323                 /*
324                  *      Reset the directory delimiter, and go ask
325                  *      the system to make the directory.
326                  */
327                 *p = FR_DIR_SEP;
328         } else {
329                 return 0;
330         }
331
332         /*
333          *      Having done everything successfully, we do the
334          *      system call to actually go create the directory.
335          */
336         return mkdir(directory, mode);
337 }
338
339
340 /*
341  *      Module malloc() call, which does stuff if the malloc fails.
342  *
343  *      This call ALWAYS succeeds!
344  */
345 void *rad_malloc(size_t size)
346 {
347         void *ptr = malloc(size);
348
349         if (ptr == NULL) {
350                 radlog(L_ERR|L_CONS, "no memory");
351                 exit(1);
352         }
353
354         return ptr;
355 }
356
357 /*
358  *      Logs an error message and aborts the program
359  *
360  */
361
362 void NEVER_RETURNS rad_assert_fail (const char *file, unsigned int line,
363                                     const char *expr)
364 {
365         radlog(L_ERR, "ASSERT FAILED %s[%u]: %s", file, line, expr);
366         abort();
367 }
368
369
370 /*
371  *      Create a new REQUEST data structure.
372  */
373 REQUEST *request_alloc(void)
374 {
375         REQUEST *request;
376
377         request = rad_malloc(sizeof(REQUEST));
378         memset(request, 0, sizeof(REQUEST));
379 #ifndef NDEBUG
380         request->magic = REQUEST_MAGIC;
381 #endif
382 #ifdef WITH_PROXY
383         request->proxy = NULL;
384 #endif
385         request->reply = NULL;
386 #ifdef WITH_PROXY
387         request->proxy_reply = NULL;
388 #endif
389         request->config_items = NULL;
390         request->username = NULL;
391         request->password = NULL;
392         request->timestamp = time(NULL);
393         request->options = RAD_REQUEST_OPTION_NONE;
394
395         request->module = "";
396         request->component = "<core>";
397         if (debug_flag) request->radlog = radlog_request;
398
399         return request;
400 }
401
402
403 /*
404  *      Create a new REQUEST, based on an old one.
405  *
406  *      This function allows modules to inject fake requests
407  *      into the server, for tunneled protocols like TTLS & PEAP.
408  */
409 REQUEST *request_alloc_fake(REQUEST *request)
410 {
411   REQUEST *fake;
412
413   fake = request_alloc();
414
415   fake->number = request->number;
416 #ifdef HAVE_PTHREAD_H
417   fake->child_pid = request->child_pid;
418 #endif
419   fake->parent = request;
420   fake->root = request->root;
421   fake->client = request->client;
422
423   /*
424    *    For new server support.
425    *
426    *    FIXME: Key instead off of a "virtual server" data structure.
427    *
428    *    FIXME: Permit different servers for inner && outer sessions?
429    */
430   fake->server = request->server;
431
432   fake->packet = rad_alloc(0);
433   if (!fake->packet) {
434           request_free(&fake);
435           return NULL;
436   }
437
438   fake->reply = rad_alloc(0);
439   if (!fake->reply) {
440           request_free(&fake);
441           return NULL;
442   }
443
444   fake->master_state = REQUEST_ACTIVE;
445   fake->child_state = REQUEST_RUNNING;
446
447   /*
448    *    Fill in the fake request.
449    */
450   fake->packet->sockfd = -1;
451   fake->packet->src_ipaddr = request->packet->src_ipaddr;
452   fake->packet->src_port = request->packet->src_port;
453   fake->packet->dst_ipaddr = request->packet->dst_ipaddr;
454   fake->packet->dst_port = 0;
455
456   /*
457    *    This isn't STRICTLY required, as the fake request MUST NEVER
458    *    be put into the request list.  However, it's still reasonable
459    *    practice.
460    */
461   fake->packet->id = fake->number & 0xff;
462   fake->packet->code = request->packet->code;
463   fake->timestamp = request->timestamp;
464  
465   /*
466    *    Required for new identity support
467    */
468   fake->listener = request->listener;
469
470   /*
471    *    Fill in the fake reply, based on the fake request.
472    */
473   fake->reply->sockfd = fake->packet->sockfd;
474   fake->reply->src_ipaddr = fake->packet->dst_ipaddr;
475   fake->reply->src_port = fake->packet->dst_port;
476   fake->reply->dst_ipaddr = fake->packet->src_ipaddr;
477   fake->reply->dst_port = fake->packet->src_port;
478   fake->reply->id = fake->packet->id;
479   fake->reply->code = 0; /* UNKNOWN code */
480
481   /*
482    *    Copy debug information.
483    */
484   fake->options = request->options;
485   fake->radlog = request->radlog;
486
487   return fake;
488 }
489
490 #ifdef WITH_COA
491 REQUEST *request_alloc_coa(REQUEST *request)
492 {
493         if (!request || request->coa) return NULL;
494
495         /*
496          *      Originate CoA requests only when necessary.
497          */
498         if ((request->packet->code != PW_AUTHENTICATION_REQUEST) &&
499             (request->packet->code != PW_ACCOUNTING_REQUEST)) return NULL;
500
501         request->coa = request_alloc_fake(request);
502         if (!request->coa) return NULL;
503
504         request->coa->packet->code = 0; /* unknown, as of yet */
505         request->coa->child_state = REQUEST_RUNNING;
506         request->coa->proxy = rad_alloc(0);
507         if (!request->coa->proxy) {
508                 request_free(&request->coa);
509                 return NULL;
510         }
511
512         return request->coa;
513 }
514 #endif
515
516 /*
517  *      Copy a quoted string.
518  */
519 int rad_copy_string(char *to, const char *from)
520 {
521         int length = 0;
522         char quote = *from;
523
524         do {
525                 if (*from == '\\') {
526                         *(to++) = *(from++);
527                         length++;
528                 }
529                 *(to++) = *(from++);
530                 length++;
531         } while (*from && (*from != quote));
532
533         if (*from != quote) return -1; /* not properly quoted */
534
535         *(to++) = quote;
536         length++;
537         *to = '\0';
538
539         return length;
540 }
541
542
543 /*
544  *      Copy a %{} string.
545  */
546 int rad_copy_variable(char *to, const char *from)
547 {
548         int length = 0;
549         int sublen;
550
551         *(to++) = *(from++);
552         length++;
553
554         while (*from) {
555                 switch (*from) {
556                 case '"':
557                 case '\'':
558                         sublen = rad_copy_string(to, from);
559                         if (sublen < 0) return sublen;
560                         from += sublen;
561                         to += sublen;
562                         length += sublen;
563                         break;
564
565                 case '}':       /* end of variable expansion */
566                         *(to++) = *(from++);
567                         *to = '\0';
568                         length++;
569                         return length; /* proper end of variable */
570
571                 case '\\':
572                         *(to++) = *(from++);
573                         *(to++) = *(from++);
574                         length += 2;
575                         break;
576
577                 case '%':       /* start of variable expansion */
578                         if (from[1] == '{') {
579                                 *(to++) = *(from++);
580                                 length++;
581
582                                 sublen = rad_copy_variable(to, from);
583                                 if (sublen < 0) return sublen;
584                                 from += sublen;
585                                 to += sublen;
586                                 length += sublen;
587                                 break;
588                         } /* else FIXME: catch %%{ ?*/
589
590                         /* FALL-THROUGH */
591                 default:
592                         *(to++) = *(from++);
593                         length++;
594                         break;
595                 }
596         } /* loop over the input string */
597
598         /*
599          *      We ended the string before a trailing '}'
600          */
601
602         return -1;
603 }
604