1#[cfg(feature = "client")]
4use std::io::SeekFrom;
5
6#[cfg(feature = "client")]
7use binrw::io::TakeSeekExt;
8use binrw::prelude::*;
9use modular_bitfield::prelude::*;
10use smb_msg_derive::*;
11
12use super::FileId;
13use smb_dtyp::binrw_util::prelude::*;
14use smb_fscc::*;
15
16#[smb_request(size = 32)]
22pub struct ChangeNotifyRequest {
23 pub flags: NotifyFlags,
25 pub output_buffer_length: u32,
27 pub file_id: FileId,
29 pub completion_filter: NotifyFilter,
31 reserved: u32,
32}
33
34#[smb_dtyp::mbitfield]
38pub struct NotifyFlags {
39 pub watch_tree: bool,
42 #[skip]
43 __: B15,
44}
45
46#[smb_dtyp::mbitfield]
52pub struct NotifyFilter {
53 pub file_name: bool,
55 pub dir_name: bool,
57 pub attributes: bool,
59 pub size: bool,
61
62 pub last_write: bool,
64 pub last_access: bool,
66 pub creation: bool,
68 pub ea: bool,
70
71 pub security: bool,
73 pub stream_name: bool,
75 pub stream_size: bool,
77 pub stream_write: bool,
79
80 #[skip]
81 __: B20,
82}
83
84impl NotifyFilter {
85 pub fn all() -> Self {
86 Self::new()
87 .with_file_name(true)
88 .with_dir_name(true)
89 .with_attributes(true)
90 .with_size(true)
91 .with_last_write(true)
92 .with_last_access(true)
93 .with_creation(true)
94 .with_ea(true)
95 .with_security(true)
96 .with_stream_name(true)
97 .with_stream_size(true)
98 .with_stream_write(true)
99 }
100}
101
102#[smb_response(size = 9)]
108pub struct ChangeNotifyResponse {
109 #[bw(calc = PosMarker::default())]
111 #[br(temp)]
112 _output_buffer_offset: PosMarker<u16>,
113 #[bw(calc = PosMarker::default())]
115 #[br(temp)]
116 _output_buffer_length: PosMarker<u32>,
117 #[br(seek_before = SeekFrom::Start(_output_buffer_offset.value.into()))]
119 #[br(map_stream = |s| s.take_seek(_output_buffer_length.value.into()))]
120 #[bw(if(!buffer.is_empty()))]
121 #[bw(write_with = PosMarker::write_aoff_size, args(&_output_buffer_offset, &_output_buffer_length))]
122 pub buffer: ChainedItemList<FileNotifyInformation, 4>,
123}
124
125#[smb_response_binrw]
130pub struct ServerToClientNotification {
131 structure_size: u16,
133 reserved: u16,
134 #[bw(calc = notification.get_type())]
136 notification_type: NotificationType,
137 #[br(args(notification_type))]
139 pub notification: Notification,
140}
141
142#[smb_response_binrw]
146#[derive(Clone, Copy)]
147#[brw(repr(u32))]
148pub enum NotificationType {
149 NotifySessionClosed = 0,
151}
152
153#[smb_response_binrw]
158#[br(import(notification_type: NotificationType))]
159pub enum Notification {
160 #[br(pre_assert(notification_type == NotificationType::NotifySessionClosed))]
162 NotifySessionClosed(NotifySessionClosed),
163}
164
165impl Notification {
166 pub fn get_type(&self) -> NotificationType {
167 match self {
168 Notification::NotifySessionClosed(_) => NotificationType::NotifySessionClosed,
169 }
170 }
171}
172
173#[smb_response_binrw]
179pub struct NotifySessionClosed {
180 reserved: u32,
181}
182
183#[cfg(test)]
184mod tests {
185 use crate::*;
186 use smb_dtyp::guid::Guid;
187
188 use super::*;
189
190 test_binrw_request! {
191 struct ChangeNotifyRequest {
192 flags: NotifyFlags::new(),
193 output_buffer_length: 2048,
194 file_id: "000005d1-000c-0000-1900-00000c000000"
195 .parse::<Guid>()
196 .unwrap()
197 .into(),
198 completion_filter: NotifyFilter::new()
199 .with_file_name(true)
200 .with_dir_name(true)
201 .with_attributes(true)
202 .with_last_write(true),
203 } => "2000000000080000d10500000c000000190000000c0000001700000000000000"
204 }
205
206 test_binrw_response! {
207 struct ChangeNotifyResponse => pending {
208 buffer: Default::default(),
209 } => "0900000000000000"
210 }
211
212 test_response! {
213 change_notify_with_data: ChangeNotify {
214 buffer: vec![
215 FileNotifyInformation {
216 action: NotifyAction::RenamedOldName,
217 file_name: "New folder".into()
218 },
219 FileNotifyInformation {
220 action: NotifyAction::RenamedNewName,
221 file_name: "jdsa".into()
222 }
223 ]
224 .into()
225 } => "09004800340000002000000004000000140000004e0065007700200066006f006c006400650072000000000005000000080000006a00640073006100"
226 }
227
228 test_response_read! {
229 change_notify_azure: ChangeNotify {
230 buffer: vec![
231 FileNotifyInformation {
232 action: NotifyAction::Added,
233 file_name: "11.txt".into()
234 },
235 FileNotifyInformation {
236 action: NotifyAction::Added,
237 file_name: "kernel.bin.til".into()
238 },
239 FileNotifyInformation {
240 action: NotifyAction::Added,
241 file_name: "ec2-3-70-222-69.eu-central-1.compute.amazonaws.com.rdp".into()
242 },
243 FileNotifyInformation {
244 action: NotifyAction::Added,
245 file_name: "ec2-18-198-51-98.eu-central-1.compute.amazonaws.com.rdp".into()
246 },
247 FileNotifyInformation {
248 action: NotifyAction::Added,
249 file_name: "Test DC.rdp".into()
250 }
251 ]
252 .into()
253 } => "090048006001000018000000010000000c000000310031002e0074007800740028000000010000001c0000006b00650072006e0065006c002e00620069006e002e00740069006c0078000000010000006c0000006500630032002d0033002d00370030002d003200320032002d00360039002e00650075002d00630065006e007400720061006c002d0031002e0063006f006d0070007500740065002e0061006d0061007a006f006e006100770073002e0063006f006d002e0072006400700080000000010000006e0000006500630032002d00310038002d003100390038002d00350031002d00390038002e00650075002d00630065006e007400720061006c002d0031002e0063006f006d0070007500740065002e0061006d0061007a006f006e006100770073002e0063006f006d002e007200640070006f557361676500000000010000001600000054006500730074002000440043002e00720064007000726e65744567"
254 }
255}