mirror of https://github.com/Cisco-Talos/clamav
parent
9e7b0c12db
commit
8139fd99cb
@ -0,0 +1,314 @@ |
||||
/*
|
||||
* Copyright (C) 2003 Tomasz Kojm <zolw@konarski.edu.pl> |
||||
* |
||||
* untgz() is based on public domain minitar utility by Charles G. Waldman |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||||
*/ |
||||
|
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <zlib.h> |
||||
|
||||
#include "clamav.h" |
||||
|
||||
#define TAR_BLOCKSIZE 512 |
||||
|
||||
int cli_untgz(int fd, const char *destdir) |
||||
{ |
||||
char *fullname, osize[13], name[101], type; |
||||
char block[TAR_BLOCKSIZE]; |
||||
int nbytes, nread, nwritten, in_block = 0; |
||||
unsigned int size; |
||||
FILE *outfile = NULL; |
||||
gzFile *infile; |
||||
|
||||
cli_dbgmsg("in cli_untgz()\n"); |
||||
|
||||
if((infile = gzdopen(fd, "rb")) == NULL) { |
||||
cli_errmsg("Can't gzdopen() descriptor %d\n", fd); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
fullname = (char *) calloc(sizeof(char), strlen(destdir) + 100 + 5); |
||||
|
||||
while(1) { |
||||
|
||||
nread = gzread(infile, block, TAR_BLOCKSIZE); |
||||
|
||||
if(!in_block && nread == 0) |
||||
break; |
||||
|
||||
if(nread != TAR_BLOCKSIZE) { |
||||
cli_errmsg("Incomplete block read.\n"); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
|
||||
if(!in_block) { |
||||
if (block[0] == '\0') /* We're done */ |
||||
break; |
||||
|
||||
strncpy(name, block, 100); |
||||
name[100] = '\0'; |
||||
strcpy(fullname, destdir); |
||||
strcat(fullname, "/"); |
||||
strcat(fullname, name); |
||||
cli_dbgmsg("Unpacking %s\n",fullname); |
||||
type = block[156]; |
||||
|
||||
switch(type) { |
||||
case '0': |
||||
case '\0': |
||||
break; |
||||
case '5': |
||||
cli_errmsg("Directories in CVD are not supported.\n"); |
||||
free(fullname); |
||||
return -1; |
||||
default: |
||||
cli_errmsg("Unknown type flag %c.\n",type); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
|
||||
in_block = 1; |
||||
|
||||
if(outfile) { |
||||
if(fclose(outfile)) { |
||||
cli_errmsg("Cannot close file %s.\n", fullname); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
outfile = NULL; |
||||
} |
||||
|
||||
if(!(outfile = fopen(fullname, "wb"))) { |
||||
cli_errmsg("Cannot create file %s.\n", fullname); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
|
||||
strncpy(osize, block + 124, 12); |
||||
osize[12] = '\0'; |
||||
size = -1; |
||||
sscanf(osize, "%o", &size); |
||||
|
||||
if(size < 0) { |
||||
cli_errmsg("Invalid size in header.\n"); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
|
||||
} else { /* write or continue writing file contents */ |
||||
nbytes = size > TAR_BLOCKSIZE ? TAR_BLOCKSIZE : size; |
||||
nwritten = fwrite(block, 1, nbytes, outfile); |
||||
|
||||
if(nwritten != nbytes) { |
||||
cli_errmsg("Wrote %d instead of %d (%s).\n", nwritten, nbytes, fullname); |
||||
free(fullname); |
||||
return -1; |
||||
} |
||||
|
||||
size -= nbytes; |
||||
if(size == 0) |
||||
in_block = 0; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
char *cli_cut(const char *line, int field) |
||||
{ |
||||
int length, counter = 0, i, j = 0, k; |
||||
char *buffer; |
||||
|
||||
length = strlen(line); |
||||
buffer = (char *) cli_calloc(length, sizeof(char)); |
||||
|
||||
for(i = 0; i < length; i++) { |
||||
if(line[i] == ':') { |
||||
counter++; |
||||
if(counter == field) { |
||||
break; |
||||
} else { |
||||
memset(buffer, 0, length); |
||||
j = 0; |
||||
} |
||||
} else { |
||||
buffer[j++] = line[i]; |
||||
} |
||||
} |
||||
|
||||
return (char *) cli_realloc(buffer, strlen(buffer) + 1); |
||||
} |
||||
|
||||
struct cl_cvd *cli_cvdhead(const char *head) |
||||
{ |
||||
char *pt; |
||||
struct cl_cvd *cvd; |
||||
|
||||
cvd = (struct cl_cvd *) cli_calloc(1, sizeof(struct cl_cvd)); |
||||
cvd->time = cli_cut(head, 2); |
||||
|
||||
pt = cli_cut(head, 3); |
||||
cvd->version = atoi(pt); |
||||
free(pt); |
||||
|
||||
pt = cli_cut(head, 4); |
||||
cvd->sigs = atoi(pt); |
||||
free(pt); |
||||
|
||||
pt = cli_cut(head, 5); |
||||
cvd->fl = (short int) atoi(pt); |
||||
free(pt); |
||||
|
||||
cvd->md5 = cli_cut(head, 6); |
||||
cvd->dsig = cli_cut(head, 7); |
||||
cvd->builder = cli_cut(head, 8); |
||||
|
||||
return cvd; |
||||
} |
||||
|
||||
struct cl_cvd *cl_cvdhead(const char *file) |
||||
{ |
||||
char head[257]; |
||||
FILE *fd; |
||||
int i; |
||||
|
||||
|
||||
if((fd = fopen(file, "rb")) == NULL) { |
||||
cli_errmsg("Can't open CVD file %s\n", file); |
||||
return NULL; |
||||
} |
||||
|
||||
if(fread(head, 1, 256, fd) != 256) { |
||||
cli_errmsg("Can't read CVD head from %s\n", file); |
||||
return NULL; |
||||
} |
||||
head[256] = 0; |
||||
|
||||
for(i = 255; i > 0 && !isalnum(head[i]); head[i] = 0, i--); |
||||
|
||||
if(strncmp(head, "ClamAV-VDB:", 11)) { |
||||
cli_errmsg("%s is not a CVD file.\n"); |
||||
return NULL; |
||||
} |
||||
|
||||
return cli_cvdhead(head); |
||||
} |
||||
|
||||
void cl_cvdfree(struct cl_cvd *cvd) |
||||
{ |
||||
free(cvd->time); |
||||
free(cvd->md5); |
||||
free(cvd->dsig); |
||||
free(cvd->builder); |
||||
free(cvd); |
||||
} |
||||
|
||||
int cli_cvdload(FILE *fd, struct cl_node **root, int *virnum) |
||||
{ |
||||
char head[257], *dir, *tmp, buffer[BUFFSIZE]; |
||||
int bytes; |
||||
struct cl_cvd *cvd; |
||||
const char *tmpdir; |
||||
FILE *tmpd; |
||||
|
||||
cli_dbgmsg("in cli_cvdload()\n"); |
||||
|
||||
if(fread(head, 1, 256, fd) != 256) { |
||||
cli_errmsg("Can't read CVD head.\n"); |
||||
return -1; |
||||
} |
||||
head[256] = 0; |
||||
|
||||
cvd = cli_cvdhead(head); |
||||
|
||||
/* verify md5/dsig */ |
||||
|
||||
|
||||
/* unpack */ |
||||
|
||||
tmpdir = getenv("TMPDIR"); |
||||
|
||||
if(tmpdir == NULL) |
||||
#ifdef P_tmpdir |
||||
tmpdir = P_tmpdir; |
||||
#else |
||||
tmpdir = "/tmp"; |
||||
#endif |
||||
|
||||
dir = cl_gentemp(tmpdir); |
||||
if(mkdir(dir, 0700)) { |
||||
cli_errmsg("cli_cvdload(): Can't create temporary directory %s\n", dir); |
||||
return CL_ETMPDIR; |
||||
} |
||||
|
||||
/*
|
||||
if(cli_untgz(fileno(fd), dir)) { |
||||
cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); |
||||
return CL_ECVDEXTR; |
||||
} |
||||
*/ |
||||
|
||||
/* FIXME: it seems there is some problem with current position after
|
||||
* gzdopen() in cli_untgz(). Temporarily we need this wrapper: |
||||
*/ |
||||
|
||||
/* start */ |
||||
|
||||
tmp = cl_gentemp(tmpdir); |
||||
if((tmpd = fopen(tmp, "wb+")) == NULL) { |
||||
cli_errmsg("Can't create temporary file %s\n", tmp); |
||||
free(dir); |
||||
free(tmp); |
||||
return -1; |
||||
} |
||||
while((bytes = fread(buffer, 1, BUFFSIZE, fd)) > 0) |
||||
fwrite(buffer, 1, bytes, tmpd); |
||||
|
||||
fflush(tmpd); |
||||
fseek(tmpd, 0L, SEEK_SET); |
||||
|
||||
if(cli_untgz(fileno(tmpd), dir)) { |
||||
cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); |
||||
cli_rmdirs(dir); |
||||
free(dir); |
||||
unlink(tmp); |
||||
free(tmp); |
||||
return CL_ECVDEXTR; |
||||
} |
||||
|
||||
fclose(tmpd); |
||||
unlink(tmp); |
||||
free(tmp); |
||||
|
||||
/* end */ |
||||
|
||||
/* load extracted directory */ |
||||
cl_loaddbdir(dir, root, virnum); |
||||
|
||||
cli_rmdirs(dir); |
||||
free(dir); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue