www.ProFTPD.de
13. März 2007, 18:18:26 *
Willkommen Gast. Bitte einloggen oder registrieren.
Haben Sie Ihre Aktivierungs E-Mail übersehen?

Einloggen mit Benutzername, Passwort und Sitzungslänge
News: SMF - Neu installiert!
 
   Übersicht   Hilfe Suche Login Registrieren  
Seiten: [1]   Nach unten
  Drucken  
Autor Thema: New SFV Checker!  (Gelesen 2063 mal)
0 Mitglieder und 1 Gast betrachten dieses Thema.
Kraklok
Gast
« am: 20. Oktober 2003, 20:10:51 »

Here is a small, quick&dirty SFV-Checker I have built. It is a module for ProFTPd (so you need to recompile it). I know it is really a shitty piece of code :oops: Just tell me what you think of it, thanks ! :wink:

mod_sfv.c
Code:

/*
* MOD_SFV.C v0.1 (oct.19 2003)
* Author : Kraklok
*
* DESCRIPTION:
* Module to enable SFV management with ProFTPd
*
* A really Quick&Dirty SFV-Checker, this module lacks much security
* (checking for length and unallowed characters for example) and is
* a great CPU-time/bandwidth/memory consummer. Also, this module is
* not designed for multiple usage at the same time. (Now, you know
* I'm not a good programmer and what Q&D means :-/ ) My only goal
* was to write a ""challenger"" to FTPSFV ;-).
*
* There is no switch to enable or disable the module, you need to
* recompile ProFTPd to enable/disable it. If enabled, MOD_SFV will
* automatically check .SFV on LIST & DELE & STOR commands. All
* filename checks are done without was sensitivity.
*
* Do not hesitate to modify it and redistribute it. It would be nice
* to see a real good SFV-Checker.
* The licence is: "do whatever you want with this code". But
* remember: "I am not responsible for anything that can happen with
* this module (corrupted uploads, file deletion, etc...)".
*
* COMPILING:
* Put the file in ./contrib directory and launch:
* ./configure --with-modules=mod_sfv[:more_modules] [more_options] &&
* make && make install
*
* It should compile without errors (with some warnings though...)
*/
/*
* INCLUDES
*/
#include "conf.h"
#include "mod_sfv.h"
/*
* DEFINITIONS
*/
static unsigned int SFVNbFiles=0; // Number of files found in .SFV
static unsigned int SFVNbFileChecked=0; // Number of files already checked

