]> git.ipfire.org Git - thirdparty/sarg.git/blame - download.c
Indent the configure script for more readability.
[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{
800eafb8
FM
164 FileObject *fp_in = NULL;
165 FILE *fp_ou = NULL;
9bd92830
FM
166
167 char *buf;
168 char *url;
169 char report_in[MAXLEN];
170 char report[MAXLEN];
171 char ip[MAXLEN];
172 char oip[MAXLEN];
173 char user[MAXLEN];
174 char ouser[MAXLEN];
175 char ouser2[MAXLEN];
176 char data[15];
177 char hora[15];
178 int z=0;
179 int count=0;
180 int i;
181 int day,month,year;
182 bool new_user;
183 struct getwordstruct gwarea;
184 longline line;
185 struct userinfostruct *uinfo;
186 struct tm t;
187
11284535
FM
188 if (!download_exists) {
189 if (!KeepTempLog && download_unsort[0]!='\0' && unlink(download_unsort))
af961877 190 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),download_unsort,strerror(errno));
11284535 191 download_unsort[0]='\0';
af961877 192 if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("No downloaded files to report\n"));
5589b847
FM
193 return;
194 }
195
b7413c4c 196 if (debugz>=LogLevel_Process)
af961877 197 debuga(__FILE__,__LINE__,_("Creating download report...\n"));
9bd92830
FM
198 ouser[0]='\0';
199 ouser2[0]='\0';
200
b2fa3eb6 201 // sort the raw file
c98d6a0f 202 snprintf(report_in,sizeof(report_in),"%s/download.int_log",tmp);
b2fa3eb6 203 download_sort(report_in);
9bd92830 204
b2fa3eb6 205 // produce the report.
9bd92830
FM
206 snprintf(report,sizeof(report),"%s/download.html",outdirname);
207
800eafb8
FM
208 if((fp_in=FileObject_Open(report_in))==NULL) {
209 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report_in,FileObject_GetLastOpenError());
9bd92830
FM
210 exit(EXIT_FAILURE);
211 }
212
213 if((fp_ou=MY_FOPEN(report,"w"))==NULL) {
af961877 214 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report,strerror(errno));
9bd92830
FM
215 exit(EXIT_FAILURE);
216 }
217
218 write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Downloads"),HTML_JS_NONE);
219 fputs("<tr><td class=\"header_c\">",fp_ou);
220 fprintf(fp_ou,_("Period: %s"),period.html);
221 fputs("</td></tr>\n",fp_ou);
222 fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Downloads"));
223 close_html_header(fp_ou);
224
225 fputs("<div class=\"report\"><table cellpadding=\"0\" cellspacing=\"2\">\n",fp_ou);
226 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"));
227
228 if ((line=longline_create())==NULL) {
af961877 229 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),report_in);
9bd92830
FM
230 exit(EXIT_FAILURE);
231 }
232
233 while((buf=longline_read(fp_in,line))!=NULL) {
234 getword_start(&gwarea,buf);
235 if (getword(data,sizeof(data),&gwarea,'\t')<0 || getword(hora,sizeof(hora),&gwarea,'\t')<0 ||
007905af 236 getword(user,sizeof(user),&gwarea,'\t')<0 || getword(ip,sizeof(ip),&gwarea,'\t')<0) {
af961877 237 debuga(__FILE__,__LINE__,_("Invalid record in file \"%s\"\n"),report_in);
9bd92830
FM
238 exit(EXIT_FAILURE);
239 }
240 if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
af961877 241 debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),report_in);
9bd92830
FM
242 exit(EXIT_FAILURE);
243 }
244 if (sscanf(data,"%d/%d/%d",&day,&month,&year)!=3) continue;
245 computedate(year,month,day,&t);
246 strftime(data,sizeof(data),"%x",&t);
247
248 uinfo=userinfo_find_from_id(user);
249 if (!uinfo) {
af961877 250 debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,report_in);
9bd92830
FM
251 exit(EXIT_FAILURE);
252 }
253 new_user=false;
254 if(!z) {
255 strcpy(ouser,user);
256 strcpy(oip,ip);
257 z++;
258 new_user=true;
259 } else {
260 if(strcmp(ouser,user) != 0) {
261 strcpy(ouser,user);
262 new_user=true;
263 }
264 if(strcmp(oip,ip) != 0) {
265 strcpy(oip,ip);
266 new_user=true;
267 }
268 }
269
270 if(DownloadReportLimit) {
271 if(strcmp(ouser2,uinfo->label) == 0) {
272 count++;
273 } else {
274 count=1;
275 strcpy(ouser2,uinfo->label);
276 }
277 if(count >= DownloadReportLimit)
278 continue;
279 }
280
281 for (i=strlen(url)-1 ; i>=0 && (unsigned char)url[i]<' ' ; i--) url[i]=0;
282
283 fputs("<tr>",fp_ou);
5138c1b9
FM
284 if (new_user) {
285 if (uinfo->topuser)
286 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);
287 else
288 fprintf(fp_ou,"<td class=\"data\">%s</td><td class=\"data\">%s</td>",uinfo->label,ip);
289 } else
9bd92830
FM
290 fputs("<td class=\"data\"></td><td class=\"data\"></td>",fp_ou);
291 fprintf(fp_ou,"<td class=\"data\">%s-%s</td><td class=\"data2\">",data,hora);
67a93701 292 if(BlockIt[0]!='\0' && url[0]!=ALIAS_PREFIX) {
9bd92830
FM
293 fprintf(fp_ou,"<a href=\"%s%s?url=\"",wwwDocumentRoot,BlockIt);
294 output_html_url(fp_ou,url);
295 fprintf(fp_ou,"\"><img src=\"%s/sarg-squidguard-block.png\"></a>&nbsp;",ImageFile);
296 }
6fa33a32 297 output_html_link(fp_ou,url,100);
67a93701 298 fputs("</td></tr>\n",fp_ou);
9bd92830 299 }
800eafb8
FM
300 if (FileObject_Close(fp_in)) {
301 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),report_in,FileObject_GetLastCloseError());
204781f4
FM
302 exit(EXIT_FAILURE);
303 }
9bd92830
FM
304 longline_destroy(&line);
305
306 fputs("</table></div>\n",fp_ou);
342bd723 307 write_html_trailer(fp_ou);
507460ae 308 if (fclose(fp_ou)==EOF) {
af961877 309 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),report,strerror(errno));
507460ae
FM
310 exit(EXIT_FAILURE);
311 }
9bd92830 312
11767c6a 313 if (!KeepTempLog && unlink(report_in)) {
af961877 314 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),report_in,strerror(errno));
08f9b029
FM
315 exit(EXIT_FAILURE);
316 }
9bd92830
FM
317
318 return;
25697a35 319}
6e792ade 320
b2fa3eb6
FM
321/*!
322Free the memory allocated by set_download_suffix().
323*/
6e792ade
FM
324void free_download(void)
325{
9bd92830
FM
326 if (DownloadSuffix) {
327 free(DownloadSuffix);
328 DownloadSuffix=NULL;
329 }
330 if (DownloadSuffixIndex) {
331 free(DownloadSuffixIndex);
332 DownloadSuffixIndex=NULL;
333 }
334 NDownloadSuffix=0;
6e792ade
FM
335}
336
b2fa3eb6
FM
337/*!
338Set the list of the suffixes corresponding to the download of files you want to detect with
339is_download_suffix(). The list is sorted to make the search faster.
340
341\param list A comma separated list of the suffixes to set in ::DownloadSuffix.
342
343\note The memory allocated by this function must be freed by free_download().
344*/
6e792ade
FM
345void set_download_suffix(const char *list)
346{
9bd92830
FM
347 char *str;
348 int i, j, k;
349 int cmp;
350
351 free_download();
352
353 DownloadSuffix=strdup(list);
354 if (!DownloadSuffix) {
af961877 355 debuga(__FILE__,__LINE__,_("Download suffix list too long\n"));
9bd92830
FM
356 exit(EXIT_FAILURE);
357 }
358 j = 1;
359 for (i=0 ; list[i] ; i++)
360 if (list[i] == ',') j++;
361 DownloadSuffixIndex=malloc(j*sizeof(char *));
362 if (!DownloadSuffixIndex) {
af961877 363 debuga(__FILE__,__LINE__,_("Too many download suffixes\n"));
9bd92830
FM
364 exit(EXIT_FAILURE);
365 }
366
367 str = DownloadSuffix;
368 for (i=0 ; DownloadSuffix[i] ; i++) {
369 if (DownloadSuffix[i] == ',') {
370 DownloadSuffix[i] = '\0';
371 if (*str) {
372 cmp = -1;
373 for (j=0 ; j<NDownloadSuffix && (cmp=strcasecmp(str,DownloadSuffixIndex[j]))>0 ; j++);
374 if (cmp != 0) {
375 for (k=NDownloadSuffix ; k>j ; k--)
376 DownloadSuffixIndex[k]=DownloadSuffixIndex[k-1];
377 NDownloadSuffix++;
378 DownloadSuffixIndex[j]=str;
379 }
380 }
381 str=DownloadSuffix+i+1;
382 }
383 }
384
385 if (*str) {
386 cmp = -1;
387 for (j=0 ; j<NDownloadSuffix && (cmp=strcasecmp(str,DownloadSuffixIndex[j]))>0 ; j++);
388 if (cmp != 0) {
389 for (k=NDownloadSuffix ; k>j ; k--)
390 DownloadSuffixIndex[k]=DownloadSuffixIndex[k-1];
391 NDownloadSuffix++;
392 DownloadSuffixIndex[j]=str;
393 }
394 }
6e792ade
FM
395}
396
b2fa3eb6
FM
397/*!
398Tell if the URL correspond to a downloaded file. The function takes the extension at the end of the
399URL with a maximum of 9 characters and compare it to the list of the download suffix in
400::DownloadSuffix. If the suffix is found in the list, the function reports the URL as the download
401of a file.
402
403\param url The URL to test.
404
405\retval 1 The URL matches a suffix of a download.
406\retval 0 The URL is not a known download.
407
408\note A downloaded file cannot be detected if the file name is embedded in a GET or POST request. Only requests
409that ends with the file name can be detected.
410
411\note A URL embedding another web site's address ending by .com at the end of the URL will match the download
412extension com if it is defined in the ::DownloadSuffix.
413*/
2824ec9b 414bool is_download_suffix(const char *url)
6e792ade 415{
9bd92830
FM
416 int urllen;
417 int i;
418 int down, up, center;
419 const char *suffix;
420 int cmp;
421 const int max_suffix=10;
422
423 if (DownloadSuffix == NULL || NDownloadSuffix == 0) return(false);
424
425 urllen=strlen(url)-1;
426 if (urllen<=0) return(false);
427 if (url[urllen] == '.') return(false); //reject a single trailing dot
428 for (i=0 ; i<urllen && (url[i]!='/' || url[i+1]=='/') && url[i]!='?' ; i++);
429 if (i>=urllen) return(false); // url is a hostname without any path or file to download
430
431 for (i=0 ; i<=max_suffix && i<urllen && url[urllen-i]!='.' ; i++)
432 if (url[urllen-i] == '/' || url[urllen-i] == '?') return(false);
433 if (i>max_suffix || i>=urllen) return(false);
434
435 suffix=url+urllen-i+1;
436 down=0;
437 up=NDownloadSuffix-1;
438 while (down<=up) {
439 center=(down+up)/2;
440 cmp=strcasecmp(suffix,DownloadSuffixIndex[center]);
441 if (cmp == 0) return(true);
442 if (cmp < 0)
443 up = center-1;
444 else
445 down = center+1;
446 }
447 return(false);
6e792ade
FM
448}
449
11284535
FM
450/*!
451Remove any temporary file left by the download module.
452*/
453void download_cleanup(void)
454{
507460ae
FM
455 if (fp_download) {
456 if (fclose(fp_download)==EOF) {
af961877 457 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),download_unsort,strerror(errno));
507460ae
FM
458 exit(EXIT_FAILURE);
459 }
11284535
FM
460 fp_download=NULL;
461 }
462 if (download_unsort[0]) {
463 if (unlink(download_unsort)==-1)
af961877 464 debuga(__FILE__,__LINE__,_("Failed to delete \"%s\": %s\n"),download_unsort,strerror(errno));
11284535
FM
465 }
466}