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/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/libclamav.map b/libclamav/libclamav.map index f4c9ef9130..d93c452c49 100644 --- a/libclamav/libclamav.map +++ b/libclamav/libclamav.map @@ -297,6 +297,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 df8b025d61..71b740c492 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 { diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 5313f8e2ac..d057912145 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -4591,6 +4591,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_ARCHIVE && (DCONF_ARCH & ARCH_CONF_EGG)) + 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/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 bde6a83a44..56d2714b64 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: @@ -135,7 +139,7 @@ fn execute_bindgen() -> Result<(), &'static str> { // 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 commiting to source control. Pointer width, integer size, etc // are probably not the same when generated as when compiled. 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 8abd5dbf52..5ff9d0cb60 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..84631852aa --- /dev/null +++ b/libclamav_rust/src/scanners.rs @@ -0,0 +1,127 @@ +/* + * 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; + } + }; + + 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 { + warn!("cl_scandesc_magic returned error: {}", ret); + return false; + } + + true + }); + + cl_error_t_CL_SUCCESS +} diff --git a/libclamav_rust/src/sys.rs b/libclamav_rust/src/sys.rs index 3fe6eb9dd7..2d02861a00 100644 --- a/libclamav_rust/src/sys.rs +++ b/libclamav_rust/src/sys.rs @@ -375,34 +375,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 +614,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 +709,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 +1174,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/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',