1 /*
2  * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
3  *
4  * Copyright (C) 2003 Lee H <lee@leeh.co.uk>
5  * Copyright (C) 2003-2005 ircd-ratbox development team
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  * 1.Redistributions of source code must retain the above copyright notice,
12  *   this list of conditions and the following disclaimer.
13  * 2.Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in the
15  *   documentation and/or other materials provided with the distribution.
16  * 3.The name of the author may not be used to endorse or promote products
17  *   derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $Id: s_log.c 26174 2008-11-04 19:42:27Z androsyn $
32  */
33 
34 #include "stdinc.h"
35 #include "struct.h"
36 #include "s_log.h"
37 #include "s_conf.h"
38 #include "send.h"
39 #include "client.h"
40 #include "s_serv.h"
41 #include "match.h"
42 #include "ircd.h"
43 
44 static FILE *log_main;
45 static FILE *log_user;
46 static FILE *log_fuser;
47 static FILE *log_oper;
48 static FILE *log_foper;
49 static FILE *log_server;
50 static FILE *log_kill;
51 static FILE *log_gline;
52 static FILE *log_kline;
53 static FILE *log_operspy;
54 static FILE *log_ioerror;
55 
56 struct log_struct
57 {
58 	char **name;
59 	FILE **logfile;
60 };
61 
62 static struct log_struct log_table[LAST_LOGFILE] = {
63 	{NULL, &log_main},
64 	{&ConfigFileEntry.fname_userlog, &log_user},
65 	{&ConfigFileEntry.fname_fuserlog, &log_fuser},
66 	{&ConfigFileEntry.fname_operlog, &log_oper},
67 	{&ConfigFileEntry.fname_foperlog, &log_foper},
68 	{&ConfigFileEntry.fname_serverlog, &log_server},
69 	{&ConfigFileEntry.fname_killlog, &log_kill},
70 	{&ConfigFileEntry.fname_klinelog, &log_kline},
71 	{&ConfigFileEntry.fname_glinelog, &log_gline},
72 	{&ConfigFileEntry.fname_operspylog, &log_operspy},
73 	{&ConfigFileEntry.fname_ioerrorlog, &log_ioerror}
74 };
75 
76 
77 static void
verify_logfile_access(const char * filename)78 verify_logfile_access(const char *filename)
79 {
80 	char *dirname, *d;
81 	char buf[512];
82 	d = rb_dirname(filename);
83 	dirname = LOCAL_COPY(d);
84 	rb_free(d);
85 
86 	if(access(dirname, F_OK) == -1)
87 	{
88 		rb_snprintf(buf, sizeof(buf), "WARNING: Unable to access logfile %s - parent directory %s does not exist", filename, dirname);
89 		if(testing_conf || server_state_foreground)
90 			fprintf(stderr, "%s\n", buf);
91 		sendto_realops_flags(UMODE_ALL, L_ALL, "%s", buf);
92 		return;
93 	}
94 
95 	if(access(filename, F_OK) == -1)
96 	{
97 		if(access(dirname, W_OK) == -1)
98 		{
99 			rb_snprintf(buf, sizeof(buf), "WARNING: Unable to access logfile %s - access to parent directory %s failed: %s",
100 				    filename, dirname, strerror(errno));
101 			if(testing_conf || server_state_foreground)
102 				fprintf(stderr, "%s\n", buf);
103 			sendto_realops_flags(UMODE_ALL, L_ALL, "%s", buf);
104 		}
105 		return;
106 	}
107 
108 	if(access(filename, W_OK) == -1)
109 	{
110 		rb_snprintf(buf, sizeof(buf), "WARNING: Access denied for logfile %s: %s", filename, strerror(errno));
111 		if(testing_conf || server_state_foreground)
112 			fprintf(stderr, "%s\n", buf);
113 		sendto_realops_flags(UMODE_ALL, L_ALL, "%s", buf);
114 		return;
115 	}
116 	return;
117 }
118 
119 void
init_main_logfile(const char * filename)120 init_main_logfile(const char *filename)
121 {
122 	verify_logfile_access(filename);
123 	if(log_main == NULL)
124 	{
125 		log_main = fopen(filename, "a");
126 	}
127 }
128 
129 void
open_logfiles(const char * filename)130 open_logfiles(const char *filename)
131 {
132 	int i;
133 
134 	close_logfiles();
135 
136 	log_main = fopen(filename, "a");
137 
138 	/* log_main is handled above, so just do the rest */
139 	for(i = 1; i < LAST_LOGFILE; i++)
140 	{
141 		/* reopen those with paths */
142 		if(!EmptyString(*log_table[i].name))
143 		{
144 			verify_logfile_access(*log_table[i].name);
145 			*log_table[i].logfile = fopen(*log_table[i].name, "a");
146 		}
147 	}
148 }
149 
150 void
close_logfiles(void)151 close_logfiles(void)
152 {
153 	int i;
154 
155 	if(log_main != NULL)
156 		fclose(log_main);
157 
158 	/* log_main is handled above, so just do the rest */
159 	for(i = 1; i < LAST_LOGFILE; i++)
160 	{
161 		if(*log_table[i].logfile != NULL)
162 		{
163 			fclose(*log_table[i].logfile);
164 			*log_table[i].logfile = NULL;
165 		}
166 	}
167 }
168 
169 void
ilog(ilogfile dest,const char * format,...)170 ilog(ilogfile dest, const char *format, ...)
171 {
172 	FILE *logfile = *log_table[dest].logfile;
173 	char buf[BUFSIZE];
174 	char buf2[BUFSIZE];
175 	va_list args;
176 
177 #ifndef _WIN32
178 
179 	if(logfile == NULL)
180 		return;
181 #endif
182 	va_start(args, format);
183 	rb_vsnprintf(buf, sizeof(buf), format, args);
184 	va_end(args);
185 
186 	rb_snprintf(buf2, sizeof(buf2), "%s %s\n", smalldate(rb_current_time()), buf);
187 #ifdef _WIN32
188 	fputs(buf2, stderr);
189 	fflush(stderr);
190 
191 	if(logfile == NULL)
192 		return;
193 #endif
194 	if(fputs(buf2, logfile) < 0)
195 	{
196 		sendto_realops_flags(UMODE_ALL, L_ALL, "Closing logfile: %s (%s)",
197 				     *log_table[dest].name, strerror(errno));
198 		fclose(logfile);
199 		*log_table[dest].logfile = NULL;
200 		return;
201 	}
202 
203 	fflush(logfile);
204 }
205 
206 void
report_operspy(struct Client * source_p,const char * token,const char * arg)207 report_operspy(struct Client *source_p, const char *token, const char *arg)
208 {
209 	/* if its not my client its already propagated */
210 	if(MyClient(source_p))
211 		sendto_match_servs(source_p, "*", CAP_ENCAP, NOCAPS,
212 				   "ENCAP * OPERSPY %s %s", token, arg ? arg : "");
213 
214 	sendto_realops_flags(UMODE_OPERSPY,
215 			     ConfigFileEntry.operspy_admin_only ? L_ADMIN : L_ALL,
216 			     "OPERSPY %s %s %s", get_oper_name(source_p), token, arg ? arg : "");
217 
218 	ilog(L_OPERSPY, "OPERSPY %s %s %s", get_oper_name(source_p), token, arg ? arg : "");
219 }
220 
221 const char *
smalldate(time_t ltime)222 smalldate(time_t ltime)
223 {
224 	static char buf[MAX_DATE_STRING];
225 	struct tm *lt;
226 
227 	lt = gmtime(&ltime);
228 
229 	rb_snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
230 		    lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
231 
232 	return buf;
233 }
234 
235 /*
236  * report_error - report an error from an errno.
237  * Record error to log and also send a copy to all *LOCAL* opers online.
238  *
239  *        text        is a *format* string for outputing error. It must
240  *                contain only two '%s', the first will be replaced
241  *                by the sockhost from the client_p, and the latter will
242  *                be taken from sys_errlist[errno].
243  *
244  *        client_p        if not NULL, is the *LOCAL* client associated with
245  *                the error.
246  *
247  * Cannot use perror() within daemon. stderr is closed in
248  * ircd and cannot be used. And, worse yet, it might have
249  * been reassigned to a normal connection...
250  *
251  * Actually stderr is still there IFF ircd was run with -s --Rodder
252  */
253 
254 void
report_error(const char * text,const char * who,const char * wholog,int error)255 report_error(const char *text, const char *who, const char *wholog, int error)
256 {
257 	who = (who) ? who : "";
258 	wholog = (wholog) ? wholog : "";
259 
260 	sendto_realops_flags(UMODE_DEBUG, L_ALL, text, who, strerror(error));
261 
262 	ilog(L_IOERROR, text, wholog, strerror(error));
263 }
264