rlm_eap: add eap_chbind.c to build
[freeradius.git] / src / main / log.c
1 /*
2  * log.c        Logging module.
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 2001,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2001  Chad Miller <cmiller@surfsouth.com>
24  */
25
26 #include <freeradius-devel/ident.h>
27 RCSID("$Id$")
28
29 #include <freeradius-devel/radiusd.h>
30
31 #ifdef HAVE_SYS_STAT_H
32 #include <sys/stat.h>
33 #endif
34
35 #ifdef HAVE_SYSLOG_H
36 #       include <syslog.h>
37 #endif
38
39 /*
40  * Logging facility names
41  */
42 static const FR_NAME_NUMBER levels[] = {
43         { ": Debug: ",          L_DBG   },
44         { ": Auth: ",           L_AUTH  },
45         { ": Proxy: ",          L_PROXY },
46         { ": Info: ",           L_INFO  },
47         { ": Acct: ",           L_ACCT  },
48         { ": Error: ",          L_ERR   },
49         { NULL, 0 }
50 };
51
52 /*
53  *      Log the message to the logfile. Include the severity and
54  *      a time stamp.
55  */
56 int vradlog(int lvl, const char *fmt, va_list ap)
57 {
58         struct main_config_t *myconfig = &mainconfig;
59         unsigned char *p;
60         char buffer[8192];
61         int len;
62
63         /*
64          *      NOT debugging, and trying to log debug messages.
65          *
66          *      Throw the message away.
67          */
68         if (!debug_flag && (lvl == L_DBG)) {
69                 return 0;
70         }
71
72         /*
73          *      If we don't want any messages, then
74          *      throw them away.
75          */
76         if (myconfig->radlog_dest == RADLOG_NULL) {
77                 return 0;
78         }
79
80         *buffer = '\0';
81         len = 0;
82
83         /*
84          *      Don't print timestamps to syslog, it does that for us.
85          *      Don't print timestamps for low levels of debugging.
86          *
87          *      Print timestamps for non-debugging, and for high levels
88          *      of debugging.
89          */
90         if ((myconfig->radlog_dest != RADLOG_SYSLOG) &&
91             (debug_flag != 1) && (debug_flag != 2)) {
92                 const char *s;
93                 time_t timeval;
94
95                 timeval = time(NULL);
96                 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
97
98                 s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
99
100                 strcat(buffer, s);
101                 len = strlen(buffer);
102         }
103
104         vsnprintf(buffer + len, sizeof(buffer) - len - 1, fmt, ap);
105
106         /*
107          *      Filter out characters not in Latin-1.
108          */
109         for (p = (unsigned char *)buffer; *p != '\0'; p++) {
110                 if (*p == '\r' || *p == '\n')
111                         *p = ' ';
112                 else if (*p == '\t') continue;
113                 else if (*p < 32 || (*p >= 128 && *p <= 160))
114                         *p = '?';
115         }
116         strcat(buffer, "\n");
117
118         switch (myconfig->radlog_dest) {
119
120 #ifdef HAVE_SYSLOG_H
121         case RADLOG_SYSLOG:
122                 switch(lvl & ~L_CONS) {
123                         case L_DBG:
124                                 lvl = LOG_DEBUG;
125                                 break;
126                         case L_AUTH:
127                                 lvl = LOG_NOTICE;
128                                 break;
129                         case L_PROXY:
130                                 lvl = LOG_NOTICE;
131                                 break;
132                         case L_ACCT:
133                                 lvl = LOG_NOTICE;
134                                 break;
135                         case L_INFO:
136                                 lvl = LOG_INFO;
137                                 break;
138                         case L_ERR:
139                                 lvl = LOG_ERR;
140                                 break;
141                 }
142                 syslog(lvl, "%s", buffer);
143                 break;
144 #endif
145
146         case RADLOG_FILES:
147         case RADLOG_STDOUT:
148         case RADLOG_STDERR:
149                 write(myconfig->radlog_fd, buffer, strlen(buffer));
150                 break;
151
152         default:
153         case RADLOG_NULL:       /* should have been caught above */
154                 break;
155         }
156
157         return 0;
158 }
159
160 int log_debug(const char *msg, ...)
161 {
162         va_list ap;
163         int r;
164
165         va_start(ap, msg);
166         r = vradlog(L_DBG, msg, ap);
167         va_end(ap);
168
169         return r;
170 }
171
172 int radlog(int lvl, const char *msg, ...)
173 {
174         va_list ap;
175         int r;
176
177         va_start(ap, msg);
178         r = vradlog(lvl, msg, ap);
179         va_end(ap);
180
181         return r;
182 }
183
184
185 /*
186  *      Dump a whole list of attributes to DEBUG2
187  */
188 void vp_listdebug(VALUE_PAIR *vp)
189 {
190         char tmpPair[70];
191         for (; vp; vp = vp->next) {
192                 vp_prints(tmpPair, sizeof(tmpPair), vp);
193                 DEBUG2("     %s", tmpPair);
194         }
195 }
196
197 extern char *request_log_file;
198 #ifdef WITH_COMMAND_SOCKET
199 extern char *debug_log_file;
200 #endif
201
202 void radlog_request(int lvl, int priority, REQUEST *request, const char *msg, ...)
203 {
204         size_t len = 0;
205         const char *filename = request_log_file;
206         FILE *fp = NULL;
207         va_list ap;
208         char buffer[8192];
209
210         va_start(ap, msg);
211
212         /*
213          *      Debug messages get treated specially.
214          */
215         if (lvl == L_DBG) {
216                 /*
217                  *      There is log function, but the debug level
218                  *      isn't high enough.  OR, we're in debug mode,
219                  *      and the debug level isn't high enough.  Return.
220                  */
221                 if ((request && request->radlog &&
222                      (priority > request->options)) ||
223                     ((debug_flag != 0) && (priority > debug_flag))) {
224                         va_end(ap);
225                         return;
226                 }
227
228                 /*
229                  *      Use the debug output file, if specified,
230                  *      otherwise leave it as "request_log_file".
231                  */
232 #ifdef WITH_COMMAND_SOCKET
233                 filename = debug_log_file;
234                 if (!filename)
235 #endif
236                   filename = request_log_file;
237
238                 /*
239                  *      Debug messages get mashed to L_INFO for
240                  *      radius.log.
241                  */
242                 if (!filename) lvl = L_INFO;
243         }
244
245         if (request && filename) {
246                 char *p;
247                 radlog_func_t rl = request->radlog;
248
249                 request->radlog = NULL;
250
251                 /*
252                  *      This is SLOW!  Doing it for every log message
253                  *      in every request is NOT recommended!
254                  */
255                 
256                 radius_xlat(buffer, sizeof(buffer), filename,
257                             request, NULL); /* FIXME: escape chars! */
258                 request->radlog = rl;
259                 
260                 p = strrchr(buffer, FR_DIR_SEP);
261                 if (p) {
262                         *p = '\0';
263                         if (rad_mkdir(buffer, S_IRWXU) < 0) {
264                                 radlog(L_ERR, "Failed creating %s: %s",
265                                        buffer,strerror(errno));
266                                 va_end(ap);
267                                 return;
268                         }
269                         *p = FR_DIR_SEP;
270                 }
271
272                 fp = fopen(buffer, "a");
273         }
274
275         /*
276          *      Print timestamps to the file.
277          */
278         if (fp) {
279                 char *s;
280                 time_t timeval;
281                 timeval = time(NULL);
282
283                 CTIME_R(&timeval, buffer + len, sizeof(buffer) - len - 1);
284                 
285                 s = strrchr(buffer, '\n');
286                 if (s) {
287                         s[0] = ' ';
288                         s[1] = '\0';
289                 }
290                 
291                 s = fr_int2str(levels, (lvl & ~L_CONS), ": ");
292                 
293                 strcat(buffer, s);
294                 len = strlen(buffer);
295         }
296         
297         if (request && request->module[0]) {
298                 snprintf(buffer + len, sizeof(buffer) + len, "%s : ", request->module);
299                 len = strlen(buffer);
300         }
301         vsnprintf(buffer + len, sizeof(buffer) - len, msg, ap);
302         
303         if (!fp) {
304                 if (request) {
305                         radlog(lvl, "(%u) %s", request->number, buffer);
306                 } else {
307                         radlog(lvl, "%s", buffer);
308                 }
309         } else {
310                 if (request) fprintf(fp, "(%u) ", request->number);
311                 fputs(buffer, fp);
312                 fputc('\n', fp);
313                 fclose(fp);
314         }
315
316         va_end(ap);
317 }