Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge clamav-sys #1135

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7acea88
clamav-sys: Initial repo
zaddach Nov 19, 2020
64ec98f
clamav-sys: Add vcpkg support
zaddach Nov 23, 2020
2fad71f
clamav-sys: Fix link in README.md
micahsnyder Nov 30, 2020
038a870
clamav-sys: Build errors with ClamAV 0.102, bumped requirement to 0.103
zaddach Jan 22, 2021
8c4bf60
clamav-sys: Fixes for building on MacOS
Apr 26, 2021
b82c9bd
clamav-sys: Fixed Path import on Windows
zaddach Jan 25, 2021
a49d62f
clamav-sys: Added cl_fmap_open_handle function
zaddach Feb 8, 2021
2c8561f
clamav-sys: Increase version number
zaddach May 21, 2021
c046b5b
clamav-sys: Added build instructions for MacOS
zaddach May 24, 2021
8fbf6ca
clamav-sys: Documented PowerShell library conflict gotcha
zaddach May 24, 2021
ceb6693
clamav-sys: Added functions to get/set engine fields
zaddach May 31, 2021
0006566
clamav-sys: Bumped version
zaddach May 31, 2021
48c1479
clamav-sys: Reformat
shutton Oct 18, 2022
70d2c28
clamav-sys: Sort whitelisted API elements by type and name
shutton Oct 19, 2022
9a08e9c
clamav-sys: Expose cl_set_clcb_msg and cl_msg
shutton Oct 18, 2022
5aa265b
clamav-sys: Extended API exposure and newtype enums
shutton Nov 6, 2023
0c29069
clamav-sys: Update repo and authors
shutton Nov 8, 2023
00fb8bc
clamav-sys: Increase clippy linting strictness
shutton Nov 14, 2023
3192bd7
clamav-sys: Update copyright
shutton Nov 14, 2023
f569b18
clamav-sys: Merge pull request #2 from Cisco-Talos/1-update-repositor…
shutton Nov 14, 2023
ccfb417
clamav-sys: Correct homepage URL
shutton Nov 14, 2023
cda143d
clamav-sys: Merge pull request #3 from Cisco-Talos/fix-homepage-url
shutton Nov 14, 2023
6c88488
clamav-sys: Update authors
shutton Jan 8, 2024
6bc4e9b
clamav-sys: Merge pull request #5 from Cisco-Talos/update-authors
shutton Jan 8, 2024
917bcc2
clamav-sys: Bury crate for merge into Cisco-Talos/clamav
shutton Jan 9, 2024
f00f640
Merge clamav-sys Rust crate
shutton Jan 9, 2024
8c7a3ff
Add clamav-sys to cargo workspace
shutton Jan 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
[workspace]

members = [
"libclamav_rust",
]
members = ["clamav-sys", "libclamav_rust"]

[profile.dev.package."*"]
opt-level = 2
2 changes: 2 additions & 0 deletions clamav-sys/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
Cargo.lock
22 changes: 22 additions & 0 deletions clamav-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
authors = [
"Jonas Zaddach <[email protected]>",
"Scott Hutton <[email protected]>",
]
categories = ["external-ffi-bindings"]
description = "ClamAV low level bindings for Rust"
edition = "2021"
homepage = "https://github.com/Cisco-Talos/clamav-sys/"
license = "GPL-2.0"
name = "clamav-sys"
repository = "https://github.com/Cisco-Talos/clamav-sys/"
version = "1.0.0"

[build-dependencies]
bindgen = "0.64.0"

[target.'cfg(unix)'.build-dependencies]
pkg-config = "0.3"

[target.'cfg(windows)'.build-dependencies]
vcpkg = "0.2.10"
339 changes: 339 additions & 0 deletions clamav-sys/LICENSE

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions clamav-sys/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# clamav-sys

