Skip to content

Commit 6483c0d

Browse files
authored
Merge pull request #42 from AvivNaaman/40-support-tree-connect-extensions
#40: Support tree connect extension
2 parents 80721f4 + 87a4769 commit 6483c0d

File tree

2 files changed

+197
-4
lines changed

2 files changed

+197
-4
lines changed

smb/src/packets/binrw_util/pos_marker.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ pub struct PosMarker<T> {
1212
}
1313

1414
impl<T> PosMarker<T> {
15+
/// Create a new PosMarker with the given value.
16+
pub fn new(value: T) -> Self {
17+
Self {
18+
pos: OnceCell::new(),
19+
value,
20+
}
21+
}
22+
23+
/// Returns a [SeekFrom] that seeks relative from the position of the PosMarker.
24+
pub fn seek_from(&self, start: u64) -> SeekFrom {
25+
SeekFrom::Start(self.pos.get().unwrap() + start)
26+
}
27+
1528
fn get_pos(&self) -> binrw::BinResult<u64> {
1629
let value = self.pos.get().ok_or(binrw::error::Error::Custom {
1730
pos: 0,
@@ -286,6 +299,22 @@ where
286299
(no_size, Some(write_offset_to), no_base, ()),
287300
)
288301
}
302+
/// Writer for value
303+
/// * fill absolute offset to offset location.
304+
#[binrw::writer(writer, endian)]
305+
pub fn write_aoff_m<U>(value: &U, write_offset_to: Option<&Self>) -> BinResult<()>
306+
where
307+
U: BinWrite<Args<'static> = ()>,
308+
{
309+
let no_size: Option<&PosMarker<T>> = None;
310+
let no_base: Option<&PosMarker<T>> = None;
311+
Self::write_hero(
312+
value,
313+
writer,
314+
endian,
315+
(no_size, write_offset_to, no_base, ()),
316+
)
317+
}
289318

290319
/// Writer for value
291320
/// * fill absolute offset to offset location.

smb/src/packets/smb2/tree_connect.rs

Lines changed: 168 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
use crate::packets::{
2+
binrw_util::prelude::*,
3+
security::{ClaimSecurityAttributeRelativeV1, ACL, SID},
4+
};
15
use binrw::prelude::*;
6+
use binrw::{io::TakeSeekExt, NullWideString};
27
use modular_bitfield::prelude::*;
38

4-
use crate::packets::binrw_util::prelude::*;
5-
69
#[bitfield]
710
#[derive(BinWrite, BinRead, Debug, Clone, Copy)]
811
#[bw(map = |&x| Self::into_bytes(x))]
@@ -14,6 +17,11 @@ pub struct TreeConnectRequestFlags {
1417
__: B13,
1518
}
1619

20+
/// Tree Connect Request
21+
///
22+
/// Supports both the base and extension variants.
23+
/// - On read, uses extension iff `flags.extension_present()` - parses just like the server intends.
24+
/// - On write, uses extension iff `tree_connect_contexts` is non-empty.
1725
#[binrw::binrw]
1826
#[derive(Debug)]
1927
pub struct TreeConnectRequest {
@@ -25,18 +33,174 @@ pub struct TreeConnectRequest {
2533
_path_offset: PosMarker<u16>,
2634
#[bw(try_calc = buffer.size().try_into())]
2735
path_length: u16,
28-
// TODO: Support extension
36+
37+
// -- Extension --
38+
#[br(if(flags.extension_present()))]
39+
#[bw(calc = if tree_connect_contexts.len() > 0 { Some(PosMarker::default())} else {None})]
40+
tree_connect_context_offset: Option<PosMarker<u32>>,
41+
#[br(if(flags.extension_present()))]
42+
#[bw(if(tree_connect_contexts.len() > 0))]
43+
#[bw(calc = if tree_connect_contexts.len() > 0 { Some(tree_connect_contexts.len().try_into().unwrap()) } else {None})]
44+
tree_connect_context_count: Option<u16>,
45+
#[br(if(flags.extension_present()))]
46+
#[bw(if(tree_connect_contexts.len() > 0))]
47+
#[bw(calc = Some([0u8; 10]))]
48+
_reserved: Option<[u8; 10]>,
49+
// -- Extension End --
50+
// ------------------------------------------------
51+
// -- Base --
2952
#[brw(little)]
3053
#[br(args(path_length as u64))]
31-
#[bw(write_with=PosMarker::write_aoff, args(&_path_offset))]
54+
#[bw(write_with = PosMarker::write_aoff, args(&_path_offset))]
3255
pub buffer: SizedWideString,
56+
57+
// -- Extension --
58+
#[br(if(flags.extension_present()))]
59+
#[br(seek_before = tree_connect_context_offset.unwrap().seek_relative(true))]
60+
#[br(count = tree_connect_context_count.unwrap())]
61+
#[bw(if(tree_connect_contexts.len() > 0))]
62+
#[bw(write_with = PosMarker::write_aoff_m, args(tree_connect_context_offset.as_ref()))]
63+
tree_connect_contexts: Vec<TreeConnectContext>,
64+
}
65+
66+
#[binrw::binrw]
67+
#[derive(Debug)]
68+
pub struct TreeConnectContext {
69+
/// MS-SMB2 2.2.9.2: Must be set to SMB2_REMOTED_IDENTITY_TREE_CONNECT_CONTEXT_ID = 1.
70+
#[bw(calc = 1)]
71+
#[br(assert(context_type == 1))]
72+
context_type: u16,
73+
data_length: u16,
74+
reserved: u32,
75+
data: RemotedIdentityTreeConnect,
3376
}
3477

78+
macro_rules! make_remoted_identity_connect{
79+
(
80+
$($field:ident: $value:ty),*
81+
) => {
82+
paste::paste! {
83+
84+
#[binrw::binrw]
85+
#[derive(Debug)]
86+
pub struct RemotedIdentityTreeConnect {
87+
// MS-SMB2 2.2.9.2.1: Must be set to 0x1.
88+
#[bw(calc = PosMarker::new(1))]
89+
#[br(assert(_ticket_type.value == 1))]
90+
_ticket_type: PosMarker<u16>,
91+
ticket_size: u16,
92+
93+
// Offsets
94+
$(
95+
#[bw(calc = PosMarker::default())]
96+
[<_$field _offset>]: PosMarker<u16>,
97+
)*
98+
99+
// Values
100+
$(
101+
#[br(seek_before = _ticket_type.seek_from([<_$field _offset>].value as u64))]
102+
#[bw(write_with = PosMarker::write_roff_b, args(&[<_$field _offset>], &_ticket_type))]
103+
$field: $value,
104+
)*
105+
}
106+
}
107+
}
108+
}
109+
110+
make_remoted_identity_connect! {
111+
user: SidAttrData,
112+
user_name: NullWideString,
113+
domain: NullWideString,
114+
groups: SidArrayData,
115+
restricted_groups: SidArrayData,
116+
privileges: PrivilegeArrayData,
117+
primary_group: SidArrayData,
118+
owner: BlobData<SID>,
119+
default_dacl: BlobData<ACL>,
120+
device_groups: SidArrayData,
121+
user_claims: BlobData<ClaimSecurityAttributeRelativeV1>,
122+
device_claims: BlobData<ClaimSecurityAttributeRelativeV1>
123+
}
124+
125+
#[binrw::binrw]
126+
#[derive(Debug, PartialEq, Eq)]
127+
pub struct BlobData<T>
128+
where
129+
T: BinRead + BinWrite,
130+
for<'a> <T as BinRead>::Args<'a>: Default,
131+
for<'b> <T as BinWrite>::Args<'b>: Default,
132+
{
133+
blob_size: PosMarker<u16>,
134+
#[br(map_stream = |s| s.take_seek(blob_size.value as u64))]
135+
pub blob_data: T,
136+
}
137+
138+
#[binrw::binrw]
139+
#[derive(Debug, PartialEq, Eq)]
140+
pub struct ArrayData<T>
141+
where
142+
T: BinRead + BinWrite + 'static,
143+
for<'a> <T as BinRead>::Args<'a>: Default + Clone,
144+
for<'b> <T as BinWrite>::Args<'b>: Default + Clone,
145+
{
146+
#[bw(try_calc = list.len().try_into())]
147+
lcount: u16,
148+
#[br(count = lcount)]
149+
pub list: Vec<T>,
150+
}
151+
152+
#[binrw::binrw]
153+
#[derive(Debug, PartialEq, Eq)]
154+
pub struct SidAttrData {
155+
pub sid_data: SID,
156+
pub attr: SidAttrSeGroup,
157+
}
158+
159+
type SidArrayData = ArrayData<SidAttrData>;
160+
161+
#[bitfield]
162+
#[derive(BinWrite, BinRead, Debug, Clone, Copy, PartialEq, Eq)]
163+
#[bw(map = |&x| Self::into_bytes(x))]
164+
pub struct SidAttrSeGroup {
165+
pub mandatory: bool,
166+
pub enabled_by_default: bool,
167+
pub group_enabled: bool,
168+
pub group_owner: bool,
169+
pub group_use_for_deny_only: bool,
170+
pub group_integrity: bool,
171+
pub group_integrity_enabled: bool,
172+
#[skip]
173+
__: B21,
174+
pub group_logon_id: B4,
175+
}
176+
177+
#[binrw::binrw]
178+
#[derive(Debug, PartialEq, Eq)]
179+
pub struct LuidAttrData {
180+
pub luid: u64,
181+
pub attr: LsaprLuidAttributes,
182+
}
183+
184+
/// [MS-LSAD 2.2.5.4](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lsad/03c834c0-f310-4e0c-832e-b6e7688364d1)
185+
#[bitfield]
186+
#[derive(BinWrite, BinRead, Debug, Clone, Copy, PartialEq, Eq)]
187+
pub struct LsaprLuidAttributes {
188+
pub default: bool,
189+
pub enabled: bool,
190+
#[skip]
191+
__: B30,
192+
}
193+
194+
type PrivilegeData = BlobData<LuidAttrData>;
195+
196+
type PrivilegeArrayData = ArrayData<PrivilegeData>;
197+
35198
impl TreeConnectRequest {
36199
pub fn new(name: &String) -> TreeConnectRequest {
37200
TreeConnectRequest {
38201
flags: TreeConnectRequestFlags::new(),
39202
buffer: name.clone().into(),
203+
tree_connect_contexts: vec![],
40204
}
41205
}
42206
}

0 commit comments

Comments
 (0)