ClamAV is an open source (GPLv2) anti-virus toolkit.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
clamav/libclamav/others_common.c

919 lines
22 KiB

/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
*
* Authors: Tomasz Kojm, Trog
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
16 years ago
#include <dirent.h>
#ifndef _WIN32
#include <sys/wait.h>
#include <sys/time.h>
#endif
#include <time.h>
#include <fcntl.h>
16 years ago
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#include <errno.h>
#include "target.h"
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "clamav.h"
#include "others.h"
#include "md5.h"
#include "cltypes.h"
#include "regex/regex.h"
#include "ltdl.h"
#include "matcher-ac.h"
#include "md5.h"
static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253 };
#ifdef CL_NOTHREADS
#undef CL_THREAD_SAFE
#endif
#ifdef CL_THREAD_SAFE
# include <pthread.h>
static pthread_mutex_t cli_gentemp_mutex = PTHREAD_MUTEX_INITIALIZER;
# ifndef HAVE_CTIME_R
static pthread_mutex_t cli_ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
# endif
static pthread_mutex_t cli_strerror_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t cli_ctx_tls_key;
static pthread_once_t cli_ctx_tls_key_once = PTHREAD_ONCE_INIT;
static void cli_ctx_tls_key_alloc(void)
{
pthread_key_create(&cli_ctx_tls_key, NULL);
}
void cli_logg_setup(const cli_ctx *ctx)
{
pthread_once(&cli_ctx_tls_key_once, cli_ctx_tls_key_alloc);
pthread_setspecific(cli_ctx_tls_key, ctx);
}
void cli_logg_unsetup(void)
{
pthread_setspecific(cli_ctx_tls_key, NULL);
}
static inline void *cli_getctx(void)
{
cli_ctx *ctx = pthread_getspecific(cli_ctx_tls_key);
return ctx ? ctx->cb_ctx : NULL;
}
#else
static const cli_ctx *current_ctx = NULL;
void cli_logg_setup(const cli_ctx *ctx)
{
current_ctx = ctx;
}
static inline void *cli_getctx(void)
{
return current_ctx ? current_ctx->cb_ctx : NULL;
}
#endif
uint8_t cli_debug_flag = 0;
static void fputs_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *context)
{
fputs(fullmsg, stderr);
}
static clcb_msg msg_callback = fputs_callback;
void cl_set_clcb_msg(clcb_msg callback)
{
msg_callback = callback;
}
#define MSGCODE(buff, len, x) \
va_list args; \
int len = sizeof(x) - 1; \
char buff[BUFSIZ]; \
strncpy(buff, x, len); \
va_start(args, str); \
vsnprintf(buff + len, sizeof(buff) - len, str, args); \
buff[sizeof(buff) - 1] = '\0'; \
va_end(args)
void cli_warnmsg(const char *str, ...)
{
MSGCODE(buff, len, "LibClamAV Warning: ");
msg_callback(CL_MSG_WARN, buff, buff+len, cli_getctx());
}
void cli_errmsg(const char *str, ...)
{
MSGCODE(buff, len, "LibClamAV Error: ");
msg_callback(CL_MSG_ERROR, buff, buff+len, cli_getctx());
}
void cli_infomsg(const cli_ctx* ctx, const char *str, ...)
{
MSGCODE(buff, len, "LibClamAV info: ");
msg_callback(CL_MSG_INFO_VERBOSE, buff, buff+len, ctx ? ctx->cb_ctx : NULL);
}
void cli_dbgmsg_internal(const char *str, ...)
{
MSGCODE(buff, len, "LibClamAV debug: ");
fputs(buff, stderr);
}
int cli_matchregex(const char *str, const char *regex)
{
regex_t reg;
16 years ago
int match, flags = REG_EXTENDED | REG_NOSUB;
#ifdef _WIN32
flags |= REG_ICASE;
#endif
if(cli_regcomp(&reg, regex, flags) == 0) {
match = (cli_regexec(&reg, str, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
cli_regfree(&reg);
return match;
}
return 0;
}
void *cli_malloc(size_t size)
{
void *alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
cli_errmsg("cli_malloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
return NULL;
}
alloc = malloc(size);
if(!alloc) {
cli_errmsg("cli_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) size);
perror("malloc_problem");
return NULL;
} else return alloc;
}
void *cli_calloc(size_t nmemb, size_t size)
{
void *alloc;
if(!nmemb || !size || size > CLI_MAX_ALLOCATION || nmemb > CLI_MAX_ALLOCATION
|| (nmemb*size > CLI_MAX_ALLOCATION)) {
cli_errmsg("cli_calloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) nmemb*size);
return NULL;
}
alloc = calloc(nmemb, size);
if(!alloc) {
cli_errmsg("cli_calloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) (nmemb * size));
perror("calloc_problem");
return NULL;
} else return alloc;
}
void *cli_realloc(void *ptr, size_t size)
{
void *alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
cli_errmsg("cli_realloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
return NULL;
}
alloc = realloc(ptr, size);
if(!alloc) {
cli_errmsg("cli_realloc(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
perror("realloc_problem");
return NULL;
} else return alloc;
}
void *cli_realloc2(void *ptr, size_t size)
{
void *alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
cli_errmsg("cli_realloc2(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
return NULL;
}
alloc = realloc(ptr, size);
if(!alloc) {
cli_errmsg("cli_realloc2(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
perror("realloc_problem");
if(ptr)
free(ptr);
return NULL;
} else return alloc;
}
char *cli_strdup(const char *s)
{
char *alloc;
if(s == NULL) {
cli_errmsg("cli_strdup(): s == NULL. Please report to http://bugs.clamav.net\n");
return NULL;
}
alloc = strdup(s);
if(!alloc) {
cli_errmsg("cli_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int) strlen(s));
perror("strdup_problem");
return NULL;
}
return alloc;
}
/* returns converted timestamp, in case of error the returned string contains at least one character */
const char* cli_ctime(const time_t *timep, char *buf, const size_t bufsize)
{
const char *ret;
if(bufsize < 26) {
/* standard says we must have at least 26 bytes buffer */
cli_warnmsg("buffer too small for ctime\n");
return " ";
}
if((uint32_t)(*timep) > 0x7fffffff) {
/* some systems can consider these timestamps invalid */
strncpy(buf, "invalid timestamp", bufsize-1);
buf[bufsize-1] = '\0';
return buf;
}
#ifdef HAVE_CTIME_R
# ifdef HAVE_CTIME_R_2
ret = ctime_r(timep, buf);
# else
ret = ctime_r(timep, buf, bufsize);
# endif
#else /* no ctime_r */
# ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_ctime_mutex);
# endif
ret = ctime(timep);
if(ret) {
strncpy(buf, ret, bufsize-1);
buf[bufsize-1] = '\0';
ret = buf;
}
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_ctime_mutex);
# endif
#endif
/* common */
if(!ret) {
buf[0] = ' ';
buf[1] = '\0';
return buf;
}
return ret;
}
/* Function: readn
Try hard to read the requested number of bytes
*/
int cli_readn(int fd, void *buff, unsigned int count)
{
int retval;
unsigned int todo;
unsigned char *current;
todo = count;
current = (unsigned char *) buff;
do {
retval = read(fd, current, todo);
if (retval == 0) {
return (count - todo);
}
if (retval < 0) {
char err[128];
if (errno == EINTR) {
continue;
}
cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err)));
return -1;
}
todo -= retval;
current += retval;
} while (todo > 0);
return count;
}
/* Function: writen
Try hard to write the specified number of bytes
*/
int cli_writen(int fd, const void *buff, unsigned int count)
{
int retval;
unsigned int todo;
const unsigned char *current;
todo = count;
current = (const unsigned char *) buff;
do {
retval = write(fd, current, todo);
if (retval < 0) {
char err[128];
if (errno == EINTR) {
continue;
}
cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err)));
return -1;
}
todo -= retval;
current += retval;
} while (todo > 0);
return count;
}
int cli_filecopy(const char *src, const char *dest)
{
16 years ago
#ifdef _WIN32
return !CopyFileA(src, dest, 0) ? 0 : -1;
16 years ago
#else
char *buffer;
int s, d, bytes;
if((s = open(src, O_RDONLY|O_BINARY)) == -1)
return -1;
if((d = open(dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRWXU)) == -1) {
close(s);
return -1;
}
if(!(buffer = cli_malloc(FILEBUFF))) {
close(s);
close(d);
return -1;
}
while((bytes = cli_readn(s, buffer, FILEBUFF)) > 0)
cli_writen(d, buffer, bytes);
free(buffer);
close(s);
return close(d);
16 years ago
#endif
}
16 years ago
#ifndef P_tmpdir
#ifdef _WIN32
#define P_tmpdir "C:\\"
#else
#define P_tmpdir "/tmp"
#endif /* _WIN32 */
#endif /* P_tmpdir */
16 years ago
const char *cli_gettmpdir(void) {
const char *tmpdir;
if(
#ifdef _WIN32
!(tmpdir = getenv("TEMP")) && !(tmpdir = getenv("TMP"))
#else
!(tmpdir = getenv("TMPDIR"))
#endif
) tmpdir = P_tmpdir;
16 years ago
return tmpdir;
}
struct dirent_data {
char *filename;
const char *dirname;
struct stat *statbuf;
long ino; /* -1: inode not available */
int is_dir;/* 0 - no, 1 - yes */
};
/* sort files before directories, and lower inodes before higher inodes */
static int ftw_compare(const void *a, const void *b)
{
const struct dirent_data *da = a;
const struct dirent_data *db = b;
long diff = da->is_dir - db->is_dir;
if (!diff) {
diff = da->ino - db->ino;
}
return diff;
}
enum filetype {
ft_unknown,
ft_link,
ft_directory,
ft_regular,
ft_skipped_special,
ft_skipped_link
};
static inline int ft_skipped(enum filetype ft)
{
return ft != ft_regular && ft != ft_directory;
}
#define FOLLOW_SYMLINK_MASK (CLI_FTW_FOLLOW_FILE_SYMLINK | CLI_FTW_FOLLOW_DIR_SYMLINK)
static int get_filetype(const char *fname, int flags, int need_stat,
struct stat *statbuf, enum filetype *ft)
{
int stated = 0;
if (*ft == ft_unknown || *ft == ft_link) {
need_stat = 1;
if ((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
/* Following only one of directory/file symlinks, or none, may
* need to lstat.
* If we're following both file and directory symlinks, we don't need
* to lstat(), we can just stat() directly.*/
if (*ft != ft_link) {
/* need to lstat to determine if it is a symlink */
if (lstat(fname, statbuf) == -1)
return -1;
if (S_ISLNK(statbuf->st_mode)) {
*ft = ft_link;
} else {
/* It was not a symlink, stat() not needed */
need_stat = 0;
stated = 1;
}
}
if (*ft == ft_link && !(flags & FOLLOW_SYMLINK_MASK)) {
/* This is a symlink, but we don't follow any symlinks */
*ft = ft_skipped_link;
return 0;
}
}
}
if (need_stat) {
if (stat(fname, statbuf) == -1)
return -1;
stated = 1;
}
if (*ft == ft_unknown || *ft == ft_link) {
if (S_ISDIR(statbuf->st_mode) &&
(*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
/* A directory, or (a symlink to a directory and we're following dir
* symlinks) */
*ft = ft_directory;
} else if (S_ISREG(statbuf->st_mode) &&
(*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
/* A file, or (a symlink to a file and we're following file symlinks) */
*ft = ft_regular;
} else {
/* default: skipped */
*ft = S_ISLNK(statbuf->st_mode) ?
ft_skipped_link : ft_skipped_special;
}
}
return stated;
}
static int handle_filetype(const char *fname, int flags,
struct stat *statbuf, int *stated, enum filetype *ft,
cli_ftw_cb callback, struct cli_ftw_cbdata *data)
{
int ret;
*stated = get_filetype(fname, flags, flags & CLI_FTW_NEED_STAT , statbuf, ft);
if (*stated == -1) {
/* we failed a stat() or lstat() */
ret = callback(NULL, NULL, fname, error_stat, data);
if (ret != CL_SUCCESS)
return ret;
*ft = ft_unknown;
} else if (*ft == ft_skipped_link || *ft == ft_skipped_special) {
/* skipped filetype */
ret = callback(stated ? statbuf : NULL, NULL, fname,
*ft == ft_skipped_link ?
warning_skipped_link : warning_skipped_special, data);
if (ret != CL_SUCCESS)
return ret;
}
return CL_SUCCESS;
}
static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk);
static int handle_entry(struct dirent_data *entry, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
{
if (!entry->is_dir) {
return callback(entry->statbuf, entry->filename, entry->filename, visit_file, data);
} else {
return cli_ftw_dir(entry->dirname, flags, maxdepth, callback, data, pathchk);
}
}
int cli_ftw(char *path, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
{
struct stat statbuf;
enum filetype ft = ft_unknown;
struct dirent_data entry;
int stated = 0;
int ret;
if (((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
char *pathend;
/* trim slashes so that dir and dir/ behave the same when
* they are symlinks, and we are not following symlinks */
#ifndef _WIN32
while (path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
#endif
pathend = path + strlen(path);
while (pathend > path && pathend[-1] == *PATHSEP) --pathend;
*pathend = '\0';
}
if(pathchk && pathchk(path, data) == 1)
return CL_SUCCESS;
ret = handle_filetype(path, flags, &statbuf, &stated, &ft, callback, data);
if (ret != CL_SUCCESS)
return ret;
if (ft_skipped(ft))
return CL_SUCCESS;
entry.statbuf = stated ? &statbuf : NULL;
entry.is_dir = ft == ft_directory;
entry.filename = entry.is_dir ? NULL : strdup(path);
entry.dirname = entry.is_dir ? path : NULL;
if (entry.is_dir) {
ret = callback(entry.statbuf, NULL, path, visit_directory_toplev, data);
if (ret != CL_SUCCESS)
return ret;
}
return handle_entry(&entry, flags, maxdepth, callback, data, pathchk);
}
static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
{
DIR *dd;
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
struct dirent d;
char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result;
#endif
struct dirent_data *entries = NULL;
size_t i, entries_cnt = 0;
int ret;
if (maxdepth < 0) {
/* exceeded recursion limit */
ret = callback(NULL, NULL, dirname, warning_skipped_dir, data);
return ret;
}
if((dd = opendir(dirname)) != NULL) {
struct dirent *dent;
int err;
errno = 0;
ret = CL_SUCCESS;
#ifdef HAVE_READDIR_R_3
while(!(err = readdir_r(dd, &result.d, &dent)) && dent) {
#elif defined(HAVE_READDIR_R_2)
while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
#else
while((dent = readdir(dd))) {
#endif
int stated = 0;
enum filetype ft;
char *fname;
struct stat statbuf;
struct stat *statbufp;
if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
continue;
#ifdef _DIRENT_HAVE_D_TYPE
switch (dent->d_type) {
case DT_DIR:
ft = ft_directory;
break;
case DT_LNK:
if (!(flags & FOLLOW_SYMLINK_MASK)) {
/* we don't follow symlinks, don't bother
* stating it */
errno = 0;
continue;
}
ft = ft_link;
break;
case DT_REG:
ft = ft_regular;
break;
case DT_UNKNOWN:
ft = ft_unknown;
break;
default:
ft = ft_skipped_special;
break;
}
#else
ft = ft_unknown;
#endif
fname = (char *) cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
if(!fname) {
ret = callback(NULL, NULL, dirname, error_mem, data);
if (ret != CL_SUCCESS)
break;
}
if(!strcmp(dirname, PATHSEP))
sprintf(fname, PATHSEP"%s", dent->d_name);
else
sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
if(pathchk && pathchk(fname, data) == 1) {
free(fname);
continue;
}
ret = handle_filetype(fname, flags, &statbuf, &stated, &ft, callback, data);
if (ret != CL_SUCCESS) {
free(fname);
break;
}
if (ft_skipped(ft)) { /* skip */
free(fname);
errno = 0;
continue;
}
if (stated && (flags & CLI_FTW_NEED_STAT)) {
statbufp = cli_malloc(sizeof(*statbufp));
if (!statbufp) {
ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
free(fname);
if (ret != CL_SUCCESS)
break;
else {
errno = 0;
continue;
}
}
memcpy(statbufp, &statbuf, sizeof(statbuf));
} else {
statbufp = 0;
}
entries_cnt++;
entries = cli_realloc(entries, entries_cnt*sizeof(*entries));
if (!entries) {
ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
free(fname);
if (statbufp)
free(statbufp);
break;
} else {
struct dirent_data *entry = &entries[entries_cnt-1];
entry->filename = fname;
entry->statbuf = statbufp;
entry->is_dir = ft == ft_directory;
entry->dirname = entry->is_dir ? fname : NULL;
#ifdef _XOPEN_UNIX
entry->ino = dent->d_ino;
#else
entry->ino = -1;
#endif
}
errno = 0;
}
#ifndef HAVE_READDIR_R_3
err = errno;
#endif
closedir(dd);
ret = CL_SUCCESS;
if (err) {
char errs[128];
cli_errmsg("Unable to readdir() directory %s: %s\n", dirname,
cli_strerror(errno, errs, sizeof(errs)));
/* report error to callback using error_stat */
ret = callback(NULL, NULL, dirname, error_stat, data);
if (ret != CL_SUCCESS) {
if (entries) {
for (i=0;i<entries_cnt;i++) {
struct dirent_data *entry = &entries[i];
free(entry->filename);
free(entry->statbuf);
}
free(entries);
}
return ret;
}
}
if (entries) {
cli_qsort(entries, entries_cnt, sizeof(*entries), ftw_compare);
for (i = 0; i < entries_cnt; i++) {
struct dirent_data *entry = &entries[i];
ret = handle_entry(entry, flags, maxdepth-1, callback, data, pathchk);
if (entry->is_dir)
free(entry->filename);
if (entry->statbuf)
free(entry->statbuf);
if (ret != CL_SUCCESS)
break;
}
for (i++;i<entries_cnt;i++) {
struct dirent_data *entry = &entries[i];
free(entry->filename);
free(entry->statbuf);
}
free(entries);
}
} else {
ret = callback(NULL, NULL, dirname, error_stat, data);
}
return ret;
}
/* strerror_r is not available everywhere, (and when it is there are two variants,
* the XSI, and the GNU one, so provide a wrapper to make sure correct one is
* used */
const char* cli_strerror(int errnum, char *buf, size_t len)
{
char *err;
# ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_strerror_mutex);
#endif
err = strerror(errnum);
strncpy(buf, err, len);
# ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_strerror_mutex);
#endif
return buf;
}
static char *cli_md5buff(const unsigned char *buffer, unsigned int len, unsigned char *dig)
{
unsigned char digest[16];
char *md5str, *pt;
cli_md5_ctx ctx;
int i;
cli_md5_init(&ctx);
cli_md5_update(&ctx, buffer, len);
cli_md5_final(digest, &ctx);
if(dig)
memcpy(dig, digest, 16);
if(!(md5str = (char *) cli_calloc(32 + 1, sizeof(char))))
return NULL;
pt = md5str;
for(i = 0; i < 16; i++) {
sprintf(pt, "%02x", digest[i]);
pt += 2;
}
return md5str;
}
unsigned int cli_rndnum(unsigned int max)
{
if(name_salt[0] == 16) { /* minimizes re-seeding after the first call to cli_gentemp() */
struct timeval tv;
gettimeofday(&tv, (struct timezone *) 0);
16 years ago
srand(tv.tv_usec+clock()+rand());
}
return 1 + (unsigned int) (max * (rand() / (1.0 + RAND_MAX)));
}
char *cli_gentemp(const char *dir)
{
char *name, *tmp;
const char *mdir;
unsigned char salt[16 + 32];
int i;
16 years ago
size_t len;
16 years ago
mdir = dir ? dir : cli_gettmpdir();
16 years ago
len = strlen(mdir) + 42;
name = (char *) cli_calloc(len, sizeof(char));
if(!name) {
cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
return NULL;
}
#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_gentemp_mutex);
#endif
memcpy(salt, name_salt, 16);
for(i = 16; i < 48; i++)
salt[i] = cli_rndnum(255);
tmp = cli_md5buff(salt, 48, name_salt);
#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_gentemp_mutex);
#endif
if(!tmp) {
free(name);
cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
return NULL;
}
16 years ago
snprintf(name, len, "%s"PATHSEP"clamav-%s", mdir, tmp);
free(tmp);
return(name);
}
int cli_gentempfd(const char *dir, char **name, int *fd)
{
*name = cli_gentemp(dir);
if(!*name)
return CL_EMEM;
*fd = open(*name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL, S_IRWXU);
/*
* EEXIST is almost impossible to occur, so we just treat it as other
* errors
*/
if(*fd == -1) {
cli_errmsg("cli_gentempfd: Can't create temporary file %s: %s\n", *name, strerror(errno));
free(*name);
return CL_ECREAT;
}
return CL_SUCCESS;
}
int cli_regcomp(regex_t *preg, const char *pattern, int cflags)
{
if (!strncmp(pattern, "(?i)", 4)) {
pattern += 4;
cflags |= REG_ICASE;
}
return cli_regcomp_real(preg, pattern, cflags);
}