1+ use crate :: packets:: {
2+ binrw_util:: prelude:: * ,
3+ security:: { ClaimSecurityAttributeRelativeV1 , ACL , SID } ,
4+ } ;
15use binrw:: prelude:: * ;
6+ use binrw:: { io:: TakeSeekExt , NullWideString } ;
27use 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 ) ]
1927pub 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+
35198impl 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