1 //--------------------------------------------------------------------------
2 // Copyright (C) 2016-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 
19 // dce_smb_commands.cc author Maya Dagon <mdagon@cisco.com>
20 // based on work by Todd Wease
21 
22 // Smb commands processing
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "dce_smb_commands.h"
29 
30 #include "utils/util.h"
31 
32 #include "dce_smb_module.h"
33 #include "dce_smb_transaction_utils.h"
34 
35 using namespace snort;
36 
37 #define SMB_DIALECT_NT_LM_012       "NT LM 0.12"  // NT LAN Manager
38 
39 #define SERVICE_0     (0)                // IPC start
40 #define SERVICE_1     (SERVICE_0+4)      // DISK start
41 #define SERVICE_FS    (SERVICE_1+3)      // Failure
42 #define SERVICE_IPC   (SERVICE_FS+1)     // IPC service
43 #define SERVICE_DISK  (SERVICE_FS+2)     // DISK service
44 
45 #define SHARE_0     (0)
46 #define SHARE_FS    (SHARE_0+5)
47 #define SHARE_IPC   (SHARE_FS+1)
48 
49 #define OS_0          (0)   // "Windows" start
50 #define OS_1    (OS_0+ 8)   // Windows 2000 and XP server
51 #define OS_2    (OS_1+ 4)   // Windows 2000 and XP client
52 #define OS_3    (OS_2+ 5)   // "Server", 2003, 2008R2, 2008
53 #define OS_4    (OS_3+20)   // Windows Vista
54 #define OS_5    (OS_4 +5)   // Windows 7
55 #define OS_6    (OS_5 +1)   // Windows NT
56 #define OS_7    (OS_6 +2)   // Windows 98
57 #define OS_FS   (OS_7+ 3)   // Failure state
58 #define OS_WIN2000    (OS_FS+1)
59 #define OS_WINXP      (OS_FS+2)
60 #define OS_WIN2003    (OS_FS+3)
61 #define OS_WINVISTA   (OS_FS+4)
62 #define OS_WIN2008    (OS_FS+5)
63 #define OS_WIN7       (OS_FS+6)
64 
65 static const DCE2_SmbFsm dce2_smb_service_fsm[] =
66 {
67     // IPC
68     { 'I',  SERVICE_0+1, SERVICE_1 },
69     { 'P',  SERVICE_0+2, SERVICE_FS },
70     { 'C',  SERVICE_0+3, SERVICE_FS },
71     { '\0', SERVICE_IPC, SERVICE_FS },
72 
73     // DISK
74     { 'A',  SERVICE_1+1, SERVICE_FS },
75     { ':',  SERVICE_1+2, SERVICE_FS },
76     { '\0', SERVICE_DISK, SERVICE_FS },
77 
78     { 0, SERVICE_FS, SERVICE_FS }
79 };
80 
81 static const DCE2_SmbFsm dce2_ipc_share_fsm[] =
82 {
83     { 'I', SHARE_0+1, SHARE_FS },
84     { 'P', SHARE_0+2, SHARE_FS },
85     { 'C', SHARE_0+3, SHARE_FS },
86     { '$', SHARE_0+4, SHARE_FS },
87     { '\0', SHARE_IPC, SHARE_FS },
88 
89     { 0, SHARE_FS, SHARE_FS }
90 };
91 
92 static const DCE2_SmbFsm dce2_smb_os_fsm[] =
93 {
94     // Windows start states
95     { 'W', OS_0+1, OS_FS },
96     { 'i', OS_0+2, OS_FS },
97     { 'n', OS_0+3, OS_FS },
98     { 'd', OS_0+4, OS_FS },
99     { 'o', OS_0+5, OS_FS },
100     { 'w', OS_0+6, OS_FS },
101     { 's', OS_0+7, OS_FS },
102     { ' ', OS_0+8, OS_FS },
103 
104     // Windows 2000 and XP server states
105     { '5', OS_1+1, OS_2 },
106     { '.', OS_1+2, OS_FS },
107     { '1', OS_WINXP, OS_1+3 },    // Windows XP
108     { '0', OS_WIN2000, OS_FS },   // Windows 2000
109 
110     // Windows 2000 or XP client states
111     { '2', OS_2+1, OS_3 },
112     { '0', OS_2+2, OS_FS },
113     { '0', OS_2+3, OS_FS },
114     { '2', OS_WINXP, OS_2+4 },    // Windows XP
115     { '0', OS_WIN2000, OS_FS },   // Windows 2000
116 
117     // "Server" string states
118     { 'S', OS_3+ 1, OS_4 },
119     { 'e', OS_3+ 2, OS_FS },
120     { 'r', OS_3+ 3, OS_FS },
121     { 'v', OS_3+ 4, OS_FS },
122     { 'e', OS_3+ 5, OS_FS },
123     { 'r', OS_3+ 6, OS_FS },
124     { ' ', OS_3+ 7, OS_FS },
125     { '2', OS_3+ 8, OS_3+12 },
126     { '0', OS_3+ 9, OS_FS },
127     { '0', OS_3+10, OS_FS },
128     { '3', OS_WIN2003, OS_3+11 },   // Windows Server 2003
129     { '8', OS_WIN2008, OS_FS },     // Windows Server 2008R2
130 
131     // Windows 2008 has this, 2008 R2 does not
132     { '(', OS_3+13, OS_FS },
133     { 'R', OS_3+14, OS_FS },
134     { ')', OS_3+15, OS_FS },
135     { ' ', OS_3+16, OS_FS },
136     { '2', OS_3+17, OS_FS },
137     { '0', OS_3+18, OS_FS },
138     { '0', OS_3+19, OS_FS },
139     { '8', OS_WIN2008, OS_FS },
140 
141     // Windows Vista states
142     { 'V', OS_4+1, OS_5 },
143     { 'i', OS_4+2, OS_FS },
144     { 's', OS_4+3, OS_FS },
145     { 't', OS_4+4, OS_FS },
146     { 'a', OS_WINVISTA, OS_FS },
147 
148     // Windows 7 state
149     { '7', OS_WIN7, OS_6 },
150 
151     // Windows NT
152     { 'N', OS_6+1, OS_7 },
153     { 'T', OS_WIN2000, OS_FS },  // Windows NT, set policy to Windows 2000
154 
155     // Windows 98
156     { '4', OS_7+1, OS_FS },
157     { '.', OS_7+2, OS_FS },
158     { '0', OS_WIN2000, OS_FS },  // Windows 98, set policy to Windows 2000
159 
160     // Failure state
161     { 0, OS_FS, OS_FS }
162 
163     // Match states shouldn't be accessed
164 };
165 
166 /********************************************************************
167  * Private function prototypes
168  *******************************************************************/
169 static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData*, const uint32_t,
170     const uint16_t, const uint8_t, const uint16_t, const uint16_t);
171 static DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData*, const uint8_t*,
172     const uint8_t*, const uint32_t, const uint16_t, const uint32_t, uint16_t);
173 static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData*, const SmbNtHdr*,
174     const DCE2_SmbComInfo*, const uint8_t*, uint32_t);
175 
176 /*********************************************************************
177  * Private functions
178  ********************************************************************/
179 
180 /********************************************************************
181  * Function: DCE2_SmbCheckFmtData()
182  *
183  * Purpose:
184  *  Checks the data count in commands with formats, e.g.
185  *  SMB_COM_WRITE, SMB_COM_WRITE_AND_CLOSE, SMB_COM_WRITE_AND_UNLOCK.
186  *
187  * Arguments:
188  *  DCE2_SmbSsnData * - SMB session data structure
189  *  const uint32_t    - remaining NetBIOS PDU length
190  *  const uint16_t    - advertised byte count
191  *  const uint8_t     - data format specifier
192  *  const uint16_t    - data count reported in command
193  *  const uint16_t    - data count reported in format field
194  *
195  * Returns: None
196  *
197  ********************************************************************/
DCE2_SmbCheckFmtData(DCE2_SmbSsnData * ssd,const uint32_t nb_len,const uint16_t bcc,const uint8_t fmt,const uint16_t com_dcnt,const uint16_t fmt_dcnt)198 static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData* ssd,
199     const uint32_t nb_len, const uint16_t bcc, const uint8_t fmt,
200     const uint16_t com_dcnt, const uint16_t fmt_dcnt)
201 {
202     if (fmt != SMB_FMT__DATA_BLOCK)
203         dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
204             ssd->sd);
205     if (com_dcnt != fmt_dcnt)
206         dce_alert(GID_DCE2, DCE2_SMB_DCNT_MISMATCH, (dce2CommonStats*)&dce2_smb_stats,
207             ssd->sd);
208     if (com_dcnt != (bcc - 3))
209         dce_alert(GID_DCE2, DCE2_SMB_INVALID_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
210             ssd->sd);
211     if (nb_len < com_dcnt)
212         dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
213             ssd->sd);
214 }
215 
216 /********************************************************************
217  * Function: DCE2_SmbCheckData()
218  *
219  * Purpose:
220  *  Ensures that the data size reported in an SMB command is kosher.
221  *
222  * Arguments:
223  *  DCE2_SmbSsnData * - SMB session data structure
224  *  const uint8_t *   - pointer to start of SMB header where offset is
225  *                      taken from.
226  *  const uint8_t *   - current pointer - should be right after command
227  *                      structure.
228  *  const uint32_t    - remaining data left in PDU from current pointer.
229  *  const uint16_t    - the byte count from the SMB command
230  *  const uint16_t    - reported data count in SMB command
231  *  const uint16_t    - reported data offset in SMB command
232  *
233  * Returns:
234  *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
235  *              DCE2_RET__SUCCESS if data can be processed
236  *
237  ********************************************************************/
DCE2_SmbCheckData(DCE2_SmbSsnData * ssd,const uint8_t * smb_hdr_ptr,const uint8_t * nb_ptr,const uint32_t nb_len,const uint16_t bcc,const uint32_t dcnt,uint16_t doff)238 static DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData* ssd,
239     const uint8_t* smb_hdr_ptr, const uint8_t* nb_ptr,
240     const uint32_t nb_len, const uint16_t bcc,
241     const uint32_t dcnt, uint16_t doff)
242 {
243     const uint8_t* offset = smb_hdr_ptr + doff;
244     const uint8_t* nb_end = nb_ptr + nb_len;
245 
246     // Byte counts don't usually matter, so no error but still alert
247     // Don't alert in the case where the data count is larger than what the
248     // byte count can handle.  This can happen if CAP_LARGE_READX or
249     // CAP_LARGE_WRITEX were negotiated.
250     if ((dcnt <= UINT16_MAX) && (bcc < dcnt))
251         dce_alert(GID_DCE2, DCE2_SMB_BCC_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
252             ssd->sd);
253 
254     if (offset > nb_end)
255     {
256         dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
257         // Error if offset is beyond data left
258         return DCE2_RET__ERROR;
259     }
260 
261     // Only check if the data count is non-zero
262     if ((dcnt != 0) && (offset < nb_ptr))
263     {
264         // Not necessarily and error if the offset puts the data
265         // before or in the command structure.
266         dce_alert(GID_DCE2, DCE2_SMB_BAD_OFF, (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
267     }
268 
269     // Not necessarily an error if the addition of the data count goes
270     // beyond the data left
271 
272     if (dcnt > (nb_end - offset))           // beyond data left
273     {
274         dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
275             ssd->sd);
276     }
277 
278     return DCE2_RET__SUCCESS;
279 }
280 
281 // SMB_COM_WRITE_ANDX - raw mode
DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)282 static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
283     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
284 {
285     // Set this now for possible reassembled packet
286     uint16_t fid = SmbWriteAndXReqFid((const SmbWriteAndXReq*)nb_ptr);
287     DCE2_SmbFileTracker* ftracker = DCE2_SmbGetFileTracker(ssd, fid);
288     ssd->cur_rtracker->ftracker = ftracker;
289     if (ftracker == nullptr)
290         return DCE2_RET__ERROR;
291 
292     // Got request to write in raw mode without having gotten the initial
293     // raw mode request or got initial raw mode request and then another
294     // without having finished the first.
295     bool start_write_raw = SmbWriteAndXReqStartRaw((const SmbWriteAndXReq*)nb_ptr);
296     bool continue_write_raw = SmbWriteAndXReqRaw((const SmbWriteAndXReq*)nb_ptr);
297     DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
298     if ((start_write_raw && (ftracker->fp_writex_raw != nullptr)
299         && (ftracker->fp_writex_raw->remaining != 0))
300         || (continue_write_raw && ((ftracker->fp_writex_raw == nullptr)
301         || (ftracker->fp_writex_raw->remaining == 0))))
302     {
303         switch (policy)
304         {
305         case DCE2_POLICY__WIN2000:
306         case DCE2_POLICY__WINXP:
307         case DCE2_POLICY__WINVISTA:
308         case DCE2_POLICY__WIN2003:
309         case DCE2_POLICY__WIN2008:
310         case DCE2_POLICY__WIN7:
311             if (ftracker->fp_writex_raw != nullptr)
312             {
313                 ftracker->fp_writex_raw->remaining = 0;
314                 DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
315             }
316             return DCE2_RET__ERROR;
317         case DCE2_POLICY__SAMBA:
318         case DCE2_POLICY__SAMBA_3_0_37:
319         case DCE2_POLICY__SAMBA_3_0_22:
320         case DCE2_POLICY__SAMBA_3_0_20:
321             // Samba doesn't do anything special here except if the two
322             // flags are set it walks past the two "length" bytes.
323             // See below.
324             break;
325         default:
326             assert(false);
327             break;
328         }
329     }
330 
331     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
332     uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
333     uint16_t doff = SmbWriteAndXReqDataOff((const SmbWriteAndXReq*)nb_ptr);
334     uint32_t dcnt = SmbWriteAndXReqDataCnt((const SmbWriteAndXReq*)nb_ptr);
335     uint16_t remaining = SmbWriteAndXReqRemaining((const SmbWriteAndXReq*)nb_ptr);
336 
337     dce2_move(nb_ptr, nb_len, com_size);
338 
339     if (DCE2_SmbCheckData(ssd, (const uint8_t*)smb_hdr, nb_ptr, nb_len,
340         byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
341         return DCE2_RET__ERROR;
342 
343     // This may move backwards
344     dce2_move(nb_ptr, nb_len, ((const uint8_t*)smb_hdr + doff) - nb_ptr);
345 
346     // If a "raw" write is requested there will be two bytes after the
347     // header/pad and before the data which is supposed to represent a
348     // length but everyone ignores it.  However we need to move past it.
349     // This is the one situation where the remaining field matters and
350     // should be equal to the total amount of data to be written.
351     if (start_write_raw)
352     {
353         if (dcnt < 2)
354             return DCE2_RET__ERROR;
355 
356         // From data size check above, nb_len >= dsize
357         dcnt -= 2;
358         dce2_move(nb_ptr, nb_len, 2);
359     }
360 
361     if (dcnt > nb_len)
362         dcnt = nb_len;
363 
364     // File tracker already validated
365     switch (policy)
366     {
367     case DCE2_POLICY__WIN2000:
368     case DCE2_POLICY__WINXP:
369     case DCE2_POLICY__WINVISTA:
370     case DCE2_POLICY__WIN2003:
371     case DCE2_POLICY__WIN2008:
372     case DCE2_POLICY__WIN7:
373         if (start_write_raw)
374         {
375             if (ftracker->fp_writex_raw == nullptr)
376             {
377                 ftracker->fp_writex_raw = (DCE2_SmbWriteAndXRaw*)
378                     snort_calloc(sizeof(DCE2_SmbWriteAndXRaw));
379                 if (ftracker->fp_writex_raw == nullptr)
380                     return DCE2_RET__ERROR;
381 
382                 ftracker->fp_writex_raw->remaining = (int)remaining;
383             }
384         }
385 
386         ftracker->fp_writex_raw->remaining -= (int)dcnt;
387         if (ftracker->fp_writex_raw->remaining < 0)
388         {
389             ftracker->fp_writex_raw->remaining = 0;
390             DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
391             return DCE2_RET__ERROR;
392         }
393 
394         // If the "raw" write isn't finished in the first request
395         // and haven't allocated a buffer yet.
396         if (start_write_raw && (ftracker->fp_writex_raw->remaining != 0)
397             && (ftracker->fp_writex_raw->buf == nullptr))
398         {
399             ftracker->fp_writex_raw->buf =
400                 DCE2_BufferNew(remaining, 0);
401             if (ftracker->fp_writex_raw->buf == nullptr)
402             {
403                 ftracker->fp_writex_raw->remaining = 0;
404                 return DCE2_RET__ERROR;
405             }
406         }
407 
408         // If data has to be added to buffer, i.e. not a start raw
409         // or a start raw and more raw requests to come.
410         if (!start_write_raw || (ftracker->fp_writex_raw->remaining != 0))
411         {
412             if (DCE2_BufferAddData(ftracker->fp_writex_raw->buf, nb_ptr,
413                 dcnt, DCE2_BufferLength(ftracker->fp_writex_raw->buf),
414                 DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS)
415             {
416                 ftracker->fp_writex_raw->remaining = 0;
417                 DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
418                 return DCE2_RET__ERROR;
419             }
420 
421             if (ftracker->fp_writex_raw->remaining == 0)
422             {
423                 const uint8_t* data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
424                 uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
425                 Packet* rpkt = DCE2_SmbGetRpkt(ssd,
426                     &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
427 
428                 if (rpkt == nullptr)
429                 {
430                     DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
431                     return DCE2_RET__ERROR;
432                 }
433 
434                 (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
435 
436                 DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
437             }
438         }
439         else
440         {
441             (void)DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
442         }
443 
444         // Windows doesn't process chained commands to raw WriteAndXs
445         // so return error so it exits the loop.
446         return DCE2_RET__ERROR;
447 
448     case DCE2_POLICY__SAMBA:
449     case DCE2_POLICY__SAMBA_3_0_37:
450     case DCE2_POLICY__SAMBA_3_0_22:
451     case DCE2_POLICY__SAMBA_3_0_20:
452         // All Samba cares about is skipping the 2 byte "length"
453         // if both flags are set.
454         break;
455     default:
456         assert(false);
457         break;
458     }
459 
460     return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
461 }
462 
DCE2_SmbSetFingerprintedClient(DCE2_SmbSsnData * ssd)463 static inline void DCE2_SmbSetFingerprintedClient(DCE2_SmbSsnData* ssd)
464 {
465     ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__FP_CLIENT;
466 }
467 
DCE2_SmbFingerprintedClient(DCE2_SmbSsnData * ssd)468 static inline bool DCE2_SmbFingerprintedClient(DCE2_SmbSsnData* ssd)
469 {
470     return ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__FP_CLIENT;
471 }
472 
DCE2_SmbSetFingerprintedServer(DCE2_SmbSsnData * ssd)473 static inline void DCE2_SmbSetFingerprintedServer(DCE2_SmbSsnData* ssd)
474 {
475     ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__FP_SERVER;
476 }
477 
DCE2_SmbFingerprintedServer(DCE2_SmbSsnData * ssd)478 static inline bool DCE2_SmbFingerprintedServer(DCE2_SmbSsnData* ssd)
479 {
480     return ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__FP_SERVER;
481 }
482 
483 /********************************************************************
484  * Functions:
485  *   DCE2_SmbOpen()
486  *   DCE2_SmbCreate()
487  *   DCE2_SmbClose()
488  *   DCE2_SmbRename()
489  *   DCE2_SmbRead()
490  *   DCE2_SmbWrite()
491  *   DCE2_SmbCreateNew()
492  *   DCE2_SmbLockAndRead()
493  *   DCE2_SmbWriteAndUnlock()
494  *   DCE2_SmbReadRaw()
495  *   DCE2_SmbWriteRaw()
496  *   DCE2_SmbWriteComplete()
497  *   DCE2_SmbWriteAndClose()
498  *   DCE2_SmbOpenAndX()
499  *   DCE2_SmbReadAndX()
500  *   DCE2_SmbWriteAndX()
501  *   DCE2_SmbTreeConnect()
502  *   DCE2_SmbTreeDisconnect()
503  *   DCE2_SmbNegotiate()
504  *   DCE2_SmbSessionSetupAndX()
505  *   DCE2_SmbLogoffAndX()
506  *   DCE2_SmbTreeConnectAndX()
507  *   DCE2_SmbNtCreateAndX()
508  *
509  * Purpose: Process SMB command
510  *
511  * Arguments:
512  *  DCE2_SmbSsnData *       - SMB session data structure
513  *  const SmbNtHdr *        - SMB header structure (packet pointer)
514  *  const DCE2_SmbComInfo * - Basic command information structure
515  *  uint8_t *               - pointer to start of command (packet pointer)
516  *  uint32_t                - remaining NetBIOS length
517  *
518  * Returns:
519  *  DCE2_Ret - DCE2_RET__ERROR if something went wrong and/or processing
520  *               should stop
521  *             DCE2_RET__SUCCESS if processing should continue
522  *
523  ********************************************************************/
524 
525 // SMB_COM_OPEN
DCE2_SmbOpen(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)526 DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
527     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
528 {
529     if (!DCE2_ComInfoCanProcessCommand(com_info))
530         return DCE2_RET__ERROR;
531 
532     if (DCE2_ComInfoIsResponse(com_info))
533     {
534         DCE2_SmbFileTracker* ftracker;
535 
536         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
537             && (SmbFileAttrsDirectory(SmbOpenRespFileAttrs((const SmbOpenResp*)nb_ptr))
538             || SmbOpenForWriting(SmbOpenRespAccessMode((const SmbOpenResp*)nb_ptr))))
539             return DCE2_RET__SUCCESS;
540 
541         ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid,
542             ssd->cur_rtracker->tid, SmbOpenRespFid((const SmbOpenResp*)nb_ptr));
543         if (ftracker == nullptr)
544             return DCE2_RET__ERROR;
545 
546         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
547 
548         if (!ftracker->is_ipc)
549         {
550             // This command can only be used to open an existing file
551             ftracker->ff_file_size = SmbOpenRespFileSize((const SmbOpenResp*)nb_ptr);
552         }
553     }
554     else
555     {
556         // Have at least 2 bytes of data based on byte count check done earlier
557 
558         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
559 
560         if (!SmbFmtAscii(*nb_ptr))
561         {
562             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
563                 ssd->sd);
564             return DCE2_RET__ERROR;
565         }
566 
567         dce2_move(nb_ptr, nb_len, 1);
568 
569         ssd->cur_rtracker->file_name =
570             get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
571             &ssd->cur_rtracker->file_name_size);
572     }
573 
574     return DCE2_RET__SUCCESS;
575 }
576 
577 // SMB_COM_CREATE
DCE2_SmbCreate(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)578 DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
579     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
580 {
581     if (!DCE2_ComInfoCanProcessCommand(com_info))
582         return DCE2_RET__ERROR;
583 
584     if (DCE2_ComInfoIsResponse(com_info))
585     {
586         DCE2_SmbFileTracker* ftracker = DCE2_SmbNewFileTracker(
587             ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
588             SmbCreateRespFid((const SmbCreateResp*)nb_ptr));
589 
590         if (ftracker == nullptr)
591             return DCE2_RET__ERROR;
592 
593         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
594 
595         // Command creates or opens and truncates file to 0 so assume
596         // upload.
597         if (!ftracker->is_ipc)
598             ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
599     }
600     else
601     {
602         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
603         {
604             uint16_t file_attrs = SmbCreateReqFileAttrs((const SmbCreateReq*)nb_ptr);
605 
606             if (SmbAttrDirectory(file_attrs))
607                 return DCE2_RET__IGNORE;
608 
609             if (SmbEvasiveFileAttrs(file_attrs))
610                 dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
611                     (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
612         }
613 
614         // Have at least 2 bytes of data based on byte count check done earlier
615 
616         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
617         assert(nb_ptr != nullptr);
618         if (!SmbFmtAscii(*nb_ptr))
619         {
620             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
621                 ssd->sd);
622             return DCE2_RET__ERROR;
623         }
624 
625         dce2_move(nb_ptr, nb_len, 1);
626 
627         ssd->cur_rtracker->file_name =
628             get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
629             &ssd->cur_rtracker->file_name_size);
630     }
631 
632     return DCE2_RET__SUCCESS;
633 }
634 
635 // SMB_COM_CLOSE
DCE2_SmbClose(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t)636 DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
637     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t)
638 {
639     if (!DCE2_ComInfoCanProcessCommand(com_info))
640         return DCE2_RET__ERROR;
641 
642     if (DCE2_ComInfoIsRequest(com_info))
643     {
644         uint16_t fid = SmbCloseReqFid((const SmbCloseReq*)nb_ptr);
645 
646         // Set this for response
647         ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid);
648 
649         if ((ssd->fb_ftracker != nullptr) && (ssd->fb_ftracker == ssd->cur_rtracker->ftracker))
650         {
651             FileVerdict verdict = DCE2_get_file_verdict();
652 
653             if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
654                 ssd->block_pdus = true;
655         }
656     }
657     else
658     {
659         DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
660     }
661 
662     return DCE2_RET__SUCCESS;
663 }
664 
665 // SMB_COM_RENAME
DCE2_SmbRename(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)666 DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
667     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
668 {
669     // NOTE: This command is only processed for CVE-2006-4696 where the buffer
670     // formats are invalid and has no bearing on DCE/RPC processing.
671 
672     if (!DCE2_ComInfoCanProcessCommand(com_info))
673         return DCE2_RET__ERROR;
674 
675     if (DCE2_ComInfoIsRequest(com_info))
676     {
677         // Have at least 4 bytes of data based on byte count check done earlier
678 
679         uint32_t i;
680 
681         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
682 
683         if (!SmbFmtAscii(*nb_ptr))
684         {
685             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
686                 ssd->sd);
687             return DCE2_RET__ERROR;
688         }
689 
690         dce2_move(nb_ptr, nb_len, 1);
691 
692         if (SmbUnicode(smb_hdr))
693         {
694             for (i = 0; i < (nb_len - 1); i += 2)
695             {
696                 if (*((const uint16_t*)(nb_ptr + i)) == 0)
697                 {
698                     i += 2;  // move past null terminating bytes
699                     break;
700                 }
701             }
702         }
703         else
704         {
705             for (i = 0; i < nb_len; i++)
706             {
707                 if (nb_ptr[i] == 0)
708                 {
709                     i++;  // move past null terminating byte
710                     break;
711                 }
712             }
713         }
714 
715         // i <= nb_len
716         dce2_move(nb_ptr, nb_len, i);
717 
718         if ((nb_len > 0) && !SmbFmtAscii(*nb_ptr))
719         {
720             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
721                 ssd->sd);
722             return DCE2_RET__ERROR;
723         }
724     }
725 
726     // Don't care about tracking response
727     return DCE2_RET__ERROR;
728 }
729 
730 // SMB_COM_READ
DCE2_SmbRead(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)731 DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
732     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
733 {
734     if (!DCE2_ComInfoCanProcessCommand(com_info))
735         return DCE2_RET__ERROR;
736 
737     if (DCE2_ComInfoIsRequest(com_info))
738     {
739         DCE2_SmbFileTracker* ftracker =
740             DCE2_SmbGetFileTracker(ssd, SmbReadReqFid((const SmbReadReq*)nb_ptr));
741 
742         // Set this for response since response doesn't have the Fid
743         ssd->cur_rtracker->ftracker = ftracker;
744         if ((ftracker != nullptr) && !ftracker->is_ipc)
745             ssd->cur_rtracker->file_offset = SmbReadReqOffset((const SmbReadReq*)nb_ptr);
746     }
747     else
748     {
749         // Have at least 3 bytes of data based on byte count check done earlier
750 
751         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
752         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
753         uint16_t com_dcnt = SmbReadRespCount((const SmbReadResp*)nb_ptr);
754         uint8_t fmt = *(nb_ptr + com_size);
755         uint16_t fmt_dcnt = alignedNtohs((const uint16_t*)(nb_ptr + com_size + 1));
756 
757         dce2_move(nb_ptr, nb_len, (com_size + 3));
758 
759         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
760 
761         if (com_dcnt > nb_len)
762             return DCE2_RET__ERROR;
763 
764         return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
765     }
766 
767     return DCE2_RET__SUCCESS;
768 }
769 
770 // SMB_COM_WRITE
DCE2_SmbWrite(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)771 DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
772     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
773 {
774     if (!DCE2_ComInfoCanProcessCommand(com_info))
775         return DCE2_RET__ERROR;
776 
777     if (DCE2_ComInfoIsRequest(com_info))
778     {
779         // Have at least 3 bytes of data based on byte count check done earlier
780 
781         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
782         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
783         uint8_t fmt = *(nb_ptr + com_size);
784         uint16_t com_dcnt = SmbWriteReqCount((const SmbWriteReq*)nb_ptr);
785         uint16_t fmt_dcnt = alignedNtohs((const uint16_t*)(nb_ptr + com_size + 1));
786         uint16_t fid = SmbWriteReqFid((const SmbWriteReq*)nb_ptr);
787         uint32_t offset = SmbWriteReqOffset((const SmbWriteReq*)nb_ptr);
788 
789         dce2_move(nb_ptr, nb_len, (com_size + 3));
790 
791         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
792 
793         if (com_dcnt == 0)
794         {
795             dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats,
796                 ssd->sd);
797             return DCE2_RET__ERROR;
798         }
799 
800         if (com_dcnt > nb_len)
801             com_dcnt = (uint16_t)nb_len;
802 
803         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
804     }
805 
806     return DCE2_RET__SUCCESS;
807 }
808 
809 // SMB_COM_CREATE_NEW
DCE2_SmbCreateNew(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)810 DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
811     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
812 {
813     if (!DCE2_ComInfoCanProcessCommand(com_info))
814         return DCE2_RET__ERROR;
815 
816     if (DCE2_ComInfoIsResponse(com_info))
817     {
818         DCE2_SmbFileTracker* ftracker = DCE2_SmbNewFileTracker(
819             ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
820             SmbCreateNewRespFid((const SmbCreateNewResp*)nb_ptr));
821 
822         if (ftracker == nullptr)
823             return DCE2_RET__ERROR;
824 
825         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
826 
827         // Command creates a new file so assume upload.
828         if (!ftracker->is_ipc)
829             ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
830     }
831     else
832     {
833         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
834         {
835             uint16_t file_attrs = SmbCreateNewReqFileAttrs((const SmbCreateNewReq*)nb_ptr);
836 
837             if (SmbAttrDirectory(file_attrs))
838                 return DCE2_RET__IGNORE;
839 
840             if (SmbEvasiveFileAttrs(file_attrs))
841                 dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
842                     (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
843         }
844 
845         // Have at least 2 bytes of data based on byte count check done earlier
846 
847         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
848         assert(nb_ptr != nullptr);
849         if (!SmbFmtAscii(*nb_ptr))
850         {
851             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
852                 ssd->sd);
853             return DCE2_RET__ERROR;
854         }
855 
856         dce2_move(nb_ptr, nb_len, 1);
857 
858         ssd->cur_rtracker->file_name =
859             get_smb_file_name(nb_ptr, nb_len, SmbUnicode(smb_hdr),
860             &ssd->cur_rtracker->file_name_size);
861     }
862 
863     return DCE2_RET__SUCCESS;
864 }
865 
866 // SMB_COM_LOCK_AND_READ
DCE2_SmbLockAndRead(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)867 DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
868     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
869 {
870     if (!DCE2_ComInfoCanProcessCommand(com_info))
871         return DCE2_RET__ERROR;
872 
873     if (DCE2_ComInfoIsRequest(com_info))
874     {
875         DCE2_SmbFileTracker* ftracker =
876             DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
877             ssd->cur_rtracker->tid, SmbLockAndReadReqFid((const SmbLockAndReadReq*)nb_ptr));
878 
879         // No sense in tracking response
880         if (ftracker == nullptr)
881             return DCE2_RET__ERROR;
882 
883         if (!ftracker->is_ipc)
884             ssd->cur_rtracker->file_offset = SmbLockAndReadReqOffset((const
885                 SmbLockAndReadReq*)nb_ptr);
886 
887         // Set this for response
888         ssd->cur_rtracker->ftracker = ftracker;
889     }
890     else
891     {
892         // Have at least 3 bytes of data based on byte count check done earlier
893         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
894         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
895         uint8_t fmt = *(nb_ptr + com_size);
896         uint16_t com_dcnt = SmbLockAndReadRespCount((const SmbLockAndReadResp*)nb_ptr);
897         uint16_t fmt_dcnt = alignedNtohs((const uint16_t*)(nb_ptr + com_size + 1));
898 
899         dce2_move(nb_ptr, nb_len, (com_size + 3));
900 
901         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
902 
903         if (com_dcnt == 0)
904         {
905             dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats,
906                 ssd->sd);
907             return DCE2_RET__ERROR;
908         }
909 
910         if (com_dcnt > nb_len)
911             com_dcnt = (uint16_t)nb_len;
912 
913         return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
914     }
915 
916     return DCE2_RET__SUCCESS;
917 }
918 
919 // SMB_COM_WRITE_AND_UNLOCK
DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)920 DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
921     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
922 {
923     if (!DCE2_ComInfoCanProcessCommand(com_info))
924     {
925         if (DCE2_ComInfoIsBadLength(com_info) || DCE2_ComInfoIsInvalidWordCount(com_info))
926             return DCE2_RET__ERROR;
927 
928         // These are special cases.  The write succeeds but the unlock fails
929         // so an error response is returned but the data was actually written.
930         if (DCE2_ComInfoIsResponse(com_info) && DCE2_ComInfoIsStatusError(com_info))
931         {
932             if (DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
933             {
934                 if (!SmbErrorInvalidDeviceRequest(smb_hdr))
935                     return DCE2_RET__ERROR;
936             }
937             else if (!SmbErrorRangeNotLocked(smb_hdr))
938             {
939                 return DCE2_RET__ERROR;
940             }
941         }
942     }
943 
944     if (DCE2_ComInfoIsRequest(com_info))
945     {
946         // Have at least 3 bytes of data based on byte count check done earlier
947 
948         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
949         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
950         uint8_t fmt = *(nb_ptr + com_size);
951         uint16_t com_dcnt = SmbWriteAndUnlockReqCount((const SmbWriteAndUnlockReq*)nb_ptr);
952         uint16_t fmt_dcnt = alignedNtohs((const uint16_t*)(nb_ptr + com_size + 1));
953         uint16_t fid = SmbWriteAndUnlockReqFid((const SmbWriteAndUnlockReq*)nb_ptr);
954         uint32_t offset = SmbWriteAndUnlockReqOffset((const SmbWriteAndUnlockReq*)nb_ptr);
955 
956         dce2_move(nb_ptr, nb_len, (com_size + 3));
957 
958         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
959 
960         if (com_dcnt == 0)
961         {
962             dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats,
963                 ssd->sd);
964             return DCE2_RET__ERROR;
965         }
966 
967         if (com_dcnt > nb_len)
968             com_dcnt = (uint16_t)nb_len;
969 
970         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
971     }
972 
973     return DCE2_RET__SUCCESS;
974 }
975 
976 // SMB_COM_OPEN_ANDX
DCE2_SmbOpenAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)977 DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
978     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
979 {
980     if (!DCE2_ComInfoCanProcessCommand(com_info))
981         return DCE2_RET__ERROR;
982 
983     if (DCE2_ComInfoIsResponse(com_info))
984     {
985         const uint16_t fid = SmbOpenAndXRespFid((const SmbOpenAndXResp*)nb_ptr);
986         const uint16_t file_attrs = SmbOpenAndXRespFileAttrs((const SmbOpenAndXResp*)nb_ptr);
987         const uint16_t resource_type = SmbOpenAndXRespResourceType((const SmbOpenAndXResp*)nb_ptr);
988         DCE2_SmbFileTracker* ftracker = nullptr;
989 
990         // Set request tracker's current file tracker in case of chained commands
991         switch (SmbAndXCom2((const SmbAndXCommon*)nb_ptr))
992         {
993         // This is in case in the request a write was chained to an open
994         // in which case the write will be to the newly opened file
995         case SMB_COM_WRITE:
996         case SMB_COM_WRITE_ANDX:
997         case SMB_COM_TRANSACTION:
998         case SMB_COM_READ_ANDX:
999             ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
1000             break;
1001         default:
1002             break;
1003         }
1004 
1005         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
1006             && (SmbFileAttrsDirectory(file_attrs)
1007             || !SmbResourceTypeDisk(resource_type)))
1008         {
1009             if (ftracker != nullptr)
1010                 DCE2_SmbRemoveFileTracker(ssd, ftracker);
1011             return DCE2_RET__SUCCESS;
1012         }
1013 
1014         if (ftracker == nullptr)
1015         {
1016             ftracker = DCE2_SmbNewFileTracker(ssd,
1017                 ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
1018             if (ftracker == nullptr)
1019                 return DCE2_RET__ERROR;
1020         }
1021 
1022         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
1023 
1024         if (!ftracker->is_ipc)
1025         {
1026             const uint16_t open_results = SmbOpenAndXRespOpenResults((const SmbOpenAndXResp*)nb_ptr);
1027 
1028             if (SmbOpenResultRead(open_results))
1029             {
1030                 ftracker->ff_file_size = SmbOpenAndXRespFileSize((const SmbOpenAndXResp*)nb_ptr);
1031             }
1032             else
1033             {
1034                 ftracker->ff_file_size = ssd->cur_rtracker->file_size;
1035                 ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
1036             }
1037         }
1038 
1039         ssd->cur_rtracker->ftracker = ftracker;
1040     }
1041     else
1042     {
1043         uint32_t pad = 0;
1044         const bool unicode = SmbUnicode(smb_hdr);
1045         uint8_t null_bytes = unicode ? 2 : 1;
1046 
1047         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
1048         {
1049             uint16_t file_attrs = SmbOpenAndXReqFileAttrs((const SmbOpenAndXReq*)nb_ptr);
1050 
1051             if (SmbEvasiveFileAttrs(file_attrs))
1052                 dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
1053                     (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
1054             ssd->cur_rtracker->file_size = SmbOpenAndXReqAllocSize((const SmbOpenAndXReq*)nb_ptr);
1055         }
1056 
1057         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
1058 
1059         if (unicode)
1060             pad = (nb_ptr - (const uint8_t*)smb_hdr) & 1;
1061 
1062         if (nb_len < (pad + null_bytes))
1063             return DCE2_RET__ERROR;
1064 
1065         dce2_move(nb_ptr, nb_len, pad);
1066 
1067         // Samba allows chaining OpenAndX/NtCreateAndX so might have
1068         // already been set.
1069         if (ssd->cur_rtracker->file_name == nullptr)
1070         {
1071             ssd->cur_rtracker->file_name =
1072                 get_smb_file_name(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_size);
1073         }
1074     }
1075 
1076     return DCE2_RET__SUCCESS;
1077 }
1078 
1079 // SMB_COM_READ_ANDX
DCE2_SmbReadAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1080 DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1081     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1082 {
1083     if (!DCE2_ComInfoCanProcessCommand(com_info))
1084         return DCE2_RET__ERROR;
1085 
1086     if (DCE2_ComInfoIsRequest(com_info))
1087     {
1088         DCE2_SmbFileTracker* ftracker =
1089             DCE2_SmbGetFileTracker(ssd, SmbReadAndXReqFid((const SmbReadAndXReq*)nb_ptr));
1090 
1091         // No sense in tracking response
1092         if (ftracker == nullptr)
1093             return DCE2_RET__ERROR;
1094 
1095         if (!ftracker->is_ipc)
1096             ssd->cur_rtracker->file_offset = SmbReadAndXReqOffset((const SmbReadAndXExtReq*)nb_ptr);
1097 
1098         // Set this for response
1099         ssd->cur_rtracker->ftracker = ftracker;
1100     }
1101     else
1102     {
1103         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1104         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
1105         uint16_t doff = SmbReadAndXRespDataOff((const SmbReadAndXResp*)nb_ptr);
1106         uint32_t dcnt = SmbReadAndXRespDataCnt((const SmbReadAndXResp*)nb_ptr);
1107 
1108         dce2_move(nb_ptr, nb_len, com_size);
1109 
1110         if (DCE2_SmbCheckData(ssd, (const uint8_t*)smb_hdr, nb_ptr, nb_len,
1111             byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
1112             return DCE2_RET__ERROR;
1113 
1114         // This may move backwards
1115         dce2_move(nb_ptr, nb_len, ((const uint8_t*)smb_hdr + doff) - nb_ptr);
1116 
1117         if (dcnt > nb_len)
1118             dcnt = nb_len;
1119 
1120         return DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt);
1121     }
1122 
1123     return DCE2_RET__SUCCESS;
1124 }
1125 
1126 // SMB_COM_WRITE_ANDX
DCE2_SmbWriteAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1127 DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1128     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1129 {
1130     if (!DCE2_ComInfoCanProcessCommand(com_info))
1131     {
1132         DCE2_SmbFileTracker* ftracker = ssd->cur_rtracker->ftracker;
1133 
1134         if ((ftracker != nullptr) && ftracker->is_ipc
1135             && (ftracker->fp_writex_raw != nullptr))
1136         {
1137             ftracker->fp_writex_raw->remaining = 0;
1138             DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
1139         }
1140 
1141         return DCE2_RET__ERROR;
1142     }
1143 
1144     if (DCE2_ComInfoIsRequest(com_info)
1145         && (SmbWriteAndXReqStartRaw((const SmbWriteAndXReq*)nb_ptr)
1146         || SmbWriteAndXReqRaw((const SmbWriteAndXReq*)nb_ptr)))
1147     {
1148         DCE2_SmbFileTracker* ftracker =
1149             DCE2_SmbGetFileTracker(ssd, SmbWriteAndXReqFid((const SmbWriteAndXReq*)nb_ptr));
1150 
1151         // Raw mode is only applicable to named pipes.
1152         if ((ftracker != nullptr) && ftracker->is_ipc)
1153             return DCE2_SmbWriteAndXRawRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
1154     }
1155 
1156     if (DCE2_ComInfoIsRequest(com_info))
1157     {
1158         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1159         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
1160         uint16_t fid = SmbWriteAndXReqFid((const SmbWriteAndXReq*)nb_ptr);
1161         uint16_t doff = SmbWriteAndXReqDataOff((const SmbWriteAndXReq*)nb_ptr);
1162         uint32_t dcnt = SmbWriteAndXReqDataCnt((const SmbWriteAndXReq*)nb_ptr);
1163         uint64_t offset = SmbWriteAndXReqOffset((const SmbWriteAndXExtReq*)nb_ptr);
1164 
1165         dce2_move(nb_ptr, nb_len, com_size);
1166 
1167         if (DCE2_SmbCheckData(ssd, (const uint8_t*)smb_hdr, nb_ptr, nb_len,
1168             byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
1169             return DCE2_RET__ERROR;
1170 
1171         // This may move backwards
1172         dce2_move(nb_ptr, nb_len, ((const uint8_t*)smb_hdr + doff) - nb_ptr);
1173 
1174         if (dcnt > nb_len)
1175         {
1176             // Current Samba errors if data count is greater than data left
1177             if (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)
1178                 return DCE2_RET__ERROR;
1179 
1180             // Windows and early Samba just use what's left
1181             dcnt = nb_len;
1182         }
1183 
1184         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
1185     }
1186 
1187     return DCE2_RET__SUCCESS;
1188 }
1189 
1190 // SMB_COM_SESSION_SETUP_ANDX
DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1191 DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1192     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1193 {
1194     if (!DCE2_ComInfoCanProcessCommand(com_info))
1195         return DCE2_RET__ERROR;
1196 
1197     if (DCE2_ComInfoIsRequest(com_info))
1198     {
1199         uint16_t max_multiplex =
1200             SmbSessionSetupAndXReqMaxMultiplex((const SmbLm10_SessionSetupAndXReq*)nb_ptr);
1201 
1202         if (max_multiplex < ssd->max_outstanding_requests)
1203             ssd->max_outstanding_requests = max_multiplex;
1204 
1205         if (!DCE2_SmbFingerprintedClient(ssd) && DCE2_GcSmbFingerprintClient(
1206             (dce2SmbProtoConf*)ssd->sd.config))
1207         {
1208             uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1;
1209             uint16_t word_count = DCE2_ComInfoWordCount(com_info);
1210             uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1211             uint32_t i;
1212 
1213             DCE2_SmbSetFingerprintedClient(ssd);
1214 
1215             // OS and Lanman strings won't be in request
1216             if ((word_count != 13) && (word_count != 12))
1217                 return DCE2_RET__SUCCESS;
1218 
1219             if (word_count == 13)
1220             {
1221                 uint16_t oem_pass_len =
1222                     SmbNt10SessionSetupAndXReqOemPassLen((const SmbNt10_SessionSetupAndXReq*)nb_ptr);
1223                 uint16_t uni_pass_len =
1224                     SmbNt10SessionSetupAndXReqUnicodePassLen((const SmbNt10_SessionSetupAndXReq*)nb_ptr);
1225 
1226                 dce2_move(nb_ptr, nb_len, com_size);
1227 
1228                 if (((uint32_t)oem_pass_len + uni_pass_len) > nb_len)
1229                 {
1230                     return DCE2_RET__ERROR;
1231                 }
1232 
1233                 dce2_move(nb_ptr, nb_len, (oem_pass_len + uni_pass_len));
1234 
1235                 // If unicode there should be a padding byte if the password
1236                 // lengths are even since the command length is odd
1237                 if ((increment == 2) && (nb_len != 0) && !((oem_pass_len + uni_pass_len) & 1))
1238                     dce2_move(nb_ptr, nb_len, 1);
1239             }
1240             else  // Extended security blob version, word count of 12
1241             {
1242                 uint16_t blob_len =
1243                     SmbSessionSetupAndXReqBlobLen((const SmbNt10_SessionSetupAndXExtReq*)nb_ptr);
1244 
1245                 dce2_move(nb_ptr, nb_len, com_size);
1246 
1247                 if (blob_len > nb_len)
1248                 {
1249                     return DCE2_RET__ERROR;
1250                 }
1251 
1252                 dce2_move(nb_ptr, nb_len, blob_len);
1253 
1254                 // If unicode there should be a padding byte if the blob
1255                 // length is even since the command length is odd
1256                 if ((increment == 2) && (nb_len != 0) && !(blob_len & 1))
1257                     dce2_move(nb_ptr, nb_len, 1);
1258             }
1259 
1260             // Attempting to fingerprint Client Windows/Samba version.
1261             // Move past Account and Domain strings
1262             // Blob version doesn't have these as they're in the blob
1263             if (DCE2_ComInfoWordCount(com_info) == 13)
1264             {
1265                 int j;
1266 
1267                 for (j = 0; j < 2; j++)
1268                 {
1269                     assert(nb_ptr != nullptr);
1270                     while ((nb_len >= increment) && (*nb_ptr != '\0'))
1271                         dce2_move(nb_ptr, nb_len, increment);
1272 
1273                     // Just return success if we run out of data
1274                     if (nb_len < increment)
1275                     {
1276                         return DCE2_RET__SUCCESS;
1277                     }
1278 
1279                     // Move past null string terminator
1280                     dce2_move(nb_ptr, nb_len, increment);
1281                 }
1282             }
1283 
1284             if (nb_len < increment)
1285             {
1286                 return DCE2_RET__SUCCESS;
1287             }
1288 
1289             // Note the below is quick and dirty.  We're assuming the client
1290             // is kosher.  It's policy will be used when the server is
1291             // sending data to it.
1292 
1293             // Windows Vista and above don't put anything here
1294             assert(nb_ptr != nullptr);
1295             if (*nb_ptr == '\0')
1296             {
1297                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA);
1298                 return DCE2_RET__SUCCESS;
1299             }
1300 
1301             // Windows
1302             if (*nb_ptr == 'W')
1303             {
1304                 int state = OS_0;
1305                 int64_t rlen = (int64_t)nb_len;
1306 
1307                 while ((rlen > 0) && (state < OS_FS))
1308                 {
1309                     if (dce2_smb_os_fsm[state].input == (char)*nb_ptr)
1310                     {
1311                         state = dce2_smb_os_fsm[state].next_state;
1312                         dce2_move(nb_ptr, rlen, increment);
1313                     }
1314                     else
1315                     {
1316                         state = dce2_smb_os_fsm[state].fail_state;
1317                     }
1318                 }
1319 
1320                 switch (state)
1321                 {
1322                 case OS_WIN2000:
1323                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000);
1324                     break;
1325                 case OS_WINXP:
1326                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP);
1327                     break;
1328                 case OS_WIN2003:
1329                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003);
1330                     break;
1331                 default:
1332                     break;
1333                 }
1334 
1335                 return DCE2_RET__SUCCESS;
1336             }
1337 
1338             // Samba puts "Unix" in the OS field
1339             if (*nb_ptr != 'U')
1340             {
1341                 return DCE2_RET__SUCCESS;
1342             }
1343 
1344             // Move past OS string
1345             for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment)
1346                 ;
1347 
1348             if ((i + increment) >= nb_len)
1349             {
1350                 return DCE2_RET__SUCCESS;
1351             }
1352 
1353             // Move to LanMan string
1354             dce2_move(nb_ptr, nb_len, i + increment);
1355 
1356             // Samba
1357             if (*nb_ptr == 'S')
1358             {
1359                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
1360             }
1361         }
1362     }
1363     else
1364     {
1365         uint16_t uid = SmbUid(smb_hdr);
1366 
1367         DCE2_SmbInsertUid(ssd, uid);
1368         ssd->cur_rtracker->uid = uid;  // Set this in case there are chained commands
1369 
1370         if (!(ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED))
1371             ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
1372 
1373         if (!DCE2_SmbFingerprintedServer(ssd) && DCE2_GcSmbFingerprintServer(
1374             (dce2SmbProtoConf*)ssd->sd.config))
1375         {
1376             uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1;
1377             uint32_t i;
1378 
1379             DCE2_SmbSetFingerprintedServer(ssd);
1380 
1381             // Set the policy based on what the server reports in the OS field
1382             // for Windows and the LanManager field for Samba
1383 
1384             if (DCE2_ComInfoByteCount(com_info) == 0)
1385                 return DCE2_RET__SUCCESS;
1386 
1387             if (DCE2_ComInfoWordCount(com_info) == 3)
1388             {
1389                 dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
1390 
1391                 // Word count 3 and Unicode has a one byte pad
1392                 if ((increment == 2) && (nb_len != 0))
1393                     dce2_move(nb_ptr, nb_len, 1);
1394             }
1395             else  // Only valid word counts are 3 and 4
1396             {
1397                 uint16_t blob_len = SmbSessionSetupAndXRespBlobLen(
1398                     (const SmbNt10_SessionSetupAndXExtResp*)nb_ptr);
1399 
1400                 dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
1401 
1402                 if (blob_len > nb_len)
1403                 {
1404                     return DCE2_RET__ERROR;
1405                 }
1406 
1407                 dce2_move(nb_ptr, nb_len, blob_len);
1408 
1409                 if ((increment == 2) && (nb_len != 0) && !(blob_len & 1))
1410                     dce2_move(nb_ptr, nb_len, 1);
1411             }
1412 
1413             // Attempting to fingerprint Server Windows/Samba version.
1414             // Note the below is quick and dirty.  We're assuming the server
1415             // is kosher.  It's policy will be used when the client is
1416             // sending data to it.
1417             assert(nb_ptr != nullptr);
1418             if ((nb_len < increment) || (*nb_ptr == '\0'))
1419             {
1420                 return DCE2_RET__SUCCESS;
1421             }
1422 
1423             // Windows
1424             if (*nb_ptr == 'W')
1425             {
1426                 int state = OS_0;
1427                 int64_t rlen = (int64_t)nb_len;
1428 
1429                 while ((rlen > 0) && (state < OS_FS))
1430                 {
1431                     if (dce2_smb_os_fsm[state].input == (char)*nb_ptr)
1432                     {
1433                         state = dce2_smb_os_fsm[state].next_state;
1434                         dce2_move(nb_ptr, rlen, increment);
1435                     }
1436                     else
1437                     {
1438                         state = dce2_smb_os_fsm[state].fail_state;
1439                     }
1440                 }
1441 
1442                 switch (state)
1443                 {
1444                 case OS_WIN2000:
1445                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000);
1446                     break;
1447                 case OS_WINXP:
1448                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP);
1449                     break;
1450                 case OS_WIN2003:
1451                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003);
1452                     break;
1453                 case OS_WIN2008:
1454                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2008);
1455                     break;
1456                 case OS_WINVISTA:
1457                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA);
1458                     break;
1459                 case OS_WIN7:
1460                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN7);
1461                     break;
1462                 default:
1463                     break;
1464                 }
1465 
1466                 return DCE2_RET__SUCCESS;
1467             }
1468 
1469             // Samba puts "Unix" in the OS field
1470             if (*nb_ptr != 'U')
1471             {
1472                 return DCE2_RET__SUCCESS;
1473             }
1474 
1475             // Move past OS string
1476             for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment)
1477                 ;
1478 
1479             if ((i + increment) >= nb_len)
1480             {
1481                 return DCE2_RET__SUCCESS;
1482             }
1483 
1484             // Move to LanMan string
1485             dce2_move(nb_ptr, nb_len, i + increment);
1486 
1487             // Samba
1488             if (*nb_ptr == 'S')
1489             {
1490                 uint8_t r1 = 0;  // Release version first digit
1491                 uint8_t r2 = 0;  // Release version second digit
1492 
1493                 // Get Major version
1494                 for (i = 0; (i < nb_len) && (*nb_ptr != '\0'); i += increment)
1495                 {
1496                     if (isdigit((int)nb_ptr[i]))
1497                         break;
1498                 }
1499 
1500                 if ((i == nb_len) || (*nb_ptr == '\0'))
1501                 {
1502                     return DCE2_RET__SUCCESS;
1503                 }
1504 
1505                 // If less than 3 set policy to earliest Samba policy we use
1506                 if ((nb_ptr[i] == '0') || (nb_ptr[i] == '1') || (nb_ptr[i] == '2'))
1507                 {
1508                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20);
1509                     return DCE2_RET__SUCCESS;
1510                 }
1511 
1512                 // Need ".\d.\d\d" or ".\d.\d\x00"
1513                 if (i + increment*5 > nb_len)
1514                 {
1515                     return DCE2_RET__SUCCESS;
1516                 }
1517 
1518                 i += increment*2;
1519 
1520                 // If it's not 0, then set to latest Samba policy we use
1521                 if (nb_ptr[i] != '0')
1522                 {
1523                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
1524                     return DCE2_RET__SUCCESS;
1525                 }
1526 
1527                 r1 = nb_ptr[i + increment*2];
1528                 r2 = nb_ptr[i + increment*3];
1529 
1530                 // First digit is 1 or no second digit or 20, Samba 3.0.20
1531                 if ((r1 == '1') || (r2 == '\0') || ((r1 == '2') && (r2 == '0')))
1532                 {
1533                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20);
1534                     return DCE2_RET__SUCCESS;
1535                 }
1536 
1537                 // 21 or 22, Samba 3.0.22
1538                 if ((r1 == '2') && (r2 <= '2'))
1539                 {
1540                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_22);
1541                     return DCE2_RET__SUCCESS;
1542                 }
1543 
1544                 // 23, 24 ... 30 ... 37, Samba 3.0.37
1545                 if ((r1 == '2') || ((r1 == '3') && (r2 <= '7')))
1546                 {
1547                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_37);
1548                     return DCE2_RET__SUCCESS;
1549                 }
1550 
1551                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
1552             }
1553         }
1554     }
1555 
1556     return DCE2_RET__SUCCESS;
1557 }
1558 
1559 // SMB_COM_NEGOTIATE
DCE2_SmbNegotiate(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1560 DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
1561     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1562 {
1563     if (!DCE2_ComInfoCanProcessCommand(com_info))
1564         return DCE2_RET__ERROR;
1565 
1566     if (DCE2_ComInfoIsRequest(com_info))
1567     {
1568         // Have at least 2 bytes based on byte count check done earlier
1569         const uint8_t* term_ptr;
1570         int ntlm_index = 0;
1571         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1572 
1573         dce2_move(nb_ptr, nb_len, com_size);
1574 
1575         while ((term_ptr = (const uint8_t*)memchr(nb_ptr, '\0', nb_len)) != nullptr)
1576         {
1577             if (!SmbFmtDialect(*nb_ptr))
1578             {
1579                 dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
1580                     ssd->sd);
1581 
1582                 // Windows errors if bad format
1583                 if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
1584                 {
1585                     return DCE2_RET__ERROR;
1586                 }
1587             }
1588 
1589             // Move past format
1590             dce2_move(nb_ptr, nb_len, 1);
1591 
1592             if (nb_len == 0)
1593                 break;
1594 
1595             // Just a null byte - acceptable by Samba and Windows
1596             if (term_ptr == nb_ptr)
1597                 continue;
1598 
1599             if ((*nb_ptr == 'N')
1600                 && (strncmp((const char*)nb_ptr, SMB_DIALECT_NT_LM_012, term_ptr - nb_ptr) == 0))
1601                 break;
1602 
1603             // Move past string and null byte
1604             dce2_move(nb_ptr, nb_len, (term_ptr - nb_ptr) + 1);
1605 
1606             ntlm_index++;
1607         }
1608 
1609         if (term_ptr != nullptr)
1610         {
1611             ssd->dialect_index = ntlm_index;
1612         }
1613         else
1614         {
1615             ssd->dialect_index = DCE2_SENTINEL;
1616             dce_alert(GID_DCE2, DCE2_SMB_DEPR_DIALECT_NEGOTIATED,
1617                 (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
1618         }
1619     }
1620     else
1621     {
1622         const uint16_t dialect_index =
1623             SmbNegotiateRespDialectIndex((const SmbCore_NegotiateProtocolResp*)nb_ptr);
1624 
1625         if ((ssd->dialect_index != DCE2_SENTINEL) && (dialect_index != ssd->dialect_index))
1626             dce_alert(GID_DCE2, DCE2_SMB_DEPR_DIALECT_NEGOTIATED,
1627                 (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
1628 
1629         ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
1630 
1631         if (DCE2_ComInfoWordCount(com_info) == 17)
1632         {
1633             ssd->max_outstanding_requests =
1634                 SmbNt_NegotiateRespMaxMultiplex((const SmbNt_NegotiateProtocolResp*)nb_ptr);
1635         }
1636         else if (DCE2_ComInfoWordCount(com_info) == 13)
1637         {
1638             ssd->max_outstanding_requests =
1639                 SmbLm_NegotiateRespMaxMultiplex((const SmbLm10_NegotiateProtocolResp*)nb_ptr);
1640         }
1641         else
1642         {
1643             ssd->max_outstanding_requests = 1;
1644         }
1645     }
1646 
1647     return DCE2_RET__SUCCESS;
1648 }
1649 
1650 // SMB_COM_TREE_CONNECT_ANDX
DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1651 DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1652     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1653 {
1654     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1655 
1656     if (!DCE2_ComInfoCanProcessCommand(com_info))
1657         return DCE2_RET__ERROR;
1658 
1659     if (DCE2_ComInfoIsRequest(com_info))
1660     {
1661         if (DCE2_ScSmbInvalidShares((dce2SmbProtoConf*)ssd->sd.config) != nullptr)
1662         {
1663             uint16_t pass_len = SmbTreeConnectAndXReqPassLen((const SmbTreeConnectAndXReq*)nb_ptr);
1664             dce2_move(nb_ptr, nb_len, com_size);
1665             if (pass_len >= nb_len)
1666                 return DCE2_RET__ERROR;
1667 
1668             // Move past password length
1669             dce2_move(nb_ptr, nb_len, pass_len);
1670 
1671             const uint8_t* bs = nullptr;
1672             // Move past path components
1673             assert(nb_ptr != nullptr);
1674             while ((bs = (const uint8_t*)memchr(nb_ptr, '\\', nb_len)) != nullptr)
1675                 dce2_move(nb_ptr, nb_len, (bs - nb_ptr) + 1);
1676 
1677             // Move past null byte if unicode
1678             if (SmbUnicode(smb_hdr) && (nb_len != 0))
1679                 dce2_move(nb_ptr, nb_len, 1);
1680 
1681             if (nb_len != 0)
1682                 DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
1683         }
1684     }
1685     else
1686     {
1687         dce2_move(nb_ptr, nb_len, com_size);
1688 
1689         int state = SERVICE_0;
1690         while ((nb_len > 0) && (state < SERVICE_FS))
1691         {
1692             if (dce2_smb_service_fsm[state].input == (char)*nb_ptr)
1693             {
1694                 state = dce2_smb_service_fsm[state].next_state;
1695                 dce2_move(nb_ptr, nb_len, 1);
1696             }
1697             else
1698             {
1699                 state = dce2_smb_service_fsm[state].fail_state;
1700             }
1701         }
1702 
1703         uint16_t tid = SmbTid(smb_hdr);
1704         bool is_ipc = true;
1705         switch (state)
1706         {
1707         case SERVICE_IPC:
1708             break;
1709         case SERVICE_DISK:
1710             is_ipc = false;
1711             break;
1712         default:
1713             return DCE2_RET__IGNORE;
1714         }
1715 
1716         // Insert tid into list
1717         DCE2_SmbInsertTid(ssd, tid, is_ipc);
1718         ssd->cur_rtracker->tid = tid;  // Set this in case there are chained commands
1719     }
1720 
1721     return DCE2_RET__SUCCESS;
1722 }
1723 
1724 // SMB_COM_TREE_CONNECT
DCE2_SmbTreeConnect(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1725 DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1726     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1727 {
1728     if (!DCE2_ComInfoCanProcessCommand(com_info))
1729         return DCE2_RET__ERROR;
1730 
1731     if (DCE2_ComInfoIsRequest(com_info))
1732     {
1733         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
1734 
1735         // Have at least 4 bytes of data based on byte count check done earlier
1736 
1737         dce2_move(nb_ptr, nb_len, com_size);
1738 
1739         // If unicode flag is set, strings, except possibly the service string
1740         // are going to be unicode.  The NT spec specifies that unicode strings
1741         // must be word aligned with respect to the beginning of the SMB and that for
1742         // type-prefixed strings (this case), the padding byte is found after the
1743         // type format byte.
1744 
1745         // This byte will realign things.
1746         if (*nb_ptr != SMB_FMT__ASCII)
1747         {
1748             dce_alert(GID_DCE2, DCE2_SMB_BAD_FORM, (dce2CommonStats*)&dce2_smb_stats,
1749                 ssd->sd);
1750             return DCE2_RET__ERROR;
1751         }
1752 
1753         dce2_move(nb_ptr, nb_len, 1);
1754 
1755         // IPC$ does not need to be case sensitive.  And the case sensitivity flag in
1756         // the SMB header doesn't seem to have any effect on this.
1757         const uint8_t* bs = nullptr;
1758         while ((bs = (const uint8_t*)memchr(nb_ptr, '\\', nb_len)) != nullptr)
1759             dce2_move(nb_ptr, nb_len, (bs - nb_ptr) + 1);
1760 
1761         bool unicode = SmbUnicode(smb_hdr);
1762         if (unicode && (nb_len > 0))
1763             dce2_move(nb_ptr, nb_len, 1);
1764 
1765         // Check for invalid shares first
1766         if ((DCE2_ScSmbInvalidShares((dce2SmbProtoConf*)ssd->sd.config) != nullptr) && (nb_len >
1767             0))
1768             DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
1769 
1770         int state = SHARE_0;
1771         uint8_t increment = unicode ? 2 : 1;
1772         while ((nb_len >= increment) && (state < SHARE_FS))
1773         {
1774             if (dce2_ipc_share_fsm[state].input == toupper((int)nb_ptr[0]))
1775             {
1776                 if (unicode && (nb_ptr[1] != 0))
1777                     break;
1778                 state = dce2_ipc_share_fsm[state].next_state;
1779                 dce2_move(nb_ptr, nb_len, increment);
1780             }
1781             else
1782             {
1783                 state = dce2_ipc_share_fsm[state].fail_state;
1784             }
1785         }
1786 
1787         bool is_ipc = false;
1788         switch (state)
1789         {
1790         case SHARE_IPC:
1791             is_ipc = true;
1792             break;
1793         case SHARE_FS:
1794         default:
1795             break;
1796         }
1797 
1798         ssd->cur_rtracker->is_ipc = is_ipc;
1799     }
1800     else
1801     {
1802         // FIXIT-L What if the TID in the SMB header differs from that returned
1803         // in the TreeConnect command response?
1804         uint16_t tid = SmbTid(smb_hdr);
1805         DCE2_SmbInsertTid(ssd, tid, ssd->cur_rtracker->is_ipc);
1806     }
1807 
1808     return DCE2_RET__SUCCESS;
1809 }
1810 
1811 // SMB_COM_NT_CREATE_ANDX
DCE2_SmbNtCreateAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)1812 DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1813     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
1814 {
1815     if (!DCE2_ComInfoCanProcessCommand(com_info))
1816         return DCE2_RET__ERROR;
1817 
1818     if (DCE2_ComInfoIsResponse(com_info))
1819     {
1820         const uint16_t fid = SmbNtCreateAndXRespFid((const SmbNtCreateAndXResp*)nb_ptr);
1821         DCE2_SmbFileTracker* ftracker = nullptr;
1822 
1823         // Set request tracker's current file tracker in case of chained commands
1824         switch (SmbAndXCom2((const SmbAndXCommon*)nb_ptr))
1825         {
1826         // This is in case in the request a write was chained to an open
1827         // in which case the write will be to the newly opened file
1828         case SMB_COM_WRITE:
1829         case SMB_COM_WRITE_ANDX:
1830         case SMB_COM_TRANSACTION:
1831         case SMB_COM_READ_ANDX:
1832             ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
1833             break;
1834         default:
1835             break;
1836         }
1837 
1838         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
1839         {
1840             const bool is_directory = SmbNtCreateAndXRespDirectory((const SmbNtCreateAndXResp*)nb_ptr);
1841             const uint16_t resource_type =
1842                 SmbNtCreateAndXRespResourceType((const SmbNtCreateAndXResp*)nb_ptr);
1843 
1844             if (is_directory || !SmbResourceTypeDisk(resource_type))
1845             {
1846                 if (ftracker != nullptr)
1847                     DCE2_SmbRemoveFileTracker(ssd, ftracker);
1848                 return DCE2_RET__SUCCESS;
1849             }
1850 
1851             // Give preference to files opened with the sequential only flag set
1852             if (((ssd->fapi_ftracker == nullptr) || !ssd->fapi_ftracker->ff_sequential_only)
1853                 && (ftracker == nullptr) && ssd->cur_rtracker->sequential_only)
1854             {
1855                 DCE2_SmbAbortFileAPI(ssd);
1856             }
1857         }
1858 
1859         if (ftracker == nullptr)
1860         {
1861             ftracker = DCE2_SmbNewFileTracker(ssd,
1862                 ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
1863             if (ftracker == nullptr)
1864                 return DCE2_RET__ERROR;
1865         }
1866 
1867         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
1868 
1869         if (!ftracker->is_ipc)
1870         {
1871             const uint32_t create_disposition =
1872                 SmbNtCreateAndXRespCreateDisposition((const SmbNtCreateAndXResp*)nb_ptr);
1873 
1874             if (SmbCreateDispositionRead(create_disposition))
1875             {
1876                 ftracker->ff_file_size =
1877                     SmbNtCreateAndXRespEndOfFile((const SmbNtCreateAndXResp*)nb_ptr);
1878             }
1879             else
1880             {
1881                 ftracker->ff_file_size = ssd->cur_rtracker->file_size;
1882                 ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
1883             }
1884 
1885             ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only;
1886         }
1887 
1888         ssd->cur_rtracker->ftracker = ftracker;
1889     }
1890     else
1891     {
1892         bool is_ipc = DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid);
1893         uint8_t smb_com2 = SmbAndXCom2((const SmbAndXCommon*)nb_ptr);
1894         uint16_t file_name_length =
1895             SmbNtCreateAndXReqFileNameLen((const SmbNtCreateAndXReq*)nb_ptr);
1896 
1897         if (!is_ipc)
1898         {
1899             uint32_t ext_file_attrs =
1900                 SmbNtCreateAndXReqFileAttrs((const SmbNtCreateAndXReq*)nb_ptr);
1901 
1902             if (SmbEvasiveFileAttrs(ext_file_attrs))
1903                 dce_alert(GID_DCE2, DCE2_SMB_EVASIVE_FILE_ATTRS,
1904                     (dce2CommonStats*)&dce2_smb_stats, ssd->sd);
1905             // If the file is going to be accessed sequentially, track it.
1906             if (SmbNtCreateAndXReqSequentialOnly((const SmbNtCreateAndXReq*)nb_ptr))
1907                 ssd->cur_rtracker->sequential_only = true;
1908 
1909             ssd->cur_rtracker->file_size = SmbNtCreateAndXReqAllocSize(
1910                 (const SmbNtCreateAndXReq*)nb_ptr);
1911         }
1912 
1913         dce2_move(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
1914 
1915         if (file_name_length > DCE2_SMB_MAX_PATH_LEN)
1916             return DCE2_RET__ERROR;
1917 
1918         uint32_t pad = 0;
1919         const bool unicode = SmbUnicode(smb_hdr);
1920         if (unicode)
1921             pad = (nb_ptr - (const uint8_t*)smb_hdr) & 1;
1922 
1923         if (nb_len < (pad + file_name_length))
1924             return DCE2_RET__ERROR;
1925 
1926         dce2_move(nb_ptr, nb_len, pad);
1927 
1928         // Samba allows chaining OpenAndX/NtCreateAndX so might have
1929         // already been set.
1930         if (ssd->cur_rtracker->file_name == nullptr)
1931         {
1932             ssd->cur_rtracker->file_name =
1933                 get_smb_file_name(nb_ptr, file_name_length, unicode,
1934                 &ssd->cur_rtracker->file_name_size);
1935         }
1936 
1937         if (is_ipc)
1938         {
1939             switch (smb_com2)
1940             {
1941             case SMB_COM_READ_ANDX:
1942                 if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
1943                     return DCE2_RET__ERROR;
1944                 break;
1945             default:
1946                 break;
1947             }
1948         }
1949     }
1950 
1951     return DCE2_RET__SUCCESS;
1952 }
1953 
1954 // SMB_COM_TREE_DISCONNECT
DCE2_SmbTreeDisconnect(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t *,uint32_t)1955 DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
1956     const DCE2_SmbComInfo* com_info, const uint8_t*, uint32_t)
1957 {
1958     if (!DCE2_ComInfoCanProcessCommand(com_info))
1959         return DCE2_RET__ERROR;
1960 
1961     if (DCE2_ComInfoIsResponse(com_info))
1962         DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
1963 
1964     return DCE2_RET__SUCCESS;
1965 }
1966 
1967 // SMB_COM_LOGOFF_ANDX
DCE2_SmbLogoffAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t *,uint32_t)1968 DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
1969     const DCE2_SmbComInfo* com_info, const uint8_t*, uint32_t)
1970 {
1971     if (!DCE2_ComInfoCanProcessCommand(com_info))
1972         return DCE2_RET__ERROR;
1973 
1974     if (DCE2_ComInfoIsResponse(com_info))
1975     {
1976         DCE2_SmbRemoveUid(ssd, ssd->cur_rtracker->uid);
1977 
1978         switch (DCE2_SsnGetServerPolicy(&ssd->sd))
1979         {
1980         case DCE2_POLICY__WIN2000:
1981         case DCE2_POLICY__WINXP:
1982         case DCE2_POLICY__WINVISTA:
1983         case DCE2_POLICY__WIN2003:
1984         case DCE2_POLICY__WIN2008:
1985         case DCE2_POLICY__WIN7:
1986             /* Windows responds to a chained LogoffAndX => SessionSetupAndX with a
1987              * word count 3 LogoffAndX without the chained SessionSetupAndX */
1988             if (DCE2_ComInfoWordCount(com_info) == 3)
1989             {
1990                 uint16_t uid = SmbUid(smb_hdr);
1991                 DCE2_SmbInsertUid(ssd, uid);
1992                 ssd->cur_rtracker->uid = uid;      // Set this in case there are chained commands
1993             }
1994             break;
1995         default:
1996             break;
1997         }
1998     }
1999 
2000     return DCE2_RET__SUCCESS;
2001 }
2002 
2003 // SMB_COM_READ_RAW
DCE2_SmbReadRaw(DCE2_SmbSsnData * ssd,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t)2004 DCE2_Ret DCE2_SmbReadRaw(DCE2_SmbSsnData* ssd, const SmbNtHdr*,
2005     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t)
2006 {
2007     if (!DCE2_ComInfoCanProcessCommand(com_info))
2008         return DCE2_RET__ERROR;
2009 
2010     if (DCE2_ComInfoIsRequest(com_info))
2011     {
2012         DCE2_SmbFileTracker* ftracker =
2013             DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
2014             ssd->cur_rtracker->tid, SmbReadRawReqFid((const SmbReadRawReq*)nb_ptr));
2015 
2016         ssd->cur_rtracker->ftracker = ftracker;
2017         ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
2018         if ((ftracker != nullptr) && !ftracker->is_ipc)
2019             ssd->cur_rtracker->file_offset = SmbReadRawReqOffset((const SmbReadRawExtReq*)nb_ptr);
2020     }
2021     else
2022     {
2023         // The server response is the raw data.  Supposedly if an error occurs,
2024         // the server will send a 0 byte read.  Just the NetBIOS header with
2025         // zero byte length.  Client upon getting the zero read is supposed to issue
2026         // another read using ReadAndX or Read to get the error.
2027         return DCE2_RET__ERROR;
2028     }
2029 
2030     return DCE2_RET__SUCCESS;
2031 }
2032 
2033 // SMB_COM_WRITE_RAW
DCE2_SmbWriteRaw(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)2034 DCE2_Ret DCE2_SmbWriteRaw(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
2035     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
2036 {
2037     if (!DCE2_ComInfoCanProcessCommand(com_info))
2038         return DCE2_RET__ERROR;
2039 
2040     if (DCE2_ComInfoIsRequest(com_info))
2041     {
2042         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
2043         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
2044         uint16_t fid = SmbWriteRawReqFid((const SmbWriteRawReq*)nb_ptr);
2045         uint16_t tdcnt = SmbWriteRawReqTotalCount((const SmbWriteRawReq*)nb_ptr);
2046         bool writethrough = SmbWriteRawReqWriteThrough((const SmbWriteRawReq*)nb_ptr);
2047         uint16_t doff = SmbWriteRawReqDataOff((const SmbWriteRawReq*)nb_ptr);
2048         uint16_t dcnt = SmbWriteRawReqDataCnt((const SmbWriteRawReq*)nb_ptr);
2049         uint64_t offset = SmbWriteRawReqOffset((const SmbWriteRawExtReq*)nb_ptr);
2050 
2051         dce2_move(nb_ptr, nb_len, com_size);
2052 
2053         if (DCE2_SmbCheckTotalCount(ssd, tdcnt, dcnt, 0) != DCE2_RET__SUCCESS)
2054             return DCE2_RET__ERROR;
2055 
2056         if (DCE2_SmbCheckData(ssd, (const uint8_t*)smb_hdr, nb_ptr, nb_len,
2057             byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
2058             return DCE2_RET__ERROR;
2059 
2060         // This may move backwards
2061         dce2_move(nb_ptr, nb_len, ((const uint8_t*)smb_hdr + doff) - nb_ptr);
2062 
2063         if (dcnt > nb_len)
2064         {
2065             dce_alert(GID_DCE2, DCE2_SMB_NB_LT_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
2066                 ssd->sd);
2067             return DCE2_RET__ERROR;
2068         }
2069 
2070         // If all of the data wasn't written in this request, the server will
2071         // send an interim SMB_COM_WRITE_RAW response and the client will send
2072         // the rest of the data raw.  In this case if the WriteThrough flag is
2073         // not set, the server will not send a final SMB_COM_WRITE_COMPLETE
2074         // response.  If all of the data is in this request the server will
2075         // send an SMB_COM_WRITE_COMPLETE response regardless of whether or
2076         // not the WriteThrough flag is set.
2077         if (dcnt != tdcnt)
2078         {
2079             ssd->cur_rtracker->writeraw_writethrough = writethrough;
2080             ssd->cur_rtracker->writeraw_remaining = tdcnt - dcnt;
2081         }
2082 
2083         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
2084     }
2085     else
2086     {
2087         DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
2088 
2089         // Samba messes this up and sends a request instead of an interim
2090         // response and a response instead of a Write Complete response.
2091         switch (policy)
2092         {
2093         case DCE2_POLICY__SAMBA:
2094         case DCE2_POLICY__SAMBA_3_0_37:
2095         case DCE2_POLICY__SAMBA_3_0_22:
2096         case DCE2_POLICY__SAMBA_3_0_20:
2097             if (SmbType(smb_hdr) != SMB_TYPE__REQUEST)
2098                 return DCE2_RET__SUCCESS;
2099             break;
2100         default:
2101             break;
2102         }
2103 
2104         // If all the data wasn't written initially this interim response will
2105         // be sent by the server and the raw data will ensue from the client.
2106         ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
2107     }
2108 
2109     return DCE2_RET__SUCCESS;
2110 }
2111 
2112 // SMB_COM_WRITE_COMPLETE
DCE2_SmbWriteComplete(DCE2_SmbSsnData *,const SmbNtHdr *,const DCE2_SmbComInfo * com_info,const uint8_t *,uint32_t)2113 DCE2_Ret DCE2_SmbWriteComplete(DCE2_SmbSsnData*, const SmbNtHdr*,
2114     const DCE2_SmbComInfo* com_info, const uint8_t*, uint32_t)
2115 {
2116     if (!DCE2_ComInfoCanProcessCommand(com_info))
2117         return DCE2_RET__ERROR;
2118 
2119     return DCE2_RET__SUCCESS;
2120 }
2121 
2122 // SMB_COM_WRITE_AND_CLOSE
DCE2_SmbWriteAndClose(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)2123 DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr,
2124     const DCE2_SmbComInfo* com_info, const uint8_t* nb_ptr, uint32_t nb_len)
2125 {
2126     if (!DCE2_ComInfoCanProcessCommand(com_info))
2127         return DCE2_RET__ERROR;
2128 
2129     if (DCE2_ComInfoIsRequest(com_info))
2130     {
2131         // Have at least one byte based on byte count check done earlier
2132 
2133         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
2134         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
2135         uint16_t dcnt = SmbWriteAndCloseReqCount((const SmbWriteAndCloseReq*)nb_ptr);
2136         uint16_t fid = SmbWriteAndCloseReqFid((const SmbWriteAndCloseReq*)nb_ptr);
2137         uint32_t offset = SmbWriteAndCloseReqOffset((const SmbWriteAndCloseReq*)nb_ptr);
2138 
2139         dce2_move(nb_ptr, nb_len, (com_size + 1));
2140 
2141         if (DCE2_SmbCheckData(ssd, (const uint8_t*)smb_hdr, nb_ptr, nb_len,
2142             byte_count, dcnt,
2143             (uint16_t)(sizeof(SmbNtHdr) + com_size + 1)) != DCE2_RET__SUCCESS)
2144             return DCE2_RET__ERROR;
2145 
2146         if (dcnt == 0)
2147         {
2148             dce_alert(GID_DCE2, DCE2_SMB_DCNT_ZERO, (dce2CommonStats*)&dce2_smb_stats,
2149                 ssd->sd);
2150             return DCE2_RET__ERROR;
2151         }
2152 
2153         // WriteAndClose has a 1 byte pad after the byte count
2154         if ((uint32_t)(dcnt + 1) != (uint32_t)byte_count)
2155             dce_alert(GID_DCE2, DCE2_SMB_INVALID_DSIZE, (dce2CommonStats*)&dce2_smb_stats,
2156                 ssd->sd);
2157 
2158         if (dcnt > nb_len)
2159             dcnt = (uint16_t)nb_len;
2160 
2161         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
2162     }
2163     else
2164     {
2165         DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
2166     }
2167 
2168     return DCE2_RET__SUCCESS;
2169 }
2170