smb2_rs/
lib.rs

1mod negotiate;
2mod sessionsetup1;
3mod sessionsetup2;
4mod error;
5
6use std::io::Cursor;
7use std::str::{FromStr};
8
9use asn1_rs::nom::number::complete::{u32};
10use asn1_rs::{Enumerated, FromDer, Oid, OctetString, OidParseError, ToDer};
11use asn1_rs::nom::AsBytes;
12
13use anyhow::{anyhow, Result};
14use binrw::{BinRead, BinReaderExt, BinWrite};
15use serde::{Deserialize, Serialize, };
16use tokio::io::{AsyncReadExt, AsyncWriteExt};
17use tokio::net::TcpStream;
18use ntlmclient;
19use ntlmclient::{Flags, Message, TargetInfoType};
20use rasn::{AsnType, Decode, Encode};
21use crate::error::{SmbError, SmbResult};
22use crate::negotiate::{NegotiateProtoResponse, NegotiateProtoRequset};
23
24///This is a configuration item that tells smb2-rs the user name, password,
25/// and other information you gave.
26pub struct SmbOptions<'a> {
27    pub Host : &'a str,
28    pub Port : &'a str,
29    pub User:        &'a str,
30    pub Domain:      &'a str,
31    pub Workstation: &'a str,
32    pub Password:    &'a str,
33    pub timeout: u16,
34    sesionSetup1RespHeader: Header,
35    sessionSetup1RespSecProvider: Vec<u8>,
36
37
38}
39// This structure is used to store the join results.
40pub struct SmbInfo {
41    pub isAuthenticated: bool,
42    pub StatusCode: String
43}
44
45
46
47
48
49
50
51
52
53
54impl SmbOptions<'_> {
55    pub fn new() -> Self {
56        let s = SmbOptions {
57            Host: "",
58            Port: "",
59            User: "",
60            Domain: "",
61            Workstation: "",
62            Password: "",
63            timeout: 0,
64            sesionSetup1RespHeader: Header::new(),
65            sessionSetup1RespSecProvider: vec![],
66        };
67        s
68    }
69}
70
71
72
73
74
75
76///Core functions. All the logic is here.
77impl SmbOptions<'_> {
78    pub async fn Conn(&mut self) -> SmbResult<SmbInfo> {
79
80
81        let target = format!("{}:{}", self.Host, self.Port);
82        let t = tokio::time::Duration::from_secs(self.timeout as u64);
83
84        //connect to server
85        let mut stream = match tokio::time::timeout(t, TcpStream::connect(target.clone())).await {
86            Ok(r) => {
87                match r {
88                    Ok(r) => r,
89                    Err(e) => return Err(SmbError::from(anyhow!(e))),
90                }
91            },
92            Err(e) => return Err(SmbError::from(anyhow!(e))),
93
94        };
95        //send negotiate req1
96        NegotiateProtoRequset(&mut stream).await?;
97        //parse nego proto response
98        let negoprotoResp = NegotiateProtoResponse(&mut stream).await?;
99
100
101        //send session setup req1
102        self.SessionSetupRequset1(&mut stream, negoprotoResp).await?;
103
104
105        //parse session setup resp1
106        self.SessionSetUpResponse1(&mut stream).await?;
107
108        //send session setup req2
109        self.SessionSetupRequset2(&mut stream).await?;
110
111        //--------------------------------
112
113        //最后一个响应,只需要读取前68个字节,即4 + 64, 64字节即为header
114        //parse result
115        let mut buffer:Vec<u8> = vec![0;68];
116        let _ = stream.read_exact(&mut buffer).await?;
117        let mut cur = Cursor::new(buffer[4..].to_vec());
118
119        let f:Header = cur.read_le()?;
120        let login_result = u32::from_le_bytes(f.status.to_ne_bytes());
121
122        stream.shutdown().await?;
123
124        let r = SmbInfo{
125            isAuthenticated: IsAuthenticated(login_result),
126            StatusCode: format!("{:#010x}", login_result),
127        };
128
129
130        Ok(r)
131    }
132}
133
134
135
136
137
138
139
140
141
142const DIALECT_SMB_2_1: i32 = 0x0210;
143
144#[derive(BinRead, BinWrite, Debug)]
145#[derive(Serialize, Deserialize, Copy, Clone)]
146struct Header {
147    protocol_id: [u8; 4],
148    structure_size: u16,
149    credit_charge: u16,
150    status: u32,
151    command: u16,
152    credits: u16,
153    flags: u32,
154    next_command: u32,
155    message_id: u64,
156    reserved: u32,
157    tree_id: u32,
158    session_id: u64,
159    signature: [u8; 16],
160}
161
162#[derive(BinRead, BinWrite, Debug)]
163struct NegotiateReq  {
164    header: Header,
165    StructureSize:u16,
166    DialectCount:u16,
167    SecurityMode:u16,
168    Reserved:u16,
169    Capabilities: u32,
170    ClientGuid:[u8; 16],
171    ClientStartTime:u64,
172    Dialects:[u16;1],
173}
174
175
176
177#[derive(Copy, Clone)]
178enum  command {
179    CommandNegotiate = 0,
180    CommandSessionSetup = 1,
181    CommandLogoff = 2,
182    CommandTreeConnect = 3,
183    CommandTreeDisconnect = 4,
184    CommandCreate = 5,
185    CommandClose = 6,
186    CommandFlush = 7,
187    CommandRead = 8,
188    CommandWrite = 9,
189    CommandLock = 10,
190    CommandIOCtl = 11,
191    CommandCancel = 12,
192    CommandEcho = 13,
193    CommandQueryDirectory = 14,
194    CommandChangeNotify = 15,
195    CommandQueryInfo = 16,
196    CommandSetInfo = 17,
197    CommandOplockBreak = 18
198}
199
200#[derive(Copy, Clone)]
201enum SecMode {
202    SecurityModeSigningEnabled = 1,
203    SecurityModeSigningRequired = 2
204}
205
206#[derive(Copy, Clone)]
207enum NegotiateFlags {
208    FlgNegUnicode = 1 << 0 as u32,
209    FlgNegOEM = 1 << 1,
210    FlgNegRequestTarget = 1 << 2,
211    FlgNegReserved10 = 1 << 3,
212    FlgNegSign = 1 << 4,
213    FlgNegSeal = 1 << 5,
214    FlgNegDatagram = 1 << 6,
215    FlgNegLmKey = 1 << 7,
216    FlgNegReserved9 = 1 << 8,
217    FlgNegNtLm = 1 << 9,
218    FlgNegReserved8 = 1 << 10,
219    FlgNegAnonymous = 1 << 11,
220    FlgNegOEMDomainSupplied = 1 << 12,
221    FlgNegOEMWorkstationSupplied = 1 << 13,
222    FlgNegReserved7 = 1 << 14,
223    FlgNegAlwaysSign = 1 << 15,
224    FlgNegTargetTypeDomain = 1 << 16,
225    FlgNegTargetTypeServer = 1 << 17,
226    FlgNegReserved6 = 1 << 18,
227    FlgNegExtendedSessionSecurity = 1 << 19,
228    FlgNegIdentify = 1 << 20,
229    FlgNegReserved5 = 1 << 21,
230    FlgNegRequestNonNtSessionKey = 1 << 22,
231    FlgNegTargetInfo = 1 << 23,
232    FlgNegReserved4 = 1 << 24,
233    FlgNegVersion = 1 << 25,
234    FlgNegReserved3 = 1 << 26,
235    FlgNegReserved2 = 1 << 27,
236    FlgNegReserved1 = 1 << 28,
237    FlgNeg128 = 1 << 29,
238    FlgNegKeyExch = 1 << 30,
239    FlgNeg56 = 1 << 31,
240}
241enum TagEnum {
242    TypeEnum = 0x0a,
243    TypeBitStr = 0x03,
244    TypeOctStr = 0x04,
245    TypeSeq = 0x30,
246    TypeOid = 0x06,
247}
248
249enum NT_STATUS_Enum {
250    STATUS_SUCCESS = 0,
251    STATUS_LOGON_FAILURE = 3221225581
252
253}
254
255
256
257
258
259//wait.....
260struct AuthMsg {
261    header: [u8; 8],
262    _type: [u8; 4],
263    lmResp: Vec<u8>,
264    ntlmResp: Vec<u8>,
265    domain: String,
266    user: String,
267    workstation: String,
268    flags: u32,
269    lmRespLen: [u8; 2],
270    lmRespMaxLen: [u8; 2],
271    lmRespOffset: [u8; 4],
272
273
274
275
276}
277
278
279
280
281
282
283fn string_to_utf16_bytes(input: &str) -> Vec<u8> {
284    let utf16_encoded: Vec<u16> = input.encode_utf16().collect();
285    let mut utf16_bytes = Vec::new();
286    for &code_unit in &utf16_encoded {
287        utf16_bytes.push((code_unit & 0xFF) as u8);
288        utf16_bytes.push((code_unit >> 8) as u8);
289    }
290
291    utf16_bytes
292}
293
294
295//
296
297#[derive(Serialize, Deserialize, Debug)]
298struct negotiate_Header  {
299    signature:   [u8;8],
300    message_type: u32
301}
302#[derive(Serialize, Deserialize, Debug)]
303struct Negotiate  {
304    negotiate_header: negotiate_Header,
305    NegotiateFlags:          u32,
306    DomainNameLen   :        u16,
307    DomainNameMaxLen:        u16,
308    DomainNameBufferOffset:  u32,
309    WorkstationLen:          u16,
310    WorkstationMaxLen:       u16,
311    WorkstationBufferOffset: u32,
312    DomainName:              Vec<u8>,
313    Workstation :            Vec<u8>
314}
315
316
317#[derive(Serialize, Deserialize, Debug)]
318struct NegTokenInit  {
319    Oid: Box<[u8]>,
320    Data: Negotiate_init_data
321}
322
323
324#[derive(Serialize, Deserialize, Debug)]
325struct Negotiate_init_data {
326    MechTypes: Vec<u8>,
327    MechToken: Vec<u8>
328}
329
330
331#[derive(BinRead, BinWrite, Debug)]
332#[derive(Serialize, Deserialize)]
333struct SessionSetup1Req  {
334    Header: Header,
335    StructureSize    :    u16,
336    Flags           :     u8,
337    SecurityMode     :    u8,
338    Capabilities    :     u32,
339    Channel          :    u32,
340    SecurityBufferOffset :  u16,
341    SecurityBufferLength : u16,
342    PreviousSessionID  :  u64,
343}
344
345
346
347
348
349
350
351impl Header {
352    pub fn new() -> Header {
353        let protocol_smb2: [u8; 4] = [0xFE, 0x53, 0x4D, 0x42];
354        let arr: [u8; 16] = [0; 16];
355        let qq = Header {
356            protocol_id: protocol_smb2,
357            structure_size: 64,
358            credit_charge: 0,
359            status: 0,
360            command: 0,
361            credits: 0,
362            flags: 0,
363            next_command: 0,
364            message_id: 0,
365            reserved: 0,
366            tree_id: 0,
367            session_id: 0,
368            signature: arr,
369        };
370        qq
371    }
372}
373
374
375
376///Calling this function gets the result of whether the connection was successful and the response code.
377pub fn IsAuthenticated(code: u32) -> bool {
378    match code {
379        0 => {
380            // println!("Status: Success")
381            true
382        },
383        3221225581 => {
384            // println!("Status: Logon Failure")
385            false
386        },
387        _ => {
388            // println!("Status: Unknown")
389            false
390        },
391    }
392}
393