From: Frédéric Marchal Date: Sun, 15 Jul 2012 16:49:48 +0000 (+0200) Subject: Don't blindly delete /tmp/sarg X-Git-Tag: v2.3.3~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=170a77ea0deb9667113e678fa891c3139f31e25c;p=thirdparty%2Fsarg.git Don't blindly delete /tmp/sarg If sarg is configured with a wrong /tmp path or the path given points to a directory the user doesn't intent to use as a temporary directory, we must not delete it's content (think about a link going to /usr/bin). To protect against that situation, sarg only deletes its own files and after making sure it only contains files created by sarg. --- diff --git a/datafile.c b/datafile.c index a0339c8..33c80d1 100644 --- a/datafile.c +++ b/datafile.c @@ -83,8 +83,8 @@ void data_file(char *tmp) if(debug) debuga(_("Reading user file: %s/%s\n"),tmp,uinfo->filename); sort_users_log(tmp,debug,uinfo); - if (snprintf(tmp3,sizeof(tmp3),"%s/%s.log",tmp,uinfo->filename)>=sizeof(tmp3)) { - debuga(_("(datafile) directory path too long: %s/%s.log\n"),tmp,uinfo->filename); + if (snprintf(tmp3,sizeof(tmp3),"%s/%s.user_log",tmp,uinfo->filename)>=sizeof(tmp3)) { + debuga(_("(datafile) directory path too long: %s/%s.user_log\n"),tmp,uinfo->filename); exit(EXIT_FAILURE); } diff --git a/include/defs.h b/include/defs.h index 69acaca..c9c8a3f 100755 --- a/include/defs.h +++ b/include/defs.h @@ -303,5 +303,6 @@ void removetmp(const char *outdir); void zdate(char *ftime,int ftimesize, const char *DateFormat); char *get_param_value(const char *param,char *line); int compar( const void *, const void * ); -void unlinkdir(const char *dir,int contentonly); +void unlinkdir(const char *dir,bool contentonly); +void emptytmpdir(const char *dir); int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next); diff --git a/log.c b/log.c index bde768b..7b20153 100644 --- a/log.c +++ b/log.c @@ -650,8 +650,8 @@ int main(int argc,char *argv[]) } if(access(tmp, R_OK) == 0) { - if (debug) debuga(_("Deleting directory %s\n"),tmp); - unlinkdir(tmp,1); + if (debug) debuga(_("Deleting temporary directory \"%s\"\n"),tmp); + emptytmpdir(tmp); } my_mkdir(tmp); snprintf(denied_unsort,sizeof(denied_unsort),"%s/denied.int_unsort",tmp); @@ -1475,8 +1475,8 @@ int main(int argc,char *argv[]) } } } - if (snprintf (tmp3, sizeof(tmp3), "%s/%s.unsort", tmp, ufile->user->filename)>=sizeof(tmp3)) { - debuga(_("Temporary user file name too long: %s/%s.unsort\n"), tmp, ufile->user->filename); + if (snprintf (tmp3, sizeof(tmp3), "%s/%s.user_unsort", tmp, ufile->user->filename)>=sizeof(tmp3)) { + debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp, ufile->user->filename); exit(EXIT_FAILURE); } if ((ufile->file = MY_FOPEN (tmp3, "a")) == NULL) { diff --git a/report.c b/report.c index 39a9d00..cb0f579 100644 --- a/report.c +++ b/report.c @@ -116,8 +116,8 @@ void gerarel(void) } while ((uinfo = userinfo_advancescan(uscan)) != NULL ) { sort_users_log(tmp,debug,uinfo); - if (snprintf(tmp3,sizeof(tmp3),"%s/%s.log",tmp,uinfo->filename)>=sizeof(tmp3)) { - debuga(_("(report) directory entry too long: %s/%s.log\n"),tmp,uinfo->filename); + if (snprintf(tmp3,sizeof(tmp3),"%s/%s.user_log",tmp,uinfo->filename)>=sizeof(tmp3)) { + debuga(_("(report) directory entry too long: %s/%s.user_log\n"),tmp,uinfo->filename); exit(EXIT_FAILURE); } if((fp_in=MY_FOPEN(tmp3,"r"))==NULL){ diff --git a/sort.c b/sort.c index b35d7a2..47e95d2 100644 --- a/sort.c +++ b/sort.c @@ -115,11 +115,11 @@ void sort_users_log(const char *tmp, int debug,struct userinfostruct *uinfo) int clen; if(debug) { - debuga(_("Sorting log %s/%s.unsort\n"),tmp,uinfo->filename); + debuga(_("Sorting log %s/%s.user_unsort\n"),tmp,uinfo->filename); } user=uinfo->filename; - clen=snprintf(csort,sizeof(csort),"sort -T \"%s\" -t \"\t\" -k 4,4 -k 1,1 -k 2,2 -o \"%s/%s.log\" \"%s/%s.unsort\"", + clen=snprintf(csort,sizeof(csort),"sort -T \"%s\" -t \"\t\" -k 4,4 -k 1,1 -k 2,2 -o \"%s/%s.user_log\" \"%s/%s.user_unsort\"", tmp, tmp, user, tmp, user); if (clen>=sizeof(csort)) { debuga(_("user name too long to sort %s\n"),csort); @@ -131,8 +131,8 @@ void sort_users_log(const char *tmp, int debug,struct userinfostruct *uinfo) debuga(_("sort command: %s\n"),csort); exit(EXIT_FAILURE); } - if (snprintf(csort,sizeof(csort),"%s/%s.unsort",tmp,user)>=sizeof(csort)) { - debuga(_("user name too long for %s/%s.unsort\n"),tmp,user); + if (snprintf(csort,sizeof(csort),"%s/%s.user_unsort",tmp,user)>=sizeof(csort)) { + debuga(_("user name too long for %s/%s.user_unsort\n"),tmp,user); exit(EXIT_FAILURE); } if (!KeepTempLog && unlink(csort)) { diff --git a/util.c b/util.c index 72006b2..dc0ba0c 100644 --- a/util.c +++ b/util.c @@ -1800,7 +1800,7 @@ char *get_param_value(const char *param,char *line) return(line); } -void unlinkdir(const char *dir,int contentonly) +void unlinkdir(const char *dir,bool contentonly) { struct stat st; DIR *dirp; @@ -1848,6 +1848,130 @@ void unlinkdir(const char *dir,int contentonly) } } +/*! +Delete every file from the temporary directory where sarg is told to store its +temporary files. + +As any stray file left over by a previous run would be included in the report, we +must delete every file from the temporary directory before we start processing the logs. + +But the temporary directory is given by the user either in the configuration file or +on the command line. We check that the user didn't give a wrong directory by looking +at the files stored in the directory. If a single file is not one of ours, we abort. + +\param dir The temporary directory to purge. +*/ +void emptytmpdir(const char *dir) +{ + struct stat st; + DIR *dirp; + struct dirent *direntp; + int dlen; + int elen; + char dname[MAXLEN]; + int err; + int i; + static const char *TmpExt[]= + { + ".int_unsort", + ".int_log", + ".day", + "htmlrel.txt", + ".user_unsort", + ".user_log", + ".utmp", + ".ip" + }; + + dirp=opendir(dir); + if (!dirp) return; + + // make sure the temporary directory contains only our files + while ((direntp = readdir(dirp)) != NULL) { + if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' || + (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0'))) + continue; + + // is it one of our files + dlen=strlen(direntp->d_name); + for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) { + elen=strlen(TmpExt[i]); + if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break; + } + if (i<0) { + debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. " + "Please check the temporary directory you gave to sarg. Adjust the path to a safe " + "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir); + exit(EXIT_FAILURE); + } + + if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) { + debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name); + exit(EXIT_FAILURE); + } + +#ifdef HAVE_LSTAT + err=lstat(dname,&st); +#else + err=stat(dname,&st); +#endif + if (err) { + debuga(_("cannot stat \"%s\"\n"),dname); + exit(EXIT_FAILURE); + } + if (S_ISDIR(st.st_mode)) { + unlinkdir(dname,0); + } else if (!S_ISREG(st.st_mode)) { + debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname); + exit(EXIT_FAILURE); + } + } + rewinddir(dirp); + + // now delete our files + while ((direntp = readdir(dirp)) != NULL) { + if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' || + (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0'))) + continue; + + // is it one of our files + dlen=strlen(direntp->d_name); + for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) { + elen=strlen(TmpExt[i]); + if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break; + } + if (i<0) { + debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. " + "Please check the temporary directory you gave to sarg. Adjust the path to a safe " + "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir); + exit(EXIT_FAILURE); + } + + if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) { + debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name); + exit(EXIT_FAILURE); + } +#ifdef HAVE_LSTAT + err=lstat(dname,&st); +#else + err=stat(dname,&st); +#endif + if (err) { + debuga(_("cannot stat \"%s\"\n"),dname); + exit(EXIT_FAILURE); + } + if (S_ISREG(st.st_mode)) { + if (unlink(dname)) { + debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno)); + exit(EXIT_FAILURE); + } + } else { + debuga(_("unknown path type %s\n"),dname); + } + } + closedir(dirp); +} + /*! Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a prefix size.