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