2008-03-07 19:37:07 +03:00
/*
2008-02-28 19:23:20 +03:00
Unix SMB / Netbios implementation .
SMB client library implementation
Copyright ( C ) Andrew Tridgell 1998
Copyright ( C ) Richard Sharpe 2000 , 2002
Copyright ( C ) John Terpstra 2000
2008-03-07 19:37:07 +03:00
Copyright ( C ) Tom Jansen ( Ninja ISD ) 2002
2008-02-28 19:23:20 +03:00
Copyright ( C ) Derrell Lipman 2003 - 2008
Copyright ( C ) Jeremy Allison 2007 , 2008
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03: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 3 of the License , or
( at your option ) any later version .
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
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 .
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2018-03-10 17:31:11 +03:00
# include "libsmb/namequery.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2012-01-30 13:53:18 +04:00
# include "auth_info.h"
2008-02-28 19:23:20 +03:00
# include "libsmbclient.h"
# include "libsmb_internal.h"
2011-02-28 12:19:44 +03:00
# include "rpc_client/cli_pipe.h"
2011-01-12 14:58:44 +03:00
# include "../librpc/gen_ndr/ndr_srvsvc_c.h"
2011-03-23 16:18:59 +03:00
# include "libsmb/nmblib.h"
2012-05-19 19:31:50 +04:00
# include "../libcli/smb/smbXcli_base.h"
2015-06-26 14:36:43 +03:00
# include "../libcli/security/security.h"
# include "lib/util/tevent_ntstatus.h"
2020-03-30 22:43:51 +03:00
# include "lib/util/time_basic.h"
2008-02-28 19:23:20 +03:00
/*
* Routine to open a directory
* We accept the URL syntax explained in SMBC_parse_path ( ) , above .
*/
2018-04-07 00:17:35 +03:00
static void remove_dirplus ( SMBCFILE * dir )
{
struct smbc_dirplus_list * d = NULL ;
d = dir - > dirplus_list ;
while ( d ! = NULL ) {
struct smbc_dirplus_list * f = d ;
d = d - > next ;
SAFE_FREE ( f - > smb_finfo - > short_name ) ;
SAFE_FREE ( f - > smb_finfo - > name ) ;
SAFE_FREE ( f - > smb_finfo ) ;
SAFE_FREE ( f ) ;
}
dir - > dirplus_list = NULL ;
dir - > dirplus_end = NULL ;
dir - > dirplus_next = NULL ;
}
2008-02-28 19:23:20 +03:00
static void
remove_dir ( SMBCFILE * dir )
{
struct smbc_dir_list * d , * f ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
d = dir - > dir_list ;
while ( d ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
f = d ; d = d - > next ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( f - > dirent ) ;
SAFE_FREE ( f ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_list = dir - > dir_end = dir - > dir_next = NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
static int
add_dirent ( SMBCFILE * dir ,
const char * name ,
const char * comment ,
2015-05-10 02:59:45 +03:00
uint32_t type )
2008-02-28 19:23:20 +03:00
{
struct smbc_dirent * dirent ;
int size ;
int name_length = ( name = = NULL ? 0 : strlen ( name ) ) ;
int comment_len = ( comment = = NULL ? 0 : strlen ( comment ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
2008-03-07 19:37:07 +03:00
* Allocate space for the dirent , which must be increased by the
2008-02-28 19:23:20 +03:00
* size of the name and the comment and 1 each for the null terminator .
*/
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
size = sizeof ( struct smbc_dirent ) + name_length + comment_len + 2 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dirent = ( struct smbc_dirent * ) SMB_MALLOC ( size ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! dirent ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_error = ENOMEM ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCTP ( dirent ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > dir_list = = NULL ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_list = SMB_MALLOC_P ( struct smbc_dir_list ) ;
if ( ! dir - > dir_list ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( dirent ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
ZERO_STRUCTP ( dir - > dir_list ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_end = dir - > dir_next = dir - > dir_list ;
}
else {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_end - > next = SMB_MALLOC_P ( struct smbc_dir_list ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! dir - > dir_end - > next ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( dirent ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
ZERO_STRUCTP ( dir - > dir_end - > next ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_end = dir - > dir_end - > next ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_end - > next = NULL ;
dir - > dir_end - > dirent = dirent ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dirent - > smbc_type = type ;
dirent - > namelen = name_length ;
dirent - > commentlen = comment_len ;
dirent - > dirlen = size ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* dirent - > namelen + 1 includes the null ( no null termination needed )
* Ditto for dirent - > commentlen .
* The space for the two null bytes was allocated .
*/
strncpy ( dirent - > name , ( name ? name : " " ) , dirent - > namelen + 1 ) ;
dirent - > comment = ( char * ) ( & dirent - > name + dirent - > namelen + 1 ) ;
strncpy ( dirent - > comment , ( comment ? comment : " " ) , dirent - > commentlen + 1 ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2018-04-07 00:50:39 +03:00
static int add_dirplus ( SMBCFILE * dir , struct file_info * finfo )
{
struct smbc_dirplus_list * new_entry = NULL ;
struct libsmb_file_info * info = NULL ;
new_entry = SMB_MALLOC_P ( struct smbc_dirplus_list ) ;
if ( new_entry = = NULL ) {
dir - > dir_error = ENOMEM ;
return - 1 ;
}
ZERO_STRUCTP ( new_entry ) ;
2019-10-18 19:45:33 +03:00
new_entry - > ino = finfo - > ino ;
2018-04-07 00:50:39 +03:00
info = SMB_MALLOC_P ( struct libsmb_file_info ) ;
if ( info = = NULL ) {
SAFE_FREE ( new_entry ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
}
ZERO_STRUCTP ( info ) ;
info - > btime_ts = finfo - > btime_ts ;
info - > atime_ts = finfo - > atime_ts ;
info - > ctime_ts = finfo - > ctime_ts ;
info - > mtime_ts = finfo - > mtime_ts ;
info - > gid = finfo - > gid ;
info - > attrs = finfo - > mode ;
info - > size = finfo - > size ;
info - > uid = finfo - > uid ;
info - > name = SMB_STRDUP ( finfo - > name ) ;
if ( info - > name = = NULL ) {
SAFE_FREE ( info ) ;
SAFE_FREE ( new_entry ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
}
if ( finfo - > short_name ) {
info - > short_name = SMB_STRDUP ( finfo - > short_name ) ;
} else {
info - > short_name = SMB_STRDUP ( " " ) ;
}
if ( info - > short_name = = NULL ) {
SAFE_FREE ( info - > name ) ;
SAFE_FREE ( info ) ;
SAFE_FREE ( new_entry ) ;
dir - > dir_error = ENOMEM ;
return - 1 ;
}
new_entry - > smb_finfo = info ;
/* Now add to the list. */
if ( dir - > dirplus_list = = NULL ) {
/* Empty list - point everything at new_entry. */
dir - > dirplus_list = new_entry ;
dir - > dirplus_end = new_entry ;
dir - > dirplus_next = new_entry ;
} else {
/* Append to list but leave the ->next cursor alone. */
dir - > dirplus_end - > next = new_entry ;
dir - > dirplus_end = new_entry ;
}
return 0 ;
}
2008-02-28 19:23:20 +03:00
static void
list_unique_wg_fn ( const char * name ,
2015-05-10 02:59:45 +03:00
uint32_t type ,
2008-02-28 19:23:20 +03:00
const char * comment ,
void * state )
{
SMBCFILE * dir = ( SMBCFILE * ) state ;
struct smbc_dir_list * dir_list ;
struct smbc_dirent * dirent ;
int dirent_type ;
int do_remove = 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dirent_type = dir - > dir_type ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( add_dirent ( dir , name , comment , dirent_type ) < 0 ) {
/* An error occurred, what do we do? */
/* FIXME: Add some code here */
2010-10-29 22:56:51 +04:00
/* Change cli_NetServerEnum to take a fn
returning NTSTATUS . . . JRA . */
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Point to the one just added */
dirent = dir - > dir_end - > dirent ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* See if this was a duplicate */
for ( dir_list = dir - > dir_list ;
dir_list ! = dir - > dir_end ;
dir_list = dir_list - > next ) {
if ( ! do_remove & &
strcmp ( dir_list - > dirent - > name , dirent - > name ) = = 0 ) {
/* Duplicate. End end of list need to be removed. */
do_remove = 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( do_remove & & dir_list - > next = = dir - > dir_end ) {
/* Found the end of the list. Remove it. */
dir - > dir_end = dir_list ;
free ( dir_list - > next ) ;
free ( dirent ) ;
dir_list - > next = NULL ;
break ;
}
}
}
static void
list_fn ( const char * name ,
2015-05-10 02:59:45 +03:00
uint32_t type ,
2008-02-28 19:23:20 +03:00
const char * comment ,
void * state )
{
SMBCFILE * dir = ( SMBCFILE * ) state ;
int dirent_type ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* We need to process the type a little . . .
*
* Disk share = 0x00000000
* Print share = 0x00000001
* Comms share = 0x00000002 ( obsolete ? )
* IPC $ share = 0x00000003
*
* administrative shares :
* ADMIN $ , IPC $ , C $ , D $ , E $ . . . are type | = 0x80000000
*/
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > dir_type = = SMBC_FILE_SHARE ) {
switch ( type ) {
case 0 | 0x80000000 :
case 0 :
dirent_type = SMBC_FILE_SHARE ;
break ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
case 1 :
dirent_type = SMBC_PRINTER_SHARE ;
break ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
case 2 :
dirent_type = SMBC_COMMS_SHARE ;
break ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
case 3 | 0x80000000 :
case 3 :
dirent_type = SMBC_IPC_SHARE ;
break ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
default :
dirent_type = SMBC_FILE_SHARE ; /* FIXME, error? */
break ;
}
}
else {
dirent_type = dir - > dir_type ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( add_dirent ( dir , name , comment , dirent_type ) < 0 ) {
/* An error occurred, what do we do? */
/* FIXME: Add some code here */
2010-10-29 22:56:51 +04:00
/* Change cli_NetServerEnum to take a fn
returning NTSTATUS . . . JRA . */
2008-02-28 19:23:20 +03:00
}
}
2010-10-29 22:56:51 +04:00
static NTSTATUS
2008-02-28 19:23:20 +03:00
dir_list_fn ( const char * mnt ,
2010-07-27 12:59:55 +04:00
struct file_info * finfo ,
2008-02-28 19:23:20 +03:00
const char * mask ,
void * state )
{
2018-04-07 00:50:39 +03:00
SMBCFILE * dirp = ( SMBCFILE * ) state ;
int ret ;
2008-03-07 19:37:07 +03:00
if ( add_dirent ( ( SMBCFILE * ) state , finfo - > name , " " ,
2011-04-29 05:57:02 +04:00
( finfo - > mode & FILE_ATTRIBUTE_DIRECTORY ? SMBC_DIR : SMBC_FILE ) ) < 0 ) {
2010-10-29 22:56:51 +04:00
SMBCFILE * dir = ( SMBCFILE * ) state ;
return map_nt_error_from_unix ( dir - > dir_error ) ;
2008-03-07 19:37:07 +03:00
}
2018-04-07 00:50:39 +03:00
ret = add_dirplus ( dirp , finfo ) ;
if ( ret < 0 ) {
return map_nt_error_from_unix ( dirp - > dir_error ) ;
}
2010-10-29 22:56:51 +04:00
return NT_STATUS_OK ;
2008-02-28 19:23:20 +03:00
}
2019-11-01 00:38:35 +03:00
static NTSTATUS
2008-02-28 19:23:20 +03:00
net_share_enum_rpc ( struct cli_state * cli ,
void ( * fn ) ( const char * name ,
2015-05-10 02:59:45 +03:00
uint32_t type ,
2008-02-28 19:23:20 +03:00
const char * comment ,
void * state ) ,
void * state )
{
2020-04-20 10:56:51 +03:00
uint32_t i ;
2008-02-28 19:23:20 +03:00
WERROR result ;
2015-05-10 02:59:45 +03:00
uint32_t preferred_len = 0xffffffff ;
uint32_t type ;
2008-03-10 06:58:43 +03:00
struct srvsvc_NetShareInfoCtr info_ctr ;
struct srvsvc_NetShareCtr1 ctr1 ;
2008-02-28 19:23:20 +03:00
fstring name = " " ;
fstring comment = " " ;
2009-11-13 00:56:33 +03:00
struct rpc_pipe_client * pipe_hnd = NULL ;
2008-02-28 19:23:20 +03:00
NTSTATUS nt_status ;
2008-03-10 06:58:43 +03:00
uint32_t resume_handle = 0 ;
uint32_t total_entries = 0 ;
2011-01-12 14:58:44 +03:00
struct dcerpc_binding_handle * b ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Open the server service pipe */
2013-05-24 15:29:28 +04:00
nt_status = cli_rpc_pipe_open_noauth ( cli , & ndr_table_srvsvc ,
2008-07-20 13:04:31 +04:00
& pipe_hnd ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
2008-02-28 19:23:20 +03:00
DEBUG ( 1 , ( " net_share_enum_rpc pipe open fail! \n " ) ) ;
2019-11-01 00:38:35 +03:00
goto done ;
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-03-10 06:58:43 +03:00
ZERO_STRUCT ( info_ctr ) ;
ZERO_STRUCT ( ctr1 ) ;
info_ctr . level = 1 ;
info_ctr . ctr . ctr1 = & ctr1 ;
2011-01-12 14:58:44 +03:00
b = pipe_hnd - > binding_handle ;
2008-02-28 19:23:20 +03:00
/* Issue the NetShareEnum RPC call and retrieve the response */
2011-01-12 14:58:44 +03:00
nt_status = dcerpc_srvsvc_NetShareEnumAll ( b , talloc_tos ( ) ,
2008-04-19 23:56:43 +04:00
pipe_hnd - > desthost ,
2008-03-10 06:58:43 +03:00
& info_ctr ,
preferred_len ,
& total_entries ,
& resume_handle ,
& result ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Was it successful? */
2011-01-12 14:58:44 +03:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
/* Nope. Go clean up. */
goto done ;
}
if ( ! W_ERROR_IS_OK ( result ) ) {
2008-02-28 19:23:20 +03:00
/* Nope. Go clean up. */
2019-11-01 00:38:35 +03:00
nt_status = werror_to_ntstatus ( result ) ;
2008-02-28 19:23:20 +03:00
goto done ;
}
2008-03-07 19:37:07 +03:00
2011-01-12 14:58:44 +03:00
if ( total_entries = = 0 ) {
/* Nope. Go clean up. */
2019-11-01 00:38:35 +03:00
nt_status = NT_STATUS_NOT_FOUND ;
2011-01-12 14:58:44 +03:00
goto done ;
}
2008-02-28 19:23:20 +03:00
/* For each returned entry... */
2010-01-16 15:31:44 +03:00
for ( i = 0 ; i < info_ctr . ctr . ctr1 - > count ; i + + ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* pull out the share name */
2008-03-10 06:58:43 +03:00
fstrcpy ( name , info_ctr . ctr . ctr1 - > array [ i ] . name ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* pull out the share's comment */
2008-03-10 06:58:43 +03:00
fstrcpy ( comment , info_ctr . ctr . ctr1 - > array [ i ] . comment ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Get the type value */
2008-03-10 06:58:43 +03:00
type = info_ctr . ctr . ctr1 - > array [ i ] . type ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Add this share to the list */
( * fn ) ( name , type , comment , state ) ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
done :
/* Close the server service pipe */
2008-04-20 15:51:46 +04:00
TALLOC_FREE ( pipe_hnd ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Tell 'em if it worked */
2019-11-01 00:38:35 +03:00
return nt_status ;
2008-02-28 19:23:20 +03:00
}
/*
* Verify that the options specified in a URL are valid
*/
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 ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* No options at all is always ok */
if ( ! * options ) return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Currently, we don't support any options. */
return - 1 ;
}
SMBCFILE *
SMBC_opendir_ctx ( SMBCCTX * context ,
const char * fname )
{
int saved_errno ;
2008-03-02 04:44:21 +03:00
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * options = NULL ;
2008-02-28 19:23:20 +03:00
char * workgroup = NULL ;
char * path = NULL ;
2017-07-22 19:36:18 +03:00
size_t path_len = 0 ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
SMBCSRV * srv = NULL ;
SMBCFILE * dir = NULL ;
struct sockaddr_storage rem_ss ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " no valid context \n " ) ) ;
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8192 ;
2008-02-28 19:23:20 +03:00
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
DEBUG ( 4 , ( " no valid fname \n " ) ) ;
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8193 ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
& options ) ) {
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " no valid path \n " ) ) ;
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8194 ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " parsed path: fname='%s' server='%s' share='%s' "
" path='%s' options='%s' \n " ,
fname , server , share , path , options ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Ensure the options are valid */
if ( SMBC_check_options ( server , share , path , options ) ) {
DEBUG ( 4 , ( " unacceptable options (%s) \n " , options ) ) ;
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8195 ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = ENOMEM ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir = SMB_MALLOC_P ( SMBCFILE ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! dir ) {
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = ENOMEM ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
ZERO_STRUCTP ( dir ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > cli_fd = 0 ;
dir - > fname = SMB_STRDUP ( fname ) ;
2020-02-22 00:07:19 +03:00
if ( dir - > fname = = NULL ) {
SAFE_FREE ( dir ) ;
TALLOC_FREE ( frame ) ;
errno = ENOMEM ;
return NULL ;
}
2008-02-28 19:23:20 +03:00
dir - > srv = NULL ;
dir - > offset = 0 ;
dir - > file = False ;
dir - > dir_list = dir - > dir_next = dir - > dir_end = NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( server [ 0 ] = = ( char ) 0 ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
int i ;
int count ;
int max_lmb_count ;
2011-04-30 21:23:55 +04:00
struct sockaddr_storage * ip_list ;
struct sockaddr_storage server_addr ;
2016-10-21 11:17:59 +03:00
struct user_auth_info * u_info ;
2011-04-30 21:23:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( share [ 0 ] ! = ( char ) 0 | | path [ 0 ] ! = ( char ) 0 ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8196 ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Determine how many local master browsers to query */
2008-03-04 02:13:33 +03:00
max_lmb_count = ( smbc_getOptionBrowseMaxLmbCount ( context ) = = 0
2008-02-28 19:23:20 +03:00
? INT_MAX
2008-03-04 02:13:33 +03:00
: smbc_getOptionBrowseMaxLmbCount ( context ) ) ;
2008-03-07 19:37:07 +03:00
2016-10-21 11:17:59 +03:00
u_info = user_auth_info_init ( frame ) ;
if ( u_info = = NULL ) {
2016-10-25 19:25:02 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
errno = ENOMEM ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2016-10-21 11:17:59 +03:00
set_cmdline_auth_info_username ( u_info , user ) ;
set_cmdline_auth_info_password ( u_info , password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* 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 .
*/
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
ip_list = NULL ;
2011-04-30 21:23:55 +04:00
status = name_resolve_bcast ( MSBROWSE , 1 , talloc_tos ( ) ,
& ip_list , & count ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
2008-02-28 19:23:20 +03:00
{
2008-03-07 19:37:07 +03:00
2011-04-30 21:23:55 +04:00
TALLOC_FREE ( ip_list ) ;
2008-03-07 19:37:07 +03:00
2011-04-30 21:23:55 +04:00
if ( ! find_master_ip ( workgroup , & server_addr ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2011-04-30 21:23:55 +04:00
ip_list = ( struct sockaddr_storage * ) talloc_memdup (
talloc_tos ( ) , & server_addr ,
sizeof ( server_addr ) ) ;
2008-02-28 19:23:20 +03:00
if ( ip_list = = NULL ) {
2011-04-22 11:51:42 +04:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = ENOMEM ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
count = 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
for ( i = 0 ; i < count & & i < max_lmb_count ; i + + ) {
char addr [ INET6_ADDRSTRLEN ] ;
char * wg_ptr = NULL ;
struct cli_state * cli = NULL ;
2008-03-07 19:37:07 +03:00
2011-04-30 21:23:55 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & ip_list [ i ] ) ;
2008-02-28 19:23:20 +03:00
DEBUG ( 99 , ( " Found master browser %d of %d: %s \n " ,
i + 1 , MAX ( count , max_lmb_count ) ,
addr ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
cli = get_ipc_connect_master_ip ( talloc_tos ( ) ,
2011-04-30 21:23:55 +04:00
& ip_list [ i ] ,
2016-10-21 11:17:59 +03:00
u_info ,
2008-02-28 19:23:20 +03:00
& wg_ptr ) ;
/* cli == NULL is the master browser refused to talk or
could not be found */
if ( ! cli ) {
continue ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
workgroup = talloc_strdup ( frame , wg_ptr ) ;
2012-05-19 19:31:50 +04:00
server = talloc_strdup ( frame , smbXcli_conn_remote_name ( cli - > conn ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
cli_shutdown ( cli ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! workgroup | | ! server ) {
2011-03-24 17:59:55 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = ENOMEM ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " using workgroup %s %s \n " ,
workgroup , server ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* 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 .
*/
2008-03-07 19:37:07 +03:00
2013-04-17 01:11:08 +04:00
srv = SMBC_server ( frame , context , True , server , port , " IPC$ " ,
2008-02-28 19:23:20 +03:00
& workgroup , & user , & password ) ;
if ( ! srv ) {
continue ;
}
2008-03-07 19:37:07 +03:00
2017-08-16 13:38:30 +03:00
if ( smbXcli_conn_protocol ( srv - > cli - > conn ) > PROTOCOL_NT1 ) {
continue ;
}
2008-02-28 19:23:20 +03:00
dir - > srv = srv ;
dir - > dir_type = SMBC_WORKGROUP ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Now, list the stuff ... */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! cli_NetServerEnum ( srv - > cli ,
workgroup ,
SV_TYPE_DOMAIN_ENUM ,
list_unique_wg_fn ,
( void * ) dir ) ) {
continue ;
}
}
2008-03-07 19:37:07 +03:00
2011-04-30 21:23:55 +04:00
TALLOC_FREE ( ip_list ) ;
2008-02-28 19:23:20 +03:00
} else {
/*
* Server not an empty string . . . Check the rest and see what
* gives
*/
if ( * share = = ' \0 ' ) {
if ( * path ! = ' \0 ' ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Should not have empty share with path */
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EINVAL + 8197 ;
2008-02-28 19:23:20 +03:00
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* We don ' t know if < server > is really a server name
* or is a workgroup / domain name . If we already have
* a server structure for it , we ' ll use it .
* Otherwise , check to see if < server > < 1 D > ,
* < server > < 1 B > , or < server > < 20 > translates . We check
* to see if < server > is an IP address first .
*/
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* See if we have an existing server . Do not
* establish a connection if one does not already
* exist .
*/
2008-03-02 04:44:21 +03:00
srv = SMBC_server ( frame , context , False ,
2013-04-17 01:11:08 +04:00
server , port , " IPC$ " ,
2008-02-28 19:23:20 +03:00
& workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* If no existing server and not an IP addr , look for
* LMB or DMB
*/
if ( ! srv & &
! is_ipaddress ( server ) & &
2009-07-28 22:51:58 +04:00
( resolve_name ( server , & rem_ss , 0x1d , false ) | | /* LMB */
resolve_name ( server , & rem_ss , 0x1b , false ) ) ) { /* DMB */
2009-11-09 23:44:47 +03:00
/*
* " server " is actually a workgroup name ,
* not a server . Make this clear .
*/
char * wgroup = server ;
2008-02-28 19:23:20 +03:00
fstring buserver ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_type = SMBC_SERVER ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* Get the backup list . . .
*/
2009-11-09 23:44:47 +03:00
if ( ! name_status_find ( wgroup , 0 , 0 ,
2008-02-28 19:23:20 +03:00
& rem_ss , buserver ) ) {
2009-11-09 23:44:47 +03:00
char addr [ INET6_ADDRSTRLEN ] ;
2008-03-07 19:37:07 +03:00
2009-11-09 23:44:47 +03:00
print_sockaddr ( addr , sizeof ( addr ) , & rem_ss ) ;
2008-03-02 04:44:21 +03:00
DEBUG ( 0 , ( " Could not get name of "
2009-11-09 23:44:47 +03:00
" local/domain master browser "
" for workgroup %s from "
" address %s \n " ,
wgroup ,
addr ) ) ;
2008-02-28 19:23:20 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = EPERM ;
2008-02-28 19:23:20 +03:00
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* Get a connection to IPC $ on the server if
* we do not already have one
*/
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
buserver , port , " IPC$ " ,
2008-03-02 04:44:21 +03:00
& workgroup ,
& user , & password ) ;
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
DEBUG ( 0 , ( " got no contact to IPC$ \n " ) ) ;
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > srv = srv ;
2008-03-07 19:37:07 +03:00
2017-08-16 13:38:30 +03:00
if ( smbXcli_conn_protocol ( srv - > cli - > conn ) > PROTOCOL_NT1 ) {
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-02-28 19:23:20 +03:00
/* Now, list the servers ... */
2009-11-09 23:44:47 +03:00
if ( ! cli_NetServerEnum ( srv - > cli , wgroup ,
2008-02-28 19:23:20 +03:00
0x0000FFFE , list_fn ,
( void * ) dir ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
} else if ( srv | |
2009-07-28 22:51:58 +04:00
( resolve_name ( server , & rem_ss , 0x20 , false ) ) ) {
2019-11-01 00:38:35 +03:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-03-02 04:44:21 +03:00
/*
* If we hadn ' t found the server , get one now
*/
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , " IPC$ " ,
2008-02-28 19:23:20 +03:00
& workgroup ,
& user , & password ) ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_type = SMBC_FILE_SHARE ;
dir - > srv = srv ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* List the shares ... */
2008-03-07 19:37:07 +03:00
2019-11-01 00:38:35 +03:00
status = net_share_enum_rpc ( srv - > cli ,
2018-09-04 17:08:58 +03:00
list_fn ,
( void * ) dir ) ;
2019-11-01 00:38:35 +03:00
if ( ! NT_STATUS_IS_OK ( status ) & &
2019-10-29 22:11:01 +03:00
smbXcli_conn_protocol ( srv - > cli - > conn ) < =
PROTOCOL_NT1 ) {
/*
* Only call cli_RNetShareEnum ( )
* on SMB1 connections , not SMB2 + .
*/
2019-11-01 00:38:35 +03:00
int rc = cli_RNetShareEnum ( srv - > cli ,
2018-09-04 17:08:58 +03:00
list_fn ,
( void * ) dir ) ;
2019-11-01 00:38:35 +03:00
if ( rc ! = 0 ) {
status = cli_nt_error ( srv - > cli ) ;
} else {
status = NT_STATUS_OK ;
}
2018-09-04 17:08:58 +03:00
}
2019-11-01 00:38:35 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* Set cli - > raw_status so SMBC_errno ( )
* will correctly return the error .
*/
srv - > cli - > raw_status = status ;
2018-09-04 17:08:58 +03:00
if ( dir ! = NULL ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2019-11-01 00:38:35 +03:00
errno = map_errno_from_nt_status (
status ) ;
2018-09-04 17:08:58 +03:00
return NULL ;
}
2008-02-28 19:23:20 +03:00
} else {
/* Neither the workgroup nor server exists */
errno = ECONNREFUSED ;
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
else {
/*
* The server and share are specified . . . work from
* there . . .
*/
char * targetpath ;
struct cli_state * targetcli ;
2010-08-02 21:22:22 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* We connect to the server and list the directory */
dir - > dir_type = SMBC_FILE_SHARE ;
2008-03-07 19:37:07 +03:00
2013-04-17 01:11:08 +04:00
srv = SMBC_server ( frame , context , True , server , port , share ,
2008-02-28 19:23:20 +03:00
& workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > srv = srv ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Now, list the files ... */
2008-03-07 19:37:07 +03:00
2017-07-22 19:36:18 +03:00
path_len = strlen ( path ) ;
2008-02-28 19:23:20 +03:00
path = talloc_asprintf_append ( path , " \\ * " ) ;
if ( ! path ) {
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2011-07-03 22:53:55 +04:00
status = cli_resolve_path (
frame , " " , context - > internal - > auth_info ,
srv - > cli , path , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2010-08-02 21:22:22 +04:00
status = cli_list ( targetcli , targetpath ,
2011-04-29 05:57:02 +04:00
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ,
2010-08-02 21:22:22 +04:00
dir_list_fn , ( void * ) dir ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
if ( dir ) {
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ;
}
saved_errno = SMBC_errno ( context , targetcli ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( saved_errno = = EINVAL ) {
2019-11-25 13:09:52 +03:00
struct stat sb = { 0 } ;
2008-03-02 04:44:21 +03:00
/*
* 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 .
*/
2017-07-22 19:36:18 +03:00
path [ path_len ] = ' \0 ' ; /* restore original path */
2008-03-07 19:37:07 +03:00
2019-11-25 13:09:52 +03:00
if ( SMBC_getatr ( context ,
srv ,
path ,
& sb ) & &
! S_ISDIR ( sb . st_mode ) ) {
2008-03-07 19:37:07 +03:00
2008-03-02 04:44:21 +03:00
/* It is. Correct the error value */
saved_errno = ENOTDIR ;
}
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* If there was an error and the server is no
* good any more . . .
*/
if ( cli_is_error ( targetcli ) & &
2008-03-04 02:13:33 +03:00
smbc_getFunctionCheckServer ( context ) ( context , srv ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* ... then remove it. */
2008-03-04 02:13:33 +03:00
if ( smbc_getFunctionRemoveUnusedServer ( context ) ( context ,
2008-03-07 19:37:07 +03:00
srv ) ) {
2008-02-28 19:23:20 +03:00
/*
* 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 .
*/
2008-03-04 02:13:33 +03:00
smbc_getFunctionRemoveCachedServer ( context ) ( context , srv ) ;
2008-02-28 19:23:20 +03:00
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2011-03-24 18:03:13 +03:00
errno = saved_errno ;
2008-02-28 19:23:20 +03:00
return NULL ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
DLIST_ADD ( context - > internal - > files , dir ) ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return dir ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
/*
* Routine to close a directory
*/
int
SMBC_closedir_ctx ( SMBCCTX * context ,
SMBCFILE * dir )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2020-03-10 21:51:09 +03:00
if ( ! dir | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2008-02-28 19:23:20 +03:00
errno = EBADF ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
remove_dir ( dir ) ; /* Clean it up */
2018-04-07 00:17:35 +03:00
remove_dirplus ( dir ) ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
DLIST_REMOVE ( context - > internal - > files , dir ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
SAFE_FREE ( dir - > fname ) ;
SAFE_FREE ( dir ) ; /* Free the space too */
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2018-06-16 01:08:17 +03:00
static int
2008-02-28 19:23:20 +03:00
smbc_readdir_internal ( SMBCCTX * context ,
struct smbc_dirent * dest ,
struct smbc_dirent * src ,
int max_namebuf_len )
{
2008-03-04 02:13:33 +03:00
if ( smbc_getOptionUrlEncodeReaddirEntries ( context ) ) {
2018-06-16 01:08:17 +03:00
int remaining_len ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* url-encode the name. get back remaining buffer space */
2018-06-16 01:08:17 +03:00
remaining_len =
2009-01-17 04:26:46 +03:00
smbc_urlencode ( dest - > name , src - > name , max_namebuf_len ) ;
2008-03-07 19:37:07 +03:00
2018-06-16 01:08:17 +03:00
/* -1 means no null termination. */
if ( remaining_len < 0 ) {
return - 1 ;
}
2008-02-28 19:23:20 +03:00
/* We now know the name length */
dest - > namelen = strlen ( dest - > name ) ;
2008-03-07 19:37:07 +03:00
2018-06-16 01:08:17 +03:00
if ( dest - > namelen + 1 < 1 ) {
/* Integer wrap. */
return - 1 ;
}
if ( dest - > namelen + 1 > = max_namebuf_len ) {
/* Out of space for comment. */
return - 1 ;
}
2008-02-28 19:23:20 +03:00
/* Save the pointer to the beginning of the comment */
dest - > comment = dest - > name + dest - > namelen + 1 ;
2008-03-07 19:37:07 +03:00
2018-06-16 01:08:17 +03:00
if ( remaining_len < 1 ) {
/* No room for comment null termination. */
return - 1 ;
}
2008-02-28 19:23:20 +03:00
/* Copy the comment */
2018-06-16 01:08:17 +03:00
strlcpy ( dest - > comment , src - > comment , remaining_len ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Save other fields */
dest - > smbc_type = src - > smbc_type ;
dest - > commentlen = strlen ( dest - > comment ) ;
dest - > dirlen = ( ( dest - > comment + dest - > commentlen + 1 ) -
( char * ) dest ) ;
} else {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* No encoding. Just copy the entry as is. */
2018-06-16 01:08:17 +03:00
if ( src - > dirlen > max_namebuf_len ) {
return - 1 ;
}
2008-02-28 19:23:20 +03:00
memcpy ( dest , src , src - > dirlen ) ;
2018-06-16 01:08:17 +03:00
if ( src - > namelen + 1 < 1 ) {
/* Integer wrap */
return - 1 ;
}
if ( src - > namelen + 1 > = max_namebuf_len ) {
/* Comment off the end. */
return - 1 ;
}
2008-02-28 19:23:20 +03:00
dest - > comment = ( char * ) ( & dest - > name + src - > namelen + 1 ) ;
}
2018-06-16 01:08:17 +03:00
return 0 ;
2008-02-28 19:23:20 +03:00
}
/*
* Routine to get a directory entry
*/
struct smbc_dirent *
SMBC_readdir_ctx ( SMBCCTX * context ,
SMBCFILE * dir )
{
int maxlen ;
2018-06-16 01:08:17 +03:00
int ret ;
2008-02-28 19:23:20 +03:00
struct smbc_dirent * dirp , * dirent ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Check that all is ok first ... */
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
DEBUG ( 0 , ( " Invalid context in SMBC_readdir_ctx() \n " ) ) ;
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2020-03-10 21:51:09 +03:00
if ( ! dir | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EBADF ;
DEBUG ( 0 , ( " Invalid dir in SMBC_readdir_ctx() \n " ) ) ;
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOTDIR ;
DEBUG ( 0 , ( " Found file vs directory in SMBC_readdir_ctx() \n " ) ) ;
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! dir - > dir_next ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dirent = dir - > dir_next - > dirent ;
if ( ! dirent ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOENT ;
TALLOC_FREE ( frame ) ;
return NULL ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-12-16 18:54:30 +03:00
dirp = & context - > internal - > dirent ;
maxlen = sizeof ( context - > internal - > _dirent_name ) ;
2008-03-07 19:37:07 +03:00
2018-06-16 01:08:17 +03:00
ret = smbc_readdir_internal ( context , dirp , dirent , maxlen ) ;
if ( ret = = - 1 ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return NULL ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_next = dir - > dir_next - > next ;
2008-03-07 19:37:07 +03:00
2019-08-26 19:54:06 +03:00
/*
* If we are returning file entries , we
* have a duplicate list in dirplus .
*
* Update dirplus_next also so readdir and
* readdirplus are kept in sync .
*/
if ( dir - > dirplus_list ! = NULL ) {
dir - > dirplus_next = dir - > dirplus_next - > next ;
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return dirp ;
}
2018-04-09 20:10:28 +03:00
/*
* Routine to get a directory entry with all attributes
*/
const struct libsmb_file_info *
SMBC_readdirplus_ctx ( SMBCCTX * context ,
SMBCFILE * dir )
{
struct libsmb_file_info * smb_finfo = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
/* Check that all is ok first ... */
if ( context = = NULL | | ! context - > internal - > initialized ) {
DBG_ERR ( " Invalid context in SMBC_readdirplus_ctx() \n " ) ;
TALLOC_FREE ( frame ) ;
errno = EINVAL ;
return NULL ;
}
2020-02-22 00:31:06 +03:00
if ( dir = = NULL | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2018-04-09 20:10:28 +03:00
DBG_ERR ( " Invalid dir in SMBC_readdirplus_ctx() \n " ) ;
TALLOC_FREE ( frame ) ;
errno = EBADF ;
return NULL ;
}
if ( dir - > dirplus_next = = NULL ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
smb_finfo = dir - > dirplus_next - > smb_finfo ;
if ( smb_finfo = = NULL ) {
TALLOC_FREE ( frame ) ;
errno = ENOENT ;
return NULL ;
}
dir - > dirplus_next = dir - > dirplus_next - > next ;
2019-08-26 20:02:47 +03:00
/*
* If we are returning file entries , we
* have a duplicate list in dir_list
*
* Update dir_next also so readdir and
* readdirplus are kept in sync .
*/
if ( dir - > dir_list ) {
dir - > dir_next = dir - > dir_next - > next ;
}
2018-04-09 20:10:28 +03:00
TALLOC_FREE ( frame ) ;
return smb_finfo ;
}
2019-10-18 20:29:48 +03:00
/*
* Routine to get a directory entry plus a filled in stat structure if
* requested .
*/
const struct libsmb_file_info * SMBC_readdirplus2_ctx ( SMBCCTX * context ,
SMBCFILE * dir ,
struct stat * st )
{
struct libsmb_file_info * smb_finfo = NULL ;
struct smbc_dirplus_list * dp_list = NULL ;
ino_t ino ;
char * full_pathname = NULL ;
2019-12-18 15:27:26 +03:00
char * workgroup = NULL ;
char * server = NULL ;
uint16_t port = 0 ;
char * share = NULL ;
char * path = NULL ;
char * user = NULL ;
char * password = NULL ;
char * options = NULL ;
int rc ;
2019-10-18 20:29:48 +03:00
TALLOC_CTX * frame = NULL ;
/*
* Allow caller to pass in NULL for stat pointer if
* required . This makes this call identical to
* smbc_readdirplus ( ) .
*/
if ( st = = NULL ) {
return SMBC_readdirplus_ctx ( context , dir ) ;
}
frame = talloc_stackframe ( ) ;
/* Check that all is ok first ... */
if ( context = = NULL | | ! context - > internal - > initialized ) {
DBG_ERR ( " Invalid context in SMBC_readdirplus2_ctx() \n " ) ;
TALLOC_FREE ( frame ) ;
errno = EINVAL ;
return NULL ;
}
2020-02-22 00:31:06 +03:00
if ( dir = = NULL | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2019-10-18 20:29:48 +03:00
DBG_ERR ( " Invalid dir in SMBC_readdirplus2_ctx() \n " ) ;
TALLOC_FREE ( frame ) ;
errno = EBADF ;
return NULL ;
}
dp_list = dir - > dirplus_next ;
if ( dp_list = = NULL ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
ino = ( ino_t ) dp_list - > ino ;
smb_finfo = dp_list - > smb_finfo ;
if ( smb_finfo = = NULL ) {
TALLOC_FREE ( frame ) ;
errno = ENOENT ;
return NULL ;
}
full_pathname = talloc_asprintf ( frame ,
" %s/%s " ,
dir - > fname ,
smb_finfo - > name ) ;
if ( full_pathname = = NULL ) {
TALLOC_FREE ( frame ) ;
errno = ENOENT ;
return NULL ;
}
2019-12-18 15:27:26 +03:00
rc = SMBC_parse_path ( frame ,
context ,
full_pathname ,
& workgroup ,
& server ,
& port ,
& share ,
& path ,
& user ,
& password ,
& options ) ;
if ( rc ! = 0 ) {
TALLOC_FREE ( frame ) ;
errno = ENOENT ;
return NULL ;
}
2020-03-10 21:51:09 +03:00
setup_stat ( st ,
path ,
smb_finfo - > size ,
smb_finfo - > attrs ,
ino ,
dir - > srv - > dev ,
smb_finfo - > atime_ts ,
smb_finfo - > ctime_ts ,
smb_finfo - > mtime_ts ) ;
2019-10-18 20:29:48 +03:00
TALLOC_FREE ( full_pathname ) ;
dir - > dirplus_next = dir - > dirplus_next - > next ;
/*
* If we are returning file entries , we
* have a duplicate list in dir_list
*
* Update dir_next also so readdir and
* readdirplus are kept in sync .
*/
if ( dir - > dir_list ) {
dir - > dir_next = dir - > dir_next - > next ;
}
TALLOC_FREE ( frame ) ;
return smb_finfo ;
}
2008-02-28 19:23:20 +03:00
/*
* Routine to get directory entries
*/
int
SMBC_getdents_ctx ( SMBCCTX * context ,
SMBCFILE * dir ,
struct smbc_dirent * dirp ,
int count )
{
int rem = count ;
int reqd ;
int maxlen ;
char * ndir = ( char * ) dirp ;
struct smbc_dir_list * dirlist ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Check that all is ok first ... */
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2020-03-10 21:51:09 +03:00
if ( ! dir | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EBADF ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOTDIR ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
/*
2008-02-28 19:23:20 +03:00
* Now , retrieve the number of entries that will fit in what was passed
2008-03-07 19:37:07 +03:00
* We have to figure out if the info is in the list , or we need to
2008-02-28 19:23:20 +03:00
* send a request to the server to get the info .
*/
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
while ( ( dirlist = dir - > dir_next ) ) {
2018-06-16 01:08:17 +03:00
int ret ;
2008-02-28 19:23:20 +03:00
struct smbc_dirent * dirent ;
2010-10-28 01:17:46 +04:00
struct smbc_dirent * currentEntry = ( struct smbc_dirent * ) ndir ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! dirlist - > dirent ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOENT ; /* Bad error */
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Do urlencoding of next entry, if so selected */
2008-12-16 18:54:30 +03:00
dirent = & context - > internal - > dirent ;
maxlen = sizeof ( context - > internal - > _dirent_name ) ;
2018-06-16 01:08:17 +03:00
ret = smbc_readdir_internal ( context , dirent ,
2008-03-02 04:44:21 +03:00
dirlist - > dirent , maxlen ) ;
2018-06-16 01:08:17 +03:00
if ( ret = = - 1 ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
reqd = dirent - > dirlen ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( rem < reqd ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( rem < count ) { /* We managed to copy something */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = 0 ;
TALLOC_FREE ( frame ) ;
return count - rem ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
else { /* Nothing copied ... */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Not enough space ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2010-10-28 01:17:46 +04:00
memcpy ( currentEntry , dirent , reqd ) ; /* Copy the data in ... */
2008-03-07 19:37:07 +03:00
2010-10-28 01:17:46 +04:00
currentEntry - > comment = & currentEntry - > name [ 0 ] +
dirent - > namelen + 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
ndir + = reqd ;
rem - = reqd ;
2008-03-07 19:37:07 +03:00
2010-10-28 01:17:46 +04:00
/* Try and align the struct for the next entry
on a valid pointer boundary by appending zeros */
2015-07-01 01:41:34 +03:00
while ( ( rem > 0 ) & & ( ( uintptr_t ) ndir & ( sizeof ( void * ) - 1 ) ) ) {
2010-10-28 01:17:46 +04:00
* ndir = ' \0 ' ;
rem - - ;
ndir + + ;
currentEntry - > dirlen + + ;
}
2008-02-28 19:23:20 +03:00
dir - > dir_next = dirlist = dirlist - > next ;
2019-08-26 20:07:32 +03:00
/*
* If we are returning file entries , we
* have a duplicate list in dirplus .
*
* Update dirplus_next also so readdir and
* readdirplus are kept in sync .
*/
if ( dir - > dirplus_list ! = NULL ) {
dir - > dirplus_next = dir - > dirplus_next - > next ;
}
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( rem = = count )
return 0 ;
else
return count - rem ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
/*
* Routine to create a directory . . .
*/
int
SMBC_mkdir_ctx ( SMBCCTX * context ,
const char * fname ,
mode_t mode )
{
SMBCSRV * srv = NULL ;
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
char * path = NULL ;
char * targetpath = NULL ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
struct cli_state * targetcli = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " smbc_mkdir(%s) \n " , fname ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_server */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>mkdir: resolving %s\n", path);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , context - > internal - > auth_info ,
srv - > cli , path , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
TALLOC_FREE ( frame ) ;
2008-02-28 19:23:20 +03:00
return - 1 ;
}
/*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
2008-03-07 19:37:07 +03:00
2009-04-21 16:52:34 +04:00
if ( ! NT_STATUS_IS_OK ( cli_mkdir ( targetcli , targetpath ) ) ) {
2008-02-28 19:23:20 +03:00
errno = SMBC_errno ( context , targetcli ) ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
/*
* Our list function simply checks to see if a directory is not empty
*/
2010-10-29 22:56:51 +04:00
static NTSTATUS
2008-02-28 19:23:20 +03:00
rmdir_list_fn ( const char * mnt ,
2010-07-27 12:59:55 +04:00
struct file_info * finfo ,
2008-02-28 19:23:20 +03:00
const char * mask ,
void * state )
{
if ( strncmp ( finfo - > name , " . " , 1 ) ! = 0 & &
strncmp ( finfo - > name , " .. " , 2 ) ! = 0 ) {
2008-12-13 19:04:12 +03:00
bool * smbc_rmdir_dirempty = ( bool * ) state ;
* smbc_rmdir_dirempty = false ;
2008-02-28 19:23:20 +03:00
}
2010-10-29 22:56:51 +04:00
return NT_STATUS_OK ;
2008-02-28 19:23:20 +03:00
}
/*
* Routine to remove a directory
*/
int
SMBC_rmdir_ctx ( SMBCCTX * context ,
const char * fname )
{
SMBCSRV * srv = NULL ;
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
char * path = NULL ;
char * targetpath = NULL ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
struct cli_state * targetcli = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " smbc_rmdir(%s) \n " , fname ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_server */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>rmdir: resolving %s\n", path);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , context - > internal - > auth_info ,
srv - > cli , path , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
/*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
2008-03-07 19:37:07 +03:00
2009-04-21 17:52:54 +04:00
if ( ! NT_STATUS_IS_OK ( cli_rmdir ( targetcli , targetpath ) ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = SMBC_errno ( context , targetcli ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( errno = = EACCES ) { /* Check if the dir empty or not */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Local storage to avoid buffer overflows */
char * lpath ;
2008-12-13 19:04:12 +03:00
bool smbc_rmdir_dirempty = true ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
lpath = talloc_asprintf ( frame , " %s \\ * " ,
targetpath ) ;
if ( ! lpath ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2010-08-02 21:22:22 +04:00
status = cli_list ( targetcli , lpath ,
2011-04-29 05:57:02 +04:00
FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ,
2010-08-02 21:22:22 +04:00
rmdir_list_fn ,
& smbc_rmdir_dirempty ) ;
2008-03-07 19:37:07 +03:00
2010-08-02 21:22:22 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
/* Fix errno to ignore latest error ... */
DEBUG ( 5 , ( " smbc_rmdir: "
" cli_list returned an error: %d \n " ,
SMBC_errno ( context , targetcli ) ) ) ;
errno = EACCES ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( smbc_rmdir_dirempty )
errno = EACCES ;
else
errno = ENOTEMPTY ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
}
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
/*
* Routine to return the current directory position
*/
off_t
SMBC_telldir_ctx ( SMBCCTX * context ,
SMBCFILE * dir )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2020-03-10 21:51:09 +03:00
if ( ! dir | | ! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EBADF ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOTDIR ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* See if we're already at the end. */
if ( dir - > dir_next = = NULL ) {
/* We are. */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*
* We return the pointer here as the offset
*/
TALLOC_FREE ( frame ) ;
return ( off_t ) ( long ) dir - > dir_next - > dirent ;
}
/*
* A routine to run down the list and see if the entry is OK
2019-08-26 20:18:28 +03:00
* Modifies the dir list and the dirplus list ( if it exists )
* to point at the correct next entry on success .
2008-02-28 19:23:20 +03:00
*/
2019-08-26 20:18:28 +03:00
static bool update_dir_ents ( SMBCFILE * dir , struct smbc_dirent * dirent )
2008-02-28 19:23:20 +03:00
{
2019-08-26 20:18:28 +03:00
struct smbc_dir_list * tmp_dir = dir - > dir_list ;
struct smbc_dirplus_list * tmp_dirplus = dir - > dirplus_list ;
2008-03-07 19:37:07 +03:00
2019-08-26 20:18:28 +03:00
/*
* Run down the list looking for what we want .
* If we ' re enumerating files both dir_list
* and dirplus_list contain the same entry
* list , as they were seeded from the same
* cli_list callback .
*
* If we ' re enumerating servers then
* dirplus_list will be NULL , so don ' t
* update in that case .
*/
2008-03-07 19:37:07 +03:00
2019-08-26 20:18:28 +03:00
while ( tmp_dir ! = NULL ) {
if ( tmp_dir - > dirent = = dirent ) {
dir - > dir_next = tmp_dir ;
if ( tmp_dirplus ! = NULL ) {
dir - > dirplus_next = tmp_dirplus ;
}
return true ;
}
tmp_dir = tmp_dir - > next ;
if ( tmp_dirplus ! = NULL ) {
tmp_dirplus = tmp_dirplus - > next ;
2008-02-28 19:23:20 +03:00
}
}
2019-08-26 20:18:28 +03:00
return false ;
2008-02-28 19:23:20 +03:00
}
/*
* Routine to seek on a directory
*/
int
SMBC_lseekdir_ctx ( SMBCCTX * context ,
SMBCFILE * dir ,
off_t offset )
{
long int l_offset = offset ; /* Handle problems of size */
struct smbc_dirent * dirent = ( struct smbc_dirent * ) l_offset ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2019-08-26 20:18:28 +03:00
bool ok ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dir - > file ! = False ) { /* FIXME, should be dir, perhaps */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = ENOTDIR ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* Now, check what we were passed and see if it is OK ... */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( dirent = = NULL ) { /* Seek to the begining of the list */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dir - > dir_next = dir - > dir_list ;
2019-08-26 20:18:28 +03:00
/* Do the same for dirplus. */
dir - > dirplus_next = dir - > dirplus_list ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( offset = = - 1 ) { /* Seek to the end of the list */
dir - > dir_next = NULL ;
2019-08-26 20:18:28 +03:00
/* Do the same for dirplus. */
dir - > dirplus_next = NULL ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
2008-03-07 19:37:07 +03:00
2019-08-26 20:18:28 +03:00
/*
* Run down the list and make sure that the entry is OK .
* Update the position of both dir and dirplus lists .
*/
2008-03-07 19:37:07 +03:00
2019-08-26 20:18:28 +03:00
ok = update_dir_ents ( dir , dirent ) ;
if ( ! ok ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Bad entry */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
/*
* Routine to fstat a dir
*/
int
SMBC_fstatdir_ctx ( SMBCCTX * context ,
SMBCFILE * dir ,
struct stat * st )
{
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/* No code yet ... */
return 0 ;
}
int
SMBC_chmod_ctx ( SMBCCTX * context ,
const char * fname ,
mode_t newmode )
{
SMBCSRV * srv = NULL ;
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
2009-02-20 07:00:46 +03:00
char * targetpath = NULL ;
struct cli_state * targetcli = NULL ;
2008-02-28 19:23:20 +03:00
char * path = NULL ;
2015-05-10 02:59:45 +03:00
uint16_t mode ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Best I can think of ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2009-02-24 03:22:43 +03:00
DEBUG ( 4 , ( " smbc_chmod(%s, 0%3o) \n " , fname , ( unsigned int ) newmode ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_server */
}
2009-02-20 07:00:46 +03:00
/*d_printf(">>>unlink: resolving %s\n", path);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , context - > internal - > auth_info ,
srv - > cli , path , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-02-20 07:00:46 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2009-02-20 07:00:46 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
mode = 0 ;
2008-03-07 19:37:07 +03:00
2011-04-29 05:36:14 +04:00
if ( ! ( newmode & ( S_IWUSR | S_IWGRP | S_IWOTH ) ) ) mode | = FILE_ATTRIBUTE_READONLY ;
2011-04-29 06:00:57 +04:00
if ( ( newmode & S_IXUSR ) & & lp_map_archive ( - 1 ) ) mode | = FILE_ATTRIBUTE_ARCHIVE ;
2011-04-29 07:23:14 +04:00
if ( ( newmode & S_IXGRP ) & & lp_map_system ( - 1 ) ) mode | = FILE_ATTRIBUTE_SYSTEM ;
2011-04-29 05:43:35 +04:00
if ( ( newmode & S_IXOTH ) & & lp_map_hidden ( - 1 ) ) mode | = FILE_ATTRIBUTE_HIDDEN ;
2008-03-07 19:37:07 +03:00
2009-05-07 03:13:42 +04:00
if ( ! NT_STATUS_IS_OK ( cli_setatr ( targetcli , targetpath , mode , 0 ) ) ) {
2009-02-20 07:00:46 +03:00
errno = SMBC_errno ( context , targetcli ) ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
int
SMBC_utimes_ctx ( SMBCCTX * context ,
const char * fname ,
struct timeval * tbuf )
{
SMBCSRV * srv = NULL ;
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
char * path = NULL ;
2020-03-30 22:43:51 +03:00
struct timespec access_time , write_time ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2020-03-26 14:29:13 +03:00
bool ok ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Best I can think of ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( tbuf = = NULL ) {
2020-03-30 22:43:51 +03:00
access_time = write_time = timespec_current ( ) ;
2008-02-28 19:23:20 +03:00
} else {
2020-03-30 22:43:51 +03:00
access_time = convert_timeval_to_timespec ( tbuf [ 0 ] ) ;
write_time = convert_timeval_to_timespec ( tbuf [ 1 ] ) ;
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( DEBUGLVL ( 4 ) ) {
2020-03-30 22:43:51 +03:00
struct timeval_buf abuf , wbuf ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
dbgtext ( " smbc_utimes(%s, atime = %s mtime = %s) \n " ,
2020-03-30 22:43:51 +03:00
fname ,
timespec_string_buf ( & access_time , false , & abuf ) ,
timespec_string_buf ( & write_time , false , & wbuf ) ) ;
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_server */
}
2008-03-07 19:37:07 +03:00
2020-03-26 14:29:13 +03:00
ok = SMBC_setatr (
context ,
srv ,
path ,
( struct timespec ) { . tv_nsec = SAMBA_UTIME_OMIT } ,
2020-03-30 22:43:51 +03:00
access_time ,
write_time ,
2020-03-26 14:29:13 +03:00
( struct timespec ) { . tv_nsec = SAMBA_UTIME_OMIT } ,
0 ) ;
if ( ! ok ) {
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_setatr */
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
/*
* Routine to unlink ( ) a file
*/
int
SMBC_unlink_ctx ( SMBCCTX * context ,
const char * fname )
{
2008-03-02 04:44:21 +03:00
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
2008-02-28 19:23:20 +03:00
char * path = NULL ;
char * targetpath = NULL ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
struct cli_state * targetcli = NULL ;
SMBCSRV * srv = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Best I can think of ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
TALLOC_FREE ( frame ) ;
return - 1 ; /* SMBC_server sets errno */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>unlink: resolving %s\n", path);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , context - > internal - > auth_info ,
srv - > cli , path , & targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
/*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
2008-03-07 19:37:07 +03:00
2011-04-29 07:23:14 +04:00
if ( ! NT_STATUS_IS_OK ( cli_unlink ( targetcli , targetpath , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = SMBC_errno ( context , targetcli ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( errno = = EACCES ) { /* Check if the file is a directory */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
int saverr = errno ;
2019-11-25 13:09:52 +03:00
struct stat sb = { 0 } ;
bool ok ;
2008-03-07 19:37:07 +03:00
2019-11-25 13:09:52 +03:00
ok = SMBC_getatr ( context , srv , path , & sb ) ;
if ( ! ok ) {
2008-02-28 19:23:20 +03:00
/* Hmmm, bad error ... What? */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = SMBC_errno ( context , targetcli ) ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
else {
2008-03-07 19:37:07 +03:00
2019-11-25 13:09:52 +03:00
if ( S_ISDIR ( sb . st_mode ) )
2008-02-28 19:23:20 +03:00
errno = EISDIR ;
else
errno = saverr ; /* Restore this */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ; /* Success ... */
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
/*
* Routine to rename ( ) a file
*/
int
SMBC_rename_ctx ( SMBCCTX * ocontext ,
2008-03-07 19:37:07 +03:00
const char * oname ,
2008-02-28 19:23:20 +03:00
SMBCCTX * ncontext ,
const char * nname )
{
char * server1 = NULL ;
char * share1 = NULL ;
char * server2 = NULL ;
char * share2 = NULL ;
char * user1 = NULL ;
char * user2 = NULL ;
char * password1 = NULL ;
char * password2 = NULL ;
char * workgroup = NULL ;
char * path1 = NULL ;
char * path2 = NULL ;
char * targetpath1 = NULL ;
char * targetpath2 = NULL ;
struct cli_state * targetcli1 = NULL ;
struct cli_state * targetcli2 = NULL ;
SMBCSRV * srv = NULL ;
2013-04-16 23:09:41 +04:00
uint16_t port1 = 0 ;
uint16_t port2 = 0 ;
2008-02-28 19:23:20 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! ocontext | | ! ncontext | |
2008-02-29 21:34:35 +03:00
! ocontext - > internal - > initialized | |
! ncontext - > internal - > initialized ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Best I can think of ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! oname | | ! nname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " smbc_rename(%s,%s) \n " , oname , nname ) ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
ocontext ,
oname ,
& workgroup ,
& server1 ,
2013-04-16 23:09:41 +04:00
& port1 ,
2008-03-02 04:44:21 +03:00
& share1 ,
& path1 ,
& user1 ,
& password1 ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user1 | | user1 [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user1 = talloc_strdup ( frame , smbc_getUser ( ocontext ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user1 ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
ncontext ,
nname ,
NULL ,
& server2 ,
2013-04-16 23:09:41 +04:00
& port2 ,
2008-03-02 04:44:21 +03:00
& share2 ,
& path2 ,
& user2 ,
& password2 ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user2 | | user2 [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user2 = talloc_strdup ( frame , smbc_getUser ( ncontext ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user2 ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( strcmp ( server1 , server2 ) | | strcmp ( share1 , share2 ) | |
strcmp ( user1 , user2 ) ) {
/* Can't rename across file systems, or users?? */
errno = EXDEV ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , ocontext , True ,
2013-04-17 01:11:08 +04:00
server1 , port1 , share1 , & workgroup , & user1 , & password1 ) ;
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
2008-03-07 19:37:07 +03:00
2009-02-20 07:00:46 +03:00
/* set the credentials to make DFS work */
smbc_set_credentials_with_fallback ( ocontext ,
workgroup ,
user1 ,
password1 ) ;
2008-02-28 19:23:20 +03:00
/*d_printf(">>>rename: resolving %s\n", path1);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , ocontext - > internal - > auth_info ,
srv - > cli , path1 , & targetcli1 , & targetpath1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path1 ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-02-20 07:00:46 +03:00
/* set the credentials to make DFS work */
smbc_set_credentials_with_fallback ( ncontext ,
workgroup ,
user2 ,
password2 ) ;
2008-02-28 19:23:20 +03:00
/*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
/*d_printf(">>>rename: resolving %s\n", path2);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , ncontext - > internal - > auth_info ,
srv - > cli , path2 , & targetcli2 , & targetpath2 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path2 ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
/*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
2008-03-07 19:37:07 +03:00
2012-05-19 19:31:50 +04:00
if ( strcmp ( smbXcli_conn_remote_name ( targetcli1 - > conn ) , smbXcli_conn_remote_name ( targetcli2 - > conn ) ) | |
2008-02-28 19:23:20 +03:00
strcmp ( targetcli1 - > share , targetcli2 - > share ) )
{
/* can't rename across file systems */
errno = EXDEV ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2008-03-07 19:37:07 +03:00
2017-03-22 00:13:07 +03:00
if ( ! NT_STATUS_IS_OK (
cli_rename ( targetcli1 , targetpath1 , targetpath2 , false ) ) ) {
2008-02-28 19:23:20 +03:00
int eno = SMBC_errno ( ocontext , targetcli1 ) ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
if ( eno ! = EEXIST | |
2017-03-22 00:13:07 +03:00
! NT_STATUS_IS_OK ( cli_unlink ( targetcli1 , targetpath2 ,
FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_HIDDEN ) ) | |
! NT_STATUS_IS_OK ( cli_rename ( targetcli1 , targetpath1 ,
targetpath2 , false ) ) ) {
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
errno = eno ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
}
}
2008-03-07 19:37:07 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ; /* Success */
}
2015-06-26 14:36:43 +03:00
struct smbc_notify_cb_state {
struct tevent_context * ev ;
struct cli_state * cli ;
uint16_t fnum ;
bool recursive ;
uint32_t completion_filter ;
unsigned callback_timeout_ms ;
smbc_notify_callback_fn cb ;
void * private_data ;
} ;
static void smbc_notify_cb_got_changes ( struct tevent_req * subreq ) ;
static void smbc_notify_cb_timedout ( struct tevent_req * subreq ) ;
static struct tevent_req * smbc_notify_cb_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev , struct cli_state * cli ,
uint16_t fnum , bool recursive , uint32_t completion_filter ,
unsigned callback_timeout_ms ,
smbc_notify_callback_fn cb , void * private_data )
{
struct tevent_req * req , * subreq ;
struct smbc_notify_cb_state * state ;
req = tevent_req_create ( mem_ctx , & state , struct smbc_notify_cb_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > cli = cli ;
state - > fnum = fnum ;
state - > recursive = recursive ;
state - > completion_filter = completion_filter ;
state - > callback_timeout_ms = callback_timeout_ms ;
state - > cb = cb ;
state - > private_data = private_data ;
subreq = cli_notify_send (
state , state - > ev , state - > cli , state - > fnum , 1000 ,
state - > completion_filter , state - > recursive ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbc_notify_cb_got_changes , req ) ;
if ( state - > callback_timeout_ms = = 0 ) {
return req ;
}
subreq = tevent_wakeup_send (
state , state - > ev ,
tevent_timeval_current_ofs ( state - > callback_timeout_ms / 1000 ,
state - > callback_timeout_ms * 1000 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbc_notify_cb_timedout , req ) ;
return req ;
}
static void smbc_notify_cb_got_changes ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbc_notify_cb_state * state = tevent_req_data (
req , struct smbc_notify_cb_state ) ;
uint32_t num_changes ;
struct notify_change * changes ;
NTSTATUS status ;
int cb_ret ;
status = cli_notify_recv ( subreq , state , & num_changes , & changes ) ;
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
{
struct smbc_notify_callback_action actions [ num_changes ] ;
uint32_t i ;
for ( i = 0 ; i < num_changes ; i + + ) {
actions [ i ] . action = changes [ i ] . action ;
actions [ i ] . filename = changes [ i ] . name ;
}
cb_ret = state - > cb ( actions , num_changes , state - > private_data ) ;
}
TALLOC_FREE ( changes ) ;
if ( cb_ret ! = 0 ) {
tevent_req_done ( req ) ;
return ;
}
subreq = cli_notify_send (
state , state - > ev , state - > cli , state - > fnum , 1000 ,
state - > completion_filter , state - > recursive ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , smbc_notify_cb_got_changes , req ) ;
}
static void smbc_notify_cb_timedout ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbc_notify_cb_state * state = tevent_req_data (
req , struct smbc_notify_cb_state ) ;
int cb_ret ;
bool ok ;
ok = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ok ) {
tevent_req_oom ( req ) ;
return ;
}
cb_ret = state - > cb ( NULL , 0 , state - > private_data ) ;
if ( cb_ret ! = 0 ) {
tevent_req_done ( req ) ;
return ;
}
subreq = tevent_wakeup_send (
state , state - > ev ,
tevent_timeval_current_ofs ( state - > callback_timeout_ms / 1000 ,
state - > callback_timeout_ms * 1000 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , smbc_notify_cb_timedout , req ) ;
}
static NTSTATUS smbc_notify_cb_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
static NTSTATUS smbc_notify_cb ( struct cli_state * cli , uint16_t fnum ,
bool recursive , uint32_t completion_filter ,
unsigned callback_timeout_ms ,
smbc_notify_callback_fn cb , void * private_data )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct tevent_context * ev ;
struct tevent_req * req ;
NTSTATUS status = NT_STATUS_NO_MEMORY ;
ev = samba_tevent_context_init ( frame ) ;
if ( ev = = NULL ) {
goto fail ;
}
req = smbc_notify_cb_send ( frame , ev , cli , fnum , recursive ,
completion_filter ,
callback_timeout_ms , cb , private_data ) ;
if ( req = = NULL ) {
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , ev , & status ) ) {
goto fail ;
}
status = smbc_notify_cb_recv ( req ) ;
TALLOC_FREE ( req ) ;
fail :
TALLOC_FREE ( frame ) ;
return status ;
}
int
SMBC_notify_ctx ( SMBCCTX * context , SMBCFILE * dir , smbc_bool recursive ,
uint32_t completion_filter , unsigned callback_timeout_ms ,
smbc_notify_callback_fn cb , void * private_data )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2015-07-14 12:44:58 +03:00
struct cli_state * cli ;
2015-06-26 14:36:43 +03:00
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * options = NULL ;
char * workgroup = NULL ;
char * path = NULL ;
uint16_t port ;
NTSTATUS status ;
uint16_t fnum ;
if ( ( context = = NULL ) | | ! context - > internal - > initialized ) {
TALLOC_FREE ( frame ) ;
errno = EINVAL ;
return - 1 ;
}
2020-03-10 21:51:09 +03:00
if ( ( dir = = NULL ) | |
! SMBC_dlist_contains ( context - > internal - > files , dir ) ) {
2015-06-26 14:36:43 +03:00
TALLOC_FREE ( frame ) ;
errno = EBADF ;
return - 1 ;
}
if ( SMBC_parse_path ( frame ,
context ,
dir - > fname ,
& workgroup ,
& server ,
& port ,
& share ,
& path ,
& user ,
& password ,
& options ) ) {
DEBUG ( 4 , ( " no valid path \n " ) ) ;
TALLOC_FREE ( frame ) ;
errno = EINVAL + 8194 ;
return - 1 ;
}
DEBUG ( 4 , ( " parsed path: fname='%s' server='%s' share='%s' "
" path='%s' options='%s' \n " ,
dir - > fname , server , share , path , options ) ) ;
DEBUG ( 4 , ( " %s(%p, %d, % " PRIu32 " ) \n " , __func__ , dir ,
( int ) recursive , completion_filter ) ) ;
2015-07-14 12:44:58 +03:00
cli = dir - > srv - > cli ;
2015-06-26 14:36:43 +03:00
status = cli_ntcreate (
cli , path , 0 , FILE_READ_DATA , 0 ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
FILE_OPEN , 0 , 0 , & fnum , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
int err = SMBC_errno ( context , cli ) ;
TALLOC_FREE ( frame ) ;
errno = err ;
return - 1 ;
}
status = smbc_notify_cb ( cli , fnum , recursive ! = 0 , completion_filter ,
callback_timeout_ms , cb , private_data ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
int err = SMBC_errno ( context , cli ) ;
cli_close ( cli , fnum ) ;
TALLOC_FREE ( frame ) ;
errno = err ;
return - 1 ;
}
cli_close ( cli , fnum ) ;
TALLOC_FREE ( frame ) ;
return 0 ;
}