Compare commits

..

62 Commits

Author SHA1 Message Date
f2ac486d24 去除未使用的头文件定义 2024-07-19 13:59:16 +08:00
ab10389228 Merge branch 'master' into dev 2024-07-18 17:58:26 +08:00
99893d8c3d 优化 2024-07-18 17:04:00 +08:00
6f25fb3672 修改配置 2024-07-18 16:29:32 +08:00
967922012c 优化 2024-07-18 16:27:53 +08:00
d8f7c47faa 修复内存泄漏 2024-07-05 09:25:44 +08:00
4aa0d3eac7 Merge branch 'dev' 2024-05-28 11:19:38 +08:00
0b5e40d5c4 优化 2024-05-28 11:08:55 +08:00
d1ae9fc12c 修改文档 2024-05-27 16:14:13 +08:00
8d613b3e54 重新架构 2024-05-27 16:05:31 +08:00
3aa4d63799 优化磁盘告警 2024-05-23 18:12:04 +08:00
130dad7ffa 修改错误 2024-05-22 15:35:14 +08:00
fa2ea1f83c Merge branch 'dev' 2024-05-22 15:26:08 +08:00
2722e9b2e1 修改帮助文件 2024-05-22 15:18:13 +08:00
f7f7d7136a 优化获取磁盘使用率 2024-05-22 15:10:19 +08:00
00567557ba 添加Nginx日志文件 2024-05-22 11:36:50 +08:00
778c9d5fff 增加Nginx规则 2024-05-21 15:28:20 +08:00
b5bd70ec71 增加Ng防护 2024-05-21 09:08:14 +08:00
950bd28f60 修改帮助文件 2023-10-14 09:02:29 +08:00
bc29a0b1a9 支持 Debian 12 2023-07-27 14:40:40 +08:00
a8fb2a8dd3 修改配置文件 rhost.conf 2023-07-04 15:11:23 +08:00
ed3fb48ce2 更新 ip2region/ip2region.xdb 2023-07-03 17:20:39 +08:00
bcb5a7fb5b 添加 ssh key 2023-07-03 14:57:09 +08:00
c949f3c04b Lowered spin from 0.9.8 to 0.9.4 in /clamav/libclamav_rust 2023-04-04 15:46:49 +08:00
315a368012 增加arm架构构建 2023-04-04 15:37:42 +08:00
ce349a46a6 日志格式输出 2023-03-10 13:21:46 +08:00
bc6e6b253c 优化读取配置文件正确性! 2023-02-28 11:04:47 +08:00
17f06235df 增加判断配置文件内容是否正确! 2023-02-27 16:33:03 +08:00
bd6793499f 修改配置文件 2023-02-22 13:56:41 +08:00
2af92f8144 优化 2023-02-21 11:43:14 +08:00
333f0ff2d2 去除aliyun IP位置API, 优化地域解析 2023-02-15 13:48:08 +08:00
da8473a3ec 修改病毒扫描时间为凌晨 2023-02-14 09:30:32 +08:00
5f1c1af36b 修改DatabaseMirror镜像地址为大陆 2023-02-05 17:52:43 +08:00
dafc57b769 修改README.md 2023-02-01 11:16:10 +08:00
72bd738a1d 使用 ip2region 地址定位库判断Ip地域 2023-01-30 15:55:22 +08:00
c2024e15f5 增加ARM64构建 2023-01-28 11:37:36 +08:00
faccc6426c 优化Makefile 2023-01-16 14:42:14 +08:00
be6b92fc60 优化Makefile 2023-01-15 11:24:32 +08:00
7478732ed8 优化Makefile 2023-01-15 11:02:57 +08:00
e424cc1c04 优化Makefil 2023-01-15 10:33:54 +08:00
45fe15f472 更新libclamav库1.0.0版本 2023-01-14 18:28:39 +08:00
b879ee0b2e 增加ip2region离线IP地址定位库,测试阶段未使用 2023-01-10 12:54:53 +08:00
5aa7e4aa06 处理地域白名单错误,添加cJSON解析,添加阿里云API解析IP地域 2023-01-09 17:59:23 +08:00
ce37ef75d6 增加进程优先级 2022-12-30 11:07:44 +08:00
a47d429273 增加帮助信息 2022-12-08 17:13:32 +08:00
13c1d09385 修改build.sh构建脚本 2022-12-08 15:49:50 +08:00
ebdaf0a0c0 修改配置文件之前一直是错误的不应该加引号 2022-12-05 14:29:35 +08:00
c96f82923d 更新 README.md 2022-12-02 10:13:07 +08:00
6303c61119 更改build.sh构建脚本, 支持低版本Debian系统 2022-12-02 09:53:02 +08:00
80c680b8aa 更改build.sh构建脚本, 支持低版本Debian系统 2022-12-02 09:31:34 +08:00
8c3f15ba6d 添加磁盘告警 2022-12-01 10:47:15 +08:00
75b9b5c5ea 增加扫描出病毒后邮件告警 2022-11-29 13:32:29 +08:00
ab042267e5 不再使用固定栈内存存储非法IP地址,使用堆内存并实时扩大内存。解决非法IP过多问题 2022-11-25 18:35:33 +08:00
f5ac5e76a5 修护更新病毒库时引起无法扫描病毒的问题 2022-11-23 13:15:49 +08:00
389ad5b279 仅支持Debian 11 低版本系统libclamav库版本较低 2022-11-19 20:16:44 +08:00
35fb36b4a0 去除Debian系统启动应用时跟新病毒库,系统版本不同libclamav版本不统一 2022-11-19 19:36:17 +08:00
2df703abbc 增加创建病毒移除目录 2022-11-19 19:30:56 +08:00
63a5ee43c4 修复 char *remove_space(const char *str) 函数非法读取内存漏洞 2022-11-14 16:07:49 +08:00
986efc0fe6 大量测试暂时未发现Bug. 2022-11-04 19:37:03 +08:00
9e7c957bf6 修复libiptc没有iptc_free(),修复内存泄漏。 2022-10-28 21:53:48 +08:00
fa5ce31540 增加解析cron定时配置,定时扫描系统 2022-10-25 23:10:34 +08:00
aa8e5cf41a 添加cron定时解析配置,设定时间杀毒 2022-10-25 23:07:47 +08:00
8591 changed files with 1230606 additions and 157699 deletions

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
]
}

21
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"files.associations": {
"assert.h": "c",
"ip2region.h": "c",
"conf.h": "c",
"ccronexpr.h": "c",
"clamscan.h": "c",
"libiptc.h": "c",
"stdio.h": "c",
"nginx.h": "c",
"cjson.h": "c",
"stdlib.h": "c",
"stddef.h": "c",
"signal.h": "c",
"time.h": "c",
"stdarg.h": "c",
"libclamav.h": "c",
"rhost.h": "c",
"warning.h": "c"
}
}

View File