clamav-sys is a minimal Rust interface around [libclamav](https://www.clamav.net).
This package is not supposed to be used stand-alone, but only through its safe wrapper,
clamav-rs.


## Building

### Unix (anything but Windows)
You should have the `clamav-dev` package of your distribution installed (ClamAV
with headers). The headers and library should be picked up automatically via
pkg-config.

### Windows
#### vcpkg
The preferred way of handling dependencies is `vcpkg`.
Point `$env:VCPKG_ROOT` to your `vcpkg` installation, and set
`$env:VCPKGRS_DYNAMIC=1` to use dynamic linking (the default method of linking will
likely not work, as `pdcurses` doesn't support the `x64-windows-static-md` triplet).

See the [vcpkg crate's documentation](https://docs.rs/vcpkg) for more details.

Gotchas:
- Windows has its own version of a zlib dll that is incompatbile with vcpkg. If
you get a message such as "The procedure entry point gzdirect could not be
located in the dynamic link library", you'll want to make sure that the vcpkg
dynamic libraries in your PATH variable are preceding the Windows one.
```
$env:PATH="$env:VCPKG_ROOT\installed\x64-windows\bin\;$env:PATH"
```
This error is especially hard to diagnose in PowerShell, as the process will
just hang without any output. In cmd.exe you'll get the aforementioned dialog
box telling you about the error.


#### Manual
If `vcpkg` is not available or cannot be found on your system, the build defaults
to a manual specification of dependencies.
You will need to define the following environment variables:
- `CLAMAV_SOURCE`: Points to the directory where the ClamAV source is located.
- `CLAMAV_BUILD`: Points to the ClamAV build directory.
- `OPENSSL_INCLUDE`: Points to the include directory containing `openssl/ssl.h`.

### MacOS
Install the development dependencies via `homebrew`:
```
brew install clamav [email protected]
```

OpenSSL is not included in the environment to avoid shadowing Apple's one, so
you need to tell the build script where it is located:
```
export OPENSSL_ROOT_DIR=/usr/local/Cellar/[email protected]/1.1.1i/
```

## Versioning
The version number of `libclamav-sys` tracks ClamAV's version number. That is,
you'll require at least ClamAV 1.0.0 to build `libclamav-sys` 1.0.0. As ClamAV
usually doesn't do breaking API changes, you'll be able to use `libclamav-sys`
with newer ClamAV versions.

No attempt at preserving downward compatibility (using a `libclamav-sys` with
a version number greater than ClamAV's) is made.
226 changes: 226 additions & 0 deletions clamav-sys/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
// Copyright (C) 2020-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
//
// Authors: Jonas Zaddach, Scott Hutton
//
// 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.

use std::env;
use std::path::PathBuf;

// Generate bindings for these functions:
const BINDGEN_FUNCTIONS: &[&str] = &[
"cl_cleanup_crypto",
"cl_cvdfree",
"cl_cvdparse",
"cl_debug",
"cl_engine_addref",
"cl_engine_compile",
"cl_engine_free",
"cl_engine_get_num",
"cl_engine_get_str",
"cl_engine_new",
"cl_engine_set_clcb_engine_compile_progress",
"cl_engine_set_clcb_engine_free_progress",
"cl_engine_set_clcb_file_inspection",
"cl_engine_set_clcb_file_props",
"cl_engine_set_clcb_hash",
"cl_engine_set_clcb_meta",
"cl_engine_set_clcb_post_scan",
"cl_engine_set_clcb_pre_cache",
"cl_engine_set_clcb_pre_scan",
"cl_engine_set_clcb_sigload",
"cl_engine_set_clcb_sigload_progress",
"cl_engine_set_clcb_stats_add_sample",
"cl_engine_set_clcb_stats_decrement_count",
"cl_engine_set_clcb_stats_flush",
"cl_engine_set_clcb_stats_get_hostid",
"cl_engine_set_clcb_stats_get_num",
"cl_engine_set_clcb_stats_get_size",
"cl_engine_set_clcb_stats_remove_sample",
"cl_engine_set_clcb_stats_submit",
"cl_engine_set_clcb_virus_found",
"cl_engine_set_num",
"cl_engine_set_stats_set_cbdata",
"cl_engine_set_str",
"cl_engine_settings_apply",
"cl_engine_settings_copy",
"cl_engine_settings_free",
"cl_engine_stats_enable",
"cl_fmap_close",
"cl_fmap_open_handle",
"cl_fmap_open_memory",
"cl_init",
"cl_initialize_crypto",
"cl_load",
"cl_retdbdir",
"cl_retflevel",
"cl_retver",
"cl_scandesc",
"cl_scandesc_callback",
"cl_scanfile",
"cl_scanfile_callback",
"cl_scanmap_callback",
"cl_set_clcb_msg",
"cl_strerror",
"cli_append_virus",
"cli_ctx",
"cli_dbgmsg_no_inline",
"cli_errmsg",
"cli_get_debug_flag",
"cli_getdsig",
"cli_infomsg_simple",
"cli_versig2",
"cli_warnmsg",
"lsig_increment_subsig_match",
];

// Generate bindings for these types (structs, prototypes, etc.):
const BINDGEN_TYPES: &[&str] = &[
"cl_cvd",
"clcb_file_props",
"clcb_meta",
"clcb_post_scan",
"clcb_pre_scan",
"cli_ac_data",
"cli_ac_result",
"cli_matcher",
"time_t",
];

// Generate "newtype" enums for these C enums
const BINDGEN_ENUMS: &[&str] = &["cl_engine_field", "cl_error_t", "cl_msg"];

const BINDGEN_CONSTANTS: &[&str] = &[
"CL_DB_.*",
"CL_INIT_DEFAULT",
"CL_SCAN_.*",
"ENGINE_OPTIONS_.*",
"LAYER_ATTRIBUTES_.*",
];

const CLAMAV_LIBRARY_NAME: &str = "clamav";

fn generate_bindings(customize_bindings: &dyn Fn(bindgen::Builder) -> bindgen::Builder) {
let mut bindings = bindgen::Builder::default();
for function in BINDGEN_FUNCTIONS {
bindings = bindings.allowlist_function(function);
}

for typename in BINDGEN_TYPES {
bindings = bindings.allowlist_type(typename);
}

for typename in BINDGEN_ENUMS {
bindings = bindings.newtype_enum(typename);
}

for constant in BINDGEN_CONSTANTS {
bindings = bindings.allowlist_var(constant);
}

bindings = bindings
.header("wrapper.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks));

bindings = customize_bindings(bindings);

// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

bindings
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}

fn cargo_common() {
println!("cargo:rustc-link-lib=dylib={}", CLAMAV_LIBRARY_NAME);

// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=wrapper.h");
}

#[cfg(windows)]
fn main() {
let include_paths = match vcpkg::find_package("clamav") {
Ok(pkg) => pkg.include_paths,
Err(err) => {
println!(
"cargo:warning=Either vcpkg is not installed, or an error occurred in vcpkg: {}",
err
);
let clamav_source = PathBuf::from(env::var("CLAMAV_SOURCE").expect("CLAMAV_SOURCE environment variable must be set and point to ClamAV's source directory"));
let clamav_build = PathBuf::from(env::var("CLAMAV_BUILD").expect("CLAMAV_BUILD environment variable must be set and point to ClamAV's build directory"));
let openssl_include = PathBuf::from(env::var("OPENSSL_INCLUDE").expect("OPENSSL_INCLUDE environment variable must be set and point to openssl's include directory"));
let profile = env::var("PROFILE").unwrap();

let library_path = match profile.as_str() {
"debug" => std::path::Path::new(&clamav_build).join("libclamav/Debug"),
"release" => std::path::Path::new(&clamav_build).join("libclamav/Release"),
_ => panic!("Unexpected build profile"),
};

println!(
"cargo:rustc-link-search=native={}",
library_path.to_str().unwrap()
);

vec![
clamav_source.join("libclamav"),
clamav_build,
openssl_include,
]
}
};

cargo_common();
generate_bindings(&|x: bindgen::Builder| -> bindgen::Builder {
let mut x = x;
for include_path in &include_paths {
x = x.clang_arg("-I").clang_arg(include_path.to_str().unwrap());
}
x
});
}

#[cfg(unix)]
fn main() {
let libclamav = pkg_config::Config::new()
.atleast_version("0.103")
.probe("libclamav")
.unwrap();

let mut include_paths = libclamav.include_paths;

if let Some(val) = std::env::var_os("OPENSSL_ROOT_DIR") {
let mut openssl_include_dir = PathBuf::from(val);
openssl_include_dir.push("include");
include_paths.push(openssl_include_dir);
}

cargo_common();
generate_bindings(&|x: bindgen::Builder| -> bindgen::Builder {
let mut x = x;
for include_path in &include_paths {
x = x.clang_arg("-I").clang_arg(include_path.to_str().unwrap());
}
x
});
}
Loading
Loading