1 /****************************************************************************
2  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3  * Copyright (C) 2008-2013 Sourcefire, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License Version 2 as
7  * published by the Free Software Foundation.  You may not use, modify or
8  * distribute this program under any other version of the GNU General
9  * Public License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  ****************************************************************************
21  *
22  ****************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "sf_types.h"
29 #include "spp_dce2.h"
30 #include "dce2_smb.h"
31 #include "dce2_tcp.h"
32 #include "dce2_co.h"
33 #include "snort_dce2.h"
34 #include "dce2_config.h"
35 #include "dce2_memory.h"
36 #include "dce2_utils.h"
37 #include "dce2_debug.h"
38 #include "dce2_stats.h"
39 #include "dce2_event.h"
40 #include "smb.h"
41 #include "sf_snort_packet.h"
42 #include "sf_types.h"
43 #include "stream_api.h"
44 #include "session_api.h"
45 #include "profiler.h"
46 #include "snort_debug.h"
47 #include "sf_dynamic_preprocessor.h"
48 #include "file_api.h"
49 #include "dce2_smb2.h"
50 
51 #ifdef DUMP_BUFFER
52 #include "dcerpc2_buffer_dump.h"
53 #endif
54 
55 #ifndef WIN32
56 #include <arpa/inet.h>  /* for ntohl */
57 #endif  /* WIN32 */
58 
59 /********************************************************************
60  * Enums
61  ********************************************************************/
62 typedef enum _DCE2_SmbComError
63 {
64     // No errors associated with the command
65     DCE2_SMB_COM_ERROR__COMMAND_OK          = 0x0000,
66 
67     // An error was reported in the SMB response header
68     DCE2_SMB_COM_ERROR__STATUS_ERROR        = 0x0001,
69 
70     // An invalid word count makes it unlikely any data accessed will be correct
71     // and if accessed the possibility of accessing out of bounds data
72     DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT  = 0x0002,
73 
74     // An invalid byte count just means the byte count is not right for
75     // the command processed.  The command can still be processed but
76     // the byte count should not be used.  In general, the byte count
77     // should not be used since Windows and Samba often times ignore it
78     DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT  = 0x0004,
79 
80     // Not enough data to process command so don't try to access any
81     // of the command's header or data.
82     DCE2_SMB_COM_ERROR__BAD_LENGTH          = 0x0008
83 
84 } DCE2_SmbComError;
85 
86 /********************************************************************
87  * Structures
88  ********************************************************************/
89 typedef struct _DCE2_SmbComInfo
90 {
91     int smb_type;   // SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
92     int cmd_error;  // mask of DCE2_SmbComError
93     uint8_t smb_com;
94     uint8_t word_count;
95     uint16_t byte_count;
96     uint16_t cmd_size;
97 
98 } DCE2_SmbComInfo;
99 
100 unsigned smb_upload_ret_cb_id = 0;
101 
102 // Inline accessor functions for DCE2_SmbComInfo
103 
DCE2_ComInfoIsResponse(const DCE2_SmbComInfo * com_info)104 static inline bool DCE2_ComInfoIsResponse(const DCE2_SmbComInfo *com_info)
105 {
106     return (com_info->smb_type == SMB_TYPE__RESPONSE) ? true : false;
107 }
108 
DCE2_ComInfoIsRequest(const DCE2_SmbComInfo * com_info)109 static inline bool DCE2_ComInfoIsRequest(const DCE2_SmbComInfo *com_info)
110 {
111     return (com_info->smb_type == SMB_TYPE__REQUEST) ? true : false;
112 }
113 
DCE2_ComInfoWordCount(const DCE2_SmbComInfo * com_info)114 static inline uint8_t DCE2_ComInfoWordCount(const DCE2_SmbComInfo *com_info)
115 {
116     return com_info->word_count;
117 }
118 
DCE2_ComInfoSmbCom(const DCE2_SmbComInfo * com_info)119 static inline uint8_t DCE2_ComInfoSmbCom(const DCE2_SmbComInfo *com_info)
120 {
121     return com_info->smb_com;
122 }
123 
DCE2_ComInfoByteCount(const DCE2_SmbComInfo * com_info)124 static inline uint16_t DCE2_ComInfoByteCount(const DCE2_SmbComInfo *com_info)
125 {
126     return com_info->byte_count;
127 }
128 
DCE2_ComInfoCommandSize(const DCE2_SmbComInfo * com_info)129 static inline uint16_t DCE2_ComInfoCommandSize(const DCE2_SmbComInfo *com_info)
130 {
131     return com_info->cmd_size;
132 }
133 
DCE2_ComInfoIsStatusError(const DCE2_SmbComInfo * com_info)134 static inline bool DCE2_ComInfoIsStatusError(const DCE2_SmbComInfo *com_info)
135 {
136     return (com_info->cmd_error & DCE2_SMB_COM_ERROR__STATUS_ERROR) ? true : false;
137 }
138 
DCE2_ComInfoIsInvalidWordCount(const DCE2_SmbComInfo * com_info)139 static inline bool DCE2_ComInfoIsInvalidWordCount(const DCE2_SmbComInfo *com_info)
140 {
141     return (com_info->cmd_error & DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT) ? true : false;
142 }
143 
DCE2_ComInfoIsBadLength(const DCE2_SmbComInfo * com_info)144 static inline bool DCE2_ComInfoIsBadLength(const DCE2_SmbComInfo *com_info)
145 {
146     return (com_info->cmd_error & DCE2_SMB_COM_ERROR__BAD_LENGTH) ? true : false;
147 }
148 
149 // If this returns false, the command should not be processed
DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo * com_info)150 static inline bool DCE2_ComInfoCanProcessCommand(const DCE2_SmbComInfo *com_info)
151 {
152     if (DCE2_ComInfoIsBadLength(com_info)
153             || DCE2_ComInfoIsStatusError(com_info)
154             || DCE2_ComInfoIsInvalidWordCount(com_info))
155         return false;
156     return true;
157 }
158 
159 /********************************************************************
160  * Global variables
161  ********************************************************************/
162 typedef DCE2_Ret (*DCE2_SmbComFunc)(DCE2_SmbSsnData *, const SmbNtHdr *,
163         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
164 
165 static DCE2_SmbComFunc smb_com_funcs[SMB_MAX_NUM_COMS];
166 static uint8_t smb_wcts[SMB_MAX_NUM_COMS][2][32];
167 static uint16_t smb_bccs[SMB_MAX_NUM_COMS][2][2];
168 static DCE2_SmbComFunc smb_chain_funcs[DCE2_POLICY__MAX][SMB_ANDX_COM__MAX][SMB_MAX_NUM_COMS];
169 static bool smb_deprecated_coms[SMB_MAX_NUM_COMS];
170 static bool smb_unusual_coms[SMB_MAX_NUM_COMS];
171 
172 // File name of the current file we are tracking for logging since the
173 // file tracker may be gone before logging occurs.
174 uint8_t smb_file_name[2*DCE2_SMB_MAX_PATH_LEN + UTF_16_LE_BOM_LEN + 2];
175 uint16_t smb_file_name_len;
176 
177 // Exported
178 SmbAndXCom smb_chain_map[SMB_MAX_NUM_COMS];
179 
180 const char *smb_com_strings[SMB_MAX_NUM_COMS] = {
181     "Create Directory",            // 0x00
182     "Delete Directory",            // 0x01
183     "Open",                        // 0x02
184     "Create",                      // 0x03
185     "Close",                       // 0x04
186     "Flush",                       // 0x05
187     "Delete",                      // 0x06
188     "Rename",                      // 0x07
189     "Query Information",           // 0x08
190     "Set Information",             // 0x09
191     "Read",                        // 0x0A
192     "Write",                       // 0x0B
193     "Lock Byte Range",             // 0x0C
194     "Unlock Byte Range",           // 0x0D
195     "Create Temporary",            // 0x0E
196     "Create New",                  // 0x0F
197     "Check Directory",             // 0x10
198     "Process Exit",                // 0x11
199     "Seek",                        // 0x12
200     "Lock And Read",               // 0x13
201     "Write And Unlock",            // 0x14
202     "Unknown",                     // 0X15
203     "Unknown",                     // 0X16
204     "Unknown",                     // 0X17
205     "Unknown",                     // 0X18
206     "Unknown",                     // 0X19
207     "Read Raw",                    // 0x1A
208     "Read Mpx",                    // 0x1B
209     "Read Mpx Secondary",          // 0x1C
210     "Write Raw",                   // 0x1D
211     "Write Mpx",                   // 0x1E
212     "Write Mpx Secondary",         // 0x1F
213     "Write Complete",              // 0x20
214     "Query Server",                // 0x21
215     "Set Information2",            // 0x22
216     "Query Information2",          // 0x23
217     "Locking AndX",                // 0x24
218     "Transaction",                 // 0x25
219     "Transaction Secondary",       // 0x26
220     "Ioctl",                       // 0x27
221     "Ioctl Secondary",             // 0x28
222     "Copy",                        // 0x29
223     "Move",                        // 0x2A
224     "Echo",                        // 0x2B
225     "Write And Close",             // 0x2C
226     "Open AndX",                   // 0x2D
227     "Read AndX",                   // 0x2E
228     "Write AndX",                  // 0x2F
229     "New File Size",               // 0x30
230     "Close And Tree Disc",         // 0x31
231     "Transaction2",                // 0x32
232     "Transaction2 Secondary",      // 0x33
233     "Find Close2",                 // 0x34
234     "Find Notify Close",           // 0x35
235     "Unknown",                     // 0X36
236     "Unknown",                     // 0X37
237     "Unknown",                     // 0X38
238     "Unknown",                     // 0X39
239     "Unknown",                     // 0X3A
240     "Unknown",                     // 0X3B
241     "Unknown",                     // 0X3C
242     "Unknown",                     // 0X3D
243     "Unknown",                     // 0X3E
244     "Unknown",                     // 0X3F
245     "Unknown",                     // 0X40
246     "Unknown",                     // 0X41
247     "Unknown",                     // 0X42
248     "Unknown",                     // 0X43
249     "Unknown",                     // 0X44
250     "Unknown",                     // 0X45
251     "Unknown",                     // 0X46
252     "Unknown",                     // 0X47
253     "Unknown",                     // 0X48
254     "Unknown",                     // 0X49
255     "Unknown",                     // 0X4A
256     "Unknown",                     // 0X4B
257     "Unknown",                     // 0X4C
258     "Unknown",                     // 0X4D
259     "Unknown",                     // 0X4E
260     "Unknown",                     // 0X4F
261     "Unknown",                     // 0X50
262     "Unknown",                     // 0X51
263     "Unknown",                     // 0X52
264     "Unknown",                     // 0X53
265     "Unknown",                     // 0X54
266     "Unknown",                     // 0X55
267     "Unknown",                     // 0X56
268     "Unknown",                     // 0X57
269     "Unknown",                     // 0X58
270     "Unknown",                     // 0X59
271     "Unknown",                     // 0X5A
272     "Unknown",                     // 0X5B
273     "Unknown",                     // 0X5C
274     "Unknown",                     // 0X5D
275     "Unknown",                     // 0X5E
276     "Unknown",                     // 0X5F
277     "Unknown",                     // 0X60
278     "Unknown",                     // 0X61
279     "Unknown",                     // 0X62
280     "Unknown",                     // 0X63
281     "Unknown",                     // 0X64
282     "Unknown",                     // 0X65
283     "Unknown",                     // 0X66
284     "Unknown",                     // 0X67
285     "Unknown",                     // 0X68
286     "Unknown",                     // 0X69
287     "Unknown",                     // 0X6A
288     "Unknown",                     // 0X6B
289     "Unknown",                     // 0X6C
290     "Unknown",                     // 0X6D
291     "Unknown",                     // 0X6E
292     "Unknown",                     // 0X6F
293     "Tree Connect",                // 0x70
294     "Tree Disconnect",             // 0x71
295     "Negotiate",                   // 0x72
296     "Session Setup AndX",          // 0x73
297     "Logoff AndX",                 // 0x74
298     "Tree Connect AndX",           // 0x75
299     "Unknown",                     // 0X76
300     "Unknown",                     // 0X77
301     "Unknown",                     // 0X78
302     "Unknown",                     // 0X79
303     "Unknown",                     // 0X7A
304     "Unknown",                     // 0X7B
305     "Unknown",                     // 0X7C
306     "Unknown",                     // 0X7D
307     "Security Package AndX",       // 0x7E
308     "Unknown",                     // 0X7F
309     "Query Information Disk",      // 0x80
310     "Search",                      // 0x81
311     "Find",                        // 0x82
312     "Find Unique",                 // 0x83
313     "Find Close",                  // 0x84
314     "Unknown",                     // 0X85
315     "Unknown",                     // 0X86
316     "Unknown",                     // 0X87
317     "Unknown",                     // 0X88
318     "Unknown",                     // 0X89
319     "Unknown",                     // 0X8A
320     "Unknown",                     // 0X8B
321     "Unknown",                     // 0X8C
322     "Unknown",                     // 0X8D
323     "Unknown",                     // 0X8E
324     "Unknown",                     // 0X8F
325     "Unknown",                     // 0X90
326     "Unknown",                     // 0X91
327     "Unknown",                     // 0X92
328     "Unknown",                     // 0X93
329     "Unknown",                     // 0X94
330     "Unknown",                     // 0X95
331     "Unknown",                     // 0X96
332     "Unknown",                     // 0X97
333     "Unknown",                     // 0X98
334     "Unknown",                     // 0X99
335     "Unknown",                     // 0X9A
336     "Unknown",                     // 0X9B
337     "Unknown",                     // 0X9C
338     "Unknown",                     // 0X9D
339     "Unknown",                     // 0X9E
340     "Unknown",                     // 0X9F
341     "Nt Transact",                 // 0xA0
342     "Nt Transact Secondary",       // 0xA1
343     "Nt Create AndX",              // 0xA2
344     "Unknown",                     // 0XA3
345     "Nt Cancel",                   // 0xA4
346     "Nt Rename",                   // 0xA5
347     "Unknown",                     // 0XA6
348     "Unknown",                     // 0XA7
349     "Unknown",                     // 0XA8
350     "Unknown",                     // 0XA9
351     "Unknown",                     // 0XAA
352     "Unknown",                     // 0XAB
353     "Unknown",                     // 0XAC
354     "Unknown",                     // 0XAD
355     "Unknown",                     // 0XAE
356     "Unknown",                     // 0XAF
357     "Unknown",                     // 0XB0
358     "Unknown",                     // 0XB1
359     "Unknown",                     // 0XB2
360     "Unknown",                     // 0XB3
361     "Unknown",                     // 0XB4
362     "Unknown",                     // 0XB5
363     "Unknown",                     // 0XB6
364     "Unknown",                     // 0XB7
365     "Unknown",                     // 0XB8
366     "Unknown",                     // 0XB9
367     "Unknown",                     // 0XBA
368     "Unknown",                     // 0XBB
369     "Unknown",                     // 0XBC
370     "Unknown",                     // 0XBD
371     "Unknown",                     // 0XBE
372     "Unknown",                     // 0XBF
373     "Open Print File",             // 0xC0
374     "Write Print File",            // 0xC1
375     "Close Print File",            // 0xC2
376     "Get Print Queue",             // 0xC3
377     "Unknown",                     // 0XC4
378     "Unknown",                     // 0XC5
379     "Unknown",                     // 0XC6
380     "Unknown",                     // 0XC7
381     "Unknown",                     // 0XC8
382     "Unknown",                     // 0XC9
383     "Unknown",                     // 0XCA
384     "Unknown",                     // 0XCB
385     "Unknown",                     // 0XCC
386     "Unknown",                     // 0XCD
387     "Unknown",                     // 0XCE
388     "Unknown",                     // 0XCF
389     "Unknown",                     // 0XD0
390     "Unknown",                     // 0XD1
391     "Unknown",                     // 0XD2
392     "Unknown",                     // 0XD3
393     "Unknown",                     // 0XD4
394     "Unknown",                     // 0XD5
395     "Unknown",                     // 0XD6
396     "Unknown",                     // 0XD7
397     "Read Bulk",                   // 0xD8
398     "Write Bulk",                  // 0xD9
399     "Write Bulk Data",             // 0xDA
400     "Unknown",                     // 0XDB
401     "Unknown",                     // 0XDC
402     "Unknown",                     // 0XDD
403     "Unknown",                     // 0XDE
404     "Unknown",                     // 0XDF
405     "Unknown",                     // 0XE0
406     "Unknown",                     // 0XE1
407     "Unknown",                     // 0XE2
408     "Unknown",                     // 0XE3
409     "Unknown",                     // 0XE4
410     "Unknown",                     // 0XE5
411     "Unknown",                     // 0XE6
412     "Unknown",                     // 0XE7
413     "Unknown",                     // 0XE8
414     "Unknown",                     // 0XE9
415     "Unknown",                     // 0XEA
416     "Unknown",                     // 0XEB
417     "Unknown",                     // 0XEC
418     "Unknown",                     // 0XED
419     "Unknown",                     // 0XEE
420     "Unknown",                     // 0XEF
421     "Unknown",                     // 0XF0
422     "Unknown",                     // 0XF1
423     "Unknown",                     // 0XF2
424     "Unknown",                     // 0XF3
425     "Unknown",                     // 0XF4
426     "Unknown",                     // 0XF5
427     "Unknown",                     // 0XF6
428     "Unknown",                     // 0XF7
429     "Unknown",                     // 0XF8
430     "Unknown",                     // 0XF9
431     "Unknown",                     // 0XFA
432     "Unknown",                     // 0XFB
433     "Unknown",                     // 0XFC
434     "Unknown",                     // 0XFD
435     "Invalid",                     // 0xFE
436     "No AndX Command"              // 0xFF
437 };
438 
439 const char *smb_transaction_sub_command_strings[TRANS_SUBCOM_MAX] = {
440     "Unknown",                               // 0x0000
441     "TRANS_SET_NMPIPE_STATE",                // 0x0001
442     "Unknown",                               // 0x0002
443     "Unknown",                               // 0x0003
444     "Unknown",                               // 0x0004
445     "Unknown",                               // 0x0005
446     "Unknown",                               // 0x0006
447     "Unknown",                               // 0x0007
448     "Unknown",                               // 0x0008
449     "Unknown",                               // 0x0009
450     "Unknown",                               // 0x000A
451     "Unknown",                               // 0x000B
452     "Unknown",                               // 0x000C
453     "Unknown",                               // 0x000D
454     "Unknown",                               // 0x000E
455     "Unknown",                               // 0x000F
456     "Unknown",                               // 0x0010
457     "TRANS_RAW_READ_NMPIPE",                 // 0x0011
458     "Unknown",                               // 0x0012
459     "Unknown",                               // 0x0013
460     "Unknown",                               // 0x0014
461     "Unknown",                               // 0x0015
462     "Unknown",                               // 0x0016
463     "Unknown",                               // 0x0017
464     "Unknown",                               // 0x0018
465     "Unknown",                               // 0x0019
466     "Unknown",                               // 0x001A
467     "Unknown",                               // 0x001B
468     "Unknown",                               // 0x001C
469     "Unknown",                               // 0x001D
470     "Unknown",                               // 0x001E
471     "Unknown",                               // 0x001F
472     "Unknown",                               // 0x0020
473     "TRANS_QUERY_NMPIPE_STATE",              // 0x0021
474     "TRANS_QUERY_NMPIPE_INFO",               // 0x0022
475     "TRANS_PEEK_NMPIPE",                     // 0x0023
476     "Unknown",                               // 0x0024
477     "Unknown",                               // 0x0025
478     "TRANS_TRANSACT_NMPIPE",                 // 0x0026
479     "Unknown",                               // 0x0027
480     "Unknown",                               // 0x0028
481     "Unknown",                               // 0x0029
482     "Unknown",                               // 0x002A
483     "Unknown",                               // 0x002B
484     "Unknown",                               // 0x002C
485     "Unknown",                               // 0x002D
486     "Unknown",                               // 0x002E
487     "Unknown",                               // 0x002F
488     "Unknown",                               // 0x0030
489     "TRANS_RAW_WRITE_NMPIPE",                // 0x0031
490     "Unknown",                               // 0x0032
491     "Unknown",                               // 0x0033
492     "Unknown",                               // 0x0034
493     "Unknown",                               // 0x0035
494     "TRANS_READ_NMPIPE",                     // 0x0036
495     "TRANS_WRITE_NMPIPE",                    // 0x0037
496     "Unknown",                               // 0x0038
497     "Unknown",                               // 0x0039
498     "Unknown",                               // 0x003A
499     "Unknown",                               // 0x003B
500     "Unknown",                               // 0x003C
501     "Unknown",                               // 0x003D
502     "Unknown",                               // 0x003E
503     "Unknown",                               // 0x003F
504     "Unknown",                               // 0x0040
505     "Unknown",                               // 0x0041
506     "Unknown",                               // 0x0042
507     "Unknown",                               // 0x0043
508     "Unknown",                               // 0x0044
509     "Unknown",                               // 0x0045
510     "Unknown",                               // 0x0046
511     "Unknown",                               // 0x0047
512     "Unknown",                               // 0x0048
513     "Unknown",                               // 0x0049
514     "Unknown",                               // 0x004A
515     "Unknown",                               // 0x004B
516     "Unknown",                               // 0x004C
517     "Unknown",                               // 0x004D
518     "Unknown",                               // 0x004E
519     "Unknown",                               // 0x004F
520     "Unknown",                               // 0x0050
521     "Unknown",                               // 0x0051
522     "Unknown",                               // 0x0052
523     "TRANS_WAIT_NMPIPE",                     // 0x0053
524     "TRANS_CALL_NMPIPE"                      // 0x0054
525 };
526 
527 const char *smb_transaction2_sub_command_strings[TRANS2_SUBCOM_MAX] = {
528     "TRANS2_OPEN2",                          // 0x0000
529     "TRANS2_FIND_FIRST2",                    // 0x0001
530     "TRANS2_FIND_NEXT2",                     // 0x0002
531     "TRANS2_QUERY_FS_INFORMATION",           // 0x0003
532     "TRANS2_SET_FS_INFORMATION",             // 0x0004
533     "TRANS2_QUERY_PATH_INFORMATION",         // 0x0005
534     "TRANS2_SET_PATH_INFORMATION",           // 0x0006
535     "TRANS2_QUERY_FILE_INFORMATION",         // 0x0007
536     "TRANS2_SET_FILE_INFORMATION",           // 0x0008
537     "TRANS2_FSCTL",                          // 0x0009
538     "TRANS2_IOCTL2",                         // 0x000A
539     "TRANS2_FIND_NOTIFY_FIRST",              // 0x000B
540     "TRANS2_FIND_NOTIFY_NEXT",               // 0x000C
541     "TRANS2_CREATE_DIRECTORY",               // 0x000D
542     "TRANS2_SESSION_SETUP",                  // 0x000E
543     "Unknown",                               // 0x000F
544     "TRANS2_GET_DFS_REFERRAL",               // 0x0010
545     "TRANS2_REPORT_DFS_INCONSISTENCY"        // 0x0011
546 };
547 
548 const char *smb_nt_transact_sub_command_strings[NT_TRANSACT_SUBCOM_MAX] = {
549     "Unknown",                               // 0x0000
550     "NT_TRANSACT_CREATE",                    // 0x0001
551     "NT_TRANSACT_IOCTL",                     // 0x0002
552     "NT_TRANSACT_SET_SECURITY_DESC",         // 0x0003
553     "NT_TRANSACT_NOTIFY_CHANGE",             // 0x0004
554     "NT_TRANSACT_RENAME",                    // 0x0005
555     "NT_TRANSACT_QUERY_SECURITY_DESC"        // 0x0006
556 };
557 
558 /********************************************************************
559  * Private function prototypes
560  ********************************************************************/
561 static inline int DCE2_SmbType(DCE2_SmbSsnData *);
562 static inline void DCE2_SmbSetValidWordCount(uint8_t, uint8_t, uint8_t);
563 static inline bool DCE2_SmbIsValidWordCount(uint8_t, uint8_t, uint8_t);
564 static inline void DCE2_SmbSetValidByteCount(uint8_t, uint8_t, uint16_t, uint16_t);
565 static inline bool DCE2_SmbIsValidByteCount(uint8_t, uint8_t, uint16_t);
566 static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData *, const NbssHdr *);
567 static DCE2_SmbRequestTracker * DCE2_SmbInspect(DCE2_SmbSsnData *, const SmbNtHdr *);
568 static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData *, const SmbNtHdr *);
569 static uint32_t DCE2_IgnoreJunkData(const uint8_t *, uint16_t, uint32_t);
570 static inline DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer **,
571         const uint8_t *, uint32_t, uint32_t);
572 static inline DCE2_Buffer ** DCE2_SmbGetSegBuffer(DCE2_SmbSsnData *);
573 static inline uint32_t * DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData *);
574 static inline DCE2_SmbDataState * DCE2_SmbGetDataState(DCE2_SmbSsnData *);
575 static inline bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData *, const uint8_t *);
576 static inline void DCE2_SmbSegAlert(DCE2_SmbSsnData *, DCE2_Event);
577 static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData *);
578 static void DCE2_SmbProcessRawData(DCE2_SmbSsnData *, const uint8_t *, uint32_t);
579 static DCE2_SmbComInfo * DCE2_SmbCheckCommand(DCE2_SmbSsnData *,
580         const SmbNtHdr *, const uint8_t, const uint8_t *, uint32_t);
581 static void DCE2_SmbProcessCommand(DCE2_SmbSsnData *, const SmbNtHdr *, const uint8_t *, uint32_t);
582 static inline DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData *, const uint8_t *,
583         const uint8_t *, const uint32_t, const uint16_t, const uint32_t, uint16_t);
584 static inline DCE2_Ret DCE2_SmbValidateTransactionFields(DCE2_SmbSsnData *, const uint8_t *,
585         const uint8_t *, const uint32_t, const uint16_t, const uint32_t,
586         const uint32_t, const uint32_t, const uint32_t, const uint32_t,
587         const uint32_t, const uint32_t, const uint32_t);
588 static inline DCE2_Ret DCE2_SmbValidateTransactionSent(DCE2_SmbSsnData *,
589         uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
590 static inline DCE2_Ret DCE2_SmbCheckTransDataParams(DCE2_SmbSsnData *,
591         const uint8_t *, const uint8_t *, const uint32_t, const uint16_t,
592         const uint32_t, const uint32_t, const uint32_t, const uint32_t);
593 static inline DCE2_Ret DCE2_SmbCheckTotalCount(DCE2_SmbSsnData *,
594         const uint32_t, const uint32_t, const uint32_t);
595 static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData *, const uint32_t,
596         const uint16_t, const uint8_t, const uint16_t, const uint16_t);
597 static inline DCE2_Ret DCE2_SmbCheckAndXOffset(DCE2_SmbSsnData *, const uint8_t *,
598         const uint8_t *, const uint32_t);
599 static inline void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData *,
600         const SmbNtHdr *, const uint8_t *, uint32_t);
601 static DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t *, uint32_t, uint16_t, bool);
602 static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker *);
603 static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData *, const SmbNtHdr *,
604         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
605 static DCE2_Ret DCE2_SmbUpdateTransSecondary(DCE2_SmbSsnData *, const SmbNtHdr *,
606         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
607 static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData *, const SmbNtHdr *,
608         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
609 static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData *, const SmbNtHdr *,
610         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
611 static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData *, const SmbNtHdr *,
612         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
613 static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData *, const SmbNtHdr *,
614         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
615 static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData *, const SmbNtHdr *,
616         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
617 static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData *, const SmbNtHdr *,
618         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
619 static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData *, const SmbNtHdr *,
620         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
621 static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData *, const SmbNtHdr *,
622         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
623 static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData *, const SmbNtHdr *,
624         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
625 static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData *, const SmbNtHdr *,
626         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
627 static DCE2_Ret DCE2_SmbReadRaw(DCE2_SmbSsnData *, const SmbNtHdr *,
628         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
629 static DCE2_Ret DCE2_SmbWriteRaw(DCE2_SmbSsnData *, const SmbNtHdr *,
630         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
631 static DCE2_Ret DCE2_SmbWriteComplete(DCE2_SmbSsnData *, const SmbNtHdr *,
632         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
633 static inline DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData *,
634         DCE2_SmbTransactionTracker *, const uint8_t *, uint32_t,
635         const uint8_t *, uint32_t);
636 static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData *, const SmbNtHdr *,
637         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
638 static DCE2_Ret DCE2_SmbTransactionSecondary(DCE2_SmbSsnData *, const SmbNtHdr *,
639         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
640 static DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData *, const SmbNtHdr *,
641         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
642 static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
643         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
644 static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
645         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
646 static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
647         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
648 static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData *, const SmbNtHdr *,
649         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
650 static inline DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData *,
651         const uint8_t *, uint32_t, bool);
652 static inline DCE2_Ret DCE2_SmbTrans2QueryFileInfoReq(DCE2_SmbSsnData *,
653         const uint8_t *, uint32_t);
654 static inline DCE2_Ret DCE2_SmbTrans2SetFileInfoReq(DCE2_SmbSsnData *,
655         const uint8_t *, uint32_t, const uint8_t *, uint32_t);
656 static DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData *, const SmbNtHdr *,
657         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
658 static DCE2_Ret DCE2_SmbTransaction2Secondary(DCE2_SmbSsnData *, const SmbNtHdr *,
659         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
660 static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData *, const SmbNtHdr *,
661         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
662 static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData *, const SmbNtHdr *,
663         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
664 static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData *, const SmbNtHdr *,
665         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
666 static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
667         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
668 static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
669         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
670 static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
671         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
672 static inline DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData *,
673         const uint8_t *, uint32_t, bool);
674 static DCE2_Ret DCE2_SmbNtTransact(DCE2_SmbSsnData *, const SmbNtHdr *,
675         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
676 static DCE2_Ret DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData *, const SmbNtHdr *,
677         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
678 static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData *, const SmbNtHdr *,
679         const DCE2_SmbComInfo *, const uint8_t *, uint32_t);
680 static inline DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData *, const uint16_t,
681         const uint8_t *, uint32_t, uint64_t);
682 static inline DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData *,
683         const uint8_t *, uint32_t);
684 static void DCE2_SmbProcessFileData(DCE2_SmbSsnData *,
685         DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool);
686 static inline DCE2_SmbRequestTracker * DCE2_SmbNewRequestTracker(DCE2_SmbSsnData *, const SmbNtHdr *);
687 static inline DCE2_Ret DCE2_SmbBufferTransactionData(DCE2_SmbTransactionTracker *,
688         const uint8_t *, uint16_t, uint16_t);
689 static inline DCE2_Ret DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker *,
690         const uint8_t *, uint16_t, uint16_t);
691 static inline DCE2_SmbRequestTracker * DCE2_SmbFindRequestTracker(DCE2_SmbSsnData *,
692         const SmbNtHdr *);
693 static inline void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData *, DCE2_SmbRequestTracker *);
694 static void DCE2_SmbInsertUid(DCE2_SmbSsnData *, const uint16_t);
695 static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData *, const uint16_t);
696 static void DCE2_SmbRemoveUid(DCE2_SmbSsnData *ssd, const uint16_t);
697 static void DCE2_SmbInsertTid(DCE2_SmbSsnData *, const uint16_t, const bool);
698 static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData *, const uint16_t);
699 static bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData *, const uint16_t);
700 static void DCE2_SmbRemoveTid(DCE2_SmbSsnData *, const uint16_t);
701 static DCE2_SmbFileTracker * DCE2_SmbNewFileTracker(DCE2_SmbSsnData *,
702         const uint16_t, const uint16_t, const uint16_t);
703 static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData *,
704         DCE2_SmbRequestTracker *, const uint16_t, const uint16_t);
705 static inline DCE2_SmbFileTracker * DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker *);
706 static DCE2_SmbFileTracker * DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData *,
707         DCE2_SmbRequestTracker *, const uint16_t);
708 static inline DCE2_SmbFileTracker * DCE2_SmbGetFileTracker(DCE2_SmbSsnData *,
709         const uint16_t);
710 static DCE2_SmbFileTracker * DCE2_SmbFindFileTracker(DCE2_SmbSsnData *, const uint16_t,
711         const uint16_t, const uint16_t);
712 static DCE2_Ret DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData *, DCE2_SmbFileTracker *);
713 static inline void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker *);
714 static inline void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker *);
715 static inline void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker *);
716 static int DCE2_SmbUidTidFidCompare(const void *, const void *);
717 static void DCE2_SmbFileTrackerDataFree(void *);
718 static void DCE2_SmbRequestTrackerDataFree(void *);
719 static inline SFSnortPacket * DCE2_SmbGetRpkt(DCE2_SmbSsnData *, const uint8_t **,
720         uint32_t *, DCE2_RpktType);
721 static inline void DCE2_SmbReturnRpkt(void);
722 static inline void DCE2_SmbSetFileName(uint8_t *, uint16_t);
723 static uint8_t* DCE2_SmbGetString(const uint8_t *, uint32_t, bool, uint16_t *);
724 static inline void DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker *ftracker, DCE2_SmbRequestTracker *cur_rtracker);
725 static inline void DCE2_SmbResetFileChunks(DCE2_SmbFileTracker *);
726 static inline void DCE2_SmbAbortFileAPI(DCE2_SmbSsnData *);
727 static inline DCE2_SmbRetransmitPending DCE2_SmbFinishFileAPI(DCE2_SmbSsnData *);
728 static inline void DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData *);
729 static int DCE2_SmbFileOffsetCompare(const void *, const void *);
730 static void DCE2_SmbFileChunkFree(void *);
731 static DCE2_Ret DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData *,
732         DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool);
733 static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData *,
734         DCE2_SmbFileTracker *, const uint8_t *, uint32_t, bool);
735 static inline void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData *,
736         DCE2_SmbFileTracker *);
737 #ifdef ACTIVE_RESPONSE
738 static void DCE2_SmbInjectDeletePdu(DCE2_SmbSsnData *, DCE2_SmbFileTracker *);
739 static void DCE2_SmbFinishFileBlockVerdict(DCE2_SmbSsnData *);
740 static File_Verdict DCE2_SmbGetFileVerdict(void *, void *);
741 #endif
742 static inline void DCE2_SmbCleanSessionFileTracker(DCE2_SmbSsnData *, DCE2_SmbFileTracker *);
743 /********************************************************************
744  * Function: DCE2_SmbType()
745  *
746  * Purpose:
747  *  Since Windows and Samba don't seem to care or even look at the
748  *  actual flag in the SMB header, make the determination based on
749  *  whether from client or server.
750  *
751  * Arguments:
752  *  DCE2_SmbSsnData * - session data structure that has the raw
753  *     packet and packet flags to make determination
754  *
755  * Returns:
756  *  SMB_TYPE__REQUEST if packet is from client
757  *  SMB_TYPE__RESPONSE if packet is from server
758  *
759  ********************************************************************/
DCE2_SmbType(DCE2_SmbSsnData * ssd)760 static inline int DCE2_SmbType(DCE2_SmbSsnData *ssd)
761 {
762     if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
763         return SMB_TYPE__REQUEST;
764     else
765         return SMB_TYPE__RESPONSE;
766 }
767 
768 /********************************************************************
769  * Function: DCE2_SmbSetValidWordCount()
770  *
771  * Purpose:
772  *  Initializes global data for valid word counts for supported
773  *  SMB command requests and responses.
774  *
775  * Arguments:
776  *  uint8_t - the SMB command code
777  *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
778  *  uint8_t - the valid word count
779  *
780  * Returns: None
781  *
782  ********************************************************************/
DCE2_SmbSetValidWordCount(uint8_t com,uint8_t resp,uint8_t wct)783 static inline void DCE2_SmbSetValidWordCount(uint8_t com,
784         uint8_t resp, uint8_t wct)
785 {
786     smb_wcts[com][resp][wct/8] |= (1 << (wct % 8));
787 }
788 
789 /********************************************************************
790  * Function: DCE2_SmbIsValidWordCount()
791  *
792  * Purpose:
793  *  Checks if a word count is valid for a given command request
794  *  or response.
795  *
796  * Arguments:
797  *  uint8_t - the SMB command code
798  *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
799  *  uint8_t - the word count to validate
800  *
801  * Returns:
802  *  bool - true if valid, false if not valid.
803  *
804  ********************************************************************/
DCE2_SmbIsValidWordCount(uint8_t com,uint8_t resp,uint8_t wct)805 static inline bool DCE2_SmbIsValidWordCount(uint8_t com,
806         uint8_t resp, uint8_t wct)
807 {
808     return (smb_wcts[com][resp][wct/8] & (1 << (wct % 8))) ? true : false;
809 }
810 
811 /********************************************************************
812  * Function: DCE2_SmbSetValidByteCount()
813  *
814  * Purpose:
815  *  Initializes global data for valid byte counts as a range for
816  *  supported SMB command requests and responses.
817  *  Since a byte count is 2 bytes, a 4 byte type is used to store
818  *  the range.  The maximum is in the most significant 2 bytes and
819  *  the minimum in the least significant 2 bytes.
820  *
821  * Arguments:
822  *  uint8_t - the SMB command code
823  *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
824  *  uint8_t - the minimum word count that is valid
825  *  uint8_t - the maximum word count that is valid
826  *
827  * Returns: None
828  *
829  ********************************************************************/
DCE2_SmbSetValidByteCount(uint8_t com,uint8_t resp,uint16_t min,uint16_t max)830 static inline void DCE2_SmbSetValidByteCount(uint8_t com,
831         uint8_t resp, uint16_t min, uint16_t max)
832 {
833     smb_bccs[com][resp][0] = min;
834     smb_bccs[com][resp][1] = max;
835 }
836 
837 /********************************************************************
838  * Function: DCE2_SmbIsValidByteCount()
839  *
840  * Purpose:
841  *  Checks if a byte count is valid for a given command request
842  *  or response.
843  *
844  * Arguments:
845  *  uint8_t - the SMB command code
846  *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
847  *  uint8_t - the byte count to validate
848  *
849  * Returns:
850  *  bool - true if valid, false if not valid.
851  *
852  ********************************************************************/
DCE2_SmbIsValidByteCount(uint8_t com,uint8_t resp,uint16_t bcc)853 static inline bool DCE2_SmbIsValidByteCount(uint8_t com,
854         uint8_t resp, uint16_t bcc)
855 {
856     return ((bcc < smb_bccs[com][resp][0])
857             || (bcc > smb_bccs[com][resp][1])) ? false : true;
858 }
859 
860 /********************************************************************
861  * Function: DCE2_SmbGetMinByteCount()
862  *
863  * Purpose:
864  *  Returns the minimum byte count for the given command request
865  *  or response.
866  *
867  * Arguments:
868  *  uint8_t - the SMB command code
869  *  uint8_t - SMB_TYPE__REQUEST or SMB_TYPE__RESPONSE
870  *
871  * Returns:
872  *  uint16_t - the minimum byte count
873  *
874  ********************************************************************/
DCE2_SmbGetMinByteCount(uint8_t com,uint8_t resp)875 static inline uint16_t DCE2_SmbGetMinByteCount(uint8_t com, uint8_t resp)
876 {
877     return smb_bccs[com][resp][0];
878 }
879 
880 /********************************************************************
881  * Function: DCE2_SmbInitGlobals()
882  *
883  * Purpose:
884  *  Initializes global variables for SMB processing.
885  *  Sets up the functions and valid word and byte counts for SMB
886  *  commands.
887  *  Sets up AndX chain mappings and valid command chaining for
888  *  supported policies.
889  *
890  * Arguments: None
891  *
892  * Returns: None
893  *
894  ********************************************************************/
DCE2_SmbInitGlobals(void)895 void DCE2_SmbInitGlobals(void)
896 {
897     int com;
898     DCE2_Policy policy;
899     SmbAndXCom andx;
900     int i;
901 
902     memset(&smb_wcts, 0, sizeof(smb_wcts));
903     memset(&smb_bccs, 0, sizeof(smb_bccs));
904 
905     if (!smb_upload_ret_cb_id)
906         smb_upload_ret_cb_id = _dpd.streamAPI->register_event_handler(DCE2_Process_Retransmitted);
907 
908     // Sets up the function to call for the command and valid word and byte
909     // counts for the command.  Ensuring valid word and byte counts is very
910     // important to processing the command as it will assume the command is
911     // legitimate and can access data that is acutally there.  Note that
912     // commands with multiple word counts indicate a different command
913     // structure, however most, if not all just have an extended version
914     // of the structure for which the extended part isn't used.  If the
915     // extended part of a command structure needs to be used, be sure to
916     // check the word count in the command function before accessing data
917     // in the extended version of the command structure.
918     for (com = 0; com < SMB_MAX_NUM_COMS; com++)
919     {
920         switch (com)
921         {
922             case SMB_COM_OPEN:
923                 smb_com_funcs[com] = DCE2_SmbOpen;
924 
925                 smb_deprecated_coms[com] = true;
926                 smb_unusual_coms[com] = false;
927 
928                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
929                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
930 
931                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
932                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
933                 break;
934             case SMB_COM_CREATE:
935                 smb_com_funcs[com] = DCE2_SmbCreate;
936 
937                 smb_deprecated_coms[com] = true;
938                 smb_unusual_coms[com] = false;
939 
940                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
941                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
942 
943                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
944                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
945                 break;
946             case SMB_COM_CLOSE:
947                 smb_com_funcs[com] = DCE2_SmbClose;
948 
949                 smb_deprecated_coms[com] = false;
950                 smb_unusual_coms[com] = false;
951 
952                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
953                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
954 
955                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
956                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
957                 break;
958             case SMB_COM_RENAME:
959                 smb_com_funcs[com] = DCE2_SmbRename;
960 
961                 smb_deprecated_coms[com] = false;
962                 smb_unusual_coms[com] = false;
963 
964                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 1);
965                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
966 
967                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 4, UINT16_MAX);
968                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
969                 break;
970             case SMB_COM_READ:
971                 smb_com_funcs[com] = DCE2_SmbRead;
972 
973                 smb_deprecated_coms[com] = true;
974                 smb_unusual_coms[com] = false;
975 
976                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
977                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
978 
979                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
980                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
981                 break;
982             case SMB_COM_WRITE:
983                 smb_com_funcs[com] = DCE2_SmbWrite;
984 
985                 smb_deprecated_coms[com] = true;
986                 smb_unusual_coms[com] = false;
987 
988                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
989                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
990 
991                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
992                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
993                 break;
994             case SMB_COM_CREATE_NEW:
995                 smb_com_funcs[com] = DCE2_SmbCreateNew;
996 
997                 smb_deprecated_coms[com] = true;
998                 smb_unusual_coms[com] = false;
999 
1000                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 3);
1001                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1002 
1003                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
1004                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1005                 break;
1006             case SMB_COM_LOCK_AND_READ:
1007                 smb_com_funcs[com] = DCE2_SmbLockAndRead;
1008 
1009                 smb_deprecated_coms[com] = true;
1010                 smb_unusual_coms[com] = false;
1011 
1012                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
1013                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 5);
1014 
1015                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
1016                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 3, UINT16_MAX);
1017                 break;
1018             case SMB_COM_WRITE_AND_UNLOCK:
1019                 smb_com_funcs[com] = DCE2_SmbWriteAndUnlock;
1020 
1021                 smb_deprecated_coms[com] = true;
1022                 smb_unusual_coms[com] = false;
1023 
1024                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 5);
1025                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1026 
1027                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
1028                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1029                 break;
1030             case SMB_COM_READ_RAW:
1031                 smb_com_funcs[com] = DCE2_SmbReadRaw;
1032 
1033                 smb_deprecated_coms[com] = true;
1034                 smb_unusual_coms[com] = false;
1035 
1036                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
1037                 // With optional OffsetHigh
1038                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
1039 
1040                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
1041                 // Response is raw data, i.e. without SMB
1042                 break;
1043             case SMB_COM_WRITE_RAW:
1044                 smb_com_funcs[com] = DCE2_SmbWriteRaw;
1045 
1046                 smb_deprecated_coms[com] = true;
1047                 smb_unusual_coms[com] = false;
1048 
1049                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
1050                 // With optional OffsetHigh
1051                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
1052                 // Interim server response
1053                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1054 
1055                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1056                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1057                 break;
1058             case SMB_COM_WRITE_COMPLETE:
1059                 // Final server response to SMB_COM_WRITE_RAW
1060                 smb_com_funcs[com] = DCE2_SmbWriteComplete;
1061 
1062                 smb_deprecated_coms[com] = true;
1063                 smb_unusual_coms[com] = false;
1064 
1065                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1066 
1067                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1068                 break;
1069             case SMB_COM_TRANSACTION:
1070                 smb_com_funcs[com] = DCE2_SmbTransaction;
1071 
1072                 smb_deprecated_coms[com] = false;
1073                 smb_unusual_coms[com] = false;
1074 
1075                 // Word count depends on setup count
1076                 //for (i = 14; i < 256; i++)
1077                 //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
1078                 // In reality, all subcommands of SMB_COM_TRANSACTION requests
1079                 // have a setup count of 2 words.
1080                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 16);
1081 
1082                 // \PIPE\LANMAN
1083                 // Not something the preprocessor is looking at as it
1084                 // doesn't carry DCE/RPC but don't want to false positive
1085                 // on the preprocessor event.
1086                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
1087 
1088                 // Word count depends on setup count
1089                 //for (i = 10; i < 256; i++)
1090                 //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
1091                 // In reality, all subcommands of SMB_COM_TRANSACTION responses
1092                 // have a setup count of 0 words.
1093                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
1094 
1095                 // Interim server response
1096                 // When client sends an incomplete transaction and needs to
1097                 // send TransactionSecondary requests to complete request.
1098                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
1099 
1100                 // Exception will be made for Interim responses when
1101                 // byte count is checked.
1102                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1103                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1104                 break;
1105             case SMB_COM_TRANSACTION_SECONDARY:
1106                 smb_com_funcs[com] = DCE2_SmbTransactionSecondary;
1107 
1108                 smb_deprecated_coms[com] = false;
1109                 smb_unusual_coms[com] = false;
1110 
1111                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 8);
1112                 // Response is an SMB_COM_TRANSACTION
1113 
1114                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1115                 break;
1116             case SMB_COM_WRITE_AND_CLOSE:
1117                 smb_com_funcs[com] = DCE2_SmbWriteAndClose;
1118 
1119                 smb_deprecated_coms[com] = true;
1120                 smb_unusual_coms[com] = false;
1121 
1122                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 6);
1123                 // For some reason MS-CIFS specifies a version of this command
1124                 // with 6 extra words (12 bytes) of reserved, i.e. useless data.
1125                 // Maybe had intentions of extending and defining the data at
1126                 // some point, but there is no documentation that I could find
1127                 // that does.
1128                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
1129                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1130 
1131                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
1132                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1133                 break;
1134             case SMB_COM_OPEN_ANDX:
1135                 smb_com_funcs[com] = DCE2_SmbOpenAndX;
1136 
1137                 smb_deprecated_coms[com] = true;
1138                 smb_unusual_coms[com] = false;
1139 
1140                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
1141                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 15);
1142                 // Extended response
1143                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
1144 
1145                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
1146                 // MS-SMB says that Windows 2000, XP and Vista set this to
1147                 // some arbitrary value that is ignored on receipt.
1148                 //DCE2_SmbSetValidByteCount(com, SMB_TYPE__RESPONSE, 0, 0);
1149                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1150                 break;
1151             case SMB_COM_READ_ANDX:
1152                 smb_com_funcs[com] = DCE2_SmbReadAndX;
1153 
1154                 smb_deprecated_coms[com] = false;
1155                 smb_unusual_coms[com] = false;
1156 
1157                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
1158                 // With optional OffsetHigh
1159                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
1160                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 12);
1161 
1162                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
1163                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1164                 break;
1165             case SMB_COM_WRITE_ANDX:
1166                 smb_com_funcs[com] = DCE2_SmbWriteAndX;
1167 
1168                 smb_deprecated_coms[com] = false;
1169                 smb_unusual_coms[com] = false;
1170 
1171                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
1172                 // With optional OffsetHigh
1173                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 14);
1174                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 6);
1175 
1176                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 1, UINT16_MAX);
1177                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1178                 break;
1179             case SMB_COM_TRANSACTION2:
1180                 smb_com_funcs[com] = DCE2_SmbTransaction2;
1181 
1182                 smb_deprecated_coms[com] = false;
1183                 smb_unusual_coms[com] = false;
1184 
1185                 // Word count depends on setup count
1186                 //for (i = 14; i < 256; i++)
1187                 //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__REQUEST, i);
1188                 // In reality, all subcommands of SMB_COM_TRANSACTION2
1189                 // requests have a setup count of 1 word.
1190                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 15);
1191 
1192                 // Word count depends on setup count
1193                 //for (i = 10; i < 256; i++)
1194                 //    DCE2_SmbSetValidWordCount(com, SMB_TYPE__RESPONSE, i);
1195                 // In reality, all subcommands of SMB_COM_TRANSACTION2
1196                 // responses have a setup count of 0 or 1 word.
1197                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 10);
1198                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 11);
1199 
1200                 // Interim server response
1201                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
1202 
1203                 // Exception will be made for Interim responses when
1204                 // byte count is checked.
1205                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1206                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1207                 break;
1208             case SMB_COM_TRANSACTION2_SECONDARY:
1209                 smb_com_funcs[com] = DCE2_SmbTransaction2Secondary;
1210 
1211                 smb_deprecated_coms[com] = false;
1212                 smb_unusual_coms[com] = false;
1213 
1214                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 9);
1215                 // Response is an SMB_COM_TRANSACTION2
1216 
1217                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1218                 break;
1219             case SMB_COM_TREE_CONNECT:
1220                 smb_com_funcs[com] = DCE2_SmbTreeConnect;
1221 
1222                 smb_deprecated_coms[com] = true;
1223                 smb_unusual_coms[com] = false;
1224 
1225                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
1226                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
1227 
1228                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 6, UINT16_MAX);
1229                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1230                 break;
1231             case SMB_COM_TREE_DISCONNECT:
1232                 smb_com_funcs[com] = DCE2_SmbTreeDisconnect;
1233 
1234                 smb_deprecated_coms[com] = false;
1235                 smb_unusual_coms[com] = false;
1236 
1237                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
1238                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
1239 
1240                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
1241                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1242                 break;
1243             case SMB_COM_NEGOTIATE:
1244                 // Not doing anything with this command right now.
1245                 smb_com_funcs[com] = DCE2_SmbNegotiate;
1246 
1247                 smb_deprecated_coms[com] = false;
1248                 smb_unusual_coms[com] = false;
1249 
1250                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 0);
1251                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 1);
1252                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 13);
1253                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 17);
1254 
1255                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
1256                 // This can vary depending on dialect so just set wide.
1257                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1258                 break;
1259             case SMB_COM_SESSION_SETUP_ANDX:
1260                 smb_com_funcs[com] = DCE2_SmbSessionSetupAndX;
1261 
1262                 smb_deprecated_coms[com] = false;
1263                 smb_unusual_coms[com] = false;
1264 
1265                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 10);
1266                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 12);
1267                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 13);
1268                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
1269                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 4);
1270 
1271                 // These can vary so just set wide.
1272                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1273                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1274                 break;
1275             case SMB_COM_LOGOFF_ANDX:
1276                 smb_com_funcs[com] = DCE2_SmbLogoffAndX;
1277 
1278                 smb_deprecated_coms[com] = false;
1279                 smb_unusual_coms[com] = false;
1280 
1281                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 2);
1282                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
1283                 // Windows responds to a LogoffAndX => SessionSetupAndX with just a
1284                 // LogoffAndX and with the word count field containing 3, but only
1285                 // has 2 words
1286                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
1287 
1288                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, 0);
1289                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1290                 break;
1291             case SMB_COM_TREE_CONNECT_ANDX:
1292                 smb_com_funcs[com] = DCE2_SmbTreeConnectAndX;
1293 
1294                 smb_deprecated_coms[com] = false;
1295                 smb_unusual_coms[com] = false;
1296 
1297                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 4);
1298                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 2);
1299                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 3);
1300                 // Extended response
1301                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 7);
1302 
1303                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 3, UINT16_MAX);
1304                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 2, UINT16_MAX);
1305                 break;
1306             case SMB_COM_NT_TRANSACT:
1307                 smb_com_funcs[com] = DCE2_SmbNtTransact;
1308 
1309                 smb_deprecated_coms[com] = false;
1310                 smb_unusual_coms[com] = false;
1311 
1312                 // Word count depends on setup count
1313                 // In reality, all subcommands of SMB_COM_NT_TRANSACT
1314                 // requests have a setup count of 0 or 4 words.
1315                 //for (i = 19; i < 256; i++)
1316                 //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, i);
1317                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 19);
1318                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 23);
1319 
1320                 // Word count depends on setup count
1321                 // In reality, all subcommands of SMB_COM_NT_TRANSACT
1322                 // responses have a setup count of 0 or 1 word.
1323                 //for (i = 18; i < 256; i++)
1324                 //    DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, i);
1325                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 18);
1326                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 19);
1327 
1328                 // Interim server response
1329                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 0);
1330 
1331                 // Exception will be made for Interim responses when
1332                 // byte count is checked.
1333                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1334                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1335                 break;
1336             case SMB_COM_NT_TRANSACT_SECONDARY:
1337                 smb_com_funcs[com] = DCE2_SmbNtTransactSecondary;
1338 
1339                 smb_deprecated_coms[com] = false;
1340                 smb_unusual_coms[com] = false;
1341 
1342                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 18);
1343                 // Response is an SMB_COM_NT_TRANSACT
1344 
1345                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1346                 break;
1347             case SMB_COM_NT_CREATE_ANDX:
1348                 smb_com_funcs[com] = DCE2_SmbNtCreateAndX;
1349 
1350                 smb_deprecated_coms[com] = false;
1351                 smb_unusual_coms[com] = false;
1352 
1353                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, 24);
1354                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 34);
1355                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 26);
1356                 // Extended response - though there are actually 50 words
1357                 DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, 42);
1358 
1359                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 2, UINT16_MAX);
1360                 // MS-SMB indicates that this field should be 0 but may be
1361                 // sent uninitialized so basically ignore it.
1362                 //DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, 0);
1363                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1364                 break;
1365             default:
1366                 smb_com_funcs[com] = NULL;
1367                 smb_deprecated_coms[com] = false;
1368                 smb_unusual_coms[com] = false;
1369                 // Just set to all valid since the specific command won't
1370                 // be processed.  Don't want to false positive on these.
1371                 for (i = 0; i < 256; i++)
1372                 {
1373                     DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__REQUEST, (uint8_t)i);
1374                     DCE2_SmbSetValidWordCount((uint8_t)com, SMB_TYPE__RESPONSE, (uint8_t)i);
1375                 }
1376                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__REQUEST, 0, UINT16_MAX);
1377                 DCE2_SmbSetValidByteCount((uint8_t)com, SMB_TYPE__RESPONSE, 0, UINT16_MAX);
1378                 break;
1379         }
1380     }
1381 
1382     // Maps commands for use in quickly determining if a command
1383     // is chainable and what command it is.
1384     for (com = 0; com < SMB_MAX_NUM_COMS; com++)
1385     {
1386         switch (com)
1387         {
1388             case SMB_COM_SESSION_SETUP_ANDX:
1389                 smb_chain_map[com] = SMB_ANDX_COM__SESSION_SETUP_ANDX;
1390                 break;
1391             case SMB_COM_LOGOFF_ANDX:
1392                 smb_chain_map[com] = SMB_ANDX_COM__LOGOFF_ANDX;
1393                 break;
1394             case SMB_COM_TREE_CONNECT_ANDX:
1395                 smb_chain_map[com] = SMB_ANDX_COM__TREE_CONNECT_ANDX;
1396                 break;
1397             case SMB_COM_OPEN_ANDX:
1398                 smb_chain_map[com] = SMB_ANDX_COM__OPEN_ANDX;
1399                 break;
1400             case SMB_COM_NT_CREATE_ANDX:
1401                 smb_chain_map[com] = SMB_ANDX_COM__NT_CREATE_ANDX;
1402                 break;
1403             case SMB_COM_WRITE_ANDX:
1404                 smb_chain_map[com] = SMB_ANDX_COM__WRITE_ANDX;
1405                 break;
1406             case SMB_COM_READ_ANDX:
1407                 smb_chain_map[com] = SMB_ANDX_COM__READ_ANDX;
1408                 break;
1409             default:
1410                 smb_chain_map[com] = SMB_ANDX_COM__NONE;
1411                 break;
1412         }
1413     }
1414 
1415     // Sets up the valid command chaining combinations per policy
1416     for (policy = DCE2_POLICY__NONE; policy < DCE2_POLICY__MAX; policy++)
1417     {
1418         for (andx = SMB_ANDX_COM__NONE; andx < SMB_ANDX_COM__MAX; andx++)
1419         {
1420             /* com is the chained command or com2 */
1421             for (com = 0; com < SMB_MAX_NUM_COMS; com++)
1422             {
1423                 DCE2_SmbComFunc com_func = NULL;
1424 
1425                 switch (policy)
1426                 {
1427                     case DCE2_POLICY__WIN2000:
1428                     case DCE2_POLICY__WINXP:
1429                     case DCE2_POLICY__WINVISTA:
1430                     case DCE2_POLICY__WIN2003:
1431                     case DCE2_POLICY__WIN2008:
1432                     case DCE2_POLICY__WIN7:
1433                         switch (andx)
1434                         {
1435                             case SMB_ANDX_COM__SESSION_SETUP_ANDX:
1436                                 switch (com)
1437                                 {
1438                                     case SMB_COM_TREE_CONNECT_ANDX:
1439                                     case SMB_COM_OPEN:
1440                                     case SMB_COM_OPEN_ANDX:
1441                                     case SMB_COM_CREATE:
1442                                     case SMB_COM_CREATE_NEW:
1443                                         com_func = smb_com_funcs[com];
1444                                         break;
1445                                     case SMB_COM_TRANSACTION:
1446                                         if (policy == DCE2_POLICY__WIN2000)
1447                                             com_func = smb_com_funcs[com];
1448                                         break;
1449                                     default:
1450                                         break;
1451                                 }
1452                                 break;
1453                             case SMB_ANDX_COM__LOGOFF_ANDX:
1454                                 switch (com)
1455                                 {
1456                                     case SMB_COM_SESSION_SETUP_ANDX:
1457                                     case SMB_COM_TREE_CONNECT_ANDX:   // Only for responses
1458                                         com_func = smb_com_funcs[com];
1459                                         break;
1460                                     default:
1461                                         break;
1462                                 }
1463                                 break;
1464                             case SMB_ANDX_COM__TREE_CONNECT_ANDX:
1465                                 switch (com)
1466                                 {
1467                                     case SMB_COM_OPEN:
1468                                     case SMB_COM_CREATE:
1469                                     case SMB_COM_CREATE_NEW:
1470                                         com_func = smb_com_funcs[com];
1471                                         break;
1472                                     case SMB_COM_TRANSACTION:
1473                                         if (policy == DCE2_POLICY__WIN2000)
1474                                             com_func = smb_com_funcs[com];
1475                                         break;
1476                                     default:
1477                                         break;
1478                                 }
1479                                 break;
1480                             case SMB_ANDX_COM__OPEN_ANDX:
1481                                 break;
1482                             case SMB_ANDX_COM__NT_CREATE_ANDX:
1483                                 switch (com)
1484                                 {
1485                                     case SMB_COM_READ_ANDX:  // Only for normal files
1486                                         com_func = smb_com_funcs[com];
1487                                         break;
1488                                     default:
1489                                         break;
1490                                 }
1491                                 break;
1492                             case SMB_ANDX_COM__WRITE_ANDX:
1493                                 switch (com)
1494                                 {
1495                                     case SMB_COM_CLOSE:
1496                                     case SMB_COM_WRITE_ANDX:
1497                                     case SMB_COM_READ:
1498                                     case SMB_COM_READ_ANDX:
1499                                         com_func = smb_com_funcs[com];
1500                                         break;
1501                                     default:
1502                                         break;
1503                                 }
1504                                 break;
1505                             case SMB_ANDX_COM__READ_ANDX:
1506                                 break;
1507                             default:
1508                                 break;
1509                         }
1510                         break;
1511                     case DCE2_POLICY__SAMBA:
1512                     case DCE2_POLICY__SAMBA_3_0_37:
1513                     case DCE2_POLICY__SAMBA_3_0_22:
1514                     case DCE2_POLICY__SAMBA_3_0_20:
1515                         switch (andx)
1516                         {
1517                             case SMB_ANDX_COM__SESSION_SETUP_ANDX:
1518                                 switch (com)
1519                                 {
1520                                     case SMB_COM_LOGOFF_ANDX:
1521                                     case SMB_COM_TREE_CONNECT:
1522                                     case SMB_COM_TREE_CONNECT_ANDX:
1523                                     case SMB_COM_TREE_DISCONNECT:
1524                                     case SMB_COM_OPEN_ANDX:
1525                                     case SMB_COM_NT_CREATE_ANDX:
1526                                     case SMB_COM_CLOSE:
1527                                     case SMB_COM_READ_ANDX:
1528                                         com_func = smb_com_funcs[com];
1529                                         break;
1530                                     case SMB_COM_WRITE:
1531                                         if ((policy == DCE2_POLICY__SAMBA_3_0_22)
1532                                                 || (policy == DCE2_POLICY__SAMBA_3_0_20))
1533                                             com_func = smb_com_funcs[com];
1534                                         break;
1535                                     default:
1536                                         break;
1537                                 }
1538                                 break;
1539                             case SMB_ANDX_COM__LOGOFF_ANDX:
1540                                 switch (com)
1541                                 {
1542                                     case SMB_COM_SESSION_SETUP_ANDX:
1543                                     case SMB_COM_TREE_DISCONNECT:
1544                                         com_func = smb_com_funcs[com];
1545                                         break;
1546                                     default:
1547                                         break;
1548                                 }
1549                                 break;
1550                             case SMB_ANDX_COM__TREE_CONNECT_ANDX:
1551                                 switch (com)
1552                                 {
1553                                     case SMB_COM_SESSION_SETUP_ANDX:
1554                                     case SMB_COM_LOGOFF_ANDX:
1555                                     case SMB_COM_TREE_DISCONNECT:
1556                                     case SMB_COM_OPEN_ANDX:
1557                                     case SMB_COM_NT_CREATE_ANDX:
1558                                     case SMB_COM_CLOSE:
1559                                     case SMB_COM_WRITE:
1560                                     case SMB_COM_READ_ANDX:
1561                                         com_func = smb_com_funcs[com];
1562                                         break;
1563                                     default:
1564                                         break;
1565                                 }
1566                                 break;
1567                             case SMB_ANDX_COM__OPEN_ANDX:
1568                                 switch (com)
1569                                 {
1570                                     case SMB_COM_SESSION_SETUP_ANDX:
1571                                     case SMB_COM_LOGOFF_ANDX:
1572                                     case SMB_COM_TREE_CONNECT:
1573                                     case SMB_COM_TREE_CONNECT_ANDX:
1574                                     case SMB_COM_TREE_DISCONNECT:
1575                                     case SMB_COM_OPEN_ANDX:
1576                                     case SMB_COM_NT_CREATE_ANDX:
1577                                     case SMB_COM_CLOSE:
1578                                     case SMB_COM_WRITE:
1579                                     case SMB_COM_READ_ANDX:
1580                                         com_func = smb_com_funcs[com];
1581                                         break;
1582                                     default:
1583                                         break;
1584                                 }
1585                                 break;
1586                             case SMB_ANDX_COM__NT_CREATE_ANDX:
1587                                 switch (com)
1588                                 {
1589                                     case SMB_COM_SESSION_SETUP_ANDX:
1590                                     case SMB_COM_TREE_CONNECT:
1591                                     case SMB_COM_TREE_CONNECT_ANDX:
1592                                     case SMB_COM_OPEN_ANDX:
1593                                     case SMB_COM_NT_CREATE_ANDX:
1594                                     case SMB_COM_WRITE:
1595                                     case SMB_COM_READ_ANDX:
1596                                         com_func = smb_com_funcs[com];
1597                                         break;
1598                                     case SMB_COM_LOGOFF_ANDX:
1599                                     case SMB_COM_TREE_DISCONNECT:
1600                                     case SMB_COM_CLOSE:
1601                                         if ((policy == DCE2_POLICY__SAMBA)
1602                                                 || (policy == DCE2_POLICY__SAMBA_3_0_37))
1603                                             com_func = smb_com_funcs[com];
1604                                         break;
1605                                     default:
1606                                         break;
1607                                 }
1608                                 break;
1609                             case SMB_ANDX_COM__WRITE_ANDX:
1610                                 switch (com)
1611                                 {
1612                                     case SMB_COM_SESSION_SETUP_ANDX:
1613                                     case SMB_COM_LOGOFF_ANDX:
1614                                     case SMB_COM_TREE_CONNECT:
1615                                     case SMB_COM_TREE_CONNECT_ANDX:
1616                                     case SMB_COM_OPEN_ANDX:
1617                                     case SMB_COM_NT_CREATE_ANDX:
1618                                     case SMB_COM_CLOSE:
1619                                     case SMB_COM_WRITE:
1620                                     case SMB_COM_READ_ANDX:
1621                                     case SMB_COM_WRITE_ANDX:
1622                                         com_func = smb_com_funcs[com];
1623                                         break;
1624                                     default:
1625                                         break;
1626                                 }
1627                                 break;
1628                             case SMB_ANDX_COM__READ_ANDX:
1629                                 switch (com)
1630                                 {
1631                                     case SMB_COM_SESSION_SETUP_ANDX:
1632                                     case SMB_COM_WRITE:
1633                                         com_func = smb_com_funcs[com];
1634                                         break;
1635                                     case SMB_COM_LOGOFF_ANDX:
1636                                     case SMB_COM_TREE_CONNECT:
1637                                     case SMB_COM_TREE_CONNECT_ANDX:
1638                                     case SMB_COM_TREE_DISCONNECT:
1639                                     case SMB_COM_OPEN_ANDX:
1640                                     case SMB_COM_NT_CREATE_ANDX:
1641                                     case SMB_COM_CLOSE:
1642                                     case SMB_COM_READ_ANDX:
1643                                         if ((policy == DCE2_POLICY__SAMBA)
1644                                                 || (policy == DCE2_POLICY__SAMBA_3_0_37))
1645                                             com_func = smb_com_funcs[com];
1646                                         break;
1647                                     default:
1648                                         break;
1649                                 }
1650                                 break;
1651                             default:
1652                                 break;
1653                         }
1654                         break;
1655                     default:
1656                         break;
1657                 }
1658 
1659                 smb_chain_funcs[policy][andx][com] = com_func;
1660             }
1661         }
1662     }
1663 }
1664 
1665 /********************************************************************
1666  * Function: DCE2_SmbInitRdata()
1667  *
1668  * Purpose:
1669  *  Initializes the reassembled packet structure for an SMB
1670  *  reassembled packet.  Uses WriteAndX and ReadAndX.
1671  *  TODO Use command that was used when reassembly occurred.
1672  *  One issue with this is that multiple different write/read
1673  *  commands can be used to write/read the full DCE/RPC
1674  *  request/response.
1675  *
1676  * Arguments:
1677  *  uint8_t * - pointer to the start of the NetBIOS header where
1678  *              data initialization should start.
1679  *  int dir   - FLAG_FROM_CLIENT or FLAG_FROM_SERVER
1680  *
1681  * Returns: None
1682  *
1683  ********************************************************************/
DCE2_SmbInitRdata(uint8_t * nb_ptr,int dir)1684 void DCE2_SmbInitRdata(uint8_t *nb_ptr, int dir)
1685 {
1686     NbssHdr *nb_hdr = (NbssHdr *)nb_ptr;
1687     SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(NbssHdr));
1688 
1689     nb_hdr->type = NBSS_SESSION_TYPE__MESSAGE;
1690     memcpy((void *)smb_hdr->smb_idf, (void *)"\xffSMB", sizeof(smb_hdr->smb_idf));
1691 
1692     if (dir == FLAG_FROM_CLIENT)
1693     {
1694         SmbWriteAndXReq *writex =
1695             (SmbWriteAndXReq *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr));
1696         uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq);
1697 
1698         smb_hdr->smb_com = SMB_COM_WRITE_ANDX;
1699         smb_hdr->smb_flg = 0x00;
1700 
1701         writex->smb_wct = 12;
1702         writex->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
1703         writex->smb_doff = SmbHtons(&offset);
1704     }
1705     else
1706     {
1707         SmbReadAndXResp *readx =
1708             (SmbReadAndXResp *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr));
1709         uint16_t offset = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp);
1710 
1711         smb_hdr->smb_com = SMB_COM_READ_ANDX;
1712         smb_hdr->smb_flg = 0x80;
1713 
1714         readx->smb_wct = 12;
1715         readx->smb_com2 = SMB_COM_NO_ANDX_COMMAND;
1716         readx->smb_doff = SmbHtons(&offset);
1717     }
1718 }
1719 
1720 /********************************************************************
1721  * Function: DCE2_SmbSetRdata()
1722  *
1723  * Purpose:
1724  *  When a reassembled packet is needed this function is called to
1725  *  fill in appropriate fields to make the reassembled packet look
1726  *  correct from an SMB standpoint.
1727  *
1728  * Arguments:
1729  *  DCE2_SmbSsnData * - the session data structure.
1730  *  uint8_t * - pointer to the start of the NetBIOS header where
1731  *              data initialization should start.
1732  *  uint16_t  - the length of the connection-oriented DCE/RPC data.
1733  *
1734  * Returns: None
1735  *
1736  ********************************************************************/
DCE2_SmbSetRdata(DCE2_SmbSsnData * ssd,uint8_t * nb_ptr,uint16_t co_len)1737 void DCE2_SmbSetRdata(DCE2_SmbSsnData *ssd, uint8_t *nb_ptr, uint16_t co_len)
1738 {
1739     NbssHdr *nb_hdr = (NbssHdr *)nb_ptr;
1740     SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(NbssHdr));
1741     uint16_t uid = (ssd->cur_rtracker == NULL) ? 0 : ssd->cur_rtracker->uid;
1742     uint16_t tid = (ssd->cur_rtracker == NULL) ? 0 : ssd->cur_rtracker->tid;
1743     DCE2_SmbFileTracker *ftracker = (ssd->cur_rtracker == NULL) ? NULL : ssd->cur_rtracker->ftracker;
1744 
1745     smb_hdr->smb_uid = SmbHtons((const uint16_t *)&uid);
1746     smb_hdr->smb_tid = SmbHtons((const uint16_t *)&tid);
1747 
1748     if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
1749     {
1750         SmbWriteAndXReq *writex =
1751             (SmbWriteAndXReq *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr));
1752         uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbWriteAndXReq) + co_len;
1753 
1754         /* The data will get truncated anyway since we can only fit
1755          * 64K in the reassembly buffer */
1756         if (nb_len > UINT16_MAX)
1757             nb_len = UINT16_MAX;
1758 
1759         nb_hdr->length = htons((uint16_t)nb_len);
1760 
1761         if ((ftracker != NULL) && (ftracker->fid_v1 > 0))
1762         {
1763             uint16_t fid = (uint16_t)ftracker->fid_v1;
1764             writex->smb_fid = SmbHtons(&fid);
1765         }
1766         else
1767         {
1768             writex->smb_fid = 0;
1769         }
1770 
1771         writex->smb_countleft = SmbHtons(&co_len);
1772         writex->smb_dsize = SmbHtons(&co_len);
1773         writex->smb_bcc = SmbHtons(&co_len);
1774     }
1775     else
1776     {
1777         SmbReadAndXResp *readx =
1778             (SmbReadAndXResp *)((uint8_t *)smb_hdr + sizeof(SmbNtHdr));
1779         uint32_t nb_len = sizeof(SmbNtHdr) + sizeof(SmbReadAndXResp) + co_len;
1780 
1781         /* The data will get truncated anyway since we can only fit
1782          * 64K in the reassembly buffer */
1783         if (nb_len > UINT16_MAX)
1784             nb_len = UINT16_MAX;
1785 
1786         nb_hdr->length = htons((uint16_t)nb_len);
1787 
1788         readx->smb_remaining = SmbHtons(&co_len);
1789         readx->smb_dsize = SmbHtons(&co_len);
1790         readx->smb_bcc = SmbHtons(&co_len);
1791     }
1792 }
1793 
1794 /********************************************************************
1795  * Function: DCE2_SmbSsnInit()
1796  *
1797  * Purpose:
1798  *  Allocates and initializes a new session data structure.
1799  *
1800  * Arguments: None
1801  *
1802  * Returns:
1803  *  DCE2_SmbSsnData * - a new initialized session data structure.
1804  *
1805  ********************************************************************/
DCE2_SmbSsnInit(SFSnortPacket * p)1806 DCE2_SmbSsnData * DCE2_SmbSsnInit(SFSnortPacket *p)
1807 {
1808     DCE2_SmbSsnData *ssd =
1809         (DCE2_SmbSsnData *)DCE2_Alloc(sizeof(DCE2_SmbSsnData), DCE2_MEM_TYPE__SMB_SSN);
1810 
1811     if (ssd == NULL)
1812         return NULL;
1813 
1814     ssd->dialect_index = DCE2_SENTINEL;
1815     ssd->max_outstanding_requests = 10;  // Until Negotiate/SessionSetupAndX
1816     ssd->cli_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
1817     ssd->srv_data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
1818     ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
1819 
1820     ssd->uid = DCE2_SENTINEL;
1821     ssd->tid = DCE2_SENTINEL;
1822     ssd->ftracker.fid_v1 = DCE2_SENTINEL;
1823     ssd->rtracker.mid = DCE2_SENTINEL;
1824     ssd->smbfound = false;
1825     ssd->max_file_depth = _dpd.fileAPI->get_max_file_depth(_dpd.getCurrentSnortConfig(), false);
1826     ssd->smbretransmit = false;
1827 
1828     DCE2_ResetRopts(&ssd->sd.ropts);
1829 
1830     dce2_stats.smb_sessions++;
1831 
1832     return ssd;
1833 }
1834 
1835 /********************************************************************
1836  * Function: DCE2_NbssHdrChecks()
1837  *
1838  * Purpose:
1839  *  Does validation of the NetBIOS header.  SMB will only run over
1840  *  the Session Message type.  On port 139, there is always an
1841  *  initial Session Request / Session Positive/Negative response
1842  *  followed by the normal SMB conversation, i.e. Negotiate,
1843  *  SessionSetupAndX, etc.
1844  *  Side effects are potential alerts for anomolous behavior.
1845  *
1846  * Arguments:
1847  *  DCE2_SmbSsnData * - the session data structure.
1848  *  const NbssHdr *   - pointer to the NetBIOS Session Service
1849  *                      header structure.  Size is already validated.
1850  *
1851  * Returns:
1852  *  DCE2_Ret  -  DCE2_RET__SUCCESS if all goes well and processing
1853  *               should continue.
1854  *               DCE2_RET__IGNORE if it's not something we need to
1855  *               look at.
1856  *               DCE2_RET__ERROR if an invalid NetBIOS Session
1857  *               Service type is found.
1858  *
1859  ********************************************************************/
DCE2_NbssHdrChecks(DCE2_SmbSsnData * ssd,const NbssHdr * nb_hdr)1860 static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData *ssd, const NbssHdr *nb_hdr)
1861 {
1862     const SFSnortPacket *p = ssd->sd.wire_pkt;
1863     bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t *)nb_hdr);
1864 
1865     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "NetBIOS Session Service type: "));
1866 
1867     switch (NbssType(nb_hdr))
1868     {
1869         case NBSS_SESSION_TYPE__MESSAGE:
1870             /* Only want to look at session messages */
1871             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Message\n"));
1872 
1873             if (!DCE2_SmbIsRawData(ssd))
1874             {
1875                 uint32_t nb_len = NbssLen(nb_hdr);
1876 
1877                 if (nb_len == 0)
1878                     return DCE2_RET__IGNORE;
1879 
1880                 if (nb_len < sizeof(SmbNtHdr))
1881                 {
1882                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "NetBIOS SS len(%u) < SMB header len(%u).\n",
1883                                 sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len));
1884 
1885                     if (is_seg_buf)
1886                         DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_NB_LT_SMBHDR);
1887                     else
1888                         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_SMBHDR, nb_len, sizeof(SmbNtHdr));
1889 
1890                     return DCE2_RET__IGNORE;
1891                 }
1892             }
1893 
1894             return DCE2_RET__SUCCESS;
1895 
1896         case NBSS_SESSION_TYPE__REQUEST:
1897             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Request\n"));
1898             if (DCE2_SsnFromServer(p))
1899             {
1900                 if (is_seg_buf)
1901                     DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1902                 else
1903                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1904             }
1905 
1906             break;
1907 
1908         case NBSS_SESSION_TYPE__POS_RESPONSE:
1909         case NBSS_SESSION_TYPE__NEG_RESPONSE:
1910         case NBSS_SESSION_TYPE__RETARGET_RESPONSE:
1911             DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
1912                     if (NbssType(nb_hdr) == NBSS_SESSION_TYPE__POS_RESPONSE)
1913                     printf("Positive Session Response\n");
1914                     else if (NbssType(nb_hdr) == NBSS_SESSION_TYPE__NEG_RESPONSE)
1915                     printf("Negative Session Response\n");
1916                     else printf("Session Retarget Response\n"););
1917             if (DCE2_SsnFromClient(p))
1918             {
1919                 if (is_seg_buf)
1920                     DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1921                 else
1922                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1923             }
1924 
1925             break;
1926 
1927         case NBSS_SESSION_TYPE__KEEP_ALIVE:
1928             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Session Keep Alive\n"));
1929             break;
1930 
1931         default:
1932             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
1933                         "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr)));
1934 
1935             if (is_seg_buf)
1936                 DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1937             else
1938                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
1939 
1940             return DCE2_RET__ERROR;
1941     }
1942 
1943     return DCE2_RET__IGNORE;
1944 }
1945 
1946 /********************************************************************
1947  * Function: DCE2_SmbInspect()
1948  *
1949  * Purpose:
1950  *  Determines whether the SMB command is something the preprocessor
1951  *  needs to inspect.
1952  *  This function returns a DCE2_SmbRequestTracker which tracks command
1953  *  requests / responses.
1954  *
1955  * Arguments:
1956  *  DCE2_SmbSsnData * - the session data structure.
1957  *  const SmbNtHdr *  - pointer to the SMB header.
1958  *
1959  * Returns:
1960  *  DCE2_SmbRequestTracker * - NULL if it's not something we want to or can
1961  *                     inspect.
1962  *                     Otherwise an initialized structure if request
1963  *                     and the found structure if response.
1964  *
1965  ********************************************************************/
DCE2_SmbInspect(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr)1966 static DCE2_SmbRequestTracker * DCE2_SmbInspect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr)
1967 {
1968     DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
1969     DCE2_SmbRequestTracker *rtracker = NULL;
1970     int smb_com = SmbCom(smb_hdr);
1971 
1972     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "SMB command: %s (0x%02X)\n",
1973                 smb_com_strings[smb_com], smb_com));
1974 
1975     if (smb_com_funcs[smb_com] == NULL)
1976     {
1977         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Command isn't processed "
1978                     "by preprocessor.\n"));
1979         return NULL;
1980     }
1981 
1982     // See if this is something we need to inspect
1983     if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
1984     {
1985         switch (smb_com)
1986         {
1987             case SMB_COM_NEGOTIATE:
1988                 if (ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED)
1989                 {
1990                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULTIPLE_NEGOTIATIONS);
1991                     return NULL;
1992                 }
1993                 break;
1994             case SMB_COM_SESSION_SETUP_ANDX:
1995                 break;
1996             case SMB_COM_TREE_CONNECT:
1997             case SMB_COM_TREE_CONNECT_ANDX:
1998             case SMB_COM_RENAME:
1999             case SMB_COM_LOGOFF_ANDX:
2000                 if (DCE2_SmbFindUid(ssd, SmbUid(smb_hdr)) != DCE2_RET__SUCCESS)
2001                     return NULL;
2002                 break;
2003             default:
2004                 if (DCE2_SmbFindTid(ssd, SmbTid(smb_hdr)) != DCE2_RET__SUCCESS)
2005                 {
2006                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
2007                                 "Couldn't find Tid (%u)\n", SmbTid(smb_hdr)));
2008 
2009                     return NULL;
2010                 }
2011 
2012                 if (DCE2_SmbIsTidIPC(ssd, SmbTid(smb_hdr)))
2013                 {
2014                     switch (smb_com)
2015                     {
2016                         case SMB_COM_OPEN:
2017                         case SMB_COM_CREATE:
2018                         case SMB_COM_CREATE_NEW:
2019                         case SMB_COM_WRITE_AND_CLOSE:
2020                         case SMB_COM_WRITE_AND_UNLOCK:
2021                         case SMB_COM_READ:
2022                             // Samba doesn't allow these commands under an IPC tree
2023                             switch (policy)
2024                             {
2025                                 case DCE2_POLICY__SAMBA:
2026                                 case DCE2_POLICY__SAMBA_3_0_37:
2027                                 case DCE2_POLICY__SAMBA_3_0_22:
2028                                 case DCE2_POLICY__SAMBA_3_0_20:
2029                                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Samba doesn't "
2030                                                 "process this command under an IPC tree.\n"));
2031                                     return NULL;
2032                                 default:
2033                                     break;
2034                             }
2035                             break;
2036                         case SMB_COM_READ_RAW:
2037                         case SMB_COM_WRITE_RAW:
2038                             // Samba and Windows Vista on don't allow these commands
2039                             // under an IPC tree, whether or not the raw read/write
2040                             // flag is set in the Negotiate capabilities.
2041                             // Windows RSTs the connection and Samba FINs it.
2042                             switch (policy)
2043                             {
2044                                 case DCE2_POLICY__WINVISTA:
2045                                 case DCE2_POLICY__WIN2008:
2046                                 case DCE2_POLICY__WIN7:
2047                                 case DCE2_POLICY__SAMBA:
2048                                 case DCE2_POLICY__SAMBA_3_0_37:
2049                                 case DCE2_POLICY__SAMBA_3_0_22:
2050                                 case DCE2_POLICY__SAMBA_3_0_20:
2051                                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Samba and "
2052                                                 "Windows Vista on don't process this "
2053                                                 "command under an IPC tree.\n"));
2054                                     return NULL;
2055                                 default:
2056                                     break;
2057                             }
2058                             break;
2059                         case SMB_COM_LOCK_AND_READ:
2060                             // The lock will fail so the read won't happen
2061                             return NULL;
2062                         default:
2063                             break;
2064                     }
2065                 }
2066                 else  // Not IPC
2067                 {
2068                     switch (smb_com)
2069                     {
2070                         // These commands are only used for IPC
2071                         case SMB_COM_TRANSACTION:
2072                         case SMB_COM_TRANSACTION_SECONDARY:
2073                             return NULL;
2074                         case SMB_COM_READ_RAW:
2075                         case SMB_COM_WRITE_RAW:
2076                             // Windows Vista on don't seem to support these
2077                             // commands, whether or not the raw read/write
2078                             // flag is set in the Negotiate capabilities.
2079                             // Windows RSTs the connection.
2080                             switch (policy)
2081                             {
2082                                 case DCE2_POLICY__WINVISTA:
2083                                 case DCE2_POLICY__WIN2008:
2084                                 case DCE2_POLICY__WIN7:
2085                                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
2086                                                 "Windows Vista on don't process "
2087                                                 "this command.\n"));
2088                                     return NULL;
2089                                 default:
2090                                     break;
2091                             }
2092                             break;
2093                         default:
2094                             break;
2095                     }
2096                 }
2097                 break;
2098         }
2099 
2100         switch (smb_com)
2101         {
2102             case SMB_COM_TRANSACTION_SECONDARY:
2103             case SMB_COM_TRANSACTION2_SECONDARY:
2104             case SMB_COM_NT_TRANSACT_SECONDARY:
2105                 rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
2106                 break;
2107             case SMB_COM_TRANSACTION:
2108             case SMB_COM_TRANSACTION2:
2109             case SMB_COM_NT_TRANSACT:
2110                 // If there is already and existing request tracker
2111                 // and the transaction is not complete, server will
2112                 // return an error.
2113                 rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
2114                 if (rtracker != NULL)
2115                     break;
2116                 // Fall through
2117             default:
2118                 rtracker = DCE2_SmbNewRequestTracker(ssd, smb_hdr);
2119                 break;
2120         }
2121     }
2122     else
2123     {
2124         rtracker = DCE2_SmbFindRequestTracker(ssd, smb_hdr);
2125     }
2126 
2127     DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
2128             if (rtracker == NULL) printf("Failed to get request tracker.\n"););
2129 
2130     return rtracker;
2131 }
2132 
2133 /********************************************************************
2134  * Function: DCE2_SmbHdrChecks()
2135  *
2136  * Checks some relevant fields in the header to make sure they're
2137  * sane.
2138  * Side effects are potential alerts for anomolous behavior.
2139  *
2140  * Arguments:
2141  *  DCE2_SmbSsnData *
2142  *      Pointer to the session data structure.
2143  *  SmbNtHdr *
2144  *      Pointer to the header struct layed over the packet data.
2145  *
2146  * Returns:
2147  *  DCE2_Ret
2148  *      DCE2_RET__IGNORE if we should continue processing, but
2149  *          ignore data because of the error.
2150  *      DCE2_RET__SUCCESS if we should continue processing.
2151  *
2152  ********************************************************************/
DCE2_SmbHdrChecks(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr)2153 static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr)
2154 {
2155     const SFSnortPacket *p = ssd->sd.wire_pkt;
2156     bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t *)smb_hdr);
2157 
2158     if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) ||
2159             (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE)))
2160     {
2161         if (is_seg_buf)
2162             DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_TYPE);
2163         else
2164             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_TYPE);
2165 
2166         // Continue looking at traffic.  Neither Windows nor Samba seem
2167         // to care, or even look at this flag
2168     }
2169 
2170     if ((SmbId(smb_hdr) != DCE2_SMB_ID)
2171             && (SmbId(smb_hdr) != DCE2_SMB2_ID))
2172     {
2173         if (is_seg_buf)
2174             DCE2_SmbSegAlert(ssd, DCE2_EVENT__SMB_BAD_ID);
2175         else
2176             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_ID);
2177 
2178         return DCE2_RET__IGNORE;
2179     }
2180 
2181     return DCE2_RET__SUCCESS;
2182 }
2183 
2184 /********************************************************************
2185  * Function: DCE2_IgnoreJunkData()
2186  *
2187  * Purpose:
2188  *   An evasion technique can be to put a bunch of junk data before
2189  *   the actual SMB request and it seems the MS implementation has
2190  *   no problem with it and seems to just ignore the data.  This
2191  *   function attempts to move past all the junk to get to the
2192  *   actual NetBIOS message request.
2193  *
2194  * Arguments:
2195  *   const uint8_t *  - pointer to the current position in the data
2196  *      being inspected
2197  *   uint16_t  -  the amount of data left to look at
2198  *   uint32_t  -  the amount of data to ignore if there doesn't seem
2199  *      to be any junk data.  Just use the length as if the bad
2200  *      NetBIOS header was good.
2201  *
2202  * Returns:
2203  *    uint32_t - the amount of bytes to ignore as junk.
2204  *
2205  ********************************************************************/
DCE2_IgnoreJunkData(const uint8_t * data_ptr,uint16_t data_len,uint32_t assumed_nb_len)2206 static uint32_t DCE2_IgnoreJunkData(const uint8_t *data_ptr, uint16_t data_len,
2207         uint32_t assumed_nb_len)
2208 {
2209     const uint8_t *tmp_ptr = data_ptr;
2210     uint32_t ignore_bytes = 0;
2211 
2212     /* Try to find \xffSMB and go back 8 bytes to beginning
2213      * of what should be a Netbios header with type Session
2214      * Message (\x00) - do appropriate buffer checks to make
2215      * sure the index is in bounds. Ignore all intervening
2216      * bytes */
2217 
2218     while ((tmp_ptr + sizeof(uint32_t)) <= (data_ptr + data_len))
2219     {
2220         if ((SmbId((SmbNtHdr *)tmp_ptr) == DCE2_SMB_ID)
2221                 || (SmbId((SmbNtHdr *)tmp_ptr) == DCE2_SMB2_ID))
2222         {
2223             break;
2224         }
2225 
2226         tmp_ptr++;
2227     }
2228 
2229     if ((tmp_ptr + sizeof(uint32_t)) > (data_ptr + data_len))
2230     {
2231         ignore_bytes = data_len;
2232     }
2233     else
2234     {
2235         if ((tmp_ptr - sizeof(NbssHdr)) > data_ptr)
2236             ignore_bytes = (tmp_ptr - data_ptr) - sizeof(NbssHdr);
2237         else  /* Just ignore whatever the bad NB header had as a length */
2238             ignore_bytes = assumed_nb_len;
2239     }
2240 
2241     return ignore_bytes;
2242 }
2243 
2244 /********************************************************************
2245  * Function: DCE2_Smb1Process()
2246  *
2247  * Purpose:
2248  *  This is the main entry point for SMB1 processing.
2249  *
2250  * Arguments:
2251  *  DCE2_SmbSsnData * - the session data structure.
2252  *
2253  * Returns: None
2254  *
2255  ********************************************************************/
DCE2_Smb1Process(DCE2_SmbSsnData * ssd)2256 static inline void DCE2_Smb1Process(DCE2_SmbSsnData *ssd)
2257 {
2258     const SFSnortPacket *p = ssd->sd.wire_pkt;
2259     const uint8_t *data_ptr = p->payload;
2260     uint16_t data_len = p->payload_size;
2261     uint32_t *ignore_bytes = DCE2_SmbGetIgnorePtr(ssd);
2262     DCE2_Buffer **seg_buf = DCE2_SmbGetSegBuffer(ssd);
2263     DCE2_SmbDataState *data_state = DCE2_SmbGetDataState(ssd);
2264 
2265 #ifdef DUMP_BUFFER
2266     dumpBuffer(DCERPC_SMB1_DUMP,data_ptr,data_len);
2267 #endif
2268     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing SMB packet.\n"));
2269     dce2_stats.smb_pkts++;
2270 
2271     /* Have to account for segmentation.  Even though stream will give
2272      * us larger chunks, we might end up in the middle of something */
2273     while (data_len > 0)
2274     {
2275         // The amount of data needed in a given state to continue processing
2276         uint32_t data_need;
2277         NbssHdr *nb_hdr = NULL;
2278         SmbNtHdr *smb_hdr = NULL;
2279         uint32_t nb_len;
2280         const uint8_t *nb_ptr;
2281         DCE2_SmbRequestTracker *rtracker = NULL;
2282         DCE2_Ret status;
2283 
2284         // We are ignoring an entire PDU or junk data so state should be NETBIOS_HEADER
2285         // Note that it could be TCP segmented so ignore_bytes could be greater than
2286         // the amount of data we have
2287         if (*ignore_bytes)
2288         {
2289             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Ignoring %u bytes\n", *ignore_bytes));
2290 
2291             if (data_len <= *ignore_bytes)
2292             {
2293                 *ignore_bytes -= data_len;
2294                 return;
2295             }
2296             else
2297             {
2298                 /* ignore bytes is less than UINT16_MAX */
2299                 DCE2_MOVE(data_ptr, data_len, (uint16_t)*ignore_bytes);
2300                 *ignore_bytes = 0;
2301             }
2302         }
2303 
2304         switch (*data_state)
2305         {
2306             // This state is to verify it's a NetBIOS Session Message packet
2307             // and to get the length of the SMB PDU.  Also does the SMB junk
2308             // data check.  If it's not a Session Message the data isn't
2309             // processed since it won't be carrying SMB.
2310             case DCE2_SMB_DATA_STATE__NETBIOS_HEADER:
2311                 data_need = sizeof(NbssHdr) - DCE2_BufferLength(*seg_buf);
2312 
2313                 // See if there is enough data to process the NetBIOS header
2314                 if (data_len < data_need)
2315                 {
2316                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len(%u) < NetBIOS SS header(%u). "
2317                                 "Queueing data.\n", data_len, data_need));
2318 
2319                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr,
2320                                 data_len, sizeof(NbssHdr)) != DCE2_RET__SUCCESS)
2321                     {
2322                         DCE2_BufferEmpty(*seg_buf);
2323                     }
2324 
2325                     return;
2326                 }
2327 
2328                 // Set the NetBIOS header structure
2329                 if (DCE2_BufferIsEmpty(*seg_buf))
2330                 {
2331                     nb_hdr = (NbssHdr *)data_ptr;
2332                 }
2333                 else
2334                 {
2335                     // If data already buffered add the remainder for the
2336                     // size of the NetBIOS header
2337                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr,
2338                                 data_need, sizeof(NbssHdr)) != DCE2_RET__SUCCESS)
2339                     {
2340                         DCE2_BufferEmpty(*seg_buf);
2341                         return;
2342                     }
2343 
2344                     nb_hdr = (NbssHdr *)DCE2_BufferData(*seg_buf);
2345                 }
2346 
2347                 nb_len = NbssLen(nb_hdr);
2348 
2349                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
2350                             "NetBIOS PDU length: %u\n", nb_len));
2351 
2352                 status = DCE2_NbssHdrChecks(ssd, nb_hdr);
2353                 if (status != DCE2_RET__SUCCESS)
2354                 {
2355                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not a NetBIOS Session Message.\n"));
2356 
2357                     if (status == DCE2_RET__IGNORE)
2358                     {
2359                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Valid NetBIOS header "
2360                                     "type so ignoring NetBIOS length bytes.\n"));
2361                         *ignore_bytes = data_need + nb_len;
2362                     }
2363                     else  // nb_ret == DCE2_RET__ERROR, i.e. invalid NetBIOS type
2364                     {
2365                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not a valid NetBIOS "
2366                                     "header type so trying to find \\xffSMB to "
2367                                     "determine how many bytes to ignore.\n"));
2368 
2369                         *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len);
2370                     }
2371 
2372                     DCE2_BufferEmpty(*seg_buf);
2373                     dce2_stats.smb_ignored_bytes += *ignore_bytes;
2374                     continue;
2375                 }
2376 
2377                 if (!DCE2_BufferIsEmpty(*seg_buf))
2378                     DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
2379 
2380                 switch (ssd->pdu_state)
2381                 {
2382                     case DCE2_SMB_PDU_STATE__COMMAND:
2383                         *data_state = DCE2_SMB_DATA_STATE__SMB_HEADER;
2384                         break;
2385                     case DCE2_SMB_PDU_STATE__RAW_DATA:
2386                         *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
2387                         // Continue here because of fall through below
2388                         continue;
2389                     default:
2390                         DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB PDU "
2391                                 "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
2392                         return;
2393                 }
2394 
2395                 // Fall through for DCE2_SMB_DATA_STATE__SMB_HEADER
2396                 // This is the normal progression without segmentation.
2397 
2398                 // This state is to do validation checks on the SMB header and
2399                 // more importantly verify it's data that needs to be inspected.
2400                 // If the TID in the SMB header is not referring to the IPC share
2401                 // there won't be any DCE/RPC traffic associated with it.
2402             case DCE2_SMB_DATA_STATE__SMB_HEADER:
2403                 data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)) - DCE2_BufferLength(*seg_buf);
2404 
2405                 // See if there is enough data to process the SMB header
2406                 if (data_len < data_need)
2407                 {
2408                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len (%u) < "
2409                                 "NetBIOS SS header + SMB header (%u). Queueing data.\n",
2410                                 data_len, data_need));
2411 
2412                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len,
2413                                 sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS)
2414                     {
2415                         DCE2_BufferEmpty(*seg_buf);
2416                         *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2417                     }
2418 
2419                     return;
2420                 }
2421 
2422                 // Set the SMB header structure
2423                 if (DCE2_BufferIsEmpty(*seg_buf))
2424                 {
2425                     smb_hdr = (SmbNtHdr *)(data_ptr + sizeof(NbssHdr));
2426                 }
2427                 else
2428                 {
2429                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need,
2430                                 sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS)
2431                     {
2432                         DCE2_BufferEmpty(*seg_buf);
2433                         *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2434                         return;
2435                     }
2436 
2437                     smb_hdr = (SmbNtHdr *)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr));
2438                 }
2439 
2440 
2441                 if (SmbId(smb_hdr) == DCE2_SMB2_ID)
2442                 {
2443                     ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
2444                     if (!DCE2_GcIsLegacyMode())
2445                     {
2446                         DCE2_Smb2InitFileTracker(&(ssd->ftracker), false, 0);
2447                     	DCE2_Smb2Process(ssd);
2448                     }
2449                     return;
2450                 }
2451 
2452                 // See if this is something we need to inspect
2453                 rtracker = DCE2_SmbInspect(ssd, smb_hdr);
2454                 if (rtracker == NULL)
2455                 {
2456                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inspecting SMB packet.\n"));
2457 
2458                     if (DCE2_BufferIsEmpty(*seg_buf))
2459                     {
2460                         *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr *)data_ptr);
2461                     }
2462                     else
2463                     {
2464                         *ignore_bytes = (NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf))
2465                                 - sizeof(SmbNtHdr)) + data_need;
2466                         DCE2_BufferEmpty(*seg_buf);
2467                     }
2468 
2469                     *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2470 
2471                     dce2_stats.smb_ignored_bytes += *ignore_bytes;
2472                     continue;
2473                 }
2474 
2475                 // Check the SMB header for anomolies
2476                 if (DCE2_SmbHdrChecks(ssd, smb_hdr) != DCE2_RET__SUCCESS)
2477                 {
2478                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Bad SMB header.\n"));
2479 
2480                     if (DCE2_BufferIsEmpty(*seg_buf))
2481                     {
2482                         *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr *)data_ptr);
2483                     }
2484                     else
2485                     {
2486                         *ignore_bytes = (NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf))
2487                                 - sizeof(SmbNtHdr)) + data_need;
2488                         DCE2_BufferEmpty(*seg_buf);
2489                     }
2490 
2491                     *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2492 
2493                     dce2_stats.smb_ignored_bytes += *ignore_bytes;
2494                     continue;
2495                 }
2496 
2497                 if (!DCE2_BufferIsEmpty(*seg_buf))
2498                     DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
2499 
2500                 *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU;
2501 
2502                 // Fall through
2503 
2504                 // This state ensures that we have the entire PDU before continuing
2505                 // to process.
2506             case DCE2_SMB_DATA_STATE__NETBIOS_PDU:
2507                 if (DCE2_BufferIsEmpty(*seg_buf))
2508                 {
2509                     nb_len = NbssLen((NbssHdr *)data_ptr);
2510                     data_need = sizeof(NbssHdr) + nb_len;
2511                 }
2512                 else
2513                 {
2514                     nb_len = NbssLen((NbssHdr *)DCE2_BufferData(*seg_buf));
2515                     data_need = (sizeof(NbssHdr) + nb_len) - DCE2_BufferLength(*seg_buf);
2516                 }
2517 
2518                 /* It's something we want to inspect so make sure we have the full NBSS packet */
2519                 if (data_len < data_need)
2520                 {
2521                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data len(%u) < "
2522                                 "NetBIOS SS header + NetBIOS len(%u). "
2523                                 "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len));
2524 
2525                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len,
2526                                 sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS)
2527                     {
2528                         DCE2_BufferEmpty(*seg_buf);
2529                         *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2530                     }
2531 
2532                     return;
2533                 }
2534 
2535                 // data_len >= data_need which means data_need <= UINT16_MAX
2536                 // So casts below of data_need to uint16_t are okay.
2537 
2538                 *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER;
2539 
2540                 if (DCE2_BufferIsEmpty(*seg_buf))
2541                 {
2542                     nb_ptr = data_ptr;
2543                     nb_len = data_need;
2544                     DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
2545                 }
2546                 else
2547                 {
2548                     SFSnortPacket *rpkt;
2549 
2550                     if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need,
2551                                 sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS)
2552                     {
2553                         DCE2_BufferEmpty(*seg_buf);
2554                         DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
2555                         continue;
2556                     }
2557 
2558                     DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need);
2559 
2560                     nb_ptr = DCE2_BufferData(*seg_buf);
2561                     nb_len = DCE2_BufferLength(*seg_buf);
2562 
2563                     // Get reassembled packet
2564                     rpkt = DCE2_SmbGetRpkt(ssd, &nb_ptr, &nb_len,
2565                             DCE2_RPKT_TYPE__SMB_SEG);
2566                     if (rpkt == NULL)
2567                     {
2568                         DCE2_BufferEmpty(*seg_buf);
2569                         continue;
2570                     }
2571 
2572                     nb_ptr = DCE2_BufferData(*seg_buf);
2573                     nb_len = DCE2_BufferLength(*seg_buf);
2574 
2575                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
2576                                 "Segmentation buffer: len: %u, size: %u\n",
2577                                 DCE2_BufferLength(*seg_buf), DCE2_BufferSize(*seg_buf)););
2578 
2579                     if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
2580                         dce2_stats.smb_cli_seg_reassembled++;
2581                     else
2582                         dce2_stats.smb_srv_seg_reassembled++;
2583                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "TCP reassembled SMB PDU\n"));
2584                     DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
2585                 }
2586 
2587                 switch (ssd->pdu_state)
2588                 {
2589                     case DCE2_SMB_PDU_STATE__COMMAND:
2590                         smb_hdr = (SmbNtHdr *)(nb_ptr + sizeof(NbssHdr));
2591                         DCE2_MOVE(nb_ptr, nb_len, (sizeof(NbssHdr) + sizeof(SmbNtHdr)));
2592                         ssd->cur_rtracker = (rtracker != NULL)
2593                             ? rtracker : DCE2_SmbFindRequestTracker(ssd, smb_hdr);
2594                         if (ssd->cur_rtracker != NULL)
2595                             DCE2_SmbProcessCommand(ssd, smb_hdr, nb_ptr, nb_len);
2596                         break;
2597                     case DCE2_SMB_PDU_STATE__RAW_DATA:
2598                         DCE2_MOVE(nb_ptr, nb_len, sizeof(NbssHdr));
2599                         if (ssd->cur_rtracker != NULL)
2600                             DCE2_SmbProcessRawData(ssd, nb_ptr, nb_len);
2601                         // Only one raw read or write
2602                         ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
2603                         break;
2604                     default:
2605                         DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB PDU "
2606                                 "state: %d\n", __FILE__, __LINE__, ssd->pdu_state);
2607                         return;
2608                 }
2609 
2610                 if (!DCE2_BufferIsEmpty(*seg_buf))
2611                 {
2612                     DCE2_SmbReturnRpkt();
2613                     DCE2_BufferDestroy(*seg_buf);
2614                     *seg_buf = NULL;
2615                 }
2616 
2617                 break;
2618 
2619             default:
2620                 DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid SMB Data "
2621                         "state: %d\n", __FILE__, __LINE__, *data_state);
2622                 return;
2623         }
2624     }
2625 }
2626 
2627 
2628 /********************************************************************
2629  * Function: DCE2_SmbProcess()
2630  *
2631  * Purpose:
2632  *  This is the main entry point for SMB processing.
2633  *
2634  * Arguments:
2635  *  DCE2_SmbSsnData * - the session data structure.
2636  *
2637  * Returns: None
2638  *
2639  ********************************************************************/
DCE2_SmbProcess(DCE2_SmbSsnData * ssd)2640 void DCE2_SmbProcess(DCE2_SmbSsnData *ssd)
2641 {
2642     DCE2_SmbVersion smb_version;
2643     const SFSnortPacket *p = ssd->sd.wire_pkt;
2644 
2645     if (DCE2_GcIsLegacyMode())
2646     {
2647         DCE2_Smb1Process(ssd);
2648         return;
2649     }
2650 
2651     smb_version = DCE2_Smb2Version(p);
2652 
2653     if ((ssd->smbfound == false) && (smb_version != DCE2_SMB_VERISON_NULL))
2654     {
2655         _dpd.sessionAPI->disable_preproc_for_session( p->stream_session, PP_HTTPINSPECT);
2656         DCE2_EnableDetect();
2657         ssd->smbfound=true;
2658     }
2659 
2660     if (smb_version == DCE2_SMB_VERISON_1)
2661     {
2662         if ((ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
2663         {
2664             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "SMB1 packet detected!\n"));
2665             ssd->sd.flags &= ~DCE2_SSN_FLAG__SMB2;
2666             DCE2_SmbCleanFileTracker(&(ssd->ftracker));
2667             ssd->ftracker.is_smb2 = false;
2668         }
2669     }
2670     else if (smb_version == DCE2_SMB_VERISON_2)
2671     {
2672         if (!(ssd->sd.flags & DCE2_SSN_FLAG__SMB2))
2673         {
2674             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "SMB2 packet detected!\n"));
2675             DCE2_SmbCleanFileTracker(&(ssd->ftracker));
2676             DCE2_Smb2InitFileTracker(&(ssd->ftracker), 0, 0);
2677             ssd->sd.flags |= DCE2_SSN_FLAG__SMB2;
2678         }
2679     }
2680 
2681     ssd->max_file_depth = _dpd.fileAPI->get_max_file_depth(_dpd.getCurrentSnortConfig(), false);
2682     if (ssd->sd.flags & DCE2_SSN_FLAG__SMB2)
2683         DCE2_Smb2Process(ssd);
2684     else
2685         DCE2_Smb1Process(ssd);
2686 }
2687 /********************************************************************
2688  * Function: DCE2_SmbHandleSegmentation()
2689  *
2690  * Wrapper around DCE2_HandleSegmentation() to allocate a new
2691  * buffer object if necessary.
2692  *
2693  * Arguments:
2694  *  DCE2_SmbBuffer **
2695  *      Pointer to pointer of buffer to add data to.  If NULL
2696  *      a new buffer will be allocated.
2697  *  uint8_t *
2698  *      Pointer to the current data cursor in packet.
2699  *  uint32_t
2700  *      Length of data to add to buffer.
2701  *  uint32_t
2702  *      The minimum allocation size so that small allocations
2703  *      aren't consistently done.
2704  *
2705  * Returns:
2706  *  DCE2_Ret
2707  *      DCE2_RET__ERROR if an error occured.  Nothing can
2708  *          be trusted.
2709  *      DCE2_RET__SUCCESS if data was successfully added.
2710  *
2711  ********************************************************************/
DCE2_SmbHandleSegmentation(DCE2_Buffer ** buf,const uint8_t * data_ptr,uint32_t add_len,uint32_t alloc_size)2712 static inline DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer **buf,
2713         const uint8_t *data_ptr, uint32_t add_len, uint32_t alloc_size)
2714 {
2715     DCE2_Ret status;
2716     PROFILE_VARS;
2717 
2718     PREPROC_PROFILE_START(dce2_pstat_smb_seg);
2719 
2720     if (buf == NULL)
2721     {
2722         PREPROC_PROFILE_END(dce2_pstat_smb_seg);
2723         return DCE2_RET__ERROR;
2724     }
2725 
2726     if (*buf == NULL)
2727     {
2728         /* No initial size or min alloc size */
2729         *buf = DCE2_BufferNew(alloc_size, alloc_size, DCE2_MEM_TYPE__SMB_SEG);
2730         if (*buf == NULL)
2731         {
2732             PREPROC_PROFILE_END(dce2_pstat_smb_seg);
2733             return DCE2_RET__ERROR;
2734         }
2735     }
2736 
2737     status = DCE2_BufferAddData(*buf, data_ptr, add_len,
2738             DCE2_BufferLength(*buf), DCE2_BUFFER_MIN_ADD_FLAG__IGNORE);
2739 
2740     DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
2741             if (status != DCE2_RET__SUCCESS)
2742             printf("Failed to add data to SMB segmentation buffer.\n"););
2743 
2744     PREPROC_PROFILE_END(dce2_pstat_smb_seg);
2745     return status;
2746 }
2747 
2748 /********************************************************************
2749  * Function: DCE2_SmbGetSegBuffer()
2750  *
2751  * Returns the appropriate segmentation buffer.
2752  *
2753  * Arguments:
2754  *  DCE2_SmbSsnData *
2755  *      Pointer to SMB session data.
2756  *
2757  * Returns:
2758  *  DCE2_SmbSeg *
2759  *      Pointer to client or server segmenation buffer.
2760  *
2761  ********************************************************************/
DCE2_SmbGetSegBuffer(DCE2_SmbSsnData * ssd)2762 static inline DCE2_Buffer ** DCE2_SmbGetSegBuffer(DCE2_SmbSsnData *ssd)
2763 {
2764     if (DCE2_SsnFromServer(ssd->sd.wire_pkt))
2765         return &ssd->srv_seg;
2766     return &ssd->cli_seg;
2767 }
2768 
2769 /********************************************************************
2770  * Function: DCE2_SmbGetIgnorePtr()
2771  *
2772  * Returns a pointer to the bytes we are ignoring on client or
2773  * server side.  Bytes are ignored if they are associated with
2774  * data we are not interested in.
2775  *
2776  * Arguments:
2777  *  DCE2_SmbSsnData * - Pointer to SMB session data.
2778  *
2779  * Returns:
2780  *  uint32_t *
2781  *      Pointer to the client or server ignore bytes.
2782  *
2783  ********************************************************************/
DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData * ssd)2784 static inline uint32_t * DCE2_SmbGetIgnorePtr(DCE2_SmbSsnData *ssd)
2785 {
2786     if (DCE2_SsnFromServer(ssd->sd.wire_pkt))
2787         return &ssd->srv_ignore_bytes;
2788     return &ssd->cli_ignore_bytes;
2789 }
2790 
2791 /********************************************************************
2792  * Function: DCE2_SmbGetDataState()
2793  *
2794  * Returns a pointer to the data state of client or server
2795  *
2796  * Arguments:
2797  *  DCE2_SmbSsnData * - Pointer to SMB session data.
2798  *
2799  * Returns:
2800  *  DCE2_SmbDataState *
2801  *      Pointer to the client or server data state.
2802  *
2803  ********************************************************************/
DCE2_SmbGetDataState(DCE2_SmbSsnData * ssd)2804 static inline DCE2_SmbDataState * DCE2_SmbGetDataState(DCE2_SmbSsnData *ssd)
2805 {
2806     if (DCE2_SsnFromServer(ssd->sd.wire_pkt))
2807         return &ssd->srv_data_state;
2808     return &ssd->cli_data_state;
2809 }
2810 
2811 /********************************************************************
2812  * Function: DCE2_SmbIsSegBuffer()
2813  *
2814  * Purpose:
2815  *  Determines whether the pointer passed in lies within one of the
2816  *  segmentation buffers or not.
2817  *
2818  * Arguments:
2819  *  DCE2_SmbSsnData *
2820  *      Pointer to SMB session data.
2821  *
2822  * Returns:
2823  *  bool  -  True is the pointer lies within one of the segmentation
2824  *           buffers.
2825  *           False if it doesn't.
2826  *
2827  ********************************************************************/
DCE2_SmbIsSegBuffer(DCE2_SmbSsnData * ssd,const uint8_t * ptr)2828 static inline bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData *ssd, const uint8_t *ptr)
2829 {
2830     DCE2_Buffer *seg_buf;
2831 
2832     if (DCE2_SsnFromServer(ssd->sd.wire_pkt))
2833         seg_buf = ssd->srv_seg;
2834     else
2835         seg_buf = ssd->cli_seg;
2836 
2837     if (DCE2_BufferIsEmpty(seg_buf))
2838         return false;
2839 
2840     /* See if we're looking at a segmentation buffer */
2841     if ((ptr < DCE2_BufferData(seg_buf)) ||
2842             (ptr > (DCE2_BufferData(seg_buf) + DCE2_BufferLength(seg_buf))))
2843     {
2844         return false;
2845     }
2846 
2847     return true;
2848 }
2849 
2850 /********************************************************************
2851  * Function: DCE2_SmbSegAlert()
2852  *
2853  * Purpose:
2854  *  To create a reassembled packet using the data in one of the
2855  *  segmentation buffers in order to generate an alert with the
2856  *  correct, or more complete data.
2857  *
2858  * Arguments:
2859  *  DCE2_SmbSsnData * - Pointer to SMB session data.
2860  *  DCE2_Event        - the event code to generate and event for.
2861  *
2862  * Returns: None
2863  *
2864  ********************************************************************/
DCE2_SmbSegAlert(DCE2_SmbSsnData * ssd,DCE2_Event event)2865 static inline void DCE2_SmbSegAlert(DCE2_SmbSsnData *ssd, DCE2_Event event)
2866 {
2867     SFSnortPacket *rpkt;
2868     DCE2_Buffer *buf;
2869     uint32_t nb_len = 0;
2870     const uint8_t *data_ptr;
2871     uint32_t data_len;
2872 
2873     if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
2874         buf = ssd->cli_seg;
2875     else
2876         buf = ssd->srv_seg;
2877 
2878     /* This should be called from the desegmentation code. */
2879     if (DCE2_BufferIsEmpty(buf))
2880         return;
2881 
2882     data_ptr = DCE2_BufferData(buf);
2883     data_len = DCE2_BufferLength(buf);
2884 
2885     rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_SEG);
2886     if (rpkt == NULL)
2887         return;
2888 
2889     if (DCE2_BufferLength(buf) >= sizeof(NbssHdr))
2890         nb_len = NbssLen((NbssHdr *)DCE2_BufferData(buf));
2891 
2892     switch (event)
2893     {
2894         case DCE2_EVENT__SMB_BAD_NBSS_TYPE:
2895             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_NBSS_TYPE);
2896             break;
2897 
2898         case DCE2_EVENT__SMB_BAD_TYPE:
2899             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_TYPE);
2900             break;
2901 
2902         case DCE2_EVENT__SMB_BAD_ID:
2903             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_ID);
2904             break;
2905 
2906         case DCE2_EVENT__SMB_NB_LT_SMBHDR:
2907             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_SMBHDR, nb_len, sizeof(SmbNtHdr));
2908             break;
2909 
2910         default:
2911             break;
2912     }
2913 
2914     DCE2_SmbReturnRpkt();
2915 }
2916 
2917 /********************************************************************
2918  * Function: DCE2_SmbIsRawData()
2919  *
2920  * Purpose:
2921  *  To determine if the current state is such that a raw read or
2922  *  write is expected.
2923  *
2924  * Arguments:
2925  *  DCE2_SmbSsnData * - Pointer to SMB session data.
2926  *
2927  * Returns:
2928  *  bool -  True if expecting raw data.
2929  *          False if not.
2930  *
2931  ********************************************************************/
DCE2_SmbIsRawData(DCE2_SmbSsnData * ssd)2932 static inline bool DCE2_SmbIsRawData(DCE2_SmbSsnData *ssd)
2933 {
2934     return (ssd->pdu_state == DCE2_SMB_PDU_STATE__RAW_DATA);
2935 }
2936 
2937 /********************************************************************
2938  * Function:
2939  *
2940  * Purpose:
2941  *
2942  * Arguments:
2943  *
2944  * Returns:
2945  *
2946  ********************************************************************/
DCE2_SmbProcessRawData(DCE2_SmbSsnData * ssd,const uint8_t * nb_ptr,uint32_t nb_len)2947 static void DCE2_SmbProcessRawData(DCE2_SmbSsnData *ssd, const uint8_t *nb_ptr, uint32_t nb_len)
2948 {
2949     DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker;
2950     bool remove_rtracker = false;
2951 
2952     if (ftracker == NULL)
2953     {
2954         DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker);
2955         ssd->cur_rtracker = NULL;
2956         return;
2957     }
2958 
2959     if (DCE2_SsnFromClient(ssd->sd.wire_pkt))
2960     {
2961         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Raw data: Write Raw\n"));
2962         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Request Fid: 0x%04X\n", ftracker->fid_v1));
2963 
2964         dce2_stats.smb_com_stats[SMB_TYPE__REQUEST][SMB_COM_WRITE_RAW]++;
2965 
2966         if (nb_len > ssd->cur_rtracker->writeraw_remaining)
2967         {
2968             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_LT_DSIZE,
2969                     ssd->cur_rtracker->writeraw_remaining, nb_len);
2970 
2971             // If this happens, Windows never responds regardless of
2972             // WriteThrough flag, so get rid of request tracker
2973             remove_rtracker = true;
2974         }
2975         else if (!ssd->cur_rtracker->writeraw_writethrough)
2976         {
2977             // If WriteThrough flag was not set on initial request, a
2978             // SMB_COM_WRITE_COMPLETE will not be sent so need to get
2979             // rid of request tracker.
2980             remove_rtracker = true;
2981         }
2982         else
2983         {
2984             ssd->cur_rtracker->writeraw_writethrough = false;
2985             ssd->cur_rtracker->writeraw_remaining = 0;
2986         }
2987     }
2988     else
2989     {
2990         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Raw data: Read Raw\n"));
2991         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Response Fid: 0x%04X\n", ftracker->fid_v1));
2992 
2993         dce2_stats.smb_com_stats[SMB_TYPE__RESPONSE][SMB_COM_READ_RAW]++;
2994 
2995         remove_rtracker = true;
2996     }
2997 
2998     // Only one raw read/write allowed
2999     ssd->pdu_state = DCE2_SMB_PDU_STATE__COMMAND;
3000 
3001     DCE2_SmbSetFileName(ftracker->file_name, ftracker->file_name_len);
3002 
3003     if (ftracker->is_ipc)
3004     {
3005         // Maximum possible fragment length is 16 bit
3006         if (nb_len > UINT16_MAX)
3007             nb_len = UINT16_MAX;
3008 
3009         DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, nb_ptr, (uint16_t)nb_len);
3010     }
3011     else
3012     {
3013         bool upload = DCE2_SsnFromClient(ssd->sd.wire_pkt) ? true : false;
3014         DCE2_SmbProcessFileData(ssd, ftracker, nb_ptr, nb_len, upload);
3015     }
3016 
3017     if (remove_rtracker)
3018     {
3019         DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker);
3020         ssd->cur_rtracker = NULL;
3021     }
3022 }
3023 
3024 /********************************************************************
3025  * Function: DCE2_SmbCheckCommand()
3026  *
3027  * Purpose:
3028  *  Checks basic validity of an SMB command.
3029  *
3030  * Arguments:
3031  *  DCE2_SmbSsnData * - pointer to session data structure
3032  *  SmbNtHdr *        - pointer to the SMB header structure
3033  *  int               - the SMB command code, i.e. SMB_COM_*
3034  *  uint8_t *         - current pointer to data, i.e. the command
3035  *  uint32_t          - the remaining length
3036  *
3037  * Returns:
3038  *  DCE2_SmbComInfo *
3039  *      Populated structure for command processing
3040  *
3041  ********************************************************************/
DCE2_SmbCheckCommand(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const uint8_t smb_com,const uint8_t * nb_ptr,uint32_t nb_len)3042 static DCE2_SmbComInfo * DCE2_SmbCheckCommand(DCE2_SmbSsnData *ssd,
3043         const SmbNtHdr *smb_hdr, const uint8_t smb_com,
3044         const uint8_t *nb_ptr, uint32_t nb_len)
3045 {
3046     SmbAndXCom andx_com = smb_chain_map[smb_com];
3047     const SmbCommon *sc = (SmbCommon *)nb_ptr;
3048     int chk_com_size;
3049     uint16_t smb_bcc;
3050     static DCE2_SmbComInfo com_info;
3051 
3052     com_info.smb_type = DCE2_SmbType(ssd);
3053     com_info.cmd_error = DCE2_SMB_COM_ERROR__COMMAND_OK;
3054     com_info.word_count = 0;
3055     com_info.smb_com = smb_com;
3056     com_info.cmd_size = 0;
3057     com_info.byte_count = 0;
3058 
3059     // Check for server error response
3060     if (com_info.smb_type == SMB_TYPE__RESPONSE)
3061     {
3062         const SmbEmptyCom *ec = (SmbEmptyCom *)nb_ptr;
3063 
3064         // Verify there is enough data to do checks
3065         if (nb_len < sizeof(SmbEmptyCom))
3066         {
3067             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, sizeof(SmbEmptyCom));
3068             com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3069             return &com_info;
3070         }
3071 
3072         // If word and byte counts are zero and there is an error
3073         // the server didn't accept client request
3074         if ((SmbEmptyComWct(ec) == 0)
3075                 && (SmbEmptyComBcc(ec) == 0) && SmbError(smb_hdr))
3076         {
3077 
3078             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
3079                         "Response error: 0x%08X\n", SmbNtStatus(smb_hdr)));
3080 
3081             // If broken pipe, clean up data associated with open named pipe
3082             if (SmbBrokenPipe(smb_hdr))
3083             {
3084                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
3085                             "  Broken or disconnected pipe.\n"));
3086 
3087                 DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
3088             }
3089 
3090             com_info.cmd_error |= DCE2_SMB_COM_ERROR__STATUS_ERROR;
3091             return &com_info;
3092         }
3093     }
3094 
3095     // Set the header size to the minimum size the command can be
3096     // without the byte count to make sure there is enough data to
3097     // get the word count.
3098     if (andx_com == SMB_ANDX_COM__NONE)
3099         chk_com_size = sizeof(SmbCommon);
3100     else
3101         chk_com_size = sizeof(SmbAndXCommon);
3102 
3103     // Verify there is enough data to do checks
3104     if (nb_len < (uint32_t)chk_com_size)
3105     {
3106         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, chk_com_size);
3107         com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3108         return &com_info;
3109     }
3110 
3111     com_info.word_count = SmbWct(sc);
3112 
3113     // Make sure the word count is a valid one for the command.  If not
3114     // testing shows an error will be returned.  And command structures
3115     // won't lie on data correctly and out of bounds data accesses are possible.
3116     if (!DCE2_SmbIsValidWordCount(smb_com, (uint8_t)com_info.smb_type, com_info.word_count))
3117     {
3118         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_WCT, com_info.word_count);
3119         com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_WORD_COUNT;
3120         return &com_info;
3121     }
3122 
3123     // This gets the size of the SMB command from word count through byte count
3124     // using the advertised value in the word count field.
3125     com_info.cmd_size = (uint16_t)SMB_COM_SIZE(com_info.word_count);
3126     if (nb_len < com_info.cmd_size)
3127     {
3128         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_COM, nb_len, com_info.cmd_size);
3129         com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3130         return &com_info;
3131     }
3132 
3133     smb_bcc = SmbBcc(nb_ptr, com_info.cmd_size);
3134 
3135     // SMB_COM_NT_CREATE_ANDX is a special case.  Who know what's going
3136     // on with the word count (see MS-CIFS and MS-SMB).  A 42 word count
3137     // command seems to actually have 50 words, so who knows where the
3138     // byte count is.  Just set to zero since it's not needed.
3139     if ((smb_com == SMB_COM_NT_CREATE_ANDX)
3140             && (com_info.smb_type == SMB_TYPE__RESPONSE))
3141         smb_bcc = 0;
3142 
3143     // If byte count is deemed invalid, alert but continue processing
3144     switch (smb_com)
3145     {
3146         // Interim responses
3147         case SMB_COM_TRANSACTION:
3148         case SMB_COM_TRANSACTION2:
3149         case SMB_COM_NT_TRANSACT:
3150             // If word count is 0, byte count must be 0
3151             if ((com_info.word_count == 0) && (com_info.smb_type == SMB_TYPE__RESPONSE))
3152             {
3153                 if (smb_bcc != 0)
3154                 {
3155                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_BCC, smb_bcc);
3156                     com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
3157                 }
3158                 break;
3159             }
3160             // Fall through
3161         default:
3162             if (!DCE2_SmbIsValidByteCount(smb_com, (uint8_t)com_info.smb_type, smb_bcc))
3163             {
3164                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_BCC, smb_bcc);
3165                 com_info.cmd_error |= DCE2_SMB_COM_ERROR__INVALID_BYTE_COUNT;
3166             }
3167             break;
3168     }
3169 
3170     // Move just past byte count field which is the end of the command
3171     DCE2_MOVE(nb_ptr, nb_len, com_info.cmd_size);
3172 
3173     // Validate that there is enough data to be able to process the command
3174     if (nb_len < DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type))
3175     {
3176         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_BCC, nb_len,
3177                 DCE2_SmbGetMinByteCount(smb_com, (uint8_t)com_info.smb_type));
3178         com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3179     }
3180 
3181     // The byte count seems to be ignored by Windows and current Samba (3.5.4)
3182     // as long as it is less than the amount of data left.  If more, an error
3183     // is returned.
3184     // !!!WARNING!!! the byte count should probably never be used.
3185     if (smb_bcc > nb_len)
3186     {
3187         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_BCC, nb_len, smb_bcc);
3188 
3189         // Large byte count doesn't seem to matter for early Samba
3190         switch (DCE2_SsnGetPolicy(&ssd->sd))
3191         {
3192             case DCE2_POLICY__SAMBA_3_0_20:
3193             case DCE2_POLICY__SAMBA_3_0_22:
3194             case DCE2_POLICY__SAMBA_3_0_37:
3195                 break;
3196             default:
3197                 com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3198                 break;
3199         }
3200     }
3201     else if ((smb_bcc == 0) && (SmbCom(smb_hdr) == SMB_COM_TRANSACTION)
3202             && (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
3203             && (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA))
3204     {
3205         // Current Samba errors on a zero byte count Transaction because it
3206         // uses it to get the Name string and if zero Name will be NULL and
3207         // it won't process it.
3208         com_info.cmd_error |= DCE2_SMB_COM_ERROR__BAD_LENGTH;
3209     }
3210 
3211     com_info.byte_count = smb_bcc;
3212 
3213     return &com_info;
3214 }
3215 
3216 /********************************************************************
3217  * Function: DCE2_SmbProcessCommand()
3218  *
3219  * Purpose:
3220  *  This is the main function for handling SMB commands and command
3221  *  chaining.
3222  *  It does an initial check of the command to determine validity
3223  *  and gets basic information about the command.  Then it calls the
3224  *  specific command function (setup in DCE2_SmbInitGlobals).
3225  *  If there is command chaining, it will do the chaining foo to
3226  *  get to the next command.
3227  *
3228  * Arguments:
3229  *  DCE2_SmbSsnData * - pointer to session data structure
3230  *  SmbNtHdr *        - pointer to the SMB header structure
3231  *  uint8_t *         - current pointer to data, i.e. the command
3232  *  uint32_t          - the remaining length
3233  *
3234  * Returns: None
3235  *
3236  ********************************************************************/
DCE2_SmbProcessCommand(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const uint8_t * nb_ptr,uint32_t nb_len)3237 static void DCE2_SmbProcessCommand(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
3238         const uint8_t *nb_ptr, uint32_t nb_len)
3239 {
3240     DCE2_Ret status = DCE2_RET__ERROR;
3241     DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
3242     uint8_t smb_com = SmbCom(smb_hdr);
3243     int smb_type = DCE2_SmbType(ssd);
3244     int num_chained = 0;
3245     bool sess_chain = false;
3246     bool tree_chain = false;
3247     bool open_chain = false;
3248 
3249     dce2_stats.smb_com_stats[smb_type][smb_com]++;
3250 
3251     while (nb_len > 0)
3252     {
3253         SmbAndXCom andx_com = smb_chain_map[smb_com];
3254         const SmbAndXCommon *andx_ptr = (SmbAndXCommon *)nb_ptr;
3255         uint8_t smb_com2;
3256         const uint8_t *off2_ptr;
3257         DCE2_SmbComInfo *com_info;
3258 
3259 #ifdef ACTIVE_RESPONSE
3260         if (ssd->block_pdus && (smb_type == SMB_TYPE__REQUEST))
3261         {
3262             _dpd.inlineDropPacket((void *)ssd->sd.wire_pkt);
3263             status = DCE2_RET__IGNORE;
3264             if (*_dpd.pkt_tracer_enabled)
3265                 _dpd.addPktTrace(VERDICT_REASON_SMB, snprintf(_dpd.trace, _dpd.traceMax,
3266                     "SMB: gid %u, server message block file drop\n", GENERATOR_DCE2));
3267             else _dpd.addPktTrace(VERDICT_REASON_SMB, 0);
3268             break;
3269         }
3270 #endif
3271 
3272         // Break out if command not supported
3273         if (smb_com_funcs[smb_com] == NULL)
3274             break;
3275 
3276         if (smb_deprecated_coms[smb_com])
3277         {
3278             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_COMMAND_USED,
3279                     smb_com_strings[smb_com]);
3280         }
3281 
3282         if (smb_unusual_coms[smb_com])
3283         {
3284             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
3285                     smb_com_strings[smb_com]);
3286         }
3287 
3288         com_info = DCE2_SmbCheckCommand(ssd, smb_hdr, smb_com, nb_ptr, nb_len);
3289 
3290         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Processing command: %s (0x%02X)\n",
3291                     smb_com_strings[smb_com], smb_com));
3292 
3293         // Note that even if the command shouldn't be processed, some of
3294         // the command functions need to know and do cleanup or some other
3295         // processing.
3296         status = smb_com_funcs[smb_com](ssd, smb_hdr,
3297                 (const DCE2_SmbComInfo *)com_info, nb_ptr, nb_len);
3298 
3299         if (status != DCE2_RET__SUCCESS)
3300             break;
3301 
3302         // This command is not chainable
3303         if (andx_com == SMB_ANDX_COM__NONE)
3304             break;
3305 
3306         /**********************************************************
3307          * AndX Chaining
3308          **********************************************************/
3309         smb_com2 = SmbAndXCom2(andx_ptr);
3310         if (smb_com2 == SMB_COM_NO_ANDX_COMMAND)
3311             break;
3312 
3313         dce2_stats.smb_chained_stats[smb_type][andx_com][smb_com2]++;
3314         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Chained SMB command: %s\n", smb_com_strings[smb_com2]));
3315 
3316         num_chained++;
3317         if (DCE2_ScSmbMaxChain(ssd->sd.sconfig) &&
3318                 (num_chained >= DCE2_ScSmbMaxChain(ssd->sd.sconfig)))
3319         {
3320             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EXCESSIVE_CHAINING, DCE2_ScSmbMaxChain(ssd->sd.sconfig));
3321         }
3322 
3323         // Multiple SessionSetupAndX, TreeConnectAndX, OpenAndX and NtCreateAndX
3324         // are only allowed by Samba.
3325         if (smb_com == SMB_COM_SESSION_SETUP_ANDX)
3326             sess_chain = true;
3327 
3328         // Check for multiple chained SessionSetupAndX
3329         if ((smb_com2 == SMB_COM_SESSION_SETUP_ANDX) && sess_chain)
3330         {
3331             // There is only one place to return a uid.
3332             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULT_CHAIN_SS);
3333             // XXX Should we continue processing?
3334             break;
3335         }
3336 
3337         // Check for chained SessionSetupAndX => .? => LogoffAndX
3338         if ((smb_com2 == SMB_COM_LOGOFF_ANDX) && sess_chain)
3339         {
3340             // This essentially deletes the uid created by the login
3341             // and doesn't make any sense.
3342             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_SS_LOGOFF);
3343         }
3344 
3345         if (smb_com == SMB_COM_TREE_CONNECT_ANDX)
3346             tree_chain = true;
3347 
3348         // Check for multiple chained TreeConnects
3349         if (((smb_com2 == SMB_COM_TREE_CONNECT_ANDX)
3350                     || (smb_com2 == SMB_COM_TREE_CONNECT)) && tree_chain)
3351         {
3352             // There is only one place to return a tid.
3353             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MULT_CHAIN_TC);
3354             // XXX Should we continue processing?
3355             break;
3356         }
3357 
3358         // Check for chained TreeConnectAndX => .? => TreeDisconnect
3359         if ((smb_com2 == SMB_COM_TREE_DISCONNECT) && tree_chain)
3360         {
3361             // This essentially deletes the tid created by the tree connect
3362             // and doesn't make any sense.
3363             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_TC_TDIS);
3364         }
3365 
3366         if ((smb_com == SMB_COM_OPEN_ANDX) || (smb_com == SMB_COM_NT_CREATE_ANDX))
3367             open_chain = true;
3368 
3369         // Check for chained OpenAndX/NtCreateAndX => .? => Close
3370         if ((smb_com2 == SMB_COM_CLOSE) && open_chain)
3371         {
3372             // This essentially deletes the fid created by the open command
3373             // and doesn't make any sense.
3374             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_CHAIN_OPEN_CLOSE);
3375         }
3376 
3377         // Check that policy allows for such chaining
3378         if (smb_chain_funcs[policy][andx_com][smb_com2] == NULL)
3379             break;
3380 
3381         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
3382 
3383         // XXX Need to test out of order chaining
3384         off2_ptr = (uint8_t *)smb_hdr + SmbAndXOff2(andx_ptr);
3385         if (DCE2_SmbCheckAndXOffset(ssd, off2_ptr, nb_ptr, nb_len) != DCE2_RET__SUCCESS)
3386             break;
3387 
3388         DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr));
3389 
3390         // XXX Need to test more.
3391         switch (smb_com)
3392         {
3393             case SMB_COM_SESSION_SETUP_ANDX:
3394             case SMB_COM_TREE_CONNECT_ANDX:
3395             case SMB_COM_OPEN_ANDX:
3396             case SMB_COM_NT_CREATE_ANDX:
3397                 switch (smb_com2)
3398                 {
3399                     case SMB_COM_WRITE:
3400                     case SMB_COM_WRITE_ANDX:
3401                     case SMB_COM_TRANSACTION:
3402                     case SMB_COM_READ_ANDX:
3403                         if (DCE2_SsnFromClient(ssd->sd.wire_pkt) && open_chain)
3404                         {
3405                             DCE2_SmbQueueTmpFileTracker(ssd, ssd->cur_rtracker,
3406                                     SmbUid(smb_hdr), SmbTid(smb_hdr));
3407                         }
3408                         break;
3409                     default:
3410                         break;
3411                 }
3412                 break;
3413             default:
3414                 break;
3415         }
3416 
3417         smb_com = smb_com2;
3418     }
3419 
3420     if (smb_type == SMB_TYPE__RESPONSE)
3421     {
3422         switch (smb_com)
3423         {
3424             case SMB_COM_TRANSACTION:
3425             case SMB_COM_TRANSACTION2:
3426             case SMB_COM_NT_TRANSACT:
3427             case SMB_COM_TRANSACTION_SECONDARY:
3428             case SMB_COM_TRANSACTION2_SECONDARY:
3429             case SMB_COM_NT_TRANSACT_SECONDARY:
3430                 // This case means there was an error with the initial response
3431                 // so the tracker isn't yet officially in response mode
3432                 if (ssd->cur_rtracker->ttracker.smb_type == SMB_TYPE__REQUEST)
3433                 {
3434                     // Samba throws out entire transaction and Windows just this request
3435                     if (DCE2_SsnIsServerSambaPolicy(&ssd->sd) && (status != DCE2_RET__SUCCESS))
3436                         break;
3437 
3438                     if (!DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
3439                         return;
3440                 }
3441                 else
3442                 {
3443                     if ((status == DCE2_RET__SUCCESS)
3444                             && !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
3445                         return;
3446                 }
3447                 break;
3448             case SMB_COM_WRITE_RAW:
3449                 if ((status == DCE2_RET__SUCCESS)
3450                         && (ssd->cur_rtracker->writeraw_remaining != 0))
3451                     return;
3452                 break;
3453             /*This is to handle packet that got verdict as pending & will be put in retry queue */
3454             case SMB_COM_CLOSE:
3455                 if (status == DCE2_RET__NOT_INSPECTED)
3456                     return;
3457             default:
3458                 break;
3459         }
3460     }
3461     else if (status != DCE2_RET__IGNORE)
3462     {
3463         switch (smb_com)
3464         {
3465             case SMB_COM_TRANSACTION:
3466             case SMB_COM_TRANSACTION_SECONDARY:
3467                 if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
3468                 {
3469                     if (!ssd->cur_rtracker->ttracker.one_way
3470                             || !DCE2_SmbIsTransactionComplete(&ssd->cur_rtracker->ttracker))
3471                         return;
3472 
3473                     // Remove the request tracker if transaction is one-way and
3474                     // all data and parameters have been sent
3475                     break;
3476                 }
3477             default:
3478                 // Anything else, keep the request tracker
3479                 return;
3480         }
3481     }
3482 
3483     DCE2_SmbRemoveRequestTracker(ssd, ssd->cur_rtracker);
3484     ssd->cur_rtracker = NULL;
3485 }
3486 
3487 /********************************************************************
3488  * Function: DCE2_SmbCheckData()
3489  *
3490  * Purpose:
3491  *  Ensures that the data size reported in an SMB command is kosher.
3492  *
3493  * Arguments:
3494  *  DCE2_SmbSsnData * - SMB session data structure
3495  *  const uint8_t *   - pointer to start of SMB header where offset is
3496  *                      taken from.
3497  *  const uint8_t *   - current pointer - should be right after command
3498  *                      structure.
3499  *  const uint32_t    - remaining data left in PDU from current pointer.
3500  *  const uint16_t    - the byte count from the SMB command
3501  *  const uint16_t    - reported data count in SMB command
3502  *  const uint16_t    - reported data offset in SMB command
3503  *
3504  * Returns:
3505  *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
3506  *              DCE2_RET__SUCCESS if data can be processed
3507  *
3508  ********************************************************************/
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)3509 static inline DCE2_Ret DCE2_SmbCheckData(DCE2_SmbSsnData *ssd,
3510         const uint8_t *smb_hdr_ptr, const uint8_t *nb_ptr,
3511         const uint32_t nb_len, const uint16_t bcc,
3512         const uint32_t dcnt, uint16_t doff)
3513 {
3514     const uint8_t *offset = smb_hdr_ptr + doff;
3515     const uint8_t *nb_end = nb_ptr + nb_len;
3516 
3517     // Byte counts don't usually matter, so no error but still alert
3518     // Don't alert in the case where the data count is larger than what the
3519     // byte count can handle.  This can happen if CAP_LARGE_READX or
3520     // CAP_LARGE_WRITEX were negotiated.
3521     if ((dcnt <= UINT16_MAX) && (bcc < dcnt))
3522         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BCC_LT_DSIZE, bcc, (uint64_t)dcnt);
3523 
3524     if (offset > nb_end)
3525     {
3526         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, offset, nb_ptr, nb_end);
3527 
3528         // Error if offset is beyond data left
3529         return DCE2_RET__ERROR;
3530     }
3531 
3532     // Only check if the data count is non-zero
3533     if ((dcnt != 0) && (offset < nb_ptr))
3534     {
3535         // Not necessarily and error if the offset puts the data
3536         // before or in the command structure.
3537         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, offset, nb_ptr, nb_end);
3538     }
3539 
3540     // Not necessarily an error if the addition of the data count goes
3541     // beyond the data left
3542     if (((offset + dcnt) > nb_end)           // beyond data left
3543             || ((offset + dcnt) < offset))   // wrap
3544     {
3545         int pad = offset - nb_ptr;
3546         if (pad > 0)
3547             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len - pad, dcnt);
3548         else
3549             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt);
3550     }
3551 
3552     return DCE2_RET__SUCCESS;
3553 }
3554 
3555 /********************************************************************
3556  * Function: DCE2_SmbValidateTransactionFields()
3557  *
3558  * Purpose:
3559  *  Wrapper that calls DCE2_SmbCheckTotalCount() for total parameter
3560  *  count and total data count and DCE2_SmbCheckTransDataParams()
3561  *
3562  * Arguments:
3563  *  DCE2_SmbSsnData * - SMB session data structure
3564  *  const uint8_t *   - pointer to start of SMB header where offset is
3565  *                      taken from.
3566  *  const uint8_t *   - current pointer - should be right after command
3567  *                      structure.
3568  *  const uint32_t    - remaining data left in PDU from current pointer.
3569  *  const uint16_t    - the byte count
3570  *  const uint32_t    - reported total data count
3571  *  const uint32_t    - reported total parameter count
3572  *  const uint32_t    - reported data count
3573  *  const uint32_t    - reported data offset
3574  *  const uint32_t    - reported data displacement
3575  *  const uint32_t    - reported parameter count
3576  *  const uint32_t    - reported parameter offset
3577  *  const uint32_t    - reported parameter displacement
3578  *
3579  * Returns:
3580  *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
3581  *              DCE2_RET__SUCCESS if data can be processed
3582  *
3583  ********************************************************************/
DCE2_SmbValidateTransactionFields(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 tdcnt,const uint32_t tpcnt,const uint32_t dcnt,const uint32_t doff,const uint32_t ddisp,const uint32_t pcnt,const uint32_t poff,const uint32_t pdisp)3584 static inline DCE2_Ret DCE2_SmbValidateTransactionFields(DCE2_SmbSsnData *ssd,
3585         const uint8_t *smb_hdr_ptr,
3586         const uint8_t *nb_ptr, const uint32_t nb_len, const uint16_t bcc,
3587         const uint32_t tdcnt, const uint32_t tpcnt,
3588         const uint32_t dcnt, const uint32_t doff, const uint32_t ddisp,
3589         const uint32_t pcnt, const uint32_t poff, const uint32_t pdisp)
3590 {
3591     if (DCE2_SmbCheckTotalCount(ssd, tdcnt, dcnt, ddisp) != DCE2_RET__SUCCESS)
3592         return DCE2_RET__ERROR;
3593 
3594     if (DCE2_SmbCheckTotalCount(ssd, tpcnt, pcnt, pdisp) != DCE2_RET__SUCCESS)
3595         return DCE2_RET__ERROR;
3596 
3597     if (DCE2_SmbCheckTransDataParams(ssd, smb_hdr_ptr,
3598                 nb_ptr, nb_len, bcc, dcnt, doff, pcnt, poff) != DCE2_RET__SUCCESS)
3599         return DCE2_RET__ERROR;
3600 
3601     return DCE2_RET__SUCCESS;
3602 }
3603 
3604 /********************************************************************
3605  * Function: DCE2_SmbValidateTransactionSent()
3606  *
3607  * Purpose:
3608  *  Checks that amount sent plus current amount is not greater than
3609  *  the total count expected.
3610  *
3611  * Arguments:
3612  *  DCE2_SmbSsnData * - SMB session data structure
3613  *  const uint32_t    - amount of data sent so far
3614  *  const uint32_t    - reported total data count
3615  *  const uint32_t    - reported data count
3616  *  const uint32_t    - amount of parameters sent so far
3617  *  const uint32_t    - reported total parameter count
3618  *  const uint32_t    - reported parameter count
3619  *
3620  * Returns:
3621  *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
3622  *              DCE2_RET__SUCCESS if data can be processed
3623  *
3624  ********************************************************************/
DCE2_SmbValidateTransactionSent(DCE2_SmbSsnData * ssd,uint32_t dsent,uint32_t dcnt,uint32_t tdcnt,uint32_t psent,uint32_t pcnt,uint32_t tpcnt)3625 static inline DCE2_Ret DCE2_SmbValidateTransactionSent(DCE2_SmbSsnData *ssd,
3626         uint32_t dsent, uint32_t dcnt, uint32_t tdcnt,
3627         uint32_t psent, uint32_t pcnt, uint32_t tpcnt)
3628 {
3629     if (((dsent + dcnt) > tdcnt) || ((psent + pcnt) > tpcnt))
3630     {
3631         if ((dsent + dcnt) > tdcnt)
3632         {
3633             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT,
3634                     ((uint64_t)dsent + dcnt), tdcnt);
3635         }
3636 
3637         if ((psent + pcnt) > tpcnt)
3638         {
3639             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT,
3640                     ((uint64_t)psent + pcnt), tpcnt);
3641         }
3642 
3643         // Samba throws out entire transaction and Windows seems to hang in
3644         // limbo forever and never responds, so stop looking
3645         return DCE2_RET__ERROR;
3646     }
3647 
3648     return DCE2_RET__SUCCESS;
3649 }
3650 
3651 /********************************************************************
3652  * Function: DCE2_SmbCheckTransDataParams()
3653  *
3654  * Purpose:
3655  *  Ensures that the data size reported in an SMB command is kosher.
3656  *  Note the 32 bit values are because of the NtTransact command
3657  *  though it's currently not checked.
3658  *
3659  * Arguments:
3660  *  DCE2_SmbSsnData * - SMB session data structure
3661  *  const uint8_t *   - pointer to start of SMB header where offset is
3662  *                      taken from.
3663  *  const uint8_t *   - current pointer - should be right after command
3664  *                      structure.
3665  *  const uint32_t    - remaining data left in PDU from current pointer.
3666  *  const uint16_t    - the byte count
3667  *  const uint32_t    - reported data count
3668  *  const uint32_t    - reported data offset
3669  *  const uint32_t    - reported parameter count
3670  *  const uint32_t    - reported parameter offset
3671  *
3672  * Returns:
3673  *  DCE2_Ret -  DCE2_RET__ERROR if data should not be processed
3674  *              DCE2_RET__SUCCESS if data can be processed
3675  *
3676  ********************************************************************/
DCE2_SmbCheckTransDataParams(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,const uint32_t doff,const uint32_t pcnt,const uint32_t poff)3677 static inline DCE2_Ret DCE2_SmbCheckTransDataParams(DCE2_SmbSsnData *ssd,
3678         const uint8_t *smb_hdr_ptr, const uint8_t *nb_ptr, const uint32_t nb_len,
3679         const uint16_t bcc, const uint32_t dcnt, const uint32_t doff,
3680         const uint32_t pcnt, const uint32_t poff)
3681 {
3682     const uint8_t *doffset = smb_hdr_ptr + doff;
3683     const uint8_t *poffset = smb_hdr_ptr + poff;
3684     const uint8_t *nb_end = nb_ptr + nb_len;
3685 
3686     if (bcc < ((uint64_t)dcnt + pcnt))
3687         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BCC_LT_DSIZE, bcc, ((uint64_t)dcnt + pcnt));
3688 
3689     // Check data offset out of bounds
3690     if ((doffset > nb_end) || (doffset < smb_hdr_ptr))
3691     {
3692         // Beyond data left or wrap
3693         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, doffset, nb_ptr, nb_end);
3694         return DCE2_RET__ERROR;
3695     }
3696 
3697     // Check data offset in bounds but backwards
3698     // Only check if the data count is non-zero
3699     if ((dcnt != 0) && (doffset < nb_ptr))
3700     {
3701         // Not necessarily and error if the offset puts the data
3702         // before or in the command structure.
3703         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, doffset, nb_ptr, nb_end);
3704     }
3705 
3706     // Check the data offset + data count
3707     if (((doffset + dcnt) > nb_end)            // beyond data left
3708             || ((doffset + dcnt) < doffset))   // wrap
3709     {
3710         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt);
3711         return DCE2_RET__ERROR;
3712     }
3713 
3714     // Check parameter offset out of bounds
3715     if ((poffset > nb_end) || (poffset < smb_hdr_ptr))
3716     {
3717         // Beyond data left or wrap
3718         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, poffset, nb_ptr, nb_end);
3719         return DCE2_RET__ERROR;
3720     }
3721 
3722     // Check parameter offset in bounds but backwards
3723     // Only check if the parameter count is non-zero
3724     if ((pcnt != 0) && (poffset < nb_ptr))
3725     {
3726         // Not necessarily and error if the offset puts the data
3727         // before or in the command structure.
3728         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, poffset, nb_ptr, nb_end);
3729     }
3730 
3731     // Check the parameter offset + parameter count
3732     if (((poffset + pcnt) > nb_end)            // beyond data left
3733             || ((poffset + pcnt) < poffset))   // wrap
3734     {
3735         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, pcnt);
3736         return DCE2_RET__ERROR;
3737     }
3738 
3739     return DCE2_RET__SUCCESS;
3740 }
3741 
3742 /********************************************************************
3743  * Function: DCE2_SmbCheckFmtData()
3744  *
3745  * Purpose:
3746  *  Checks the data count in commands with formats, e.g.
3747  *  SMB_COM_WRITE, SMB_COM_WRITE_AND_CLOSE, SMB_COM_WRITE_AND_UNLOCK.
3748  *
3749  * Arguments:
3750  *  DCE2_SmbSsnData * - SMB session data structure
3751  *  const uint32_t    - remaining NetBIOS PDU length
3752  *  const uint16_t    - advertised byte count
3753  *  const uint8_t     - data format specifier
3754  *  const uint16_t    - data count reported in command
3755  *  const uint16_t    - data count reported in format field
3756  *
3757  * Returns: None
3758  *
3759  ********************************************************************/
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)3760 static inline void DCE2_SmbCheckFmtData(DCE2_SmbSsnData *ssd,
3761         const uint32_t nb_len, const uint16_t bcc, const uint8_t fmt,
3762         const uint16_t com_dcnt, const uint16_t fmt_dcnt)
3763 {
3764     if (fmt != SMB_FMT__DATA_BLOCK)
3765         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, fmt);
3766 
3767     if (com_dcnt != fmt_dcnt)
3768         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_MISMATCH, com_dcnt, fmt_dcnt);
3769 
3770     if (com_dcnt != (bcc - 3))
3771         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_DSIZE, com_dcnt, bcc);
3772 
3773     if (nb_len < com_dcnt)
3774         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, com_dcnt);
3775 }
3776 
3777 /********************************************************************
3778  * Function: DCE2_SmbCheckTotalCount()
3779  *
3780  * Purpose:
3781  *  Validates the advertised total data/param count.  Makes sure the
3782  *  current count isn't greater than total count, that the
3783  *  displacement + count isn't greater than the total data count and
3784  *  that the total data count isn't zero.  Mainly relevant to Write Raw,
3785  *  Transaction and Transaction Secondary commands.
3786  *
3787  * Arguments:
3788  *  DCE2_SmbSsnData * - SMB session data structure
3789  *  const uint32_t    - total data count
3790  *  const uint32_t    - data count/size
3791  *  const uint32_t    - data displacement
3792  *
3793  * Returns:
3794  *  DCE2_Ret - DCE2_RET__SUCCESS if all is ok
3795  *             DCE2_RET__ERROR if any of the checks fail.
3796  *
3797  ********************************************************************/
DCE2_SmbCheckTotalCount(DCE2_SmbSsnData * ssd,const uint32_t tcnt,const uint32_t cnt,const uint32_t disp)3798 static inline DCE2_Ret DCE2_SmbCheckTotalCount(DCE2_SmbSsnData *ssd,
3799         const uint32_t tcnt, const uint32_t cnt, const uint32_t disp)
3800 {
3801     DCE2_Ret ret = DCE2_RET__SUCCESS;
3802 
3803     if (cnt > tcnt)
3804     {
3805         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_LT_DSIZE, tcnt, cnt);
3806         ret = DCE2_RET__ERROR;
3807     }
3808 
3809     if (((uint64_t)disp + cnt) > tcnt)
3810     {
3811         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DSENT_GT_TDCNT, ((uint64_t)disp + cnt), tcnt);
3812         ret = DCE2_RET__ERROR;
3813     }
3814 
3815     return ret;
3816 }
3817 
3818 /********************************************************************
3819  * Function: DCE2_SmbCheckAndXOffset()
3820  *
3821  * Purpose:
3822  *  Validates that the AndXOffset is within bounds of the remaining
3823  *  data we have to work with.
3824  *
3825  * Arguments:
3826  *  uint8_t * - pointer to where the offset would take us.
3827  *  uint8_t * - pointer to bound offset
3828  *  uint8_t * - length of data where offset should be within
3829  *
3830  * Returns:
3831  *  DCE2_RET__SUCCESS - Offset is okay.
3832  *  DCE2_RET__ERROR   - Offset is bad.
3833  *
3834  ********************************************************************/
DCE2_SmbCheckAndXOffset(DCE2_SmbSsnData * ssd,const uint8_t * off_ptr,const uint8_t * start_bound,const uint32_t length)3835 static inline DCE2_Ret DCE2_SmbCheckAndXOffset(DCE2_SmbSsnData *ssd,
3836         const uint8_t *off_ptr, const uint8_t *start_bound, const uint32_t length)
3837 {
3838     /* Offset should not point within data we just looked at or be equal to
3839      * or beyond the length of the NBSS length left */
3840     if ((off_ptr < start_bound) ||
3841             (off_ptr > (start_bound + length)))
3842     {
3843         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_OFF, off_ptr,
3844                 start_bound, start_bound + length);
3845 
3846         return DCE2_RET__ERROR;
3847     }
3848 
3849     return DCE2_RET__SUCCESS;
3850 }
3851 
3852 /********************************************************************
3853  * Function: DCE2_SmbInvalidShareCheck()
3854  *
3855  * Purpose:
3856  *  Checks the share reported in a TreeConnect or TreeConnectAndX
3857  *  against the invalid share list configured in the dcerpc2
3858  *  configuration in snort.conf.
3859  *
3860  * Arguments:
3861  *  DCE2_SmbSsnData * - SMB session data structure
3862  *  SmbNtHdr *        - pointer to the SMB header structure
3863  *  uint8_t *         - current pointer to the share to check
3864  *  uint32_t          - the remaining length
3865  *
3866  * Returns: None
3867  *  Alerts if there is an invalid share match.
3868  *
3869  ********************************************************************/
DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const uint8_t * nb_ptr,uint32_t nb_len)3870 static inline void DCE2_SmbInvalidShareCheck(DCE2_SmbSsnData *ssd,
3871         const SmbNtHdr *smb_hdr, const uint8_t *nb_ptr, uint32_t nb_len)
3872 {
3873     DCE2_List *share_list = DCE2_ScSmbInvalidShares(ssd->sd.sconfig);
3874     DCE2_SmbShare *smb_share;
3875 
3876     if (share_list == NULL)
3877         return;
3878 
3879     for (smb_share = (DCE2_SmbShare *)DCE2_ListFirst(share_list);
3880             smb_share != NULL;
3881             smb_share = (DCE2_SmbShare *)DCE2_ListNext(share_list))
3882     {
3883         unsigned int i;
3884         const char *share_str;
3885         unsigned int share_str_len;
3886 
3887         if (SmbUnicode(smb_hdr))
3888         {
3889             share_str = smb_share->unicode_str;
3890             share_str_len = smb_share->unicode_str_len;
3891         }
3892         else
3893         {
3894             share_str = smb_share->ascii_str;
3895             share_str_len = smb_share->ascii_str_len;
3896         }
3897 
3898         /* Make sure we have enough data */
3899         if (nb_len < share_str_len)
3900             continue;
3901 
3902         /* Test for share match */
3903         for (i = 0; i < share_str_len; i++)
3904         {
3905             /* All share strings should have been converted to upper case and
3906              * should include null terminating bytes */
3907             if ((nb_ptr[i] != share_str[i]) && (nb_ptr[i] != tolower((int)share_str[i])))
3908                 break;
3909         }
3910 
3911         if (i == share_str_len)
3912         {
3913             /* Should only match one share since no duplicate shares in list */
3914             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SHARE, smb_share->ascii_str);
3915             break;
3916         }
3917     }
3918 }
3919 
3920 /********************************************************************
3921  * Functions:
3922  *   DCE2_SmbOpen()
3923  *   DCE2_SmbCreate()
3924  *   DCE2_SmbClose()
3925  *   DCE2_SmbRename()
3926  *   DCE2_SmbRead()
3927  *   DCE2_SmbWrite()
3928  *   DCE2_SmbCreateNew()
3929  *   DCE2_SmbLockAndRead()
3930  *   DCE2_SmbWriteAndUnlock()
3931  *   DCE2_SmbReadRaw()
3932  *   DCE2_SmbWriteRaw()
3933  *   DCE2_SmbWriteComplete()
3934  *   DCE2_SmbTransaction()
3935  *   DCE2_SmbTransactionSecondary()
3936  *   DCE2_SmbWriteAndClose()
3937  *   DCE2_SmbOpenAndX()
3938  *   DCE2_SmbReadAndX()
3939  *   DCE2_SmbWriteAndX()
3940  *   DCE2_SmbTransaction2()
3941  *   DCE2_SmbTransaction2Secondary()
3942  *   DCE2_SmbTreeConnect()
3943  *   DCE2_SmbTreeDisconnect()
3944  *   DCE2_SmbNegotiate()
3945  *   DCE2_SmbSessionSetupAndX()
3946  *   DCE2_SmbLogoffAndX()
3947  *   DCE2_SmbTreeConnectAndX()
3948  *   DCE2_SmbNtTransact()
3949  *   DCE2_SmbNtTransactSecondary()
3950  *   DCE2_SmbNtCreateAndX()
3951  *
3952  * Purpose: Process SMB command
3953  *
3954  * Arguments:
3955  *  DCE2_SmbSsnData *       - SMB session data structure
3956  *  const SmbNtHdr *        - SMB header structure (packet pointer)
3957  *  const DCE2_SmbComInfo * - Basic command information structure
3958  *  uint8_t *               - pointer to start of command (packet pointer)
3959  *  uint32_t                - remaining NetBIOS length
3960  *
3961  * Returns:
3962  *  DCE2_Ret - DCE2_RET__ERROR if something went wrong and/or processing
3963  *               should stop
3964  *             DCE2_RET__SUCCESS if processing should continue
3965  *
3966  ********************************************************************/
3967 
3968 // 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)3969 static DCE2_Ret DCE2_SmbOpen(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
3970         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
3971 {
3972     if (!DCE2_ComInfoCanProcessCommand(com_info))
3973         return DCE2_RET__ERROR;
3974 
3975     if (DCE2_ComInfoIsResponse(com_info))
3976     {
3977         DCE2_SmbFileTracker *ftracker;
3978 
3979         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
3980                 && (SmbFileAttrsDirectory(SmbOpenRespFileAttrs((SmbOpenResp *)nb_ptr))
3981                     || SmbOpenForWriting(SmbOpenRespAccessMode((SmbOpenResp *)nb_ptr))))
3982             return DCE2_RET__SUCCESS;
3983 
3984         ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid,
3985                 ssd->cur_rtracker->tid, SmbOpenRespFid((SmbOpenResp *)nb_ptr));
3986         if (ftracker == NULL)
3987             return DCE2_RET__ERROR;
3988 
3989         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
3990 
3991         if (!ftracker->is_ipc)
3992         {
3993             // This command can only be used to open an existing file
3994             ftracker->ff_file_size = SmbOpenRespFileSize((SmbOpenResp *)nb_ptr);
3995         }
3996     }
3997     else
3998     {
3999         // Have at least 2 bytes of data based on byte count check done earlier
4000 
4001         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
4002 
4003         if (!SmbFmtAscii(*nb_ptr))
4004         {
4005             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
4006             return DCE2_RET__ERROR;
4007         }
4008 
4009         DCE2_MOVE(nb_ptr, nb_len, 1);
4010 
4011         ssd->cur_rtracker->file_name =
4012             DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_len);
4013     }
4014 
4015 
4016     return DCE2_RET__SUCCESS;
4017 }
4018 
4019 // 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)4020 static DCE2_Ret DCE2_SmbCreate(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4021         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4022 {
4023     if (!DCE2_ComInfoCanProcessCommand(com_info))
4024         return DCE2_RET__ERROR;
4025 
4026     if (DCE2_ComInfoIsResponse(com_info))
4027     {
4028         DCE2_SmbFileTracker *ftracker = DCE2_SmbNewFileTracker(
4029                 ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
4030                 SmbCreateRespFid((SmbCreateResp *)nb_ptr));
4031 
4032         if (ftracker == NULL)
4033             return DCE2_RET__ERROR;
4034 
4035         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
4036 
4037         // Command creates or opens and truncates file to 0 so assume
4038         // upload.
4039         if (!ftracker->is_ipc)
4040             ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
4041     }
4042     else
4043     {
4044         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
4045         {
4046             uint16_t file_attrs = SmbCreateReqFileAttrs((SmbCreateReq *)nb_ptr);
4047 
4048             if (SmbAttrDirectory(file_attrs))
4049                 return DCE2_RET__IGNORE;
4050 
4051             if (SmbEvasiveFileAttrs(file_attrs))
4052                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
4053         }
4054 
4055         // Have at least 2 bytes of data based on byte count check done earlier
4056 
4057         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
4058 
4059         if (!SmbFmtAscii(*nb_ptr))
4060         {
4061             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
4062             return DCE2_RET__ERROR;
4063         }
4064 
4065         DCE2_MOVE(nb_ptr, nb_len, 1);
4066 
4067         ssd->cur_rtracker->file_name =
4068             DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_len);
4069     }
4070 
4071     return DCE2_RET__SUCCESS;
4072 }
4073 
4074 // SMB_COM_CLOSE
DCE2_SmbClose(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4075 static DCE2_Ret DCE2_SmbClose(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4076         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4077 {
4078     if (!DCE2_ComInfoCanProcessCommand(com_info))
4079         return DCE2_RET__ERROR;
4080 
4081     if (DCE2_ComInfoIsRequest(com_info))
4082     {
4083         uint16_t fid = SmbCloseReqFid((SmbCloseReq *)nb_ptr);
4084 
4085         // Set this for response
4086         ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid);
4087 
4088 #ifdef ACTIVE_RESPONSE
4089         if ((ssd->fb_ftracker != NULL) && (ssd->fb_ftracker == ssd->cur_rtracker->ftracker))
4090         {
4091             void *ssnptr = ssd->sd.wire_pkt->stream_session;
4092             void *p = (void *)ssd->sd.wire_pkt;
4093             File_Verdict verdict = DCE2_SmbGetFileVerdict(p, ssnptr);
4094 
4095             if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
4096                 ssd->block_pdus = true;
4097         }
4098 #endif
4099     }
4100     else
4101     {
4102         return DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
4103     }
4104 
4105     return DCE2_RET__SUCCESS;
4106 }
4107 
4108 // 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)4109 static DCE2_Ret DCE2_SmbRename(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4110         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4111 {
4112     // NOTE: This command is only processed for CVE-2006-4696 where the buffer
4113     // formats are invalid and has no bearing on DCE/RPC processing.
4114 
4115     if (!DCE2_ComInfoCanProcessCommand(com_info))
4116         return DCE2_RET__ERROR;
4117 
4118     if (DCE2_ComInfoIsRequest(com_info))
4119     {
4120         // Have at least 4 bytes of data based on byte count check done earlier
4121 
4122         uint32_t i;
4123 
4124         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
4125 
4126         if (!SmbFmtAscii(*nb_ptr))
4127         {
4128             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
4129             return DCE2_RET__ERROR;
4130         }
4131 
4132         DCE2_MOVE(nb_ptr, nb_len, 1);
4133 
4134         if (SmbUnicode(smb_hdr))
4135         {
4136             for (i = 0; i < (nb_len - 1); i += 2)
4137             {
4138                 if (*((uint16_t *)(nb_ptr + i)) == 0)
4139                 {
4140                     i += 2;  // move past null terminating bytes
4141                     break;
4142                 }
4143             }
4144         }
4145         else
4146         {
4147             for (i = 0; i < nb_len; i++)
4148             {
4149                 if (nb_ptr[i] == 0)
4150                 {
4151                     i++;  // move past null terminating byte
4152                     break;
4153                 }
4154             }
4155         }
4156 
4157         // i <= nb_len
4158         DCE2_MOVE(nb_ptr, nb_len, i);
4159 
4160         if ((nb_len > 0) && !SmbFmtAscii(*nb_ptr))
4161         {
4162             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
4163             return DCE2_RET__ERROR;
4164         }
4165     }
4166 
4167     // Don't care about tracking response
4168     return DCE2_RET__ERROR;
4169 }
4170 
4171 // SMB_COM_READ
DCE2_SmbRead(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4172 static DCE2_Ret DCE2_SmbRead(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4173         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4174 {
4175     if (!DCE2_ComInfoCanProcessCommand(com_info))
4176         return DCE2_RET__ERROR;
4177 
4178     if (DCE2_ComInfoIsRequest(com_info))
4179     {
4180         DCE2_SmbFileTracker *ftracker =
4181             DCE2_SmbGetFileTracker(ssd, SmbReadReqFid((SmbReadReq *)nb_ptr));
4182 
4183         // Set this for response since response doesn't have the Fid
4184         ssd->cur_rtracker->ftracker = ftracker;
4185         if ((ftracker != NULL) && !ftracker->is_ipc)
4186             ssd->cur_rtracker->file_offset = SmbReadReqOffset((SmbReadReq *)nb_ptr);
4187     }
4188     else
4189     {
4190         // Have at least 3 bytes of data based on byte count check done earlier
4191 
4192         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4193         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4194         uint16_t com_dcnt = SmbReadRespCount((SmbReadResp *)nb_ptr);
4195         uint8_t fmt = *(nb_ptr + com_size);
4196         uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1));
4197 
4198         DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
4199 
4200         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
4201 
4202         if (com_dcnt > nb_len)
4203             return DCE2_RET__ERROR;
4204 
4205         return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
4206     }
4207 
4208     return DCE2_RET__SUCCESS;
4209 }
4210 
4211 // SMB_COM_WRITE
DCE2_SmbWrite(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4212 static DCE2_Ret DCE2_SmbWrite(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4213         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4214 {
4215     if (!DCE2_ComInfoCanProcessCommand(com_info))
4216         return DCE2_RET__ERROR;
4217 
4218     if (DCE2_ComInfoIsRequest(com_info))
4219     {
4220         // Have at least 3 bytes of data based on byte count check done earlier
4221 
4222         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4223         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4224         uint8_t fmt = *(nb_ptr + com_size);
4225         uint16_t com_dcnt = SmbWriteReqCount((SmbWriteReq *)nb_ptr);
4226         uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1));
4227         uint16_t fid = SmbWriteReqFid((SmbWriteReq *)nb_ptr);
4228         uint32_t offset = SmbWriteReqOffset((SmbWriteReq *)nb_ptr);
4229 
4230         DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
4231 
4232         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
4233 
4234         if (com_dcnt == 0)
4235         {
4236             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO);
4237             return DCE2_RET__ERROR;
4238         }
4239 
4240         if (com_dcnt > nb_len)
4241             com_dcnt = (uint16_t)nb_len;
4242 
4243         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
4244     }
4245 
4246     return DCE2_RET__SUCCESS;
4247 }
4248 
4249 // 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)4250 static DCE2_Ret DCE2_SmbCreateNew(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4251         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4252 {
4253     if (!DCE2_ComInfoCanProcessCommand(com_info))
4254         return DCE2_RET__ERROR;
4255 
4256     if (DCE2_ComInfoIsResponse(com_info))
4257     {
4258         DCE2_SmbFileTracker *ftracker = DCE2_SmbNewFileTracker(
4259                 ssd, ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
4260                 SmbCreateNewRespFid((SmbCreateNewResp *)nb_ptr));
4261 
4262         if (ftracker == NULL)
4263             return DCE2_RET__ERROR;
4264 
4265         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
4266 
4267         // Command creates a new file so assume upload.
4268         if (!ftracker->is_ipc)
4269             ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
4270     }
4271     else
4272     {
4273         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
4274         {
4275             uint16_t file_attrs = SmbCreateNewReqFileAttrs((SmbCreateNewReq *)nb_ptr);
4276 
4277             if (SmbAttrDirectory(file_attrs))
4278                 return DCE2_RET__IGNORE;
4279 
4280             if (SmbEvasiveFileAttrs(file_attrs))
4281                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
4282         }
4283 
4284         // Have at least 2 bytes of data based on byte count check done earlier
4285 
4286         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
4287 
4288         if (!SmbFmtAscii(*nb_ptr))
4289         {
4290             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
4291             return DCE2_RET__ERROR;
4292         }
4293 
4294         DCE2_MOVE(nb_ptr, nb_len, 1);
4295 
4296         ssd->cur_rtracker->file_name =
4297             DCE2_SmbGetString(nb_ptr, nb_len, SmbUnicode(smb_hdr), &ssd->cur_rtracker->file_name_len);
4298     }
4299 
4300     return DCE2_RET__SUCCESS;
4301 }
4302 
4303 // SMB_COM_LOCK_AND_READ
DCE2_SmbLockAndRead(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4304 static DCE2_Ret DCE2_SmbLockAndRead(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4305         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4306 {
4307     if (!DCE2_ComInfoCanProcessCommand(com_info))
4308         return DCE2_RET__ERROR;
4309 
4310     if (DCE2_ComInfoIsRequest(com_info))
4311     {
4312         DCE2_SmbFileTracker *ftracker =
4313             DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
4314                     ssd->cur_rtracker->tid, SmbLockAndReadReqFid((SmbLockAndReadReq *)nb_ptr));
4315 
4316         // No sense in tracking response
4317         if (ftracker == NULL)
4318             return DCE2_RET__ERROR;
4319 
4320         if (!ftracker->is_ipc)
4321             ssd->cur_rtracker->file_offset = SmbLockAndReadReqOffset((SmbLockAndReadReq *)nb_ptr);
4322 
4323         // Set this for response
4324         ssd->cur_rtracker->ftracker = ftracker;
4325     }
4326     else
4327     {
4328         // Have at least 3 bytes of data based on byte count check done earlier
4329 
4330         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4331         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4332         uint8_t fmt = *(nb_ptr + com_size);
4333         uint16_t com_dcnt = SmbLockAndReadRespCount((SmbLockAndReadResp *)nb_ptr);
4334         uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1));
4335 
4336         DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
4337 
4338         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
4339 
4340         if (com_dcnt == 0)
4341         {
4342             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO);
4343             return DCE2_RET__ERROR;
4344         }
4345 
4346         if (com_dcnt > nb_len)
4347             com_dcnt = (uint16_t)nb_len;
4348 
4349         return DCE2_SmbProcessResponseData(ssd, nb_ptr, com_dcnt);
4350     }
4351 
4352     return DCE2_RET__SUCCESS;
4353 }
4354 
4355 // 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)4356 static DCE2_Ret DCE2_SmbWriteAndUnlock(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4357         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4358 {
4359     if (!DCE2_ComInfoCanProcessCommand(com_info))
4360     {
4361         if (DCE2_ComInfoIsBadLength(com_info) || DCE2_ComInfoIsInvalidWordCount(com_info))
4362             return DCE2_RET__ERROR;
4363 
4364         // These are special cases.  The write succeeds but the unlock fails
4365         // so an error reponse is returned but the data was actually written.
4366         if (DCE2_ComInfoIsResponse(com_info) && DCE2_ComInfoIsStatusError(com_info))
4367         {
4368             if (DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
4369             {
4370                 if (!SmbErrorInvalidDeviceRequest(smb_hdr))
4371                     return DCE2_RET__ERROR;
4372             }
4373             else if (!SmbErrorRangeNotLocked(smb_hdr))
4374             {
4375                 return DCE2_RET__ERROR;
4376             }
4377         }
4378     }
4379 
4380     if (DCE2_ComInfoIsRequest(com_info))
4381     {
4382         // Have at least 3 bytes of data based on byte count check done earlier
4383 
4384         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4385         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4386         uint8_t fmt = *(nb_ptr + com_size);
4387         uint16_t com_dcnt = SmbWriteAndUnlockReqCount((SmbWriteAndUnlockReq *)nb_ptr);
4388         uint16_t fmt_dcnt = SmbNtohs((uint16_t *)(nb_ptr + com_size + 1));
4389         uint16_t fid = SmbWriteAndUnlockReqFid((SmbWriteAndUnlockReq *)nb_ptr);
4390         uint32_t offset = SmbWriteAndUnlockReqOffset((SmbWriteAndUnlockReq *)nb_ptr);
4391 
4392         DCE2_MOVE(nb_ptr, nb_len, (com_size + 3));
4393 
4394         DCE2_SmbCheckFmtData(ssd, nb_len, byte_count, fmt, com_dcnt, fmt_dcnt);
4395 
4396         if (com_dcnt == 0)
4397         {
4398             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO);
4399             return DCE2_RET__ERROR;
4400         }
4401 
4402         if (com_dcnt > nb_len)
4403             com_dcnt = (uint16_t)nb_len;
4404 
4405         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, com_dcnt, offset);
4406     }
4407 
4408     return DCE2_RET__SUCCESS;
4409 }
4410 
4411 // SMB_COM_READ_RAW
DCE2_SmbReadRaw(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4412 static DCE2_Ret DCE2_SmbReadRaw(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4413         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4414 {
4415     if (!DCE2_ComInfoCanProcessCommand(com_info))
4416         return DCE2_RET__ERROR;
4417 
4418     if (DCE2_ComInfoIsRequest(com_info))
4419     {
4420         DCE2_SmbFileTracker *ftracker =
4421             DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
4422                     ssd->cur_rtracker->tid, SmbReadRawReqFid((SmbReadRawReq *)nb_ptr));
4423 
4424         ssd->cur_rtracker->ftracker = ftracker;
4425         ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
4426         if ((ftracker != NULL) && !ftracker->is_ipc)
4427             ssd->cur_rtracker->file_offset = SmbReadRawReqOffset((SmbReadRawExtReq *)nb_ptr);
4428     }
4429     else
4430     {
4431         // The server response is the raw data.  Supposedly if an error occurs,
4432         // the server will send a 0 byte read.  Just the NetBIOS header with
4433         // zero byte length.  Client upon getting the zero read is supposed to issue
4434         // another read using ReadAndX or Read to get the error.
4435         return DCE2_RET__ERROR;
4436     }
4437 
4438     return DCE2_RET__SUCCESS;
4439 }
4440 
4441 // 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)4442 static DCE2_Ret DCE2_SmbWriteRaw(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4443         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4444 {
4445     if (!DCE2_ComInfoCanProcessCommand(com_info))
4446         return DCE2_RET__ERROR;
4447 
4448     if (DCE2_ComInfoIsRequest(com_info))
4449     {
4450         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4451         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4452         uint16_t fid = SmbWriteRawReqFid((SmbWriteRawReq *)nb_ptr);
4453         uint16_t tdcnt = SmbWriteRawReqTotalCount((SmbWriteRawReq *)nb_ptr);
4454         bool writethrough = SmbWriteRawReqWriteThrough((SmbWriteRawReq *)nb_ptr);
4455         uint16_t doff = SmbWriteRawReqDataOff((SmbWriteRawReq *)nb_ptr);
4456         uint16_t dcnt = SmbWriteRawReqDataCnt((SmbWriteRawReq *)nb_ptr);
4457         uint64_t offset = SmbWriteRawReqOffset((SmbWriteRawExtReq *)nb_ptr);
4458 
4459         DCE2_MOVE(nb_ptr, nb_len, com_size);
4460 
4461         if (DCE2_SmbCheckTotalCount(ssd, tdcnt, dcnt, 0) != DCE2_RET__SUCCESS)
4462             return DCE2_RET__ERROR;
4463 
4464         if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
4465                     byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
4466             return DCE2_RET__ERROR;
4467 
4468         // This may move backwards
4469         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
4470 
4471         if (dcnt > nb_len)
4472         {
4473             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_NB_LT_DSIZE, nb_len, dcnt);
4474             return DCE2_RET__ERROR;
4475         }
4476 
4477         // If all of the data wasn't written in this request, the server will
4478         // send an interim SMB_COM_WRITE_RAW response and the client will send
4479         // the rest of the data raw.  In this case if the WriteThrough flag is
4480         // not set, the server will not send a final SMB_COM_WRITE_COMPLETE
4481         // response.  If all of the data is in this request the server will
4482         // send an SMB_COM_WRITE_COMPLETE response regardless of whether or
4483         // not the WriteThrough flag is set.
4484         if (dcnt != tdcnt)
4485         {
4486             ssd->cur_rtracker->writeraw_writethrough = writethrough;
4487             ssd->cur_rtracker->writeraw_remaining = tdcnt - dcnt;
4488         }
4489 
4490         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
4491     }
4492     else
4493     {
4494         DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
4495 
4496         // Samba messes this up and sends a request instead of an interim
4497         // response and a response instead of a Write Complete response.
4498         switch (policy)
4499         {
4500             case DCE2_POLICY__SAMBA:
4501             case DCE2_POLICY__SAMBA_3_0_37:
4502             case DCE2_POLICY__SAMBA_3_0_22:
4503             case DCE2_POLICY__SAMBA_3_0_20:
4504                 if (SmbType(smb_hdr) != SMB_TYPE__REQUEST)
4505                     return DCE2_RET__SUCCESS;
4506                 break;
4507             default:
4508                 break;
4509         }
4510 
4511         // If all the data wasn't written initially this interim response will
4512         // be sent by the server and the raw data will ensue from the client.
4513         ssd->pdu_state = DCE2_SMB_PDU_STATE__RAW_DATA;
4514     }
4515 
4516     return DCE2_RET__SUCCESS;
4517 }
4518 
4519 // SMB_COM_WRITE_COMPLETE
DCE2_SmbWriteComplete(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4520 static DCE2_Ret DCE2_SmbWriteComplete(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4521         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4522 {
4523     if (!DCE2_ComInfoCanProcessCommand(com_info))
4524         return DCE2_RET__ERROR;
4525 
4526     return DCE2_RET__SUCCESS;
4527 }
4528 
4529 #define TRANS_NM_PIPE_0       (0)
4530 #define TRANS_NM_PIPE_1       (TRANS_NM_PIPE_0+7)
4531 #define TRANS_NM_PIPE_2       (TRANS_NM_PIPE_1+1)
4532 #define TRANS_NM_PIPE_3       (TRANS_NM_PIPE_2+1)
4533 #define TRANS_NM_PIPE_4       (TRANS_NM_PIPE_3+5)
4534 #define TRANS_NM_PIPE_5       (TRANS_NM_PIPE_4+5)
4535 #define TRANS_NM_PIPE_6       (TRANS_NM_PIPE_5+1)
4536 #define TRANS_NM_PIPE_7       (TRANS_NM_PIPE_6+5)
4537 #define TRANS_NM_PIPE_8       (TRANS_NM_PIPE_7+3)
4538 #define TRANS_NM_PIPE_9       (TRANS_NM_PIPE_8+6)
4539 #define TRANS_NM_PIPE_FS      (TRANS_NM_PIPE_9+1)
4540 #define TRANS_NM_PIPE_DONE    (TRANS_NM_PIPE_FS+1)
4541 
4542 static DCE2_SmbFsm dce2_samba_pipe_fsm[] =
4543 {
4544     // Normal sequence
4545     {'\\', TRANS_NM_PIPE_0+1, TRANS_NM_PIPE_FS },
4546     {'P' , TRANS_NM_PIPE_0+2, TRANS_NM_PIPE_FS },
4547     {'I' , TRANS_NM_PIPE_0+3, TRANS_NM_PIPE_FS },
4548     {'P' , TRANS_NM_PIPE_0+4, TRANS_NM_PIPE_FS },
4549     {'E' , TRANS_NM_PIPE_0+5, TRANS_NM_PIPE_FS },
4550     {'\\', TRANS_NM_PIPE_0+6, TRANS_NM_PIPE_1  },
4551     {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_2 },
4552 
4553     // Win98
4554     {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS },
4555 
4556     {'W' , TRANS_NM_PIPE_2+1, TRANS_NM_PIPE_5  },
4557 
4558     {'K' , TRANS_NM_PIPE_3+1, TRANS_NM_PIPE_4  },
4559     {'S' , TRANS_NM_PIPE_3+2, TRANS_NM_PIPE_FS },
4560     {'S' , TRANS_NM_PIPE_3+3, TRANS_NM_PIPE_FS },
4561     {'V' , TRANS_NM_PIPE_3+4, TRANS_NM_PIPE_FS },
4562     {'C' , TRANS_NM_PIPE_9  , TRANS_NM_PIPE_FS },
4563 
4564     {'I' , TRANS_NM_PIPE_4+1, TRANS_NM_PIPE_FS },
4565     {'N' , TRANS_NM_PIPE_4+2, TRANS_NM_PIPE_FS },
4566     {'R' , TRANS_NM_PIPE_4+3, TRANS_NM_PIPE_FS },
4567     {'E' , TRANS_NM_PIPE_4+4, TRANS_NM_PIPE_FS },
4568     {'G' , TRANS_NM_PIPE_9  , TRANS_NM_PIPE_FS },
4569 
4570 
4571     {'S' , TRANS_NM_PIPE_5+1, TRANS_NM_PIPE_8  },
4572 
4573     {'R' , TRANS_NM_PIPE_6+1, TRANS_NM_PIPE_5  },
4574     {'V' , TRANS_NM_PIPE_6+2, TRANS_NM_PIPE_FS },
4575     {'S' , TRANS_NM_PIPE_6+3, TRANS_NM_PIPE_FS },
4576     {'V' , TRANS_NM_PIPE_6+4, TRANS_NM_PIPE_FS },
4577     {'C' , TRANS_NM_PIPE_9  , TRANS_NM_PIPE_FS },
4578 
4579     {'A' , TRANS_NM_PIPE_7+1, TRANS_NM_PIPE_FS },
4580     {'M' , TRANS_NM_PIPE_7+2, TRANS_NM_PIPE_FS },
4581     {'R' , TRANS_NM_PIPE_9  , TRANS_NM_PIPE_FS },
4582 
4583 
4584     {'L' , TRANS_NM_PIPE_8+1, TRANS_NM_PIPE_FS },
4585     {'S' , TRANS_NM_PIPE_8+2, TRANS_NM_PIPE_FS },
4586     {'A' , TRANS_NM_PIPE_8+3, TRANS_NM_PIPE_FS },
4587     {'R' , TRANS_NM_PIPE_8+4, TRANS_NM_PIPE_FS },
4588     {'P' , TRANS_NM_PIPE_8+5, TRANS_NM_PIPE_FS },
4589     {'C' , TRANS_NM_PIPE_9  , TRANS_NM_PIPE_FS },
4590 
4591     {'\0', TRANS_NM_PIPE_DONE, TRANS_NM_PIPE_FS },
4592 
4593     {0, TRANS_NM_PIPE_FS, TRANS_NM_PIPE_FS }
4594 };
4595 
4596 // Validates Name for Samba Transaction requests
DCE2_SmbTransactionGetName(const uint8_t * nb_ptr,uint32_t nb_len,uint16_t bcc,bool unicode)4597 static DCE2_Ret DCE2_SmbTransactionGetName(const uint8_t *nb_ptr,
4598         uint32_t nb_len, uint16_t bcc, bool unicode)
4599 {
4600     uint8_t increment = unicode ? 2 : 1;
4601     int state = TRANS_NM_PIPE_0;
4602 
4603     if ((nb_len == 0) || (bcc == 0))
4604         return DCE2_RET__ERROR;
4605 
4606     if (bcc < nb_len)
4607         nb_len = bcc;
4608 
4609     if (unicode)
4610         DCE2_MOVE(nb_ptr, nb_len, 1);  // One byte pad for unicode
4611 
4612     while ((nb_len >= increment) && (state < TRANS_NM_PIPE_FS))
4613     {
4614         if (dce2_samba_pipe_fsm[state].input == toupper((int)nb_ptr[0]))
4615         {
4616             if (unicode && (nb_ptr[1] != 0))
4617                 break;
4618             state = dce2_samba_pipe_fsm[state].next_state;
4619             DCE2_MOVE(nb_ptr, nb_len, increment);
4620         }
4621         else
4622         {
4623             state = dce2_samba_pipe_fsm[state].fail_state;
4624         }
4625     }
4626 
4627     switch (state)
4628     {
4629         case TRANS_NM_PIPE_DONE:
4630             break;
4631         case TRANS_NM_PIPE_FS:
4632         default:
4633             return DCE2_RET__ERROR;
4634     }
4635 
4636     return DCE2_RET__SUCCESS;
4637 }
4638 
4639 // Convenience function to determine whether or not the transaction is complete
4640 // for one side, i.e. all data and parameters sent.
DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker * ttracker)4641 static inline bool DCE2_SmbIsTransactionComplete(DCE2_SmbTransactionTracker *ttracker)
4642 {
4643     if ((ttracker->tdcnt == ttracker->dsent)
4644             && (ttracker->tpcnt == ttracker->psent))
4645         return true;
4646     return false;
4647 }
4648 
4649 // SMB_COM_TRANSACTION Request
DCE2_SmbTransactionReq(DCE2_SmbSsnData * ssd,DCE2_SmbTransactionTracker * ttracker,const uint8_t * data_ptr,uint32_t data_len,const uint8_t * param_ptr,uint32_t param_len)4650 static inline DCE2_Ret DCE2_SmbTransactionReq(DCE2_SmbSsnData *ssd,
4651         DCE2_SmbTransactionTracker *ttracker,
4652         const uint8_t *data_ptr, uint32_t data_len,
4653         const uint8_t *param_ptr, uint32_t param_len)
4654 {
4655     switch (ttracker->subcom)
4656     {
4657         case TRANS_TRANSACT_NMPIPE:
4658         case TRANS_WRITE_NMPIPE:
4659             if (DCE2_SmbProcessRequestData(ssd, 0,
4660                         data_ptr, data_len, 0) != DCE2_RET__SUCCESS)
4661                 return DCE2_RET__ERROR;
4662             break;
4663 
4664         case TRANS_SET_NMPIPE_STATE:
4665             // Only two parameters but more seems okay
4666             if (param_len >= 2)
4667             {
4668                 if ((SmbNtohs((uint16_t *)param_ptr) & PIPE_STATE_MESSAGE_MODE))
4669                     ttracker->pipe_byte_mode = false;
4670                 else
4671                     ttracker->pipe_byte_mode = true;
4672 
4673                 // Won't get a response
4674                 if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way)
4675                 {
4676                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
4677                                 "Setting pipe to %s mode\n",
4678                                 ttracker->pipe_byte_mode ? "byte" : "message"));
4679 
4680                     ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode;
4681                 }
4682             }
4683             break;
4684 
4685         case TRANS_READ_NMPIPE:
4686             break;
4687 
4688         default:
4689             return DCE2_RET__IGNORE;
4690     }
4691 
4692     if (DCE2_SsnIsWindowsPolicy(&ssd->sd) && ttracker->one_way && ttracker->disconnect_tid)
4693         DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
4694 
4695     return DCE2_RET__SUCCESS;
4696 }
4697 
4698 // SMB_COM_TRANSACTION
DCE2_SmbTransaction(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4699 static DCE2_Ret DCE2_SmbTransaction(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4700         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4701 {
4702     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4703     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
4704 
4705     // Got a matching request for an in progress transaction - don't process it,
4706     // but don't want to remove tracker.
4707     if (DCE2_ComInfoIsRequest(com_info)
4708             && !DCE2_SmbIsTransactionComplete(ttracker))
4709     {
4710         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request "
4711                     "that matches an in progress transaction - not inspecting.\n"));
4712         return DCE2_RET__ERROR;
4713     }
4714 
4715     // Avoid decoding/tracking \PIPE\LANMAN requests
4716     if (DCE2_ComInfoIsRequest(com_info)
4717             && (DCE2_ComInfoWordCount(com_info) != 16))
4718     {
4719         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "\\PIPE\\LANMAN request - not inspecting\n"));
4720         return DCE2_RET__IGNORE;
4721     }
4722 
4723     if (!DCE2_ComInfoCanProcessCommand(com_info))
4724         return DCE2_RET__ERROR;
4725 
4726     // Interim response is sent if client didn't send all data / parameters
4727     // in initial Transaction request and will have to complete the request
4728     // with TransactionSecondary commands.
4729     if (DCE2_ComInfoIsResponse(com_info)
4730             && (com_size == sizeof(SmbTransactionInterimResp)))
4731     {
4732         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
4733                     "  Server Transaction interim response.\n"));
4734 
4735         return DCE2_RET__SUCCESS;
4736     }
4737 
4738     if (DCE2_ComInfoIsRequest(com_info))
4739     {
4740         uint16_t doff, dcnt, pcnt, poff;
4741         const uint8_t *data_ptr, *param_ptr;
4742         DCE2_Ret status =
4743             DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
4744 
4745         if (status != DCE2_RET__FULL)
4746             return status;
4747 
4748         ttracker->disconnect_tid = SmbTransactionReqDisconnectTid((SmbTransactionReq *)nb_ptr);
4749         ttracker->one_way = SmbTransactionReqOneWay((SmbTransactionReq *)nb_ptr);
4750 
4751         doff = SmbTransactionReqDataOff((SmbTransactionReq *)nb_ptr);
4752         dcnt = SmbTransactionReqDataCnt((SmbTransactionReq *)nb_ptr);
4753         pcnt = SmbTransactionReqParamCnt((SmbTransactionReq *)nb_ptr);
4754         poff = SmbTransactionReqParamOff((SmbTransactionReq *)nb_ptr);
4755 
4756         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
4757         data_ptr = nb_ptr;
4758 
4759         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
4760         param_ptr = nb_ptr;
4761 
4762         status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, dcnt, param_ptr, pcnt);
4763         if (status != DCE2_RET__SUCCESS)
4764             return status;
4765     }
4766     else
4767     {
4768         DCE2_Ret status =
4769             DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len);
4770 
4771         if (status != DCE2_RET__FULL)
4772             return status;
4773 
4774         switch (ttracker->subcom)
4775         {
4776             case TRANS_TRANSACT_NMPIPE:
4777             case TRANS_READ_NMPIPE:
4778                 if (!DCE2_BufferIsEmpty(ttracker->dbuf))
4779                 {
4780                     const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf);
4781                     uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
4782                     SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr,
4783                             &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
4784 
4785                     if (rpkt == NULL)
4786                         return DCE2_RET__ERROR;
4787 
4788                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Reassembled Transaction response\n"));
4789                     DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
4790 
4791                     status = DCE2_SmbProcessResponseData(ssd, data_ptr, data_len);
4792 
4793                     DCE2_SmbReturnRpkt();
4794 
4795                     if (status != DCE2_RET__SUCCESS)
4796                         return status;
4797                 }
4798                 else
4799                 {
4800                     uint16_t dcnt = SmbTransactionRespDataCnt((SmbTransactionResp *)nb_ptr);
4801                     uint16_t doff = SmbTransactionRespDataOff((SmbTransactionResp *)nb_ptr);
4802 
4803                     DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
4804 
4805                     if (DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt) != DCE2_RET__SUCCESS)
4806                         return DCE2_RET__ERROR;
4807                 }
4808                 break;
4809 
4810             case TRANS_SET_NMPIPE_STATE:
4811                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Setting pipe "
4812                             "to %s mode\n", ttracker->pipe_byte_mode ? "byte" : "message"));
4813                 ssd->cur_rtracker->ftracker->fp_byte_mode = ttracker->pipe_byte_mode;
4814                 break;
4815 
4816             case TRANS_WRITE_NMPIPE:
4817                 break;
4818 
4819             default:
4820                 return DCE2_RET__ERROR;
4821         }
4822 
4823         if (ttracker->disconnect_tid)
4824             DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
4825     }
4826 
4827     return DCE2_RET__SUCCESS;
4828 }
4829 
4830 // SMB_COM_TRANSACTION_SECONDARY
DCE2_SmbTransactionSecondary(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)4831 static DCE2_Ret DCE2_SmbTransactionSecondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4832         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4833 {
4834     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
4835     DCE2_Ret status;
4836     SFSnortPacket *rpkt = NULL;
4837 
4838     if (!DCE2_ComInfoCanProcessCommand(com_info))
4839         return DCE2_RET__ERROR;
4840 
4841     status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len);
4842     if (status != DCE2_RET__FULL)
4843         return status;
4844 
4845     switch (ttracker->subcom)
4846     {
4847         case TRANS_TRANSACT_NMPIPE:
4848         case TRANS_WRITE_NMPIPE:
4849             {
4850                 const uint8_t *data_ptr = DCE2_BufferData(ttracker->dbuf);
4851                 uint32_t data_len = DCE2_BufferLength(ttracker->dbuf);
4852                 rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
4853 
4854                 if (rpkt == NULL)
4855                     return DCE2_RET__ERROR;
4856 
4857                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Reassembled Transaction request\n"));
4858                 DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
4859 
4860                 status = DCE2_SmbTransactionReq(ssd, ttracker, data_ptr, data_len,
4861                         DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
4862 
4863                 DCE2_SmbReturnRpkt();
4864             }
4865             break;
4866 
4867         default:
4868             status = DCE2_SmbTransactionReq(ssd, ttracker,
4869                     DCE2_BufferData(ttracker->dbuf), DCE2_BufferLength(ttracker->dbuf),
4870                     DCE2_BufferData(ttracker->pbuf), DCE2_BufferLength(ttracker->pbuf));
4871             break;
4872     }
4873 
4874     return status;
4875 }
4876 
4877 // 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)4878 static DCE2_Ret DCE2_SmbWriteAndClose(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4879         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4880 {
4881     if (!DCE2_ComInfoCanProcessCommand(com_info))
4882         return DCE2_RET__ERROR;
4883 
4884     if (DCE2_ComInfoIsRequest(com_info))
4885     {
4886         // Have at least one byte based on byte count check done earlier
4887 
4888         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
4889         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
4890         uint16_t dcnt = SmbWriteAndCloseReqCount((SmbWriteAndCloseReq *)nb_ptr);
4891         uint16_t fid = SmbWriteAndCloseReqFid((SmbWriteAndCloseReq *)nb_ptr);
4892         uint32_t offset = SmbWriteAndCloseReqOffset((SmbWriteAndCloseReq *)nb_ptr);
4893 
4894         DCE2_MOVE(nb_ptr, nb_len, (com_size + 1));
4895 
4896         if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
4897                     byte_count, dcnt,
4898                     (uint16_t)(sizeof(SmbNtHdr) + com_size + 1)) != DCE2_RET__SUCCESS)
4899             return DCE2_RET__ERROR;
4900 
4901         if (dcnt == 0)
4902         {
4903             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DCNT_ZERO);
4904             return DCE2_RET__ERROR;
4905         }
4906 
4907         // WriteAndClose has a 1 byte pad after the byte count
4908         if ((uint32_t)(dcnt + 1) != (uint32_t)byte_count)
4909             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_DSIZE, (dcnt + 1), byte_count);
4910 
4911         if (dcnt > nb_len)
4912             dcnt = (uint16_t)nb_len;
4913 
4914         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
4915     }
4916     else
4917     {
4918         DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
4919     }
4920 
4921     return DCE2_RET__SUCCESS;
4922 }
4923 
4924 // 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)4925 static DCE2_Ret DCE2_SmbOpenAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
4926         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
4927 {
4928     if (!DCE2_ComInfoCanProcessCommand(com_info))
4929         return DCE2_RET__ERROR;
4930 
4931     if (DCE2_ComInfoIsResponse(com_info))
4932     {
4933         const uint16_t fid = SmbOpenAndXRespFid((SmbOpenAndXResp *)nb_ptr);
4934         const uint16_t file_attrs = SmbOpenAndXRespFileAttrs((SmbOpenAndXResp *)nb_ptr);
4935         const uint16_t resource_type = SmbOpenAndXRespResourceType((SmbOpenAndXResp *)nb_ptr);
4936         DCE2_SmbFileTracker *ftracker = NULL;
4937 
4938         // Set request tracker's current file tracker in case of chained commands
4939         switch (SmbAndXCom2((SmbAndXCommon *)nb_ptr))
4940         {
4941             // This is in case in the request a write was chained to an open
4942             // in which case the write will be to the newly opened file
4943             case SMB_COM_WRITE:
4944             case SMB_COM_WRITE_ANDX:
4945             case SMB_COM_TRANSACTION:
4946             case SMB_COM_READ_ANDX:
4947                 ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
4948                 break;
4949             default:
4950                 break;
4951         }
4952 
4953         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
4954                 && (SmbFileAttrsDirectory(file_attrs)
4955                     || !SmbResourceTypeDisk(resource_type)))
4956         {
4957             if (ftracker != NULL)
4958                 DCE2_SmbRemoveFileTracker(ssd, ftracker);
4959             return DCE2_RET__SUCCESS;
4960         }
4961 
4962         if (ftracker == NULL)
4963         {
4964             ftracker = DCE2_SmbNewFileTracker(ssd,
4965                     ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
4966             if (ftracker == NULL)
4967                 return DCE2_RET__ERROR;
4968         }
4969 
4970         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
4971 
4972         if (!ftracker->is_ipc)
4973         {
4974             const uint16_t open_results = SmbOpenAndXRespOpenResults((SmbOpenAndXResp *)nb_ptr);
4975 
4976             if (SmbOpenResultRead(open_results))
4977             {
4978                 ftracker->ff_file_size = SmbOpenAndXRespFileSize((SmbOpenAndXResp *)nb_ptr);
4979             }
4980             else
4981             {
4982                 ftracker->ff_file_size = ssd->cur_rtracker->file_size;
4983                 ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
4984             }
4985         }
4986 
4987         ssd->cur_rtracker->ftracker = ftracker;
4988     }
4989     else
4990     {
4991         uint32_t pad = 0;
4992         const bool unicode = SmbUnicode(smb_hdr);
4993         uint8_t null_bytes = unicode ? 2 : 1;
4994 
4995         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
4996         {
4997             uint16_t file_attrs = SmbOpenAndXReqFileAttrs((SmbOpenAndXReq *)nb_ptr);
4998 
4999             if (SmbEvasiveFileAttrs(file_attrs))
5000                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
5001 
5002             ssd->cur_rtracker->file_size = SmbOpenAndXReqAllocSize((SmbOpenAndXReq *)nb_ptr);
5003         }
5004 
5005         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
5006 
5007         if (unicode)
5008             pad = (nb_ptr - (const uint8_t *)smb_hdr) & 1;
5009 
5010         if (nb_len < (pad + null_bytes))
5011             return DCE2_RET__ERROR;
5012 
5013         DCE2_MOVE(nb_ptr, nb_len, pad);
5014 
5015         // Samba allows chaining OpenAndX/NtCreateAndX so might have
5016         // already been set.
5017         if (ssd->cur_rtracker->file_name == NULL)
5018         {
5019             ssd->cur_rtracker->file_name =
5020                 DCE2_SmbGetString(nb_ptr, nb_len, unicode, &ssd->cur_rtracker->file_name_len);
5021         }
5022     }
5023 
5024     return DCE2_RET__SUCCESS;
5025 }
5026 
5027 // 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)5028 static DCE2_Ret DCE2_SmbReadAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5029         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5030 {
5031     if (!DCE2_ComInfoCanProcessCommand(com_info))
5032         return DCE2_RET__ERROR;
5033 
5034     if (DCE2_ComInfoIsRequest(com_info))
5035     {
5036         DCE2_SmbFileTracker *ftracker =
5037             DCE2_SmbGetFileTracker(ssd, SmbReadAndXReqFid((SmbReadAndXReq *)nb_ptr));
5038 
5039         // No sense in tracking response
5040         if (ftracker == NULL)
5041             return DCE2_RET__ERROR;
5042 
5043         if (!ftracker->is_ipc)
5044             ssd->cur_rtracker->file_offset = SmbReadAndXReqOffset((SmbReadAndXExtReq *)nb_ptr);
5045 
5046         // Set this for response
5047         ssd->cur_rtracker->ftracker = ftracker;
5048     }
5049     else
5050     {
5051         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5052         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
5053         uint16_t doff = SmbReadAndXRespDataOff((SmbReadAndXResp *)nb_ptr);
5054         uint32_t dcnt = SmbReadAndXRespDataCnt((SmbReadAndXResp *)nb_ptr);
5055 
5056         DCE2_MOVE(nb_ptr, nb_len, com_size);
5057 
5058         if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
5059                     byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
5060             return DCE2_RET__ERROR;
5061 
5062         // This may move backwards
5063         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
5064 
5065         if (dcnt > nb_len)
5066             dcnt = nb_len;
5067 
5068         return DCE2_SmbProcessResponseData(ssd, nb_ptr, dcnt);
5069     }
5070 
5071     return DCE2_RET__SUCCESS;
5072 }
5073 
5074 // 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)5075 static DCE2_Ret DCE2_SmbWriteAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5076         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5077 {
5078     if (!DCE2_ComInfoCanProcessCommand(com_info))
5079     {
5080         DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker;
5081 
5082         if ((ftracker != NULL) && ftracker->is_ipc
5083                 && (ftracker->fp_writex_raw != NULL))
5084         {
5085             ftracker->fp_writex_raw->remaining = 0;
5086             DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5087         }
5088 
5089         return DCE2_RET__ERROR;
5090     }
5091 
5092     if (DCE2_ComInfoIsRequest(com_info)
5093             && (SmbWriteAndXReqStartRaw((SmbWriteAndXReq *)nb_ptr)
5094                 || SmbWriteAndXReqRaw((SmbWriteAndXReq *)nb_ptr)))
5095     {
5096         DCE2_SmbFileTracker *ftracker =
5097             DCE2_SmbGetFileTracker(ssd, SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr));
5098 
5099         // Raw mode is only applicable to named pipes.
5100         if ((ftracker != NULL) && ftracker->is_ipc)
5101             return DCE2_SmbWriteAndXRawRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
5102     }
5103 
5104     if (DCE2_ComInfoIsRequest(com_info))
5105     {
5106         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5107         uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
5108         uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr);
5109         uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq *)nb_ptr);
5110         uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq *)nb_ptr);
5111         uint64_t offset = SmbWriteAndXReqOffset((SmbWriteAndXExtReq *)nb_ptr);
5112 
5113         DCE2_MOVE(nb_ptr, nb_len, com_size);
5114 
5115         if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
5116                     byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
5117             return DCE2_RET__ERROR;
5118 
5119         // This may move backwards
5120         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
5121 
5122         if (dcnt > nb_len)
5123         {
5124             // Current Samba errors if data count is greater than data left
5125             if (DCE2_SsnGetPolicy(&ssd->sd) == DCE2_POLICY__SAMBA)
5126                 return DCE2_RET__ERROR;
5127 
5128             // Windows and early Samba just use what's left
5129             dcnt = nb_len;
5130         }
5131 
5132         return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, offset);
5133     }
5134 
5135     return DCE2_RET__SUCCESS;
5136 }
5137 
5138 // 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)5139 static DCE2_Ret DCE2_SmbWriteAndXRawRequest(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5140         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5141 {
5142     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5143     uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
5144     uint16_t fid = SmbWriteAndXReqFid((SmbWriteAndXReq *)nb_ptr);
5145     uint16_t doff = SmbWriteAndXReqDataOff((SmbWriteAndXReq *)nb_ptr);
5146     uint32_t dcnt = SmbWriteAndXReqDataCnt((SmbWriteAndXReq *)nb_ptr);
5147     bool start_write_raw = SmbWriteAndXReqStartRaw((SmbWriteAndXReq *)nb_ptr);
5148     bool continue_write_raw = SmbWriteAndXReqRaw((SmbWriteAndXReq *)nb_ptr);
5149     uint16_t remaining = SmbWriteAndXReqRemaining((SmbWriteAndXReq *)nb_ptr);
5150     DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
5151     DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, fid);
5152 
5153     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
5154                 "Processing WriteAndX with raw mode flags\n"));
5155 
5156     // Set this now for possible reassembled packet
5157     ssd->cur_rtracker->ftracker = ftracker;
5158 
5159     if (ftracker == NULL)
5160         return DCE2_RET__ERROR;
5161 
5162     // Got request to write in raw mode without having gotten the initial
5163     // raw mode request or got initial raw mode request and then another
5164     // without having finished the first.
5165     if ((start_write_raw && (ftracker->fp_writex_raw != NULL)
5166                 && (ftracker->fp_writex_raw->remaining != 0))
5167             || (continue_write_raw && ((ftracker->fp_writex_raw == NULL)
5168                     || (ftracker->fp_writex_raw->remaining == 0))))
5169     {
5170         switch (policy)
5171         {
5172             case DCE2_POLICY__WIN2000:
5173             case DCE2_POLICY__WINXP:
5174             case DCE2_POLICY__WINVISTA:
5175             case DCE2_POLICY__WIN2003:
5176             case DCE2_POLICY__WIN2008:
5177             case DCE2_POLICY__WIN7:
5178                 if (ftracker->fp_writex_raw != NULL)
5179                 {
5180                     ftracker->fp_writex_raw->remaining = 0;
5181                     DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5182                 }
5183                 return DCE2_RET__ERROR;
5184             case DCE2_POLICY__SAMBA:
5185             case DCE2_POLICY__SAMBA_3_0_37:
5186             case DCE2_POLICY__SAMBA_3_0_22:
5187             case DCE2_POLICY__SAMBA_3_0_20:
5188                 // Samba doesn't do anything special here except if the two
5189                 // flags are set it walks past the two "length" bytes.
5190                 // See below.
5191                 break;
5192             default:
5193                 DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d",
5194                         __FILE__, __LINE__, policy);
5195                 break;
5196         }
5197     }
5198 
5199     DCE2_MOVE(nb_ptr, nb_len, com_size);
5200 
5201     if (DCE2_SmbCheckData(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
5202                 byte_count, dcnt, doff) != DCE2_RET__SUCCESS)
5203         return DCE2_RET__ERROR;
5204 
5205     // This may move backwards
5206     DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
5207 
5208     // If a "raw" write is requested there will be two bytes after the
5209     // header/pad and before the data which is supposed to represent a
5210     // length but everyone ignores it.  However we need to move past it.
5211     // This is the one situation where the remaining field matters and
5212     // should be equal to the total amount of data to be written.
5213     if (start_write_raw)
5214     {
5215         if (dcnt < 2)
5216             return DCE2_RET__ERROR;
5217 
5218         // From data size check above, nb_len >= dsize
5219         dcnt -= 2;
5220         DCE2_MOVE(nb_ptr, nb_len, 2);
5221     }
5222 
5223     if (dcnt > nb_len)
5224         dcnt = nb_len;
5225 
5226     // File tracker already validated
5227     switch (policy)
5228     {
5229         case DCE2_POLICY__WIN2000:
5230         case DCE2_POLICY__WINXP:
5231         case DCE2_POLICY__WINVISTA:
5232         case DCE2_POLICY__WIN2003:
5233         case DCE2_POLICY__WIN2008:
5234         case DCE2_POLICY__WIN7:
5235             if (start_write_raw)
5236             {
5237                 if (ftracker->fp_writex_raw == NULL)
5238                 {
5239                     ftracker->fp_writex_raw = (DCE2_SmbWriteAndXRaw *)
5240                         DCE2_Alloc(sizeof(DCE2_SmbWriteAndXRaw), DCE2_MEM_TYPE__SMB_FID);
5241                     if (ftracker->fp_writex_raw == NULL)
5242                         return DCE2_RET__ERROR;
5243 
5244                     ftracker->fp_writex_raw->remaining = (int)remaining;
5245                 }
5246             }
5247 
5248             ftracker->fp_writex_raw->remaining -= (int)dcnt;
5249             if (ftracker->fp_writex_raw->remaining < 0)
5250             {
5251                 ftracker->fp_writex_raw->remaining = 0;
5252                 DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5253                 return DCE2_RET__ERROR;
5254             }
5255 
5256             // If the "raw" write isn't finished in the first request
5257             // and haven't allocated a buffer yet.
5258             if (start_write_raw && (ftracker->fp_writex_raw->remaining != 0)
5259                     && (ftracker->fp_writex_raw->buf == NULL))
5260             {
5261                 ftracker->fp_writex_raw->buf =
5262                     DCE2_BufferNew(remaining, 0, DCE2_MEM_TYPE__SMB_FID);
5263                 if (ftracker->fp_writex_raw->buf == NULL)
5264                 {
5265                     ftracker->fp_writex_raw->remaining = 0;
5266                     return DCE2_RET__ERROR;
5267                 }
5268             }
5269 
5270             // If data has to be added to buffer, i.e. not a start raw
5271             // or a start raw and more raw requests to come.
5272             if (!start_write_raw || (ftracker->fp_writex_raw->remaining != 0))
5273             {
5274                 if (DCE2_BufferAddData(ftracker->fp_writex_raw->buf, nb_ptr,
5275                             dcnt, DCE2_BufferLength(ftracker->fp_writex_raw->buf),
5276                             DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS)
5277                 {
5278                     ftracker->fp_writex_raw->remaining = 0;
5279                     DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5280                     return DCE2_RET__ERROR;
5281                 }
5282 
5283                 if (ftracker->fp_writex_raw->remaining == 0)
5284                 {
5285                     // Create reassembled packet
5286                     const uint8_t *data_ptr = DCE2_BufferData(ftracker->fp_writex_raw->buf);
5287                     uint32_t data_len = DCE2_BufferLength(ftracker->fp_writex_raw->buf);
5288                     SFSnortPacket *rpkt = DCE2_SmbGetRpkt(ssd,
5289                             &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_TRANS);
5290 
5291                     if (rpkt == NULL)
5292                     {
5293                         DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5294                         return DCE2_RET__ERROR;
5295                     }
5296 
5297                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
5298                                 "Reassembled WriteAndX raw mode request\n"));
5299                     DCE2_DEBUG_CODE(DCE2_DEBUG__MAIN, DCE2_PrintPktData(rpkt->payload, rpkt->payload_size););
5300 
5301                     (void)DCE2_SmbProcessRequestData(ssd, fid, data_ptr, data_len, 0);
5302 
5303                     DCE2_SmbReturnRpkt();
5304                     DCE2_BufferEmpty(ftracker->fp_writex_raw->buf);
5305                 }
5306             }
5307             else
5308             {
5309                 (void)DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
5310             }
5311 
5312             // Windows doesn't process chained commands to raw WriteAndXs
5313             // so return error so it exits the loop.
5314             return DCE2_RET__ERROR;
5315 
5316         case DCE2_POLICY__SAMBA:
5317         case DCE2_POLICY__SAMBA_3_0_37:
5318         case DCE2_POLICY__SAMBA_3_0_22:
5319         case DCE2_POLICY__SAMBA_3_0_20:
5320             // All Samba cares about is skipping the 2 byte "length"
5321             // if both flags are set.
5322             break;
5323         default:
5324             DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d",
5325                     __FILE__, __LINE__, policy);
5326             break;
5327     }
5328 
5329     return DCE2_SmbProcessRequestData(ssd, fid, nb_ptr, dcnt, 0);
5330 }
5331 
5332 // TRANS2_OPEN2
DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData * ssd,const uint8_t * param_ptr,uint32_t param_len,bool unicode)5333 static inline DCE2_Ret DCE2_SmbTrans2Open2Req(DCE2_SmbSsnData *ssd,
5334         const uint8_t *param_ptr, uint32_t param_len, bool unicode)
5335 {
5336     if (param_len < sizeof(SmbTrans2Open2ReqParams))
5337         return DCE2_RET__ERROR;
5338 
5339     if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
5340     {
5341         uint16_t file_attrs =
5342             SmbTrans2Open2ReqFileAttrs((SmbTrans2Open2ReqParams *)param_ptr);
5343 
5344         if (SmbEvasiveFileAttrs(file_attrs))
5345             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
5346 
5347         ssd->cur_rtracker->file_size =
5348             SmbTrans2Open2ReqAllocSize((SmbTrans2Open2ReqParams *)param_ptr);
5349     }
5350 
5351     DCE2_MOVE(param_ptr, param_len, sizeof(SmbTrans2Open2ReqParams));
5352 
5353     ssd->cur_rtracker->file_name =
5354         DCE2_SmbGetString(param_ptr, param_len, unicode, &ssd->cur_rtracker->file_name_len);
5355 
5356     return DCE2_RET__SUCCESS;
5357 }
5358 
5359 // TRANS2_QUERY_FILE_INFORMATION
DCE2_SmbTrans2QueryFileInfoReq(DCE2_SmbSsnData * ssd,const uint8_t * param_ptr,uint32_t param_len)5360 static inline DCE2_Ret DCE2_SmbTrans2QueryFileInfoReq(DCE2_SmbSsnData *ssd,
5361         const uint8_t *param_ptr, uint32_t param_len)
5362 {
5363     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
5364     DCE2_SmbFileTracker *ftracker;
5365 
5366     if (param_len < sizeof(SmbTrans2QueryFileInfoReqParams))
5367         return DCE2_RET__ERROR;
5368 
5369     ftracker = DCE2_SmbFindFileTracker(ssd,
5370             ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
5371             SmbTrans2QueryFileInfoReqFid((SmbTrans2QueryFileInfoReqParams *)param_ptr));
5372 
5373     if ((ftracker == NULL) || ftracker->is_ipc
5374             || DCE2_SmbFileUpload(ftracker->ff_file_direction))
5375         return DCE2_RET__IGNORE;
5376 
5377     ttracker->info_level =
5378         SmbTrans2QueryFileInfoReqInfoLevel((SmbTrans2QueryFileInfoReqParams *)param_ptr);
5379 
5380     ssd->cur_rtracker->ftracker = ftracker;
5381 
5382     return DCE2_RET__SUCCESS;
5383 }
5384 
5385 // TRANS2_SET_FILE_INFORMATION
DCE2_SmbTrans2SetFileInfoReq(DCE2_SmbSsnData * ssd,const uint8_t * param_ptr,uint32_t param_len,const uint8_t * data_ptr,uint32_t data_len)5386 static inline DCE2_Ret DCE2_SmbTrans2SetFileInfoReq(DCE2_SmbSsnData *ssd,
5387         const uint8_t *param_ptr, uint32_t param_len,
5388         const uint8_t *data_ptr, uint32_t data_len)
5389 {
5390     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
5391     DCE2_SmbFileTracker *ftracker;
5392 
5393     if ((param_len < sizeof(SmbTrans2SetFileInfoReqParams))
5394             || (data_len < sizeof(uint64_t)))
5395         return DCE2_RET__ERROR;
5396 
5397     ttracker->info_level =
5398         SmbTrans2SetFileInfoReqInfoLevel((SmbTrans2SetFileInfoReqParams *)param_ptr);
5399 
5400     // Check to see if there is an attempt to set READONLY/HIDDEN/SYSTEM
5401     // attributes on a file
5402     if (SmbSetFileInfoSetFileBasicInfo(ttracker->info_level)
5403             && (data_len >= sizeof(SmbSetFileBasicInfo)))
5404     {
5405         uint32_t ext_file_attrs =
5406             SmbSetFileInfoExtFileAttrs((SmbSetFileBasicInfo *)data_ptr);
5407 
5408         if (SmbEvasiveFileAttrs(ext_file_attrs))
5409             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
5410 
5411         // Don't need to see the response
5412         return DCE2_RET__IGNORE;
5413     }
5414 
5415     // Only looking for end of file information for this subcommand
5416     if (!SmbSetFileInfoEndOfFile(ttracker->info_level))
5417         return DCE2_RET__IGNORE;
5418 
5419     ftracker = DCE2_SmbFindFileTracker(ssd,
5420             ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
5421             SmbTrans2SetFileInfoReqFid((SmbTrans2SetFileInfoReqParams *)param_ptr));
5422 
5423     if ((ftracker == NULL) || ftracker->is_ipc
5424             || DCE2_SmbFileDownload(ftracker->ff_file_direction)
5425             || (ftracker->ff_bytes_processed != 0))
5426         return DCE2_RET__IGNORE;
5427 
5428     ssd->cur_rtracker->file_size = SmbNtohq((uint64_t *)data_ptr);
5429     ssd->cur_rtracker->ftracker = ftracker;
5430 
5431     return DCE2_RET__SUCCESS;
5432 }
5433 
5434 // SMB_COM_TRANSACTION2
DCE2_SmbTransaction2(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)5435 static DCE2_Ret DCE2_SmbTransaction2(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5436         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5437 {
5438     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5439     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
5440 
5441     // Got a matching request for an in progress transaction - don't process it,
5442     // but don't want to remove tracker.
5443     if (DCE2_ComInfoIsRequest(com_info)
5444             && !DCE2_SmbIsTransactionComplete(ttracker))
5445     {
5446         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request "
5447                     "that matches an in progress transaction - not inspecting.\n"));
5448         return DCE2_RET__ERROR;
5449     }
5450 
5451     if (!DCE2_ComInfoCanProcessCommand(com_info))
5452         return DCE2_RET__ERROR;
5453 
5454     // Interim response is sent if client didn't send all data / parameters
5455     // in initial Transaction2 request and will have to complete the request
5456     // with Transaction2Secondary commands.
5457     if (DCE2_ComInfoIsResponse(com_info)
5458             && (com_size == sizeof(SmbTransaction2InterimResp)))
5459     {
5460         return DCE2_RET__SUCCESS;
5461     }
5462 
5463     if (DCE2_ComInfoIsRequest(com_info))
5464     {
5465         uint16_t pcnt = SmbTransaction2ReqParamCnt((SmbTransaction2Req *)nb_ptr);
5466         uint16_t poff = SmbTransaction2ReqParamOff((SmbTransaction2Req *)nb_ptr);
5467         uint16_t dcnt = SmbTransaction2ReqDataCnt((SmbTransaction2Req *)nb_ptr);
5468         uint16_t doff = SmbTransaction2ReqDataOff((SmbTransaction2Req *)nb_ptr);
5469         const uint8_t *data_ptr;
5470         DCE2_Ret status =
5471             DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
5472 
5473         if (status != DCE2_RET__FULL)
5474             return status;
5475 
5476         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
5477 
5478         switch (ttracker->subcom)
5479         {
5480             case TRANS2_OPEN2:
5481                 if (DCE2_SmbTrans2Open2Req(ssd, nb_ptr, pcnt,
5482                             SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS)
5483                     return DCE2_RET__ERROR;
5484                 break;
5485 
5486             case TRANS2_QUERY_FILE_INFORMATION:
5487                 status = DCE2_SmbTrans2QueryFileInfoReq(ssd, nb_ptr, pcnt);
5488                 if (status != DCE2_RET__SUCCESS)
5489                     return status;
5490                 break;
5491 
5492             case TRANS2_SET_FILE_INFORMATION:
5493                 data_ptr = nb_ptr;
5494                 DCE2_MOVE(data_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - data_ptr);
5495 
5496                 status = DCE2_SmbTrans2SetFileInfoReq(ssd, nb_ptr, pcnt, data_ptr, dcnt);
5497                 if (status != DCE2_RET__SUCCESS)
5498                     return status;
5499                 break;
5500 
5501             default:
5502                 return DCE2_RET__IGNORE;
5503         }
5504     }
5505     else
5506     {
5507         const uint8_t *ptr;
5508         uint32_t len;
5509         DCE2_SmbFileTracker *ftracker = NULL;
5510         DCE2_Ret status =
5511             DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len);
5512 
5513         if (status != DCE2_RET__FULL)
5514             return status;
5515 
5516         switch (ttracker->subcom)
5517         {
5518             case TRANS2_OPEN2:
5519                 if (!DCE2_BufferIsEmpty(ttracker->pbuf))
5520                 {
5521                     ptr = DCE2_BufferData(ttracker->pbuf);
5522                     len = DCE2_BufferLength(ttracker->pbuf);
5523                 }
5524                 else
5525                 {
5526                     uint16_t poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr);
5527                     uint16_t pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr);
5528 
5529                     DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
5530 
5531                     ptr = nb_ptr;
5532                     len = pcnt;
5533                 }
5534 
5535                 if (len < sizeof(SmbTrans2Open2RespParams))
5536                     return DCE2_RET__ERROR;
5537 
5538                 if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid)
5539                         && (SmbFileAttrsDirectory(SmbTrans2Open2RespFileAttrs(
5540                                     (SmbTrans2Open2RespParams *)ptr))
5541                             || !SmbResourceTypeDisk(SmbTrans2Open2RespResourceType(
5542                                     (SmbTrans2Open2RespParams *)ptr))))
5543                 {
5544                     return DCE2_RET__SUCCESS;
5545                 }
5546 
5547                 ftracker = DCE2_SmbNewFileTracker(ssd, ssd->cur_rtracker->uid,
5548                         ssd->cur_rtracker->tid, SmbTrans2Open2RespFid((SmbTrans2Open2RespParams *)ptr));
5549                 if (ftracker == NULL)
5550                     return DCE2_RET__ERROR;
5551 
5552                 DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
5553 
5554                 if (!ftracker->is_ipc)
5555                 {
5556                     uint16_t open_results =
5557                         SmbTrans2Open2RespActionTaken((SmbTrans2Open2RespParams *)ptr);
5558 
5559                     if (SmbOpenResultRead(open_results))
5560                     {
5561                         ftracker->ff_file_size =
5562                             SmbTrans2Open2RespFileDataSize((SmbTrans2Open2RespParams *)ptr);
5563                     }
5564                     else
5565                     {
5566                         ftracker->ff_file_size = ssd->cur_rtracker->file_size;
5567                         ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
5568                     }
5569                 }
5570                 break;
5571 
5572             case TRANS2_QUERY_FILE_INFORMATION:
5573                 ftracker = ssd->cur_rtracker->ftracker;
5574                 if (ftracker == NULL)
5575                     return DCE2_RET__ERROR;
5576 
5577                 if (!DCE2_BufferIsEmpty(ttracker->dbuf))
5578                 {
5579                     ptr = DCE2_BufferData(ttracker->dbuf);
5580                     len = DCE2_BufferLength(ttracker->dbuf);
5581                 }
5582                 else
5583                 {
5584                     uint16_t doff = SmbTransaction2RespDataOff((SmbTransaction2Resp *)nb_ptr);
5585                     uint16_t dcnt = SmbTransaction2RespDataCnt((SmbTransaction2Resp *)nb_ptr);
5586 
5587                     DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
5588 
5589                     ptr = nb_ptr;
5590                     len = dcnt;
5591                 }
5592 
5593                 switch (ttracker->info_level)
5594                 {
5595                     case SMB_INFO_STANDARD:
5596                         if (len >= sizeof(SmbQueryInfoStandard))
5597                         {
5598                             ftracker->ff_file_size =
5599                                 SmbQueryInfoStandardFileDataSize((SmbQueryInfoStandard *)ptr);
5600                         }
5601                         break;
5602                     case SMB_INFO_QUERY_EA_SIZE:
5603                         if (len >= sizeof(SmbQueryInfoQueryEaSize))
5604                         {
5605                             ftracker->ff_file_size =
5606                                 SmbQueryInfoQueryEaSizeFileDataSize((SmbQueryInfoQueryEaSize *)ptr);
5607                         }
5608                         break;
5609                     case SMB_QUERY_FILE_STANDARD_INFO:
5610                         if (len >= sizeof(SmbQueryFileStandardInfo))
5611                         {
5612                             ftracker->ff_file_size =
5613                                 SmbQueryFileStandardInfoEndOfFile((SmbQueryFileStandardInfo *)ptr);
5614                         }
5615                         break;
5616                     case SMB_QUERY_FILE_ALL_INFO:
5617                         if (len >= sizeof(SmbQueryFileAllInfo))
5618                         {
5619                             ftracker->ff_file_size =
5620                                 SmbQueryFileAllInfoEndOfFile((SmbQueryFileAllInfo *)ptr);
5621                         }
5622                         break;
5623                     case SMB_INFO_PT_FILE_STANDARD_INFO:
5624                         if (len >= sizeof(SmbQueryPTFileStreamInfo))
5625                         {
5626                             ftracker->ff_file_size =
5627                                 SmbQueryPTFileStreamInfoStreamSize((SmbQueryPTFileStreamInfo *)ptr);
5628                         }
5629                         break;
5630                     case SMB_INFO_PT_FILE_STREAM_INFO:
5631                         if (len >= sizeof(SmbQueryFileStandardInfo))
5632                         {
5633 
5634                             ftracker->ff_file_size =
5635                                 SmbQueryFileStandardInfoEndOfFile((SmbQueryFileStandardInfo *)ptr);
5636                         }
5637                         break;
5638                     case SMB_INFO_PT_FILE_ALL_INFO:
5639                         if (len >= sizeof(SmbQueryPTFileAllInfo))
5640                         {
5641                             ftracker->ff_file_size =
5642                                 SmbQueryPTFileAllInfoEndOfFile((SmbQueryPTFileAllInfo *)ptr);
5643                         }
5644                         break;
5645                     case SMB_INFO_PT_NETWORK_OPEN_INFO:
5646                         if (len >= sizeof(SmbQueryPTNetworkOpenInfo))
5647                         {
5648                             ftracker->ff_file_size =
5649                                 SmbQueryPTNetworkOpenInfoEndOfFile((SmbQueryPTNetworkOpenInfo *)ptr);
5650                         }
5651                         break;
5652                     default:
5653                         break;
5654                 }
5655                 break;
5656 
5657             case TRANS2_SET_FILE_INFORMATION:
5658                 ftracker = ssd->cur_rtracker->ftracker;
5659                 if (ftracker == NULL)
5660                     return DCE2_RET__ERROR;
5661 
5662                 if (!DCE2_BufferIsEmpty(ttracker->pbuf))
5663                 {
5664                     ptr = DCE2_BufferData(ttracker->pbuf);
5665                     len = DCE2_BufferLength(ttracker->pbuf);
5666                 }
5667                 else
5668                 {
5669                     uint16_t poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr);
5670                     uint16_t pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr);
5671 
5672                     DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
5673 
5674                     ptr = nb_ptr;
5675                     len = pcnt;
5676                 }
5677 
5678                 // *ptr will be non-zero if there was an error.
5679                 if ((len >= 2) && (*ptr == 0))
5680                     ftracker->ff_file_size = ssd->cur_rtracker->file_size;
5681                 break;
5682 
5683             default:
5684                 break;
5685         }
5686     }
5687 
5688     return DCE2_RET__SUCCESS;
5689 }
5690 
5691 // SMB_COM_TRANSACTION2_SECONDARY
DCE2_SmbTransaction2Secondary(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)5692 static DCE2_Ret DCE2_SmbTransaction2Secondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5693         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5694 {
5695     DCE2_Ret status;
5696     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
5697 
5698     if (!DCE2_ComInfoCanProcessCommand(com_info))
5699         return DCE2_RET__ERROR;
5700 
5701     status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len);
5702     if (status != DCE2_RET__FULL)
5703         return status;
5704 
5705     switch (ttracker->subcom)
5706     {
5707         case TRANS2_OPEN2:
5708             status = DCE2_SmbTrans2Open2Req(ssd, DCE2_BufferData(ttracker->pbuf),
5709                     DCE2_BufferLength(ttracker->pbuf), SmbUnicode(smb_hdr));
5710             if (status != DCE2_RET__SUCCESS)
5711                 return status;
5712             break;
5713 
5714         case TRANS2_QUERY_FILE_INFORMATION:
5715             status = DCE2_SmbTrans2QueryFileInfoReq(ssd, DCE2_BufferData(ttracker->pbuf),
5716                     DCE2_BufferLength(ttracker->pbuf));
5717             if (status != DCE2_RET__SUCCESS)
5718                 return status;
5719             break;
5720 
5721         case TRANS2_SET_FILE_INFORMATION:
5722             status = DCE2_SmbTrans2SetFileInfoReq(ssd, DCE2_BufferData(ttracker->pbuf),
5723                     DCE2_BufferLength(ttracker->pbuf),
5724                     DCE2_BufferData(ttracker->dbuf),
5725                     DCE2_BufferLength(ttracker->dbuf));
5726             if (status != DCE2_RET__SUCCESS)
5727                 return status;
5728             break;
5729 
5730         default:
5731             break;
5732     }
5733 
5734     return DCE2_RET__SUCCESS;
5735 }
5736 
5737 #define SHARE_0     (0)
5738 #define SHARE_FS    (SHARE_0+5)
5739 #define SHARE_IPC   (SHARE_FS+1)
5740 
5741 static DCE2_SmbFsm dce2_ipc_share_fsm[] =
5742 {
5743     {'I' , SHARE_0+1, SHARE_FS },
5744     {'P' , SHARE_0+2, SHARE_FS },
5745     {'C' , SHARE_0+3, SHARE_FS },
5746     {'$' , SHARE_0+4, SHARE_FS },
5747     {'\0', SHARE_IPC, SHARE_FS },
5748 
5749     {0, SHARE_FS, SHARE_FS }
5750 };
5751 
5752 // 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)5753 static DCE2_Ret DCE2_SmbTreeConnect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5754         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5755 {
5756     if (!DCE2_ComInfoCanProcessCommand(com_info))
5757         return DCE2_RET__ERROR;
5758 
5759     if (DCE2_ComInfoIsRequest(com_info))
5760     {
5761         uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5762         const uint8_t *bs = NULL;
5763         bool unicode = SmbUnicode(smb_hdr);
5764         uint8_t increment = unicode ? 2 : 1;
5765         int state = SHARE_0;
5766         bool is_ipc = false;
5767 
5768         // Have at least 4 bytes of data based on byte count check done earlier
5769 
5770         DCE2_MOVE(nb_ptr, nb_len, com_size);
5771 
5772         // If unicode flag is set, strings, except possibly the service string
5773         // are going to be unicode.  The NT spec specifies that unicode strings
5774         // must be word aligned with respect to the beginning of the SMB and that for
5775         // type-prefixed strings (this case), the padding byte is found after the
5776         // type format byte.
5777 
5778         // This byte will realign things.
5779         if (*nb_ptr != SMB_FMT__ASCII)
5780         {
5781             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
5782             return DCE2_RET__ERROR;
5783         }
5784 
5785         DCE2_MOVE(nb_ptr, nb_len, 1);
5786 
5787         // IPC$ does not need to be case sensitive.  And the case sensitivity flag in
5788         // the SMB header doesn't seem to have any effect on this.
5789         while ((bs = memchr(nb_ptr, '\\', nb_len)) != NULL)
5790             DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1);
5791 
5792         if (unicode && (nb_len > 0))
5793             DCE2_MOVE(nb_ptr, nb_len, 1);
5794 
5795         // Check for invalid shares first
5796         if ((DCE2_ScSmbInvalidShares(ssd->sd.sconfig) != NULL) && (nb_len > 0))
5797             DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
5798 
5799         while ((nb_len >= increment) && (state < SHARE_FS))
5800         {
5801             if (dce2_ipc_share_fsm[state].input == toupper((int)nb_ptr[0]))
5802             {
5803                 if (unicode && (nb_ptr[1] != 0))
5804                     break;
5805                 state = dce2_ipc_share_fsm[state].next_state;
5806                 DCE2_MOVE(nb_ptr, nb_len, increment);
5807             }
5808             else
5809             {
5810                 state = dce2_ipc_share_fsm[state].fail_state;
5811             }
5812         }
5813 
5814         switch (state)
5815         {
5816             case SHARE_IPC:
5817                 is_ipc = true;
5818                 break;
5819             case SHARE_FS:
5820             default:
5821                 break;
5822         }
5823 
5824         ssd->cur_rtracker->is_ipc = is_ipc;
5825     }
5826     else
5827     {
5828         // XXX What if the TID in the SMB header differs from that returned
5829         // in the TreeConnect command response?
5830         uint16_t tid = SmbTid(smb_hdr);
5831         DCE2_SmbInsertTid(ssd, tid, ssd->cur_rtracker->is_ipc);
5832 
5833         DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
5834                 if (ssd->cur_rtracker->is_ipc) printf("Tid (%u) is an IPC tree\n", tid);
5835                 else printf("Tid (%u) not an IPC tree\n", tid););
5836     }
5837 
5838     return DCE2_RET__SUCCESS;
5839 }
5840 
5841 // SMB_COM_TREE_DISCONNECT
DCE2_SmbTreeDisconnect(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)5842 static DCE2_Ret DCE2_SmbTreeDisconnect(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5843         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5844 {
5845     if (!DCE2_ComInfoCanProcessCommand(com_info))
5846         return DCE2_RET__ERROR;
5847 
5848     if (DCE2_ComInfoIsResponse(com_info))
5849         DCE2_SmbRemoveTid(ssd, ssd->cur_rtracker->tid);
5850 
5851     return DCE2_RET__SUCCESS;
5852 }
5853 
5854 // SMB_COM_NEGOTIATE
DCE2_SmbNegotiate(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)5855 static DCE2_Ret DCE2_SmbNegotiate(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
5856         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
5857 {
5858     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
5859     PROFILE_VARS;
5860 
5861     if (!DCE2_ComInfoCanProcessCommand(com_info))
5862         return DCE2_RET__ERROR;
5863 
5864     PREPROC_PROFILE_START(dce2_pstat_smb_negotiate);
5865 
5866     if (DCE2_ComInfoIsRequest(com_info))
5867     {
5868         // Have at least 2 bytes based on byte count check done earlier
5869 
5870         uint8_t *term_ptr;
5871         int ntlm_index = 0;
5872 
5873         DCE2_MOVE(nb_ptr, nb_len, com_size);
5874 
5875         while ((term_ptr = memchr(nb_ptr, '\0', nb_len)) != NULL)
5876         {
5877             if (!SmbFmtDialect(*nb_ptr))
5878             {
5879                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_BAD_FORMAT, *nb_ptr);
5880 
5881                 // Windows errors if bad format
5882                 if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
5883                 {
5884                     PREPROC_PROFILE_END(dce2_pstat_smb_negotiate);
5885                     return DCE2_RET__ERROR;
5886                 }
5887             }
5888 
5889             // Move past format
5890             DCE2_MOVE(nb_ptr, nb_len, 1);
5891 
5892             if (nb_len == 0)
5893                 break;
5894 
5895             // Just a NULL byte - acceptable by Samba and Windows
5896             if (term_ptr == nb_ptr)
5897                 continue;
5898 
5899             if ((*nb_ptr == 'N')
5900                     && (strncmp((const char *)nb_ptr, SMB_DIALECT_NT_LM_012, term_ptr - nb_ptr) == 0))
5901                 break;
5902 
5903             // Move past string and NULL byte
5904             DCE2_MOVE(nb_ptr, nb_len, (term_ptr - nb_ptr) + 1);
5905 
5906             ntlm_index++;
5907         }
5908 
5909         if (term_ptr != NULL)
5910         {
5911             ssd->dialect_index = ntlm_index;
5912         }
5913         else
5914         {
5915             ssd->dialect_index = DCE2_SENTINEL;
5916             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED);
5917         }
5918     }
5919     else
5920     {
5921         uint16_t dialect_index =
5922             SmbNegotiateRespDialectIndex((SmbCore_NegotiateProtocolResp *)nb_ptr);
5923 
5924         if ((ssd->dialect_index != DCE2_SENTINEL) && (dialect_index != ssd->dialect_index))
5925             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_DIALECT_NEGOTIATED);
5926 
5927         ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
5928 
5929         if (DCE2_ComInfoWordCount(com_info) == 17)
5930         {
5931             ssd->max_outstanding_requests =
5932                 SmbNt_NegotiateRespMaxMultiplex((SmbNt_NegotiateProtocolResp *)nb_ptr);
5933         }
5934         else if (DCE2_ComInfoWordCount(com_info) == 13)
5935         {
5936             ssd->max_outstanding_requests =
5937                 SmbLm_NegotiateRespMaxMultiplex((SmbLm10_NegotiateProtocolResp *)nb_ptr);
5938         }
5939         else
5940         {
5941             ssd->max_outstanding_requests = 1;
5942         }
5943     }
5944 
5945     PREPROC_PROFILE_END(dce2_pstat_smb_negotiate);
5946     return DCE2_RET__SUCCESS;
5947 }
5948 
5949 #define OS_0          (0)   // "Windows" start
5950 #define OS_1    (OS_0+ 8)   // Windows 2000 and XP server
5951 #define OS_2    (OS_1+ 4)   // Windows 2000 and XP client
5952 #define OS_3    (OS_2+ 5)   // "Server", 2003, 2008R2, 2008
5953 #define OS_4    (OS_3+20)   // Windows Vista
5954 #define OS_5    (OS_4 +5)   // Windows 7
5955 #define OS_6    (OS_5 +1)   // Windows NT
5956 #define OS_7    (OS_6 +2)   // Windows 98
5957 #define OS_FS   (OS_7+ 3)   // Failure state
5958 #define OS_WIN2000    (OS_FS+1)
5959 #define OS_WINXP      (OS_FS+2)
5960 #define OS_WIN2003    (OS_FS+3)
5961 #define OS_WINVISTA   (OS_FS+4)
5962 #define OS_WIN2008    (OS_FS+5)
5963 #define OS_WIN7       (OS_FS+6)
5964 
5965 static DCE2_SmbFsm dce2_smb_os_fsm[] =
5966 {
5967     // Windows start states
5968     { 'W', OS_0+1, OS_FS },
5969     { 'i', OS_0+2, OS_FS },
5970     { 'n', OS_0+3, OS_FS },
5971     { 'd', OS_0+4, OS_FS },
5972     { 'o', OS_0+5, OS_FS },
5973     { 'w', OS_0+6, OS_FS },
5974     { 's', OS_0+7, OS_FS },
5975     { ' ', OS_0+8, OS_FS },
5976 
5977     // Windows 2000 and XP server states
5978     { '5', OS_1+1, OS_2 },
5979     { '.', OS_1+2, OS_FS },
5980     { '1', OS_WINXP, OS_1+3 },    // Windows XP
5981     { '0', OS_WIN2000, OS_FS },   // Windows 2000
5982 
5983     // Windows 2000 or XP client states
5984     { '2', OS_2+1, OS_3 },
5985     { '0', OS_2+2, OS_FS },
5986     { '0', OS_2+3, OS_FS },
5987     { '2', OS_WINXP, OS_2+4 },    // Windows XP
5988     { '0', OS_WIN2000, OS_FS },   // Windows 2000
5989 
5990     // "Server" string states
5991     { 'S', OS_3+ 1, OS_4 },
5992     { 'e', OS_3+ 2, OS_FS },
5993     { 'r', OS_3+ 3, OS_FS },
5994     { 'v', OS_3+ 4, OS_FS },
5995     { 'e', OS_3+ 5, OS_FS },
5996     { 'r', OS_3+ 6, OS_FS },
5997     { ' ', OS_3+ 7, OS_FS },
5998     { '2', OS_3+ 8, OS_3+12 },
5999     { '0', OS_3+ 9, OS_FS },
6000     { '0', OS_3+10, OS_FS },
6001     { '3', OS_WIN2003, OS_3+11 },   // Windows Server 2003
6002     { '8', OS_WIN2008, OS_FS },     // Windows Server 2008R2
6003 
6004     // Windows 2008 has this, 2008 R2 does not
6005     { '(', OS_3+13, OS_FS },
6006     { 'R', OS_3+14, OS_FS },
6007     { ')', OS_3+15, OS_FS },
6008     { ' ', OS_3+16, OS_FS },
6009     { '2', OS_3+17, OS_FS },
6010     { '0', OS_3+18, OS_FS },
6011     { '0', OS_3+19, OS_FS },
6012     { '8', OS_WIN2008, OS_FS },
6013 
6014     // Windows Vista states
6015     { 'V', OS_4+1, OS_5 },
6016     { 'i', OS_4+2, OS_FS },
6017     { 's', OS_4+3, OS_FS },
6018     { 't', OS_4+4, OS_FS },
6019     { 'a', OS_WINVISTA, OS_FS },
6020 
6021     // Windows 7 state
6022     { '7', OS_WIN7, OS_6 },
6023 
6024     // Windows NT
6025     { 'N', OS_6+1, OS_7 },
6026     { 'T', OS_WIN2000, OS_FS },  // Windows NT, set policy to Windows 2000
6027 
6028     // Windows 98
6029     { '4', OS_7+1, OS_FS },
6030     { '.', OS_7+2, OS_FS },
6031     { '0', OS_WIN2000, OS_FS },  // Windows 98, set policy to Windows 2000
6032 
6033     // Failure state
6034     { 0, OS_FS, OS_FS }
6035 
6036     // Match states shouldn't be accessed
6037 };
6038 
6039 // 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)6040 static DCE2_Ret DCE2_SmbSessionSetupAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6041         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6042 {
6043     if (!DCE2_ComInfoCanProcessCommand(com_info))
6044         return DCE2_RET__ERROR;
6045 
6046     if (DCE2_ComInfoIsRequest(com_info))
6047     {
6048         uint16_t max_multiplex =
6049             SmbSessionSetupAndXReqMaxMultiplex((SmbLm10_SessionSetupAndXReq *)nb_ptr);
6050 
6051         if (max_multiplex < ssd->max_outstanding_requests)
6052             ssd->max_outstanding_requests = max_multiplex;
6053 
6054         if (!DCE2_SmbFingerprintedClient(ssd) && DCE2_GcSmbFingerprintClient())
6055         {
6056             uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1;
6057             uint16_t word_count = DCE2_ComInfoWordCount(com_info);
6058             uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
6059             uint32_t i;
6060             PROFILE_VARS;
6061 
6062             DCE2_SmbSetFingerprintedClient(ssd);
6063 
6064             // OS and Lanman strings won't be in request
6065             if ((word_count != 13) && (word_count != 12))
6066                 return DCE2_RET__SUCCESS;
6067 
6068             PREPROC_PROFILE_START(dce2_pstat_smb_fingerprint);
6069 
6070             if (word_count == 13)
6071             {
6072                 uint16_t oem_pass_len =
6073                     SmbNt10SessionSetupAndXReqOemPassLen((SmbNt10_SessionSetupAndXReq *)nb_ptr);
6074                 uint16_t uni_pass_len =
6075                     SmbNt10SessionSetupAndXReqUnicodePassLen((SmbNt10_SessionSetupAndXReq *)nb_ptr);
6076 
6077                 DCE2_MOVE(nb_ptr, nb_len, com_size);
6078 
6079                 if (((uint32_t)oem_pass_len + uni_pass_len) > nb_len)
6080                 {
6081                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6082                     return DCE2_RET__ERROR;
6083                 }
6084 
6085                 DCE2_MOVE(nb_ptr, nb_len, (oem_pass_len + uni_pass_len));
6086 
6087                 // If unicode there should be a padding byte if the password
6088                 // lengths are even since the command length is odd
6089                 if ((increment == 2) && (nb_len != 0) && !((oem_pass_len + uni_pass_len) & 1))
6090                     DCE2_MOVE(nb_ptr, nb_len, 1);
6091             }
6092             else  // Extended security blob version, word count of 12
6093             {
6094                 uint16_t blob_len =
6095                     SmbSessionSetupAndXReqBlobLen((SmbNt10_SessionSetupAndXExtReq *)nb_ptr);
6096 
6097                 DCE2_MOVE(nb_ptr, nb_len, com_size);
6098 
6099                 if (blob_len > nb_len)
6100                 {
6101                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6102                     return DCE2_RET__ERROR;
6103                 }
6104 
6105                 DCE2_MOVE(nb_ptr, nb_len, blob_len);
6106 
6107                 // If unicode there should be a padding byte if the blob
6108                 // length is even since the command length is odd
6109                 if ((increment == 2) && (nb_len != 0) && !(blob_len & 1))
6110                     DCE2_MOVE(nb_ptr, nb_len, 1);
6111             }
6112 
6113             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Attempting to fingerprint "
6114                         "Client Windows/Samba version ... \n"));
6115 
6116             // Move past Account and Domain strings
6117             // Blob version doesn't have these as they're in the blob
6118             if (DCE2_ComInfoWordCount(com_info) == 13)
6119             {
6120                 int j;
6121 
6122                 for (j = 0; j < 2; j++)
6123                 {
6124                     while ((nb_len >= increment) && (*nb_ptr != '\0'))
6125                         DCE2_MOVE(nb_ptr, nb_len, increment);
6126 
6127                     // Just return success if we run out of data
6128                     if (nb_len < increment)
6129                     {
6130                         PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6131                         return DCE2_RET__SUCCESS;
6132                     }
6133 
6134                     // Move past NULL string terminator
6135                     DCE2_MOVE(nb_ptr, nb_len, increment);
6136                 }
6137             }
6138 
6139             if (nb_len < increment)
6140             {
6141                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6142                 return DCE2_RET__SUCCESS;
6143             }
6144 
6145             // Note the below is quick and dirty.  We're assuming the client
6146             // is kosher.  It's policy will be used when the server is
6147             // sending data to it.
6148 
6149 #ifdef DEBUG
6150             {
6151                 uint32_t k, l = 0;
6152                 char buf[65535];
6153 
6154                 for (k = 0; (k < nb_len) && (nb_ptr[k] != 0); k += increment, l++)
6155                     buf[l] = nb_ptr[k];
6156 
6157                 buf[l] = 0;
6158                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "  Client OS: %s\n", buf));
6159 
6160                 k += increment;
6161 
6162                 l = 0;
6163                 for (; k < nb_len && nb_ptr[k] != 0; k += increment, l++)
6164                     buf[l] = nb_ptr[k];
6165 
6166                 buf[l] = 0;
6167                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "  Client Lanman: %s\n", buf));
6168             }
6169 #endif
6170 
6171             // Windows Vista and above don't put anything here
6172             if (*nb_ptr == '\0')
6173             {
6174                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6175                             "Setting client policy to Windows Vista\n"));
6176                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA);
6177                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6178                 return DCE2_RET__SUCCESS;
6179             }
6180 
6181             // Windows
6182             if (*nb_ptr == 'W')
6183             {
6184                 int state = OS_0;
6185                 int64_t rlen = (int64_t)nb_len;
6186 
6187                 while ((rlen > 0) && (state < OS_FS))
6188                 {
6189                     if (dce2_smb_os_fsm[state].input == (char)*nb_ptr)
6190                     {
6191                         state = dce2_smb_os_fsm[state].next_state;
6192                         DCE2_MOVE(nb_ptr, rlen, increment);
6193                     }
6194                     else
6195                     {
6196                         state = dce2_smb_os_fsm[state].fail_state;
6197                     }
6198                 }
6199 
6200                 switch (state)
6201                 {
6202                     case OS_WIN2000:
6203                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6204                                     "Setting client policy to Windows 2000\n"));
6205                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000);
6206                         break;
6207                     case OS_WINXP:
6208                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6209                                     "Setting client policy to Windows XP\n"));
6210                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP);
6211                         break;
6212                     case OS_WIN2003:
6213                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6214                                     "Setting client policy to Windows 2003\n"));
6215                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003);
6216                         break;
6217                     default:
6218                         break;
6219                 }
6220 
6221                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6222                 return DCE2_RET__SUCCESS;
6223             }
6224 
6225             // Samba puts "Unix" in the OS field
6226             if (*nb_ptr != 'U')
6227             {
6228                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6229                 return DCE2_RET__SUCCESS;
6230             }
6231 
6232             // Move past OS string
6233             for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment);
6234 
6235             if ((i + increment) >= nb_len)
6236             {
6237                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6238                 return DCE2_RET__SUCCESS;
6239             }
6240 
6241             // Move to LanMan string
6242             DCE2_MOVE(nb_ptr, nb_len, i + increment);
6243 
6244             // Samba
6245             if (*nb_ptr == 'S')
6246             {
6247                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6248                             "Setting client policy to Samba\n"));
6249                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
6250             }
6251 
6252             PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6253         }
6254     }
6255     else
6256     {
6257         uint16_t uid = SmbUid(smb_hdr);
6258 
6259         DCE2_SmbInsertUid(ssd, uid);
6260         ssd->cur_rtracker->uid = uid;  // Set this in case there are chained commands
6261 
6262         if (!(ssd->ssn_state_flags & DCE2_SMB_SSN_STATE__NEGOTIATED))
6263             ssd->ssn_state_flags |= DCE2_SMB_SSN_STATE__NEGOTIATED;
6264 
6265         if (!DCE2_SmbFingerprintedServer(ssd) && DCE2_GcSmbFingerprintServer())
6266         {
6267             uint8_t increment = SmbUnicode(smb_hdr) ? 2 : 1;
6268             uint32_t i;
6269             PROFILE_VARS;
6270 
6271             DCE2_SmbSetFingerprintedServer(ssd);
6272 
6273             // Set the policy based on what the server reports in the OS field
6274             // for Windows and the LanManager field for Samba
6275 
6276             if (DCE2_ComInfoByteCount(com_info) == 0)
6277                 return DCE2_RET__SUCCESS;
6278 
6279             PREPROC_PROFILE_START(dce2_pstat_smb_fingerprint);
6280 
6281             if (DCE2_ComInfoWordCount(com_info) == 3)
6282             {
6283                 DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
6284 
6285                 // Word count 3 and Unicode has a one byte pad
6286                 if ((increment == 2) && (nb_len != 0))
6287                     DCE2_MOVE(nb_ptr, nb_len, 1);
6288             }
6289             else  // Only valid word counts are 3 and 4
6290             {
6291                 uint16_t blob_len = SmbSessionSetupAndXRespBlobLen((SmbNt10_SessionSetupAndXExtResp *)nb_ptr);
6292 
6293                 DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
6294 
6295                 if (blob_len > nb_len)
6296                 {
6297                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6298                     return DCE2_RET__ERROR;
6299                 }
6300 
6301                 DCE2_MOVE(nb_ptr, nb_len, blob_len);
6302 
6303                 if ((increment == 2) && (nb_len != 0) && !(blob_len & 1))
6304                     DCE2_MOVE(nb_ptr, nb_len, 1);
6305             }
6306 
6307             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Attempting to fingerprint "
6308                         "Server Windows/Samba version ... \n"));
6309 
6310             // Note the below is quick and dirty.  We're assuming the server
6311             // is kosher.  It's policy will be used when the client is
6312             // sending data to it.
6313 
6314 #ifdef DEBUG
6315             {
6316                 uint32_t k, l = 0;
6317                 char buf[65535];
6318 
6319                 for (k = 0; (k < nb_len) && (nb_ptr[k] != 0); k += increment, l++)
6320                     buf[l] = nb_ptr[k];
6321 
6322                 buf[l] = 0;
6323                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "  Server OS: %s\n", buf));
6324 
6325                 k += increment;
6326 
6327                 l = 0;
6328                 for (; k < nb_len && nb_ptr[k] != 0; k += increment, l++)
6329                     buf[l] = nb_ptr[k];
6330 
6331                 buf[l] = 0;
6332                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "  Server Lanman: %s\n", buf));
6333             }
6334 #endif
6335 
6336             if ((nb_len < increment) || (*nb_ptr == '\0'))
6337             {
6338                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6339                 return DCE2_RET__SUCCESS;
6340             }
6341 
6342             // Next field should be OS string
6343             for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment);
6344             i -= increment;
6345 
6346             // Windows
6347             if (*nb_ptr == 'W')
6348             {
6349                 int state = OS_0;
6350                 int64_t rlen = (int64_t)nb_len;
6351 
6352                 while ((rlen > 0) && (state < OS_FS))
6353                 {
6354                     if (dce2_smb_os_fsm[state].input == (char)*nb_ptr)
6355                     {
6356                         state = dce2_smb_os_fsm[state].next_state;
6357                         DCE2_MOVE(nb_ptr, rlen, increment);
6358                     }
6359                     else
6360                     {
6361                         state = dce2_smb_os_fsm[state].fail_state;
6362                     }
6363                 }
6364 
6365                 switch (state)
6366                 {
6367                     case OS_WIN2000:
6368                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6369                                     "Setting server policy to Windows 2000\n"));
6370                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2000);
6371                         break;
6372                     case OS_WINXP:
6373                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6374                                     "Setting server policy to Windows XP\n"));
6375                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINXP);
6376                         break;
6377                     case OS_WIN2003:
6378                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6379                                     "Setting server policy to Windows 2003\n"));
6380                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2003);
6381                         break;
6382                     case OS_WIN2008:
6383                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6384                                     "Setting server policy to Windows 2008\n"));
6385                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN2008);
6386                         break;
6387                     case OS_WINVISTA:
6388                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6389                                     "Setting server policy to Windows Vista\n"));
6390                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WINVISTA);
6391                         break;
6392                     case OS_WIN7:
6393                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6394                                     "Setting server policy to Windows 7\n"));
6395                         DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__WIN7);
6396                         break;
6397                     default:
6398                         break;
6399                 }
6400 
6401                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6402                 return DCE2_RET__SUCCESS;
6403             }
6404 
6405             // Samba puts "Unix" in the OS field
6406             if (*nb_ptr != 'U')
6407             {
6408                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6409                 return DCE2_RET__SUCCESS;
6410             }
6411 
6412             // Move past OS string
6413             for (i = 0; (i < nb_len) && (nb_ptr[i] != '\0'); i += increment);
6414 
6415             if ((i + increment) >= nb_len)
6416             {
6417                 PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6418                 return DCE2_RET__SUCCESS;
6419             }
6420 
6421             // Move to LanMan string
6422             DCE2_MOVE(nb_ptr, nb_len, i + increment);
6423 
6424             // Samba
6425             if (*nb_ptr == 'S')
6426             {
6427                 uint8_t r1 = 0;  // Release version first digit
6428                 uint8_t r2 = 0;  // Release version second digit
6429 
6430                 // Get Major version
6431                 for (i = 0; (i < nb_len) && (*nb_ptr != '\0'); i += increment)
6432                 {
6433                     if (isdigit((int)nb_ptr[i]))
6434                         break;
6435                 }
6436 
6437                 if ((i == nb_len) || (*nb_ptr == '\0'))
6438                 {
6439                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6440                     return DCE2_RET__SUCCESS;
6441                 }
6442 
6443                 // If less than 3 set policy to earliest Samba policy we use
6444                 if ((nb_ptr[i] == '0') || (nb_ptr[i] == '1') || (nb_ptr[i] == '2'))
6445                 {
6446                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6447                                 "Setting server policy to Samba 3.0.20\n"));
6448                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20);
6449                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6450                     return DCE2_RET__SUCCESS;
6451                 }
6452 
6453                 // Need ".\d.\d\d" or ".\d.\d\x00"
6454                 if (i + increment*5 > nb_len)
6455                 {
6456                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6457                     return DCE2_RET__SUCCESS;
6458                 }
6459 
6460                 i += increment*2;
6461 
6462                 // If it's not 0, then set to latest Samba policy we use
6463                 if (nb_ptr[i] != '0')
6464                 {
6465                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6466                                 "Setting server policy to current Samba\n"));
6467                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
6468                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6469                     return DCE2_RET__SUCCESS;
6470                 }
6471 
6472                 r1 = nb_ptr[i + increment*2];
6473                 r2 = nb_ptr[i + increment*3];
6474 
6475                 // First digit is 1 or no second digit or 20, Samba 3.0.20
6476                 if ((r1 == '1') || (r2 == '\0') || ((r1 == '2') && (r2 == '0')))
6477                 {
6478                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6479                                 "Setting server policy to Samba 3.0.20\n"));
6480                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_20);
6481                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6482                     return DCE2_RET__SUCCESS;
6483                 }
6484 
6485                 // 21 or 22, Samba 3.0.22
6486                 if ((r1 == '2') && (r2 <= '2'))
6487                 {
6488                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6489                                 "Setting server policy to Samba 3.0.22\n"));
6490                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_22);
6491                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6492                     return DCE2_RET__SUCCESS;
6493                 }
6494 
6495                 // 23, 24 ... 30 ... 37, Samba 3.0.37
6496                 if ((r1 == '2') || ((r1 == '3') && (r2 <= '7')))
6497                 {
6498                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6499                                 "Setting server policy to Samba 3.0.37\n"));
6500                     DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA_3_0_37);
6501                     PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6502                     return DCE2_RET__SUCCESS;
6503                 }
6504 
6505                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6506                             "Setting server policy to current Samba\n"));
6507                 DCE2_SsnSetPolicy(&ssd->sd, DCE2_POLICY__SAMBA);
6508             }
6509 
6510             PREPROC_PROFILE_END(dce2_pstat_smb_fingerprint);
6511         }
6512     }
6513 
6514     return DCE2_RET__SUCCESS;
6515 }
6516 
6517 // SMB_COM_LOGOFF_ANDX
DCE2_SmbLogoffAndX(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)6518 static DCE2_Ret DCE2_SmbLogoffAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6519         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6520 {
6521     if (!DCE2_ComInfoCanProcessCommand(com_info))
6522         return DCE2_RET__ERROR;
6523 
6524     if (DCE2_ComInfoIsResponse(com_info))
6525     {
6526         DCE2_SmbRemoveUid(ssd, ssd->cur_rtracker->uid);
6527 
6528         switch (DCE2_SsnGetServerPolicy(&ssd->sd))
6529         {
6530             case DCE2_POLICY__WIN2000:
6531             case DCE2_POLICY__WINXP:
6532             case DCE2_POLICY__WINVISTA:
6533             case DCE2_POLICY__WIN2003:
6534             case DCE2_POLICY__WIN2008:
6535             case DCE2_POLICY__WIN7:
6536                 /* Windows responds to a chained LogoffAndX => SessionSetupAndX with a
6537                  * word count 3 LogoffAndX without the chained SessionSetupAndX */
6538                 if (DCE2_ComInfoWordCount(com_info) == 3)
6539                 {
6540                     uint16_t uid = SmbUid(smb_hdr);
6541                     DCE2_SmbInsertUid(ssd, uid);
6542                     ssd->cur_rtracker->uid = uid;  // Set this in case there are chained commands
6543                 }
6544                 break;
6545             default:
6546                 break;
6547         }
6548     }
6549 
6550     return DCE2_RET__SUCCESS;
6551 }
6552 
6553 #define SERVICE_0     (0)                // IPC start
6554 #define SERVICE_1     (SERVICE_0+4)      // DISK start
6555 #define SERVICE_FS    (SERVICE_1+3)      // Failure
6556 #define SERVICE_IPC   (SERVICE_FS+1)     // IPC service
6557 #define SERVICE_DISK  (SERVICE_FS+2)     // DISK service
6558 
6559 static DCE2_SmbFsm dce2_smb_service_fsm[] =
6560 {
6561     // IPC
6562     { 'I',  SERVICE_0+1, SERVICE_1 },
6563     { 'P',  SERVICE_0+2, SERVICE_FS },
6564     { 'C',  SERVICE_0+3, SERVICE_FS },
6565     { '\0', SERVICE_IPC, SERVICE_FS },
6566 
6567     // DISK
6568     { 'A',  SERVICE_1+1, SERVICE_FS },
6569     { ':',  SERVICE_1+2, SERVICE_FS },
6570     { '\0', SERVICE_DISK, SERVICE_FS },
6571 
6572     { 0, SERVICE_FS, SERVICE_FS }
6573 };
6574 
6575 // 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)6576 static DCE2_Ret DCE2_SmbTreeConnectAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6577         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6578 {
6579     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
6580 
6581     if (!DCE2_ComInfoCanProcessCommand(com_info))
6582         return DCE2_RET__ERROR;
6583 
6584     if (DCE2_ComInfoIsRequest(com_info))
6585     {
6586         if (DCE2_ScSmbInvalidShares(ssd->sd.sconfig) != NULL)
6587         {
6588             uint16_t pass_len = SmbTreeConnectAndXReqPassLen((SmbTreeConnectAndXReq *)nb_ptr);
6589             const uint8_t *bs = NULL;
6590 
6591             DCE2_MOVE(nb_ptr, nb_len, com_size);
6592 
6593             if (pass_len >= nb_len)
6594                 return DCE2_RET__ERROR;
6595 
6596             // Move past password length
6597             DCE2_MOVE(nb_ptr, nb_len, pass_len);
6598 
6599             // Move past path components
6600             while ((bs = memchr(nb_ptr, '\\', nb_len)) != NULL)
6601                 DCE2_MOVE(nb_ptr, nb_len, (bs - nb_ptr) + 1);
6602 
6603             // Move past NULL byte if unicode
6604             if (SmbUnicode(smb_hdr) && (nb_len != 0))
6605                 DCE2_MOVE(nb_ptr, nb_len, 1);
6606 
6607             if (nb_len != 0)
6608                 DCE2_SmbInvalidShareCheck(ssd, smb_hdr, nb_ptr, nb_len);
6609         }
6610     }
6611     else
6612     {
6613         uint16_t tid = SmbTid(smb_hdr);
6614         bool is_ipc = true;
6615         int state = SERVICE_0;
6616 
6617         DCE2_MOVE(nb_ptr, nb_len, com_size);
6618 
6619         while ((nb_len > 0) && (state < SERVICE_FS))
6620         {
6621             if (dce2_smb_service_fsm[state].input == (char)*nb_ptr)
6622             {
6623                 state = dce2_smb_service_fsm[state].next_state;
6624                 DCE2_MOVE(nb_ptr, nb_len, 1);
6625             }
6626             else
6627             {
6628                 state = dce2_smb_service_fsm[state].fail_state;
6629             }
6630         }
6631 
6632         switch (state)
6633         {
6634             case SERVICE_IPC:
6635                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6636                             "Tid (%u) is an IPC tree.\n", tid););
6637                 break;
6638             case SERVICE_DISK:
6639                 is_ipc = false;
6640                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
6641                             "Tid (%u) is a DISK tree.\n", tid););
6642                 break;
6643             default:
6644                 return DCE2_RET__IGNORE;
6645         }
6646 
6647         // Insert tid into list
6648         DCE2_SmbInsertTid(ssd, tid, is_ipc);
6649         ssd->cur_rtracker->tid = tid;  // Set this in case there are chained commands
6650     }
6651 
6652     return DCE2_RET__SUCCESS;
6653 }
6654 
6655 // NT_TRANSACT_CREATE
DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData * ssd,const uint8_t * param_ptr,uint32_t param_len,bool unicode)6656 static inline DCE2_Ret DCE2_SmbNtTransactCreateReq(DCE2_SmbSsnData *ssd,
6657         const uint8_t *param_ptr, uint32_t param_len, bool unicode)
6658 {
6659     uint32_t pad = 0;
6660     uint32_t file_name_length;
6661     const uint8_t *param_start = param_ptr;
6662 
6663     if (param_len < sizeof(SmbNtTransactCreateReqParams))
6664         return DCE2_RET__ERROR;
6665 
6666     if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
6667     {
6668         uint32_t ext_file_attrs =
6669             SmbNtTransactCreateReqFileAttrs((SmbNtTransactCreateReqParams *)param_ptr);
6670 
6671         if (SmbEvasiveFileAttrs(ext_file_attrs))
6672             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
6673 
6674         // If the file is going to be accessed sequentially, track it.
6675         if (SmbNtTransactCreateReqSequentialOnly((SmbNtTransactCreateReqParams *)param_ptr))
6676             ssd->cur_rtracker->sequential_only = true;
6677 
6678         ssd->cur_rtracker->file_size =
6679             SmbNtTransactCreateReqAllocSize((SmbNtTransactCreateReqParams *)param_ptr);
6680     }
6681 
6682     file_name_length =
6683         SmbNtTransactCreateReqFileNameLength((SmbNtTransactCreateReqParams *)param_ptr);
6684 
6685     if (file_name_length > DCE2_SMB_MAX_PATH_LEN)
6686         return DCE2_RET__ERROR;
6687 
6688     DCE2_MOVE(param_ptr, param_len, sizeof(SmbNtTransactCreateReqParams));
6689 
6690     if (unicode)
6691         pad = (param_ptr - param_start) & 1;
6692 
6693     if (param_len < (pad + file_name_length))
6694         return DCE2_RET__ERROR;
6695 
6696     DCE2_MOVE(param_ptr, param_len, pad);
6697 
6698     ssd->cur_rtracker->file_name =
6699         DCE2_SmbGetString(param_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_len);
6700 
6701     return DCE2_RET__SUCCESS;
6702 }
6703 
6704 // SMB_COM_NT_TRANSACT
DCE2_SmbNtTransact(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)6705 static DCE2_Ret DCE2_SmbNtTransact(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6706         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6707 {
6708     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
6709     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
6710 
6711     // NOTE: Only looking at NT_TRANSACT_CREATE as another way to open a named pipe
6712 
6713     // Got a matching request for an in progress transaction - don't process it,
6714     // but don't want to remove tracker.
6715     if (DCE2_ComInfoIsRequest(com_info)
6716             && !DCE2_SmbIsTransactionComplete(ttracker))
6717     {
6718         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Got new transaction request "
6719                     "that matches an in progress transaction - not inspecting.\n"));
6720         return DCE2_RET__ERROR;
6721     }
6722 
6723     if (!DCE2_ComInfoCanProcessCommand(com_info))
6724         return DCE2_RET__ERROR;
6725 
6726     // Interim response is sent if client didn't send all data / parameters
6727     // in initial NtTransact request and will have to complete the request
6728     // with NtTransactSecondary commands.
6729     if (DCE2_ComInfoIsResponse(com_info)
6730             && (com_size == sizeof(SmbNtTransactInterimResp)))
6731     {
6732         return DCE2_RET__SUCCESS;
6733     }
6734 
6735     if (DCE2_ComInfoIsRequest(com_info))
6736     {
6737         uint32_t pcnt = SmbNtTransactReqParamCnt((SmbNtTransactReq *)nb_ptr);
6738         uint32_t poff = SmbNtTransactReqParamOff((SmbNtTransactReq *)nb_ptr);
6739         DCE2_Ret status =
6740             DCE2_SmbUpdateTransRequest(ssd, smb_hdr, com_info, nb_ptr, nb_len);
6741 
6742         if (status != DCE2_RET__FULL)
6743             return status;
6744 
6745         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
6746 
6747         switch (ttracker->subcom)
6748         {
6749             case NT_TRANSACT_CREATE:
6750                 status = DCE2_SmbNtTransactCreateReq(ssd, nb_ptr, pcnt, SmbUnicode(smb_hdr));
6751                 if (status != DCE2_RET__SUCCESS)
6752                     return status;
6753                 break;
6754 
6755             default:
6756                 return DCE2_RET__IGNORE;
6757         }
6758     }
6759     else
6760     {
6761         const uint8_t *ptr;
6762         uint32_t len;
6763         DCE2_SmbFileTracker *ftracker = NULL;
6764 
6765         DCE2_Ret status =
6766             DCE2_SmbUpdateTransResponse(ssd, smb_hdr, com_info, nb_ptr, nb_len);
6767 
6768         if (status != DCE2_RET__FULL)
6769             return status;
6770 
6771         if (!DCE2_BufferIsEmpty(ttracker->pbuf))
6772         {
6773             ptr = DCE2_BufferData(ttracker->pbuf);
6774             len = DCE2_BufferLength(ttracker->pbuf);
6775         }
6776         else
6777         {
6778             uint32_t poff = SmbNtTransactRespParamOff((SmbNtTransactResp *)nb_ptr);
6779             uint32_t pcnt = SmbNtTransactRespParamCnt((SmbNtTransactResp *)nb_ptr);
6780 
6781             DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
6782 
6783             ptr = nb_ptr;
6784             len = pcnt;
6785         }
6786 
6787         if (len < sizeof(SmbNtTransactCreateRespParams))
6788             return DCE2_RET__ERROR;
6789 
6790         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
6791         {
6792             const bool is_directory =
6793                 SmbNtTransactCreateRespDirectory((SmbNtTransactCreateRespParams *)ptr);
6794             const uint16_t resource_type =
6795                 SmbNtTransactCreateRespResourceType((SmbNtTransactCreateRespParams *)ptr);
6796 
6797             if (is_directory || !SmbResourceTypeDisk(resource_type))
6798                 return DCE2_RET__SUCCESS;
6799 
6800             // Give preference to files opened with the sequential only flag set
6801             if (((ssd->fapi_ftracker == NULL) || !ssd->fapi_ftracker->ff_sequential_only)
6802                     && ssd->cur_rtracker->sequential_only)
6803             {
6804                 DCE2_SmbAbortFileAPI(ssd);
6805             }
6806         }
6807 
6808         ftracker = DCE2_SmbNewFileTracker(ssd,
6809                 ssd->cur_rtracker->uid, ssd->cur_rtracker->tid,
6810                 SmbNtTransactCreateRespFid((SmbNtTransactCreateRespParams *)ptr));
6811         if (ftracker == NULL)
6812             return DCE2_RET__ERROR;
6813 
6814         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
6815 
6816         if (!ftracker->is_ipc)
6817         {
6818             uint32_t create_disposition =
6819                 SmbNtTransactCreateRespCreateAction((SmbNtTransactCreateRespParams *)ptr);
6820 
6821             if (SmbCreateDispositionRead(create_disposition))
6822             {
6823                 ftracker->ff_file_size =
6824                     SmbNtTransactCreateRespEndOfFile((SmbNtTransactCreateRespParams *)ptr);
6825             }
6826             else
6827             {
6828                 ftracker->ff_file_size = ssd->cur_rtracker->file_size;
6829                 ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
6830             }
6831 
6832             ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only;
6833 
6834             DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
6835                     if (ftracker->ff_sequential_only)
6836                     printf("File opened for sequential only access.\n"););
6837         }
6838     }
6839 
6840     return DCE2_RET__SUCCESS;
6841 }
6842 
6843 // SMB_COM_NT_TRANSACT_SECONDARY
DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)6844 static DCE2_Ret DCE2_SmbNtTransactSecondary(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6845         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6846 {
6847     DCE2_Ret status;
6848     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
6849 
6850     if (!DCE2_ComInfoCanProcessCommand(com_info))
6851         return DCE2_RET__ERROR;
6852 
6853     status = DCE2_SmbUpdateTransSecondary(ssd, smb_hdr, com_info, nb_ptr, nb_len);
6854     if (status != DCE2_RET__FULL)
6855         return status;
6856 
6857     switch (ttracker->subcom)
6858     {
6859         case NT_TRANSACT_CREATE:
6860             status = DCE2_SmbNtTransactCreateReq(ssd, DCE2_BufferData(ttracker->pbuf),
6861                     DCE2_BufferLength(ttracker->pbuf), SmbUnicode(smb_hdr));
6862             if (status != DCE2_RET__SUCCESS)
6863                 return status;
6864             break;
6865 
6866         default:
6867             break;
6868     }
6869 
6870     return DCE2_RET__SUCCESS;
6871 }
6872 
6873 // 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)6874 static DCE2_Ret DCE2_SmbNtCreateAndX(DCE2_SmbSsnData *ssd, const SmbNtHdr *smb_hdr,
6875         const DCE2_SmbComInfo *com_info, const uint8_t *nb_ptr, uint32_t nb_len)
6876 {
6877     if (!DCE2_ComInfoCanProcessCommand(com_info))
6878         return DCE2_RET__ERROR;
6879 
6880     if (DCE2_ComInfoIsResponse(com_info))
6881     {
6882         const uint16_t fid = SmbNtCreateAndXRespFid((SmbNtCreateAndXResp *)nb_ptr);
6883         DCE2_SmbFileTracker *ftracker = NULL;
6884 
6885         // Set request tracker's current file tracker in case of chained commands
6886         switch (SmbAndXCom2((SmbAndXCommon *)nb_ptr))
6887         {
6888             // This is in case in the request a write was chained to an open
6889             // in which case the write will be to the newly opened file
6890             case SMB_COM_WRITE:
6891             case SMB_COM_WRITE_ANDX:
6892             case SMB_COM_TRANSACTION:
6893             case SMB_COM_READ_ANDX:
6894                 ftracker = DCE2_SmbDequeueTmpFileTracker(ssd, ssd->cur_rtracker, fid);
6895                 break;
6896             default:
6897                 break;
6898         }
6899 
6900         if (!DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid))
6901         {
6902             const bool is_directory = SmbNtCreateAndXRespDirectory((SmbNtCreateAndXResp *)nb_ptr);
6903             const uint16_t resource_type =
6904                 SmbNtCreateAndXRespResourceType((SmbNtCreateAndXResp *)nb_ptr);
6905 
6906             if (is_directory || !SmbResourceTypeDisk(resource_type))
6907             {
6908                 if (ftracker != NULL)
6909                     DCE2_SmbRemoveFileTracker(ssd, ftracker);
6910                 return DCE2_RET__SUCCESS;
6911             }
6912 
6913             // Give preference to files opened with the sequential only flag set
6914             if (((ssd->fapi_ftracker == NULL) || !ssd->fapi_ftracker->ff_sequential_only)
6915                     && (ftracker == NULL) && ssd->cur_rtracker->sequential_only)
6916             {
6917                 DCE2_SmbAbortFileAPI(ssd);
6918             }
6919         }
6920 
6921         if (ftracker == NULL)
6922         {
6923             ftracker = DCE2_SmbNewFileTracker(ssd,
6924                     ssd->cur_rtracker->uid, ssd->cur_rtracker->tid, fid);
6925             if (ftracker == NULL)
6926                 return DCE2_RET__ERROR;
6927         }
6928 
6929         DCE2_Update_Ftracker_from_ReqTracker(ftracker, ssd->cur_rtracker);
6930 
6931         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File name: %s\n",
6932                     (ftracker->file_name == NULL) ? "NULL" : ftracker->file_name));
6933 
6934         if (!ftracker->is_ipc)
6935         {
6936             const uint32_t create_disposition =
6937                 SmbNtCreateAndXRespCreateDisposition((SmbNtCreateAndXResp *)nb_ptr);
6938 
6939             if (SmbCreateDispositionRead(create_disposition))
6940             {
6941                 ftracker->ff_file_size =
6942                     SmbNtCreateAndXRespEndOfFile((SmbNtCreateAndXResp *)nb_ptr);
6943             }
6944             else
6945             {
6946                 ftracker->ff_file_size = ssd->cur_rtracker->file_size;
6947                 ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UPLOAD;
6948             }
6949 
6950             ftracker->ff_sequential_only = ssd->cur_rtracker->sequential_only;
6951 
6952             DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
6953                     if (ftracker->ff_sequential_only)
6954                     printf("File opened for sequential only access.\n"););
6955         }
6956 
6957         ssd->cur_rtracker->ftracker = ftracker;
6958     }
6959     else
6960     {
6961         uint32_t pad = 0;
6962         uint16_t file_name_length =
6963             SmbNtCreateAndXReqFileNameLen((SmbNtCreateAndXReq *)nb_ptr);
6964         const bool unicode = SmbUnicode(smb_hdr);
6965         bool is_ipc = DCE2_SmbIsTidIPC(ssd, ssd->cur_rtracker->tid);
6966         uint8_t smb_com2 = SmbAndXCom2((SmbAndXCommon *)nb_ptr);
6967 
6968         if (!is_ipc)
6969         {
6970             uint32_t ext_file_attrs =
6971                 SmbNtCreateAndXReqFileAttrs((SmbNtCreateAndXReq *)nb_ptr);
6972 
6973             if (SmbEvasiveFileAttrs(ext_file_attrs))
6974                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_EVASIVE_FILE_ATTRS);
6975 
6976             // If the file is going to be accessed sequentially, track it.
6977             if (SmbNtCreateAndXReqSequentialOnly((SmbNtCreateAndXReq *)nb_ptr))
6978                 ssd->cur_rtracker->sequential_only = true;
6979 
6980             ssd->cur_rtracker->file_size = SmbNtCreateAndXReqAllocSize((SmbNtCreateAndXReq *)nb_ptr);
6981         }
6982 
6983         DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
6984 
6985         if (file_name_length > DCE2_SMB_MAX_PATH_LEN)
6986             return DCE2_RET__ERROR;
6987 
6988         if (unicode)
6989             pad = (nb_ptr - (const uint8_t *)smb_hdr) & 1;
6990 
6991         if (nb_len < (pad + file_name_length))
6992             return DCE2_RET__ERROR;
6993 
6994         DCE2_MOVE(nb_ptr, nb_len, pad);
6995 
6996         // Samba allows chaining OpenAndX/NtCreateAndX so might have
6997         // already been set.
6998         if (ssd->cur_rtracker->file_name == NULL)
6999         {
7000             ssd->cur_rtracker->file_name =
7001                 DCE2_SmbGetString(nb_ptr, file_name_length, unicode, &ssd->cur_rtracker->file_name_len);
7002         }
7003 
7004         if (is_ipc)
7005         {
7006             switch (smb_com2)
7007             {
7008                 case SMB_COM_READ_ANDX:
7009                     if (DCE2_SsnIsWindowsPolicy(&ssd->sd))
7010                         return DCE2_RET__ERROR;
7011                     break;
7012                 default:
7013                     break;
7014             }
7015         }
7016     }
7017 
7018     return DCE2_RET__SUCCESS;
7019 }
7020 
DCE2_SmbProcessRequestData(DCE2_SmbSsnData * ssd,const uint16_t fid,const uint8_t * data_ptr,uint32_t data_len,uint64_t offset)7021 static inline DCE2_Ret DCE2_SmbProcessRequestData(DCE2_SmbSsnData *ssd,
7022         const uint16_t fid, const uint8_t *data_ptr, uint32_t data_len, uint64_t offset)
7023 {
7024     DCE2_SmbFileTracker *ftracker = DCE2_SmbGetFileTracker(ssd, fid);
7025 
7026     if (ftracker == NULL)
7027         return DCE2_RET__ERROR;
7028 
7029     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7030                 "Processing request data with Fid: 0x%04X ~~~~~~~~~~~~~~~~~\n", ftracker->fid_v1));
7031 
7032     // Set this in case of chained commands or reassembled packet
7033     ssd->cur_rtracker->ftracker = ftracker;
7034 
7035     DCE2_SmbSetFileName(ftracker->file_name, ftracker->file_name_len);
7036 
7037     if (ftracker->is_ipc)
7038     {
7039         // Maximum possible fragment length is 16 bit
7040         if (data_len > UINT16_MAX)
7041             data_len = UINT16_MAX;
7042 
7043         DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len);
7044 
7045         if (!ftracker->fp_used)
7046             ftracker->fp_used = true;
7047     }
7048     else
7049     {
7050         ftracker->ff_file_offset = offset;
7051         DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, true);
7052     }
7053 
7054     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"));
7055 
7056     return DCE2_RET__SUCCESS;
7057 }
7058 
DCE2_SmbProcessResponseData(DCE2_SmbSsnData * ssd,const uint8_t * data_ptr,uint32_t data_len)7059 static inline DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData *ssd,
7060         const uint8_t *data_ptr, uint32_t data_len)
7061 {
7062     DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker;
7063 
7064     if (ftracker == NULL)
7065         return DCE2_RET__ERROR;
7066 
7067     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7068                 "Processing response data with Fid: 0x%04X ~~~~~~~~~~~~~~~~\n", ftracker->fid_v1));
7069 
7070     DCE2_SmbSetFileName(ftracker->file_name, ftracker->file_name_len);
7071 
7072     if (ftracker->is_ipc)
7073     {
7074         // Maximum possible fragment length is 16 bit
7075         if (data_len > UINT16_MAX)
7076             data_len = UINT16_MAX;
7077 
7078         DCE2_CoProcess(&ssd->sd, ftracker->fp_co_tracker, data_ptr, (uint16_t)data_len);
7079     }
7080     else
7081     {
7082         ftracker->ff_file_offset = ssd->cur_rtracker->file_offset;
7083         DCE2_SmbProcessFileData(ssd, ftracker, data_ptr, data_len, false);
7084     }
7085 
7086     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"));
7087 
7088     return DCE2_RET__SUCCESS;
7089 }
7090 
DCE2_SmbNewRequestTracker(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr)7091 static inline DCE2_SmbRequestTracker * DCE2_SmbNewRequestTracker(DCE2_SmbSsnData *ssd,
7092         const SmbNtHdr *smb_hdr)
7093 {
7094     DCE2_SmbRequestTracker *rtracker = NULL;
7095     DCE2_SmbRequestTracker *tmp_rtracker = NULL;
7096     uint16_t pid = SmbPid(smb_hdr);
7097     uint16_t mid = SmbMid(smb_hdr);
7098     uint16_t uid = SmbUid(smb_hdr);
7099     uint16_t tid = SmbTid(smb_hdr);
7100     PROFILE_VARS;
7101 
7102     PREPROC_PROFILE_START(dce2_pstat_smb_req);
7103 
7104     if (ssd == NULL)
7105     {
7106         PREPROC_PROFILE_END(dce2_pstat_smb_req);
7107         return NULL;
7108     }
7109 
7110     if (ssd->outstanding_requests >= ssd->max_outstanding_requests)
7111     {
7112         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_MAX_REQS_EXCEEDED,
7113                 ssd->max_outstanding_requests);
7114     }
7115 
7116     // Check for outstanding requests with the same MID
7117     tmp_rtracker = &ssd->rtracker;
7118     while ((tmp_rtracker != NULL) && (tmp_rtracker->mid != DCE2_SENTINEL))
7119     {
7120         if (tmp_rtracker->mid == (int)mid)
7121         {
7122             // Have yet to see an MID repeatedly used so shouldn't
7123             // be any outstanding requests with the same MID.
7124             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_REQS_SAME_MID);
7125             break;
7126         }
7127 
7128         // Look at the next request in the queue
7129         if (tmp_rtracker == &ssd->rtracker)
7130             tmp_rtracker = DCE2_QueueFirst(ssd->rtrackers);
7131         else
7132             tmp_rtracker = DCE2_QueueNext(ssd->rtrackers);
7133     }
7134 
7135     if (ssd->rtracker.mid == DCE2_SENTINEL)
7136     {
7137         rtracker = &ssd->rtracker;
7138     }
7139     else
7140     {
7141         if (ssd->rtrackers == NULL)
7142         {
7143             ssd->rtrackers = DCE2_QueueNew(DCE2_SmbRequestTrackerDataFree, DCE2_MEM_TYPE__SMB_REQ);
7144             if (ssd->rtrackers == NULL)
7145             {
7146                 PREPROC_PROFILE_END(dce2_pstat_smb_req);
7147                 return NULL;
7148             }
7149         }
7150 
7151         rtracker = (DCE2_SmbRequestTracker *)DCE2_Alloc(sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ);
7152         if (rtracker == NULL)
7153         {
7154             PREPROC_PROFILE_END(dce2_pstat_smb_req);
7155             return NULL;
7156         }
7157 
7158         if (DCE2_QueueEnqueue(ssd->rtrackers, (void *)rtracker) != DCE2_RET__SUCCESS)
7159         {
7160             DCE2_Free((void *)rtracker, sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ);
7161             PREPROC_PROFILE_END(dce2_pstat_smb_req);
7162             return NULL;
7163         }
7164     }
7165 
7166     rtracker->smb_com = SmbCom(smb_hdr);
7167     rtracker->uid = uid;
7168     rtracker->tid = tid;
7169     rtracker->pid = pid;
7170     rtracker->mid = (int)mid;
7171     memset(&rtracker->ttracker, 0, sizeof(rtracker->ttracker));
7172     rtracker->ftracker = NULL;
7173     rtracker->sequential_only = false;
7174 
7175     ssd->outstanding_requests++;
7176     if (ssd->outstanding_requests > dce2_stats.smb_max_outstanding_requests)
7177         dce2_stats.smb_max_outstanding_requests = ssd->outstanding_requests;
7178 
7179     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Added new request tracker => "
7180                 "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n",
7181                 rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid));
7182     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7183                 "Current outstanding requests: %u\n", ssd->outstanding_requests));
7184 
7185     PREPROC_PROFILE_END(dce2_pstat_smb_req);
7186     return rtracker;
7187 }
7188 
7189 /********************************************************************
7190  * Function:
7191  *
7192  * Purpose:
7193  *
7194  * Arguments:
7195  *
7196  * Returns:
7197  *
7198  ********************************************************************/
DCE2_SmbBufferTransactionData(DCE2_SmbTransactionTracker * ttracker,const uint8_t * data_ptr,uint16_t dcnt,uint16_t ddisp)7199 static inline DCE2_Ret DCE2_SmbBufferTransactionData(DCE2_SmbTransactionTracker *ttracker,
7200         const uint8_t *data_ptr, uint16_t dcnt, uint16_t ddisp)
7201 {
7202     PROFILE_VARS;
7203 
7204     PREPROC_PROFILE_START(dce2_pstat_smb_req);
7205 
7206     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Buffering transaction data.\n"));
7207 
7208     if (ttracker->dbuf == NULL)
7209     {
7210         /* Buf size should be the total data count we need */
7211         ttracker->dbuf = DCE2_BufferNew(ttracker->tdcnt, 0, DCE2_MEM_TYPE__SMB_REQ);
7212         if (ttracker->dbuf == NULL)
7213         {
7214             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to allocate new "
7215                         "buffer to for transaction data.\n"));
7216             PREPROC_PROFILE_END(dce2_pstat_smb_req);
7217             return DCE2_RET__ERROR;
7218         }
7219     }
7220 
7221     if (DCE2_BufferAddData(ttracker->dbuf, data_ptr, dcnt, ddisp,
7222                 DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS)
7223     {
7224         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7225                     "Failed to buffer transaction data.\n"));
7226         PREPROC_PROFILE_END(dce2_pstat_smb_req);
7227         return DCE2_RET__ERROR;
7228     }
7229 
7230     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7231                 "Successfully buffered transaction data.\n"));
7232 
7233     PREPROC_PROFILE_END(dce2_pstat_smb_req);
7234     return DCE2_RET__SUCCESS;
7235 }
7236 
7237 /********************************************************************
7238  * Function:
7239  *
7240  * Purpose:
7241  *
7242  * Arguments:
7243  *
7244  * Returns:
7245  *
7246  ********************************************************************/
DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker * ttracker,const uint8_t * param_ptr,uint16_t pcnt,uint16_t pdisp)7247 static inline DCE2_Ret DCE2_SmbBufferTransactionParameters(DCE2_SmbTransactionTracker *ttracker,
7248         const uint8_t *param_ptr, uint16_t pcnt, uint16_t pdisp)
7249 {
7250     PROFILE_VARS;
7251 
7252     PREPROC_PROFILE_START(dce2_pstat_smb_req);
7253 
7254     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Buffering transaction parameters.\n"));
7255 
7256     if (ttracker->pbuf == NULL)
7257     {
7258         /* Buf size should be the total data count we need */
7259         ttracker->pbuf = DCE2_BufferNew(ttracker->tpcnt, 0, DCE2_MEM_TYPE__SMB_REQ);
7260         if (ttracker->pbuf == NULL)
7261         {
7262             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to allocate new "
7263                         "buffer to for transaction parameter.\n"));
7264             PREPROC_PROFILE_END(dce2_pstat_smb_req);
7265             return DCE2_RET__ERROR;
7266         }
7267     }
7268 
7269     if (DCE2_BufferAddData(ttracker->pbuf, param_ptr, pcnt, pdisp,
7270                 DCE2_BUFFER_MIN_ADD_FLAG__IGNORE) != DCE2_RET__SUCCESS)
7271     {
7272         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7273                     "Failed to buffer transaction parameter data.\n"));
7274         PREPROC_PROFILE_END(dce2_pstat_smb_req);
7275         return DCE2_RET__ERROR;
7276     }
7277 
7278     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
7279                 "Successfully buffered transaction parameter data.\n"));
7280 
7281     PREPROC_PROFILE_END(dce2_pstat_smb_req);
7282     return DCE2_RET__SUCCESS;
7283 }
7284 
7285 /********************************************************************
7286  * Function:
7287  *
7288  * Purpose:
7289  *
7290  * Arguments:
7291  *
7292  * Returns:
7293  *
7294  ********************************************************************/
DCE2_SmbFindRequestTracker(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr)7295 static inline DCE2_SmbRequestTracker * DCE2_SmbFindRequestTracker(DCE2_SmbSsnData *ssd,
7296         const SmbNtHdr *smb_hdr)
7297 {
7298     DCE2_Policy policy = DCE2_SsnGetPolicy(&ssd->sd);
7299     DCE2_SmbRequestTracker *first_rtracker = NULL;
7300     DCE2_SmbRequestTracker *win_rtracker = NULL;
7301     DCE2_SmbRequestTracker *first_mid_rtracker = NULL;
7302     DCE2_SmbRequestTracker *tmp_rtracker = NULL;
7303     DCE2_SmbRequestTracker *ret_rtracker = NULL;
7304     int smb_com = SmbCom(smb_hdr);
7305     uint16_t uid = SmbUid(smb_hdr);
7306     uint16_t tid = SmbTid(smb_hdr);
7307     uint16_t pid = SmbPid(smb_hdr);
7308     uint16_t mid = SmbMid(smb_hdr);
7309     PROFILE_VARS;
7310 
7311     PREPROC_PROFILE_START(dce2_pstat_smb_req);
7312 
7313     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Find request tracker => "
7314                 "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ", uid, tid, pid, mid));
7315 
7316     tmp_rtracker = &ssd->rtracker;
7317 
7318     switch (smb_com)
7319     {
7320         case SMB_COM_TRANSACTION_SECONDARY:
7321             smb_com = SMB_COM_TRANSACTION;
7322             break;
7323         case SMB_COM_TRANSACTION2_SECONDARY:
7324             smb_com = SMB_COM_TRANSACTION2;
7325             break;
7326         case SMB_COM_NT_TRANSACT_SECONDARY:
7327             smb_com = SMB_COM_NT_TRANSACT;
7328             break;
7329         case SMB_COM_WRITE_COMPLETE:
7330             smb_com = SMB_COM_WRITE_RAW;
7331             break;
7332         default:
7333             break;
7334     }
7335 
7336     while (tmp_rtracker != NULL)
7337     {
7338         if ((tmp_rtracker->mid == (int)mid) && (tmp_rtracker->smb_com == smb_com))
7339         {
7340             // This is the normal case except for SessionSetupAndX and
7341             // TreeConnect/TreeConnectAndX which will fall into the
7342             // default case below.
7343             if ((tmp_rtracker->pid == pid) && (tmp_rtracker->uid == uid)
7344                     && (tmp_rtracker->tid == tid))
7345             {
7346                 ret_rtracker = tmp_rtracker;
7347             }
7348             else
7349             {
7350                 switch (smb_com)
7351                 {
7352                     case SMB_COM_TRANSACTION:
7353                     case SMB_COM_TRANSACTION2:
7354                     case SMB_COM_NT_TRANSACT:
7355                     case SMB_COM_TRANSACTION_SECONDARY:
7356                     case SMB_COM_TRANSACTION2_SECONDARY:
7357                     case SMB_COM_NT_TRANSACT_SECONDARY:
7358                         // These should conform to above
7359                         break;
7360                     default:
7361                         if (tmp_rtracker->pid == pid)
7362                             ret_rtracker = tmp_rtracker;
7363                         break;
7364                 }
7365             }
7366 
7367             if (ret_rtracker != NULL)
7368             {
7369                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Found.\n"));
7370                 PREPROC_PROFILE_END(dce2_pstat_smb_req);
7371                 return ret_rtracker;
7372             }
7373 
7374             // Take the first one where the PIDs also match
7375             // in the case of the Transacts above
7376             if ((tmp_rtracker->pid == pid) && (win_rtracker == NULL))
7377                 win_rtracker = tmp_rtracker;
7378 
7379             // Set this to the first matching request in the queue
7380             // where the Mid matches.  Don't set for Windows if from
7381             // client since PID/MID are necessary
7382             if (((DCE2_SmbType(ssd) == SMB_TYPE__RESPONSE)
7383                         || !DCE2_SsnIsWindowsPolicy(&ssd->sd))
7384                     && first_mid_rtracker == NULL)
7385             {
7386                 first_mid_rtracker = tmp_rtracker;
7387             }
7388         }
7389 
7390         // Set the first one we see for early Samba versions
7391         if ((first_rtracker == NULL) && (tmp_rtracker->mid != DCE2_SENTINEL)
7392                 && (tmp_rtracker->smb_com == smb_com))
7393             first_rtracker = tmp_rtracker;
7394 
7395         // Look at the next request in the queue
7396         if (tmp_rtracker == &ssd->rtracker)
7397             tmp_rtracker = DCE2_QueueFirst(ssd->rtrackers);
7398         else
7399             tmp_rtracker = DCE2_QueueNext(ssd->rtrackers);
7400     }
7401 
7402     switch (policy)
7403     {
7404         case DCE2_POLICY__SAMBA_3_0_20:
7405         case DCE2_POLICY__SAMBA_3_0_22:
7406             ret_rtracker = first_rtracker;
7407             break;
7408         case DCE2_POLICY__SAMBA:
7409         case DCE2_POLICY__SAMBA_3_0_37:
7410             ret_rtracker = first_mid_rtracker;
7411             break;
7412         case DCE2_POLICY__WIN2000:
7413         case DCE2_POLICY__WINXP:
7414         case DCE2_POLICY__WINVISTA:
7415         case DCE2_POLICY__WIN2003:
7416         case DCE2_POLICY__WIN2008:
7417         case DCE2_POLICY__WIN7:
7418             if (win_rtracker != NULL)
7419                 ret_rtracker = win_rtracker;
7420             else
7421                 ret_rtracker = first_mid_rtracker;
7422             break;
7423         default:
7424             DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d",
7425                     __FILE__, __LINE__, policy);
7426             break;
7427     }
7428 
7429     DCE2_DEBUG_CODE(DCE2_DEBUG__SMB,
7430             if (ret_rtracker != NULL) printf("Found.\n");
7431             else printf("Not found\n"););
7432 
7433     PREPROC_PROFILE_END(dce2_pstat_smb_req);
7434     return ret_rtracker;
7435 }
7436 
7437 /********************************************************************
7438  * Function:
7439  *
7440  * Purpose:
7441  *
7442  * Arguments:
7443  *
7444  * Returns:
7445  *
7446  ********************************************************************/
DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData * ssd,DCE2_SmbRequestTracker * rtracker)7447 static inline void DCE2_SmbRemoveRequestTracker(DCE2_SmbSsnData *ssd,
7448         DCE2_SmbRequestTracker *rtracker)
7449 {
7450     DCE2_SmbRequestTracker *tmp_node;
7451     PROFILE_VARS;
7452 
7453     PREPROC_PROFILE_START(dce2_pstat_smb_req);
7454 
7455     if ((ssd == NULL) || (rtracker == NULL))
7456     {
7457         PREPROC_PROFILE_END(dce2_pstat_smb_req);
7458         return;
7459     }
7460 
7461     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing request tracker => "
7462                 "Uid: %u, Tid: %u, Pid: %u, Mid: %u ... ",
7463                 rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid));
7464 
7465     if (rtracker == &ssd->rtracker)
7466     {
7467         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removed\n"));
7468 
7469         DCE2_SmbCleanRequestTracker(&ssd->rtracker);
7470         ssd->outstanding_requests--;
7471 
7472         PREPROC_PROFILE_END(dce2_pstat_smb_req);
7473         return;
7474     }
7475 
7476     for (tmp_node = DCE2_QueueFirst(ssd->rtrackers);
7477             tmp_node != NULL;
7478             tmp_node = DCE2_QueueNext(ssd->rtrackers))
7479     {
7480         if (tmp_node == (void *)rtracker)
7481         {
7482             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removed.\n"));
7483 
7484             DCE2_QueueRemoveCurrent(ssd->rtrackers);
7485             ssd->outstanding_requests--;
7486 
7487             PREPROC_PROFILE_END(dce2_pstat_smb_req);
7488             return;
7489         }
7490     }
7491 
7492     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not removed.\n"));
7493 
7494     PREPROC_PROFILE_END(dce2_pstat_smb_req);
7495 }
7496 
7497 /********************************************************************
7498  * Function:
7499  *
7500  * Purpose:
7501  *
7502  * Arguments:
7503  *
7504  * Returns:
7505  *
7506  ********************************************************************/
DCE2_SmbInsertUid(DCE2_SmbSsnData * ssd,const uint16_t uid)7507 static void DCE2_SmbInsertUid(DCE2_SmbSsnData *ssd, const uint16_t uid)
7508 {
7509     PROFILE_VARS;
7510 
7511     PREPROC_PROFILE_START(dce2_pstat_smb_uid);
7512 
7513     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Inserting Uid: %u\n", uid););
7514 
7515     if (ssd->uid == DCE2_SENTINEL)
7516     {
7517         ssd->uid = (int)uid;
7518     }
7519     else
7520     {
7521         if (ssd->uids == NULL)
7522         {
7523             ssd->uids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare,
7524                     NULL, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_UID);
7525 
7526             if (ssd->uids == NULL)
7527             {
7528                 PREPROC_PROFILE_END(dce2_pstat_smb_uid);
7529                 return;
7530             }
7531         }
7532 
7533         DCE2_ListInsert(ssd->uids, (void *)(uintptr_t)uid, (void *)(uintptr_t)uid);
7534     }
7535 
7536     PREPROC_PROFILE_END(dce2_pstat_smb_uid);
7537 }
7538 
7539 /********************************************************************
7540  * Function:
7541  *
7542  * Purpose:
7543  *
7544  * Arguments:
7545  *
7546  * Returns:
7547  *
7548  ********************************************************************/
DCE2_SmbFindUid(DCE2_SmbSsnData * ssd,const uint16_t uid)7549 static DCE2_Ret DCE2_SmbFindUid(DCE2_SmbSsnData *ssd, const uint16_t uid)
7550 {
7551     DCE2_Ret status;
7552     PROFILE_VARS;
7553 
7554     PREPROC_PROFILE_START(dce2_pstat_smb_uid);
7555 
7556     if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid))
7557         status = DCE2_RET__SUCCESS;
7558     else
7559         status = DCE2_ListFindKey(ssd->uids, (void *)(uintptr_t)uid);
7560 
7561     PREPROC_PROFILE_END(dce2_pstat_smb_uid);
7562 
7563     return status;
7564 }
7565 
7566 /********************************************************************
7567  * Function:
7568  *
7569  * Purpose:
7570  *
7571  * Arguments:
7572  *
7573  * Returns:
7574  *
7575  ********************************************************************/
DCE2_SmbRemoveUid(DCE2_SmbSsnData * ssd,const uint16_t uid)7576 static void DCE2_SmbRemoveUid(DCE2_SmbSsnData *ssd, const uint16_t uid)
7577 {
7578     const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
7579     PROFILE_VARS;
7580 
7581     PREPROC_PROFILE_START(dce2_pstat_smb_uid);
7582 
7583     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Uid: %u\n", uid););
7584 
7585     if ((ssd->uid != DCE2_SENTINEL) && (ssd->uid == (int)uid))
7586         ssd->uid = DCE2_SENTINEL;
7587     else
7588         DCE2_ListRemove(ssd->uids, (void *)(uintptr_t)uid);
7589 
7590     switch (policy)
7591     {
7592         case DCE2_POLICY__WIN2000:
7593         case DCE2_POLICY__WIN2003:
7594         case DCE2_POLICY__WINXP:
7595         case DCE2_POLICY__WINVISTA:
7596         case DCE2_POLICY__WIN2008:
7597         case DCE2_POLICY__WIN7:
7598         case DCE2_POLICY__SAMBA:
7599         case DCE2_POLICY__SAMBA_3_0_37:
7600             // Removing uid invalidates any fid that was created with it */
7601             if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL) &&
7602                     (ssd->ftracker.uid_v1 == uid))
7603             {
7604                 DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
7605             }
7606 
7607             if (ssd->ftrackers != NULL)
7608             {
7609                 DCE2_SmbFileTracker *ftracker;
7610 
7611                 for (ftracker = DCE2_ListFirst(ssd->ftrackers);
7612                         ftracker != NULL;
7613                         ftracker = DCE2_ListNext(ssd->ftrackers))
7614                 {
7615                     if (ftracker->uid_v1 == uid)
7616                     {
7617                         if (ssd->fapi_ftracker == ftracker)
7618                             DCE2_SmbFinishFileAPI(ssd);
7619 
7620 #ifdef ACTIVE_RESPONSE
7621                         if (ssd->fb_ftracker == ftracker)
7622                             DCE2_SmbFinishFileBlockVerdict(ssd);
7623 #endif
7624 
7625                         DCE2_ListRemoveCurrent(ssd->ftrackers);
7626                         DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
7627                     }
7628                 }
7629             }
7630 
7631             break;
7632 
7633         case DCE2_POLICY__SAMBA_3_0_20:
7634         case DCE2_POLICY__SAMBA_3_0_22:
7635             // Removing Uid used to create file doesn't invalidate it.
7636             break;
7637 
7638         default:
7639             DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d",
7640                     __FILE__, __LINE__, policy);
7641             break;
7642     }
7643 
7644     PREPROC_PROFILE_END(dce2_pstat_smb_uid);
7645 }
7646 
7647 /********************************************************************
7648  * Function:
7649  *
7650  * Purpose:
7651  *
7652  * Arguments:
7653  *
7654  * Returns:
7655  *
7656  ********************************************************************/
DCE2_SmbInsertTid(DCE2_SmbSsnData * ssd,const uint16_t tid,const bool is_ipc)7657 static void DCE2_SmbInsertTid(DCE2_SmbSsnData *ssd,
7658         const uint16_t tid, const bool is_ipc)
7659 {
7660     int insert_tid = (int)tid;
7661     PROFILE_VARS;
7662 
7663     PREPROC_PROFILE_START(dce2_pstat_smb_tid);
7664 
7665     if (!is_ipc && (!DCE2_ScSmbFileInspection(ssd->sd.sconfig)
7666                 || ((ssd->max_file_depth == -1) && DCE2_ScSmbFileDepth(ssd->sd.sconfig) == -1)))
7667     {
7668         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inserting TID (%u) "
7669                     "because it's not IPC and not inspecting normal file "
7670                     "data.", tid));
7671         PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7672         return;
7673     }
7674 
7675     if (is_ipc && DCE2_ScSmbFileInspectionOnly(ssd->sd.sconfig))
7676     {
7677         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not inserting TID (%u) "
7678                     "because it's IPC and only inspecting normal file "
7679                     "data.", tid));
7680         PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7681         return;
7682     }
7683 
7684     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Inserting Tid: %u\n", tid));
7685 
7686     // Set a bit so as to distinguish between IPC and non-IPC TIDs
7687     if (!is_ipc)
7688         insert_tid |= (1 << 16);
7689 
7690     if (ssd->tid == DCE2_SENTINEL)
7691     {
7692         ssd->tid = insert_tid;
7693     }
7694     else
7695     {
7696         if (ssd->tids == NULL)
7697         {
7698             ssd->tids = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED, DCE2_SmbUidTidFidCompare,
7699                     NULL, NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_TID);
7700 
7701             if (ssd->tids == NULL)
7702             {
7703                 PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7704                 return;
7705             }
7706         }
7707 
7708         DCE2_ListInsert(ssd->tids, (void *)(uintptr_t)tid, (void *)(uintptr_t)insert_tid);
7709     }
7710 
7711     PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7712 }
7713 
7714 /********************************************************************
7715  * Function:
7716  *
7717  * Purpose:
7718  *
7719  * Arguments:
7720  *
7721  * Returns:
7722  *
7723  ********************************************************************/
DCE2_SmbFindTid(DCE2_SmbSsnData * ssd,const uint16_t tid)7724 static DCE2_Ret DCE2_SmbFindTid(DCE2_SmbSsnData *ssd, const uint16_t tid)
7725 {
7726     DCE2_Ret status;
7727     PROFILE_VARS;
7728 
7729     PREPROC_PROFILE_START(dce2_pstat_smb_tid);
7730 
7731     if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid))
7732         status = DCE2_RET__SUCCESS;
7733     else
7734         status = DCE2_ListFindKey(ssd->tids, (void *)(uintptr_t)tid);
7735 
7736     PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7737     return status;
7738 }
7739 
7740 /********************************************************************
7741  * Function:  DCE2_SmbIsTidIPC()
7742  *
7743  * Purpose: Checks to see if the TID passed in was to IPC or not.
7744  *
7745  * Arguments:
7746  *  DCE2_SmbSsnData * - pointer to session data
7747  *  const uint16_t    - the TID to check
7748  *
7749  * Returns:
7750  *  bool - True if TID is IPC, false if not or if TID not found.
7751  *
7752  ********************************************************************/
DCE2_SmbIsTidIPC(DCE2_SmbSsnData * ssd,const uint16_t tid)7753 static bool DCE2_SmbIsTidIPC(DCE2_SmbSsnData *ssd, const uint16_t tid)
7754 {
7755     if ((ssd->tid != DCE2_SENTINEL)
7756             && ((ssd->tid & 0x0000ffff) == (int)tid))
7757     {
7758         if ((ssd->tid >> 16) == 0)
7759             return true;
7760     }
7761     else
7762     {
7763         int check_tid = (int)(uintptr_t)DCE2_ListFind(ssd->tids, (void *)(uintptr_t)tid);
7764         if (((check_tid & 0x0000ffff) == (int)tid) && ((check_tid >> 16) == 0))
7765             return true;
7766     }
7767 
7768     return false;
7769 }
7770 
7771 /********************************************************************
7772  * Function:
7773  *
7774  * Purpose:
7775  *
7776  * Arguments:
7777  *
7778  * Returns:
7779  *
7780  ********************************************************************/
DCE2_SmbRemoveTid(DCE2_SmbSsnData * ssd,const uint16_t tid)7781 static void DCE2_SmbRemoveTid(DCE2_SmbSsnData *ssd, const uint16_t tid)
7782 {
7783     PROFILE_VARS;
7784 
7785     PREPROC_PROFILE_START(dce2_pstat_smb_tid);
7786 
7787     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Tid: %u\n", tid));
7788 
7789     if ((ssd->tid != DCE2_SENTINEL) && ((ssd->tid & 0x0000ffff) == (int)tid))
7790         ssd->tid = DCE2_SENTINEL;
7791     else
7792         DCE2_ListRemove(ssd->tids, (void *)(uintptr_t)tid);
7793 
7794     // Removing Tid invalidates files created with it
7795     if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL)
7796             && (ssd->ftracker.tid_v1 == tid))
7797     {
7798         DCE2_SmbRemoveFileTracker(ssd, &ssd->ftracker);
7799     }
7800 
7801     if (ssd->ftrackers != NULL)
7802     {
7803         DCE2_SmbFileTracker *ftracker;
7804 
7805         for (ftracker = DCE2_ListFirst(ssd->ftrackers);
7806                 ftracker != NULL;
7807                 ftracker = DCE2_ListNext(ssd->ftrackers))
7808         {
7809             if (ftracker->tid_v1 == (int)tid)
7810             {
7811                 if (ssd->fapi_ftracker == ftracker)
7812                     DCE2_SmbFinishFileAPI(ssd);
7813 
7814 #ifdef ACTIVE_RESPONSE
7815                 if (ssd->fb_ftracker == ftracker)
7816                     DCE2_SmbFinishFileBlockVerdict(ssd);
7817 #endif
7818 
7819                 DCE2_ListRemoveCurrent(ssd->ftrackers);
7820                 DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
7821             }
7822         }
7823     }
7824 
7825     PREPROC_PROFILE_END(dce2_pstat_smb_tid);
7826 }
7827 
DCE2_SmbInitFileTracker(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker,const bool is_ipc,const uint16_t uid,const uint16_t tid,const int fid)7828 static inline DCE2_Ret DCE2_SmbInitFileTracker(DCE2_SmbSsnData *ssd,
7829         DCE2_SmbFileTracker *ftracker, const bool is_ipc, const uint16_t uid,
7830         const uint16_t tid, const int fid)
7831 {
7832     if (ftracker == NULL)
7833         return DCE2_RET__ERROR;
7834 
7835     ftracker->uid_v1 = uid;
7836     ftracker->tid_v1 = tid;
7837     ftracker->fid_v1 = fid;
7838     ftracker->is_ipc = is_ipc;
7839     ftracker->is_smb2 = false;
7840     ftracker->file_name = NULL;
7841     ftracker->file_name_len = 0;
7842     if (is_ipc)
7843     {
7844         DCE2_CoTracker *co_tracker = DCE2_Alloc(sizeof(DCE2_CoTracker), DCE2_MEM_TYPE__SMB_FID);
7845         if (co_tracker == NULL)
7846             return DCE2_RET__ERROR;
7847         DCE2_CoInitTracker(co_tracker);
7848         ftracker->fp_co_tracker = co_tracker;
7849         ftracker->fp_byte_mode = false;
7850         ftracker->fp_used = false;
7851         ftracker->fp_writex_raw = NULL;
7852     }
7853     else
7854     {
7855         ftracker->ff_file_size = 0;
7856         ftracker->ff_file_offset = 0;
7857         ftracker->ff_bytes_processed = 0;
7858         ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
7859         ftracker->ff_file_chunks = NULL;
7860         ftracker->ff_bytes_queued = 0;
7861         if ((ssd->fapi_ftracker == NULL) && (ssd->max_file_depth != -1))
7862         {
7863             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Designating file tracker "
7864                         "for file API processing: 0x%04X\n", (uint16_t)fid););
7865             ssd->fapi_ftracker = ftracker;
7866         }
7867     }
7868 
7869     return DCE2_RET__SUCCESS;
7870 }
7871 
7872 /********************************************************************
7873  * Function:
7874  *
7875  * Purpose:
7876  *
7877  * Arguments:
7878  *
7879  * Returns:
7880  *
7881  ********************************************************************/
DCE2_SmbNewFileTracker(DCE2_SmbSsnData * ssd,const uint16_t uid,const uint16_t tid,const uint16_t fid)7882 static DCE2_SmbFileTracker * DCE2_SmbNewFileTracker(DCE2_SmbSsnData *ssd,
7883         const uint16_t uid, const uint16_t tid, const uint16_t fid)
7884 {
7885     DCE2_SmbFileTracker *ftracker = NULL;
7886     bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid);
7887     PROFILE_VARS;
7888 
7889     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
7890 
7891     // Already have tracker for file API and not setting file data pointer
7892     // so don't create new file tracker.
7893     if (!is_ipc && (ssd->fapi_ftracker != NULL)
7894             && (DCE2_ScSmbFileDepth(ssd->sd.sconfig) == -1))
7895         return NULL;
7896 
7897     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Creating new file tracker "
7898                 "with Uid: %u, Tid: %u, Fid: 0x%04X\n", uid, tid, fid));
7899 
7900     if (ssd->ftracker.fid_v1 == DCE2_SENTINEL)
7901     {
7902         ftracker = &ssd->ftracker;
7903         if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) != DCE2_RET__SUCCESS)
7904         {
7905             DCE2_SmbCleanFileTracker(ftracker);
7906             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7907             return NULL;
7908         }
7909     }
7910     else
7911     {
7912         ftracker = (DCE2_SmbFileTracker *)
7913             DCE2_Alloc(sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
7914 
7915         if (ftracker == NULL)
7916         {
7917             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7918             return NULL;
7919         }
7920 
7921         if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, (int)fid) != DCE2_RET__SUCCESS)
7922         {
7923             DCE2_SmbCleanFileTracker(ftracker);
7924             DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
7925             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7926             return NULL;
7927         }
7928 
7929         if (ssd->ftrackers == NULL)
7930         {
7931             ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED,
7932                     DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, NULL,
7933                     DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FID);
7934 
7935             if (ssd->ftrackers == NULL)
7936             {
7937                 DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
7938                 PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7939                 return NULL;
7940             }
7941         }
7942 
7943         if (DCE2_ListInsert(ssd->ftrackers, (void *)(uintptr_t)fid,
7944                     (void *)ftracker) != DCE2_RET__SUCCESS)
7945         {
7946             DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
7947             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7948             return NULL;
7949         }
7950     }
7951 
7952     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7953     return ftracker;
7954 }
7955 
7956 /********************************************************************
7957  * Function:
7958  *
7959  * Purpose:
7960  *
7961  * Arguments:
7962  *
7963  * Returns:
7964  *
7965  ********************************************************************/
DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData * ssd,DCE2_SmbRequestTracker * rtracker,const uint16_t uid,const uint16_t tid)7966 static void DCE2_SmbQueueTmpFileTracker(DCE2_SmbSsnData *ssd,
7967         DCE2_SmbRequestTracker *rtracker, const uint16_t uid, const uint16_t tid)
7968 {
7969     DCE2_SmbFileTracker *ftracker;
7970     bool is_ipc = DCE2_SmbIsTidIPC(ssd, tid);
7971     PROFILE_VARS;
7972 
7973     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
7974 
7975     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Queueing file tracker "
7976                 "with Uid: %u, Tid: %u\n", uid, tid));
7977 
7978     ftracker = (DCE2_SmbFileTracker *)
7979         DCE2_Alloc(sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
7980 
7981     if (ftracker == NULL)
7982     {
7983         PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7984         return;
7985     }
7986 
7987     if (DCE2_SmbInitFileTracker(ssd, ftracker, is_ipc, uid, tid, DCE2_SENTINEL) != DCE2_RET__SUCCESS)
7988     {
7989         DCE2_SmbCleanFileTracker(ftracker);
7990         DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
7991         PREPROC_PROFILE_END(dce2_pstat_smb_fid);
7992         return;
7993     }
7994 
7995     if (!is_ipc && (ssd->fapi_ftracker == ftracker))
7996         ssd->fapi_ftracker = NULL;
7997 
7998     if (rtracker->ft_queue == NULL)
7999     {
8000         rtracker->ft_queue = DCE2_QueueNew(DCE2_SmbFileTrackerDataFree, DCE2_MEM_TYPE__SMB_FID);
8001         if (rtracker->ft_queue == NULL)
8002         {
8003             DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
8004             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8005             return;
8006         }
8007     }
8008 
8009     if (DCE2_QueueEnqueue(rtracker->ft_queue, (void *)ftracker) != DCE2_RET__SUCCESS)
8010     {
8011         DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
8012         PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8013         return;
8014     }
8015 
8016     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8017 }
8018 
8019 /********************************************************************
8020  * Function:
8021  *
8022  * Purpose:
8023  *
8024  * Arguments:
8025  *
8026  * Returns: None
8027  *
8028  ********************************************************************/
DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker * rtracker)8029 static inline DCE2_SmbFileTracker * DCE2_SmbGetTmpFileTracker(DCE2_SmbRequestTracker *rtracker)
8030 {
8031     if (!DCE2_QueueIsEmpty(rtracker->ft_queue))
8032         return (DCE2_SmbFileTracker *)DCE2_QueueLast(rtracker->ft_queue);
8033     return NULL;
8034 }
8035 
8036 /********************************************************************
8037  * Function:
8038  *
8039  * Purpose:
8040  *
8041  * Arguments:
8042  *
8043  * Returns: None
8044  *
8045  ********************************************************************/
DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData * ssd,DCE2_SmbRequestTracker * rtracker,const uint16_t fid)8046 static DCE2_SmbFileTracker * DCE2_SmbDequeueTmpFileTracker(DCE2_SmbSsnData *ssd,
8047         DCE2_SmbRequestTracker *rtracker, const uint16_t fid)
8048 {
8049     DCE2_SmbFileTracker *ftracker;
8050     PROFILE_VARS;
8051 
8052     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
8053 
8054     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Dequeueing file tracker "
8055                 "and binding to fid: 0x%04X\n", fid));
8056 
8057     ftracker = (DCE2_SmbFileTracker *)DCE2_QueueDequeue(rtracker->ft_queue);
8058     if (ftracker == NULL)
8059     {
8060         PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8061         return NULL;
8062     }
8063 
8064     if (ssd->ftracker.fid_v1 == DCE2_SENTINEL)
8065     {
8066         memcpy(&ssd->ftracker, ftracker, sizeof(DCE2_SmbFileTracker));
8067         DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
8068         if (ssd->fapi_ftracker == ftracker)
8069             ssd->fapi_ftracker = &ssd->ftracker;
8070         ftracker = &ssd->ftracker;
8071     }
8072     else
8073     {
8074         if (ssd->ftrackers == NULL)
8075         {
8076             ssd->ftrackers = DCE2_ListNew(DCE2_LIST_TYPE__SPLAYED,
8077                     DCE2_SmbUidTidFidCompare, DCE2_SmbFileTrackerDataFree, NULL,
8078                     DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FID);
8079 
8080             if (ssd->ftrackers == NULL)
8081             {
8082                 DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
8083                 PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8084                 return NULL;
8085             }
8086         }
8087 
8088         if (DCE2_ListInsert(ssd->ftrackers, (void *)(uintptr_t)fid,
8089                     (void *)ftracker) != DCE2_RET__SUCCESS)
8090         {
8091             DCE2_SmbCleanSessionFileTracker(ssd, ftracker);
8092             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8093             return NULL;
8094         }
8095     }
8096 
8097     // Other values were intialized when queueing.
8098     ftracker->fid_v1 = (int)fid;
8099 
8100     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8101     return ftracker;
8102 }
8103 
8104 /********************************************************************
8105  * Function:
8106  *
8107  * Purpose:
8108  *
8109  * Arguments:
8110  *
8111  * Returns:
8112  *
8113  ********************************************************************/
DCE2_SmbGetFileTracker(DCE2_SmbSsnData * ssd,const uint16_t fid)8114 static inline DCE2_SmbFileTracker * DCE2_SmbGetFileTracker(DCE2_SmbSsnData *ssd,
8115         const uint16_t fid)
8116 {
8117     DCE2_SmbFileTracker *ftracker = ssd->cur_rtracker->ftracker;
8118 
8119     if (ftracker == NULL)
8120     {
8121         // Write could've been chained to an OpenAndX or NtCreateAndX so a
8122         // temporary file tracker would've been created until we get the
8123         // response with the Fid returned from the OpenAndX / NtCreateAndX
8124         ftracker = DCE2_SmbGetTmpFileTracker(ssd->cur_rtracker);
8125         if (ftracker == NULL)
8126         {
8127             // Otherwise find it with the passed in Fid
8128             ftracker = DCE2_SmbFindFileTracker(ssd, ssd->cur_rtracker->uid,
8129                     ssd->cur_rtracker->tid, fid);
8130         }
8131     }
8132 
8133     return ftracker;
8134 }
8135 
8136 /********************************************************************
8137  * Function:
8138  *
8139  * Purpose:
8140  *
8141  * Arguments:
8142  *
8143  * Returns:
8144  *
8145  ********************************************************************/
DCE2_SmbFindFileTracker(DCE2_SmbSsnData * ssd,const uint16_t uid,const uint16_t tid,const uint16_t fid)8146 static DCE2_SmbFileTracker * DCE2_SmbFindFileTracker(DCE2_SmbSsnData *ssd,
8147         const uint16_t uid, const uint16_t tid, const uint16_t fid)
8148 {
8149     const DCE2_Policy policy = DCE2_SsnGetServerPolicy(&ssd->sd);
8150     DCE2_SmbFileTracker *ftracker;
8151     PROFILE_VARS;
8152 
8153     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
8154 
8155     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Finding file tracker with "
8156                 "Uid: %u, Tid: %u, Fid: 0x%04X ... ", uid, tid, fid));
8157 
8158     if ((ssd->ftracker.fid_v1 != DCE2_SENTINEL) && (ssd->ftracker.fid_v1 == (int)fid))
8159     {
8160         ftracker = &ssd->ftracker;
8161     }
8162     else
8163     {
8164         ftracker = (DCE2_SmbFileTracker *)
8165             DCE2_ListFind(ssd->ftrackers, (void *)(uintptr_t)fid);
8166     }
8167 
8168     if (ftracker == NULL)
8169     {
8170         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n"));
8171         PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8172         return NULL;
8173     }
8174 
8175     // Note IPC Tid has already been validated in initial processing
8176     switch (policy)
8177     {
8178         case DCE2_POLICY__SAMBA:
8179         case DCE2_POLICY__SAMBA_3_0_37:
8180             // Only Uid used to open file can be used to make a request
8181             if (ftracker->uid_v1 != uid)
8182             {
8183                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n"));
8184                 PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8185                 return NULL;
8186             }
8187 
8188             break;
8189 
8190         case DCE2_POLICY__WIN2000:
8191         case DCE2_POLICY__SAMBA_3_0_20:
8192         case DCE2_POLICY__SAMBA_3_0_22:
8193             // Any valid Uid can be used to make a request to a file ...
8194             // except for Windows 2000 on the first use.
8195             if ((policy != DCE2_POLICY__WIN2000) || (ftracker->is_ipc && ftracker->fp_used))
8196             {
8197                 // Check that the Uid exists
8198                 if (DCE2_SmbFindUid(ssd, uid) != DCE2_RET__SUCCESS)
8199                 {
8200                     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n"));
8201                     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8202                     return NULL;
8203                 }
8204 
8205                 break;
8206             }
8207 
8208             // Fall through for Windows 2000 for first request to file
8209 
8210         case DCE2_POLICY__WIN2003:
8211         case DCE2_POLICY__WINXP:
8212         case DCE2_POLICY__WINVISTA:
8213         case DCE2_POLICY__WIN2008:
8214         case DCE2_POLICY__WIN7:
8215             // Both Uid and Tid used to create file must be used to make a request
8216             if ((ftracker->uid_v1 != uid) || (ftracker->tid_v1 != tid))
8217             {
8218                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Not found.\n"));
8219                 PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8220                 return NULL;
8221             }
8222 
8223             break;
8224 
8225         default:
8226             DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid policy: %d",
8227                     __FILE__, __LINE__, policy);
8228             break;
8229     }
8230 
8231     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Found with "
8232                 "Uid: %u, Tid: %u, Fid: 0x%04X\n",
8233                 ftracker->uid_v1, ftracker->tid_v1, ftracker->fid_v1));
8234 
8235     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8236     return ftracker;
8237 }
8238 
8239 /********************************************************************
8240  * Function:
8241  *
8242  * Purpose:
8243  *
8244  * Arguments:
8245  *
8246  * Returns:
8247  *
8248  ********************************************************************/
DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker)8249 static DCE2_Ret DCE2_SmbRemoveFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker)
8250 {
8251     PROFILE_VARS;
8252 
8253     if (ftracker == NULL)
8254         return DCE2_RET__ERROR;
8255 
8256     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
8257 
8258     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
8259                 "Removing file tracker with Fid: 0x%04X\n", ftracker->fid_v1));
8260 
8261     if (ssd->fapi_ftracker == ftracker)
8262     {
8263        /* If the finish API returns pending set , we return from here
8264         * with not inspected and do not remove the file & request
8265         * trackers for upcoming retry packet.
8266         */
8267 
8268         DCE2_SmbRetransmitPending flag = DCE2_SmbFinishFileAPI(ssd);
8269         if (flag == DCE2_SMB_RETRANSMIT_PENDING__SET)
8270         {
8271             PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8272             return DCE2_RET__NOT_INSPECTED;
8273         }
8274      }
8275 
8276 #ifdef ACTIVE_RESPONSE
8277     if (ssd->fb_ftracker == ftracker)
8278         DCE2_SmbFinishFileBlockVerdict(ssd);
8279 #endif
8280 
8281     if (ftracker == &ssd->ftracker)
8282         DCE2_SmbCleanFileTracker(&ssd->ftracker);
8283     else if (ssd->ftrackers != NULL)
8284         DCE2_ListRemove(ssd->ftrackers, (void *)(uintptr_t)ftracker->fid_v1);
8285 
8286     DCE2_SmbRemoveFileTrackerFromRequestTrackers(ssd, ftracker);
8287 
8288     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8289     return DCE2_RET__SUCCESS;
8290 }
8291 
8292 /********************************************************************
8293  * Function:
8294  *
8295  * Purpose:
8296  *
8297  * Arguments:
8298  *
8299  * Returns:
8300  *
8301  ********************************************************************/
DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker * ftracker)8302 static inline void DCE2_SmbCleanFileTracker(DCE2_SmbFileTracker *ftracker)
8303 {
8304     PROFILE_VARS;
8305 
8306     if (ftracker == NULL)
8307         return;
8308 
8309     PREPROC_PROFILE_START(dce2_pstat_smb_fid);
8310 
8311     ftracker->fid_v1 = DCE2_SENTINEL;
8312     if (ftracker->file_name != NULL)
8313     {
8314         DCE2_Free((void *)ftracker->file_name, ftracker->file_name_len, DCE2_MEM_TYPE__SMB_SSN);
8315         ftracker->file_name = NULL;
8316         ftracker->file_name_len = 0;
8317     }
8318 
8319     if (ftracker->is_ipc)
8320     {
8321         ftracker->fp_used = 0;
8322         ftracker->fp_byte_mode = 0;
8323 
8324         if (ftracker->fp_writex_raw != NULL)
8325         {
8326             DCE2_BufferDestroy(ftracker->fp_writex_raw->buf);
8327             DCE2_Free((void *)ftracker->fp_writex_raw,
8328                     sizeof(DCE2_SmbWriteAndXRaw), DCE2_MEM_TYPE__SMB_FID);
8329             ftracker->fp_writex_raw = NULL;
8330         }
8331 
8332         if (ftracker->fp_co_tracker != NULL)
8333         {
8334             DCE2_CoCleanTracker(ftracker->fp_co_tracker);
8335             DCE2_Free((void *)ftracker->fp_co_tracker, sizeof(DCE2_CoTracker), DCE2_MEM_TYPE__SMB_FID);
8336             ftracker->fp_co_tracker = NULL;
8337         }
8338     }
8339     else
8340     {
8341         ftracker->ff_file_size = 0;
8342         ftracker->ff_file_offset = 0;
8343         ftracker->ff_bytes_processed = 0;
8344         ftracker->ff_file_direction = DCE2_SMB_FILE_DIRECTION__UNKNOWN;
8345         ftracker->ff_bytes_queued = 0;
8346         ftracker->ff_sequential_only = false;
8347         if (ftracker->ff_file_chunks != NULL)
8348         {
8349             DCE2_ListDestroy(ftracker->ff_file_chunks);
8350             ftracker->ff_file_chunks = NULL;
8351         }
8352     }
8353 
8354     PREPROC_PROFILE_END(dce2_pstat_smb_fid);
8355 }
8356 
8357 /********************************************************************
8358  *
8359  * Remove file tracker and associated pointers in session
8360  *
8361  ********************************************************************/
DCE2_SmbCleanSessionFileTracker(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker)8362 static inline void DCE2_SmbCleanSessionFileTracker(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker)
8363 {
8364     DCE2_SmbCleanFileTracker(ftracker);
8365     DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
8366     if (ssd->fapi_ftracker == ftracker)
8367         ssd->fapi_ftracker = NULL;
8368 }
8369 /********************************************************************
8370  * Function:
8371  *
8372  * Purpose:
8373  *
8374  * Arguments:
8375  *
8376  * Returns: void
8377  *
8378  ********************************************************************/
DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker * ttracker)8379 static inline void DCE2_SmbCleanTransactionTracker(DCE2_SmbTransactionTracker *ttracker)
8380 {
8381     PROFILE_VARS;
8382 
8383     PREPROC_PROFILE_START(dce2_pstat_smb_req);
8384 
8385     if (ttracker == NULL)
8386     {
8387         PREPROC_PROFILE_END(dce2_pstat_smb_req);
8388         return;
8389     }
8390 
8391     if (ttracker->dbuf != NULL)
8392         DCE2_BufferDestroy(ttracker->dbuf);
8393 
8394     if (ttracker->pbuf != NULL)
8395         DCE2_BufferDestroy(ttracker->pbuf);
8396 
8397     memset(ttracker, 0, sizeof(*ttracker));
8398 
8399     PREPROC_PROFILE_END(dce2_pstat_smb_req);
8400 }
8401 
8402 /********************************************************************
8403  * Function:
8404  *
8405  * Purpose:
8406  *
8407  * Arguments:
8408  *
8409  * Returns:
8410  *
8411  ********************************************************************/
DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker * rtracker)8412 static inline void DCE2_SmbCleanRequestTracker(DCE2_SmbRequestTracker *rtracker)
8413 {
8414     PROFILE_VARS;
8415 
8416     PREPROC_PROFILE_START(dce2_pstat_smb_req);
8417 
8418     if (rtracker == NULL)
8419     {
8420         PREPROC_PROFILE_END(dce2_pstat_smb_req);
8421         return;
8422     }
8423 
8424     if (rtracker->mid == DCE2_SENTINEL)
8425     {
8426         PREPROC_PROFILE_END(dce2_pstat_smb_req);
8427         return;
8428     }
8429 
8430     rtracker->mid = DCE2_SENTINEL;
8431     rtracker->ftracker = NULL;
8432     rtracker->sequential_only = false;
8433 
8434     DCE2_SmbCleanTransactionTracker(&rtracker->ttracker);
8435 
8436     DCE2_QueueDestroy(rtracker->ft_queue);
8437     rtracker->ft_queue = NULL;
8438 
8439     if (rtracker->file_name != NULL)
8440     {
8441         DCE2_Free((void *)rtracker->file_name, rtracker->file_name_len, DCE2_MEM_TYPE__SMB_SSN);
8442         rtracker->file_name = NULL;
8443     }
8444 
8445     PREPROC_PROFILE_END(dce2_pstat_smb_req);
8446 }
8447 
8448 /********************************************************************
8449  * Function:
8450  *
8451  * Purpose:
8452  *
8453  * Arguments:
8454  *
8455  * Returns:
8456  *
8457  ********************************************************************/
DCE2_SmbUidTidFidCompare(const void * a,const void * b)8458 static int DCE2_SmbUidTidFidCompare(const void *a, const void *b)
8459 {
8460     int x = (int)(uintptr_t)a;
8461     int y = (int)(uintptr_t)b;
8462 
8463     if (x == y)
8464         return 0;
8465 
8466     /* Only care about equality for finding */
8467     return -1;
8468 }
8469 
8470 /********************************************************************
8471  * Function:
8472  *
8473  * Purpose:
8474  *
8475  * Arguments:
8476  *
8477  * Returns:
8478  *
8479  ********************************************************************/
DCE2_SmbDataFree(DCE2_SmbSsnData * ssd)8480 void DCE2_SmbDataFree(DCE2_SmbSsnData *ssd)
8481 {
8482     if (ssd == NULL)
8483         return;
8484 
8485     // XXX This tries to account for the situation where we never knew the file
8486     // size and the TCP session was shutdown before an SMB_COM_CLOSE on the file.
8487     // Possibly need to add callback to fileAPI since it may have already
8488     // released it's resources.
8489     //DCE2_SmbFinishFileAPI(ssd);
8490 
8491     if (ssd->uids != NULL)
8492     {
8493         DCE2_ListDestroy(ssd->uids);
8494         ssd->uids = NULL;
8495     }
8496 
8497     if (ssd->tids != NULL)
8498     {
8499         DCE2_ListDestroy(ssd->tids);
8500         ssd->tids = NULL;
8501     }
8502 
8503     DCE2_SmbCleanFileTracker(&ssd->ftracker);
8504     if (ssd->ftrackers != NULL)
8505     {
8506         DCE2_ListDestroy(ssd->ftrackers);
8507         ssd->ftrackers = NULL;
8508     }
8509 
8510     DCE2_SmbCleanRequestTracker(&ssd->rtracker);
8511     if (ssd->rtrackers != NULL)
8512     {
8513         DCE2_QueueDestroy(ssd->rtrackers);
8514         ssd->rtrackers = NULL;
8515     }
8516 
8517     if (ssd->cli_seg != NULL)
8518     {
8519         DCE2_BufferDestroy(ssd->cli_seg);
8520         ssd->cli_seg = NULL;
8521     }
8522 
8523     if (ssd->srv_seg != NULL)
8524     {
8525         DCE2_BufferDestroy(ssd->srv_seg);
8526         ssd->srv_seg = NULL;
8527     }
8528 
8529     if (ssd->smb2_requests != NULL)
8530     {
8531         DCE2_Smb2CleanRequests(ssd->smb2_requests);
8532         ssd->smb2_requests = NULL;
8533     }
8534 }
8535 
8536 /********************************************************************
8537  * Function:
8538  *
8539  * Purpose:
8540  *
8541  * Arguments:
8542  *
8543  * Returns:
8544  *
8545  ********************************************************************/
DCE2_SmbSsnFree(void * ssn)8546 void DCE2_SmbSsnFree(void *ssn)
8547 {
8548     DCE2_SmbSsnData *ssd = (DCE2_SmbSsnData *)ssn;
8549 
8550     if (ssd == NULL)
8551         return;
8552 
8553     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Removing Session: %p\n", ssd));
8554 
8555     DCE2_SmbDataFree(ssd);
8556     DCE2_Free((void *)ssn, sizeof(DCE2_SmbSsnData), DCE2_MEM_TYPE__SMB_SSN);
8557 }
8558 
8559 /********************************************************************
8560  * Function:
8561  *
8562  * Purpose:
8563  *
8564  * Arguments:
8565  *
8566  * Returns:
8567  *
8568  ********************************************************************/
DCE2_SmbFileTrackerDataFree(void * data)8569 static void DCE2_SmbFileTrackerDataFree(void *data)
8570 {
8571     DCE2_SmbFileTracker *ftracker = (DCE2_SmbFileTracker *)data;
8572 
8573     if (ftracker == NULL)
8574         return;
8575 
8576     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Freeing file tracker: "
8577                 "Uid: %u, Tid: %u, Fid: 0x%04X\n",
8578                 ftracker->uid_v1, ftracker->tid_v1, ftracker->fid_v1));
8579 
8580     DCE2_SmbCleanFileTracker(ftracker);
8581     DCE2_Free((void *)ftracker, sizeof(DCE2_SmbFileTracker), DCE2_MEM_TYPE__SMB_FID);
8582 }
8583 
8584 /********************************************************************
8585  * Function:
8586  *
8587  * Purpose:
8588  *
8589  * Arguments:
8590  *
8591  * Returns:
8592  *
8593  ********************************************************************/
DCE2_SmbRequestTrackerDataFree(void * data)8594 static void DCE2_SmbRequestTrackerDataFree(void *data)
8595 {
8596     DCE2_SmbRequestTracker *rtracker = (DCE2_SmbRequestTracker *)data;
8597 
8598     if (rtracker == NULL)
8599         return;
8600 
8601     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Freeing request tracker: "
8602                 "Uid: %u, Tid: %u, Pid: %u, Mid: %u\n",
8603                 rtracker->uid, rtracker->tid, rtracker->pid, rtracker->mid));
8604 
8605     DCE2_SmbCleanRequestTracker(rtracker);
8606     DCE2_Free((void *)rtracker, sizeof(DCE2_SmbRequestTracker), DCE2_MEM_TYPE__SMB_REQ);
8607 }
8608 
8609 /********************************************************************
8610  * Function:
8611  *
8612  * Purpose:
8613  *
8614  * Arguments:
8615  *
8616  * Returns:
8617  *
8618  ********************************************************************/
DCE2_SmbGetRpkt(DCE2_SmbSsnData * ssd,const uint8_t ** data,uint32_t * data_len,DCE2_RpktType rtype)8619 static inline SFSnortPacket * DCE2_SmbGetRpkt(DCE2_SmbSsnData *ssd,
8620         const uint8_t **data, uint32_t *data_len, DCE2_RpktType rtype)
8621 {
8622     SFSnortPacket *rpkt;
8623     uint16_t header_len;
8624 
8625     if ((ssd == NULL) || (data == NULL) || (*data == NULL)
8626             || (data_len == NULL) || (*data_len == 0))
8627         return NULL;
8628 
8629     rpkt = DCE2_GetRpkt(ssd->sd.wire_pkt, rtype, *data, *data_len);
8630 
8631     if (rpkt == NULL)
8632     {
8633         DCE2_Log(DCE2_LOG_TYPE__ERROR,
8634                 "%s(%d) Failed to create reassembly packet.",
8635                 __FILE__, __LINE__);
8636 
8637         return NULL;
8638     }
8639 
8640     if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS)
8641     {
8642         DCE2_Log(DCE2_LOG_TYPE__ERROR,
8643                 "%s(%d) Failed to push packet onto packet stack.",
8644                 __FILE__, __LINE__);
8645         return NULL;
8646     }
8647 
8648     *data = rpkt->payload;
8649     *data_len = rpkt->payload_size;
8650 
8651     switch (rtype)
8652     {
8653         case DCE2_RPKT_TYPE__SMB_TRANS:
8654             if (DCE2_SmbType(ssd) == SMB_TYPE__REQUEST)
8655                 header_len = DCE2_MOCK_HDR_LEN__SMB_CLI;
8656             else
8657                 header_len = DCE2_MOCK_HDR_LEN__SMB_SRV;
8658             DCE2_SmbSetRdata(ssd, (uint8_t *)rpkt->payload,
8659                     (uint16_t)(rpkt->payload_size - header_len));
8660             DCE2_MOVE(*data, *data_len, header_len);
8661             break;
8662         case DCE2_RPKT_TYPE__SMB_SEG:
8663         default:
8664             break;
8665     }
8666 
8667     return rpkt;
8668 }
8669 
8670 /********************************************************************
8671  * Function:
8672  *
8673  * Purpose:
8674  *
8675  * Arguments:
8676  *
8677  * Returns:
8678  *
8679  ********************************************************************/
DCE2_SmbReturnRpkt(void)8680 static inline void DCE2_SmbReturnRpkt(void)
8681 {
8682     DCE2_PopPkt();
8683 }
8684 
8685 #define DCE2_SMB_TRANS__NONE    0x00
8686 #define DCE2_SMB_TRANS__DATA    0x01
8687 #define DCE2_SMB_TRANS__PARAMS  0x02
8688 #define DCE2_SMB_TRANS__BOTH    (DCE2_SMB_TRANS__DATA|DCE2_SMB_TRANS__PARAMS)
8689 
8690 /********************************************************************
8691  * Function: DCE2_SmbUpdateTransRequest()
8692  *
8693  * Purpose:
8694  *  Handles common checks and updates of transaction requests -
8695  *  SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT
8696  *
8697  * Arguments:
8698  *  DCE2_SmbSsnData *       - pointer to SMB session data
8699  *  const SmbNtHdr *        - pointer to SMB header
8700  *  const DCE2_SmbComInfo * - pointer to com info structure
8701  *  const uint8_t *         - pointer to data
8702  *  uint32_t                - data length
8703  *
8704  * Returns:
8705  *  DCE2_Ret
8706  *      DCE2_RET__IGNORE if we don't process the subcommand
8707  *      DCE2_RET__FULL if the transaction is complete
8708  *      DCE2_RET__ERROR if an error occurred.
8709  *      DCE2_RET__SUCCESS if ok (but not complete).
8710  *
8711  ********************************************************************/
DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)8712 static DCE2_Ret DCE2_SmbUpdateTransRequest(DCE2_SmbSsnData *ssd,
8713         const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info,
8714         const uint8_t *nb_ptr, uint32_t nb_len)
8715 {
8716     uint32_t tpcnt, pcnt, poff;
8717     uint32_t tdcnt, dcnt, doff;
8718     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
8719     uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
8720     uint16_t fid;
8721     uint8_t setup_count;
8722     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
8723     uint16_t sub_com;
8724     int data_params = DCE2_SMB_TRANS__NONE;
8725     uint8_t smb_com = DCE2_ComInfoSmbCom(com_info);
8726 
8727     switch (smb_com)
8728     {
8729         case SMB_COM_TRANSACTION:
8730             sub_com = SmbTransactionReqSubCom((SmbTransactionReq *)nb_ptr);
8731             fid = SmbTransactionReqFid((SmbTransactionReq *)nb_ptr);
8732             setup_count = SmbTransactionReqSetupCnt((SmbTransactionReq *)nb_ptr);
8733             tdcnt = SmbTransactionReqTotalDataCnt((SmbTransactionReq *)nb_ptr);
8734             doff = SmbTransactionReqDataOff((SmbTransactionReq *)nb_ptr);
8735             dcnt = SmbTransactionReqDataCnt((SmbTransactionReq *)nb_ptr);
8736             tpcnt = SmbTransactionReqTotalParamCnt((SmbTransactionReq *)nb_ptr);
8737             pcnt = SmbTransactionReqParamCnt((SmbTransactionReq *)nb_ptr);
8738             poff = SmbTransactionReqParamOff((SmbTransactionReq *)nb_ptr);
8739 
8740             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
8741                         "Transaction subcommand: %s (0x%04X)\n",
8742                         (sub_com < TRANS_SUBCOM_MAX)
8743                         ? smb_transaction_sub_command_strings[sub_com]
8744                         : "Unknown", sub_com));
8745 
8746             if (sub_com < TRANS_SUBCOM_MAX)
8747                 dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][sub_com]++;
8748             else
8749                 dce2_stats.smb_trans_subcom_stats[SMB_TYPE__REQUEST][TRANS_SUBCOM_MAX]++;
8750 
8751             ssd->cur_rtracker->ftracker = DCE2_SmbGetFileTracker(ssd, fid);
8752             if (ssd->cur_rtracker->ftracker == NULL)
8753                 return DCE2_RET__IGNORE;
8754 
8755             switch (sub_com)
8756             {
8757                 case TRANS_TRANSACT_NMPIPE:
8758                     if (DCE2_SsnIsWindowsPolicy(&ssd->sd)
8759                             && ssd->cur_rtracker->ftracker->fp_byte_mode)
8760                     {
8761                         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Pipe is in byte "
8762                                     "mode - TRANS_TRANSACT_NMPIPE won't work\n"));
8763                         return DCE2_RET__ERROR;
8764                     }
8765                     data_params = DCE2_SMB_TRANS__DATA;
8766                     break;
8767 
8768                 case TRANS_READ_NMPIPE:
8769                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
8770                             smb_transaction_sub_command_strings[sub_com]);
8771                     break;
8772 
8773                 case TRANS_SET_NMPIPE_STATE:
8774                     data_params = DCE2_SMB_TRANS__PARAMS;
8775                     break;
8776 
8777                 case TRANS_WRITE_NMPIPE:
8778                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
8779                             smb_transaction_sub_command_strings[sub_com]);
8780                     data_params = DCE2_SMB_TRANS__DATA;
8781                     break;
8782 
8783                 // Not implemented according to MS-CIFS
8784                 case TRANS_RAW_READ_NMPIPE:
8785 
8786                 // Can only write 2 NULL bytes and subsequent writes return pipe disconnected
8787                 case TRANS_RAW_WRITE_NMPIPE:
8788 
8789                 // Can at most do a DCE/RPC bind
8790                 case TRANS_CALL_NMPIPE:
8791                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_DEPR_COMMAND_USED,
8792                             smb_transaction_sub_command_strings[sub_com]);
8793 
8794                 // Aren't looking at these or the three above
8795                 case TRANS_QUERY_NMPIPE_STATE:
8796                 case TRANS_QUERY_NMPIPE_INFO:
8797                 case TRANS_PEEK_NMPIPE:
8798                 case TRANS_WAIT_NMPIPE:
8799                 default:
8800                     // Don't want to track the response
8801                     return DCE2_RET__IGNORE;
8802             }
8803 
8804             // Servers return error if incorrect setup count
8805             if (setup_count != 2)
8806             {
8807                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT,
8808                         smb_com_strings[SMB_COM_TRANSACTION],
8809                         smb_transaction_sub_command_strings[sub_com],
8810                         setup_count);
8811                 return DCE2_RET__ERROR;
8812             }
8813 
8814             DCE2_MOVE(nb_ptr, nb_len, com_size);
8815 
8816             // Samba validates the Name which should be \PIPE\ and errors
8817             // if not.  Windows doesn't care.
8818             // And Samba uses the ByteCount to validate
8819             if (DCE2_SsnIsSambaPolicy(&ssd->sd)
8820                     && (DCE2_SmbTransactionGetName(nb_ptr, nb_len,
8821                             byte_count, SmbUnicode(smb_hdr)) != DCE2_RET__SUCCESS))
8822             {
8823                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Failed to validate "
8824                             "pipe name for Samba.\n"));
8825                 return DCE2_RET__ERROR;
8826             }
8827             break;
8828 
8829         case SMB_COM_TRANSACTION2:
8830             sub_com = SmbTransaction2ReqSubCom((SmbTransaction2Req *)nb_ptr);
8831             setup_count = SmbTransaction2ReqSetupCnt((SmbTransaction2Req *)nb_ptr);
8832             tdcnt = SmbTransaction2ReqTotalDataCnt((SmbTransaction2Req *)nb_ptr);
8833             doff = SmbTransaction2ReqDataOff((SmbTransaction2Req *)nb_ptr);
8834             dcnt = SmbTransaction2ReqDataCnt((SmbTransaction2Req *)nb_ptr);
8835             tpcnt = SmbTransaction2ReqTotalParamCnt((SmbTransaction2Req *)nb_ptr);
8836             pcnt = SmbTransaction2ReqParamCnt((SmbTransaction2Req *)nb_ptr);
8837             poff = SmbTransaction2ReqParamOff((SmbTransaction2Req *)nb_ptr);
8838 
8839             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
8840                         "Transaction2 subcommand: %s (0x%04X)\n",
8841                         (sub_com < TRANS2_SUBCOM_MAX)
8842                         ? smb_transaction2_sub_command_strings[sub_com]
8843                         : "Unknown", sub_com));
8844 
8845             if (sub_com < TRANS2_SUBCOM_MAX)
8846                 dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][sub_com]++;
8847             else
8848                 dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__REQUEST][TRANS2_SUBCOM_MAX]++;
8849 
8850             switch (sub_com)
8851             {
8852                 case TRANS2_OPEN2:
8853                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
8854                             smb_transaction2_sub_command_strings[sub_com]);
8855                     data_params = DCE2_SMB_TRANS__PARAMS;
8856                     break;
8857                 case TRANS2_QUERY_FILE_INFORMATION:
8858                     data_params = DCE2_SMB_TRANS__PARAMS;
8859                     break;
8860                 case TRANS2_SET_FILE_INFORMATION:
8861                     data_params = DCE2_SMB_TRANS__BOTH;
8862                     break;
8863                 case TRANS2_FIND_FIRST2:
8864                 case TRANS2_FIND_NEXT2:
8865                 case TRANS2_QUERY_FS_INFORMATION:
8866                 case TRANS2_SET_FS_INFORMATION:
8867                 case TRANS2_QUERY_PATH_INFORMATION:
8868                 case TRANS2_SET_PATH_INFORMATION:
8869                 case TRANS2_FSCTL:
8870                 case TRANS2_IOCTL2:
8871                 case TRANS2_FIND_NOTIFY_FIRST:
8872                 case TRANS2_FIND_NOTIFY_NEXT:
8873                 case TRANS2_CREATE_DIRECTORY:
8874                 case TRANS2_SESSION_SETUP:
8875                 case TRANS2_GET_DFS_REFERRAL:
8876                 case TRANS2_REPORT_DFS_INCONSISTENCY:
8877                 default:
8878                     // Don't want to process this transaction any more
8879                     return DCE2_RET__IGNORE;
8880             }
8881 
8882             if (setup_count != 1)
8883             {
8884                 DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT,
8885                         smb_com_strings[SMB_COM_TRANSACTION2],
8886                         smb_transaction2_sub_command_strings[sub_com],
8887                         setup_count);
8888                 return DCE2_RET__ERROR;
8889             }
8890 
8891             DCE2_MOVE(nb_ptr, nb_len, com_size);
8892 
8893             break;
8894 
8895         case SMB_COM_NT_TRANSACT:
8896             sub_com = SmbNtTransactReqSubCom((SmbNtTransactReq *)nb_ptr);
8897             setup_count = SmbNtTransactReqSetupCnt((SmbNtTransactReq *)nb_ptr);
8898             tdcnt = SmbNtTransactReqTotalDataCnt((SmbNtTransactReq *)nb_ptr);
8899             doff = SmbNtTransactReqDataOff((SmbNtTransactReq *)nb_ptr);
8900             dcnt = SmbNtTransactReqDataCnt((SmbNtTransactReq *)nb_ptr);
8901             tpcnt = SmbNtTransactReqTotalParamCnt((SmbNtTransactReq *)nb_ptr);
8902             pcnt = SmbNtTransactReqParamCnt((SmbNtTransactReq *)nb_ptr);
8903             poff = SmbNtTransactReqParamOff((SmbNtTransactReq *)nb_ptr);
8904 
8905             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
8906                         "Nt Transact subcommand: %s (0x%04X)\n",
8907                         (sub_com < NT_TRANSACT_SUBCOM_MAX)
8908                         ? smb_nt_transact_sub_command_strings[sub_com]
8909                         : "Unknown", sub_com));
8910 
8911             if (sub_com < NT_TRANSACT_SUBCOM_MAX)
8912                 dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][sub_com]++;
8913             else
8914                 dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__REQUEST][NT_TRANSACT_SUBCOM_MAX]++;
8915 
8916             switch (sub_com)
8917             {
8918                 case NT_TRANSACT_CREATE:
8919                     DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_UNUSUAL_COMMAND_USED,
8920                             smb_nt_transact_sub_command_strings[sub_com]);
8921                     if (setup_count != 0)
8922                     {
8923                         DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_INVALID_SETUP_COUNT,
8924                                 smb_com_strings[SMB_COM_NT_TRANSACT],
8925                                 smb_nt_transact_sub_command_strings[sub_com],
8926                                 setup_count);
8927                         return DCE2_RET__ERROR;
8928                     }
8929                     data_params = DCE2_SMB_TRANS__PARAMS;
8930                     break;
8931                 case NT_TRANSACT_IOCTL:
8932                 case NT_TRANSACT_SET_SECURITY_DESC:
8933                 case NT_TRANSACT_NOTIFY_CHANGE:
8934                 case NT_TRANSACT_RENAME:
8935                 case NT_TRANSACT_QUERY_SECURITY_DESC:
8936                 default:
8937                     // Don't want to process this transaction any more
8938                     return DCE2_RET__IGNORE;
8939             }
8940 
8941             DCE2_MOVE(nb_ptr, nb_len, com_size);
8942 
8943             break;
8944 
8945         default:
8946             return DCE2_RET__ERROR;
8947     }
8948 
8949     if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
8950                 byte_count, tdcnt, tpcnt, dcnt, doff, 0, pcnt, poff, 0) != DCE2_RET__SUCCESS)
8951         return DCE2_RET__ERROR;
8952 
8953     ttracker->smb_type = SMB_TYPE__REQUEST;
8954     ttracker->subcom = (uint8_t)sub_com;
8955     ttracker->tdcnt = tdcnt;
8956     ttracker->dsent = dcnt;
8957     ttracker->tpcnt = tpcnt;
8958     ttracker->psent = pcnt;
8959 
8960     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data count: %u, "
8961                 "Total data count: %u, Param count: %u, "
8962                 "Total param count: %u\n", dcnt, tdcnt, pcnt, tpcnt));
8963 
8964     // Testing shows that Transacts aren't processed until
8965     // all of the data and parameters are received, so overlapping
8966     // writes to the same FID can occur as long as the pid/mid are
8967     // distinct (and that depends on policy).  So we need to buffer
8968     // data up for each incomplete Transact so data doesn't get mangled
8969     // together with multiple ones intermixing at the same time.
8970 
8971     if (data_params & DCE2_SMB_TRANS__DATA)
8972     {
8973         if (tdcnt == 0)
8974             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_ZERO);
8975 
8976         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
8977 
8978         // If all of the data and parameters weren't sent, buffer what was sent
8979         if (((dcnt != tdcnt) || (pcnt != tpcnt)) && (dcnt != 0)
8980                 && (DCE2_SmbBufferTransactionData(ttracker,
8981                         nb_ptr, dcnt, 0) != DCE2_RET__SUCCESS))
8982         {
8983             return DCE2_RET__ERROR;
8984         }
8985     }
8986 
8987     if (data_params & DCE2_SMB_TRANS__PARAMS)
8988     {
8989         if (tpcnt == 0)
8990             DCE2_Alert(&ssd->sd, DCE2_EVENT__SMB_TDCNT_ZERO);
8991 
8992         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
8993 
8994         // If all of the data and parameters weren't sent, buffer what was sent
8995         if (((pcnt != tpcnt) || (dcnt != tdcnt)) && (pcnt != 0)
8996                 && (DCE2_SmbBufferTransactionParameters(ttracker,
8997                         nb_ptr, pcnt, 0) != DCE2_RET__SUCCESS))
8998         {
8999             return DCE2_RET__ERROR;
9000         }
9001     }
9002 
9003     if ((dcnt == tdcnt) && (pcnt == tpcnt))
9004         return DCE2_RET__FULL;
9005 
9006     return DCE2_RET__SUCCESS;
9007 }
9008 
9009 /********************************************************************
9010  * Function: DCE2_SmbUpdateTransSecondary()
9011  *
9012  * Purpose:
9013  *  Handles common checks and updates of transaction secondary
9014  *  requests - SMB_COM_TRANSACTION_SECONDARY,
9015  *  SMB_COM_TRANSACTION2_SECONDARY and
9016  *  SMB_COM_NT_TRANSACT_SECONDARY
9017  *
9018  * Arguments:
9019  *  DCE2_SmbSsnData *       - pointer to SMB session data
9020  *  const SmbNtHdr *        - pointer to SMB header
9021  *  const DCE2_SmbComInfo * - pointer to com info structure
9022  *  const uint8_t *         - pointer to data
9023  *  uint32_t                - data length
9024  *
9025  * Returns:
9026  *  DCE2_Ret
9027  *      DCE2_RET__IGNORE if we don't process the subcommand
9028  *      DCE2_RET__FULL if the transaction is complete
9029  *      DCE2_RET__ERROR if an error occurred.
9030  *      DCE2_RET__SUCCESS if ok (but not complete).
9031  *
9032  ********************************************************************/
DCE2_SmbUpdateTransSecondary(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)9033 static DCE2_Ret DCE2_SmbUpdateTransSecondary(DCE2_SmbSsnData *ssd,
9034         const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info,
9035         const uint8_t *nb_ptr, uint32_t nb_len)
9036 {
9037     uint16_t com_size = DCE2_ComInfoCommandSize(com_info);
9038     uint16_t byte_count = DCE2_ComInfoByteCount(com_info);
9039     uint32_t tdcnt, doff, dcnt, ddisp;
9040     uint32_t tpcnt, poff, pcnt, pdisp;
9041     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
9042     uint16_t sub_com = ttracker->subcom;
9043     int data_params = DCE2_SMB_TRANS__NONE;
9044     uint8_t smb_com = DCE2_ComInfoSmbCom(com_info);
9045 
9046     switch (smb_com)
9047     {
9048         case SMB_COM_TRANSACTION_SECONDARY:
9049             tdcnt = SmbTransactionSecondaryReqTotalDataCnt((SmbTransactionSecondaryReq *)nb_ptr);
9050             doff = SmbTransactionSecondaryReqDataOff((SmbTransactionSecondaryReq *)nb_ptr);
9051             dcnt = SmbTransactionSecondaryReqDataCnt((SmbTransactionSecondaryReq *)nb_ptr);
9052             ddisp = SmbTransactionSecondaryReqDataDisp((SmbTransactionSecondaryReq *)nb_ptr);
9053             tpcnt = SmbTransactionSecondaryReqTotalParamCnt((SmbTransactionSecondaryReq *)nb_ptr);
9054             poff = SmbTransactionSecondaryReqParamOff((SmbTransactionSecondaryReq *)nb_ptr);
9055             pcnt = SmbTransactionSecondaryReqParamCnt((SmbTransactionSecondaryReq *)nb_ptr);
9056             pdisp = SmbTransactionSecondaryReqParamDisp((SmbTransactionSecondaryReq *)nb_ptr);
9057 
9058             switch (sub_com)
9059             {
9060                 case TRANS_TRANSACT_NMPIPE:
9061                 case TRANS_WRITE_NMPIPE:
9062                     data_params = DCE2_SMB_TRANS__DATA;
9063                     break;
9064                 case TRANS_SET_NMPIPE_STATE:
9065                     data_params = DCE2_SMB_TRANS__PARAMS;
9066                     break;
9067                 default:
9068                     return DCE2_RET__IGNORE;
9069             }
9070             break;
9071 
9072         case SMB_COM_TRANSACTION2_SECONDARY:
9073             tdcnt = SmbTransaction2SecondaryReqTotalDataCnt((SmbTransaction2SecondaryReq *)nb_ptr);
9074             doff = SmbTransaction2SecondaryReqDataOff((SmbTransaction2SecondaryReq *)nb_ptr);
9075             dcnt = SmbTransaction2SecondaryReqDataCnt((SmbTransaction2SecondaryReq *)nb_ptr);
9076             ddisp = SmbTransaction2SecondaryReqDataDisp((SmbTransaction2SecondaryReq *)nb_ptr);
9077             tpcnt = SmbTransaction2SecondaryReqTotalParamCnt((SmbTransaction2SecondaryReq *)nb_ptr);
9078             poff = SmbTransaction2SecondaryReqParamOff((SmbTransaction2SecondaryReq *)nb_ptr);
9079             pcnt = SmbTransaction2SecondaryReqParamCnt((SmbTransaction2SecondaryReq *)nb_ptr);
9080             pdisp = SmbTransaction2SecondaryReqParamDisp((SmbTransaction2SecondaryReq *)nb_ptr);
9081 
9082             switch (sub_com)
9083             {
9084                 case TRANS2_OPEN2:
9085                 case TRANS2_QUERY_FILE_INFORMATION:
9086                     data_params = DCE2_SMB_TRANS__PARAMS;
9087                     break;
9088                 case TRANS2_SET_FILE_INFORMATION:
9089                     data_params = DCE2_SMB_TRANS__BOTH;
9090                     break;
9091                 default:
9092                     return DCE2_RET__IGNORE;
9093             }
9094             break;
9095 
9096         case SMB_COM_NT_TRANSACT_SECONDARY:
9097             tdcnt = SmbNtTransactSecondaryReqTotalDataCnt((SmbNtTransactSecondaryReq *)nb_ptr);
9098             doff = SmbNtTransactSecondaryReqDataOff((SmbNtTransactSecondaryReq *)nb_ptr);
9099             dcnt = SmbNtTransactSecondaryReqDataCnt((SmbNtTransactSecondaryReq *)nb_ptr);
9100             ddisp = SmbNtTransactSecondaryReqDataDisp((SmbNtTransactSecondaryReq *)nb_ptr);
9101             tpcnt = SmbNtTransactSecondaryReqTotalParamCnt((SmbNtTransactSecondaryReq *)nb_ptr);
9102             poff = SmbNtTransactSecondaryReqParamOff((SmbNtTransactSecondaryReq *)nb_ptr);
9103             pcnt = SmbNtTransactSecondaryReqParamCnt((SmbNtTransactSecondaryReq *)nb_ptr);
9104             pdisp = SmbNtTransactSecondaryReqParamDisp((SmbNtTransactSecondaryReq *)nb_ptr);
9105 
9106             switch (sub_com)
9107             {
9108                 case NT_TRANSACT_CREATE:
9109                     data_params = DCE2_SMB_TRANS__PARAMS;
9110                     break;
9111                 default:
9112                     return DCE2_RET__IGNORE;
9113             }
9114             break;
9115 
9116         default:
9117             return DCE2_RET__ERROR;
9118     }
9119 
9120     if (DCE2_SsnIsSambaPolicy(&ssd->sd))
9121     {
9122         // If the total count decreases, Samba will reset this to the new
9123         // total count.
9124         if (tdcnt < ttracker->tdcnt)
9125             ttracker->tdcnt = tdcnt;
9126         if (tpcnt < ttracker->tpcnt)
9127             ttracker->tpcnt = tpcnt;
9128     }
9129     else
9130     {
9131         // Windows always uses the total data count from the first transaction.
9132         tdcnt = (uint16_t)ttracker->tdcnt;
9133         tpcnt = (uint16_t)ttracker->tpcnt;
9134     }
9135 
9136     DCE2_MOVE(nb_ptr, nb_len, com_size);
9137 
9138     if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
9139                 byte_count, tdcnt, tpcnt, dcnt, doff, ddisp, pcnt, poff, pdisp) != DCE2_RET__SUCCESS)
9140         return DCE2_RET__ERROR;
9141 
9142     if (DCE2_SmbValidateTransactionSent(ssd, ttracker->dsent, dcnt, ttracker->tdcnt,
9143                 ttracker->psent, pcnt, ttracker->tpcnt) != DCE2_RET__SUCCESS)
9144         return DCE2_RET__IGNORE;
9145 
9146     ttracker->dsent += dcnt;
9147     ttracker->psent += pcnt;
9148 
9149     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data displacement: %u, "
9150                 "Data count: %u, Total data count: %u\n"
9151                 "Parameter displacement: %u, "
9152                 "Parameter count: %u, Total parameter count: %u\n",
9153                 ddisp, dcnt, tdcnt, pdisp, pcnt, tpcnt));
9154 
9155     if (data_params & DCE2_SMB_TRANS__DATA)
9156     {
9157         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
9158 
9159         if ((dcnt != 0)
9160                 && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
9161                     != DCE2_RET__SUCCESS))
9162         {
9163             return DCE2_RET__ERROR;
9164         }
9165     }
9166 
9167     if (data_params & DCE2_SMB_TRANS__PARAMS)
9168     {
9169         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
9170 
9171         if ((pcnt != 0)
9172                 && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
9173                     != DCE2_RET__SUCCESS))
9174         {
9175             return DCE2_RET__ERROR;
9176         }
9177     }
9178 
9179     if ((ttracker->dsent == ttracker->tdcnt)
9180             && (ttracker->psent == ttracker->tpcnt))
9181     {
9182         return DCE2_RET__FULL;
9183     }
9184 
9185     return DCE2_RET__SUCCESS;
9186 }
9187 
9188 /********************************************************************
9189  * Function: DCE2_SmbUpdateTransResponse()
9190  *
9191  * Purpose:
9192  *  Handles common checks and updates of transaction responses -
9193  *  SMB_COM_TRANSACTION, SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT
9194  *
9195  * Arguments:
9196  *  DCE2_SmbSsnData *       - pointer to SMB session data
9197  *  const SmbNtHdr *        - pointer to SMB header
9198  *  const DCE2_SmbComInfo * - pointer to com info structure
9199  *  const uint8_t *         - pointer to data
9200  *  uint32_t                - data length
9201  *
9202  * Returns:
9203  *  DCE2_Ret
9204  *      DCE2_RET__FULL if the transaction is complete
9205  *      DCE2_RET__ERROR if an error occurred.
9206  *      DCE2_RET__SUCCESS if ok (but not complete).
9207  *
9208  ********************************************************************/
DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData * ssd,const SmbNtHdr * smb_hdr,const DCE2_SmbComInfo * com_info,const uint8_t * nb_ptr,uint32_t nb_len)9209 static DCE2_Ret DCE2_SmbUpdateTransResponse(DCE2_SmbSsnData *ssd,
9210         const SmbNtHdr *smb_hdr, const DCE2_SmbComInfo *com_info,
9211         const uint8_t *nb_ptr, uint32_t nb_len)
9212 {
9213     uint32_t tpcnt, pcnt, poff, pdisp;
9214     uint32_t tdcnt, dcnt, doff, ddisp;
9215     DCE2_SmbTransactionTracker *ttracker = &ssd->cur_rtracker->ttracker;
9216     uint16_t sub_com = ttracker->subcom;
9217     int data_params = DCE2_SMB_TRANS__NONE;
9218     uint8_t smb_com = DCE2_ComInfoSmbCom(com_info);
9219 
9220     switch (smb_com)
9221     {
9222         case SMB_COM_TRANSACTION:
9223             tdcnt = SmbTransactionRespTotalDataCnt((SmbTransactionResp *)nb_ptr);
9224             doff = SmbTransactionRespDataOff((SmbTransactionResp *)nb_ptr);
9225             dcnt = SmbTransactionRespDataCnt((SmbTransactionResp *)nb_ptr);
9226             ddisp = SmbTransactionRespDataDisp((SmbTransactionResp *)nb_ptr);
9227             tpcnt = SmbTransactionRespTotalParamCnt((SmbTransactionResp *)nb_ptr);
9228             pcnt = SmbTransactionRespParamCnt((SmbTransactionResp *)nb_ptr);
9229             poff = SmbTransactionRespParamOff((SmbTransactionResp *)nb_ptr);
9230             pdisp = SmbTransactionRespParamDisp((SmbTransactionResp *)nb_ptr);
9231 
9232             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
9233                         "Transaction subcommand: %s (0x%04X)\n",
9234                         (sub_com < TRANS_SUBCOM_MAX)
9235                         ? smb_transaction_sub_command_strings[sub_com]
9236                         : "Unknown", sub_com));
9237 
9238             if (sub_com < TRANS_SUBCOM_MAX)
9239                 dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++;
9240             else
9241                 dce2_stats.smb_trans_subcom_stats[SMB_TYPE__RESPONSE][TRANS_SUBCOM_MAX]++;
9242 
9243             switch (sub_com)
9244             {
9245                 case TRANS_TRANSACT_NMPIPE:
9246                 case TRANS_READ_NMPIPE:
9247                     data_params = DCE2_SMB_TRANS__DATA;
9248                     break;
9249                 case TRANS_SET_NMPIPE_STATE:
9250                 case TRANS_WRITE_NMPIPE:
9251                     data_params = DCE2_SMB_TRANS__PARAMS;
9252                     break;
9253                 default:
9254                     return DCE2_RET__ERROR;
9255             }
9256 
9257             break;
9258 
9259         case SMB_COM_TRANSACTION2:
9260             tpcnt = SmbTransaction2RespTotalParamCnt((SmbTransaction2Resp *)nb_ptr);
9261             pcnt = SmbTransaction2RespParamCnt((SmbTransaction2Resp *)nb_ptr);
9262             poff = SmbTransaction2RespParamOff((SmbTransaction2Resp *)nb_ptr);
9263             pdisp = SmbTransaction2RespParamDisp((SmbTransaction2Resp *)nb_ptr);
9264             tdcnt = SmbTransaction2RespTotalDataCnt((SmbTransaction2Resp *)nb_ptr);
9265             dcnt = SmbTransaction2RespDataCnt((SmbTransaction2Resp *)nb_ptr);
9266             doff = SmbTransaction2RespDataOff((SmbTransaction2Resp *)nb_ptr);
9267             ddisp = SmbTransaction2RespDataDisp((SmbTransaction2Resp *)nb_ptr);
9268 
9269             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
9270                         "Transaction2 subcommand: %s (0x%04X)\n",
9271                         (sub_com < TRANS2_SUBCOM_MAX)
9272                         ? smb_transaction2_sub_command_strings[sub_com]
9273                         : "Unknown", sub_com));
9274 
9275             if (sub_com < TRANS2_SUBCOM_MAX)
9276                 dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++;
9277             else
9278                 dce2_stats.smb_trans2_subcom_stats[SMB_TYPE__RESPONSE][TRANS2_SUBCOM_MAX]++;
9279 
9280             switch (sub_com)
9281             {
9282                 case TRANS2_OPEN2:
9283                 case TRANS2_SET_FILE_INFORMATION:
9284                     data_params = DCE2_SMB_TRANS__PARAMS;
9285                     break;
9286                 case TRANS2_QUERY_FILE_INFORMATION:
9287                     data_params = DCE2_SMB_TRANS__DATA;
9288                     break;
9289                 default:
9290                     return DCE2_RET__ERROR;
9291             }
9292 
9293             break;
9294 
9295         case SMB_COM_NT_TRANSACT:
9296             tpcnt = SmbNtTransactRespTotalParamCnt((SmbNtTransactResp *)nb_ptr);
9297             pcnt = SmbNtTransactRespParamCnt((SmbNtTransactResp *)nb_ptr);
9298             poff = SmbNtTransactRespParamOff((SmbNtTransactResp *)nb_ptr);
9299             pdisp = SmbNtTransactRespParamDisp((SmbNtTransactResp *)nb_ptr);
9300             tdcnt = SmbNtTransactRespTotalDataCnt((SmbNtTransactResp *)nb_ptr);
9301             dcnt = SmbNtTransactRespDataCnt((SmbNtTransactResp *)nb_ptr);
9302             doff = SmbNtTransactRespDataOff((SmbNtTransactResp *)nb_ptr);
9303             ddisp = SmbNtTransactRespDataDisp((SmbNtTransactResp *)nb_ptr);
9304 
9305             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
9306                         "Nt Transact subcommand: %s (0x%04X)\n",
9307                         (sub_com < NT_TRANSACT_SUBCOM_MAX)
9308                         ? smb_nt_transact_sub_command_strings[sub_com]
9309                         : "Unknown", sub_com));
9310 
9311             if (sub_com < NT_TRANSACT_SUBCOM_MAX)
9312                 dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][sub_com]++;
9313             else
9314                 dce2_stats.smb_nt_transact_subcom_stats[SMB_TYPE__RESPONSE][NT_TRANSACT_SUBCOM_MAX]++;
9315 
9316             switch (sub_com)
9317             {
9318                 case NT_TRANSACT_CREATE:
9319                     data_params = DCE2_SMB_TRANS__PARAMS;
9320                     break;
9321                 default:
9322                     return DCE2_RET__ERROR;
9323             }
9324 
9325             break;
9326 
9327         default:
9328             return DCE2_RET__ERROR;
9329     }
9330 
9331     DCE2_MOVE(nb_ptr, nb_len, DCE2_ComInfoCommandSize(com_info));
9332 
9333     // From client request
9334     if (ttracker->smb_type == SMB_TYPE__REQUEST)
9335     {
9336         ttracker->smb_type = SMB_TYPE__RESPONSE;
9337         ttracker->tdcnt = tdcnt;
9338         ttracker->tpcnt = tpcnt;
9339         ttracker->dsent = 0;
9340         ttracker->psent = 0;
9341         DCE2_BufferDestroy(ttracker->dbuf);
9342         ttracker->dbuf = NULL;
9343         DCE2_BufferDestroy(ttracker->pbuf);
9344         ttracker->pbuf = NULL;
9345     }
9346     else
9347     {
9348         if (tdcnt < ttracker->tdcnt)
9349             ttracker->tdcnt = tdcnt;
9350         if (tpcnt < ttracker->tpcnt)
9351             ttracker->tpcnt = pcnt;
9352     }
9353 
9354     if (DCE2_SmbValidateTransactionFields(ssd, (uint8_t *)smb_hdr, nb_ptr, nb_len,
9355                 DCE2_ComInfoByteCount(com_info), tdcnt, tpcnt, dcnt, doff, ddisp,
9356                 pcnt, poff, pdisp) != DCE2_RET__SUCCESS)
9357         return DCE2_RET__ERROR;
9358 
9359     if (DCE2_SmbValidateTransactionSent(ssd, ttracker->dsent, dcnt, ttracker->tdcnt,
9360                 ttracker->psent, pcnt, ttracker->tpcnt) != DCE2_RET__SUCCESS)
9361         return DCE2_RET__ERROR;
9362 
9363     ttracker->dsent += dcnt;
9364     ttracker->psent += pcnt;
9365 
9366     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Data displacement: %u, "
9367                 "Data count: %u, Total data count: %u\n"
9368                 "Parameter displacement: %u, "
9369                 "Parameter count: %u, Total parameter count: %u\n",
9370                 ddisp, dcnt, tdcnt, pdisp, pcnt, tpcnt));
9371 
9372     if (data_params & DCE2_SMB_TRANS__DATA)
9373     {
9374         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + doff) - nb_ptr);
9375 
9376         if ((ttracker->dsent < ttracker->tdcnt)
9377                 || (ttracker->psent < ttracker->tpcnt)
9378                 || !DCE2_BufferIsEmpty(ttracker->dbuf))
9379         {
9380             if ((dcnt != 0)
9381                     && (DCE2_SmbBufferTransactionData(ttracker, nb_ptr, dcnt, ddisp)
9382                         != DCE2_RET__SUCCESS))
9383             {
9384                 return DCE2_RET__ERROR;
9385             }
9386         }
9387     }
9388 
9389     if (data_params & DCE2_SMB_TRANS__PARAMS)
9390     {
9391         DCE2_MOVE(nb_ptr, nb_len, ((uint8_t *)smb_hdr + poff) - nb_ptr);
9392 
9393         if ((ttracker->dsent < ttracker->tdcnt)
9394                 || (ttracker->psent < ttracker->tpcnt)
9395                 || !DCE2_BufferIsEmpty(ttracker->dbuf))
9396         {
9397             if ((pcnt != 0)
9398                     && (DCE2_SmbBufferTransactionParameters(ttracker, nb_ptr, pcnt, pdisp)
9399                         != DCE2_RET__SUCCESS))
9400             {
9401                 return DCE2_RET__ERROR;
9402             }
9403         }
9404     }
9405 
9406     if ((ttracker->dsent == ttracker->tdcnt)
9407             && (ttracker->psent == ttracker->tpcnt))
9408     {
9409         return DCE2_RET__FULL;
9410     }
9411 
9412     return DCE2_RET__SUCCESS;
9413 }
9414 
DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker)9415 static inline void DCE2_SmbRemoveFileTrackerFromRequestTrackers(DCE2_SmbSsnData *ssd,
9416         DCE2_SmbFileTracker *ftracker)
9417 {
9418     DCE2_SmbRequestTracker *rtracker;
9419 
9420     if (ftracker == NULL)
9421         return;
9422 
9423     // NULL out file trackers of any outstanding requests
9424     // that reference this file tracker
9425     if (ssd->rtracker.ftracker == ftracker)
9426         ssd->rtracker.ftracker = NULL;
9427 
9428     if ((ssd->cur_rtracker != NULL) && (ssd->cur_rtracker->ftracker == ftracker))
9429         ssd->cur_rtracker->ftracker = NULL;
9430 
9431     for (rtracker = DCE2_QueueFirst(ssd->rtrackers);
9432             rtracker != NULL;
9433             rtracker = DCE2_QueueNext(ssd->rtrackers))
9434     {
9435         if (rtracker->ftracker == ftracker)
9436             rtracker->ftracker = NULL;
9437     }
9438 }
9439 
DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData * ssd)9440 static inline void DCE2_SmbSetNewFileAPIFileTracker(DCE2_SmbSsnData *ssd)
9441 {
9442     DCE2_SmbFileTracker *ftracker = &ssd->ftracker;
9443 
9444     while (ftracker != NULL)
9445     {
9446         if ((ftracker != ssd->fapi_ftracker) && (ftracker->fid_v1 != DCE2_SENTINEL)
9447                 && !ftracker->is_ipc && ftracker->ff_sequential_only
9448                 && (ftracker->ff_bytes_processed == 0))
9449         {
9450             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Designating file tracker "
9451                         "for file API processing: \"%s\" (0x%04X)\n",
9452                         ftracker->file_name, (uint16_t)ftracker->fid_v1););
9453             break;
9454         }
9455 
9456         if (ftracker == &ssd->ftracker)
9457             ftracker = DCE2_ListFirst(ssd->ftrackers);
9458         else
9459             ftracker = DCE2_ListNext(ssd->ftrackers);
9460     }
9461 
9462     ssd->fapi_ftracker = ftracker;
9463 }
9464 
DCE2_SmbResetFileChunks(DCE2_SmbFileTracker * ftracker)9465 static inline void DCE2_SmbResetFileChunks(DCE2_SmbFileTracker *ftracker)
9466 {
9467     if (ftracker == NULL)
9468         return;
9469 
9470     DCE2_ListDestroy(ftracker->ff_file_chunks);
9471     ftracker->ff_file_chunks = NULL;
9472     ftracker->ff_bytes_queued = 0;
9473 }
9474 
DCE2_SmbAbortFileAPI(DCE2_SmbSsnData * ssd)9475 static inline void DCE2_SmbAbortFileAPI(DCE2_SmbSsnData *ssd)
9476 {
9477     DCE2_SmbResetFileChunks(ssd->fapi_ftracker);
9478     ssd->fapi_ftracker = NULL;
9479 }
9480 
9481 #ifdef ACTIVE_RESPONSE
9482 static uint8_t dce2_smb_delete_pdu[65535];
9483 
DCE2_SmbInitDeletePdu(void)9484 void DCE2_SmbInitDeletePdu(void)
9485 {
9486     NbssHdr *nb_hdr = (NbssHdr *)dce2_smb_delete_pdu;
9487     SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(*nb_hdr));
9488     SmbDeleteReq *del_req = (SmbDeleteReq *)((uint8_t *)smb_hdr + sizeof(*smb_hdr));
9489     uint8_t *del_req_fmt = (uint8_t *)del_req + sizeof(*del_req);
9490     uint16_t smb_flg2 = 0xc843;
9491     uint16_t search_attrs = 0x0006;
9492 
9493     memset(dce2_smb_delete_pdu, 0, sizeof(dce2_smb_delete_pdu));
9494 
9495     nb_hdr->type = 0;
9496     nb_hdr->flags = 0;
9497 
9498     memcpy((void *)smb_hdr->smb_idf, (void *)"\xffSMB", sizeof(smb_hdr->smb_idf));
9499     smb_hdr->smb_com = SMB_COM_DELETE;
9500     smb_hdr->smb_status.nt_status = 0;
9501     //smb_hdr->smb_flg = 0x18;
9502     smb_hdr->smb_flg = 0;
9503     smb_hdr->smb_flg2 = SmbHtons(&smb_flg2);
9504     smb_hdr->smb_tid = 0;   // needs to be set before injected
9505     smb_hdr->smb_pid = 777;
9506     smb_hdr->smb_uid = 0;   // needs to be set before injected
9507     smb_hdr->smb_mid = 777;
9508 
9509     del_req->smb_wct = 1;
9510     del_req->smb_search_attrs = SmbHtons(&search_attrs);
9511     *del_req_fmt = SMB_FMT__ASCII;
9512 }
9513 
DCE2_SmbInjectDeletePdu(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker)9514 static void DCE2_SmbInjectDeletePdu(DCE2_SmbSsnData *ssd, DCE2_SmbFileTracker *ftracker)
9515 {
9516     NbssHdr *nb_hdr = (NbssHdr *)dce2_smb_delete_pdu;
9517     SmbNtHdr *smb_hdr = (SmbNtHdr *)((uint8_t *)nb_hdr + sizeof(*nb_hdr));
9518     SmbDeleteReq *del_req = (SmbDeleteReq *)((uint8_t *)smb_hdr + sizeof(*smb_hdr));
9519     char *del_filename = (char *)((uint8_t *)del_req + sizeof(*del_req) + 1);
9520     uint32_t len;
9521     uint16_t file_name_len = ftracker->file_name_len;
9522 
9523     nb_hdr->length = htons(sizeof(*smb_hdr) + sizeof(*del_req) + 1 + file_name_len);
9524     len = ntohs(nb_hdr->length) + sizeof(*nb_hdr);
9525     smb_hdr->smb_tid = SmbHtons(&ftracker->tid_v1);
9526     smb_hdr->smb_uid = SmbHtons(&ftracker->uid_v1);
9527     del_req->smb_bcc = 1 + file_name_len;
9528     if (SmbUnicode(smb_hdr))
9529         memcpy(del_filename, ftracker->file_name + UTF_16_LE_BOM_LEN, file_name_len - UTF_16_LE_BOM_LEN);
9530     else
9531         memcpy(del_filename, ftracker->file_name, file_name_len);
9532    _dpd.activeInjectData((void *)ssd->sd.wire_pkt, 0, (uint8_t *)nb_hdr, len);
9533 }
9534 
DCE2_SmbFinishFileBlockVerdict(DCE2_SmbSsnData * ssd)9535 static void DCE2_SmbFinishFileBlockVerdict(DCE2_SmbSsnData *ssd)
9536 {
9537     void *ssnptr = ssd->sd.wire_pkt->stream_session;
9538     void *p = (void *)ssd->sd.wire_pkt;
9539     File_Verdict verdict;
9540     PROFILE_VARS;
9541 
9542     PREPROC_PROFILE_START(dce2_pstat_smb_file);
9543 
9544     verdict = DCE2_SmbGetFileVerdict(p, ssnptr);
9545     if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
9546     {
9547         DCE2_SmbInjectDeletePdu(ssd, ssd->fb_ftracker);
9548 
9549         PREPROC_PROFILE_START(dce2_pstat_smb_file_api);
9550         _dpd.fileAPI->render_block_verdict(NULL, p);
9551         PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9552     }
9553 
9554     ssd->fb_ftracker = NULL;
9555     ssd->block_pdus = false;
9556 
9557     PREPROC_PROFILE_END(dce2_pstat_smb_file);
9558 }
9559 
DCE2_SmbGetFileVerdict(void * p,void * ssnptr)9560 static File_Verdict DCE2_SmbGetFileVerdict(void *p, void *ssnptr)
9561 {
9562     File_Verdict verdict;
9563     PROFILE_VARS;
9564 
9565     PREPROC_PROFILE_START(dce2_pstat_smb_file_api);
9566 
9567     verdict = _dpd.fileAPI->get_file_verdict(ssnptr);
9568     if (verdict == FILE_VERDICT_PENDING)
9569     {
9570         _dpd.fileAPI->file_signature_lookup(p, true);
9571         verdict = _dpd.fileAPI->get_file_verdict(ssnptr);
9572     }
9573 
9574     PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9575     return verdict;
9576 }
9577 #endif
9578 
DCE2_SmbFinishFileAPI(DCE2_SmbSsnData * ssd)9579 static inline DCE2_SmbRetransmitPending DCE2_SmbFinishFileAPI(DCE2_SmbSsnData *ssd)
9580 {
9581     void *ssnptr = ssd->sd.wire_pkt->stream_session;
9582     void *p = (void *)ssd->sd.wire_pkt;
9583     DCE2_SmbFileTracker *ftracker = ssd->fapi_ftracker;
9584     bool upload;
9585     PROFILE_VARS;
9586 
9587     if (ftracker == NULL)
9588         return DCE2_SMB_RETRANSMIT_PENDING__UNSET;
9589 
9590     PREPROC_PROFILE_START(dce2_pstat_smb_file);
9591 
9592     upload = _dpd.fileAPI->get_file_direction(ssnptr);
9593 
9594     /*This is a case of retrasmitted packet in upload sceanrio with Pending verdict*/
9595     if ((ssd->smbretransmit))
9596     {
9597          ssd->smbretransmit = false;
9598          _dpd.fileAPI->file_signature_lookup(p, true);
9599          File_Verdict verdict = _dpd.fileAPI->get_file_verdict(ssnptr);
9600          if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
9601          {
9602              ssd->fb_ftracker = ftracker;
9603              ssd->fapi_ftracker = NULL;
9604              PREPROC_PROFILE_END(dce2_pstat_smb_file);
9605              return DCE2_SMB_RETRANSMIT_PENDING__UNSET;
9606          }
9607          else if (verdict == FILE_VERDICT_PENDING)
9608          {
9609              PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9610              return DCE2_SMB_RETRANSMIT_PENDING__SET;
9611          }
9612          else /*if we get some other verdict , clean up*/
9613          {
9614              ssd->fapi_ftracker = NULL;
9615              PREPROC_PROFILE_END(dce2_pstat_smb_file);
9616              return DCE2_SMB_RETRANSMIT_PENDING__UNSET;
9617          }
9618     }
9619 
9620     if (_dpd.fileAPI->get_file_processed_size(ssnptr) != 0)
9621     {
9622         // Never knew the size of the file so never knew when to tell the
9623         // fileAPI the upload/download was finished.
9624         if ((ftracker->ff_file_size == 0)
9625                 && (ftracker->ff_bytes_processed != 0))
9626         {
9627             DCE2_SmbSetFileName(ftracker->file_name, ftracker->file_name_len);
9628 
9629             PREPROC_PROFILE_START(dce2_pstat_smb_file_api);
9630 
9631 #ifdef ACTIVE_RESPONSE
9632             if (_dpd.fileAPI->file_process(p, NULL, 0, SNORT_FILE_END, upload, upload, false))
9633             {
9634                 if (upload)
9635                 {
9636                     File_Verdict verdict =
9637                         _dpd.fileAPI->get_file_verdict(ssd->sd.wire_pkt->stream_session);
9638 
9639                     if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
9640                         ssd->fb_ftracker = ftracker;
9641 
9642                     else if ((verdict == FILE_VERDICT_PENDING) && (smb_upload_ret_cb_id != 0))
9643                     {
9644                         _dpd.streamAPI->set_event_handler(ssnptr, smb_upload_ret_cb_id, SE_REXMIT);
9645                         PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9646                         return DCE2_SMB_RETRANSMIT_PENDING__SET;
9647                     }
9648                 }
9649             }
9650 #else
9651             (void)_dpd.fileAPI->file_process(p, NULL, 0, SNORT_FILE_END, upload, false, false);
9652 #endif
9653 
9654             PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9655 
9656             dce2_stats.smb_files_processed++;
9657         }
9658     }
9659 
9660     ssd->fapi_ftracker = NULL;
9661 
9662     PREPROC_PROFILE_END(dce2_pstat_smb_file);
9663     return DCE2_SMB_RETRANSMIT_PENDING__UNSET;
9664 }
9665 
DCE2_SmbIsVerdictSuspend(bool upload,FilePosition position)9666 static inline bool DCE2_SmbIsVerdictSuspend(bool upload, FilePosition position)
9667 {
9668 #ifdef ACTIVE_RESPONSE
9669     if (upload &&
9670             ((position == SNORT_FILE_FULL) || (position == SNORT_FILE_END)))
9671         return true;
9672 #endif
9673     return false;
9674 }
9675 
DCE2_SmbFileAPIProcess(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker,const uint8_t * data_ptr,uint32_t data_len,bool upload)9676 static DCE2_Ret DCE2_SmbFileAPIProcess(DCE2_SmbSsnData *ssd,
9677         DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr,
9678         uint32_t data_len, bool upload)
9679 {
9680     FilePosition position;
9681     PROFILE_VARS;
9682 
9683 #ifdef ACTIVE_RESPONSE
9684     if (ssd->fb_ftracker && (ssd->fb_ftracker != ftracker))
9685         return DCE2_RET__SUCCESS;
9686 #endif
9687 
9688     // Trim data length if it exceeds the maximum file depth
9689     if ((ssd->max_file_depth != 0)
9690             && (ftracker->ff_bytes_processed + data_len) > (uint64_t)ssd->max_file_depth)
9691         data_len = ssd->max_file_depth - ftracker->ff_bytes_processed;
9692 
9693     if (ftracker->ff_file_size == 0)
9694     {
9695         // Don't know the file size.
9696         if ((ftracker->ff_bytes_processed == 0) && (ssd->max_file_depth != 0)
9697                 && (data_len == (uint64_t)ssd->max_file_depth))
9698             position = SNORT_FILE_FULL;
9699         else if (ftracker->ff_bytes_processed == 0)
9700             position = SNORT_FILE_START;
9701         else if ((ssd->max_file_depth != 0)
9702                 && ((ftracker->ff_bytes_processed + data_len) == (uint64_t)ssd->max_file_depth))
9703             position = SNORT_FILE_END;
9704         else
9705             position = SNORT_FILE_MIDDLE;
9706     }
9707     else
9708     {
9709         if ((ftracker->ff_bytes_processed == 0)
9710                 && ((data_len == ftracker->ff_file_size)
9711                     || ((ssd->max_file_depth != 0) && (data_len == (uint64_t)ssd->max_file_depth))))
9712             position = SNORT_FILE_FULL;
9713         else if (ftracker->ff_bytes_processed == 0)
9714             position = SNORT_FILE_START;
9715         else if (((ftracker->ff_bytes_processed + data_len) >= ftracker->ff_file_size)
9716                 || ((ssd->max_file_depth != 0)
9717                     && ((ftracker->ff_bytes_processed + data_len) == (uint64_t)ssd->max_file_depth)))
9718             position = SNORT_FILE_END;
9719         else
9720             position = SNORT_FILE_MIDDLE;
9721     }
9722 
9723     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Sending SMB file data to file API ........\n"));
9724 
9725     PREPROC_PROFILE_START(dce2_pstat_smb_file_api);
9726 
9727     if (!_dpd.fileAPI->file_process((void *)ssd->sd.wire_pkt,
9728                 (uint8_t *)data_ptr, (int)data_len, position, upload,
9729                 DCE2_SmbIsVerdictSuspend(upload, position), false))
9730     {
9731         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File API returned FAILURE "
9732                     "for (0x%02X) %s\n", ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD"));
9733 
9734         PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9735 
9736         // Failure.  Abort tracking this file under file API
9737         return DCE2_RET__ERROR;
9738     }
9739     else
9740     {
9741         PREPROC_PROFILE_END(dce2_pstat_smb_file_api);
9742 
9743         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File API returned SUCCESS "
9744                     "for (0x%02X) %s\n", ftracker->fid_v1, upload ? "UPLOAD" : "DOWNLOAD"));
9745 
9746         if (((position == SNORT_FILE_START) || (position == SNORT_FILE_FULL))
9747                 && (smb_file_name_len != 0))
9748         {
9749             _dpd.fileAPI->set_file_name((void *)ssd->sd.wire_pkt->stream_session,
9750                     (uint8_t *)smb_file_name, smb_file_name_len, false);
9751         }
9752 
9753         if ((position == SNORT_FILE_FULL) || (position == SNORT_FILE_END))
9754         {
9755 #ifdef ACTIVE_RESPONSE
9756             if (upload)
9757             {
9758                 File_Verdict verdict = _dpd.fileAPI->get_file_verdict(ssd->sd.wire_pkt->stream_session);
9759 
9760                 if ((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT)
9761                         || (verdict == FILE_VERDICT_PENDING))
9762                 {
9763                     ssd->fb_ftracker = ftracker;
9764                 }
9765             }
9766 #endif
9767             ftracker->ff_sequential_only = false;
9768 
9769             dce2_stats.smb_files_processed++;
9770             return DCE2_RET__FULL;
9771         }
9772     }
9773 
9774     return DCE2_RET__SUCCESS;
9775 }
9776 
DCE2_SmbFileOffsetCompare(const void * a,const void * b)9777 static int DCE2_SmbFileOffsetCompare(const void *a, const void *b)
9778 {
9779     const DCE2_SmbFileChunk *x = (DCE2_SmbFileChunk *)a;
9780     const DCE2_SmbFileChunk *y = (DCE2_SmbFileChunk *)b;
9781 
9782     if (x->offset > y->offset)
9783         return 1;
9784     if (x->offset < y->offset)
9785         return -1;
9786 
9787     return 0;
9788 }
9789 
DCE2_SmbFileChunkFree(void * data)9790 static void DCE2_SmbFileChunkFree(void *data)
9791 {
9792     DCE2_SmbFileChunk *fc = (DCE2_SmbFileChunk *)data;
9793 
9794     if (fc == NULL)
9795         return;
9796 
9797     if (fc->data != NULL)
9798         DCE2_Free((void *)fc->data, fc->length, DCE2_MEM_TYPE__SMB_FILE);
9799 
9800     DCE2_Free((void *)fc, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE);
9801 }
9802 
DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker,const uint8_t * data_ptr,uint32_t data_len,bool upload)9803 static DCE2_Ret DCE2_SmbHandleOutOfOrderFileData(DCE2_SmbSsnData *ssd,
9804         DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr,
9805         uint32_t data_len, bool upload)
9806 {
9807     if (ftracker->ff_file_offset == ftracker->ff_bytes_processed)
9808     {
9809         uint64_t initial_offset = ftracker->ff_file_offset;
9810         uint64_t next_offset = initial_offset + data_len;
9811         DCE2_SmbFileChunk *file_chunk = DCE2_ListFirst(ftracker->ff_file_chunks);
9812         DCE2_Ret ret = DCE2_SmbFileAPIProcess(ssd, ftracker, data_ptr, data_len, upload);
9813 
9814         ftracker->ff_bytes_processed += data_len;
9815         ftracker->ff_file_offset = ftracker->ff_bytes_processed;
9816 
9817         if (ret != DCE2_RET__SUCCESS)
9818             return ret;
9819 
9820         // Should already be chunks in here if we came into this function
9821         // with an in order chunk, but check just in case.
9822         if (file_chunk == NULL)
9823             return DCE2_RET__ERROR;
9824 
9825         while (file_chunk != NULL)
9826         {
9827             if (file_chunk->offset > next_offset)
9828                 break;
9829 
9830             if (file_chunk->offset == next_offset)
9831             {
9832                 ret = DCE2_SmbFileAPIProcess(ssd, ftracker,
9833                         file_chunk->data, file_chunk->length, upload);
9834 
9835                 ftracker->ff_bytes_processed += file_chunk->length;
9836                 ftracker->ff_file_offset = ftracker->ff_bytes_processed;
9837 
9838                 if (ret != DCE2_RET__SUCCESS)
9839                     return ret;
9840 
9841                 next_offset = file_chunk->offset + file_chunk->length;
9842             }
9843 
9844             ftracker->ff_bytes_queued -= file_chunk->length;
9845             DCE2_ListRemoveCurrent(ftracker->ff_file_chunks);
9846 
9847             file_chunk = DCE2_ListNext(ftracker->ff_file_chunks);
9848         }
9849 
9850         if (initial_offset == 0)
9851             DCE2_SmbResetFileChunks(ftracker);
9852     }
9853     else
9854     {
9855         DCE2_SmbFileChunk *file_chunk;
9856         DCE2_Ret ret;
9857 
9858         if (ftracker->ff_file_chunks == NULL)
9859         {
9860             ftracker->ff_file_chunks = DCE2_ListNew(DCE2_LIST_TYPE__SORTED,
9861                     DCE2_SmbFileOffsetCompare, DCE2_SmbFileChunkFree,
9862                     NULL, DCE2_LIST_FLAG__NO_DUPS, DCE2_MEM_TYPE__SMB_FILE);
9863 
9864             if (ftracker->ff_file_chunks == NULL)
9865                 return DCE2_RET__ERROR;
9866         }
9867 
9868         if ((ftracker->ff_bytes_queued + data_len) > (DCE2_GcMemcap() >> 4))
9869             return DCE2_RET__ERROR;
9870 
9871         file_chunk = DCE2_Alloc(sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE);
9872         if (file_chunk == NULL)
9873             return DCE2_RET__ERROR;
9874 
9875         file_chunk->data = DCE2_Alloc(data_len, DCE2_MEM_TYPE__SMB_FILE);
9876         if (file_chunk->data == NULL)
9877         {
9878             DCE2_Free(file_chunk, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE);
9879             return DCE2_RET__ERROR;
9880         }
9881 
9882         file_chunk->offset = ftracker->ff_file_offset;
9883         file_chunk->length = data_len;
9884         memcpy(file_chunk->data, data_ptr, data_len);
9885         ftracker->ff_bytes_queued += data_len;
9886 
9887         if ((ret = DCE2_ListInsert(ftracker->ff_file_chunks,
9888                     (void *)file_chunk, (void *)file_chunk)) != DCE2_RET__SUCCESS)
9889         {
9890             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Insert file chunk failed: "
9891                         "0x%02X.\n", ftracker->fid_v1););
9892 
9893             DCE2_Free(file_chunk->data, data_len, DCE2_MEM_TYPE__SMB_FILE);
9894             DCE2_Free(file_chunk, sizeof(DCE2_SmbFileChunk), DCE2_MEM_TYPE__SMB_FILE);
9895 
9896             if (ret != DCE2_RET__DUPLICATE)
9897                 return DCE2_RET__ERROR;
9898         }
9899     }
9900 
9901     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Currently buffering %u bytes "
9902                 "of out of order file data.\n", ftracker->ff_bytes_queued););
9903 
9904     return DCE2_RET__SUCCESS;
9905 }
9906 
9907 /********************************************************************
9908  * Function: DCE2_SmbProcessFileData()
9909  *
9910  * Purpose:
9911  *  Processes regular file data send via reads/writes.  Sends
9912  *  data to the file API for type id and signature and sets the
9913  *  file data ptr for rule inspection.
9914  *
9915  * Arguments:
9916  *  DCE2_SmbSsnData *      - pointer to SMB session data
9917  *  DCE2_SmbFileTracker *  - pointer to file tracker
9918  *  const uint8_t *        - pointer to file data
9919  *  uint32_t               - length of file data
9920  *  bool                   - whether it's an upload (true) or
9921  *                           download (false)
9922  *
9923  * Returns: None
9924  *
9925  ********************************************************************/
DCE2_SmbProcessFileData(DCE2_SmbSsnData * ssd,DCE2_SmbFileTracker * ftracker,const uint8_t * data_ptr,uint32_t data_len,bool upload)9926 static void DCE2_SmbProcessFileData(DCE2_SmbSsnData *ssd,
9927         DCE2_SmbFileTracker *ftracker, const uint8_t *data_ptr,
9928         uint32_t data_len, bool upload)
9929 {
9930     bool cur_upload = DCE2_SmbFileUpload(ftracker->ff_file_direction) ? true : false;
9931     int64_t file_data_depth = DCE2_ScSmbFileDepth(ssd->sd.sconfig);
9932     PROFILE_VARS;
9933 
9934     if (data_len == 0)
9935         return;
9936 
9937     PREPROC_PROFILE_START(dce2_pstat_smb_file);
9938 
9939     DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB,
9940                 "File size: "STDu64", File offset: "STDu64", Bytes processed: "STDu64", "
9941                 "Data len: %u\n", ftracker->ff_file_size, ftracker->ff_file_offset,
9942                 ftracker->ff_bytes_processed, data_len););
9943 
9944     // Account for wrapping.  Not likely but just in case.
9945     if ((ftracker->ff_bytes_processed + data_len) < ftracker->ff_bytes_processed)
9946     {
9947         DCE2_SmbRemoveFileTracker(ssd, ftracker);
9948 
9949         PREPROC_PROFILE_END(dce2_pstat_smb_file);
9950         return;
9951     }
9952 
9953     if ((ftracker->ff_bytes_processed == 0)
9954             && DCE2_SmbFileDirUnknown(ftracker->ff_file_direction))
9955     {
9956         ftracker->ff_file_direction =
9957             upload ? DCE2_SMB_FILE_DIRECTION__UPLOAD : DCE2_SMB_FILE_DIRECTION__DOWNLOAD;
9958     }
9959     else if (cur_upload != upload)
9960     {
9961         if (cur_upload)
9962         {
9963             // Went from writing to reading.  Ignore the read.
9964             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Went from writing to "
9965                         "reading - ignoring read.\n"););
9966 
9967             PREPROC_PROFILE_END(dce2_pstat_smb_file);
9968             return;
9969         }
9970 
9971         DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Went from reading to "
9972                     "writing - consider transfer done.\n"););
9973 
9974         // Went from reading to writing.  Consider the transfer done
9975         // and remove the file tracker.
9976         DCE2_SmbRemoveFileTracker(ssd, ftracker);
9977 
9978         PREPROC_PROFILE_END(dce2_pstat_smb_file);
9979         return;
9980     }
9981 
9982     if ((file_data_depth != -1) &&
9983             ((ftracker->ff_file_offset == ftracker->ff_bytes_processed)
9984              && ((file_data_depth == 0) || (ftracker->ff_bytes_processed < (uint64_t)file_data_depth))))
9985     {
9986         _dpd.setFileDataPtr((uint8_t *)data_ptr,
9987                 (data_len > UINT16_MAX) ? UINT16_MAX : (uint16_t)data_len);
9988 
9989         DCE2_FileDetect(&ssd->sd);
9990     }
9991 
9992     if (ftracker == ssd->fapi_ftracker)
9993     {
9994         DCE2_Ret ret;
9995 
9996         if ((ftracker->ff_file_offset != ftracker->ff_bytes_processed)
9997                 || !DCE2_ListIsEmpty(ftracker->ff_file_chunks))
9998         {
9999             if ((ssd->max_file_depth != 0)
10000                     && (ftracker->ff_file_offset >= (uint64_t)ssd->max_file_depth))
10001             {
10002                 // If the offset is beyond the max file depth, ignore it.
10003                 PREPROC_PROFILE_END(dce2_pstat_smb_file);
10004                 return;
10005             }
10006             else if (upload && (data_len == 1)
10007                     && (ftracker->ff_file_offset > ftracker->ff_bytes_processed))
10008             {
10009                 // Sometimes a write one byte is done at a high offset, I'm
10010                 // guessing to make sure the system has sufficient disk
10011                 // space to complete the full write.  Ignore it because it
10012                 // will likely be overwritten.
10013                 PREPROC_PROFILE_END(dce2_pstat_smb_file);
10014                 return;
10015             }
10016 
10017             if ((ftracker->ff_file_offset == 0) && (ftracker->ff_bytes_processed != 0))
10018             {
10019                 // Sometimes initial reads/writes are out of order to get file info
10020                 // such as an icon, then proceed to write in order.  Usually the
10021                 // first read/write is at offset 0, then the next ones are somewhere
10022                 // off in the distance.  Reset and continue on below.
10023                 DCE2_SmbResetFileChunks(ftracker);
10024                 ftracker->ff_bytes_processed = 0;
10025             }
10026             else if (ftracker->ff_file_offset < ftracker->ff_bytes_processed)
10027             {
10028                 DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "File offset ("STDu64") is "
10029                             "less than bytes processed ("STDu64") - aborting.\n",
10030                             ftracker->ff_file_offset, ftracker->ff_bytes_processed););
10031 
10032                 DCE2_SmbAbortFileAPI(ssd);
10033                 DCE2_SmbSetNewFileAPIFileTracker(ssd);
10034                 PREPROC_PROFILE_END(dce2_pstat_smb_file);
10035                 return;
10036             }
10037             else
10038             {
10039                 ret = DCE2_SmbHandleOutOfOrderFileData(ssd, ftracker, data_ptr, data_len, upload);
10040                 if (ret != DCE2_RET__SUCCESS)
10041                 {
10042                     DCE2_SmbAbortFileAPI(ssd);
10043                     DCE2_SmbSetNewFileAPIFileTracker(ssd);
10044                 }
10045 
10046                 PREPROC_PROFILE_END(dce2_pstat_smb_file);
10047                 return;
10048             }
10049         }
10050 
10051         ret = DCE2_SmbFileAPIProcess(ssd, ftracker, data_ptr, data_len, upload);
10052 
10053         ftracker->ff_bytes_processed += data_len;
10054         ftracker->ff_file_offset = ftracker->ff_bytes_processed;
10055 
10056         if (ret != DCE2_RET__SUCCESS)
10057         {
10058             DCE2_SmbAbortFileAPI(ssd);
10059             DCE2_SmbSetNewFileAPIFileTracker(ssd);
10060         }
10061     }
10062     else
10063     {
10064         if (ftracker->ff_file_offset == ftracker->ff_bytes_processed)
10065         {
10066             ftracker->ff_bytes_processed += data_len;
10067             ftracker->ff_file_offset = ftracker->ff_bytes_processed;
10068         }
10069 
10070         if ((file_data_depth == -1)
10071                 || ((file_data_depth != 0)
10072                     && (ftracker->ff_bytes_processed >= (uint64_t)file_data_depth)))
10073         {
10074             DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__SMB, "Bytes processed ("STDu64") "
10075                         "is at or beyond file data depth ("STDu64") - finished.\n",
10076                         ftracker->ff_bytes_processed, file_data_depth););
10077 
10078             DCE2_SmbRemoveFileTracker(ssd, ftracker);
10079 
10080             PREPROC_PROFILE_END(dce2_pstat_smb_file);
10081             return;
10082         }
10083     }
10084 
10085     PREPROC_PROFILE_END(dce2_pstat_smb_file);
10086 }
10087 
10088 /********************************************************************
10089  * Function: DCE2_SmbSetFileName()
10090  *
10091  * Purpose:
10092  *  Copies the NULL terminated file name passed in to the global
10093  *  array for logging the file name for events.
10094  *
10095  * Arguments:
10096  *  uint8_t*  - NULL terminated file name(ASCII or UTF-16LE)
10097  *              file_name returned by DCE2_SmbGetString can be max 2*DCE2_SMB_MAX_PATH_LEN + UTF_16_LE_BOM_LEN + 2 bytes
10098  *              No need to check for overflow
10099  *  uint16_t  - file_name_len which includes NULL terminated bytes
10100  *
10101  * Returns: None
10102  *
10103  ********************************************************************/
DCE2_SmbSetFileName(uint8_t * file_name,uint16_t file_name_len)10104 static inline void DCE2_SmbSetFileName(uint8_t* file_name, uint16_t file_name_len)
10105 {
10106     if (file_name == NULL)
10107         return;
10108 
10109     smb_file_name_len = file_name_len;
10110     memcpy(smb_file_name, file_name, file_name_len);
10111 }
10112 
10113 /********************************************************************
10114  * Function: DCE2_SmbGetString()
10115  *
10116  * Purpose:
10117  *  Parses data passed in and returns a byte stream.
10118  *  unicode stream is prepended with BOM
10119  *
10120  * Arguments:
10121  *  const uint8_t *  - pointer to data
10122  *  uint32_t         - data length
10123  *  bool             - true if the data is unicode (UTF-16LE)
10124  *  uint16_t *       - Returns the length of the output buffer including the NULL terminated bytes
10125  *
10126  * Returns:
10127  *  uint8_t *        - NULL terminated byte stream (ASCII or UTF-16LE with BOM)
10128  *
10129  ********************************************************************/
DCE2_SmbGetString(const uint8_t * data,uint32_t data_len,bool unicode,uint16_t * file_name_len)10130 static uint8_t* DCE2_SmbGetString(const uint8_t *data,
10131         uint32_t data_len, bool unicode, uint16_t *file_name_len)
10132 {
10133     uint8_t *fname = NULL;
10134     uint32_t i = 0;
10135     uint8_t inc = unicode ? 2 : 1;
10136     *file_name_len = 0;
10137 
10138     if (data_len < inc)
10139         return NULL;
10140     for (i = 0; i < data_len; i += inc)
10141     {
10142         uint16_t uchar = unicode ? SmbNtohs((uint16_t *)(data + i)) : data[i];
10143         if (uchar == 0)
10144             break;
10145     }
10146     if(i > inc*DCE2_SMB_MAX_PATH_LEN)
10147         return NULL;
10148 
10149     if(unicode)
10150     {
10151         fname = (uint8_t *)DCE2_Alloc(i + UTF_16_LE_BOM_LEN + 2, DCE2_MEM_TYPE__SMB_SSN);
10152         if (fname == NULL)
10153             return NULL;
10154 
10155         memcpy(fname, UTF_16_LE_BOM, UTF_16_LE_BOM_LEN);//Prepend with BOM
10156         memcpy(fname + UTF_16_LE_BOM_LEN, data, i);
10157         *file_name_len = i + UTF_16_LE_BOM_LEN + 2;
10158     }
10159     else
10160     {
10161         fname = (uint8_t *)DCE2_Alloc(i + 1, DCE2_MEM_TYPE__SMB_SSN);
10162         if (fname == NULL)
10163             return NULL;
10164         memcpy(fname, data, i);
10165         *file_name_len = i + 1;
10166     }
10167 
10168     return fname;
10169 }
10170 
DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker * ftracker,DCE2_SmbRequestTracker * cur_rtracker)10171 static inline void DCE2_Update_Ftracker_from_ReqTracker(DCE2_SmbFileTracker *ftracker, DCE2_SmbRequestTracker *cur_rtracker)
10172 {
10173     ftracker->file_name = cur_rtracker->file_name;
10174     ftracker->file_name_len = cur_rtracker->file_name_len;
10175     cur_rtracker->file_name = NULL;
10176     cur_rtracker->file_name_len = 0;
10177     return;
10178 }
10179 
DCE2_Process_Retransmitted(SFSnortPacket * p)10180 void DCE2_Process_Retransmitted(SFSnortPacket *p)
10181 {
10182      DCE2_SsnData *sd = (DCE2_SsnData *)DCE2_SsnGetAppData(p);
10183      if (sd != NULL)
10184      {
10185          sd->wire_pkt = p;
10186          DCE2_SmbSsnData *ssd = (DCE2_SmbSsnData *)sd;
10187          ssd->smbretransmit = true;
10188          DCE2_SmbRemoveFileTracker(ssd, ssd->cur_rtracker->ftracker);
10189      }
10190 }
10191