]> git.ipfire.org Git - thirdparty/sarg.git/blame - redirector.c
Protect a few buffers against overflows
[thirdparty/sarg.git] / redirector.c
CommitLineData
25697a35 1/*
94ff9470 2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
fbd133bb 3 * 1998, 2011
25697a35
GS
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
1164c474
FM
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
25697a35
GS
9 * ---------------------------------------------------------------------
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
24 *
25 */
26
27#include "include/conf.h"
5f3cfd1d 28#include "include/defs.h"
25697a35 29
d6e703cc
FM
30static char **files_done = NULL;
31static int nfiles_done = 0;
32
33
42b117e3 34static void read_log(const char *wentp, FILE *fp_ou,int dfrom,int duntil)
491b862f 35{
9bd92830
FM
36 FILE *fp_in = NULL;
37 char *buf;
38 char leks[5], sep[2], res[MAXLEN];
39 char hour[15];
40 char source[128], list[128];
0a6722a1
FM
41 char full_url[MAX_URL_LEN];
42 const char *url;
9bd92830 43 char user[MAX_USER_LEN];
ad4353be 44 char ip[45];
9bd92830
FM
45 long long int lmon, lday, lyear;
46 int mon, day, year;
47 int idata=0;
48 int i;
9bd92830
FM
49 bool id_is_ip;
50 struct getwordstruct gwarea;
51 struct getwordstruct gwarea1;
52 struct userinfostruct *uinfo;
53 longline line;
491b862f 54
9bd92830
FM
55 if(debug) {
56 debuga(_("Reading redirector log file %s\n"),wentp);
57 }
d6e703cc 58
9bd92830
FM
59 /* With squidGuard, you can log groups in only one log file.
60 We must parse each log files only one time. Example :
61 dest porn {
62 domainlist porn/domains
63 urllist porn/urls
64 log file1.log
65 }
66 dest aggressive {
67 domainlist aggressive/domains
68 urllist aggressive/urls
69 log file2.log
70 }
71 dest audio-video {
72 domainlist audio-video/domains
73 urllist audio-video/urls
74 log file1.log
75 }
76 */
77 for (i=0; i<nfiles_done; i++)
78 if (!strcmp(wentp, files_done[i])) return;
06e3cc62 79
9bd92830
FM
80 nfiles_done++;
81 files_done = realloc(files_done, nfiles_done*sizeof(char *));
82 if (!files_done) {
83 debuga(_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
84 exit(EXIT_FAILURE);
85 }
86 files_done[nfiles_done-1] = strdup(wentp);
87 if (!files_done[nfiles_done-1]) {
88 debuga(_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
89 exit(EXIT_FAILURE);
90 }
d6e703cc 91
9bd92830
FM
92 if ((fp_in=fopen(wentp,"r"))==NULL) {
93 debuga(_("(squidguard) Cannot open log file %s\n"),wentp);
94 exit(EXIT_FAILURE);
95 }
06e3cc62 96
9bd92830
FM
97 if ((line=longline_create())==NULL) {
98 debuga(_("Not enough memory to read the redirector log\n"));
99 exit(EXIT_FAILURE);
100 }
2d4c92a1 101
9bd92830
FM
102 while ((buf=longline_read(fp_in,line)) != NULL) {
103 getword_start(&gwarea,buf);
104 if(RedirectorLogFormat[0] != '\0') {
105 getword_start(&gwarea1,RedirectorLogFormat);
106 leks[0]='\0';
107 if (getword(leks,sizeof(leks),&gwarea1,'#')<0) {
6d4c9798 108 debuga(_("Invalid \"redirector_log_format\" option in your sarg.conf (too many characters before first tag)\n"));
9bd92830
FM
109 exit(EXIT_FAILURE);
110 }
111 year=0;
112 mon=0;
113 day=0;
114 hour[0]='\0';
115 source[0]='\0';
116 list[0]='\0';
117 ip[0]='\0';
118 user[0]='\0';
0a6722a1 119 full_url[0]='\0';
9bd92830 120 while(strcmp(leks,"end") != 0) {
6d4c9798
FM
121 if (getword(leks,sizeof(leks),&gwarea1,'#')<0) {
122 debuga(_("Invalid \"redirector_log_format\" option in your sarg.conf (missing # at end of tag)\n"));
123 exit(EXIT_FAILURE);
124 }
125 if (getword(sep,sizeof(sep),&gwarea1,'#')<0) {
126 debuga(_("Invalid \"redirector_log_format\" option in your sarg.conf (too many characters in column separator)\n"));
9bd92830
FM
127 exit(EXIT_FAILURE);
128 }
129 if(strcmp(leks,"end") != 0) {
130 if (getword_limit(res,sizeof(res),&gwarea,sep[0])<0) {
6d4c9798 131 debuga(_("Parsing of tag \"%s\" in redirector log %s returned no result\n"),leks,wentp);
9bd92830
FM
132 exit(EXIT_FAILURE);
133 }
134 if(strcmp(leks,"year") == 0) {
135 year=atoi(res);
136 } else if(strcmp(leks,"mon") == 0) {
137 mon=atoi(res);
138 } else if(strcmp(leks,"day") == 0) {
139 day=atoi(res);
140 } else if(strcmp(leks,"hour") == 0) {
141 if (strlen(res)>=sizeof(hour)) {
142 debuga(_("Hour string too long in redirector log file %s\n"),wentp);
143 exit(EXIT_FAILURE);
144 }
145 strcpy(hour,res);
146 } else if(strcmp(leks,"source") == 0) {
147 if (strlen(res)>=sizeof(source)) {
148 debuga(_("Banning source name too long in redirector log file %s\n"),wentp);
149 exit(EXIT_FAILURE);
150 }
151 strcpy(source,res);
152 } else if(strcmp(leks,"list") == 0) {
153 if (strlen(res)>=sizeof(list)) {
154 debuga(_("Banning list name too long in redirector log file %s\n"),wentp);
155 exit(EXIT_FAILURE);
156 }
157 strcpy(list,res);
158 } else if(strcmp(leks,"ip") == 0) {
159 if (strlen(res)>=sizeof(ip)) {
160 debuga(_("IP address too long in redirector log file %s\n"),wentp);
161 exit(EXIT_FAILURE);
162 }
163 strcpy(ip,res);
164 } else if(strcmp(leks,"user") == 0) {
165 if (strlen(res)>=sizeof(user)) {
166 debuga(_("User ID too long in redirector log file %s\n"),wentp);
167 exit(EXIT_FAILURE);
168 }
169 strcpy(user,res);
170 } else if(strcmp(leks,"url") == 0) {
0a6722a1 171 if (strlen(res)>=sizeof(full_url)) {
9bd92830
FM
172 debuga(_("URL too long in redirector log file %s\n"),wentp);
173 exit(EXIT_FAILURE);
174 }
0a6722a1 175 strcpy(full_url,res);
9bd92830
FM
176 }
177 }
178 }
179 } else {
180 if (getword_atoll(&lyear,&gwarea,'-')<0 || getword_atoll(&lmon,&gwarea,'-')<0 ||
007905af 181 getword_atoll(&lday,&gwarea,' ')<0) {
9bd92830
FM
182 debuga(_("Invalid date found in file %s\n"),wentp);
183 exit(EXIT_FAILURE);
184 }
185 year=(int)lyear;
186 mon=(int)lmon;
187 day=(int)lday;
188 if (getword(hour,sizeof(hour),&gwarea,' ')<0) {
189 debuga(_("Invalid time found in file %s\n"),wentp);
190 exit(EXIT_FAILURE);
191 }
192 if (getword_skip(MAXLEN,&gwarea,'(')<0 || getword(source,sizeof(source),&gwarea,'/')<0) {
193 debuga(_("Invalid redirected source in file %s\n"),wentp);
194 exit(EXIT_FAILURE);
195 }
196 if (getword(list,sizeof(list),&gwarea,'/')<0) {
197 debuga(_("Invalid redirected list in file %s\n"),wentp);
198 exit(EXIT_FAILURE);
199 }
0a6722a1 200 if (getword_skip(MAXLEN,&gwarea,' ')<0 || getword_limit(full_url,sizeof(full_url),&gwarea,' ')<0) {
9bd92830
FM
201 debuga(_("Invalid URL in file %s\n"),wentp);
202 exit(EXIT_FAILURE);
203 }
204 if (getword(ip,sizeof(ip),&gwarea,'/')<0) {
205 debuga(_("Invalid source IP in file %s\n"),wentp);
206 exit(EXIT_FAILURE);
207 }
208 if (getword_skip(MAXLEN,&gwarea,' ')<0 || getword(user,sizeof(user),&gwarea,' ')<0) {
209 debuga(_("Invalid user in file %s\n"),wentp);
210 exit(EXIT_FAILURE);
211 }
9bd92830 212 }
0a6722a1 213 url=process_url(full_url,false);
491b862f 214
9bd92830 215 //sprintf(warea,"%04d%02d%02d",year,mon,day);
491b862f 216
9bd92830
FM
217 if(RedirectorFilterOutDate) {
218 idata = year*10000+mon*100+day;
219 if(idata < dfrom || idata > duntil)
220 continue;
221 }
491b862f 222
9bd92830
FM
223 if(UserIp) {
224 strcpy(user,ip);
225 id_is_ip=true;
226 } else {
227 id_is_ip=false;
228 if(strcmp(user,"-") == 0 || strcmp(user," ") == 0 || strcmp(user,"") == 0) {
229 if(RecordsWithoutUser == RECORDWITHOUTUSER_IP) {
230 strcpy(user,ip);
231 id_is_ip=true;
232 }
233 if(RecordsWithoutUser == RECORDWITHOUTUSER_IGNORE)
234 continue;
235 if(RecordsWithoutUser == RECORDWITHOUTUSER_EVERYBODY)
236 strcpy(user,"everybody");
237 }
238 }
239 uinfo=userinfo_find_from_id(user);
240 if (!uinfo) {
241 uinfo=userinfo_create(user);
242 uinfo->id_is_ip=id_is_ip;
93551487 243 uinfo->no_report=true;
9bd92830
FM
244 if(Ip2Name && id_is_ip) ip2name(user,sizeof(user));
245 user_find(uinfo->label,MAX_USER_LEN, user);
246 }
247 fprintf(fp_ou,"%s\t%04d%02d%02d\t%s\t%s\t%s\t",uinfo->id,year,mon,day,hour,ip,url);
248 if (source[0] && list[0])
249 fprintf(fp_ou,"%s/%s\n",source,list);
250 else if (source[0])
251 fprintf(fp_ou,"%s\n",source);
252 else
253 fprintf(fp_ou,"%s\n",list);
330b1c52 254 redirector_count++;
9bd92830
FM
255 }
256 fclose(fp_in);
257 longline_destroy(&line);
258 return;
491b862f
GS
259}
260
261
330b1c52 262void redirector_log(void)
25697a35 263{
9bd92830
FM
264 FILE *fp_ou = NULL, *fp_guard = NULL;
265 char buf[MAXLEN];
266 char guard_in[MAXLEN];
267 char guard_ou[MAXLEN];
268 char logdir[MAXLEN];
269 char user[MAXLEN];
270 char tmp6[MAXLEN];
271 int i;
272 int y;
273 int cstatus;
274 int dfrom, duntil;
275 char *str;
276 char *str2;
25697a35 277
9bd92830 278 str2 = user;
d6e703cc 279
9bd92830 280 if(SquidGuardConf[0] == '\0' && NRedirectorLogs == 0)
007905af 281 return;
25697a35 282
9bd92830
FM
283 sprintf(guard_in,"%s/redirector.unsort",tmp);
284 sprintf(guard_ou,"%s/redirector.log",tmp);
285 if((fp_ou=fopen(guard_in,"a"))==NULL) {
286 debuga(_("(squidguard) Cannot open log file %s\n"),guard_in);
287 exit(EXIT_FAILURE);
288 }
25697a35 289
9bd92830
FM
290 dfrom=(period.start.tm_year+1900)*10000+(period.start.tm_mon+1)*100+period.start.tm_mday;
291 duntil=(period.end.tm_year+1900)*10000+(period.end.tm_mon+1)*100+period.end.tm_mday;
25697a35 292
9bd92830
FM
293 if (NRedirectorLogs>0) {
294 for (i=0 ; i<NRedirectorLogs ; i++)
295 read_log(RedirectorLogs[i],fp_ou,dfrom,duntil);
296 } else {
297 if(access(SquidGuardConf, R_OK) != 0) {
298 debuga(_("Cannot open squidGuard config file: %s\n"),SquidGuardConf);
299 exit(EXIT_FAILURE);
300 }
25697a35 301
9bd92830
FM
302 if((fp_guard=fopen(SquidGuardConf,"r"))==NULL) {
303 debuga(_("(squidguard) Cannot open log file %s\n"),SquidGuardConf);
304 exit(EXIT_FAILURE);
305 }
5f3cfd1d 306
9bd92830
FM
307 logdir[0]=0;
308 while(fgets(buf,sizeof(buf),fp_guard)!=NULL) {
309 fixendofline(buf);
310 if((str=get_param_value("logdir",buf))!=NULL) {
311 /*
312 We want to tolerate spaces inside the directory name but we must also
313 remove the trailing spaces left by the editor after the directory name.
314 This should not be a problem as nobody use a file name with trailing spaces.
315 */
316 for (y=strlen(str)-1 ; y>=0 && (unsigned char)str[y]<=' ' ; y--);
317 if (y>=sizeof(logdir)-1) y=sizeof(logdir)-2;
318 logdir[y+1] = '\0';
319 while (y>=0) {
320 logdir[y] = str[y];
321 y--;
322 }
323 } else if((str=get_param_value("log",buf))!=NULL) {
324 if((str2=get_param_value("anonymous",str))!=NULL)
325 str=str2;
d6e703cc 326
9bd92830
FM
327 /*
328 If logdir is defined, we prepend it to the log file name, otherwise, we assume
329 the log directive provides an absolute file name to the log file. Therefore,
330 we don't need to add an additionnal / at the beginning of the log file name.
331 */
332 y=(logdir[0]) ? sprintf(wentp,"%s/",logdir) : 0;
333 /*
334 Spaces are allowed in the name of the log file. The file name ends at the first #
335 because it is assumed it is an end of line comment. Any space before the # is then
336 removed. Any control character (i.e. a character with a code lower than 32) ends
337 the file name. That includes the terminating zero.
338 */
339 while((unsigned char)*str>=' ' && *str!='#' && y<sizeof(wentp)-1)
340 wentp[y++]=*str++;
341 if(*str=='#') {
342 str--;
343 while(*str==' ' && y>0) {
344 str--;
345 y--;
346 }
347 }
348 wentp[y]=0;
349 read_log(wentp,fp_ou,dfrom,duntil);
350 }
351 }
352 }
491b862f 353
9bd92830
FM
354 if (fp_guard) fclose(fp_guard);
355 if (fp_ou) fclose(fp_ou);
491b862f 356
9bd92830
FM
357 if (files_done) {
358 for (y=0; y<nfiles_done; y++)
359 if (files_done[y]) free(files_done[y]);
360 free(files_done);
361 }
c274f011 362
9bd92830
FM
363 if(debug) {
364 debuga(_("Sorting file: %s\n"),guard_ou);
365 }
25697a35 366
78eeb33f
FM
367 if (snprintf(tmp6,sizeof(tmp6),"sort -t \"\t\" -k 1,1 -k 2,2 -k 4,4 \"%s\" -o \"%s\"",guard_in, guard_ou)>=sizeof(tmp6)) {
368 debuga(_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),guard_in,guard_ou);
369 exit(EXIT_FAILURE);
370 }
9bd92830
FM
371 cstatus=system(tmp6);
372 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
373 debuga(_("sort command return status %d\n"),WEXITSTATUS(cstatus));
374 debuga(_("sort command: %s\n"),tmp6);
375 exit(EXIT_FAILURE);
376 }
491b862f 377
08f9b029
FM
378 if (unlink(guard_in)) {
379 debuga(_("Cannot delete %s - %s\n"),guard_in,strerror(errno));
380 exit(EXIT_FAILURE);
381 }
9bd92830 382 return;
25697a35 383}
330b1c52 384
7ae50eee
FM
385static void show_ignored_redirector(FILE *fp_ou,int count)
386{
387 char ignored[80];
388
389 snprintf(ignored,sizeof(ignored),ngettext("%d more redirector entry not shown here&hellip;","%d more redirector entries not shown here&hellip;",count),count);
390 fprintf(fp_ou,"<tr><td class=\"data\"></td><td class=\"data\"></td><td class=\"data\"></td><td class=\"data2 more\">%s</td><td class=\"data\"></td></tr>\n",ignored);
391}
392
330b1c52
FM
393void redirector_report(void)
394{
395 FILE *fp_in = NULL, *fp_ou = NULL;
396
397 char *buf;
398 char *url;
399 char squidguard_in[MAXLEN];
400 char report[MAXLEN];
401 char ip[45];
402 char rule[255];
403 char oip[45];
404 char user[MAXLEN];
405 char ouser[MAXLEN];
406 char data[15];
407 char hora[15];
408 char ouser2[255];
409 char oname[MAXLEN];
410 bool z=false;
411 int count=0;
412 long long int data2;
413 bool new_user;
414 struct getwordstruct gwarea;
415 const struct userinfostruct *uinfo;
416 struct tm t;
417 longline line;
418
419 ouser[0]='\0';
420 ouser2[0]='\0';
421
422 sprintf(squidguard_in,"%s/redirector.log",tmp);
423 if(!redirector_count) {
424 unlink(squidguard_in);
425 return;
426 }
427
428 snprintf(report,sizeof(report),"%s/redirector.html",outdirname);
429
430 if((fp_in=fopen(squidguard_in,"r"))==NULL) {
431 debuga(_("(squidguard) Cannot open log file %s\n"),squidguard_in);
432 exit(EXIT_FAILURE);
433 }
434
435 if((fp_ou=fopen(report,"w"))==NULL) {
436 debuga(_("(squidguard) Cannot open log file %s\n"),report);
437 exit(EXIT_FAILURE);
438 }
439
440 if ((line=longline_create())==NULL) {
441 debuga(_("Not enough memory to read the processed redirector log\n"));
442 exit(EXIT_FAILURE);
443 }
444
445 write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Redirector report"),HTML_JS_NONE);
446 fputs("<tr><td class=\"header_c\">",fp_ou);
447 fprintf(fp_ou,_("Period: %s"),period.html);
448 fputs("</td></tr>\n",fp_ou);
449 fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Redirector report"));
450 close_html_header(fp_ou);
451
452 fputs("<div class=\"report\"><table cellpadding=1 cellspacing=2>\n",fp_ou);
453 fprintf(fp_ou,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",_("USERID"),_("IP/NAME"),_("DATE/TIME"),_("ACCESSED SITE"),_("RULE"));
454
455 while((buf=longline_read(fp_in,line))!=NULL) {
456 getword_start(&gwarea,buf);
457 if (getword(user,sizeof(user),&gwarea,'\t')<0) {
458 debuga(_("Invalid user in file %s\n"),squidguard_in);
459 exit(EXIT_FAILURE);
460 }
461 if (getword_atoll(&data2,&gwarea,'\t')<0) {
462 debuga(_("Invalid date in file %s\n"),squidguard_in);
463 exit(EXIT_FAILURE);
464 }
465 if (getword(hora,sizeof(hora),&gwarea,'\t')<0) {
466 debuga(_("Invalid time in file %s\n"),squidguard_in);
467 exit(EXIT_FAILURE);
468 }
469 if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
470 debuga(_("Invalid IP address in file %s\n"),squidguard_in);
471 exit(EXIT_FAILURE);
472 }
473 if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
474 debuga(_("Invalid URL in file %s\n"),squidguard_in);
475 exit(EXIT_FAILURE);
476 }
477 if (getword(rule,sizeof(rule),&gwarea,'\n')<0) {
478 debuga(_("Invalid rule in file %s\n"),squidguard_in);
479 exit(EXIT_FAILURE);
480 }
481
482 uinfo=userinfo_find_from_id(user);
483 if (!uinfo) {
484 debuga(_("Unknown user ID %s in file %s\n"),user,squidguard_in);
485 exit(EXIT_FAILURE);
486 }
487
488 computedate(data2/10000,(data2/100)%10,data2%100,&t);
489 strftime(data,sizeof(data),"%x",&t);
490
491 new_user=false;
492 if(!z) {
493 strcpy(ouser,user);
494 strcpy(oip,ip);
495 strcpy(oname,ip);
496 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
497 z=true;
498 new_user=true;
499 } else {
500 if(strcmp(ouser,user) != 0) {
501 strcpy(ouser,user);
502 new_user=true;
503 }
504 if(strcmp(oip,ip) != 0) {
505 strcpy(oip,ip);
506 strcpy(oname,ip);
507 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
508 new_user=true;
509 }
510 }
511
512 if(SquidGuardReportLimit) {
513 if(strcmp(ouser2,uinfo->label) == 0) {
514 count++;
515 } else {
7ae50eee
FM
516 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
517 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
330b1c52
FM
518 count=1;
519 strcpy(ouser2,uinfo->label);
520 }
7ae50eee 521 if(count > SquidGuardReportLimit)
330b1c52
FM
522 continue;
523 }
524
525 if (new_user)
526 fprintf(fp_ou,"<tr><td class=\"data2\">%s</td><td class=\"data2\">%s</td>",uinfo->label,ip);
527 else
528 fputs("<tr><td class=\"data2\"></td><td class=\"data2\"></td>",fp_ou);
529 fprintf(fp_ou,"<td class=\"data2\">%s-%s</td><td class=\"data2\">",data,hora);
530 output_html_link(fp_ou,url,100);
531 fprintf(fp_ou,"</td><td class=\"data2\">%s</td></tr>\n",rule);
532 }
533 fclose(fp_in);
534 longline_destroy(&line);
535
7ae50eee
FM
536 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
537 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
538
330b1c52
FM
539 fputs("</table></div>\n",fp_ou);
540 if (write_html_trailer(fp_ou)<0)
541 debuga(_("Write error in file %s\n"),report);
542 if (fclose(fp_ou)==EOF)
543 debuga(_("Failed to close file %s - %s\n"),report,strerror(errno));
544
545 if (unlink(squidguard_in)) {
546 debuga(_("Cannot delete %s - %s\n"),squidguard_in,strerror(errno));
547 exit(EXIT_FAILURE);
548 }
549
550 return;
551}