@@ -1,45 +1,87 @@
CROSS_COMPILE ?=
CC := $(CROSS_COMPILE)gcc
CFLAGS += -Os -g -Wall
LIB += -lcurl -lip4tc ./clamscan/clamscan.o ./clamscan/manager.o -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -lclamav ./clamscan/shared/libshared.a -lssl -lcrypto -lz -lpthread
IPTC_CFLAGS += -DHAVE_CONFIG_H -I./libiptc -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT
AR := $(CROSS_COMPILE)ar
RANLIB := $(CROSS_COMPILE)ranlib
OBG = rhost
CL_CFLAGS += -Wall -Os -DHAVE_CONFIG_H -I./clamscan -I./clamscan/shared -I./clamscan/libclamav -I./clamscan/libclamunrar_iface -I/usr/include/json-c -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
SHARED_CFLAGS += -Wall -Os -DHAVE_CONFIG_H -I./clamscan -I./clamscan/shared -I./clamscan/libclamav -I./clamscan/libclamunrar_iface -I/usr/include/json-c -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
CFLAGS += -Os -g -Wall -DCRON_USE_LOCAL_TIME -DCRON_TEST_MALLOC
all: conf.o rhost.o libiptc.o
CMAKE = $(shell if test -f /etc/centos-release; then echo "1"; else echo "0"; fi)
ifeq ("$(CMAKE)", "1")
CMAKE := cmake3
else
CMAKE := cmake
endif
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/actions.c -fPIC -DPIC -o ./clamscan/shared/actions.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/cdiff.c -fPIC -DPIC -o ./clamscan/shared/cdiff.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/cert_util.c -fPIC -DPIC -o ./clamscan/shared/cert_util.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/clamdcom.c -fPIC -DPIC -o ./clamscan/shared/clamdcom.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/getopt.c -fPIC -DPIC -o ./clamscan/shared/getopt.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/hostid.c -fPIC -DPIC -o ./clamscan/shared/hostid.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/idmef_logging.c -fPIC -DPIC -o ./clamscan/shared/idmef_logging.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/misc.c -fPIC -DPIC -o ./clamscan/shared/misc.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/optparser.c -fPIC -DPIC -o ./clamscan/shared/optparser.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/output.c -fPIC -DPIC -o ./clamscan/shared/output.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/tar.c -fPIC -DPIC -o ./clamscan/shared/tar.o
$(CC) $(SHARED_CFLAGS) -c ./clamscan/shared/linux/cert_util_linux.c -fPIC -DPIC -o ./clamscan/shared/linux/cert_util_linux.o
ar cr ./clamscan/shared/libshared.a ./clamscan/shared/actions.o ./clamscan/shared/cdiff.o ./clamscan/shared/cert_util.o ./clamscan/shared/clamdcom.o ./clamscan/shared/getopt.o ./clamscan/shared/hostid.o ./clamscan/shared/idmef_logging.o ./clamscan/shared/misc.o ./clamscan/shared/optparser.o ./clamscan/shared/output.o ./clamscan/shared/tar.o ./clamscan/shared/linux/cert_util_linux.o
$(CC) $(CL_CFLAGS) -c clamscan/clamscan.c -o clamscan/clamscan.o
$(CC) $(CL_CFLAGS) -c clamscan/manager.c -o clamscan/manager.o
$(CC) $(CFLAGS) $^ -o $(OBG) $(LIB)
ARCH := $(shell bash get_architecture.sh)
IPTC_CFLAGS += -DHAVE_CONFIG_H -I./libiptc -D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 -D_REENTRANT
IPTC_LIB += -lip4tc
ip2region_CFLAGS += -Os -g -Wall -I/ip2region -c
ip2region_LIB += ip2region.o xdb_searcher.o
CLAMAV_CFLAGS += -DHAVE_CONFIG_H -I./clamav/libclamav -I./clamav/ -I./clamav/libclamunrar_iface -I./clamav/common -isystem ./clamav/ -isystem /usr/include/libxml2 -isystem /usr/include/json-c -fPIE -Wall -Wextra -Wformat-security -std=gnu90
CLAMAV_LIB += ./clamav/clamscan/clamscan.c.o ./clamav/clamscan/manager.c.o ./clamav/libcommon.a -Wl,-rpath,/lib /lib/libclamav.so.11.0.0 -lmspack ./clamav/libclamav_rust/$(ARCH)/debug/libclamav_rust.a -lgcc_s -lutil -lrt -lpthread -lm -ldl -lc -lbz2 -lpcre2-8 -lxml2 -ljson-c -lc -ldl -lm -lssl -lcrypto -lz -lcurl -lsystemd
FRESHCLAM_CFLAGS += -DHAVE_CONFIG_H -I./clamav/libfreshclam -I./clamav/common -I./clamav/libclamav -I./clamav/libclamunrar_iface -isystem ./clamav/ -isystem ./clamav/libclamav_rust -isystem /usr/include/libxml2 -isystem /usr/include/json-c -fPIE -Wall -Wextra -Wformat-security -std=gnu90
FRESHCLAM_LIB += ./clamav/freshclam/freshclam.c.o ./clamav/freshclam/execute.c.o ./clamav/freshclam/notify.c.o -Wl,-rpath,/lib /lib/libfreshclam.so.2.0.2 ./clamav/libcommon.a -Wl,-rpath,/lib /lib/libclamav.so.11.0.0 -lmspack ./clamav/libclamav_rust/$(ARCH)/debug/libclamav_rust.a -lgcc_s -lutil -lrt -lpthread -lm -ldl -lc -lbz2 -lpcre2-8 -lxml2 -ljson-c -lc -ldl -lm -lz -lsystemd -lcurl -lssl -lcrypto -lresolv
LIBCOMMON__CFLAGS += -DHAVE_CONFIG_H -I./clamav/common -I./clamav/libclamav -I./clamav/ -I./clamav/libclamunrar_iface -isystem ./clamav/ -isystem /usr/include/libxml2 -isystem /usr/include/json-c -fPIC -Wall -Wextra -Wformat-security
LIBCOMMON_LIB += ./clamav/common/cert_util.c.o ./clamav/common/actions.c.o ./clamav/common/clamdcom.c.o ./clamav/common/getopt.c.o ./clamav/common/hostid.c.o ./clamav/common/idmef_logging.c.o ./clamav/common/misc.c.o ./clamav/common/optparser.c.o ./clamav/common/output.c.o ./clamav/common/tar.c.o ./clamav/common/linux/cert_util_linux.c.o
all: libclamav_rust libclamav rhost nginx.o
rhost: conf.o common.o rhost.o libiptc.o ccronexpr.o rule.o nginx.o disk.o ip.o warning.o
$(CC) $(ip2region_CFLAGS) ip2region/ip2region.c
$(CC) $(ip2region_CFLAGS) ip2region/xdb_searcher.c
$(CC) $(CLAMAV_CFLAGS) -o ./clamav/clamscan/clamscan.c.o -c ./clamav/clamscan/clamscan.c
$(CC) $(CLAMAV_CFLAGS) -o ./clamav/clamscan/manager.c.o -c ./clamav/clamscan/manager.c
$(CC) $(FRESHCLAM_CFLAGS) -o ./clamav/freshclam/freshclam.c.o -c ./clamav/freshclam/freshclam.c
$(CC) $(FRESHCLAM_CFLAGS) -o ./clamav/freshclam/execute.c.o -c ./clamav/freshclam/execute.c
$(CC) $(FRESHCLAM_CFLAGS) -o ./clamav/freshclam/notify.c.o -c ./clamav/freshclam/notify.c
$(CC) $(CFLAGS) $^ -o $(OBG) $(ip2region_LIB) $(CLAMAV_LIB) $(IPTC_LIB) $(FRESHCLAM_LIB)
chmod +x $(OBG)
libclamav_rust:
cd clamav/libclamav_rust && $(CMAKE) -E env CARGO_CMD=build CARGO_TARGET_DIR=./ MAINTAINER_MODE=OFF RUSTFLAGS="" \
cargo build --target $(ARCH) --target-dir ./
cd ..
libclamav:
cd clamav/ && bash -x build-libclamav.sh
cp ${PWD}/clamav/libclamav.so.11.0.0 /lib/
cp ${PWD}/clamav/libfreshclam.so.2.0.2 /lib/
rm -rf /lib/libclamav.so.11 && ln -s /lib/libclamav.so.11.0.0 /lib/libclamav.so.11
rm -rf /lib/libfreshclam.so.2 && ln -s /lib/libfreshclam.so.2.0.2 /lib/libfreshclam.so.2
cd ..
test:
echo $(CMAKE) $(ARCH) $(CFLAGS)
static: conf.o rhost.o libiptc.o
$(CC) $(IPTC_CFLAGS) -c libiptc/libip4tc.c -o libiptc/libip4tc.o
ar crs libiptc/libip4tc.a libiptc/libip4tc.o
$(CC) $(CFLAGS) $^ libiptc/libip4tc.o -o $(OBG) `/data/curl/bin/curl-config --cflags --static-libs` `pkg-config --libs --static libbrotlidec`
#$(CC) $(CFLAGS) $^ libiptc/libip4tc.o -o $(OBG) `/data/curl/bin/curl-config --cflags --static-libs` `pkg-config --libs --static libbrotlidec`
.PHONY: clean
clean:
rm -rf *.o
rm libiptc/*.o libiptc/*.a
rm clamscan/shared/*.o clamscan/shared/libshared.a clamscan/*.o
rm $(OBG)
rm -rf $(OBG) $(cJSON_LIB) $(ip2region_LIB)
rm -rf `find ./clamav/ -name *.o`
rm -rf ./clamav/*.a
rm -rf ./clamav/libclamav.so.11.0.0
rm -rf ./clamav/libfreshclam.so.2.0.2
rm -rf ${PWD}/clamav/libclamav.so.11
rm -rf ${PWD}/clamav/libfreshclam.so.2
rm -rf clamav/libclamav_rust/debug
rm -rf clamav/libclamav_rust/$(ARCH)

160
README.md
View File

@@ -1,91 +1,127 @@
# denyhosts
ssh防止暴力破解,适用Debian 8、9、11 Centos 7
支持钉钉告警和邮件告警
支持第三方QQ邮箱告警
- 拒绝主机&杀毒
```text
适用系统:
Debian 11、12
Centos 7
支持系统病毒扫描
支持一次运行检测、后台运行检测
支持钉钉告警和邮件告
支持第三方QQ邮箱告警
```
Debian系统请安装libcurl、iptables-devel、libclamav-devel
apt install libclamav-dev libip4tc-dev libcurl4-openssl-dev #(或者libcurl4-gnutls-dev)
```text
Debian
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
apt -y install libclamav-dev libip4tc-dev libcurl4-openssl-dev #(或者libcurl4-gnutls-dev)
apt -y install libsystemd-dev libjson-c-dev libpcre2-dev clamav-freshclam
apt -y install libltdl-dev libmspack-dev cmake
freshclam # 更新病毒库(必要)
Debian系统使用libiptc库需要nftables切换到iptables (使用了libip4tc-dev库)
Switching to the legacy version:(切换到 iptables)
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy
```
```text
Centos 7
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
yum install clamav clamav-update clamav-lib clamav-devel json-c-devel pcre2-devel
yum install iptables-devel libcurl-devel
yum install systemd-devel libtool-ltdl-devel libmspack-devel
yum install cmake3
yum -y install centos-release-scl
yum -y install devtoolset-11-gcc
source /opt/rh/devtoolset-11/enable #临时
echo "source /opt/rh/devtoolset-11/enable" >> /etc/profile #永久
mv /etc/cron.d/clamav-update /root
sed -i "s/DatabaseMirror .*/DatabaseMirror clamavdb.c3sl.ufpr.br/g" /etc/freshclam.conf
freshclam # 更新病毒库(必要)
```
```
Centos 7系统请安装libcurl、iptables-devel、libclamav-devel
yum install clamav clamav-update clamav-lib
yum install iptables-devel libcurl-devel
freshclam # 更新病毒库(必要)
```
```
```text
用法
cd /root
git clone https://git.aixiao.me/aixiao/denyhosts
cd denyhosts
make clean; make
chmod a+x /root/denyhosts/denyhosts.sh
make clean
make all
bash build.sh
crontab 定时任务,像这样.
0 22 * * * /root/denyhosts/denyhosts.sh
启动:
./rhost -d -r / --exclude-dir="^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home" --move=/opt/infected --max-filesize 1024M -l clamscan.log # 用户指定参数,后台运行并扫描病毒
示列:
./rhost -d -r / --exclude-dir="^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home" --move=/opt/infected --max-filesize 1024M -l #后台运行并扫描病毒
./rhost -d # 后台运行读取配置文件参数
./rhost # 只处理非法攻击
关闭:
killall rhost
帮助:
./rhost -h
Rhost Reject host&scan for viruses (Rhost 拒绝主机并扫描病毒)
Author: AIXIAO@AIXIAO.ME
Version: 1.0
Usage: [-?h] [-d]
Options:
-d : Background running
-? -h --help : help information
The configuration file needs to be in the same directory as the executable file!
配置文件需要与可执行文件位于同一目录中!
May 22 2024 15:05:59 Compile、link.
```
```
Debian系统使用libiptc库需要nftables切换到iptables
Switching to the legacy version:(切换到 iptables)
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy
```
```
```text
配置文件
global {
DAEMON = "off"; // on开启后台运行off不开启
TIME = "10"; // 睡眠时间
DAEMON = "off"; // on开启后台运行,off不开启
TIME = "1"; // 睡眠时间(大于等于1,单位秒)
CLAMAV = 1; // clamav 是否扫描病毒
CLAMAV_TIME = "1726"; // clamav 扫描时间(小时分钟,默认每天运行)
PUBLIC_IP = "http://inet-ip.aixiao.me/"; // 获取公网IP
PUBLIC_IP = "http://inet-ip.info"; // 获取公网IP
IS_DISK = 1; // 磁盘使用率(1开启,非1关闭)
DISK_USE = 50; // 任意某块磁盘使用率告警(大于等于1)
CLAMAV = 1; // clamav 是否扫描病毒(1开启,非1关闭)
CLAMAV_ARG = "-r / --exclude-dir=^/sys|^/dev|^/proc|^/opt/infected|^/root|^/home --move=/opt/infected --max-filesize 1024M -l clamscan.log";
CLAMAV_TIME = "* 45 11 * * *"; // clamav 扫描时间(Cron格式, 秒 分 时 天 月 周)
IS_BLOCKED = 1; // 是否封禁攻击IP(1开启,非1关闭)
IPV4_RESTRICTION = 1; // 是否启用IP白名单
IPV4_WHITE_LIST = "1.1.1.1 "; // IP白名单
IPV4_RESTRICTION = 1; // 是否启用IP白名单(1开启,非1关闭)
IPV4_WHITE_LIST = "1.1.1.1 2.2.2.2 "; // IP白名单(空格隔开)
REGION = 1; // 是否启用地域白名单(1开启,非1关闭)
IP2REGION = 1; // 是否使用本地 ip2region 地址定位库(1使用,非1不使用)
REGION_LIST = "河南 郑州 上海"; // 地域列表(空格隔开)
NGINX = 1; // 是否启用Nginx白名单
NGINX_LOG_FILE= "/usr/local/nginx/logs/access.log"; // Nginx 日志文件
NGINX_REGION_LIST = "中国 河南 郑州 上海 内网"; // 地域列表(空格隔开)
REGION = 1; // 是否启用地域白名单
REGION_LIST = "河南 郑州"; // 地域列表
IS_BLOCKED = 1; // 是否封禁攻击IP
REFUSE_NUMBER = 3; // 拒绝攻击次数
IS_MAIL = 0; // 开启邮件告警
IS_DING_WEBHOOK = 0; // 开启叮叮告警
IS_DING_WEBHOOK = 0; // 开启叮叮告警(1开启,非1关闭)
PHONE = "15565979082"; // @的人手机号
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=7f069c672cb878987aa6772cca336740eece4ce36bde12b51b45e9f440e0565a"; // 钉钉WEBHOOK
DING_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=396bce0384cded025087cff3c176ea5e9afb9bd8fcaa46d6fa8c51dd172ba513"; // 钉钉WEBHOOK
IS_QQMAIL = 0; // 开启QQ邮箱告警(默认使用gomailhttps://git.aixiao.me/aixiao/gomail.git)
RECV_MAIL = "1605227279@qq.com"; // 接收者QQ
IS_MAIL = 0; // 开启QQ邮箱告警(默认使用gomail: https://git.aixiao.me/aixiao/gomail.git)(1开启,非1关闭)
RECV_MAIL = "1605227279@qq.com"; // 接收者邮箱
}
```

164
build.sh Normal file
View File

@@ -0,0 +1,164 @@
:
check_os()
{
if cat /etc/issue | grep -i 'ubuntu' >> /dev/null 2>&1 ; then
OS=ubuntu
OS_VER=$(cat /etc/issue | head -n1 | awk '{print$2}')
echo -e SYSTEM: UBUNTU $(uname -m) ${OS_VER}\\nKERNEL: $(uname -sr)
elif test -f /etc/debian_version ; then
OS=debian
OS_VER=$(cat /etc/debian_version)
echo -e SYSTEM: DEBIAN $(uname -m) ${OS_VER}\\nKERNEL: $(uname -sr)
elif test -f /etc/centos-release ; then
OS=centos
OS_VER=$(cat /etc/centos-release | grep -o -E '[0-9.]{3,}') 2>> /dev/null
echo -e SYSTEM: CENTOS $(uname -m) ${OS_VER}\\nKERNEL: $(uname -sr)
else
echo The system does not support
exit 3
fi
}
pkg_install()
{
if test "$OS" = "ubuntu" -o "$OS" = "debian"; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh;
apt -y install build-essential
apt -y install make
apt -y install tmux
apt -y install libclamav-dev libip4tc-dev libcurl4-openssl-dev #(或者libcurl4-gnutls-dev)
apt -y install libsystemd-dev libjson-c-dev libpcre2-dev clamav-freshclam
apt -y install libltdl-dev libmspack-dev
# Debian系统使用libiptc库需要nftables切换到iptables
# Switching to the legacy version:(切换到 iptables)
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set arptables /usr/sbin/arptables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy
freshclam # 更新病毒库(必要)
else
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh;
yum -y groupinstall "Development Tools"
yum -y install make
yum -y install tmux
yum -y install bzip2-devel
yum -y install libxslt-devel libxml2-devel
yum -y install clamav clamav-update clamav-lib clamav-devel json-c-devel pcre2-devel
yum -y install iptables-devel libcurl-devel
yum -y install systemd-devel libtool-ltdl-devel libmspack-devel
yum -y install centos-release-scl
yum -y install devtoolset-11-gcc
#source /opt/rh/devtoolset-11/enable #临时
if test "`grep "devtoolset" /etc/profile`" = ""; then
echo "source /opt/rh/devtoolset-11/enable" >> /etc/profile #永久
fi
source /opt/rh/devtoolset-11/enable
freshclam # 更新病毒库(必要)
fi
}
main()
{
#cd clamscan/libclamav
#bash build.sh
#cd ../..
make clean
make libclamav_rust
make libclamav
make all
if test "$OS" = "centos"; then
if test -f /etc/cron.d/clamav-update; then # 去除自动更新病毒库
mv /etc/cron.d/clamav-update /root
fi
if test -f /etc/freshclam.conf; then # 更改病毒库镜像
sed -i "s/DatabaseMirror .*/DatabaseMirror db.cn.clamav.net/g" /etc/freshclam.conf
fi
fi
if test -f /etc/clamav/freshclam.conf; then
sed -i "s/DatabaseMirror .*/DatabaseMirror db.cn.clamav.net/g" /etc/clamav/freshclam.conf
else
:
fi
tmux new-session -s main -d; tmux send -t main 'cd ~/RHOST/; killall rhost; ./rhost -d' ENTER
tmux at -t main
}
binary()
{
cd ~
if ! test -f RHOST; then
mkdir -p RHOST
fi
if test "$OS" = "centos"; then
wget -T 30 https://git.aixiao.me/attachments/18147490-6d10-4407-8537-03b3c1eeb357 -O RHOST/rhost
wget -T 30 https://git.aixiao.me/attachments/e6309b7b-0e98-4a11-8fc1-7c624649f3b8 -O RHOST/rhost.conf
wget -T 30 https://git.aixiao.me/attachments/1ddf1579-b660-4d91-821d-82fe5f0ec8c0 -O RHOST/freshclam.conf
if test -f /etc/cron.d/clamav-update; then # 去除自动更新病毒库
mv /etc/cron.d/clamav-update /root
fi
if test -f /etc/freshclam.conf; then # 更改病毒库镜像
sed -i "s/DatabaseMirror .*/DatabaseMirror clamavdb.c3sl.ufpr.br/g" /etc/freshclam.conf
fi
if test -f /etc/clamav/freshclam.conf; then
sed -i "s/DatabaseMirror .*/DatabaseMirror clamavdb.c3sl.ufpr.br/g" /etc/clamav/freshclam.conf
else
:
fi
chmod +x RHOST/rhost
cd ~/RHOST/
tmux new-session -s main -d; tmux send -t main 'cd ~/RHOST/; killall rhost; ./rhost -d' ENTER
tmux at -t main
elif test "$OS" = "debian"; then
wget -T 30 https://git.aixiao.me/attachments/40a3317f-48eb-4465-9ae3-fc46251c5bcc -O RHOST/rhost
wget -T 30 https://git.aixiao.me/attachments/e6309b7b-0e98-4a11-8fc1-7c624649f3b8 -O RHOST/rhost.conf
wget -T 30 https://git.aixiao.me/attachments/1ddf1579-b660-4d91-821d-82fe5f0ec8c0 -O RHOST/freshclam.conf
chmod +x RHOST/rhost
cd ~/RHOST/
tmux new-session -s main -d; tmux send -t main 'cd ~/RHOST/; killall rhost; ./rhost -d' ENTER
tmux at -t main
fi
}
check_os
pkg_install
if test "${1}" = "binary"; then
binary
exit 0
fi
main

1272
ccronexpr.c Normal file

File diff suppressed because it is too large Load Diff

95
ccronexpr.h Normal file
View File

@@ -0,0 +1,95 @@
/*
* Copyright 2015, alex at staticlibs.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* File: ccronexpr.h
* Author: alex
*
* Created on February 24, 2015, 9:35 AM
*/
#ifndef CCRONEXPR_H
#define CCRONEXPR_H
#if defined(__cplusplus) && !defined(CRON_COMPILE_AS_CXX)
extern "C" {
#endif
#ifndef ANDROID
#include <time.h>
#else /* ANDROID */
#include <time64.h>
#endif /* ANDROID */
#include <stdint.h> /*added for use if uint*_t data types*/
/**
* Parsed cron expression
*/
typedef struct {
uint8_t seconds[8];
uint8_t minutes[8];
uint8_t hours[3];
uint8_t days_of_week[1];
uint8_t days_of_month[4];
uint8_t months[2];
} cron_expr;
/**
* Parses specified cron expression.
*
* @param expression cron expression as nul-terminated string,
* should be no longer that 256 bytes
* @param pointer to cron expression structure, it's client code responsibility
* to free/destroy it afterwards
* @param error output error message, will be set to string literal
* error message in case of error. Will be set to NULL on success.
* The error message should NOT be freed by client.
*/
void cron_parse_expr(const char* expression, cron_expr* target, const char** error);
/**
* Uses the specified expression to calculate the next 'fire' date after
* the specified date. All dates are processed as UTC (GMT) dates
* without timezones information. To use local dates (current system timezone)
* instead of GMT compile with '-DCRON_USE_LOCAL_TIME'
*
* @param expr parsed cron expression to use in next date calculation
* @param date start date to start calculation from
* @return next 'fire' date in case of success, '((time_t) -1)' in case of error.
*/
time_t cron_next(cron_expr* expr, time_t date);
/**
* Uses the specified expression to calculate the previous 'fire' date after
* the specified date. All dates are processed as UTC (GMT) dates
* without timezones information. To use local dates (current system timezone)
* instead of GMT compile with '-DCRON_USE_LOCAL_TIME'
*
* @param expr parsed cron expression to use in previous date calculation
* @param date start date to start calculation from
* @return previous 'fire' date in case of success, '((time_t) -1)' in case of error.
*/
time_t cron_prev(cron_expr* expr, time_t date);
#if defined(__cplusplus) && !defined(CRON_COMPILE_AS_CXX)
} /* extern "C"*/
#endif
#endif /* CCRONEXPR_H */

327
clamav/build-libclamav.sh Normal file

File diff suppressed because one or more lines are too long

617
clamav/clamav-config.h Normal file
View File

@@ -0,0 +1,617 @@
/* clamav-config.h.cmake.in. Autoconf compatibility layer for CMake. */
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* mmap flag for anonymous maps */
#define ANONYMOUS_MAP MAP_ANONYMOUS
/* bind 8 compatibility mode, required on some systems to get T_TXT, etc from nameser_compat.h */
/* #undef BIND_8_COMPAT */
/* name of the clamav group */
#define CLAMAVGROUP "clamav"
/* name of the clamav user */
#define CLAMAVUSER "clamav"
/* enable debugging */
/* #undef CL_DEBUG */
/* enable experimental code */
/* #undef CL_EXPERIMENTAL */
/* thread safe */
#define CL_THREAD_SAFE 1
/* curses header location */
#define CURSES_INCLUDE <ncurses.h>
/* os is aix */
/* #undef C_AIX */
/* os is beos */
/* #undef C_BEOS */
/* Increase thread stack size. */
/* #undef C_BIGSTACK */
/* os is bsd flavor */
/* #undef C_BSD */
/* os is darwin */
/* #undef C_DARWIN */
/* target is gnu-hurd */
/* #undef C_GNU_HURD */
/* os is hpux */
/* #undef C_HPUX */
/* os is interix */
/* #undef C_INTERIX */
/* os is irix */
/* #undef C_IRIX */
/* target is kfreebsd-gnu */
/* #undef C_KFREEBSD_GNU */
/* target is linux */
#define C_LINUX 1
/* os is OS/2 */
/* #undef C_OS2 */
/* os is osf/tru64 */
/* #undef C_OSF */
/* os is QNX 6.x.x */
/* #undef C_QNX6 */
/* os is solaris */
/* #undef C_SOLARIS */
#ifndef _WIN32
/* Path to virus database directory. */
#define DATADIR "/var/lib/clamav"
/* where to look for the config file */
#define CONFDIR "/etc/clamav"
#endif
/* Have sys/fanotify.h */
#define HAVE_SYS_FANOTIFY_H 1
/* whether _XOPEN_SOURCE needs to be defined for fd passing to work */
/* #undef FDPASS_NEED_XOPEN */
/* file i/o buffer size */
#define FILEBUFF 8192
/* scan buffer size */
#define SCANBUFF 131072
/* enable workaround for broken DNS servers */
/* #undef FRESHCLAM_DNS_FIX */
/* use "Cache-Control: no-cache" in freshclam */
/* #undef FRESHCLAM_NO_CACHE */
/* attrib aligned */
#define HAVE_ATTRIB_ALIGNED 1
/* attrib packed */
#define HAVE_ATTRIB_PACKED 1
/* have bzip2 */
#define HAVE_BZLIB_H 1
/* Define to 1 if you have the `ctime_r' function. */
/* #undef HAVE_CTIME_R */
/* ctime_r takes 2 arguments */
/* #undef HAVE_CTIME_R_2 */
/* ctime_r takes 3 arguments */
/* #undef HAVE_CTIME_R_3 */
/* Define to 1 if you have the declaration of `cygwin_conv_path', and to 0 if
you don't. */
/* #undef HAVE_DECL_CYGWIN_CONV_PATH */
/* Define to 1 if you have a deprecated version of the 'libjson' library
(-ljson). */
/* #undef HAVE_DEPRECATED_JSON */
/* Define to 1 if you have the <dirent.h> header file. */
#define HAVE_DIRENT_H 1
/* Define if you have the GNU dld library. */
/* #undef HAVE_DLD */
/* Define to 1 if you have the <dld.h> header file. */
/* #undef HAVE_DLD_H */
/* Define to 1 if you have the `dlerror' function. */
/* #undef HAVE_DLERROR */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <dl.h> header file. */
/* #undef HAVE_DL_H */
/* Define if you have the _dyld_func_lookup function. */
/* #undef HAVE_DYLD */
/* Define to 1 if you have the `enable_extended_FILE_stdio' function. */
/* #undef HAVE_ENABLE_EXTENDED_FILE_STDIO */
/* Define to 1 if the system has the type `error_t'. */
/* #undef HAVE_ERROR_T */
/* have working file descriptor passing support */
#define HAVE_FD_PASSING 1
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#define HAVE_FSEEKO 1
/* have getaddrinfo() */
#define HAVE_GETADDRINFO 1
/* Define to 1 if you have the `getnameinfo' function. */
/* #undef HAVE_GETNAMEINFO */
/* Define to 1 if getpagesize() is available */
#define HAVE_GETPAGESIZE 1
/* Define to 1 if you have the <grp.h> header file. */
#define HAVE_GRP_H 1
/* Define if you have the iconv() function and it works. */
#define HAVE_ICONV 1
/* Define to 1 if you have the `initgroups' function. */
#define HAVE_INITGROUPS 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <inttypes.h> header file (for libjson-c). */
#define JSON_C_HAVE_INTTYPES_H 1
/* Define to 1 if you have the 'libjson' library (-ljson). */
#define HAVE_JSON 1
/* Define to '1' if you have the check.h library */
/* #undef HAVE_LIBCHECK */
/* Define to '1' if you have the ncurses.h library */
#define HAVE_LIBNCURSES 1
/* Define to '1' if you have the curses.h library */
/* #undef HAVE_LIBPDCURSES */
/* Define to 1 if you have the `ssl' library (-lssl). */
#define HAVE_LIBSSL 1
/* Define to 1 if you have the 'libxml2' library (-lxml2). */
#define HAVE_LIBXML2 1
/* Define to 1 if you have the `z' library (-lz). */
#define HAVE_LIBZ 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the `madvise' function. */
/* #undef HAVE_MADVISE */
/* Define to 1 if you have the `mallinfo' function. */
/* #undef HAVE_MALLINFO */
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
/* Define to 1 if you have the `mkstemp' function. */
/* #undef HAVE_MKSTEMP */
/* Define to 1 if you have a working `mmap' system call that supports
MAP_PRIVATE. */
#define HAVE_MMAP 1
/* Define to 1 if you have a pcre library (-lpcre). */
#define HAVE_PCRE 1
/* Define to 1 if you using the pcre2 library. */
#define USING_PCRE2 1
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
/* Define to 1 if you have the <poll.h> header file. */
#define HAVE_POLL_H 1
/* "pragma pack" */
/* #undef HAVE_PRAGMA_PACK */
/* "pragma pack hppa/hp-ux style" */
/* #undef HAVE_PRAGMA_PACK_HPPA */
/* Define if libtool can extract symbol lists from object files. */
/* #undef HAVE_PRELOADED_SYMBOLS */
/* Define to 1 if you have the <pthread.h> header file */
#define HAVE_PTHREAD_H 1
/* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
/* Define to 1 if you have the `readdir' function. */
/* #undef HAVE_READDIR */
/* Define to 1 if you have the `recvmsg' function. */
#define HAVE_RECVMSG 1
/* have resolv.h */
#define HAVE_RESOLV_H 1
/* Define signed right shift implementation */
#define HAVE_SAR 1
/* Define to 1 if you have the `sched_yield' function. */
/* #undef HAVE_SCHED_YIELD */
/* Define to 1 if you have the `sendmsg' function. */
#define HAVE_SENDMSG 1
/* Define to 1 if you have the `setgroups' function. */
/* #undef HAVE_SETGROUPS */
/* Define to 1 if you have the `setsid' function. */
#define HAVE_SETSID 1
/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1
/* enable stat64 */
/* #undef HAVE_STAT64 */
/* Define to 1 if you have the <stdbool.h> header file. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasestr' function. */
/* #undef HAVE_STRCASESTR */
/* Define to 1 if you have the `strerror_r' function. */
#define HAVE_STRERROR_R 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strlcat' function. */
/* #undef HAVE_STRLCAT */
/* Define to 1 if you have the `strlcpy' function. */
/* #undef HAVE_STRLCPY */
/* Define to 1 if you have the `strndup' function. */
#define HAVE_STRNDUP 1
/* using internal strn functions */
/* #undef HAVE_STRNI */
/* Define to 1 if you have the `strnlen' function. */
#define HAVE_STRNLEN 1
/* Define to 1 if you have the `strnstr' function. */
/* #undef HAVE_STRNSTR */
/* Define to 1 if sysconf(_SC_PAGESIZE) is available */
#define HAVE_SYSCONF_SC_PAGESIZE 1
/* Define to 1 if you have the `sysctlbyname' function. */
/* #undef HAVE_SYSCTLBYNAME */
/* systemd is supported */
#define HAVE_SYSTEMD 1
/* Use private fts() implementation which is LFS safe */
#define HAVE_SYSTEM_LFS_FTS 1
/* Define to 1 if you have the <sys/cdefs.h> header file. */
#define HAVE_SYS_CDEFS_H 1
/* Define to 1 if you have the <sys/dl.h> header file. */
/* #undef HAVE_SYS_DL_H */
/* Define to 1 if you have the <sys/filio.h> header file. */
/* #undef HAVE_SYS_FILIO_H */
/* Define to 1 if you have the <sys/inttypes.h> header file. */
/* #undef HAVE_SYS_INTTYPES_H */
/* Define to 1 if you have the <sys/int_types.h> header file. */
/* #undef HAVE_SYS_INT_TYPES_H */
/* Define to 1 if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/queue.h> header file. */
#define HAVE_SYS_QUEUE_H 1
/* "have <sys/select.h>" */
#define HAVE_SYS_SELECT_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/times.h> header file. */
#define HAVE_SYS_TIMES_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/uio.h> header file. */
#define HAVE_SYS_UIO_H 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the `timegm' function. */
#define HAVE_TIMEGM 1
/* Define this if uname(2) is POSIX */
#define HAVE_UNAME_SYSCALL 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
/* This value is set to 1 to indicate that the system argz facility works */
/* #undef HAVE_WORKING_ARGZ */
/* yara sources are compiled in */
#define HAVE_YARA 1
/* Define to 1 if you have the <zlib.h> header file. */
#define HAVE_ZLIB_H 1
/* For internal use only - DO NOT DEFINE */
/* #undef HAVE__INTERNAL__SHA_COLLECT */
/* Define as const if the declaration of iconv() needs const. */
/* #undef ICONV_CONST */
/* Define if UNRAR is linked instead of loaded. */
/* #undef UNRAR_LINKED */
/* Define if UNRAR is linked instead of loaded. */
/* #undef HAVE_SYSTEM_TOMSFASTMATH */
/* "Full clamav library version number" */
#define LIBCLAMAV_FULLVER "11.0.0"
/* "Major clamav library version number" */
#define LIBCLAMAV_MAJORVER 11
/* "Full freshclam library version number" */
#define LIBFRESHCLAM_FULLVER "2.0.2"
/* "Major freshclam library version number" */
#define LIBFRESHCLAM_MAJORVER 2
/* The archive extension */
#define LT_LIBEXT ".a"
/* The archive prefix */
#define LT_LIBPREFIX "lib"
/* Define to the extension used for runtime loadable modules, say, ".so" or ".dylib". */
#define LT_MODULE_EXT ".so"
/* Define to the name of the environment variable that determines the run-time
module search path. */
#ifdef _WIN32
#define SEARCH_LIBDIR "/usr"
#else
#define SEARCH_LIBDIR "/usr/lib/x86_64-linux-gnu"
#endif
/* Define to the shared library suffix, say, ".dylib". */
#define LT_SHARED_EXT ".so"
/* disable assertions */
/* #undef NDEBUG */
/* Define if dlsym() requires a leading underscore in symbol names. */
/* #undef NEED_USCORE */
/* bzip funtions do not have bz2 prefix */
/* #undef NOBZ2PREFIX */
/* "no fd_set" */
/* #undef NO_FD_SET */
/* Name of package */
#define PACKAGE "ClamAV"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "https://github.com/Cisco-Talos/clamav/issues"
/* Define to the full name of this package. */
#define PACKAGE_NAME "ClamAV"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "ClamAV 1.0.0"
/* Define to the one symbol short name of this package. */
/* #undef PACKAGE_TARNAME */
/* Define to the home page for this package. */
#define PACKAGE_URL "https://www.clamav.net/"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0.0"
/* Libprelude support enabled */
/* #undef PRELUDE */
/* Define whether application use libtool >= 2.0 */
/* #undef PRELUDE_APPLICATION_USE_LIBTOOL2 */
/* Define to if the `setpgrp' function takes no argument. */
/* #undef SETPGRP_VOID */
/* The number of bytes in type int */
#define SIZEOF_INT 4
/* The number of bytes in type long */
#define SIZEOF_LONG 8
/* The number of bytes in type long long */
#define SIZEOF_LONG_LONG 8
/* The number of bytes in type short */
#define SIZEOF_SHORT 2
/* The number of bytes in type void * */
#define SIZEOF_VOID_P 8
/* Define to if you have the ANSI C header files. */
/* #undef STDC_HEADERS */
/* Support for IPv6 */
/* #undef SUPPORT_IPv6 */
/* enable memory pools */
#define USE_MPOOL 1
/* use syslog */
#define USE_SYSLOG 1
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
/* #undef _POSIX_PTHREAD_SEMANTICS */
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
/* #undef _TANDEM_SOURCE */
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
/* #undef __EXTENSIONS__ */
#endif
/* LLVM version (if found) */
/* #undef LLVM_VERSION */
/* Version number of package */
#define VERSION "1.0.0"
/* Version suffix for package */
#define VERSION_SUFFIX ""
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* #undef WORDS_BIGENDIAN */
# endif
#endif
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
/* #undef YYTEXT_POINTER */
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
/* #undef _LARGEFILE_SOURCE */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* POSIX compatibility */
/* #undef _POSIX_PII_SOCKET */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* thread safe */
#define _REENTRANT 1
/* Define so that glibc/gnulib argp.h does not typedef error_t. */
/* #undef __error_t_defined */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#define inline inline
#endif
/* Define to `long int' if <sys/types.h> does not define. */
/* #undef off_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef ssize_t */
/* Define to the equivalent of the C99 'restrict' keyword, or to
nothing if this is not supported. Do not define if restrict is
supported directly. */
#define restrict __restrict
/* Work around a bug in Sun C++: it does not support _Restrict or
__restrict__, even though the corresponding Sun C compiler ends up with
"#define restrict _Restrict" or "#define restrict __restrict__" in the
previous line. Perhaps some future version of Sun C++ will work with
restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
#if defined __SUNPRO_CC && !defined __RESTRICT
# define _Restrict
# define __restrict__
#endif
/* Define to "int" if <sys/socket.h> does not define. */
/* #undef socklen_t */
#include "platform.h"

84
clamav/clamav-types.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
*
* Authors: Tomasz Kojm, Micah Snyder
*
* WARNING: This file was generated by CMake. Do not edit!
*
* 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.
*/
#ifndef __CLAMAV_TYPES_H
#define __CLAMAV_TYPES_H
#include <inttypes.h>
/* Ensure we have print format types */
/* PRIu64 should be in <inttypes.h> */
#ifndef _SF64_PREFIX
#define _SF64_PREFIX "l"
#endif
#ifndef PRIu64
#define PRIu64 _SF64_PREFIX "u"
#endif
#ifndef PRIx64
#define PRIx64 _SF64_PREFIX "i"
#endif
#ifndef PRIi64
#define PRIi64 _SF64_PREFIX "x"
#endif
#ifndef STDu64
#define STDu64 "%" PRIu64
#define STDi64 "%" PRIi64
#define STDx64 "%" PRIx64
#endif
/* PRIu32 should also be in <inttypes.h> */
#ifndef PRIu32
#ifndef _SF32_PREFIX
#define _SF32_PREFIX ""
#endif
#define PRIu32 _SF32_PREFIX "u"
#define PRIi32 _SF32_PREFIX "i"
#define PRIx32 _SF32_PREFIX "x"
#endif
#ifndef STDu32
#define STDu32 "%" PRIu32
#define STDi32 "%" PRIi32
#define STDx32 "%" PRIx32
#endif
#ifndef INT32_MAX
#define INT32_MAX 2147483647
#endif
#endif

68
clamav/clamav-version.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2019-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* Authors: Micah Snyder
*
* WARNING: This file was generated by CMake. Do not edit!
*
* 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.
*/
#ifndef CLAMAV_VER_H
#define CLAMAV_VER_H
/**
* @macro
* Version number of the clamav package release
*/
#define CLAMAV_VERSION "1.0.0"
/**
* @macro
* Numerical representation of the version number of the clamav package
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define CLAMAV_VERSION_NUM 0x010000
/**
* @macro
* Version number of the clamav library release
*/
#define LIBCLAMAV_VERSION "11.0.0"
/**
* @macro
* Numerical representation of the version number of the libclamav library
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define LIBCLAMAV_VERSION_NUM 0x0b0000
/**
* @macro
* Version number of the clamav library release
*/
#define LIBFRESHCLAM_VERSION "2.0.2"
/**
* @macro
* Numerical representation of the version number of the libfreshclam library
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define LIBFRESHCLAM_VERSION_NUM 0x020200
#endif /* CLAMAV_VER_H */

208
clamav/clamav_rust.h Normal file
View File

