2000-12-26 05:57:10 +00:00
/*
2002-07-15 10:35:28 +00:00
Unix SMB / Netbios implementation .
2000-12-26 05:57:10 +00:00
SMB client library implementation
Copyright ( C ) Andrew Tridgell 1998
2002-07-15 10:35:28 +00:00
Copyright ( C ) Richard Sharpe 2000 , 2002
2000-12-26 05:57:10 +00:00
Copyright ( C ) John Terpstra 2000
2002-07-15 10:35:28 +00:00
Copyright ( C ) Tom Jansen ( Ninja ISD ) 2002
2005-03-10 23:41:19 +00:00
Copyright ( C ) Derrell Lipman 2003 , 2004
2000-12-26 05:57:10 +00:00
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 .
*/
# include "includes.h"
2002-07-15 10:35:28 +00:00
2004-10-07 04:01:18 +00:00
# include "include/libsmb_internal.h"
2000-12-26 05:57:10 +00:00
2005-03-10 23:41:19 +00:00
/*
* DOS Attribute values ( used internally )
*/
typedef struct DOS_ATTR_DESC
{
int mode ;
unsigned long long size ;
time_t a_time ;
time_t c_time ;
time_t m_time ;
unsigned long long inode ;
} DOS_ATTR_DESC ;
2003-10-24 17:01:19 +00:00
/*
* Internal flags for extended attributes
*/
/* internal mode values */
# define SMBC_XATTR_MODE_ADD 1
# define SMBC_XATTR_MODE_REMOVE 2
# define SMBC_XATTR_MODE_REMOVE_ALL 3
# define SMBC_XATTR_MODE_SET 4
# define SMBC_XATTR_MODE_CHOWN 5
# define SMBC_XATTR_MODE_CHGRP 6
# define CREATE_ACCESS_READ READ_CONTROL_ACCESS
2003-10-25 04:13:32 +00:00
/*We should test for this in configure ... */
# ifndef ENOTSUP
# define ENOTSUP EOPNOTSUPP
# endif
2003-10-24 17:01:19 +00:00
2002-07-15 10:35:28 +00:00
/*
* Functions exported by libsmb_cache . c that we need here
2000-12-26 05:57:10 +00:00
*/
2002-07-15 10:35:28 +00:00
int smbc_default_cache_functions ( SMBCCTX * context ) ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
/*
* check if an element is part of the list .
* FIXME : Does not belong here !
* Can anyone put this in a macro in dlinklist . h ?
* - - Tom
*/
static int DLIST_CONTAINS ( SMBCFILE * list , SMBCFILE * p ) {
if ( ! p | | ! list ) return False ;
do {
if ( p = = list ) return True ;
list = list - > next ;
} while ( list ) ;
return False ;
}
2001-02-26 11:53:22 +00:00
2005-03-28 19:52:23 +00:00
static int smbc_close_ctx ( SMBCCTX * context , SMBCFILE * file ) ;
static off_t smbc_lseek_ctx ( SMBCCTX * context , SMBCFILE * file , off_t offset , int whence ) ;
2001-01-05 13:43:19 +00:00
extern BOOL in_client ;
2002-07-15 10:35:28 +00:00
/*
* Is the logging working / configfile read ?
*/
2000-12-26 05:57:10 +00:00
static int smbc_initialized = 0 ;
2003-04-16 14:45:11 +00:00
static int
hex2int ( unsigned int _char )
{
if ( _char > = ' A ' & & _char < = ' F ' )
return _char - ' A ' + 10 ;
if ( _char > = ' a ' & & _char < = ' f ' )
return _char - ' a ' + 10 ;
if ( _char > = ' 0 ' & & _char < = ' 9 ' )
return _char - ' 0 ' ;
return - 1 ;
}
2005-03-10 23:41:19 +00:00
/*
* smbc_urldecode ( )
*
* Convert strings of % xx to their single character equivalent . Each ' x ' must
* be a valid hexadecimal digit , or that % sequence is left undecoded .
*
* dest may , but need not be , the same pointer as src .
*
* Returns the number of % sequences which could not be converted due to lack
* of two following hexadecimal digits .
*/
int
smbc_urldecode ( char * dest , char * src , size_t max_dest_len )
2003-04-16 14:45:11 +00:00
{
2005-03-10 23:41:19 +00:00
int old_length = strlen ( src ) ;
int i = 0 ;
int err_count = 0 ;
pstring temp ;
char * p ;
2003-04-16 14:45:11 +00:00
2005-03-10 23:41:19 +00:00
if ( old_length = = 0 ) {
return 0 ;
}
p = temp ;
while ( i < old_length ) {
unsigned char character = src [ i + + ] ;
2003-04-16 14:45:11 +00:00
2005-03-10 23:41:19 +00:00
if ( character = = ' % ' ) {
int a = i + 1 < old_length ? hex2int ( src [ i ] ) : - 1 ;
int b = i + 1 < old_length ? hex2int ( src [ i + 1 ] ) : - 1 ;
2003-04-16 14:45:11 +00:00
2005-03-10 23:41:19 +00:00
/* Replace valid sequence */
if ( a ! = - 1 & & b ! = - 1 ) {
2003-04-16 14:45:11 +00:00
2005-03-10 23:41:19 +00:00
/* Replace valid %xx sequence with %dd */
character = ( a * 16 ) + b ;
if ( character = = ' \0 ' ) {
break ; /* Stop at %00 */
}
i + = 2 ;
} else {
err_count + + ;
}
}
* p + + = character ;
}
* p = ' \0 ' ;
strncpy ( dest , temp , max_dest_len ) ;
return err_count ;
}
/*
* smbc_urlencode ( )
*
* Convert any characters not specifically allowed in a URL into their % xx
* equivalent .
*
* Returns the remaining buffer length .
*/
int
smbc_urlencode ( char * dest , char * src , int max_dest_len )
{
char hex [ ] = " 0123456789ABCDEF " ;
for ( ; * src ! = ' \0 ' & & max_dest_len > = 3 ; src + + ) {
if ( ( * src < ' 0 ' & &
* src ! = ' - ' & &
* src ! = ' . ' ) | |
( * src > ' 9 ' & &
* src < ' A ' ) | |
( * src > ' Z ' & &
* src < ' a ' & &
* src ! = ' _ ' ) | |
( * src > ' z ' ) ) {
* dest + + = ' % ' ;
* dest + + = hex [ ( * src > > 4 ) & 0x0f ] ;
* dest + + = hex [ * src & 0x0f ] ;
max_dest_len - = 3 ;
} else {
* dest + + = * src ;
max_dest_len - - ;
}
}
2003-04-16 14:45:11 +00:00
2005-03-10 23:41:19 +00:00
* dest + + = ' \0 ' ;
max_dest_len - - ;
return max_dest_len ;
2003-04-16 14:45:11 +00:00
}
2000-12-26 05:57:10 +00:00
/*
* Function to parse a path and turn it into components
*
2004-03-19 16:22:47 +00:00
* The general format of an SMB URI is explain in Christopher Hertel ' s CIFS
* book , at http : //ubiqx.org/cifs/Appendix-D.html. We accept a subset of the
2005-03-10 23:41:19 +00:00
* general format ( " smb: " only ; we do not look for " cifs: " ) .
2004-03-19 16:22:47 +00:00
*
*
* We accept :
* smb : //[[[domain;]user[:password@]]server[/share[/path[/file]]]][?options]
*
* Meaning of URLs :
*
2005-03-10 23:41:19 +00:00
* smb : // Show all workgroups.
2004-03-19 16:22:47 +00:00
*
2005-03-10 23:41:19 +00:00
* The method of locating the list of workgroups varies
* depending upon the setting of the context variable
* context - > options . browse_max_lmb_count . This value
* determine the maximum number of local master browsers to
* query for the list of workgroups . In order to ensure that
* a complete list of workgroups is obtained , all master
* browsers must be queried , but if there are many
* workgroups , the time spent querying can begin to add up .
* For small networks ( not many workgroups ) , it is suggested
* that this variable be set to 0 , indicating query all local
* master browsers . When the network has many workgroups , a
* reasonable setting for this variable might be around 3.
2004-03-19 16:22:47 +00:00
*
* smb : //name/ if name<1D> or name<1B> exists, list servers in
* workgroup , else , if name < 20 > exists , list all shares
* for server . . .
*
2005-03-10 23:41:19 +00:00
* If " options " are provided , this function returns the entire option list as a
* string , for later parsing by the caller . Note that currently , no options
* are supported .
2000-12-26 05:57:10 +00:00
*/
static const char * smbc_prefix = " smb: " ;
static int
2004-03-19 16:22:47 +00:00
smbc_parse_path ( SMBCCTX * context ,
const char * fname ,
char * server , int server_len ,
char * share , int share_len ,
char * path , int path_len ,
char * user , int user_len ,
char * password , int password_len ,
char * options , int options_len )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
static pstring s ;
pstring userinfo ;
2003-01-13 20:04:40 +00:00
const char * p ;
2001-11-21 03:55:59 +00:00
char * q , * r ;
int len ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
server [ 0 ] = share [ 0 ] = path [ 0 ] = user [ 0 ] = password [ 0 ] = ( char ) 0 ;
2004-03-19 16:22:47 +00:00
if ( options ! = NULL & & options_len > 0 ) {
options [ 0 ] = ( char ) 0 ;
}
2001-11-21 03:55:59 +00:00
pstrcpy ( s , fname ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* see if it has the right prefix */
len = strlen ( smbc_prefix ) ;
2003-10-24 17:01:19 +00:00
if ( strncmp ( s , smbc_prefix , len ) | | ( s [ len ] ! = ' / ' & & s [ len ] ! = 0 ) ) {
return - 1 ; /* What about no smb: ? */
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
p = s + len ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Watch the test below, we are testing to see if we should exit */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( strncmp ( p , " // " , 2 ) & & strncmp ( p , " \\ \\ " , 2 ) ) {
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
DEBUG ( 1 , ( " Invalid path (does not begin with smb:// " ) ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2004-03-19 16:22:47 +00:00
p + = 2 ; /* Skip the double slash */
/* See if any options were specified */
2005-03-10 23:41:19 +00:00
if ( ( q = strrchr ( p , ' ? ' ) ) ! = NULL ) {
2004-03-19 16:22:47 +00:00
/* There are options. Null terminate here and point to them */
* q + + = ' \0 ' ;
DEBUG ( 4 , ( " Found options '%s' " , q ) ) ;
/* Copy the options */
if ( options ! = NULL & & options_len > 0 ) {
safe_strcpy ( options , q , options_len - 1 ) ;
}
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( * p = = ( char ) 0 )
2003-04-16 14:45:11 +00:00
goto decoding ;
2001-01-06 12:15:46 +00:00
2001-11-21 03:55:59 +00:00
if ( * p = = ' / ' ) {
2001-01-06 12:15:46 +00:00
2002-07-15 10:35:28 +00:00
strncpy ( server , context - > workgroup ,
( strlen ( context - > workgroup ) < 16 ) ? strlen ( context - > workgroup ) : 16 ) ;
2001-11-21 03:55:59 +00:00
return 0 ;
}
2001-01-06 12:15:46 +00:00
2001-11-21 03:55:59 +00:00
/*
* ok , its for us . Now parse out the server , share etc .
*
* However , we want to parse out [ [ domain ; ] user [ : password ] @ ] if it
* exists . . .
*/
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
/* check that '@' occurs before '/', if '/' exists at all */
q = strchr_m ( p , ' @ ' ) ;
r = strchr_m ( p , ' / ' ) ;
if ( q & & ( ! r | | q < r ) ) {
pstring username , passwd , domain ;
2003-01-13 20:04:40 +00:00
const char * u = userinfo ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
next_token ( & p , userinfo , " @ " , sizeof ( fstring ) ) ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
username [ 0 ] = passwd [ 0 ] = domain [ 0 ] = 0 ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
if ( strchr_m ( u , ' ; ' ) ) {
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
next_token ( & u , domain , " ; " , sizeof ( fstring ) ) ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
if ( strchr_m ( u , ' : ' ) ) {
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
next_token ( & u , username , " : " , sizeof ( fstring ) ) ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
pstrcpy ( passwd , u ) ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
}
else {
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
pstrcpy ( username , u ) ;
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
if ( username [ 0 ] )
2004-03-19 16:22:47 +00:00
strncpy ( user , username , user_len ) ; /* FIXME, domain */
2001-01-29 09:34:24 +00:00
2001-11-21 03:55:59 +00:00
if ( passwd [ 0 ] )
2004-03-19 16:22:47 +00:00
strncpy ( password , passwd , password_len ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! next_token ( & p , server , " / " , sizeof ( fstring ) ) ) {
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2003-04-16 14:45:11 +00:00
if ( * p = = ( char ) 0 ) goto decoding ; /* That's it ... */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! next_token ( & p , share , " / " , sizeof ( fstring ) ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2004-03-19 16:22:47 +00:00
safe_strcpy ( path , p , path_len - 1 ) ;
2003-04-16 14:45:11 +00:00
2001-11-21 03:55:59 +00:00
all_string_sub ( path , " / " , " \\ " , 0 ) ;
2000-12-26 05:57:10 +00:00
2003-04-16 14:45:11 +00:00
decoding :
2005-03-10 23:41:19 +00:00
( void ) smbc_urldecode ( path , path , path_len ) ;
( void ) smbc_urldecode ( server , server , server_len ) ;
( void ) smbc_urldecode ( share , share , share_len ) ;
( void ) smbc_urldecode ( user , user , user_len ) ;
( void ) smbc_urldecode ( password , password , password_len ) ;
2003-04-16 14:45:11 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
/*
2004-03-19 16:22:47 +00:00
* Verify that the options specified in a URL are valid
2000-12-26 05:57:10 +00:00
*/
2004-03-19 16:22:47 +00:00
static int smbc_check_options ( char * server , char * share , char * path , char * options )
{
DEBUG ( 4 , ( " smbc_check_options(): server='%s' share='%s' path='%s' options='%s' \n " , server , share , path , options ) ) ;
/* No options at all is always ok */
if ( ! * options ) return 0 ;
2000-12-26 05:57:10 +00:00
2005-03-10 23:41:19 +00:00
/* Currently, we don't support any options. */
return - 1 ;
2004-03-19 16:22:47 +00:00
}
/*
* Convert an SMB error into a UNIX error . . .
*/
2002-07-15 10:35:28 +00:00
static int smbc_errno ( SMBCCTX * context , struct cli_state * c )
2000-12-26 05:57:10 +00:00
{
2002-09-25 15:19:00 +00:00
int ret = cli_errno ( c ) ;
2001-08-10 06:00:33 +00:00
if ( cli_is_dos_error ( c ) ) {
uint8 eclass ;
uint32 ecode ;
cli_dos_error ( c , & eclass , & ecode ) ;
DEBUG ( 3 , ( " smbc_error %d %d (0x%x) -> %d \n " ,
( int ) eclass , ( int ) ecode , ( int ) ecode , ret ) ) ;
} else {
2001-08-27 19:46:22 +00:00
NTSTATUS status ;
2001-08-10 06:00:33 +00:00
2001-08-10 06:16:05 +00:00
status = cli_nt_error ( c ) ;
2001-08-10 06:00:33 +00:00
2001-09-04 10:57:29 +00:00
DEBUG ( 3 , ( " smbc errno %s -> %d \n " ,
2002-09-25 15:19:00 +00:00
nt_errstr ( status ) , ret ) ) ;
2001-08-10 06:00:33 +00:00
}
2000-12-26 05:57:10 +00:00
return ret ;
}
2002-07-15 10:35:28 +00:00
/*
* Check a server_fd .
* returns 0 if the server is in shape . Returns 1 on error
*
* Also useable outside libsmbclient to enable external cache
* to do some checks too .
*/
int smbc_check_server ( SMBCCTX * context , SMBCSRV * server )
{
2002-09-25 15:19:00 +00:00
if ( send_keepalive ( server - > cli . fd ) = = False )
2002-07-15 10:35:28 +00:00
return 1 ;
/* connection is ok */
return 0 ;
}
/*
2003-01-13 20:04:40 +00:00
* Remove a server from the cached server list it ' s unused .
2002-07-15 10:35:28 +00:00
* On success , 0 is returned . 1 is returned if the server could not be removed .
*
* Also useable outside libsmbclient
*/
int smbc_remove_unused_server ( SMBCCTX * context , SMBCSRV * srv )
{
SMBCFILE * file ;
/* are we being fooled ? */
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized | | ! srv ) return 1 ;
2002-07-15 10:35:28 +00:00
/* Check all open files/directories for a relation with this server */
2003-01-13 20:04:40 +00:00
for ( file = context - > internal - > _files ; file ; file = file - > next ) {
2002-07-15 10:35:28 +00:00
if ( file - > srv = = srv ) {
/* Still used */
DEBUG ( 3 , ( " smbc_remove_usused_server: %p still used by %p. \n " ,
srv , file ) ) ;
return 1 ;
}
}
2003-01-13 20:04:40 +00:00
DLIST_REMOVE ( context - > internal - > _servers , srv ) ;
2002-07-15 10:35:28 +00:00
cli_shutdown ( & srv - > cli ) ;
DEBUG ( 3 , ( " smbc_remove_usused_server: %p removed. \n " , srv ) ) ;
context - > callbacks . remove_cached_srv_fn ( context , srv ) ;
return 0 ;
}
2003-10-24 17:01:19 +00:00
SMBCSRV * find_server ( SMBCCTX * context ,
const char * server ,
const char * share ,
fstring workgroup ,
fstring username ,
fstring password )
{
SMBCSRV * srv ;
int auth_called = 0 ;
check_server_cache :
srv = context - > callbacks . get_cached_srv_fn ( context , server , share ,
workgroup , username ) ;
2005-03-10 23:41:19 +00:00
2003-10-24 17:01:19 +00:00
if ( ! auth_called & & ! srv & & ( ! username [ 0 ] | | ! password [ 0 ] ) ) {
context - > callbacks . auth_fn ( server , share ,
workgroup , sizeof ( fstring ) ,
username , sizeof ( fstring ) ,
password , sizeof ( fstring ) ) ;
/*
* However , smbc_auth_fn may have picked up info relating to
* an existing connection , so try for an existing connection
* again . . .
*/
auth_called = 1 ;
goto check_server_cache ;
}
if ( srv ) {
if ( context - > callbacks . check_server_fn ( context , srv ) ) {
/*
* This server is no good anymore
* Try to remove it and check for more possible
* servers in the cache
*/
if ( context - > callbacks . remove_unused_server_fn ( context ,
srv ) ) {
/*
* We could not remove the server completely ,
* remove it from the cache so we will not get
* it again . It will be removed when the last
* file / dir is closed .
*/
context - > callbacks . remove_cached_srv_fn ( context ,
srv ) ;
}
/*
* Maybe there are more cached connections to this
* server
*/
goto check_server_cache ;
}
2005-03-10 23:41:19 +00:00
2003-10-24 17:01:19 +00:00
return srv ;
}
return NULL ;
}
2000-12-26 05:57:10 +00:00
/*
* Connect to a server , possibly on an existing connection
2001-01-12 05:10:45 +00:00
*
* Here , what we want to do is : If the server and username
* match an existing connection , reuse that , otherwise , establish a
* new connection .
*
* If we have to create a new connection , call the auth_fn to get the
* info we need , unless the username and password were passed in .
2000-12-26 05:57:10 +00:00
*/
2002-07-15 10:35:28 +00:00
SMBCSRV * smbc_server ( SMBCCTX * context ,
2003-04-16 14:45:11 +00:00
const char * server , const char * share ,
fstring workgroup , fstring username ,
fstring password )
2000-12-26 05:57:10 +00:00
{
2002-07-15 10:35:28 +00:00
SMBCSRV * srv = NULL ;
2001-11-21 03:55:59 +00:00
struct cli_state c ;
struct nmb_name called , calling ;
2003-04-16 14:45:11 +00:00
const char * server_n = server ;
2001-11-21 03:55:59 +00:00
pstring ipenv ;
struct in_addr ip ;
2002-07-15 10:35:28 +00:00
int tried_reverse = 0 ;
2005-03-10 23:41:19 +00:00
int port_try_first ;
int port_try_next ;
2005-03-31 21:16:20 +00:00
const char * username_used ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
zero_ip ( & ip ) ;
2001-11-21 03:55:59 +00:00
ZERO_STRUCT ( c ) ;
if ( server [ 0 ] = = 0 ) {
errno = EPERM ;
return NULL ;
}
2003-10-24 17:01:19 +00:00
srv = find_server ( context , server , share ,
workgroup , username , password ) ;
2005-03-10 23:41:19 +00:00
/*
* If we found a connection and we ' re only allowed one share per
* server . . .
*/
2005-03-11 17:01:30 +00:00
if ( srv & & * share ! = ' \0 ' & & context - > options . one_share_per_server ) {
2005-03-10 23:41:19 +00:00
/*
* . . . then if there ' s no current connection to the share ,
* connect to it . find_server ( ) , or rather the function
* pointed to by context - > callbacks . get_cached_srv_fn which
* was called by find_server ( ) , will have issued a tree
* disconnect if the requested share is not the same as the
* one that was already connected .
*/
if ( srv - > cli . cnum = = ( uint16 ) - 1 ) {
/* Ensure we have accurate auth info */
context - > callbacks . auth_fn ( server , share ,
workgroup , sizeof ( fstring ) ,
username , sizeof ( fstring ) ,
password , sizeof ( fstring ) ) ;
if ( ! cli_send_tconX ( & srv - > cli , share , " ????? " ,
password , strlen ( password ) + 1 ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
cli_shutdown ( & srv - > cli ) ;
context - > callbacks . remove_cached_srv_fn ( context , srv ) ;
srv = NULL ;
}
/* Regenerate the dev value since it's based on both server and share */
if ( srv ) {
srv - > dev = ( dev_t ) ( str_checksum ( server ) ^ str_checksum ( share ) ) ;
}
}
}
/* If we have a connection... */
if ( srv ) {
/* ... then we're done here. Give 'em what they came for. */
2003-10-24 17:01:19 +00:00
return srv ;
2005-03-10 23:41:19 +00:00
}
2001-11-21 03:55:59 +00:00
2002-07-15 10:35:28 +00:00
make_nmb_name ( & calling , context - > netbios_name , 0x0 ) ;
2001-11-21 03:55:59 +00:00
make_nmb_name ( & called , server , 0x20 ) ;
DEBUG ( 4 , ( " smbc_server: server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " -> server_n=[%s] server=[%s] \n " , server_n , server ) ) ;
2000-12-26 05:57:10 +00:00
again :
2001-11-21 03:55:59 +00:00
slprintf ( ipenv , sizeof ( ipenv ) - 1 , " HOST_%s " , server_n ) ;
2002-07-15 10:35:28 +00:00
zero_ip ( & ip ) ;
2001-11-21 03:55:59 +00:00
/* have to open a new connection */
2002-07-15 10:35:28 +00:00
if ( ! cli_initialise ( & c ) ) {
2003-10-24 17:01:19 +00:00
errno = ENOMEM ;
2001-11-21 03:55:59 +00:00
return NULL ;
}
2005-01-24 20:21:15 +00:00
if ( context - > flags & SMB_CTX_FLAG_USE_KERBEROS ) {
c . use_kerberos = True ;
}
if ( context - > flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ) {
c . fallback_after_kerberos = True ;
}
2002-07-15 10:35:28 +00:00
c . timeout = context - > timeout ;
2005-03-10 23:41:19 +00:00
/*
* Force use of port 139 for first try if share is $ IPC , empty , or
* null , so browse lists can work
*/
2005-04-19 19:23:49 +00:00
if ( share = = NULL | | * share = = ' \0 ' | | strcmp ( share , " IPC$ " ) = = 0 ) {
2005-03-10 23:41:19 +00:00
port_try_first = 139 ;
port_try_next = 445 ;
2005-04-19 19:23:49 +00:00
} else {
2005-03-10 23:41:19 +00:00
port_try_first = 445 ;
port_try_next = 139 ;
}
c . port = port_try_first ;
2003-10-24 17:01:19 +00:00
2002-07-15 10:35:28 +00:00
if ( ! cli_connect ( & c , server_n , & ip ) ) {
2005-03-10 23:41:19 +00:00
/* First connection attempt failed. Try alternate port. */
c . port = port_try_next ;
2003-10-24 17:01:19 +00:00
if ( ! cli_connect ( & c , server_n , & ip ) ) {
2005-03-10 23:41:19 +00:00
cli_shutdown ( & c ) ;
errno = ETIMEDOUT ;
2003-10-24 17:01:19 +00:00
return NULL ;
}
2002-07-15 10:35:28 +00:00
}
2001-11-21 03:55:59 +00:00
if ( ! cli_session_request ( & c , & calling , & called ) ) {
cli_shutdown ( & c ) ;
if ( strcmp ( called . name , " *SMBSERVER " ) ) {
make_nmb_name ( & called , " *SMBSERVER " , 0x20 ) ;
goto again ;
}
2002-07-15 10:35:28 +00:00
else { /* Try one more time, but ensure we don't loop */
/* Only try this if server is an IP address ... */
if ( is_ipaddress ( server ) & & ! tried_reverse ) {
fstring remote_name ;
struct in_addr rem_ip ;
2002-09-25 15:19:00 +00:00
if ( ( rem_ip . s_addr = inet_addr ( server ) ) = = INADDR_NONE ) {
2002-07-15 10:35:28 +00:00
DEBUG ( 4 , ( " Could not convert IP address %s to struct in_addr \n " , server ) ) ;
2005-03-10 23:41:19 +00:00
errno = ETIMEDOUT ;
2002-07-15 10:35:28 +00:00
return NULL ;
}
tried_reverse + + ; /* Yuck */
if ( name_status_find ( " * " , 0 , 0 , rem_ip , remote_name ) ) {
make_nmb_name ( & called , remote_name , 0x20 ) ;
goto again ;
}
}
}
2005-03-10 23:41:19 +00:00
errno = ETIMEDOUT ;
2001-11-21 03:55:59 +00:00
return NULL ;
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " session request ok \n " ) ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_negprot ( & c ) ) {
cli_shutdown ( & c ) ;
2005-03-10 23:41:19 +00:00
errno = ETIMEDOUT ;
2001-11-21 03:55:59 +00:00
return NULL ;
}
2005-03-31 21:16:20 +00:00
username_used = username ;
if ( ! cli_session_setup ( & c , username_used ,
2001-11-21 03:55:59 +00:00
password , strlen ( password ) ,
password , strlen ( password ) ,
2005-03-31 21:16:20 +00:00
workgroup ) ) {
/* Failed. Try an anonymous login, if allowed by flags. */
username_used = " " ;
if ( ( context - > flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ) | |
! cli_session_setup ( & c , username_used ,
password , 1 ,
password , 0 ,
workgroup ) ) {
cli_shutdown ( & c ) ;
errno = EPERM ;
return NULL ;
}
2001-11-21 03:55:59 +00:00
}
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
if ( ! cli_send_tconX ( & c , share , " ????? " ,
password , strlen ( password ) + 1 ) ) {
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & c ) ;
2001-11-21 03:55:59 +00:00
cli_shutdown ( & c ) ;
return NULL ;
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
/*
* Ok , we have got a nice connection
* Let ' s find a free server_fd
*/
2004-12-07 18:25:53 +00:00
srv = SMB_MALLOC_P ( SMBCSRV ) ;
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
errno = ENOMEM ;
goto failed ;
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
ZERO_STRUCTP ( srv ) ;
srv - > cli = c ;
srv - > dev = ( dev_t ) ( str_checksum ( server ) ^ str_checksum ( share ) ) ;
2000-12-26 05:57:10 +00:00
2004-05-09 17:29:09 +00:00
/* now add it to the cache (internal or external) */
/* Let the cache function set errno if it wants to */
errno = 0 ;
2005-03-31 21:16:20 +00:00
if ( context - > callbacks . add_cached_srv_fn ( context , srv , server , share , workgroup , username_used ) ) {
2004-05-09 17:29:09 +00:00
int saved_errno = errno ;
2002-07-15 10:35:28 +00:00
DEBUG ( 3 , ( " Failed to add server to cache \n " ) ) ;
2004-05-09 22:39:39 +00:00
errno = saved_errno ;
2004-05-09 17:29:09 +00:00
if ( errno = = 0 ) {
errno = ENOMEM ;
}
2001-11-21 03:55:59 +00:00
goto failed ;
}
2002-07-15 10:35:28 +00:00
DEBUG ( 2 , ( " Server connect ok: //%s/%s: %p \n " ,
server , share , srv ) ) ;
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
DLIST_ADD ( context - > internal - > _servers , srv ) ;
2001-11-21 03:55:59 +00:00
return srv ;
2000-12-26 05:57:10 +00:00
failed :
2001-11-21 03:55:59 +00:00
cli_shutdown ( & c ) ;
if ( ! srv ) return NULL ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
SAFE_FREE ( srv ) ;
return NULL ;
}
2003-10-24 17:01:19 +00:00
/*
* Connect to a server for getting / setting attributes , possibly on an existing
* connection . This works similarly to smbc_server ( ) .
*/
SMBCSRV * smbc_attr_server ( SMBCCTX * context ,
2003-10-24 18:58:41 +00:00
const char * server , const char * share ,
fstring workgroup ,
fstring username , fstring password ,
POLICY_HND * pol )
2003-10-24 17:01:19 +00:00
{
struct in_addr ip ;
struct cli_state * ipc_cli ;
NTSTATUS nt_status ;
SMBCSRV * ipc_srv = NULL ;
/*
2005-03-10 23:41:19 +00:00
* See if we ' ve already created this special connection . Reference our
* " special " share name ' * IPC $ ' , which is an impossible real share name
* due to the leading asterisk .
2003-10-24 17:01:19 +00:00
*/
2005-03-10 23:41:19 +00:00
ipc_srv = find_server ( context , server , " *IPC$ " ,
2003-10-24 17:01:19 +00:00
workgroup , username , password ) ;
if ( ! ipc_srv ) {
/* We didn't find a cached connection. Get the password */
if ( * password = = ' \0 ' ) {
/* ... then retrieve it now. */
context - > callbacks . auth_fn ( server , share ,
workgroup , sizeof ( fstring ) ,
username , sizeof ( fstring ) ,
password , sizeof ( fstring ) ) ;
}
zero_ip ( & ip ) ;
nt_status = cli_full_connection ( & ipc_cli ,
global_myname ( ) , server ,
& ip , 0 , " IPC$ " , " ????? " ,
username , workgroup ,
password , 0 ,
Undefined , NULL ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2004-03-19 16:22:47 +00:00
DEBUG ( 1 , ( " cli_full_connection failed! (%s) \n " ,
2003-10-24 17:01:19 +00:00
nt_errstr ( nt_status ) ) ) ;
errno = ENOTSUP ;
return NULL ;
}
if ( ! cli_nt_session_open ( ipc_cli , PI_LSARPC ) ) {
2004-03-19 16:22:47 +00:00
DEBUG ( 1 , ( " cli_nt_session_open fail! \n " ) ) ;
2003-10-24 17:01:19 +00:00
errno = ENOTSUP ;
2004-03-19 16:22:47 +00:00
cli_shutdown ( ipc_cli ) ;
2003-10-24 17:01:19 +00:00
return NULL ;
}
/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
but NT sends 0x2000000 so we might as well do it too . */
nt_status = cli_lsa_open_policy ( ipc_cli ,
ipc_cli - > mem_ctx ,
True ,
GENERIC_EXECUTE_ACCESS ,
2003-10-24 18:58:41 +00:00
pol ) ;
2003-10-24 17:01:19 +00:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
errno = smbc_errno ( context , ipc_cli ) ;
2004-03-19 16:22:47 +00:00
cli_shutdown ( ipc_cli ) ;
2003-10-24 17:01:19 +00:00
return NULL ;
}
2004-12-07 18:25:53 +00:00
ipc_srv = SMB_MALLOC_P ( SMBCSRV ) ;
2003-10-24 17:01:19 +00:00
if ( ! ipc_srv ) {
errno = ENOMEM ;
2004-03-19 16:22:47 +00:00
cli_shutdown ( ipc_cli ) ;
2003-10-24 17:01:19 +00:00
return NULL ;
}
ZERO_STRUCTP ( ipc_srv ) ;
ipc_srv - > cli = * ipc_cli ;
free ( ipc_cli ) ;
/* now add it to the cache (internal or external) */
2004-03-19 16:22:47 +00:00
errno = 0 ; /* let cache function set errno if it likes */
2003-10-24 17:01:19 +00:00
if ( context - > callbacks . add_cached_srv_fn ( context , ipc_srv ,
server ,
2005-03-10 23:41:19 +00:00
" *IPC$ " ,
2003-10-24 17:01:19 +00:00
workgroup ,
username ) ) {
DEBUG ( 3 , ( " Failed to add server to cache \n " ) ) ;
2004-03-19 16:22:47 +00:00
if ( errno = = 0 ) {
errno = ENOMEM ;
}
cli_shutdown ( & ipc_srv - > cli ) ;
free ( ipc_srv ) ;
2003-10-24 17:01:19 +00:00
return NULL ;
}
2004-03-19 16:22:47 +00:00
DLIST_ADD ( context - > internal - > _servers , ipc_srv ) ;
2003-10-24 17:01:19 +00:00
}
return ipc_srv ;
}
2000-12-26 05:57:10 +00:00
/*
* Routine to open ( ) a file . . .
*/
2002-07-15 10:35:28 +00:00
static SMBCFILE * smbc_open_ctx ( SMBCCTX * context , const char * fname , int flags , mode_t mode )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
fstring server , share , user , password , workgroup ;
pstring path ;
2002-07-15 10:35:28 +00:00
SMBCSRV * srv = NULL ;
SMBCFILE * file = NULL ;
2001-11-21 03:55:59 +00:00
int fd ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Best I can think of ... */
2002-07-15 10:35:28 +00:00
return NULL ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
2002-07-15 10:35:28 +00:00
return NULL ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return NULL ;
}
2001-01-12 05:10:45 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2000-12-26 05:57:10 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-11-17 07:30:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( errno = = EPERM ) errno = EACCES ;
2002-07-15 10:35:28 +00:00
return NULL ; /* smbc_server sets errno */
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Hmmm, the test for a directory is suspect here ... FIXME */
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
if ( strlen ( path ) > 0 & & path [ strlen ( path ) - 1 ] = = ' \\ ' ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
fd = - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
else {
2002-07-15 10:35:28 +00:00
2004-12-07 18:25:53 +00:00
file = SMB_MALLOC_P ( SMBCFILE ) ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
if ( ! file ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOMEM ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
ZERO_STRUCTP ( file ) ;
2001-11-21 03:55:59 +00:00
if ( ( fd = cli_open ( & srv - > cli , path , flags , DENY_NONE ) ) < 0 ) {
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
/* Handle the error ... */
2001-01-24 12:32:20 +00:00
2002-07-15 10:35:28 +00:00
SAFE_FREE ( file ) ;
errno = smbc_errno ( context , & srv - > cli ) ;
return NULL ;
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Fill in file struct */
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
file - > cli_fd = fd ;
2004-12-07 18:25:53 +00:00
file - > fname = SMB_STRDUP ( fname ) ;
2002-07-15 10:35:28 +00:00
file - > srv = srv ;
file - > offset = 0 ;
file - > file = True ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
DLIST_ADD ( context - > internal - > _files , file ) ;
2005-03-28 19:52:23 +00:00
/*
* If the file was opened in O_APPEND mode , all write
* operations should be appended to the file . To do that ,
* though , using this protocol , would require a getattrE ( )
* call for each and every write , to determine where the end
* of the file is . ( There does not appear to be an append flag
* in the protocol . ) Rather than add all of that overhead of
* retrieving the current end - of - file offset prior to each
* write operation , we ' ll assume that most append operations
* will continuously write , so we ' ll just set the offset to
* the end of the file now and hope that ' s adequate .
*
* Note to self : If this proves inadequate , and O_APPEND
* should , in some cases , be forced for each write , add a
* field in the context options structure , for
* " strict_append_mode " which would select between the current
* behavior ( if FALSE ) or issuing a getattrE ( ) prior to each
* write and forcing the write to the end of the file ( if
* TRUE ) . Adding that capability will likely require adding
* an " append " flag into the _SMBCFILE structure to track
* whether a file was opened in O_APPEND mode . - - djl
*/
if ( flags & O_APPEND ) {
if ( smbc_lseek_ctx ( context , file , 0 , SEEK_END ) < 0 ) {
( void ) smbc_close_ctx ( context , file ) ;
errno = ENXIO ;
return NULL ;
}
}
2002-07-15 10:35:28 +00:00
return file ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Check if opendir needed ... */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( fd = = - 1 ) {
int eno = 0 ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
eno = smbc_errno ( context , & srv - > cli ) ;
file = context - > opendir ( context , fname ) ;
if ( ! file ) errno = eno ;
return file ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
errno = EINVAL ; /* FIXME, correct errno ? */
return NULL ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to create a file
*/
static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC ; /* FIXME: Do we need this */
2002-07-15 10:35:28 +00:00
static SMBCFILE * smbc_creat_ctx ( SMBCCTX * context , const char * path , mode_t mode )
2000-12-26 05:57:10 +00:00
{
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2002-07-15 10:35:28 +00:00
return smbc_open_ctx ( context , path , creat_bits , mode ) ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to read ( ) a file . . .
*/
2002-07-15 10:35:28 +00:00
static ssize_t smbc_read_ctx ( SMBCCTX * context , SMBCFILE * file , void * buf , size_t count )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
int ret ;
2000-12-26 05:57:10 +00:00
2005-03-22 21:17:01 +00:00
/*
* offset :
*
* Compiler bug ( possibly ) - - gcc ( GCC ) 3.3 .5 ( Debian 1 : 3.3 .5 - 2 ) - -
* appears to pass file - > offset ( which is type off_t ) differently than
* a local variable of type off_t . Using local variable " offset " in
* the call to cli_read ( ) instead of file - > offset fixes a problem
* retrieving data at an offset greater than 4 GB .
*/
off_t offset = file - > offset ;
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2002-07-15 10:35:28 +00:00
DEBUG ( 4 , ( " smbc_read(%p, %d) \n " , file , ( int ) count ) ) ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! file | | ! DLIST_CONTAINS ( context - > internal - > _files , file ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Check that the buffer exists ... */
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
if ( buf = = NULL ) {
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2005-03-22 21:17:01 +00:00
ret = cli_read ( & file - > srv - > cli , file - > cli_fd , buf , offset , count ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ret < 0 ) {
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & file - > srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
file - > offset + = ret ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " --> %d \n " , ret ) ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return ret ; /* Success, ret bytes of data ... */
2000-12-26 05:57:10 +00:00
}
/*
* Routine to write ( ) a file . . .
*/
2002-07-15 10:35:28 +00:00
static ssize_t smbc_write_ctx ( SMBCCTX * context , SMBCFILE * file , void * buf , size_t count )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
int ret ;
2005-03-22 21:17:01 +00:00
off_t offset = file - > offset ; /* See "offset" comment in smbc_read_ctx() */
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! file | | ! DLIST_CONTAINS ( context - > internal - > _files , file ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Check that the buffer exists ... */
2001-02-26 11:53:22 +00:00
2001-11-21 03:55:59 +00:00
if ( buf = = NULL ) {
2001-02-26 11:53:22 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-02-26 11:53:22 +00:00
2001-11-21 03:55:59 +00:00
}
2001-02-26 11:53:22 +00:00
2005-03-22 21:17:01 +00:00
ret = cli_write ( & file - > srv - > cli , file - > cli_fd , 0 , buf , offset , count ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ret < = 0 ) {
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & file - > srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
file - > offset + = ret ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return ret ; /* Success, 0 bytes of data ... */
2000-12-26 05:57:10 +00:00
}
2001-01-05 13:43:19 +00:00
2000-12-26 05:57:10 +00:00
/*
* Routine to close ( ) a file . . .
*/
2002-07-15 10:35:28 +00:00
static int smbc_close_ctx ( SMBCCTX * context , SMBCFILE * file )
2000-12-26 05:57:10 +00:00
{
2002-07-15 10:35:28 +00:00
SMBCSRV * srv ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! file | | ! DLIST_CONTAINS ( context - > internal - > _files , file ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
/* IS a dir ... */
if ( ! file - > file ) {
return context - > closedir ( context , file ) ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
}
if ( ! cli_close ( & file - > srv - > cli , file - > cli_fd ) ) {
DEBUG ( 3 , ( " cli_close failed on %s. purging server. \n " ,
file - > fname ) ) ;
/* Deallocate slot and remove the server
* from the server cache if unused */
errno = smbc_errno ( context , & file - > srv - > cli ) ;
srv = file - > srv ;
2003-01-13 20:04:40 +00:00
DLIST_REMOVE ( context - > internal - > _files , file ) ;
2002-07-15 10:35:28 +00:00
SAFE_FREE ( file - > fname ) ;
SAFE_FREE ( file ) ;
context - > callbacks . remove_unused_server_fn ( context , srv ) ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2003-01-13 20:04:40 +00:00
DLIST_REMOVE ( context - > internal - > _files , file ) ;
2002-07-15 10:35:28 +00:00
SAFE_FREE ( file - > fname ) ;
SAFE_FREE ( file ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
2002-07-15 10:35:28 +00:00
/*
* Get info from an SMB server on a file . Use a qpathinfo call first
* and if that fails , use getatr , as Win95 sometimes refuses qpathinfo
*/
static BOOL smbc_getatr ( SMBCCTX * context , SMBCSRV * srv , char * path ,
2005-03-22 21:17:01 +00:00
uint16 * mode , SMB_OFF_T * size ,
2002-07-15 10:35:28 +00:00
time_t * c_time , time_t * a_time , time_t * m_time ,
SMB_INO_T * ino )
{
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2002-07-15 10:35:28 +00:00
errno = EINVAL ;
return - 1 ;
}
DEBUG ( 4 , ( " smbc_getatr: sending qpathinfo \n " ) ) ;
if ( ! srv - > no_pathinfo2 & &
cli_qpathinfo2 ( & srv - > cli , path , c_time , a_time , m_time , NULL ,
size , mode , ino ) ) return True ;
/* if this is NT then don't bother with the getatr */
2003-10-24 17:01:19 +00:00
if ( srv - > cli . capabilities & CAP_NT_SMBS ) {
errno = EPERM ;
return False ;
}
2002-07-15 10:35:28 +00:00
if ( cli_getatr ( & srv - > cli , path , mode , size , m_time ) ) {
2005-06-01 17:40:40 +00:00
if ( m_time ! = NULL ) {
if ( a_time ! = NULL ) * a_time = * m_time ;
if ( c_time ! = NULL ) * c_time = * m_time ;
}
2002-07-15 10:35:28 +00:00
srv - > no_pathinfo2 = True ;
return True ;
}
2003-10-24 17:01:19 +00:00
errno = EPERM ;
2002-07-15 10:35:28 +00:00
return False ;
}
2000-12-26 05:57:10 +00:00
/*
* Routine to unlink ( ) a file
*/
2002-07-15 10:35:28 +00:00
static int smbc_unlink_ctx ( SMBCCTX * context , const char * fname )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
fstring server , share , user , password , workgroup ;
pstring path ;
2002-07-15 10:35:28 +00:00
SMBCSRV * srv = NULL ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2000-12-26 05:57:10 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2001-01-12 05:10:45 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-11-17 07:30:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ; /* smbc_server sets errno */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_unlink ( & srv - > cli , path ) ) {
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
if ( errno = = EACCES ) { /* Check if the file is a directory */
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
int saverr = errno ;
2005-03-22 21:17:01 +00:00
SMB_OFF_T size = 0 ;
2001-11-21 03:55:59 +00:00
uint16 mode = 0 ;
time_t m_time = 0 , a_time = 0 , c_time = 0 ;
SMB_INO_T ino = 0 ;
2001-01-24 12:32:20 +00:00
2002-07-15 10:35:28 +00:00
if ( ! smbc_getatr ( context , srv , path , & mode , & size ,
2001-11-21 03:55:59 +00:00
& c_time , & a_time , & m_time , & ino ) ) {
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
/* Hmmm, bad error ... What? */
2001-01-24 12:32:20 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
}
else {
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
if ( IS_DOS_DIR ( mode ) )
errno = EISDIR ;
else
errno = saverr ; /* Restore this */
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
}
}
2001-01-24 12:32:20 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return 0 ; /* Success ... */
2000-12-26 05:57:10 +00:00
}
/*
* Routine to rename ( ) a file
*/
2002-07-15 10:35:28 +00:00
static int smbc_rename_ctx ( SMBCCTX * ocontext , const char * oname ,
SMBCCTX * ncontext , const char * nname )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
fstring server1 , share1 , server2 , share2 , user1 , user2 , password1 , password2 , workgroup ;
pstring path1 , path2 ;
2002-07-15 10:35:28 +00:00
SMBCSRV * srv = NULL ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! ocontext | | ! ncontext | |
! ocontext - > internal | | ! ncontext - > internal | |
! ocontext - > internal - > _initialized | |
! ncontext - > internal - > _initialized ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
if ( ! oname | | ! nname ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " smbc_rename(%s,%s) \n " , oname , nname ) ) ;
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
smbc_parse_path ( ocontext , oname ,
server1 , sizeof ( server1 ) ,
share1 , sizeof ( share1 ) ,
path1 , sizeof ( path1 ) ,
user1 , sizeof ( user1 ) ,
password1 , sizeof ( password1 ) ,
NULL , 0 ) ;
2001-01-12 05:10:45 +00:00
2003-03-22 09:27:42 +00:00
if ( user1 [ 0 ] = = ( char ) 0 ) fstrcpy ( user1 , ocontext - > user ) ;
2001-01-12 05:10:45 +00:00
2004-03-19 16:22:47 +00:00
smbc_parse_path ( ncontext , nname ,
server2 , sizeof ( server2 ) ,
share2 , sizeof ( share2 ) ,
path2 , sizeof ( path2 ) ,
user2 , sizeof ( user2 ) ,
password2 , sizeof ( password2 ) ,
NULL , 0 ) ;
2000-12-26 05:57:10 +00:00
2003-03-22 09:27:42 +00:00
if ( user2 [ 0 ] = = ( char ) 0 ) fstrcpy ( user2 , ncontext - > user ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( strcmp ( server1 , server2 ) | | strcmp ( share1 , share2 ) | |
strcmp ( user1 , user2 ) ) {
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
/* Can't rename across file systems, or users?? */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EXDEV ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , ocontext - > workgroup ) ;
2002-07-15 10:35:28 +00:00
/* HELP !!! Which workgroup should I use ? Or are they always the same -- Tom */
srv = smbc_server ( ocontext , server1 , share1 , workgroup , user1 , password1 ) ;
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_rename ( & srv - > cli , path1 , path2 ) ) {
2002-07-15 10:35:28 +00:00
int eno = smbc_errno ( ocontext , & srv - > cli ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( eno ! = EEXIST | |
! cli_unlink ( & srv - > cli , path2 ) | |
! cli_rename ( & srv - > cli , path1 , path2 ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = eno ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return 0 ; /* Success */
2000-12-26 05:57:10 +00:00
}
/*
* A routine to lseek ( ) a file
*/
2002-07-15 10:35:28 +00:00
static off_t smbc_lseek_ctx ( SMBCCTX * context , SMBCFILE * file , off_t offset , int whence )
2000-12-26 05:57:10 +00:00
{
2005-03-22 21:17:01 +00:00
SMB_OFF_T size ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! file | | ! DLIST_CONTAINS ( context - > internal - > _files , file ) ) {
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2002-07-15 10:35:28 +00:00
if ( ! file - > file ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ; /* Can't lseek a dir ... */
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
switch ( whence ) {
case SEEK_SET :
2002-07-15 10:35:28 +00:00
file - > offset = offset ;
2001-11-21 03:55:59 +00:00
break ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
case SEEK_CUR :
2002-07-15 10:35:28 +00:00
file - > offset + = offset ;
2001-11-21 03:55:59 +00:00
break ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
case SEEK_END :
2002-07-15 10:35:28 +00:00
if ( ! cli_qfileinfo ( & file - > srv - > cli , file - > cli_fd , NULL , & size , NULL , NULL ,
2003-04-16 14:45:11 +00:00
NULL , NULL , NULL ) )
{
SMB_BIG_UINT b_size = size ;
if ( ! cli_getattrE ( & file - > srv - > cli , file - > cli_fd , NULL , & b_size , NULL , NULL ,
NULL ) )
{
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2003-04-16 14:45:11 +00:00
} else
size = b_size ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
file - > offset = size + offset ;
2001-11-21 03:55:59 +00:00
break ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
default :
errno = EINVAL ;
break ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
return file - > offset ;
2000-12-26 05:57:10 +00:00
}
/*
* Generate an inode number from file name for those things that need it
*/
static
2002-07-15 10:35:28 +00:00
ino_t smbc_inode ( SMBCCTX * context , const char * name )
2000-12-26 05:57:10 +00:00
{
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2002-07-15 10:35:28 +00:00
errno = EINVAL ;
return - 1 ;
}
2001-11-21 03:55:59 +00:00
if ( ! * name ) return 2 ; /* FIXME, why 2 ??? */
return ( ino_t ) str_checksum ( name ) ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to put basic stat info into a stat structure . . . Used by stat and
* fstat below .
*/
static
2005-03-22 21:17:01 +00:00
int smbc_setup_stat ( SMBCCTX * context , struct stat * st , char * fname ,
SMB_OFF_T size , int mode )
2000-12-26 05:57:10 +00:00
{
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
st - > st_mode = 0 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( IS_DOS_DIR ( mode ) ) {
st - > st_mode = SMBC_DIR_MODE ;
} else {
st - > st_mode = SMBC_FILE_MODE ;
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( IS_DOS_ARCHIVE ( mode ) ) st - > st_mode | = S_IXUSR ;
if ( IS_DOS_SYSTEM ( mode ) ) st - > st_mode | = S_IXGRP ;
if ( IS_DOS_HIDDEN ( mode ) ) st - > st_mode | = S_IXOTH ;
if ( ! IS_DOS_READONLY ( mode ) ) st - > st_mode | = S_IWUSR ;
st - > st_size = size ;
2003-10-14 03:56:42 +00:00
# ifdef HAVE_STAT_ST_BLKSIZE
2001-11-21 03:55:59 +00:00
st - > st_blksize = 512 ;
2003-10-14 03:56:42 +00:00
# endif
# ifdef HAVE_STAT_ST_BLOCKS
2001-11-21 03:55:59 +00:00
st - > st_blocks = ( size + 511 ) / 512 ;
2003-10-14 03:56:42 +00:00
# endif
2001-11-21 03:55:59 +00:00
st - > st_uid = getuid ( ) ;
st - > st_gid = getgid ( ) ;
if ( IS_DOS_DIR ( mode ) ) {
st - > st_nlink = 2 ;
} else {
st - > st_nlink = 1 ;
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( st - > st_ino = = 0 ) {
2002-07-15 10:35:28 +00:00
st - > st_ino = smbc_inode ( context , fname ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
return True ; /* FIXME: Is this needed ? */
2001-02-26 11:53:22 +00:00
2000-12-26 05:57:10 +00:00
}
/*
* Routine to stat a file given a name
*/
2002-07-15 10:35:28 +00:00
static int smbc_stat_ctx ( SMBCCTX * context , const char * fname , struct stat * st )
2000-12-26 05:57:10 +00:00
{
2002-07-15 10:35:28 +00:00
SMBCSRV * srv ;
2001-11-21 03:55:59 +00:00
fstring server , share , user , password , workgroup ;
pstring path ;
time_t m_time = 0 , a_time = 0 , c_time = 0 ;
2005-03-22 21:17:01 +00:00
SMB_OFF_T size = 0 ;
2001-11-21 03:55:59 +00:00
uint16 mode = 0 ;
SMB_INO_T ino = 0 ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " smbc_stat(%s) \n " , fname ) ) ;
2000-12-26 05:57:10 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2001-01-12 05:10:45 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2000-12-26 05:57:10 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-11-17 07:30:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
if ( ! smbc_getatr ( context , srv , path , & mode , & size ,
2001-11-21 03:55:59 +00:00
& c_time , & a_time , & m_time , & ino ) ) {
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
st - > st_ino = ino ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
smbc_setup_stat ( context , st , path , size , mode ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
st - > st_atime = a_time ;
st - > st_ctime = c_time ;
st - > st_mtime = m_time ;
st - > st_dev = srv - > dev ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to stat a file given an fd
*/
2002-07-15 10:35:28 +00:00
static int smbc_fstat_ctx ( SMBCCTX * context , SMBCFILE * file , struct stat * st )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
time_t c_time , a_time , m_time ;
2005-03-22 21:17:01 +00:00
SMB_OFF_T size ;
2001-11-21 03:55:59 +00:00
uint16 mode ;
SMB_INO_T ino = 0 ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! file | | ! DLIST_CONTAINS ( context - > internal - > _files , file ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
if ( ! file - > file ) {
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
return context - > fstatdir ( context , file , st ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
if ( ! cli_qfileinfo ( & file - > srv - > cli , file - > cli_fd ,
2003-04-16 14:45:11 +00:00
& mode , & size , & c_time , & a_time , & m_time , NULL , & ino ) ) {
if ( ! cli_getattrE ( & file - > srv - > cli , file - > cli_fd ,
2005-03-22 21:17:01 +00:00
& mode , & size , & c_time , & a_time , & m_time ) ) {
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2005-03-22 21:17:01 +00:00
}
2001-11-21 03:55:59 +00:00
}
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
st - > st_ino = ino ;
2000-12-26 05:57:10 +00:00
2002-07-15 10:35:28 +00:00
smbc_setup_stat ( context , st , file - > fname , size , mode ) ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
st - > st_atime = a_time ;
st - > st_ctime = c_time ;
st - > st_mtime = m_time ;
2002-07-15 10:35:28 +00:00
st - > st_dev = file - > srv - > dev ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to open a directory
2004-03-19 16:22:47 +00:00
* We accept the URL syntax explained in smbc_parse_path ( ) , above .
2000-12-26 05:57:10 +00:00
*/
2002-07-15 10:35:28 +00:00
static void smbc_remove_dir ( SMBCFILE * dir )
2001-01-05 13:43:19 +00:00
{
2001-11-21 03:55:59 +00:00
struct smbc_dir_list * d , * f ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
d = dir - > dir_list ;
while ( d ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
f = d ; d = d - > next ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
SAFE_FREE ( f - > dirent ) ;
SAFE_FREE ( f ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dir - > dir_list = dir - > dir_end = dir - > dir_next = NULL ;
2001-01-05 13:43:19 +00:00
}
2002-07-15 10:35:28 +00:00
static int add_dirent ( SMBCFILE * dir , const char * name , const char * comment , uint32 type )
2000-12-26 05:57:10 +00:00
{
2001-11-21 03:55:59 +00:00
struct smbc_dirent * dirent ;
int size ;
2005-03-10 23:41:19 +00:00
int name_length = ( name = = NULL ? 0 : strlen ( name ) ) ;
int comment_len = ( comment = = NULL ? 0 : strlen ( comment ) ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/*
* Allocate space for the dirent , which must be increased by the
2005-03-10 23:41:19 +00:00
* size of the name and the comment and 1 each for the null terminator .
2001-11-21 03:55:59 +00:00
*/
2001-01-05 13:43:19 +00:00
2005-03-10 23:41:19 +00:00
size = sizeof ( struct smbc_dirent ) + name_length + comment_len + 2 ;
2001-01-05 13:43:19 +00:00
2004-12-07 18:25:53 +00:00
dirent = SMB_MALLOC ( size ) ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
if ( ! dirent ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dir - > dir_error = ENOMEM ;
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
ZERO_STRUCTP ( dirent ) ;
2001-11-21 03:55:59 +00:00
if ( dir - > dir_list = = NULL ) {
2001-01-05 13:43:19 +00:00
2004-12-07 18:25:53 +00:00
dir - > dir_list = SMB_MALLOC_P ( struct smbc_dir_list ) ;
2001-11-21 03:55:59 +00:00
if ( ! dir - > dir_list ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
SAFE_FREE ( dirent ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
ZERO_STRUCTP ( dir - > dir_list ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dir - > dir_end = dir - > dir_next = dir - > dir_list ;
}
else {
2001-01-05 13:43:19 +00:00
2004-12-07 18:25:53 +00:00
dir - > dir_end - > next = SMB_MALLOC_P ( struct smbc_dir_list ) ;
2002-07-15 10:35:28 +00:00
if ( ! dir - > dir_end - > next ) {
2001-11-21 03:55:59 +00:00
SAFE_FREE ( dirent ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
ZERO_STRUCTP ( dir - > dir_end - > next ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dir - > dir_end = dir - > dir_end - > next ;
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dir - > dir_end - > next = NULL ;
dir - > dir_end - > dirent = dirent ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
dirent - > smbc_type = type ;
2005-03-10 23:41:19 +00:00
dirent - > namelen = name_length ;
dirent - > commentlen = comment_len ;
2001-11-21 03:55:59 +00:00
dirent - > dirlen = size ;
2001-01-07 07:10:50 +00:00
2005-03-10 23:41:19 +00:00
strncpy ( dirent - > name , ( name ? name : " " ) , dirent - > namelen + 1 ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
dirent - > comment = ( char * ) ( & dirent - > name + dirent - > namelen + 1 ) ;
2005-03-10 23:41:19 +00:00
strncpy ( dirent - > comment , ( comment ? comment : " " ) , dirent - > commentlen + 1 ) ;
2003-04-16 14:45:11 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
2004-03-19 16:22:47 +00:00
static void
list_unique_wg_fn ( const char * name , uint32 type , const char * comment , void * state )
{
SMBCFILE * dir = ( SMBCFILE * ) state ;
struct smbc_dir_list * dir_list ;
struct smbc_dirent * dirent ;
int dirent_type ;
2004-11-24 01:03:23 +00:00
int do_remove = 0 ;
2004-03-19 16:22:47 +00:00
dirent_type = dir - > dir_type ;
if ( add_dirent ( dir , name , comment , dirent_type ) < 0 ) {
/* An error occurred, what do we do? */
/* FIXME: Add some code here */
}
/* Point to the one just added */
dirent = dir - > dir_end - > dirent ;
/* See if this was a duplicate */
for ( dir_list = dir - > dir_list ;
dir_list ! = dir - > dir_end ;
dir_list = dir_list - > next ) {
2004-11-24 01:03:23 +00:00
if ( ! do_remove & &
2004-03-19 16:22:47 +00:00
strcmp ( dir_list - > dirent - > name , dirent - > name ) = = 0 ) {
/* Duplicate. End end of list need to be removed. */
2004-11-24 01:03:23 +00:00
do_remove = 1 ;
2004-03-19 16:22:47 +00:00
}
2004-11-24 01:03:23 +00:00
if ( do_remove & & dir_list - > next = = dir - > dir_end ) {
2004-03-19 16:22:47 +00:00
/* Found the end of the list. Remove it. */
dir - > dir_end = dir_list ;
free ( dir_list - > next ) ;
dir_list - > next = NULL ;
break ;
}
}
}
2001-01-05 13:43:19 +00:00
static void
list_fn ( const char * name , uint32 type , const char * comment , void * state )
{
2002-07-15 10:35:28 +00:00
SMBCFILE * dir = ( SMBCFILE * ) state ;
2001-11-21 03:55:59 +00:00
int dirent_type ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
/* We need to process the type a little ... */
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
if ( dir - > dir_type = = SMBC_FILE_SHARE ) {
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
switch ( type ) {
case 0 : /* Directory tree */
dirent_type = SMBC_FILE_SHARE ;
break ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
case 1 :
dirent_type = SMBC_PRINTER_SHARE ;
break ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
case 2 :
dirent_type = SMBC_COMMS_SHARE ;
break ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
case 3 :
dirent_type = SMBC_IPC_SHARE ;
break ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
default :
dirent_type = SMBC_FILE_SHARE ; /* FIXME, error? */
break ;
}
}
else dirent_type = dir - > dir_type ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
if ( add_dirent ( dir , name , comment , dirent_type ) < 0 ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/* An error occurred, what do we do? */
/* FIXME: Add some code here */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
}
2001-01-06 14:48:55 +00:00
static void
2005-03-10 23:41:19 +00:00
dir_list_fn ( const char * mnt , file_info * finfo , const char * mask , void * state )
2001-01-06 14:48:55 +00:00
{
2002-07-15 10:35:28 +00:00
if ( add_dirent ( ( SMBCFILE * ) state , finfo - > name , " " ,
2001-11-21 03:55:59 +00:00
( finfo - > mode & aDIR ? SMBC_DIR : SMBC_FILE ) ) < 0 ) {
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
/* Handle an error ... */
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
/* FIXME: Add some code ... */
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-06 14:48:55 +00:00
}
2002-07-15 10:35:28 +00:00
static SMBCFILE * smbc_opendir_ctx ( SMBCCTX * context , const char * fname )
2001-01-05 13:43:19 +00:00
{
2004-03-19 16:22:47 +00:00
fstring server , share , user , password , options ;
2003-04-16 14:45:11 +00:00
pstring workgroup ;
2001-11-21 03:55:59 +00:00
pstring path ;
2005-04-19 19:23:49 +00:00
uint16 mode ;
char * p ;
2002-07-15 10:35:28 +00:00
SMBCSRV * srv = NULL ;
SMBCFILE * dir = NULL ;
2001-11-21 03:55:59 +00:00
struct in_addr rem_ip ;
2001-01-05 13:43:19 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2003-04-16 14:45:11 +00:00
DEBUG ( 4 , ( " no valid context \n " ) ) ;
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8192 ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2003-04-16 14:45:11 +00:00
DEBUG ( 4 , ( " no valid fname \n " ) ) ;
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8193 ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
2004-05-05 14:57:51 +00:00
user , sizeof ( user ) ,
2004-03-19 16:22:47 +00:00
password , sizeof ( password ) ,
options , sizeof ( options ) ) ) {
2003-04-16 14:45:11 +00:00
DEBUG ( 4 , ( " no valid path \n " ) ) ;
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8194 ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2004-03-19 16:22:47 +00:00
DEBUG ( 4 , ( " parsed path: fname='%s' server='%s' share='%s' path='%s' options='%s' \n " , fname , server , share , path , options ) ) ;
/* Ensure the options are valid */
if ( smbc_check_options ( server , share , path , options ) ) {
DEBUG ( 4 , ( " unacceptable options (%s) \n " , options ) ) ;
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8195 ;
2004-03-19 16:22:47 +00:00
return NULL ;
}
2003-04-16 14:45:11 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2001-01-05 13:43:19 +00:00
2003-04-16 14:45:11 +00:00
pstrcpy ( workgroup , context - > workgroup ) ;
2001-01-05 13:43:19 +00:00
2004-12-07 18:25:53 +00:00
dir = SMB_MALLOC_P ( SMBCFILE ) ;
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
if ( ! dir ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOMEM ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
ZERO_STRUCTP ( dir ) ;
dir - > cli_fd = 0 ;
2004-12-07 18:25:53 +00:00
dir - > fname = SMB_STRDUP ( fname ) ;
2002-07-15 10:35:28 +00:00
dir - > srv = NULL ;
dir - > offset = 0 ;
dir - > file = False ;
dir - > dir_list = dir - > dir_next = dir - > dir_end = NULL ;
2001-01-05 13:43:19 +00:00
2005-03-10 23:41:19 +00:00
if ( server [ 0 ] = = ( char ) 0 ) {
2004-03-19 16:22:47 +00:00
int i ;
int count ;
2005-03-10 23:41:19 +00:00
int max_lmb_count ;
2004-03-19 16:22:47 +00:00
struct ip_service * ip_list ;
struct ip_service server_addr ;
struct user_auth_info u_info ;
struct cli_state * cli ;
2001-01-05 13:43:19 +00:00
2004-03-19 16:22:47 +00:00
if ( share [ 0 ] ! = ( char ) 0 | | path [ 0 ] ! = ( char ) 0 ) {
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8196 ;
2004-03-19 16:22:47 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
return NULL ;
}
2005-03-10 23:41:19 +00:00
/* Determine how many local master browsers to query */
2005-03-11 17:01:30 +00:00
max_lmb_count = ( context - > options . browse_max_lmb_count = = 0
2005-03-10 23:41:19 +00:00
? INT_MAX
2005-03-11 17:01:30 +00:00
: context - > options . browse_max_lmb_count ) ;
2005-03-10 23:41:19 +00:00
2004-03-19 16:22:47 +00:00
pstrcpy ( u_info . username , user ) ;
pstrcpy ( u_info . password , password ) ;
/*
* We have server and share and path empty but options
* requesting that we scan all master browsers for their list
* of workgroups / domains . This implies that we must first try
* broadcast queries to find all master browsers , and if that
* doesn ' t work , then try our other methods which return only
* a single master browser .
*/
if ( ! name_resolve_bcast ( MSBROWSE , 1 , & ip_list , & count ) ) {
if ( ! find_master_ip ( workgroup , & server_addr . ip ) ) {
errno = ENOENT ;
return NULL ;
}
ip_list = & server_addr ;
count = 1 ;
}
2005-03-10 23:41:19 +00:00
for ( i = 0 ; i < count & & i < max_lmb_count ; i + + ) {
2005-03-22 21:17:01 +00:00
DEBUG ( 99 , ( " Found master browser %d of %d: %s \n " , i + 1 , MAX ( count , max_lmb_count ) , inet_ntoa ( ip_list [ i ] . ip ) ) ) ;
2004-03-19 16:22:47 +00:00
cli = get_ipc_connect_master_ip ( & ip_list [ i ] , workgroup , & u_info ) ;
2004-05-07 15:59:13 +00:00
/* cli == NULL is the master browser refused to talk or
could not be found */
if ( ! cli )
continue ;
2004-03-19 16:22:47 +00:00
fstrcpy ( server , cli - > desthost ) ;
cli_shutdown ( cli ) ;
DEBUG ( 4 , ( " using workgroup %s %s \n " , workgroup , server ) ) ;
/*
* For each returned master browser IP address , get a
* connection to IPC $ on the server if we do not
* already have one , and determine the
* workgroups / domains that it knows about .
*/
srv = smbc_server ( context , server ,
" IPC$ " , workgroup , user , password ) ;
if ( ! srv ) {
2005-03-22 21:17:01 +00:00
continue ;
2004-03-19 16:22:47 +00:00
}
dir - > srv = srv ;
dir - > dir_type = SMBC_WORKGROUP ;
/* Now, list the stuff ... */
if ( ! cli_NetServerEnum ( & srv - > cli , workgroup , SV_TYPE_DOMAIN_ENUM , list_unique_wg_fn ,
( void * ) dir ) ) {
2005-03-22 21:17:01 +00:00
continue ;
2004-03-19 16:22:47 +00:00
}
}
} else {
/*
* Server not an empty string . . . Check the rest and see what
* gives
*/
2001-11-21 03:55:59 +00:00
if ( share [ 0 ] = = ( char ) 0 ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( path [ 0 ] ! = ( char ) 0 ) { /* Should not have empty share with path */
2001-01-05 13:43:19 +00:00
2005-03-10 23:41:19 +00:00
errno = EINVAL + 8197 ;
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
/* Check to see if <server><1D>, <server><1B>, or <server><20> translates */
2001-11-21 03:55:59 +00:00
/* However, we check to see if <server> is an IP address first */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! is_ipaddress ( server ) & & /* Not an IP addr so check next */
2002-07-15 10:35:28 +00:00
( resolve_name ( server , & rem_ip , 0x1d ) | | /* Found LMB */
resolve_name ( server , & rem_ip , 0x1b ) ) ) { /* Found DMB */
2004-03-13 02:16:21 +00:00
fstring buserver ;
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_type = SMBC_SERVER ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/*
* Get the backup list . . .
*/
2001-01-05 13:43:19 +00:00
2001-02-19 05:50:09 +00:00
2004-03-19 16:22:47 +00:00
if ( ! name_status_find ( server , 0 , 0 , rem_ip , buserver ) ) {
2001-02-26 11:53:22 +00:00
2002-07-15 10:35:28 +00:00
DEBUG ( 0 , ( " Could not get name of local/domain master browser for server %s \n " , server ) ) ;
2001-11-21 03:55:59 +00:00
errno = EPERM ; /* FIXME, is this correct */
2002-07-15 10:35:28 +00:00
return NULL ;
2001-02-26 11:53:22 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/*
* Get a connection to IPC $ on the server if we do not already have one
*/
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , buserver , " IPC$ " , workgroup , user , password ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2003-04-16 14:45:11 +00:00
DEBUG ( 0 , ( " got no contact to IPC$ \n " ) ) ;
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
dir - > srv = srv ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/* Now, list the servers ... */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_NetServerEnum ( & srv - > cli , server , 0x0000FFFE , list_fn ,
2002-07-15 10:35:28 +00:00
( void * ) dir ) ) {
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-11-21 03:55:59 +00:00
}
}
else {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( resolve_name ( server , & rem_ip , 0x20 ) ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/* Now, list the shares ... */
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_type = SMBC_FILE_SHARE ;
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , " IPC$ " , workgroup , user , password ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
dir - > srv = srv ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/* Now, list the servers ... */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( cli_RNetShareEnum ( & srv - > cli , list_fn ,
2002-07-15 10:35:28 +00:00
( void * ) dir ) < 0 ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = cli_errno ( & srv - > cli ) ;
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
else {
2001-01-05 13:43:19 +00:00
2004-05-08 20:15:52 +00:00
errno = ECONNREFUSED ; /* Neither the workgroup nor server exists */
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
else { /* The server and share are specified ... work from there ... */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/* Well, we connect to the server and list the directory */
2001-01-06 14:48:55 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_type = SMBC_FILE_SHARE ;
2001-01-06 14:48:55 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-06 14:48:55 +00:00
2002-07-15 10:35:28 +00:00
dir - > srv = srv ;
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
/* Now, list the files ... */
2001-01-06 14:48:55 +00:00
2005-04-19 19:23:49 +00:00
p = path + strlen ( path ) ;
2001-11-21 03:55:59 +00:00
pstrcat ( path , " \\ * " ) ;
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( cli_list ( & srv - > cli , path , aDIR | aSYSTEM | aHIDDEN , dir_list_fn ,
2002-07-15 10:35:28 +00:00
( void * ) dir ) < 0 ) {
2001-01-06 14:48:55 +00:00
2002-07-15 10:35:28 +00:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
2001-11-21 03:55:59 +00:00
}
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2005-04-19 19:23:49 +00:00
if ( errno = = EINVAL ) {
/*
* See if they asked to opendir something
* other than a directory . If so , the
* converted error value we got would have
* been EINVAL rather than ENOTDIR .
*/
* p = ' \0 ' ; /* restore original path */
if ( smbc_getatr ( context , srv , path ,
& mode , NULL ,
NULL , NULL , NULL ,
NULL ) & &
! IS_DOS_DIR ( mode ) ) {
/* It is. Correct the error value */
errno = ENOTDIR ;
}
}
2002-07-15 10:35:28 +00:00
return NULL ;
2001-01-06 14:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2003-01-13 20:04:40 +00:00
DLIST_ADD ( context - > internal - > _files , dir ) ;
2002-07-15 10:35:28 +00:00
return dir ;
2001-01-05 13:43:19 +00:00
}
2000-12-26 05:57:10 +00:00
/*
* Routine to close a directory
*/
2002-07-15 10:35:28 +00:00
static int smbc_closedir_ctx ( SMBCCTX * context , SMBCFILE * dir )
2000-12-26 05:57:10 +00:00
{
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! dir | | ! DLIST_CONTAINS ( context - > internal - > _files , dir ) ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2002-07-15 10:35:28 +00:00
smbc_remove_dir ( dir ) ; /* Clean it up */
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
DLIST_REMOVE ( context - > internal - > _files , dir ) ;
2001-01-07 07:10:50 +00:00
2002-07-15 10:35:28 +00:00
if ( dir ) {
2001-03-27 12:13:59 +00:00
2002-07-15 10:35:28 +00:00
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ; /* Free the space too */
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
2005-03-10 23:41:19 +00:00
static void smbc_readdir_internal ( SMBCCTX * context ,
struct smbc_dirent * dest ,
struct smbc_dirent * src ,
int max_namebuf_len )
{
2005-03-11 17:01:30 +00:00
if ( context - > options . urlencode_readdir_entries ) {
2005-03-10 23:41:19 +00:00
/* url-encode the name. get back remaining buffer space */
max_namebuf_len =
smbc_urlencode ( dest - > name , src - > name , max_namebuf_len ) ;
/* We now know the name length */
dest - > namelen = strlen ( dest - > name ) ;
/* Save the pointer to the beginning of the comment */
dest - > comment = dest - > name + dest - > namelen + 1 ;
/* Copy the comment */
strncpy ( dest - > comment , src - > comment , max_namebuf_len ) ;
/* Ensure the comment is null terminated */
if ( max_namebuf_len > src - > commentlen ) {
dest - > comment [ src - > commentlen ] = ' \0 ' ;
} else {
dest - > comment [ max_namebuf_len - 1 ] = ' \0 ' ;
}
/* Save other fields */
dest - > smbc_type = src - > smbc_type ;
dest - > commentlen = strlen ( dest - > comment ) ;
dest - > dirlen = ( ( dest - > comment + dest - > commentlen + 1 ) -
( char * ) dest ) ;
} else {
/* No encoding. Just copy the entry as is. */
memcpy ( dest , src , src - > dirlen ) ;
dest - > comment = ( char * ) ( & dest - > name + src - > namelen + 1 ) ;
}
}
2000-12-26 05:57:10 +00:00
/*
* Routine to get a directory entry
*/
2002-07-15 10:35:28 +00:00
struct smbc_dirent * smbc_readdir_ctx ( SMBCCTX * context , SMBCFILE * dir )
2001-01-12 05:10:45 +00:00
{
2005-03-10 23:41:19 +00:00
int maxlen ;
2001-11-21 03:55:59 +00:00
struct smbc_dirent * dirp , * dirent ;
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
/* Check that all is ok first ... */
2001-01-12 05:10:45 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
2004-03-19 16:22:47 +00:00
DEBUG ( 0 , ( " Invalid context in smbc_readdir_ctx() \n " ) ) ;
2001-11-21 03:55:59 +00:00
return NULL ;
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 05:10:45 +00:00
2003-01-13 20:04:40 +00:00
if ( ! dir | | ! DLIST_CONTAINS ( context - > internal - > _files , dir ) ) {
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
2004-03-19 16:22:47 +00:00
DEBUG ( 0 , ( " Invalid dir in smbc_readdir_ctx() \n " ) ) ;
2001-11-21 03:55:59 +00:00
return NULL ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2002-07-15 10:35:28 +00:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOTDIR ;
2004-03-19 16:22:47 +00:00
DEBUG ( 0 , ( " Found file vs directory in smbc_readdir_ctx() \n " ) ) ;
2001-11-21 03:55:59 +00:00
return NULL ;
2001-01-12 05:10:45 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 05:10:45 +00:00
2004-03-19 16:22:47 +00:00
if ( ! dir - > dir_next ) {
2001-11-21 03:55:59 +00:00
return NULL ;
2004-03-19 16:22:47 +00:00
}
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
dirent = dir - > dir_next - > dirent ;
if ( ! dirent ) {
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
errno = ENOENT ;
return NULL ;
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
}
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
dirp = ( struct smbc_dirent * ) context - > internal - > _dirent ;
maxlen = ( sizeof ( context - > internal - > _dirent ) -
sizeof ( struct smbc_dirent ) ) ;
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
smbc_readdir_internal ( context , dirp , dirent , maxlen ) ;
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
dir - > dir_next = dir - > dir_next - > next ;
2001-01-12 05:10:45 +00:00
2005-03-10 23:41:19 +00:00
return dirp ;
2001-01-12 05:10:45 +00:00
}
/*
* Routine to get directory entries
*/
2005-03-10 23:41:19 +00:00
static int smbc_getdents_ctx ( SMBCCTX * context ,
SMBCFILE * dir ,
struct smbc_dirent * dirp ,
int count )
2000-12-26 05:57:10 +00:00
{
2005-03-10 23:41:19 +00:00
int rem = count ;
int reqd ;
int maxlen ;
2001-11-21 03:55:59 +00:00
char * ndir = ( char * ) dirp ;
2005-03-10 23:41:19 +00:00
struct smbc_dir_list * dirlist ;
2000-12-26 05:57:10 +00:00
2001-11-21 03:55:59 +00:00
/* Check that all is ok first ... */
2001-01-05 13:43:19 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2003-01-13 20:04:40 +00:00
if ( ! dir | | ! DLIST_CONTAINS ( context - > internal - > _files , dir ) ) {
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2002-07-15 10:35:28 +00:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOTDIR ;
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
/*
* Now , retrieve the number of entries that will fit in what was passed
* We have to figure out if the info is in the list , or we need to
* send a request to the server to get the info .
*/
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
while ( ( dirlist = dir - > dir_next ) ) {
2001-11-21 03:55:59 +00:00
struct smbc_dirent * dirent ;
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
if ( ! dirlist - > dirent ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOENT ; /* Bad error */
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2005-03-10 23:41:19 +00:00
/* Do urlencoding of next entry, if so selected */
dirent = ( struct smbc_dirent * ) context - > internal - > _dirent ;
maxlen = ( sizeof ( context - > internal - > _dirent ) -
sizeof ( struct smbc_dirent ) ) ;
smbc_readdir_internal ( context , dirent , dirlist - > dirent , maxlen ) ;
reqd = dirent - > dirlen ;
if ( rem < reqd ) {
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( rem < count ) { /* We managed to copy something */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = 0 ;
return count - rem ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
else { /* Nothing copied ... */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Not enough space ... */
return - 1 ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2002-02-26 17:40:43 +00:00
memcpy ( ndir , dirent , reqd ) ; /* Copy the data in ... */
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
( ( struct smbc_dirent * ) ndir ) - > comment =
2005-03-10 23:41:19 +00:00
( char * ) ( & ( ( struct smbc_dirent * ) ndir ) - > name +
dirent - > namelen +
1 ) ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
ndir + = reqd ;
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
rem - = reqd ;
2001-01-05 13:43:19 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_next = dirlist = dirlist - > next ;
2001-11-21 03:55:59 +00:00
}
2001-01-05 13:43:19 +00:00
2001-11-21 03:55:59 +00:00
if ( rem = = count )
return 0 ;
else
return count - rem ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to create a directory . . .
*/
2002-07-15 10:35:28 +00:00
static int smbc_mkdir_ctx ( SMBCCTX * context , const char * fname , mode_t mode )
2000-12-26 05:57:10 +00:00
{
2002-07-15 10:35:28 +00:00
SMBCSRV * srv ;
2001-11-21 03:55:59 +00:00
fstring server , share , user , password , workgroup ;
pstring path ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " smbc_mkdir(%s) \n " , fname ) ) ;
2001-01-12 12:48:55 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2001-01-12 12:48:55 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2001-01-12 12:48:55 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-11-17 07:30:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ; /* errno set by smbc_server */
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_mkdir ( & srv - > cli , path ) ) {
2001-01-12 12:48:55 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2001-01-12 12:48:55 +00:00
}
2001-03-27 12:13:59 +00:00
/*
* Our list function simply checks to see if a directory is not empty
*/
static int smbc_rmdir_dirempty = True ;
2005-03-10 23:41:19 +00:00
static void rmdir_list_fn ( const char * mnt , file_info * finfo , const char * mask , void * state )
2001-03-27 12:13:59 +00:00
{
2001-11-21 03:55:59 +00:00
if ( strncmp ( finfo - > name , " . " , 1 ) ! = 0 & & strncmp ( finfo - > name , " .. " , 2 ) ! = 0 )
smbc_rmdir_dirempty = False ;
2001-03-27 12:13:59 +00:00
}
2001-01-12 12:48:55 +00:00
/*
* Routine to remove a directory
*/
2002-07-15 10:35:28 +00:00
static int smbc_rmdir_ctx ( SMBCCTX * context , const char * fname )
2001-01-12 12:48:55 +00:00
{
2002-07-15 10:35:28 +00:00
SMBCSRV * srv ;
2001-11-21 03:55:59 +00:00
fstring server , share , user , password , workgroup ;
pstring path ;
2001-01-12 12:48:55 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 4 , ( " smbc_rmdir(%s) \n " , fname ) ) ;
2001-01-12 12:48:55 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) )
{
errno = EINVAL ;
return - 1 ;
}
2001-01-12 12:48:55 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2001-01-12 12:48:55 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-11-17 07:30:19 +00:00
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( ! srv ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ; /* errno set by smbc_server */
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
/* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
mode = aDIR | aRONLY ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
else if ( strncmp ( srv - > cli . dev , " LPT " , 3 ) = = 0 ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( strcmp ( path , " \\ " ) = = 0 ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
mode = aDIR | aRONLY ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
else {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
mode = aRONLY ;
smbc_stat_printjob ( srv , path , & size , & m_time ) ;
c_time = a_time = m_time ;
2002-07-15 10:35:28 +00:00
2001-11-21 03:55:59 +00:00
}
else { */
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
if ( ! cli_rmdir ( & srv - > cli , path ) ) {
2001-01-12 12:48:55 +00:00
2002-07-15 10:35:28 +00:00
errno = smbc_errno ( context , & srv - > cli ) ;
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
if ( errno = = EACCES ) { /* Check if the dir empty or not */
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
pstring lpath ; /* Local storage to avoid buffer overflows */
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
smbc_rmdir_dirempty = True ; /* Make this so ... */
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
pstrcpy ( lpath , path ) ;
pstrcat ( lpath , " \\ * " ) ;
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
if ( cli_list ( & srv - > cli , lpath , aDIR | aSYSTEM | aHIDDEN , rmdir_list_fn ,
NULL ) < 0 ) {
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
/* Fix errno to ignore latest error ... */
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
DEBUG ( 5 , ( " smbc_rmdir: cli_list returned an error: %d \n " ,
2002-07-15 10:35:28 +00:00
smbc_errno ( context , & srv - > cli ) ) ) ;
2001-11-21 03:55:59 +00:00
errno = EACCES ;
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
if ( smbc_rmdir_dirempty )
errno = EACCES ;
else
errno = ENOTEMPTY ;
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-27 12:13:59 +00:00
2001-11-21 03:55:59 +00:00
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2001-01-07 07:10:50 +00:00
2000-12-26 05:57:10 +00:00
}
2001-01-12 12:48:55 +00:00
/*
* Routine to return the current directory position
*/
2002-07-15 10:35:28 +00:00
static off_t smbc_telldir_ctx ( SMBCCTX * context , SMBCFILE * dir )
2001-01-12 12:48:55 +00:00
{
2003-04-16 14:45:11 +00:00
off_t ret_val ; /* Squash warnings about cast */
2001-01-12 12:48:55 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2003-01-13 20:04:40 +00:00
if ( ! dir | | ! DLIST_CONTAINS ( context - > internal - > _files , dir ) ) {
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
errno = EBADF ;
return - 1 ;
2001-03-01 19:21:57 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-01 19:21:57 +00:00
2002-07-15 10:35:28 +00:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOTDIR ;
return - 1 ;
2001-01-12 12:48:55 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-12 12:48:55 +00:00
2003-04-16 14:45:11 +00:00
/*
* We return the pointer here as the offset
*/
ret_val = ( int ) dir - > dir_next ;
return ret_val ;
2001-01-12 12:48:55 +00:00
}
2001-03-06 14:00:48 +00:00
/*
* A routine to run down the list and see if the entry is OK
*/
struct smbc_dir_list * smbc_check_dir_ent ( struct smbc_dir_list * list ,
struct smbc_dirent * dirent )
{
2001-11-21 03:55:59 +00:00
/* Run down the list looking for what we want */
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
if ( dirent ) {
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
struct smbc_dir_list * tmp = list ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
while ( tmp ) {
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
if ( tmp - > dirent = = dirent )
return tmp ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
tmp = tmp - > next ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
return NULL ; /* Not found, or an error */
2001-03-06 14:00:48 +00:00
}
2000-12-26 05:57:10 +00:00
/*
* Routine to seek on a directory
*/
2002-07-15 10:35:28 +00:00
static int smbc_lseekdir_ctx ( SMBCCTX * context , SMBCFILE * dir , off_t offset )
2000-12-26 05:57:10 +00:00
{
2003-04-16 14:45:11 +00:00
long int l_offset = offset ; /* Handle problems of size */
struct smbc_dirent * dirent = ( struct smbc_dirent * ) l_offset ;
struct smbc_dir_list * list_ent = ( struct smbc_dir_list * ) NULL ;
2000-12-26 05:57:10 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2002-07-15 10:35:28 +00:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2001-03-05 13:34:48 +00:00
2001-11-21 03:55:59 +00:00
errno = ENOTDIR ;
return - 1 ;
2001-03-05 13:34:48 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-05 13:34:48 +00:00
2001-11-21 03:55:59 +00:00
/* Now, check what we were passed and see if it is OK ... */
2001-03-05 13:34:48 +00:00
2001-11-21 03:55:59 +00:00
if ( dirent = = NULL ) { /* Seek to the begining of the list */
2001-03-06 14:00:48 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_next = dir - > dir_list ;
2001-11-21 03:55:59 +00:00
return 0 ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
/* Now, run down the list and make sure that the entry is OK */
/* This may need to be changed if we change the format of the list */
2001-03-06 14:00:48 +00:00
2002-07-15 10:35:28 +00:00
if ( ( list_ent = smbc_check_dir_ent ( dir - > dir_list , dirent ) ) = = NULL ) {
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ; /* Bad entry */
return - 1 ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
}
2001-03-06 14:00:48 +00:00
2002-07-15 10:35:28 +00:00
dir - > dir_next = list_ent ;
2001-03-06 14:00:48 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
}
/*
* Routine to fstat a dir
*/
2002-07-15 10:35:28 +00:00
static int smbc_fstatdir_ctx ( SMBCCTX * context , SMBCFILE * dir , struct stat * st )
2000-12-26 05:57:10 +00:00
{
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
}
2001-01-07 07:10:50 +00:00
2001-11-21 03:55:59 +00:00
/* No code yet ... */
2001-02-26 11:53:22 +00:00
2001-11-21 03:55:59 +00:00
return 0 ;
2000-12-26 05:57:10 +00:00
2001-02-05 13:02:20 +00:00
}
2003-10-24 17:01:19 +00:00
int smbc_chmod_ctx ( SMBCCTX * context , const char * fname , mode_t newmode )
2002-07-15 10:35:28 +00:00
{
2003-10-24 17:01:19 +00:00
SMBCSRV * srv ;
fstring server , share , user , password , workgroup ;
2002-07-15 10:35:28 +00:00
pstring path ;
2003-10-24 17:01:19 +00:00
uint16 mode ;
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2002-07-15 10:35:28 +00:00
2003-10-24 17:01:19 +00:00
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
2002-07-15 10:35:28 +00:00
}
if ( ! fname ) {
errno = EINVAL ;
2003-10-24 17:01:19 +00:00
return - 1 ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
DEBUG ( 4 , ( " smbc_chmod(%s, 0%3o) \n " , fname , newmode ) ) ;
2002-07-15 10:35:28 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2002-07-15 10:35:28 +00:00
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
2001-11-21 03:55:59 +00:00
}
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
mode = 0 ;
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
if ( ! ( newmode & ( S_IWUSR | S_IWGRP | S_IWOTH ) ) ) mode | = aRONLY ;
if ( ( newmode & S_IXUSR ) & & lp_map_archive ( - 1 ) ) mode | = aARCH ;
if ( ( newmode & S_IXGRP ) & & lp_map_system ( - 1 ) ) mode | = aSYSTEM ;
if ( ( newmode & S_IXOTH ) & & lp_map_hidden ( - 1 ) ) mode | = aHIDDEN ;
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
if ( ! cli_setatr ( & srv - > cli , path , mode , 0 ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
2001-11-21 03:55:59 +00:00
return - 1 ;
}
2003-10-24 17:01:19 +00:00
return 0 ;
2001-02-06 19:25:12 +00:00
}
2003-10-24 17:01:19 +00:00
int smbc_utimes_ctx ( SMBCCTX * context , const char * fname , struct timeval * tbuf )
2001-02-06 19:25:12 +00:00
{
2005-06-01 17:40:40 +00:00
int fd ;
int ret ;
2003-10-24 17:01:19 +00:00
SMBCSRV * srv ;
2002-07-15 10:35:28 +00:00
fstring server , share , user , password , workgroup ;
2001-11-21 03:55:59 +00:00
pstring path ;
2005-06-01 17:40:40 +00:00
time_t c_time ;
time_t a_time ;
time_t m_time ;
2001-02-06 19:25:12 +00:00
2003-01-13 20:04:40 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
2001-02-06 19:25:12 +00:00
2003-10-24 17:01:19 +00:00
errno = EINVAL ; /* Best I can think of ... */
2001-11-21 03:55:59 +00:00
return - 1 ;
2003-10-24 17:01:19 +00:00
2001-11-21 03:55:59 +00:00
}
2001-02-06 19:25:12 +00:00
2001-11-21 03:55:59 +00:00
if ( ! fname ) {
2003-10-24 17:01:19 +00:00
2001-11-21 03:55:59 +00:00
errno = EINVAL ;
return - 1 ;
2001-02-06 19:25:12 +00:00
2001-11-21 03:55:59 +00:00
}
2001-02-06 19:25:12 +00:00
2005-06-01 17:40:40 +00:00
if ( tbuf = = NULL ) {
a_time = m_time = time ( NULL ) ;
} else {
a_time = tbuf [ 0 ] . tv_sec ;
m_time = tbuf [ 1 ] . tv_sec ;
}
{
char atimebuf [ 32 ] ;
char mtimebuf [ 32 ] ;
DEBUG ( 4 , ( " smbc_utimes(%s, atime = %s mtime = %s) \n " ,
fname ,
ctime_r ( & a_time , atimebuf ) ,
ctime_r ( & m_time , mtimebuf ) ) ) ;
}
2001-02-06 19:25:12 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2001-02-06 19:25:12 +00:00
2003-03-22 09:27:42 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
2003-10-24 17:01:19 +00:00
2003-03-22 09:27:42 +00:00
fstrcpy ( workgroup , context - > workgroup ) ;
2002-07-15 10:35:28 +00:00
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
2005-06-01 17:40:40 +00:00
/*
* cli_setatr ( ) does not work on win98 , and it also doesn ' t support
* setting the access time ( only the modification time ) , so in all
* cases , we open the specified file and use cli_setattrE ( ) which
* should work on all OS versions , and supports both times .
*/
if ( ( fd = cli_open ( & srv - > cli , path , O_RDWR , DENY_NONE ) ) < 0 ) {
errno = smbc_errno ( context , & srv - > cli ) ;
2003-10-24 17:01:19 +00:00
return - 1 ;
2005-06-01 17:40:40 +00:00
}
2002-07-15 10:35:28 +00:00
2005-06-01 17:40:40 +00:00
/* Get the creat time of the file; we'll need it in the set call */
ret = cli_getattrE ( & srv - > cli , fd , NULL , NULL , & c_time , NULL , NULL ) ;
2001-02-05 13:02:20 +00:00
2005-06-01 17:40:40 +00:00
/* Some OS versions don't support create time */
if ( c_time = = 0 ) {
c_time = time ( NULL ) ;
}
/*
* For sanity sake , since there is no POSIX function to set the create
* time of a file , if the existing create time is greater than either
* of access time or modification time , set create time to the
* smallest of those . This ensure that the create time of a file is
* never greater than its last access or modification time .
*/
if ( c_time > a_time ) c_time = a_time ;
if ( c_time > m_time ) c_time = m_time ;
/* If we sucessfully retrieved the create time... */
if ( ret ) {
/* ... then set the new attributes */
ret = cli_setattrE ( & srv - > cli , fd , c_time , a_time , m_time ) ;
}
cli_close ( & srv - > cli , fd ) ;
return ret ;
2000-12-26 05:57:10 +00:00
}
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
However NT4 gives a " The information may have been modified by a
computer running Windows NT 5.0 " if denied ACEs do not appear before
allowed ACEs . */
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
static int ace_compare ( SEC_ACE * ace1 , SEC_ACE * ace2 )
{
if ( sec_ace_equal ( ace1 , ace2 ) )
return 0 ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( ace1 - > type ! = ace2 - > type )
return ace2 - > type - ace1 - > type ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) )
return sid_compare ( & ace1 - > trustee , & ace2 - > trustee ) ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( ace1 - > flags ! = ace2 - > flags )
return ace1 - > flags - ace2 - > flags ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( ace1 - > info . mask ! = ace2 - > info . mask )
return ace1 - > info . mask - ace2 - > info . mask ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( ace1 - > size ! = ace2 - > size )
return ace1 - > size - ace2 - > size ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
return memcmp ( ace1 , ace2 , sizeof ( SEC_ACE ) ) ;
}
2001-11-17 07:30:19 +00:00
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
static void sort_acl ( SEC_ACL * the_acl )
{
uint32 i ;
if ( ! the_acl ) return ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
qsort ( the_acl - > ace , the_acl - > num_aces , sizeof ( the_acl - > ace [ 0 ] ) , QSORT_CAST ace_compare ) ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
for ( i = 1 ; i < the_acl - > num_aces ; ) {
if ( sec_ace_equal ( & the_acl - > ace [ i - 1 ] , & the_acl - > ace [ i ] ) ) {
int j ;
for ( j = i ; j < the_acl - > num_aces - 1 ; j + + ) {
the_acl - > ace [ j ] = the_acl - > ace [ j + 1 ] ;
}
the_acl - > num_aces - - ;
} else {
i + + ;
}
2001-11-21 03:55:59 +00:00
}
2003-10-24 17:01:19 +00:00
}
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
/* convert a SID to a string, either numeric or username/group */
static void convert_sid_to_string ( struct cli_state * ipc_cli ,
POLICY_HND * pol ,
fstring str ,
BOOL numeric ,
DOM_SID * sid )
{
char * * domains = NULL ;
char * * names = NULL ;
uint32 * types = NULL ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
sid_to_string ( str , sid ) ;
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
if ( numeric ) return ; /* no lookup desired */
/* Ask LSA to convert the sid to a name */
if ( ! NT_STATUS_IS_OK ( cli_lsa_lookup_sids ( ipc_cli , ipc_cli - > mem_ctx ,
pol , 1 , sid , & domains ,
& names , & types ) ) | |
! domains | | ! domains [ 0 ] | | ! names | | ! names [ 0 ] ) {
return ;
2001-11-21 03:55:59 +00:00
}
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
/* Converted OK */
2001-02-04 19:48:26 +00:00
2003-10-24 17:01:19 +00:00
slprintf ( str , sizeof ( fstring ) - 1 , " %s%s%s " ,
domains [ 0 ] , lp_winbind_separator ( ) ,
names [ 0 ] ) ;
2001-02-04 19:48:26 +00:00
}
2003-10-24 17:01:19 +00:00
/* convert a string to a SID, either numeric or username/group */
static BOOL convert_string_to_sid ( struct cli_state * ipc_cli ,
POLICY_HND * pol ,
BOOL numeric ,
DOM_SID * sid ,
const char * str )
2002-07-15 10:35:28 +00:00
{
2003-10-24 17:01:19 +00:00
uint32 * types = NULL ;
DOM_SID * sids = NULL ;
BOOL result = True ;
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
if ( numeric ) {
if ( strncmp ( str , " S- " , 2 ) = = 0 ) {
return string_to_sid ( sid , str ) ;
}
2003-01-13 20:04:40 +00:00
2003-10-24 17:01:19 +00:00
result = False ;
goto done ;
}
2002-07-15 10:35:28 +00:00
2003-10-24 17:01:19 +00:00
if ( ! NT_STATUS_IS_OK ( cli_lsa_lookup_names ( ipc_cli , ipc_cli - > mem_ctx ,
pol , 1 , & str , & sids ,
& types ) ) ) {
result = False ;
goto done ;
2003-01-13 20:04:40 +00:00
}
2003-10-24 17:01:19 +00:00
sid_copy ( sid , & sids [ 0 ] ) ;
done :
2003-01-13 20:04:40 +00:00
2003-10-24 17:01:19 +00:00
return result ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
/* parse an ACE in the same format as print_ace() */
static BOOL parse_ace ( struct cli_state * ipc_cli ,
POLICY_HND * pol ,
SEC_ACE * ace ,
BOOL numeric ,
char * str )
2001-02-05 13:02:20 +00:00
{
2003-10-24 17:01:19 +00:00
char * p ;
const char * cp ;
fstring tok ;
unsigned atype , aflags , amask ;
DOM_SID sid ;
SEC_ACCESS mask ;
const struct perm_value * v ;
struct perm_value {
const char * perm ;
uint32 mask ;
} ;
/* These values discovered by inspection */
static const struct perm_value special_values [ ] = {
{ " R " , 0x00120089 } ,
{ " W " , 0x00120116 } ,
{ " X " , 0x001200a0 } ,
{ " D " , 0x00010000 } ,
{ " P " , 0x00040000 } ,
{ " O " , 0x00080000 } ,
{ NULL , 0 } ,
} ;
static const struct perm_value standard_values [ ] = {
{ " READ " , 0x001200a9 } ,
{ " CHANGE " , 0x001301bf } ,
{ " FULL " , 0x001f01ff } ,
{ NULL , 0 } ,
} ;
ZERO_STRUCTP ( ace ) ;
p = strchr_m ( str , ' : ' ) ;
if ( ! p ) return False ;
* p = ' \0 ' ;
p + + ;
/* Try to parse numeric form */
if ( sscanf ( p , " %i/%i/%i " , & atype , & aflags , & amask ) = = 3 & &
convert_string_to_sid ( ipc_cli , pol , numeric , & sid , str ) ) {
goto done ;
}
/* Try to parse text form */
if ( ! convert_string_to_sid ( ipc_cli , pol , numeric , & sid , str ) ) {
return False ;
}
cp = p ;
if ( ! next_token ( & cp , tok , " / " , sizeof ( fstring ) ) ) {
return False ;
}
if ( StrnCaseCmp ( tok , " ALLOWED " , strlen ( " ALLOWED " ) ) = = 0 ) {
atype = SEC_ACE_TYPE_ACCESS_ALLOWED ;
} else if ( StrnCaseCmp ( tok , " DENIED " , strlen ( " DENIED " ) ) = = 0 ) {
atype = SEC_ACE_TYPE_ACCESS_DENIED ;
} else {
return False ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
/* Only numeric form accepted for flags at present */
if ( ! ( next_token ( & cp , tok , " / " , sizeof ( fstring ) ) & &
sscanf ( tok , " %i " , & aflags ) ) ) {
return False ;
}
if ( ! next_token ( & cp , tok , " / " , sizeof ( fstring ) ) ) {
return False ;
}
if ( strncmp ( tok , " 0x " , 2 ) = = 0 ) {
if ( sscanf ( tok , " %i " , & amask ) ! = 1 ) {
return False ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
goto done ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
for ( v = standard_values ; v - > perm ; v + + ) {
if ( strcmp ( tok , v - > perm ) = = 0 ) {
amask = v - > mask ;
goto done ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
}
p = tok ;
while ( * p ) {
BOOL found = False ;
for ( v = special_values ; v - > perm ; v + + ) {
if ( v - > perm [ 0 ] = = * p ) {
amask | = v - > mask ;
found = True ;
}
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
if ( ! found ) return False ;
p + + ;
2002-07-15 10:35:28 +00:00
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
if ( * p ) {
return False ;
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
done :
mask . mask = amask ;
init_sec_ace ( ace , & sid , atype , mask , aflags ) ;
return True ;
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
/* add an ACE to a list of ACEs in a SEC_ACL */
static BOOL add_ace ( SEC_ACL * * the_acl , SEC_ACE * ace , TALLOC_CTX * ctx )
2002-07-15 10:35:28 +00:00
{
2003-10-24 17:01:19 +00:00
SEC_ACL * new ;
SEC_ACE * aces ;
if ( ! * the_acl ) {
( * the_acl ) = make_sec_acl ( ctx , 3 , 1 , ace ) ;
return True ;
}
2002-07-15 10:35:28 +00:00
2004-12-07 18:25:53 +00:00
aces = SMB_CALLOC_ARRAY ( SEC_ACE , 1 + ( * the_acl ) - > num_aces ) ;
2003-10-24 17:01:19 +00:00
memcpy ( aces , ( * the_acl ) - > ace , ( * the_acl ) - > num_aces * sizeof ( SEC_ACE ) ) ;
memcpy ( aces + ( * the_acl ) - > num_aces , ace , sizeof ( SEC_ACE ) ) ;
new = make_sec_acl ( ctx , ( * the_acl ) - > revision , 1 + ( * the_acl ) - > num_aces , aces ) ;
SAFE_FREE ( aces ) ;
( * the_acl ) = new ;
return True ;
}
/* parse a ascii version of a security descriptor */
static SEC_DESC * sec_desc_parse ( TALLOC_CTX * ctx ,
struct cli_state * ipc_cli ,
POLICY_HND * pol ,
BOOL numeric ,
char * str )
{
const char * p = str ;
fstring tok ;
SEC_DESC * ret ;
size_t sd_size ;
DOM_SID * grp_sid = NULL , * owner_sid = NULL ;
SEC_ACL * dacl = NULL ;
int revision = 1 ;
while ( next_token ( & p , tok , " \t , \r \n " , sizeof ( tok ) ) ) {
if ( StrnCaseCmp ( tok , " REVISION: " , 9 ) = = 0 ) {
revision = strtol ( tok + 9 , NULL , 16 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " OWNER: " , 6 ) = = 0 ) {
2004-12-07 18:25:53 +00:00
owner_sid = SMB_CALLOC_ARRAY ( DOM_SID , 1 ) ;
2003-10-24 17:01:19 +00:00
if ( ! owner_sid | |
! convert_string_to_sid ( ipc_cli , pol ,
numeric ,
owner_sid , tok + 6 ) ) {
DEBUG ( 5 , ( " Failed to parse owner sid \n " ) ) ;
return NULL ;
}
continue ;
}
if ( StrnCaseCmp ( tok , " OWNER+: " , 7 ) = = 0 ) {
2004-12-07 18:25:53 +00:00
owner_sid = SMB_CALLOC_ARRAY ( DOM_SID , 1 ) ;
2003-10-24 17:01:19 +00:00
if ( ! owner_sid | |
! convert_string_to_sid ( ipc_cli , pol ,
False ,
owner_sid , tok + 7 ) ) {
DEBUG ( 5 , ( " Failed to parse owner sid \n " ) ) ;
return NULL ;
}
continue ;
}
if ( StrnCaseCmp ( tok , " GROUP: " , 6 ) = = 0 ) {
2004-12-07 18:25:53 +00:00
grp_sid = SMB_CALLOC_ARRAY ( DOM_SID , 1 ) ;
2003-10-24 17:01:19 +00:00
if ( ! grp_sid | |
! convert_string_to_sid ( ipc_cli , pol ,
numeric ,
grp_sid , tok + 6 ) ) {
DEBUG ( 5 , ( " Failed to parse group sid \n " ) ) ;
return NULL ;
}
continue ;
}
if ( StrnCaseCmp ( tok , " GROUP+: " , 7 ) = = 0 ) {
2004-12-07 18:25:53 +00:00
grp_sid = SMB_CALLOC_ARRAY ( DOM_SID , 1 ) ;
2003-10-24 17:01:19 +00:00
if ( ! grp_sid | |
! convert_string_to_sid ( ipc_cli , pol ,
False ,
grp_sid , tok + 6 ) ) {
DEBUG ( 5 , ( " Failed to parse group sid \n " ) ) ;
return NULL ;
}
continue ;
}
if ( StrnCaseCmp ( tok , " ACL: " , 4 ) = = 0 ) {
SEC_ACE ace ;
if ( ! parse_ace ( ipc_cli , pol , & ace , numeric , tok + 4 ) ) {
DEBUG ( 5 , ( " Failed to parse ACL %s \n " , tok ) ) ;
return NULL ;
}
if ( ! add_ace ( & dacl , & ace , ctx ) ) {
DEBUG ( 5 , ( " Failed to add ACL %s \n " , tok ) ) ;
return NULL ;
}
continue ;
}
if ( StrnCaseCmp ( tok , " ACL+: " , 5 ) = = 0 ) {
SEC_ACE ace ;
if ( ! parse_ace ( ipc_cli , pol , & ace , False , tok + 5 ) ) {
DEBUG ( 5 , ( " Failed to parse ACL %s \n " , tok ) ) ;
return NULL ;
}
if ( ! add_ace ( & dacl , & ace , ctx ) ) {
DEBUG ( 5 , ( " Failed to add ACL %s \n " , tok ) ) ;
return NULL ;
}
continue ;
}
DEBUG ( 5 , ( " Failed to parse security descriptor \n " ) ) ;
2002-07-15 10:35:28 +00:00
return NULL ;
2001-11-21 03:55:59 +00:00
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
ret = make_sec_desc ( ctx , revision , SEC_DESC_SELF_RELATIVE ,
owner_sid , grp_sid , NULL , dacl , & sd_size ) ;
2002-07-15 10:35:28 +00:00
2003-10-24 17:01:19 +00:00
SAFE_FREE ( grp_sid ) ;
SAFE_FREE ( owner_sid ) ;
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
return ret ;
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
2005-03-10 23:41:19 +00:00
/* Obtain the current dos attributes */
static DOS_ATTR_DESC * dos_attr_query ( SMBCCTX * context ,
TALLOC_CTX * ctx ,
const char * filename ,
SMBCSRV * srv )
{
time_t m_time = 0 , a_time = 0 , c_time = 0 ;
2005-03-22 21:17:01 +00:00
SMB_OFF_T size = 0 ;
2005-03-10 23:41:19 +00:00
uint16 mode = 0 ;
SMB_INO_T inode = 0 ;
DOS_ATTR_DESC * ret ;
2005-05-03 07:33:49 +00:00
ret = TALLOC_P ( ctx , DOS_ATTR_DESC ) ;
2005-03-10 23:41:19 +00:00
if ( ! ret ) {
errno = ENOMEM ;
return NULL ;
}
/* Obtain the DOS attributes */
2005-03-31 05:06:04 +00:00
if ( ! smbc_getatr ( context , srv , CONST_DISCARD ( char * , filename ) ,
& mode , & size ,
2005-03-10 23:41:19 +00:00
& c_time , & a_time , & m_time , & inode ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
DEBUG ( 5 , ( " dos_attr_query Failed to query old attributes \n " ) ) ;
return NULL ;
}
ret - > mode = mode ;
ret - > size = size ;
ret - > a_time = a_time ;
ret - > c_time = c_time ;
ret - > m_time = m_time ;
ret - > inode = inode ;
return ret ;
}
/* parse a ascii version of a security descriptor */
static void dos_attr_parse ( SMBCCTX * context ,
DOS_ATTR_DESC * dad ,
SMBCSRV * srv ,
char * str )
{
const char * p = str ;
fstring tok ;
while ( next_token ( & p , tok , " \t , \r \n " , sizeof ( tok ) ) ) {
if ( StrnCaseCmp ( tok , " MODE: " , 5 ) = = 0 ) {
dad - > mode = strtol ( tok + 5 , NULL , 16 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " SIZE: " , 5 ) = = 0 ) {
dad - > size = strtoll ( tok + 5 , NULL , 10 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " A_TIME: " , 7 ) = = 0 ) {
dad - > a_time = strtoll ( tok + 7 , NULL , 10 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " C_TIME: " , 7 ) = = 0 ) {
dad - > c_time = strtoll ( tok + 7 , NULL , 10 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " M_TIME: " , 7 ) = = 0 ) {
dad - > m_time = strtoll ( tok + 7 , NULL , 10 ) ;
continue ;
}
if ( StrnCaseCmp ( tok , " INODE: " , 6 ) = = 0 ) {
dad - > inode = strtoll ( tok + 6 , NULL , 10 ) ;
continue ;
}
}
}
2003-10-24 17:01:19 +00:00
/*****************************************************
retrieve the acls for a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-03-10 23:41:19 +00:00
static int cacl_get ( SMBCCTX * context , TALLOC_CTX * ctx , SMBCSRV * srv ,
2003-10-24 17:01:19 +00:00
struct cli_state * ipc_cli , POLICY_HND * pol ,
2005-03-31 05:06:04 +00:00
char * filename , char * attr_name , char * buf , int bufsize )
2003-10-24 17:01:19 +00:00
{
uint32 i ;
int n = 0 ;
int n_used ;
BOOL all ;
2005-03-10 23:41:19 +00:00
BOOL all_nt ;
2005-03-31 05:06:04 +00:00
BOOL all_nt_acls ;
2005-03-10 23:41:19 +00:00
BOOL all_dos ;
BOOL some_nt ;
BOOL some_dos ;
2005-03-31 05:06:04 +00:00
BOOL exclude_nt_revision = False ;
BOOL exclude_nt_owner = False ;
BOOL exclude_nt_group = False ;
BOOL exclude_nt_acl = False ;
BOOL exclude_dos_mode = False ;
BOOL exclude_dos_size = False ;
BOOL exclude_dos_ctime = False ;
BOOL exclude_dos_atime = False ;
BOOL exclude_dos_mtime = False ;
BOOL exclude_dos_inode = False ;
2003-10-24 17:01:19 +00:00
BOOL numeric = True ;
BOOL determine_size = ( bufsize = = 0 ) ;
int fnum = - 1 ;
SEC_DESC * sd ;
fstring sidstr ;
2005-03-31 05:06:04 +00:00
fstring name_sandbox ;
char * name ;
char * pExclude ;
2003-10-24 17:01:19 +00:00
char * p ;
2005-03-10 23:41:19 +00:00
time_t m_time = 0 , a_time = 0 , c_time = 0 ;
2005-03-22 21:17:01 +00:00
SMB_OFF_T size = 0 ;
2005-03-10 23:41:19 +00:00
uint16 mode = 0 ;
SMB_INO_T ino = 0 ;
struct cli_state * cli = & srv - > cli ;
2003-10-24 17:01:19 +00:00
2005-03-31 05:06:04 +00:00
/* Copy name so we can strip off exclusions (if any are specified) */
strncpy ( name_sandbox , attr_name , sizeof ( name_sandbox ) - 1 ) ;
/* Ensure name is null terminated */
name_sandbox [ sizeof ( name_sandbox ) - 1 ] = ' \0 ' ;
/* Play in the sandbox */
name = name_sandbox ;
/* If there are any exclusions, point to them and mask them from name */
if ( ( pExclude = strchr ( name , ' ! ' ) ) ! = NULL )
{
* pExclude + + = ' \0 ' ;
}
2005-03-10 23:41:19 +00:00
all = ( StrnCaseCmp ( name , " system.* " , 8 ) = = 0 ) ;
all_nt = ( StrnCaseCmp ( name , " system.nt_sec_desc.* " , 20 ) = = 0 ) ;
2005-03-31 05:06:04 +00:00
all_nt_acls = ( StrnCaseCmp ( name , " system.nt_sec_desc.acl.* " , 24 ) = = 0 ) ;
2005-03-10 23:41:19 +00:00
all_dos = ( StrnCaseCmp ( name , " system.dos_attr.* " , 17 ) = = 0 ) ;
some_nt = ( StrnCaseCmp ( name , " system.nt_sec_desc. " , 19 ) = = 0 ) ;
some_dos = ( StrnCaseCmp ( name , " system.dos_attr. " , 16 ) = = 0 ) ;
numeric = ( * ( name + strlen ( name ) - 1 ) ! = ' + ' ) ;
2001-02-05 13:02:20 +00:00
2005-03-31 05:06:04 +00:00
/* Look for exclusions from "all" requests */
if ( all | | all_nt | | all_dos ) {
/* Exclusions are delimited by '!' */
for ( ; pExclude ! = NULL ; pExclude = ( p = = NULL ? NULL : p + 1 ) ) {
/* Find end of this exclusion name */
if ( ( p = strchr ( pExclude , ' ! ' ) ) ! = NULL )
{
* p = ' \0 ' ;
}
/* Which exclusion name is this? */
if ( StrCaseCmp ( pExclude , " nt_sec_desc.revision " ) = = 0 ) {
exclude_nt_revision = True ;
}
else if ( StrCaseCmp ( pExclude , " nt_sec_desc.owner " ) = = 0 ) {
exclude_nt_owner = True ;
}
else if ( StrCaseCmp ( pExclude , " nt_sec_desc.group " ) = = 0 ) {
exclude_nt_group = True ;
}
else if ( StrCaseCmp ( pExclude , " nt_sec_desc.acl " ) = = 0 ) {
exclude_nt_acl = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.mode " ) = = 0 ) {
exclude_dos_mode = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.size " ) = = 0 ) {
exclude_dos_size = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.c_time " ) = = 0 ) {
exclude_dos_ctime = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.a_time " ) = = 0 ) {
exclude_dos_atime = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.m_time " ) = = 0 ) {
exclude_dos_mtime = True ;
}
else if ( StrCaseCmp ( pExclude , " dos_attr.inode " ) = = 0 ) {
exclude_dos_inode = True ;
}
else {
DEBUG ( 5 , ( " cacl_get received unknown exclusion: %s \n " ,
pExclude ) ) ;
errno = ENOATTR ;
return - 1 ;
}
}
}
2005-03-10 23:41:19 +00:00
n_used = 0 ;
2001-02-05 13:02:20 +00:00
2005-03-10 23:41:19 +00:00
/*
* If we are ( possibly ) talking to an NT or new system and some NT
* attributes have been requested . . .
*/
2005-03-31 05:06:04 +00:00
if ( ipc_cli & & ( all | | some_nt | | all_nt_acls ) ) {
2005-03-10 23:41:19 +00:00
/* Point to the portion after "system.nt_sec_desc." */
name + = 19 ; /* if (all) this will be invalid but unused */
2001-11-17 07:30:19 +00:00
2005-03-10 23:41:19 +00:00
/* ... then obtain any NT attributes which were requested */
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_READ ) ;
2003-10-24 17:01:19 +00:00
2005-03-10 23:41:19 +00:00
if ( fnum = = - 1 ) {
DEBUG ( 5 , ( " cacl_get failed to open %s: %s \n " ,
filename , cli_errstr ( cli ) ) ) ;
errno = 0 ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
2005-03-10 23:41:19 +00:00
sd = cli_query_secdesc ( cli , fnum , ctx ) ;
2003-10-24 17:01:19 +00:00
2005-03-10 23:41:19 +00:00
if ( ! sd ) {
DEBUG ( 5 ,
( " cacl_get Failed to query old descriptor \n " ) ) ;
errno = 0 ;
return - 1 ;
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
cli_close ( cli , fnum ) ;
2005-03-31 05:06:04 +00:00
if ( ! exclude_nt_revision ) {
if ( all | | all_nt ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx ,
" REVISION:%d " ,
sd - > revision ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" REVISION:%d " , sd - > revision ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " revision " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " %d " ,
sd - > revision ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " %d " ,
sd - > revision ) ;
2005-03-10 23:41:19 +00:00
}
2003-10-24 17:01:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2003-10-24 17:01:19 +00:00
2005-03-31 05:06:04 +00:00
if ( ! exclude_nt_owner ) {
/* Get owner and group sid */
if ( sd - > owner_sid ) {
convert_sid_to_string ( ipc_cli , pol ,
sidstr ,
numeric ,
sd - > owner_sid ) ;
2005-03-10 23:41:19 +00:00
} else {
2005-03-31 05:06:04 +00:00
fstrcpy ( sidstr , " " ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( all | | all_nt ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " ,OWNER:%s " ,
sidstr ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,OWNER:%s " , sidstr ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrnCaseCmp ( name , " owner " , 5 ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " %s " , sidstr ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " %s " ,
sidstr ) ;
2005-03-10 23:41:19 +00:00
}
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_nt_group ) {
if ( sd - > grp_sid ) {
convert_sid_to_string ( ipc_cli , pol ,
sidstr , numeric ,
sd - > grp_sid ) ;
} else {
fstrcpy ( sidstr , " " ) ;
}
2005-03-10 23:41:19 +00:00
if ( all | | all_nt ) {
if ( determine_size ) {
2005-03-31 05:06:04 +00:00
p = talloc_asprintf ( ctx , " ,GROUP:%s " ,
sidstr ) ;
2005-03-10 23:41:19 +00:00
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
2005-03-31 05:06:04 +00:00
" ,GROUP:%s " , sidstr ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrnCaseCmp ( name , " group " , 5 ) = = 0 ) {
2005-03-10 23:41:19 +00:00
if ( determine_size ) {
2005-03-31 05:06:04 +00:00
p = talloc_asprintf ( ctx , " %s " , sidstr ) ;
2005-03-10 23:41:19 +00:00
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
2005-03-31 05:06:04 +00:00
n = snprintf ( buf , bufsize , " %s " , sidstr ) ;
2005-03-10 23:41:19 +00:00
}
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
2005-03-10 23:41:19 +00:00
errno = ERANGE ;
2003-10-24 17:01:19 +00:00
return - 1 ;
}
2005-03-10 23:41:19 +00:00
buf + = n ;
n_used + = n ;
bufsize - = n ;
2003-10-24 17:01:19 +00:00
}
2001-02-05 13:02:20 +00:00
2005-03-31 05:06:04 +00:00
if ( ! exclude_nt_acl ) {
/* Add aces to value buffer */
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
SEC_ACE * ace = & sd - > dacl - > ace [ i ] ;
convert_sid_to_string ( ipc_cli , pol ,
sidstr , numeric ,
& ace - > trustee ) ;
if ( all | | all_nt ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" ,ACL: "
" %s:%d/%d/0x%08x " ,
sidstr ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf (
buf , bufsize ,
" ,ACL:%s:%d/%d/0x%08x " ,
sidstr ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
}
} else if ( ( StrnCaseCmp ( name , " acl " , 3 ) = = 0 & &
StrCaseCmp ( name + 3 , sidstr ) = = 0 ) | |
( StrnCaseCmp ( name , " acl+ " , 4 ) = = 0 & &
StrCaseCmp ( name + 4 , sidstr ) = = 0 ) ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" %d/%d/0x%08x " ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" %d/%d/0x%08x " ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
}
} else if ( all_nt_acls ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" %s%s:%d/%d/0x%08x " ,
i ? " , " : " " ,
sidstr ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" %s%s:%d/%d/0x%08x " ,
i ? " , " : " " ,
sidstr ,
ace - > type ,
ace - > flags ,
ace - > info . mask ) ;
}
}
if ( n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
}
}
2005-03-10 23:41:19 +00:00
/* Restore name pointer to its original value */
name - = 19 ;
2003-10-24 17:01:19 +00:00
}
2001-02-05 13:02:20 +00:00
2005-03-10 23:41:19 +00:00
if ( all | | some_dos ) {
/* Point to the portion after "system.dos_attr." */
name + = 16 ; /* if (all) this will be invalid but unused */
2003-10-24 17:01:19 +00:00
2005-03-10 23:41:19 +00:00
/* Obtain the DOS attributes */
if ( ! smbc_getatr ( context , srv , filename , & mode , & size ,
& c_time , & a_time , & m_time , & ino ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
return - 1 ;
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_mode ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx ,
" %sMODE:0x%x " ,
( ipc_cli & &
( all | | some_nt )
? " , "
: " " ) ,
mode ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" %sMODE:0x%x " ,
( ipc_cli & &
( all | | some_nt )
? " , "
: " " ) ,
mode ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " mode " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " 0x%x " , mode ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " 0x%x " , mode ) ;
2005-03-10 23:41:19 +00:00
}
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_size ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" ,SIZE:%llu " ,
( unsigned long long ) size ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,SIZE:%llu " ,
( unsigned long long ) size ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " size " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" %llu " ,
( unsigned long long ) size ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" %llu " ,
( unsigned long long ) size ) ;
2005-03-10 23:41:19 +00:00
}
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_ctime ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx ,
" ,C_TIME:%lu " ,
c_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,C_TIME:%lu " , c_time ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " c_time " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " %lu " , c_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " %lu " , c_time ) ;
2005-03-10 23:41:19 +00:00
}
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_atime ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx ,
" ,A_TIME:%lu " ,
a_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,A_TIME:%lu " , a_time ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " a_time " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " %lu " , a_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " %lu " , a_time ) ;
2005-03-10 23:41:19 +00:00
}
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_mtime ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx ,
" ,M_TIME:%lu " ,
m_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,M_TIME:%lu " , m_time ) ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " m_time " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf ( ctx , " %lu " , m_time ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize , " %lu " , m_time ) ;
2005-03-10 23:41:19 +00:00
}
}
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2005-03-10 23:41:19 +00:00
}
2005-03-31 05:06:04 +00:00
if ( ! exclude_dos_inode ) {
if ( all | | all_dos ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" ,INODE:%llu " ,
( unsigned long long ) ino ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" ,INODE:%llu " ,
( unsigned long long ) ino ) ;
2003-10-24 17:01:19 +00:00
}
2005-03-31 05:06:04 +00:00
} else if ( StrCaseCmp ( name , " inode " ) = = 0 ) {
if ( determine_size ) {
p = talloc_asprintf (
ctx ,
" %llu " ,
( unsigned long long ) ino ) ;
if ( ! p ) {
errno = ENOMEM ;
return - 1 ;
}
n = strlen ( p ) ;
} else {
n = snprintf ( buf , bufsize ,
" %llu " ,
( unsigned long long ) ino ) ;
2003-10-24 17:01:19 +00:00
}
}
2005-03-10 23:41:19 +00:00
2005-03-31 05:06:04 +00:00
if ( ! determine_size & & n > bufsize ) {
errno = ERANGE ;
return - 1 ;
}
buf + = n ;
n_used + = n ;
bufsize - = n ;
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
/* Restore name pointer to its original value */
name - = 16 ;
}
2003-10-24 17:01:19 +00:00
if ( n_used = = 0 ) {
errno = ENOATTR ;
return - 1 ;
}
2005-03-10 23:41:19 +00:00
2003-10-24 17:01:19 +00:00
return n_used ;
}
/*****************************************************
set the ACLs on a file given an ascii description
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int cacl_set ( TALLOC_CTX * ctx , struct cli_state * cli ,
struct cli_state * ipc_cli , POLICY_HND * pol ,
const char * filename , const char * the_acl ,
int mode , int flags )
{
int fnum ;
int err = 0 ;
SEC_DESC * sd = NULL , * old ;
SEC_ACL * dacl = NULL ;
DOM_SID * owner_sid = NULL ;
DOM_SID * grp_sid = NULL ;
uint32 i , j ;
size_t sd_size ;
int ret = 0 ;
char * p ;
BOOL numeric = True ;
/* the_acl will be null for REMOVE_ALL operations */
if ( the_acl ) {
numeric = ( ( p = strchr ( the_acl , ' : ' ) ) ! = NULL & &
p > the_acl & &
p [ - 1 ] ! = ' + ' ) ;
/* if this is to set the entire ACL... */
if ( * the_acl = = ' * ' ) {
/* ... then increment past the first colon */
the_acl = p + 1 ;
}
2005-03-31 05:06:04 +00:00
sd = sec_desc_parse ( ctx , ipc_cli , pol , numeric ,
CONST_DISCARD ( char * , the_acl ) ) ;
2003-10-24 17:01:19 +00:00
if ( ! sd ) {
errno = EINVAL ;
return - 1 ;
}
}
/* The desired access below is the only one I could find that works
with NT4 , W2KP and Samba */
fnum = cli_nt_create ( cli , filename , CREATE_ACCESS_READ ) ;
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
if ( fnum = = - 1 ) {
DEBUG ( 5 , ( " cacl_set failed to open %s: %s \n " ,
filename , cli_errstr ( cli ) ) ) ;
errno = 0 ;
return - 1 ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
old = cli_query_secdesc ( cli , fnum , ctx ) ;
if ( ! old ) {
DEBUG ( 5 , ( " cacl_set Failed to query old descriptor \n " ) ) ;
errno = 0 ;
return - 1 ;
2002-07-15 10:35:28 +00:00
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
cli_close ( cli , fnum ) ;
switch ( mode ) {
case SMBC_XATTR_MODE_REMOVE_ALL :
old - > dacl - > num_aces = 0 ;
SAFE_FREE ( old - > dacl - > ace ) ;
SAFE_FREE ( old - > dacl ) ;
old - > off_dacl = 0 ;
dacl = old - > dacl ;
break ;
case SMBC_XATTR_MODE_REMOVE :
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
BOOL found = False ;
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
if ( sec_ace_equal ( & sd - > dacl - > ace [ i ] ,
& old - > dacl - > ace [ j ] ) ) {
uint32 k ;
for ( k = j ; k < old - > dacl - > num_aces - 1 ; k + + ) {
old - > dacl - > ace [ k ] = old - > dacl - > ace [ k + 1 ] ;
}
old - > dacl - > num_aces - - ;
if ( old - > dacl - > num_aces = = 0 ) {
SAFE_FREE ( old - > dacl - > ace ) ;
SAFE_FREE ( old - > dacl ) ;
old - > off_dacl = 0 ;
}
found = True ;
dacl = old - > dacl ;
break ;
}
}
if ( ! found ) {
err = ENOATTR ;
ret = - 1 ;
goto failed ;
}
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
break ;
case SMBC_XATTR_MODE_ADD :
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
BOOL found = False ;
for ( j = 0 ; old - > dacl & & j < old - > dacl - > num_aces ; j + + ) {
if ( sid_equal ( & sd - > dacl - > ace [ i ] . trustee ,
& old - > dacl - > ace [ j ] . trustee ) ) {
if ( ! ( flags & SMBC_XATTR_FLAG_CREATE ) ) {
err = EEXIST ;
ret = - 1 ;
goto failed ;
}
old - > dacl - > ace [ j ] = sd - > dacl - > ace [ i ] ;
ret = - 1 ;
found = True ;
}
}
if ( ! found & & ( flags & SMBC_XATTR_FLAG_REPLACE ) ) {
err = ENOATTR ;
ret = - 1 ;
goto failed ;
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
for ( i = 0 ; sd - > dacl & & i < sd - > dacl - > num_aces ; i + + ) {
add_ace ( & old - > dacl , & sd - > dacl - > ace [ i ] , ctx ) ;
}
2002-07-15 10:35:28 +00:00
}
2003-10-24 17:01:19 +00:00
dacl = old - > dacl ;
break ;
case SMBC_XATTR_MODE_SET :
old = sd ;
owner_sid = old - > owner_sid ;
grp_sid = old - > grp_sid ;
dacl = old - > dacl ;
break ;
case SMBC_XATTR_MODE_CHOWN :
owner_sid = sd - > owner_sid ;
break ;
case SMBC_XATTR_MODE_CHGRP :
grp_sid = sd - > grp_sid ;
break ;
2002-07-15 10:35:28 +00:00
}
2003-04-16 14:45:11 +00:00
2003-10-24 17:01:19 +00:00
/* Denied ACE entries must come before allowed ones */
sort_acl ( old - > dacl ) ;
2001-03-05 13:34:48 +00:00
2003-10-24 17:01:19 +00:00
/* Create new security descriptor and set it */
sd = make_sec_desc ( ctx , old - > revision , SEC_DESC_SELF_RELATIVE ,
owner_sid , grp_sid , NULL , dacl , & sd_size ) ;
fnum = cli_nt_create ( cli , filename ,
WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS ) ;
if ( fnum = = - 1 ) {
DEBUG ( 5 , ( " cacl_set failed to open %s: %s \n " ,
filename , cli_errstr ( cli ) ) ) ;
errno = 0 ;
return - 1 ;
2001-11-21 03:55:59 +00:00
}
2003-04-16 14:45:11 +00:00
2003-10-24 17:01:19 +00:00
if ( ! cli_set_secdesc ( cli , fnum , sd ) ) {
DEBUG ( 5 , ( " ERROR: secdesc set failed: %s \n " , cli_errstr ( cli ) ) ) ;
ret = - 1 ;
}
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
/* Clean up */
2001-02-05 13:02:20 +00:00
2003-10-24 17:01:19 +00:00
failed :
cli_close ( cli , fnum ) ;
if ( err ! = 0 ) {
errno = err ;
}
return ret ;
}
int smbc_setxattr_ctx ( SMBCCTX * context ,
const char * fname ,
const char * name ,
const void * value ,
size_t size ,
int flags )
{
int ret ;
2005-03-10 23:41:19 +00:00
int ret2 ;
2003-10-24 17:01:19 +00:00
SMBCSRV * srv ;
SMBCSRV * ipc_srv ;
fstring server , share , user , password , workgroup ;
pstring path ;
TALLOC_CTX * ctx ;
POLICY_HND pol ;
2005-03-10 23:41:19 +00:00
DOS_ATTR_DESC * dad ;
2003-10-24 17:01:19 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
}
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
2005-03-10 23:41:19 +00:00
DEBUG ( 4 , ( " smbc_setxattr(%s, %s, %.*s) \n " , fname , name , ( int ) size , ( const char * ) value ) ) ;
2003-10-24 17:01:19 +00:00
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
fstrcpy ( workgroup , context - > workgroup ) ;
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
2005-03-10 23:41:19 +00:00
if ( ! srv - > no_nt_session ) {
ipc_srv = smbc_attr_server ( context , server , share ,
workgroup , user , password ,
& pol ) ;
srv - > no_nt_session = True ;
} else {
ipc_srv = NULL ;
2003-10-24 17:01:19 +00:00
}
ctx = talloc_init ( " smbc_setxattr " ) ;
if ( ! ctx ) {
errno = ENOMEM ;
return - 1 ;
}
2005-03-10 23:41:19 +00:00
/*
* Are they asking to set the entire set of known attributes ?
*/
if ( StrCaseCmp ( name , " system.* " ) = = 0 | |
StrCaseCmp ( name , " system.*+ " ) = = 0 ) {
/* Yup. */
char * namevalue =
talloc_asprintf ( ctx , " %s:%s " , name + 7 , ( const char * ) value ) ;
if ( ! namevalue ) {
errno = ENOMEM ;
ret = - 1 ;
return - 1 ;
}
if ( ipc_srv ) {
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
namevalue ,
( * namevalue = = ' * '
? SMBC_XATTR_MODE_SET
: SMBC_XATTR_MODE_ADD ) ,
flags ) ;
} else {
ret = 0 ;
}
/* get a DOS Attribute Descriptor with current attributes */
dad = dos_attr_query ( context , ctx , path , srv ) ;
if ( dad ) {
/* Overwrite old with new, using what was provided */
dos_attr_parse ( context , dad , srv , namevalue ) ;
/* Set the new DOS attributes */
#if 0 /* not yet implemented */
if ( ! cli_setpathinfo ( & srv - > cli , path ,
dad - > c_time ,
dad - > a_time ,
dad - > m_time ,
dad - > mode ) ) {
if ( ! cli_setatr ( & srv - > cli , path ,
dad - > mode , dad - > m_time ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
}
}
# else
if ( ! cli_setatr ( & srv - > cli , path ,
dad - > mode , dad - > m_time ) ) {
errno = smbc_errno ( context , & srv - > cli ) ;
}
# endif
}
/* we only fail if both NT and DOS sets failed */
if ( ret < 0 & & ! dad ) {
ret = - 1 ; /* in case dad was null */
}
else {
ret = 0 ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
2003-10-24 17:01:19 +00:00
/*
* Are they asking to set an access control element or to set
* the entire access control list ?
*/
if ( StrCaseCmp ( name , " system.nt_sec_desc.* " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.*+ " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.revision " ) = = 0 | |
StrnCaseCmp ( name , " system.nt_sec_desc.acl " , 22 ) = = 0 | |
StrnCaseCmp ( name , " system.nt_sec_desc.acl+ " , 23 ) = = 0 ) {
/* Yup. */
char * namevalue =
2005-03-10 23:41:19 +00:00
talloc_asprintf ( ctx , " %s:%s " , name + 19 , ( const char * ) value ) ;
if ( ! ipc_srv ) {
ret = - 1 ; /* errno set by smbc_server() */
}
else if ( ! namevalue ) {
2003-10-24 17:01:19 +00:00
errno = ENOMEM ;
ret = - 1 ;
} else {
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
namevalue ,
( * namevalue = = ' * '
? SMBC_XATTR_MODE_SET
: SMBC_XATTR_MODE_ADD ) ,
flags ) ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
/*
* Are they asking to set the owner ?
*/
if ( StrCaseCmp ( name , " system.nt_sec_desc.owner " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.owner+ " ) = = 0 ) {
/* Yup. */
char * namevalue =
2005-03-10 23:41:19 +00:00
talloc_asprintf ( ctx , " %s:%s " , name + 19 , ( const char * ) value ) ;
if ( ! ipc_srv ) {
ret = - 1 ; /* errno set by smbc_server() */
}
else if ( ! namevalue ) {
2003-10-24 17:01:19 +00:00
errno = ENOMEM ;
ret = - 1 ;
} else {
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
namevalue , SMBC_XATTR_MODE_CHOWN , 0 ) ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
/*
* Are they asking to set the group ?
*/
if ( StrCaseCmp ( name , " system.nt_sec_desc.group " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.group+ " ) = = 0 ) {
/* Yup. */
char * namevalue =
2005-03-10 23:41:19 +00:00
talloc_asprintf ( ctx , " %s:%s " , name + 19 , ( const char * ) value ) ;
if ( ! ipc_srv ) {
/* errno set by smbc_server() */
ret = - 1 ;
}
else if ( ! namevalue ) {
2003-10-24 17:01:19 +00:00
errno = ENOMEM ;
ret = - 1 ;
} else {
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
namevalue , SMBC_XATTR_MODE_CHOWN , 0 ) ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
2005-03-10 23:41:19 +00:00
/*
* Are they asking to set a DOS attribute ?
*/
if ( StrCaseCmp ( name , " system.dos_attr.* " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.mode " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.c_time " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.a_time " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.m_time " ) = = 0 ) {
/* get a DOS Attribute Descriptor with current attributes */
dad = dos_attr_query ( context , ctx , path , srv ) ;
if ( dad ) {
char * namevalue =
talloc_asprintf ( ctx , " %s:%s " , name + 16 , ( const char * ) value ) ;
if ( ! namevalue ) {
errno = ENOMEM ;
ret = - 1 ;
} else {
/* Overwrite old with provided new params */
dos_attr_parse ( context , dad , srv , namevalue ) ;
/* Set the new DOS attributes */
#if 0 /* not yet implemented */
ret2 = cli_setpathinfo ( & srv - > cli , path ,
dad - > c_time ,
dad - > a_time ,
dad - > m_time ,
dad - > mode ) ;
if ( ! ret2 ) {
ret2 = cli_setatr ( & srv - > cli , path ,
dad - > mode ,
dad - > m_time ) ;
if ( ! ret2 ) {
errno = smbc_errno ( context ,
& srv - > cli ) ;
}
}
# else
ret2 = cli_setatr ( & srv - > cli , path ,
dad - > mode , dad - > m_time ) ;
if ( ! ret2 ) {
errno = smbc_errno ( context , & srv - > cli ) ;
}
# endif
/* ret2 has True (success) / False (failure) */
if ( ret2 ) {
ret = 0 ;
} else {
ret = - 1 ;
}
}
} else {
ret = - 1 ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
2003-10-24 17:01:19 +00:00
/* Unsupported attribute name */
talloc_destroy ( ctx ) ;
errno = EINVAL ;
return - 1 ;
}
int smbc_getxattr_ctx ( SMBCCTX * context ,
const char * fname ,
const char * name ,
const void * value ,
size_t size )
{
int ret ;
SMBCSRV * srv ;
SMBCSRV * ipc_srv ;
fstring server , share , user , password , workgroup ;
pstring path ;
TALLOC_CTX * ctx ;
POLICY_HND pol ;
2005-03-10 23:41:19 +00:00
2003-10-24 17:01:19 +00:00
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
}
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
DEBUG ( 4 , ( " smbc_getxattr(%s, %s) \n " , fname , name ) ) ;
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
fstrcpy ( workgroup , context - > workgroup ) ;
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
2005-03-10 23:41:19 +00:00
if ( ! srv - > no_nt_session ) {
ipc_srv = smbc_attr_server ( context , server , share ,
workgroup , user , password ,
& pol ) ;
if ( ! ipc_srv ) {
srv - > no_nt_session = True ;
}
} else {
ipc_srv = NULL ;
2003-10-24 17:01:19 +00:00
}
ctx = talloc_init ( " smbc:getxattr " ) ;
if ( ! ctx ) {
errno = ENOMEM ;
return - 1 ;
}
/* Are they requesting a supported attribute? */
2005-03-10 23:41:19 +00:00
if ( StrCaseCmp ( name , " system.* " ) = = 0 | |
2005-03-31 05:06:04 +00:00
StrnCaseCmp ( name , " system.*! " , 9 ) = = 0 | |
2005-03-10 23:41:19 +00:00
StrCaseCmp ( name , " system.*+ " ) = = 0 | |
2005-03-31 05:06:04 +00:00
StrnCaseCmp ( name , " system.*+! " , 10 ) = = 0 | |
2005-03-10 23:41:19 +00:00
StrCaseCmp ( name , " system.nt_sec_desc.* " ) = = 0 | |
2005-03-31 05:06:04 +00:00
StrnCaseCmp ( name , " system.nt_sec_desc.*! " , 21 ) = = 0 | |
2003-10-24 17:01:19 +00:00
StrCaseCmp ( name , " system.nt_sec_desc.*+ " ) = = 0 | |
2005-03-31 05:06:04 +00:00
StrnCaseCmp ( name , " system.nt_sec_desc.*+! " , 22 ) = = 0 | |
2003-10-24 17:01:19 +00:00
StrCaseCmp ( name , " system.nt_sec_desc.revision " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.owner " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.owner+ " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.group " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.group+ " ) = = 0 | |
StrnCaseCmp ( name , " system.nt_sec_desc.acl " , 22 ) = = 0 | |
2005-03-10 23:41:19 +00:00
StrnCaseCmp ( name , " system.nt_sec_desc.acl+ " , 23 ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.* " ) = = 0 | |
2005-03-31 05:06:04 +00:00
StrnCaseCmp ( name , " system.dos_attr.*! " , 18 ) = = 0 | |
2005-03-10 23:41:19 +00:00
StrCaseCmp ( name , " system.dos_attr.mode " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.size " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.c_time " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.a_time " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.m_time " ) = = 0 | |
StrCaseCmp ( name , " system.dos_attr.inode " ) = = 0 ) {
2003-10-24 17:01:19 +00:00
/* Yup. */
2005-03-10 23:41:19 +00:00
ret = cacl_get ( context , ctx , srv ,
ipc_srv = = NULL ? NULL : & ipc_srv - > cli ,
2005-03-31 05:06:04 +00:00
& pol , path ,
CONST_DISCARD ( char * , name ) ,
CONST_DISCARD ( char * , value ) , size ) ;
2003-10-24 17:01:19 +00:00
if ( ret < 0 & & errno = = 0 ) {
errno = smbc_errno ( context , & srv - > cli ) ;
}
talloc_destroy ( ctx ) ;
return ret ;
}
/* Unsupported attribute name */
talloc_destroy ( ctx ) ;
errno = EINVAL ;
return - 1 ;
}
int smbc_removexattr_ctx ( SMBCCTX * context ,
const char * fname ,
const char * name )
{
int ret ;
SMBCSRV * srv ;
SMBCSRV * ipc_srv ;
fstring server , share , user , password , workgroup ;
pstring path ;
TALLOC_CTX * ctx ;
POLICY_HND pol ;
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ; /* Best I can think of ... */
return - 1 ;
}
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
DEBUG ( 4 , ( " smbc_removexattr(%s, %s) \n " , fname , name ) ) ;
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
fstrcpy ( workgroup , context - > workgroup ) ;
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
2005-03-10 23:41:19 +00:00
if ( ! srv - > no_nt_session ) {
ipc_srv = smbc_attr_server ( context , server , share ,
workgroup , user , password ,
& pol ) ;
srv - > no_nt_session = True ;
} else {
ipc_srv = NULL ;
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
if ( ! ipc_srv ) {
return - 1 ; /* errno set by smbc_attr_server */
2003-10-24 17:01:19 +00:00
}
2005-03-10 23:41:19 +00:00
2003-10-24 17:01:19 +00:00
ctx = talloc_init ( " smbc_removexattr " ) ;
if ( ! ctx ) {
errno = ENOMEM ;
return - 1 ;
}
/* Are they asking to set the entire ACL? */
if ( StrCaseCmp ( name , " system.nt_sec_desc.* " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.*+ " ) = = 0 ) {
/* Yup. */
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
NULL , SMBC_XATTR_MODE_REMOVE_ALL , 0 ) ;
talloc_destroy ( ctx ) ;
return ret ;
}
/*
* Are they asking to remove one or more spceific security descriptor
* attributes ?
*/
if ( StrCaseCmp ( name , " system.nt_sec_desc.revision " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.owner " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.owner+ " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.group " ) = = 0 | |
StrCaseCmp ( name , " system.nt_sec_desc.group+ " ) = = 0 | |
StrnCaseCmp ( name , " system.nt_sec_desc.acl " , 22 ) = = 0 | |
StrnCaseCmp ( name , " system.nt_sec_desc.acl+ " , 23 ) = = 0 ) {
/* Yup. */
ret = cacl_set ( ctx , & srv - > cli ,
& ipc_srv - > cli , & pol , path ,
name + 19 , SMBC_XATTR_MODE_REMOVE , 0 ) ;
talloc_destroy ( ctx ) ;
return ret ;
}
/* Unsupported attribute name */
talloc_destroy ( ctx ) ;
errno = EINVAL ;
return - 1 ;
}
int smbc_listxattr_ctx ( SMBCCTX * context ,
const char * fname ,
char * list ,
size_t size )
{
/*
* This isn ' t quite what listxattr ( ) is supposed to do . This returns
2005-03-10 23:41:19 +00:00
* the complete set of attribute names , always , rather than only those
2003-10-24 17:01:19 +00:00
* attribute names which actually exist for a file . Hmmm . . .
*/
const char supported [ ] =
2005-03-10 23:41:19 +00:00
" system.* \0 "
" system.*+ \0 "
2003-10-24 17:01:19 +00:00
" system.nt_sec_desc.revision \0 "
" system.nt_sec_desc.owner \0 "
" system.nt_sec_desc.owner+ \0 "
" system.nt_sec_desc.group \0 "
" system.nt_sec_desc.group+ \0 "
2005-03-31 05:06:04 +00:00
" system.nt_sec_desc.acl.* \0 "
2003-10-24 17:01:19 +00:00
" system.nt_sec_desc.acl \0 "
" system.nt_sec_desc.acl+ \0 "
" system.nt_sec_desc.* \0 "
" system.nt_sec_desc.*+ \0 "
2005-03-10 23:41:19 +00:00
" system.dos_attr.* \0 "
" system.dos_attr.mode \0 "
" system.dos_attr.c_time \0 "
" system.dos_attr.a_time \0 "
" system.dos_attr.m_time \0 "
2003-10-24 17:01:19 +00:00
;
if ( size = = 0 ) {
return sizeof ( supported ) ;
}
if ( sizeof ( supported ) > size ) {
errno = ERANGE ;
return - 1 ;
}
/* this can't be strcpy() because there are embedded null characters */
memcpy ( list , supported , sizeof ( supported ) ) ;
return sizeof ( supported ) ;
}
/*
* Open a print file to be written to by other calls
*/
static SMBCFILE * smbc_open_print_job_ctx ( SMBCCTX * context , const char * fname )
{
fstring server , share , user , password ;
pstring path ;
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ;
return NULL ;
}
if ( ! fname ) {
errno = EINVAL ;
return NULL ;
}
DEBUG ( 4 , ( " smbc_open_print_job_ctx(%s) \n " , fname ) ) ;
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return NULL ;
}
2003-10-24 17:01:19 +00:00
/* What if the path is empty, or the file exists? */
return context - > open ( context , fname , O_WRONLY , 666 ) ;
}
/*
* Routine to print a file on a remote server . . .
*
* We open the file , which we assume to be on a remote server , and then
* copy it to a print file on the share specified by printq .
*/
static int smbc_print_file_ctx ( SMBCCTX * c_file , const char * fname , SMBCCTX * c_print , const char * printq )
{
SMBCFILE * fid1 , * fid2 ;
int bytes , saverr , tot_bytes = 0 ;
char buf [ 4096 ] ;
if ( ! c_file | | ! c_file - > internal - > _initialized | | ! c_print | |
! c_print - > internal - > _initialized ) {
errno = EINVAL ;
return - 1 ;
}
if ( ! fname & & ! printq ) {
errno = EINVAL ;
return - 1 ;
}
/* Try to open the file for reading ... */
if ( ( int ) ( fid1 = c_file - > open ( c_file , fname , O_RDONLY , 0666 ) ) < 0 ) {
DEBUG ( 3 , ( " Error, fname=%s, errno=%i \n " , fname , errno ) ) ;
return - 1 ; /* smbc_open sets errno */
}
/* Now, try to open the printer file for writing */
if ( ( int ) ( fid2 = c_print - > open_print_job ( c_print , printq ) ) < 0 ) {
saverr = errno ; /* Save errno */
c_file - > close ( c_file , fid1 ) ;
errno = saverr ;
return - 1 ;
}
while ( ( bytes = c_file - > read ( c_file , fid1 , buf , sizeof ( buf ) ) ) > 0 ) {
tot_bytes + = bytes ;
if ( ( c_print - > write ( c_print , fid2 , buf , bytes ) ) < 0 ) {
saverr = errno ;
c_file - > close ( c_file , fid1 ) ;
c_print - > close ( c_print , fid2 ) ;
errno = saverr ;
}
}
saverr = errno ;
c_file - > close ( c_file , fid1 ) ; /* We have to close these anyway */
c_print - > close ( c_print , fid2 ) ;
if ( bytes < 0 ) {
errno = saverr ;
return - 1 ;
}
return tot_bytes ;
}
/*
* Routine to list print jobs on a printer share . . .
*/
static int smbc_list_print_jobs_ctx ( SMBCCTX * context , const char * fname , smbc_list_print_job_fn fn )
{
SMBCSRV * srv ;
fstring server , share , user , password , workgroup ;
pstring path ;
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ;
return - 1 ;
}
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
DEBUG ( 4 , ( " smbc_list_print_jobs(%s) \n " , fname ) ) ;
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
fstrcpy ( workgroup , context - > workgroup ) ;
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
if ( cli_print_queue ( & srv - > cli , ( void ( * ) ( struct print_job_info * ) ) fn ) < 0 ) {
errno = smbc_errno ( context , & srv - > cli ) ;
return - 1 ;
}
return 0 ;
}
/*
* Delete a print job from a remote printer share
*/
static int smbc_unlink_print_job_ctx ( SMBCCTX * context , const char * fname , int id )
{
SMBCSRV * srv ;
fstring server , share , user , password , workgroup ;
pstring path ;
int err ;
if ( ! context | | ! context - > internal | |
! context - > internal - > _initialized ) {
errno = EINVAL ;
return - 1 ;
}
if ( ! fname ) {
errno = EINVAL ;
return - 1 ;
}
DEBUG ( 4 , ( " smbc_unlink_print_job(%s) \n " , fname ) ) ;
2004-03-19 16:22:47 +00:00
if ( smbc_parse_path ( context , fname ,
server , sizeof ( server ) ,
share , sizeof ( share ) ,
path , sizeof ( path ) ,
user , sizeof ( user ) ,
password , sizeof ( password ) ,
NULL , 0 ) ) {
errno = EINVAL ;
return - 1 ;
}
2003-10-24 17:01:19 +00:00
if ( user [ 0 ] = = ( char ) 0 ) fstrcpy ( user , context - > user ) ;
fstrcpy ( workgroup , context - > workgroup ) ;
srv = smbc_server ( context , server , share , workgroup , user , password ) ;
if ( ! srv ) {
return - 1 ; /* errno set by smbc_server */
}
if ( ( err = cli_printjob_del ( & srv - > cli , id ) ) ! = 0 ) {
if ( err < 0 )
errno = smbc_errno ( context , & srv - > cli ) ;
else if ( err = = ERRnosuchprintjob )
errno = EINVAL ;
return - 1 ;
}
return 0 ;
}
/*
* Get a new empty handle to fill in with your own info
*/
SMBCCTX * smbc_new_context ( void )
{
SMBCCTX * context ;
2004-12-07 18:25:53 +00:00
context = SMB_MALLOC_P ( SMBCCTX ) ;
2003-10-24 17:01:19 +00:00
if ( ! context ) {
errno = ENOMEM ;
return NULL ;
}
ZERO_STRUCTP ( context ) ;
2004-12-07 18:25:53 +00:00
context - > internal = SMB_MALLOC_P ( struct smbc_internal_data ) ;
2003-10-24 17:01:19 +00:00
if ( ! context - > internal ) {
errno = ENOMEM ;
return NULL ;
}
ZERO_STRUCTP ( context - > internal ) ;
/* ADD REASONABLE DEFAULTS */
context - > debug = 0 ;
context - > timeout = 20000 ; /* 20 seconds */
2005-03-11 17:01:30 +00:00
context - > options . browse_max_lmb_count = 3 ; /* # LMBs to query */
context - > options . urlencode_readdir_entries = False ; /* backward compat */
context - > options . one_share_per_server = False ; /* backward compat */
2005-03-10 23:41:19 +00:00
context - > open = smbc_open_ctx ;
context - > creat = smbc_creat_ctx ;
context - > read = smbc_read_ctx ;
context - > write = smbc_write_ctx ;
context - > close = smbc_close_ctx ;
context - > unlink = smbc_unlink_ctx ;
context - > rename = smbc_rename_ctx ;
context - > lseek = smbc_lseek_ctx ;
context - > stat = smbc_stat_ctx ;
context - > fstat = smbc_fstat_ctx ;
context - > opendir = smbc_opendir_ctx ;
context - > closedir = smbc_closedir_ctx ;
context - > readdir = smbc_readdir_ctx ;
context - > getdents = smbc_getdents_ctx ;
context - > mkdir = smbc_mkdir_ctx ;
context - > rmdir = smbc_rmdir_ctx ;
context - > telldir = smbc_telldir_ctx ;
context - > lseekdir = smbc_lseekdir_ctx ;
context - > fstatdir = smbc_fstatdir_ctx ;
context - > chmod = smbc_chmod_ctx ;
context - > utimes = smbc_utimes_ctx ;
context - > setxattr = smbc_setxattr_ctx ;
context - > getxattr = smbc_getxattr_ctx ;
context - > removexattr = smbc_removexattr_ctx ;
context - > listxattr = smbc_listxattr_ctx ;
context - > open_print_job = smbc_open_print_job_ctx ;
context - > print_file = smbc_print_file_ctx ;
context - > list_print_jobs = smbc_list_print_jobs_ctx ;
context - > unlink_print_job = smbc_unlink_print_job_ctx ;
context - > callbacks . check_server_fn = smbc_check_server ;
2003-10-24 17:01:19 +00:00
context - > callbacks . remove_unused_server_fn = smbc_remove_unused_server ;
smbc_default_cache_functions ( context ) ;
return context ;
}
/*
* Free a context
*
* Returns 0 on success . Otherwise returns 1 , the SMBCCTX is _not_ freed
* and thus you ' ll be leaking memory if not handled properly .
*
*/
int smbc_free_context ( SMBCCTX * context , int shutdown_ctx )
{
if ( ! context ) {
errno = EBADF ;
return 1 ;
}
if ( shutdown_ctx ) {
SMBCFILE * f ;
DEBUG ( 1 , ( " Performing aggressive shutdown. \n " ) ) ;
f = context - > internal - > _files ;
while ( f ) {
context - > close ( context , f ) ;
f = f - > next ;
}
context - > internal - > _files = NULL ;
/* First try to remove the servers the nice way. */
if ( context - > callbacks . purge_cached_fn ( context ) ) {
SMBCSRV * s ;
2004-03-19 16:22:47 +00:00
SMBCSRV * next ;
2003-10-24 17:01:19 +00:00
DEBUG ( 1 , ( " Could not purge all servers, Nice way shutdown failed. \n " ) ) ;
s = context - > internal - > _servers ;
while ( s ) {
2004-03-19 16:22:47 +00:00
DEBUG ( 1 , ( " Forced shutdown: %p (fd=%d) \n " , s , s - > cli . fd ) ) ;
2003-10-24 17:01:19 +00:00
cli_shutdown ( & s - > cli ) ;
context - > callbacks . remove_cached_srv_fn ( context , s ) ;
2004-03-19 16:22:47 +00:00
next = s - > next ;
DLIST_REMOVE ( context - > internal - > _servers , s ) ;
2003-10-24 17:01:19 +00:00
SAFE_FREE ( s ) ;
2004-03-19 16:22:47 +00:00
s = next ;
2003-10-24 17:01:19 +00:00
}
context - > internal - > _servers = NULL ;
}
}
else {
/* This is the polite way */
if ( context - > callbacks . purge_cached_fn ( context ) ) {
DEBUG ( 1 , ( " Could not purge all servers, free_context failed. \n " ) ) ;
errno = EBUSY ;
return 1 ;
}
if ( context - > internal - > _servers ) {
DEBUG ( 1 , ( " Active servers in context, free_context failed. \n " ) ) ;
errno = EBUSY ;
return 1 ;
}
if ( context - > internal - > _files ) {
DEBUG ( 1 , ( " Active files in context, free_context failed. \n " ) ) ;
errno = EBUSY ;
return 1 ;
}
}
/* Things we have to clean up */
SAFE_FREE ( context - > workgroup ) ;
SAFE_FREE ( context - > netbios_name ) ;
SAFE_FREE ( context - > user ) ;
DEBUG ( 3 , ( " Context %p succesfully freed \n " , context ) ) ;
SAFE_FREE ( context - > internal ) ;
SAFE_FREE ( context ) ;
return 0 ;
}
/*
* Initialise the library etc
*
* We accept a struct containing handle information .
* valid values for info - > debug from 0 to 100 ,
* and insist that info - > fn must be non - null .
*/
SMBCCTX * smbc_init_context ( SMBCCTX * context )
{
pstring conf ;
int pid ;
char * user = NULL , * home = NULL ;
if ( ! context | | ! context - > internal ) {
errno = EBADF ;
return NULL ;
}
/* Do not initialise the same client twice */
if ( context - > internal - > _initialized ) {
return 0 ;
}
if ( ! context - > callbacks . auth_fn | | context - > debug < 0 | | context - > debug > 100 ) {
errno = EINVAL ;
return NULL ;
}
if ( ! smbc_initialized ) {
/* Do some library wide intialisations the first time we get called */
/* Set this to what the user wants */
DEBUGLEVEL = context - > debug ;
setup_logging ( " libsmbclient " , True ) ;
/* Here we would open the smb.conf file if needed ... */
home = getenv ( " HOME " ) ;
slprintf ( conf , sizeof ( conf ) , " %s/.smb/smb.conf " , home ) ;
load_interfaces ( ) ; /* Load the list of interfaces ... */
in_client = True ; /* FIXME, make a param */
if ( ! lp_load ( conf , True , False , False ) ) {
/*
* Well , if that failed , try the dyn_CONFIGFILE
* Which points to the standard locn , and if that
* fails , silently ignore it and use the internal
* defaults . . .
*/
2005-03-31 20:28:47 +00:00
if ( ! lp_load ( dyn_CONFIGFILE , True , False , False ) ) {
DEBUG ( 5 , ( " Could not load either config file: "
" %s or %s \n " ,
conf , dyn_CONFIGFILE ) ) ;
} else {
/*
* We loaded the global config file . Now lets
* load user - specific modifications to the
* global config .
*/
slprintf ( conf , sizeof ( conf ) ,
" %s/.smb/smb.conf.append " , home ) ;
if ( ! lp_load ( conf , True , False , False ) ) {
DEBUG ( 10 ,
( " Could not append config file: "
" %s \n " ,
conf ) ) ;
}
}
2003-10-24 17:01:19 +00:00
}
reopen_logs ( ) ; /* Get logging working ... */
/*
* Block SIGPIPE ( from lib / util_sock . c : write ( ) )
* It is not needed and should not stop execution
*/
BlockSignals ( True , SIGPIPE ) ;
/* Done with one-time initialisation */
smbc_initialized = 1 ;
}
if ( ! context - > user ) {
/*
* FIXME : Is this the best way to get the user info ?
*/
user = getenv ( " USER " ) ;
/* walk around as "guest" if no username can be found */
2004-12-07 18:25:53 +00:00
if ( ! user ) context - > user = SMB_STRDUP ( " guest " ) ;
else context - > user = SMB_STRDUP ( user ) ;
2003-10-24 17:01:19 +00:00
}
if ( ! context - > netbios_name ) {
/*
* We try to get our netbios name from the config . If that fails we fall
* back on constructing our netbios name from our hostname etc
*/
if ( global_myname ( ) ) {
2004-12-07 18:25:53 +00:00
context - > netbios_name = SMB_STRDUP ( global_myname ( ) ) ;
2003-10-24 17:01:19 +00:00
}
else {
/*
* Hmmm , I want to get hostname as well , but I am too lazy for the moment
*/
pid = sys_getpid ( ) ;
2004-12-07 18:25:53 +00:00
context - > netbios_name = SMB_MALLOC ( 17 ) ;
2003-10-24 17:01:19 +00:00
if ( ! context - > netbios_name ) {
errno = ENOMEM ;
return NULL ;
}
slprintf ( context - > netbios_name , 16 , " smbc%s%d " , context - > user , pid ) ;
}
}
DEBUG ( 1 , ( " Using netbios name %s. \n " , context - > netbios_name ) ) ;
if ( ! context - > workgroup ) {
if ( lp_workgroup ( ) ) {
2004-12-07 18:25:53 +00:00
context - > workgroup = SMB_STRDUP ( lp_workgroup ( ) ) ;
2003-10-24 17:01:19 +00:00
}
else {
/* TODO: Think about a decent default workgroup */
2004-12-07 18:25:53 +00:00
context - > workgroup = SMB_STRDUP ( " samba " ) ;
2003-10-24 17:01:19 +00:00
}
}
DEBUG ( 1 , ( " Using workgroup %s. \n " , context - > workgroup ) ) ;
/* shortest timeout is 1 second */
if ( context - > timeout > 0 & & context - > timeout < 1000 )
context - > timeout = 1000 ;
/*
* FIXME : Should we check the function pointers here ?
*/
context - > internal - > _initialized = 1 ;
return context ;
2001-02-05 13:02:20 +00:00
}
2005-03-10 23:41:19 +00:00
/* Return the verion of samba, and thus libsmbclient */
const char *
smbc_version ( void )
{
return samba_version_string ( ) ;
}