Branch data Line data Source code
1 : : // $Id: NetbiosSSN.cc 6916 2009-09-24 20:48:36Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <ctype.h>
8 : :
9 : : #include "NetVar.h"
10 : : #include "NetbiosSSN.h"
11 : : #include "Sessions.h"
12 : : #include "Event.h"
13 : :
14 : : double netbios_ssn_session_timeout = 15.0;
15 : :
16 : : #define MAKE_INT16(dest, src) dest = *src; dest <<=8; src++; dest |= *src; src++;
17 : :
18 : 0 : NetbiosSSN_RawMsgHdr::NetbiosSSN_RawMsgHdr(const u_char*& data, int& len)
19 : : {
20 : 0 : type = *data; ++data, --len;
21 : 0 : flags = *data; ++data, --len;
22 : 0 : length = *data; ++data, --len;
23 : :
24 : 0 : length <<= 8;
25 : 0 : length |= *data;
26 : 0 : ++data, --len;
27 : 0 : }
28 : :
29 : 0 : NetbiosDGM_RawMsgHdr::NetbiosDGM_RawMsgHdr(const u_char*& data, int& len)
30 : : {
31 : 0 : type = *data; ++data, --len;
32 : 0 : flags = *data; ++data, --len;
33 : :
34 : 0 : MAKE_INT16(id, data); len -= 2;
35 : :
36 : 0 : srcip = *data++ << 24;
37 : 0 : srcip |= *data++ << 16;
38 : 0 : srcip |= *data++ << 8;
39 : 0 : srcip |= *data++;
40 : 0 : len -=4;
41 : :
42 : 0 : MAKE_INT16(srcport, data); len -= 2;
43 : 0 : MAKE_INT16(length, data); len -= 2;
44 : 0 : MAKE_INT16(offset, data);; len -= 2;
45 : 0 : }
46 : :
47 : :
48 : : NetbiosSSN_Interpreter::NetbiosSSN_Interpreter(Analyzer* arg_analyzer,
49 : 0 : SMB_Session* arg_smb_session)
50 : : {
51 : 0 : analyzer = arg_analyzer;
52 : 0 : smb_session = arg_smb_session;
53 : 0 : }
54 : :
55 : : int NetbiosSSN_Interpreter::ParseMessage(unsigned int type, unsigned int flags,
56 : 0 : const u_char* data, int len, int is_query)
57 : : {
58 [ # # ]: 0 : if ( netbios_session_message )
59 : : {
60 : 0 : val_list* vl = new val_list;
61 : 0 : vl->append(analyzer->BuildConnVal());
62 : 0 : vl->append(new Val(is_query, TYPE_BOOL));
63 : 0 : vl->append(new Val(type, TYPE_COUNT));
64 : 0 : vl->append(new Val(len, TYPE_COUNT));
65 : 0 : analyzer->ConnectionEvent(netbios_session_message, vl);
66 : : }
67 : :
68 [ # # # # # : 0 : switch ( type ) {
# # # # ]
69 : : case NETBIOS_SSN_MSG:
70 : 0 : return ParseSessionMsg(data, len, is_query);
71 : :
72 : : case NETBIOS_SSN_REQ:
73 : 0 : return ParseSessionReq(data, len, is_query);
74 : :
75 : : case NETBIOS_SSN_POS_RESP:
76 : 0 : return ParseSessionPosResp(data, len, is_query);
77 : :
78 : : case NETBIOS_SSN_NEG_RESP:
79 : 0 : return ParseSessionNegResp(data, len, is_query);
80 : :
81 : : case NETBIOS_SSN_RETARG_RESP:
82 : 0 : return ParseRetArgResp(data, len, is_query);
83 : :
84 : : case NETBIOS_SSN_KEEP_ALIVE:
85 : 0 : return ParseKeepAlive(data, len, is_query);
86 : :
87 : : case NETBIOS_DGM_DIRECT_UNIQUE:
88 : : case NETBIOS_DGM_DIRECT_GROUP:
89 : : case NETBIOS_DGM_BROADCAST:
90 : 0 : return ParseBroadcast(data, len, is_query);
91 : :
92 : : case NETBIOS_DGM_ERROR:
93 : : case NETBIOS_DGG_QUERY_REQ:
94 : : case NETBIOS_DGM_POS_RESP:
95 : : case NETBIOS_DGM_NEG_RESP:
96 : 0 : return ParseDatagram(data, len, is_query);
97 : :
98 : : default:
99 : 0 : analyzer->Weird(fmt("unknown_netbios_type: 0x%x", type));
100 : 0 : return 1;
101 : : }
102 : : }
103 : :
104 : : int NetbiosSSN_Interpreter::ParseDatagram(const u_char* data, int len,
105 : 0 : int is_query)
106 : : {
107 [ # # ]: 0 : if ( smb_session )
108 : : {
109 : 0 : smb_session->Deliver(is_query, len, data);
110 : 0 : return 0;
111 : : }
112 : :
113 : 0 : return 0;
114 : : }
115 : :
116 : : int NetbiosSSN_Interpreter::ParseBroadcast(const u_char* data, int len,
117 : 0 : int is_query)
118 : : {
119 : : // FIND THE NUL-TERMINATED NAME STRINGS HERE!
120 : : // Not sure what's in them, so we don't keep them currently.
121 : :
122 : 0 : BroString* srcname = new BroString((char*) data);
123 : 0 : data += srcname->Len()+1;
124 : 0 : len -= srcname->Len();
125 : :
126 : 0 : BroString* dstname = new BroString((char*) data);
127 : 0 : data += dstname->Len()+1;
128 : 0 : len -= dstname->Len();
129 : :
130 [ # # ]: 0 : if ( smb_session )
131 : : {
132 : 0 : smb_session->Deliver(is_query, len, data);
133 : 0 : return 0;
134 : : }
135 : :
136 : 0 : return 0;
137 : : }
138 : :
139 : : int NetbiosSSN_Interpreter::ParseMessageTCP(const u_char* data, int len,
140 : 0 : int is_query)
141 : : {
142 : 0 : NetbiosSSN_RawMsgHdr hdr(data, len);
143 : :
144 [ # # ]: 0 : if ( hdr.length > unsigned(len) )
145 : : analyzer->Weird(fmt("excess_netbios_hdr_len (%d > %d)",
146 : 0 : hdr.length, len));
147 : :
148 [ # # ]: 0 : else if ( hdr.length < unsigned(len) )
149 : : {
150 : 0 : analyzer->Weird("deficit_netbios_hdr_len");
151 : 0 : len = hdr.length;
152 : : }
153 : :
154 : 0 : return ParseMessage(hdr.type, hdr.flags, data, len, is_query);
155 : : }
156 : :
157 : : int NetbiosSSN_Interpreter::ParseMessageUDP(const u_char* data, int len,
158 : 0 : int is_query)
159 : : {
160 : :
161 : 0 : NetbiosDGM_RawMsgHdr hdr(data, len);
162 : :
163 [ # # ]: 0 : if ( unsigned(hdr.length-14) > unsigned(len) )
164 : : analyzer->Weird(fmt("excess_netbios_hdr_len (%d > %d)",
165 : 0 : hdr.length, len));
166 : :
167 [ # # ]: 0 : else if ( hdr.length < unsigned(len) )
168 : : {
169 : : analyzer->Weird(fmt("deficit_netbios_hdr_len (%d < %d)",
170 : 0 : hdr.length, len));
171 : 0 : len = hdr.length;
172 : : }
173 : :
174 : 0 : return ParseMessage(hdr.type, hdr.flags, data, len, is_query);
175 : : }
176 : :
177 : :
178 : : int NetbiosSSN_Interpreter::ParseSessionMsg(const u_char* data, int len,
179 : 0 : int is_query)
180 : : {
181 [ # # ][ # # ]: 0 : if ( len < 4 || strncmp((const char*) data, "\xffSMB", 4) )
182 : : {
183 : : // This should be an event, too.
184 : 0 : analyzer->Weird("netbios_raw_session_msg");
185 : 0 : Event(netbios_session_raw_message, data, len, is_query);
186 : 0 : return 0;
187 : : }
188 : :
189 [ # # ]: 0 : if ( smb_session )
190 : : {
191 : 0 : smb_session->Deliver(is_query, len, data);
192 : 0 : return 0;
193 : : }
194 : : else
195 : : {
196 : 0 : analyzer->Weird("no_smb_session_using_parsesambamsg");
197 : 0 : data += 4;
198 : 0 : len -= 4;
199 : 0 : return ParseSambaMsg(data, len, is_query);
200 : : }
201 : : }
202 : :
203 : : int NetbiosSSN_Interpreter::ParseSambaMsg(const u_char* data, int len,
204 : 0 : int is_query)
205 : : {
206 : 0 : return 0;
207 : : }
208 : :
209 : : int NetbiosSSN_Interpreter::ConvertName(const u_char* name, int name_len,
210 : 0 : u_char*& xname, int& xlen)
211 : : {
212 : : // Taken from tcpdump's smbutil.c.
213 : :
214 : 0 : xname = 0;
215 : :
216 [ # # ]: 0 : if ( name_len < 1 )
217 : 0 : return 0;
218 : :
219 : 0 : int len = (*name++) / 2;
220 : 0 : xlen = len;
221 : :
222 [ # # ][ # # ]: 0 : if ( len > 30 || len < 1 || name_len < len )
[ # # ]
223 : 0 : return 0;
224 : :
225 : 0 : u_char* convert_name = new u_char[len + 1];
226 : 0 : *convert_name = 0;
227 : 0 : xname = convert_name;
228 : :
229 [ # # ]: 0 : while ( len-- )
230 : : {
231 [ # # ][ # # ]: 0 : if ( name[0] < 'A' || name[0] > 'P' ||
[ # # ][ # # ]
232 : : name[1] < 'A' || name[1] > 'P' )
233 : : {
234 : 0 : *convert_name = 0;
235 : 0 : return 0;
236 : : }
237 : :
238 : 0 : *convert_name = ((name[0] - 'A') << 4) + (name[1] - 'A');
239 : 0 : name += 2;
240 : 0 : ++convert_name;
241 : : }
242 : :
243 : 0 : *convert_name = 0;
244 : :
245 : 0 : return 1;
246 : : }
247 : :
248 : : int NetbiosSSN_Interpreter::ParseSessionReq(const u_char* data, int len,
249 : 0 : int is_query)
250 : : {
251 [ # # ]: 0 : if ( ! is_query )
252 : 0 : analyzer->Weird("netbios_server_session_request");
253 : :
254 : : u_char* xname;
255 : : int xlen;
256 : :
257 [ # # ]: 0 : if ( ConvertName(data, len, xname, xlen) )
258 : 0 : Event(netbios_session_request, xname, xlen);
259 : :
260 : 0 : delete xname;
261 : :
262 : 0 : return 0;
263 : : }
264 : :
265 : : int NetbiosSSN_Interpreter::ParseSessionPosResp(const u_char* data, int len,
266 : 0 : int is_query)
267 : : {
268 [ # # ]: 0 : if ( is_query )
269 : 0 : analyzer->Weird("netbios_client_session_reply");
270 : :
271 : 0 : Event(netbios_session_accepted, data, len);
272 : :
273 : 0 : return 0;
274 : : }
275 : :
276 : : int NetbiosSSN_Interpreter::ParseSessionNegResp(const u_char* data, int len,
277 : 0 : int is_query)
278 : : {
279 [ # # ]: 0 : if ( is_query )
280 : 0 : analyzer->Weird("netbios_client_session_reply");
281 : :
282 : 0 : Event(netbios_session_rejected, data, len);
283 : :
284 : : #if 0
285 : : case 0x80:
286 : : printf("Not listening on called name\n");
287 : : break;
288 : : case 0x81:
289 : : printf("Not listening for calling name\n");
290 : : break;
291 : : case 0x82:
292 : : printf("Called name not present\n");
293 : : break;
294 : : case 0x83:
295 : : printf("Called name present, but insufficient resources\n");
296 : : break;
297 : : default:
298 : : printf("Unspecified error 0x%X\n",ecode);
299 : : break;
300 : : #endif
301 : :
302 : 0 : return 0;
303 : : }
304 : :
305 : : int NetbiosSSN_Interpreter::ParseRetArgResp(const u_char* data, int len,
306 : 0 : int is_query)
307 : : {
308 [ # # ]: 0 : if ( is_query )
309 : 0 : analyzer->Weird("netbios_client_session_reply");
310 : :
311 : 0 : Event(netbios_session_ret_arg_resp, data, len);
312 : :
313 : 0 : return 0;
314 : : }
315 : :
316 : : int NetbiosSSN_Interpreter::ParseKeepAlive(const u_char* data, int len,
317 : 0 : int is_query)
318 : : {
319 : 0 : Event(netbios_session_keepalive, data, len);
320 : :
321 : 0 : return 0;
322 : : }
323 : :
324 : : void NetbiosSSN_Interpreter::Event(EventHandlerPtr event, const u_char* data,
325 : 0 : int len, int is_orig)
326 : : {
327 [ # # ]: 0 : if ( ! event )
328 : 0 : return;
329 : :
330 : 0 : val_list* vl = new val_list;
331 : 0 : vl->append(analyzer->BuildConnVal());
332 [ # # ]: 0 : if ( is_orig >= 0 )
333 : 0 : vl->append(new Val(is_orig, TYPE_BOOL));
334 : 0 : vl->append(new StringVal(new BroString(data, len, 0)));
335 : :
336 : 0 : analyzer->ConnectionEvent(event, vl);
337 : : }
338 : :
339 : :
340 : : Contents_NetbiosSSN::Contents_NetbiosSSN(Connection* conn, bool orig,
341 : 0 : NetbiosSSN_Interpreter* arg_interp)
342 : 0 : : TCP_SupportAnalyzer(AnalyzerTag::Contents_NetbiosSSN, conn, orig)
343 : : {
344 : 0 : interp = arg_interp;
345 : 0 : type = flags = msg_size = 0;
346 : 0 : msg_buf = 0;
347 : 0 : buf_n = msg_size = 0;
348 : 0 : state = NETBIOS_SSN_TYPE;
349 : 0 : }
350 : :
351 : 0 : Contents_NetbiosSSN::~Contents_NetbiosSSN()
352 : : {
353 [ # # ][ # # ]: 0 : delete [] msg_buf;
[ # # ]
354 [ # # ][ # # ]: 0 : }
[ # # ]
355 : :
356 : 0 : void Contents_NetbiosSSN::Flush()
357 : : {
358 [ # # ]: 0 : if ( buf_n > 0 )
359 : : { // Deliver partial message.
360 : 0 : interp->ParseMessage(type, flags, msg_buf, buf_n, IsOrig());
361 : 0 : msg_size = 0;
362 : : }
363 : 0 : }
364 : :
365 : 0 : void Contents_NetbiosSSN::DeliverStream(int len, const u_char* data, bool orig)
366 : : {
367 : 0 : TCP_SupportAnalyzer::DeliverStream(len, data, orig);
368 : :
369 [ # # ]: 0 : if ( state == NETBIOS_SSN_TYPE )
370 : : {
371 : 0 : type = *data;
372 : 0 : state = NETBIOS_SSN_FLAGS;
373 : :
374 : 0 : ++data;
375 : 0 : --len;
376 : :
377 [ # # ]: 0 : if ( len == 0 )
378 : 0 : return;
379 : : }
380 : :
381 [ # # ]: 0 : if ( state == NETBIOS_SSN_FLAGS )
382 : : {
383 : 0 : flags = *data;
384 : 0 : state = NETBIOS_SSN_LEN_HI;
385 : :
386 : 0 : ++data;
387 : 0 : --len;
388 : :
389 [ # # ]: 0 : if ( len == 0 )
390 : 0 : return;
391 : : }
392 : :
393 [ # # ]: 0 : if ( state == NETBIOS_SSN_LEN_HI )
394 : : {
395 : 0 : msg_size = (*data) << 8;
396 : 0 : state = NETBIOS_SSN_LEN_LO;
397 : :
398 : 0 : ++data;
399 : 0 : --len;
400 : :
401 [ # # ]: 0 : if ( len == 0 )
402 : 0 : return;
403 : : }
404 : :
405 [ # # ]: 0 : if ( state == NETBIOS_SSN_LEN_LO )
406 : : {
407 : 0 : msg_size += *data;
408 : 0 : state = NETBIOS_SSN_BUF;
409 : :
410 : 0 : buf_n = 0;
411 : :
412 [ # # ]: 0 : if ( msg_buf )
413 : : {
414 [ # # ]: 0 : if ( buf_len < msg_size )
415 : : {
416 [ # # ]: 0 : delete [] msg_buf;
417 : 0 : buf_len = msg_size;
418 : 0 : msg_buf = new u_char[buf_len];
419 : : }
420 : : }
421 : : else
422 : : {
423 : 0 : buf_len = msg_size;
424 [ # # ]: 0 : if ( buf_len > 0 )
425 : 0 : msg_buf = new u_char[buf_len];
426 : : }
427 : :
428 : 0 : ++data;
429 : 0 : --len;
430 : :
431 [ # # ][ # # ]: 0 : if ( len == 0 && msg_size != 0 )
432 : 0 : return;
433 : : }
434 : :
435 [ # # ]: 0 : if ( state != NETBIOS_SSN_BUF )
436 : 0 : Conn()->Internal("state inconsistency in Contents_NetbiosSSN::Deliver");
437 : :
438 : : int n;
439 [ # # ][ # # ]: 0 : for ( n = 0; buf_n < msg_size && n < len; ++n )
440 : 0 : msg_buf[buf_n++] = data[n];
441 : :
442 [ # # ]: 0 : if ( buf_n < msg_size )
443 : : // Haven't filled up the message buffer yet, no more to do.
444 : 0 : return;
445 : :
446 : 0 : (void) interp->ParseMessage(type, flags, msg_buf, msg_size, IsOrig());
447 : 0 : buf_n = 0;
448 : :
449 : 0 : state = NETBIOS_SSN_TYPE;
450 : :
451 [ # # ]: 0 : if ( n < len )
452 : : // More data to munch on.
453 : 0 : DeliverStream(len - n, data + n, orig);
454 : : }
455 : :
456 : 0 : NetbiosSSN_Analyzer::NetbiosSSN_Analyzer(Connection* conn)
457 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::NetbiosSSN, conn)
458 : : {
459 : 0 : smb_session = new SMB_Session(this);
460 : 0 : interp = new NetbiosSSN_Interpreter(this, smb_session);
461 : 0 : orig_netbios = resp_netbios = 0;
462 : 0 : did_session_done = 0;
463 : :
464 [ # # # # ]: 0 : if ( Conn()->ConnTransport() == TRANSPORT_TCP )
465 : : {
466 : 0 : orig_netbios = new Contents_NetbiosSSN(conn, true, interp);
467 : 0 : resp_netbios = new Contents_NetbiosSSN(conn, false, interp);
468 : 0 : AddSupportAnalyzer(orig_netbios);
469 : 0 : AddSupportAnalyzer(resp_netbios);
470 : : }
471 : : else
472 : : {
473 : 0 : ADD_ANALYZER_TIMER(&NetbiosSSN_Analyzer::ExpireTimer,
474 : : network_time + netbios_ssn_session_timeout, 1,
475 : : TIMER_NB_EXPIRE);
476 : : }
477 : 0 : }
478 : :
479 : 0 : NetbiosSSN_Analyzer::~NetbiosSSN_Analyzer()
480 : : {
481 : 0 : delete interp;
482 [ # # # # ]: 0 : delete smb_session;
[ # # ]
483 [ # # ][ # # ]: 0 : }
[ # # ]
484 : :
485 : 0 : void NetbiosSSN_Analyzer::Done()
486 : : {
487 : 0 : TCP_ApplicationAnalyzer::Done();
488 : 0 : interp->Timeout();
489 : :
490 [ # # # # ]: 0 : if ( Conn()->ConnTransport() == TRANSPORT_UDP && ! did_session_done )
[ # # ]
491 : 0 : Event(udp_session_done);
492 : : else
493 : 0 : interp->Timeout();
494 : 0 : }
495 : :
496 : 0 : void NetbiosSSN_Analyzer::EndpointEOF(bool orig)
497 : : {
498 : 0 : TCP_ApplicationAnalyzer::EndpointEOF(orig);
499 : :
500 [ # # ]: 0 : (orig ? orig_netbios : resp_netbios)->Flush();
501 : 0 : }
502 : :
503 : : void NetbiosSSN_Analyzer::ConnectionClosed(TCP_Endpoint* endpoint,
504 : 0 : TCP_Endpoint* peer, int gen_event)
505 : : {
506 : 0 : TCP_ApplicationAnalyzer::ConnectionClosed(endpoint, peer, gen_event);
507 : :
508 : : // Question: Why do we flush *both* endpoints upon connection close?
509 : : // orig_netbios->Flush();
510 : : // resp_netbios->Flush();
511 : 0 : }
512 : :
513 : : void NetbiosSSN_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
514 : 0 : int seq, const IP_Hdr* ip, int caplen)
515 : : {
516 : 0 : TCP_ApplicationAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
517 : :
518 [ # # ]: 0 : if ( orig )
519 : 0 : interp->ParseMessageUDP(data, len, 1);
520 : : else
521 : 0 : interp->ParseMessageUDP(data, len, 0);
522 : 0 : }
523 : :
524 : 0 : void NetbiosSSN_Analyzer::ExpireTimer(double t)
525 : : {
526 : : // The - 1.0 in the following is to allow 1 second for the
527 : : // common case of a single request followed by a single reply,
528 : : // so we don't needlessly set the timer twice in that case.
529 [ # # ][ # # ]: 0 : if ( terminating ||
[ # # ]
530 : : network_time - Conn()->LastTime() >=
531 : : netbios_ssn_session_timeout - 1.0 )
532 : : {
533 : 0 : Event(connection_timeout);
534 : 0 : sessions->Remove(Conn());
535 : : }
536 : : else
537 : 0 : ADD_ANALYZER_TIMER(&NetbiosSSN_Analyzer::ExpireTimer,
538 : : t + netbios_ssn_session_timeout,
539 : : 1, TIMER_NB_EXPIRE);
540 [ + - ][ + - ]: 6 : }
|