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