print-smb.c revision 1.9 1 /*
2 * Copyright (C) Andrew Tridgell 1995-1999
3 *
4 * This software may be distributed either under the terms of the
5 * BSD-style license that accompanies tcpdump or the GNU GPL version 2
6 * or later
7 */
8
9 #include <sys/cdefs.h>
10 #ifndef lint
11 __RCSID("$NetBSD: print-smb.c,v 1.9 2023/08/17 20:19:40 christos Exp $");
12 #endif
13
14 /* \summary: SMB/CIFS printer */
15
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include "netdissect-stdinc.h"
21
22 #include <string.h>
23
24 #include "netdissect.h"
25 #include "extract.h"
26 #include "smb.h"
27
28
29 static int request = 0;
30 static int unicodestr = 0;
31
32 extern const u_char *startbuf;
33
34 const u_char *startbuf = NULL;
35
36 struct smbdescript {
37 const char *req_f1;
38 const char *req_f2;
39 const char *rep_f1;
40 const char *rep_f2;
41 void (*fn)(netdissect_options *, const u_char *, const u_char *, const u_char *, const u_char *);
42 };
43
44 struct smbdescriptint {
45 const char *req_f1;
46 const char *req_f2;
47 const char *rep_f1;
48 const char *rep_f2;
49 void (*fn)(netdissect_options *, const u_char *, const u_char *, u_int, u_int);
50 };
51
52 struct smbfns
53 {
54 int id;
55 const char *name;
56 int flags;
57 struct smbdescript descript;
58 };
59
60 struct smbfnsint
61 {
62 int id;
63 const char *name;
64 int flags;
65 struct smbdescriptint descript;
66 };
67
68 #define DEFDESCRIPT { NULL, NULL, NULL, NULL, NULL }
69
70 #define FLG_CHAIN (1 << 0)
71
72 static const struct smbfns *
73 smbfind(int id, const struct smbfns *list)
74 {
75 int sindex;
76
77 for (sindex = 0; list[sindex].name; sindex++)
78 if (list[sindex].id == id)
79 return(&list[sindex]);
80
81 return(&list[0]);
82 }
83
84 static const struct smbfnsint *
85 smbfindint(int id, const struct smbfnsint *list)
86 {
87 int sindex;
88
89 for (sindex = 0; list[sindex].name; sindex++)
90 if (list[sindex].id == id)
91 return(&list[sindex]);
92
93 return(&list[0]);
94 }
95
96 static void
97 trans2_findfirst(netdissect_options *ndo,
98 const u_char *param, const u_char *data, u_int pcnt, u_int dcnt)
99 {
100 const char *fmt;
101
102 if (request)
103 fmt = "Attribute=[A]\nSearchCount=[u]\nFlags=[w]\nLevel=[uP4]\nFile=[S]\n";
104 else
105 fmt = "Handle=[w]\nCount=[u]\nEOS=[w]\nEoffset=[u]\nLastNameOfs=[w]\n";
106
107 smb_fdata(ndo, param, fmt, param + pcnt, unicodestr);
108 if (dcnt) {
109 ND_PRINT("data:\n");
110 smb_data_print(ndo, data, dcnt);
111 }
112 }
113
114 static void
115 trans2_qfsinfo(netdissect_options *ndo,
116 const u_char *param, const u_char *data, u_int pcnt, u_int dcnt)
117 {
118 static u_int level = 0;
119 const char *fmt="";
120
121 if (request) {
122 level = GET_LE_U_2(param);
123 fmt = "InfoLevel=[u]\n";
124 smb_fdata(ndo, param, fmt, param + pcnt, unicodestr);
125 } else {
126 switch (level) {
127 case 1:
128 fmt = "idFileSystem=[W]\nSectorUnit=[U]\nUnit=[U]\nAvail=[U]\nSectorSize=[u]\n";
129 break;
130 case 2:
131 fmt = "CreationTime=[T2]VolNameLength=[lb]\nVolumeLabel=[c]\n";
132 break;
133 case 0x105:
134 fmt = "Capabilities=[W]\nMaxFileLen=[U]\nVolNameLen=[lU]\nVolume=[C]\n";
135 break;
136 default:
137 fmt = "UnknownLevel\n";
138 break;
139 }
140 smb_fdata(ndo, data, fmt, data + dcnt, unicodestr);
141 }
142 if (dcnt) {
143 ND_PRINT("data:\n");
144 smb_data_print(ndo, data, dcnt);
145 }
146 }
147
148 static const struct smbfnsint trans2_fns[] = {
149 { 0, "TRANSACT2_OPEN", 0,
150 { "Flags2=[w]\nMode=[w]\nSearchAttrib=[A]\nAttrib=[A]\nTime=[T2]\nOFun=[w]\nSize=[U]\nRes=([w, w, w, w, w])\nPath=[S]",
151 NULL,
152 "Handle=[u]\nAttrib=[A]\nTime=[T2]\nSize=[U]\nAccess=[w]\nType=[w]\nState=[w]\nAction=[w]\nInode=[W]\nOffErr=[u]\n|EALength=[u]\n",
153 NULL, NULL }},
154 { 1, "TRANSACT2_FINDFIRST", 0,
155 { NULL, NULL, NULL, NULL, trans2_findfirst }},
156 { 2, "TRANSACT2_FINDNEXT", 0, DEFDESCRIPT },
157 { 3, "TRANSACT2_QFSINFO", 0,
158 { NULL, NULL, NULL, NULL, trans2_qfsinfo }},
159 { 4, "TRANSACT2_SETFSINFO", 0, DEFDESCRIPT },
160 { 5, "TRANSACT2_QPATHINFO", 0, DEFDESCRIPT },
161 { 6, "TRANSACT2_SETPATHINFO", 0, DEFDESCRIPT },
162 { 7, "TRANSACT2_QFILEINFO", 0, DEFDESCRIPT },
163 { 8, "TRANSACT2_SETFILEINFO", 0, DEFDESCRIPT },
164 { 9, "TRANSACT2_FSCTL", 0, DEFDESCRIPT },
165 { 10, "TRANSACT2_IOCTL", 0, DEFDESCRIPT },
166 { 11, "TRANSACT2_FINDNOTIFYFIRST", 0, DEFDESCRIPT },
167 { 12, "TRANSACT2_FINDNOTIFYNEXT", 0, DEFDESCRIPT },
168 { 13, "TRANSACT2_MKDIR", 0, DEFDESCRIPT },
169 { -1, NULL, 0, DEFDESCRIPT }
170 };
171
172
173 static void
174 print_trans2(netdissect_options *ndo,
175 const u_char *words, const u_char *dat, const u_char *buf, const u_char *maxbuf)
176 {
177 u_int bcc;
178 static const struct smbfnsint *fn = &trans2_fns[0];
179 const u_char *data, *param;
180 const u_char *w = words + 1;
181 const char *f1 = NULL, *f2 = NULL;
182 u_int pcnt, dcnt;
183
184 ND_TCHECK_1(words);
185 if (request) {
186 ND_TCHECK_2(w + (14 * 2));
187 pcnt = GET_LE_U_2(w + 9 * 2);
188 param = buf + GET_LE_U_2(w + 10 * 2);
189 dcnt = GET_LE_U_2(w + 11 * 2);
190 data = buf + GET_LE_U_2(w + 12 * 2);
191 fn = smbfindint(GET_LE_U_2(w + 14 * 2), trans2_fns);
192 } else {
193 if (GET_U_1(words) == 0) {
194 ND_PRINT("%s\n", fn->name);
195 ND_PRINT("Trans2Interim\n");
196 return;
197 }
198 ND_TCHECK_2(w + (7 * 2));
199 pcnt = GET_LE_U_2(w + 3 * 2);
200 param = buf + GET_LE_U_2(w + 4 * 2);
201 dcnt = GET_LE_U_2(w + 6 * 2);
202 data = buf + GET_LE_U_2(w + 7 * 2);
203 }
204
205 ND_PRINT("%s param_length=%u data_length=%u\n", fn->name, pcnt, dcnt);
206
207 if (request) {
208 if (GET_U_1(words) == 8) {
209 smb_fdata(ndo, words + 1,
210 "Trans2Secondary\nTotParam=[u]\nTotData=[u]\nParamCnt=[u]\nParamOff=[u]\nParamDisp=[u]\nDataCnt=[u]\nDataOff=[u]\nDataDisp=[u]\nHandle=[u]\n",
211 maxbuf, unicodestr);
212 return;
213 } else {
214 smb_fdata(ndo, words + 1,
215 "TotParam=[u]\nTotData=[u]\nMaxParam=[u]\nMaxData=[u]\nMaxSetup=[b][P1]\nFlags=[w]\nTimeOut=[D]\nRes1=[w]\nParamCnt=[u]\nParamOff=[u]\nDataCnt=[u]\nDataOff=[u]\nSetupCnt=[b][P1]\n",
216 words + 1 + 14 * 2, unicodestr);
217 }
218 f1 = fn->descript.req_f1;
219 f2 = fn->descript.req_f2;
220 } else {
221 smb_fdata(ndo, words + 1,
222 "TotParam=[u]\nTotData=[u]\nRes1=[w]\nParamCnt=[u]\nParamOff=[u]\nParamDisp[u]\nDataCnt=[u]\nDataOff=[u]\nDataDisp=[u]\nSetupCnt=[b][P1]\n",
223 words + 1 + 10 * 2, unicodestr);
224 f1 = fn->descript.rep_f1;
225 f2 = fn->descript.rep_f2;
226 }
227
228 bcc = GET_LE_U_2(dat);
229 ND_PRINT("smb_bcc=%u\n", bcc);
230 if (fn->descript.fn)
231 (*fn->descript.fn)(ndo, param, data, pcnt, dcnt);
232 else {
233 smb_fdata(ndo, param, f1 ? f1 : "Parameters=\n", param + pcnt, unicodestr);
234 smb_fdata(ndo, data, f2 ? f2 : "Data=\n", data + dcnt, unicodestr);
235 }
236 return;
237 trunc:
238 nd_print_trunc(ndo);
239 }
240
241 static void
242 print_browse(netdissect_options *ndo,
243 const u_char *param, u_int paramlen, const u_char *data, u_int datalen)
244 {
245 const u_char *maxbuf = data + datalen;
246 u_int command;
247
248 command = GET_U_1(data);
249
250 smb_fdata(ndo, param, "BROWSE PACKET\n|Param ", param+paramlen, unicodestr);
251
252 switch (command) {
253 case 0xF:
254 data = smb_fdata(ndo, data,
255 "BROWSE PACKET:\nType=[B] (LocalMasterAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nElectionVersion=[w]\nBrowserConstant=[w]\n",
256 maxbuf, unicodestr);
257 break;
258
259 case 0x1:
260 data = smb_fdata(ndo, data,
261 "BROWSE PACKET:\nType=[B] (HostAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nElectionVersion=[w]\nBrowserConstant=[w]\n",
262 maxbuf, unicodestr);
263 break;
264
265 case 0x2:
266 data = smb_fdata(ndo, data,
267 "BROWSE PACKET:\nType=[B] (AnnouncementRequest)\nFlags=[B]\nReplySystemName=[S]\n",
268 maxbuf, unicodestr);
269 break;
270
271 case 0xc:
272 data = smb_fdata(ndo, data,
273 "BROWSE PACKET:\nType=[B] (WorkgroupAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nCommentPointer=[W]\nServerName=[S]\n",
274 maxbuf, unicodestr);
275 break;
276
277 case 0x8:
278 data = smb_fdata(ndo, data,
279 "BROWSE PACKET:\nType=[B] (ElectionFrame)\nElectionVersion=[B]\nOSSummary=[W]\nUptime=[(W, W)]\nServerName=[S]\n",
280 maxbuf, unicodestr);
281 break;
282
283 case 0xb:
284 data = smb_fdata(ndo, data,
285 "BROWSE PACKET:\nType=[B] (BecomeBackupBrowser)\nName=[S]\n",
286 maxbuf, unicodestr);
287 break;
288
289 case 0x9:
290 data = smb_fdata(ndo, data,
291 "BROWSE PACKET:\nType=[B] (GetBackupList)\nListCount?=[B]\nToken=[W]\n",
292 maxbuf, unicodestr);
293 break;
294
295 case 0xa:
296 data = smb_fdata(ndo, data,
297 "BROWSE PACKET:\nType=[B] (BackupListResponse)\nServerCount?=[B]\nToken=[W]\n*Name=[S]\n",
298 maxbuf, unicodestr);
299 break;
300
301 case 0xd:
302 data = smb_fdata(ndo, data,
303 "BROWSE PACKET:\nType=[B] (MasterAnnouncement)\nMasterName=[S]\n",
304 maxbuf, unicodestr);
305 break;
306
307 case 0xe:
308 data = smb_fdata(ndo, data,
309 "BROWSE PACKET:\nType=[B] (ResetBrowser)\nOptions=[B]\n", maxbuf, unicodestr);
310 break;
311
312 default:
313 data = smb_fdata(ndo, data, "Unknown Browser Frame ", maxbuf, unicodestr);
314 break;
315 }
316 }
317
318
319 static void
320 print_ipc(netdissect_options *ndo,
321 const u_char *param, u_int paramlen, const u_char *data, u_int datalen)
322 {
323 if (paramlen)
324 smb_fdata(ndo, param, "Command=[w]\nStr1=[S]\nStr2=[S]\n", param + paramlen,
325 unicodestr);
326 if (datalen)
327 smb_fdata(ndo, data, "IPC ", data + datalen, unicodestr);
328 }
329
330
331 static void
332 print_trans(netdissect_options *ndo,
333 const u_char *words, const u_char *data1, const u_char *buf, const u_char *maxbuf)
334 {
335 u_int bcc;
336 const char *f1, *f2, *f3, *f4;
337 const u_char *data, *param;
338 const u_char *w = words + 1;
339 u_int datalen, paramlen;
340
341 if (request) {
342 ND_TCHECK_2(w + (12 * 2));
343 paramlen = GET_LE_U_2(w + 9 * 2);
344 param = buf + GET_LE_U_2(w + 10 * 2);
345 datalen = GET_LE_U_2(w + 11 * 2);
346 data = buf + GET_LE_U_2(w + 12 * 2);
347 f1 = "TotParamCnt=[u]\nTotDataCnt=[u]\nMaxParmCnt=[u]\nMaxDataCnt=[u]\nMaxSCnt=[u]\nTransFlags=[w]\nRes1=[w]\nRes2=[w]\nRes3=[w]\nParamCnt=[u]\nParamOff=[u]\nDataCnt=[u]\nDataOff=[u]\nSUCnt=[u]\n";
348 f2 = "|Name=[S]\n";
349 f3 = "|Param ";
350 f4 = "|Data ";
351 } else {
352 ND_TCHECK_2(w + (7 * 2));
353 paramlen = GET_LE_U_2(w + 3 * 2);
354 param = buf + GET_LE_U_2(w + 4 * 2);
355 datalen = GET_LE_U_2(w + 6 * 2);
356 data = buf + GET_LE_U_2(w + 7 * 2);
357 f1 = "TotParamCnt=[u]\nTotDataCnt=[u]\nRes1=[u]\nParamCnt=[u]\nParamOff=[u]\nRes2=[u]\nDataCnt=[u]\nDataOff=[u]\nRes3=[u]\nLsetup=[u]\n";
358 f2 = "|Unknown ";
359 f3 = "|Param ";
360 f4 = "|Data ";
361 }
362
363 smb_fdata(ndo, words + 1, f1,
364 ND_MIN(words + 1 + 2 * GET_U_1(words), maxbuf),
365 unicodestr);
366
367 bcc = GET_LE_U_2(data1);
368 ND_PRINT("smb_bcc=%u\n", bcc);
369 if (bcc > 0) {
370 smb_fdata(ndo, data1 + 2, f2, maxbuf - (paramlen + datalen), unicodestr);
371
372 #define MAILSLOT_BROWSE_STR "\\MAILSLOT\\BROWSE"
373 ND_TCHECK_LEN(data1 + 2, strlen(MAILSLOT_BROWSE_STR) + 1);
374 if (strcmp((const char *)(data1 + 2), MAILSLOT_BROWSE_STR) == 0) {
375 print_browse(ndo, param, paramlen, data, datalen);
376 return;
377 }
378 #undef MAILSLOT_BROWSE_STR
379
380 #define PIPE_LANMAN_STR "\\PIPE\\LANMAN"
381 ND_TCHECK_LEN(data1 + 2, strlen(PIPE_LANMAN_STR) + 1);
382 if (strcmp((const char *)(data1 + 2), PIPE_LANMAN_STR) == 0) {
383 print_ipc(ndo, param, paramlen, data, datalen);
384 return;
385 }
386 #undef PIPE_LANMAN_STR
387
388 if (paramlen)
389 smb_fdata(ndo, param, f3, ND_MIN(param + paramlen, maxbuf), unicodestr);
390 if (datalen)
391 smb_fdata(ndo, data, f4, ND_MIN(data + datalen, maxbuf), unicodestr);
392 }
393 return;
394 trunc:
395 nd_print_trunc(ndo);
396 }
397
398
399 static void
400 print_negprot(netdissect_options *ndo,
401 const u_char *words, const u_char *data, const u_char *buf _U_, const u_char *maxbuf)
402 {
403 u_int wct, bcc;
404 const char *f1 = NULL, *f2 = NULL;
405
406 wct = GET_U_1(words);
407 if (request)
408 f2 = "*|Dialect=[Y]\n";
409 else {
410 if (wct == 1)
411 f1 = "Core Protocol\nDialectIndex=[u]";
412 else if (wct == 17)
413 f1 = "NT1 Protocol\nDialectIndex=[u]\nSecMode=[B]\nMaxMux=[u]\nNumVcs=[u]\nMaxBuffer=[U]\nRawSize=[U]\nSessionKey=[W]\nCapabilities=[W]\nServerTime=[T3]TimeZone=[u]\nCryptKey=";
414 else if (wct == 13)
415 f1 = "Coreplus/Lanman1/Lanman2 Protocol\nDialectIndex=[u]\nSecMode=[w]\nMaxXMit=[u]\nMaxMux=[u]\nMaxVcs=[u]\nBlkMode=[w]\nSessionKey=[W]\nServerTime=[T1]TimeZone=[u]\nRes=[W]\nCryptKey=";
416 }
417
418 if (f1)
419 smb_fdata(ndo, words + 1, f1, ND_MIN(words + 1 + wct * 2, maxbuf),
420 unicodestr);
421 else
422 smb_data_print(ndo, words + 1, ND_MIN(wct * 2, ND_BYTES_BETWEEN(maxbuf, words + 1)));
423
424 bcc = GET_LE_U_2(data);
425 ND_PRINT("smb_bcc=%u\n", bcc);
426 if (bcc > 0) {
427 if (f2)
428 smb_fdata(ndo, data + 2, f2, ND_MIN(data + 2 + GET_LE_U_2(data),
429 maxbuf), unicodestr);
430 else
431 smb_data_print(ndo, data + 2,
432 ND_MIN(GET_LE_U_2(data), ND_BYTES_BETWEEN(maxbuf, data + 2)));
433 }
434 }
435
436 static void
437 print_sesssetup(netdissect_options *ndo,
438 const u_char *words, const u_char *data, const u_char *buf _U_, const u_char *maxbuf)
439 {
440 u_int wct, bcc;
441 const char *f1 = NULL, *f2 = NULL;
442
443 wct = GET_U_1(words);
444 if (request) {
445 if (wct == 10)
446 f1 = "Com2=[w]\nOff2=[u]\nBufSize=[u]\nMpxMax=[u]\nVcNum=[u]\nSessionKey=[W]\nPassLen=[u]\nCryptLen=[u]\nCryptOff=[u]\nPass&Name=\n";
447 else
448 f1 = "Com2=[B]\nRes1=[B]\nOff2=[u]\nMaxBuffer=[u]\nMaxMpx=[u]\nVcNumber=[u]\nSessionKey=[W]\nCaseInsensitivePasswordLength=[u]\nCaseSensitivePasswordLength=[u]\nRes=[W]\nCapabilities=[W]\nPass1&Pass2&Account&Domain&OS&LanMan=\n";
449 } else {
450 if (wct == 3) {
451 f1 = "Com2=[w]\nOff2=[u]\nAction=[w]\n";
452 } else if (wct == 13) {
453 f1 = "Com2=[B]\nRes=[B]\nOff2=[u]\nAction=[w]\n";
454 f2 = "NativeOS=[S]\nNativeLanMan=[S]\nPrimaryDomain=[S]\n";
455 }
456 }
457
458 if (f1)
459 smb_fdata(ndo, words + 1, f1, ND_MIN(words + 1 + wct * 2, maxbuf),
460 unicodestr);
461 else
462 smb_data_print(ndo, words + 1, ND_MIN(wct * 2, ND_BYTES_BETWEEN(maxbuf, words + 1)));
463
464 bcc = GET_LE_U_2(data);
465 ND_PRINT("smb_bcc=%u\n", bcc);
466 if (bcc > 0) {
467 if (f2)
468 smb_fdata(ndo, data + 2, f2, ND_MIN(data + 2 + GET_LE_U_2(data),
469 maxbuf), unicodestr);
470 else
471 smb_data_print(ndo, data + 2,
472 ND_MIN(GET_LE_U_2(data), ND_BYTES_BETWEEN(maxbuf, data + 2)));
473 }
474 }
475
476 static void
477 print_lockingandx(netdissect_options *ndo,
478 const u_char *words, const u_char *data, const u_char *buf _U_, const u_char *maxbuf)
479 {
480 u_int wct, bcc;
481 const u_char *maxwords;
482 const char *f1 = NULL, *f2 = NULL;
483
484 wct = GET_U_1(words);
485 if (request) {
486 f1 = "Com2=[w]\nOff2=[u]\nHandle=[u]\nLockType=[w]\nTimeOut=[D]\nUnlockCount=[u]\nLockCount=[u]\n";
487 if (GET_U_1(words + 7) & 0x10)
488 f2 = "*Process=[u]\n[P2]Offset=[M]\nLength=[M]\n";
489 else
490 f2 = "*Process=[u]\nOffset=[D]\nLength=[U]\n";
491 } else {
492 f1 = "Com2=[w]\nOff2=[u]\n";
493 }
494
495 maxwords = ND_MIN(words + 1 + wct * 2, maxbuf);
496 if (wct)
497 smb_fdata(ndo, words + 1, f1, maxwords, unicodestr);
498
499 bcc = GET_LE_U_2(data);
500 ND_PRINT("smb_bcc=%u\n", bcc);
501 if (bcc > 0) {
502 if (f2)
503 smb_fdata(ndo, data + 2, f2, ND_MIN(data + 2 + GET_LE_U_2(data),
504 maxbuf), unicodestr);
505 else
506 smb_data_print(ndo, data + 2,
507 ND_MIN(GET_LE_U_2(data), ND_BYTES_BETWEEN(maxbuf, data + 2)));
508 }
509 }
510
511
512 static const struct smbfns smb_fns[] = {
513 { -1, "SMBunknown", 0, DEFDESCRIPT },
514
515 { SMBtcon, "SMBtcon", 0,
516 { NULL, "Path=[Z]\nPassword=[Z]\nDevice=[Z]\n",
517 "MaxXmit=[u]\nTreeId=[u]\n", NULL,
518 NULL } },
519
520 { SMBtdis, "SMBtdis", 0, DEFDESCRIPT },
521 { SMBexit, "SMBexit", 0, DEFDESCRIPT },
522 { SMBioctl, "SMBioctl", 0, DEFDESCRIPT },
523
524 { SMBecho, "SMBecho", 0,
525 { "ReverbCount=[u]\n", NULL,
526 "SequenceNum=[u]\n", NULL,
527 NULL } },
528
529 { SMBulogoffX, "SMBulogoffX", FLG_CHAIN, DEFDESCRIPT },
530
531 { SMBgetatr, "SMBgetatr", 0,
532 { NULL, "Path=[Z]\n",
533 "Attribute=[A]\nTime=[T2]Size=[U]\nRes=([w,w,w,w,w])\n", NULL,
534 NULL } },
535
536 { SMBsetatr, "SMBsetatr", 0,
537 { "Attribute=[A]\nTime=[T2]Res=([w,w,w,w,w])\n", "Path=[Z]\n",
538 NULL, NULL, NULL } },
539
540 { SMBchkpth, "SMBchkpth", 0,
541 { NULL, "Path=[Z]\n", NULL, NULL, NULL } },
542
543 { SMBsearch, "SMBsearch", 0,
544 { "Count=[u]\nAttrib=[A]\n",
545 "Path=[Z]\nBlkType=[B]\nBlkLen=[u]\n|Res1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\nRes2=[W]\n",
546 "Count=[u]\n",
547 "BlkType=[B]\nBlkLen=[u]\n*\nRes1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\nRes2=[W]\nAttrib=[a]\nTime=[T1]Size=[U]\nName=[s13]\n",
548 NULL } },
549
550 { SMBopen, "SMBopen", 0,
551 { "Mode=[w]\nAttribute=[A]\n", "Path=[Z]\n",
552 "Handle=[u]\nOAttrib=[A]\nTime=[T2]Size=[U]\nAccess=[w]\n",
553 NULL, NULL } },
554
555 { SMBcreate, "SMBcreate", 0,
556 { "Attrib=[A]\nTime=[T2]", "Path=[Z]\n", "Handle=[u]\n", NULL, NULL } },
557
558 { SMBmknew, "SMBmknew", 0,
559 { "Attrib=[A]\nTime=[T2]", "Path=[Z]\n", "Handle=[u]\n", NULL, NULL } },
560
561 { SMBunlink, "SMBunlink", 0,
562 { "Attrib=[A]\n", "Path=[Z]\n", NULL, NULL, NULL } },
563
564 { SMBread, "SMBread", 0,
565 { "Handle=[u]\nByteCount=[u]\nOffset=[D]\nCountLeft=[u]\n", NULL,
566 "Count=[u]\nRes=([w,w,w,w])\n", NULL, NULL } },
567
568 { SMBwrite, "SMBwrite", 0,
569 { "Handle=[u]\nByteCount=[u]\nOffset=[D]\nCountLeft=[u]\n", NULL,
570 "Count=[u]\n", NULL, NULL } },
571
572 { SMBclose, "SMBclose", 0,
573 { "Handle=[u]\nTime=[T2]", NULL, NULL, NULL, NULL } },
574
575 { SMBmkdir, "SMBmkdir", 0,
576 { NULL, "Path=[Z]\n", NULL, NULL, NULL } },
577
578 { SMBrmdir, "SMBrmdir", 0,
579 { NULL, "Path=[Z]\n", NULL, NULL, NULL } },
580
581 { SMBdskattr, "SMBdskattr", 0,
582 { NULL, NULL,
583 "TotalUnits=[u]\nBlocksPerUnit=[u]\nBlockSize=[u]\nFreeUnits=[u]\nMedia=[w]\n",
584 NULL, NULL } },
585
586 { SMBmv, "SMBmv", 0,
587 { "Attrib=[A]\n", "OldPath=[Z]\nNewPath=[Z]\n", NULL, NULL, NULL } },
588
589 /*
590 * this is a Pathworks specific call, allowing the
591 * changing of the root path
592 */
593 { pSETDIR, "SMBsetdir", 0, { NULL, "Path=[Z]\n", NULL, NULL, NULL } },
594
595 { SMBlseek, "SMBlseek", 0,
596 { "Handle=[u]\nMode=[w]\nOffset=[D]\n", "Offset=[D]\n", NULL, NULL, NULL } },
597
598 { SMBflush, "SMBflush", 0, { "Handle=[u]\n", NULL, NULL, NULL, NULL } },
599
600 { SMBsplopen, "SMBsplopen", 0,
601 { "SetupLen=[u]\nMode=[w]\n", "Ident=[Z]\n", "Handle=[u]\n",
602 NULL, NULL } },
603
604 { SMBsplclose, "SMBsplclose", 0,
605 { "Handle=[u]\n", NULL, NULL, NULL, NULL } },
606
607 { SMBsplretq, "SMBsplretq", 0,
608 { "MaxCount=[u]\nStartIndex=[u]\n", NULL,
609 "Count=[u]\nIndex=[u]\n",
610 "*Time=[T2]Status=[B]\nJobID=[u]\nSize=[U]\nRes=[B]Name=[s16]\n",
611 NULL } },
612
613 { SMBsplwr, "SMBsplwr", 0,
614 { "Handle=[u]\n", NULL, NULL, NULL, NULL } },
615
616 { SMBlock, "SMBlock", 0,
617 { "Handle=[u]\nCount=[U]\nOffset=[D]\n", NULL, NULL, NULL, NULL } },
618
619 { SMBunlock, "SMBunlock", 0,
620 { "Handle=[u]\nCount=[U]\nOffset=[D]\n", NULL, NULL, NULL, NULL } },
621
622 /* CORE+ PROTOCOL FOLLOWS */
623
624 { SMBreadbraw, "SMBreadbraw", 0,
625 { "Handle=[u]\nOffset=[D]\nMaxCount=[u]\nMinCount=[u]\nTimeOut=[D]\nRes=[u]\n",
626 NULL, NULL, NULL, NULL } },
627
628 { SMBwritebraw, "SMBwritebraw", 0,
629 { "Handle=[u]\nTotalCount=[u]\nRes=[w]\nOffset=[D]\nTimeOut=[D]\nWMode=[w]\nRes2=[W]\n|DataSize=[u]\nDataOff=[u]\n",
630 NULL, "WriteRawAck", NULL, NULL } },
631
632 { SMBwritec, "SMBwritec", 0,
633 { NULL, NULL, "Count=[u]\n", NULL, NULL } },
634
635 { SMBwriteclose, "SMBwriteclose", 0,
636 { "Handle=[u]\nCount=[u]\nOffset=[D]\nTime=[T2]Res=([w,w,w,w,w,w])",
637 NULL, "Count=[u]\n", NULL, NULL } },
638
639 { SMBlockread, "SMBlockread", 0,
640 { "Handle=[u]\nByteCount=[u]\nOffset=[D]\nCountLeft=[u]\n", NULL,
641 "Count=[u]\nRes=([w,w,w,w])\n", NULL, NULL } },
642
643 { SMBwriteunlock, "SMBwriteunlock", 0,
644 { "Handle=[u]\nByteCount=[u]\nOffset=[D]\nCountLeft=[u]\n", NULL,
645 "Count=[u]\n", NULL, NULL } },
646
647 { SMBreadBmpx, "SMBreadBmpx", 0,
648 { "Handle=[u]\nOffset=[D]\nMaxCount=[u]\nMinCount=[u]\nTimeOut=[D]\nRes=[w]\n",
649 NULL,
650 "Offset=[D]\nTotCount=[u]\nRemaining=[u]\nRes=([w,w])\nDataSize=[u]\nDataOff=[u]\n",
651 NULL, NULL } },
652
653 { SMBwriteBmpx, "SMBwriteBmpx", 0,
654 { "Handle=[u]\nTotCount=[u]\nRes=[w]\nOffset=[D]\nTimeOut=[D]\nWMode=[w]\nRes2=[W]\nDataSize=[u]\nDataOff=[u]\n", NULL,
655 "Remaining=[u]\n", NULL, NULL } },
656
657 { SMBwriteBs, "SMBwriteBs", 0,
658 { "Handle=[u]\nTotCount=[u]\nOffset=[D]\nRes=[W]\nDataSize=[u]\nDataOff=[u]\n",
659 NULL, "Count=[u]\n", NULL, NULL } },
660
661 { SMBsetattrE, "SMBsetattrE", 0,
662 { "Handle=[u]\nCreationTime=[T2]AccessTime=[T2]ModifyTime=[T2]", NULL,
663 NULL, NULL, NULL } },
664
665 { SMBgetattrE, "SMBgetattrE", 0,
666 { "Handle=[u]\n", NULL,
667 "CreationTime=[T2]AccessTime=[T2]ModifyTime=[T2]Size=[U]\nAllocSize=[U]\nAttribute=[A]\n",
668 NULL, NULL } },
669
670 { SMBtranss, "SMBtranss", 0, DEFDESCRIPT },
671 { SMBioctls, "SMBioctls", 0, DEFDESCRIPT },
672
673 { SMBcopy, "SMBcopy", 0,
674 { "TreeID2=[u]\nOFun=[w]\nFlags=[w]\n", "Path=[S]\nNewPath=[S]\n",
675 "CopyCount=[u]\n", "|ErrStr=[S]\n", NULL } },
676
677 { SMBmove, "SMBmove", 0,
678 { "TreeID2=[u]\nOFun=[w]\nFlags=[w]\n", "Path=[S]\nNewPath=[S]\n",
679 "MoveCount=[u]\n", "|ErrStr=[S]\n", NULL } },
680
681 { SMBopenX, "SMBopenX", FLG_CHAIN,
682 { "Com2=[w]\nOff2=[u]\nFlags=[w]\nMode=[w]\nSearchAttrib=[A]\nAttrib=[A]\nTime=[T2]OFun=[w]\nSize=[U]\nTimeOut=[D]\nRes=[W]\n",
683 "Path=[S]\n",
684 "Com2=[w]\nOff2=[u]\nHandle=[u]\nAttrib=[A]\nTime=[T2]Size=[U]\nAccess=[w]\nType=[w]\nState=[w]\nAction=[w]\nFileID=[W]\nRes=[w]\n",
685 NULL, NULL } },
686
687 { SMBreadX, "SMBreadX", FLG_CHAIN,
688 { "Com2=[w]\nOff2=[u]\nHandle=[u]\nOffset=[D]\nMaxCount=[u]\nMinCount=[u]\nTimeOut=[D]\nCountLeft=[u]\n",
689 NULL,
690 "Com2=[w]\nOff2=[u]\nRemaining=[u]\nRes=[W]\nDataSize=[u]\nDataOff=[u]\nRes=([w,w,w,w])\n",
691 NULL, NULL } },
692
693 { SMBwriteX, "SMBwriteX", FLG_CHAIN,
694 { "Com2=[w]\nOff2=[u]\nHandle=[u]\nOffset=[D]\nTimeOut=[D]\nWMode=[w]\nCountLeft=[u]\nRes=[w]\nDataSize=[u]\nDataOff=[u]\n",
695 NULL,
696 "Com2=[w]\nOff2=[u]\nCount=[u]\nRemaining=[u]\nRes=[W]\n",
697 NULL, NULL } },
698
699 { SMBffirst, "SMBffirst", 0,
700 { "Count=[u]\nAttrib=[A]\n",
701 "Path=[Z]\nBlkType=[B]\nBlkLen=[u]\n|Res1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\n",
702 "Count=[u]\n",
703 "BlkType=[B]\nBlkLen=[u]\n*\nRes1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\nRes2=[W]\nAttrib=[a]\nTime=[T1]Size=[U]\nName=[s13]\n",
704 NULL } },
705
706 { SMBfunique, "SMBfunique", 0,
707 { "Count=[u]\nAttrib=[A]\n",
708 "Path=[Z]\nBlkType=[B]\nBlkLen=[u]\n|Res1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\n",
709 "Count=[u]\n",
710 "BlkType=[B]\nBlkLen=[u]\n*\nRes1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\nRes2=[W]\nAttrib=[a]\nTime=[T1]Size=[U]\nName=[s13]\n",
711 NULL } },
712
713 { SMBfclose, "SMBfclose", 0,
714 { "Count=[u]\nAttrib=[A]\n",
715 "Path=[Z]\nBlkType=[B]\nBlkLen=[u]\n|Res1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\n",
716 "Count=[u]\n",
717 "BlkType=[B]\nBlkLen=[u]\n*\nRes1=[B]\nMask=[s11]\nSrv1=[B]\nDirIndex=[u]\nSrv2=[w]\nRes2=[W]\nAttrib=[a]\nTime=[T1]Size=[U]\nName=[s13]\n",
718 NULL } },
719
720 { SMBfindnclose, "SMBfindnclose", 0,
721 { "Handle=[u]\n", NULL, NULL, NULL, NULL } },
722
723 { SMBfindclose, "SMBfindclose", 0,
724 { "Handle=[u]\n", NULL, NULL, NULL, NULL } },
725
726 { SMBsends, "SMBsends", 0,
727 { NULL, "Source=[Z]\nDest=[Z]\n", NULL, NULL, NULL } },
728
729 { SMBsendstrt, "SMBsendstrt", 0,
730 { NULL, "Source=[Z]\nDest=[Z]\n", "GroupID=[u]\n", NULL, NULL } },
731
732 { SMBsendend, "SMBsendend", 0,
733 { "GroupID=[u]\n", NULL, NULL, NULL, NULL } },
734
735 { SMBsendtxt, "SMBsendtxt", 0,
736 { "GroupID=[u]\n", NULL, NULL, NULL, NULL } },
737
738 { SMBsendb, "SMBsendb", 0,
739 { NULL, "Source=[Z]\nDest=[Z]\n", NULL, NULL, NULL } },
740
741 { SMBfwdname, "SMBfwdname", 0, DEFDESCRIPT },
742 { SMBcancelf, "SMBcancelf", 0, DEFDESCRIPT },
743 { SMBgetmac, "SMBgetmac", 0, DEFDESCRIPT },
744
745 { SMBnegprot, "SMBnegprot", 0,
746 { NULL, NULL, NULL, NULL, print_negprot } },
747
748 { SMBsesssetupX, "SMBsesssetupX", FLG_CHAIN,
749 { NULL, NULL, NULL, NULL, print_sesssetup } },
750
751 { SMBtconX, "SMBtconX", FLG_CHAIN,
752 { "Com2=[w]\nOff2=[u]\nFlags=[w]\nPassLen=[u]\nPasswd&Path&Device=\n",
753 NULL, "Com2=[w]\nOff2=[u]\n", "ServiceType=[R]\n", NULL } },
754
755 { SMBlockingX, "SMBlockingX", FLG_CHAIN,
756 { NULL, NULL, NULL, NULL, print_lockingandx } },
757
758 { SMBtrans2, "SMBtrans2", 0, { NULL, NULL, NULL, NULL, print_trans2 } },
759
760 { SMBtranss2, "SMBtranss2", 0, DEFDESCRIPT },
761 { SMBctemp, "SMBctemp", 0, DEFDESCRIPT },
762 { SMBreadBs, "SMBreadBs", 0, DEFDESCRIPT },
763 { SMBtrans, "SMBtrans", 0, { NULL, NULL, NULL, NULL, print_trans } },
764
765 { SMBnttrans, "SMBnttrans", 0, DEFDESCRIPT },
766 { SMBnttranss, "SMBnttranss", 0, DEFDESCRIPT },
767
768 { SMBntcreateX, "SMBntcreateX", FLG_CHAIN,
769 { "Com2=[w]\nOff2=[u]\nRes=[b]\nNameLen=[lu]\nFlags=[W]\nRootDirectoryFid=[U]\nAccessMask=[W]\nAllocationSize=[L]\nExtFileAttributes=[W]\nShareAccess=[W]\nCreateDisposition=[W]\nCreateOptions=[W]\nImpersonationLevel=[W]\nSecurityFlags=[b]\n",
770 "Path=[C]\n",
771 "Com2=[w]\nOff2=[u]\nOplockLevel=[b]\nFid=[u]\nCreateAction=[W]\nCreateTime=[T3]LastAccessTime=[T3]LastWriteTime=[T3]ChangeTime=[T3]ExtFileAttributes=[W]\nAllocationSize=[L]\nEndOfFile=[L]\nFileType=[w]\nDeviceState=[w]\nDirectory=[b]\n",
772 NULL, NULL } },
773
774 { SMBntcancel, "SMBntcancel", 0, DEFDESCRIPT },
775
776 { -1, NULL, 0, DEFDESCRIPT }
777 };
778
779
780 /*
781 * print a SMB message
782 */
783 static void
784 print_smb(netdissect_options *ndo,
785 const u_char *buf, const u_char *maxbuf)
786 {
787 uint16_t flags2;
788 u_int nterrcodes;
789 u_int command;
790 uint32_t nterror;
791 const u_char *words, *maxwords, *data;
792 const struct smbfns *fn;
793 const char *fmt_smbheader =
794 "[P4]SMB Command = [B]\nError class = [BP1]\nError code = [u]\nFlags1 = [B]\nFlags2 = [B][P13]\nTree ID = [u]\nProc ID = [u]\nUID = [u]\nMID = [u]\nWord Count = [b]\n";
795 u_int smboffset;
796
797 ndo->ndo_protocol = "smb";
798
799 request = (GET_U_1(buf + 9) & 0x80) ? 0 : 1;
800 startbuf = buf;
801
802 command = GET_U_1(buf + 4);
803
804 fn = smbfind(command, smb_fns);
805
806 if (ndo->ndo_vflag > 1)
807 ND_PRINT("\n");
808
809 ND_PRINT("SMB PACKET: %s (%s)", fn->name, request ? "REQUEST" : "REPLY");
810
811 if (ndo->ndo_vflag < 2)
812 return;
813
814 ND_PRINT("\n");
815 flags2 = GET_LE_U_2(buf + 10);
816 unicodestr = flags2 & 0x8000;
817 nterrcodes = flags2 & 0x4000;
818
819 /* print out the header */
820 smb_fdata(ndo, buf, fmt_smbheader, buf + 33, unicodestr);
821
822 if (nterrcodes) {
823 nterror = GET_LE_U_4(buf + 5);
824 if (nterror)
825 ND_PRINT("NTError = %s\n", nt_errstr(nterror));
826 } else {
827 if (GET_U_1(buf + 5))
828 ND_PRINT("SMBError = %s\n", smb_errstr(GET_U_1(buf + 5),
829 GET_LE_U_2(buf + 7)));
830 }
831
832 smboffset = 32;
833
834 for (;;) {
835 const char *f1, *f2;
836 int wct;
837 u_int bcc;
838 u_int newsmboffset;
839
840 words = buf + smboffset;
841 wct = GET_U_1(words);
842 data = words + 1 + wct * 2;
843 maxwords = ND_MIN(data, maxbuf);
844
845 if (request) {
846 f1 = fn->descript.req_f1;
847 f2 = fn->descript.req_f2;
848 } else {
849 f1 = fn->descript.rep_f1;
850 f2 = fn->descript.rep_f2;
851 }
852
853 smb_reset();
854 if (fn->descript.fn)
855 (*fn->descript.fn)(ndo, words, data, buf, maxbuf);
856 else {
857 if (wct) {
858 if (f1)
859 smb_fdata(ndo, words + 1, f1, words + 1 + wct * 2, unicodestr);
860 else {
861 u_int i;
862 u_int v;
863
864 for (i = 0; words + 1 + 2 * i < maxwords; i++) {
865 v = GET_LE_U_2(words + 1 + 2 * i);
866 ND_PRINT("smb_vwv[%u]=%u (0x%X)\n", i, v, v);
867 }
868 }
869 }
870
871 bcc = GET_LE_U_2(data);
872 ND_PRINT("smb_bcc=%u\n", bcc);
873 if (f2) {
874 if (bcc > 0)
875 smb_fdata(ndo, data + 2, f2, data + 2 + bcc, unicodestr);
876 } else {
877 if (bcc > 0) {
878 ND_PRINT("smb_buf[]=\n");
879 smb_data_print(ndo, data + 2, ND_MIN(bcc, ND_BYTES_BETWEEN(maxbuf, data + 2)));
880 }
881 }
882 }
883
884 if ((fn->flags & FLG_CHAIN) == 0)
885 break;
886 if (wct == 0)
887 break;
888 command = GET_U_1(words + 1);
889 if (command == 0xFF)
890 break;
891 newsmboffset = GET_LE_U_2(words + 3);
892
893 fn = smbfind(command, smb_fns);
894
895 ND_PRINT("\nSMB PACKET: %s (%s) (CHAINED)\n",
896 fn->name, request ? "REQUEST" : "REPLY");
897 if (newsmboffset <= smboffset) {
898 ND_PRINT("Bad andX offset: %u <= %u\n", newsmboffset, smboffset);
899 break;
900 }
901 smboffset = newsmboffset;
902 }
903 }
904
905
906 /*
907 * print a NBT packet received across tcp on port 139
908 */
909 void
910 nbt_tcp_print(netdissect_options *ndo,
911 const u_char *data, u_int length)
912 {
913 u_int caplen;
914 u_int type;
915 u_int nbt_len;
916 const u_char *maxbuf;
917
918 ndo->ndo_protocol = "nbt_tcp";
919 if (length < 4)
920 goto trunc;
921 if (ndo->ndo_snapend < data)
922 goto trunc;
923 caplen = ND_BYTES_AVAILABLE_AFTER(data);
924 if (caplen < 4)
925 goto trunc;
926 maxbuf = data + caplen;
927 type = GET_U_1(data);
928 nbt_len = GET_BE_U_2(data + 2);
929 length -= 4;
930 caplen -= 4;
931
932 startbuf = data;
933
934 if (ndo->ndo_vflag < 2) {
935 ND_PRINT(" NBT Session Packet: ");
936 switch (type) {
937 case 0x00:
938 ND_PRINT("Session Message");
939 break;
940
941 case 0x81:
942 ND_PRINT("Session Request");
943 break;
944
945 case 0x82:
946 ND_PRINT("Session Granted");
947 break;
948
949 case 0x83:
950 {
951 u_int ecode;
952
953 if (nbt_len < 4)
954 goto trunc;
955 if (length < 4)
956 goto trunc;
957 if (caplen < 4)
958 goto trunc;
959 ecode = GET_U_1(data + 4);
960
961 ND_PRINT("Session Reject, ");
962 switch (ecode) {
963 case 0x80:
964 ND_PRINT("Not listening on called name");
965 break;
966 case 0x81:
967 ND_PRINT("Not listening for calling name");
968 break;
969 case 0x82:
970 ND_PRINT("Called name not present");
971 break;
972 case 0x83:
973 ND_PRINT("Called name present, but insufficient resources");
974 break;
975 default:
976 ND_PRINT("Unspecified error 0x%X", ecode);
977 break;
978 }
979 }
980 break;
981
982 case 0x85:
983 ND_PRINT("Session Keepalive");
984 break;
985
986 default:
987 data = smb_fdata(ndo, data, "Unknown packet type [rB]", maxbuf, 0);
988 break;
989 }
990 } else {
991 ND_PRINT("\n>>> NBT Session Packet\n");
992 switch (type) {
993 case 0x00:
994 data = smb_fdata(ndo, data, "[P1]NBT Session Message\nFlags=[B]\nLength=[ru]\n",
995 data + 4, 0);
996 if (data == NULL)
997 break;
998 if (nbt_len >= 4 && caplen >= 4 && memcmp(data,"\377SMB",4) == 0) {
999 if (nbt_len > caplen) {
1000 if (nbt_len > length)
1001 ND_PRINT("WARNING: Packet is continued in later TCP segments\n");
1002 else
1003 ND_PRINT("WARNING: Short packet. Try increasing the snap length by %u\n",
1004 nbt_len - caplen);
1005 }
1006 print_smb(ndo, data, maxbuf > data + nbt_len ? data + nbt_len : maxbuf);
1007 } else
1008 ND_PRINT("Session packet:(raw data or continuation?)\n");
1009 break;
1010
1011 case 0x81:
1012 data = smb_fdata(ndo, data,
1013 "[P1]NBT Session Request\nFlags=[B]\nLength=[ru]\nDestination=[n1]\nSource=[n1]\n",
1014 maxbuf, 0);
1015 break;
1016
1017 case 0x82:
1018 data = smb_fdata(ndo, data, "[P1]NBT Session Granted\nFlags=[B]\nLength=[ru]\n", maxbuf, 0);
1019 break;
1020
1021 case 0x83:
1022 {
1023 const u_char *origdata;
1024 u_int ecode;
1025
1026 origdata = data;
1027 data = smb_fdata(ndo, data, "[P1]NBT SessionReject\nFlags=[B]\nLength=[ru]\nReason=[B]\n",
1028 maxbuf, 0);
1029 if (data == NULL)
1030 break;
1031 if (nbt_len >= 1 && caplen >= 1) {
1032 ecode = GET_U_1(origdata + 4);
1033 switch (ecode) {
1034 case 0x80:
1035 ND_PRINT("Not listening on called name\n");
1036 break;
1037 case 0x81:
1038 ND_PRINT("Not listening for calling name\n");
1039 break;
1040 case 0x82:
1041 ND_PRINT("Called name not present\n");
1042 break;
1043 case 0x83:
1044 ND_PRINT("Called name present, but insufficient resources\n");
1045 break;
1046 default:
1047 ND_PRINT("Unspecified error 0x%X\n", ecode);
1048 break;
1049 }
1050 }
1051 }
1052 break;
1053
1054 case 0x85:
1055 data = smb_fdata(ndo, data, "[P1]NBT Session Keepalive\nFlags=[B]\nLength=[ru]\n", maxbuf, 0);
1056 break;
1057
1058 default:
1059 data = smb_fdata(ndo, data, "NBT - Unknown packet type\nType=[B]\n", maxbuf, 0);
1060 break;
1061 }
1062 }
1063 return;
1064 trunc:
1065 nd_print_trunc(ndo);
1066 }
1067
1068 static const struct tok opcode_str[] = {
1069 { 0, "QUERY" },
1070 { 5, "REGISTRATION" },
1071 { 6, "RELEASE" },
1072 { 7, "WACK" },
1073 { 8, "REFRESH(8)" },
1074 { 9, "REFRESH" },
1075 { 15, "MULTIHOMED REGISTRATION" },
1076 { 0, NULL }
1077 };
1078
1079 /*
1080 * print a NBT packet received across udp on port 137
1081 */
1082 void
1083 nbt_udp137_print(netdissect_options *ndo,
1084 const u_char *data, u_int length)
1085 {
1086 const u_char *maxbuf = data + length;
1087 u_int name_trn_id, response, opcode, nm_flags, rcode;
1088 u_int qdcount, ancount, nscount, arcount;
1089 const u_char *p;
1090 u_int total, i;
1091
1092 ndo->ndo_protocol = "nbt_udp137";
1093 name_trn_id = GET_BE_U_2(data);
1094 response = (GET_U_1(data + 2) >> 7);
1095 opcode = (GET_U_1(data + 2) >> 3) & 0xF;
1096 nm_flags = ((GET_U_1(data + 2) & 0x7) << 4) + (GET_U_1(data + 3) >> 4);
1097 rcode = GET_U_1(data + 3) & 0xF;
1098 qdcount = GET_BE_U_2(data + 4);
1099 ancount = GET_BE_U_2(data + 6);
1100 nscount = GET_BE_U_2(data + 8);
1101 arcount = GET_BE_U_2(data + 10);
1102 startbuf = data;
1103
1104 if (maxbuf <= data)
1105 return;
1106
1107 if (ndo->ndo_vflag > 1)
1108 ND_PRINT("\n>>> ");
1109
1110 ND_PRINT("NBT UDP PACKET(137): %s", tok2str(opcode_str, "OPUNKNOWN", opcode));
1111 if (response) {
1112 ND_PRINT("; %s", rcode ? "NEGATIVE" : "POSITIVE");
1113 }
1114 ND_PRINT("; %s; %s", response ? "RESPONSE" : "REQUEST",
1115 (nm_flags & 1) ? "BROADCAST" : "UNICAST");
1116
1117 if (ndo->ndo_vflag < 2)
1118 return;
1119
1120 ND_PRINT("\nTrnID=0x%X\nOpCode=%u\nNmFlags=0x%X\nRcode=%u\nQueryCount=%u\nAnswerCount=%u\nAuthorityCount=%u\nAddressRecCount=%u\n",
1121 name_trn_id, opcode, nm_flags, rcode, qdcount, ancount, nscount,
1122 arcount);
1123
1124 p = data + 12;
1125
1126 total = ancount + nscount + arcount;
1127
1128 if (qdcount > 100 || total > 100) {
1129 ND_PRINT("Corrupt packet??\n");
1130 return;
1131 }
1132
1133 if (qdcount) {
1134 ND_PRINT("QuestionRecords:\n");
1135 for (i = 0; i < qdcount; i++) {
1136 p = smb_fdata(ndo, p,
1137 "|Name=[n1]\nQuestionType=[rw]\nQuestionClass=[rw]\n#",
1138 maxbuf, 0);
1139 if (p == NULL)
1140 goto out;
1141 }
1142 }
1143
1144 if (total) {
1145 ND_PRINT("\nResourceRecords:\n");
1146 for (i = 0; i < total; i++) {
1147 u_int rdlen;
1148 u_int restype;
1149
1150 p = smb_fdata(ndo, p, "Name=[n1]\n#", maxbuf, 0);
1151 if (p == NULL)
1152 goto out;
1153 restype = GET_BE_U_2(p);
1154 p = smb_fdata(ndo, p, "ResType=[rw]\nResClass=[rw]\nTTL=[rU]\n", p + 8, 0);
1155 if (p == NULL)
1156 goto out;
1157 rdlen = GET_BE_U_2(p);
1158 ND_PRINT("ResourceLength=%u\nResourceData=\n", rdlen);
1159 p += 2;
1160 if (rdlen == 6) {
1161 p = smb_fdata(ndo, p, "AddrType=[rw]\nAddress=[b.b.b.b]\n", p + rdlen, 0);
1162 if (p == NULL)
1163 goto out;
1164 } else {
1165 if (restype == 0x21) {
1166 u_int numnames;
1167
1168 numnames = GET_U_1(p);
1169 p = smb_fdata(ndo, p, "NumNames=[B]\n", p + 1, 0);
1170 if (p == NULL)
1171 goto out;
1172 while (numnames) {
1173 p = smb_fdata(ndo, p, "Name=[n2]\t#", maxbuf, 0);
1174 if (p == NULL)
1175 goto out;
1176 ND_TCHECK_1(p);
1177 if (p >= maxbuf)
1178 goto out;
1179 if (GET_U_1(p) & 0x80)
1180 ND_PRINT("<GROUP> ");
1181 switch (GET_U_1(p) & 0x60) {
1182 case 0x00: ND_PRINT("B "); break;
1183 case 0x20: ND_PRINT("P "); break;
1184 case 0x40: ND_PRINT("M "); break;
1185 case 0x60: ND_PRINT("_ "); break;
1186 }
1187 if (GET_U_1(p) & 0x10)
1188 ND_PRINT("<DEREGISTERING> ");
1189 if (GET_U_1(p) & 0x08)
1190 ND_PRINT("<CONFLICT> ");
1191 if (GET_U_1(p) & 0x04)
1192 ND_PRINT("<ACTIVE> ");
1193 if (GET_U_1(p) & 0x02)
1194 ND_PRINT("<PERMANENT> ");
1195 ND_PRINT("\n");
1196 p += 2;
1197 numnames--;
1198 }
1199 } else {
1200 if (p >= maxbuf)
1201 goto out;
1202 smb_data_print(ndo, p, ND_MIN(rdlen, length - ND_BYTES_BETWEEN(p, data)));
1203 p += rdlen;
1204 }
1205 }
1206 }
1207 }
1208
1209 if (p < maxbuf)
1210 smb_fdata(ndo, p, "AdditionalData:\n", maxbuf, 0);
1211
1212 out:
1213 return;
1214 trunc:
1215 nd_print_trunc(ndo);
1216 }
1217
1218 /*
1219 * Print an SMB-over-TCP packet received across tcp on port 445
1220 */
1221 void
1222 smb_tcp_print(netdissect_options *ndo,
1223 const u_char * data, u_int length)
1224 {
1225 u_int caplen;
1226 u_int smb_len;
1227 const u_char *maxbuf;
1228
1229 ndo->ndo_protocol = "smb_tcp";
1230 if (length < 4)
1231 goto trunc;
1232 if (ndo->ndo_snapend < data)
1233 goto trunc;
1234 caplen = ND_BYTES_AVAILABLE_AFTER(data);
1235 if (caplen < 4)
1236 goto trunc;
1237 maxbuf = data + caplen;
1238 smb_len = GET_BE_U_3(data + 1);
1239 length -= 4;
1240 caplen -= 4;
1241
1242 startbuf = data;
1243 data += 4;
1244
1245 if (smb_len >= 4 && caplen >= 4 && memcmp(data,"\377SMB",4) == 0) {
1246 if (smb_len > caplen) {
1247 if (smb_len > length)
1248 ND_PRINT(" WARNING: Packet is continued in later TCP segments\n");
1249 else
1250 ND_PRINT(" WARNING: Short packet. Try increasing the snap length by %u\n",
1251 smb_len - caplen);
1252 } else
1253 ND_PRINT(" ");
1254 print_smb(ndo, data, maxbuf > data + smb_len ? data + smb_len : maxbuf);
1255 } else
1256 ND_PRINT(" SMB-over-TCP packet:(raw data or continuation?)\n");
1257 return;
1258 trunc:
1259 nd_print_trunc(ndo);
1260 }
1261
1262 /*
1263 * print a NBT packet received across udp on port 138
1264 */
1265 void
1266 nbt_udp138_print(netdissect_options *ndo,
1267 const u_char *data, u_int length)
1268 {
1269 const u_char *maxbuf = data + length;
1270
1271 ndo->ndo_protocol = "nbt_udp138";
1272 if (maxbuf > ndo->ndo_snapend)
1273 maxbuf = ndo->ndo_snapend;
1274 if (maxbuf <= data)
1275 return;
1276 startbuf = data;
1277
1278 if (ndo->ndo_vflag < 2) {
1279 ND_PRINT("NBT UDP PACKET(138)");
1280 return;
1281 }
1282
1283 data = smb_fdata(ndo, data,
1284 "\n>>> NBT UDP PACKET(138) Res=[rw] ID=[rw] IP=[b.b.b.b] Port=[ru] Length=[ru] Res2=[rw]\nSourceName=[n1]\nDestName=[n1]\n#",
1285 maxbuf, 0);
1286
1287 if (data != NULL) {
1288 /* If there isn't enough data for "\377SMB", don't check for it. */
1289 if ((data + 3) >= maxbuf)
1290 goto out;
1291
1292 if (memcmp(data, "\377SMB",4) == 0)
1293 print_smb(ndo, data, maxbuf);
1294 }
1295 out:
1296 return;
1297 }
1298
1299
1300 /*
1301 print netbeui frames
1302 */
1303 static struct nbf_strings {
1304 const char *name;
1305 const char *nonverbose;
1306 const char *verbose;
1307 } nbf_strings[0x20] = {
1308 { "Add Group Name Query", ", [P23]Name to add=[n2]#",
1309 "[P5]ResponseCorrelator=[w]\n[P16]Name to add=[n2]\n" },
1310 { "Add Name Query", ", [P23]Name to add=[n2]#",
1311 "[P5]ResponseCorrelator=[w]\n[P16]Name to add=[n2]\n" },
1312 { "Name In Conflict", NULL, NULL },
1313 { "Status Query", NULL, NULL },
1314 { NULL, NULL, NULL }, /* not used */
1315 { NULL, NULL, NULL }, /* not used */
1316 { NULL, NULL, NULL }, /* not used */
1317 { "Terminate Trace", NULL, NULL },
1318 { "Datagram", NULL,
1319 "[P7]Destination=[n2]\nSource=[n2]\n" },
1320 { "Broadcast Datagram", NULL,
1321 "[P7]Destination=[n2]\nSource=[n2]\n" },
1322 { "Name Query", ", [P7]Name=[n2]#",
1323 "[P1]SessionNumber=[B]\nNameType=[B][P2]\nResponseCorrelator=[w]\nName=[n2]\nName of sender=[n2]\n" },
1324 { NULL, NULL, NULL }, /* not used */
1325 { NULL, NULL, NULL }, /* not used */
1326 { "Add Name Response", ", [P1]GroupName=[w] [P4]Destination=[n2] Source=[n2]#",
1327 "AddNameInProcess=[B]\nGroupName=[w]\nTransmitCorrelator=[w][P2]\nDestination=[n2]\nSource=[n2]\n" },
1328 { "Name Recognized", NULL,
1329 "[P1]Data2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nDestination=[n2]\nSource=[n2]\n" },
1330 { "Status Response", NULL, NULL },
1331 { NULL, NULL, NULL }, /* not used */
1332 { NULL, NULL, NULL }, /* not used */
1333 { NULL, NULL, NULL }, /* not used */
1334 { "Terminate Trace", NULL, NULL },
1335 { "Data Ack", NULL,
1336 "[P3]TransmitCorrelator=[w][P2]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1337 { "Data First/Middle", NULL,
1338 "Flags=[{RECEIVE_CONTINUE|NO_ACK||PIGGYBACK_ACK_INCLUDED|}]\nResyncIndicator=[w][P2]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1339 { "Data Only/Last", NULL,
1340 "Flags=[{|NO_ACK|PIGGYBACK_ACK_ALLOWED|PIGGYBACK_ACK_INCLUDED|}]\nResyncIndicator=[w][P2]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1341 { "Session Confirm", NULL,
1342 "Data1=[B]\nData2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1343 { "Session End", NULL,
1344 "[P1]Data2=[w][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1345 { "Session Initialize", NULL,
1346 "Data1=[B]\nData2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1347 { "No Receive", NULL,
1348 "Flags=[{|SEND_NO_ACK}]\nDataBytesAccepted=[b][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1349 { "Receive Outstanding", NULL,
1350 "[P1]DataBytesAccepted=[b][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1351 { "Receive Continue", NULL,
1352 "[P2]TransmitCorrelator=[w]\n[P2]RemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" },
1353 { NULL, NULL, NULL }, /* not used */
1354 { NULL, NULL, NULL }, /* not used */
1355 { "Session Alive", NULL, NULL }
1356 };
1357
1358 void
1359 netbeui_print(netdissect_options *ndo,
1360 u_short control, const u_char *data, u_int length)
1361 {
1362 const u_char *maxbuf = data + length;
1363 u_int len;
1364 u_int command;
1365 const u_char *data2;
1366 int is_truncated = 0;
1367
1368 ndo->ndo_protocol = "netbeui";
1369 if (maxbuf > ndo->ndo_snapend)
1370 maxbuf = ndo->ndo_snapend;
1371 len = GET_LE_U_2(data);
1372 command = GET_U_1(data + 4);
1373 data2 = data + len;
1374 if (data2 >= maxbuf) {
1375 data2 = maxbuf;
1376 is_truncated = 1;
1377 }
1378
1379 startbuf = data;
1380
1381 if (ndo->ndo_vflag < 2) {
1382 ND_PRINT("NBF Packet: ");
1383 data = smb_fdata(ndo, data, "[P5]#", maxbuf, 0);
1384 } else {
1385 ND_PRINT("\n>>> NBF Packet\nType=0x%X ", control);
1386 data = smb_fdata(ndo, data, "Length=[u] Signature=[w] Command=[B]\n#", maxbuf, 0);
1387 }
1388 if (data == NULL)
1389 goto out;
1390
1391 if (command > 0x1f || nbf_strings[command].name == NULL) {
1392 if (ndo->ndo_vflag < 2)
1393 data = smb_fdata(ndo, data, "Unknown NBF Command#", data2, 0);
1394 else
1395 data = smb_fdata(ndo, data, "Unknown NBF Command\n", data2, 0);
1396 } else {
1397 if (ndo->ndo_vflag < 2) {
1398 ND_PRINT("%s", nbf_strings[command].name);
1399 if (nbf_strings[command].nonverbose != NULL)
1400 data = smb_fdata(ndo, data, nbf_strings[command].nonverbose, data2, 0);
1401 } else {
1402 ND_PRINT("%s:\n", nbf_strings[command].name);
1403 if (nbf_strings[command].verbose != NULL)
1404 data = smb_fdata(ndo, data, nbf_strings[command].verbose, data2, 0);
1405 else
1406 ND_PRINT("\n");
1407 }
1408 }
1409
1410 if (ndo->ndo_vflag < 2)
1411 return;
1412
1413 if (data == NULL)
1414 goto out;
1415
1416 if (is_truncated) {
1417 /* data2 was past the end of the buffer */
1418 goto out;
1419 }
1420
1421 /* If this isn't a command that would contain an SMB message, quit. */
1422 if (command != 0x08 && command != 0x09 && command != 0x15 &&
1423 command != 0x16)
1424 goto out;
1425
1426 /* If there isn't enough data for "\377SMB", don't look for it. */
1427 if ((data2 + 3) >= maxbuf)
1428 goto out;
1429
1430 if (memcmp(data2, "\377SMB",4) == 0)
1431 print_smb(ndo, data2, maxbuf);
1432 else {
1433 u_int i;
1434 for (i = 0; i < 128; i++) {
1435 if ((data2 + i + 3) >= maxbuf)
1436 break;
1437 if (memcmp(data2 + i, "\377SMB", 4) == 0) {
1438 ND_PRINT("found SMB packet at %u\n", i);
1439 print_smb(ndo, data2 + i, maxbuf);
1440 break;
1441 }
1442 }
1443 }
1444
1445 out:
1446 return;
1447 }
1448
1449
1450 /*
1451 * print IPX-Netbios frames
1452 */
1453 void
1454 ipx_netbios_print(netdissect_options *ndo,
1455 const u_char *data, u_int length)
1456 {
1457 /*
1458 * this is a hack till I work out how to parse the rest of the
1459 * NetBIOS-over-IPX stuff
1460 */
1461 u_int i;
1462 const u_char *maxbuf;
1463
1464 ndo->ndo_protocol = "ipx_netbios";
1465 maxbuf = data + length;
1466 /* Don't go past the end of the captured data in the packet. */
1467 if (maxbuf > ndo->ndo_snapend)
1468 maxbuf = ndo->ndo_snapend;
1469 startbuf = data;
1470 for (i = 0; i < 128; i++) {
1471 if ((data + i + 4) > maxbuf)
1472 break;
1473 if (memcmp(data + i, "\377SMB", 4) == 0) {
1474 smb_fdata(ndo, data, "\n>>> IPX transport ", data + i, 0);
1475 print_smb(ndo, data + i, maxbuf);
1476 break;
1477 }
1478 }
1479 if (i == 128)
1480 smb_fdata(ndo, data, "\n>>> Unknown IPX ", maxbuf, 0);
1481 }
1482