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