diff --git a/clamav-devel/ChangeLog b/clamav-devel/ChangeLog index 1bfd9fc05..507bf8a07 100644 --- a/clamav-devel/ChangeLog +++ b/clamav-devel/ChangeLog @@ -1,3 +1,7 @@ +Tue Mar 22 22:22:30 CET 2005 (tk) +--------------------------------- + * libclamav: add support for old fashioned tar archives + Tue Mar 22 11:27:58 GMT 2005 (njh) ---------------------------------- * libclamav/mbox.c: Not all Worm.Bagle.AC were being caught diff --git a/clamav-devel/libclamav/Makefile.am b/clamav-devel/libclamav/Makefile.am index da40a6eb9..5bce0828c 100644 --- a/clamav-devel/libclamav/Makefile.am +++ b/clamav-devel/libclamav/Makefile.am @@ -120,6 +120,8 @@ libclamav_la_SOURCES = \ special.c \ special.h \ binhex.c \ - binhex.h + binhex.h \ + is_tar.c \ + is_tar.h lib_LTLIBRARIES = libclamav.la diff --git a/clamav-devel/libclamav/Makefile.in b/clamav-devel/libclamav/Makefile.in index d392f29df..ce9acc343 100644 --- a/clamav-devel/libclamav/Makefile.in +++ b/clamav-devel/libclamav/Makefile.in @@ -80,7 +80,7 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \ text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \ cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \ chmunpack.lo rebuildpe.lo petite.lo fsg.lo line.lo untar.lo \ - special.lo binhex.lo + special.lo binhex.lo is_tar.lo libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -89,8 +89,9 @@ am__depfiles_maybe = depfiles @AMDEP_TRUE@ ./$(DEPDIR)/cabd.Plo ./$(DEPDIR)/chmunpack.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/cvd.Plo ./$(DEPDIR)/dsig.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/filetypes.Plo ./$(DEPDIR)/fsg.Plo \ -@AMDEP_TRUE@ ./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/line.Plo \ -@AMDEP_TRUE@ ./$(DEPDIR)/lzxd.Plo ./$(DEPDIR)/matcher-ac.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/htmlnorm.Plo ./$(DEPDIR)/is_tar.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/line.Plo ./$(DEPDIR)/lzxd.Plo \ +@AMDEP_TRUE@ ./$(DEPDIR)/matcher-ac.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/matcher-bm.Plo ./$(DEPDIR)/matcher.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/mbox.Plo ./$(DEPDIR)/md5.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/message.Plo ./$(DEPDIR)/msexpand.Plo \ @@ -331,7 +332,9 @@ libclamav_la_SOURCES = \ special.c \ special.h \ binhex.c \ - binhex.h + binhex.h \ + is_tar.c \ + is_tar.h lib_LTLIBRARIES = libclamav.la all: all-am @@ -412,6 +415,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filetypes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/htmlnorm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/is_tar.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/line.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzxd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matcher-ac.Plo@am__quote@ diff --git a/clamav-devel/libclamav/filetypes.c b/clamav-devel/libclamav/filetypes.c index 0c96e6c39..4d7991f35 100644 --- a/clamav-devel/libclamav/filetypes.c +++ b/clamav-devel/libclamav/filetypes.c @@ -61,7 +61,6 @@ static const struct cli_magic_s cli_magic[] = { {0, "SZDD", 4, "compress.exe'd", CL_TYPE_MSSZDD}, {0, "MSCF", 4, "MS CAB", CL_TYPE_MSCAB}, {0, "ITSF", 4, "MS CHM", CL_TYPE_MSCHM}, - {257, "ustar", 5, "POSIX tar", CL_TYPE_TAR}, {0, "#@~^", 4, "SCRENC", CL_TYPE_SCRENC}, {0, "(This file must be converted with BinHex 4.0)", 45, "BinHex", CL_TYPE_BINHEX}, @@ -197,6 +196,48 @@ cli_file_t cli_filetype(const char *buf, size_t buflen) return ascii ? CL_TYPE_UNKNOWN_TEXT : CL_TYPE_UNKNOWN_DATA; } +int is_tar(unsigned char *buf, int nbytes); + +cli_file_t cli_filetype2(int desc) +{ + char smallbuff[MAGIC_BUFFER_SIZE + 1]; + unsigned char *bigbuff; + int bread; + cli_file_t ret = CL_TYPE_UNKNOWN_DATA; + + + memset(smallbuff, 0, sizeof(smallbuff)); + if((bread = read(desc, smallbuff, MAGIC_BUFFER_SIZE)) > 0) + ret = cli_filetype(smallbuff, bread); + + if(ret == CL_TYPE_UNKNOWN_DATA || ret == CL_TYPE_UNKNOWN_TEXT) { + + if(!(bigbuff = (unsigned char *) cli_calloc(16384 + 1, sizeof(unsigned char)))) + return ret; + + lseek(desc, 0, SEEK_SET); + if((bread = read(desc, bigbuff, 16384)) > 0) { + + bigbuff[bread] = 0; + + switch(is_tar(bigbuff, bread)) { + case 1: + ret = CL_TYPE_OLD_TAR; + cli_dbgmsg("Recognized old fashioned tar file\n"); + break; + case 2: + ret = CL_TYPE_POSIX_TAR; + cli_dbgmsg("Recognized POSIX tar file\n"); + break; + } + } + + free(bigbuff); + } + + return ret; +} + int cli_addtypesigs(struct cl_node *root) { int i, ret; diff --git a/clamav-devel/libclamav/filetypes.h b/clamav-devel/libclamav/filetypes.h index 602cbd59c..a03c16558 100644 --- a/clamav-devel/libclamav/filetypes.h +++ b/clamav-devel/libclamav/filetypes.h @@ -20,7 +20,7 @@ #ifndef __FILETYPES_H #define __FILETYPES_H -#define MAGIC_BUFFER_SIZE 262 +#define MAGIC_BUFFER_SIZE 50 #define CL_TYPENO 500 typedef enum { @@ -28,7 +28,8 @@ typedef enum { CL_TYPE_UNKNOWN_DATA, CL_TYPE_MSEXE, CL_TYPE_DATA, - CL_TYPE_TAR, + CL_TYPE_POSIX_TAR, + CL_TYPE_OLD_TAR, CL_TYPE_GZ, CL_TYPE_ZIP, CL_TYPE_BZ, @@ -49,6 +50,7 @@ typedef enum { } cli_file_t; cli_file_t cli_filetype(const char *buf, size_t buflen); +cli_file_t cli_filetype2(int desc); int cli_addtypesigs(struct cl_node *root); #endif diff --git a/clamav-devel/libclamav/is_tar.c b/clamav-devel/libclamav/is_tar.c new file mode 100644 index 000000000..eb357594d --- /dev/null +++ b/clamav-devel/libclamav/is_tar.c @@ -0,0 +1,97 @@ +/* + * is_tar() -- figure out whether file is a tar archive. + * + * Stolen (by the author of the file utility!) from the public domain tar program: + * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu). + * + * @(#)list.c 1.18 9/23/86 Public Domain - gnu + * $Id: is_tar.c,v 1.1 2005/03/22 21:26:25 kojm Exp $ + * + * Comments changed and some code/comments reformatted + * for file command by Ian Darwin. + */ + +#if HAVE_CONFIG_H +#include "clamav-config.h" +#endif + +#include +#include +#include +#include "is_tar.h" + +#include "others.h" + +#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') ) + +static int from_oct(int digs, char *where); + +/* + * Return + * 0 if the checksum is bad (i.e., probably not a tar archive), + * 1 for old UNIX tar file, + * 2 for Unix Std (POSIX) tar file. + */ +int is_tar(unsigned char *buf, int nbytes) +{ + union record *header = (union record *)buf; + int i; + int sum, recsum; + char *p; + + + if (nbytes < sizeof(union record)) + return 0; + + recsum = from_oct(8, header->header.chksum); + + sum = 0; + p = header->charptr; + for (i = sizeof(union record); --i >= 0;) { + /* + * We can't use unsigned char here because of old compilers, + * e.g. V7. + */ + sum += 0xFF & *p++; + } + + /* Adjust checksum to count the "chksum" field as blanks. */ + for (i = sizeof(header->header.chksum); --i >= 0;) + sum -= 0xFF & header->header.chksum[i]; + sum += ' '* sizeof header->header.chksum; + + if (sum != recsum) + return 0; /* Not a tar archive */ + + if (0==strcmp(header->header.magic, TMAGIC)) + return 2; /* Unix Standard tar archive */ + + return 1; /* Old fashioned tar archive */ +} + + +/* + * Quick and dirty octal conversion. + * + * Result is -1 if the field is invalid (all blank, or nonoctal). + */ +static int from_oct(int digs, char *where) +{ + int value; + + while (isspace((unsigned char)*where)) { /* Skip spaces */ + where++; + if (--digs <= 0) + return -1; /* All blank field */ + } + value = 0; + while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ + value = (value << 3) | (*where++ - '0'); + --digs; + } + + if (digs > 0 && *where && !isspace((unsigned char)*where)) + return -1; /* Ended on non-space/nul */ + + return value; +} diff --git a/clamav-devel/libclamav/is_tar.h b/clamav-devel/libclamav/is_tar.h new file mode 100644 index 000000000..d52555bfd --- /dev/null +++ b/clamav-devel/libclamav/is_tar.h @@ -0,0 +1,45 @@ +/* + * Header file for public domain tar (tape archive) program. + * + * @(#)tar.h 1.20 86/10/29 Public Domain. + * + * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu. + * + * $Id: is_tar.h,v 1.1 2005/03/22 21:26:25 kojm Exp $ # checkin only + */ + +/* + * Header block on tape. + * + * I'm going to use traditional DP naming conventions here. + * A "block" is a big chunk of stuff that we do I/O on. + * A "record" is a piece of info that we care about. + * Typically many "record"s fit into a "block". + */ +#define RECORDSIZE 512 +#define NAMSIZ 100 +#define TUNMLEN 32 +#define TGNMLEN 32 + +union record { + char charptr[RECORDSIZE]; + struct header { + char name[NAMSIZ]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char linkflag; + char linkname[NAMSIZ]; + char magic[8]; + char uname[TUNMLEN]; + char gname[TGNMLEN]; + char devmajor[8]; + char devminor[8]; + } header; +}; + +/* The magic field is filled with this if uname and gname are valid. */ +#define TMAGIC "ustar " /* 7 chars and a null */ diff --git a/clamav-devel/libclamav/scanners.c b/clamav-devel/libclamav/scanners.c index cf8465d4e..b57a783d3 100644 --- a/clamav-devel/libclamav/scanners.c +++ b/clamav-devel/libclamav/scanners.c @@ -23,9 +23,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -1126,7 +1126,7 @@ static int cli_scanole2(int desc, const char **virname, long int *scanned, const return ret; } -static int cli_scantar(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec) +static int cli_scantar(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec, unsigned int posix) { char *dir; int ret = CL_CLEAN; @@ -1141,7 +1141,7 @@ static int cli_scantar(int desc, const char **virname, long int *scanned, const return CL_ETMPDIR; } - if((ret = cli_untar(dir, desc))) + if((ret = cli_untar(dir, desc, posix))) cli_dbgmsg("Tar: %s\n", cl_strerror(ret)); else ret = cli_scandir(dir, virname, scanned, root, limits, options, arec, mrec); @@ -1289,11 +1289,21 @@ static int cli_scanmail(int desc, const char **virname, long int *scanned, const int cli_magic_scandesc(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec) { - char magic[MAGIC_BUFFER_SIZE + 1]; int ret = CL_CLEAN, nret; int bread = 0; cli_file_t type; + struct stat sb; + + + if(fstat(desc, &sb) == -1) { + cli_errmsg("Can's fstat descriptor %d\n", desc); + return CL_EIO; + } + if(sb.st_size <= 5) { + cli_dbgmsg("Small data (%d bytes)\n", sb.st_size); + return CL_CLEAN; + } if(!root) { cli_errmsg("CRITICAL: root == NULL\n"); @@ -1325,18 +1335,8 @@ int cli_magic_scandesc(int desc, const char **virname, long int *scanned, const } lseek(desc, 0, SEEK_SET); - memset(magic, 0, sizeof(magic)); - - if((bread = read(desc, magic, MAGIC_BUFFER_SIZE)) == -1) { - cli_dbgmsg("Can't read from descriptor %d\n"); - return CL_EIO; - } else if(bread < 2) { - /* short read - no need to do magic */ - return CL_CLEAN; - } - + type = cli_filetype2(desc); lseek(desc, 0, SEEK_SET); - type = cli_filetype(magic, bread); type == CL_TYPE_MAIL ? mrec++ : arec++; @@ -1388,9 +1388,14 @@ int cli_magic_scandesc(int desc, const char **virname, long int *scanned, const ret = cli_scanole2(desc, virname, scanned, root, limits, options, arec, mrec); break; - case CL_TYPE_TAR: + case CL_TYPE_POSIX_TAR: + if(SCAN_ARCHIVE) + ret = cli_scantar(desc, virname, scanned, root, limits, options, arec, mrec, 1); + break; + + case CL_TYPE_OLD_TAR: if(SCAN_ARCHIVE) - ret = cli_scantar(desc, virname, scanned, root, limits, options, arec, mrec); + ret = cli_scantar(desc, virname, scanned, root, limits, options, arec, mrec, 0); break; case CL_TYPE_BINHEX: diff --git a/clamav-devel/libclamav/untar.c b/clamav-devel/libclamav/untar.c index c366264ae..2fc00b804 100644 --- a/clamav-devel/libclamav/untar.c +++ b/clamav-devel/libclamav/untar.c @@ -21,6 +21,9 @@ * * Change History: * $Log: untar.c,v $ + * Revision 1.25 2005/03/22 21:26:27 kojm + * add support for old fashioned tar archives + * * Revision 1.24 2005/03/20 18:34:18 nigelhorne * Minor tidy * @@ -94,7 +97,7 @@ * First draft * */ -static char const rcsid[] = "$Id: untar.c,v 1.24 2005/03/20 18:34:18 nigelhorne Exp $"; +static char const rcsid[] = "$Id: untar.c,v 1.25 2005/03/22 21:26:27 kojm Exp $"; #include #include @@ -126,7 +129,7 @@ octal(const char *str) } int -cli_untar(const char *dir, int desc) +cli_untar(const char *dir, int desc, unsigned int posix) { int size = 0; int in_block = 0; @@ -169,11 +172,13 @@ cli_untar(const char *dir, int desc) break; /* Notice assumption that BLOCKSIZE > 262 */ - strncpy(magic, block+257, 5); - magic[5] = '\0'; - if(strcmp(magic, "ustar") != 0) { - cli_dbgmsg("Incorrect magic string '%s' in tar header\n", magic); - return CL_EFORMAT; + if(posix) { + strncpy(magic, block+257, 5); + magic[5] = '\0'; + if(strcmp(magic, "ustar") != 0) { + cli_dbgmsg("Incorrect magic string '%s' in tar header\n", magic); + return CL_EFORMAT; + } } type = block[156]; diff --git a/clamav-devel/libclamav/untar.h b/clamav-devel/libclamav/untar.h index 421692920..a705b4433 100644 --- a/clamav-devel/libclamav/untar.h +++ b/clamav-devel/libclamav/untar.h @@ -17,6 +17,9 @@ * * Change History: * $Log: untar.h,v $ + * Revision 1.3 2005/03/22 21:26:27 kojm + * add support for old fashioned tar archives + * * Revision 1.2 2004/09/05 18:58:22 nigelhorne * Extract files completed * @@ -24,4 +27,4 @@ * First draft * */ -int cli_untar(const char *dir, int desc); +int cli_untar(const char *dir, int desc, unsigned int posix);