@@ -0,0 +1,208 @@
/* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */
#ifndef __CLAMAV_RUST_H
#define __CLAMAV_RUST_H
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "clamav.h"
#include "matcher-ac.h"
typedef struct cli_matcher cli_matcher; typedef struct cli_ctx_tag cli_ctx;
typedef enum IndicatorType {
/**
* For hash-based indicators.
*/
IndicatorType_Strong,
/**
* For potentially unwanted applications/programs that are not malicious but may be used maliciously.
*/
IndicatorType_PotentiallyUnwanted,
/**
* Weak indicators that together with other indicators can be used to form a stronger indicator.
* This type of indicator should NEVER alert the user on its own.
*/
IndicatorType_Weak,
} IndicatorType;
/**
* A generic container for any error that implements `Into<std::error::Error>`
*/
typedef struct FFIError FFIError;
bool script2cdiff(const char *script, const char *builder, const char *server);
/**
* This function is only meant to be called from sigtool.c
*/
int32_t cdiff_apply(int32_t fd, uint16_t mode);
/**
* Initialize a match vector
*/
evidence_t evidence_new(void);
/**
* Free the evidence
*/
void evidence_free(evidence_t evidence);
/**
* C interface for Evidence::render_verdict().
* Handles all the unsafe ffi stuff.
*
* Render a verdict based on the evidence, depending on the severity of the
* indicators found and the scan configuration.
*
* The individual alerting-indicators would have already been printed at this point.
*
* # Safety
*
* No parameters may be NULL
*/
bool evidence_render_verdict(evidence_t evidence);
/**
* C interface to get a string name for one of the alerts.
* Will first check for one from the strong indicators, then pua.
*
* # Safety
*
* Returns a string that is either static, or allocated when reading the database.
* So the lifetime of the string is good at least until you reload or unload the databases.
*
* No parameters may be NULL
*/
const char *evidence_get_last_alert(evidence_t evidence);
/**
* C interface to get a string name for one of the alerts.
* Will first check for one from the strong indicators, then pua.
*
* # Safety
*
* Returns a string that is either static, or allocated when reading the database.
* So the lifetime of the string is good at least until you reload or unload the databases.
*
* No parameters may be NULL
*/
const char *evidence_get_indicator(evidence_t evidence,
enum IndicatorType indicator_type,
uintptr_t index);
/**
* C interface to check number of alerting indicators in evidence.
*
* # Safety
*
* No parameters may be NULL
*/
uintptr_t evidence_num_alerts(evidence_t evidence);
/**
* C interface to check number of indicators in evidence.
* Handles all the unsafe ffi stuff.
*
* # Safety
*
* No parameters may be NULL
*/
uintptr_t evidence_num_indicators_type(evidence_t evidence, enum IndicatorType indicator_type);
/**
* C interface for Evidence::add_indicator().
* Handles all the unsafe ffi stuff.
*
* Add an indicator to the evidence.
*
* # Safety
*
* `hexsig` and `err` must not be NULL
*/
bool evidence_add_indicator(evidence_t evidence,
const char *name,
enum IndicatorType indicator_type,
struct FFIError **err);
/**
* Compute (and cache) a formatted error string from the provided [`FFIError`] pointer.
*
* # Safety
*
* `err` must not be NULL
*/
const char *ffierror_fmt(struct FFIError *err);
/**
* Free a [`FFIError`] structure
*
* # Safety
*
* `err` must not be NULL
*/
void ffierror_free(struct FFIError *err);
/**
* Initialize the hashmap
*/
fuzzyhashmap_t fuzzy_hashmap_new(void);
/**
* Free the hashmap
*/
void fuzzy_hash_free_hashmap(fuzzyhashmap_t fuzzy_hashmap);
/**
* C interface for FuzzyHashMap::check().
* Handles all the unsafe ffi stuff.
*
* # Safety
*
* No parameters may be NULL
*/
bool fuzzy_hash_check(fuzzyhashmap_t fuzzy_hashmap,
cli_ac_data *mdata,
image_fuzzy_hash_t image_fuzzy_hash);
/**
* C interface for FuzzyHashMap::load_subsignature().
* Handles all the unsafe ffi stuff.
*
* # Safety
*
* `hexsig` and `err` must not be NULL
*/
bool fuzzy_hash_load_subsignature(fuzzyhashmap_t fuzzy_hashmap,
const char *hexsig,
uint32_t lsig_id,
uint32_t subsig_id,
struct FFIError **err);
/**
* C interface for fuzzy_hash_calculate_image().
* Handles all the unsafe ffi stuff.
*
* # Safety
*
* `file_bytes` and `hash_out` must not be NULL
*/
bool fuzzy_hash_calculate_image(const uint8_t *file_bytes,
uintptr_t file_size,
uint8_t *hash_out,
uintptr_t hash_out_len,
struct FFIError **err);
bool clrs_log_init(void);
/**
* API exported for C code to log to standard error using Rust.
* This would be be an alternative to fputs, and reliably prints
* non-ASCII UTF8 characters on Windows, where fputs does not.
*/
void clrs_eprint(const char *c_buf);
#endif /* __CLAMAV_RUST_H */

View File

@@ -0,0 +1,48 @@
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
# Windows compatibility headers
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
endif()
# The clamscan executable.
add_executable( clamscan )
target_sources( clamscan
PRIVATE
clamscan.c
manager.c
manager.h
global.h )
if(WIN32)
target_sources( clamscan
PRIVATE
${CMAKE_SOURCE_DIR}/win32/res/clamscan.rc
${CMAKE_SOURCE_DIR}/win32/res/clam.manifest )
endif()
target_include_directories( clamscan
PRIVATE ${CMAKE_BINARY_DIR} # For clamav-config.h
)
set_target_properties( clamscan PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
if (APPLE AND CLAMAV_SIGN_FILE)
set_target_properties( clamscan PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${CODE_SIGN_IDENTITY}
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
)
endif()
target_link_libraries( clamscan
PRIVATE
ClamAV::libclamav
ClamAV::common )
if(WIN32)
install(TARGETS clamscan DESTINATION . COMPONENT programs)
install(FILES $<TARGET_PDB_FILE:clamscan> DESTINATION . OPTIONAL COMPONENT programs)
else()
install(TARGETS clamscan DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs)
endif()

21
clamav/clamscan/Doxyfile Normal file
View File

@@ -0,0 +1,21 @@
PROJECT_NAME = ClamAV - Clamscan
OUTPUT_DIRECTORY = ../docs/clamscan
WARNINGS = YES
FILE_PATTERNS = *.c *.h
PERL_PATH = /usr/bin/perl
SEARCHENGINE = YES
GENERATE_LATEX=NO
OPTIMIZE_OUTPUT_FOR_C=YES
HAVE_DOT=YES
CALL_GRAPH=YES
CALLER_GRAPH=YES
JAVADOC_AUTOBRIEF=YES
GENERATE_MAN=NO
EXAMPLE_PATH=examples
DOT_CLEANUP=NO
MAX_DOT_GRAPH_DEPTH=3
EXTRACT_ALL=YES
INPUT = .

346
clamav/clamscan/clamscan.c Normal file
View File

@@ -0,0 +1,346 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
* 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 <stdlib.h>
#include <string.h>
#include <signal.h>
#include <locale.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <time.h>
#ifdef C_LINUX
#include <sys/resource.h>
#endif
// libclamav
#include "clamav.h"
#include "others.h"
#include "str.h"
// common
#include "misc.h"
#include "output.h"
#include "actions.h"
#include "optparser.h"
#include "global.h"
#include "manager.h"
void help(void);
struct s_info info;
short recursion = 0, bell = 0;
short printinfected = 0, printclean = 1;
int _clamscan(int argc, char **argv)
{
int ds, dms, ret;
double mb, rmb;
struct timeval t1, t2;
time_t date_start, date_end;
char buffer[26];
#ifndef _WIN32
sigset_t sigset;
#endif
struct optstruct *opts;
const struct optstruct *opt;
if (check_flevel())
exit(2);
#if !defined(_WIN32)
if (!setlocale(LC_CTYPE, "")) {
mprintf(LOGG_WARNING, "Failed to set locale\n");
}
#if !defined(C_BEOS)
sigemptyset(&sigset);
sigaddset(&sigset, SIGXFSZ);
sigprocmask(SIG_SETMASK, &sigset, NULL);
#endif /* !C_BEOS */
#endif /* !_WIN32 */
cl_initialize_crypto();
if ((opts = optparse(NULL, argc, argv, 1, OPT_CLAMSCAN, 0, NULL)) == NULL) {
mprintf(LOGG_ERROR, "Can't parse command line options\n");
return 2;
}
if (optget(opts, "verbose")->enabled) {
mprintf_verbose = 1;
logg_verbose = 1;
}
if (optget(opts, "quiet")->enabled)
mprintf_quiet = 1;
if (optget(opts, "stdout")->enabled)
mprintf_stdout = 1;
if (optget(opts, "debug")->enabled) {
#if defined(C_LINUX)
/* njh@bandsman.co.uk: create a dump if needed */
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
perror("setrlimit");
#endif
cl_debug(); /* enable debug messages */
}
if (optget(opts, "gen-mdb")->enabled) {
cl_always_gen_section_hash();
}
if (optget(opts, "version")->enabled) {
print_version(optget(opts, "database")->strarg);
optfree(opts);
return 0;
}
if (optget(opts, "help")->enabled) {
optfree(opts);
help();
return 0;
}
if (optget(opts, "recursive")->enabled)
recursion = 1;
if (optget(opts, "infected")->enabled)
printinfected = 1;
if (optget(opts, "suppress-ok-results")->enabled)
printclean = 0;
if (optget(opts, "bell")->enabled)
bell = 1;
/* initialize logger */
if ((opt = optget(opts, "log"))->enabled) {
logg_file = opt->strarg;
if (logg(LOGG_INFO_NF, "\n-------------------------------------------------------------------------------\n\n")) {
mprintf(LOGG_ERROR, "Problem with internal logger.\n");
optfree(opts);
return 2;
}
} else
logg_file = NULL;
if (actsetup(opts)) {
optfree(opts);
logg_close();
exit(2);
}
memset(&info, 0, sizeof(struct s_info));
date_start = time(NULL);
gettimeofday(&t1, NULL);
ret = scanmanager(opts);
if (!optget(opts, "no-summary")->enabled) {
struct tm tmp;
date_end = time(NULL);
gettimeofday(&t2, NULL);
ds = t2.tv_sec - t1.tv_sec;
dms = t2.tv_usec - t1.tv_usec;
ds -= (dms < 0) ? (1) : (0);
dms += (dms < 0) ? (1000000) : (0);
logg(LOGG_INFO, "\n----------- SCAN SUMMARY -----------\n");
logg(LOGG_INFO, "Known viruses: %u\n", info.sigs);
logg(LOGG_INFO, "Engine version: %s\n", get_version());
logg(LOGG_INFO, "Scanned directories: %u\n", info.dirs);
logg(LOGG_INFO, "Scanned files: %u\n", info.files);
logg(LOGG_INFO, "Infected files: %u\n", info.ifiles);
if (info.errors)
logg(LOGG_INFO, "Total errors: %u\n", info.errors);
if (notremoved) {
logg(LOGG_INFO, "Not removed: %u\n", notremoved);
}
if (notmoved) {
logg(LOGG_INFO, "Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved);
}
mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
logg(LOGG_INFO, "Data scanned: %2.2lf MB\n", mb);
rmb = info.rblocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
logg(LOGG_INFO, "Data read: %2.2lf MB (ratio %.2f:1)\n", rmb, info.rblocks ? (double)info.blocks / (double)info.rblocks : 0);
logg(LOGG_INFO, "Time: %u.%3.3u sec (%u m %u s)\n", ds, dms / 1000, ds / 60, ds % 60);
#ifdef _WIN32
if (0 != localtime_s(&tmp, &date_start)) {
#else
if (!localtime_r(&date_start, &tmp)) {
#endif
logg(LOGG_ERROR, "Failed to get local time for Start Date.\n");
}
strftime(buffer, sizeof(buffer), "%Y:%m:%d %H:%M:%S", &tmp);
logg(LOGG_INFO, "Start Date: %s\n", buffer);
#ifdef _WIN32
if (0 != localtime_s(&tmp, &date_end)) {
#else
if (!localtime_r(&date_end, &tmp)) {
#endif
logg(LOGG_ERROR, "Failed to get local time for End Date.\n");
}
strftime(buffer, sizeof(buffer), "%Y:%m:%d %H:%M:%S", &tmp);
logg(LOGG_INFO, "End Date: %s\n", buffer);
}
optfree(opts);
return ret;
}
void help(void)
{
mprintf_stdout = 1;
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " Clam AntiVirus: Scanner %s\n", get_version());
mprintf(LOGG_INFO, " By The ClamAV Team: https://www.clamav.net/about.html#credits\n");
mprintf(LOGG_INFO, " (C) 2022 Cisco Systems, Inc.\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " clamscan [options] [file/directory/-]\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " --help -h Show this help\n");
mprintf(LOGG_INFO, " --version -V Print version number\n");
mprintf(LOGG_INFO, " --verbose -v Be verbose\n");
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives\n");
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages\n");
mprintf(LOGG_INFO, " --quiet Only output error messages\n");
mprintf(LOGG_INFO, " --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning\n");
mprintf(LOGG_INFO, " --infected -i Only print infected files\n");
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files\n");
mprintf(LOGG_INFO, " --bell Sound bell on virus detection\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n");
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n");
mprintf(LOGG_INFO, " --gen-json[=yes/no(*)] Generate JSON metadata for the scanned file(s). For testing & development use ONLY.\n");
mprintf(LOGG_INFO, " JSON will be printed if --debug is enabled.\n");
mprintf(LOGG_INFO, " A JSON file will dropped to the temp directory if --leave-temps is enabled.\n");
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR\n");
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures\n");
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE\n");
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively\n");
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match\n");
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems\n");
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always)\n");
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always)\n");
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE\n");
mprintf(LOGG_INFO, " --remove[=yes/no(*)] Remove infected files. Be careful!\n");
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY\n");
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY\n");
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX\n");
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX\n");
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX\n");
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX\n");
#ifdef _WIN32
mprintf(LOGG_INFO, " --memory Scan loaded executable modules\n");
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules\n");
mprintf(LOGG_INFO, " --unload Unload infected modules from processes\n");
#endif
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database\n");
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode\n");
mprintf(LOGG_INFO, " **Caution**: You should NEVER run bytecode signatures from untrusted sources.\n");
mprintf(LOGG_INFO, " Doing so may result in arbitrary code execution.\n");
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds)\n");
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics\n");
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications\n");
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT\n");
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT\n");
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card)\n");
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both)\n");
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect\n");
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect\n");
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only\n");
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files\n");
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection\n");
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection\n");
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts\n");
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found\n");
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility\n");
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files\n");
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files\n");
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers\n");
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files\n");
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files\n");
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files\n");
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files\n");
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files\n");
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav)\n");
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF)\n");
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF)\n");
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents\n");
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives\n");
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents\n");
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros\n");
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit\n");
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs\n");
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs\n");
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections\n");
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files\n");
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds)\n");
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean\n");
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**)\n");
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**)\n");
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**)\n");
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level\n");
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE\n");
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize\n");
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan\n");
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize\n");
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze\n");
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned\n");
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned\n");
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function\n");
#if HAVE_PCRE
mprintf(LOGG_INFO, " --pcre-match-limit=#n Maximum calls to the PCRE match function.\n");
mprintf(LOGG_INFO, " --pcre-recmatch-limit=#n Maximum recursive calls to the PCRE match function.\n");
mprintf(LOGG_INFO, " --pcre-max-filesize=#n Maximum size file to perform PCRE subsig matching.\n");
#endif /* HAVE_PCRE */
mprintf(LOGG_INFO, " --disable-cache Disable caching and cache checks for hash sums of scanned files.\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, "Pass in - as the filename for stdin.\n");
mprintf(LOGG_INFO, "\n");
mprintf(LOGG_INFO, "(*) Default scan settings\n");
mprintf(LOGG_INFO, "(**) Certain files (e.g. documents, archives, etc.) may in turn contain other\n");
mprintf(LOGG_INFO, " files inside. The above options ensure safe processing of this kind of data.\n\n");
}

