]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Don't blindly delete /tmp/sarg
authorFrédéric Marchal <fmarchal@users.sourceforge.net>
Sun, 15 Jul 2012 16:49:48 +0000 (18:49 +0200)
committerFrédéric Marchal <fmarchal@users.sourceforge.net>
Sun, 15 Jul 2012 16:49:48 +0000 (18:49 +0200)
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.

datafile.c
include/defs.h
log.c
report.c
sort.c
util.c

index a0339c8d3e72f82eacf8ef8aa1fbdab8c8c3ade6..33c80d104c75e001d57374351396a18c2d90b6e1 100644 (file)
@@ -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);
                }
 
index 69acaca0a264e2fc164a694ed0ffd2970ee5dbca..c9c8a3f59f33f3242ac26be7f2466931fd13ad7a 100755 (executable)
@@ -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 bde768b61a88aad3d48fa3fc906daa8c4bf21462..7b20153504a35f2c6d757f28560844bf54f2383f 100644 (file)
--- 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) {
index 39a9d00b63bddb3312e12c231416533c18b5d76f..cb0f579ff2f81b14e1185dae16dcd34f68b65c2a 100644 (file)
--- 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 b35d7a228f245399273abd42ddde37cefcec8ceb..47e95d25e4c9ae6c12787d1f9b2a91804e189eab 100644 (file)
--- 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 72006b2318715667fe4835f1a74b1a4c021ba839..dc0ba0c26e3da0a93b45ead33bdf2d427e62f19e 100644 (file)
--- 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.