]> The Tcpdump Group git mirrors - tcpdump/commitdiff
patches from Andrew Tridgell <[email protected]> to add decoding of SMB packets
authorassar <assar>
Sun, 21 Nov 1999 15:57:50 +0000 (15:57 +0000)
committerassar <assar>
Sun, 21 Nov 1999 15:57:50 +0000 (15:57 +0000)
Makefile.in
print-llc.c
print-tcp.c
print-udp.c
smb.h [new file with mode: 0644]
smbutil.c [new file with mode: 0644]
tcpdump.1

index fb6e380d68d8e9dfac004c814005e7b301993f71..ed0df249b579ccb581fb871885a6286601be8282 100644 (file)
@@ -17,7 +17,7 @@
 #  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 #
-# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.215 1999-11-21 09:36:43 fenner Exp $ (LBL)
+# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.216 1999-11-21 15:57:52 assar Exp $ (LBL)
 
 #
 # Various configurable paths (remember to edit Makefile.in, not Makefile)
@@ -75,7 +75,8 @@ CSRC =        tcpdump.c \
        parsenfsfh.c util.c savestr.c setsignal.c \
        print-esp.c print-ah.c print-vjc.c print-isakmp.c print-chdlc.c \
        print-ipcomp.c print-mobile.c print-l2tp.c print-bgp.c print-rx.c \
-       print-lane.c print-cip.c print-pppoe.c print-lcp.c
+       print-lane.c print-cip.c print-pppoe.c print-lcp.c \
+       print-smb.c smbutil.c
 LOCALSRC = @LOCALSRC@
 GENSRC = version.c
 LIBOBJS = @LIBOBJS@
index 5515dc5e928bc0cf338eed7428db8bf412a755c2..4df0f9f93e3525bd32ad571fbe8a1d3042238655 100644 (file)
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-llc.c,v 1.25 1999-11-21 09:36:56 fenner Exp $";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-llc.c,v 1.26 1999-11-21 15:57:52 assar Exp $";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -83,10 +83,12 @@ llc_print(const u_char *p, u_int length, u_int caplen,
                ipx_print(p, length);
                return (1);
        }
-#ifdef notyet
-       else if (p[0] == 0xf0 && p[1] == 0xf0)
-               netbios_print(p, length);
-#endif
+       else if (p[0] == 0xf0 && p[1] == 0xf0) {
+         /* we don't actually have a full netbeui parser yet, but the
+            smb parser can handle many smb-in-netbeui packets, which
+            is very useful, so we call that */
+         netbeui_print(p+2,p+min(caplen,length));
+       }
        if (llc.ssap == LLCSAP_ISONS && llc.dsap == LLCSAP_ISONS
            && llc.llcui == LLC_UI) {
                isoclns_print(p + 3, length - 3, caplen - 3, esrc, edst);
@@ -161,6 +163,13 @@ llc_print(const u_char *p, u_int length, u_int caplen,
                        caplen -= 3;
                    }
                }
+
+               if (!strcmp(m,"ui") && f=='C') {
+                 /* we don't have a proper ipx decoder yet, but there
+                     is a partial one in the smb code */
+                 ipx_netbios_print(p,p+min(caplen,length));
+               }
+
        } else {
                char f;
                llc.llcis = ntohs(llc.llcis);
@@ -189,8 +198,5 @@ llc_print(const u_char *p, u_int length, u_int caplen,
                caplen -= 4;
        }
        (void)printf(" len=%d", length);
-       if (caplen > 0) {
-               default_print_unaligned(p, caplen);
-       }
        return(1);
 }
