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