2006-03-21 23:27:59 +03:00
/* $NetBSD: smbutil.c,v 1.7 2006/03/21 20:27:59 christos Exp $ */
2001-06-25 23:26:28 +04:00
/*
2001-09-19 07:37:58 +04:00
* 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
*/
2001-06-25 23:26:28 +04:00
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
2001-06-25 23:59:56 +04:00
# include <sys/cdefs.h>
2001-06-25 23:26:28 +04:00
# ifndef lint
2001-06-25 23:59:56 +04:00
#if 0
2004-09-28 03:04:24 +04:00
static const char rcsid [ ] _U_ =
" @(#) Header: /tcpdump/master/tcpdump/smbutil.c,v 1.26.2.2 2003/11/16 08:51:56 guy Exp " ;
2001-06-25 23:59:56 +04:00
# else
2006-03-21 23:27:59 +03:00
__RCSID ( " $NetBSD: smbutil.c,v 1.7 2006/03/21 20:27:59 christos Exp $ " ) ;
2001-06-25 23:59:56 +04:00
# endif
2001-06-25 23:26:28 +04:00
# endif
2004-09-28 03:04:24 +04:00
# include <tcpdump-stdinc.h>
2001-06-25 23:26:28 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "interface.h"
2002-02-18 12:37:05 +03:00
# include "extract.h"
2001-06-25 23:26:28 +04:00
# include "smb.h"
2002-02-18 12:37:05 +03:00
extern const u_char * startbuf ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/*
* interpret a 32 bit dos packed date / time to some parameters
*/
static void
interpret_dos_date ( u_int32_t date , struct tm * tp )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
u_int32_t p0 , p1 , p2 , p3 ;
p0 = date & 0xFF ;
p1 = ( ( date & 0xFF00 ) > > 8 ) & 0xFF ;
p2 = ( ( date & 0xFF0000 ) > > 16 ) & 0xFF ;
p3 = ( ( date & 0xFF000000 ) > > 24 ) & 0xFF ;
tp - > tm_sec = 2 * ( p0 & 0x1F ) ;
tp - > tm_min = ( ( p0 > > 5 ) & 0xFF ) + ( ( p1 & 0x7 ) < < 3 ) ;
tp - > tm_hour = ( p1 > > 3 ) & 0xFF ;
tp - > tm_mday = ( p2 & 0x1F ) ;
tp - > tm_mon = ( ( p2 > > 5 ) & 0xFF ) + ( ( p3 & 0x1 ) < < 3 ) - 1 ;
tp - > tm_year = ( ( p3 > > 1 ) & 0xFF ) + 80 ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* common portion :
* create a unix date from a dos date
*/
static time_t
int_unix_date ( u_int32_t dos_date )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
struct tm t ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
if ( dos_date = = 0 )
return ( 0 ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
interpret_dos_date ( dos_date , & t ) ;
t . tm_wday = 1 ;
t . tm_yday = 1 ;
t . tm_isdst = 0 ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
return ( mktime ( & t ) ) ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* create a unix date from a dos date
* in network byte order
*/
static time_t
make_unix_date ( const u_char * date_ptr )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
u_int32_t dos_date = 0 ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
dos_date = EXTRACT_LE_32BITS ( date_ptr ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
return int_unix_date ( dos_date ) ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* create a unix date from a dos date
* in halfword - swapped network byte order !
*/
static time_t
make_unix_date2 ( const u_char * date_ptr )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
u_int32_t x , x2 ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
x = EXTRACT_LE_32BITS ( date_ptr ) ;
x2 = ( ( x & 0xFFFF ) < < 16 ) | ( ( x & 0xFFFF0000 ) > > 16 ) ;
return int_unix_date ( x2 ) ;
}
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/*
* interpret an 8 byte " filetime " structure to a time_t
* It ' s originally in " 100ns units since jan 1st 1601 "
*/
static time_t
interpret_long_date ( const u_char * p )
{
double d ;
time_t ret ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
TCHECK2 ( p [ 4 ] , 4 ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/* this gives us seconds since jan 1st 1601 (approx) */
d = ( EXTRACT_LE_32BITS ( p + 4 ) * 256.0 + p [ 3 ] ) * ( 1.0e-7 * ( 1 < < 24 ) ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/* now adjust by 369 years to make the secs since 1970 */
d - = 369.0 * 365.25 * 24 * 60 * 60 ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/* and a fudge factor as we got it wrong by a few days */
d + = ( 3 * 24 * 60 * 60 + 6 * 60 * 60 + 2 ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
if ( d < 0 )
return ( 0 ) ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
ret = ( time_t ) d ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
return ( ret ) ;
trunc :
return ( 0 ) ;
}
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/*
* interpret the weird netbios " name " . Return the name type , or - 1 if
* we run past the end of the buffer
*/
static int
name_interpret ( const u_char * in , const u_char * maxbuf , char * out )
{
int ret ;
int len ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
if ( in > = maxbuf )
2001-06-25 23:26:28 +04:00
return ( - 1 ) ; /* name goes past the end of the buffer */
2002-02-18 12:37:05 +03:00
TCHECK2 ( * in , 1 ) ;
len = ( * in + + ) / 2 ;
* out = 0 ;
if ( len > 30 | | len < 1 )
2001-06-25 23:26:28 +04:00
return ( 0 ) ;
2002-02-18 12:37:05 +03:00
while ( len - - ) {
TCHECK2 ( * in , 2 ) ;
if ( in + 1 > = maxbuf )
return ( - 1 ) ; /* name goes past the end of the buffer */
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 + + ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
* out = 0 ;
ret = out [ - 1 ] ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
return ( ret ) ;
2001-06-25 23:26:28 +04:00
trunc :
2002-02-18 12:37:05 +03:00
return ( - 1 ) ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* find a pointer to a netbios name
*/
static const u_char *
name_ptr ( const u_char * buf , int ofs , const u_char * maxbuf )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
const u_char * p ;
u_char c ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
p = buf + ofs ;
if ( p > = maxbuf )
2001-06-25 23:26:28 +04:00
return ( NULL ) ; /* name goes past the end of the buffer */
2002-02-18 12:37:05 +03:00
TCHECK2 ( * p , 1 ) ;
c = * p ;
/* XXX - this should use the same code that the DNS dissector does */
if ( ( c & 0xC0 ) = = 0xC0 ) {
u_int16_t l = EXTRACT_16BITS ( buf + ofs ) & 0x3FFF ;
if ( l = = 0 ) {
/* We have a pointer that points to itself. */
return ( NULL ) ;
}
p = buf + l ;
if ( p > = maxbuf )
return ( NULL ) ; /* name goes past the end of the buffer */
TCHECK2 ( * p , 1 ) ;
return ( buf + l ) ;
} else
return ( buf + ofs ) ;
2001-06-25 23:26:28 +04:00
trunc :
2002-02-18 12:37:05 +03:00
return ( NULL ) ; /* name goes past the end of the buffer */
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* extract a netbios name from a buf
*/
static int
name_extract ( const u_char * buf , int ofs , const u_char * maxbuf , char * name )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
const u_char * p = name_ptr ( buf , ofs , maxbuf ) ;
if ( p = = NULL )
return ( - 1 ) ; /* error (probably name going past end of buffer) */
name [ 0 ] = ' \0 ' ;
return ( name_interpret ( p , maxbuf , name ) ) ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/*
* return the total storage length of a mangled name
*/
static int
name_len ( const unsigned char * s , const unsigned char * maxbuf )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
const unsigned char * s0 = s ;
unsigned char c ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
if ( s > = maxbuf )
2001-06-25 23:26:28 +04:00
return ( - 1 ) ; /* name goes past the end of the buffer */
2002-02-18 12:37:05 +03:00
TCHECK2 ( * s , 1 ) ;
c = * s ;
if ( ( c & 0xC0 ) = = 0xC0 )
return ( 2 ) ;
while ( * s ) {
if ( s > = maxbuf )
return ( - 1 ) ; /* name goes past the end of the buffer */
TCHECK2 ( * s , 1 ) ;
s + = ( * s ) + 1 ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
return ( PTR_DIFF ( s , s0 ) + 1 ) ;
2001-06-25 23:26:28 +04:00
trunc :
2002-02-18 12:37:05 +03:00
return ( - 1 ) ; /* name goes past the end of the buffer */
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
static void
print_asc ( const unsigned char * buf , int len )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
int i ;
for ( i = 0 ; i < len ; i + + )
safeputchar ( buf [ i ] ) ;
2001-06-25 23:26:28 +04:00
}
2004-09-28 03:04:24 +04:00
static const char *
2002-02-18 12:37:05 +03:00
name_type_str ( int name_type )
2001-06-25 23:26:28 +04:00
{
2004-09-28 03:04:24 +04:00
const char * f = NULL ;
2002-02-18 12:37:05 +03:00
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 ) ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
void
print_data ( const unsigned char * buf , int len )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
int i = 0 ;
if ( len < = 0 )
return ;
printf ( " [%03X] " , i ) ;
for ( i = 0 ; i < len ; /*nothing*/ ) {
printf ( " %02X " , buf [ i ] & 0xff ) ;
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 = SMBMIN ( 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 " ) ;
2001-06-25 23:26:28 +04:00
}
}
2002-02-18 12:37:05 +03:00
static void
2004-09-28 03:04:24 +04:00
write_bits ( unsigned int val , const char * fmt )
2001-06-25 23:26:28 +04:00
{
2004-09-28 03:04:24 +04:00
const char * p = fmt ;
2002-02-18 12:37:05 +03:00
int i = 0 ;
while ( ( p = strchr ( fmt , ' | ' ) ) ) {
size_t l = PTR_DIFF ( p , fmt ) ;
if ( l & & ( val & ( 1 < < i ) ) )
printf ( " %.*s " , ( int ) l , fmt ) ;
fmt = p + 1 ;
i + + ;
}
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
/* convert a UCS2 string into iso-8859-1 string */
static const char *
2002-05-31 13:45:44 +04:00
unistr ( const u_char * s , int * len )
2001-06-25 23:26:28 +04:00
{
2002-02-18 12:37:05 +03:00
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 ;
}
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
/* maybe it isn't unicode - a cheap trick */
if ( ! use_unicode | | ( s [ 0 ] & & s [ 1 ] ) ) {
2002-05-31 13:45:44 +04:00
* len = strlen ( ( const char * ) s ) + 1 ;
return ( const char * ) s ;
2002-02-18 12:37:05 +03:00
}
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
* len = 0 ;
2001-06-25 23:26:28 +04:00
2002-02-18 12:37:05 +03:00
if ( s [ 0 ] = = 0 & & s [ 1 ] ! = 0 ) {
s + + ;
* len = 1 ;
}
2001-06-25 23:26:28 +04:00
2004-09-28 03:04:24 +04:00
while ( l < ( int ) ( sizeof ( buf ) - 1 ) & & s [ 0 ] & & s [ 1 ] = = 0 ) {
2002-02-18 12:37:05 +03:00
buf [ l ] = s [ 0 ] ;
s + = 2 ;
l + + ;
2001-06-25 23:26:28 +04:00
* len + = 2 ;
2002-02-18 12:37:05 +03:00
}
buf [ l ] = 0 ;
* len + = 2 ;
return buf ;
2001-06-25 23:26:28 +04:00
}
2002-02-18 12:37:05 +03:00
static const u_char *
smb_fdata1 ( const u_char * buf , const char * fmt , const u_char * maxbuf )
2001-06-25 23:26:28 +04:00
{
int reverse = 0 ;
2004-09-28 03:04:24 +04:00
const char * attrib_fmt = " READONLY|HIDDEN|SYSTEM|VOLUME|DIR|ARCHIVE| " ;
2001-06-25 23:26:28 +04:00
int len ;
while ( * fmt & & buf < maxbuf ) {
switch ( * fmt ) {
case ' a ' :
2002-02-18 12:37:05 +03:00
write_bits ( buf [ 0 ] , attrib_fmt ) ;
2001-06-25 23:26:28 +04:00
buf + + ;
fmt + + ;
break ;
case ' A ' :
2002-02-18 12:37:05 +03:00
write_bits ( EXTRACT_LE_16BITS ( buf ) , attrib_fmt ) ;
2001-06-25 23:26:28 +04:00
buf + = 2 ;
fmt + + ;
break ;
case ' { ' :
{
char bitfmt [ 128 ] ;
2002-05-31 13:45:44 +04:00
char * p ;
int l ;
p = strchr ( + + fmt , ' } ' ) ;
l = PTR_DIFF ( p , fmt ) ;
2004-09-28 03:04:24 +04:00
if ( ( unsigned int ) l > sizeof ( bitfmt ) - 1 )
l = sizeof ( bitfmt ) - 1 ;
2001-06-25 23:26:28 +04:00
strncpy ( bitfmt , fmt , l ) ;
2004-09-28 03:04:24 +04:00
bitfmt [ l ] = ' \0 ' ;
2001-06-25 23:26:28 +04:00
fmt = p + 1 ;
2002-02-18 12:37:05 +03:00
write_bits ( buf [ 0 ] , bitfmt ) ;
2001-06-25 23:26:28 +04:00
buf + + ;
break ;
}
case ' P ' :
{
int l = atoi ( fmt + 1 ) ;
buf + = l ;
fmt + + ;
2002-05-31 13:45:44 +04:00
while ( isdigit ( ( unsigned char ) * fmt ) )
2001-06-25 23:26:28 +04:00
fmt + + ;
break ;
}
case ' r ' :
reverse = ! reverse ;
fmt + + ;
break ;
case ' D ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK2 ( buf [ 0 ] , 4 ) ;
x = reverse ? EXTRACT_32BITS ( buf ) : EXTRACT_LE_32BITS ( buf ) ;
2001-06-25 23:26:28 +04:00
printf ( " %d (0x%x) " , x , x ) ;
buf + = 4 ;
fmt + + ;
break ;
}
case ' L ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x1 , x2 ;
TCHECK2 ( buf [ 4 ] , 4 ) ;
x1 = reverse ? EXTRACT_32BITS ( buf ) :
EXTRACT_LE_32BITS ( buf ) ;
x2 = reverse ? EXTRACT_32BITS ( buf + 4 ) :
EXTRACT_LE_32BITS ( buf + 4 ) ;
2001-06-25 23:26:28 +04:00
if ( x2 )
printf ( " 0x%08x:%08x " , x2 , x1 ) ;
else
printf ( " %d (0x%08x%08x) " , x1 , x2 , x1 ) ;
buf + = 8 ;
fmt + + ;
break ;
}
case ' d ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK2 ( buf [ 0 ] , 2 ) ;
x = reverse ? EXTRACT_16BITS ( buf ) :
EXTRACT_LE_16BITS ( buf ) ;
2001-06-25 23:26:28 +04:00
printf ( " %d (0x%x) " , x , x ) ;
buf + = 2 ;
fmt + + ;
break ;
}
case ' W ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK2 ( buf [ 0 ] , 4 ) ;
x = reverse ? EXTRACT_32BITS ( buf ) :
EXTRACT_LE_32BITS ( buf ) ;
2001-06-25 23:26:28 +04:00
printf ( " 0x%X " , x ) ;
buf + = 4 ;
fmt + + ;
break ;
}
case ' w ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK2 ( buf [ 0 ] , 2 ) ;
x = reverse ? EXTRACT_16BITS ( buf ) :
EXTRACT_LE_16BITS ( buf ) ;
2001-06-25 23:26:28 +04:00
printf ( " 0x%X " , x ) ;
buf + = 2 ;
fmt + + ;
break ;
}
case ' B ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK ( buf [ 0 ] ) ;
x = buf [ 0 ] ;
2001-06-25 23:26:28 +04:00
printf ( " 0x%X " , x ) ;
buf + = 1 ;
fmt + + ;
break ;
}
case ' b ' :
{
2002-02-18 12:37:05 +03:00
unsigned int x ;
TCHECK ( buf [ 0 ] ) ;
x = buf [ 0 ] ;
2001-06-25 23:26:28 +04:00
printf ( " %u (0x%x) " , x , x ) ;
buf + = 1 ;
fmt + + ;
break ;
}
case ' S ' :
{
2002-02-18 12:37:05 +03:00
/*XXX unistr() */
2001-06-25 23:26:28 +04:00
printf ( " %.*s " , ( int ) PTR_DIFF ( maxbuf , buf ) , unistr ( buf , & len ) ) ;
buf + = len ;
fmt + + ;
break ;
}
case ' Z ' :
{
if ( * buf ! = 4 & & * buf ! = 2 )
printf ( " Error! ASCIIZ buffer of type %u (safety=%lu) \n " , * buf ,
( unsigned long ) PTR_DIFF ( maxbuf , buf ) ) ;
printf ( " %.*s " , ( int ) 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 + + ;
2002-05-31 13:45:44 +04:00
while ( isdigit ( ( unsigned char ) * fmt ) )
2001-06-25 23:26:28 +04:00
fmt + + ;
break ;
}
case ' h ' :
{
int l = atoi ( fmt + 1 ) ;
while ( l - - )
printf ( " %02x " , * buf + + ) ;
fmt + + ;
2002-05-31 13:45:44 +04:00
while ( isdigit ( ( unsigned char ) * fmt ) )
2001-06-25 23:26:28 +04:00
fmt + + ;
break ;
}
case ' n ' :
{
int t = atoi ( fmt + 1 ) ;
char nbuf [ 255 ] ;
int name_type ;
int len ;
switch ( t ) {
case 1 :
name_type = name_extract ( startbuf , PTR_DIFF ( buf , startbuf ) ,
maxbuf , nbuf ) ;
if ( name_type < 0 )
goto trunc ;
len = name_len ( buf , maxbuf ) ;
if ( len < 0 )
goto trunc ;
buf + = len ;
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 + + ;
2002-05-31 13:45:44 +04:00
while ( isdigit ( ( unsigned char ) * fmt ) )
2001-06-25 23:26:28 +04:00
fmt + + ;
break ;
}
case ' T ' :
{
time_t t ;
2004-09-28 03:04:24 +04:00
struct tm * lt ;
const char * tstring ;
u_int32_t x ;
2002-02-18 12:37:05 +03:00
x = EXTRACT_LE_32BITS ( buf ) ;
2001-06-25 23:26:28 +04:00
switch ( atoi ( fmt + 1 ) ) {
case 1 :
2004-09-28 03:04:24 +04:00
if ( x = = 0 | | x = = 0xFFFFFFFF )
2001-06-25 23:26:28 +04:00
t = 0 ;
else
t = make_unix_date ( buf ) ;
buf + = 4 ;
break ;
case 2 :
2004-09-28 03:04:24 +04:00
if ( x = = 0 | | x = = 0xFFFFFFFF )
2001-06-25 23:26:28 +04:00
t = 0 ;
else
t = make_unix_date2 ( buf ) ;
buf + = 4 ;
break ;
case 3 :
t = interpret_long_date ( buf ) ;
buf + = 8 ;
break ;
2006-03-21 23:27:59 +03:00
default :
t = 0 ;
break ;
2001-06-25 23:26:28 +04:00
}
2004-09-28 03:04:24 +04:00
if ( t ! = 0 ) {
lt = localtime ( & t ) ;
if ( lt ! = NULL )
tstring = asctime ( lt ) ;
else
tstring = " (Can't convert time) \n " ;
} else
tstring = " NULL \n " ;
printf ( " %s " , tstring ) ;
2001-06-25 23:26:28 +04:00
fmt + + ;
2002-05-31 13:45:44 +04:00
while ( isdigit ( ( unsigned char ) * fmt ) )
2001-06-25 23:26:28 +04:00
fmt + + ;
break ;
}
default :
putchar ( * fmt ) ;
fmt + + ;
break ;
}
}
if ( buf > = maxbuf & & * fmt )
printf ( " END OF BUFFER \n " ) ;
return ( buf ) ;
trunc :
printf ( " \n " ) ;
printf ( " WARNING: Short packet. Try increasing the snap length \n " ) ;
return ( NULL ) ;
}
2002-02-18 12:37:05 +03:00
const u_char *
smb_fdata ( const u_char * buf , const char * fmt , const u_char * maxbuf )
2001-06-25 23:26:28 +04:00
{
static int depth = 0 ;
char s [ 128 ] ;
char * p ;
while ( * fmt ) {
switch ( * fmt ) {
case ' * ' :
fmt + + ;
while ( buf < maxbuf ) {
2002-02-18 12:37:05 +03:00
const u_char * buf2 ;
2001-06-25 23:26:28 +04:00
depth + + ;
2002-02-18 12:37:05 +03:00
buf2 = smb_fdata ( buf , fmt , maxbuf ) ;
2001-06-25 23:26:28 +04:00
depth - - ;
2002-02-18 12:37:05 +03:00
if ( buf2 = = NULL )
return ( NULL ) ;
2001-06-25 23:26:28 +04:00
if ( buf2 = = buf )
return ( buf ) ;
buf = buf2 ;
}
2002-02-18 12:37:05 +03:00
return ( buf ) ;
2001-06-25 23:26:28 +04:00
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 ) ;
memset ( s , 0 , sizeof ( s ) ) ;
p = strchr ( fmt , ' ] ' ) ;
2004-09-28 03:04:24 +04:00
if ( ( size_t ) ( p - fmt + 1 ) > sizeof ( s ) ) {
2001-06-25 23:26:28 +04:00
/* overrun */
return ( buf ) ;
}
strncpy ( s , fmt , p - fmt ) ;
s [ p - fmt ] = ' \0 ' ;
fmt = p + 1 ;
2002-02-18 12:37:05 +03:00
buf = smb_fdata1 ( buf , s , maxbuf ) ;
2001-06-25 23:26:28 +04:00
if ( buf = = NULL )
return ( NULL ) ;
break ;
default :
putchar ( * fmt ) ;
fmt + + ;
fflush ( stdout ) ;
break ;
}
}
if ( ! depth & & buf < maxbuf ) {
size_t len = PTR_DIFF ( maxbuf , buf ) ;
printf ( " Data: (%lu bytes) \n " , ( unsigned long ) len ) ;
print_data ( buf , len ) ;
return ( buf + len ) ;
}
return ( buf ) ;
}
typedef struct {
2002-02-18 12:37:05 +03:00
const char * name ;
2001-06-25 23:26:28 +04:00
int code ;
2002-02-18 12:37:05 +03:00
const char * message ;
2001-06-25 23:26:28 +04:00
} 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 ;
2004-09-28 03:04:24 +04:00
const char * class ;
2001-06-25 23:26:28 +04:00
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 ) {
snprintf ( ret , sizeof ( ret ) , " %s - %s (%s) " ,
err_classes [ i ] . class , err [ j ] . name , err [ j ] . message ) ;
return ret ;
}
}
snprintf ( ret , sizeof ( ret ) , " %s - %d " , err_classes [ i ] . class , num ) ;
return ret ;
}
snprintf ( ret , sizeof ( ret ) , " ERROR: Unknown error (%d,%d) " , class , num ) ;
return ( ret ) ;
}