smb_server_proto_smb1/
create.rs1use smb_server_proto::buf::Reader;
4
5use crate::session_setup::BodyError;
6
7impl From<smb_server_proto::error::ProtoError> for BodyError {
8 fn from(_: smb_server_proto::error::ProtoError) -> Self {
9 BodyError::TooShort
10 }
11}
12
13#[derive(Debug)]
15pub struct NtCreateReq {
16 pub name_len: usize,
18 pub root_fid: u32,
20 pub desired_access: u32,
22 pub ext_attrs: u32,
24 pub disposition: u32,
26 pub create_options: u32,
28 pub name: String,
30}
31
32fn u16le(w: &[u8], off: usize) -> u16 {
33 w.get(off..off + 2)
34 .map(|s| u16::from_le_bytes(s.try_into().unwrap()))
35 .unwrap_or(0)
36}
37
38fn u32le(w: &[u8], off: usize) -> u32 {
39 w.get(off..off + 4)
40 .map(|s| u32::from_le_bytes(s.try_into().unwrap()))
41 .unwrap_or(0)
42}
43
44impl NtCreateReq {
45 pub fn parse(
49 words: &[u8],
50 data: &[u8],
51 unicode: bool,
52 bc_off_abs: usize,
53 ) -> Result<Self, BodyError> {
54 use super::session_setup::BodyError;
55 if words.len() < 48 || data.is_empty() {
56 return Err(BodyError::TooShort);
57 }
58 let name_len = u16le(words, 5) as usize;
59 let root_fid = u32le(words, 11);
60 let desired_access = u32le(words, 15);
61 let ext_attrs = u32le(words, 27);
62 let disposition = u32le(words, 35);
63 let create_options = u32le(words, 39);
64
65 let mut start = 0;
67 if !bc_off_abs.is_multiple_of(2) && !data.is_empty() {
68 start = 1;
69 }
70 let mut rd = Reader::new(data, start);
71 let raw_len = name_len.min(data.len().saturating_sub(start));
72 let raw = rd.take(raw_len)?.to_vec();
73 let name = decode_name(&raw, unicode);
74
75 Ok(NtCreateReq {
76 name_len,
77 root_fid,
78 desired_access,
79 ext_attrs,
80 disposition,
81 create_options,
82 name,
83 })
84 }
85}
86
87fn decode_name(raw: &[u8], unicode: bool) -> String {
89 if unicode {
90 let units: Vec<u16> = raw
91 .chunks_exact(2)
92 .map(|c| c[0] as u16 | ((c[1] as u16) << 8))
93 .take_while(|&u| u != 0)
94 .collect();
95 String::from_utf16_lossy(&units)
96 } else {
97 String::from_utf8_lossy(raw.split(|&b| b == 0).next().unwrap_or(&[])).into_owned()
98 }
99}
100
101#[allow(clippy::too_many_arguments)]
104pub fn build_response(
105 fid: u16,
106 action: u32,
107 times: [smb_server_proto::types::FileTime; 4],
108 attrs: u32,
109 alloc: u64,
110 eof: u64,
111 is_dir: bool,
112) -> Vec<u8> {
113 let mut params = Vec::with_capacity(68);
114 params.push(0xFF); params.push(0);
116 params.extend_from_slice(&0u16.to_le_bytes());
117 params.push(0); params.extend_from_slice(&fid.to_le_bytes());
119 params.extend_from_slice(&action.to_le_bytes());
120 for t in × {
121 params.extend_from_slice(&t.0.to_le_bytes());
122 }
123 params.extend_from_slice(&attrs.to_le_bytes());
124 params.extend_from_slice(&alloc.to_le_bytes());
125 params.extend_from_slice(&eof.to_le_bytes());
126 params.extend_from_slice(&0u16.to_le_bytes()); params.extend_from_slice(&0u16.to_le_bytes()); params.push(if is_dir { 1 } else { 0 }); params
130}
131
132pub fn map_create_err(e: &std::io::Error) -> smb_server_proto::types::Status {
134 use smb_server_proto::types::Status;
135 match e.kind() {
136 std::io::ErrorKind::NotFound => Status::OBJECT_NAME_NOT_FOUND,
137 std::io::ErrorKind::PermissionDenied => Status::ACCESS_DENIED,
138 std::io::ErrorKind::AlreadyExists => Status::OBJECT_NAME_COLLISION,
139 _ => Status::UNSUCCESSFUL,
140 }
141}