Code "cleanups." I confess that I sometimes went beyond the TODO
[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 "autoconf.h"
26 #include "libradius.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <signal.h>
33
34 #include <sys/stat.h>
35 #include <fcntl.h>
36
37 #if HAVE_UNISTD_H
38 #       include <unistd.h>
39 #endif
40
41 #include "radiusd.h"
42
43 /*
44  *      The signal() function in Solaris 2.5.1 sets SA_NODEFER in
45  *      sa_flags, which causes grief if signal() is called in the
46  *      handler before the cause of the signal has been cleared.
47  *      (Infinite recursion).
48  *
49  *      The same problem appears on HPUX, so we avoid it, if we can.
50  *
51  *      Using sigaction() to reset the signal handler fixes the problem,
52  *      so where available, we prefer that solution.
53  */
54 void (*reset_signal(int signo, void (*func)(int)))(int)
55 {
56 #ifdef HAVE_SIGACTION
57         struct sigaction act, oact;
58
59         act.sa_handler = func;
60         sigemptyset(&act.sa_mask);
61         act.sa_flags = 0;
62 #ifdef  SA_INTERRUPT            /* SunOS */
63         act.sa_flags |= SA_INTERRUPT;
64 #endif
65         if (sigaction(signo, &act, &oact) < 0)
66                 return SIG_ERR;
67         return oact.sa_handler;
68 #else
69         
70         /*
71          *      re-set by calling the 'signal' function, which
72          *      may cause infinite recursion and core dumps due to
73          *      stack growth.
74          *
75          *      However, the system is too dumb to implement sigaction(),
76          *      so we don't have a choice.
77          */
78         signal(signo, func);
79 #endif
80 }
81
82
83 /*
84  *      Free a REQUEST struct.
85  */
86 void request_free(REQUEST **request_ptr)
87 {
88         REQUEST *request;
89         
90         if (request_ptr == NULL) 
91                 return;
92         request = *request_ptr;
93
94         if (request->packet) 
95                 rad_free(&request->packet);
96
97         if (request->proxy) 
98                 rad_free(&request->proxy);
99
100         if (request->reply) 
101                 rad_free(&request->reply);
102
103         if (request->proxy_reply) 
104                 rad_free(&request->proxy_reply);
105
106         if (request->config_items) 
107                 pairfree(&request->config_items);
108
109 #ifndef NDEBUG
110         request->magic = 0x01020304;    /* set the request to be nonsense */
111 #endif
112         free(request);
113
114         *request_ptr = NULL;
115 }
116
117 /*
118  *      Check a filename for sanity.
119  *
120  *      Allow only uppercase/lowercase letters, numbers, and '-_/.'
121  */
122 int rad_checkfilename(const char *filename)
123 {
124         if (strspn(filename, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/.") == strlen(filename)) {
125                 return 0;
126         }
127
128         return -1;
129 }
130
131 /*
132  *      Create possibly many directories.
133  *
134  *      Note that the input directory name is NOT a constant!
135  *      This is so that IF an error is returned, the 'directory' ptr
136  *      points to the name of the file which caused the error.
137  */
138 int rad_mkdir(char *directory, int mode)
139 {
140         int rcode;
141         char *p;
142         struct stat st;
143
144         /*
145          *      If the directory exists, don't do anything.
146          */
147         if (stat(directory, &st) == 0) {
148                 return 0;
149         }
150
151         /*
152          *      Look for the LAST directory name.  Try to create that,
153          *      failing on any error.
154          */
155         p = strrchr(directory, '/');
156         if (p != NULL) {
157                 *p = '\0';
158                 rcode = rad_mkdir(directory, mode);
159
160                 /*
161                  *      On error, we leave the directory name as the
162                  *      one which caused the error.
163                  */
164                 if (rcode < 0) {
165                         return rcode;
166                 }
167
168                 /*
169                  *      Reset the directory delimiter, and go ask
170                  *      the system to make the directory.
171                  */
172                 *p = '/';
173         } else {
174                 return 0;
175         }
176
177         /*
178          *      Having done everything successfully, we do the
179          *      system call to actually go create the directory.
180          */
181         return mkdir(directory, mode);
182 }
183
184
185 /*
186  *      Module malloc() call, which does stuff if the malloc fails.
187  *
188  *      This call ALWAYS succeeds!
189  */
190 void *rad_malloc(size_t size)
191 {
192         void *ptr = malloc(size);
193         
194         if (ptr == NULL) {
195                 radlog(L_ERR|L_CONS, "no memory");
196                 exit(1);
197         }
198
199         return ptr;
200 }
201
202 void xfree(const char *ptr)
203 {
204         free((char *)ptr);
205 }