If we have no effective user, don't call getpwnam().
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2001  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 static const char rcsid[] = "$Id$";
27
28 #include "autoconf.h"
29 #include "libradius.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <unistd.h>
35 #include <pwd.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <errno.h>
39
40 #include "radiusd.h"
41
42 #if HAVE_SYSLOG_H
43 #       include <syslog.h>
44 #endif
45
46 static int r_mkdir(const char *);
47
48
49 static int r_mkdir(const char *part) {
50         char *ptr, parentdir[500];
51         struct stat st;
52
53         if (stat(part, &st) == 0)
54                 return(0);
55
56         ptr = strrchr(part, '/');
57
58         if (ptr == part)
59                 return(0);
60
61         snprintf(parentdir, (ptr - part)+1, "%s", part);
62
63         if (r_mkdir(parentdir) != 0)
64                 return(1);
65
66         if (mkdir(part, 0770) != 0) {
67                 fprintf(stderr, "mkdir(%s) error: %s\n", part, strerror(errno));
68                 return(1);
69         }
70
71         fprintf(stderr, "Created directory %s\n", part);
72
73         return(0);
74 }
75                 
76
77 int radlogdir_iswritable(const char *effectiveuser) {
78         struct passwd *pwent;
79
80         if (radlog_dir[0] != '/')
81                 return(0);
82
83         if (r_mkdir(radlog_dir) != 0)
84                 return(1);
85
86         /* FIXME: do we have this function? */
87         if (strstr(radlog_dir, "radius") == NULL)
88                 return(0);
89
90         /* we have a logdir that mentions 'radius', so it's probably 
91          * safe to chown the immediate directory to be owned by the normal 
92          * process owner. we gotta do it before we give up root.  -chad
93          */
94         
95         if (!effectiveuser) {
96                 return 1;
97         }
98
99         pwent = getpwnam(effectiveuser);
100
101         if (pwent == NULL) /* uh oh! */
102                 return(1);
103
104         if (chown(radlog_dir, pwent->pw_uid, -1) != 0)
105                 return(1);
106
107         return(0);
108 }
109
110
111 /*
112  *      Log the message to the logfile. Include the severity and
113  *      a time stamp.
114  */
115 static int do_log(int lvl, const char *fmt, va_list ap)
116 {
117         FILE *msgfd = NULL;
118         const char *s = ": ";
119         unsigned char *p;
120         char buffer[8192];
121         int len;
122
123         /*
124          *      NOT debugging, and trying to log debug messages.
125          *
126          *      Throw the message away.
127          */
128         if (!debug_flag && (lvl == L_DBG)) {
129                 return 0;
130         }
131
132         if (debug_flag 
133             || (radlog_dest == RADLOG_STDOUT)
134             || (radlog_dir == NULL)) {
135                 msgfd = stdout;
136
137         } else if (radlog_dest == RADLOG_STDERR) {
138                 msgfd = stderr;
139
140         } else if (radlog_dest != RADLOG_SYSLOG) {
141
142                 sprintf(buffer, "%.1000s/%.1000s", radlog_dir, RADIUS_LOG);
143                 if ((msgfd = fopen(buffer, "a")) == NULL) {
144                          fprintf(stderr, "%s: Couldn't open %s for logging: %s\n",
145                                  progname, buffer, strerror(errno));
146                                 
147                          fprintf(stderr, "  (");
148                          vfprintf(stderr, fmt, ap);  /* the message that caused the log */
149                          fprintf(stderr, ")\n");
150                          return -1;
151                 }
152         
153         }
154
155 #if HAVE_SYSLOG_H
156         if (radlog_dest == RADLOG_SYSLOG) {
157                 *buffer = '\0';
158                 len = 0;
159         } else
160 #endif
161         {
162                 time_t timeval;
163                 timeval = time(NULL);
164                 ctime_r(&timeval, buffer);
165
166                 switch(lvl & ~L_CONS) {
167                         case L_DBG:
168                                 s = ": Debug: ";
169                                 break;
170                         case L_AUTH:
171                                 s = ": Auth: ";
172                                 break;
173                         case L_PROXY:
174                                 s = ": Proxy: ";
175                                 break;
176                         case L_INFO:
177                                 s = ": Info: ";
178                                 break;
179                         case L_ERR:
180                                 s = ": Error: ";
181                                 break;
182                 }
183                 strcat(buffer, s);
184                 len = strlen(buffer);
185         }
186
187 #ifdef HAVE_VSNPRINTF
188         vsnprintf(buffer + len, sizeof(buffer) - len -1, fmt, ap);
189 #else
190         vsprintf(buffer + len, fmt, ap);
191         if (strlen(buffer) >= sizeof(buffer) - 1)
192                 /* What can we do? */
193                 _exit(42);
194 #endif
195
196         /*
197          *      Filter out characters not in Latin-1.
198          */
199         for (p = (unsigned char *)buffer; *p != '\0'; p++) {
200                 if (*p == '\r' || *p == '\n')
201                         *p = ' ';
202                 else if (*p < 32 || (*p >= 128 && *p <= 160))
203                         *p = '?';
204         }
205         strcat(buffer, "\n");
206         
207         /*
208          *   If we're debugging, for small values of debug, then
209          *   we don't do timestamps.
210          */
211         if ((debug_flag == 1) || (debug_flag == 2)) {
212                 p = buffer + len;
213
214         } else {
215                 /*
216                  *  No debugging, or lots of debugging.  Print
217                  *  the time stamps.
218                  */
219                 p = buffer;
220         }
221
222 #if HAVE_SYSLOG_H
223         if (radlog_dest != RADLOG_SYSLOG)
224 #endif
225         {
226                 fputs(p, msgfd);
227                 if (msgfd == stdout) {
228                         fflush(stdout);
229                 } else if (msgfd == stderr) {
230                         fflush(stderr);
231                 } else {
232                         fclose(msgfd);
233                 }
234         }
235 #if HAVE_SYSLOG_H
236         else {                  /* it was syslog */
237                 switch(lvl & ~L_CONS) {
238                         case L_DBG:
239                                 lvl = LOG_DEBUG;
240                                 break;
241                         case L_AUTH:
242                                 lvl = LOG_NOTICE;
243                                 break;
244                         case L_PROXY:
245                                 lvl = LOG_NOTICE;
246                                 break;
247                         case L_INFO:
248                                 lvl = LOG_INFO;
249                                 break;
250                         case L_ERR:
251                                 lvl = LOG_ERR;
252                                 break;
253                 }
254                 syslog(lvl, "%s", buffer + len); /* don't print timestamp */
255         }
256 #endif
257
258         return 0;
259 }
260
261 int log_debug(const char *msg, ...)
262 {
263         va_list ap;
264         int r;
265
266         va_start(ap, msg);
267         r = do_log(L_DBG, msg, ap);
268         va_end(ap);
269
270         return r;
271 }
272
273 int radlog(int lvl, const char *msg, ...)
274 {
275         va_list ap;
276         int r;
277
278         va_start(ap, msg);
279         r = do_log(lvl, msg, ap);
280         va_end(ap);
281
282         return r;
283 }