dcerpc 0.2.6

Pure-Rust DCE/RPC (MS-RPCE): hand-rolled NDR marshaling, PDUs, NTLMSSP sign+seal (packet privacy), TCP + SMB named-pipe transports, EPM, and SAMR/LSAT/DRSUAPI/SVCCTL/RRP/Netlogon/DCOM-WMI clients — no FFI
Documentation
//! A minimal DCE/RPC (MS-RPCE) stack in Rust.
//!
//! Layers, bottom-up:
//!   `ndr`       — NDR (Network Data Representation) transfer-syntax marshaling.
//!   `pdu`       — connection-oriented RPC PDUs (bind / bind_ack / request / response / fault).
//!   `transport` — ncacn_ip_tcp (RPC directly over TCP).
//!   `epm`       — endpoint mapper (ept_map): interface UUID → dynamic port.
//!   `samr`      — the SAMR interface (UUID/opnums/structs); rides a named-pipe transport.
//!
//! Interface UUIDs are parsed from their canonical strings via `windows_sddl::sid::Guid`,
//! whose byte layout already matches the DCE UUID on-wire encoding.

pub mod dcom;
pub mod dcom_wmi;
pub mod dfsnm;
#[deprecated(
    since = "0.2.1",
    note = "moved to standalone crate `ms-drsr`; will be removed in dcerpc 0.4.0"
)]
pub mod drsuapi;
pub mod efsr;
pub mod epm;
pub mod fsrvp;
pub mod icpr;
pub mod lsat;
pub mod ndr;
pub mod netlogon;
pub mod pdu;
pub mod rprn;
pub mod rrp;
pub mod samr;
pub mod srvsvc;
pub mod svcctl;
pub mod transport;
pub mod tsch;
pub mod wkssvc;

use windows_sddl::sid::Guid;

#[derive(Debug, thiserror::Error)]
pub enum RpcError {
    #[error("buffer underrun: need {need} at {pos}")]
    Underrun { need: usize, pos: usize },
    #[error("unexpected PDU type {0:#04x}")]
    UnexpectedPdu(u8),
    #[error("RPC fault, status {0:#010x}")]
    Fault(u32),
    #[error("bind rejected")]
    BindRejected,
    #[error("protocol: {0}")]
    Protocol(String),
    #[error(transparent)]
    Io(#[from] std::io::Error),
}

pub type Result<T> = std::result::Result<T, RpcError>;

/// NDR decode errors surface as RPC underruns, so `?` works across the boundary.
impl From<ms_ndr::NdrError> for RpcError {
    fn from(e: ms_ndr::NdrError) -> Self {
        match e {
            ms_ndr::NdrError::Underrun { need, pos } => RpcError::Underrun { need, pos },
        }
    }
}

/// A DCE/RPC abstract syntax: interface UUID + version.
#[derive(Clone, Copy, Debug)]
pub struct Syntax {
    pub uuid: [u8; 16],
    pub ver_major: u16,
    pub ver_minor: u16,
}

impl Syntax {
    /// Build from the canonical UUID string, e.g. "12345778-1234-abcd-ef00-0123456789ac".
    pub fn new(uuid: &str, ver_major: u16, ver_minor: u16) -> Self {
        Syntax {
            uuid: Guid::parse(uuid).expect("valid interface UUID").0,
            ver_major,
            ver_minor,
        }
    }
}

/// The NDR transfer syntax (v2.0) every bind offers.
pub fn ndr_transfer_syntax() -> Syntax {
    Syntax::new("8a885d04-1ceb-11c9-9fe8-08002b104860", 2, 0)
}