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