1676
clamav/clamscan/manager.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
# Windows compatibility headers
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
endif()
# The "common" static library.
add_library( common STATIC )
target_sources( common
PRIVATE
cert_util.c
actions.c
clamdcom.c
getopt.c
hostid.c
idmef_logging.c
misc.c
optparser.c
output.c
tar.c
PUBLIC
cert_util.h
actions.h
clamdcom.h
fdpassing.h
getopt.h
hostid.h
idmef_logging.h
misc.h
optparser.h
output.h
tar.h )
target_include_directories( common
PRIVATE ${CMAKE_BINARY_DIR}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
if(FOUND_SYSTEMD)
target_include_directories( common
PRIVATE ${SYSTEMD_INCLUDE_DIRS} )
endif()
if(APPLE)
target_sources( common PRIVATE mac/cert_util_mac.m )
elseif(WIN32)
target_sources( common
PRIVATE service.c scanmem.c exescanner.c
PUBLIC service.h scanmem.h exescanner.h )
target_sources( common PRIVATE win/cert_util_win.c )
else()
target_sources( common PRIVATE linux/cert_util_linux.c )
endif()
target_link_libraries( common
PUBLIC
ClamAV::libclamav
ZLIB::ZLIB
CURL::libcurl
OpenSSL::SSL
OpenSSL::Crypto )
if(WIN32)
target_link_libraries( common
PUBLIC
crypt32
psapi)
endif()
if(HAVE_SYSTEMD)
target_link_libraries( common
PRIVATE
SYSTEMD::systemd )
endif()
set_target_properties( common PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
if(WIN32)
set_target_properties(common PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
add_library( ClamAV::common ALIAS common )

View File

@@ -154,11 +154,11 @@ static HANDLE win32_openat(
cchNextDirectoryName = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
filenameW = malloc(cchNextDirectoryName * sizeof(WCHAR));
if (NULL == filenameW) {
logg("win32_openat: failed to allocate memory for next directory name UTF16LE string\n");
logg(LOGG_INFO, "win32_openat: failed to allocate memory for next directory name UTF16LE string\n");
goto done;
}
if (0 == MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, cchNextDirectoryName)) {
logg("win32_openat: failed to allocate buffer for unicode version of intermediate directory name.\n");
logg(LOGG_INFO, "win32_openat: failed to allocate buffer for unicode version of intermediate directory name.\n");
goto done;
}
pRtlInitUnicodeString(&filenameU, filenameW);
@@ -183,32 +183,32 @@ static HANDLE win32_openat(
NULL, // EaBuffer
0); // EaLength
if (!NT_SUCCESS(ntStatus) || (NULL == next_handle)) {
logg("win32_openat: Failed to open file '%s'. \nError: 0x%x \nioStatusBlock: 0x%x\n", filename, ntStatus, ioStatusBlock.Information);
logg(LOGG_INFO, "win32_openat: Failed to open file '%s'. \nError: 0x%x \nioStatusBlock: 0x%x\n", filename, ntStatus, ioStatusBlock.Information);
goto done;
}
logg("*win32_openat: Opened file \"%s\"\n", filename);
logg(LOGG_DEBUG, "win32_openat: Opened file \"%s\"\n", filename);
if (0 == GetFileInformationByHandleEx(
next_handle, // hFile,
FileAttributeTagInfo, // FileInformationClass
&tagInfo, // lpFileInformation
sizeof(FILE_ATTRIBUTE_TAG_INFO))) { // dwBufferSize
logg("win32_openat: Failed to get file information by handle '%s'. Error: %d.\n", filename, GetLastError());
logg(LOGG_INFO, "win32_openat: Failed to get file information by handle '%s'. Error: %d.\n", filename, GetLastError());
CloseHandle(next_handle);
next_handle = NULL;
goto done;
}
logg("*win32_openat: tagInfo.FileAttributes: 0x%0x\n", tagInfo.FileAttributes);
logg("*win32_openat: tagInfo.ReparseTag: 0x%0x\n", tagInfo.ReparseTag);
logg(LOGG_DEBUG, "win32_openat: tagInfo.FileAttributes: 0x%0x\n", tagInfo.FileAttributes);
logg(LOGG_DEBUG, "win32_openat: tagInfo.ReparseTag: 0x%0x\n", tagInfo.ReparseTag);
if (0 != (tagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
logg("win32_openat: File is a soft link: '%s' Aborting path traversal.\n\n", filename);
logg(LOGG_INFO, "win32_openat: File is a soft link: '%s' Aborting path traversal.\n\n", filename);
CloseHandle(next_handle);
next_handle = NULL;
goto done;
}
logg("*win32_openat: File or directory is not a soft link.\n\n");
logg(LOGG_DEBUG, "win32_openat: File or directory is not a soft link.\n\n");
done:
if (NULL != filenameW) {
@@ -265,37 +265,37 @@ static int traverse_to(const char *directory, bool want_directory_handle, HANDLE
#endif
if (NULL == directory || NULL == out_handle) {
logg("traverse_to: Invalid arguments!\n");
logg(LOGG_INFO, "traverse_to: Invalid arguments!\n");
goto done;
}
#ifdef _WIN32
ntdll = LoadLibraryA("ntdll.dll");
if (NULL == ntdll) {
logg("traverse_to: failed to load ntdll!\n");
logg(LOGG_INFO, "traverse_to: failed to load ntdll!\n");
goto done;
}
pNtCreateFile = (PNTCF)GetProcAddress(ntdll, "NtCreateFile");
if (NULL == pNtCreateFile) {
logg("traverse_to: failed to get NtCreateFile proc address!\n");
logg(LOGG_INFO, "traverse_to: failed to get NtCreateFile proc address!\n");
goto done;
}
pRtlInitUnicodeString = (PRIUS)GetProcAddress(ntdll, "RtlInitUnicodeString");
if (NULL == pRtlInitUnicodeString) {
logg("traverse_to: failed to get pRtlInitUnicodeString proc address!\n");
logg(LOGG_INFO, "traverse_to: failed to get pRtlInitUnicodeString proc address!\n");
goto done;
}
#endif
tokenized_directory = strdup(directory);
if (NULL == tokenized_directory) {
logg("traverse_to: Failed to get copy of directory path to be tokenized!\n");
logg(LOGG_INFO, "traverse_to: Failed to get copy of directory path to be tokenized!\n");
goto done;
}
tokens_count = cli_strtokenize(tokenized_directory, *PATHSEP, PATH_MAX / 2, tokens);
if (0 == tokens_count) {
logg("traverse_to: tokenize of target directory returned 0 tokens!\n");
logg(LOGG_INFO, "traverse_to: tokenize of target directory returned 0 tokens!\n");
goto done;
}
@@ -306,7 +306,7 @@ static int traverse_to(const char *directory, bool want_directory_handle, HANDLE
*/
current_handle = open("/", O_RDONLY | O_NOFOLLOW);
if (-1 == current_handle) {
logg("traverse_to: Failed to open file descriptor for '/' directory.\n");
logg(LOGG_INFO, "traverse_to: Failed to open file descriptor for '/' directory.\n");
goto done;
}
#endif
@@ -316,7 +316,7 @@ static int traverse_to(const char *directory, bool want_directory_handle, HANDLE
}
if (0 == tokens_count) {
logg("traverse_to: Failed to get copy of directory path to be tokenized!\n");
logg(LOGG_INFO, "traverse_to: Failed to get copy of directory path to be tokenized!\n");
goto done;
}
@@ -328,7 +328,7 @@ static int traverse_to(const char *directory, bool want_directory_handle, HANDLE
#ifndef _WIN32
next_handle = openat(current_handle, tokens[i], O_RDONLY | O_NOFOLLOW);
if (-1 == next_handle) {
logg("traverse_to: Failed open %s\n", tokens[i]);
logg(LOGG_INFO, "traverse_to: Failed open %s\n", tokens[i]);
goto done;
}
close(current_handle);
@@ -369,14 +369,14 @@ static int traverse_to(const char *directory, bool want_directory_handle, HANDLE
shareAccess);
}
if (NULL == next_handle) {
logg("traverse_to: Failed open %s\n", tokens[i]);
logg(LOGG_INFO, "traverse_to: Failed open %s\n", tokens[i]);
goto done;
}
CloseHandle(current_handle);
current_handle = next_handle;
next_handle = NULL;
#endif
logg("*traverse_to: Handle opened for '%s' directory.\n", tokens[i]);
logg(LOGG_DEBUG, "traverse_to: Handle opened for '%s' directory.\n", tokens[i]);
}
status = 0;
@@ -426,22 +426,22 @@ static int traverse_rename(const char *source, const char *destination)
#endif
if (NULL == source || NULL == destination) {
logg("traverse_rename: Invalid arguments!\n");
logg(LOGG_INFO, "traverse_rename: Invalid arguments!\n");
goto done;
}
#ifndef _WIN32
if (0 != traverse_to(source, true, &source_directory_fd)) {
logg("traverse_rename: Failed to open file descriptor for source directory!\n");
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for source directory!\n");
goto done;
}
#else
if (0 != traverse_to(source, false, &source_file_handle)) {
logg("traverse_rename: Failed to open file descriptor for source file!\n");
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for source file!\n");
goto done;
}
if (0 != traverse_to(destination, true, &destination_dir_handle)) {
logg("traverse_rename: Failed to open file descriptor for destination directory!\n");
logg(LOGG_INFO, "traverse_rename: Failed to open file descriptor for destination directory!\n");
goto done;
}
#endif
@@ -449,12 +449,12 @@ static int traverse_rename(const char *source, const char *destination)
#ifndef _WIN32
ret = cli_basename(source, strlen(source), &source_basename);
if (CL_SUCCESS != ret) {
logg("traverse_rename: Failed to get basename of source path:%s\n\tError: %d\n", source, (int)ret);
logg(LOGG_INFO, "traverse_rename: Failed to get basename of source path:%s\n\tError: %d\n", source, (int)ret);
goto done;
}
if (0 != renameat(source_directory_fd, source_basename, -1, destination)) {
logg("traverse_rename: Failed to rename: %s\n\tto: %s\nError:%s\n", source, destination, strerror(errno));
logg(LOGG_INFO, "traverse_rename: Failed to rename: %s\n\tto: %s\nError:%s\n", source, destination, strerror(errno));
goto done;
}
#else
@@ -462,17 +462,17 @@ static int traverse_rename(const char *source, const char *destination)
cchDestFilepath = MultiByteToWideChar(CP_UTF8, 0, destination, strlen(destination), NULL, 0);
destFilepathW = calloc(cchDestFilepath * sizeof(WCHAR), 1);
if (NULL == destFilepathW) {
logg("traverse_rename: failed to allocate memory for destination basename UTF16LE string\n");
logg(LOGG_INFO, "traverse_rename: failed to allocate memory for destination basename UTF16LE string\n");
goto done;
}
if (0 == MultiByteToWideChar(CP_UTF8, 0, destination, strlen(destination), destFilepathW, cchDestFilepath)) {
logg("traverse_rename: failed to allocate buffer for UTF16LE version of destination file basename.\n");
logg(LOGG_INFO, "traverse_rename: failed to allocate buffer for UTF16LE version of destination file basename.\n");
goto done;
}
fileInfo = calloc(1, sizeof(FILE_RENAME_INFO) + cchDestFilepath * sizeof(WCHAR));
if (NULL == fileInfo) {
logg("traverse_rename: failed to allocate memory for fileInfo struct\n");
logg(LOGG_INFO, "traverse_rename: failed to allocate memory for fileInfo struct\n");
goto done;
}
@@ -486,7 +486,7 @@ static int traverse_rename(const char *source, const char *destination)
fileInfo, // FileInformation
sizeof(FILE_RENAME_INFO) + cchDestFilepath * sizeof(WCHAR))) { // Length
logg("traverse_rename: Failed to set file rename info for '%s' to '%s'.\nError: %d\n", source, destination, GetLastError());
logg(LOGG_INFO, "traverse_rename: Failed to set file rename info for '%s' to '%s'.\nError: %d\n", source, destination, GetLastError());
goto done;
}
#endif
@@ -544,7 +544,7 @@ static int traverse_unlink(const char *target)
char *target_basename = NULL;
if (NULL == target) {
logg("traverse_unlink: Invalid arguments!\n");
logg(LOGG_INFO, "traverse_unlink: Invalid arguments!\n");
goto done;
}
@@ -555,19 +555,19 @@ static int traverse_unlink(const char *target)
/* On Windows, we want a handle to the file, not the directory */
if (0 != traverse_to(target, false, &target_file_handle)) {
#endif
logg("traverse_unlink: Failed to open file descriptor for target directory!\n");
logg(LOGG_INFO, "traverse_unlink: Failed to open file descriptor for target directory!\n");
goto done;
}
ret = cli_basename(target, strlen(target), &target_basename);
if (CL_SUCCESS != ret) {
logg("traverse_unlink: Failed to get basename of target path: %s\n\tError: %d\n", target, (int)ret);
logg(LOGG_INFO, "traverse_unlink: Failed to get basename of target path: %s\n\tError: %d\n", target, (int)ret);
goto done;
}
#ifndef _WIN32
if (0 != unlinkat(target_directory_fd, target_basename, 0)) {
logg("traverse_unlink: Failed to unlink: %s\nError:%s\n", target, strerror(errno));
logg(LOGG_INFO, "traverse_unlink: Failed to unlink: %s\nError:%s\n", target, strerror(errno));
goto done;
}
#else
@@ -578,11 +578,11 @@ static int traverse_unlink(const char *target)
&fileInfo, // FileInformation
sizeof(FILE_DISPOSITION_INFO))) { // Length
logg("traverse_unlink: Failed to set file disposition to 'DELETE' for '%s'.\n", target);
logg(LOGG_INFO, "traverse_unlink: Failed to set file disposition to 'DELETE' for '%s'.\n", target);
goto done;
}
if (FALSE == CloseHandle(target_file_handle)) {
logg("traverse_unlink: Failed to set close & delete file '%s'.\n", target);
logg(LOGG_INFO, "traverse_unlink: Failed to set close & delete file '%s'.\n", target);
goto done;
}
target_file_handle = NULL;
@@ -626,14 +626,14 @@ static void action_move(const char *filename)
#else
if (fd < 0 || (((copied = 1)) && filecopy(filename, nuname))) {
#endif
logg("!Can't move file %s to %s\n", filename, nuname);
logg(LOGG_ERROR, "Can't move file %s to %s\n", filename, nuname);
notmoved++;
if (nuname) traverse_unlink(nuname);
} else {
if (copied && (0 != traverse_unlink(filename)))
logg("!Can't unlink '%s' after copy: %s\n", filename, strerror(errno));
logg(LOGG_ERROR, "Can't unlink '%s' after copy: %s\n", filename, strerror(errno));
else
logg("~%s: moved to '%s'\n", filename, nuname);
logg(LOGG_INFO, "%s: moved to '%s'\n", filename, nuname);
}
done:
@@ -649,11 +649,11 @@ static void action_copy(const char *filename)
int fd = getdest(filename, &nuname);
if (fd < 0 || filecopy(filename, nuname)) {
logg("!Can't copy file '%s'\n", filename);
logg(LOGG_ERROR, "Can't copy file '%s'\n", filename);
notmoved++;
if (nuname) traverse_unlink(nuname);
} else
logg("~%s: copied to '%s'\n", filename, nuname);
logg(LOGG_INFO, "%s: copied to '%s'\n", filename, nuname);
if (fd >= 0) close(fd);
if (nuname) free(nuname);
@@ -668,10 +668,10 @@ static void action_remove(const char *filename)
}
if (0 != traverse_unlink(filename)) {
logg("!Can't remove file '%s'\n", filename);
logg(LOGG_ERROR, "Can't remove file '%s'\n", filename);
notremoved++;
} else {
logg("~%s: Removed.\n", filename);
logg(LOGG_INFO, "%s: Removed.\n", filename);
}
done:
@@ -683,7 +683,7 @@ static int isdir(void)
{
STATBUF sb;
if (CLAMSTAT(actarget, &sb) || !S_ISDIR(sb.st_mode)) {
logg("!'%s' doesn't exist or is not a directory\n", actarget);
logg(LOGG_ERROR, "'%s' doesn't exist or is not a directory\n", actarget);
return 0;
}
return 1;
@@ -704,7 +704,7 @@ int actsetup(const struct optstruct *opts)
#ifndef _WIN32
ret = cli_realpath((const char *)actarget, &actarget);
if (CL_SUCCESS != ret || NULL == actarget) {
logg("action_setup: Failed to get realpath of %s\n", actarget);
logg(LOGG_INFO, "action_setup: Failed to get realpath of %s\n", actarget);
return 0;
}
#endif

View File

@@ -46,14 +46,14 @@ static cl_error_t _x509_to_pem(X509 *cert,
char *pem_data = NULL;
if (cert == NULL || data == NULL || len == NULL) {
mprintf("!_x509_to_pem: Invalid argument\n");
mprintf(LOGG_ERROR, "_x509_to_pem: Invalid argument\n");
goto done;
}
/* Output the certs to a new BIO using the PEM format */
out = BIO_new(BIO_s_mem());
if (!out) {
mprintf("!BIO_new failed\n");
mprintf(LOGG_ERROR, "BIO_new failed\n");
goto done;
}
@@ -64,14 +64,14 @@ static cl_error_t _x509_to_pem(X509 *cert,
/* Convert the BIO to char* */
pem_len = BIO_get_mem_data(out, &pem_data);
if (pem_len <= 0 || !pem_data) {
mprintf("!BIO_new: BIO_get_mem_data failed\n");
mprintf(LOGG_ERROR, "BIO_new: BIO_get_mem_data failed\n");
BIO_free_all(out);
goto done;
}
*data = calloc(1, pem_len + 1);
if (!*data) {
mprintf("!BIO_new: malloc failed\n");
mprintf(LOGG_ERROR, "BIO_new: malloc failed\n");
BIO_free_all(out);
goto done;
}
@@ -85,7 +85,7 @@ static cl_error_t _x509_to_pem(X509 *cert,
ret = CL_SUCCESS;
done:
return (0);
return ret;
}
/**
@@ -119,22 +119,22 @@ static cl_error_t _x509_to_pem_append(X509 *ca_cert,
if (ca_cert == NULL || total_buf_len == NULL ||
remaining_buf_len == NULL || *cert_data == NULL) {
mprintf("!NULL parameter given\n");
mprintf(LOGG_ERROR, "NULL parameter given\n");
goto done;
}
current_len = *total_buf_len;
if (_x509_to_pem(ca_cert, &pem_data, &pem_data_len) != 0) {
mprintf("!Failed to convert x509 certificate to PEM\n");
if (CL_SUCCESS != _x509_to_pem(ca_cert, &pem_data, &pem_data_len)) {
mprintf(LOGG_ERROR, "Failed to convert x509 certificate to PEM\n");
goto done;
}
if (pem_data_len > (int)*remaining_buf_len) {
tmp = realloc(*cert_data, current_len + pem_data_len + 1);
if (tmp == NULL) {
mprintf("!Could not realloc enough memory for PEM "
"certificate\n");
mprintf(LOGG_ERROR, "Could not realloc enough memory for PEM "
"certificate\n");
free(*cert_data);
*cert_data = NULL;
@@ -199,7 +199,7 @@ void cert_store_unload(void)
pt_err = pthread_mutex_lock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
cert_store_unload_int();
@@ -207,7 +207,7 @@ void cert_store_unload(void)
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
}
@@ -236,7 +236,7 @@ static cl_error_t x509_cert_name_cmp(X509 *cert_a, X509 *cert_b, int *cmp_out)
a = X509_get_subject_name(cert_a);
if (-1 == X509_NAME_print_ex(bio_out_a, a, 0, XN_FLAG_SEP_SPLUS_SPC)) {
mprintf("!Failed to print x509 certificate name!\n");
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
goto done;
}
BIO_get_mem_ptr(bio_out_a, &biomem_a);
@@ -244,7 +244,7 @@ static cl_error_t x509_cert_name_cmp(X509 *cert_a, X509 *cert_b, int *cmp_out)
b = X509_get_subject_name(cert_b);
if (-1 == X509_NAME_print_ex(bio_out_b, b, 0, XN_FLAG_SEP_SPLUS_SPC)) {
mprintf("!Failed to print x509 certificate name!\n");
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
goto done;
}
BIO_get_mem_ptr(bio_out_b, &biomem_b);
@@ -284,14 +284,14 @@ cl_error_t x509_get_cert_name(X509 *cert, char **name)
a = X509_get_subject_name(cert);
if (-1 == X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC)) {
mprintf("!Failed to print x509 certificate name!\n");
mprintf(LOGG_ERROR, "Failed to print x509 certificate name!\n");
goto done;
}
BIO_get_mem_ptr(bio_out, &biomem);
cert_name = malloc(biomem->length + 1);
if (!cert_name) {
mprintf("!Failed to allocate memory for certificate name biomem structure!\n");
mprintf(LOGG_ERROR, "Failed to allocate memory for certificate name biomem structure!\n");
goto done;
}
@@ -323,13 +323,13 @@ cl_error_t cert_store_export_pem(char **cert_data,
bool add_additional_ca_cert = true;
if ((cert_data == NULL) || (cert_data_len == NULL)) {
mprintf("!One or more arguments are NULL\n");
mprintf(LOGG_ERROR, "One or more arguments are NULL\n");
goto done;
}
*cert_data = calloc(1, STARTING_RAW_PEM_LENGTH + 1);
if (*cert_data == NULL) {
mprintf("!Could not allocate memory for PEM certs\n");
mprintf(LOGG_ERROR, "Could not allocate memory for PEM certs\n");
goto done;
}
*cert_data_len = 0;
@@ -337,7 +337,7 @@ cl_error_t cert_store_export_pem(char **cert_data,
pt_err = pthread_mutex_lock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
locked = true;
@@ -430,7 +430,7 @@ done:
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
locked = false;
}
@@ -451,14 +451,14 @@ cl_error_t cert_store_set_trusted_int(X509 **trusted_certs, size_t trusted_cert_
do {
if ((trusted_certs == NULL) || (trusted_cert_count == 0)) {
mprintf("!Empty trusted certificate list\n");
mprintf(LOGG_ERROR, "Empty trusted certificate list\n");
break;
}
tmp_trusted.certificates = calloc(trusted_cert_count,
sizeof(*tmp_trusted.certificates));
if (!tmp_trusted.certificates) {
mprintf("!Failed to reserve memory for trusted certs\n");
mprintf(LOGG_ERROR, "Failed to reserve memory for trusted certs\n");
break;
}
@@ -480,7 +480,7 @@ cl_error_t cert_store_set_trusted_int(X509 **trusted_certs, size_t trusted_cert_
tmp_trusted.certificates[tmp_trusted.count] =
X509_dup(trusted_certs[i]);
if (!tmp_trusted.certificates[tmp_trusted.count]) {
mprintf("!X509_dup failed at index: %zu\n", i);
mprintf(LOGG_ERROR, "X509_dup failed at index: %zu\n", i);
continue; /* continue on error */
}
@@ -509,7 +509,7 @@ cl_error_t cert_store_set_trusted(X509 **trusted_certs, size_t trusted_cert_coun
pt_err = pthread_mutex_lock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
if (_cert_store.loaded) {
@@ -519,7 +519,7 @@ cl_error_t cert_store_set_trusted(X509 **trusted_certs, size_t trusted_cert_coun
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
return ret;
@@ -533,7 +533,7 @@ size_t cert_store_remove_trusted(void)
pt_err = pthread_mutex_lock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
if (_cert_store.loaded) {
@@ -544,7 +544,7 @@ size_t cert_store_remove_trusted(void)
pt_err = pthread_mutex_unlock(&_cert_store.mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
return count;
@@ -558,7 +558,7 @@ void cert_fill_X509_store(X509_STORE *store, X509 **certs, size_t cert_count)
if (store && certs && cert_count > 0) {
for (i = 0; i < cert_count; ++i) {
if (!certs[i]) {
mprintf("!NULL cert at index %zu in X509 cert list; skipping\n", i);
mprintf(LOGG_ERROR, "NULL cert at index %zu in X509 cert list; skipping\n", i);
continue;
}
if (X509_STORE_add_cert(store, certs[i]) != 1) {
@@ -571,15 +571,18 @@ void cert_fill_X509_store(X509_STORE *store, X509 **certs, size_t cert_count)
#endif
err = ERR_get_error();
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == ERR_GET_REASON(err)) {
mprintf("*Certificate skipped; already exists in store: %s\n",
mprintf(LOGG_DEBUG, "Certificate skipped; already exists in store: %s\n",
(name ? name : ""));
} else {
mprintf("!Failed to add certificate to store: %s (%lu) [%s]\n",
mprintf(LOGG_ERROR, "Failed to add certificate to store: %s (%lu) [%s]\n",
ERR_error_string(err, NULL), err,
(name ? name : ""));
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
free(name);
if (NULL != name) {
free(name);
name = NULL;
}
#endif
}
}
@@ -593,24 +596,24 @@ void cert_store_export_certs(X509_STORE *store, X509 *additional_ca_cert)
do {
if (!store) {
mprintf("!NULL X509 store\n");
mprintf(LOGG_ERROR, "NULL X509 store\n");
break;
}
cert_store = cert_store_get_int();
if (!cert_store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
break;
}
pt_err = pthread_mutex_lock(&cert_store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
if (!cert_store->loaded) {
mprintf("!Cert store not loaded\n");
mprintf(LOGG_ERROR, "Cert store not loaded\n");
break;
}
@@ -637,16 +640,19 @@ void cert_store_export_certs(X509_STORE *store, X509 *additional_ca_cert)
name = additional_ca_cert->name;
#endif
if (X509_R_CERT_ALREADY_IN_HASH_TABLE == ERR_GET_REASON(err)) {
mprintf("Certificate is already in trust [%s]\n",
mprintf(LOGG_INFO, "Certificate is already in trust [%s]\n",
(name ? name : ""));
} else {
mprintf("!Failed to add CA certificate for the SSL context. "
"Error: %d [%s]\n",
mprintf(LOGG_ERROR, "Failed to add CA certificate for the SSL context. "
"Error: %d [%s]\n",
ERR_GET_REASON(err),
(name ? name : ""));
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
free(name);
if (NULL != name) {
free(name);
name = NULL;
}
#endif
}
} while (0);
@@ -655,7 +661,7 @@ void cert_store_export_certs(X509_STORE *store, X509 *additional_ca_cert)
pt_err = pthread_mutex_unlock(&cert_store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
}
}
@@ -670,13 +676,13 @@ CURLcode sslctx_function(CURL *curl, void *ssl_ctx, void *userptr)
cert_store = cert_store_get_int();
if (!cert_store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
goto done;
}
if (!cert_store->loaded) {
if (CL_SUCCESS != cert_store_load(NULL, 0)) {
mprintf("!Failed to load cert store\n");
mprintf(LOGG_ERROR, "Failed to load cert store\n");
goto done;
}
}

483
clamav/common/clamdcom.c Normal file
View File

@@ -0,0 +1,483 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2009-2013 Sourcefire, Inc.
*
* Author: aCaB
*
* 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 <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <errno.h>
#ifndef _WIN32
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#endif
#include "clamav.h"
#include "actions.h"
#include "output.h"
#include "clamdcom.h"
#ifndef _WIN32
struct sockaddr_un nixsock;
#endif
static const char *scancmd[] = {"CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN"};
/* Sends bytes over a socket
* Returns 0 on success */
int sendln(int sockd, const char *line, unsigned int len)
{
while (len) {
int sent = send(sockd, line, len, 0);
if (sent <= 0) {
if (sent && errno == EINTR) continue;
logg(LOGG_ERROR, "Can't send to clamd: %s\n", strerror(errno));
return 1;
}
line += sent;
len -= sent;
}
return 0;
}
/* Inits a RECVLN struct before it can be used in recvln() - see below */
void recvlninit(struct RCVLN *s, int sockd)
{
s->sockd = sockd;
s->bol = s->cur = s->buf;
s->r = 0;
}
/* Receives a full (terminated with \0) line from a socket
* Sets rbol to the begin of the received line, and optionally
* reol to the end of line.
* Should be called repeatedly until all input is consumed
* Returns:
* - the length of the line (a positive number) on success
* - 0 if the connection is closed
* - -1 on error
*/
int recvln(struct RCVLN *s, char **rbol, char **reol)
{
char *eol;
while (1) {
if (!s->r) {
s->r = recv(s->sockd, s->cur, sizeof(s->buf) - (s->cur - s->buf), 0);
if (s->r <= 0) {
if (s->r && errno == EINTR) {
s->r = 0;
continue;
}
if (s->r || s->cur != s->buf) {
*s->cur = '\0';
if (strcmp(s->buf, "UNKNOWN COMMAND\n"))
logg(LOGG_ERROR, "Communication error\n");
else
logg(LOGG_ERROR, "Command rejected by clamd (wrong clamd version?)\n");
return -1;
}
return 0;
}
}
if ((eol = memchr(s->cur, 0, s->r))) {
int ret = 0;
eol++;
s->r -= eol - s->cur;
*rbol = s->bol;
if (reol) *reol = eol;
ret = eol - s->bol;
if (s->r)
s->bol = s->cur = eol;
else
s->bol = s->cur = s->buf;
return ret;
}
s->r += s->cur - s->bol;
if (!eol && s->r == sizeof(s->buf)) {
logg(LOGG_ERROR, "Overlong reply from clamd\n");
return -1;
}
if (!eol) {
if (s->buf != s->bol) { /* old memmove sux */
memmove(s->buf, s->bol, s->r);
s->bol = s->buf;
}
s->cur = &s->bol[s->r];
s->r = 0;
}
}
}
/* Determines if a path should be excluded
* 0: scan, 1: skip */
int chkpath(const char *path, struct optstruct *clamdopts)
{
int status = 0;
const struct optstruct *opt;
char *real_path = NULL;
if (!path) {
status = 1;
goto done;
}
if ((opt = optget(clamdopts, "ExcludePath"))->enabled) {
while (opt) {
if (match_regex(path, opt->strarg) == 1) {
logg(LOGG_DEBUG, "%s: Excluded\n", path);
status = 1;
goto done;
}
opt = opt->nextarg;
}
}
done:
if (NULL != real_path) {
free(real_path);
}
return status;
}
#ifdef HAVE_FD_PASSING
/* Issues a FILDES command and pass a FD to clamd
* Returns >0 on success, 0 soft fail, -1 hard fail */
int send_fdpass(int sockd, const char *filename)
{
struct iovec iov[1];
struct msghdr msg;
struct cmsghdr *cmsg;
unsigned char fdbuf[CMSG_SPACE(sizeof(int))];
char dummy[] = "";
int fd;
const char zFILDES[] = "zFILDES";
if (filename) {
if ((fd = open(filename, O_RDONLY)) < 0) {
logg(LOGG_INFO, "%s: Failed to open file\n", filename);
return 0;
}
} else
fd = 0;
if (sendln(sockd, zFILDES, sizeof(zFILDES))) {
close(fd);
return -1;
}
iov[0].iov_base = dummy;
iov[0].iov_len = 1;
memset(&msg, 0, sizeof(msg));
msg.msg_control = fdbuf;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_controllen = CMSG_LEN(sizeof(int));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = fd;
if (sendmsg(sockd, &msg, 0) == -1) {
logg(LOGG_ERROR, "FD send failed: %s\n", strerror(errno));
close(fd);
return -1;
}
close(fd);
return 1;
}
#endif
/* Issues an INSTREAM command to clamd and streams the given file
* Returns >0 on success, 0 soft fail, -1 hard fail */
int send_stream(int sockd, const char *filename, struct optstruct *clamdopts)
{
uint32_t buf[BUFSIZ / sizeof(uint32_t)];
int fd, len;
unsigned long int todo = optget(clamdopts, "StreamMaxLength")->numarg;
const char zINSTREAM[] = "zINSTREAM";
if (filename) {
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) < 0) {
logg(LOGG_INFO, "%s: Failed to open file. ERROR\n", filename);
return 0;
}
} else {
/* Read stream from STDIN */
fd = 0;
}
if (sendln(sockd, zINSTREAM, sizeof(zINSTREAM))) {
close(fd);
return -1;
}
while ((len = read(fd, &buf[1], sizeof(buf) - sizeof(uint32_t))) > 0) {
if ((unsigned int)len > todo) len = todo;
buf[0] = htonl(len);
if (sendln(sockd, (const char *)buf, len + sizeof(uint32_t))) {
close(fd);
return -1;
}
todo -= len;
if (!todo) {
len = 0;
break;
}
}
close(fd);
if (len) {
logg(LOGG_ERROR, "Failed to read from %s.\n", filename ? filename : "STDIN");
return 0;
}
*buf = 0;
sendln(sockd, (const char *)buf, 4);
return 1;
}
/* Connects to clamd
* Returns a FD or -1 on error */
int dconnect(struct optstruct *clamdopts)
{
int sockd, res;
const struct optstruct *opt;
struct addrinfo hints, *info, *p;
char port[10];
char *ipaddr;
#ifndef _WIN32
opt = optget(clamdopts, "LocalSocket");
if (opt->enabled) {
if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
if (connect(sockd, (struct sockaddr *)&nixsock, sizeof(nixsock)) == 0)
return sockd;
else {
logg(LOGG_ERROR, "Could not connect to clamd on LocalSocket %s: %s\n", opt->strarg, strerror(errno));
close(sockd);
}
}
}
#endif
snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg);
opt = optget(clamdopts, "TCPAddr");
while (opt) {
if (opt->enabled) {
ipaddr = NULL;
if (opt->strarg)
ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg);
memset(&hints, 0x00, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((res = getaddrinfo(ipaddr, port, &hints, &info))) {
logg(LOGG_ERROR, "Could not lookup %s: %s\n", ipaddr ? ipaddr : "", gai_strerror(res));
opt = opt->nextarg;
continue;
}
for (p = info; p != NULL; p = p->ai_next) {
if ((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
logg(LOGG_ERROR, "Can't create the socket: %s\n", strerror(errno));
continue;
}
if (connect(sockd, p->ai_addr, p->ai_addrlen) < 0) {
logg(LOGG_ERROR, "Could not connect to clamd on %s: %s\n", opt->strarg, strerror(errno));
closesocket(sockd);
continue;
}
freeaddrinfo(info);
return sockd;
}
freeaddrinfo(info);
}
opt = opt->nextarg;
}
return -1;
}
/* Sends a proper scan request to clamd and parses its replies
* This is used only in non IDSESSION mode
* Returns the number of infected files or -1 on error
* NOTE: filename may be NULL for STREAM scantype. */
int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors, struct optstruct *clamdopts)
{
int infected = 0, len = 0, beenthere = 0;
char *bol, *eol;
struct RCVLN rcv;
STATBUF sb;
if (filename) {
if (1 == chkpath(filename, clamdopts)) {
goto done;
}
}
recvlninit(&rcv, sockd);
switch (scantype) {
case MULTI:
case CONT:
case ALLMATCH:
if (!filename) {
logg(LOGG_INFO, "Filename cannot be NULL for MULTISCAN or CONTSCAN.\n");
infected = -1;
goto done;
}
len = strlen(filename) + strlen(scancmd[scantype]) + 3;
if (!(bol = malloc(len))) {
logg(LOGG_ERROR, "Cannot allocate a command buffer: %s\n", strerror(errno));
infected = -1;
goto done;
}
sprintf(bol, "z%s %s", scancmd[scantype], filename);
if (sendln(sockd, bol, len)) {
free(bol);
infected = -1;
goto done;
}
free(bol);
break;
case STREAM:
/* NULL filename safe in send_stream() */
len = send_stream(sockd, filename, clamdopts);
break;
#ifdef HAVE_FD_PASSING
case FILDES:
/* NULL filename safe in send_fdpass() */
len = send_fdpass(sockd, filename);
break;
#endif
}
if (len <= 0) {
if (printok)
*printok = 0;
if (errors)
(*errors)++;
infected = len;
goto done;
}
while ((len = recvln(&rcv, &bol, &eol))) {
if (len == -1) {
infected = -1;
goto done;
}
beenthere = 1;
if (!filename) logg(LOGG_INFO, "%s\n", bol);
if (len > 7) {
char *colon = strrchr(bol, ':');
if (colon && colon[1] != ' ') {
char *br;
*colon = 0;
br = strrchr(bol, '(');
if (br)
*br = 0;
colon = strrchr(bol, ':');
}
if (!colon) {
char *unkco = "UNKNOWN COMMAND";
if (!strncmp(bol, unkco, sizeof(unkco) - 1))
logg(LOGG_INFO, "clamd replied \"UNKNOWN COMMAND\". Command was %s\n",
(scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" : scancmd[scantype]);
else
logg(LOGG_INFO, "Failed to parse reply: \"%s\"\n", bol);
infected = -1;
goto done;
} else if (!memcmp(eol - 7, " FOUND", 6)) {
static char last_filename[PATH_MAX + 1] = {'\0'};
*(eol - 7) = 0;
if (printok)
*printok = 0;
if (scantype != ALLMATCH) {
infected++;
} else {
if (filename != NULL && strcmp(filename, last_filename)) {
infected++;
strncpy(last_filename, filename, PATH_MAX);
last_filename[PATH_MAX] = '\0';
}
}
if (filename) {
if (scantype >= STREAM) {
logg(LOGG_INFO, "%s%s FOUND\n", filename, colon);
if (action) action(filename);
} else {
logg(LOGG_INFO, "%s FOUND\n", bol);
*colon = '\0';
if (action)
action(bol);
}
}
} else if (!memcmp(eol - 7, " ERROR", 6)) {
if (errors)
(*errors)++;
if (printok)
*printok = 0;
if (filename) {
if (scantype >= STREAM)
logg(LOGG_INFO, "%s%s\n", filename, colon);
else
logg(LOGG_INFO, "%s\n", bol);
}
}
}
}
if (!beenthere) {
if (!filename) {
logg(LOGG_INFO, "STDIN: noreply from clamd\n.");
infected = -1;
goto done;
}
if (CLAMSTAT(filename, &sb) == -1) {
logg(LOGG_INFO, "%s: stat() failed with %s, clamd may not be responding\n",
filename, strerror(errno));
infected = -1;
goto done;
}
if (!S_ISDIR(sb.st_mode)) {
logg(LOGG_INFO, "%s: no reply from clamd\n", filename);
infected = -1;
goto done;
}
}
done:
return infected;
}

67
clamav/common/clamdcom.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2009-2013 Sourcefire, Inc.
*
* Author: aCaB
*
* 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.
*/
#ifndef __CLAMDCOM_H
#define __CLAMDCOM_H
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include "misc.h"
enum {
CONT,
MULTI,
STREAM,
FILDES,
ALLMATCH,
MAX_SCANTYPE = ALLMATCH
};
struct RCVLN {
char buf[PATH_MAX + 1024]; /* FIXME must match that in clamd - bb1349 */
int sockd;
int r;
char *cur;
char *bol;
};
#ifndef _WIN32
extern struct sockaddr_un nixsock;
#endif
int sendln(int sockd, const char *line, unsigned int len);
void recvlninit(struct RCVLN *s, int sockd);
int recvln(struct RCVLN *s, char **rbol, char **reol);
int chkpath(const char *path, struct optstruct *clamdopts);
#ifdef HAVE_FD_PASSING
int send_fdpass(int sockd, const char *filename);
#endif
int send_stream(int sockd, const char *filename, struct optstruct *clamdopts);
int dconnect(struct optstruct *clamdopts);
int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors, struct optstruct *clamdopts);
#endif

330
clamav/common/exeScanner.c Normal file
View File

@@ -0,0 +1,330 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#include "exescanner.h"
/* -1 = wildchar - -2 = stop here */
sigs_t signatures[] = {
{{0x60, 0xbe, -1, -1, -1, -1, 0x8d, 0xbe, -1, -1, -1, 0xff, 0x57, -2},
"UPX",
.0f},
{{0x94, 0xbc, 0x5d, 0x07, 0x42, 0x00, 0xb9, 0x1d, 0x00, 0x00, 0x00, 0x80,
0x34, 0x0c, 0x44, 0xe2},
"UPXSHiT",
.0f},
{{0xbe, 0xa4, 0x01, 0x40, 0x00, 0xad, 0x93, 0xad, 0x97, 0xad, 0x56, 0x96,
0xb2, 0x80, 0xa4, 0xb6},
"FSG 1.33",
.0f},
{{0x4d, 0x5a, -1, -1, -1, -1, -1, -1, -1, -1, 0x00, 0x00, 0x50, 0x45, 0x00,
0x00},
"FSG 2.00",
.0f},
{{0x4d, 0x5a, 0x4b, 0x45, 0x52, 0x4e, 0x45, 0x4c, 0x33, 0x32, 0x2e, 0x44,
0x4c, 0x4c, 0x00, 0x00},
"WinUpack 0.39",
.0f},
{{0xbe, 0x88, 0x01, 0x40, 0x00, 0xad, 0x8b, 0xf8, 0x95, 0xad, 0x91, 0xf3,
0xa5, 0xad, 0xb5, 0x1c},
"Upack 2.4/2.9",
.0f},
{{0xbe, 0x48, 0x01, 0x40, 0x00, 0xad, 0x8b, 0xf8, 0x95, 0xa5, 0x33, 0xc0,
0x33, 0xc9, 0xab, 0x48},
"Upack 1.1/1.2",
.0f},
{{0x83, 0xec, 0x20, 0x53, 0x55, 0x56, 0x33, 0xdb, 0x57, 0x89, 0x5c, 0x24,
0x18, 0xc7, 0x44, 0x24},
"NullSoft PiMP",
.0f},
{{0xe9, -1, -1, -1, 0xff, 0x0c, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00},
"Mew 11 1.2",
.0f},
{{0x60, 0xe9, 0x3d, 0x04, 0x00, 0x00, -2}, "ASPack 2.11", .0f},
{{0x60, 0xe8, 0x03, 0x00, 0x00, 0x00, 0xe9, 0xeb, 0x04, 0x5d, 0x45, 0x55,
0xc3, 0xe8, 0x01, 0x00},
"ASPack 2.12",
.0f},
{{0x55, 0x83, 0xc4, 0x04, 0x76, 0x08, 0x7a, 0x06, 0x74, 0x04, 0x66, 0x83,
0xea, 0x00, 0xf5, 0x50},
"Morphine 1.4/2.7",
.0f},
{{0x56, 0x72, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x0b, 0xd2, 0xf9,
0x84, 0xdb, 0x68, 0x34},
"Morphine 1.4/2.7 [2]",
.0f},
{{0x53, 0x51, 0x52, 0x56, 0x57, 0x55, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x5d,
0x8b, 0xd5, 0x81, 0xed},
"PEDiminisher 0.1",
.0f},
{{0xe8, 0xf6, 0x03, 0x00, 0x00, 0xe9, 0x9e, 0xfd, 0xff, 0xff, 0xcc, 0xcc,
0xcc, 0xcc, 0xcc, 0xcc},
"MSVC8 Release",
-1.0f},
{{0xe9, -1, -1, -1, 0x00, 0xe9, -1, -1, -1, 0x00, 0xe9, -1, -1, -1, 0x00,
0xe9},
"MSVC8 Debug",
-1.0f},
{{0xe8, -1, -1, 0x00, 0x00, 0xe9, 0x16, 0xfe, 0xff, 0xff, -2},
"MSVC6 Release",
-2.0f},
{{0xe9, 0x96, 0xee, 0x0e, 0x00, 0xb8, 0x6c, 0x02, 0x58, 0x00, 0xe8, 0xae,
0xe4, 0x0e, 0x00, 0x83},
"MSVC6 Release (2)",
-1.0f},
{{0x55, 0x8b, 0xec, 0x6a, 0xff, 0x68, 0xb0, 0x41, 0x40, 0x00, 0x68, 0x10,
0x36, 0x40, 0x00, 0x64},
"MSVC6 Release (3)",
-1.0f},
{{0x55, 0x8b, 0xec, 0x53, 0x8b, 0x5d, 0x08, 0x56, 0x8b, 0x75, 0x0c, 0x57,
0x8b, 0x7d, 0x10, 0x85},
"MSVC6 Release (4)",
-1.0f},
{{0x83, 0x7c, 0x24, 0x08, 0x01, 0x75, 0x05, 0xe8, -1, -1, 0x00, 0x00, 0xff,
0x74, 0x24, 0x04},
"MSVC6 Release DLL",
-1.0f},
{{0xff, 0x25, -1, -1, -1, -1, 0xcc, 0xcc, 0x03, 0x30, 0x01, 0x00, 0x07,
0x00, 0x00, 0x00},
"DotNet",
-1.0f},
{{0x55, 0x89, 0xe5, -2}, "MinGW", -1.0f},
{{0}, 0, 0}};
int sigcmp(const uint8_t *data, const int16_t *sig, size_t n)
{
uint8_t *d = (uint8_t *)data;
int16_t *s = (int16_t *)sig;
while (n-- != 0) {
if (*s == -2)
return 0;
if ((*s != -1) && (*d != *s))
return (*d < *s) ? -1 : +1;
d++;
s++;
}
return 0;
}
sigs_t *checksig(uint8_t *data)
{
int i = 0;
while (signatures[i].name) {
if (!sigcmp(data, signatures[i].sig, 16))
return &signatures[i];
i++;
}
return NULL;
}
double calc_entropy(const unsigned char *data, size_t size)
{
double entropy = .0f;
size_t p[256];
size_t c, i;
memset(p, 0, sizeof(p));
for (c = 0; c < size; c++)
p[data[c]]++;
for (i = 0; i < 256; i++)
if (p[i])
entropy -= ((double)p[i] / size) * log((double)p[i] / size);
return entropy;
}
#define FILLBYTES(dst) \
if (IsBadReadPtr(seek, sizeof(dst))) { \
logg(LOGG_ERROR, "exeScanner: Bad pointer!!!\n"); \
goto cleanup; \
} \
memcpy(&dst, seek, sizeof(dst));
/* Packed exe heuristic detection, errors are handled as like of non packed data
*/
int is_packed(const char *filename)
{
int packed = 0;
int i = 0, c = 0;
int badsection = 0;
double entropy = 0.0;
sigs_t *sig = NULL;
uint16_t e_mz;
uint32_t e_lfanew, e_magic;
uint32_t epoff = 0;
unsigned char *seek = NULL, *s_start = NULL, *ep = NULL, *lpMapAddress = NULL;
PIMAGE_FILE_HEADER pehdr;
PIMAGE_OPTIONAL_HEADER32 opthdr;
PIMAGE_SECTION_HEADER sechdr;
char secname[IMAGE_SIZEOF_SHORT_NAME];
HANDLE hFile = INVALID_HANDLE_VALUE, hMapFile = NULL;
hFile = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
elogg(LOGG_INFO, "exeScanner: CreateFileA failed %lu\n", GetLastError());
return packed; /* Returning packed, the module is loaded so it must exists
on disk */
}
hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, "exeScanner");
if (!hMapFile) {
elogg(LOGG_INFO, "exeScanner: CreateFileMappingA() failed %lu\n", GetLastError());
goto cleanup;
}
lpMapAddress = (LPBYTE)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (!lpMapAddress) {
elogg(LOGG_INFO, "exeScanner: MapViewOfFile() failed %lu\n", GetLastError());
goto cleanup;
}
seek = lpMapAddress;
/* DOS Signature 'MZ' */
FILLBYTES(e_mz);
if (e_mz != IMAGE_DOS_SIGNATURE) {
elogg(LOGG_INFO, "exeScanner: DOS Signature not found\n");
goto cleanup;
}
seek += 0x3c;
FILLBYTES(e_lfanew);
if (!e_lfanew) {
elogg(LOGG_INFO, "exeScanner: Invalid PE offset\n");
goto cleanup;
}
seek = lpMapAddress + e_lfanew;
/* PE Signature 'PE' */
FILLBYTES(e_magic);
if (e_magic != IMAGE_NT_SIGNATURE) {
elogg(LOGG_INFO, "exeScanner: PE Signature not found\n");
goto cleanup;
}
seek += sizeof(e_magic);
if (IsBadReadPtr(seek, sizeof(IMAGE_FILE_HEADER)))
goto cleanup;
pehdr = (PIMAGE_FILE_HEADER)seek;
seek += sizeof(IMAGE_FILE_HEADER);
if (IsBadReadPtr(seek, sizeof(IMAGE_OPTIONAL_HEADER32)))
goto cleanup;
opthdr = (PIMAGE_OPTIONAL_HEADER32)seek;
seek += sizeof(IMAGE_OPTIONAL_HEADER32);
if (pehdr->Machine != IMAGE_FILE_MACHINE_I386) {
elogg(LOGG_INFO, "exeScanner: Not an x86 executable\n");
goto cleanup;
}
/* Invalid sections number */
if ((pehdr->NumberOfSections < 1) || (pehdr->NumberOfSections > 32)) {
elogg(LOGG_INFO, "exeScanner: Invalid sections number\n");
packed = 1;
goto cleanup;
}
for (i = 0; i < pehdr->NumberOfSections; i++) {
double section_entropy = .0f;
if (IsBadReadPtr(seek, sizeof(IMAGE_SECTION_HEADER)))
goto cleanup;
sechdr = (PIMAGE_SECTION_HEADER)seek;
seek += sizeof(IMAGE_SECTION_HEADER);
if (opthdr->AddressOfEntryPoint >= sechdr->VirtualAddress)
epoff = opthdr->AddressOfEntryPoint - sechdr->VirtualAddress +
sechdr->PointerToRawData;
s_start = lpMapAddress + sechdr->PointerToRawData;
if (!IsBadReadPtr(s_start, sechdr->SizeOfRawData))
section_entropy = calc_entropy(s_start, sechdr->SizeOfRawData);
entropy = MAX(entropy, section_entropy);
/* Sanitize the section name */
memcpy(secname, sechdr->Name, IMAGE_SIZEOF_SHORT_NAME);
for (c = 0; (c < IMAGE_SIZEOF_SHORT_NAME) && secname[c]; c++)
if (!isprint(secname[c]))
secname[c] = '?';
secname[IMAGE_SIZEOF_SHORT_NAME - 1] = 0;
elogg(LOGG_INFO, "exeScanner: Section name: [%s] - Entropy %f\n", secname,
section_entropy);
if (!sechdr->SizeOfRawData)
badsection = 1;
}
elogg(LOGG_INFO, "exeScanner: Max entropy = %f\n", entropy);
/* EP Check */
elogg(LOGG_INFO, "exeScanner: Entry Point rva: 0x%lx - raw: 0x%lx\n",
opthdr->AddressOfEntryPoint, epoff);
ep = lpMapAddress + epoff;
if (!IsBadReadPtr(ep, EP_SIGNATURE_SIZE)) {
#ifdef DUMP_SIGNATURE
int i;
for (i = 0; i < EP_SIGNATURE_SIZE; i++)
elogg(LOGG_INFO, "%02x ", ep[i]);
elogg(LOGG_INFO, "\n[C Code]: ");
for (i = 0; i < EP_SIGNATURE_SIZE - 1; i++)
elogg(LOGG_INFO, "0x%02x, ", ep[i]);
elogg(LOGG_INFO, "0x%02x\n", ep[i]);
#endif
if ((sig = checksig(ep))) {
elogg(LOGG_INFO, "exeScanner: Signature check: %s\n", sig->name);
entropy += sig->score;
packed = (sig->score >= .0f);
if (sig->score < .0f)
elogg(
"exeScanner: Whitelisted signature found, lowering entropy to %f\n",
entropy);
} else
elogg(LOGG_INFO, "exeScanner: Signature check: Nothing found\n");
} else
elogg(LOGG_INFO, "exeScanner: Invalid address of Entry Point\n");
if (badsection) {
if ((entropy == .0f) || (entropy > ENTROPY_THRESHOLD)) {
elogg(LOGG_INFO, "exeScanner: found zero SizeOfRawData and entropy %f\n", entropy);
packed = 1;
goto cleanup;
}
}
cleanup:
if (lpMapAddress)
UnmapViewOfFile(lpMapAddress);
if (hMapFile)
CloseHandle(hMapFile);
CloseHandle(hFile);
return packed;
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2006-2008 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#ifndef _EXESCANNER_H_
#define _EXESCANNER_H_
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef EXESCANNER_STANDALONE
#define DUMP_SIGNATURE
#include <windows.h>
#define logg printf
#define elogg printf
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef __int16 int16_t;
#else
#include "output.h"
#include <others.h>
static inline void elogg(const char *fmt, ...){};
#endif /* EXESCANNER_STANDALONE */
#define ENTROPY_THRESHOLD 4.0
#define EP_SIGNATURE_SIZE 16
#ifndef IMAGE_DOS_SIGNATURE
#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
typedef struct _sigs_t {
int16_t sig[16];
const char *name;
double score;
} sigs_t;
extern int is_packed(const char *filename);
static const char screv[] =
{
0x65, 0x78, 0x65, 0x53, 0x63, 0x61, 0x6e, 0x6e,
0x65, 0x72, 0x7c, 0x47, 0x50, 0x4c, 0x7c, 0x47,
0x69, 0x61, 0x6e, 0x6c, 0x75, 0x69, 0x67, 0x69,
0x20, 0x54, 0x69, 0x65, 0x73, 0x69, 0x7c, 0x3c,
0x73, 0x68, 0x65, 0x72, 0x70, 0x79, 0x61, 0x40,
0x6e, 0x65, 0x74, 0x66, 0x61, 0x72, 0x6d, 0x2e,
0x69, 0x74, 0x3e};
#endif /* _EXESCANNER_H_ */

View File

@@ -9,10 +9,10 @@
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -193,7 +193,8 @@ static int _getopt_internal(int argc, char *argv[], const char *shortopts,
if ((argv[i][0] == '-') &&
(argv[i][1] != '\0')) {
optind = i;
opt = _getopt_internal(argc, argv, shortopts,
opt = _getopt_internal(argc, argv, shortopts,
longopts, longind,
long_only);
while (i > j) {

View File

@@ -9,10 +9,10 @@
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND

View File

@@ -58,7 +58,7 @@ char *get_hostid(void *cbdata)
if (!is_valid_hostid())
return strdup(STATS_ANON_UUID);
logg("HostID is valid: %s\n", hostid);
logg(LOGG_INFO, "HostID is valid: %s\n", hostid);
return strdup(hostid);
}

View File

@@ -35,7 +35,7 @@ void prelude_logging(const char *filename, const char *virname, const char *virh
UNUSEDPARAM(virhash);
UNUSEDPARAM(virsize);
logg("You have to compile with libprelude using ./configure --enable-prelude\n");
logg(LOGG_INFO, "You have to compile with libprelude using ./configure --enable-prelude\n");
}
#else
@@ -98,32 +98,32 @@ int prelude_initialize_client(const char *analyzer_name)
ret = prelude_init(0, NULL);
if (ret < 0) {
logg("Unable to initialize the prelude library : %s", prelude_strerror(ret));
logg(LOGG_INFO, "Unable to initialize the prelude library : %s", prelude_strerror(ret));
return -1;
}
ret = prelude_client_new(&prelude_client, analyzer_name);
if (ret < 0) {
logg("Unable to create a prelude client object : %s", prelude_strerror(ret));
logg(LOGG_INFO, "Unable to create a prelude client object : %s", prelude_strerror(ret));
return -1;
}
ret = idmef_analyzer_setup(prelude_client_get_analyzer(prelude_client), analyzer_name);
if (ret < 0) {
logg("%s", prelude_strerror(ret));
logg(LOGG_INFO, "%s", prelude_strerror(ret));
return -1;
}
ret = prelude_client_start(prelude_client);
if (ret < 0 || !prelude_client) {
logg("Unable to start prelude client : %s", prelude_strerror(ret));
logg(LOGG_INFO, "Unable to start prelude client : %s", prelude_strerror(ret));
prelude_client_destroy(prelude_client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
return -1;
}
ret = prelude_client_set_flags(prelude_client, PRELUDE_CLIENT_FLAGS_ASYNC_SEND | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER);
if (ret < 0) {
logg("Unable to send asynchronous send and timer : %s", prelude_strerror(ret));
logg(LOGG_INFO, "Unable to send asynchronous send and timer : %s", prelude_strerror(ret));
prelude_client_destroy(prelude_client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
return -1;
}
@@ -242,7 +242,7 @@ void prelude_logging(const char *filename, const char *virname, const char *virh
if (ret < 0)
goto err;
logg("le client : %s", prelude_client_get_config_filename(prelude_client));
logg(LOGG_INFO, "le client : %s", prelude_client_get_config_filename(prelude_client));
prelude_client_send_idmef(prelude_client, idmef);
idmef_message_destroy(idmef);
@@ -252,7 +252,7 @@ err:
if (idmef != NULL)
idmef_message_destroy(idmef);
logg("%s error: %s", prelude_strsource(ret), prelude_strerror(ret));
logg(LOGG_INFO, "%s error: %s", prelude_strsource(ret), prelude_strerror(ret));
return;
}
#endif

View File

@@ -55,14 +55,14 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
do {
store = cert_store_get_int();
if (!store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
break;
}
pt_err = pthread_mutex_lock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
if (store->loaded) {
@@ -77,10 +77,10 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
if (trusted_certs && trusted_cert_count > 0) {
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
mprintf("*Trusted certificates loaded: %zu\n",
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
store->trusted_certs.count);
} else {
mprintf("^Continuing without trusted certificates\n");
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
/* proceed as if we succeeded using only certificates from the
* system */
}
@@ -94,7 +94,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
pt_err = pthread_mutex_unlock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
}

View File

@@ -130,7 +130,7 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
status = SecKeychainOpen(kc_info.file_path, &keychain);
if (status != errSecSuccess) {
mprintf("!Failed to open %s keychain: %s (%d)\n",
mprintf(LOGG_ERROR, "Failed to open %s keychain: %s (%d)\n",
kc_info.name,
kc_info.file_path,
status);
@@ -139,13 +139,13 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
status = SecKeychainGetStatus(keychain, &keychainStatus);
if (status != errSecSuccess) {
mprintf("!Failed to get the status of the %s keychain: %d\n",
mprintf(LOGG_ERROR, "Failed to get the status of the %s keychain: %d\n",
kc_info.name,
status);
goto done;
}
if (!(keychainStatus & kSecReadPermStatus)) {
mprintf("!The %s keychain is not readable: %" PRIu32 "\n",
mprintf(LOGG_ERROR, "The %s keychain is not readable: %" PRIu32 "\n",
kc_info.name,
keychainStatus);
goto done;
@@ -158,7 +158,7 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
* has been tampered with.
*/
if (keychainStatus & (kSecUnlockStateStatus | kSecWritePermStatus)) {
mprintf("!System Root Certificates Keychain has invalid permissions: %" PRIu32 "\n",
mprintf(LOGG_ERROR, "System Root Certificates Keychain has invalid permissions: %" PRIu32 "\n",
keychainStatus);
/* continue on error */
}
@@ -167,7 +167,7 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
search_list = CFArrayCreate(kCFAllocatorDefault,
(const void **)&keychain, 1, &kCFTypeArrayCallBacks);
if (search_list == NULL) {
mprintf("!Failed to create %s keychain search list\n",
mprintf(LOGG_ERROR, "Failed to create %s keychain search list\n",
kc_info.name);
goto done;
}
@@ -179,7 +179,7 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (query == NULL) {
mprintf("!Failed to create %s keychain query dictionary\n",
mprintf(LOGG_ERROR, "Failed to create %s keychain query dictionary\n",
kc_info.name);
goto done;
}
@@ -187,10 +187,10 @@ static CFTypeRef _get_cert_ref(keychain_type_t keychain_type)
status = SecItemCopyMatching(query, &items);
if (status != errSecSuccess) {
if (status == errSecItemNotFound) {
mprintf("*No items found in %s keychain\n",
mprintf(LOGG_DEBUG, "No items found in %s keychain\n",
kc_info.name);
} else {
mprintf("!Unable to copy certificates from %s keychain (%d)\n",
mprintf(LOGG_ERROR, "Unable to copy certificates from %s keychain (%d)\n",
kc_info.name,
status);
}
@@ -239,7 +239,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
store = cert_store_get_int();
if (!store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
goto done;
}
@@ -259,7 +259,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
}
if (CFGetTypeID(items) != CFArrayGetTypeID()) {
mprintf("!Expected array of certificates from %s keychain, "
mprintf(LOGG_ERROR, "Expected array of certificates from %s keychain, "
"got type %lu\n",
kc_info.name,
CFGetTypeID(items));
@@ -275,7 +275,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
kc_data->certs = (CFArrayRef)items;
kc_data->certs_count = CFArrayGetCount(items);
mprintf("*Found %ld certificates from %s keychain\n",
mprintf(LOGG_DEBUG, "Found %ld certificates from %s keychain\n",
kc_data->certs_count,
kc_info.name);
@@ -283,7 +283,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
}
if (total_certificates < 1) {
mprintf("!No certificate found in keychains. Expect at least one "
mprintf(LOGG_ERROR, "No certificate found in keychains. Expect at least one "
"certificate to be found in system root and system "
"keychains\n");
goto done;
@@ -291,19 +291,19 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
store = cert_store_get_int();
if (!store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
goto done;
}
pt_err = pthread_mutex_lock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
locked = true;
if (store->loaded) {
mprintf("*Cert store already loaded\n");
mprintf(LOGG_DEBUG, "Cert store already loaded\n");
ret = CL_SUCCESS;
goto done;
}
@@ -312,7 +312,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
store->system_certs.certificates = calloc(total_certificates,
sizeof(*store->system_certs.certificates));
if (store->system_certs.certificates == NULL) {
mprintf("!Failed to reserve memory for system cert list\n");
mprintf(LOGG_ERROR, "Failed to reserve memory for system cert list\n");
goto done;
}
@@ -342,16 +342,19 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
#endif
if (x509) {
mprintf("*Found %s trusted certificate %s\n",
mprintf(LOGG_DEBUG, "Found %s trusted certificate %s\n",
kc_info.name,
(name ? name : "<no name>"));
store->system_certs.certificates[store->system_certs.count++] = x509;
} else {
mprintf("!Failed conversion of DER format to X.509\n");
mprintf(LOGG_ERROR, "Failed conversion of DER format to X.509\n");
}
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
free(name);
if (NULL != name) {
free(name);
name = NULL;
}
#endif
CFRelease(cert_data);
@@ -363,10 +366,10 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
if (trusted_certs && trusted_cert_count > 0) {
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
mprintf("*Trusted certificates loaded: %zu\n",
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
store->trusted_certs.count);
} else {
mprintf("^Continuing without trusted certificates\n");
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
/* proceed as if we succeeded using only certificates from the
* system */
}
@@ -380,7 +383,7 @@ done:
pt_err = pthread_mutex_unlock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
locked = false;
}

View File

@@ -333,7 +333,7 @@ int daemonize_parent_wait(const char *const user, const char *const log_file)
int daemonizePid = daemonize_all_return();
if (daemonizePid == -1) {
return -1;
} else if (daemonizePid) { //parent
} else if (daemonizePid) { // parent
/* The parent will wait until either the child process
* exits, or signals the parent that it's initialization is
* complete. If it exits, it is due to an error condition,
@@ -360,7 +360,7 @@ int daemonize_parent_wait(const char *const user, const char *const log_file)
int exitStatus;
wait(&exitStatus);
if (WIFEXITED(exitStatus)) { //error
if (WIFEXITED(exitStatus)) { // error
exitStatus = WEXITSTATUS(exitStatus);
exit(exitStatus);
}
@@ -385,7 +385,7 @@ int drop_privileges(const char *const user_name, const char *const log_file)
struct passwd *user = NULL;
if ((user = getpwnam(user_name)) == NULL) {
logg("^Can't get information about user %s.\n", user_name);
logg(LOGG_WARNING, "Can't get information about user %s.\n", user_name);
fprintf(stderr, "ERROR: Can't get information about user %s.\n", user_name);
goto done;
}
@@ -393,13 +393,13 @@ int drop_privileges(const char *const user_name, const char *const log_file)
#ifdef HAVE_INITGROUPS
if (initgroups(user_name, user->pw_gid)) {
fprintf(stderr, "ERROR: initgroups() failed.\n");
logg("^initgroups() failed.\n");
logg(LOGG_WARNING, "initgroups() failed.\n");
goto done;
}
#elif HAVE_SETGROUPS
if (setgroups(1, &user->pw_gid)) {
fprintf(stderr, "ERROR: setgroups() failed.\n");
logg("^setgroups() failed.\n");
logg(LOGG_WARNING, "setgroups() failed.\n");
goto done;
}
#endif
@@ -411,7 +411,7 @@ int drop_privileges(const char *const user_name, const char *const log_file)
fprintf(stderr, "ERROR: lchown to user '%s' failed on\n", user->pw_name);
fprintf(stderr, "log file '%s'.\n", log_file);
fprintf(stderr, "Error was '%s'\n", strerror(errno));
logg("^lchown to user '%s' failed on log file '%s'. Error was '%s'\n",
logg(LOGG_WARNING, "lchown to user '%s' failed on log file '%s'. Error was '%s'\n",
user->pw_name, log_file, strerror(errno));
goto done;
}
@@ -419,13 +419,13 @@ int drop_privileges(const char *const user_name, const char *const log_file)
if (setgid(user->pw_gid)) {
fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int)user->pw_gid);
logg("^setgid(%d) failed.\n", (int)user->pw_gid);
logg(LOGG_WARNING, "setgid(%d) failed.\n", (int)user->pw_gid);
goto done;
}
if (setuid(user->pw_uid)) {
fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int)user->pw_uid);
logg("^setuid(%d) failed.\n", (int)user->pw_uid);
logg(LOGG_WARNING, "setuid(%d) failed.\n", (int)user->pw_uid);
goto done;
}
}

View File

@@ -72,7 +72,7 @@ int daemonize(void);
/*closes stdin, stdout, stderr. This is called by daemonize, but not
* daemonize_all_return. Users of daemonize_all_return should call this
* when initialization is complete.*/
int close_std_descriptors();
int close_std_descriptors(void);
/*Returns the return value of fork. All processes return */
int daemonize_all_return(void);

View File

@@ -158,6 +158,7 @@ const struct clam_option __clam_options[] = {
{NULL, "sha256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "mdb", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "imp", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "fuzzy-img", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "print-certs", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "html-normalise", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_SIGTOOL, "", ""},
{NULL, "ascii-normalise", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_SIGTOOL, "", ""},
@@ -200,6 +201,13 @@ const struct clam_option __clam_options[] = {
{NULL, "archive-verbose", 'a', CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
#ifdef _WIN32
{NULL, "install-service", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM, "", ""},
{NULL, "uninstall-service", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM, "", ""},
{NULL, "daemon", 'd', CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "", ""},
{NULL, "service-mode", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM, "", ""},
#endif
/* cmdline only - deprecated */
{NULL, "bytecode-trust-all", 't', CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
{NULL, "http-proxy", 0, CLOPT_TYPE_STRING, NULL, 0, NULL, 0, OPT_FRESHCLAM | OPT_DEPRECATED, "", ""},
@@ -231,6 +239,12 @@ const struct clam_option __clam_options[] = {
{NULL, "tgz", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
{NULL, "deb", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
#ifdef _WIN32
{NULL, "memory", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
{NULL, "kill", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
{NULL, "unload", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
#endif
/* config file/cmdline options */
{"AlertExceedsMax", "alert-exceeds-max", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
@@ -283,7 +297,7 @@ const struct clam_option __clam_options[] = {
{"MaxConnectionQueueLength", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 200, NULL, 0, OPT_CLAMD, "Maximum length the queue of pending connections may grow to.", "30"},
{"StreamMaxLength", NULL, 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD, "Close the STREAM session when the data size limit is exceeded.\nThe value should match your MTA's limit for the maximum attachment size.", "25M"},
{"StreamMaxLength", NULL, 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD, "Close the STREAM session when the data size limit is exceeded.\nThe value should match your MTA's limit for the maximum attachment size.", "100M"},
{"StreamMinPort", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 1024, NULL, 0, OPT_CLAMD, "The STREAM command uses an FTP-like protocol.\nThis option sets the lower boundary for the port range.", "1024"},
@@ -319,7 +333,7 @@ const struct clam_option __clam_options[] = {
{"DisableCache", "disable-cache", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option allows you to disable clamd's caching feature.", "no"},
{"VirusEvent", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Execute a command when a virus is found. In the command string %v will be\nreplaced with the virus name. Additionally, two environment variables will\nbe defined: $CLAM_VIRUSEVENT_FILENAME and $CLAM_VIRUSEVENT_VIRUSNAME.", "/usr/bin/mailx -s \"ClamAV VIRUS ALERT: %v\" alert < /dev/null"},
{"VirusEvent", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD, "Execute a command when a virus is found. In the command string %v will be\nreplaced with the virus name and %f will be replaced with the file name.\nAdditionally, two environment variables will be defined: $CLAM_VIRUSEVENT_FILENAME\nand $CLAM_VIRUSEVENT_VIRUSNAME.", "/usr/bin/mailx -s \"ClamAV VIRUS ALERT: %v\" alert < /dev/null"},
{"ExitOnOOM", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Stop the daemon when libclamav reports an out of memory condition.", "yes"},
@@ -331,6 +345,8 @@ const struct clam_option __clam_options[] = {
{"LeaveTemporaryFiles", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Don't remove temporary files (for debugging purposes).", "no"},
{"GenerateMetadataJson", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Record metadata about the file being scanned.\nScan metadata is useful for file analysis purposes and for debugging scan behavior.\nThe JSON metadata will be printed after the scan is complete if Debug is enabled.\nA metadata.json file will be written to the scan temp directory if LeaveTemporaryFiles is enabled.", "no"},
{"User", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Run the daemon as a specified user (the process must be started by root).", "clamav"},
/* Scan options */
@@ -420,22 +436,22 @@ const struct clam_option __clam_options[] = {
{"MaxScanTime", "max-scantime", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of time a scan may take to complete.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result allow scanning\nof certain files to lock up the scanning process/threads resulting in a Denial of Service.\nThe value is in milliseconds.", "120000"},
{"MaxScanSize", "max-scansize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXSCANSIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of data to be scanned for each input file.\nArchives and other containers are recursively extracted and scanned up to this\nvalue.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage.", "100M"},
{"MaxScanSize", "max-scansize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXSCANSIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of data to be scanned for each input file.\nArchives and other containers are recursively extracted and scanned up to this\nvalue.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage.", "400M"},
{"MaxFileSize", "max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD | OPT_MILTER | OPT_CLAMSCAN, "Files/messages larger than this limit won't be scanned. Affects the input\nfile itself as well as files contained inside it (when the input file is\nan archive, a document or some other kind of container).\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "25M"},
{"MaxFileSize", "max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD | OPT_MILTER | OPT_CLAMSCAN, "Files/messages larger than this limit won't be scanned. Affects the input\nfile itself as well as files contained inside it (when the input file is\nan archive, a document or some other kind of container).\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "100M"},
{"MaxRecursion", "max-recursion", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXRECLEVEL, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR\nfile, all files within it will also be scanned. This option specifies how\ndeeply the process should be continued.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "17"},
{"MaxFiles", "max-files", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_MAXFILES, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Number of files to be scanned within an archive, a document, or any other\ncontainer file.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "10000"},
/* Engine maximums */
{"MaxEmbeddedPE", "max-embeddedpe", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXEMBEDDEDPE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a file to check for embedded PE.\nFiles larger than this value will skip the additional analysis step.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "10M"},
{"MaxEmbeddedPE", "max-embeddedpe", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXEMBEDDEDPE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a file to check for embedded PE.\nFiles larger than this value will skip the additional analysis step.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "40M"},
{"MaxHTMLNormalize", "max-htmlnormalize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXHTMLNORMALIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a HTML file to normalize.\nHTML files larger than this value will not be normalized or scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "10M"},
{"MaxHTMLNormalize", "max-htmlnormalize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXHTMLNORMALIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a HTML file to normalize.\nHTML files larger than this value will not be normalized or scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "40M"},
{"MaxHTMLNoTags", "max-htmlnotags", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXHTMLNOTAGS, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a normalized HTML file to scan.\nHTML files larger than this value after normalization will not be scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "2M"},
{"MaxHTMLNoTags", "max-htmlnotags", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXHTMLNOTAGS, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a normalized HTML file to scan.\nHTML files larger than this value after normalization will not be scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "8M"},
{"MaxScriptNormalize", "max-scriptnormalize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXSCRIPTNORMALIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a script file to normalize.\nScript content larger than this value will not be normalized or scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "5M"},
{"MaxScriptNormalize", "max-scriptnormalize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXSCRIPTNORMALIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a script file to normalize.\nScript content larger than this value will not be normalized or scanned.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "20M"},
{"MaxZipTypeRcg", "max-ziptypercg", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXZIPTYPERCG, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum size of a ZIP file to reanalyze type recognition.\nZIP files larger than this value will skip the step to potentially reanalyze as PE.\nNegative values are not allowed.\nWARNING: setting this limit too high may result in severe damage or impact performance.", "1M"},
@@ -449,7 +465,7 @@ const struct clam_option __clam_options[] = {
{"PCRERecMatchLimit", "pcre-recmatch-limit", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, CLI_DEFAULT_PCRE_RECMATCH_LIMIT, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum recursive calls to the PCRE match function during an instance of regex matching.\nInstances using more than this limit will be terminated and alert the user but the scan will continue.\nFor more information on match_limit_recursion, see the PCRE documentation.\nNegative values are not allowed and values > PCREMatchLimit are superfluous.\nWARNING: setting this limit too high may severely impact performance.", "5000"},
{"PCREMaxFileSize", "pcre-max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_PCRE_MAX_FILESIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum filesize for which PCRE subsigs will be executed.\nFiles exceeding this limit will not have PCRE subsigs executed unless a subsig is encompassed to a smaller buffer.\nNegative values are not allowed.\nSetting this value to zero disables the limit.\nWARNING: setting this limit too high or disabling it may severely impact performance.", "25M"},
{"PCREMaxFileSize", "pcre-max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_PCRE_MAX_FILESIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum filesize for which PCRE subsigs will be executed.\nFiles exceeding this limit will not have PCRE subsigs executed unless a subsig is encompassed to a smaller buffer.\nNegative values are not allowed.\nSetting this value to zero disables the limit.\nWARNING: setting this limit too high or disabling it may severely impact performance.", "100M"},
/* OnAccess settings */
{"OnAccessMountPath", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option specifies a directory or mount point which should be scanned on access. The mount point specified, or the mount point containing the specified directory will be watched, but only notifications will occur. If any directories are specified, this option will preempt the DDD system. It can also be used multiple times.", "/\n/home/user"},
@@ -458,9 +474,9 @@ const struct clam_option __clam_options[] = {
{"OnAccessExcludePath", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option allows excluding directories from on-access scanning. It can\nbe used multiple times. Only works with DDD system.", "/home/bofh\n/root"},
{"OnAccessExcludeRootUID", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "Use this option to whitelist the root UID (0) and allow any processes run under root to access all watched files without triggering scans.", "no"},
{"OnAccessExcludeRootUID", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_CLAMD, "Use this option to exclude the root UID (0) and allow any processes run under root to access all watched files without triggering scans.", "no"},
{"OnAccessExcludeUID", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "With this option you can whitelist specific UIDs. Processes with these UIDs\nwill be able to access all files.\nThis option can be used multiple times (one per line). Using a value of 0 on any line will disable this option entirely. To whitelist the root UID please enable the OnAccessExcludeRootUID option.", "0"},
{"OnAccessExcludeUID", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "With this option you can exclude specific UIDs. Processes with these UIDs\nwill be able to access all files.\nThis option can be used multiple times (one per line). Using a value of 0 on any line will disable this option entirely. To exclude the root UID please enable the OnAccessExcludeRootUID option.", "0"},
{"OnAccessExcludeUname", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option allows exclusions via user names when using the on-access scanning client. It can\nbe used multiple times.", "clamuser"},
@@ -548,7 +564,7 @@ const struct clam_option __clam_options[] = {
{"ConnectTimeout", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 30, NULL, 0, OPT_FRESHCLAM, "Timeout in seconds when connecting to database server.", "30"},
{"ReceiveTimeout", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_FRESHCLAM, "Maximum time in seconds for each download operation. 0 means no timeout.", "0"},
{"ReceiveTimeout", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 60, NULL, 0, OPT_FRESHCLAM, "Timeout in seconds when reading from database server. 0 means no timeout.", "60"},
{"Bytecode", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_FRESHCLAM, "This option enables downloading of bytecode.cvd, which includes additional\ndetection mechanisms and improvements to the ClamAV engine.", "yes"},
@@ -605,7 +621,9 @@ const struct clam_option __clam_options[] = {
{"Chroot", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "Chroot to the specified directory.\nChrooting is performed just after reading the config file and before\ndropping privileges.", "/newroot"},
{"Whitelist", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of basic POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned. Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be whitelisted.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/whitelisted_addresses"},
{"AllowList", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of basic POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned. Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be allowed.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/allowed_addresses"},
// The Whitelist option should remain functional for a version or two, but has been deprecated in the documentation in favor of "AllowList".
{"Whitelist", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of basic POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned. Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be allowed.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/allowed_addresses"},
{"SkipAuthenticated", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "Messages from authenticated SMTP users matching this extended POSIX\nregular expression (egrep-like) will not be scanned.\nAs an alternative, a file containing a plain (not regex) list of names (one\nper line) can be specified using the prefix \"file:\".\ne.g. SkipAuthenticated file:/etc/good_guys\n\nNote: this is the AUTH login name!", "SkipAuthenticated ^(tom|dick|henry)$"},
@@ -706,22 +724,22 @@ static struct optstruct *optget_i(struct optstruct *opts, const char *name)
/*
static void optprint(const struct optstruct *opts)
{
const struct optstruct *h;
const struct optstruct *h;
printf("\nOPTIONS:\n\n");
while(opts) {
printf("OPT_NAME: %s\n", opts->name);
printf("OPT_CMD: %s\n", opts->cmd);
printf("OPT_STRARG: %s\n", opts->strarg ? opts->strarg : "NONE");
printf("OPT_NUMARG: %d\n", opts->numarg);
h = opts;
while((h = h->nextarg)) {
printf("SUBARG_OPT_STRARG: %s\n", h->strarg ? h->strarg : "NONE");
printf("SUBARG_OPT_NUMARG: %d\n", h->numarg);
}
printf("----------------\n");
opts = opts->next;
printf("OPT_NAME: %s\n", opts->name);
printf("OPT_CMD: %s\n", opts->cmd);
printf("OPT_STRARG: %s\n", opts->strarg ? opts->strarg : "NONE");
printf("OPT_NUMARG: %d\n", opts->numarg);
h = opts;
while((h = h->nextarg)) {
printf("SUBARG_OPT_STRARG: %s\n", h->strarg ? h->strarg : "NONE");
printf("SUBARG_OPT_NUMARG: %d\n", h->numarg);
}
printf("----------------\n");
opts = opts->next;
}
}
*/

View File

@@ -298,26 +298,7 @@ void logg_close(void)
#endif
}
/*
* legend:
* ! - ERROR:
* ^ - WARNING:
* ~ - normal
* # - normal, not foreground (logfile and syslog only)
* * - verbose
* $ - debug
* none - normal
*
* Default Foreground LogVerbose Debug Syslog
* ! yes mprintf yes yes LOG_ERR
* ^ yes mprintf yes yes LOG_WARNING
* ~ yes mprintf yes yes LOG_INFO
* # yes no yes yes LOG_INFO
* * no mprintf yes yes LOG_DEBUG
* $ no mprintf no yes LOG_DEBUG
* none yes mprintf yes yes LOG_INFO
*/
int logg(const char *str, ...)
int logg(loglevel_t loglevel, const char *str, ...)
{
va_list args;
char buffer[1025], *abuffer = NULL, *buff;
@@ -328,8 +309,8 @@ int logg(const char *str, ...)
struct flock fl;
#endif
if ((*str == '$' && logg_verbose < 2) ||
(*str == '*' && !logg_verbose))
if ((loglevel == LOGG_DEBUG_NV && logg_verbose < 2) ||
(loglevel == LOGG_DEBUG && !logg_verbose))
return 0;
ARGLEN(args, str, len);
@@ -399,7 +380,7 @@ int logg(const char *str, ...)
/* Need to avoid logging time for verbose messages when logverbose
is not set or we get a bunch of timestamps in the log without
newlines... */
if (logg_time && ((*buff != '*') || logg_verbose)) {
if (logg_time && ((loglevel != LOGG_DEBUG) || logg_verbose)) {
char timestr[32];
time(&currtime);
cli_ctime(&currtime, timestr, sizeof(timestr));
@@ -408,17 +389,17 @@ int logg(const char *str, ...)
fprintf(logg_fp, "%s -> ", timestr);
}
if (*buff == '!') {
fprintf(logg_fp, "ERROR: %s", buff + 1);
if (loglevel == LOGG_ERROR) {
fprintf(logg_fp, "ERROR: %s", buff);
flush = 1;
} else if (*buff == '^') {
} else if (loglevel == LOGG_WARNING) {
if (!logg_nowarn)
fprintf(logg_fp, "WARNING: %s", buff + 1);
fprintf(logg_fp, "WARNING: %s", buff);
flush = 1;
} else if (*buff == '*' || *buff == '$') {
fprintf(logg_fp, "%s", buff + 1);
} else if (*buff == '#' || *buff == '~') {
fprintf(logg_fp, "%s", buff + 1);
} else if (loglevel == LOGG_DEBUG || loglevel == LOGG_DEBUG_NV) {
fprintf(logg_fp, "%s", buff);
} else if (loglevel == LOGG_INFO_NF || loglevel == LOGG_INFO) {
fprintf(logg_fp, "%s", buff);
} else
fprintf(logg_fp, "%s", buff);
@@ -427,16 +408,16 @@ int logg(const char *str, ...)
}
if (logg_foreground) {
if (buff[0] != '#') {
if (loglevel != LOGG_INFO_NF) {
if (logg_time) {
char timestr[32];
time(&currtime);
cli_ctime(&currtime, timestr, sizeof(timestr));
/* cut trailing \n */
timestr[strlen(timestr) - 1] = '\0';
mprintf("%s -> %s", timestr, buff);
mprintf(loglevel, "%s -> %s", timestr, buff);
} else {
mprintf("%s", buff);
mprintf(loglevel, "%s", buff);
}
}
}
@@ -444,15 +425,13 @@ int logg(const char *str, ...)
#if defined(USE_SYSLOG) && !defined(C_AIX)
if (logg_syslog) {
cli_chomp(buff);
if (buff[0] == '!') {
syslog(LOG_ERR, "%s", buff + 1);
} else if (buff[0] == '^') {
if (loglevel == LOGG_ERROR) {
syslog(LOG_ERR, "%s", buff);
} else if (loglevel == LOGG_WARNING) {
if (!logg_nowarn)
syslog(LOG_WARNING, "%s", buff + 1);
} else if (buff[0] == '*' || buff[0] == '$') {
syslog(LOG_DEBUG, "%s", buff + 1);
} else if (buff[0] == '#' || buff[0] == '~') {
syslog(LOG_INFO, "%s", buff + 1);
syslog(LOG_WARNING, "%s", buff);
} else if (loglevel == LOGG_DEBUG || loglevel == LOGG_DEBUG_NV) {
syslog(LOG_DEBUG, "%s", buff);
} else
syslog(LOG_INFO, "%s", buff);
}
@@ -467,7 +446,7 @@ int logg(const char *str, ...)
return 0;
}
void mprintf(const char *str, ...)
void mprintf(loglevel_t loglevel, const char *str, ...)
{
va_list args;
FILE *fd;
@@ -479,21 +458,6 @@ void mprintf(const char *str, ...)
fd = stdout;
/* legend:
* ! - error
* @ - error with logging
* ...
*/
/*
* ERROR WARNING STANDARD
* normal stderr stderr stdout
*
* verbose stderr stderr stdout
*
* quiet stderr no no
*/
ARGLEN(args, str, len);
if (len <= sizeof(buffer)) {
len = sizeof(buffer);
@@ -541,26 +505,22 @@ void mprintf(const char *str, ...)
len = sizeof(buffer) + 1;
} while (0);
#endif
if (buff[0] == '!') {
if (loglevel == LOGG_ERROR) {
if (!mprintf_stdout)
fd = stderr;
fprintf(fd, "ERROR: %s", &buff[1]);
} else if (buff[0] == '@') {
if (!mprintf_stdout)
fd = stderr;
fprintf(fd, "ERROR: %s", &buff[1]);
fprintf(fd, "ERROR: %s", buff);
} else if (!mprintf_quiet) {
if (buff[0] == '^') {
if (loglevel == LOGG_WARNING) {
if (!mprintf_nowarn) {
if (!mprintf_stdout)
fd = stderr;
fprintf(fd, "WARNING: %s", &buff[1]);
fprintf(fd, "WARNING: %s", buff);
}
} else if (buff[0] == '*') {
} else if (loglevel == LOGG_DEBUG) {
if (mprintf_verbose)
fprintf(fd, "%s", &buff[1]);
} else if (buff[0] == '~') {
fprintf(fd, "%s", &buff[1]);
fprintf(fd, "%s", buff);
} else if (loglevel == LOGG_INFO) {
fprintf(fd, "%s", buff);
} else
fprintf(fd, "%s", buff);
}

97
clamav/common/output.h Normal file
View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
* 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.
*/
#ifndef __OUTPUT_H
#define __OUTPUT_H
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef __GNUC__
int mdprintf(int desc, const char *str, ...) __attribute__((format(printf, 2, 3)));
#else
int mdprintf(int desc, const char *str, ...);
#endif
/*
* legend:
* NAME EXPLAIN
* LOGG_INFO normal
* LOGG_INFO_NF normal, no foreground (logfile and syslog only)
* LOGG_DEBUG debug, verbose
* LOGG_DEBUG_NV debug, non-verbose
* LOGG_WARNING warning
* LOGG_ERROR ERROR
*/
typedef enum loglevel {
LOGG_INFO,
LOGG_INFO_NF,
LOGG_DEBUG,
LOGG_DEBUG_NV,
LOGG_WARNING,
LOGG_ERROR
} loglevel_t;
/*
* @param loglevel legend:
* NAME EXPLAIN
* LOGG_INFO normal
* LOGG_INFO_NF normal, no foreground (logfile and syslog only)
* LOGG_DEBUG debug, verbose
* LOGG_DEBUG_NV debug, non-verbose
* LOGG_WARNING warning
* LOGG_ERROR ERROR
*
* @return 0 fur success and -1 for error, e.g. log file access problems
*/
#ifdef __GNUC__
int logg(loglevel_t loglevel, const char *str, ...) __attribute__((format(printf, 2, 3)));
#else
int logg(loglevel_t loglevel, const char *str, ...);
#endif
void logg_close(void);
extern short int logg_verbose, logg_nowarn, logg_lock, logg_time, logg_noflush, logg_rotate;
extern off_t logg_size;
extern const char *logg_file;
#if defined(USE_SYSLOG) && !defined(C_AIX)
extern short logg_syslog;
int logg_facility(const char *name);
#endif
#ifdef __GNUC__
void mprintf(loglevel_t loglevel, const char *str, ...) __attribute__((format(printf, 2, 3)));
#else
void mprintf(loglevel_t loglevel, const char *str, ...);
#endif
extern short int mprintf_disabled, mprintf_verbose, mprintf_quiet, mprintf_nowarn, mprintf_stdout, mprintf_send_timeout, mprintf_progress;
#endif

710
clamav/common/scanmem.c Normal file
View File

@@ -0,0 +1,710 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <windns.h>
#include <clamav.h>
#include <others.h>
#include "actions.h"
#include "output.h"
#include "clamdcom.h"
#include "exescanner.h"
#include "scanmem.h"
typedef int (*proc_callback)(PROCESSENTRY32 ProcStruct, MODULEENTRY32 me32, void *data, struct mem_info *info);
int sock;
struct optstruct *clamdopts;
static inline int lookup_cache(filelist_t **list, const char *filename)
{
filelist_t *current = *list;
while (current) {
/* Cache hit */
if (!_stricmp(filename, current->filename)) {
return current->res;
}
current = current->next;
}
return -1;
}
static inline void insert_cache(filelist_t **list, const char *filename,
int res)
{
filelist_t *current = *list, *prev = NULL;
if (!current) /* New */
*list = current = malloc(sizeof(filelist_t));
else {
while (current->next)
current = current->next;
prev = current;
prev->next = current = malloc(sizeof(filelist_t));
}
current->next = NULL;
current->res = res;
current->filename[0] = 0;
strncat(current->filename, filename,
MAX_PATH - 1 - strlen(current->filename));
current->filename[MAX_PATH - 1] = 0;
}
static inline void free_cache(filelist_t **list)
{
filelist_t *current, *prev;
current = prev = *list;
if (!current)
return;
do {
prev = current;
current = prev->next;
free(prev);
} while (current);
}
static inline char *wc2mb(const wchar_t *wc, DWORD flags)
{
BOOL invalid = FALSE;
DWORD len = 0, res = 0;
char *mb = NULL;
len = WideCharToMultiByte(CP_ACP, flags, wc, -1, NULL, 0, NULL, &invalid);
if (!len && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
fprintf(stderr, "WideCharToMultiByte() failed with %d\n", GetLastError());
return NULL;
}
mb = cli_malloc(len + 1);
if (!mb) return NULL;
res = WideCharToMultiByte(CP_ACP, flags, wc, -1, mb, len, NULL, &invalid);
if (res && ((!invalid || (flags != WC_NO_BEST_FIT_CHARS)))) return mb;
free(mb);
return NULL;
}
/* Needed to Scan System Processes */
int EnablePrivilege(LPCSTR PrivilegeName, DWORD yesno)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LoadLibraryA("advapi32.dll")) {
logg(LOGG_WARNING, "EnablePrivilege functions are missing\n");
return 0;
}
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
return 0;
if (!LookupPrivilegeValue(NULL, PrivilegeName, &luid))
return 0;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = yesno;
AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
CloseHandle(hToken);
return (GetLastError() == ERROR_SUCCESS) ? 1 : 0;
}
static char *getaltpath(const wchar_t *filename)
{
WIN32_FIND_DATAW wfdw;
HANDLE hf = INVALID_HANDLE_VALUE;
wchar_t *part = _wcsdup(filename);
wchar_t comprev[MAX_PATH + 1] = L"", compose[MAX_PATH + 1];
wchar_t *rev = comprev, *slash = part, *c = NULL;
size_t l, la;
size_t i;
do {
if (slash != part)
*slash = 0;
/* c: d: etc */
if ((wcslen(part) == 2) && (part[1] == L':')) {
*rev++ = L':';
*rev++ = part[0];
break;
}
hf = FindFirstFileW(part, &wfdw);
if (hf == INVALID_HANDLE_VALUE) /* Network path */
{
for (i = wcslen(part); i > 0; i--)
*rev++ = part[i - 1];
break;
}
FindClose(hf);
l = wcslen(wfdw.cFileName);
la = wcslen(wfdw.cAlternateFileName);
if (la)
for (i = la; i > 0; i--)
*rev++ = *(wfdw.cAlternateFileName + i - 1);
else
for (i = l; i > 0; i--)
*rev++ = *(wfdw.cFileName + i - 1);
*rev++ = '\\';
} while ((slash = wcsrchr(part, L'\\')));
rev = comprev;
c = compose;
for (i = wcslen(rev); i > 0; i--)
*c++ = *(rev + i - 1);
*c = 0;
free(part);
return wc2mb(compose, WC_NO_BEST_FIT_CHARS);
}
int walkmodules_th(proc_callback callback, void *data, struct mem_info *info)
{
HANDLE hSnap = INVALID_HANDLE_VALUE, hModuleSnap = INVALID_HANDLE_VALUE;
PROCESSENTRY32 ps;
MODULEENTRY32 me32;
logg(LOGG_INFO, " *** Memory Scan: using ToolHelp ***\n\n");
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
return -1;
ps.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &ps)) {
CloseHandle(hSnap);
return -1;
}
do {
/* system process */
if (!ps.th32ProcessID)
continue;
hModuleSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, ps.th32ProcessID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
continue;
me32.dwSize = sizeof(MODULEENTRY32);
if (!Module32First(hModuleSnap, &me32)) {
CloseHandle(hModuleSnap);
continue;
}
/* Check and transform non ANSI filenames to ANSI using altnames */
if (GetModuleFileNameEx) {
HANDLE hFile = CreateFile(
me32.szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
wchar_t name[MAX_PATH + 1];
char *converted = NULL;
HANDLE p;
if (err == ERROR_BAD_NETPATH) {
logg(LOGG_WARNING, "Warning scanning files on non-ansi network paths is not "
"supported\n");
logg(LOGG_WARNING, "File: %s\n", me32.szExePath);
continue;
}
if ((err != ERROR_INVALID_NAME) && (err != ERROR_PATH_NOT_FOUND)) {
logg(LOGG_WARNING, "Expected ERROR_INVALID_NAME/ERROR_PATH_NOT_FOUND but got %d\n",
err);
continue;
}
p = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
ps.th32ProcessID);
if (!GetModuleFileNameEx(p, NULL, name, MAX_PATH)) {
logg(LOGG_WARNING, "GetModuleFileNameExW() failed %d\n", GetLastError());
CloseHandle(p);
continue;
}
CloseHandle(p);
if (!(converted = getaltpath(name))) {
logg(LOGG_WARNING, "Cannot map filename to ANSI codepage\n");
continue;
}
strcpy(me32.szExePath, converted);
free(converted);
} else
CloseHandle(hFile);
}
do
if (callback(ps, me32, data, info))
break;
while (Module32Next(hModuleSnap, &me32));
CloseHandle(hModuleSnap);
} while (Process32Next(hSnap, &ps));
CloseHandle(hSnap);
return 0;
}
int walkmodules_psapi(proc_callback callback, void *data, struct mem_info *info)
{
DWORD procs[1024], needed, nprocs, mneeded;
HANDLE hProc;
HMODULE mods[1024];
PROCESSENTRY32 ps;
MODULEENTRY32 me32;
MODULEINFO mi;
int i, j;
logg(LOGG_INFO, " *** Memory Scan: using PsApi ***\n\n");
if (!EnumProcesses(procs, sizeof(procs), &needed))
return -1;
nprocs = needed / sizeof(DWORD);
memset(&ps, 0, sizeof(PROCESSENTRY32));
memset(&me32, 0, sizeof(MODULEENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
me32.dwSize = sizeof(MODULEENTRY32);
for (i = 0; i < nprocs; i++) {
if (!procs[i])
continue; /* System process */
hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
procs[i]);
if (!hProc)
continue;
if (!EnumProcessModules(hProc, mods, sizeof(mods),
&mneeded)) {
CloseHandle(hProc);
continue;
}
if (!GetModuleBaseName(hProc, mods[0], ps.szExeFile,
MAX_PATH - 1)) {
CloseHandle(hProc);
continue;
}
ps.th32ProcessID = procs[i];
for (j = 0; j < (mneeded / sizeof(HMODULE)); j++) {
if (!GetModuleBaseNameA(hProc, mods[j], me32.szModule,
MAX_PATH - 1))
continue;
if (!GetModuleFileNameExA(hProc, mods[j], me32.szExePath,
MAX_PATH - 1))
continue;
if (!GetModuleInformation(hProc, mods[j], &mi,
sizeof(mi)))
continue;
me32.hModule = mods[j];
me32.th32ProcessID = procs[i];
me32.modBaseAddr = mi.lpBaseOfDll;
me32.modBaseSize = mi.SizeOfImage;
if (callback(ps, me32, data, info))
break;
}
CloseHandle(hProc);
}
return 0;
}
int kill_process(DWORD pid)
{
HANDLE hProc;
if (GetCurrentProcessId() == pid) {
logg(LOGG_WARNING, "Don't want to kill myself\n");
return 1;
}
if ((hProc = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid))) {
TerminateProcess(hProc, 0);
if (WaitForSingleObject(hProc, TIMEOUT_MODULE) != WAIT_OBJECT_0)
logg(LOGG_WARNING, "Unable to unload process from memory\n");
CloseHandle(hProc);
} else
logg(LOGG_WARNING, "OpenProcess() failed %lu\n", GetLastError());
return 1; /* Skip to next process anyway */
}
/* Not so safe ;) */
int unload_module(DWORD pid, HANDLE hModule)
{
DWORD rc = 1;
HANDLE ht;
HANDLE hProc;
if (GetCurrentProcessId() == pid) {
logg(LOGG_WARNING, "Don't want to unload modules from myself\n");
return 1;
}
hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, pid);
if (!hProc) {
logg(LOGG_WARNING, "OpenProcess() failed %lu\n", GetLastError());
return 1; /* Skip to next process */
}
if ((ht = CreateRemoteThread(
hProc, 0, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, hModule, 0,
&rc))) {
if (WaitForSingleObject(ht, TIMEOUT_MODULE) == WAIT_TIMEOUT) {
CloseHandle(ht);
CloseHandle(hProc);
logg(LOGG_INFO, "The module may trying to trick us, killing the process, please "
"rescan\n");
return kill_process(pid);
}
CloseHandle(ht);
rc = 0; /* Continue scanning this process */
} else {
DWORD res = GetLastError();
if (res == ERROR_CALL_NOT_IMPLEMENTED) {
logg(LOGG_WARNING, "Module unloading is not supported on this OS\n");
rc = -1; /* Don't complain about removing/moving the file */
} else {
logg(LOGG_ERROR, "CreateRemoteThread() failed %lu\n", res);
rc = 1; /* Skip to next process */
}
}
CloseHandle(hProc);
return rc;
}
#define FILLBYTES(dst) \
if (IsBadReadPtr(seek, sizeof(dst))) { \
logg(LOGG_ERROR, "ScanMem Align: Bad pointer!!!\n"); \
return 1; \
} \
memcpy(&dst, seek, sizeof(dst))
/* PE Realignment - FIXME: a lot of code is copy/paste from exeScanner.c */
int align_pe(unsigned char *buffer, size_t size)
{
int i = 0;
uint16_t e_mz;
uint32_t e_lfanew, e_magic;
unsigned char *seek = buffer;
PIMAGE_FILE_HEADER pehdr;
PIMAGE_OPTIONAL_HEADER32 opthdr;
PIMAGE_SECTION_HEADER sechdr;
FILLBYTES(e_mz);
if (e_mz != IMAGE_DOS_SIGNATURE) {
/* cli_dbgmsg("ScanMem Align: DOS Signature not found\n"); */
return 0;
}
seek += 0x3c;
FILLBYTES(e_lfanew);
if (!e_lfanew) {
/* cli_dbgmsg("ScanMem Align: Invalid PE offset\n"); */
return 0;
}
seek = buffer + e_lfanew;
/* PE Signature 'PE' */
FILLBYTES(e_magic);
if (e_magic != IMAGE_NT_SIGNATURE) {
/* cli_dbgmsg("ScanMem Align: PE Signature not found\n"); */
return 0;
}
seek += sizeof(e_magic);
if (IsBadReadPtr(seek, sizeof(IMAGE_FILE_HEADER)))
return 0;
pehdr = (PIMAGE_FILE_HEADER)seek;
seek += sizeof(IMAGE_FILE_HEADER);
if (IsBadReadPtr(seek, sizeof(IMAGE_OPTIONAL_HEADER32)))
return 0;
opthdr = (PIMAGE_OPTIONAL_HEADER32)seek;
seek += sizeof(IMAGE_OPTIONAL_HEADER32);
/* Invalid sections number */
if ((pehdr->NumberOfSections < 1) || (pehdr->NumberOfSections > 32)) {
/* cli_dbgmsg("ScanMem Align: Invalid sections number\n"); */
return 0;
}
for (i = 0; i < pehdr->NumberOfSections; i++) {
if (IsBadWritePtr(seek, sizeof(IMAGE_SECTION_HEADER)))
return 0;
sechdr = (PIMAGE_SECTION_HEADER)seek;
seek += sizeof(IMAGE_SECTION_HEADER);
sechdr->PointerToRawData = sechdr->VirtualAddress;
sechdr->SizeOfRawData = sechdr->Misc.VirtualSize;
}
return 1;
}
int dump_pe(const char *filename, PROCESSENTRY32 ProcStruct,
MODULEENTRY32 me32)
{
#ifdef _WIN64 /* MinGW has a broken header for ReadProcessMemory() */
size_t bytesread = 0;
#else
DWORD bytesread = 0;
#endif
DWORD byteswrite = 0;
int ret = -1;
HANDLE hFile = INVALID_HANDLE_VALUE, hProc = NULL;
unsigned char *buffer = NULL;
if (!(hProc = OpenProcess(PROCESS_VM_READ, FALSE, ProcStruct.th32ProcessID)))
return -1;
buffer = malloc((size_t)me32.modBaseSize);
if (!ReadProcessMemory(hProc, me32.modBaseAddr, buffer,
(size_t)me32.modBaseSize, &bytesread)) {
free(buffer);
CloseHandle(hProc);
return ret;
}
CloseHandle(hProc);
/* PE Realignment */
align_pe(buffer, me32.modBaseSize);
hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
logg(LOGG_INFO, "Error creating %s\n", filename);
free(buffer);
return ret;
}
if (WriteFile(hFile, buffer, (DWORD)bytesread, &byteswrite, NULL))
ret = _open_osfhandle((intptr_t)hFile, O_RDONLY | O_BINARY);
free(buffer);
return ret;
}
int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *info)
{
int fd;
int scantype;
int ret = CL_CLEAN;
const char *virname = NULL;
logg(LOGG_DEBUG, "Scanning %s\n", filename);
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) {
logg(LOGG_WARNING, "Can't open file %s, %s\n", filename, strerror(errno));
return -1;
}
if (info->d) { // clamdscan
if (optget(info->opts, "stream")->enabled)
scantype = STREAM;
else if (optget(info->opts, "multiscan")->enabled)
scantype = MULTI;
else if (optget(info->opts, "allmatch")->enabled)
scantype = ALLMATCH;
else
scantype = CONT;
if ((sock = dconnect(clamdopts)) < 0) {
info->errors++;
return -1;
}
if (dsresult(sock, scantype, filename, NULL, &info->errors, clamdopts) > 0) {
info->ifiles++;
ret = CL_VIRUS;
}
} else { // clamscan
ret = cl_scandesc(fd, filename, &virname, &info->blocks, info->engine, info->options);
if (ret == CL_VIRUS) {
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
info->ifiles++;
} else if (scan_data->printclean) {
logg(LOGG_INFO, "%s: OK \n", filename);
}
}
close(fd);
return ret;
}
int scanmem_cb(PROCESSENTRY32 ProcStruct, MODULEENTRY32 me32, void *data, struct mem_info *info)
{
scanmem_data *scan_data = data;
int rc = 0;
int isprocess = 0;
char modulename[MAX_PATH] = "";
char expandmodule[MAX_PATH] = "";
if (!scan_data)
return 0;
scan_data->res = CL_CLEAN;
modulename[0] = 0;
/* Special case, btw why I get \SystemRoot\ in process szExePath?
There are also other cases? */
if ((strlen(me32.szExePath) > 12) &&
!strncmp(me32.szExePath, "\\SystemRoot\\", 12)) {
expandmodule[0] = 0;
strncat(expandmodule, me32.szExePath, MAX_PATH - 1 - strlen(expandmodule));
expandmodule[MAX_PATH - 1] = 0;
snprintf(expandmodule, MAX_PATH - 1, "%%SystemRoot%%\\%s",
&me32.szExePath[12]);
expandmodule[MAX_PATH - 1] = 0;
ExpandEnvironmentStrings(expandmodule, modulename, MAX_PATH - 1);
modulename[MAX_PATH - 1] = 0;
}
if (!modulename[0]) {
strncpy(modulename, me32.szExePath, MAX_PATH - 1);
modulename[MAX_PATH - 1] = 0;
}
scan_data->res = lookup_cache(&scan_data->files, modulename);
isprocess = !_stricmp(ProcStruct.szExeFile, modulename) ||
!_stricmp(ProcStruct.szExeFile, me32.szModule);
if (scan_data->res == -1) {
if (isprocess)
scan_data->processes++;
else
scan_data->modules++;
info->files++;
/* check for module exclusion */
scan_data->res = CL_CLEAN;
if (!(scan_data->exclude && chkpath(modulename, clamdopts)))
scan_data->res = scanfile(modulename, scan_data, info);
if ((scan_data->res != CL_VIRUS) && is_packed(modulename)) {
char *dumped = cli_gentemp(NULL);
int fd = -1;
if ((fd = dump_pe(dumped, ProcStruct, me32)) > 0) {
close(fd);
scan_data->res = scanfile(dumped, scan_data, info);
DeleteFile(dumped);
}
free(dumped);
}
insert_cache(&scan_data->files, modulename, scan_data->res);
}
if (scan_data->res == CL_VIRUS) {
if (isprocess && scan_data->kill) {
logg(LOGG_INFO, "Unloading program %s from memory\n", modulename);
rc = kill_process(ProcStruct.th32ProcessID);
} else if (scan_data->unload) {
logg(LOGG_INFO, "Unloading module %s from %s\n", me32.szModule, modulename);
if ((rc = unload_module(ProcStruct.th32ProcessID, me32.hModule)) == -1)
/* CreateProcessThread() is not implemented */
return 0;
}
if (action)
action(modulename);
return rc;
}
return rc;
}
int scanmem(struct mem_info *info)
{
scanmem_data data;
data.files = NULL;
data.printclean = 1;
data.kill = 0;
data.unload = 0;
data.exclude = 0;
data.res = CL_CLEAN;
data.processes = 0;
data.modules = 0;
HMODULE psapi_ok = LoadLibrary("psapi.dll");
HMODULE k32_ok = LoadLibrary("kernel32.dll");
if (!(psapi_ok || k32_ok)) {
logg(LOGG_INFO, " *** Memory Scanning is not supported on this OS ***\n\n");
return -1;
}
if (optget(info->opts, "infected")->enabled)
data.printclean = 0;
if (optget(info->opts, "kill")->enabled)
data.kill = 1;
if (optget(info->opts, "unload")->enabled)
data.unload = 1;
if (optget(info->opts, "exclude")->enabled)
data.exclude = 1;
if (info->d) {
if ((sock = dconnect(clamdopts)) < 0) {
info->errors++;
return -1;
}
}
logg(LOGG_INFO, " *** Scanning Programs in Computer Memory ***\n");
if (!EnablePrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED))
logg(LOGG_INFO, "---Please login as an Administrator to scan System processes loaded "
"in computer memory---\n");
if (k32_ok)
walkmodules_th(scanmem_cb, (void *)&data, info);
else
walkmodules_psapi(scanmem_cb, (void *)&data, info);
free_cache(&data.files);
logg(LOGG_INFO, "\n *** Scanned %lu processes - %lu modules ***\n", data.processes,
data.modules);
logg(LOGG_INFO, " *** Computer Memory Scan Completed ***\n\n");
return data.res;
}

68
clamav/common/scanmem.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2005-2010 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#ifndef __SCANMEM_H
#define __SCANMEM_H
#ifndef TH32CS_SNAPMODULE32
#define TH32CS_SNAPMODULE32 0x00000010
#endif
#define TIMEOUT_MODULE 30000
int scanmem(struct mem_info *info);
/* cache helpers */
typedef struct _filelist_t {
char filename[MAX_PATH];
int res;
struct _filelist_t *next;
} filelist_t;
/* Callback */
typedef struct _cb_data_t {
const char *filename;
size_t size, count;
int oldvalue;
int fd;
} cb_data_t;
typedef struct _scanmem_data_t {
filelist_t *files;
int printclean, kill, unload, exclude;
int res;
uint32_t processes, modules;
} scanmem_data;
struct mem_info {
unsigned int d; /*1 = clamdscan, 0 = clamscan */
unsigned int files; /* number of scanned files */
unsigned int ifiles; /* number of infected files */
unsigned long int blocks; /* number of *scanned* 16kb blocks */
unsigned int errors;
struct cl_engine *engine;
const struct optstruct *opts;
struct cl_scan_options *options;
};
#endif

228
clamav/common/service.c Normal file
View File

@@ -0,0 +1,228 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2008-2010 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#include <platform.h>
#include <winsvc.h>
#include "service.h"
#include "output.h"
static SERVICE_STATUS svc;
static SERVICE_STATUS_HANDLE svc_handle;
static SERVICE_TABLE_ENTRYA DT[] = {{"Service", ServiceMain}, {NULL, NULL}};
static HANDLE evStart;
static HANDLE DispatcherThread;
static int checkpoint_every = 5000;
int svc_uninstall(const char *name, int verbose)
{
SC_HANDLE sm, svc;
int ret = 1;
if (!(sm = OpenSCManagerA(NULL, NULL, DELETE))) {
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
fprintf(stderr, "Windows Services are not supported on this Platform\n");
else
fprintf(stderr, "Unable to Open SCManager (%d)\n", GetLastError());
return 0;
}
if ((svc = OpenServiceA(sm, name, DELETE))) {
if (DeleteService(svc)) {
if (verbose) printf("Service %s successfully removed\n", name);
} else {
fprintf(stderr, "Unable to Open Service %s (%d)\n", name, GetLastError());
ret = 0;
}
} else {
if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) {
if (verbose) printf("Service %s does not exist\n", name);
} else {
fprintf(stderr, "Unable to Open Service %s (%d)\n", name, GetLastError());
ret = 0;
}
}
if (svc) CloseServiceHandle(svc);
CloseServiceHandle(sm);
return ret;
}
int svc_install(const char *name, const char *dname, const char *desc)
{
SC_HANDLE sm, svc;
char modulepath[MAX_PATH];
char binpath[MAX_PATH];
SERVICE_DESCRIPTIONA sdesc = {(char *)desc};
if (!GetModuleFileName(NULL, modulepath, MAX_PATH - 1)) {
fprintf(stderr, "Unable to get the executable name (%d)\n", GetLastError());
return 0;
}
if (!svc_uninstall(name, 0)) return 0;
if (!(sm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE | DELETE))) {
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
fprintf(stderr, "Windows Services are not supported on this Platform\n");
else
fprintf(stderr, "Unable to Open SCManager (%d)\n", GetLastError());
return 0;
}
if (strchr(modulepath, ' '))
snprintf(binpath, MAX_PATH - 1, "\"%s\" --daemon --service-mode", modulepath);
else
snprintf(binpath, MAX_PATH - 1, "%s --daemon --service-mode", modulepath);
svc = CreateServiceA(sm, name, dname, SERVICE_CHANGE_CONFIG,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
binpath,
NULL, /* Load group order */
NULL, /* Tag Id */
NULL, /* Dependencies */
NULL, /* User -> Local System */
"");
if (!svc) {
fprintf(stderr, "Unable to Create Service %s (%d)\n", name, GetLastError());
CloseServiceHandle(sm);
return 0;
}
/* ChangeServiceConfig2A() */
if (!ChangeServiceConfig2A(svc, SERVICE_CONFIG_DESCRIPTION, &sdesc))
fprintf(stderr, "Unable to set description for Service %s (%d)\n", name, GetLastError());
CloseServiceHandle(svc);
CloseServiceHandle(sm);
printf("Service %s successfully created.\n", name);
printf("Use 'net start %s' and 'net stop %s' to start/stop the service.\n", name, name);
return 1;
}
static void svc_getcpvalue(const char *name)
{
HKEY hKey;
DWORD dwType;
DWORD value, vlen = sizeof(DWORD);
char subkey[MAX_PATH];
snprintf(subkey, MAX_PATH - 1, "SYSTEM\\CurrentControlSet\\Services\\%s", name);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
return;
if ((RegQueryValueExA(hKey, "Checkpoint", NULL, &dwType, (LPBYTE)&value, &vlen) == ERROR_SUCCESS) &&
(vlen == sizeof(DWORD) && (dwType == REG_DWORD)))
checkpoint_every = value;
RegCloseKey(hKey);
}
void svc_register(const char *name)
{
DWORD tid;
DT->lpServiceName = (char *)name;
svc_getcpvalue(name);
evStart = CreateEvent(NULL, TRUE, FALSE, NULL);
DispatcherThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartServiceCtrlDispatcherA, (LPVOID)DT, 0, &tid);
}
void svc_ready(void)
{
WaitForSingleObject(evStart, INFINITE);
svc.dwCurrentState = SERVICE_RUNNING;
svc.dwControlsAccepted |= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
svc.dwCheckPoint = 0;
if (!SetServiceStatus(svc_handle, &svc)) {
logg(LOGG_INFO, "[service] SetServiceStatus() failed with %d\n", GetLastError());
exit(1);
}
}
int svc_checkpoint(const char *type, const char *name, unsigned int custom, void *context)
{
if (svc.dwCurrentState == SERVICE_START_PENDING) {
svc.dwCheckPoint++;
if ((svc.dwCheckPoint % checkpoint_every) == 0)
SetServiceStatus(svc_handle, &svc);
}
return 0;
}
void WINAPI ServiceCtrlHandler(DWORD code)
{
switch (code) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
svc.dwCurrentState = SERVICE_STOPPED;
svc.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
SetServiceStatus(svc_handle, &svc);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
}
SetServiceStatus(svc_handle, &svc);
}
BOOL WINAPI cw_stop_ctrl_handler(DWORD CtrlType)
{
if (CtrlType == CTRL_C_EVENT) {
SetConsoleCtrlHandler(cw_stop_ctrl_handler, FALSE);
fprintf(stderr, "Control+C pressed, aborting...\n");
exit(0);
}
return TRUE;
}
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv)
{
svc.dwServiceType = SERVICE_WIN32;
svc.dwCurrentState = SERVICE_START_PENDING;
svc.dwControlsAccepted = 0;
svc.dwWin32ExitCode = NO_ERROR;
svc.dwServiceSpecificExitCode = 0;
svc.dwCheckPoint = 0;
svc.dwWaitHint = 0;
if (!(svc_handle = RegisterServiceCtrlHandlerA(DT->lpServiceName, ServiceCtrlHandler))) {
logg(LOGG_INFO, "[service] RegisterServiceCtrlHandler() failed with %d\n", GetLastError());
exit(1);
}
if (!SetServiceStatus(svc_handle, &svc)) {
logg(LOGG_INFO, "[service] SetServiceStatus() failed with %d\n", GetLastError());
exit(1);
}
SetEvent(evStart);
WaitForSingleObject(DispatcherThread, INFINITE);
cw_stop_ctrl_handler(CTRL_C_EVENT);
}

38
clamav/common/service.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2021-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2008-2010 Gianluigi Tiesi <sherpya@netfarm.it>
*
* Authors: Gianluigi Tiesi
*
* 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.
*/
#ifndef __SERVICE_H
#define __SERVICE_H
#include <platform.h>
#include <winsvc.h>
int svc_uninstall(const char *name, int verbose);
int svc_install(const char *name, const char *dname, const char *desc);
static void svc_getcpvalue(const char *name);
void svc_register(const char *name);
void svc_ready(void);
int svc_checkpoint(const char *type, const char *name, unsigned int custom, void *context);
void WINAPI ServiceCtrlHandler(DWORD code);
BOOL WINAPI cw_stop_ctrl_handler(DWORD CtrlType);
void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
#endif

View File

@@ -51,25 +51,25 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
hStore = CertOpenSystemStoreA(NULL, "ROOT");
if (NULL == hStore) {
mprintf("!Failed to open system certificate store.\n");
mprintf(LOGG_ERROR, "Failed to open system certificate store.\n");
goto done;
}
store = cert_store_get_int();
if (!store) {
mprintf("!Failed to retrieve cert store\n");
mprintf(LOGG_ERROR, "Failed to retrieve cert store\n");
goto done;
}
pt_err = pthread_mutex_lock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex lock failed\n");
mprintf(LOGG_ERROR, "Mutex lock failed\n");
}
locked = true;
if (store->loaded) {
mprintf("Cert store already loaded\n");
mprintf(LOGG_INFO, "Cert store already loaded\n");
ret = CL_SUCCESS;
goto done;
}
@@ -84,7 +84,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
x509 = NULL;
x509 = d2i_X509(NULL, &encoded_cert, pWinCertContext->cbCertEncoded);
if (NULL == x509) {
mprintf("!Failed to convert system certificate to x509.\n");
mprintf(LOGG_ERROR, "Failed to convert system certificate to x509.\n");
continue;
}
@@ -92,7 +92,7 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
store->system_certs.certificates,
(numCertificatesFound + 1) * sizeof(*store->system_certs.certificates));
if (store->system_certs.certificates == NULL) {
mprintf("!Failed to reserve memory for system cert list\n");
mprintf(LOGG_ERROR, "Failed to reserve memory for system cert list\n");
goto done;
}
@@ -105,15 +105,15 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
issuer = malloc(issuerLen);
if (NULL == issuer) {
mprintf("!Failed to allocate memory for certificate name.\n");
mprintf(LOGG_ERROR, "Failed to allocate memory for certificate name.\n");
ret = CURLE_OUT_OF_MEMORY;
goto done;
}
if (0 == CertGetNameStringA(pWinCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer, issuerLen)) {
mprintf("!Failed to get friendly display name for certificate.\n");
mprintf(LOGG_ERROR, "Failed to get friendly display name for certificate.\n");
} else {
mprintf("Certificate loaded from Windows certificate store: %s\n", issuer);
mprintf(LOGG_INFO, "Certificate loaded from Windows certificate store: %s\n", issuer);
}
free(issuer);
@@ -125,24 +125,24 @@ cl_error_t cert_store_load(X509 **trusted_certs, size_t trusted_cert_count)
lastError = GetLastError();
switch (lastError) {
case E_INVALIDARG:
mprintf("!The handle in the hCertStore parameter is not the same as that in the certificate context pointed to by pPrevCertContext.\n");
mprintf(LOGG_ERROR, "The handle in the hCertStore parameter is not the same as that in the certificate context pointed to by pPrevCertContext.\n");
break;
case CRYPT_E_NOT_FOUND:
case ERROR_NO_MORE_FILES:
if (0 == numCertificatesFound) {
mprintf("!No certificates were found.\n");
mprintf(LOGG_ERROR, "No certificates were found.\n");
}
break;
default:
mprintf("!Unexpected error code from CertEnumCertificatesInStore()\n");
mprintf(LOGG_ERROR, "Unexpected error code from CertEnumCertificatesInStore()\n");
}
if (trusted_certs && trusted_cert_count > 0) {
if (cert_store_set_trusted_int(trusted_certs, trusted_cert_count) == 0) {
mprintf("*Trusted certificates loaded: %zu\n",
mprintf(LOGG_DEBUG, "Trusted certificates loaded: %zu\n",
store->trusted_certs.count);
} else {
mprintf("^Continuing without trusted certificates\n");
mprintf(LOGG_WARNING, "Continuing without trusted certificates\n");
/* proceed as if we succeeded using only certificates from the
* system */
}
@@ -156,7 +156,7 @@ done:
pt_err = pthread_mutex_unlock(&store->mutex);
if (pt_err) {
errno = pt_err;
mprintf("!Mutex unlock failed\n");
mprintf(LOGG_ERROR, "Mutex unlock failed\n");
}
locked = false;
}

View File

@@ -0,0 +1,64 @@
# Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
# Windows compatibility headers
include_directories(${CMAKE_SOURCE_DIR}/win32/compat)
endif()
# The freshclam executable.
add_executable( freshclam-bin )
target_sources( freshclam-bin
PRIVATE
freshclam.c
execute.c
execute.h
notify.c
notify.h )
if(WIN32)
target_sources( freshclam-bin
PRIVATE
${CMAKE_SOURCE_DIR}/win32/res/freshclam.rc
${CMAKE_SOURCE_DIR}/win32/res/clam.manifest )
endif()
set_target_properties( freshclam-bin PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}" )
if (APPLE AND CLAMAV_SIGN_FILE)
set_target_properties( freshclam-bin PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ${CODE_SIGN_IDENTITY}
XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEVELOPMENT_TEAM_ID}
)
endif()
target_link_libraries(freshclam-bin
PRIVATE
ClamAV::libfreshclam
ClamAV::libclamav
ClamAV::common )
if(WIN32)
install(TARGETS freshclam-bin DESTINATION . COMPONENT programs)
install(FILES $<TARGET_PDB_FILE:freshclam-bin> DESTINATION . OPTIONAL COMPONENT programs)
else()
install(TARGETS freshclam-bin DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT programs)
endif()
# Install an empty database directory
INSTALL(CODE "FILE(MAKE_DIRECTORY \${ENV}\${CMAKE_INSTALL_PREFIX}/\${DATABASE_DIRECTORY})" COMPONENT programs)
# Now we rename freshclam-bin executable to freshclam using target properties
set_target_properties( freshclam-bin
PROPERTIES OUTPUT_NAME freshclam )
if(SYSTEMD_FOUND)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/clamav-freshclam.service.in
${CMAKE_CURRENT_BINARY_DIR}/clamav-freshclam.service @ONLY)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/clamav-freshclam.service
DESTINATION ${SYSTEMD_UNIT_DIR}
COMPONENT programs)
endif()

21
clamav/freshclam/Doxyfile Normal file
View File

@@ -0,0 +1,21 @@
PROJECT_NAME = ClamAV - FreshClam
OUTPUT_DIRECTORY = ../docs/freshclam
WARNINGS = YES
FILE_PATTERNS = *.c *.h
PERL_PATH = /usr/bin/perl
SEARCHENGINE = YES
GENERATE_LATEX=NO
OPTIMIZE_OUTPUT_FOR_C=YES
HAVE_DOT=YES
CALL_GRAPH=YES
CALLER_GRAPH=YES
JAVADOC_AUTOBRIEF=YES
GENERATE_MAN=NO
EXAMPLE_PATH=examples
DOT_CLEANUP=NO
MAX_DOT_GRAPH_DEPTH=3
EXTRACT_ALL=YES
INPUT = .

View File

@@ -0,0 +1,13 @@
[Unit]
Description=ClamAV virus database updater
Documentation=man:freshclam(1) man:freshclam.conf(5) https://docs.clamav.net/
# If user wants it run from cron, don't start the daemon.
ConditionPathExists=!/etc/cron.d/clamav-freshclam
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=@prefix@/bin/freshclam -d --foreground=true
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,79 @@
/*
* By Per Jessen <per@computer.org> with changes by the ClamAV team
*
* 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.
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include "output.h"
#include "optparser.h"
#include "execute.h"
#define MAX_CHILDREN 5
int g_active_children;
void execute(const char *type, const char *text, int bDaemonized)
{
int ret;
if (!bDaemonized) {
if (sscanf(text, "EXIT_%d", &ret) == 1) {
logg(LOGG_DEBUG, "%s: EXIT_%d\n", type, ret);
exit(ret);
}
if (system(text) == -1)
logg(LOGG_INFO, "%s: system(%s) failed\n", type, text);
return;
}
#ifdef _WIN32
if (system(text) == -1) {
logg(LOGG_WARNING, "%s: couldn't execute \"%s\".\n", type, text);
return;
}
#else
if (g_active_children < MAX_CHILDREN) {
pid_t pid;
switch (pid = fork()) {
case 0:
if (-1 == system(text)) {
logg(LOGG_WARNING, "%s: couldn't execute \"%s\".\n", type, text);
}
exit(0);
case -1:
logg(LOGG_WARNING, "%s::fork() failed, %s.\n", type, strerror(errno));
break;
default:
g_active_children++;
}
} else {
logg(LOGG_WARNING, "%s: already %d processes active.\n", type, g_active_children);
}
#endif
}

View File

@@ -0,0 +1,29 @@
/*
* By Per Jessen <per@computer.org>
*
* 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.
*/
#ifndef __EXECUTE_H
#define __EXECUTE_H
#include "optparser.h"
extern int g_active_children;
void execute(const char *type, const char *text, int bDaemonized);
#endif

2114
clamav/freshclam/freshclam.c Normal file

File diff suppressed because it is too large Load Diff

176
clamav/freshclam/notify.c Normal file
View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2002-2013 Sourcefire, Inc.
*
* 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>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
#include <string.h>
#include <errno.h>
#include "optparser.h"
#include "output.h"
#include "clamdcom.h"
#include "notify.h"
int clamd_connect(const char *cfgfile, const char *option)
{
#ifndef _WIN32
struct sockaddr_un server;
#endif
struct addrinfo hints, *res, *p;
char port[6];
int ret;
struct optstruct *opts;
const struct optstruct *opt;
int sockd;
if ((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, 0, NULL)) == NULL) {
logg(LOGG_ERROR, "%s: Can't find or parse configuration file %s\n", option,
cfgfile);
return -11;
}
#ifndef _WIN32
if ((opt = optget(opts, "LocalSocket"))->enabled) {
memset(&server, 0x00, sizeof(server));
server.sun_family = AF_UNIX;
strncpy(server.sun_path, opt->strarg, sizeof(server.sun_path));
server.sun_path[sizeof(server.sun_path) - 1] = '\0';
if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
logg(LOGG_WARNING, "Clamd was NOT notified: Can't create socket endpoint for %s: %s\n",
opt->strarg, strerror(errno));
optfree(opts);
return -1;
}
if (connect(sockd, (struct sockaddr *)&server,
sizeof(struct sockaddr_un)) < 0) {
logg(LOGG_WARNING, "Clamd was NOT notified: Can't connect to clamd through %s: %s\n",
opt->strarg, strerror(errno));
closesocket(sockd);
optfree(opts);
return -11;
}
return sockd;
} else
#endif
if ((opt = optget(opts, "TCPSocket"))->enabled) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
snprintf(port, sizeof(port), "%u", (unsigned int)opt->numarg);
port[5] = 0;
opt = optget(opts, "TCPAddr");
while (opt) {
ret = getaddrinfo(opt->strarg, port, &hints, &res);
if (ret) {
logg(LOGG_ERROR, "%s: Can't resolve hostname %s (%s)\n", option,
opt->strarg ? opt->strarg : "",
(ret ==
EAI_SYSTEM)
? strerror(errno)
: gai_strerror(ret));
opt = opt->nextarg;
continue;
}
for (p = res; p != NULL; p = p->ai_next) {
if ((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
logg(LOGG_ERROR, "%s: Can't create TCP socket to connect to %s: %s\n",
option, opt->strarg ? opt->strarg : "localhost", strerror(errno));
continue;
}
if (connect(sockd, p->ai_addr, p->ai_addrlen) == -1) {
logg(LOGG_ERROR, "%s: Can't connect to clamd on %s:%s: %s\n", option,
opt->strarg ? opt->strarg : "localhost", port, strerror(errno));
closesocket(sockd);
continue;
}
optfree(opts);
freeaddrinfo(res);
return sockd;
}
freeaddrinfo(res);
opt = opt->nextarg;
}
} else {
logg(LOGG_ERROR, "%s: No communication socket specified in %s\n", option,
cfgfile);
optfree(opts);
return 1;
}
optfree(opts);
return -1;
}
int notify(const char *cfgfile)
{
char buff[20];
int sockd, bread;
if ((sockd = clamd_connect(cfgfile, "NotifyClamd")) < 0)
return 1;
if (sendln(sockd, "RELOAD", 7) < 0) {
logg(LOGG_ERROR, "NotifyClamd: Could not write to clamd socket: %s\n", strerror(errno));
closesocket(sockd);
return 1;
}
memset(buff, 0, sizeof(buff));
if ((bread = recv(sockd, buff, sizeof(buff), 0)) > 0) {
if (!strstr(buff, "RELOADING")) {
logg(LOGG_ERROR, "NotifyClamd: Unknown answer from clamd: '%s'\n", buff);
closesocket(sockd);
return -1;
}
}
closesocket(sockd);
logg(LOGG_INFO, "Clamd successfully notified about the update.\n");
return 0;
}

27
clamav/freshclam/notify.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
* Copyright (C) 2002-2007 Tomasz Kojm <tkojm@clamav.net>
*
* 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.
*/
#ifndef __NOTIFY_H
#define __NOTIFY_H
int notify(const char *cfgfile);
int clamd_connect(const char *cfgfile, const char *option);
#endif

Some files were not shown because too many files have changed in this diff Show More