]> git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
Fix several possible sprintf buffer overflows
[thirdparty/sarg.git] / util.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 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
29
30 #include "include/conf.h"
31 #include "include/defs.h"
32
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
35 #else
36 #define USE_GETWORD_BACKTRACE 0
37 #endif
38
39 static char mtab1[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
40
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode=NULL;
43
44 #if USE_GETWORD_BACKTRACE
45 static void getword_backtrace(void)
46 {
47 void *buffer[5];
48 int i, n;
49 char **calls;
50
51 n=backtrace(buffer,sizeof(buffer)/sizeof(buffer[0]));
52 if (n<=0) return;
53 calls=backtrace_symbols(buffer,n);
54 if (calls) {
55 debuga(_("getword backtrace:\n"));
56 for (i=0 ; i<n ; i++) {
57 fprintf(stderr,"SARG: %d:%s\n",i+1,calls[i]);
58 }
59 free(calls);
60 }
61 }
62 #endif //USE_GETWORD_BACKTRACE
63
64 void getword_start(struct getwordstruct *gwarea, const char *line)
65 {
66 gwarea->beginning=line;
67 gwarea->current=line;
68 gwarea->modified=0;
69 }
70
71 void getword_restart(struct getwordstruct *gwarea)
72 {
73 if (gwarea->modified) {
74 debuga(_("Cannot parse again the line as it was modified\n"));
75 exit(EXIT_FAILURE);
76 }
77 gwarea->current=gwarea->beginning;
78 }
79
80 int getword(char *word, int limit, struct getwordstruct *gwarea, char stop)
81 {
82 int x;
83
84 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
85 if(x>=limit) {
86 debuga(_("End of word not found in getword after %d bytes.\n"),x);
87 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
88 debuga(_("Record=\"%s\"\n"),gwarea->current);
89 debuga(_("searching for \'x%x\'\n"),stop);
90 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
91 word[(limit>0) ? limit-1 : 0]='\0';
92 #if USE_GETWORD_BACKTRACE
93 getword_backtrace();
94 #endif
95 return(-1);
96 }
97 word[x] = gwarea->current[x];
98 }
99
100 word[x] = '\0';
101 if (gwarea->current[x]) ++x;
102 gwarea->current+=x;
103 return(0);
104 }
105
106 int getword_limit(char *word, int limit, struct getwordstruct *gwarea, char stop)
107 {
108 int x;
109
110 limit--;
111 for(x=0; x<limit && gwarea->current[x] && gwarea->current[x] != stop ;x++) {
112 word[x] = gwarea->current[x];
113 }
114 word[x] = '\0';
115 gwarea->current+=x;
116 while (*gwarea->current && *gwarea->current != stop) gwarea->current++;
117 if (*gwarea->current) ++gwarea->current;
118 return(0);
119 }
120
121 int getword_multisep(char *word, int limit, struct getwordstruct *gwarea, char stop)
122 {
123 int x;
124
125 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
126 if(x>=limit) {
127 debuga(_("End of word not found in getword_multisep after %d bytes.\n"),x);
128 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
129 debuga(_("Record=\"%s\"\n"),gwarea->current);
130 debuga(_("searching for \'x%x\'\n"),stop);
131 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
132 if (limit>0) word[limit-1]='\0';
133 #if USE_GETWORD_BACKTRACE
134 getword_backtrace();
135 #endif
136 //exit(EXIT_FAILURE);
137 return(-1);
138 }
139 word[x] = gwarea->current[x];
140 }
141
142 word[x] = '\0';
143 while (gwarea->current[x] && gwarea->current[x]==stop) ++x;
144 gwarea->current+=x;
145 return(0);
146 }
147
148 int getword_skip(int limit, struct getwordstruct *gwarea, char stop)
149 {
150 int x;
151
152 for(x=0;(gwarea->current[x] && (gwarea->current[x] != stop ));x++) {
153 if(x>=limit) {
154 debuga(_("End of word not found in getword_skip after %d bytes.\n"),x);
155 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
156 debuga(_("Record=\"%s\"\n"),gwarea->current);
157 debuga(_("searching for \'x%x\'\n"),stop);
158 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
159 #if USE_GETWORD_BACKTRACE
160 getword_backtrace();
161 #endif
162 return(-1);
163 }
164 }
165
166 if (gwarea->current[x]) ++x;
167 gwarea->current+=x;
168 return(0);
169 }
170
171 int getword_atoll(long long int *number, struct getwordstruct *gwarea, char stop)
172 {
173 int x;
174 int sign=+1;
175 int digit;
176
177 if (gwarea->current[0] == '-') {
178 gwarea->current++;
179 sign=-1;
180 } else if (gwarea->current[0] == '+') {
181 gwarea->current++;
182 }
183 *number=0LL;
184 for(x=0;isdigit(gwarea->current[x]);x++) {
185 digit=gwarea->current[x]-'0';
186 if (*number >= (LLONG_MAX-digit)/10) {
187 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea->beginning);
188 return(-1);
189 }
190 *number=(*number * 10) + digit;
191 }
192 if(gwarea->current[x] && gwarea->current[x]!=stop) {
193 debuga(_("End of number not found in getword_atoll after %d bytes.\n"),x);
194 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
195 debuga(_("Record=\"%s\"\n"),gwarea->current);
196 debuga(_("searching for \'x%x\'\n"),stop);
197 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
198 #if USE_GETWORD_BACKTRACE
199 getword_backtrace();
200 #endif
201 return(-1);
202 }
203 *number*=sign;
204
205 if (gwarea->current[x]) ++x;
206 gwarea->current+=x;
207 return(0);
208 }
209
210 int getword_atoi(int *number, struct getwordstruct *gwarea, char stop)
211 {
212 int x;
213 int sign=+1;
214 int digit;
215
216 if (gwarea->current[0] == '-') {
217 gwarea->current++;
218 sign=-1;
219 } else if (gwarea->current[0] == '+') {
220 gwarea->current++;
221 }
222 *number=0;
223 for(x=0;isdigit(gwarea->current[x]);x++) {
224 digit=gwarea->current[x]-'0';
225 if (*number > (INT_MAX-digit)/10) {
226 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea->beginning);
227 return(-1);
228 }
229 *number=(*number * 10) + digit;
230 }
231 if(gwarea->current[x] && gwarea->current[x]!=stop) {
232 debuga(_("End of number not found in getword_atoi after %d bytes.\n"),x);
233 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
234 debuga(_("Record=\"%s\"\n"),gwarea->current);
235 debuga(_("searching for \'x%x\'\n"),stop);
236 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
237 #if USE_GETWORD_BACKTRACE
238 getword_backtrace();
239 #endif
240 return(-1);
241 }
242 *number*=sign;
243
244 if (gwarea->current[x]) ++x;
245 gwarea->current+=x;
246 return(0);
247 }
248
249 int getword_atol(long int *number, struct getwordstruct *gwarea, char stop)
250 {
251 long int x;
252 long int sign=+1;
253 int digit;
254
255 if (gwarea->current[0] == '-') {
256 gwarea->current++;
257 sign=-1;
258 } else if (gwarea->current[0] == '+') {
259 gwarea->current++;
260 }
261 *number=0;
262 for(x=0;isdigit(gwarea->current[x]);x++) {
263 digit=gwarea->current[x]-'0';
264 if (*number > (LONG_MAX-digit)/10) {
265 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea->beginning);
266 return(-1);
267 }
268 *number=(*number * 10) + digit;
269 }
270 if(gwarea->current[x] && gwarea->current[x]!=stop) {
271 debuga(_("End of number not found in getword_atol after %ld bytes.\n"),x);
272 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
273 debuga(_("Record=\"%s\"\n"),gwarea->current);
274 debuga(_("searching for \'x%x\'\n"),stop);
275 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
276 #if USE_GETWORD_BACKTRACE
277 getword_backtrace();
278 #endif
279 return(-1);
280 }
281 *number*=sign;
282
283 if (gwarea->current[x]) ++x;
284 gwarea->current+=x;
285 return(0);
286 }
287
288 int getword_atolu(unsigned long int *number, struct getwordstruct *gwarea, char stop)
289 {
290 unsigned long int x;
291 int digit;
292
293 if (gwarea->current[0] == '-') {
294 debuga(_("getword_atolu got a negative number.\n"));
295 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
296 debuga(_("Record=\"%s\"\n"),gwarea->current);
297 return(-1);
298 }
299 if (gwarea->current[0] == '+') {
300 gwarea->current++;
301 }
302 *number=0;
303 for(x=0;isdigit(gwarea->current[x]);x++) {
304 digit=gwarea->current[x]-'0';
305 if (*number > (ULONG_MAX-digit)/10) {
306 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea->beginning);
307 return(-1);
308 }
309 *number=(*number * 10) + digit;
310 }
311 if(gwarea->current[x] && gwarea->current[x]!=stop) {
312 debuga(_("End of number not found in getword_atolu after %ld bytes.\n"),x);
313 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
314 debuga(_("Record=\"%s\"\n"),gwarea->current);
315 debuga(_("searching for \'x%x\'\n"),stop);
316 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
317 #if USE_GETWORD_BACKTRACE
318 getword_backtrace();
319 #endif
320 return(-1);
321 }
322
323 if (gwarea->current[x]) ++x;
324 gwarea->current+=x;
325 return(0);
326 }
327
328
329 int getword_ptr(char *orig_line,char **word, struct getwordstruct *gwarea, char stop)
330 {
331 /*!
332 \note Why pass the original buffer to the function ? Because we must modify it to
333 insert the terminating ASCII zero for the word we return and that's not compatible
334 with getword_restart(). Moreover, getword_start() sometime works on constant strings
335 so this function require the original buffer to detect any missuse.
336 */
337 int x;
338 int sep;
339 int start;
340
341 if (orig_line && orig_line!=gwarea->beginning) {
342 debuga(_("Invalid buffer passed to getword_ptr\n"));
343 return(-1);
344 }
345
346 start=(gwarea->current-gwarea->beginning);
347 if (word && orig_line) *word=orig_line+start;
348 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++);
349 sep=(gwarea->current[x]!='\0');
350 if (word && orig_line) orig_line[start+x] = '\0';
351 if (sep) ++x;
352 gwarea->current+=x;
353 gwarea->modified=1;
354 return(0);
355 }
356
357 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
358 long long int my_atoll (const char *nptr)
359 {
360 long long int returnval=0LL;
361 int max_digits = MAXLLL ;
362
363 // Soak up all the white space
364 while (isspace( *nptr )) {
365 nptr++;
366 }
367
368 //For each character left to right
369 //change the character to a single digit
370 //multiply what we had before by 10 and add the new digit
371
372 while (--max_digits && isdigit( *nptr ))
373 {
374 returnval = ( returnval * 10 ) + ( *nptr++ - '0' ) ;
375 }
376
377 return returnval;
378 }
379
380 int is_absolute(const char *path)
381 {
382 if (*path=='/') return(1);
383 #ifdef _WIN32
384 if (isalpha(path[0]) && path[1]==':') return(1);
385 #endif
386 return(0);
387 }
388
389 void my_mkdir(const char *name)
390 {
391 char w0[MAXLEN];
392 int i;
393 int chars;
394
395 if(!is_absolute(name)) {
396 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name);
397 exit(EXIT_FAILURE);
398 }
399
400 chars=0;
401 for (i=0 ; name[i] ; i++) {
402 if (i>=sizeof(w0)) {
403 debuga(_("directory name too long: %s\n"),name);
404 exit(EXIT_FAILURE);
405 }
406 if (chars>0 && name[i] == '/') {
407 w0[i] = '\0';
408 if (access(w0, R_OK) != 0) {
409 if (mkdir(w0,0755)) {
410 debuga(_("Cannot create directory %s - %s\n"),w0,strerror(errno));
411 exit(EXIT_FAILURE);
412 }
413 }
414 }
415 if (name[i] != '/') chars++;
416 w0[i] = name[i];
417 }
418
419 if (access(name, R_OK) != 0) {
420 if (mkdir(name,0755)) {
421 debuga(_("Cannot create directory %s - %s\n"),name,strerror(errno));
422 exit(EXIT_FAILURE);
423 }
424 }
425 }
426
427
428 void my_lltoa(unsigned long long int n, char *s, int ssize, int len)
429 {
430 int i;
431 int slen = 0;
432 int j;
433 char c;
434
435 ssize--;
436 if (len>ssize) {
437 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
438 abort();
439 }
440
441 do {
442 s[slen++] = (n % 10) + '0';
443 } while ((n /= 10) > 0 && slen<ssize);
444 s[slen] = '\0';
445
446 for (i = 0, j = slen-1; i<j; i++, j--) {
447 c = s[i];
448 s[i] = s[j];
449 s[j] = c;
450 }
451
452 if(len>slen) {
453 i=len-slen;
454 for(j=slen; j>=0; j--)
455 s[j+i]=s[j];
456 for(j=0 ; j<i ; j++)
457 s[j]='0';
458 }
459 }
460
461 int month2num(const char *month)
462 {
463 int m;
464
465 for(m=0 ; m<12 && strcmp(mtab1[m],month) != 0; m++);
466 return(m);
467 }
468
469 int builddia(int day, int month, int year)
470 {
471 return(year*10000+month*100+day);
472 }
473
474 /*!
475 Compare two dates.
476
477 \param date1 The first date to compare.
478 \param date2 The second date to compare.
479
480 \retval -1 If date1<date2.
481 \retval 0 If date1==date2.
482 \retval 1 if date1>date2.
483 */
484 int compare_date(struct tm *date1,struct tm *date2)
485 {
486 if (date1->tm_year<date2->tm_year) return(-1);
487 if (date1->tm_year>date2->tm_year) return(1);
488 if (date1->tm_mon<date2->tm_mon) return(-1);
489 if (date1->tm_mon>date2->tm_mon) return(1);
490 if (date1->tm_mday<date2->tm_mday) return(-1);
491 if (date1->tm_mday>date2->tm_mday) return(1);
492 if (date1->tm_hour<date2->tm_hour) return(-1);
493 if (date1->tm_hour>date2->tm_hour) return(1);
494 if (date1->tm_min<date2->tm_min) return(-1);
495 if (date1->tm_min>date2->tm_min) return(1);
496 if (date1->tm_sec<date2->tm_sec) return(-1);
497 if (date1->tm_sec>date2->tm_sec) return(1);
498 return(0);
499 }
500
501 void buildymd(const char *dia, const char *mes, const char *ano, char *wdata,int wdata_size)
502 {
503 int nmes;
504
505 nmes=month2num(mes);
506 snprintf(wdata,wdata_size,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
507 }
508
509
510 int conv_month(const char *month)
511 {
512 int x;
513
514 for(x=0; x<12 && strncmp(mtab1[x],month,3)!=0; x++);
515 return(x+1);
516 }
517
518
519 const char *conv_month_name(int month)
520 {
521 static char str[4];
522
523 if (month<1 || month>12) {
524 snprintf(str,sizeof(str),"%03d",month);
525 return(str);
526 }
527 return(mtab1[month-1]);
528 }
529
530
531 void name_month(char *month,int month_len)
532 {
533 int x, z=atoi(month)-1;
534 char m[255];
535 char w[20];
536 struct getwordstruct gwarea;
537
538 strcpy(m,_("January,February,March,April,May,June,July,August,September,October,November,December"));
539 getword_start(&gwarea,m);
540
541 for(x=0; x<z; x++)
542 if (getword_multisep(w,sizeof(w),&gwarea,',')<0) {
543 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
544 exit(EXIT_FAILURE);
545 }
546 if (getword_multisep(month,month_len,&gwarea,',')<0) {
547 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
548 exit(EXIT_FAILURE);
549 }
550 }
551
552
553 /*!
554 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
555
556 \param msg The printf like message to format.
557 \param ... The arguments to format in the message.
558 */
559 void debuga(const char *msg,...)
560 {
561 va_list ap;
562
563 fputs(_("SARG: "),stderr);
564 va_start(ap,msg);
565 vfprintf(stderr,msg,ap);
566 va_end(ap);
567 }
568
569
570 /*!
571 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
572
573 \param msg The printf like message to format.
574 \param ... The arguments to format in the message.
575 */
576 void debugaz(const char *msg,...)
577 {
578 va_list ap;
579
580 fputs(_("SARG: (info) "),stderr);
581 va_start(ap,msg);
582 vfprintf(stderr,msg,ap);
583 va_end(ap);
584 }
585
586
587 char *fixnum(long long int value, int n)
588 {
589 #define MAXLEN_FIXNUM 256
590 char num[MAXLEN_FIXNUM]="";
591 char buf[MAXLEN_FIXNUM * 2];
592 char *pbuf;
593 static char ret[MAXLEN_FIXNUM * 2];
594 char *pret;
595 register int i, j, k;
596 int numlen;
597 static char abbrev[30]="";
598
599 my_lltoa(value, num, sizeof(num), 0);
600
601 if(DisplayedValues==DISPLAY_ABBREV) {
602 numlen = strlen(num);
603 if(numlen <= 3)
604 strcpy(abbrev,num);
605 else if (numlen%3 == 1) {
606 abbrev[0]=num[0];
607 abbrev[1]=(UseComma) ? ',' : '.';
608 abbrev[2]=num[1];
609 abbrev[3]=num[2];
610 abbrev[4]='\0';
611 }
612 else if (numlen%3 == 2) {
613 abbrev[0]=num[0];
614 abbrev[1]=num[1];
615 abbrev[2]=(UseComma) ? ',' : '.';
616 abbrev[3]=num[2];
617 abbrev[4]=num[3];
618 abbrev[5]='\0';
619 }
620 else if (numlen%3 == 0) {
621 abbrev[0]=num[0];
622 abbrev[1]=num[1];
623 abbrev[2]=num[2];
624 abbrev[3]=(UseComma) ? ',' : '.';
625 abbrev[4]=num[3];
626 abbrev[5]=num[4];
627 abbrev[6]='\0';
628 }
629 if (n) {
630 if (numlen <= 3) {
631 //no prefix
632 }
633 else if (numlen <= 6)
634 strcat(abbrev,"K");
635 else if (numlen <= 9)
636 strcat(abbrev,"M");
637 else if (numlen <= 12)
638 strcat(abbrev,"G");
639 else if (numlen <= 15)
640 strcat(abbrev,"T");
641 else if (numlen >= 18)
642 strcat(abbrev,"P");
643 else if (numlen <= 21)
644 strcat(abbrev,"E");
645 else if (numlen <= 24)
646 strcat(abbrev,"Z");
647 else if (numlen <= 27)
648 strcat(abbrev,"Y");
649 else
650 strcat(abbrev,"???");
651 }
652 return(abbrev);
653 }
654
655 bzero(buf, MAXLEN_FIXNUM*2);
656
657 pbuf = buf;
658 pret = ret;
659 k = 0;
660
661 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
662 if ( k == 2 && i != 0 ) {
663 k = 0;
664 pbuf[j++] = num[i];
665 pbuf[j++] = (UseComma) ? ',' : '.';
666 continue;
667 }
668 pbuf[j] = num[i];
669 j++;
670 k++;
671 }
672
673 pret[0]='\0';
674
675 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
676 pret[j] = pbuf[i];
677
678 pret[j] = '\0';
679
680 return pret;
681 }
682
683
684 char *fixnum2(long long int value, int n)
685 {
686 #define MAXLEN_FIXNUM2 1024
687 char num[MAXLEN_FIXNUM2];
688 char buf[MAXLEN_FIXNUM2 * 2];
689 char *pbuf;
690 static char ret[MAXLEN_FIXNUM2 * 2];
691 char *pret;
692 register int i, j, k;
693
694 my_lltoa(value, num, sizeof(num), 0);
695 bzero(buf, MAXLEN_FIXNUM2*2);
696
697 pbuf = buf;
698 pret = ret;
699 k = 0;
700
701 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
702 if ( k == 2 && i != 0 ) {
703 k = 0;
704 pbuf[j++] = num[i];
705 pbuf[j++] = (UseComma) ? ',' : '.';
706 continue;
707 }
708 pbuf[j] = num[i];
709 j++;
710 k++;
711 }
712
713 pret[0]='\0';
714
715 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
716 pret[j] = pbuf[i];
717
718 pret[j] = '\0';
719
720 return pret;
721 }
722
723
724 char *buildtime(long long int elap)
725 {
726 long int num = elap / 1000LL;
727 int hor = 0;
728 int min = 0;
729 int sec = 0;
730 static char buf[20];
731
732 hor=num / 3600L;
733 min=(num % 3600L) / 60L;
734 sec=num % 60L;
735 snprintf(buf,sizeof(buf),"%02d:%02d:%02d",hor,min,sec);
736
737 return(buf);
738 }
739
740
741 /*!
742 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
743
744 \param dirname The directory to look for the connection directory.
745 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
746 \param data The buffer to store the content of the file. It must be more than 80
747 bytes long.
748
749 \retval 0 No error.
750 \retval -1 File not found.
751 */
752 int obtdate(const char *dirname, const char *name, char *data)
753 {
754 FILE *fp_in;
755 char wdir[MAXLEN];
756
757 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-date",dirname,name)>=sizeof(wdir)) {
758 debuga(_("Buffer to small to store %s%s/sarg-date"),dirname,name);
759 exit(EXIT_FAILURE);
760 }
761 if ((fp_in = fopen(wdir, "rt")) == 0) {
762 if (snprintf(wdir,sizeof(wdir),"%s%s/date",dirname,name)>=sizeof(wdir)) {
763 debuga(_("Buffer to small to store %s%s/date"),dirname,name);
764 exit(EXIT_FAILURE);
765 }
766 if ((fp_in = fopen(wdir, "rt")) == 0) {
767 data[0]='\0';
768 return(-1);
769 }
770 }
771
772 if (!fgets(data,80,fp_in)) {
773 debuga(_("Failed to read the date in %s\n"),wdir);
774 exit(EXIT_FAILURE);
775 }
776 fclose(fp_in);
777 fixendofline(data);
778
779 return(0);
780 }
781
782
783 void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
784 {
785 struct tm ltm;
786 time_t unixtime;
787 struct tm *fulltm;
788
789 memset(&ltm,0,sizeof(ltm));
790 if (year>=1900) ltm.tm_year=year-1900;
791 if (month>=1 && month<=12) ltm.tm_mon=month-1;
792 if (day>=1 && day<=31) ltm.tm_mday=day;
793 if (hour>=0 && hour<24) ltm.tm_hour=hour;
794 if (minute>=0 && minute<60) ltm.tm_min=minute;
795 if (second>=0 && second<60) ltm.tm_sec=second;
796 ltm.tm_isdst=dst;
797 unixtime=mktime(&ltm); //fill the missing entries
798 fulltm=localtime(&unixtime);
799 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
800 strftime(date,date_size,"%c",fulltm);
801 }
802
803
804 void computedate(int year,int month,int day,struct tm *t)
805 {
806 memset(t,0,sizeof(*t));
807 t->tm_year=year-1900;
808 t->tm_mon=month-1;
809 t->tm_mday=day;
810 }
811
812
813 int obtuser(const char *dirname, const char *name)
814 {
815 FILE *fp_in;
816 char wdir[MAXLEN];
817 char tuser[20];
818 int nuser;
819
820 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-users",dirname,name)>=sizeof(wdir)) {
821 debuga(_("Buffer too small to store %s%s/sarg-users"),dirname,name);
822 exit(EXIT_FAILURE);
823 }
824 if((fp_in=fopen(wdir,"r"))==NULL) {
825 if (snprintf(wdir,sizeof(wdir),"%s%s/users",dirname,name)>=sizeof(wdir)) {
826 debuga(_("Buffer too small to store %s%s/users"),dirname,name);
827 exit(EXIT_FAILURE);
828 }
829 if((fp_in=fopen(wdir,"r"))==NULL) {
830 return(0);
831 }
832 }
833
834 if (!fgets(tuser,sizeof(tuser),fp_in)) {
835 debuga(_("Failed to read the number of users in %s\n"),wdir);
836 exit(EXIT_FAILURE);
837 }
838 fclose(fp_in);
839 nuser=atoi(tuser);
840
841 return(nuser);
842 }
843
844
845 void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
846 {
847 FILE *fp_in;
848 char *buf;
849 char wdir[MAXLEN];
850 char user[MAX_USER_LEN];
851 char sep;
852 struct getwordstruct gwarea;
853 longline line;
854
855 *tbytes=0;
856 *media=0;
857
858 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-general",dirname,name)>=sizeof(wdir)) {
859 debuga(_("Buffer too small to store %s%s/sarg-general"),dirname,name);
860 exit(EXIT_FAILURE);
861 }
862 if ((fp_in = fopen(wdir, "r")) == 0) {
863 if (snprintf(wdir,sizeof(wdir),"%s%s/general",dirname,name)>=sizeof(wdir)) {
864 debuga(_("Buffer too small to store %s%s/general"),dirname,name);
865 exit(EXIT_FAILURE);
866 }
867 if ((fp_in = fopen(wdir, "r")) == 0) {
868 return;
869 }
870 }
871
872 if ((line=longline_create())==NULL) {
873 debuga(_("Not enough memory to read the file %s\n"),wdir);
874 exit(EXIT_FAILURE);
875 }
876
877 while((buf=longline_read(fp_in,line))!=NULL) {
878 if (strncmp(buf,"TOTAL\t",6) == 0)
879 sep='\t'; //new file
880 else if (strncmp(buf,"TOTAL ",6) == 0)
881 sep=' '; //old file
882 else
883 continue;
884 getword_start(&gwarea,buf);
885 if (getword(user,sizeof(user),&gwarea,sep)<0) {
886 debuga(_("There is a invalid user in file %s\n"),wdir);
887 exit(EXIT_FAILURE);
888 }
889 if(strcmp(user,"TOTAL") != 0)
890 continue;
891 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
892 debuga(_("There a broken total number of access in file %s\n"),wdir);
893 exit(EXIT_FAILURE);
894 }
895 if (getword_atoll(tbytes,&gwarea,sep)<0) {
896 debuga(_("There is a broken number of bytes in file %s\n"),wdir);
897 exit(EXIT_FAILURE);
898 }
899 break;
900 }
901 fclose(fp_in);
902 longline_destroy(&line);
903
904 if (nuser <= 0)
905 return;
906
907 *media=*tbytes / nuser;
908 return;
909 }
910
911 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
912 {
913 const char *str;
914 int day0, month0, year0, hour0, minute0;
915 int day1, month1, year1, hour1, minute1;
916 int i;
917
918 memset(period,0,sizeof(*period));
919
920 str=arqtt;
921 while((str=strstr(str,"sarg-"))!=NULL) {
922 str+=5;
923 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
924 day0=(str[0]-'0')*10+(str[1]-'0');
925 if (day0<1 || day0>31) continue;
926 str+=2;
927 month0=(str[0]-'0')*10+(str[1]-'0')-1;
928 if (month0<0 || month0>11) continue;
929 str+=2;
930 year0=0;
931 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
932 if (i!=4) continue;
933 str+=4;
934 if (str[0]!='_') continue;
935 str++;
936
937 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
938 hour0=(str[0]-'0')*10+(str[1]-'0');
939 str+=2;
940 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
941 minute0=(str[0]-'0')*10+(str[1]-'0');
942 str+=2;
943
944 if (*str != '-') continue;
945 str++;
946
947 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
948 day1=(str[0]-'0')*10+(str[1]-'0');
949 if (day1<1 || day1>31) continue;
950 str+=2;
951 month1=(str[0]-'0')*10+(str[1]-'0')-1;
952 if (month1<0 || month1>11) continue;
953 str+=2;
954 year1=0;
955 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
956 if (i!=4) continue;
957 str+=4;
958
959 if (str[0]!='_') continue;
960 str++;
961
962 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
963 hour1=(str[0]-'0')*10+(str[1]-'0');
964 str+=2;
965 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
966 minute1=(str[0]-'0')*10+(str[1]-'0');
967 str+=2;
968
969 period->start.tm_mday=day0;
970 period->start.tm_mon=month0;
971 period->start.tm_year=year0-1900;
972 period->start.tm_hour=hour0;
973 period->start.tm_min=minute0;
974 period->end.tm_mday=day1;
975 period->end.tm_mon=month1;
976 period->end.tm_year=year1-1900;
977 period->end.tm_hour=hour1;
978 period->end.tm_min=minute1;
979 return(0);
980 }
981 return(-1);
982 }
983
984 void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
985 {
986 memset(&period->start,0,sizeof(period->start));
987 period->start.tm_mday=dfrom%100;
988 period->start.tm_mon=(dfrom/100)%100-1;
989 period->start.tm_year=(dfrom/10000)-1900;
990
991 memset(&period->end,0,sizeof(period->end));
992 period->end.tm_mday=duntil%100;
993 period->end.tm_mon=(duntil/100)%100-1;
994 period->end.tm_year=(duntil/10000)-1900;
995 }
996
997 /*!
998 Update the \a main period to encompass the period in \a candidate.
999 */
1000 void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
1001 {
1002 int cdate;
1003 int mdate;
1004
1005 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
1006 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
1007 if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
1008
1009 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
1010 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
1011 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
1012 }
1013
1014 int getperiod_buildtext(struct periodstruct *period)
1015 {
1016 int i;
1017 int range;
1018 char text1[40], text2[40];
1019
1020 if (df=='u') {
1021 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
1022 } else if(df=='e') {
1023 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
1024 } else /*if (df=='w')*/ {
1025 IndexTree=INDEX_TREE_FILE;
1026 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
1027 }
1028 if (i == 0) return(-1);
1029
1030 range=(period->start.tm_year!=period->end.tm_year ||
1031 period->start.tm_mon!=period->end.tm_mon ||
1032 period->start.tm_mday!=period->end.tm_mday);
1033 if (range) {
1034 if (df=='u') {
1035 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
1036 } else if (df=='e') {
1037 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
1038 } else {
1039 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
1040 }
1041 if (i == 0) return(-1);
1042 }
1043
1044 if (range) {
1045 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1046 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
1047 } else {
1048 safe_strcpy(period->text,text1,sizeof(period->text));
1049 safe_strcpy(period->html,text1,sizeof(period->html));
1050 }
1051 return(0);
1052 }
1053
1054 static void copy_images(void)
1055 {
1056 FILE *img_in, *img_ou;
1057 char images[512];
1058 char imgdir[MAXLEN];
1059 char srcfile[MAXLEN];
1060 char dstfile[MAXLEN];
1061 DIR *dirp;
1062 struct dirent *direntp;
1063 char buffer[MAXLEN];
1064 size_t nread;
1065 struct stat info;
1066
1067 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1068 debuga(_("Cannot copy images to target directory %simages\n"),outdir);
1069 exit(EXIT_FAILURE);
1070 }
1071 if (access(images,R_OK)!=0) {
1072 if (mkdir(images,0755)) {
1073 debuga(_("Cannot create directory %s - %s\n"),images,strerror(errno));
1074 exit(EXIT_FAILURE);
1075 }
1076 }
1077
1078 strcpy(imgdir,IMAGEDIR);
1079 dirp = opendir(imgdir);
1080 if(dirp==NULL) {
1081 debuga(_("(util) Can't open directory %s: %s\n"),imgdir,strerror(errno));
1082 return;
1083 }
1084 while ((direntp = readdir( dirp )) != NULL ){
1085 if(direntp->d_name[0]=='.')
1086 continue;
1087 if (snprintf(srcfile,sizeof(srcfile),"%s/%s",imgdir,direntp->d_name)>=sizeof(srcfile)) {
1088 debuga(_("Buffer too small to store %s/%s"),imgdir,direntp->d_name);
1089 exit(EXIT_FAILURE);
1090 }
1091 if (stat(srcfile,&info)) {
1092 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile,strerror(errno));
1093 continue;
1094 }
1095 if (S_ISREG(info.st_mode)) {
1096 if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
1097 debuga(_("Buffer too small to store %s/%s"),images,direntp->d_name);
1098 exit(EXIT_FAILURE);
1099 }
1100 img_in = fopen(srcfile, "rb");
1101 if(img_in!=NULL) {
1102 img_ou = fopen(dstfile, "wb");
1103 if(img_ou!=NULL) {
1104 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1105 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1106 debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
1107 break;
1108 }
1109 }
1110 if (fclose(img_ou)==EOF) {
1111 debuga(_("Error while copying image %s: %s\n"),dstfile,strerror(errno));
1112 exit(EXIT_FAILURE);
1113 }
1114 } else
1115 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile, strerror(errno));
1116 fclose(img_in);
1117 } else
1118 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile, strerror(errno));
1119 }
1120 }
1121 (void) closedir(dirp);
1122
1123 return;
1124 }
1125
1126 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
1127 {
1128 FILE *fp_ou;
1129 int num=1, count=0;
1130 char wdir[MAXLEN];
1131 char dirname2[MAXLEN];
1132 int y1, y2;
1133 int m1, m2;
1134 int d1, d2;
1135 int wlen, wlen2;
1136 time_t curtime;
1137 struct tm *loctm;
1138
1139 strcpy(wdir,outdir);
1140 wlen=strlen(wdir);
1141 y1=per1->start.tm_year+1900;
1142 y2=per1->end.tm_year+1900;
1143 m1=per1->start.tm_mon+1;
1144 m2=per1->end.tm_mon+1;
1145 d1=per1->start.tm_mday;
1146 d2=per1->end.tm_mday;
1147 if(IndexTree == INDEX_TREE_DATE) {
1148 wlen+=sprintf(wdir+wlen,"%04d",y1);
1149 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1150 if(access(wdir, R_OK) != 0)
1151 my_mkdir(wdir);
1152
1153 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1154 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1155 if(access(wdir, R_OK) != 0)
1156 my_mkdir(wdir);
1157
1158 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1159 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1160 } else {
1161 if (df == 'u') {
1162 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1163 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1164 } else if (df == 'e') {
1165 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1166 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1167 } else if (df == 'w') {
1168 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1169 if (wlen2==0) return(-1);
1170 wlen+=wlen2;
1171 }
1172 }
1173
1174 if(us[0] != '\0') {
1175 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1176 if (uinfo) {
1177 strcat(wdir,"-");
1178 strcat(wdir,uinfo->filename);
1179 }
1180 }
1181 if(addr[0] != '\0') {
1182 strcat(wdir,"-");
1183 strcat(wdir,addr);
1184 }
1185 if(site[0] != '\0') {
1186 strcat(wdir,"-");
1187 strcat(wdir,site);
1188 }
1189
1190 strcpy(outdirname,wdir);
1191
1192 if(IndexTree != INDEX_TREE_DATE) {
1193 if(!OverwriteReport) {
1194 while(num) {
1195 if(access(wdir,R_OK) == 0) {
1196 sprintf(wdir,"%s.%d",outdirname,num);
1197 num++;
1198 count++;
1199 } else
1200 break;
1201 }
1202
1203 if(count > 0) {
1204 if(debug)
1205 debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
1206 rename(outdirname,wdir);
1207 }
1208 } else {
1209 if(access(outdirname,R_OK) == 0) {
1210 unlinkdir(outdirname,1);
1211 }
1212 }
1213 my_mkdir(outdirname);
1214 } else {
1215 strcpy(dirname2,wdir);
1216 if(!OverwriteReport) {
1217 while(num) {
1218 if(access(wdir,R_OK) == 0) {
1219 sprintf(wdir,"%s.%d",dirname2,num);
1220 num++;
1221 count++;
1222 } else
1223 break;
1224 }
1225
1226 if(count > 0) {
1227 if(debug)
1228 debuga(_("File %s already exists, moved to %s\n"),dirname2,wdir);
1229 rename(dirname2,wdir);
1230 strcpy(dirname2,wdir);
1231 }
1232 } else {
1233 if(access(wdir,R_OK) == 0) {
1234 unlinkdir(wdir,1);
1235 }
1236 }
1237
1238 if(access(wdir, R_OK) != 0)
1239 my_mkdir(wdir);
1240 }
1241
1242 strcpy(dirname2,wdir);
1243
1244 if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
1245 debuga(_("Buffer too small to store %s/sarg-date"),outdirname);
1246 exit(EXIT_FAILURE);
1247 }
1248 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1249 debuga(_("cannot open %s for writing: %s\n"),wdir,strerror(errno));
1250 perror("SARG:");
1251 exit(EXIT_FAILURE);
1252 }
1253 time(&curtime);
1254 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1255 loctm=localtime(&curtime);
1256 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1257 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1258 debuga(_("Failed to write the date in %s\n"),wdir);
1259 perror("SARG:");
1260 exit(EXIT_FAILURE);
1261 }
1262 if (fclose(fp_ou)==EOF) {
1263 debuga(_("Failed to write the date in %s: %s\n"),wdir,strerror(errno));
1264 exit(EXIT_FAILURE);
1265 }
1266
1267 copy_images();
1268 return(0);
1269 }
1270
1271 /*!
1272 Copy a string without overflowing the buffer. The copied string
1273 is properly terminated by an ASCII zero.
1274
1275 \param dest The destination buffer.
1276 \param src The source buffer.
1277 \param length The size of the destination buffer. The program is aborted
1278 if the length is negative or zero.
1279 */
1280 void safe_strcpy(char *dest,const char *src,int length)
1281 {
1282 if (length<=0) {
1283 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1284 exit(EXIT_FAILURE);
1285 }
1286 strncpy(dest,src,length-1);
1287 dest[length-1]='\0';
1288 }
1289
1290 void strip_latin(char *line)
1291 {
1292 int i,j;
1293 int skip;
1294
1295 j=0;
1296 skip=0;
1297 for (i=0;line[i];i++){
1298 if (skip){
1299 if (line[i]==';') skip=0;
1300 } else {
1301 if (line[i]=='&')
1302 skip=1;
1303 else
1304 line[j++]=line[i];
1305 }
1306 }
1307 line[j]='\0';
1308 return;
1309 }
1310
1311 void zdate(char *ftime,int ftimesize, char DateFormat)
1312 {
1313 time_t t;
1314 struct tm *local;
1315
1316 t = time(NULL);
1317 local = localtime(&t);
1318 if (DateFormat=='u')
1319 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1320 else if (DateFormat=='e')
1321 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1322 else if (DateFormat=='w')
1323 strftime(ftime, ftimesize, "%W-%H-%M", local);
1324 return;
1325 }
1326
1327
1328 char *fixtime(long long int elap)
1329 {
1330 long int num = elap / 1000LL;
1331 int hor = 0;
1332 int min = 0;
1333 int sec = 0;
1334 static char buf[20];
1335
1336 hor=num / 3600L;
1337 min=(num % 3600L) / 60L;
1338 sec=num % 60L;
1339
1340 if(hor==0 && min==0 && sec==0)
1341 strcpy(buf,"0");
1342 else
1343 snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
1344
1345 return buf;
1346 }
1347
1348
1349 void date_from(char *date,int date_size, int *dfrom, int *duntil)
1350 {
1351 int d0=0;
1352 int m0=0;
1353 int y0=0;
1354 int d1=0;
1355 int m1=0;
1356 int y1=0;
1357
1358 if (isdigit(date[0])) {
1359 int next=-1;
1360
1361 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1362 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1363 exit(EXIT_FAILURE);
1364 }
1365 if (date[next]=='-') {
1366 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1367 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1368 exit(EXIT_FAILURE);
1369 }
1370 } else if (date[next]!='\0') {
1371 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1372 exit(EXIT_FAILURE);
1373 } else {
1374 d1=d0;
1375 m1=m0;
1376 y1=y0;
1377 }
1378 } else {
1379 int i;
1380 time_t Today,t1;
1381 struct tm *Date0,Date1;
1382
1383 if (time(&Today)==(time_t)-1) {
1384 debuga(_("Failed to get the current time\n"));
1385 exit(EXIT_FAILURE);
1386 }
1387 if (sscanf(date,"day-%d",&i)==1) {
1388 if (i<0) {
1389 debuga(_("Invalid number of days in -d parameter\n"));
1390 exit(EXIT_FAILURE);
1391 }
1392 Today-=i*24*60*60;
1393 Date0=localtime(&Today);
1394 if (Date0==NULL) {
1395 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1396 exit(EXIT_FAILURE);
1397 }
1398 y0=y1=Date0->tm_year+1900;
1399 m0=m1=Date0->tm_mon+1;
1400 d0=d1=Date0->tm_mday;
1401 } else if (sscanf(date,"week-%d",&i)==1) {
1402 /*
1403 There is no portable way to find the first day of the week even though the
1404 information is available in the locale. nl_langinfo has the unofficial
1405 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1406 undocumented as is their return value and it is discouraged to use them.
1407 Beside, nl_langinfo isn't available on windows and the first day of the
1408 week isn't available at all on that system.
1409 */
1410 const int FirstWeekDay=1;
1411 time_t WeekBegin;
1412
1413 if (i<0) {
1414 debuga(_("Invalid number of weeks in -d parameter\n"));
1415 exit(EXIT_FAILURE);
1416 }
1417 Date0=localtime(&Today);
1418 if (Date0==NULL) {
1419 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1420 exit(EXIT_FAILURE);
1421 }
1422 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1423 WeekBegin-=i*7*24*60*60;
1424 Date0=localtime(&WeekBegin);
1425 if (Date0==NULL) {
1426 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1427 exit(EXIT_FAILURE);
1428 }
1429 y0=Date0->tm_year+1900;
1430 m0=Date0->tm_mon+1;
1431 d0=Date0->tm_mday;
1432 WeekBegin+=6*24*60*60;
1433 Date0=localtime(&WeekBegin);
1434 if (Date0==NULL) {
1435 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1436 exit(EXIT_FAILURE);
1437 }
1438 y1=Date0->tm_year+1900;
1439 m1=Date0->tm_mon+1;
1440 d1=Date0->tm_mday;
1441 } else if (sscanf(date,"month-%d",&i)==1) {
1442 if (i<0) {
1443 debuga(_("Invalid number of months in -d parameter\n"));
1444 exit(EXIT_FAILURE);
1445 }
1446 Date0=localtime(&Today);
1447 if (Date0==NULL) {
1448 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1449 exit(EXIT_FAILURE);
1450 }
1451 if (Date0->tm_mon<i%12) {
1452 y0=Date0->tm_year+1900-i/12-1;
1453 m0=(Date0->tm_mon+12-i%12)%12+1;
1454 d0=1;
1455 } else {
1456 y0=Date0->tm_year+1900-i/12;
1457 m0=Date0->tm_mon-i%12+1;
1458 d0=1;
1459 }
1460 memcpy(&Date1,Date0,sizeof(struct tm));
1461 Date1.tm_isdst=-1;
1462 Date1.tm_mday=1;
1463 if (m0<12) {
1464 Date1.tm_mon=m0;
1465 Date1.tm_year=y0-1900;
1466 } else {
1467 Date1.tm_mon=0;
1468 Date1.tm_year=y0-1900+1;
1469 }
1470 t1=mktime(&Date1);
1471 t1-=24*60*60;
1472 Date0=localtime(&t1);
1473 y1=Date0->tm_year+1900;
1474 m1=Date0->tm_mon+1;
1475 d1=Date0->tm_mday;
1476 } else {
1477 debuga(_("Invalid date range passed on command line\n"));
1478 exit(EXIT_FAILURE);
1479 }
1480 }
1481
1482 *dfrom=y0*10000+m0*100+d0;
1483 *duntil=y1*10000+m1*100+d1;
1484 snprintf(date,date_size,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1485 return;
1486 }
1487
1488
1489 char *strlow(char *string)
1490 {
1491 char *s;
1492
1493 if (string)
1494 {
1495 for (s = string; *s; ++s)
1496 *s = tolower(*s);
1497 }
1498
1499 return string;
1500 }
1501
1502
1503
1504
1505 char *strup(char *string)
1506 {
1507 char *s;
1508
1509 if (string)
1510 {
1511 for (s = string; *s; ++s)
1512 *s = toupper(*s);
1513 }
1514
1515 return string;
1516 }
1517
1518
1519 void removetmp(const char *outdir)
1520 {
1521 FILE *fp_gen;
1522 char filename[256];
1523
1524 if(!RemoveTempFiles)
1525 return;
1526
1527 if(debug) {
1528 debuga(_("Purging temporary file sarg-general\n"));
1529 }
1530 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1531 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir);
1532 exit(EXIT_FAILURE);
1533 }
1534 if((fp_gen=fopen(filename,"w"))==NULL){
1535 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename,strerror(errno));
1536 exit(EXIT_FAILURE);
1537 }
1538 totalger(fp_gen,filename);
1539 if (fclose(fp_gen)==EOF) {
1540 debuga(_("Failed to close %s after writing the total line: %s\n"),filename,strerror(errno));
1541 exit(EXIT_FAILURE);
1542 }
1543 }
1544
1545 void load_excludecodes(const char *ExcludeCodes)
1546 {
1547 FILE *fp_in;
1548 char data[80];
1549 int i;
1550 int Stored;
1551 long int MemSize;
1552
1553 if(ExcludeCodes[0] == '\0')
1554 return;
1555
1556 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1557 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes,strerror(errno));
1558 exit(EXIT_FAILURE);
1559 }
1560
1561 if (fseek(fp_in, 0, SEEK_END)==-1) {
1562 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1563 exit(EXIT_FAILURE);
1564 }
1565 MemSize = ftell(fp_in);
1566 if (MemSize<0) {
1567 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
1568 exit(EXIT_FAILURE);
1569 }
1570 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1571 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1572 exit(EXIT_FAILURE);
1573 }
1574
1575 MemSize+=1;
1576 if((excludecode=(char *) malloc(MemSize))==NULL) {
1577 debuga(_("malloc error (%ld)\n"),MemSize);
1578 exit(EXIT_FAILURE);
1579 }
1580 memset(excludecode,0,MemSize);
1581
1582 Stored=0;
1583 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1584 if (data[0]=='#') continue;
1585 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1586 if (i<0) continue;
1587 if (Stored+i+2>=MemSize) {
1588 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
1589 break;
1590 }
1591 strcat(excludecode,data);
1592 strcat(excludecode,";");
1593 Stored+=i+1;
1594 }
1595
1596 fclose(fp_in);
1597 return;
1598 }
1599
1600 void free_excludecodes(void)
1601 {
1602 if (excludecode) {
1603 free(excludecode);
1604 excludecode=NULL;
1605 }
1606 }
1607
1608 int vercode(const char *code)
1609 {
1610 char *cod;
1611 int clen;
1612
1613 if (excludecode && excludecode[0]!='\0') {
1614 clen=strlen(code);
1615 cod=excludecode;
1616 while (cod) {
1617 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1618 return 1;
1619 cod=strchr(cod,';');
1620 if (cod) cod++;
1621 }
1622 }
1623 return 0;
1624 }
1625
1626 void fixnone(char *str)
1627 {
1628 int i;
1629
1630 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1631 if(i==3 && strncmp(str,"none",4) == 0)
1632 str[0]='\0';
1633
1634 return;
1635 }
1636
1637 void fixendofline(char *str)
1638 {
1639 int i;
1640
1641 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1642 }
1643
1644 #ifdef LEGACY_TESTVALIDUSERCHAR
1645 int testvaliduserchar(const char *user)
1646 {
1647 int x=0;
1648 int y=0;
1649
1650 for (y=0; y<strlen(UserInvalidChar); y++) {
1651 for (x=0; x<strlen(user); x++) {
1652 if(user[x] == UserInvalidChar[y])
1653 return 1;
1654 }
1655 }
1656 return 0;
1657 }
1658 #else
1659 int testvaliduserchar(const char *user)
1660 {
1661 char * p_UserInvalidChar = UserInvalidChar ;
1662 const char * p_user ;
1663
1664 while( *p_UserInvalidChar ) {
1665 p_user = user ;
1666 while ( *p_user ) {
1667 if( *p_UserInvalidChar == *p_user )
1668 return 1;
1669 p_user++ ;
1670 }
1671 p_UserInvalidChar++ ;
1672 }
1673 return 0;
1674 }
1675 #endif
1676
1677 int compar( const void *a, const void *b )
1678 {
1679 if( *(int *)a > *(int *)b ) return 1;
1680 if( *(int *)a < *(int *)b ) return -1;
1681 return 0;
1682 }
1683
1684 int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
1685 {
1686 int i, j, d, flag, r1, r2;
1687 char *pbuf, **bp, *strbufs[ 24 ];
1688
1689 bp = strbufs;
1690 strtok( buf, " \t" );
1691 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1692 if( ++bp >= &strbufs[ 24 ] )
1693 break;
1694 list->len++;
1695 }
1696 if( ! list->len )
1697 return -1;
1698 d = 0;
1699 for( i = 0; i < list->len; i++ ) {
1700 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1701 pbuf = strbufs[ i ];
1702 strtok( pbuf, "-" );
1703 pbuf = strtok( NULL, "\0" );
1704 r1 = atoi( strbufs[ i ] );
1705 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1706 return -1;
1707 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1708 for( j = r1; j <= r2; j++ )
1709 list->list[ i + d++ ] = j;
1710 d--;
1711 }
1712 }
1713 else
1714 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1715 return 1;
1716 }
1717 list->len += d;
1718 qsort( list->list, list->len, sizeof( int ), compar );
1719 do {
1720 flag = 0;
1721 for( i = 0; i < list->len - 1; i++ )
1722 if( list->list[ i ] == list->list[ i + 1 ] ) {
1723 for( j = i + 1; j < list->len; j++ )
1724 list->list[ j - 1 ] = list->list[ j ];
1725 list->len--;
1726 flag = 1;
1727 break;
1728 }
1729 } while( flag );
1730 return 0;
1731 }
1732
1733
1734 char *get_size(const char *path, const char *file)
1735 {
1736 FILE *fp;
1737 static char response[255];
1738 char cmd[255];
1739 char *ptr;
1740
1741 if (snprintf(cmd,sizeof(cmd),"du -skh %s%s",path,file)>=sizeof(cmd)) {
1742 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path,file);
1743 exit(EXIT_FAILURE);
1744 }
1745 if ((fp = popen(cmd, "r")) == NULL) {
1746 debuga(_("Cannot get disk space with command %s\n"),cmd);
1747 exit(EXIT_FAILURE);
1748 }
1749 if (!fgets(response, sizeof(response), fp)) {
1750 debuga(_("Cannot get disk size with command %s\n"),cmd);
1751 exit(EXIT_FAILURE);
1752 }
1753 ptr=strchr(response,'\t');
1754 if (ptr==NULL) {
1755 debuga(_("The command %s failed\n"),cmd);
1756 exit(EXIT_FAILURE);
1757 }
1758 pclose(fp);
1759 *ptr='\0';
1760
1761 return (response);
1762 }
1763
1764 void show_info(FILE *fp_ou)
1765 {
1766 char ftime[127];
1767
1768 if(!ShowSargInfo) return;
1769 zdate(ftime, sizeof(ftime), df);
1770 fputs("<div class=\"info\">",fp_ou);
1771 fprintf(fp_ou,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
1772 fputs("</div>\n",fp_ou);
1773 }
1774
1775 void show_sarg(FILE *fp_ou, int depth)
1776 {
1777 int i;
1778
1779 if(!ShowSargLogo) return;
1780 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1781 for (i=0 ; i<depth ; i++)
1782 fputs("../",fp_ou);
1783 fputs("images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a>&nbsp;Squid Analysis Report Generator</div>\n",fp_ou);
1784 }
1785
1786 void write_logo_image(FILE *fp_ou)
1787 {
1788 if(LogoImage[0]!='\0')
1789 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
1790 }
1791
1792 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
1793 {
1794 int i;
1795
1796 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1797 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1798 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1799 css(fp_ou);
1800 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1801 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1802 if (strncmp(SortTableJs,"../",3)==0) {
1803 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1804 }
1805 fputs(SortTableJs,fp_ou);
1806 fputs("\"></script>\n",fp_ou);
1807 }
1808 fputs("</head>\n<body>\n",fp_ou);
1809 }
1810
1811 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
1812 {
1813 write_html_head(fp_ou,depth,page_title,javascript);
1814 write_logo_image(fp_ou);
1815 show_sarg(fp_ou, depth);
1816 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
1817 }
1818
1819 void close_html_header(FILE *fp_ou)
1820 {
1821 fputs("</table></div>\n",fp_ou);
1822 }
1823
1824 int write_html_trailer(FILE *fp_ou)
1825 {
1826 show_info(fp_ou);
1827 if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
1828 return(0);
1829 }
1830
1831 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
1832 {
1833 int i=0;
1834
1835 while (*str && (maxlen<=0 || i<maxlen)) {
1836 switch (*str) {
1837 case '&':
1838 fputs("&amp;",fp_ou);
1839 break;
1840 case '<':
1841 fputs("&lt;",fp_ou);
1842 break;
1843 case '>':
1844 fputs("&gt;",fp_ou);
1845 break;
1846 case '"':
1847 fputs("&quot;",fp_ou);
1848 break;
1849 case '\'':
1850 fputs("&#39;",fp_ou);
1851 break;
1852 default:
1853 fputc(*str,fp_ou);
1854 }
1855 str++;
1856 i++;
1857 }
1858 if (maxlen>0 && i>=maxlen)
1859 fputs("&hellip;",fp_ou);
1860 }
1861
1862 void output_html_url(FILE *fp_ou,const char *url)
1863 {
1864 while (*url) {
1865 if (*url=='&')
1866 fputs("&amp;",fp_ou);
1867 else
1868 fputc(*url,fp_ou);
1869 url++;
1870 }
1871 }
1872
1873 /*!
1874 Write a host name inside an A tag of a HTML file. If the host name starts
1875 with a star, it is assumed to be an alias that cannot be put inside a link
1876 so the A tag is not written around the host name.
1877
1878 \param fp_ou The handle of the HTML file.
1879 \param url The host to display in the HTML file.
1880 \param maxlen The maximum number of characters to print into the host name.
1881 */
1882 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
1883 {
1884 if (url[0]==ALIAS_PREFIX) {
1885 // this is an alias, no need for a A tag
1886 output_html_string(fp_ou,url+1,100);
1887 } else {
1888 if (skip_scheme(url)==url)
1889 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
1890 else
1891 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
1892 output_html_url(fp_ou,url);
1893 fputs("\">",fp_ou);
1894 output_html_string(fp_ou,url,100);
1895 fputs("</a>",fp_ou);
1896 }
1897 }
1898
1899 void url_module(const char *url, char *w2)
1900 {
1901 int x, y;
1902 char w[255];
1903
1904 y=0;
1905 for(x=strlen(url)-1; x>=0; x--) {
1906 if(url[x] == '/' || y>=sizeof(w)-1) break;
1907 w[y++]=url[x];
1908 }
1909 if (x<0) {
1910 w2[0]='\0';
1911 return;
1912 }
1913
1914 x=0;
1915 for(y=y-1; y>=0; y--) {
1916 w2[x++]=w[y];
1917 }
1918 w2[x]='\0';
1919 }
1920
1921 /*!
1922 Mangle an URL to produce a part that can be used as an anchor in
1923 a html <a name=""> tag.
1924
1925 \param url The URL to mangle.
1926 \param anchor The buffer to write the mangled URL.
1927 \param size The size of the buffer.
1928 */
1929 void url_to_anchor(const char *url,char *anchor,int size)
1930 {
1931 int i,j;
1932 bool skip;
1933
1934 // find url end
1935 for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
1936 i--;
1937 if (i<=0) {
1938 anchor[0]='\0';
1939 return;
1940 }
1941
1942 // only keep really safe characters
1943 skip=false;
1944 j=size-1;
1945 anchor[j]='\0';
1946 while (j>0 && i>=0)
1947 {
1948 if(isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
1949 anchor[--j]=url[i];
1950 skip=false;
1951 } else {
1952 if (!skip) anchor[--j]='_';
1953 skip=true;
1954 }
1955 i--;
1956 }
1957 if (j>0)
1958 {
1959 while ( anchor[j])
1960 {
1961 *anchor=anchor[j];
1962 anchor++;
1963 }
1964 *anchor='\0';
1965 }
1966 }
1967
1968 void version(void)
1969 {
1970 printf(_("SARG Version: %s\n"),VERSION);
1971 exit(EXIT_SUCCESS);
1972 }
1973
1974 char *get_param_value(const char *param,char *line)
1975 {
1976 int plen;
1977
1978 while (*line==' ' || *line=='\t') line++;
1979 plen=strlen(param);
1980 if (strncasecmp(line,param,plen)) return(NULL);
1981 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
1982 line+=plen;
1983 while (*line==' ' || *line=='\t') line++;
1984 return(line);
1985 }
1986
1987 void unlinkdir(const char *dir,bool contentonly)
1988 {
1989 struct stat st;
1990 DIR *dirp;
1991 struct dirent *direntp;
1992 char dname[MAXLEN];
1993 int err;
1994
1995 dirp=opendir(dir);
1996 if (!dirp) return;
1997 while ((direntp = readdir(dirp)) != NULL) {
1998 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
1999 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2000 continue;
2001 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2002 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2003 exit(EXIT_FAILURE);
2004 }
2005 #ifdef HAVE_LSTAT
2006 err=lstat(dname,&st);
2007 #else
2008 err=stat(dname,&st);
2009 #endif
2010 if (err) {
2011 debuga(_("cannot stat %s\n"),dname);
2012 exit(EXIT_FAILURE);
2013 }
2014 if (S_ISREG(st.st_mode)) {
2015 if (unlink(dname)) {
2016 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2017 exit(EXIT_FAILURE);
2018 }
2019 } else if (S_ISDIR(st.st_mode)) {
2020 unlinkdir(dname,0);
2021 } else {
2022 debuga(_("unknown path type %s\n"),dname);
2023 }
2024 }
2025 closedir(dirp);
2026
2027 if (!contentonly) {
2028 if (rmdir(dir)) {
2029 debuga(_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
2030 exit(EXIT_FAILURE);
2031 }
2032 }
2033 }
2034
2035 /*!
2036 Delete every file from the temporary directory where sarg is told to store its
2037 temporary files.
2038
2039 As any stray file left over by a previous run would be included in the report, we
2040 must delete every file from the temporary directory before we start processing the logs.
2041
2042 But the temporary directory is given by the user either in the configuration file or
2043 on the command line. We check that the user didn't give a wrong directory by looking
2044 at the files stored in the directory. If a single file is not one of ours, we abort.
2045
2046 \param dir The temporary directory to purge.
2047 */
2048 void emptytmpdir(const char *dir)
2049 {
2050 struct stat st;
2051 DIR *dirp;
2052 struct dirent *direntp;
2053 int dlen;
2054 int elen;
2055 char dname[MAXLEN];
2056 int err;
2057 int i;
2058 static const char *TmpExt[]=
2059 {
2060 ".int_unsort",
2061 ".int_log",
2062 ".day",
2063 "htmlrel.txt",
2064 ".user_unsort",
2065 ".user_log",
2066 ".utmp",
2067 ".ip"
2068 };
2069
2070 dirp=opendir(dir);
2071 if (!dirp) return;
2072
2073 // make sure the temporary directory contains only our files
2074 while ((direntp = readdir(dirp)) != NULL) {
2075 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2076 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2077 continue;
2078
2079 // is it one of our files
2080 dlen=strlen(direntp->d_name);
2081 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2082 elen=strlen(TmpExt[i]);
2083 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2084 }
2085 if (i<0) {
2086 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2087 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2088 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2089 exit(EXIT_FAILURE);
2090 }
2091
2092 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2093 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2094 exit(EXIT_FAILURE);
2095 }
2096
2097 #ifdef HAVE_LSTAT
2098 err=lstat(dname,&st);
2099 #else
2100 err=stat(dname,&st);
2101 #endif
2102 if (err) {
2103 debuga(_("cannot stat \"%s\"\n"),dname);
2104 exit(EXIT_FAILURE);
2105 }
2106 if (S_ISDIR(st.st_mode)) {
2107 unlinkdir(dname,0);
2108 } else if (!S_ISREG(st.st_mode)) {
2109 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
2110 exit(EXIT_FAILURE);
2111 }
2112 }
2113 rewinddir(dirp);
2114
2115 // now delete our files
2116 while ((direntp = readdir(dirp)) != NULL) {
2117 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2118 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2119 continue;
2120
2121 // is it one of our files
2122 dlen=strlen(direntp->d_name);
2123 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2124 elen=strlen(TmpExt[i]);
2125 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2126 }
2127 if (i<0) {
2128 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2129 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2130 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2131 exit(EXIT_FAILURE);
2132 }
2133
2134 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2135 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2136 exit(EXIT_FAILURE);
2137 }
2138 #ifdef HAVE_LSTAT
2139 err=lstat(dname,&st);
2140 #else
2141 err=stat(dname,&st);
2142 #endif
2143 if (err) {
2144 debuga(_("cannot stat \"%s\"\n"),dname);
2145 exit(EXIT_FAILURE);
2146 }
2147 if (S_ISREG(st.st_mode)) {
2148 if (unlink(dname)) {
2149 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2150 exit(EXIT_FAILURE);
2151 }
2152 } else {
2153 debuga(_("unknown path type %s\n"),dname);
2154 }
2155 }
2156 closedir(dirp);
2157 }
2158
2159 /*!
2160 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2161 prefix size.
2162
2163 \param buf The buffer to parse.
2164 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2165 The pointer may be NULL.
2166 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2167 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2168 \param nbits The number of prefix bits for an IP address.
2169 \param next The content of the line after the extracted address.
2170
2171 \retval 3 The pattern is a IPv6 address.
2172 \retval 2 The pattern is a IPv4 address.
2173 \retval 1 The patter is a string.
2174 \retval 0 Empty pattern.
2175 */
2176 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
2177 {
2178 int i;
2179 int j;
2180 int ip_size;
2181 unsigned int value4, value6;
2182 unsigned short int addr[8];
2183 int addr_len;
2184 int nibble6_len;
2185 int mask, max_mask;
2186 int pad_pos;
2187 int pad_len;
2188 bool bracket=false;
2189 bool port=false;
2190 bool port_num=0;
2191
2192 // skip leading spaces and tabs
2193 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
2194
2195 // find out the nature of the pattern
2196 ip_size=0x60 | 0x04;
2197 if (*buf=='[') {
2198 bracket=true;
2199 ip_size=0x60;
2200 buf++;
2201 }
2202 value4=0U;
2203 value6=0U;
2204 addr_len=0;
2205 nibble6_len=0;
2206 pad_pos=-1;
2207 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
2208 if (ip_size & 0x04) {
2209 if (isdigit(buf[i])) {
2210 if (port) {
2211 port_num=port_num*10+(buf[i]-'0');
2212 if (port_num>65535) ip_size&=~0x04;
2213 } else {
2214 value4=value4*10+(buf[i]-'0');
2215 if (value4>0xFFU) ip_size&=~0x04;
2216 }
2217 } else if (buf[i]=='.' && addr_len<4) {
2218 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2219 value4=0U;
2220 } else if (!port && buf[i]==':') {
2221 port=true;
2222 } else {
2223 ip_size&=~0x04;
2224 }
2225 }
2226 if (ip_size & 0x60) {
2227 if (isdigit(buf[i])) {
2228 value6=(value6<<4)+(buf[i]-'0');
2229 nibble6_len++;
2230 if (value6>0xFFFFU) ip_size&=~0x60;
2231 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2232 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
2233 nibble6_len++;
2234 if (value6>0xFFFFU) ip_size&=~0x60;
2235 } else if (buf[i]==':' && addr_len<8) {
2236 if (nibble6_len>0) {
2237 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2238 nibble6_len=0;
2239 }
2240 value6=0U;
2241 if (buf[i+1]==':') {
2242 pad_pos=addr_len;
2243 i++;
2244 }
2245 } else {
2246 ip_size&=~0x60;
2247 }
2248 }
2249 }
2250 if (i==0) return(0);
2251 if (ip_size & 0x04) {
2252 if (addr_len!=3)
2253 ip_size&=~0x04;
2254 else
2255 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2256 }
2257 if (ip_size & 0x60) {
2258 if (pad_pos<0 && addr_len!=7) {
2259 ip_size&=~0x60;
2260 } else if (pad_pos>=0 && addr_len>=7)
2261 ip_size&=~0x60;
2262 else if (nibble6_len>0)
2263 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2264 }
2265 if (!ip_size) {
2266 if (text) {
2267 *text=buf;
2268 if (bracket) (*text)--;
2269 }
2270 while ((unsigned char)buf[i]>' ') i++;
2271 if (next) *next=buf+i;
2272 return(1);
2273 }
2274 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2275 if (buf[i]=='/') {
2276 i++;
2277 mask=atoi(buf+i);
2278 while (isdigit(buf[i])) i++;
2279 if (mask<0 || mask>max_mask) mask=max_mask;
2280 } else
2281 mask=max_mask;
2282 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
2283 if (next) *next=buf+i;
2284 if (ip_size & 0x04) {
2285 if (nbits) *nbits=mask;
2286 for (i=0 ; i<addr_len ; i++)
2287 ipv4[i]=(unsigned char)addr[i];
2288 return(2);
2289 }
2290
2291 // IPv6 address
2292 if (nbits) *nbits=mask;
2293 i=0;
2294 j=0;
2295 if (pad_pos>=0) {
2296 while (i<pad_pos)
2297 ipv6[j++]=(unsigned short int)addr[i++];
2298 pad_len=8-addr_len;
2299 while (j<pad_pos+pad_len)
2300 ipv6[j++]=0;
2301 }
2302 while (i<addr_len)
2303 ipv6[j++]=(unsigned short int)addr[i++];
2304 return(3);
2305 }