diff --git a/rust/crates/nasl-function-proc-macro/src/codegen.rs b/rust/crates/nasl-function-proc-macro/src/codegen.rs index 8016886b8..7adc48b13 100644 --- a/rust/crates/nasl-function-proc-macro/src/codegen.rs +++ b/rust/crates/nasl-function-proc-macro/src/codegen.rs @@ -33,6 +33,12 @@ impl<'a> ArgsStruct<'a> { }) } + fn has_register_arg(&self) -> bool { + self.args + .iter() + .any(|arg| matches!(arg.kind, ArgKind::Register)) + } + fn get_args(&self) -> TokenStream { self .args.iter().map(|arg| { @@ -146,6 +152,9 @@ impl<'a> ArgsStruct<'a> { } fn gen_checks(&self) -> TokenStream { + if self.has_register_arg() { + return quote! {}; + } let named_array = self.make_array_of_names(ArgKind::get_named_arg_name); let maybe_named_array = self.make_array_of_names(ArgKind::get_maybe_named_arg_name); let num_allowed_positional_args = if self.has_positional_iterator_arg() { @@ -160,6 +169,43 @@ impl<'a> ArgsStruct<'a> { } } + fn impl_add_to_set( + &self, + ident: &Ident, + fn_name: &Ident, + asyncness: Option, + ) -> TokenStream { + let nasl_function_expr = match (asyncness, &self.receiver_type) { + (Some(_), ReceiverType::None) => { + quote! { AsyncStateless(Box::new(#fn_name)) } + } + (Some(_), ReceiverType::RefSelf) => { + quote! { AsyncStateful(Box::new(Self::#fn_name)) } + } + (Some(_), ReceiverType::RefMutSelf) => { + quote! { AsyncStatefulMut(Box::new(Self::#fn_name)) } + } + (None, ReceiverType::None) => quote! { SyncStateless(#fn_name) }, + (None, ReceiverType::RefSelf) => { + quote! { SyncStateful(Self::#fn_name) } + } + (None, ReceiverType::RefMutSelf) => { + quote! { SyncStatefulMut(Self::#fn_name) } + } + }; + + let (generics, state_type) = match &self.receiver_type { + ReceiverType::None => (quote! { < S > }, quote! { S }), + ReceiverType::RefSelf | ReceiverType::RefMutSelf => (quote! {}, quote! { Self }), + }; + + quote! { + fn #ident #generics (set: &mut crate::nasl::utils::StoredFunctionSet<#state_type>, name: &str) { + set.add_nasl_function(name, crate::nasl::utils::NaslFunction::#nasl_function_expr); + } + } + } + pub fn impl_nasl_function_args(&self) -> TokenStream { let ItemFn { attrs, @@ -193,21 +239,26 @@ impl<'a> ArgsStruct<'a> { }; let asyncness = sig.asyncness; let checks = self.gen_checks(); - let mangled_name = format!("_internal_{}", ident); - let mangled_ident = Ident::new(&mangled_name, ident.span()); - let inner_call = self.get_inner_call_expr(&mangled_ident, asyncness); + let mangled_ident_original_fn = Ident::new(&format!("_internal_{}", ident), ident.span()); + let mangled_ident_transformed_fn = + Ident::new(&(format!("_internal_convert_{}", ident)), ident.span()); + let inner_call = self.get_inner_call_expr(&mangled_ident_original_fn, asyncness); + let add_to_set = self.impl_add_to_set(ident, &mangled_ident_transformed_fn, asyncness); + quote! { #[allow(clippy::too_many_arguments)] - #asyncness fn #mangled_ident #generics ( #fn_args ) -> #output_ty { + #asyncness fn #mangled_ident_original_fn #generics ( #fn_args ) -> #output_ty { #(#stmts)* } - #(#attrs)* #vis #asyncness #fn_token #ident #generics ( #inputs ) -> crate::nasl::NaslResult { + #(#attrs)* #vis #asyncness #fn_token #mangled_ident_transformed_fn #generics ( #inputs ) -> crate::nasl::NaslResult { #checks #get_args let _result = #inner_call; <#output_ty as crate::nasl::ToNaslResult>::to_nasl_result(_result) } + + #add_to_set } } } diff --git a/rust/crates/nasl-function-proc-macro/src/lib.rs b/rust/crates/nasl-function-proc-macro/src/lib.rs index d8a5b015e..255c6afdf 100644 --- a/rust/crates/nasl-function-proc-macro/src/lib.rs +++ b/rust/crates/nasl-function-proc-macro/src/lib.rs @@ -1,3 +1,72 @@ +//! This crate provides the `nasl_function` proc macro, which is +//! designed to make implementing new NASL builtin functions as +//! convenient as possible. +//! +//! Design: There are two main purposes that the `nasl_function` macro +//! serves. +//! +//! Purpose 1: Unify argument handling. +//! +//! The `nasl_function!` macro provides a structured approach to argument handling +//! within NASL builtin functions. The macro takes as input a function +//! taking any number of arguments, along with instructions on whether +//! those arguments are named, positional, optional, etc. It then +//! produces a function that automatically handles conversion of the +//! arguments into the correct types and produces consistent error +//! messages if the function has been called with an invalid set of +//! arguments. +//! +//! To do so, the macro transforms the annotated function into a function +//! taking `&Context` and `&Register` as arguments (plus self arguments +//! if needed) and then calls the original function from within the transformed +//! function, deriving each argument from the `FromNaslValue` implementation +//! of its type and handling optional and named arguments appropriately. +//! +//! The macro renames the inner function into a proper, first class +//! function instead of a closure in order to provide support for +//! async functions (without relying on the unstable async +//! closures). +//! +//! Purpose 2: Provide a uniform way to add builtin functions to function sets. +//! +//! NASL builtin functions come in one of several types, depending on +//! their asyncness and whether they are stateless or stateful (and +//! whether they require mutable access to their state, if they +//! are). The `NaslFunction` type defined in the executor code is a +//! singular type which can represent all the various variants of +//! builtin functions. The executor also provides the +//! `StoredFunctionSet`, which represents a set of `NaslFunction`s +//! together with their state. This state struct is used both as the +//! actual state that these functions require, as well as an +//! identifying name. Together, the `NaslFunction` and +//! `StoredFunctionSet` types provide the ability to store NASL +//! functions in a type-erased way, so that the interpreter can run +//! them independently of their properties. +//! +//! In order to provide a unified interface for adding NASL functions +//! to `StoredFunctionSet`s, there needs to be a way to convert any of +//! the 6 variants which builtin functions come in (sync_stateless, +//! async_stateless, sync_stateful, ... ) into their corresponding +//! variant of `NaslFunction`. On the surface, this problem sounds +//! simple: Simply implement `Into` for `Fn(&Context, +//! &Register) -> NaslResult` as well as for `Fn(&Context, &Register) +//! -> Future`, as well as for the other 4 variants. Then +//! provide a `add_function` method on `StoredFunctionSet` that takes +//! any `impl Into` as argument. The problem with this +//! approach is that the Rust compiler cannot determine that these 6 +//! implementations are coherent, i.e. it believes that there might be +//! a type `T` that implements multiple of these `Fn` traits +//! simultaneously, which would result in overlapping trait impls. +//! +//! In order to solve this problem, the `nasl_function!` macro +//! transforms the annotated function into a special function that +//! takes a `StoredFunctionSet` and adds the correct variant of +//! `NaslFunction` to the set. This is a very indirect approach, but +//! it works because the `nasl_function!` macro knows exactly what the +//! signature of the annotated function is and can therefore derive +//! which of the 6 variants of `NaslFunction` it should become, +//! without requiring type-erasure via an intermediate trait. + mod codegen; mod error; mod parse; diff --git a/rust/src/nasl/builtin/array/mod.rs b/rust/src/nasl/builtin/array/mod.rs index 85bc29f24..e84179140 100644 --- a/rust/src/nasl/builtin/array/mod.rs +++ b/rust/src/nasl/builtin/array/mod.rs @@ -84,7 +84,6 @@ pub struct Array; function_set! { Array, - sync_stateless, ( make_array, make_list, diff --git a/rust/src/nasl/builtin/cert/mod.rs b/rust/src/nasl/builtin/cert/mod.rs index 733a220c4..2298c521c 100644 --- a/rust/src/nasl/builtin/cert/mod.rs +++ b/rust/src/nasl/builtin/cert/mod.rs @@ -437,7 +437,6 @@ impl NaslCerts { function_set! { NaslCerts, - sync_stateful, ( (NaslCerts::cert_open, "cert_open"), (NaslCerts::cert_close, "cert_close"), diff --git a/rust/src/nasl/builtin/cryptographic/aes_cbc.rs b/rust/src/nasl/builtin/cryptographic/aes_cbc.rs index 17b71ce49..a0914e8d7 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_cbc.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_cbc.rs @@ -71,7 +71,8 @@ where /// Currently the data is filled with zeroes. Therefore the length of the encrypted data must be /// known for decryption. If no length is given, the last block is decrypted as a whole. /// - The iv must have a length of 16 bytes -fn aes128_cbc_encrypt(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes128_cbc_encrypt(register: &Register) -> Result { cbc::(register, Crypt::Encrypt) } @@ -83,7 +84,8 @@ fn aes128_cbc_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_cbc_decrypt(register: &Register) -> Result { cbc::(register, Crypt::Decrypt) } @@ -94,7 +96,8 @@ fn aes128_cbc_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_cbc_encrypt(register: &Register) -> Result { cbc::(register, Crypt::Encrypt) } @@ -106,7 +109,8 @@ fn aes192_cbc_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_cbc_decrypt(register: &Register) -> Result { cbc::(register, Crypt::Decrypt) } @@ -117,7 +121,8 @@ fn aes192_cbc_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_cbc_encrypt(register: &Register) -> Result { cbc::(register, Crypt::Encrypt) } @@ -129,7 +134,8 @@ fn aes256_cbc_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_cbc_decrypt(register: &Register) -> Result { cbc::(register, Crypt::Decrypt) } @@ -137,7 +143,6 @@ pub struct AesCbc; function_set! { AesCbc, - sync_stateless, ( aes128_cbc_encrypt, aes128_cbc_decrypt, diff --git a/rust/src/nasl/builtin/cryptographic/aes_ccm.rs b/rust/src/nasl/builtin/cryptographic/aes_ccm.rs index b52e6d0f5..a37afabae 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_ccm.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_ccm.rs @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception -use crate::nasl::utils::error::FnError; use aes::cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, BlockSizeUser}; use aes::{Aes128, Aes192, Aes256}; use ccm::{ @@ -12,10 +11,7 @@ use ccm::{ }; use digest::generic_array::ArrayLength; -use crate::nasl::syntax::NaslValue; -use crate::nasl::utils::{Context, Register}; - -use crate::function_set; +use crate::nasl::prelude::*; use super::{get_aad, get_data, get_iv, get_key, get_len, Crypt, CryptographicError}; @@ -71,7 +67,8 @@ where /// - The length of the key should be 16 bytes long /// - The iv must have a length of 7-13 bytes /// - The tag_size default is 16, it can be set to either 4, 6, 8, 10, 12, 14 or 16 -fn aes128_ccm_encrypt(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes128_ccm_encrypt(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, false) } @@ -82,7 +79,8 @@ fn aes128_ccm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_ccm_encrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, true) } @@ -93,7 +91,8 @@ fn aes128_ccm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_ccm_decrypt(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, false) } @@ -104,7 +103,8 @@ fn aes128_ccm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_ccm_decrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, true) } @@ -115,7 +115,8 @@ fn aes128_ccm_decrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ccm_encrypt(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, false) } @@ -126,7 +127,8 @@ fn aes192_ccm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ccm_encrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, true) } @@ -137,7 +139,8 @@ fn aes192_ccm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ccm_decrypt(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, false) } @@ -148,7 +151,8 @@ fn aes192_ccm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ccm_decrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, true) } @@ -159,7 +163,8 @@ fn aes192_ccm_decrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ccm_encrypt(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, false) } @@ -170,7 +175,8 @@ fn aes256_ccm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ccm_encrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Encrypt, true) } @@ -181,7 +187,8 @@ fn aes256_ccm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ccm_decrypt(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, false) } @@ -192,7 +199,8 @@ fn aes256_ccm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ccm_decrypt_auth(register: &Register) -> Result { ccm::(register, Crypt::Decrypt, true) } @@ -234,7 +242,6 @@ pub struct AesCcm; function_set! { AesCcm, - sync_stateless, ( aes128_ccm_encrypt, aes128_ccm_encrypt_auth, diff --git a/rust/src/nasl/builtin/cryptographic/aes_cmac.rs b/rust/src/nasl/builtin/cryptographic/aes_cmac.rs index 4e80eb718..f322516f2 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_cmac.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_cmac.rs @@ -2,12 +2,10 @@ // // SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception -use crate::nasl::syntax::NaslValue; -use crate::nasl::utils::{Context, FnError, Register}; use aes::Aes128; use cmac::{Cmac, Mac}; -use crate::function_set; +use crate::nasl::prelude::*; use super::{get_data, get_key, CryptographicError}; @@ -16,7 +14,8 @@ use super::{get_data, get_key, CryptographicError}; /// This function expects 2 named arguments key and data either in a string or data type. /// It is important to notice, that internally the CMAC algorithm is used and not, as the name /// suggests, CBC-MAC. -fn aes_cmac(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes_cmac(register: &Register) -> Result { let key = get_key(register)?; let data = get_data(register)?; @@ -31,7 +30,6 @@ pub struct AesCmac; function_set! { AesCmac, - sync_stateless, ( (aes_cmac, "aes_mac_cbc"), aes_cmac, diff --git a/rust/src/nasl/builtin/cryptographic/aes_ctr.rs b/rust/src/nasl/builtin/cryptographic/aes_ctr.rs index 7e6d9ec08..961014a69 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_ctr.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_ctr.rs @@ -56,7 +56,8 @@ where /// Currently the data is filled with zeroes. Therefore the length of the encrypted data must be /// known for decryption. If no length is given, the last block is decrypted as a whole. /// - The iv must have a length of 16 bytes. It is used as the initial counter. -fn aes128_ctr_encrypt(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes128_ctr_encrypt(register: &Register) -> Result { ctr::(register, Crypt::Encrypt) } @@ -68,7 +69,8 @@ fn aes128_ctr_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_ctr_decrypt(register: &Register) -> Result { ctr::(register, Crypt::Decrypt) } @@ -79,7 +81,8 @@ fn aes128_ctr_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ctr_encrypt(register: &Register) -> Result { ctr::(register, Crypt::Encrypt) } @@ -91,7 +94,8 @@ fn aes192_ctr_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_ctr_decrypt(register: &Register) -> Result { ctr::(register, Crypt::Decrypt) } @@ -102,7 +106,8 @@ fn aes192_ctr_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ctr_encrypt(register: &Register) -> Result { ctr::(register, Crypt::Encrypt) } @@ -114,7 +119,8 @@ fn aes256_ctr_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_ctr_decrypt(register: &Register) -> Result { ctr::(register, Crypt::Decrypt) } @@ -122,7 +128,6 @@ pub struct AesCtr; function_set! { AesCtr, - sync_stateless, ( aes128_ctr_encrypt, aes128_ctr_decrypt, diff --git a/rust/src/nasl/builtin/cryptographic/aes_gcm.rs b/rust/src/nasl/builtin/cryptographic/aes_gcm.rs index 55bab0129..016d2775e 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_gcm.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_gcm.rs @@ -76,7 +76,8 @@ where /// - The iv must have a length of 16 bytes. It is used as the initial counter. /// - The result contains the ciphertext and the calculated tag in a single data type. /// - The tag has a size of 16 Bytes. -fn aes128_gcm_encrypt(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes128_gcm_encrypt(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, false) } @@ -89,7 +90,8 @@ fn aes128_gcm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_gcm_encrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, true) } @@ -102,7 +104,8 @@ fn aes128_gcm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_gcm_decrypt(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, false) } @@ -115,7 +118,8 @@ fn aes128_gcm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes128_gcm_decrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, true) } @@ -128,7 +132,8 @@ fn aes128_gcm_decrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_gcm_encrypt(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, false) } @@ -141,7 +146,8 @@ fn aes192_gcm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_gcm_encrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, true) } @@ -154,7 +160,8 @@ fn aes192_gcm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_gcm_decrypt(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, false) } @@ -167,7 +174,8 @@ fn aes192_gcm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes192_gcm_decrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, true) } @@ -180,7 +188,8 @@ fn aes192_gcm_decrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_gcm_encrypt(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, false) } @@ -193,7 +202,8 @@ fn aes256_gcm_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_gcm_encrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Encrypt, true) } @@ -206,7 +216,8 @@ fn aes256_gcm_encrypt_auth(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_gcm_decrypt(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, false) } @@ -219,7 +230,8 @@ fn aes256_gcm_decrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn aes256_gcm_decrypt_auth(register: &Register) -> Result { gcm::(register, Crypt::Decrypt, true) } @@ -227,7 +239,6 @@ pub struct AesGcmFns; function_set! { AesGcmFns, - sync_stateless, ( aes128_gcm_encrypt, aes128_gcm_encrypt_auth, diff --git a/rust/src/nasl/builtin/cryptographic/aes_gmac.rs b/rust/src/nasl/builtin/cryptographic/aes_gmac.rs index 195738c9e..94cf78c0f 100644 --- a/rust/src/nasl/builtin/cryptographic/aes_gmac.rs +++ b/rust/src/nasl/builtin/cryptographic/aes_gmac.rs @@ -10,7 +10,8 @@ use crate::nasl::prelude::*; /// /// This function expects 3 named arguments key, data and iv either in a string or data type. #[cfg(feature = "nasl-c-lib")] -fn aes_gmac(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn aes_gmac(register: &Register) -> Result { use super::{get_data, get_iv, get_key, CryptographicError}; use nasl_c_lib::cryptographic::mac::aes_gmac; @@ -29,7 +30,6 @@ pub struct AesGmac; #[cfg(feature = "nasl-c-lib")] function_set! { AesGmac, - sync_stateless, ( aes_gmac ) @@ -38,7 +38,6 @@ function_set! { #[cfg(not(feature = "nasl-c-lib"))] function_set! { AesGmac, - sync_stateless, ( ) } diff --git a/rust/src/nasl/builtin/cryptographic/bf_cbc.rs b/rust/src/nasl/builtin/cryptographic/bf_cbc.rs index 1f24a09a7..574444cf2 100644 --- a/rust/src/nasl/builtin/cryptographic/bf_cbc.rs +++ b/rust/src/nasl/builtin/cryptographic/bf_cbc.rs @@ -74,7 +74,8 @@ where /// The return value is an array a with a[0] being the encrypted data and /// a[1] the new initialization vector to use for the next part of the /// data. -fn bf_cbc_encrypt(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn bf_cbc_encrypt(register: &Register) -> Result { cbc::(register, Crypt::Encrypt) } @@ -88,7 +89,8 @@ fn bf_cbc_encrypt(register: &Register, _: &Context) -> Result Result { +#[nasl_function] +fn bf_cbc_decrypt(register: &Register) -> Result { cbc::(register, Crypt::Decrypt) } @@ -96,7 +98,6 @@ pub struct BfCbc; function_set! { BfCbc, - sync_stateless, ( bf_cbc_encrypt, bf_cbc_decrypt, diff --git a/rust/src/nasl/builtin/cryptographic/des.rs b/rust/src/nasl/builtin/cryptographic/des.rs index ddd8b2c37..1fb8e9636 100644 --- a/rust/src/nasl/builtin/cryptographic/des.rs +++ b/rust/src/nasl/builtin/cryptographic/des.rs @@ -7,7 +7,8 @@ use aes::cipher::BlockEncrypt; use ccm::KeyInit; use des::cipher::generic_array::GenericArray; -fn encrypt_des(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn encrypt_des(register: &Register) -> Result { let positional = register.positional(); if positional.len() != 2 { return Err(ArgumentError::MissingPositionals { @@ -38,7 +39,6 @@ pub struct Des; function_set! { Des, - sync_stateless, ( (encrypt_des, "DES"), ) diff --git a/rust/src/nasl/builtin/cryptographic/hash.rs b/rust/src/nasl/builtin/cryptographic/hash.rs index be4ef0aa5..5687163ac 100644 --- a/rust/src/nasl/builtin/cryptographic/hash.rs +++ b/rust/src/nasl/builtin/cryptographic/hash.rs @@ -73,7 +73,6 @@ pub struct Hash; function_set! { Hash, - sync_stateless, ( (hash_md2, "MD2"), (hash_md4, "MD4"), diff --git a/rust/src/nasl/builtin/cryptographic/hmac.rs b/rust/src/nasl/builtin/cryptographic/hmac.rs index 556cc5899..96b8afc23 100644 --- a/rust/src/nasl/builtin/cryptographic/hmac.rs +++ b/rust/src/nasl/builtin/cryptographic/hmac.rs @@ -92,7 +92,6 @@ pub struct HmacFns; function_set! { HmacFns, - sync_stateless, ( (hmac_md2, "HMAC_MD2"), (hmac_md5, "HMAC_MD5"), diff --git a/rust/src/nasl/builtin/cryptographic/rc4.rs b/rust/src/nasl/builtin/cryptographic/rc4.rs index 224e41027..ba3d94058 100644 --- a/rust/src/nasl/builtin/cryptographic/rc4.rs +++ b/rust/src/nasl/builtin/cryptographic/rc4.rs @@ -7,8 +7,6 @@ use rc4::{consts::*, KeyInit, StreamCipher}; use std::sync::{Arc, Mutex, MutexGuard}; use crate::nasl::prelude::*; -use crate::nasl::syntax::NaslValue; -use crate::nasl::utils::{Context, Register}; use super::{get_data, get_key, CryptographicError}; @@ -58,11 +56,8 @@ pub struct CipherHandlers { impl CipherHandlers { /// Closes a stream cipher. - pub fn close_stream_cipher( - &self, - register: &Register, - _: &Context, - ) -> Result { + #[nasl_function] + pub fn close_stream_cipher(&self, register: &Register) -> Result { let hd = match register.named("hd") { Some(ContextType::Value(NaslValue::Number(x))) => *x as i32, _ => return Err(CryptographicError::Rc4("Handler ID not found".to_string()).into()), @@ -84,7 +79,8 @@ impl CipherHandlers { /// -key: the key used for encryption /// /// Returns the id of the encrypted data cipher handler on success. - pub fn open_rc4_cipher(&self, register: &Register, _: &Context) -> Result { + #[nasl_function] + pub fn open_rc4_cipher(&self, register: &Register) -> Result { // Get Arguments let key = match get_key(register) { @@ -113,7 +109,8 @@ impl CipherHandlers { /// -hd: the handler index. (mandatory if not key and iv is given) /// -iv: string Initialization vector (mandatory if no handler is given). /// -key: string key (mandatory if no handler is given). - pub fn rc4_encrypt(&self, register: &Register, _: &Context) -> Result { + #[nasl_function] + pub fn rc4_encrypt(&self, register: &Register) -> Result { let data = match get_data(register) { Ok(d) if !d.is_empty() => d.to_vec(), _ => return Err(CryptographicError::Rc4("Missing data argument".to_string()).into()), @@ -255,7 +252,6 @@ build_rc4key_enum! { function_set! { CipherHandlers, - sync_stateful, ( (CipherHandlers::close_stream_cipher, "close_stream_cipher"), (CipherHandlers::open_rc4_cipher, "open_rc4_cipher"), diff --git a/rust/src/nasl/builtin/cryptographic/rsa.rs b/rust/src/nasl/builtin/cryptographic/rsa.rs index 2ce383d8a..a88eb552d 100644 --- a/rust/src/nasl/builtin/cryptographic/rsa.rs +++ b/rust/src/nasl/builtin/cryptographic/rsa.rs @@ -123,7 +123,6 @@ fn rsa_public_decrypt(sign: &[u8], n: &[u8], e: &[u8]) -> Result Result { let vh = context.target_vhosts(); let v = if !vh.is_empty() { @@ -129,7 +130,8 @@ pub fn get_host_name_source(context: &Context, hostname: Hostname) -> String { } /// Return the target's IP address or 127.0.0.1 if not set. -fn nasl_get_host_ip(_register: &Register, context: &Context) -> Result { +#[nasl_function] +fn nasl_get_host_ip(context: &Context) -> Result { let ip = get_host_ip(context)?; Ok(NaslValue::String(ip.to_string())) } @@ -194,7 +196,6 @@ pub struct Host; function_set! { Host, - sync_stateless, ( get_host_names, (nasl_get_host_ip, "get_host_ip"), diff --git a/rust/src/nasl/builtin/http/mod.rs b/rust/src/nasl/builtin/http/mod.rs index 9fd9274c3..bae5cee4d 100644 --- a/rust/src/nasl/builtin/http/mod.rs +++ b/rust/src/nasl/builtin/http/mod.rs @@ -277,31 +277,32 @@ impl NaslHttp { } /// Wrapper function for GET request. See http2_req - async fn get<'a>(&self, register: &Register, ctx: &Context<'a>) -> Result { + #[nasl_function] + async fn get(&self, register: &Register, ctx: &Context<'_>) -> Result { self.http2_req(register, ctx, Method::GET).await } /// Wrapper function for POST request. See http2_req - async fn post<'a>(&self, register: &Register, ctx: &Context<'a>) -> Result { + #[nasl_function] + async fn post(&self, register: &Register, ctx: &Context<'_>) -> Result { self.http2_req(register, ctx, Method::POST).await } /// Wrapper function for PUT request. See http2_req - async fn put<'a>(&self, register: &Register, ctx: &Context<'a>) -> Result { + #[nasl_function] + async fn put(&self, register: &Register, ctx: &Context<'_>) -> Result { self.http2_req(register, ctx, Method::PUT).await } /// Wrapper function for HEAD request. See http2_req - async fn head<'a>(&self, register: &Register, ctx: &Context<'a>) -> Result { + #[nasl_function] + async fn head(&self, register: &Register, ctx: &Context<'_>) -> Result { self.http2_req(register, ctx, Method::HEAD).await } /// Wrapper function for DELETE request. See http2_req - async fn delete<'a>( - &self, - register: &Register, - ctx: &Context<'a>, - ) -> Result { + #[nasl_function] + async fn delete(&self, register: &Register, ctx: &Context<'_>) -> Result { self.http2_req(register, ctx, Method::DELETE).await } @@ -353,11 +354,8 @@ impl NaslHttp { /// /// On success the function returns an integer /// representing the http code response. Null on error. - async fn get_response_code( - &self, - register: &Register, - _: &Context<'_>, - ) -> Result { + #[nasl_function] + async fn get_response_code(&self, register: &Register) -> Result { let handle_id = match register.named("handle") { Some(ContextType::Value(NaslValue::Number(x))) => *x as i32, _ => { @@ -382,11 +380,8 @@ impl NaslHttp { /// - header_item A string to add to the header /// /// On success the function returns an integer. 0 on success. Null on error. - async fn set_custom_header( - &self, - register: &Register, - _: &Context<'_>, - ) -> Result { + #[nasl_function] + async fn set_custom_header(&self, register: &Register) -> Result { let header_item = match register.named("header_item") { Some(ContextType::Value(NaslValue::String(x))) => x, _ => return Err(FnError::missing_argument("No command passed")), @@ -418,7 +413,6 @@ impl NaslHttp { function_set! { NaslHttp, - async_stateful, ( (NaslHttp::handle, "http2_handle"), (NaslHttp::close_handle, "http2_close_handle"), diff --git a/rust/src/nasl/builtin/isotime/mod.rs b/rust/src/nasl/builtin/isotime/mod.rs index 565e36149..472b080bb 100644 --- a/rust/src/nasl/builtin/isotime/mod.rs +++ b/rust/src/nasl/builtin/isotime/mod.rs @@ -120,7 +120,6 @@ pub struct NaslIsotime; function_set! { NaslIsotime, - sync_stateless, ( isotime_add, isotime_is_valid, diff --git a/rust/src/nasl/builtin/knowledge_base/mod.rs b/rust/src/nasl/builtin/knowledge_base/mod.rs index cb798160c..5e7a273a4 100644 --- a/rust/src/nasl/builtin/knowledge_base/mod.rs +++ b/rust/src/nasl/builtin/knowledge_base/mod.rs @@ -110,7 +110,6 @@ pub struct KnowledgeBase; function_set! { KnowledgeBase, - sync_stateless, ( set_kb_item, get_kb_item, diff --git a/rust/src/nasl/builtin/misc/mod.rs b/rust/src/nasl/builtin/misc/mod.rs index 92cc6a92e..241f155ba 100644 --- a/rust/src/nasl/builtin/misc/mod.rs +++ b/rust/src/nasl/builtin/misc/mod.rs @@ -254,7 +254,6 @@ pub struct Misc; function_set! { Misc, - sync_stateless, ( rand, get_byte_order, diff --git a/rust/src/nasl/builtin/network/network.rs b/rust/src/nasl/builtin/network/network.rs index 078b2440b..761bdc7f6 100644 --- a/rust/src/nasl/builtin/network/network.rs +++ b/rust/src/nasl/builtin/network/network.rs @@ -154,7 +154,6 @@ pub struct Network; function_set! { Network, - sync_stateless, ( scanner_add_port, islocalnet, diff --git a/rust/src/nasl/builtin/network/socket.rs b/rust/src/nasl/builtin/network/socket.rs index 8f337b087..77108e368 100644 --- a/rust/src/nasl/builtin/network/socket.rs +++ b/rust/src/nasl/builtin/network/socket.rs @@ -705,7 +705,6 @@ impl NaslSockets { function_set! { NaslSockets, - sync_stateful, ( (NaslSockets::open_sock_kdc, "open_sock_kdc"), (NaslSockets::open_sock_tcp, "open_sock_tcp"), diff --git a/rust/src/nasl/builtin/raw_ip/frame_forgery.rs b/rust/src/nasl/builtin/raw_ip/frame_forgery.rs index e45c73eb7..4bf76d057 100644 --- a/rust/src/nasl/builtin/raw_ip/frame_forgery.rs +++ b/rust/src/nasl/builtin/raw_ip/frame_forgery.rs @@ -346,6 +346,7 @@ fn send_frame( /// /// It takes the following argument: /// - cap_timeout: time to wait for answer in seconds, 5 by default +#[nasl_function] fn nasl_send_arp_request(register: &Register, context: &Context) -> Result { let timeout = match register.named("pcap_timeout") { Some(ContextType::Value(NaslValue::Number(x))) => *x as i32 * 1000i32, // to milliseconds @@ -399,10 +400,8 @@ fn nasl_send_arp_request(register: &Register, context: &Context) -> Result Result { +#[nasl_function] +fn nasl_get_local_mac_address_from_ip(register: &Register) -> Result { let positional = register.positional(); if positional.is_empty() { return Err(ArgumentError::MissingPositionals { @@ -431,7 +430,8 @@ fn nasl_get_local_mac_address_from_ip( /// - ether_proto: is an int containing the ethernet type (normally given as hexadecimal). /// It is optional and its default value is 0x0800. A list of Types can be e.g. looked up here. /// - payload: is any data, which is then attached as payload to the frame. -fn nasl_forge_frame(register: &Register, _: &Context) -> Result { +#[nasl_function] +fn nasl_forge_frame(register: &Register) -> Result { let src_haddr = validate_mac_address(register.named("src_haddr"))?; let dst_haddr = validate_mac_address(register.named("dst_haddr"))?; let ether_proto = match register.named("ether_proto") { @@ -459,6 +459,7 @@ fn nasl_forge_frame(register: &Register, _: &Context) -> Result Result { let frame = match register.named("frame") { Some(ContextType::Value(NaslValue::Data(x))) => x, @@ -513,7 +514,8 @@ fn nasl_send_frame(register: &Register, context: &Context) -> Result Result { +#[nasl_function] +fn nasl_dump_frame(register: &Register) -> Result { let frame: Frame = match register.named("frame") { Some(ContextType::Value(NaslValue::Data(x))) => (x as &[u8]).try_into()?, _ => return Err(FnError::wrong_unnamed_argument("Data", "Invalid data type")), @@ -549,7 +551,6 @@ pub struct FrameForgery; function_set! { FrameForgery, - sync_stateless, ( (nasl_send_frame, "send_frame"), (nasl_dump_frame, "dump_frame"), diff --git a/rust/src/nasl/builtin/raw_ip/packet_forgery.rs b/rust/src/nasl/builtin/raw_ip/packet_forgery.rs index f1bcf043c..30c47036b 100644 --- a/rust/src/nasl/builtin/raw_ip/packet_forgery.rs +++ b/rust/src/nasl/builtin/raw_ip/packet_forgery.rs @@ -144,6 +144,7 @@ fn safe_copy_from_slice( /// - ip_v is: the IP version. 4 by default. /// /// Returns the IP datagram or NULL on error. +#[nasl_function] fn forge_ip_packet(register: &Register, configs: &Context) -> Result { let dst_addr = get_host_ip(configs)?; @@ -283,6 +284,7 @@ fn forge_ip_packet(register: &Register, configs: &Context) -> Result Result { let mut buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -372,6 +374,7 @@ fn set_ip_elements(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -403,7 +406,8 @@ fn get_ip_element(register: &Register, _configs: &Context) -> Result Result { +#[nasl_function] +fn dump_ip_packet(register: &Register) -> Result { let positional = register.positional(); if positional.is_empty() { return Err(ArgumentError::MissingPositionals { @@ -458,6 +462,7 @@ fn dump_protocol(pkt: &Ipv4Packet) -> String { /// - code: is the identifier of the option to add /// - length: is the length of the option data /// - value: is the option data +#[nasl_function] fn insert_ip_options(register: &Register, _configs: &Context) -> Result { let buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -551,6 +556,7 @@ fn insert_ip_options(register: &Register, _configs: &Context) -> Result Result { let mut ip_buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -666,6 +672,7 @@ fn forge_tcp_packet(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("tcp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -709,6 +716,7 @@ fn get_tcp_element(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("tcp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -783,6 +791,7 @@ fn get_tcp_option(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("tcp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -919,6 +928,7 @@ fn set_tcp_elements(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("tcp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1098,7 +1108,8 @@ fn insert_tcp_options(register: &Register, _configs: &Context) -> Result Result { +#[nasl_function] +fn dump_tcp_packet(register: &Register) -> Result { let positional = register.positional(); if positional.is_empty() { return Err(error( @@ -1200,6 +1211,7 @@ fn format_flags(pkt: &TcpPacket) -> String { /// - update_ip_len: is a flag (TRUE by default). If set, NASL will recompute the size field of the IP datagram. /// /// Returns the modified IP datagram or NULL on error. +#[nasl_function] fn forge_udp_packet(register: &Register, _configs: &Context) -> Result { let mut ip_buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1278,6 +1290,7 @@ fn forge_udp_packet(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("udp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1379,7 +1392,8 @@ fn set_udp_elements(register: &Register, _configs: &Context) -> Result Result { +#[nasl_function] +fn dump_udp_packet(register: &Register) -> Result { let positional = register.positional(); if positional.is_empty() { return Err(error( @@ -1431,6 +1445,7 @@ fn dump_udp_packet(register: &Register, _: &Context) -> Result Result { let buf = match register.named("udp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1466,6 +1481,7 @@ fn get_udp_element(register: &Register, _configs: &Context) -> Result Result { let mut ip_buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1557,6 +1573,7 @@ fn forge_icmp_packet(register: &Register, _configs: &Context) -> Result Result { let buf = match register.named("icmp") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1613,7 +1630,8 @@ fn get_icmp_element(register: &Register, _configs: &Context) -> Result Result { +#[nasl_function] +fn dump_icmp_packet(register: &Register) -> Result { let positional = register.positional(); if positional.is_empty() { return Err(FnError::missing_argument("icmp")); @@ -1739,6 +1757,7 @@ pub mod igmp { /// - group: IGMP group /// - type: IGMP type. 0 by default. /// - update_ip_len: If this flag is set, NASL will recompute the size field of the IP datagram. Default: True. +#[nasl_function] fn forge_igmp_packet(register: &Register, _configs: &Context) -> Result { let mut ip_buf = match register.named("ip") { Some(ContextType::Value(NaslValue::Data(d))) => d.clone(), @@ -1831,6 +1850,7 @@ fn new_raw_socket() -> Result { /// /// Its argument is: /// - port: port for the ping +#[nasl_function] fn nasl_tcp_ping(register: &Register, configs: &Context) -> Result { let rnd_tcp_port = || -> u16 { (random_impl().unwrap_or(0) % 65535 + 1024) as u16 }; @@ -1967,6 +1987,7 @@ fn nasl_tcp_ping(register: &Register, configs: &Context) -> Result Result { let use_pcap = match register.named("pcap_active") { Some(ContextType::Value(NaslValue::Boolean(x))) => *x, @@ -2101,20 +2122,12 @@ fn nasl_send_packet(register: &Register, configs: &Context) -> Result Result { - nasl_send_capture(register, configs) -} - /// Read the next packet. /// /// - interface: network interface name, by default NASL will try to find the best one /// - pcap_filter: BPF filter, by default it listens to everything /// - timeout: timeout in seconds, 5 by default +#[nasl_function] fn nasl_send_capture(register: &Register, configs: &Context) -> Result { let interface = match register.named("interface") { Some(ContextType::Value(NaslValue::String(x))) => x.to_string(), @@ -2238,7 +2251,6 @@ pub struct PacketForgery; function_set! { PacketForgery, - sync_stateless, ( forge_ip_packet, set_ip_elements, @@ -2261,7 +2273,8 @@ function_set! { forge_igmp_packet, (nasl_tcp_ping, "tcp_ping"), (nasl_send_packet, "send_packet"), - (nasl_pcap_next, "pcap_next"), + // These two functions are the same + (nasl_send_capture, "pcap_next"), (nasl_send_capture, "send_capture"), ) } diff --git a/rust/src/nasl/builtin/regex/mod.rs b/rust/src/nasl/builtin/regex/mod.rs index eda1fdfba..6c4724181 100644 --- a/rust/src/nasl/builtin/regex/mod.rs +++ b/rust/src/nasl/builtin/regex/mod.rs @@ -168,7 +168,6 @@ pub struct RegularExpressions; function_set! { RegularExpressions, - sync_stateless, ( ereg, egrep, diff --git a/rust/src/nasl/builtin/report_functions/mod.rs b/rust/src/nasl/builtin/report_functions/mod.rs index 689e9ae26..a874c0c46 100644 --- a/rust/src/nasl/builtin/report_functions/mod.rs +++ b/rust/src/nasl/builtin/report_functions/mod.rs @@ -70,6 +70,7 @@ impl Reporting { /// - port, optional TCP or UDP port number of the service /// - proto is the protocol ("tcp" by default; "udp" is the other value). /// - uri specifies the location of a found product + #[nasl_function] fn log_message(&self, register: &Register, context: &Context) -> Result { self.store_result(ResultType::Log, register, context) } @@ -81,6 +82,7 @@ impl Reporting { /// - port, optional TCP or UDP port number of the service /// - proto is the protocol ("tcp" by default; "udp" is the other value). /// - uri specifies the location of a found product + #[nasl_function] fn security_message( &self, register: &Register, @@ -96,6 +98,7 @@ impl Reporting { /// - port, optional TCP or UDP port number of the service /// - proto is the protocol ("tcp" by default; "udp" is the other value). /// - uri specifies the location of a found product + #[nasl_function] fn error_message(&self, register: &Register, context: &Context) -> Result { self.store_result(ResultType::Error, register, context) } @@ -103,7 +106,6 @@ impl Reporting { function_set! { Reporting, - sync_stateful, ( (Reporting::log_message, "log_message"), (Reporting::security_message, "security_message"), diff --git a/rust/src/nasl/builtin/ssh/mod.rs b/rust/src/nasl/builtin/ssh/mod.rs index d5bdfe79c..c8ad39b62 100644 --- a/rust/src/nasl/builtin/ssh/mod.rs +++ b/rust/src/nasl/builtin/ssh/mod.rs @@ -23,10 +23,7 @@ use std::time::Duration; use ::russh::{cipher, Preferred}; use russh_keys::key; -use crate::nasl::{ - prelude::*, - utils::{IntoFunctionSet, StoredFunctionSet}, -}; +use crate::nasl::prelude::*; use error::SshErrorKind; use utils::CommaSeparated; @@ -67,43 +64,41 @@ impl Output { } } -impl IntoFunctionSet for Ssh { - type State = Ssh; - fn into_function_set(self) -> StoredFunctionSet { - let mut set = StoredFunctionSet::new(self); - set.async_stateful_mut("ssh_connect", Ssh::nasl_ssh_connect); - set.async_stateful("ssh_request_exec", Ssh::nasl_ssh_request_exec); - set.async_stateful("ssh_userauth", Ssh::nasl_ssh_userauth); - set.async_stateful_mut("ssh_disconnect", Ssh::nasl_ssh_disconnect); - #[cfg(feature = "nasl-builtin-libssh")] - { - set.async_stateful( - "ssh_session_id_from_sock", - Ssh::nasl_ssh_session_id_from_sock, - ); - set.async_stateful("ssh_get_sock", Ssh::nasl_ssh_get_sock); - set.async_stateful("ssh_set_login", Ssh::nasl_ssh_set_login); - set.async_stateful("ssh_shell_open", Ssh::nasl_ssh_shell_open); - set.async_stateful("ssh_shell_read", Ssh::nasl_ssh_shell_read); - set.async_stateful("ssh_shell_write", Ssh::nasl_ssh_shell_write); - set.async_stateful("ssh_shell_close", Ssh::nasl_ssh_shell_close); - set.async_stateful("ssh_login_interactive", Ssh::nasl_ssh_login_interactive); - set.async_stateful( - "ssh_login_interactive_pass", - Ssh::nasl_ssh_login_interactive_pass, - ); - set.async_stateful("ssh_get_issue_banner", Ssh::nasl_ssh_get_issue_banner); - set.async_stateful("ssh_get_server_banner", Ssh::nasl_ssh_get_server_banner); - set.async_stateful("ssh_get_auth_methods", Ssh::nasl_ssh_get_auth_methods); - set.async_stateful("ssh_get_host_key", Ssh::nasl_ssh_get_host_key); - set.async_stateful("sftp_enabled_check", Ssh::nasl_sftp_enabled_check); - set.async_stateful( - "ssh_execute_netconf_subsystem", - Ssh::nasl_ssh_execute_netconf_subsystem, - ); - } - set - } +#[cfg(feature = "nasl-builtin-libssh")] +function_set! { + Ssh, + ( + (Ssh::nasl_ssh_connect, "ssh_connect"), + (Ssh::nasl_ssh_request_exec, "ssh_request_exec"), + (Ssh::nasl_ssh_userauth, "ssh_userauth"), + (Ssh::nasl_ssh_disconnect, "ssh_disconnect"), + (Ssh::nasl_ssh_session_id_from_sock, "ssh_session_id_from_sock"), + (Ssh::nasl_ssh_get_sock, "ssh_get_sock"), + (Ssh::nasl_ssh_set_login, "ssh_set_login"), + (Ssh::nasl_ssh_shell_open, "ssh_shell_open"), + (Ssh::nasl_ssh_shell_read, "ssh_shell_read"), + (Ssh::nasl_ssh_shell_write, "ssh_shell_write"), + (Ssh::nasl_ssh_shell_close, "ssh_shell_close"), + (Ssh::nasl_ssh_login_interactive, "ssh_login_interactive"), + (Ssh::nasl_ssh_login_interactive_pass, "ssh_login_interactive_pass"), + (Ssh::nasl_ssh_get_issue_banner, "ssh_get_issue_banner"), + (Ssh::nasl_ssh_get_server_banner, "ssh_get_server_banner"), + (Ssh::nasl_ssh_get_auth_methods, "ssh_get_auth_methods"), + (Ssh::nasl_ssh_get_host_key, "ssh_get_host_key"), + (Ssh::nasl_sftp_enabled_check, "sftp_enabled_check"), + (Ssh::nasl_ssh_execute_netconf_subsystem, "ssh_execute_netconf_subsystem"), + ) +} + +#[cfg(not(feature = "nasl-builtin-libssh"))] +function_set! { + Ssh, + ( + (Ssh::nasl_ssh_connect, "ssh_connect"), + (Ssh::nasl_ssh_request_exec, "ssh_request_exec"), + (Ssh::nasl_ssh_userauth, "ssh_userauth"), + (Ssh::nasl_ssh_disconnect, "ssh_disconnect"), + ) } impl Ssh { diff --git a/rust/src/nasl/builtin/string/mod.rs b/rust/src/nasl/builtin/string/mod.rs index 957fc8e38..d0384e6f2 100644 --- a/rust/src/nasl/builtin/string/mod.rs +++ b/rust/src/nasl/builtin/string/mod.rs @@ -117,6 +117,12 @@ fn write_nasl_string(s: &mut String, value: &NaslValue) -> Result<(), StringErro /// NASL function to parse values into string representations #[nasl_function] fn string(positional: CheckedPositionals<&NaslValue>) -> Result { + combine_positionals_to_string(positional) +} + +fn combine_positionals_to_string( + positional: CheckedPositionals<&NaslValue>, +) -> Result { let mut s = String::with_capacity(2 * positional.len()); for p in positional { write_nasl_string_value(&mut s, p)?; @@ -290,8 +296,9 @@ fn stridx(haystack: NaslValue, needle: NaslValue, offset: Option) -> i64 /// NASL function to display any number of NASL values /// /// Internally the string function is used to concatenate the given parameters -fn display(register: &Register, configs: &Context) -> Result { - println!("{}", &string(register, configs)?); +#[nasl_function] +fn display(positional: CheckedPositionals<&NaslValue>) -> Result { + println!("{}", &combine_positionals_to_string(positional)?); Ok(NaslValue::Null) } @@ -480,7 +487,6 @@ pub struct NaslString; function_set! { NaslString, - sync_stateless, ( hexstr, hex, diff --git a/rust/src/nasl/builtin/sys/mod.rs b/rust/src/nasl/builtin/sys/mod.rs index d9b2b5f4d..24edbfcc7 100644 --- a/rust/src/nasl/builtin/sys/mod.rs +++ b/rust/src/nasl/builtin/sys/mod.rs @@ -114,7 +114,6 @@ async fn get_tmp_dir() -> PathBuf { function_set! { Sys, - async_stateless, ( pread, fread, diff --git a/rust/src/nasl/builtin/tests.rs b/rust/src/nasl/builtin/tests.rs index 9cf53a3ba..b691dd56c 100644 --- a/rust/src/nasl/builtin/tests.rs +++ b/rust/src/nasl/builtin/tests.rs @@ -24,7 +24,6 @@ struct Foo; function_set! { Foo, - sync_stateless, (foo1, foo2, add_positionals) } @@ -44,3 +43,60 @@ fn variadic_positionals_start_at_correct_index() { let mut t = TestBuilder::default().with_executor(Executor::single(Foo)); t.ok("add_positionals(1, 2, 3, 4);", 7); } + +struct Bar; + +impl Bar { + #[nasl_function] + fn sync_stateful_ref(&self) -> usize { + 1 + } + + #[nasl_function] + fn sync_stateful_mut(&mut self) -> usize { + 2 + } + + #[nasl_function] + async fn async_stateful_ref(&self) -> usize { + 3 + } + + #[nasl_function] + async fn async_stateful_mut(&mut self) -> usize { + 4 + } +} + +#[nasl_function] +async fn sync_stateless() -> usize { + 5 +} + +#[nasl_function] +async fn async_stateless() -> usize { + 6 +} + +function_set! { + Bar, + ( + (Bar::sync_stateful_ref, "sync_stateful_ref"), + (Bar::sync_stateful_mut, "sync_stateful_mut"), + (Bar::async_stateful_ref, "async_stateful_ref"), + (Bar::async_stateful_mut, "async_stateful_mut"), + sync_stateless, + async_stateless, + ) +} + +#[test] +fn functions_added_properly() { + let mut t = TestBuilder::default().with_executor(Executor::single(Bar)); + t.ok("sync_stateful_ref();", 1); + t.ok("sync_stateful_mut();", 2); + t.ok("async_stateful_ref();", 3); + t.ok("async_stateful_mut();", 4); + t.ok("sync_stateless();", 5); + t.ok("async_stateless();", 6); +} diff --git a/rust/src/nasl/interpreter/tests/retry.rs b/rust/src/nasl/interpreter/tests/retry.rs index d850f03ff..6e64c6ad4 100644 --- a/rust/src/nasl/interpreter/tests/retry.rs +++ b/rust/src/nasl/interpreter/tests/retry.rs @@ -31,7 +31,6 @@ impl Counter { function_set! { Counter, - sync_stateful_mut, ( (Counter::check_counter_retry, "check_counter_retry"), (Counter::check_counter, "check_counter"), diff --git a/rust/src/nasl/utils/executor/mod.rs b/rust/src/nasl/utils/executor/mod.rs index 4d07b5a36..772abd521 100644 --- a/rust/src/nasl/utils/executor/mod.rs +++ b/rust/src/nasl/utils/executor/mod.rs @@ -8,6 +8,8 @@ //! the functions take two arguments (`Context` and `Register`), which makes them stateless, //! or three arguments (some `State`, `Context` and `Register`), which makes them stateful. //! Typically, stateful functions are implemented as methods on the state struct. +//! Stateful functions come in two flavors that differ in whether they take `&mut State` or +//! `&State` as the first argument. //! //! In order to create new sets of NASL functions, the `function_set!` macro is provided. mod nasl_function; @@ -15,7 +17,8 @@ mod nasl_function; use std::collections::HashMap; use async_trait::async_trait; -use nasl_function::{AsyncDoubleArgFn, AsyncTripleArgFn, NaslFunction}; +pub use nasl_function::NaslFunction; +use nasl_function::{AsyncDoubleArgFn, AsyncTripleArgFn}; use tokio::sync::RwLock; use crate::nasl::prelude::*; @@ -137,6 +140,10 @@ impl StoredFunctionSet { .insert(k.to_string(), NaslFunction::SyncStateless(v)); } + pub fn add_nasl_function(&mut self, k: &str, f: NaslFunction) { + self.fns.insert(k.to_string(), f); + } + /// Add a set of functions to this set. This is useful in order /// to combine multiple smaller sets into one large set which can /// then be exported. @@ -228,18 +235,18 @@ pub trait IntoFunctionSet { #[macro_export] macro_rules! internal_call_expr { - ($method_name: ident, $set_name: ident $(,)?) => { + ($set_name: ident $(,)?) => { }; - ($method_name: ident, $set_name: ident, ($fn_name: path, $name: literal) $(, $($tt: tt)*)?) => { - $set_name.$method_name($name, $fn_name); + ($set_name: ident, ($fn_name: path, $name: literal) $(, $($tt: tt)*)?) => { + $fn_name(&mut $set_name, $name); $( - $crate::internal_call_expr!($method_name, $set_name, $($tt)*); + $crate::internal_call_expr!($set_name, $($tt)*); )? }; - ($method_name: ident, $set_name: ident, $fn_name: path $(, $($tt: tt)*)?) => { - $set_name.$method_name(stringify!($fn_name), $fn_name); + ($set_name: ident, $fn_name: path $(, $($tt: tt)*)?) => { + $fn_name(&mut $set_name, stringify!($fn_name)); $( - $crate::internal_call_expr!($method_name, $set_name, $($tt)*); + $crate::internal_call_expr!($set_name, $($tt)*); )? }; } @@ -261,7 +268,6 @@ macro_rules! internal_call_expr { /// /// function_set! { /// Foo, -/// sync_stateless, /// ( /// foo, /// bar, @@ -271,25 +277,16 @@ macro_rules! internal_call_expr { /// /// This will implement `IntoFunctionSet` for `Foo`, so that it can be /// used within the executor. -/// -/// Depending on the asyncness and statefulness of the NASL functions -/// that one wants to add, the second argument should be one of the following -/// four: -/// -/// 1. `async_stateful` (for `async fn(&S, &Register, &Context)`) -/// 2. `sync_stateful` (for `fn(&S, &Register, &Context)`) -/// 3. `async_stateless` (for `async fn(&Register, &Context)`) -/// 4. `sync_stateless` (for `fn(&Register, &Context)`) #[macro_export] macro_rules! function_set { - ($ty: ty, $method_name: ident, ($($tt: tt)*)) => { + ($ty: ty, ($($tt: tt)*)) => { impl $crate::nasl::utils::IntoFunctionSet for $ty { type State = $ty; #[allow(unused_mut)] fn into_function_set(self) -> $crate::nasl::utils::StoredFunctionSet { let mut set = $crate::nasl::utils::StoredFunctionSet::new(self); - $crate::internal_call_expr!($method_name, set, $($tt)*); + $crate::internal_call_expr!(set, $($tt)*); set } } diff --git a/rust/src/nasl/utils/executor/nasl_function.rs b/rust/src/nasl/utils/executor/nasl_function.rs index 29c758209..084fe9860 100644 --- a/rust/src/nasl/utils/executor/nasl_function.rs +++ b/rust/src/nasl/utils/executor/nasl_function.rs @@ -135,7 +135,7 @@ where } } -/// Represents one of the four types of NaslFunctions. +/// Represents one of the six types of NaslFunctions. /// This type exists in order to make it possible to /// store a collection of different NASL functions inside /// a single function set. diff --git a/rust/src/nasl/utils/mod.rs b/rust/src/nasl/utils/mod.rs index 544cc4e77..d84070a1e 100644 --- a/rust/src/nasl/utils/mod.rs +++ b/rust/src/nasl/utils/mod.rs @@ -17,7 +17,7 @@ pub use error::ArgumentError; pub use error::FnError; pub use error::InternalError; -pub use executor::{Executor, IntoFunctionSet, StoredFunctionSet}; +pub use executor::{Executor, IntoFunctionSet, NaslFunction, StoredFunctionSet}; /// The result of a function call. pub type NaslResult = Result;