index 3a2af9c655f69bfb1bff05a8daa4fa3047a8c532..987f7ad6c327554b74fb78d67d5d294726b7a551 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.59 1999-11-21 09:37:02 fenner Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.60 1999-11-21 15:57:51 assar Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -108,6 +108,8 @@ struct tcp_seq_hash {
 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
 
 
+#define NETBIOS_SSN_PORT 139
+
 void
 tcp_print(register const u_char *bp, register u_int length,
          register const u_char *bp2)
@@ -483,6 +485,8 @@ tcp_print(register const u_char *bp, register u_int length,
        bp += (tp->th_off * 4);
        if (sport == 179 || dport == 179)
                bgp_print(bp, length);
+       if (sport == NETBIOS_SSN_PORT || dport == NETBIOS_SSN_PORT)
+               nbt_tcp_print(bp, length);
        return;
 bad:
        fputs("[bad opt]", stdout);
index 49e3848ad6dca35fd3f58dcf111e04003b9eadf6..74662ebd9b24fd018fafc2f949af3705c1d191b2 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-udp.c,v 1.66 1999-11-21 12:38:24 itojun Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-udp.c,v 1.67 1999-11-21 15:57:51 assar Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -307,6 +307,8 @@ rtcp_print(const u_char *hdr, const u_char *ep)
 #define ISAKMP_PORT_USER2 8500 /*??? - nonstandard*/
 #define RX_PORT_LOW 7000       /*XXX*/
 #define RX_PORT_HIGH 7009      /*XXX*/
+#define NETBIOS_NS_PORT   137
+#define NETBIOS_DGRAM_PORT   138
 
 #ifdef INET6
 #define RIPNG_PORT 521         /*XXX*/
@@ -507,6 +509,12 @@ udp_print(register const u_char *bp, u_int length, register const u_char *bp2)
                        krb_print((const void *)(up + 1), length);
                else if (ISPORT(L2TP_PORT))
                        l2tp_print((const u_char *)(up + 1), length);
+               else if (ISPORT(NETBIOS_NS_PORT)) {
+                 nbt_udp137_print((const u_char *)(up + 1), length);
+               }
+               else if (ISPORT(NETBIOS_DGRAM_PORT)) {
+                 nbt_udp138_print((const u_char *)(up + 1), length);
+               }
                else if (dport == 3456)
                        vat_print((const void *)(up + 1), length, up);
                /*
diff --git a/smb.h b/smb.h
new file mode 100644 (file)
index 0000000..ae47037
--- /dev/null
+++ b/smb.h
@@ -0,0 +1,152 @@
+/* 
+   Copyright (C) Andrew Tridgell 1995-1999
+
+   This software may be distributed either under the terms of the
+   BSD-style license that accompanies tcpdump or the GNU GPL version 2
+   or later */
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
+
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
+
+#define uint16 unsigned short
+#define uint32 unsigned int
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+/* the complete */
+#define SMBmkdir      0x00   /* create directory */
+#define SMBrmdir      0x01   /* delete directory */
+#define SMBopen       0x02   /* open file */
+#define SMBcreate     0x03   /* create file */
+#define SMBclose      0x04   /* close file */
+#define SMBflush      0x05   /* flush file */
+#define SMBunlink     0x06   /* delete file */
+#define SMBmv         0x07   /* rename file */
+#define SMBgetatr     0x08   /* get file attributes */
+#define SMBsetatr     0x09   /* set file attributes */
+#define SMBread       0x0A   /* read from file */
+#define SMBwrite      0x0B   /* write to file */
+#define SMBlock       0x0C   /* lock byte range */
+#define SMBunlock     0x0D   /* unlock byte range */
+#define SMBctemp      0x0E   /* create temporary file */
+#define SMBmknew      0x0F   /* make new file */
+#define SMBchkpth     0x10   /* check directory path */
+#define SMBexit       0x11   /* process exit */
+#define SMBlseek      0x12   /* seek */
+#define SMBtcon       0x70   /* tree connect */
+#define SMBtconX      0x75   /* tree connect and X*/
+#define SMBtdis       0x71   /* tree disconnect */
+#define SMBnegprot    0x72   /* negotiate protocol */
+#define SMBdskattr    0x80   /* get disk attributes */
+#define SMBsearch     0x81   /* search directory */
+#define SMBsplopen    0xC0   /* open print spool file */
+#define SMBsplwr      0xC1   /* write to print spool file */
+#define SMBsplclose   0xC2   /* close print spool file */
+#define SMBsplretq    0xC3   /* return print queue */
+#define SMBsends      0xD0   /* send single block message */
+#define SMBsendb      0xD1   /* send broadcast message */
+#define SMBfwdname    0xD2   /* forward user name */
+#define SMBcancelf    0xD3   /* cancel forward */
+#define SMBgetmac     0xD4   /* get machine name */
+#define SMBsendstrt   0xD5   /* send start of multi-block message */
+#define SMBsendend    0xD6   /* send end of multi-block message */
+#define SMBsendtxt    0xD7   /* send text of multi-block message */
+
+/* Core+ protocol */
+#define SMBlockread      0x13   /* Lock a range and read */
+#define SMBwriteunlock 0x14 /* Unlock a range then write */
+#define SMBreadbraw   0x1a  /* read a block of data with no smb header */
+#define SMBwritebraw  0x1d  /* write a block of data with no smb header */
+#define SMBwritec     0x20  /* secondary write request */
+#define SMBwriteclose 0x2c  /* write a file then close it */
+
+/* dos extended protocol */
+#define SMBreadBraw      0x1A   /* read block raw */
+#define SMBreadBmpx      0x1B   /* read block multiplexed */
+#define SMBreadBs        0x1C   /* read block (secondary response) */
+#define SMBwriteBraw     0x1D   /* write block raw */
+#define SMBwriteBmpx     0x1E   /* write block multiplexed */
+#define SMBwriteBs       0x1F   /* write block (secondary request) */
+#define SMBwriteC        0x20   /* write complete response */
+#define SMBsetattrE      0x22   /* set file attributes expanded */
+#define SMBgetattrE      0x23   /* get file attributes expanded */
+#define SMBlockingX      0x24   /* lock/unlock byte ranges and X */
+#define SMBtrans         0x25   /* transaction - name, bytes in/out */
+#define SMBtranss        0x26   /* transaction (secondary request/response) */
+#define SMBioctl         0x27   /* IOCTL */
+#define SMBioctls        0x28   /* IOCTL  (secondary request/response) */
+#define SMBcopy          0x29   /* copy */
+#define SMBmove          0x2A   /* move */
+#define SMBecho          0x2B   /* echo */
+#define SMBopenX         0x2D   /* open and X */
+#define SMBreadX         0x2E   /* read and X */
+#define SMBwriteX        0x2F   /* write and X */
+#define SMBsesssetupX    0x73   /* Session Set Up & X (including User Logon) */
+#define SMBffirst        0x82   /* find first */
+#define SMBfunique       0x83   /* find unique */
+#define SMBfclose        0x84   /* find close */
+#define SMBinvalid       0xFE   /* invalid command */
+
+/* Extended 2.0 protocol */
+#define SMBtrans2        0x32   /* TRANS2 protocol set */
+#define SMBtranss2       0x33   /* TRANS2 protocol set, secondary command */
+#define SMBfindclose     0x34   /* Terminate a TRANSACT2_FINDFIRST */
+#define SMBfindnclose    0x35   /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+#define SMBulogoffX      0x74   /* user logoff */
+
+/* NT SMB extensions. */
+#define SMBnttrans       0xA0   /* NT transact */
+#define SMBnttranss      0xA1   /* NT transact secondary */
+#define SMBntcreateX     0xA2   /* NT create and X */
+#define SMBntcancel      0xA4   /* NT cancel */
+
+/* pathworks special */
+#define pSETDIR '\377'
+
+
+/* these are the TRANS2 sub commands */
+#define TRANSACT2_OPEN          0
+#define TRANSACT2_FINDFIRST     1
+#define TRANSACT2_FINDNEXT      2
+#define TRANSACT2_QFSINFO       3
+#define TRANSACT2_SETFSINFO     4
+#define TRANSACT2_QPATHINFO     5
+#define TRANSACT2_SETPATHINFO   6
+#define TRANSACT2_QFILEINFO     7
+#define TRANSACT2_SETFILEINFO   8
+#define TRANSACT2_FSCTL         9
+#define TRANSACT2_IOCTL           10
+#define TRANSACT2_FINDNOTIFYFIRST 11
+#define TRANSACT2_FINDNOTIFYNEXT  12
+#define TRANSACT2_MKDIR           13
+
+#define PTR_DIFF(p1,p2) ((unsigned long)(((char *)(p1)) - (char *)(p2)))
+
+/* some protos */
+uchar *fdata(uchar *buf,char *fmt,uchar *maxbuf);
diff --git a/smbutil.c b/smbutil.c
new file mode 100644 (file)
index 0000000..11de719
--- /dev/null
+++ b/smbutil.c
@@ -0,0 +1,689 @@
+/* 
+   Copyright (C) Andrew Tridgell 1995-1999
+
+   This software may be distributed either under the terms of the
+   BSD-style license that accompanies tcpdump or the GNU GPL version 2
+   or later */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "smb.h"
+
+extern uchar *startbuf;
+
+/*******************************************************************
+  interpret a 32 bit dos packed date/time to some parameters
+********************************************************************/
+static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
+{
+  uint32 p0,p1,p2,p3;
+
+  p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; 
+  p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
+
+  *second = 2*(p0 & 0x1F);
+  *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
+  *hour = (p1>>3)&0xFF;
+  *day = (p2&0x1F);
+  *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
+  *year = ((p3>>1)&0xFF) + 80;
+}
+
+/*******************************************************************
+  create a unix date from a dos date
+********************************************************************/
+time_t make_unix_date(void *date_ptr)
+{
+  uint32 dos_date=0;
+  struct tm t;
+
+  dos_date = IVAL(date_ptr,0);
+
+  if (dos_date == 0) return(0);
+  
+  interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
+                    &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
+  t.tm_wday = 1;
+  t.tm_yday = 1;
+  t.tm_isdst = 0;
+
+  return (mktime(&t));
+}
+
+/*******************************************************************
+  create a unix date from a dos date
+********************************************************************/
+time_t make_unix_date2(void *date_ptr)
+{
+  uint32 x,x2;
+
+  x = IVAL(date_ptr,0);
+  x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
+  SIVAL(&x,0,x2);
+
+  return(make_unix_date((void *)&x));
+}
+
+/****************************************************************************
+interpret an 8 byte "filetime" structure to a time_t
+It's originally in "100ns units since jan 1st 1601"
+****************************************************************************/
+time_t interpret_long_date(char *p)
+{
+  double d;
+  time_t ret;
+
+  /* this gives us seconds since jan 1st 1601 (approx) */
+  d = (IVAL(p,4)*256.0 + CVAL(p,3)) * (1.0e-7 * (1<<24));
+  /* now adjust by 369 years to make the secs since 1970 */
+  d -= 369.0*365.25*24*60*60;
+
+  /* and a fudge factor as we got it wrong by a few days */
+  d += (3*24*60*60 + 6*60*60 + 2);
+
+  if (d<0)
+    return(0);
+
+  ret = (time_t)d;
+
+  return(ret);
+}
+
+
+/****************************************************************************
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+  int ret;
+  int len = (*in++) / 2;
+
+  *out=0;
+
+  if (len > 30 || len<1) return(0);
+
+  while (len--)
+    {
+      if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+       *out = 0;
+       return(0);
+      }
+      *out = ((in[0]-'A')<<4) + (in[1]-'A');
+      in += 2;
+      out++;
+    }
+  *out = 0;
+  ret = out[-1];
+
+  return(ret);
+}
+
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+static char *name_ptr(char *buf,int ofs)
+{
+  unsigned char c = *(unsigned char *)(buf+ofs);
+
+  if ((c & 0xC0) == 0xC0)
+    {
+      uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+      return(buf + l);
+    }
+  else
+    return(buf+ofs);
+}  
+
+/****************************************************************************
+extract a netbios name from a buf
+****************************************************************************/
+static int name_extract(char *buf,int ofs,char *name)
+{
+  char *p = name_ptr(buf,ofs);
+  int d = PTR_DIFF(p,buf+ofs);
+  strcpy(name,"");
+  return(name_interpret(p,name));
+}  
+  
+
+/****************************************************************************
+return the total storage length of a mangled name
+****************************************************************************/
+static int name_len(unsigned char *s)
+{
+  char *s0 = s;
+  unsigned char c = *(unsigned char *)s;
+  if ((c & 0xC0) == 0xC0)
+    return(2);  
+  while (*s) s += (*s)+1;
+  return(PTR_DIFF(s,s0)+1);
+}
+
+void print_asc(unsigned char *buf,int len)
+{
+  int i;
+  for (i=0;i<len;i++)
+    printf("%c",isprint(buf[i])?buf[i]:'.');
+}
+
+static char *name_type_str(int name_type)
+{
+  static char *f = NULL;
+  switch (name_type) {
+  case 0:    f = "Workstation"; break;
+  case 0x03: f = "Client?"; break;
+  case 0x20: f = "Server"; break;
+  case 0x1d: f = "Master Browser"; break;
+  case 0x1b: f = "Domain Controller"; break;
+  case 0x1e: f = "Browser Server"; break;
+  default:   f = "Unknown"; break;
+  }
+  return(f);
+}
+
+void print_data(unsigned char *buf,int len)
+{
+  int i=0;
+  if (len<=0) return;
+  printf("[%03X] ",i);
+  for (i=0;i<len;) {
+    printf("%02X ",(int)buf[i]);
+    i++;
+    if (i%8 == 0) printf(" ");
+    if (i%16 == 0) {      
+      print_asc(&buf[i-16],8); printf(" ");
+      print_asc(&buf[i-8],8); printf("\n");
+      if (i<len) printf("[%03X] ",i);
+    }
+  }
+  if (i%16) {
+    int n;
+
+    n = 16 - (i%16);
+    printf(" ");
+    if (n>8) printf(" ");
+    while (n--) printf("   ");
+
+    n = MIN(8,i%16);
+    print_asc(&buf[i-(i%16)],n); printf(" ");
+    n = (i%16) - n;
+    if (n>0) print_asc(&buf[i-n],n); 
+    printf("\n");    
+  }
+}
+
+
+static void write_bits(unsigned int val,char *fmt)
+{
+  char *p = fmt;
+  int i=0;
+
+  while ((p=strchr(fmt,'|'))) {
+    int l = PTR_DIFF(p,fmt);
+    if (l && (val & (1<<i))) 
+      printf("%.*s ",l,fmt);
+    fmt = p+1;
+    i++;
+  }
+}
+
+/* convert a unicode string */
+static char *unistr(char *s, int *len)
+{
+       static char buf[1000];
+       int l=0;
+       static int use_unicode = -1;
+
+       if (use_unicode == -1) {
+               char *p = getenv("USE_UNICODE");
+               if (p && (atoi(p) == 1)) 
+                       use_unicode = 1;
+               else
+                       use_unicode = 0;
+       }
+
+       /* maybe it isn't unicode - a cheap trick */
+       if (!use_unicode || (s[0] && s[1])) {
+               *len = strlen(s)+1;
+               return s;
+       }
+
+       *len = 0;
+
+       if (s[0] == 0 && s[1] != 0) {
+               s++;
+               *len = 1;
+       }
+
+       while (l < (sizeof(buf)-1) && s[0] && s[1] == 0) {
+               buf[l] = s[0];
+               s += 2; l++;
+               *len += 2;
+       }
+       buf[l] = 0;
+       *len += 2;
+       return buf;
+}
+
+uchar *fdata1(uchar *buf,char *fmt,uchar *maxbuf)
+{
+  int reverse=0;
+  char *attrib_fmt = "READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE|";
+  int len;
+
+  while (*fmt && buf<maxbuf) {
+    switch (*fmt) {
+    case 'a':
+      write_bits(CVAL(buf,0),attrib_fmt);
+      buf++; fmt++;
+      break;
+
+    case 'A':
+      write_bits(SVAL(buf,0),attrib_fmt);
+      buf+=2; fmt++;
+      break;
+
+    case '{':
+      {
+       char bitfmt[128];
+       char *p = strchr(++fmt,'}');
+       int l = PTR_DIFF(p,fmt);
+       strncpy(bitfmt,fmt,l);
+       bitfmt[l]=0;
+       fmt = p+1;
+       write_bits(CVAL(buf,0),bitfmt);
+       buf++;
+       break;
+      }
+
+    case 'P':
+      {
+       int l = atoi(fmt+1);
+       buf += l;
+       fmt++;
+       while (isdigit(*fmt)) fmt++;
+       break;
+      }
+    case 'r':
+      reverse = !reverse;
+      fmt++;
+      break;
+    case 'D':
+      {
+       unsigned int x = reverse?RIVAL(buf,0):IVAL(buf,0);
+       printf("%d (0x%x)",x, x);
+       buf += 4;
+       fmt++;
+       break;
+      }
+    case 'L':
+      {
+       unsigned int x1 = reverse?RIVAL(buf,0):IVAL(buf,0);
+       unsigned int x2 = reverse?RIVAL(buf,4):IVAL(buf,4);
+       if (x2) {
+               printf("0x%08x:%08x",x2, x1);
+       } else {
+               printf("%d (0x%08x%08x)",x1, x2, x1);
+       }
+       buf += 8;
+       fmt++;
+       break;
+      }
+    case 'd':
+      {
+       unsigned int x = reverse?RSVAL(buf,0):SVAL(buf,0);
+       printf("%d (0x%x)",x, x);
+       buf += 2;
+       fmt++;
+       break;
+      }
+    case 'W':
+      {
+       unsigned int x = reverse?RIVAL(buf,0):IVAL(buf,0);
+       printf("0x%X",x);
+       buf += 4;
+       fmt++;
+       break;
+      }
+    case 'w':
+      {
+       unsigned int x = reverse?RSVAL(buf,0):SVAL(buf,0);
+       printf("0x%X",x);
+       buf += 2;
+       fmt++;
+       break;
+      }
+    case 'B':
+      {
+       unsigned int x = CVAL(buf,0);
+       printf("0x%X",x);
+       buf += 1;
+       fmt++;
+       break;
+      }
+    case 'b':
+      {
+       unsigned int x = CVAL(buf,0);
+       printf("%d (0x%x)",x, x);
+       buf += 1;
+       fmt++;
+       break;
+      }
+    case 'S':
+      {        
+             printf("%.*s",PTR_DIFF(maxbuf,buf),unistr(buf, &len));
+             buf += len;
+             fmt++;
+             break;
+      }
+    case 'Z':
+      {        
+       if (*buf != 4 && *buf != 2) 
+         printf("Error! ASCIIZ buffer of type %d (safety=%d)\n",
+                *buf,PTR_DIFF(maxbuf,buf));
+       printf("%.*s",PTR_DIFF(maxbuf,buf+1),unistr(buf+1, &len));
+       buf += len+1;
+       fmt++;
+       break;
+      }
+    case 's':
+      {        
+       int l = atoi(fmt+1);
+       printf("%-*.*s",l,l,buf);
+       buf += l;       
+       fmt++; while (isdigit(*fmt)) fmt++;
+       break;
+      }
+    case 'h':
+      {        
+       int l = atoi(fmt+1);
+       while (l--) printf("%02x",*buf++);
+       fmt++; while (isdigit(*fmt)) fmt++;
+       break;
+      }
+    case 'n':
+      {        
+       int t = atoi(fmt+1);
+       char nbuf[255];
+       int name_type;
+       switch (t) {
+       case 1:
+         name_type = name_extract(startbuf,PTR_DIFF(buf,startbuf),nbuf);
+         buf += name_len(buf);
+         printf("%-15.15s NameType=0x%02X (%s)",
+                nbuf,name_type,name_type_str(name_type));
+         break;
+       case 2:
+         name_type = buf[15];
+         printf("%-15.15s NameType=0x%02X (%s)",
+                buf,name_type,name_type_str(name_type));
+         buf += 16;
+         break;
+       }
+       fmt++; while (isdigit(*fmt)) fmt++;
+       break;
+      }
+    case 'T':
+      {        
+       time_t t;
+       int x = IVAL(buf,0);
+       switch (atoi(fmt+1)) {
+       case 1:
+         if (x==0 || x==-1 || x==0xFFFFFFFF)
+           t = 0;
+         else
+           t = make_unix_date(buf); 
+         buf+=4;
+         break;
+       case 2:
+         if (x==0 || x==-1 || x==0xFFFFFFFF)
+           t = 0;
+         else
+           t = make_unix_date2(buf); 
+         buf+=4;
+         break;
+       case 3:
+         t = interpret_long_date(buf); 
+         buf+=8;
+         break;
+       }
+       printf("%s",t?asctime(localtime(&t)):"NULL\n");
+       fmt++; while (isdigit(*fmt)) fmt++;
+       break;
+      }
+    default:
+      putchar(*fmt);
+      fmt++;
+      break;      
+    }
+  }
+
+  if (buf>=maxbuf && *fmt)
+    printf("END OF BUFFER\n");
+
+  return(buf);
+}
+
+uchar *fdata(uchar *buf,char *fmt,uchar *maxbuf)
+{
+  static int depth=0;
+  char s[128];
+  char *p;
+
+  while (*fmt) {
+    switch (*fmt) {
+    case '*':
+      fmt++;
+      while (buf < maxbuf) {
+       uchar *buf2;
+       depth++;
+       buf2 = fdata(buf,fmt,maxbuf);
+       depth--;
+       if (buf2 == buf) return(buf);
+       buf = buf2;
+      }
+      break;
+
+    case '|':
+      fmt++;
+      if (buf>=maxbuf) return(buf);
+      break;
+
+    case '%':
+      fmt++;
+      buf=maxbuf;
+      break;
+
+    case '#':
+      fmt++;
+      return(buf);
+      break;
+
+    case '[':
+      fmt++;
+      if (buf>=maxbuf) return(buf);
+      bzero(s,sizeof(s));
+      p = strchr(fmt,']');
+      strncpy(s,fmt,p-fmt);
+      fmt = p+1;
+      buf = fdata1(buf,s,maxbuf);
+      break;
+
+    default:
+      putchar(*fmt); fmt++;
+      fflush(stdout);
+      break;
+    }
+  }
+  if (!depth && buf<maxbuf) {
+    int len = PTR_DIFF(maxbuf,buf);
+    printf("Data: (%d bytes)\n",len);
+    print_data(buf,len);
+    return(buf+len);
+  }
+  return(buf);
+}
+
+typedef struct
+{
+  char *name;
+  int code;
+  char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+static err_code_struct dos_msgs[] = {
+  {"ERRbadfunc",1,"Invalid function."},
+  {"ERRbadfile",2,"File not found."},
+  {"ERRbadpath",3,"Directory invalid."},
+  {"ERRnofids",4,"No file descriptors available"},
+  {"ERRnoaccess",5,"Access denied."},
+  {"ERRbadfid",6,"Invalid file handle."},
+  {"ERRbadmcb",7,"Memory control blocks destroyed."},
+  {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
+  {"ERRbadmem",9,"Invalid memory block address."},
+  {"ERRbadenv",10,"Invalid environment."},
+  {"ERRbadformat",11,"Invalid format."},
+  {"ERRbadaccess",12,"Invalid open mode."},
+  {"ERRbaddata",13,"Invalid data."},
+  {"ERR",14,"reserved."},
+  {"ERRbaddrive",15,"Invalid drive specified."},
+  {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
+  {"ERRdiffdevice",17,"Not same device."},
+  {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
+  {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
+  {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
+  {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
+  {"ERRbadpipe",230,"Pipe invalid."},
+  {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
+  {"ERRpipeclosing",232,"Pipe close in progress."},
+  {"ERRnotconnected",233,"No process on other end of pipe."},
+  {"ERRmoredata",234,"There is more data to be returned."},
+  {NULL,-1,NULL}};
+
+/* Server Error Messages */
+err_code_struct server_msgs[] = {
+  {"ERRerror",1,"Non-specific error code."},
+  {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+  {"ERRbadtype",3,"reserved."},
+  {"ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
+  {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
+  {"ERRinvnetname",6,"Invalid network name in tree connect."},
+  {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
+  {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
+  {"ERRqtoobig",50,"Print queue full -- no space."},
+  {"ERRqeof",51,"EOF on print queue dump."},
+  {"ERRinvpfid",52,"Invalid print file FID."},
+  {"ERRsmbcmd",64,"The server did not recognize the command received."},
+  {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
+  {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
+  {"ERRreserved",68,"reserved."},
+  {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
+  {"ERRreserved",70,"reserved."},
+  {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
+  {"ERRpaused",81,"Server is paused."},
+  {"ERRmsgoff",82,"Not receiving messages."},
+  {"ERRnoroom",83,"No room to buffer message."},
+  {"ERRrmuns",87,"Too many remote user names."},
+  {"ERRtimeout",88,"Operation timed out."},
+  {"ERRnoresource",89,"No resources currently available for request."},
+  {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
+  {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
+  {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
+  {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
+  {"ERRcontmpx",252,"Continue in MPX mode."},
+  {"ERRreserved",253,"reserved."},
+  {"ERRreserved",254,"reserved."},
+  {"ERRnosupport",0xFFFF,"Function not supported."},
+  {NULL,-1,NULL}};
+
+/* Hard Error Messages */
+err_code_struct hard_msgs[] = {
+  {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
+  {"ERRbadunit",20,"Unknown unit."},
+  {"ERRnotready",21,"Drive not ready."},
+  {"ERRbadcmd",22,"Unknown command."},
+  {"ERRdata",23,"Data error (CRC)."},
+  {"ERRbadreq",24,"Bad request structure length."},
+  {"ERRseek",25 ,"Seek error."},
+  {"ERRbadmedia",26,"Unknown media type."},
+  {"ERRbadsector",27,"Sector not found."},
+  {"ERRnopaper",28,"Printer out of paper."},
+  {"ERRwrite",29,"Write fault."},
+  {"ERRread",30,"Read fault."},
+  {"ERRgeneral",31,"General failure."},
+  {"ERRbadshare",32,"A open conflicts with an existing open."},
+  {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+  {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
+  {"ERRFCBUnavail",35,"No FCBs are available to process request."},
+  {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
+  {NULL,-1,NULL}};
+
+
+static struct
+{
+  int code;
+  char *class;
+  err_code_struct *err_msgs;
+} err_classes[] = { 
+  {0,"SUCCESS",NULL},
+  {0x01,"ERRDOS",dos_msgs},
+  {0x02,"ERRSRV",server_msgs},
+  {0x03,"ERRHRD",hard_msgs},
+  {0x04,"ERRXOS",NULL},
+  {0xE1,"ERRRMX1",NULL},
+  {0xE2,"ERRRMX2",NULL},
+  {0xE3,"ERRRMX3",NULL},
+  {0xFF,"ERRCMD",NULL},
+  {-1,NULL,NULL}};
+
+
+/****************************************************************************
+return a SMB error string from a SMB buffer
+****************************************************************************/
+char *smb_errstr(int class,int num)
+{
+  static char ret[128];
+  int i,j;
+
+  ret[0]=0;
+
+  for (i=0;err_classes[i].class;i++)
+    if (err_classes[i].code == class)
+      {
+       if (err_classes[i].err_msgs)
+         {
+           err_code_struct *err = err_classes[i].err_msgs;
+           for (j=0;err[j].name;j++)
+             if (num == err[j].code)
+               {
+                 sprintf(ret,"%s - %s (%s)",err_classes[i].class,
+                         err[j].name,err[j].message);
+                 return ret;
+               }
+         }
+
+       sprintf(ret,"%s - %d",err_classes[i].class,num);
+       return ret;
+      }
+  
+  sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
+  return(ret);
+}
+
+
+
index da72158bec186fefdba85113a3ac7572c14cd290..3d544e705e018f18366320763c73a5916d49ef23 100644 (file)
--- a/tcpdump.1
+++ b/tcpdump.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /tcpdump/master/tcpdump/Attic/tcpdump.1,v 1.69 1999-10-30 05:11:22 itojun Exp $ (LBL)
+.\" @(#) $Header: /tcpdump/master/tcpdump/Attic/tcpdump.1,v 1.70 1999-11-21 15:57:50 assar Exp $ (LBL)
 .\"
 .\" Copyright (c) 1987, 1988, 1989, 1990, 1991, 1992, 1994, 1995, 1996, 1997
 .\"    The Regents of the University of California.  All rights reserved.
@@ -965,6 +965,27 @@ to print.  Use the \fB\-s\fP flag to increase the snaplen if you
 need to seriously investigate name server traffic.  `\fB\-s 128\fP'
 has worked well for me.
 
+.HD
+SMB/CIFS decoding
+.LP
+tcpdump now includes fairly extensive SMB/CIFS/NBT decoding for data
+on UDP/137, UDP/138 and TCP/139. Some primitive decoding of IPX and
+NetBEUI SMB data is also done. 
+
+By default a fairly minimal decode is done, with a much more detailed
+decode done if -v is used. Be warned that with -v a single SMB packet
+may take up a page or more, so only use -v if you really want all the
+gory details.
+
+If you are decoding SMB sessions containing unicode strings then you
+may wish to set the environment variable USE_UNICODE to 1. A patch to
+auto-detect unicode srings would be welcome.
+
+For information on SMB packet formats and what all te fields mean see
+www.cifs.org or the pub/samba/specs/ directory on your favourite
+samba.org mirror site. The SMB patches were written by Andrew Tridgell
+
 .HD
 NFS Requests and Replies
 .LP