mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2026-05-05 22:25:38 -04:00
508 lines
11 KiB
C
508 lines
11 KiB
C
/*
|
|
* Copyright (C) 2006 Nigel Horne <njh@bandsman.co.uk>
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*
|
|
* Unix/Linux compatibility for Windows
|
|
* Inspired by glib and the cygwin source code
|
|
* Tested under Microsoft Visual Studio 2005
|
|
*/
|
|
#include <windows.h>
|
|
|
|
#if HAVE_CONFIG_H
|
|
#include "clamav-config.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include "clamav.h"
|
|
#include "others.h"
|
|
|
|
#ifndef CL_DEBUG
|
|
#define NDEBUG /* map CLAMAV debug onto standard */
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <direct.h>
|
|
#include <io.h>
|
|
#include <pthread.h>
|
|
|
|
#ifdef USE_SYSLOG
|
|
#include <strsafe.h>
|
|
#include "syslog.h"
|
|
#endif
|
|
|
|
static const char *basename(const char *file_name);
|
|
|
|
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
|
#define _W32_FT_OFFSET (116444736000000000ULL)
|
|
|
|
/*
|
|
* Patches for 64 bit support in opendir by
|
|
* Mark Pizzolato clamav-win32@subscriptions.pizzolato.net
|
|
*/
|
|
DIR *
|
|
opendir(const char *dirname)
|
|
{
|
|
DIR *ret = cli_calloc(1, sizeof(DIR));
|
|
char mask[_MAX_PATH + 3];
|
|
size_t i, j;
|
|
|
|
if(ret == NULL)
|
|
return NULL;
|
|
|
|
/* struct _WIN32_FIND_DATAA is what a LPWIN32_FIND_DATA points to */
|
|
ret->find_file_data = cli_calloc(1, sizeof(struct _WIN32_FIND_DATAA));
|
|
|
|
if(ret->find_file_data == NULL) {
|
|
free(ret);
|
|
return NULL;
|
|
}
|
|
ret->dir_name = cli_strdup(dirname);
|
|
|
|
if(ret->dir_name == NULL) {
|
|
free(ret->find_file_data);
|
|
free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
j = strlen(dirname);
|
|
for(i = 0; i < j; i++)
|
|
if(ret->dir_name[i] == '/')
|
|
ret->dir_name[i] = '\\';
|
|
|
|
if(j && dirname[j - 1] == '\\')
|
|
ret->dir_name[--j] = '\0';
|
|
|
|
sprintf(mask, "%s\\*", ret->dir_name);
|
|
|
|
ret->find_file_handle = FindFirstFile(mask,
|
|
(LPWIN32_FIND_DATA)ret->find_file_data);
|
|
|
|
if(ret->find_file_handle == INVALID_HANDLE_VALUE) {
|
|
free(ret->find_file_data);
|
|
free(ret->dir_name);
|
|
free(ret);
|
|
|
|
cli_warnmsg("Can't opendir(%s)\n", dirname);
|
|
return NULL;
|
|
}
|
|
|
|
ret->just_opened = TRUE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct dirent *
|
|
readdir(DIR *dir)
|
|
{
|
|
/* NOTE: not thread safe */
|
|
static struct dirent result;
|
|
|
|
if(dir == NULL)
|
|
return NULL;
|
|
|
|
if(dir->just_opened)
|
|
dir->just_opened = FALSE;
|
|
else if(!FindNextFile((HANDLE)dir->find_file_handle, (LPWIN32_FIND_DATA)dir->find_file_data))
|
|
switch(GetLastError ()) {
|
|
case ERROR_NO_MORE_FILES:
|
|
return NULL;
|
|
default:
|
|
errno = EIO;
|
|
return NULL;
|
|
}
|
|
|
|
strcpy(result.d_name, basename(((LPWIN32_FIND_DATA)dir->find_file_data)->cFileName));
|
|
|
|
return &result;
|
|
}
|
|
|
|
int
|
|
readdir_r(DIR *dir, struct dirent *dirent, struct dirent **output)
|
|
{
|
|
if(dir == NULL)
|
|
return -1;
|
|
if(dirent == NULL)
|
|
return -1;
|
|
if(output == NULL)
|
|
return -1;
|
|
|
|
if(dir->just_opened)
|
|
dir->just_opened = FALSE;
|
|
else if(!FindNextFile((HANDLE)dir->find_file_handle, (LPWIN32_FIND_DATA)dir->find_file_data))
|
|
switch(GetLastError()) {
|
|
case ERROR_NO_MORE_FILES:
|
|
*output = NULL;
|
|
return -1;
|
|
default:
|
|
errno = EIO;
|
|
*output = NULL;
|
|
return -1;
|
|
}
|
|
|
|
strcpy(dirent->d_name, basename(((LPWIN32_FIND_DATA)dir->find_file_data)->cFileName));
|
|
*output = dirent;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
rewinddir(DIR *dir)
|
|
{
|
|
char mask[_MAX_PATH + 3];
|
|
|
|
if(dir == NULL)
|
|
return;
|
|
|
|
if(!FindClose((HANDLE)dir->find_file_handle))
|
|
cli_warnmsg("rewinddir(): FindClose() failed\n");
|
|
|
|
sprintf(mask, "%s\\*", dir->dir_name);
|
|
|
|
dir->find_file_handle = FindFirstFile (mask,
|
|
(LPWIN32_FIND_DATA)dir->find_file_data);
|
|
|
|
if(dir->find_file_handle == INVALID_HANDLE_VALUE) {
|
|
errno = EIO;
|
|
return;
|
|
}
|
|
dir->just_opened = TRUE;
|
|
}
|
|
|
|
int
|
|
closedir(DIR *dir)
|
|
{
|
|
if(dir == NULL)
|
|
return -1;
|
|
|
|
if(!FindClose((HANDLE)dir->find_file_handle)) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
free(dir->dir_name);
|
|
free(dir->find_file_data);
|
|
free(dir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const char *
|
|
basename(const char *file_name)
|
|
{
|
|
const char *base;
|
|
|
|
if(file_name == NULL)
|
|
return NULL;
|
|
|
|
base = strrchr(file_name, '\\');
|
|
|
|
if(base)
|
|
return base + 1;
|
|
|
|
if(isalpha(file_name[0] & 0xFF) && (file_name[1] == ':'))
|
|
return (const char *)(file_name + 2);
|
|
|
|
return file_name;
|
|
}
|
|
|
|
/* From the cygwin source code */
|
|
int
|
|
gettimeofday(struct timeval *tp, void *tz)
|
|
{
|
|
if(tp) {
|
|
union {
|
|
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
|
FILETIME ft;
|
|
} _now;
|
|
|
|
GetSystemTimeAsFileTime(&_now.ft);
|
|
tp->tv_usec = (long)((_now.ns100 / 10ULL) % 1000000ULL );
|
|
tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
|
|
}
|
|
/*
|
|
* Always return 0 as per Open Group Base Specifications Issue 6.
|
|
* Do not set errno on error.
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
/* TODO */
|
|
int
|
|
geteuid(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
getuid(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
getgid(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* mmap patches for more than one map area by
|
|
* Mark Pizzolato clamav-win32@subscriptions.pizzolato.net
|
|
*/
|
|
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static struct mmap_context {
|
|
struct mmap_context *link;
|
|
HANDLE h;
|
|
LPVOID view;
|
|
size_t length;
|
|
} *mmaps = NULL;
|
|
|
|
caddr_t
|
|
mmap(caddr_t address, size_t length, int protection, int flags, int fd, off_t offset)
|
|
{
|
|
LPVOID addr;
|
|
HANDLE h;
|
|
struct mmap_context *ctx;
|
|
|
|
if(flags != MAP_PRIVATE) {
|
|
cli_errmsg("mmap: only MAP_PRIVATE is supported\n");
|
|
return MAP_FAILED;
|
|
}
|
|
if(protection != PROT_READ) {
|
|
cli_errmsg("mmap: only PROT_READ is supported\n");
|
|
return MAP_FAILED;
|
|
}
|
|
if(address != NULL) {
|
|
cli_errmsg("mmap: only NULL map address is supported\n");
|
|
return MAP_FAILED;
|
|
}
|
|
h = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, PAGE_READONLY, 0, 0, NULL);
|
|
|
|
if(h == NULL) {
|
|
cli_errmsg("mmap: CreateFileMapping failed - error %d\n",
|
|
GetLastError());
|
|
return MAP_FAILED;
|
|
}
|
|
if(GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
cli_errmsg("mmap: ERROR_ALREADY_EXISTS\n");
|
|
CloseHandle(h);
|
|
return MAP_FAILED;
|
|
}
|
|
addr = MapViewOfFile(h, FILE_MAP_READ,
|
|
(DWORD)0, ((DWORD)offset & 0xFFFFFFFF),
|
|
length);
|
|
|
|
if(addr == NULL) {
|
|
cli_errmsg("mmap failed - error %d\n", GetLastError());
|
|
CloseHandle(h);
|
|
return MAP_FAILED;
|
|
}
|
|
pthread_mutex_lock(&mmap_mutex);
|
|
ctx = cli_malloc(sizeof(*ctx));
|
|
if(NULL == ctx) {
|
|
pthread_mutex_unlock(&mmap_mutex);
|
|
cli_errmsg("mmap: can't create context block\n");
|
|
UnmapViewOfFile(addr);
|
|
CloseHandle(h);
|
|
return MAP_FAILED;
|
|
}
|
|
ctx->h = h;
|
|
ctx->view = addr;
|
|
ctx->length = length;
|
|
ctx->link = mmaps;
|
|
mmaps = ctx;
|
|
pthread_mutex_unlock(&mmap_mutex);
|
|
return (caddr_t)addr;
|
|
}
|
|
|
|
int
|
|
munmap(caddr_t addr, size_t length)
|
|
{
|
|
struct mmap_context *ctx = mmaps, *lctx = NULL;
|
|
|
|
pthread_mutex_lock(&mmap_mutex);
|
|
|
|
for(; ctx && (ctx->view != addr); ctx = ctx->link)
|
|
lctx = ctx;
|
|
|
|
if(ctx == NULL) {
|
|
pthread_mutex_unlock(&mmap_mutex);
|
|
cli_warnmsg("munmap with no corresponding mmap\n");
|
|
return -1;
|
|
}
|
|
|
|
if(ctx->length != length) {
|
|
pthread_mutex_unlock(&mmap_mutex);
|
|
cli_warnmsg("munmap with incorrect length specified (%u != %u) - partial munmap unsupported\n",
|
|
length, ctx->length);
|
|
return -1;
|
|
}
|
|
|
|
if(lctx == NULL)
|
|
mmaps = ctx->link;
|
|
else
|
|
lctx->link = ctx->link;
|
|
|
|
pthread_mutex_unlock(&mmap_mutex);
|
|
|
|
UnmapViewOfFile(ctx->view);
|
|
CloseHandle(ctx->h);
|
|
free(ctx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
chown(const char *filename, short uid, short gid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef USE_SYSLOG
|
|
/*
|
|
* Put into the Windows Event Log
|
|
* Right Click My Computer->Manage->Event Viewer->Application
|
|
* See http://cybertiggyr.com/gene/wel/src/insert-log.c for inspiration
|
|
* http://msdn2.microsoft.com/en-gb/library/aa363634(VS.85).aspx
|
|
* and http://msdn2.microsoft.com/en-us/library/aa363680(VS.85).aspx
|
|
*
|
|
* FIXME: Not thread safe, but see shared/output.c, which ensures this code is
|
|
* single threaded - therefore don't call this code directly
|
|
*/
|
|
static HANDLE logg_handle;
|
|
static int initlog(const char *source);
|
|
|
|
void
|
|
openlog(const char *name, int options, int facility)
|
|
{
|
|
if(logg_handle != NULL)
|
|
closelog();
|
|
else
|
|
(void)initlog(name);
|
|
|
|
logg_handle = RegisterEventSource(NULL, name);
|
|
|
|
if(logg_handle == NULL)
|
|
cli_warnmsg("openlog: Can't register source %s - error %d\n", name, GetLastError());
|
|
}
|
|
|
|
void
|
|
closelog(void)
|
|
{
|
|
if(logg_handle != NULL)
|
|
DeregisterEventSource(logg_handle);
|
|
}
|
|
|
|
void
|
|
syslog(int level, const char *format, ...)
|
|
{
|
|
if(logg_handle == NULL)
|
|
openlog("Clam AntiVirus", 0, LOG_LOCAL6);
|
|
|
|
if(logg_handle != NULL) {
|
|
va_list args;
|
|
char buff[512];
|
|
char *ptr;
|
|
|
|
va_start(args, format);
|
|
(void)vsnprintf(buff, sizeof(buff), format, args);
|
|
va_end(args);
|
|
|
|
ptr = buff;
|
|
|
|
/*
|
|
* Category = 0, eventId = CLAMAV_EVENTMSG, SID = NULL, 1 string
|
|
*/
|
|
if(!ReportEventA(logg_handle, (WORD)level, 0, CLAMAV_EVENTMSG, NULL, 1, 0, (LPCSTR *)&ptr, NULL))
|
|
cli_warnmsg("syslog: ReportEventA(%d, %d, 0, %d, NULL, 1, 0, %s, NULL) failed: %d\n",
|
|
logg_handle, level, CLAMAV_EVENTMSG, buff, GetLastError());
|
|
}
|
|
}
|
|
|
|
static int
|
|
initlog(const char *source)
|
|
{
|
|
/*DWORD dwCategoryNum = 1; /* The number of categories for the event source. */
|
|
HKEY hk;
|
|
DWORD dwData, /*dwDisp,*/ len;
|
|
char path[MAX_PATH];
|
|
|
|
/* Create the event source as a subkey of the log. */
|
|
(void)snprintf(path, sizeof(path),
|
|
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
|
|
source);
|
|
|
|
if(RegCreateKey(HKEY_LOCAL_MACHINE, path, &hk) != 0) {
|
|
cli_warnmsg("Could not create the registry key\n");
|
|
/*return 0;*/
|
|
}
|
|
|
|
/* Set the name of the message file. */
|
|
GetModuleFileName(NULL, path, sizeof(path));
|
|
path[sizeof(path) - 1] = '\0';
|
|
len = (DWORD)(strlen(path) + 1);
|
|
|
|
if(RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE)path, len)) {
|
|
cli_warnmsg("Could not set the event message file\n");
|
|
RegCloseKey(hk);
|
|
return 0;
|
|
}
|
|
|
|
/* Set the supported event types. */
|
|
dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
|
|
|
|
if(RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD))) {
|
|
cli_warnmsg("Could not set the supported types\n");
|
|
RegCloseKey(hk);
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
/* Set the category message file and number of categories. */
|
|
if(RegSetValueEx(hk, "CategoryMessageFile", 0, REG_EXPAND_SZ,
|
|
(LPBYTE)path, len)) {
|
|
cli_warnmsg("Could not set the category message file\n");
|
|
RegCloseKey(hk);
|
|
return 0;
|
|
}
|
|
|
|
if(RegSetValueEx(hk, "CategoryCount", 0, REG_DWORD, (LPBYTE)&dwCategoryNum, sizeof(DWORD))) {
|
|
cli_warnmsg("Could not set the category count\n");
|
|
RegCloseKey(hk);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
RegCloseKey(hk);
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
int
|
|
snprintf(char *str, size_t size, const char *format, ...)
|
|
{
|
|
int ret;
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
ret = _vsnprintf_s(str, size, _TRUNCATE, format, args);
|
|
va_end(args);
|
|
return ret;
|
|
} |