static struct SFVEntry *sfventry=NULL; // SFV definition variable
/*
* ResetSFVParam()
* ---------------
* DESCRIPTION:
* Reset all the variables associated with SFV management
* IN:
* /
* OUT:
* /
*/
void ResetSFVParam(void)
{
struct SFVEntry *tempnext=NULL; // Temporary entry in the sfv file

#ifdef DEBUG_MOD_SFV
int i=0;
#endif

while(sfventry!=NULL) // Free the memory allocated for each sfv-entry
{
tempnext=sfventry->next;
free(sfventry);
sfventry=tempnext;

#ifdef DEBUG_MOD_SFV
i++;
#endif

}
SFVNbFiles=0; // Set the variable back to zero
SFVNbFileChecked=0; //

#ifdef DEBUG_MOD_SFV
// Show how many entries were fried:
pr_response_add(R_212, "[DEBUG_MOD_SFV]%d entries released",i);
#endif

return;
}
/*
* SFVLineContainsForbiddenChars()
* -------------------------------
* DESCRIPTION:
* Check if the first character of the current line in .SFV file is a forbidden character
* IN:
* firstchar(char)=first character of the current line in SFV file
* OUT:
* status(int)=tells if the character is allowed or not (status=0 => allowed, status!=0 => forbidden)
*/
int SFVLineContainsForbiddenChars(char firstchar)
{
char allowedchars[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int status;

for(status=0;status<sizeof(allowedchars);status++)
{
if(firstchar==allowedchars[status])
{
status=0;
break;
}
}
return status;

}
/*
* CheckFileAlreadyOk()
* --------------------
* DESCRIPTION:
* Check if a filename exists.
* IN:
* fname(char*)=pointer to a filename
* OUT:
* ret(int)=tells if the filename exists (ret=1 => exists, ret=0 => cannot find the filename)
*/
int CheckFileAlreadyOk(char *fname)
{
DIR *dir;
struct dirent *directory;
int ret=0;

// Open working directory
if((dir=opendir(session.cwd))==NULL) return ret;
// Read each entity within the working dir.
while((directory=readdir(dir))!=NULL)
{
// Test if filename exists
if(strncasecmp(directory->d_name,fname,strlen(directory->d_name))==0)
{
#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV]%s exists",fname);
#endif
ret=1;
break;
}
}
closedir(dir);
return ret;
}
/*
* DeleteINFODIR()
* ---------------
* DESCRIPTION:
* Deletes INFO-DIR ([MySERV]-blahblah-[MySERV] directory).
* !! ASSUMES this call is followed by a LIST-command
* IN:
* cmd(cmd_rec*)=[look at ProFTPd Dev.Guide for more infos]
* OUT:
* MODRET=[look at ProFTPd Dev.Guide for more infos]
*/
MODRET DeleteINFODIR(cmd_rec *cmd)
{
DIR *dir;
struct dirent *directory;

// Open working directory
if((dir=opendir(session.cwd))==NULL) return DECLINED(cmd);
// Read each entity within the working dir.
while((directory=readdir(dir))!=NULL)
{
// Test if beginning & end tags are present in current entity
// (!! this means a file named with INFODIRTAG_BEGIN & INFODIRTAG_END would make it fail !!)
if(strncmp(directory->d_name,INFODIRTAG_BEGIN,strlen(INFODIRTAG_BEGIN))==0 && strncmp((directory->d_name)+strlen(directory->d_name)-strlen(INFODIRTAG_END),INFODIRTAG_END,strlen(INFODIRTAG_END))==0)
{
// If it matches, delete the entity...
rmdir(directory->d_name);
#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV]%s deleted",directory->d_name);
#endif
}
}
closedir(dir);
return DECLINED(cmd);
}
/*
* CreateMissingFiles()
* --------------------
* DESCRIPTION:
* Create [original_filename].missing file when the file misses
* IN:
* /
* OUT:
* /
*/
void CreateMissingFiles(void)
{
static struct SFVEntry *tempsfv=NULL;
char missing[MAX_FNAME];

tempsfv=sfventry;
// for each entry in 'sfventry', create a .MISSING_STRING file
while(tempsfv)
{
sprintf(missing,"%s.%s",tempsfv->fname,MISSING_STRING);
creat(missing,S_IWUSR);
tempsfv=tempsfv->next;
}
}
/*
* ParseSFV()
* ----------
* DESCRIPTION:
* Find the .SFV file and parse it to fill teh sfventry list.
* IN:
* sfvname(char*)=pointer to the sfvfile. If NULL, the function will search for it.
* OUT:
* /
*/
void ParseSFV(char *sfvname)
{

DIR *dir;
struct dirent *directory;
FILE *fp;
char sfvline[MAX_FNAME];
static struct SFVEntry *tempsfv=NULL,*rootsfv=NULL;

ResetSFVParam();
// Do we need to search for the .SFV file ?
if(sfvname==NULL)
{
if((dir=opendir(session.cwd))==NULL) return;
while((directory=readdir(dir))!=NULL)
{
if(strlen(directory->d_name) > 4)
{
if(strncasecmp((directory->d_name)+strlen(directory->d_name)-4,".SFV",4)==0)
{
sfvname=directory->d_name;
break;
}
}
}
closedir(dir);
}

if((fp=fopen(sfvname,"rt"))==NULL) return;
while(1)
{
if(feof(fp)) break; // while not  EOF...
if(fgets(sfvline,MAX_FNAME,fp)==NULL) break; // try to extract a line from .SFV file
if(SFVLineContainsForbiddenChars(sfvline[0])==0)
{
// We found a valid SFV line : parse it...
if(((struct SFVEntry*)tempsfv=malloc(sizeof(struct SFVEntry)))!=NULL)
{
tempsfv->next=NULL;
if(sscanf(sfvline,"%s %8lX",tempsfv->fname,&(tempsfv->crc))>0)
{
#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV] %s found with CRC=%8lX",tempsfv->fname,tempsfv->crc);
#endif
// Check if the file is already upped (we assume that if it was upped, it is good :/)
if(CheckFileAlreadyOk(tempsfv->fname))
{
SFVNbFileChecked++;
}
// If not, add it to the list of needed files
else
{
if(sfventry==NULL) // If this is the first entry:
{
sfventry=tempsfv;
rootsfv=tempsfv;
}
else // If not, add it as a (*next)
{
rootsfv->next=tempsfv;
rootsfv=rootsfv->next;
}
}
SFVNbFiles++; // File counter
tempsfv=NULL;
}
else // If we couldn't read an entry, we can free the memory
{
free(tempsfv);
tempsfv=NULL;
}
}
}
}
fclose(fp);
if(SFVNbFiles!=SFVNbFileChecked)
{
sprintf(sfvline,"%s%dF-%d%%%s",INFODIRTAG_BEGIN,SFVNbFileChecked,(int)(((double)SFVNbFileChecked/(double)SFVNbFiles)*100),INFODIRTAG_END);
mkdir(sfvline,S_IWUSR);
CreateMissingFiles();
}
else{
sprintf(sfvline,"%s%dF-Done!%s",INFODIRTAG_BEGIN,SFVNbFileChecked,INFODIRTAG_END);
mkdir(sfvline,S_IWUSR);
}

#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV]%s created",sfvline);
pr_response_add(R_212, "[DEBUG_MOD_SFV]%d files in SFV",SFVNbFiles);
pr_response_add(R_212, "[DEBUG_MOD_SFV]%d files already upped",SFVNbFileChecked);
#endif

return;

}
/*
* CheckSFV()
* ----------
* DESCRIPTION:
* Checks the first .SFV file found in CWD & check if an uploaded file is good
* IN:
* cmd(cmd_rec*)=[look at ProFTPd Dev.Guide for more infos]
* OUT:
* MODRET=[look at ProFTPd Dev.Guide for more infos]
*/
MODRET CheckSFV(cmd_rec *cmd)
{
struct SFVEntry *tempnext=NULL,*tempprevious=NULL;
char missing[MAX_FNAME];
unsigned int fnlength=0;

DeleteINFODIR(cmd);
#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV]Upped file is %s",session.xfer.filename);
#endif

// Check if we are uploading
if(session.xfer.filename!=NULL)
{
// We are uploading a whole directory (no LIST before STOR)
if(sfventry==NULL)
{
// Could this be a .SFV we are uploading ?
if((fnlength=strlen(session.xfer.filename))>4)
if(strncasecmp((session.xfer.filename)+strlen(session.xfer.filename)-4,".SFV",4)==0)
// Yes!
ParseSFV(session.xfer.filename);
}
// Delete INFO-DIR because we need to recreate it if anything has changed
tempnext=sfventry;
tempprevious=tempnext;
// For each entry in the sfv-entry list
while(tempnext)
{
// if the file we uploaded match an entry of the list
if(strncasecmp(tempnext->fname,session.xfer.filename,strlen(tempnext->fname))==0)
{
// Compute the CRC32 & compare it to the value in the .SFV
if(tempnext->crc==ComputeCRC(session.xfer.filename))
{
#ifdef DEBUG_MOD_SFV
pr_response_add(R_212, "[DEBUG_MOD_SFV]CRC matches for %s",session.xfer.filename);
#endif
// Delete [original_filename].missing file when the original is up
sprintf(missing,"%s.%s",tempnext->fname,MISSING_STRING);
unlink(missing);
// Delete from the sfv-entry list.
if(tempnext==sfventry) sfventry=tempnext->next;
else tempprevious->next=tempnext->next;
free(tempnext);
}
// If there was a problem during teh upload, delete the file.
else unlink(session.xfer.filename);
break;
}
else{
tempprevious=tempnext;
tempnext=tempnext->next;
}
}
}
// Else this is just a LIST
ParseSFV(NULL);

return DECLINED(cmd);
}
/*
* Commands handling table
*/
static cmdtable sfv_cmdtab[] = {
  { PRE_CMD, C_LIST, G_NONE, CheckSFV,  FALSE, FALSE },
  { POST_CMD, C_STOR, G_NONE, CheckSFV,  FALSE, FALSE },
  { POST_CMD, C_DELE, G_NONE, DeleteINFODIR,  FALSE, FALSE },
  { 0, NULL }
};
/*
* Module definition
*/
module sfv_module = {
  NULL, NULL,
  0x20,
  "sfv",
  NULL,
  sfv_cmdtab,
  NULL,
  NULL,
  NULL
};


mod_sfv.h
Code:

/*
* MOD_SFV.H v0.1 (oct.19 2003)
* Author : Kraklok (+TL)
*
* DESCRIPTION:
* Contains all the defines and other functions (ComputeCRC())
*
*/
/*
* INCLUDES
*/
#include <sys/vfs.h>
#include <sys/types.h>
#include <dirent.h>
/*
* DEFINES
*/
#define DEBUG_MOD_SFV 1 // Sets debugging on
#define MAX_FNAME 256 // Maximum filename length
#define MISSING_STRING "missing" // String to add at the end of missing files
#define INFODIRTAG_BEGIN "[MyServ]-" // Beginning tag for INFO-DIR
#define INFODIRTAG_END "-[MyServ]" // Ending tag for INFO-DIR
/*
* STRUCTURES
*/
/*
* struct SFVEntry
* ---------------
* DESCRIPTION:
* Describes an entry of the SFV file. All entries are linked.
*/
struct SFVEntry{
char fname[MAX_FNAME]; // Filename to check
unsigned long crc; // CRC32 associated with this file
struct SFVEntry *next; // pointer to next SFV entry
};
/*
* FUNCTIONS
*/
/*
* CRC()
* -----
* DESCRIPTION:
* Function used to compute CRC32 value.
* IN:
* crc(unsigned long)=CRC32 computed value
* localread(long)=numbre of bytes in *buffer
* buffer(char*)=pointer to content of file
* OUT:
* crc(long unsigned)=CRC32 computed value
*
*
* Ripped from TL's FTPSFV
* Thanks to TL (tl@bunker-werk.net)
* http://www.bunker-werk.net/proftpd/
*/
unsigned long CRC(unsigned long crc,long localread, char *buffer)
{
unsigned long CRCTABLE[]={0x00000000,0x77073096,0xee0e612c,0x990951ba,0x076dc419,0x706af48f,
0xe963a535,0x9e6495a3,0x0edb8832,0x79dcb8a4,0xe0d5e91e,0x97d2d988,
0x09b64c2b,0x7eb17cbd,0xe7b82d07,0x90bf1d91,0x1db71064,0x6ab020f2,
0xf3b97148,0x84be41de,0x1adad47d,0x6ddde4eb,0xf4d4b551,0x83d385c7,
0x136c9856,0x646ba8c0,0xfd62f97a,0x8a65c9ec,0x14015c4f,0x63066cd9,
0xfa0f3d63,0x8d080df5,0x3b6e20c8,0x4c69105e,0xd56041e4,0xa2677172,
0x3c03e4d1,0x4b04d447,0xd20d85fd,0xa50ab56b,0x35b5a8fa,0x42b2986c,
0xdbbbc9d6,0xacbcf940,0x32d86ce3,0x45df5c75,0xdcd60dcf,0xabd13d59,
0x26d930ac,0x51de003a,0xc8d75180,0xbfd06116,0x21b4f4b5,0x56b3c423,
0xcfba9599,0xb8bda50f,0x2802b89e,0x5f058808,0xc60cd9b2,0xb10be924,
0x2f6f7c87,0x58684c11,0xc1611dab,0xb6662d3d,0x76dc4190,0x01db7106,
0x98d220bc,0xefd5102a,0x71b18589,0x06b6b51f,0x9fbfe4a5,0xe8b8d433,
0x7807c9a2,0x0f00f934,0x9609a88e,0xe10e9818,0x7f6a0dbb,0x086d3d2d,
0x91646c97,0xe6635c01,0x6b6b51f4,0x1c6c6162,0x856530d8,0xf262004e,
0x6c0695ed,0x1b01a57b,0x8208f4c1,0xf50fc457,0x65b0d9c6,0x12b7e950,
0x8bbeb8ea,0xfcb9887c,0x62dd1ddf,0x15da2d49,0x8cd37cf3,0xfbd44c65,
0x4db26158,0x3ab551ce,0xa3bc0074,0xd4bb30e2,0x4adfa541,0x3dd895d7,
0xa4d1c46d,0xd3d6f4fb,0x4369e96a,0x346ed9fc,0xad678846,0xda60b8d0,
0x44042d73,0x33031de5,0xaa0a4c5f,0xdd0d7cc9,0x5005713c,0x270241aa,
0xbe0b1010,0xc90c2086,0x5768b525,0x206f85b3,0xb966d409,0xce61e49f,
0x5edef90e,0x29d9c998,0xb0d09822,0xc7d7a8b4,0x59b33d17,0x2eb40d81,
0xb7bd5c3b,0xc0ba6cad,0xedb88320,0x9abfb3b6,0x03b6e20c,0x74b1d29a,
0xead54739,0x9dd277af,0x04db2615,0x73dc1683,0xe3630b12,0x94643b84,
0x0d6d6a3e,0x7a6a5aa8,0xe40ecf0b,0x9309ff9d,0x0a00ae27,0x7d079eb1,
0xf00f9344,0x8708a3d2,0x1e01f268,0x6906c2fe,0xf762575d,0x806567cb,
0x196c3671,0x6e6b06e7,0xfed41b76,0x89d32be0,0x10da7a5a,0x67dd4acc,
0xf9b9df6f,0x8ebeeff9,0x17b7be43,0x60b08ed5,0xd6d6a3e8,0xa1d1937e,
0x38d8c2c4,0x4fdff252,0xd1bb67f1,0xa6bc5767,0x3fb506dd,0x48b2364b,
0xd80d2bda,0xaf0a1b4c,0x36034af6,0x41047a60,0xdf60efc3,0xa867df55,
0x316e8eef,0x4669be79,0xcb61b38c,0xbc66831a,0x256fd2a0,0x5268e236,
0xcc0c7795,0xbb0b4703,0x220216b9,0x5505262f,0xc5ba3bbe,0xb2bd0b28,
0x2bb45a92,0x5cb36a04,0xc2d7ffa7,0xb5d0cf31,0x2cd99e8b,0x5bdeae1d,
0x9b64c2b0,0xec63f226,0x756aa39c,0x026d930a,0x9c0906a9,0xeb0e363f,
0x72076785,0x05005713,0x95bf4a82,0xe2b87a14,0x7bb12bae,0x0cb61b38,
0x92d28e9b,0xe5d5be0d,0x7cdcefb7,0x0bdbdf21,0x86d3d2d4,0xf1d4e242,
0x68ddb3f8,0x1fda836e,0x81be16cd,0xf6b9265b,0x6fb077e1,0x18b74777,
0x88085ae6,0xff0f6a70,0x66063bca,0x11010b5c,0x8f659eff,0xf862ae69,
0x616bffd3,0x166ccf45,0xa00ae278,0xd70dd2ee,0x4e048354,0x3903b3c2,
0xa7672661,0xd06016f7,0x4969474d,0x3e6e77db,0xaed16a4a,0xd9d65adc,
0x40df0b66,0x37d83bf0,0xa9bcae53,0xdebb9ec5,0x47b2cf7f,0x30b5ffe9,
0xbdbdf21c,0xcabac28a,0x53b39330,0x24b4a3a6,0xbad03605,0xcdd70693,
0x54de5729,0x23d967bf,0xb3667a2e,0xc4614ab8,0x5d681b02,0x2a6f2b94,
0xb40bbe37,0xc30c8ea1,0x5a05df1b,0x2d02ef8d
};

do{
crc=((crc>>8)&0xFFFFFF)^CRCTABLE[(unsigned char)((crc & 0xff)^*buffer++)];
  }while(--localread);

  return crc;
}
/*
* ComputeCRC()
* ------------
* DESCRIPTION:
* Function used to compute CRC32 value, given a filename.
* IN:
* fname(char*)=pointer to the filename
* OUT:
* crc(long unsigned)=CRC32 computed value
*
*
* Ripped from TL's FTPSFV
* Thanks to TL (tl@bunker-werk.net)
* http://www.bunker-werk.net/proftpd/
*/
unsigned long ComputeCRC(char *fname)
{
/*
* Note: different buffer sizes may result in noticable
* different performance depending on system, so feel
* free to modify.
*/
#define BUFFERSIZE 65536*16

unsigned long crc=0xffffffff;
FILE *f=NULL;
long localread=0;
char buffer[BUFFERSIZE];

if((f=fopen(fname,"rb"))!= NULL)
{
while((localread=fread(buffer,1,BUFFERSIZE,f))>0)
            {
            crc=CRC(crc,localread,buffer);
            }
      fclose(f);
      crc=crc^0xffffffff;
    }
return crc;
}


(Thanks to TL for the SFV-Check code :wink:)
Gespeichert
Wörsty
Moderator
ProFTPD
*****
Offline Offline

Beiträge: 1602


50772603
Profil anzeigen WWW E-Mail
« Antwort #1 am: 21. Oktober 2003, 10:55:23 »

Zitat
Just tell me what you think of it, thanks

Sorry. I can't read c-Code :oops:

But it looks good  :roll: :wink:
Gespeichert

RedHat 8.0 (2.4er Kernel)
proftpd 1.2.10
-mod_sql_mysql
-mow_wrap
-mod_exec
-mod_ifsession[/size]
Kraklok
Gast
« Antwort #2 am: 21. Oktober 2003, 13:24:21 »

:lol:

Thank you anyway L&auml;chelnd
Gespeichert
TL
ProFTPD
*
Offline Offline

Beiträge: 97


Profil anzeigen WWW E-Mail
« Antwort #3 am: 21. Oktober 2003, 21:49:12 »

hmm, I haven't yet looked closely to the code, but it REALLY consumes VERY MUCH cpu-time...
Also a few logical bugs seem to be in the code.
What do you mean by " It would be nice to see a real good SFV-Checker." ?  :?:
Do you think ftpsfv is bad or need some enhancements? If you think so, just drop a mail or write your opinion here in the board, I will try to it better...  :wink:
Gespeichert
Kraklok
Gast
« Antwort #4 am: 22. Oktober 2003, 09:51:34 »

Hello TL!

I don't think FTPSFV is bad, it is a good piece of software but I don't like it  L&auml;chelnd

1- I don't like the ftpexecd daemon. I don't like having many processes running.
2- I don't like ftpsfvcheck.pl because I needed to install PERL (you will say I could have rewritten it :wink:)
3- I had to create a fifo-file (I don't like to mess my system with new files)
4- When I tried it, it checked the file with case-sensitivity and always failed (filename in lower case in .SFV et filename upped in uppercase). Maybe it is just a parameter to set but I didn't check...

Anyway, this an open-design and so it is good and I'm sure many people are happy with it. :wink:

I just would like to see FTPSFV to be more integrated to ProFPTd. :idea:
Gespeichert
TL
ProFTPD
*
Offline Offline

Beiträge: 97


Profil anzeigen WWW E-Mail
« Antwort #5 am: 22. Oktober 2003, 18:21:00 »

Ok, I see...
The problem with the case-sensitive filenames ist fixed in the current version... Zwinkernd
In my opinion it makes more sense to handle the .sfv checking asynchronly to the ftp-process, so the user/client can directly continue to work and has not to wait until the processing of the uploaded file has finished.  That was my main reason for doing the .sfv checking via an external daemon and not via a module...
If enough users are wanting ftpSFV integrated into proftpd, there will be a mod for proftpd...  :!:
Gespeichert
Seiten: [1]   Nach oben
  Drucken  
 
Gehe zu:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC Prüfe XHTML 1.0 Prüfe CSS
Seite erstellt in 0.076 Sekunden mit 20 Zugriffen.