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.10 2024/09/02 16:15:33 christos Exp $"); 12 #endif 13 14 /* \summary: SMB/CIFS printer */ 15 16 #include <config.h> 17 18 #include "netdissect-stdinc.h" 19 20 #include <string.h> 21 22 #include "netdissect.h" 23 #include "extract.h" 24 #include "smb.h" 25 26 27 static int request = 0; 28 static int unicodestr = 0; 29 30 extern const u_char *startbuf; 31 32 const u_char *startbuf = NULL; 33 34 struct smbdescript { 35 const char *req_f1; 36 const char *req_f2; 37 const char *rep_f1; 38 const char *rep_f2; 39 void (*fn)(netdissect_options *, const u_char *, const u_char *, const u_char *, const u_char *); 40 }; 41 42 struct smbdescriptint { 43 const char *req_f1; 44 const char *req_f2; 45 const char *rep_f1; 46 const char *rep_f2; 47 void (*fn)(netdissect_options *, const u_char *, const u_char *, u_int, u_int); 48 }; 49 50 struct smbfns 51 { 52 int id; 53 const char *name; 54 int flags; 55 struct smbdescript descript; 56 }; 57 58 struct smbfnsint 59 { 60 int id; 61 const char *name; 62 int flags; 63 struct smbdescriptint descript; 64 }; 65 66 #define DEFDESCRIPT { NULL, NULL, NULL, NULL, NULL } 67 68 #define FLG_CHAIN (1 << 0) 69 70 static const struct smbfns * 71 smbfind(int id, const struct smbfns *list) 72 { 73 int sindex; 74 75 for (sindex = 0; list[sindex].name; sindex++) 76 if (list[sindex].id == id) 77 return(&list[sindex]); 78 79 return(&list[0]); 80 } 81 82 static const struct smbfnsint * 83 smbfindint(int id, const struct smbfnsint *list) 84 { 85 int sindex; 86 87 for (sindex = 0; list[sindex].name; sindex++) 88 if (list[sindex].id == id) 89 return(&list[sindex]); 90 91 return(&list[0]); 92 } 93 94 static void 95 trans2_findfirst(netdissect_options *ndo, 96 const u_char *param, const u_char *data, u_int pcnt, u_int dcnt) 97 { 98 const char *fmt; 99 100 if (request) 101 fmt = "Attribute=[A]\nSearchCount=[u]\nFlags=[w]\nLevel=[uP4]\nFile=[S]\n"; 102 else 103 fmt = "Handle=[w]\nCount=[u]\nEOS=[w]\nEoffset=[u]\nLastNameOfs=[w]\n"; 104 105 smb_fdata(ndo, param, fmt, param + pcnt, unicodestr); 106 if (dcnt) { 107 ND_PRINT("data:\n"); 108 smb_data_print(ndo, data, dcnt); 109 } 110 } 111 112 static void 113 trans2_qfsinfo(netdissect_options *ndo, 114 const u_char *param, const u_char *data, u_int pcnt, u_int dcnt) 115 { 116 static u_int level = 0; 117 const char *fmt=""; 118 119 if (request) { 120 level = GET_LE_U_2(param); 121 fmt = "InfoLevel=[u]\n"; 122 smb_fdata(ndo, param, fmt, param + pcnt, unicodestr); 123 } else { 124 switch (level) { 125 case 1: 126 fmt = "idFileSystem=[W]\nSectorUnit=[U]\nUnit=[U]\nAvail=[U]\nSectorSize=[u]\n"; 127 break; 128 case 2: 129 fmt = "CreationTime=[T2]VolNameLength=[lb]\nVolumeLabel=[c]\n"; 130 break; 131 case 0x105: 132 fmt = "Capabilities=[W]\nMaxFileLen=[U]\nVolNameLen=[lU]\nVolume=[C]\n"; 133 break; 134 default: 135 fmt = "UnknownLevel\n"; 136 break; 137 } 138 smb_fdata(ndo, data, fmt, data + dcnt, unicodestr); 139 } 140 if (dcnt) { 141 ND_PRINT("data:\n"); 142 smb_data_print(ndo, data, dcnt); 143 } 144 } 145 146 static const struct smbfnsint trans2_fns[] = { 147 { 0, "TRANSACT2_OPEN", 0, 148 { "Flags2=[w]\nMode=[w]\nSearchAttrib=[A]\nAttrib=[A]\nTime=[T2]\nOFun=[w]\nSize=[U]\nRes=([w, w, w, w, w])\nPath=[S]", 149 NULL, 150 "Handle=[u]\nAttrib=[A]\nTime=[T2]\nSize=[U]\nAccess=[w]\nType=[w]\nState=[w]\nAction=[w]\nInode=[W]\nOffErr=[u]\n|EALength=[u]\n", 151 NULL, NULL }}, 152 { 1, "TRANSACT2_FINDFIRST", 0, 153 { NULL, NULL, NULL, NULL, trans2_findfirst }}, 154 { 2, "TRANSACT2_FINDNEXT", 0, DEFDESCRIPT }, 155 { 3, "TRANSACT2_QFSINFO", 0, 156 { NULL, NULL, NULL, NULL, trans2_qfsinfo }}, 157 { 4, "TRANSACT2_SETFSINFO", 0, DEFDESCRIPT }, 158 { 5, "TRANSACT2_QPATHINFO", 0, DEFDESCRIPT }, 159 { 6, "TRANSACT2_SETPATHINFO", 0, DEFDESCRIPT }, 160 { 7, "TRANSACT2_QFILEINFO", 0, DEFDESCRIPT }, 161 { 8, "TRANSACT2_SETFILEINFO", 0, DEFDESCRIPT }, 162 { 9, "TRANSACT2_FSCTL", 0, DEFDESCRIPT }, 163 { 10, "TRANSACT2_IOCTL", 0, DEFDESCRIPT }, 164 { 11, "TRANSACT2_FINDNOTIFYFIRST", 0, DEFDESCRIPT }, 165 { 12, "TRANSACT2_FINDNOTIFYNEXT", 0, DEFDESCRIPT }, 166 { 13, "TRANSACT2_MKDIR", 0, DEFDESCRIPT }, 167 { -1, NULL, 0, DEFDESCRIPT } 168 }; 169 170 171 static void 172 print_trans2(netdissect_options *ndo, 173 const u_char *words, const u_char *dat, const u_char *buf, const u_char *maxbuf) 174 { 175 u_int bcc; 176 static const struct smbfnsint *fn = &trans2_fns[0]; 177 const u_char *data, *param; 178 const u_char *w = words + 1; 179 const char *f1 = NULL, *f2 = NULL; 180 u_int pcnt, dcnt; 181 182 ND_TCHECK_1(words); 183 if (request) { 184 ND_TCHECK_2(w + (14 * 2)); 185 pcnt = GET_LE_U_2(w + 9 * 2); 186 param = buf + GET_LE_U_2(w + 10 * 2); 187 dcnt = GET_LE_U_2(w + 11 * 2); 188 data = buf + GET_LE_U_2(w + 12 * 2); 189 fn = smbfindint(GET_LE_U_2(w + 14 * 2), trans2_fns); 190 } else { 191 if (GET_U_1(words) == 0) { 192 ND_PRINT("%s\n", fn->name); 193 ND_PRINT("Trans2Interim\n"); 194 return; 195 } 196 ND_TCHECK_2(w + (7 * 2)); 197 pcnt = GET_LE_U_2(w + 3 * 2); 198 param = buf + GET_LE_U_2(w + 4 * 2); 199 dcnt = GET_LE_U_2(w + 6 * 2); 200 data = buf + GET_LE_U_2(w + 7 * 2); 201 } 202 203 ND_PRINT("%s param_length=%u data_length=%u\n", fn->name, pcnt, dcnt); 204 205 if (request) { 206 if (GET_U_1(words) == 8) { 207 smb_fdata(ndo, words + 1, 208 "Trans2Secondary\nTotParam=[u]\nTotData=[u]\nParamCnt=[u]\nParamOff=[u]\nParamDisp=[u]\nDataCnt=[u]\nDataOff=[u]\nDataDisp=[u]\nHandle=[u]\n", 209 maxbuf, unicodestr); 210 return; 211 } else { 212 smb_fdata(ndo, words + 1, 213 "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", 214 words + 1 + 14 * 2, unicodestr); 215 } 216 f1 = fn->descript.req_f1; 217 f2 = fn->descript.req_f2; 218 } else { 219 smb_fdata(ndo, words + 1, 220 "TotParam=[u]\nTotData=[u]\nRes1=[w]\nParamCnt=[u]\nParamOff=[u]\nParamDisp[u]\nDataCnt=[u]\nDataOff=[u]\nDataDisp=[u]\nSetupCnt=[b][P1]\n", 221 words + 1 + 10 * 2, unicodestr); 222 f1 = fn->descript.rep_f1; 223 f2 = fn->descript.rep_f2; 224 } 225 226 bcc = GET_LE_U_2(dat); 227 ND_PRINT("smb_bcc=%u\n", bcc); 228 if (fn->descript.fn) 229 (*fn->descript.fn)(ndo, param, data, pcnt, dcnt); 230 else { 231 smb_fdata(ndo, param, f1 ? f1 : "Parameters=\n", param + pcnt, unicodestr); 232 smb_fdata(ndo, data, f2 ? f2 : "Data=\n", data + dcnt, unicodestr); 233 } 234 return; 235 trunc: 236 nd_print_trunc(ndo); 237 } 238 239 static void 240 print_browse(netdissect_options *ndo, 241 const u_char *param, u_int paramlen, const u_char *data, u_int datalen) 242 { 243 const u_char *maxbuf = data + datalen; 244 u_int command; 245 246 command = GET_U_1(data); 247 248 smb_fdata(ndo, param, "BROWSE PACKET\n|Param ", param+paramlen, unicodestr); 249 250 switch (command) { 251 case 0xF: 252 data = smb_fdata(ndo, data, 253 "BROWSE PACKET:\nType=[B] (LocalMasterAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nElectionVersion=[w]\nBrowserConstant=[w]\n", 254 maxbuf, unicodestr); 255 break; 256 257 case 0x1: 258 data = smb_fdata(ndo, data, 259 "BROWSE PACKET:\nType=[B] (HostAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nElectionVersion=[w]\nBrowserConstant=[w]\n", 260 maxbuf, unicodestr); 261 break; 262 263 case 0x2: 264 data = smb_fdata(ndo, data, 265 "BROWSE PACKET:\nType=[B] (AnnouncementRequest)\nFlags=[B]\nReplySystemName=[S]\n", 266 maxbuf, unicodestr); 267 break; 268 269 case 0xc: 270 data = smb_fdata(ndo, data, 271 "BROWSE PACKET:\nType=[B] (WorkgroupAnnouncement)\nUpdateCount=[w]\nRes1=[B]\nAnnounceInterval=[u]\nName=[n2]\nMajorVersion=[B]\nMinorVersion=[B]\nServerType=[W]\nCommentPointer=[W]\nServerName=[S]\n", 272 maxbuf, unicodestr); 273 break; 274 275 case 0x8: 276 data = smb_fdata(ndo, data, 277 "BROWSE PACKET:\nType=[B] (ElectionFrame)\nElectionVersion=[B]\nOSSummary=[W]\nUptime=[(W, W)]\nServerName=[S]\n", 278 maxbuf, unicodestr); 279 break; 280 281 case 0xb: 282 data = smb_fdata(ndo, data, 283 "BROWSE PACKET:\nType=[B] (BecomeBackupBrowser)\nName=[S]\n", 284 maxbuf, unicodestr); 285 break; 286 287 case 0x9: 288 data = smb_fdata(ndo, data, 289 "BROWSE PACKET:\nType=[B] (GetBackupList)\nListCount?=[B]\nToken=[W]\n", 290 maxbuf, unicodestr); 291 break; 292 293 case 0xa: 294 data = smb_fdata(ndo, data, 295 "BROWSE PACKET:\nType=[B] (BackupListResponse)\nServerCount?=[B]\nToken=[W]\n*Name=[S]\n", 296 maxbuf, unicodestr); 297 break; 298 299 case 0xd: 300 data = smb_fdata(ndo, data, 301 "BROWSE PACKET:\nType=[B] (MasterAnnouncement)\nMasterName=[S]\n", 302 maxbuf, unicodestr); 303 break; 304 305 case 0xe: 306 data = smb_fdata(ndo, data, 307 "BROWSE PACKET:\nType=[B] (ResetBrowser)\nOptions=[B]\n", maxbuf, unicodestr); 308 break; 309 310 default: 311 data = smb_fdata(ndo, data, "Unknown Browser Frame ", maxbuf, unicodestr); 312 break; 313 } 314 } 315 316 317 static void 318 print_ipc(netdissect_options *ndo, 319 const u_char *param, u_int paramlen, const u_char *data, u_int datalen) 320 { 321 if (paramlen) 322 smb_fdata(ndo, param, "Command=[w]\nStr1=[S]\nStr2=[S]\n", param + paramlen, 323 unicodestr); 324 if (datalen) 325 smb_fdata(ndo, data, "IPC ", data + datalen, unicodestr); 326 } 327 328 329 static void 330 print_trans(netdissect_options *ndo, 331 const u_char *words, const u_char *data1, const u_char *buf, const u_char *maxbuf) 332 { 333 u_int bcc; 334 const char *f1, *f2, *f3, *f4; 335 const u_char *data, *param; 336 const u_char *w = words + 1; 337 u_int datalen, paramlen; 338 339 if (request) { 340 ND_TCHECK_2(w + (12 * 2)); 341 paramlen = GET_LE_U_2(w + 9 * 2); 342 param = buf + GET_LE_U_2(w + 10 * 2); 343 datalen = GET_LE_U_2(w + 11 * 2); 344 data = buf + GET_LE_U_2(w + 12 * 2); 345 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"; 346 f2 = "|Name=[S]\n"; 347 f3 = "|Param "; 348 f4 = "|Data "; 349 } else { 350 ND_TCHECK_2(w + (7 * 2)); 351 paramlen = GET_LE_U_2(w + 3 * 2); 352 param = buf + GET_LE_U_2(w + 4 * 2); 353 datalen = GET_LE_U_2(w + 6 * 2); 354 data = buf + GET_LE_U_2(w + 7 * 2); 355 f1 = "TotParamCnt=[u]\nTotDataCnt=[u]\nRes1=[u]\nParamCnt=[u]\nParamOff=[u]\nRes2=[u]\nDataCnt=[u]\nDataOff=[u]\nRes3=[u]\nLsetup=[u]\n"; 356 f2 = "|Unknown "; 357 f3 = "|Param "; 358 f4 = "|Data "; 359 } 360 361 smb_fdata(ndo, words + 1, f1, 362 ND_MIN(words + 1 + 2 * GET_U_1(words), maxbuf), 363 unicodestr); 364 365 bcc = GET_LE_U_2(data1); 366 ND_PRINT("smb_bcc=%u\n", bcc); 367 if (bcc > 0) { 368 smb_fdata(ndo, data1 + 2, f2, maxbuf - (paramlen + datalen), unicodestr); 369 370 #define MAILSLOT_BROWSE_STR "\\MAILSLOT\\BROWSE" 371 ND_TCHECK_LEN(data1 + 2, strlen(MAILSLOT_BROWSE_STR) + 1); 372 if (strcmp((const char *)(data1 + 2), MAILSLOT_BROWSE_STR) == 0) { 373 print_browse(ndo, param, paramlen, data, datalen); 374 return; 375 } 376 #undef MAILSLOT_BROWSE_STR 377 378 #define PIPE_LANMAN_STR "\\PIPE\\LANMAN" 379 ND_TCHECK_LEN(data1 + 2, strlen(PIPE_LANMAN_STR) + 1); 380 if (strcmp((const char *)(data1 + 2), PIPE_LANMAN_STR) == 0) { 381 print_ipc(ndo, param, paramlen, data, datalen); 382 return; 383 } 384 #undef PIPE_LANMAN_STR 385 386 if (paramlen) 387 smb_fdata(ndo, param, f3, ND_MIN(param + paramlen, maxbuf), unicodestr); 388 if (datalen) 389 smb_fdata(ndo, data, f4, ND_MIN(data + datalen, maxbuf), unicodestr); 390 } 391 return; 392 trunc: 393 nd_print_trunc(ndo); 394 } 395 396 397 static void 398 print_negprot(netdissect_options *ndo, 399 const u_char *words, const u_char *data, const u_char *buf _U_, const u_char *maxbuf) 400 { 401 u_int wct, bcc; 402 const char *f1 = NULL, *f2 = NULL; 403 404 wct = GET_U_1(words); 405 if (request) 406 f2 = "*|Dialect=[Y]\n"; 407 else { 408 if (wct == 1) 409 f1 = "Core Protocol\nDialectIndex=[u]"; 410 else if (wct == 17) 411 f1 = "NT1 Protocol\nDialectIndex=[u]\nSecMode=[B]\nMaxMux=[u]\nNumVcs=[u]\nMaxBuffer=[U]\nRawSize=[U]\nSessionKey=[W]\nCapabilities=[W]\nServerTime=[T3]TimeZone=[u]\nCryptKey="; 412 else if (wct == 13) 413 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="; 414 } 415 416 if (f1) 417 smb_fdata(ndo, words + 1, f1, ND_MIN(words + 1 + wct * 2, maxbuf), 418 unicodestr); 419 else 420 smb_data_print(ndo, words + 1, 421 ND_MIN(wct * 2, ND_BYTES_BETWEEN(words + 1, maxbuf))); 422 423 bcc = GET_LE_U_2(data); 424 ND_PRINT("smb_bcc=%u\n", bcc); 425 if (bcc > 0) { 426 if (f2) 427 smb_fdata(ndo, data + 2, f2, ND_MIN(data + 2 + GET_LE_U_2(data), 428 maxbuf), unicodestr); 429 else 430 smb_data_print(ndo, data + 2, 431 ND_MIN(GET_LE_U_2(data), ND_BYTES_BETWEEN(data + 2, maxbuf))); 432 } 433 } 434 435 static void 436 print_sesssetup(netdissect_options *ndo, 437 const u_char *words, const u_char *data, const u_char *buf _U_, const u_char *maxbuf) 438 { 439 u_int wct, bcc; 440 const char *f1 = NULL, *f2 = NULL; 441 442 wct = GET_U_1(words); 443 if (request) { 444 if (wct == 10) 445 f1 = "Com2=[w]\nOff2=[u]\nBufSize=[u]\nMpxMax=[u]\nVcNum=[u]\nSessionKey=[W]\nPassLen=[u]\nCryptLen=[u]\nCryptOff=[u]\nPass&Name=\n"; 446 else 447 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"; 448 } else { 449 if (wct == 3) { 450 f1 = "Com2=[w]\nOff2=[u]\nAction=[w]\n"; 451 } else if (wct == 13) { 452 f1 = "Com2=[B]\nRes=[B]\nOff2=[u]\nAction=[w]\n"; 453 f2 = "NativeOS=[S]\nNativeLanMan=[S]\nPrimaryDomain=[S]\n"; 454 } 455 } 456 457 if (f1) 458 smb_fdata(ndo, words + 1, f1, ND_MIN(words + 1 + wct * 2, maxbuf), 459 unicodestr); 460 else 461 smb_data_print(ndo, words + 1, 462 ND_MIN(wct * 2, ND_BYTES_BETWEEN(words + 1, maxbuf))); 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(data + 2, maxbuf))); 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(data + 2, maxbuf))); 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, 880 ND_MIN(bcc, ND_BYTES_BETWEEN(data + 2, maxbuf))); 881 } 882 } 883 } 884 885 if ((fn->flags & FLG_CHAIN) == 0) 886 break; 887 if (wct == 0) 888 break; 889 command = GET_U_1(words + 1); 890 if (command == 0xFF) 891 break; 892 newsmboffset = GET_LE_U_2(words + 3); 893 894 fn = smbfind(command, smb_fns); 895 896 ND_PRINT("\nSMB PACKET: %s (%s) (CHAINED)\n", 897 fn->name, request ? "REQUEST" : "REPLY"); 898 if (newsmboffset <= smboffset) { 899 ND_PRINT("Bad andX offset: %u <= %u\n", newsmboffset, smboffset); 900 break; 901 } 902 smboffset = newsmboffset; 903 } 904 } 905 906 907 /* 908 * print a NBT packet received across tcp on port 139 909 */ 910 void 911 nbt_tcp_print(netdissect_options *ndo, 912 const u_char *data, u_int length) 913 { 914 u_int caplen; 915 u_int type; 916 u_int nbt_len; 917 const u_char *maxbuf; 918 919 ndo->ndo_protocol = "nbt_tcp"; 920 if (length < 4) 921 goto trunc; 922 if (ndo->ndo_snapend < data) 923 goto trunc; 924 caplen = ND_BYTES_AVAILABLE_AFTER(data); 925 if (caplen < 4) 926 goto trunc; 927 maxbuf = data + caplen; 928 type = GET_U_1(data); 929 nbt_len = GET_BE_U_2(data + 2); 930 length -= 4; 931 caplen -= 4; 932 933 startbuf = data; 934 935 if (ndo->ndo_vflag < 2) { 936 ND_PRINT(" NBT Session Packet: "); 937 switch (type) { 938 case 0x00: 939 ND_PRINT("Session Message"); 940 break; 941 942 case 0x81: 943 ND_PRINT("Session Request"); 944 break; 945 946 case 0x82: 947 ND_PRINT("Session Granted"); 948 break; 949 950 case 0x83: 951 { 952 u_int ecode; 953 954 if (nbt_len < 4) 955 goto trunc; 956 if (length < 4) 957 goto trunc; 958 if (caplen < 4) 959 goto trunc; 960 ecode = GET_U_1(data + 4); 961 962 ND_PRINT("Session Reject, "); 963 switch (ecode) { 964 case 0x80: 965 ND_PRINT("Not listening on called name"); 966 break; 967 case 0x81: 968 ND_PRINT("Not listening for calling name"); 969 break; 970 case 0x82: 971 ND_PRINT("Called name not present"); 972 break; 973 case 0x83: 974 ND_PRINT("Called name present, but insufficient resources"); 975 break; 976 default: 977 ND_PRINT("Unspecified error 0x%X", ecode); 978 break; 979 } 980 } 981 break; 982 983 case 0x85: 984 ND_PRINT("Session Keepalive"); 985 break; 986 987 default: 988 data = smb_fdata(ndo, data, "Unknown packet type [rB]", maxbuf, 0); 989 break; 990 } 991 } else { 992 ND_PRINT("\n>>> NBT Session Packet\n"); 993 switch (type) { 994 case 0x00: 995 data = smb_fdata(ndo, data, "[P1]NBT Session Message\nFlags=[B]\nLength=[ru]\n", 996 data + 4, 0); 997 if (data == NULL) 998 break; 999 if (nbt_len >= 4 && caplen >= 4 && memcmp(data,"\377SMB",4) == 0) { 1000 if (nbt_len > caplen) { 1001 if (nbt_len > length) 1002 ND_PRINT("WARNING: Packet is continued in later TCP segments\n"); 1003 else 1004 ND_PRINT("WARNING: Short packet. Try increasing the snap length by %u\n", 1005 nbt_len - caplen); 1006 } 1007 print_smb(ndo, data, maxbuf > data + nbt_len ? data + nbt_len : maxbuf); 1008 } else 1009 ND_PRINT("Session packet:(raw data or continuation?)\n"); 1010 break; 1011 1012 case 0x81: 1013 data = smb_fdata(ndo, data, 1014 "[P1]NBT Session Request\nFlags=[B]\nLength=[ru]\nDestination=[n1]\nSource=[n1]\n", 1015 maxbuf, 0); 1016 break; 1017 1018 case 0x82: 1019 data = smb_fdata(ndo, data, "[P1]NBT Session Granted\nFlags=[B]\nLength=[ru]\n", maxbuf, 0); 1020 break; 1021 1022 case 0x83: 1023 { 1024 const u_char *origdata; 1025 u_int ecode; 1026 1027 origdata = data; 1028 data = smb_fdata(ndo, data, "[P1]NBT SessionReject\nFlags=[B]\nLength=[ru]\nReason=[B]\n", 1029 maxbuf, 0); 1030 if (data == NULL) 1031 break; 1032 if (nbt_len >= 1 && caplen >= 1) { 1033 ecode = GET_U_1(origdata + 4); 1034 switch (ecode) { 1035 case 0x80: 1036 ND_PRINT("Not listening on called name\n"); 1037 break; 1038 case 0x81: 1039 ND_PRINT("Not listening for calling name\n"); 1040 break; 1041 case 0x82: 1042 ND_PRINT("Called name not present\n"); 1043 break; 1044 case 0x83: 1045 ND_PRINT("Called name present, but insufficient resources\n"); 1046 break; 1047 default: 1048 ND_PRINT("Unspecified error 0x%X\n", ecode); 1049 break; 1050 } 1051 } 1052 } 1053 break; 1054 1055 case 0x85: 1056 data = smb_fdata(ndo, data, "[P1]NBT Session Keepalive\nFlags=[B]\nLength=[ru]\n", maxbuf, 0); 1057 break; 1058 1059 default: 1060 data = smb_fdata(ndo, data, "NBT - Unknown packet type\nType=[B]\n", maxbuf, 0); 1061 break; 1062 } 1063 } 1064 return; 1065 trunc: 1066 nd_print_trunc(ndo); 1067 } 1068 1069 static const struct tok opcode_str[] = { 1070 { 0, "QUERY" }, 1071 { 5, "REGISTRATION" }, 1072 { 6, "RELEASE" }, 1073 { 7, "WACK" }, 1074 { 8, "REFRESH(8)" }, 1075 { 9, "REFRESH" }, 1076 { 15, "MULTIHOMED REGISTRATION" }, 1077 { 0, NULL } 1078 }; 1079 1080 /* 1081 * print a NBT packet received across udp on port 137 1082 */ 1083 void 1084 nbt_udp137_print(netdissect_options *ndo, 1085 const u_char *data, u_int length) 1086 { 1087 const u_char *maxbuf = data + length; 1088 u_int name_trn_id, response, opcode, nm_flags, rcode; 1089 u_int qdcount, ancount, nscount, arcount; 1090 const u_char *p; 1091 u_int total, i; 1092 1093 ndo->ndo_protocol = "nbt_udp137"; 1094 name_trn_id = GET_BE_U_2(data); 1095 response = (GET_U_1(data + 2) >> 7); 1096 opcode = (GET_U_1(data + 2) >> 3) & 0xF; 1097 nm_flags = ((GET_U_1(data + 2) & 0x7) << 4) + (GET_U_1(data + 3) >> 4); 1098 rcode = GET_U_1(data + 3) & 0xF; 1099 qdcount = GET_BE_U_2(data + 4); 1100 ancount = GET_BE_U_2(data + 6); 1101 nscount = GET_BE_U_2(data + 8); 1102 arcount = GET_BE_U_2(data + 10); 1103 startbuf = data; 1104 1105 if (maxbuf <= data) 1106 return; 1107 1108 if (ndo->ndo_vflag > 1) 1109 ND_PRINT("\n>>> "); 1110 1111 ND_PRINT("NBT UDP PACKET(137): %s", tok2str(opcode_str, "OPUNKNOWN", opcode)); 1112 if (response) { 1113 ND_PRINT("; %s", rcode ? "NEGATIVE" : "POSITIVE"); 1114 } 1115 ND_PRINT("; %s; %s", response ? "RESPONSE" : "REQUEST", 1116 (nm_flags & 1) ? "BROADCAST" : "UNICAST"); 1117 1118 if (ndo->ndo_vflag < 2) 1119 return; 1120 1121 ND_PRINT("\nTrnID=0x%X\nOpCode=%u\nNmFlags=0x%X\nRcode=%u\nQueryCount=%u\nAnswerCount=%u\nAuthorityCount=%u\nAddressRecCount=%u\n", 1122 name_trn_id, opcode, nm_flags, rcode, qdcount, ancount, nscount, 1123 arcount); 1124 1125 p = data + 12; 1126 1127 total = ancount + nscount + arcount; 1128 1129 if (qdcount > 100 || total > 100) { 1130 ND_PRINT("Corrupt packet??\n"); 1131 return; 1132 } 1133 1134 if (qdcount) { 1135 ND_PRINT("QuestionRecords:\n"); 1136 for (i = 0; i < qdcount; i++) { 1137 p = smb_fdata(ndo, p, 1138 "|Name=[n1]\nQuestionType=[rw]\nQuestionClass=[rw]\n#", 1139 maxbuf, 0); 1140 if (p == NULL) 1141 goto out; 1142 } 1143 } 1144 1145 if (total) { 1146 ND_PRINT("\nResourceRecords:\n"); 1147 for (i = 0; i < total; i++) { 1148 u_int rdlen; 1149 u_int restype; 1150 1151 p = smb_fdata(ndo, p, "Name=[n1]\n#", maxbuf, 0); 1152 if (p == NULL) 1153 goto out; 1154 restype = GET_BE_U_2(p); 1155 p = smb_fdata(ndo, p, "ResType=[rw]\nResClass=[rw]\nTTL=[rU]\n", p + 8, 0); 1156 if (p == NULL) 1157 goto out; 1158 rdlen = GET_BE_U_2(p); 1159 ND_PRINT("ResourceLength=%u\nResourceData=\n", rdlen); 1160 p += 2; 1161 if (rdlen == 6) { 1162 p = smb_fdata(ndo, p, "AddrType=[rw]\nAddress=[b.b.b.b]\n", p + rdlen, 0); 1163 if (p == NULL) 1164 goto out; 1165 } else { 1166 if (restype == 0x21) { 1167 u_int numnames; 1168 1169 numnames = GET_U_1(p); 1170 p = smb_fdata(ndo, p, "NumNames=[B]\n", p + 1, 0); 1171 if (p == NULL) 1172 goto out; 1173 while (numnames) { 1174 p = smb_fdata(ndo, p, "Name=[n2]\t#", maxbuf, 0); 1175 if (p == NULL) 1176 goto out; 1177 ND_TCHECK_1(p); 1178 if (p >= maxbuf) 1179 goto out; 1180 if (GET_U_1(p) & 0x80) 1181 ND_PRINT("<GROUP> "); 1182 switch (GET_U_1(p) & 0x60) { 1183 case 0x00: ND_PRINT("B "); break; 1184 case 0x20: ND_PRINT("P "); break; 1185 case 0x40: ND_PRINT("M "); break; 1186 case 0x60: ND_PRINT("_ "); break; 1187 } 1188 if (GET_U_1(p) & 0x10) 1189 ND_PRINT("<DEREGISTERING> "); 1190 if (GET_U_1(p) & 0x08) 1191 ND_PRINT("<CONFLICT> "); 1192 if (GET_U_1(p) & 0x04) 1193 ND_PRINT("<ACTIVE> "); 1194 if (GET_U_1(p) & 0x02) 1195 ND_PRINT("<PERMANENT> "); 1196 ND_PRINT("\n"); 1197 p += 2; 1198 numnames--; 1199 } 1200 } else { 1201 if (p >= maxbuf) 1202 goto out; 1203 smb_data_print(ndo, p, 1204 ND_MIN(rdlen, length - ND_BYTES_BETWEEN(data, p))); 1205 p += rdlen; 1206 } 1207 } 1208 } 1209 } 1210 1211 if (p < maxbuf) 1212 smb_fdata(ndo, p, "AdditionalData:\n", maxbuf, 0); 1213 1214 out: 1215 return; 1216 trunc: 1217 nd_print_trunc(ndo); 1218 } 1219 1220 /* 1221 * Print an SMB-over-TCP packet received across tcp on port 445 1222 */ 1223 void 1224 smb_tcp_print(netdissect_options *ndo, 1225 const u_char * data, u_int length) 1226 { 1227 u_int caplen; 1228 u_int smb_len; 1229 const u_char *maxbuf; 1230 1231 ndo->ndo_protocol = "smb_tcp"; 1232 if (length < 4) 1233 goto trunc; 1234 if (ndo->ndo_snapend < data) 1235 goto trunc; 1236 caplen = ND_BYTES_AVAILABLE_AFTER(data); 1237 if (caplen < 4) 1238 goto trunc; 1239 maxbuf = data + caplen; 1240 smb_len = GET_BE_U_3(data + 1); 1241 length -= 4; 1242 caplen -= 4; 1243 1244 startbuf = data; 1245 data += 4; 1246 1247 if (smb_len >= 4 && caplen >= 4 && memcmp(data,"\377SMB",4) == 0) { 1248 if (smb_len > caplen) { 1249 if (smb_len > length) 1250 ND_PRINT(" WARNING: Packet is continued in later TCP segments\n"); 1251 else 1252 ND_PRINT(" WARNING: Short packet. Try increasing the snap length by %u\n", 1253 smb_len - caplen); 1254 } else 1255 ND_PRINT(" "); 1256 print_smb(ndo, data, maxbuf > data + smb_len ? data + smb_len : maxbuf); 1257 } else 1258 ND_PRINT(" SMB-over-TCP packet:(raw data or continuation?)\n"); 1259 return; 1260 trunc: 1261 nd_print_trunc(ndo); 1262 } 1263 1264 /* 1265 * print a NBT packet received across udp on port 138 1266 */ 1267 void 1268 nbt_udp138_print(netdissect_options *ndo, 1269 const u_char *data, u_int length) 1270 { 1271 const u_char *maxbuf = data + length; 1272 1273 ndo->ndo_protocol = "nbt_udp138"; 1274 if (maxbuf > ndo->ndo_snapend) 1275 maxbuf = ndo->ndo_snapend; 1276 if (maxbuf <= data) 1277 return; 1278 startbuf = data; 1279 1280 if (ndo->ndo_vflag < 2) { 1281 ND_PRINT("NBT UDP PACKET(138)"); 1282 return; 1283 } 1284 1285 data = smb_fdata(ndo, data, 1286 "\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#", 1287 maxbuf, 0); 1288 1289 if (data != NULL) { 1290 /* If there isn't enough data for "\377SMB", don't check for it. */ 1291 if ((data + 3) >= maxbuf) 1292 goto out; 1293 1294 if (memcmp(data, "\377SMB",4) == 0) 1295 print_smb(ndo, data, maxbuf); 1296 } 1297 out: 1298 return; 1299 } 1300 1301 1302 /* 1303 print netbeui frames 1304 */ 1305 static struct nbf_strings { 1306 const char *name; 1307 const char *nonverbose; 1308 const char *verbose; 1309 } nbf_strings[0x20] = { 1310 { "Add Group Name Query", ", [P23]Name to add=[n2]#", 1311 "[P5]ResponseCorrelator=[w]\n[P16]Name to add=[n2]\n" }, 1312 { "Add Name Query", ", [P23]Name to add=[n2]#", 1313 "[P5]ResponseCorrelator=[w]\n[P16]Name to add=[n2]\n" }, 1314 { "Name In Conflict", NULL, NULL }, 1315 { "Status Query", NULL, NULL }, 1316 { NULL, NULL, NULL }, /* not used */ 1317 { NULL, NULL, NULL }, /* not used */ 1318 { NULL, NULL, NULL }, /* not used */ 1319 { "Terminate Trace", NULL, NULL }, 1320 { "Datagram", NULL, 1321 "[P7]Destination=[n2]\nSource=[n2]\n" }, 1322 { "Broadcast Datagram", NULL, 1323 "[P7]Destination=[n2]\nSource=[n2]\n" }, 1324 { "Name Query", ", [P7]Name=[n2]#", 1325 "[P1]SessionNumber=[B]\nNameType=[B][P2]\nResponseCorrelator=[w]\nName=[n2]\nName of sender=[n2]\n" }, 1326 { NULL, NULL, NULL }, /* not used */ 1327 { NULL, NULL, NULL }, /* not used */ 1328 { "Add Name Response", ", [P1]GroupName=[w] [P4]Destination=[n2] Source=[n2]#", 1329 "AddNameInProcess=[B]\nGroupName=[w]\nTransmitCorrelator=[w][P2]\nDestination=[n2]\nSource=[n2]\n" }, 1330 { "Name Recognized", NULL, 1331 "[P1]Data2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nDestination=[n2]\nSource=[n2]\n" }, 1332 { "Status Response", NULL, NULL }, 1333 { NULL, NULL, NULL }, /* not used */ 1334 { NULL, NULL, NULL }, /* not used */ 1335 { NULL, NULL, NULL }, /* not used */ 1336 { "Terminate Trace", NULL, NULL }, 1337 { "Data Ack", NULL, 1338 "[P3]TransmitCorrelator=[w][P2]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1339 { "Data First/Middle", NULL, 1340 "Flags=[{RECEIVE_CONTINUE|NO_ACK||PIGGYBACK_ACK_INCLUDED|}]\nResyncIndicator=[w][P2]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1341 { "Data Only/Last", NULL, 1342 "Flags=[{|NO_ACK|PIGGYBACK_ACK_ALLOWED|PIGGYBACK_ACK_INCLUDED|}]\nResyncIndicator=[w][P2]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1343 { "Session Confirm", NULL, 1344 "Data1=[B]\nData2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1345 { "Session End", NULL, 1346 "[P1]Data2=[w][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1347 { "Session Initialize", NULL, 1348 "Data1=[B]\nData2=[w]\nTransmitCorrelator=[w]\nResponseCorelator=[w]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1349 { "No Receive", NULL, 1350 "Flags=[{|SEND_NO_ACK}]\nDataBytesAccepted=[b][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1351 { "Receive Outstanding", NULL, 1352 "[P1]DataBytesAccepted=[b][P4]\nRemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1353 { "Receive Continue", NULL, 1354 "[P2]TransmitCorrelator=[w]\n[P2]RemoteSessionNumber=[B]\nLocalSessionNumber=[B]\n" }, 1355 { NULL, NULL, NULL }, /* not used */ 1356 { NULL, NULL, NULL }, /* not used */ 1357 { "Session Alive", NULL, NULL } 1358 }; 1359 1360 void 1361 netbeui_print(netdissect_options *ndo, 1362 u_short control, const u_char *data, u_int length) 1363 { 1364 const u_char *maxbuf = data + length; 1365 u_int len; 1366 u_int command; 1367 const u_char *data2; 1368 int is_truncated = 0; 1369 1370 ndo->ndo_protocol = "netbeui"; 1371 if (maxbuf > ndo->ndo_snapend) 1372 maxbuf = ndo->ndo_snapend; 1373 len = GET_LE_U_2(data); 1374 command = GET_U_1(data + 4); 1375 data2 = data + len; 1376 if (data2 >= maxbuf) { 1377 data2 = maxbuf; 1378 is_truncated = 1; 1379 } 1380 1381 startbuf = data; 1382 1383 if (ndo->ndo_vflag < 2) { 1384 ND_PRINT("NBF Packet: "); 1385 data = smb_fdata(ndo, data, "[P5]#", maxbuf, 0); 1386 } else { 1387 ND_PRINT("\n>>> NBF Packet\nType=0x%X ", control); 1388 data = smb_fdata(ndo, data, "Length=[u] Signature=[w] Command=[B]\n#", maxbuf, 0); 1389 } 1390 if (data == NULL) 1391 goto out; 1392 1393 if (command > 0x1f || nbf_strings[command].name == NULL) { 1394 if (ndo->ndo_vflag < 2) 1395 data = smb_fdata(ndo, data, "Unknown NBF Command#", data2, 0); 1396 else 1397 data = smb_fdata(ndo, data, "Unknown NBF Command\n", data2, 0); 1398 } else { 1399 if (ndo->ndo_vflag < 2) { 1400 ND_PRINT("%s", nbf_strings[command].name); 1401 if (nbf_strings[command].nonverbose != NULL) 1402 data = smb_fdata(ndo, data, nbf_strings[command].nonverbose, data2, 0); 1403 } else { 1404 ND_PRINT("%s:\n", nbf_strings[command].name); 1405 if (nbf_strings[command].verbose != NULL) 1406 data = smb_fdata(ndo, data, nbf_strings[command].verbose, data2, 0); 1407 else 1408 ND_PRINT("\n"); 1409 } 1410 } 1411 1412 if (ndo->ndo_vflag < 2) 1413 return; 1414 1415 if (data == NULL) 1416 goto out; 1417 1418 if (is_truncated) { 1419 /* data2 was past the end of the buffer */ 1420 goto out; 1421 } 1422 1423 /* If this isn't a command that would contain an SMB message, quit. */ 1424 if (command != 0x08 && command != 0x09 && command != 0x15 && 1425 command != 0x16) 1426 goto out; 1427 1428 /* If there isn't enough data for "\377SMB", don't look for it. */ 1429 if ((data2 + 3) >= maxbuf) 1430 goto out; 1431 1432 if (memcmp(data2, "\377SMB",4) == 0) 1433 print_smb(ndo, data2, maxbuf); 1434 else { 1435 u_int i; 1436 for (i = 0; i < 128; i++) { 1437 if ((data2 + i + 3) >= maxbuf) 1438 break; 1439 if (memcmp(data2 + i, "\377SMB", 4) == 0) { 1440 ND_PRINT("found SMB packet at %u\n", i); 1441 print_smb(ndo, data2 + i, maxbuf); 1442 break; 1443 } 1444 } 1445 } 1446 1447 out: 1448 return; 1449 } 1450 1451 1452 /* 1453 * print IPX-Netbios frames 1454 */ 1455 void 1456 ipx_netbios_print(netdissect_options *ndo, 1457 const u_char *data, u_int length) 1458 { 1459 /* 1460 * this is a hack till I work out how to parse the rest of the 1461 * NetBIOS-over-IPX stuff 1462 */ 1463 u_int i; 1464 const u_char *maxbuf; 1465 1466 ndo->ndo_protocol = "ipx_netbios"; 1467 maxbuf = data + length; 1468 /* Don't go past the end of the captured data in the packet. */ 1469 if (maxbuf > ndo->ndo_snapend) 1470 maxbuf = ndo->ndo_snapend; 1471 startbuf = data; 1472 for (i = 0; i < 128; i++) { 1473 if ((data + i + 4) > maxbuf) 1474 break; 1475 if (memcmp(data + i, "\377SMB", 4) == 0) { 1476 smb_fdata(ndo, data, "\n>>> IPX transport ", data + i, 0); 1477 print_smb(ndo, data + i, maxbuf); 1478 break; 1479 } 1480 } 1481 if (i == 128) 1482 smb_fdata(ndo, data, "\n>>> Unknown IPX ", maxbuf, 0); 1483 } 1484