use crate::ndr::NdrEncoder;
use crate::transport::SmbPipe;
use crate::{Result, Syntax};
use smb2_client::SmbClient;
pub fn fsrvp_syntax() -> Syntax {
Syntax::new("a8e0653c-2744-4389-a61d-7373df8b2292", 1, 0)
}
pub const OPNUM_IS_PATH_SUPPORTED: u16 = 8;
pub fn encode_is_path_supported(share_name: &str) -> Vec<u8> {
let mut e = NdrEncoder::new();
e.referent();
e.conformant_varying_wstr(share_name);
e.into_bytes()
}
pub struct CoerceClient<'a> {
pipe: SmbPipe<'a>,
}
impl<'a> CoerceClient<'a> {
pub async fn bind_sealed(
client: &'a mut SmbClient,
file_id: [u8; 16],
domain: &str,
user: &str,
password: &str,
host: &str,
) -> Result<Self> {
let mut pipe = SmbPipe::new(client, file_id);
pipe.bind_sealed(fsrvp_syntax(), domain, user, password, host)
.await?;
Ok(CoerceClient { pipe })
}
pub async fn coerce(&mut self, listener: &str) -> Result<u32> {
let share = format!("\\\\{listener}\\share\\");
let resp = self
.pipe
.call_sealed(OPNUM_IS_PATH_SUPPORTED, &encode_is_path_supported(&share))
.await?;
let status = resp
.len()
.checked_sub(4)
.and_then(|o| resp.get(o..o + 4))
.map(|b| u32::from_le_bytes(b.try_into().unwrap()))
.unwrap_or(0);
Ok(status)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_path_supported_marshals_referent_and_string() {
let stub = encode_is_path_supported("\\\\10.0.0.1\\share\\");
assert_ne!(u32::from_le_bytes(stub[0..4].try_into().unwrap()), 0);
let max = u32::from_le_bytes(stub[4..8].try_into().unwrap());
let actual = u32::from_le_bytes(stub[12..16].try_into().unwrap());
assert_eq!(max, actual);
assert!(actual > 0);
}
}