2000-02-09 17:10:08 +03:00
/*
Unix SMB / Netbios implementation .
Version 2.0
mask_match tester
Copyright ( C ) Andrew Tridgell 1999
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# define NO_SYSLOG
# include "includes.h"
extern int DEBUGLEVEL ;
static fstring password ;
static fstring username ;
static int got_pass ;
2001-02-26 02:47:27 +03:00
static int max_protocol = PROTOCOL_NT1 ;
2000-02-09 17:10:08 +03:00
static BOOL showall = False ;
2000-04-30 16:34:26 +04:00
static BOOL old_list = False ;
2000-02-09 17:10:08 +03:00
static char * maskchars = " <> \" ?*abc. " ;
static char * filechars = " abcdefghijklm. " ;
2001-02-27 07:18:12 +03:00
static int verbose ;
2001-03-21 09:44:49 +03:00
static int die_on_error ;
2000-02-09 17:10:08 +03:00
2001-02-26 02:47:27 +03:00
/* a test fn for LANMAN mask support */
int ms_fnmatch_lanman_core ( char * pattern , char * string )
2000-02-09 17:10:08 +03:00
{
2001-02-26 02:47:27 +03:00
char * p = pattern , * n = string ;
char c ;
2001-02-27 15:04:49 +03:00
if ( strcmp ( p , " ? " ) = = 0 & & strcmp ( n , " . " ) = = 0 ) goto match ;
2001-02-27 09:11:59 +03:00
2001-02-26 02:47:27 +03:00
while ( ( c = * p + + ) ) {
switch ( c ) {
2001-02-27 15:04:49 +03:00
case ' . ' :
2001-03-21 08:54:09 +03:00
/* if (! *n && ! *p) goto match; */
2001-02-27 15:04:49 +03:00
if ( * n ! = ' . ' ) goto nomatch ;
n + + ;
break ;
2001-02-26 02:47:27 +03:00
case ' ? ' :
2001-02-27 15:04:49 +03:00
if ( ( * n = = ' . ' & & n [ 1 ] ! = ' . ' ) | | ! * n ) goto next ;
2001-02-26 02:47:27 +03:00
n + + ;
break ;
case ' > ' :
if ( n [ 0 ] = = ' . ' ) {
2001-02-27 07:18:12 +03:00
if ( ! n [ 1 ] & & ms_fnmatch_lanman_core ( p , n + 1 ) = = 0 ) goto match ;
if ( ms_fnmatch_lanman_core ( p , n ) = = 0 ) goto match ;
goto nomatch ;
2001-02-26 02:47:27 +03:00
}
2001-02-27 15:04:49 +03:00
if ( ! * n ) goto next ;
2001-02-26 02:47:27 +03:00
n + + ;
break ;
2000-02-09 17:10:08 +03:00
2001-02-26 02:47:27 +03:00
case ' * ' :
2001-02-27 07:18:12 +03:00
if ( ! * p ) goto match ;
2001-02-26 02:47:27 +03:00
for ( ; * n ; n + + ) {
2001-02-27 07:18:12 +03:00
if ( ms_fnmatch_lanman_core ( p , n ) = = 0 ) goto match ;
2001-02-26 02:47:27 +03:00
}
break ;
case ' < ' :
for ( ; * n ; n + + ) {
2001-02-27 07:18:12 +03:00
if ( ms_fnmatch_lanman_core ( p , n ) = = 0 ) goto match ;
2001-07-04 11:36:09 +04:00
if ( * n = = ' . ' & & ! strchr_m ( n + 1 , ' . ' ) ) {
2001-02-26 02:47:27 +03:00
n + + ;
break ;
}
}
break ;
case ' " ' :
2001-02-27 07:18:12 +03:00
if ( * n = = 0 & & ms_fnmatch_lanman_core ( p , n ) = = 0 ) goto match ;
if ( * n ! = ' . ' ) goto nomatch ;
2001-02-26 02:47:27 +03:00
n + + ;
break ;
default :
2001-02-27 07:18:12 +03:00
if ( c ! = * n ) goto nomatch ;
2001-02-26 02:47:27 +03:00
n + + ;
}
}
2001-02-27 07:18:12 +03:00
if ( ! * n ) goto match ;
2001-02-26 02:47:27 +03:00
2001-02-27 07:18:12 +03:00
nomatch :
if ( verbose ) printf ( " NOMATCH pattern=[%s] string=[%s] \n " , pattern , string ) ;
2001-02-26 02:47:27 +03:00
return - 1 ;
2001-02-27 07:18:12 +03:00
2001-02-27 15:04:49 +03:00
next :
if ( ms_fnmatch_lanman_core ( p , n ) = = 0 ) goto match ;
goto nomatch ;
2001-02-27 07:18:12 +03:00
match :
if ( verbose ) printf ( " MATCH pattern=[%s] string=[%s] \n " , pattern , string ) ;
return 0 ;
2001-02-26 02:47:27 +03:00
}
int ms_fnmatch_lanman ( char * pattern , char * string )
{
2001-02-27 15:04:49 +03:00
if ( ! strpbrk ( pattern , " ?*<> \" " ) ) {
2001-03-21 08:54:09 +03:00
if ( strcmp ( string , " .. " ) = = 0 ) string = " . " ;
2001-02-27 15:04:49 +03:00
return strcmp ( pattern , string ) ;
2001-02-27 09:11:59 +03:00
}
2001-03-21 08:54:09 +03:00
if ( strcmp ( string , " .. " ) = = 0 | | strcmp ( string , " . " ) = = 0 ) {
return ms_fnmatch_lanman_core ( pattern , " .. " ) & &
ms_fnmatch_lanman_core ( pattern , " . " ) ;
}
2001-02-27 15:04:49 +03:00
return ms_fnmatch_lanman_core ( pattern , string ) ;
2001-02-26 02:47:27 +03:00
}
2001-08-20 09:15:26 +04:00
static BOOL reg_match_one ( struct cli_state * cli , char * pattern , char * file )
2001-02-26 02:47:27 +03:00
{
2000-04-30 18:37:57 +04:00
/* oh what a weird world this is */
if ( old_list & & strcmp ( pattern , " *.* " ) = = 0 ) return True ;
2001-02-26 09:53:42 +03:00
if ( strcmp ( pattern , " . " ) = = 0 ) return False ;
2001-02-26 02:47:27 +03:00
if ( max_protocol < = PROTOCOL_LANMAN2 ) {
return ms_fnmatch_lanman ( pattern , file ) = = 0 ;
}
2001-03-21 08:54:09 +03:00
if ( strcmp ( file , " .. " ) = = 0 ) file = " . " ;
2001-08-20 09:15:26 +04:00
return ms_fnmatch ( pattern , file , cli - > protocol ) = = 0 ;
2000-02-09 17:10:08 +03:00
}
2001-08-20 09:15:26 +04:00
static char * reg_test ( struct cli_state * cli , char * pattern , char * long_name , char * short_name )
2000-02-10 16:43:59 +03:00
{
static fstring ret ;
fstrcpy ( ret , " --- " ) ;
2001-07-04 11:36:09 +04:00
pattern = 1 + strrchr_m ( pattern , ' \\ ' ) ;
2000-02-10 16:43:59 +03:00
2001-08-20 09:15:26 +04:00
if ( reg_match_one ( cli , pattern , " . " ) ) ret [ 0 ] = ' + ' ;
if ( reg_match_one ( cli , pattern , " .. " ) ) ret [ 1 ] = ' + ' ;
if ( reg_match_one ( cli , pattern , long_name ) | |
( * short_name & & reg_match_one ( cli , pattern , short_name ) ) ) ret [ 2 ] = ' + ' ;
2000-02-10 16:43:59 +03:00
return ret ;
}
2000-02-09 17:10:08 +03:00
/*****************************************************
return a connection to a server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct cli_state * connect_one ( char * share )
{
struct cli_state * c ;
struct nmb_name called , calling ;
char * server_n ;
char * server ;
struct in_addr ip ;
extern struct in_addr ipzero ;
server = share + 2 ;
2001-07-04 11:36:09 +04:00
share = strchr_m ( server , ' \\ ' ) ;
2000-02-09 17:10:08 +03:00
if ( ! share ) return NULL ;
* share = 0 ;
share + + ;
server_n = server ;
ip = ipzero ;
2000-02-09 17:17:12 +03:00
make_nmb_name ( & calling , " masktest " , 0x0 ) ;
make_nmb_name ( & called , server , 0x20 ) ;
2000-02-09 17:10:08 +03:00
again :
ip = ipzero ;
/* have to open a new connection */
if ( ! ( c = cli_initialise ( NULL ) ) | | ( cli_set_port ( c , 139 ) = = 0 ) | |
! cli_connect ( c , server_n , & ip ) ) {
DEBUG ( 0 , ( " Connection to %s failed \n " , server_n ) ) ;
return NULL ;
}
2001-02-26 02:47:27 +03:00
c - > protocol = max_protocol ;
2000-02-09 17:10:08 +03:00
if ( ! cli_session_request ( c , & calling , & called ) ) {
DEBUG ( 0 , ( " session request to %s failed \n " , called . name ) ) ;
cli_shutdown ( c ) ;
if ( strcmp ( called . name , " *SMBSERVER " ) ) {
2000-02-09 17:17:12 +03:00
make_nmb_name ( & called , " *SMBSERVER " , 0x20 ) ;
2000-02-09 17:10:08 +03:00
goto again ;
}
return NULL ;
}
DEBUG ( 4 , ( " session request ok \n " ) ) ;
if ( ! cli_negprot ( c ) ) {
DEBUG ( 0 , ( " protocol negotiation failed \n " ) ) ;
cli_shutdown ( c ) ;
return NULL ;
}
if ( ! got_pass ) {
char * pass = getpass ( " Password: " ) ;
if ( pass ) {
pstrcpy ( password , pass ) ;
}
}
if ( ! cli_session_setup ( c , username ,
password , strlen ( password ) ,
password , strlen ( password ) ,
2000-05-24 09:56:34 +04:00
lp_workgroup ( ) ) ) {
2000-02-09 17:10:08 +03:00
DEBUG ( 0 , ( " session setup failed: %s \n " , cli_errstr ( c ) ) ) ;
return NULL ;
}
/*
* These next two lines are needed to emulate
* old client behaviour for people who have
* scripts based on client output .
* QUESTION ? Do we want to have a ' client compatibility
* mode to turn these on / off ? JRA .
*/
if ( * c - > server_domain | | * c - > server_os | | * c - > server_type )
DEBUG ( 1 , ( " Domain=[%s] OS=[%s] Server=[%s] \n " ,
c - > server_domain , c - > server_os , c - > server_type ) ) ;
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
if ( ! cli_send_tconX ( c , share , " ????? " ,
password , strlen ( password ) + 1 ) ) {
DEBUG ( 0 , ( " tree connect failed: %s \n " , cli_errstr ( c ) ) ) ;
cli_shutdown ( c ) ;
return NULL ;
}
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
return c ;
}
static char * resultp ;
2001-07-05 09:53:08 +04:00
static file_info * f_info ;
2000-02-09 17:10:08 +03:00
2001-01-05 16:11:29 +03:00
void listfn ( file_info * f , const char * s , void * state )
2000-02-09 17:10:08 +03:00
{
if ( strcmp ( f - > name , " . " ) = = 0 ) {
resultp [ 0 ] = ' + ' ;
} else if ( strcmp ( f - > name , " .. " ) = = 0 ) {
resultp [ 1 ] = ' + ' ;
} else {
resultp [ 2 ] = ' + ' ;
}
2001-07-05 09:53:08 +04:00
f_info = f ;
2000-02-09 17:10:08 +03:00
}
2001-02-26 08:13:19 +03:00
static void get_real_name ( struct cli_state * cli ,
pstring long_name , fstring short_name )
2000-05-24 09:56:34 +04:00
{
2001-02-26 09:53:42 +03:00
/* nasty hack to force level 260 listings - tridge */
cli - > capabilities | = CAP_NT_SMBS ;
2001-02-26 08:13:19 +03:00
if ( max_protocol < = PROTOCOL_LANMAN1 ) {
cli_list_new ( cli , " \\ masktest \\ *.* " , aHIDDEN | aDIR , listfn , NULL ) ;
} else {
cli_list_new ( cli , " \\ masktest \\ * " , aHIDDEN | aDIR , listfn , NULL ) ;
}
2001-07-05 09:53:08 +04:00
if ( f_info ) {
fstrcpy ( short_name , f_info - > short_name ) ;
2000-05-24 09:56:34 +04:00
strlower ( short_name ) ;
2001-07-05 09:53:08 +04:00
pstrcpy ( long_name , f_info - > name ) ;
2001-02-26 02:47:27 +03:00
strlower ( long_name ) ;
2000-05-24 09:56:34 +04:00
}
2001-03-21 08:54:09 +03:00
if ( * short_name = = 0 ) {
fstrcpy ( short_name , long_name ) ;
}
#if 0
2001-07-04 11:36:09 +04:00
if ( ! strchr_m ( short_name , ' . ' ) ) {
2001-03-21 08:54:09 +03:00
fstrcat ( short_name , " . " ) ;
}
# endif
2000-05-24 09:56:34 +04:00
}
2000-02-09 17:10:08 +03:00
2000-04-30 15:11:19 +04:00
static void testpair ( struct cli_state * cli , char * mask , char * file )
2000-02-09 17:10:08 +03:00
{
int fnum ;
2000-04-30 15:11:19 +04:00
fstring res1 ;
char * res2 ;
2000-02-09 17:10:08 +03:00
static int count ;
2000-04-30 08:45:16 +04:00
fstring short_name ;
2001-02-26 02:47:27 +03:00
pstring long_name ;
2000-02-09 17:10:08 +03:00
count + + ;
fstrcpy ( res1 , " --- " ) ;
2000-04-30 08:45:16 +04:00
2000-04-30 15:11:19 +04:00
fnum = cli_open ( cli , file , O_CREAT | O_TRUNC | O_RDWR , 0 ) ;
2000-02-09 17:10:08 +03:00
if ( fnum = = - 1 ) {
2000-04-30 15:11:19 +04:00
DEBUG ( 0 , ( " Can't create %s \n " , file ) ) ;
2000-02-09 17:10:08 +03:00
return ;
}
2000-04-30 15:11:19 +04:00
cli_close ( cli , fnum ) ;
2000-02-09 17:10:08 +03:00
resultp = res1 ;
2000-04-30 08:45:16 +04:00
fstrcpy ( short_name , " " ) ;
2001-07-05 09:53:08 +04:00
f_info = NULL ;
2001-02-26 08:13:19 +03:00
get_real_name ( cli , long_name , short_name ) ;
2001-07-05 09:53:08 +04:00
f_info = NULL ;
2001-02-26 08:13:19 +03:00
fstrcpy ( res1 , " --- " ) ;
cli_list ( cli , mask , aHIDDEN | aDIR , listfn , NULL ) ;
2000-02-09 17:10:08 +03:00
2001-08-20 09:15:26 +04:00
res2 = reg_test ( cli , mask , long_name , short_name ) ;
2000-02-09 17:10:08 +03:00
2001-02-27 09:13:32 +03:00
if ( showall | | strcmp ( res1 , res2 ) ) {
2001-02-26 08:13:19 +03:00
DEBUG ( 0 , ( " %s %s %d mask=[%s] file=[%s] rfile=[%s/%s] \n " ,
res1 , res2 , count , mask , file , long_name , short_name ) ) ;
2001-03-21 09:44:49 +03:00
if ( die_on_error ) exit ( 1 ) ;
2000-02-09 17:10:08 +03:00
}
2000-04-30 15:11:19 +04:00
cli_unlink ( cli , file ) ;
2000-02-10 16:43:59 +03:00
2000-05-25 01:11:34 +04:00
if ( count % 100 = = 0 ) DEBUG ( 0 , ( " %d \n " , count ) ) ;
2000-02-09 17:10:08 +03:00
}
static void test_mask ( int argc , char * argv [ ] ,
2000-04-30 15:11:19 +04:00
struct cli_state * cli )
2000-02-09 17:10:08 +03:00
{
pstring mask , file ;
2000-04-30 15:11:19 +04:00
int l1 , l2 , i , l ;
2000-02-09 17:10:08 +03:00
int mc_len = strlen ( maskchars ) ;
int fc_len = strlen ( filechars ) ;
2000-05-24 09:56:34 +04:00
cli_mkdir ( cli , " \\ masktest " ) ;
2000-02-09 17:10:08 +03:00
2000-04-30 15:11:19 +04:00
cli_unlink ( cli , " \\ masktest \\ * " ) ;
2000-02-09 17:10:08 +03:00
if ( argc > = 2 ) {
while ( argc > = 2 ) {
pstrcpy ( mask , " \\ masktest \\ " ) ;
pstrcpy ( file , " \\ masktest \\ " ) ;
pstrcat ( mask , argv [ 0 ] ) ;
pstrcat ( file , argv [ 1 ] ) ;
2000-04-30 15:11:19 +04:00
testpair ( cli , mask , file ) ;
2000-02-09 17:10:08 +03:00
argv + = 2 ;
argc - = 2 ;
}
goto finished ;
}
while ( 1 ) {
l1 = 1 + random ( ) % 20 ;
l2 = 1 + random ( ) % 20 ;
pstrcpy ( mask , " \\ masktest \\ " ) ;
pstrcpy ( file , " \\ masktest \\ " ) ;
l = strlen ( mask ) ;
for ( i = 0 ; i < l1 ; i + + ) {
mask [ i + l ] = maskchars [ random ( ) % mc_len ] ;
}
mask [ l + l1 ] = 0 ;
for ( i = 0 ; i < l2 ; i + + ) {
file [ i + l ] = filechars [ random ( ) % fc_len ] ;
}
file [ l + l2 ] = 0 ;
if ( strcmp ( file + l , " . " ) = = 0 | |
strcmp ( file + l , " .. " ) = = 0 | |
strcmp ( mask + l , " .. " ) = = 0 ) continue ;
2001-03-21 09:44:49 +03:00
if ( strspn ( file + l , " . " ) = = strlen ( file + l ) ) continue ;
2000-04-30 15:11:19 +04:00
testpair ( cli , mask , file ) ;
2000-02-09 17:10:08 +03:00
}
finished :
2000-04-30 15:11:19 +04:00
cli_rmdir ( cli , " \\ masktest " ) ;
2000-02-09 17:10:08 +03:00
}
static void usage ( void )
{
printf (
" Usage: \n \
2000-04-30 15:11:19 +04:00
masktest / / server / share [ options . . ] \ n \
2000-02-09 17:10:08 +03:00
options : \ n \
2000-05-23 03:38:56 +04:00
- W workgroup \ n \
2000-02-09 17:10:08 +03:00
- U user % % pass \ n \
- s seed \ n \
2001-08-24 03:16:42 +04:00
- M max protocol \ n \
2000-02-09 17:10:08 +03:00
- f filechars ( default % s ) \ n \
- m maskchars ( default % s ) \ n \
- a show all tests \ n \
\ n \
This program tests wildcard matching between two servers . It generates \ n \
random pairs of filenames / masks and tests that they match in the same \ n \
2000-04-30 15:11:19 +04:00
way on the servers and internally \ n \
2000-02-09 17:10:08 +03:00
" ,
filechars , maskchars ) ;
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main ( int argc , char * argv [ ] )
{
2000-04-30 15:11:19 +04:00
char * share ;
struct cli_state * cli ;
2000-02-09 17:10:08 +03:00
extern char * optarg ;
extern int optind ;
extern FILE * dbf ;
int opt ;
char * p ;
int seed ;
2000-03-26 13:20:47 +04:00
static pstring servicesf = CONFIGFILE ;
2000-02-09 17:10:08 +03:00
setlinebuf ( stdout ) ;
dbf = stderr ;
2000-04-30 15:11:19 +04:00
if ( argv [ 1 ] [ 0 ] = = ' - ' | | argc < 2 ) {
2000-02-09 17:10:08 +03:00
usage ( ) ;
exit ( 1 ) ;
}
2000-04-30 15:11:19 +04:00
share = argv [ 1 ] ;
2000-02-09 17:10:08 +03:00
2000-04-30 15:11:19 +04:00
all_string_sub ( share , " / " , " \\ " , 0 ) ;
2000-02-09 17:10:08 +03:00
setup_logging ( argv [ 0 ] , True ) ;
2000-04-30 16:34:26 +04:00
argc - = 1 ;
argv + = 1 ;
2000-02-09 17:10:08 +03:00
TimeInit ( ) ;
2000-03-26 13:20:47 +04:00
lp_load ( servicesf , True , False , False ) ;
load_interfaces ( ) ;
2000-02-09 17:10:08 +03:00
if ( getenv ( " USER " ) ) {
pstrcpy ( username , getenv ( " USER " ) ) ;
}
seed = time ( NULL ) ;
2001-03-21 09:44:49 +03:00
while ( ( opt = getopt ( argc , argv , " U:s:hm:f:aoW:M:vE " ) ) ! = EOF ) {
2000-02-09 17:10:08 +03:00
switch ( opt ) {
2001-03-21 09:44:49 +03:00
case ' E ' :
die_on_error = 1 ;
break ;
2001-02-27 07:18:12 +03:00
case ' v ' :
verbose + + ;
break ;
2001-02-26 02:47:27 +03:00
case ' M ' :
max_protocol = interpret_protocol ( optarg , max_protocol ) ;
break ;
2000-02-09 17:10:08 +03:00
case ' U ' :
pstrcpy ( username , optarg ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( username , ' % ' ) ;
2000-02-09 17:10:08 +03:00
if ( p ) {
* p = 0 ;
pstrcpy ( password , p + 1 ) ;
got_pass = 1 ;
}
break ;
case ' s ' :
seed = atoi ( optarg ) ;
break ;
case ' h ' :
usage ( ) ;
exit ( 1 ) ;
case ' m ' :
maskchars = optarg ;
break ;
case ' f ' :
filechars = optarg ;
break ;
case ' a ' :
showall = 1 ;
break ;
2000-04-30 16:34:26 +04:00
case ' o ' :
old_list = True ;
break ;
2000-02-09 17:10:08 +03:00
default :
printf ( " Unknown option %c (%d) \n " , ( char ) opt , opt ) ;
exit ( 1 ) ;
}
}
argc - = optind ;
argv + = optind ;
2000-04-30 15:11:19 +04:00
cli = connect_one ( share ) ;
if ( ! cli ) {
DEBUG ( 0 , ( " Failed to connect to %s \n " , share ) ) ;
2000-02-09 17:10:08 +03:00
exit ( 1 ) ;
}
2000-05-27 04:28:02 +04:00
/* need to init seed after connect as clientgen uses random numbers */
DEBUG ( 0 , ( " seed=%d \n " , seed ) ) ;
srandom ( seed ) ;
2000-04-30 15:11:19 +04:00
test_mask ( argc , argv , cli ) ;
2000-02-09 17:10:08 +03:00
return ( 0 ) ;
}