diff --git a/Cargo.lock b/Cargo.lock index 77e4719bb0..3f0fb8911e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -25,9 +25,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.21.3" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bindgen" @@ -48,7 +48,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.31", + "syn 2.0.38", "which", ] @@ -66,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -79,12 +79,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - [[package]] name = "bytemuck" version = "1.14.0" @@ -93,9 +87,15 @@ checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cbindgen" @@ -115,15 +115,6 @@ dependencies = [ "toml", ] -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - [[package]] name = "cexpr" version = "0.6.0" @@ -148,10 +139,12 @@ dependencies = [ "cbindgen", "flate2", "hex", + "hex-literal", "image", "libc", "log", "num-traits", + "onenote_parser", "rustdct", "sha1", "sha2", @@ -180,9 +173,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -196,16 +189,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -272,31 +255,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] -name = "errno" -version = "0.3.3" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", + "cfg-if", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "enum-primitive-derive" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e" +dependencies = [ + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "errno" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ - "cc", "libc", + "windows-sys", ] [[package]] name = "exr" -version = "1.7.0" +version = "1.71.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e481eb11a482815d3e9d618db8c42a93207134662873809335a92327440c18" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" dependencies = [ "bit_field", "flume", @@ -310,24 +302,24 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fdeflate" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" dependencies = [ "simd-adler32", ] [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -335,29 +327,13 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.14" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "pin-project", "spin", ] -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - [[package]] name = "generic-array" version = "0.14.7" @@ -368,19 +344,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - [[package]] name = "gif" version = "0.12.0" @@ -418,18 +381,18 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "home" version = "0.5.5" @@ -468,6 +431,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -483,15 +455,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -512,9 +475,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libloading" @@ -528,15 +491,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -550,9 +513,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.3" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -579,15 +542,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom", -] - [[package]] name = "nom" version = "7.1.3" @@ -630,23 +584,13 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.18.0" @@ -654,30 +598,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +name = "onenote_parser" +version = "0.3.1" +source = "git+https://github.com/Cisco-Talos/onenote.rs.git?branch=CLAM-2329-new-from-slice#8b450447e58143004b68dd21c11b710fdb79be92" +dependencies = [ + "bytes", + "encoding_rs", + "enum-primitive-derive", + "itertools", + "num-traits", + "paste", + "thiserror", + "uuid", + "widestring", +] [[package]] -name = "pin-project" -version = "1.1.3" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] -name = "pin-project-internal" -version = "1.1.3" +name = "peeking_take_while" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.31", -] +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "png" @@ -699,7 +645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.31", + "syn 2.0.38", ] [[package]] @@ -713,9 +659,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -740,9 +686,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", @@ -750,30 +696,28 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.5" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -783,9 +727,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -794,9 +738,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-hash" @@ -830,11 +774,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.11" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", @@ -855,29 +799,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.38", ] [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -886,9 +830,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -897,9 +841,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -920,9 +864,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "spin" @@ -952,9 +896,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -963,9 +907,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", @@ -976,22 +920,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.38", ] [[package]] @@ -1026,15 +970,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" @@ -1043,70 +987,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" +name = "uuid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" [[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.31", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.31", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "weezl" @@ -1126,6 +1016,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" diff --git a/INSTALL.md b/INSTALL.md index 1831f675dd..7ceab5a4bf 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -585,6 +585,14 @@ But if you: -D OPENSSL_SSL_LIBRARY="_filepath of libssl library_" ``` +_Tip_: For Windows, you may need to do this instead: +```sh + -D OPENSSL_ROOT_DIR="_path to openssl install root_" + -D OPENSSL_INCLUDE_DIR="_filepath of openssl header directory_" + -D LIB_EAY_RELEASE="_filepath of libcrypto library_" # or LIB_EAY_DEBUG for Debug builds + -D SSL_EAY_RELEASE="_filepath of libssl library_" # or SSL_EAY_DEBUG for Debug builds +``` + ### `libjson-c` _Tip_: You're strongly encouraged to link with the a static json-c library. diff --git a/clamd/server-th.c b/clamd/server-th.c index 81dcfcbf14..9f48832058 100644 --- a/clamd/server-th.c +++ b/clamd/server-th.c @@ -1291,6 +1291,13 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne logg(LOGG_INFO, "HWP3 support disabled.\n"); } + if (optget(opts, "ScanOneNote")->enabled) { + logg(LOGG_INFO, "OneNote support enabled.\n"); + options.parse |= CL_SCAN_PARSE_ONENOTE; + } else { + logg(LOGG_INFO, "OneNote support disabled.\n"); + } + if (optget(opts, "PhishingScanURLs")->enabled) { /* TODO: Remove deprecated option in a future feature release */ if ((optget(opts, "PhishingAlwaysBlockCloak")->enabled) || diff --git a/clamscan/clamscan.c b/clamscan/clamscan.c index b9004a873a..aef32418d8 100644 --- a/clamscan/clamscan.c +++ b/clamscan/clamscan.c @@ -304,6 +304,7 @@ void help(void) 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-onenote[=yes(*)/no] Scan OneNote 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"); diff --git a/clamscan/manager.c b/clamscan/manager.c index 42e803f166..9f755a5559 100644 --- a/clamscan/manager.c +++ b/clamscan/manager.c @@ -1552,6 +1552,9 @@ int scanmanager(const struct optstruct *opts) if (optget(opts, "scan-hwp3")->enabled) options.parse |= CL_SCAN_PARSE_HWP3; + if (optget(opts, "scan-onenote")->enabled) + options.parse |= CL_SCAN_PARSE_ONENOTE; + /* TODO: Remove deprecated option in a future feature release */ if ((optget(opts, "algorithmic-detection")->enabled) && /* && used due to default-yes for both options */ (optget(opts, "heuristic-alerts")->enabled)) { diff --git a/cmake/FindRust.cmake b/cmake/FindRust.cmake index 4a90c41d3c..6e6b5fc264 100644 --- a/cmake/FindRust.cmake +++ b/cmake/FindRust.cmake @@ -236,7 +236,7 @@ function(add_rust_executable) # Build the executable. add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${EXE_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with:\n\t ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") @@ -265,7 +265,7 @@ endfunction() function(add_rust_library) set(options) - set(oneValueArgs TARGET SOURCE_DIRECTORY BINARY_DIRECTORY PRECOMPILE_TESTS) + set(oneValueArgs TARGET SOURCE_DIRECTORY BINARY_DIRECTORY PRECOMPILE_TESTS INCLUDE_DIRECTORIES) cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(WIN32) @@ -287,8 +287,8 @@ function(add_rust_library) if("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64;x86_64|x86_64;arm64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" COMMAND lipo -create ${ARGS_BINARY_DIRECTORY}/x86_64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a ${ARGS_BINARY_DIRECTORY}/aarch64-apple-darwin/${CARGO_BUILD_TYPE}/lib${ARGS_TARGET}.a -output "${OUTPUT}" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" @@ -297,14 +297,14 @@ function(add_rust_library) elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(arm64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=aarch64-apple-darwin WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") elseif("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(x86_64)$") add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} --target=x86_64-apple-darwin COMMAND ${CMAKE_COMMAND} -E make_directory "${ARGS_BINARY_DIRECTORY}/${RUST_COMPILER_TARGET}/${CARGO_BUILD_TYPE}" WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} @@ -312,7 +312,7 @@ function(add_rust_library) else() add_custom_command( OUTPUT "${OUTPUT}" - COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} + COMMAND ${CMAKE_COMMAND} -E env "CARGO_CMD=build" "CARGO_TARGET_DIR=${ARGS_BINARY_DIRECTORY}" "MAINTAINER_MODE=${MAINTAINER_MODE}" "CARGO_INCLUDE_DIRECTORIES=\"${ARGS_INCLUDE_DIRECTORIES}\"" "RUSTFLAGS=${RUSTFLAGS}" ${cargo_EXECUTABLE} ${MY_CARGO_ARGS} WORKING_DIRECTORY "${ARGS_SOURCE_DIRECTORY}" DEPENDS ${LIB_SOURCES} COMMENT "Building ${ARGS_TARGET} in ${ARGS_BINARY_DIRECTORY} with: ${cargo_EXECUTABLE} ${MY_CARGO_ARGS_STRING}") diff --git a/common/optparser.c b/common/optparser.c index e7a8996240..50bdae904f 100644 --- a/common/optparser.c +++ b/common/optparser.c @@ -434,6 +434,8 @@ const struct clam_option __clam_options[] = { {"ScanHWP3", "scan-hwp3", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option enables scanning HWP3 files.\nIf you turn off this option, the original files will still be scanned, but\nwithout additional processing.", "yes"}, + {"ScanOneNote", "scan-onenote", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option enables scanning OneNote files.\nIf you turn off this option, the original files will still be scanned, but\nwithout additional processing.", "yes"}, + {"ScanArchive", "scan-archive", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Scan within archives and compressed files.\nIf you turn off this option, the original files will still be scanned, but\nwithout unpacking and additional processing.", "yes"}, {"ForceToDisk", "force-to-disk", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option causes memory or nested map scans to dump the content to disk.\nIf you turn on this option, more data is written to disk and is available\nwhen the leave-temps option is enabled at the cost of more disk writes.", "no"}, diff --git a/docs/man/clamd.conf.5.in b/docs/man/clamd.conf.5.in index 322c07965e..e177590296 100644 --- a/docs/man/clamd.conf.5.in +++ b/docs/man/clamd.conf.5.in @@ -479,6 +479,13 @@ If you turn off this option, the original files will still be scanned, but witho .br Default: yes .TP +\fBScanOneNote BOOL\fR +This option enables scanning OneNote files. +.br +If you turn off this option, the original files will still be scanned, but without additional processing. +.br +Default: yes +.TP \fBScanArchive BOOL\fR Scan within archives and compressed files. .br diff --git a/etc/clamd.conf.sample b/etc/clamd.conf.sample index a22481232b..49410e00b5 100644 --- a/etc/clamd.conf.sample +++ b/etc/clamd.conf.sample @@ -426,6 +426,12 @@ Example # Default: yes #ScanHWP3 yes +# This option enables scanning of OneNote files. +# If you turn off this option, the original files will still be scanned, but +# without additional processing. +# Default: yes +#ScanOneNote yes + ## ## Mail files diff --git a/libclamav/clamav.h b/libclamav/clamav.h index e2fd46f2e2..20e8e905e9 100644 --- a/libclamav/clamav.h +++ b/libclamav/clamav.h @@ -180,6 +180,7 @@ struct cl_scan_options { #define CL_SCAN_PARSE_OLE2 0x80 #define CL_SCAN_PARSE_HTML 0x100 #define CL_SCAN_PARSE_PE 0x200 +#define CL_SCAN_PARSE_ONENOTE 0x400 /* heuristic alerting options */ #define CL_SCAN_HEURISTIC_BROKEN 0x2 /* alert on broken PE and broken ELF files */ diff --git a/libclamav/dconf.c b/libclamav/dconf.c index fc1a119593..b1fe370a4c 100644 --- a/libclamav/dconf.c +++ b/libclamav/dconf.c @@ -118,6 +118,7 @@ static struct dconf_module modules[] = { {"DOCUMENT", "OOXML", DOC_CONF_OOXML, 1}, {"DOCUMENT", "MSPML", DOC_CONF_MSXML, 1}, {"DOCUMENT", "HWP", DOC_CONF_HWP, 1}, + {"DOCUMENT", "ONENOTE", DOC_CONF_ONENOTE, 1}, {"MAIL", "MBOX", MAIL_CONF_MBOX, 1}, {"MAIL", "TNEF", MAIL_CONF_TNEF, 1}, diff --git a/libclamav/dconf.h b/libclamav/dconf.h index 7bb5fabd08..f70989887f 100644 --- a/libclamav/dconf.h +++ b/libclamav/dconf.h @@ -109,6 +109,7 @@ struct cli_dconf { #define DOC_CONF_MSXML 0x80 #define DOC_CONF_OOXML 0x100 #define DOC_CONF_HWP 0x200 +#define DOC_CONF_ONENOTE 0x400 /* Mail flags */ #define MAIL_CONF_MBOX 0x1 diff --git a/libclamav/filetypes.c b/libclamav/filetypes.c index f370fd23a9..44abd6e815 100644 --- a/libclamav/filetypes.c +++ b/libclamav/filetypes.c @@ -138,6 +138,7 @@ static const struct ftmap_s { { "CL_TYPE_EGG", CL_TYPE_EGG }, { "CL_TYPE_EGGSFX", CL_TYPE_EGGSFX }, { "CL_TYPE_UDF", CL_TYPE_UDF }, + { "CL_TYPE_ONENOTE", CL_TYPE_ONENOTE }, { NULL, CL_TYPE_IGNORED } }; // clang-format on diff --git a/libclamav/filetypes.h b/libclamav/filetypes.h index 449fb00fa2..b75a9e277c 100644 --- a/libclamav/filetypes.h +++ b/libclamav/filetypes.h @@ -92,6 +92,7 @@ typedef enum cli_file { CL_TYPE_OOXML_HWP, CL_TYPE_PS, CL_TYPE_EGG, + CL_TYPE_ONENOTE, /* Section for partition types */ CL_TYPE_PART_ANY, /* unknown partition type */ diff --git a/libclamav/filetypes_int.h b/libclamav/filetypes_int.h index 0e7049795f..e3e7bd64f1 100644 --- a/libclamav/filetypes_int.h +++ b/libclamav/filetypes_int.h @@ -204,5 +204,6 @@ static const char *ftypes_int[] = { "0:0:4d4d:TIFF Big Endian:CL_TYPE_ANY:CL_TYPE_GRAPHICS:81:121", "1:*:377abcaf271c:7zip-SFX:CL_TYPE_ANY:CL_TYPE_7ZSFX:74", "1:0:3c3f786d6c2076657273696f6e3d22312e3022{0-1024}70726f6769643d22576f72642e446f63756d656e74223f3e:Microsoft Word 2003 XML Document:CL_TYPE_ANY:CL_TYPE_XML_WORD:80", + "0:0:e4525c7b8cd8a74daeb15378d02996d3:Microsoft OneNote Document:CL_TYPE_ANY:CL_TYPE_ONENOTE:200", NULL}; #endif diff --git a/libclamav/fmap.c b/libclamav/fmap.c index 5ca70a0ec8..0548b8adf5 100644 --- a/libclamav/fmap.c +++ b/libclamav/fmap.c @@ -132,7 +132,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha m = cl_fmap_open_handle((void *)(ssize_t)fd, offset, len, pread_cb, 1); if (!m) return NULL; - m->mtime = st.st_mtime; + m->mtime = (uint64_t)st.st_mtime; if (NULL != name) { m->name = cli_strdup(name); @@ -152,8 +152,8 @@ static void unmap_win32(fmap_t *m) if (NULL != m->data) { UnmapViewOfFile(m->data); } - if (NULL != m->mh) { - CloseHandle(m->mh); + if (NULL != m->windows_map_handle) { + CloseHandle(m->windows_map_handle); } if (NULL != m->name) { free(m->name); @@ -169,8 +169,8 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha STATBUF st; fmap_t *m = NULL; const void *data; - HANDLE fh; - HANDLE mh; + HANDLE windows_file_handle; + HANDLE windows_map_handle; *empty = 0; if (FSTAT(fd, &st)) { @@ -194,30 +194,30 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha pages = fmap_align_items(len, pgsz); - if ((fh = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { + if ((windows_file_handle = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { cli_errmsg("fmap: cannot get a valid handle for descriptor %d\n", fd); return NULL; } - if (!(mh = CreateFileMapping(fh, NULL, PAGE_READONLY, (DWORD)((len >> 31) >> 1), (DWORD)len, NULL))) { + if (!(windows_map_handle = CreateFileMapping(windows_file_handle, NULL, PAGE_READONLY, (DWORD)((len >> 31) >> 1), (DWORD)len, NULL))) { cli_errmsg("fmap: cannot create a map of descriptor %d\n", fd); return NULL; } - if (!(data = MapViewOfFile(mh, FILE_MAP_READ, (DWORD)((offset >> 31) >> 1), (DWORD)(offset), len))) { + if (!(data = MapViewOfFile(windows_map_handle, FILE_MAP_READ, (DWORD)((offset >> 31) >> 1), (DWORD)(offset), len))) { cli_errmsg("fmap: cannot map file descriptor %d\n", fd); - CloseHandle(mh); + CloseHandle(windows_map_handle); return NULL; } if (!(m = cl_fmap_open_memory(data, len))) { cli_errmsg("fmap: cannot allocate fmap_t\n", fd); UnmapViewOfFile(data); - CloseHandle(mh); + CloseHandle(windows_map_handle); return NULL; } - m->handle = (void *)(size_t)fd; - m->handle_is_fd = 1; /* This is probably(?) needed so `fmap_fd()` can return the file descriptor. */ - m->fh = fh; - m->mh = mh; - m->unmap = unmap_win32; + m->handle = (void *)(size_t)fd; + m->handle_is_fd = true; /* This is probably(?) needed so `fmap_fd()` can return the file descriptor. */ + m->windows_file_handle = (void *)windows_file_handle; + m->windows_map_handle = (void *)windows_map_handle; + m->unmap = unmap_win32; if (NULL != name) { m->name = cli_strdup(name); @@ -416,7 +416,7 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, } m->handle = handle; m->pread_cb = pread_cb; - m->aging = use_aging; + m->aging = use_aging != 0 ? true : false; m->offset = offset; m->nested_offset = 0; m->len = len; /* m->nested_offset + m->len = m->real_len */ @@ -430,7 +430,7 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len, m->need_offstr = handle_need_offstr; m->gets = handle_gets; m->unneed_off = handle_unneed_off; - m->handle_is_fd = 1; + m->handle_is_fd = true; m->have_md5 = false; m->have_sha1 = false; m->have_sha256 = false; @@ -587,7 +587,7 @@ static int fmap_readpage(fmap_t *m, uint64_t first_page, uint64_t count, uint64_ cli_warnmsg("fmap_readpage: fstat failed: %s\n", errtxt); return 1; } - if (m->mtime != st.st_mtime) { + if (m->mtime != (uint64_t)st.st_mtime) { cli_warnmsg("fmap_readpage: file changed as we read it\n"); return 1; } diff --git a/libclamav/fmap.h b/libclamav/fmap.h index 87742752cf..2e298e46c2 100644 --- a/libclamav/fmap.h +++ b/libclamav/fmap.h @@ -51,19 +51,19 @@ struct cl_fmap { const void *data; /* internal */ - time_t mtime; + uint64_t mtime; uint64_t pages; uint64_t pgsz; uint64_t paged; - uint16_t aging; - bool dont_cache_flag; /** indicates if we should not cache scan results for this fmap. Used if limits exceeded */ - uint16_t handle_is_fd; /** non-zero if map->handle is an fd. */ - size_t offset; /** file offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0 */ - size_t nested_offset; /** offset from start of original fmap (data) for nested scan. 0 for orig fmap. */ - size_t real_len; /** len from start of original fmap (data) to end of current (possibly nested) map. */ - /* real_len == nested_offset + len. - real_len is needed for nested maps because we only reference the original mapping data. - We convert caller's fmap offsets & lengths to real data offsets using nested_offset & real_len. */ + bool aging; /** indicates if we should age off memory mapped pages */ + bool dont_cache_flag; /** indicates if we should not cache scan results for this fmap. Used if limits exceeded */ + bool handle_is_fd; /** non-zero if map->handle is an fd. */ + size_t offset; /** file offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0 */ + size_t nested_offset; /** offset from start of original fmap (data) for nested scan. 0 for orig fmap. */ + size_t real_len; /** len from start of original fmap (data) to end of current (possibly nested) map. */ + /* real_len == nested_offset + len. + real_len is needed for nested maps because we only reference the original mapping data. + We convert caller's fmap offsets & lengths to real data offsets using nested_offset & real_len. */ /* external */ size_t len; /** length of data from nested_offset, accessible via current fmap */ @@ -82,10 +82,8 @@ struct cl_fmap { const void *(*need_offstr)(fmap_t *, size_t at, size_t len_hint); const void *(*gets)(fmap_t *, char *dst, size_t *at, size_t max_len); void (*unneed_off)(fmap_t *, size_t at, size_t len); -#ifdef _WIN32 - HANDLE fh; - HANDLE mh; -#endif + void *windows_file_handle; + void *windows_map_handle; bool have_md5; unsigned char md5[CLI_HASHLEN_MD5]; bool have_sha1; @@ -424,7 +422,7 @@ cl_error_t fmap_dump_to_file(fmap_t *map, const char *filepath, const char *tmpd * @brief Return the open file descriptor for the fmap (if available). * * This function will only provide the file descriptor if the fmap handle is set, - * and if the handle is in fact a file descriptor (handle_is_fd != 0). + * and if the handle is in fact a file descriptor (handle_is_fd == true). * * @param m The fmap. * @return int The file descriptor, or -1 if not available. diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map index fbd35f69c2..f927cae37c 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -292,6 +292,7 @@ CLAMAV_PRIVATE { readdb_parse_ldb_subsignature; fuzzy_hash_calculate_image; ffierror_fmt; + cli_magic_scan_buff; __cli_strcasestr; __cli_strndup; diff --git a/libclamav/others.h b/libclamav/others.h index e05d120253..e72a348ebf 100644 --- a/libclamav/others.h +++ b/libclamav/others.h @@ -191,6 +191,7 @@ typedef struct recursion_level_tag { } recursion_level_t; typedef void *evidence_t; +typedef void *onedump_t; /* internal clamav context */ typedef struct cli_ctx_tag { @@ -568,6 +569,7 @@ extern LIBCLAMAV_EXPORT int have_rar; #define SCAN_PARSE_OLE2 (ctx->options->parse & CL_SCAN_PARSE_OLE2) #define SCAN_PARSE_HTML (ctx->options->parse & CL_SCAN_PARSE_HTML) #define SCAN_PARSE_PE (ctx->options->parse & CL_SCAN_PARSE_PE) +#define SCAN_PARSE_ONENOTE (ctx->options->parse & CL_SCAN_PARSE_ONENOTE) #define SCAN_HEURISTIC_BROKEN (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN) #define SCAN_HEURISTIC_BROKEN_MEDIA (ctx->options->heuristic & CL_SCAN_HEURISTIC_BROKEN_MEDIA) diff --git a/libclamav/png.c b/libclamav/png.c index bf3c8eb340..ac3bb8ed53 100644 --- a/libclamav/png.c +++ b/libclamav/png.c @@ -137,7 +137,7 @@ cl_error_t cli_parsepng(cli_ctx *ctx) if (chunk_data_length > 0) { ptr = (uint8_t *)fmap_need_off_once(map, offset, chunk_data_length); if (NULL == ptr) { - cli_warnmsg("PNG: Unexpected early end-of-file.\n"); + cli_dbgmsg("PNG: Unexpected early end-of-file.\n"); if (SCAN_HEURISTIC_BROKEN_MEDIA) { status = cli_append_potentially_unwanted(ctx, "Heuristics.Broken.Media.PNG.EOFReadingChunk"); } diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 12b97306d3..8110110499 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -473,10 +473,6 @@ static cl_error_t cli_scanrar_file(const char *filepath, int desc, cli_ctx *ctx) /* * Free up any malloced metadata... */ - if (metadata.filename != NULL) { - free(metadata.filename); - metadata.filename = NULL; - } if (NULL != filename_base) { free(filename_base); filename_base = NULL; @@ -512,11 +508,6 @@ static cl_error_t cli_scanrar_file(const char *filepath, int desc, cli_ctx *ctx) filename_base = NULL; } - if (metadata.filename != NULL) { - free(metadata.filename); - metadata.filename = NULL; - } - if (NULL != extract_fullpath) { free(extract_fullpath); extract_fullpath = NULL; @@ -4591,6 +4582,11 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type) ret = cli_scanegg(ctx); break; + case CL_TYPE_ONENOTE: + if (SCAN_PARSE_ONENOTE && (DCONF_ARCH & DOC_CONF_ONENOTE)) + ret = scan_onenote(ctx); + break; + case CL_TYPE_OOXML_WORD: case CL_TYPE_OOXML_PPT: case CL_TYPE_OOXML_XL: diff --git a/libclamav_rust/CMakeLists.txt b/libclamav_rust/CMakeLists.txt index 7df3ffee91..5874b33923 100644 --- a/libclamav_rust/CMakeLists.txt +++ b/libclamav_rust/CMakeLists.txt @@ -8,6 +8,7 @@ add_rust_library(TARGET clamav_rust SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" BINARY_DIRECTORY "${CMAKE_BINARY_DIR}" + INCLUDE_DIRECTORIES "$" # Tests cannot be pre-compiled here, because there are circular dependencies # between libclamav_rust and libclamav to include calls like `cli_getdsig()` # as well as the logging functions. diff --git a/libclamav_rust/Cargo.toml b/libclamav_rust/Cargo.toml index e0d38c149f..26a3a22b3a 100644 --- a/libclamav_rust/Cargo.toml +++ b/libclamav_rust/Cargo.toml @@ -20,6 +20,8 @@ base64 = "0.21.0" sha1 = "0.10.5" unicode-segmentation = "1.10.1" bindgen = "0.65" +onenote_parser = { git = "https://github.com/Cisco-Talos/onenote.rs.git", branch = "CLAM-2329-new-from-slice" } +hex-literal = "0.4.1" [lib] crate-type = ["staticlib"] diff --git a/libclamav_rust/build.rs b/libclamav_rust/build.rs index c4846bfbe5..36dd19dd77 100644 --- a/libclamav_rust/build.rs +++ b/libclamav_rust/build.rs @@ -52,6 +52,7 @@ const BINDGEN_FUNCTIONS: &[&str] = &[ "cli_versig2", "cli_getdsig", "cli_get_debug_flag", + "cli_magic_scan_buff", ]; // Generate bindings for these types (structs, enums): @@ -61,6 +62,7 @@ const BINDGEN_TYPES: &[&str] = &[ "cli_ac_result", "css_image_extractor_t", "css_image_handle_t", + "onedump_t", ]; // Find the required functions and types in these headers: @@ -70,6 +72,8 @@ const BINDGEN_HEADERS: &[&str] = &[ "../libclamav/others.h", "../libclamav/dsig.h", "../libclamav/htmlnorm.h", + "../libclamav/fmap.h", + "../libclamav/scanners.h", ]; // Find the required headers in these directories: @@ -129,13 +133,14 @@ fn main() -> Result<(), &'static str> { fn execute_bindgen() -> Result<(), &'static str> { let build_dir = PathBuf::from(env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| ".".into())); let build_include_path = format!("-I{}", build_dir.join(".").to_str().unwrap()); + let has_include_directories = env::var("CARGO_INCLUDE_DIRECTORIES").ok(); // Configure and generate bindings. let mut builder = builder() // Silence code-style warnings for generated bindings. .raw_line("#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]") // Make the bindings pretty. - .rustfmt_bindings(true) + .formatter(bindgen::Formatter::Rustfmt) // Disable the layout tests. // We're committing to source control. Pointer width, integer size, etc // are probably not the same when generated as when compiled. @@ -143,6 +148,14 @@ fn execute_bindgen() -> Result<(), &'static str> { // Enable bindgen to find generated headers in the build directory, too. .clang_arg(build_include_path); + // If include directories were specified, add them to the builder. + if let Some(include_directories) = has_include_directories { + for include_directory in include_directories.split(';') { + // Enable bindgen to find dependencies headers. + builder = builder.clang_arg(format!("-I{include_directory}")); + } + } + for &include_path in BINDGEN_INCLUDE_PATHS { builder = builder.clang_arg(include_path); } diff --git a/libclamav_rust/cbindgen.toml b/libclamav_rust/cbindgen.toml index e13a2ff4d7..1a0d30892c 100644 --- a/libclamav_rust/cbindgen.toml +++ b/libclamav_rust/cbindgen.toml @@ -36,6 +36,7 @@ include = [ "evidence::evidence_num_indicators_type", "evidence::evidence_add_indicator", "evidence::IndicatorType", + "scanners::scan_onenote", ] # prefix = "CAPI_" diff --git a/libclamav_rust/src/cdiff.rs b/libclamav_rust/src/cdiff.rs index 693187c812..1ec54dd54f 100644 --- a/libclamav_rust/src/cdiff.rs +++ b/libclamav_rust/src/cdiff.rs @@ -36,7 +36,6 @@ use crate::validate_str_param; use flate2::{read::GzDecoder, write::GzEncoder, Compression}; use log::{debug, error, warn}; use sha2::{Digest, Sha256}; -use thiserror::Error; /// Size of a digital signature const SIG_SIZE: usize = 350; @@ -88,8 +87,8 @@ struct Context { } /// Possible errors returned by cdiff_apply() and script2cdiff -#[derive(Debug, Error)] -pub enum CdiffError { +#[derive(thiserror::Error, Debug)] +pub enum Error { #[error("Error in header: {0}")] Header(#[from] HeaderError), @@ -151,7 +150,7 @@ pub enum CdiffError { /// Errors particular to input handling (i.e., syntax, or side effects from /// handling input) -#[derive(Error, Debug)] +#[derive(thiserror::Error, Debug)] pub enum InputError { #[error("Unsupported command provided: {0}")] UnknownCommand(String), @@ -199,7 +198,7 @@ pub enum InputError { } /// Errors encountered while processing -#[derive(Debug, Error)] +#[derive(thiserror::Error, Debug)] pub enum ProcessingError { #[error("File {0} not closed before calling action MOVE")] NotClosedBeforeAction(String), @@ -238,7 +237,7 @@ pub enum ProcessingError { IoError(#[from] std::io::Error), } -#[derive(Error, Debug)] +#[derive(thiserror::Error, Debug)] pub enum HeaderError { #[error("invalid magic")] BadMagic, @@ -253,7 +252,7 @@ pub enum HeaderError { IoError(#[from] std::io::Error), } -#[derive(Error, Debug)] +#[derive(thiserror::Error, Debug)] pub enum SignatureError { #[error("IO error: {0}")] IoError(#[from] std::io::Error), @@ -265,7 +264,7 @@ pub enum SignatureError { TooLarge, } -#[derive(Error, Debug)] +#[derive(thiserror::Error, Debug)] pub enum InvalidNumber { #[error("not unicode")] NotUnicode(#[from] std::str::Utf8Error), @@ -462,7 +461,7 @@ pub extern "C" fn _script2cdiff( /// signature from the sha256 of the contents written. /// /// This function will panic if any of the &str parameters contain interior NUL bytes -pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Result<(), CdiffError> { +pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Result<(), Error> { // Make a copy of the script file name to use for the cdiff file let cdiff_file_name_string = script_file_name.to_string(); let mut cdiff_file_name = cdiff_file_name_string.as_str(); @@ -476,18 +475,18 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu // Get right-most hyphen index let hyphen_index = cdiff_file_name .rfind('-') - .ok_or(CdiffError::FilenameMissingHyphen)?; + .ok_or(Error::FilenameMissingHyphen)?; // Get the version, which should be to the right of the hyphen let version_string = cdiff_file_name .get((hyphen_index + 1)..) - .ok_or(CdiffError::FilenameMissingVersion)?; + .ok_or(Error::FilenameMissingVersion)?; // Parse the version into usize let version = version_string .to_string() .parse::() - .map_err(CdiffError::VersionParse)?; + .map_err(Error::VersionParse)?; // Add .cdiff suffix let cdiff_file_name = format!("{}.{}", cdiff_file_name, "cdiff"); @@ -495,21 +494,21 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu // Open cdiff_file_name for writing let mut cdiff_file: File = File::create(&cdiff_file_name) - .map_err(|e| CdiffError::FileCreate(cdiff_file_name.to_owned(), e))?; + .map_err(|e| Error::FileCreate(cdiff_file_name.to_owned(), e))?; // Open the original script file for reading let script_file: File = File::open(script_file_name) - .map_err(|e| CdiffError::FileOpen(script_file_name.to_owned(), e))?; + .map_err(|e| Error::FileOpen(script_file_name.to_owned(), e))?; // Get file length let script_file_len = script_file .metadata() - .map_err(|e| CdiffError::FileMeta(script_file_name.to_owned(), e))? + .map_err(|e| Error::FileMeta(script_file_name.to_owned(), e))? .len(); // Write header to cdiff file write!(cdiff_file, "ClamAV-Diff:{}:{}:", version, script_file_len) - .map_err(|e| CdiffError::FileWrite(script_file_name.to_owned(), e))?; + .map_err(|e| Error::FileWrite(script_file_name.to_owned(), e))?; // Set up buffered reader and gz writer let mut reader = BufReader::new(script_file); @@ -521,12 +520,12 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu // Get cdiff file writer back from flate2 let mut cdiff_file = gz .finish() - .map_err(|e| CdiffError::FileWrite(cdiff_file_name.to_owned(), e))?; + .map_err(|e| Error::FileWrite(cdiff_file_name.to_owned(), e))?; // Get the new cdiff file len let cdiff_file_len = cdiff_file .metadata() - .map_err(|e| CdiffError::FileMeta(cdiff_file_name.to_owned(), e))? + .map_err(|e| Error::FileMeta(cdiff_file_name.to_owned(), e))? .len(); debug!( "script2cdiff() - wrote {} bytes to {}", @@ -536,7 +535,7 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu // Calculate SHA2-256 to get the sigature // TODO: Do this while the file is being written let bytes = std::fs::read(&cdiff_file_name) - .map_err(|e| CdiffError::FileRead(cdiff_file_name.to_owned(), e))?; + .map_err(|e| Error::FileRead(cdiff_file_name.to_owned(), e))?; let sha256 = { let mut hasher = Sha256::new(); hasher.update(&bytes); @@ -561,12 +560,12 @@ pub fn script2cdiff(script_file_name: &str, builder: &str, server: &str) -> Resu // Write cdiff footer delimiter cdiff_file .write_all(b":") - .map_err(|e| CdiffError::FileWrite(cdiff_file_name.to_owned(), e))?; + .map_err(|e| Error::FileWrite(cdiff_file_name.to_owned(), e))?; // Write dsig to cdiff footer cdiff_file .write_all(dsig.to_bytes()) - .map_err(|e| CdiffError::FileWrite(cdiff_file_name, e))?; + .map_err(|e| Error::FileWrite(cdiff_file_name, e))?; // Exit success Ok(()) @@ -609,7 +608,7 @@ pub extern "C" fn _cdiff_apply(fd: i32, mode: u16) -> i32 { /// A cdiff file contains a footer that is the signed signature of the sha256 /// file contains of the header and the body. The footer begins after the first /// ':' character to the left of EOF. -pub fn cdiff_apply(file: &mut File, mode: ApplyMode) -> Result<(), CdiffError> { +pub fn cdiff_apply(file: &mut File, mode: ApplyMode) -> Result<(), Error> { let path = std::env::current_dir().unwrap(); debug!("cdiff_apply() - current directory is {}", path.display()); @@ -649,7 +648,7 @@ pub fn cdiff_apply(file: &mut File, mode: ApplyMode) -> Result<(), CdiffError> { }; debug!("cdiff_apply() - cli_versig2() result = {}", versig_result); if versig_result != 0 { - return Err(CdiffError::InvalidDigitalSignature); + return Err(Error::InvalidDigitalSignature); } // Read file length from header @@ -1042,7 +1041,7 @@ fn process_lines( ctx: &mut Context, reader: &mut T, uncompressed_size: usize, -) -> Result<(), CdiffError> +) -> Result<(), Error> where T: BufRead, { @@ -1059,7 +1058,7 @@ where match linebuf.first() { // Skip comment lines Some(b'#') => continue, - _ => process_line(ctx, &linebuf).map_err(|e| CdiffError::Input { + _ => process_line(ctx, &linebuf).map_err(|e| Error::Input { line: line_no, err: e, operation: String::from_utf8_lossy(&linebuf).to_string(), @@ -1150,7 +1149,7 @@ fn read_size(file: &mut File) -> Result<(u32, usize), HeaderError> { } /// Calculate the sha256 of the first len bytes of a file -fn get_hash(file: &mut File, len: usize) -> Result<[u8; 32], CdiffError> { +fn get_hash(file: &mut File, len: usize) -> Result<[u8; 32], Error> { let mut hasher = Sha256::new(); // Seek to beginning of file @@ -1193,7 +1192,7 @@ mod tests { use std::path::Path; /// CdiffTestError enumerates all possible errors returned by this testing library. - #[derive(Error, Debug)] + #[derive(thiserror::Error, Debug)] pub enum CdiffTestError { /// Represents all other cases of `std::io::Error`. #[error(transparent)] @@ -1545,7 +1544,7 @@ mod tests { fn script2cdiff_missing_hyphen() { assert!(matches!( script2cdiff("", "", ""), - Err(CdiffError::FilenameMissingHyphen) + Err(Error::FilenameMissingHyphen) )); } } diff --git a/libclamav_rust/src/css_image_extract.rs b/libclamav_rust/src/css_image_extract.rs index f24aca10b4..45662fdafb 100644 --- a/libclamav_rust/src/css_image_extract.rs +++ b/libclamav_rust/src/css_image_extract.rs @@ -24,14 +24,13 @@ use std::{ffi::CStr, mem::ManuallyDrop, os::raw::c_char}; use base64::{engine::general_purpose as base64_engine_standard, Engine as _}; use log::{debug, error, warn}; -use thiserror::Error; use unicode_segmentation::UnicodeSegmentation; use crate::sys; -/// CdiffError enumerates all possible errors returned by this library. -#[derive(Error, Debug)] -pub enum CssExtractError { +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { #[error("Invalid format")] Format, @@ -56,7 +55,7 @@ pub struct CssImageExtractor<'a> { } impl<'a> CssImageExtractor<'a> { - pub fn new(css: &'a str) -> Result { + pub fn new(css: &'a str) -> Result { Ok(Self { remaining: css }) } @@ -152,7 +151,7 @@ impl<'a> CssImageExtractor<'a> { }; // Trim off " at end. - let c = url_parameter.graphemes(true).rev().next(); + let c = url_parameter.graphemes(true).next_back(); if let Some(c) = c { if c == "\"" { (url_parameter, _) = url_parameter.split_at(url_parameter.len() - 1); diff --git a/libclamav_rust/src/ctx.rs b/libclamav_rust/src/ctx.rs new file mode 100644 index 0000000000..fbef5c9d53 --- /dev/null +++ b/libclamav_rust/src/ctx.rs @@ -0,0 +1,98 @@ +/* + * Rust equivalent of libclamav's scanners.c module + * + * Copyright (C) 2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Authors: Micah Snyder + * + * 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::{convert::TryInto, path::PathBuf, slice}; + +use crate::{fmap::FMap, sys::cli_ctx, util::str_from_ptr}; + +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Invalid format")] + Format, + + #[error("Invalid NULL pointer: {0}")] + NullPointer(&'static str), + + #[error("{0} parameter is NULL")] + NullParam(&'static str), + + #[error("No more files to extract")] + NoMoreFiles, + + #[error("Invalid FMap: {0}")] + BadMap(#[from] crate::fmap::Error), + + #[error("String not UTF8: {0}")] + Utf8(#[from] std::str::Utf8Error), +} + +/// Get the ctx.sub_filepath as an Option<'str> +/// +/// # Safety +/// +/// Must be a valid ctx pointer. +pub unsafe fn sub_filepath(ctx: *mut cli_ctx) -> Result, Error> { + if ctx.is_null() { + return Err(Error::NullPointer("ctx")); + } + + Ok(str_from_ptr(unsafe { *ctx }.sub_filepath) + .map_err(Error::Utf8)? + .map(PathBuf::from)) +} + +/// Get the ctx.target_filepath as an Option<'str> +/// +/// # Safety +/// +/// Must be a valid ctx pointer. +pub unsafe fn target_filepath(ctx: *mut cli_ctx) -> Result, Error> { + if ctx.is_null() { + return Err(Error::NullPointer("ctx")); + } + + Ok(str_from_ptr(unsafe { *ctx }.target_filepath) + .map_err(Error::Utf8)? + .map(PathBuf::from)) +} + +/// Get the fmap for the current layer. +/// +/// # Safety +/// +/// Must be a valid ctx pointer. +pub unsafe fn current_fmap(ctx: *mut cli_ctx) -> Result { + if ctx.is_null() { + return Err(Error::NullPointer("ctx")); + } + + let recursion_stack_size = unsafe { *ctx }.recursion_stack_size as usize; + let recursion_level = unsafe { *ctx }.recursion_level as usize; + + let recursion_stack = + unsafe { slice::from_raw_parts((*ctx).recursion_stack, recursion_stack_size) }; + + let current_level = recursion_stack[recursion_level]; + + current_level.fmap.try_into().map_err(Error::BadMap) +} diff --git a/libclamav_rust/src/evidence.rs b/libclamav_rust/src/evidence.rs index f0e7404caa..7cfef3009e 100644 --- a/libclamav_rust/src/evidence.rs +++ b/libclamav_rust/src/evidence.rs @@ -23,13 +23,12 @@ use std::{collections::HashMap, ffi::CStr, mem::ManuallyDrop, os::raw::c_char}; use log::{debug, error, warn}; -use thiserror::Error; use crate::{ffi_util::FFIError, rrf_call, sys, validate_str_param}; -/// CdiffError enumerates all possible errors returned by this library. -#[derive(Error, Debug)] -pub enum EvidenceError { +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { #[error("Invalid format")] Format, @@ -240,21 +239,21 @@ impl Evidence { name: &str, static_virname: *const c_char, indicator_type: IndicatorType, - ) -> Result<(), EvidenceError> { + ) -> Result<(), Error> { let meta: IndicatorMeta = IndicatorMeta { static_virname }; match indicator_type { IndicatorType::Strong => { self.strong .entry(name.to_string()) - .or_insert_with(Vec::new) + .or_default() .push(meta); } IndicatorType::PotentiallyUnwanted => { self.pua .entry(name.to_string()) - .or_insert_with(Vec::new) + .or_default() .push(meta); } @@ -265,7 +264,7 @@ impl Evidence { IndicatorType::Weak => { self.weak .entry(name.to_string()) - .or_insert_with(Vec::new) + .or_default() .push(meta); } } diff --git a/libclamav_rust/src/fmap.rs b/libclamav_rust/src/fmap.rs new file mode 100644 index 0000000000..6468da5adc --- /dev/null +++ b/libclamav_rust/src/fmap.rs @@ -0,0 +1,105 @@ +/* + * Rust interface for libclamav FMap module + * + * Copyright (C) 2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Authors: Micah Snyder + * + * 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::convert::TryFrom; + +use log::{debug, error}; + +use crate::{sys, util::str_from_ptr}; + +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Invalid parameter: {0}")] + InvalidParameter(String), + + #[error("{0} parmeter is NULL")] + NullParam(&'static str), + + #[error("Offset {0} and length {1} not contained in FMap of size {2}")] + NotContained(usize, usize, usize), + + #[error("FMap pointer not initialized: {0}")] + UninitializedPtr(&'static str), + + #[error("Attempted to create Rust FMap interface from NULL pointer")] + Null, +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct FMap { + fmap_ptr: *mut sys::cl_fmap_t, +} + +impl TryFrom<*mut sys::cl_fmap_t> for FMap { + type Error = Error; + + fn try_from(value: *mut sys::cl_fmap_t) -> Result { + if value.is_null() { + return Err(Error::Null); + } + + Ok(FMap { fmap_ptr: value }) + } +} + +impl<'a> FMap { + /// Simple wrapper around C FMAP module's fmap.need() method. + pub fn need_off(&'a self, at: usize, len: usize) -> Result<&'a [u8], Error> { + // Get the need() method function pointer from the fmap. + let need_fn = match unsafe { *self.fmap_ptr }.need { + Some(ptr) => ptr, + None => return Err(Error::UninitializedPtr("need()")), + }; + + let ptr: *const u8 = unsafe { need_fn(self.fmap_ptr, at, len, 1) } as *const u8; + + if ptr.is_null() { + let fmap_size = unsafe { *self.fmap_ptr }.len; + debug!( + "need_off at {:?} len {:?} for fmap size {:?} returned NULL", + at, len, fmap_size + ); + return Err(Error::NotContained(at, len, fmap_size)); + } + + let slice: &[u8] = unsafe { std::slice::from_raw_parts(ptr, len) }; + + Ok(slice) + } + + pub fn len(&self) -> usize { + unsafe { (*self.fmap_ptr).len } + } + + pub fn is_empty(&self) -> bool { + unsafe { (*self.fmap_ptr).len == 0 } + } + + pub fn name(&self) -> &'static str { + unsafe { + str_from_ptr((*self.fmap_ptr).name) + .unwrap_or(Some("")) + .unwrap_or("") + } + } +} diff --git a/libclamav_rust/src/fuzzy_hash.rs b/libclamav_rust/src/fuzzy_hash.rs index 79bbef9f8f..c502595de6 100644 --- a/libclamav_rust/src/fuzzy_hash.rs +++ b/libclamav_rust/src/fuzzy_hash.rs @@ -34,14 +34,13 @@ use image::{imageops::FilterType::Lanczos3, DynamicImage, ImageBuffer, Luma, Pix use log::{debug, error, warn}; use num_traits::{NumCast, ToPrimitive, Zero}; use rustdct::DctPlanner; -use thiserror::Error; use transpose::transpose; use crate::{ffi_error, ffi_util::FFIError, rrf_call, sys, validate_str_param}; -/// CdiffError enumerates all possible errors returned by this library. -#[derive(Error, Debug)] -pub enum FuzzyHashError { +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { #[error("Invalid format")] Format, @@ -68,6 +67,9 @@ pub enum FuzzyHashError { #[error("{0} parmeter is NULL")] NullParam(&'static str), + + #[error("{0} hash must be {1} characters in length")] + InvalidHashLength(&'static str, usize), } #[derive(PartialEq, Eq, Hash, Debug)] @@ -81,18 +83,18 @@ pub enum FuzzyHash { } impl TryFrom<&str> for ImageFuzzyHash { - type Error = &'static str; + type Error = Error; fn try_from(value: &str) -> Result { if value.len() != 16 { - return Err("Image fuzzy hash must be 16 characters in length"); + return Err(Error::InvalidHashLength("ImageFuzzyHash", 16)); } let mut hashbytes = [0; 8]; if hex::decode_to_slice(value, &mut hashbytes).is_ok() { Ok(ImageFuzzyHash { bytes: hashbytes }) } else { - Err("Failed to decode image fuzzy hash bytes from hex to bytes") + Err(Error::FormatHashBytes(value.to_string())) } } } @@ -205,11 +207,11 @@ pub unsafe extern "C" fn _fuzzy_hash_calculate_image( err: *mut *mut FFIError, ) -> bool { if hash_out.is_null() { - return ffi_error!(err = err, FuzzyHashError::NullParam("hash_out")); + return ffi_error!(err = err, Error::NullParam("hash_out")); } let buffer = if file_bytes.is_null() { - return ffi_error!(err = err, FuzzyHashError::NullParam("file_bytes")); + return ffi_error!(err = err, Error::NullParam("file_bytes")); } else { slice::from_raw_parts(file_bytes, file_size) }; @@ -223,7 +225,7 @@ pub unsafe extern "C" fn _fuzzy_hash_calculate_image( if hash_out_len < hash_bytes.len() { return ffi_error!( err = err, - FuzzyHashError::InvalidParameter(format!( + Error::InvalidParameter(format!( "hash_bytes output parameter too small to hold the hash: {} < {}", hash_out_len, hash_bytes.len() @@ -257,24 +259,24 @@ impl FuzzyHashMap { hexsig: &str, lsig_id: u32, subsig_id: u32, - ) -> Result<(), FuzzyHashError> { + ) -> Result<(), Error> { let mut hexsig_split = hexsig.split('#'); let algorithm = match hexsig_split.next() { Some(x) => x, - None => return Err(FuzzyHashError::Format), + None => return Err(Error::Format), }; let hash = match hexsig_split.next() { Some(x) => x, - None => return Err(FuzzyHashError::Format), + None => return Err(Error::Format), }; let distance: u32 = match hexsig_split.next() { Some(x) => match x.parse::() { Ok(n) => n, Err(_) => { - return Err(FuzzyHashError::FormatHammingDistance(x.to_string())); + return Err(Error::FormatHammingDistance(x.to_string())); } }, None => 0, @@ -285,7 +287,7 @@ impl FuzzyHashMap { error!( "Non-zero hamming distances for image fuzzy hashes are not supported in this version." ); - return Err(FuzzyHashError::InvalidHammingDistance(distance)); + return Err(Error::InvalidHammingDistance(distance)); } match algorithm { @@ -293,7 +295,7 @@ impl FuzzyHashMap { // Convert the hash string to an image fuzzy hash bytes struct let image_fuzzy_hash = hash .try_into() - .map_err(|e| FuzzyHashError::FormatHashBytes(format!("{}: {}", e, hash)))?; + .map_err(|e| Error::FormatHashBytes(format!("{}: {}", e, hash)))?; let fuzzy_hash = FuzzyHash::Image(image_fuzzy_hash); @@ -308,14 +310,14 @@ impl FuzzyHashMap { // Then add the current meta struct to the entry. self.hashmap .entry(fuzzy_hash) - .or_insert_with(Vec::new) + .or_default() .push(meta); Ok(()) } _ => { error!("Unknown fuzzy hash algorithm: {}", algorithm); - Err(FuzzyHashError::UnknownAlgorithm(algorithm.to_string())) + Err(Error::UnknownAlgorithm(algorithm.to_string())) } } } @@ -412,17 +414,17 @@ impl FuzzyHashMap { /// /// param: hash_out is an output variable /// param: hash_out_len indicates the size of the hash_out buffer -pub fn fuzzy_hash_calculate_image(buffer: &[u8]) -> Result, FuzzyHashError> { +pub fn fuzzy_hash_calculate_image(buffer: &[u8]) -> Result, Error> { // Load image and attempt to catch panics in case the decoders encounter unexpected issues - let result = panic::catch_unwind(|| -> Result { - let image = image::load_from_memory(buffer).map_err(FuzzyHashError::ImageLoad)?; + let result = panic::catch_unwind(|| -> Result { + let image = image::load_from_memory(buffer).map_err(Error::ImageLoad)?; Ok(image) }); let og_image = match result { Ok(image) => image?, - Err(_) => return Err(FuzzyHashError::ImageLoadPanic()), + Err(_) => return Err(Error::ImageLoadPanic()), }; // Drop the alpha channel (if exists). diff --git a/libclamav_rust/src/lib.rs b/libclamav_rust/src/lib.rs index 2b7cc97ec8..49caffb6de 100644 --- a/libclamav_rust/src/lib.rs +++ b/libclamav_rust/src/lib.rs @@ -24,9 +24,13 @@ pub mod sys; pub mod cdiff; +pub mod css_image_extract; +pub mod ctx; pub mod evidence; pub mod ffi_util; +pub mod fmap; pub mod fuzzy_hash; pub mod logging; +pub mod onenote; +pub mod scanners; pub mod util; -pub mod css_image_extract; diff --git a/libclamav_rust/src/onenote.rs b/libclamav_rust/src/onenote.rs new file mode 100644 index 0000000000..1fd690c6b9 --- /dev/null +++ b/libclamav_rust/src/onenote.rs @@ -0,0 +1,285 @@ +/* + * Onenote document parser to extract embedded files. + * + * Copyright (C) 2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Authors: Micah Snyder + * + * 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::{ + convert::TryInto, + mem, panic, + path::{Path, PathBuf}, +}; + +use hex_literal::hex; +use log::{debug, error}; +use onenote_parser; + +/// Error enumerates all possible errors returned by this library. +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Invalid format")] + Format, + + #[error("Invalid parameter: {0}")] + InvalidParameter(String), + + #[error("Failed to open file: {0}, {1}")] + FailedToOpen(PathBuf, String), + + #[error("Failed to get size for file: {0}")] + FailedToGetFileSize(PathBuf), + + #[error("{0} parameter is NULL")] + NullParam(&'static str), + + #[error("No more files to extract")] + NoMoreFiles, + + #[error("Unable to parse OneNote file")] + Parse, + + #[error("Failed to parse OneNote file due to a panic in the onenote_parser library")] + OneNoteParserPanic, +} + +fn find_bytes(haystack: &[u8], needle: &[u8]) -> Option { + haystack + .windows(needle.len()) + .position(|window| window == needle) +} + +/// Struct representing a file extracted from a OneNote document. +/// This has the option of providing a file name, if one was found when extracting the file. +pub struct ExtractedFile { + pub name: Option, + pub data: Vec, +} + +/// Struct used for a file handle for our OneNote parser. +/// This struct is used to keep track of state for our iterator to work through the document extracting each file. +/// There are three different ways we keep track of state depending on the file format and the way in which the file was opened. +#[derive(Default)] +pub struct OneNote<'a> { + embedded_files: Vec, + remaining_vec: Option>, + remaining: Option<&'a [u8]>, +} + +// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-onestore/8806fd18-6735-4874-b111-227b83eaac26 +#[repr(packed)] +#[allow(dead_code)] +struct FileDataHeader { + guid_header: [u8; 16], + cb_length: u64, + unused: u32, + reserved: u64, +} +const SIZE_OF_FILE_DATA_HEADER: usize = mem::size_of::(); + +// Hex sequence identifying the start of a file data store object. +const FILE_DATA_STORE_OBJECT: &[u8] = &hex!("e716e3bd65261145a4c48d4d0b7a9eac"); + +// Hex sequence identifying the start of a OneNote file. +const ONE_MAGIC: &[u8] = &hex!("e4525c7b8cd8a74daeb15378d02996d3"); + +impl<'a> OneNote<'a> { + /// Open a OneNote document given a slice bytes. + pub fn from_bytes(data: &'a [u8], filename: &Path) -> Result, Error> { + debug!( + "Inspecting OneNote file for attachments from in-memory buffer of size {}-bytes named {}\n", + data.len(), filename.to_string_lossy() + ); + + fn parse_section_buffer(data: &[u8], filename: &Path) -> Result, Error> { + let mut embedded_files: Vec = vec![]; + let mut parser = onenote_parser::Parser::new(); + + if let Ok(section) = parser.parse_section_buffer(data, filename) { + // file appears to be OneStore 2.8 `.one` file. + section.page_series().iter().for_each(|page_series| { + page_series.pages().iter().for_each(|page| { + page.contents().iter().for_each(|page_content| { + if let Some(page_outline) = page_content.outline() { + page_outline.items().iter().for_each(|outline_item| { + outline_item.element().iter().for_each(|&outline_element| { + outline_element.contents().iter().for_each(|content| { + if let Some(embedded_file) = content.embedded_file() { + let data = embedded_file.data(); + let name = embedded_file.filename(); + + // If name is empty, set to None. + let name = if name.is_empty() { + debug!("Found unnamed attached file of size {}-bytes", data.len()); + None + } else { + debug!("Found attached file '{}' of size {}-bytes", name, data.len()); + Some(name.to_string()) + }; + + embedded_files.push(ExtractedFile { + name, + data: data.to_vec(), + }); + } + }); + }); + }); + } + }); + }); + }); + } else { + return Err(Error::Parse); + } + + Ok(embedded_files) + } + + // Try to parse the section buffer using the onenote_parser crate. + // Attempt to catch panics in case the parser encounter unexpected issues. + let result_result = panic::catch_unwind(|| -> Result, Error> { + parse_section_buffer(data, filename) + }); + + // Check if it panicked. If no panic, grab the parse result. + let result = result_result.map_err(|_| Error::OneNoteParserPanic)?; + + if let Ok(embedded_files) = result { + // Successfully parsed the OneNote file with the onenote_parser crate. + Ok(OneNote { + embedded_files, + ..Default::default() + }) + } else { + debug!("Unable to parse OneNote file with onenote_parser crate. Trying a different method known to work with older office 2010 OneNote files to extract attachments."); + + let embedded_files: Vec = vec![]; + + // Verify that the OneNote document file magic is correct. + // We don't check this for the onenote_parser crate because it does this for us, and may add support for newer OneNote file formats in the future. + let file_magic = data.get(0..16).ok_or(Error::Format)?; + if file_magic != ONE_MAGIC { + return Err(Error::Format); + } + + Ok(OneNote { + embedded_files, + remaining: Some(data), + ..Default::default() + }) + } + } + + /// Open a OneNote document given the document was provided as a slice of bytes. + pub fn next_file(&mut self) -> Option { + debug!("Looking to extract file from OneNote section..."); + + let mut file_data: Option> = None; + + let remaining = if let Some(remaining_in) = self.remaining { + let remaining = if let Some(pos) = find_bytes(remaining_in, FILE_DATA_STORE_OBJECT) { + let (_, remaining) = remaining_in.split_at(pos); + // Found file data store object. + remaining + } else { + return None; + }; + + let data_length = if let Some(x) = remaining.get(16..20) { + u32::from_le_bytes(x.try_into().unwrap()) as u64 + } else { + return None; + }; + + let data: &[u8] = remaining + .get(SIZE_OF_FILE_DATA_HEADER..SIZE_OF_FILE_DATA_HEADER + data_length as usize)?; + + file_data = Some(data.to_vec()); + + Some(&remaining[SIZE_OF_FILE_DATA_HEADER + (data_length as usize)..remaining.len()]) + } else { + None + }; + + self.remaining = remaining; + + file_data.map(|data| ExtractedFile { data, name: None }) + } + + /// Get the next file from the OneNote document using the method required for when we've read the file into a Vec. + pub fn next_file_vec(&mut self) -> Option { + debug!("Looking to extract file from OneNote section..."); + + let mut file_data: Option> = None; + + self.remaining_vec = if let Some(ref remaining_vec) = self.remaining_vec { + let remaining = if let Some(pos) = find_bytes(remaining_vec, FILE_DATA_STORE_OBJECT) { + let (_, remaining) = remaining_vec.split_at(pos); + // Found file data store object. + remaining + } else { + return None; + }; + + let data_length = if let Some(x) = remaining.get(16..20) { + u32::from_le_bytes(x.try_into().unwrap()) as u64 + } else { + return None; + }; + + let data: &[u8] = remaining + .get(SIZE_OF_FILE_DATA_HEADER..SIZE_OF_FILE_DATA_HEADER + data_length as usize)?; + + file_data = Some(data.to_vec()); + + Some(Vec::from( + &remaining[SIZE_OF_FILE_DATA_HEADER + (data_length as usize)..remaining.len()], + )) + } else { + None + }; + + file_data.map(|data| ExtractedFile { data, name: None }) + } + + /// Get the next file from the OneNote document using the method required for the onenote_parser crate. + pub fn next_file_parser(&mut self) -> Option { + self.embedded_files.pop() + } +} + +impl<'a> Iterator for OneNote<'a> { + type Item = ExtractedFile; + + fn next(&mut self) -> Option { + // Find the next embedded file + if self.remaining.is_some() { + // Data stored in a slice. + self.next_file() + } else if self.remaining_vec.is_some() { + // Data stored in a Vec. + self.next_file_vec() + } else if !self.embedded_files.is_empty() { + // Data stored in a Vec. + self.next_file_parser() + } else { + None + } + } +} diff --git a/libclamav_rust/src/scanners.rs b/libclamav_rust/src/scanners.rs new file mode 100644 index 0000000000..27866ac4ad --- /dev/null +++ b/libclamav_rust/src/scanners.rs @@ -0,0 +1,129 @@ +/* + * Rust equivalent of libclamav's scanners.c module + * + * Copyright (C) 2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * Authors: Micah Snyder + * + * 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::{ + ffi::{c_char, CString}, + path::Path, + ptr::null_mut, +}; + +use libc::c_void; +use log::{debug, error, warn}; + +use crate::{ + ctx, + onenote::OneNote, + sys::{cl_error_t, cl_error_t_CL_ERROR, cl_error_t_CL_SUCCESS, cli_ctx, cli_magic_scan_buff}, +}; + +/// Rust wrapper of libclamav's cli_magic_scan_buff() function. +/// Use magic sigs to identify the file type and then scan it. +fn magic_scan(ctx: *mut cli_ctx, buf: &[u8], name: Option) -> cl_error_t { + let ptr = buf.as_ptr(); + let len = buf.len(); + + match &name { + Some(name) => debug!("Scanning {}-byte file named {}.", len, name), + None => debug!("Scanning {}-byte unnamed file.", len), + } + + // Convert name to a C string. + let name = match name { + Some(name) => name, + None => String::from(""), + }; + + let name_ptr: *mut c_char = match CString::new(name) { + Ok(name_cstr) => { + // into_raw() so name_cstr doesn't get dropped and + // we don't do an unsafe deref of the pointer. + name_cstr.into_raw() + } + Err(_) => null_mut(), + }; + + let ret = unsafe { cli_magic_scan_buff(ptr as *const c_void, len, ctx, name_ptr, 0) }; + + if ret != cl_error_t_CL_SUCCESS { + debug!("cli_magic_scan_buff returned error: {}", ret); + } + + // Okay now safe to drop the name CString. + let _ = unsafe { CString::from_raw(name_ptr) }; + + ret +} + +/// Scan a OneNote file for attachments +/// +/// # Safety +/// +/// Must be a valid ctx pointer. +#[no_mangle] +pub unsafe extern "C" fn scan_onenote(ctx: *mut cli_ctx) -> cl_error_t { + let fmap = match ctx::current_fmap(ctx) { + Ok(fmap) => fmap, + Err(e) => { + warn!("Error getting FMap from ctx: {e}"); + return cl_error_t_CL_ERROR; + } + }; + + let file_bytes = match fmap.need_off(0, fmap.len()) { + Ok(bytes) => bytes, + Err(err) => { + error!( + "Failed to get file bytes for fmap of size {}: {err}", + fmap.len() + ); + return cl_error_t_CL_ERROR; + } + }; + + let one = match OneNote::from_bytes(file_bytes, Path::new(fmap.name())) { + Ok(x) => x, + Err(err) => { + error!("Failed to parse OneNote file: {}", err.to_string()); + return cl_error_t_CL_ERROR; + } + }; + + let mut scan_result = cl_error_t_CL_SUCCESS; + + one.into_iter().all(|attachment| { + debug!( + "Extracted {}-byte attachment with name: {:?}", + attachment.data.len(), + attachment.name + ); + + let ret = magic_scan(ctx, &attachment.data, attachment.name); + if ret != cl_error_t_CL_SUCCESS { + scan_result = ret; + return false; + } + + true + }); + + scan_result +} diff --git a/libclamav_rust/src/sys.rs b/libclamav_rust/src/sys.rs index 1df2323184..ccac0bb1de 100644 --- a/libclamav_rust/src/sys.rs +++ b/libclamav_rust/src/sys.rs @@ -268,14 +268,15 @@ pub struct cl_fmap { pub handle: *mut ::std::os::raw::c_void, pub pread_cb: clcb_pread, pub data: *const ::std::os::raw::c_void, - pub mtime: time_t, + pub mtime: u64, pub pages: u64, pub pgsz: u64, pub paged: u64, - pub aging: u16, + pub aging: bool, + #[doc = " indicates if we should age off memory mapped pages"] pub dont_cache_flag: bool, #[doc = " indicates if we should not cache scan results for this fmap. Used if limits exceeded"] - pub handle_is_fd: u16, + pub handle_is_fd: bool, #[doc = " non-zero if map->handle is an fd."] pub offset: usize, #[doc = " file offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0"] @@ -311,6 +312,8 @@ pub struct cl_fmap { >, pub unneed_off: ::std::option::Option, + pub windows_file_handle: *mut ::std::os::raw::c_void, + pub windows_map_handle: *mut ::std::os::raw::c_void, pub have_md5: bool, pub md5: [::std::os::raw::c_uchar; 16usize], pub have_sha1: bool, @@ -375,34 +378,36 @@ pub const cli_file_CL_TYPE_HWP3: cli_file = 550; pub const cli_file_CL_TYPE_OOXML_HWP: cli_file = 551; pub const cli_file_CL_TYPE_PS: cli_file = 552; pub const cli_file_CL_TYPE_EGG: cli_file = 553; -pub const cli_file_CL_TYPE_PART_ANY: cli_file = 554; -pub const cli_file_CL_TYPE_PART_HFSPLUS: cli_file = 555; -pub const cli_file_CL_TYPE_MBR: cli_file = 556; -pub const cli_file_CL_TYPE_HTML: cli_file = 557; -pub const cli_file_CL_TYPE_MAIL: cli_file = 558; -pub const cli_file_CL_TYPE_SFX: cli_file = 559; -pub const cli_file_CL_TYPE_ZIPSFX: cli_file = 560; -pub const cli_file_CL_TYPE_RARSFX: cli_file = 561; -pub const cli_file_CL_TYPE_7ZSFX: cli_file = 562; -pub const cli_file_CL_TYPE_CABSFX: cli_file = 563; -pub const cli_file_CL_TYPE_ARJSFX: cli_file = 564; -pub const cli_file_CL_TYPE_EGGSFX: cli_file = 565; -pub const cli_file_CL_TYPE_NULSFT: cli_file = 566; -pub const cli_file_CL_TYPE_AUTOIT: cli_file = 567; -pub const cli_file_CL_TYPE_ISHIELD_MSI: cli_file = 568; -pub const cli_file_CL_TYPE_ISO9660: cli_file = 569; -pub const cli_file_CL_TYPE_DMG: cli_file = 570; -pub const cli_file_CL_TYPE_GPT: cli_file = 571; -pub const cli_file_CL_TYPE_APM: cli_file = 572; -pub const cli_file_CL_TYPE_XDP: cli_file = 573; -pub const cli_file_CL_TYPE_XML_WORD: cli_file = 574; -pub const cli_file_CL_TYPE_XML_XL: cli_file = 575; -pub const cli_file_CL_TYPE_XML_HWP: cli_file = 576; -pub const cli_file_CL_TYPE_HWPOLE2: cli_file = 577; -pub const cli_file_CL_TYPE_MHTML: cli_file = 578; -pub const cli_file_CL_TYPE_LNK: cli_file = 579; -pub const cli_file_CL_TYPE_OTHER: cli_file = 580; -pub const cli_file_CL_TYPE_IGNORED: cli_file = 581; +pub const cli_file_CL_TYPE_ONENOTE: cli_file = 554; +pub const cli_file_CL_TYPE_PART_ANY: cli_file = 555; +pub const cli_file_CL_TYPE_PART_HFSPLUS: cli_file = 556; +pub const cli_file_CL_TYPE_MBR: cli_file = 557; +pub const cli_file_CL_TYPE_HTML: cli_file = 558; +pub const cli_file_CL_TYPE_MAIL: cli_file = 559; +pub const cli_file_CL_TYPE_SFX: cli_file = 560; +pub const cli_file_CL_TYPE_ZIPSFX: cli_file = 561; +pub const cli_file_CL_TYPE_RARSFX: cli_file = 562; +pub const cli_file_CL_TYPE_7ZSFX: cli_file = 563; +pub const cli_file_CL_TYPE_CABSFX: cli_file = 564; +pub const cli_file_CL_TYPE_ARJSFX: cli_file = 565; +pub const cli_file_CL_TYPE_EGGSFX: cli_file = 566; +pub const cli_file_CL_TYPE_NULSFT: cli_file = 567; +pub const cli_file_CL_TYPE_AUTOIT: cli_file = 568; +pub const cli_file_CL_TYPE_ISHIELD_MSI: cli_file = 569; +pub const cli_file_CL_TYPE_ISO9660: cli_file = 570; +pub const cli_file_CL_TYPE_DMG: cli_file = 571; +pub const cli_file_CL_TYPE_GPT: cli_file = 572; +pub const cli_file_CL_TYPE_APM: cli_file = 573; +pub const cli_file_CL_TYPE_XDP: cli_file = 574; +pub const cli_file_CL_TYPE_XML_WORD: cli_file = 575; +pub const cli_file_CL_TYPE_XML_XL: cli_file = 576; +pub const cli_file_CL_TYPE_XML_HWP: cli_file = 577; +pub const cli_file_CL_TYPE_HWPOLE2: cli_file = 578; +pub const cli_file_CL_TYPE_MHTML: cli_file = 579; +pub const cli_file_CL_TYPE_LNK: cli_file = 580; +pub const cli_file_CL_TYPE_UDF: cli_file = 581; +pub const cli_file_CL_TYPE_OTHER: cli_file = 582; +pub const cli_file_CL_TYPE_IGNORED: cli_file = 583; pub type cli_file = ::std::os::raw::c_uint; pub use self::cli_file as cli_file_t; #[repr(C)] @@ -612,6 +617,7 @@ pub struct recursion_level_tag { } pub type recursion_level_t = recursion_level_tag; pub type evidence_t = *mut ::std::os::raw::c_void; +pub type onedump_t = *mut ::std::os::raw::c_void; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct cli_ctx_tag { @@ -706,6 +712,7 @@ pub struct cl_engine { pub tmpdir: *mut ::std::os::raw::c_char, pub keeptmp: u32, pub engine_options: u64, + pub cache_size: u32, pub maxscantime: u32, pub maxscansize: u64, pub maxfilesize: u64, @@ -1170,6 +1177,16 @@ extern "C" { } pub type css_image_extractor_t = *mut ::std::os::raw::c_void; pub type css_image_handle_t = *mut ::std::os::raw::c_void; +extern "C" { + #[doc = " @brief Convenience wrapper for cli_magic_scan_nested_fmap_type().\n\n Creates an fmap and calls cli_magic_scan_nested_fmap_type() for you, with type CL_TYPE_ANY.\n\n @param buffer Pointer to the buffer to be scanned.\n @param length Size in bytes of the buffer being scanned.\n @param ctx Scanning context structure.\n @param name (optional) Original name of the file (to set fmap name metadata)\n @param attributes Layer attributes of the file being scanned (is it normalized, decrypted, etc)\n @return int CL_SUCCESS, or an error code."] + pub fn cli_magic_scan_buff( + buffer: *const ::std::os::raw::c_void, + length: usize, + ctx: *mut cli_ctx, + name: *const ::std::os::raw::c_char, + attributes: u32, + ) -> cl_error_t; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct re_guts { diff --git a/libclamav_rust/src/util.rs b/libclamav_rust/src/util.rs index 7b5f3aece4..47f2d8b4b3 100644 --- a/libclamav_rust/src/util.rs +++ b/libclamav_rust/src/util.rs @@ -20,7 +20,7 @@ * MA 02110-1301, USA. */ -use std::fs::File; +use std::{ffi::CStr, fs::File}; /// Obtain a std::fs::File from an i32 in a platform-independent manner. /// @@ -46,3 +46,19 @@ pub fn file_from_fd_or_handle(fd: i32) -> File { #[cfg(not(any(windows, unix)))] compile_error!("implemented only for unix and windows targets") } + +/// Get a string from a pointer +/// +/// # Safety +/// +/// The caller is responsible for making sure the lifetime of the pointer +/// exceeds the lifetime of the output string. +/// +/// ptr must be a valid pointer to a C string. +pub unsafe fn str_from_ptr(ptr: *const i8) -> Result, std::str::Utf8Error> { + if ptr.is_null() { + return Ok(None); + } + + Some(unsafe { CStr::from_ptr(ptr) }.to_str()).transpose() +} diff --git a/libclamunrar_iface/unrar_iface.cpp b/libclamunrar_iface/unrar_iface.cpp index af81da7dd7..e6df63bd6f 100644 --- a/libclamunrar_iface/unrar_iface.cpp +++ b/libclamunrar_iface/unrar_iface.cpp @@ -212,6 +212,7 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen if (archiveData == NULL) { unrar_dbgmsg("unrar_open: Not enough memory to allocate main archive header data structure.\n"); status = UNRAR_EMEM; + goto done; } archiveData->ArcName = (char*)filename; archiveData->OpenMode = RAR_OM_EXTRACT; @@ -220,6 +221,7 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen if (archiveData->CmtBuf == NULL) { unrar_dbgmsg("unrar_open: Not enough memory to allocate main archive header comment buffer.\n"); status = UNRAR_EMEM; + goto done; } archiveData->CmtBufSize = CMTBUFSIZE; @@ -231,23 +233,24 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen } switch (archiveData->CmtState) { - case 0: { + case ERAR_SUCCESS: { unrar_dbgmsg("unrar_open: Comments are not present in this archive.\n"); break; } case ERAR_BAD_DATA: { unrar_dbgmsg("unrar_open: Archive Comments may be broken.\n"); + break; } case ERAR_SMALL_BUF: { - unrar_dbgmsg("unrar_open: Archive Comments are not present in this file.\n"); + unrar_dbgmsg("unrar_open: Comment buffer was too small, comments are not read completely.\n"); + break; } case 1: { - unrar_dbgmsg("unrar_open: Archive Comments:\n\t %s\n", archiveData->CmtBuf); + unrar_dbgmsg("unrar_open: Archive Comments read completely.\n"); break; } case ERAR_NO_MEMORY: { - unrar_dbgmsg("unrar_open: Memory error when reading archive comments!\n"); - status = UNRAR_EMEM; + unrar_dbgmsg("unrar_open: Not enough memory to extract comments!\n"); break; } default: { @@ -261,7 +264,6 @@ cl_unrar_error_t unrar_open(const char* filename, void** hArchive, char** commen if (NULL == *comment) { unrar_dbgmsg("unrar_open: Error duplicating comment buffer.\n"); *comment_size = 0; - status = UNRAR_EMEM; } } @@ -306,7 +308,7 @@ cl_unrar_error_t unrar_peek_file_header(void* hArchive, unrar_metadata_t* file_m struct RARHeaderDataEx headerData; int read_header_ret = 0; - wchar_t RedirName[1024]; + wchar_t RedirName[2048]; memset(&headerData, 0, sizeof(struct RARHeaderDataEx)); @@ -324,9 +326,9 @@ cl_unrar_error_t unrar_peek_file_header(void* hArchive, unrar_metadata_t* file_m headerData.CmtBuf = NULL; headerData.CmtBufSize = 0; - headerData.RedirNameSize = 1024 * sizeof(wchar_t); + headerData.RedirNameSize = 2048; headerData.RedirName = (wchar_t*)&RedirName; - memset(headerData.RedirName, 0, headerData.RedirNameSize); + memset(headerData.RedirName, 0, headerData.RedirNameSize * sizeof(wchar_t)); read_header_ret = RARReadHeaderEx(hArchive, &headerData); if (ERAR_SUCCESS != read_header_ret) { @@ -336,11 +338,11 @@ cl_unrar_error_t unrar_peek_file_header(void* hArchive, unrar_metadata_t* file_m file_metadata->unpack_size = headerData.UnpSize + ((int64_t)headerData.UnpSizeHigh << 32); file_metadata->pack_size = headerData.PackSize + ((int64_t)headerData.PackSizeHigh << 32); - file_metadata->filename = unrar_strndup(headerData.FileName, 1024); - file_metadata->crc = headerData.FileCRC; - file_metadata->encrypted = (headerData.Flags & RHDF_ENCRYPTED) ? 1 : 0; - file_metadata->is_dir = (headerData.Flags & RHDF_DIRECTORY) ? 1 : 0; - file_metadata->method = headerData.Method; + strncpy(file_metadata->filename, headerData.FileName, 1024); + file_metadata->crc = headerData.FileCRC; + file_metadata->encrypted = (headerData.Flags & RHDF_ENCRYPTED) ? 1 : 0; + file_metadata->is_dir = (headerData.Flags & RHDF_DIRECTORY) ? 1 : 0; + file_metadata->method = headerData.Method; unrar_dbgmsg("unrar_peek_file_header: Name: %s\n", headerData.FileName); unrar_dbgmsg("unrar_peek_file_header: Directory?: %u\n", file_metadata->is_dir); diff --git a/libclamunrar_iface/unrar_iface.h b/libclamunrar_iface/unrar_iface.h index 5a0922b4ed..db2e57b95a 100644 --- a/libclamunrar_iface/unrar_iface.h +++ b/libclamunrar_iface/unrar_iface.h @@ -57,7 +57,7 @@ typedef enum cl_unrar_error_tag { typedef struct unrar_metadata_tag { uint64_t pack_size; uint64_t unpack_size; - char *filename; + char filename[1024]; uint32_t crc; unsigned int encrypted; uint8_t method; diff --git a/unit_tests/check_clamav.c b/unit_tests/check_clamav.c index 9d913bf030..692c092de4 100644 --- a/unit_tests/check_clamav.c +++ b/unit_tests/check_clamav.c @@ -533,7 +533,7 @@ END_TEST static char **testfiles = NULL; static unsigned testfiles_n = 0; -static const int expected_testfiles = 49; +static const int expected_testfiles = 52; static unsigned skip_files(void) { diff --git a/unit_tests/clamd_test.py b/unit_tests/clamd_test.py index 9e0fe9ca0a..bd8544928a 100644 --- a/unit_tests/clamd_test.py +++ b/unit_tests/clamd_test.py @@ -652,3 +652,151 @@ def test_clamd_11_alertexceedsmax_maxfilesize(self): unexpected_results = ['OK', 'MaxFileSize FOUND', 'Can\'t allocate memory ERROR'] self.verify_output(output.out, expected=expected_results, unexpected=unexpected_results) assert output.ec == 1 + + def test_clamd_12_onenote_disabled(self): + self.step_name('Test that clamd.conf `ScanOneNote no` disables onenote support.') + + testpaths = [ + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.2007.one", + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.2010.one", + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.webapp-export.one", + ] + + testfiles = ' '.join([str(testpath) for testpath in testpaths]) + + # We'll use a config that sets `ScanOneNote yes` + config = ''' + Foreground yes + PidFile {pid} + DatabaseDirectory {dbdir} + LogFileMaxSize 0 + LogTime yes + #Debug yes + LogClean yes + LogVerbose yes + ExitOnOOM yes + DetectPUA yes + ScanPDF yes + CommandReadTimeout 1 + MaxQueue 800 + MaxConnectionQueueLength 1024 + ScanOneNote yes + '''.format(pid=TC.clamd_pid, dbdir=TC.path_db) + if operating_system == 'windows': + # Only have TCP socket option for Windows. + config += ''' + TCPSocket {socket} + TCPAddr localhost + '''.format(socket=TC.clamd_port_num) + else: + # Use LocalSocket for Posix, because that's what check_clamd expects. + config += ''' + LocalSocket {localsocket} + TCPSocket {tcpsocket} + TCPAddr localhost + '''.format(localsocket=TC.clamd_socket, tcpsocket=TC.clamd_port_num) + + clamd_config = TC.path_tmp / 'clamd-test.conf' + clamd_config.write_text(config) + + # Copy database to database path + shutil.copy( + str(TC.path_build / 'unit_tests' / 'input' / 'clamav.hdb'), + str(TC.path_db), + ) + + # + # Start ClamD with our custom config + # + self.start_clamd(clamd_config=clamd_config) + + poll = self.proc.poll() + assert poll == None # subprocess is alive if poll() returns None + + # Check the big_file scan exceeds max filesize + output = self.execute_command('{clamdscan} -c {clamd_config} --wait --ping 10 {testfiles}'.format( + clamdscan=TC.clamdscan, clamd_config=clamd_config, testfiles=testfiles)) + + assert output.ec == 1 # virus found + + expected_results = ['{}: ClamAV-Test-File.UNOFFICIAL FOUND'.format(testpath.name) for testpath in testpaths] + expected_results.append('Infected files: {}'.format(len(testpaths))) + self.verify_output(output.out, expected=expected_results) + + + # + # Now retry with ScanOneNote disabled + # + + # First kill clamd + if self.proc != None: + try: + self.proc.terminate() + self.proc.wait(timeout=120) + self.proc.stdin.close() + except OSError as exc: + self.log.warning('Unexpected exception {}'.format(exc)) + pass # ignore + self.proc = None + try: + TC.clamd_pid.unlink() + except Exception: + pass # missing_ok=True is too for common use. + try: + TC.clamd_socket.unlink() + except Exception: + pass # missing_ok=True is too for common use. + + # Then update the config. + # This time, we'll use a config that sets `ScanOneNote no` + config = ''' + Foreground yes + PidFile {pid} + DatabaseDirectory {dbdir} + LogFileMaxSize 0 + LogTime yes + #Debug yes + LogClean yes + LogVerbose yes + ExitOnOOM yes + DetectPUA yes + ScanPDF yes + CommandReadTimeout 1 + MaxQueue 800 + MaxConnectionQueueLength 1024 + ScanOneNote no + '''.format(pid=TC.clamd_pid, dbdir=TC.path_db) + if operating_system == 'windows': + # Only have TCP socket option for Windows. + config += ''' + TCPSocket {socket} + TCPAddr localhost + '''.format(socket=TC.clamd_port_num) + else: + # Use LocalSocket for Posix, because that's what check_clamd expects. + config += ''' + LocalSocket {localsocket} + TCPSocket {tcpsocket} + TCPAddr localhost + '''.format(localsocket=TC.clamd_socket, tcpsocket=TC.clamd_port_num) + + clamd_config = TC.path_tmp / 'clamd-test.conf' + clamd_config.write_text(config) + + # + # Start ClamD with our custom config + # + self.start_clamd(clamd_config=clamd_config) + + poll = self.proc.poll() + assert poll == None # subprocess is alive if poll() returns None + + # Check the big_file scan exceeds max filesize + output = self.execute_command('{clamdscan} -c {clamd_config} --wait --ping 10 {testfiles}'.format( + clamdscan=TC.clamdscan, clamd_config=clamd_config, testfiles=testfiles)) + + assert output.ec == 0 # virus found + + expected_results = ['{}: OK'.format(testpath.name) for testpath in testpaths] + expected_results.append('Infected files: 0') + self.verify_output(output.out, expected=expected_results) diff --git a/unit_tests/clamscan/assorted_test.py b/unit_tests/clamscan/assorted_test.py index 7cd94887f1..7df4751ba7 100644 --- a/unit_tests/clamscan/assorted_test.py +++ b/unit_tests/clamscan/assorted_test.py @@ -4,6 +4,7 @@ Run clamscan tests. """ +import shutil import unittest import sys from zipfile import ZIP_DEFLATED, ZipFile @@ -238,3 +239,46 @@ def test_iso_missing_joliet(self): unexpected_results = ['OK'] self.verify_output(output.out, expected=expected_results, unexpected=unexpected_results) + + def test_onenote_disabled(self): + self.step_name('Test that clamscan --scan-onenote=no disables onenote support') + + testpaths = [ + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.2007.one", + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.2010.one", + TC.path_build / "unit_tests" / "input" / "clamav_hdb_scanfiles" / "clam.exe.webapp-export.one", + ] + + testfiles = ' '.join([str(testpath) for testpath in testpaths]) + + command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles}'.format( + valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, + clamscan=TC.clamscan, + path_db=TC.path_build / 'unit_tests' / 'input' / 'clamav.hdb', + testfiles=testfiles, + ) + output = self.execute_command(command) + + assert output.ec == 1 # virus found + + expected_results = ['{}: ClamAV-Test-File.UNOFFICIAL FOUND'.format(testpath.name) for testpath in testpaths] + expected_results.append('Scanned files: {}'.format(len(testpaths))) + expected_results.append('Infected files: {}'.format(len(testpaths))) + self.verify_output(output.out, expected=expected_results) + + # Try again with onenote support disabled. + + command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} --scan-onenote=no {testfiles}'.format( + valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, + clamscan=TC.clamscan, + path_db=TC.path_build / 'unit_tests' / 'input' / 'clamav.hdb', + testfiles=testfiles, + ) + output = self.execute_command(command) + + assert output.ec == 0 # virus found + + expected_results = ['{}: OK'.format(testpath.name) for testpath in testpaths] + expected_results.append('Scanned files: 3') + expected_results.append('Infected files: 0') + self.verify_output(output.out, expected=expected_results) diff --git a/unit_tests/clamscan/fuzzy_img_hash_test.py b/unit_tests/clamscan/fuzzy_img_hash_test.py index b7242b6b44..b9275d4996 100644 --- a/unit_tests/clamscan/fuzzy_img_hash_test.py +++ b/unit_tests/clamscan/fuzzy_img_hash_test.py @@ -82,7 +82,7 @@ def test_sigs_bad_hash(self): expected_stderr = [ 'LibClamAV Error: Failed to load', - 'Invalid hash: Image fuzzy hash must be 16 characters in length: abcdef', + 'Invalid hash: ImageFuzzyHash hash must be 16 characters in length: abcdef', ] unexpected_stdout = [ 'logo.png.bad.UNOFFICIAL FOUND', diff --git a/unit_tests/input/CMakeLists.txt b/unit_tests/input/CMakeLists.txt index 506bce80d7..822439a0f6 100644 --- a/unit_tests/input/CMakeLists.txt +++ b/unit_tests/input/CMakeLists.txt @@ -54,6 +54,9 @@ set(TESTFILES clam.exe.bz2 clam.bz2.zip clam.exe_and_mail.tar.gz + clam.exe.2007.one + clam.exe.2010.one + clam.exe.webapp-export.one ) if(ENABLE_UNRAR) diff --git a/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2007.one.xor b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2007.one.xor new file mode 100644 index 0000000000..69546c65b1 Binary files /dev/null and b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2007.one.xor differ diff --git a/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2010.one.xor b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2010.one.xor new file mode 100644 index 0000000000..c8e152b28b Binary files /dev/null and b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.2010.one.xor differ diff --git a/unit_tests/input/clamav_hdb_scanfiles/clam.exe.webapp-export.one.xor b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.webapp-export.one.xor new file mode 100644 index 0000000000..592e704703 Binary files /dev/null and b/unit_tests/input/clamav_hdb_scanfiles/clam.exe.webapp-export.one.xor differ diff --git a/win32/conf_examples/clamd.conf.sample b/win32/conf_examples/clamd.conf.sample index d44d7beb64..98fff9454a 100644 --- a/win32/conf_examples/clamd.conf.sample +++ b/win32/conf_examples/clamd.conf.sample @@ -398,6 +398,12 @@ TCPAddr localhost # Default: yes #ScanHWP3 yes +# This option enables scanning of OneNote files. +# If you turn off this option, the original files will still be scanned, but +# without additional processing. +# Default: yes +#ScanOneNote yes + ## ## Mail files