]> 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.
 #
 #  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)
 
 #
 # 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 \
        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@
 LOCALSRC = @LOCALSRC@
 GENSRC = version.c
 LIBOBJS = @LIBOBJS@
index 5515dc5e928bc0cf338eed7428db8bf412a755c2..4df0f9f93e3525bd32ad571fbe8a1d3042238655 100644 (file)
@@ -24,7 +24,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #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
 #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);
        }
                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);
        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;
                    }
                }
                        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);
        } 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);
                caplen -= 4;
        }
        (void)printf(" len=%d", length);
-       if (caplen > 0) {
-               default_print_unaligned(p, caplen);
-       }
        return(1);
 }
        return(1);
 }
index 3a2af9c655f69bfb1bff05a8daa4fa3047a8c532..987f7ad6c327554b74fb78d67d5d294726b7a551 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #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
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -108,6 +108,8 @@ struct tcp_seq_hash {
 static struct tcp_seq_hash tcp_seq_hash[TSEQ_HASHSIZE];
 
 
 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)
 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);
        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);
        return;
 bad:
        fputs("[bad opt]", stdout);
index 49e3848ad6dca35fd3f58dcf111e04003b9eadf6..74662ebd9b24fd018fafc2f949af3705c1d191b2 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
 
 #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
 #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 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*/
 
 #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);
                        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);
                /*
                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.
 .\"
 .\" 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.
 
 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
 .HD
 NFS Requests and Replies
 .LP