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