From: Frederic Marchal Date: Wed, 5 Jun 2013 20:17:02 +0000 (+0200) Subject: Create multiple per_user_limit files X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e29ae2342d52af35565ebc3198d31802556e51b;p=thirdparty%2Fsarg.git Create multiple per_user_limit files Each file can have a different limit. For each file, it is possible to write the user's ID or the user's IP address. If the files exists, they are purged. --- diff --git a/getconf.c b/getconf.c index 6722a2b..20b7a72 100644 --- a/getconf.c +++ b/getconf.c @@ -32,6 +32,8 @@ extern numlist hours, weekdays; extern FileListObject AccessLog; +extern int PerUserLimitsNumber; +extern struct PerUserLimitStruct PerUserLimits[MAX_USER_LIMITS]; struct param_list { @@ -435,6 +437,66 @@ static int getparam_sort(const char *param,struct sort_list *options,int noption return(1); } +static int getparam_userlimit(const char *param,char *buf) +{ + int plen; + char *file_begin,*file_end; + int limit; + int digit; + int userid; + + plen=strlen(param); + if (strncmp(buf,param,plen) != 0) return(0); + buf+=plen; + if ((unsigned char)*buf>' ') return(0); + while (*buf && (unsigned char)*buf<=' ') buf++; + + /* + options are made of a file name, an integer limit and an optional + integer flag. The file name may contain spaces. We keep searching + until a valid number is found after a space. + */ + file_begin=buf; + do { + while (*buf && (unsigned char)*buf>' ') buf++; + if (*buf!=' ') { + debuga(_("Missing limit in per_user_limit\n")); + exit(EXIT_FAILURE); + } + file_end=buf; + while (*buf && (unsigned char)*buf<=' ') buf++; + limit=0; + while (*buf && isdigit(*buf)) { + digit=*buf-'0'; + if (limit>=(INT_MAX-digit)/10) break; + limit=limit*10+digit; + buf++; + } + } while (*buf && *buf!=' '); + + userid=0; + if (*buf==' ') { + while (*buf && (unsigned char)*buf<=' ') buf++; + if (!isdigit(*buf)) { + debuga(_("Invalid user ID/IP output type flag in per_user_limit\n")); + exit(EXIT_FAILURE); + } + userid=*buf-'0'; + } + + if (PerUserLimitsNumber>=MAX_USER_LIMITS) { + debuga(_("Too many per_user_limit\n")); + exit(EXIT_FAILURE); + } + *file_end='\0'; + safe_strcpy(PerUserLimits[PerUserLimitsNumber].File,file_begin,sizeof(PerUserLimits[PerUserLimitsNumber].File)); + PerUserLimits[PerUserLimitsNumber].Limit=limit; + PerUserLimits[PerUserLimitsNumber].UserId=userid; + PerUserLimitsNumber++; + + return(1); +} + static void parmtest(char *buf) { char wbuf[2048]; @@ -567,10 +629,7 @@ static void parmtest(char *buf) if (getparam_string("output_email",buf,OutputEmail,sizeof(OutputEmail))>0) return; - if (getparam_2words("per_user_limit",buf,PerUserLimitFile,sizeof(PerUserLimitFile),wbuf,sizeof(wbuf))>0) { - PerUserLimit=atoi(wbuf); - return; - } + if (getparam_userlimit("per_user_limit",buf)>0) return; if (getparam_int("lastlog",buf,&LastLog)>0) return; diff --git a/html.c b/html.c index 54d953f..d330b77 100644 --- a/html.c +++ b/html.c @@ -27,6 +27,11 @@ #include "include/conf.h" #include "include/defs.h" +//! Number of limits. +int PerUserLimitsNumber=0; +//! Log user's who downloaded more than the limit. +struct PerUserLimitStruct PerUserLimits[MAX_USER_LIMITS]; + extern struct globalstatstruct globstat; void htmlrel(void) @@ -51,13 +56,15 @@ void htmlrel(void) double perc=0, perc2=0, ouperc=0, inperc=0; int count; int cstatus; + int i; + unsigned int user_limit[(MAX_USER_LIMITS+sizeof(unsigned int)-1)/sizeof(unsigned int)]; bool have_denied_report; const char *sort_field; const char *sort_order; char siteind[MAX_TRUNCATED_URL]; struct getwordstruct gwarea; longline line,line1; - struct userinfostruct *uinfo; + const struct userinfostruct *uinfo; userscan uscan; if (snprintf(tmp2,sizeof(tmp2),"%s/sargtmp.int_unsort",tmp)>=sizeof(tmp2)) { @@ -77,6 +84,14 @@ void htmlrel(void) sort_labels(&sort_field,&sort_order); + for (i=0 ; i\n",fp_ou); } - if (PerUserLimit > 0 && (int)(tnbytes/1000000LLU) > PerUserLimit && !uinfo->user_limit) { - FILE *fp_usr; + if (PerUserLimitsNumber>0) { + int limit=(int)(tnbytes/1000000LLU); + int maskid; + int mask; + for (i=0 ; iPerUserLimits[i].Limit && (user_limit[maskid] & mask)==0) { + FILE *fp_usr; + + if((fp_usr = fopen(PerUserLimits[i].File, "a")) == 0) { + debuga(_("(html10) Cannot open per user limit file %s: %s\n"),PerUserLimits[i].File,strerror(errno)); + exit(EXIT_FAILURE); + } + if (PerUserLimits[i].UserId) + fprintf(fp_usr,"%s\n",uinfo->label); + else + fprintf(fp_usr,"%s\n",uinfo->ip); + if (fclose(fp_usr)==EOF) { + debuga(_("Write error in per user limit file %s: %s\n"),PerUserLimits[i].File,strerror(errno)); + exit(EXIT_FAILURE); + } + user_limit[maskid]|=mask; - if((fp_usr = fopen(PerUserLimitFile, "a")) == 0) { - debuga(_("(html10) Cannot open file %s: %s\n"),PerUserLimitFile,strerror(errno)); - exit(EXIT_FAILURE); - } - fprintf(fp_usr,"%s\n",uinfo->ip); - if (fclose(fp_usr)==EOF) { - debuga(_("Write error in %s: %s\n"),PerUserLimitFile,strerror(errno)); - exit(EXIT_FAILURE); + if(debug) + debuga(_("User %s limit exceeded (%d MB). Added to file %s\n"),uinfo->label, + PerUserLimits[i].Limit,PerUserLimits[i].File); + } } - uinfo->user_limit=1; - - if(debug) - debuga(_("User %s limit exceeded (%d MB). Added to file %s\n"),uinfo->label,PerUserLimit,PerUserLimitFile); } if ((ReportType & REPORT_TYPE_TOPUSERS) != 0 && (UserReportFields & USERREPORTFIELDS_AVERAGE) != 0) { diff --git a/include/conf.h b/include/conf.h index 4611f29..821ce85 100755 --- a/include/conf.h +++ b/include/conf.h @@ -279,6 +279,9 @@ Sarg will complain that there are too many days in the files if this limit is ov //! The character prefixed in front of the host names that are aliased. #define ALIAS_PREFIX '*' +//! Maximum number of limit files that can be stored. +#define MAX_USER_LIMITS 16 + struct periodstruct { //! The first date of the period. @@ -346,8 +349,6 @@ char module[255]; char ExcludeHosts[255]; char ExcludeUsers[255]; char DateFormat; -char PerUserLimitFile[255]; -int PerUserLimit; bool UserIp; char MaxElapsed[255]; unsigned long int datetimeby; diff --git a/include/defs.h b/include/defs.h index 6760806..9431913 100755 --- a/include/defs.h +++ b/include/defs.h @@ -61,8 +61,6 @@ struct userinfostruct const char *filename; //! \c True if this user is in the topuser list. int topuser; - //! \c True if the user's limit has been reached. - int user_limit; //! A general purpose flag that can be set when scanning the user's list. int flag; #ifdef ENABLE_DOUBLE_CHECK_DATA @@ -118,6 +116,19 @@ struct ReadLogDataStruct int EndTime; }; +/*! +\brief How to log every user crossing the download limit. +*/ +struct PerUserLimitStruct +{ + //! File to save the user's IP or ID to. + char File[255]; + //! Limit above which the user is reported. + int Limit; + //! \c True to report the user's ID or \c false to report the user's IP. + bool UserId; +}; + // auth.c void htaccess(const struct userinfostruct *uinfo); diff --git a/sarg.conf b/sarg.conf index 5a078d4..f52d108 100644 --- a/sarg.conf +++ b/sarg.conf @@ -224,9 +224,11 @@ # #date_format u -# TAG: per_user_limit file MB -# Saves userid on file if download exceed n MB. +# TAG: per_user_limit file MB flag +# Saves userid (if flag is 1) or userip (if flag is 0) in file if download exceed n MB. # This option allow you to disable user access if user exceed a download limit. +# The option may be repeated up to 16 times to generate several files with +# different content type or limit. # #per_user_limit none diff --git a/userinfo.c b/userinfo.c index 37451b0..24b038f 100644 --- a/userinfo.c +++ b/userinfo.c @@ -117,7 +117,6 @@ struct userinfostruct *userinfo_create(const char *userid,const char *ip) user->id_is_ip=1; user->ip=user->id; } - user->user_limit=0; if (AnonymousOutputFiles) { snprintf(filename,sizeof(filename),"%d",AnonymousCounter++);