Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,14 @@ jobs:

- name: clippy
run: cargo clippy --workspace --features server -- -D warnings

fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- name: rustfmt
run: cargo fmt --all --check
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
**/.vscode/
IMPLEMENTATION_PLAN.md
AUDIT.md
.claude/
52 changes: 37 additions & 15 deletions smb-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub struct SMBParseError {
impl<T: Into<Box<dyn Error + Send + Sync>>> From<T> for SMBParseError {
fn from(value: T) -> Self {
Self {
error: value.into()
error: value.into(),
}
}
}
Expand All @@ -72,12 +72,11 @@ pub struct SMBCryptoError {
impl<T: Into<Box<dyn Error + Send + Sync>>> From<T> for SMBCryptoError {
fn from(value: T) -> Self {
Self {
message: value.into()
message: value.into(),
}
}
}


impl Display for SMBCryptoError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Crypto operation failed with error: {}", self.message)
Expand All @@ -92,14 +91,18 @@ pub struct SMBPreconditionFailedError {
impl<T: Into<String>> From<T> for SMBPreconditionFailedError {
fn from(value: T) -> Self {
Self {
message: value.into()
message: value.into(),
}
}
}

impl Display for SMBPreconditionFailedError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Operation failed with unmet precondition: {}", self.message)
write!(
f,
"Operation failed with unmet precondition: {}",
self.message
)
}
}

Expand All @@ -111,7 +114,7 @@ pub struct SMBIOError {
impl<T: Into<io::Error>> From<T> for SMBIOError {
fn from(value: T) -> Self {
Self {
error: value.into()
error: value.into(),
}
}
}
Expand All @@ -136,7 +139,7 @@ impl SMBResponseError {
impl<T: Into<NTStatus>> From<T> for SMBResponseError {
fn from(value: T) -> Self {
Self {
status: value.into()
status: value.into(),
}
}
}
Expand Down Expand Up @@ -164,7 +167,11 @@ impl<T: Into<usize>, U: Into<usize>> From<(T, U)> for SMBPayloadTooSmallError {

impl Display for SMBPayloadTooSmallError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Expected {} bytes, was actually {} bytes", self.expected, self.actual)
write!(
f,
"Expected {} bytes, was actually {} bytes",
self.expected, self.actual
)
}
}

Expand All @@ -176,7 +183,7 @@ pub struct SMBServerError {
impl<T: Into<Box<dyn Error + Send + Sync>>> From<T> for SMBServerError {
fn from(value: T) -> Self {
Self {
error: value.into()
error: value.into(),
}
}
}
Expand All @@ -196,7 +203,7 @@ impl Display for SMBError {
Self::IOError(x) => write!(f, "{}", x),
Self::ResponseError(x) => write!(f, "{}", x),
Self::PayloadTooSmall(x) => write!(f, "{}", x),
Self::ServerError(x) => write!(f, "{}", x)
Self::ServerError(x) => write!(f, "{}", x),
}
}
}
Expand All @@ -211,22 +218,34 @@ mod tests {
fn server_error_display_says_server() {
let err = SMBError::server_error("something broke");
let msg = format!("{}", err);
assert!(msg.contains("Server operation failed"), "ServerError Display should say 'Server operation failed', got: {}", msg);
assert!(
msg.contains("Server operation failed"),
"ServerError Display should say 'Server operation failed', got: {}",
msg
);
assert!(msg.contains("something broke"));
}

#[test]
fn parse_error_display_says_parse() {
let err = SMBError::parse_error("bad bytes");
let msg = format!("{}", err);
assert!(msg.contains("Parse failed"), "ParseError Display should say 'Parse failed', got: {}", msg);
assert!(
msg.contains("Parse failed"),
"ParseError Display should say 'Parse failed', got: {}",
msg
);
}

#[test]
fn crypto_error_display_says_crypto() {
let err = SMBError::crypto_error("bad key");
let msg = format!("{}", err);
assert!(msg.contains("Crypto operation failed"), "CryptoError Display should say 'Crypto operation failed', got: {}", msg);
assert!(
msg.contains("Crypto operation failed"),
"CryptoError Display should say 'Crypto operation failed', got: {}",
msg
);
}

#[test]
Expand All @@ -241,6 +260,9 @@ mod tests {
fn response_error_display() {
let err = SMBError::response_error(NTStatus::AccessDenied);
let msg = format!("{}", err);
assert!(msg.contains("AccessDenied"), "should mention the NTStatus variant");
assert!(
msg.contains("AccessDenied"),
"should mention the NTStatus variant"
);
}
}
}
69 changes: 54 additions & 15 deletions smb-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ pub trait SMBByteSize {
}

pub trait SMBFromBytes: SMBByteSize {
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self> where Self: Sized;
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self>
where
Self: Sized;
}

pub trait SMBToBytes: SMBByteSize {
Expand All @@ -44,7 +46,10 @@ impl<T: SMBByteSize> SMBVecByteSize for Vec<T> {
}

impl<T: SMBFromBytes> SMBFromBytes for PhantomData<T> {
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self> where Self: Sized {
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self>
where
Self: Sized,
{
let (remaining, _) = T::smb_from_bytes(input)?;
Ok((remaining, PhantomData))
}
Expand All @@ -63,10 +68,17 @@ impl<T> SMBByteSize for PhantomData<T> {
}

impl SMBVecFromBytesCnt for String {
fn smb_from_bytes_vec_cnt(input: &[u8], align: usize, count: usize) -> SMBParseResult<&[u8], Self> where Self: Sized {
fn smb_from_bytes_vec_cnt(
input: &[u8],
align: usize,
count: usize,
) -> SMBParseResult<&[u8], Self>
where
Self: Sized,
{
let (remaining, vec) = <Vec<u8>>::smb_from_bytes_vec_cnt(input, align, count)?;
let str = String::from_utf8(vec)
.map_err(|_e| SMBError::parse_error("Invalid byte slice"))?;
let str =
String::from_utf8(vec).map_err(|_e| SMBError::parse_error("Invalid byte slice"))?;
Ok((remaining, str))
}
}
Expand All @@ -78,19 +90,40 @@ impl SMBVecByteSize for String {
}

pub trait SMBVecFromBytesCnt {
fn smb_from_bytes_vec_cnt(input: &[u8], align: usize, count: usize) -> SMBParseResult<&[u8], Self> where Self: Sized;
fn smb_from_bytes_vec_cnt(
input: &[u8],
align: usize,
count: usize,
) -> SMBParseResult<&[u8], Self>
where
Self: Sized;
}

pub trait SMBVecFromBytesLen {
fn smb_from_bytes_vec_len(input: &[u8], align: usize, len: usize) -> SMBParseResult<&[u8], Self> where Self: Sized;
fn smb_from_bytes_vec_len(
input: &[u8],
align: usize,
len: usize,
) -> SMBParseResult<&[u8], Self>
where
Self: Sized;
}

pub trait SMBEnumFromBytes {
fn smb_enum_from_bytes(input: &[u8], discriminator: u64) -> SMBParseResult<&[u8], Self> where Self: Sized;
fn smb_enum_from_bytes(input: &[u8], discriminator: u64) -> SMBParseResult<&[u8], Self>
where
Self: Sized;
}

impl<T: SMBFromBytes> SMBVecFromBytesCnt for Vec<T> {
fn smb_from_bytes_vec_cnt(input: &[u8], align: usize, count: usize) -> SMBParseResult<&[u8], Self> where Self: Sized {
fn smb_from_bytes_vec_cnt(
input: &[u8],
align: usize,
count: usize,
) -> SMBParseResult<&[u8], Self>
where
Self: Sized,
{
let mut remaining = input;
let mut done_cnt = 0;
let mut msg_vec = Vec::<T>::new();
Expand All @@ -115,7 +148,10 @@ impl<T: SMBFromBytes> SMBVecFromBytesCnt for Vec<T> {
}

impl<T: SMBFromBytes> SMBVecFromBytesLen for Vec<T> {
fn smb_from_bytes_vec_len(input: &[u8], align: usize, len: usize) -> SMBParseResult<&[u8], Self> where Self: Sized {
fn smb_from_bytes_vec_len(input: &[u8], align: usize, len: usize) -> SMBParseResult<&[u8], Self>
where
Self: Sized,
{
let mut remaining = input;
let mut msg_vec = Vec::<T>::new();
let mut pos = 0;
Expand All @@ -124,7 +160,7 @@ impl<T: SMBFromBytes> SMBVecFromBytesLen for Vec<T> {
remaining = &remaining[extra..];
let (_, val) = T::smb_from_bytes(remaining)?;
let size = T::smb_byte_size(&val);
pos += size;
pos += size;
extra = if align > 0 && !pos.is_multiple_of(align) {
align - (pos % align)
} else {
Expand All @@ -139,9 +175,12 @@ impl<T: SMBFromBytes> SMBVecFromBytesLen for Vec<T> {
}

impl SMBFromBytes for Uuid {
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self> where Self: Sized {
fn smb_from_bytes(input: &[u8]) -> SMBParseResult<&[u8], Self>
where
Self: Sized,
{
if 16 > input.len() {
return Err(SMBError::payload_too_small(16usize, input.len()))
return Err(SMBError::payload_too_small(16usize, input.len()));
}
let uuid = Uuid::from_slice(&input[0..16])
.map_err(|_e| SMBError::parse_error("Invalid byte slice"))?;
Expand Down Expand Up @@ -170,7 +209,7 @@ macro_rules! impl_parse_fixed_slice {
let res = <[u8; $size]>::try_from(&$input[0..$size])
.map_err(|_e| SMBError::parse_error("Invalid byte slice"))?;
Ok((&$input[$size..], res))
}}
}};
}

macro_rules! impl_smb_byte_size_for_slice {(
Expand Down Expand Up @@ -278,4 +317,4 @@ impl_smb_from_bytes_unsigned_type! {

impl_smb_to_bytes_unsigned_type! {
u8 u16 u32 u64 u128
}
}
36 changes: 26 additions & 10 deletions smb-core/src/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,71 @@
/// macros from the `tracing` crate. When disabled, they compile to no-ops.

#[cfg(feature = "tracing")]
pub use tracing::{trace, debug, info, warn, error, info_span, debug_span, trace_span};
pub use tracing::{debug, debug_span, error, info, info_span, trace, trace_span, warn};

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! trace {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! debug {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! info {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! warn {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! error {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! info_span {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! debug_span {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
#[macro_export]
macro_rules! trace_span {
($($t:tt)*) => {()};
($($t:tt)*) => {
()
};
}

#[cfg(not(feature = "tracing"))]
pub use crate::{trace, debug, info, warn, error, info_span, debug_span, trace_span};
pub use crate::{debug, debug_span, error, info, info_span, trace, trace_span, warn};
Loading
Loading