]> git.ipfire.org Git - thirdparty/sarg.git/blame - download.c
Rename configure.in as configure.ac
[thirdparty/sarg.git] / download.c
CommitLineData
25697a35 1/*
94ff9470 2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
110ce984 3 * 1998, 2015
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"
f83d7b44 29#include "include/readlog.h"
25697a35 30
b2fa3eb6
FM
31/*!
32The buffer to store the list of the suffixes to take into account when generating
33the report of the downloaded files. The suffixes in the list are separated by the ASCII
34null.
35*/
2824ec9b 36/*@null@*/static char *DownloadSuffix=NULL;
b2fa3eb6
FM
37
38/*!
39The index of all the suffixes stored in ::DownloadSuffix. The list is sorted alphabetically.
40to speed up the search.
41*/
2824ec9b 42/*@null@*/static char **DownloadSuffixIndex=NULL;
b2fa3eb6
FM
43
44/*!
45The number of suffixes in ::DownloadSuffixIndex.
46*/
6e792ade
FM
47static int NDownloadSuffix=0;
48
11284535
FM
49//! Name of the file containing the unsorted downloaded entries.
50static char download_unsort[MAXLEN]="";
51//! The file handle to write the entries.
52static FILE *fp_download=NULL;
53//! \c True if at least one downloaded entry exists.
54static bool download_exists=false;
55
56/*!
57Open a file to store the denied accesses.
58
59\return The file handle or NULL if no file is necessary.
60*/
61void download_open(void)
62{
63 if ((ReportType & REPORT_TYPE_DOWNLOADS) == 0) {
af961877 64 if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("Download report not produced as it is not requested\n"));
11284535
FM
65 return;
66 }
67 if (Privacy) {
af961877 68 if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("Download report not produced because privacy option is active\n"));
11284535
FM
69 return;
70 }
71
72 snprintf(download_unsort,sizeof(download_unsort),"%s/download.int_unsort",tmp);
73 if ((fp_download=MY_FOPEN(download_unsort,"w"))==NULL) {
af961877 74 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),download_unsort,strerror(errno));
11284535
FM
75 exit(EXIT_FAILURE);
76 }
77 return;
78}
79
80/*!
81Write one entry in the unsorted downloaded file provided that it is required.
82
83\param log_entry The entry to write into the log file.
84\param url The URL of the downloaded file.
85*/
86void download_write(const struct ReadLogStruct *log_entry,const char *url)
87{
88 char date[80];
89
88776d28 90 if (fp_download && strstr(log_entry->HttpCode,"DENIED") == 0) {
11284535
FM
91 strftime(date,sizeof(date),"%d/%m/%Y\t%H:%M:%S",&log_entry->EntryTime);
92 fprintf(fp_download,"%s\t%s\t%s\t%s\n",date,log_entry->User,log_entry->Ip,url);
93 download_exists=true;
94 }
95}
96
97/*!
98Close the file opened by denied_open().
99*/
100void download_close(void)
101{
102 if (fp_download)
103 {
507460ae 104 if (fclose(fp_download)==EOF) {
af961877 105 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),download_unsort,strerror(errno));
11284535
FM
106 exit(EXIT_FAILURE);
107 }
108 fp_download=NULL;
109 }
110}
111
112/*!
113Tell the caller if a download report exists.
114
115\return \c True if the report is available or \c false if no report
116was generated.
117*/
118bool is_download(void)
119{
120 return(download_exists);
121}
122
b2fa3eb6
FM
123/*!
124Sort the raw log file with the downloaded files.
125
126\param report_in The name of the file where to store the sorted entries.
73b57f55
FM
127
128The file is sorted by columns 3, 1, 2 and 5 that are the columns of the user's ID, the
129date, the time and the URL.
b2fa3eb6
FM
130*/
131static void download_sort(const char *report_in)
132{
133 int clen;
134 char csort[MAXLEN];
135 int cstatus;
bd43d81f 136
11284535
FM
137 clen=snprintf(csort,sizeof(csort),"sort -T \"%s\" -t \"\t\" -k 3,3 -k 1,1 -k 2,2 -k 5,5 -o \"%s\" \"%s\"",
138 tmp, report_in, download_unsort);
b2fa3eb6 139 if (clen>=sizeof(csort)) {
af961877 140 debuga(__FILE__,__LINE__,_("Path too long to sort file \"%s\"\n"),download_unsort);
b2fa3eb6
FM
141 exit(EXIT_FAILURE);
142 }
143 cstatus=system(csort);
144 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
af961877
FM
145 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
146 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
b2fa3eb6
FM
147 exit(EXIT_FAILURE);
148 }
11284535
FM
149 if (!KeepTempLog) {
150 if (unlink(download_unsort)) {
af961877 151 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),download_unsort,strerror(errno));
11284535
FM
152 exit(EXIT_FAILURE);
153 }
154 download_unsort[0]='\0';
b2fa3eb6
FM
155 }
156}
157
158/*!
159Generate the report of the downloaded files. The list of the suffixes to take into account
160is set with set_download_suffix().
161*/
32e71fa4 162void download_report(void)
25697a35 163{
9bd92830
FM
164 FILE *fp_in = NULL, *fp_ou = NULL;
165
166 char *buf;
167 char *url;
168 char report_in[MAXLEN];
169 char report[MAXLEN];
170 char ip[MAXLEN];
171 char oip[MAXLEN];
172 char user[MAXLEN];
173 char ouser[MAXLEN];
174 char ouser2[MAXLEN];
175 char data[15];
176 char hora[15];
177 int z=0;
178 int count=0;
179 int i;
180 int day,month,year;
181 bool new_user;
182 struct getwordstruct gwarea;
183 longline line;
184 struct userinfostruct *uinfo;
185 struct tm t;
186
11284535
FM
187 if (!download_exists) {
188 if (!KeepTempLog && download_unsort[0]!='\0' && unlink(download_unsort))
af961877 189 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),download_unsort,strerror(errno));
11284535 190 download_unsort[0]='\0';
af961877 191 if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("No downloaded files to report\n"));
5589b847
FM
192 return;
193 }
194
b7413c4c 195 if (debugz>=LogLevel_Process)
af961877 196 debuga(__FILE__,__LINE__,_("Creating download report...\n"));
9bd92830
FM
197 ouser[0]='\0';
198 ouser2[0]='\0';
199
b2fa3eb6 200 // sort the raw file
c98d6a0f 201 snprintf(report_in,sizeof(report_in),"%s/download.int_log",tmp);
b2fa3eb6 202 download_sort(report_in);
9bd92830 203
b2fa3eb6 204 // produce the report.
9bd92830
FM
205 snprintf(report,sizeof(report),"%s/download.html",outdirname);
206
207 if((fp_in=MY_FOPEN(report_in,"r"))==NULL) {
af961877 208 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report_in,strerror(errno));
9bd92830
FM
209 exit(EXIT_FAILURE);
210 }
211
212 if((fp_ou=MY_FOPEN(report,"w"))==NULL) {
af961877 213 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report,strerror(errno));
9bd92830
FM
214 exit(EXIT_FAILURE);
215 }
216
217 write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Downloads"),HTML_JS_NONE);
218 fputs("<tr><td class=\"header_c\">",fp_ou);
219 fprintf(fp_ou,_("Period: %s"),period.html);
220 fputs("</td></tr>\n",fp_ou);
221 fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Downloads"));
222 close_html_header(fp_ou);
223
224 fputs("<div class=\"report\"><table cellpadding=\"0\" cellspacing=\"2\">\n",fp_ou);
225 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></tr>\n",_("USERID"),_("IP/NAME"),_("DATE/TIME"),_("ACCESSED SITE"));
226
227 if ((line=longline_create())==NULL) {
af961877 228 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),report_in);
9bd92830
FM
229 exit(EXIT_FAILURE);
230 }
231
232 while((buf=longline_read(fp_in,line))!=NULL) {
233 getword_start(&gwarea,buf);
234 if (getword(data,sizeof(data),&gwarea,'\t')<0 || getword(hora,sizeof(hora),&gwarea,'\t')<0 ||
007905af 235 getword(user,sizeof(user),&gwarea,'\t')<0 || getword(ip,sizeof(ip),&gwarea,'\t')<0) {
af961877 236 debuga(__FILE__,__LINE__,_("Invalid record in file \"%s\"\n"),report_in);
9bd92830
FM
237 exit(EXIT_FAILURE);
238 }
239 if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
af961877 240 debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),report_in);
9bd92830
FM
241 exit(EXIT_FAILURE);
242 }
243 if (sscanf(data,"%d/%d/%d",&day,&month,&year)!=3) continue;
244 computedate(year,month,day,&t);
245 strftime(data,sizeof(data),"%x",&t);
246
247 uinfo=userinfo_find_from_id(user);
248 if (!uinfo) {
af961877 249 debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,report_in);
9bd92830
FM
250 exit(EXIT_FAILURE);
251 }
252 new_user=false;
253 if(!z) {
254 strcpy(ouser,user);
255 strcpy(oip,ip);
256 z++;
257 new_user=true;
258 } else {
259 if(strcmp(ouser,user) != 0) {
260 strcpy(ouser,user);
261 new_user=true;
262 }
263 if(strcmp(oip,ip) != 0) {
264 strcpy(oip,ip);
265 new_user=true;
266 }
267 }
268
269 if(DownloadReportLimit) {
270 if(strcmp(ouser2,uinfo->label) == 0) {
271 count++;
272 } else {
273 count=1;
274 strcpy(ouser2,uinfo->label);
275 }
276 if(count >= DownloadReportLimit)
277 continue;
278 }
279
280 for (i=strlen(url)-1 ; i>=0 && (unsigned char)url[i]<' ' ; i--) url[i]=0;
281
282 fputs("<tr>",fp_ou);
5138c1b9
FM
283 if (new_user) {
284 if (uinfo->topuser)
285 fprintf(fp_ou,"<td class=\"data\"><a href=\"%s/%s.html\">%s</a></td><td class=\"data\">%s</td>",uinfo->filename,uinfo->filename,uinfo->label,ip);
286 else
287 fprintf(fp_ou,"<td class=\"data\">%s</td><td class=\"data\">%s</td>",uinfo->label,ip);
288 } else
9bd92830
FM
289 fputs("<td class=\"data\"></td><td class=\"data\"></td>",fp_ou);
290 fprintf(fp_ou,"<td class=\"data\">%s-%s</td><td class=\"data2\">",data,hora);
67a93701 291 if(BlockIt[0]!='\0' && url[0]!=ALIAS_PREFIX) {
9bd92830
FM
292 fprintf(fp_ou,"<a href=\"%s%s?url=\"",wwwDocumentRoot,BlockIt);
293 output_html_url(fp_ou,url);
294 fprintf(fp_ou,"\"><img src=\"%s/sarg-squidguard-block.png\"></a>&nbsp;",ImageFile);
295 }
6fa33a32 296 output_html_link(fp_ou,url,100);
67a93701 297 fputs("</td></tr>\n",fp_ou);
9bd92830 298 }
204781f4 299 if (fclose(fp_in)==EOF) {
af961877 300 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),report_in,strerror(errno));
204781f4
FM
301 exit(EXIT_FAILURE);
302 }
9bd92830
FM
303 longline_destroy(&line);
304
305 fputs("</table></div>\n",fp_ou);
342bd723 306 write_html_trailer(fp_ou);
507460ae 307 if (fclose(fp_ou)==EOF) {
af961877 308 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),report,strerror(errno));
507460ae
FM
309 exit(EXIT_FAILURE);
310 }
9bd92830 311
11767c6a 312 if (!KeepTempLog && unlink(report_in)) {
af961877 313 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),report_in,strerror(errno));
08f9b029
FM
314 exit(EXIT_FAILURE);
315 }
9bd92830
FM
316
317 return;
25697a35 318}
6e792ade 319
b2fa3eb6
FM
320/*!
321Free the memory allocated by set_download_suffix().
322*/
6e792ade
FM
323void free_download(void)
324{
9bd92830
FM
325 if (DownloadSuffix) {
326 free(DownloadSuffix);
327 DownloadSuffix=NULL;
328 }
329 if (DownloadSuffixIndex) {
330 free(DownloadSuffixIndex);
331 DownloadSuffixIndex=NULL;
332 }
333 NDownloadSuffix=0;
6e792ade
FM
334}
335
b2fa3eb6
FM
336/*!
337Set the list of the suffixes corresponding to the download of files you want to detect with
338is_download_suffix(). The list is sorted to make the search faster.
339
340\param list A comma separated list of the suffixes to set in ::DownloadSuffix.
341
342\note The memory allocated by this function must be freed by free_download().
343*/
6e792ade
FM
344void set_download_suffix(const char *list)
345{
9bd92830
FM
346 char *str;
347 int i, j, k;
348 int cmp;
349
350 free_download();
351
352 DownloadSuffix=strdup(list);
353 if (!DownloadSuffix) {
af961877 354 debuga(__FILE__,__LINE__,_("Download suffix list too long\n"));
9bd92830
FM
355 exit(EXIT_FAILURE);
356 }
357 j = 1;
358 for (i=0 ; list[i] ; i++)
359 if (list[i] == ',') j++;
360 DownloadSuffixIndex=malloc(j*sizeof(char *));
361 if (!DownloadSuffixIndex) {
af961877 362 debuga(__FILE__,__LINE__,_("Too many download suffixes\n"));
9bd92830
FM
363 exit(EXIT_FAILURE);
364 }
365
366 str = DownloadSuffix;
367 for (i=0 ; DownloadSuffix[i] ; i++) {
368 if (DownloadSuffix[i] == ',') {
369 DownloadSuffix[i] = '\0';
370 if (*str) {
371 cmp = -1;
372 for (j=0 ; j<NDownloadSuffix && (cmp=strcasecmp(str,DownloadSuffixIndex[j]))>0 ; j++);
373 if (cmp != 0) {
374 for (k=NDownloadSuffix ; k>j ; k--)
375 DownloadSuffixIndex[k]=DownloadSuffixIndex[k-1];
376 NDownloadSuffix++;
377 DownloadSuffixIndex[j]=str;
378 }
379 }
380 str=DownloadSuffix+i+1;
381 }
382 }
383
384 if (*str) {
385 cmp = -1;
386 for (j=0 ; j<NDownloadSuffix && (cmp=strcasecmp(str,DownloadSuffixIndex[j]))>0 ; j++);
387 if (cmp != 0) {
388 for (k=NDownloadSuffix ; k>j ; k--)
389 DownloadSuffixIndex[k]=DownloadSuffixIndex[k-1];
390 NDownloadSuffix++;
391 DownloadSuffixIndex[j]=str;
392 }
393 }
6e792ade
FM
394}
395
b2fa3eb6
FM
396/*!
397Tell if the URL correspond to a downloaded file. The function takes the extension at the end of the
398URL with a maximum of 9 characters and compare it to the list of the download suffix in
399::DownloadSuffix. If the suffix is found in the list, the function reports the URL as the download
400of a file.
401
402\param url The URL to test.
403
404\retval 1 The URL matches a suffix of a download.
405\retval 0 The URL is not a known download.
406
407\note A downloaded file cannot be detected if the file name is embedded in a GET or POST request. Only requests
408that ends with the file name can be detected.
409
410\note A URL embedding another web site's address ending by .com at the end of the URL will match the download
411extension com if it is defined in the ::DownloadSuffix.
412*/
2824ec9b 413bool is_download_suffix(const char *url)
6e792ade 414{
9bd92830
FM
415 int urllen;
416 int i;
417 int down, up, center;
418 const char *suffix;
419 int cmp;
420 const int max_suffix=10;
421
422 if (DownloadSuffix == NULL || NDownloadSuffix == 0) return(false);
423
424 urllen=strlen(url)-1;
425 if (urllen<=0) return(false);
426 if (url[urllen] == '.') return(false); //reject a single trailing dot
427 for (i=0 ; i<urllen && (url[i]!='/' || url[i+1]=='/') && url[i]!='?' ; i++);
428 if (i>=urllen) return(false); // url is a hostname without any path or file to download
429
430 for (i=0 ; i<=max_suffix && i<urllen && url[urllen-i]!='.' ; i++)
431 if (url[urllen-i] == '/' || url[urllen-i] == '?') return(false);
432 if (i>max_suffix || i>=urllen) return(false);
433
434 suffix=url+urllen-i+1;
435 down=0;
436 up=NDownloadSuffix-1;
437 while (down<=up) {
438 center=(down+up)/2;
439 cmp=strcasecmp(suffix,DownloadSuffixIndex[center]);
440 if (cmp == 0) return(true);
441 if (cmp < 0)
442 up = center-1;
443 else
444 down = center+1;
445 }
446 return(false);
6e792ade
FM
447}
448
11284535
FM
449/*!
450Remove any temporary file left by the download module.
451*/
452void download_cleanup(void)
453{
507460ae
FM
454 if (fp_download) {
455 if (fclose(fp_download)==EOF) {
af961877 456 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),download_unsort,strerror(errno));
507460ae
FM
457 exit(EXIT_FAILURE);
458 }
11284535
FM
459 fp_download=NULL;
460 }
461 if (download_unsort[0]) {
462 if (unlink(download_unsort)==-1)
af961877 463 debuga(__FILE__,__LINE__,_("Failed to delete \"%s\": %s\n"),download_unsort,strerror(errno));
11284535
FM
464 }
465}