1996-05-04 11:50:46 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Locking functions
2000-04-28 01:12:33 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 2000
2006-04-10 19:33:04 +04:00
Copyright ( C ) Jeremy Allison 1992 - 2006
2005-07-08 08:51:27 +04:00
Copyright ( C ) Volker Lendecke 2005
2011-05-28 12:24:20 +04:00
1996-05-04 11:50:46 +04: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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2011-05-28 12:24:20 +04:00
1996-05-04 11:50:46 +04: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 .
2011-05-28 12:24:20 +04:00
1996-05-04 11:50:46 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-08-15 19:11:34 +04:00
Revision History :
12 aug 96 : Erik . Devriendt @ te6 . siemens . be
added support for shared memory implementation of share mode locking
1997-05-20 04:32:51 +04:00
May 1997. Jeremy Allison ( jallison @ whistle . com ) . Modified share mode
locking to deal with multiple share modes per open file .
1997-10-07 22:46:19 +04:00
September 1997. Jeremy Allison ( jallison @ whistle . com ) . Added oplock
support .
2011-12-15 18:48:33 +04:00
rewritten completely to use new tdb code . Tridge , Dec ' 99
2000-04-28 01:12:33 +04:00
Added POSIX locking support . Jeremy Allison ( jeremy @ valinux . com ) , Apr . 2000.
2006-04-10 19:33:04 +04:00
Added Unix Extensions POSIX locking support . Jeremy Allison Mar 2006.
1996-05-04 11:50:46 +04:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2017-01-01 23:00:55 +03:00
# include "lib/util/server_id.h"
2011-03-23 14:43:17 +03:00
# include "locking/proto.h"
2010-07-04 20:18:58 +04:00
# include "smbd/globals.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-07-06 18:40:21 +04:00
# include "dbwrap/dbwrap_open.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-02-25 01:05:57 +03:00
# include "serverid.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2011-11-24 17:11:28 +04:00
# include "../librpc/gen_ndr/ndr_open_files.h"
2015-04-21 11:16:16 +03:00
# include "librpc/gen_ndr/ndr_file_id.h"
2014-10-11 01:32:19 +04:00
# include "locking/leases_db.h"
1996-05-04 11:50:46 +04:00
2005-04-27 22:32:37 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_LOCKING
2007-07-17 04:50:48 +04:00
# define NO_LOCKING_COUNT (-1)
2000-04-12 21:59:09 +04:00
/****************************************************************************
2006-04-10 19:33:04 +04:00
Debugging aids : - ) .
2000-04-12 21:59:09 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-04-10 19:33:04 +04:00
const char * lock_type_name ( enum brl_type lock_type )
2000-04-12 21:59:09 +04:00
{
2006-04-10 19:33:04 +04:00
switch ( lock_type ) {
case READ_LOCK :
return " READ " ;
case WRITE_LOCK :
return " WRITE " ;
default :
return " other " ;
}
}
const char * lock_flav_name ( enum brl_flavour lock_flav )
{
return ( lock_flav = = WINDOWS_LOCK ) ? " WINDOWS_LOCK " : " POSIX_LOCK " ;
2000-04-12 21:59:09 +04:00
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1998-07-23 04:10:26 +04:00
Utility function called to see if a file region is locked .
2006-04-10 19:33:04 +04:00
Called in the read / write codepath .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-12 21:59:09 +04:00
2009-03-14 00:15:28 +03:00
void init_strict_lock_struct ( files_struct * fsp ,
2010-05-07 17:20:50 +04:00
uint64_t smblctx ,
2009-03-14 00:15:28 +03:00
br_off start ,
br_off size ,
enum brl_type lock_type ,
struct lock_struct * plock )
{
SMB_ASSERT ( lock_type = = READ_LOCK | | lock_type = = WRITE_LOCK ) ;
2010-05-07 17:20:50 +04:00
plock - > context . smblctx = smblctx ;
2009-03-14 00:15:28 +03:00
plock - > context . tid = fsp - > conn - > cnum ;
2011-12-15 14:50:43 +04:00
plock - > context . pid = messaging_server_id ( fsp - > conn - > sconn - > msg_ctx ) ;
2009-03-14 00:15:28 +03:00
plock - > start = start ;
plock - > size = size ;
plock - > fnum = fsp - > fnum ;
plock - > lock_type = lock_type ;
plock - > lock_flav = lp_posix_cifsu_locktype ( fsp ) ;
}
2017-07-09 15:34:10 +03:00
bool strict_lock_check_default ( files_struct * fsp , struct lock_struct * plock )
1996-05-04 11:50:46 +04:00
{
2014-07-11 00:23:37 +04:00
struct byte_range_lock * br_lck ;
2006-11-11 20:05:11 +03:00
int strict_locking = lp_strict_locking ( fsp - > conn - > params ) ;
2009-03-14 00:15:28 +03:00
bool ret = False ;
if ( plock - > size = = 0 ) {
return True ;
2006-04-10 19:33:04 +04:00
}
1996-05-04 11:50:46 +04:00
2006-11-11 20:05:11 +03:00
if ( ! lp_locking ( fsp - > conn - > params ) | | ! strict_locking ) {
2009-03-14 00:15:28 +03:00
return True ;
2006-04-10 19:33:04 +04:00
}
1998-07-28 22:26:47 +04:00
2004-12-11 03:30:28 +03:00
if ( strict_locking = = Auto ) {
2017-03-14 23:34:07 +03:00
uint32_t lease_type = fsp_lease_type ( fsp ) ;
if ( ( lease_type & SMB2_LEASE_READ ) & &
( plock - > lock_type = = READ_LOCK ) )
{
DBG_DEBUG ( " optimisation - read lease on file %s \n " ,
fsp_str_dbg ( fsp ) ) ;
2014-07-11 00:23:37 +04:00
return true ;
2004-12-11 03:30:28 +03:00
}
2017-03-14 23:34:07 +03:00
if ( ( lease_type & SMB2_LEASE_WRITE ) & &
( plock - > lock_type = = WRITE_LOCK ) )
{
DBG_DEBUG ( " optimisation - write lease on file %s \n " ,
fsp_str_dbg ( fsp ) ) ;
2014-07-11 00:23:37 +04:00
return true ;
2006-04-10 19:33:04 +04:00
}
2004-12-10 01:10:40 +03:00
}
2001-06-30 05:59:48 +04:00
2014-07-11 00:23:37 +04:00
br_lck = brl_get_locks_readonly ( fsp ) ;
if ( ! br_lck ) {
return true ;
}
2014-07-11 17:35:45 +04:00
ret = brl_locktest ( br_lck , plock ) ;
2014-07-11 00:23:37 +04:00
2014-08-19 16:36:55 +04:00
if ( ! ret ) {
/*
* We got a lock conflict . Retry with rw locks to enable
* autocleanup . This is the slow path anyway .
*/
br_lck = brl_get_locks ( talloc_tos ( ) , fsp ) ;
2019-02-04 19:19:55 +03:00
if ( br_lck = = NULL ) {
return true ;
}
2014-08-19 16:36:55 +04:00
ret = brl_locktest ( br_lck , plock ) ;
TALLOC_FREE ( br_lck ) ;
}
2014-07-11 14:52:06 +04:00
DEBUG ( 10 , ( " strict_lock_default: flavour = %s brl start=%ju "
" len=%ju %s for fnum %ju file %s \n " ,
lock_flav_name ( plock - > lock_flav ) ,
( uintmax_t ) plock - > start , ( uintmax_t ) plock - > size ,
ret ? " unlocked " : " locked " ,
( uintmax_t ) plock - > fnum , fsp_str_dbg ( fsp ) ) ) ;
1996-05-04 11:50:46 +04:00
2006-04-10 19:33:04 +04:00
return ret ;
}
/****************************************************************************
Find out if a lock could be granted - return who is blocking us if we can ' t .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-12 21:59:09 +04:00
2006-04-10 19:33:04 +04:00
NTSTATUS query_lock ( files_struct * fsp ,
2010-05-07 17:20:50 +04:00
uint64_t * psmblctx ,
2008-10-14 03:59:36 +04:00
uint64_t * pcount ,
uint64_t * poffset ,
2006-04-10 19:33:04 +04:00
enum brl_type * plock_type ,
enum brl_flavour lock_flav )
{
struct byte_range_lock * br_lck = NULL ;
2000-04-12 21:59:09 +04:00
2006-07-11 22:01:26 +04:00
if ( ! fsp - > can_lock ) {
return fsp - > is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE ;
2001-06-30 05:59:48 +04:00
}
2006-11-11 20:05:11 +03:00
if ( ! lp_locking ( fsp - > conn - > params ) ) {
2006-04-10 19:33:04 +04:00
return NT_STATUS_OK ;
}
2009-11-16 11:40:47 +03:00
br_lck = brl_get_locks_readonly ( fsp ) ;
2006-04-10 19:33:04 +04:00
if ( ! br_lck ) {
return NT_STATUS_NO_MEMORY ;
}
2009-11-16 11:40:47 +03:00
return brl_lockquery ( br_lck ,
2010-05-07 17:20:50 +04:00
psmblctx ,
2011-12-15 14:50:43 +04:00
messaging_server_id ( fsp - > conn - > sconn - > msg_ctx ) ,
2006-04-10 19:33:04 +04:00
poffset ,
pcount ,
plock_type ,
lock_flav ) ;
2000-04-12 21:59:09 +04:00
}
1996-05-04 11:50:46 +04:00
2009-02-10 08:51:29 +03:00
static void increment_current_lock_count ( files_struct * fsp ,
enum brl_flavour lock_flav )
{
if ( lock_flav = = WINDOWS_LOCK & &
fsp - > current_lock_count ! = NO_LOCKING_COUNT ) {
/* blocking ie. pending, locks also count here,
* as this is an efficiency counter to avoid checking
* the lock db . on close . JRA . */
fsp - > current_lock_count + + ;
} else {
/* Notice that this has had a POSIX lock request.
* We can ' t count locks after this so forget them .
*/
fsp - > current_lock_count = NO_LOCKING_COUNT ;
}
}
static void decrement_current_lock_count ( files_struct * fsp ,
enum brl_flavour lock_flav )
{
if ( lock_flav = = WINDOWS_LOCK & &
fsp - > current_lock_count ! = NO_LOCKING_COUNT ) {
SMB_ASSERT ( fsp - > current_lock_count > 0 ) ;
fsp - > current_lock_count - - ;
}
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1998-07-23 04:10:26 +04:00
Utility function called by locking requests .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-12 21:59:09 +04:00
2019-07-01 16:56:27 +03:00
struct do_lock_state {
struct files_struct * fsp ;
2019-08-08 20:26:28 +03:00
TALLOC_CTX * req_mem_ctx ;
const struct GUID * req_guid ;
2019-07-01 16:56:27 +03:00
uint64_t smblctx ;
uint64_t count ;
uint64_t offset ;
enum brl_type lock_type ;
enum brl_flavour lock_flav ;
struct server_id blocker_pid ;
uint64_t blocker_smblctx ;
NTSTATUS status ;
} ;
static void do_lock_fn (
struct db_record * rec ,
bool * modified_dependent ,
void * private_data )
{
struct do_lock_state * state = private_data ;
struct byte_range_lock * br_lck = NULL ;
2019-08-08 20:26:28 +03:00
br_lck = brl_get_locks_for_locking ( talloc_tos ( ) ,
state - > fsp ,
state - > req_mem_ctx ,
state - > req_guid ) ;
2019-07-01 16:56:27 +03:00
if ( br_lck = = NULL ) {
state - > status = NT_STATUS_NO_MEMORY ;
return ;
}
state - > status = brl_lock (
br_lck ,
state - > smblctx ,
messaging_server_id ( state - > fsp - > conn - > sconn - > msg_ctx ) ,
state - > offset ,
state - > count ,
state - > lock_type ,
state - > lock_flav ,
& state - > blocker_pid ,
& state - > blocker_smblctx ) ;
TALLOC_FREE ( br_lck ) ;
}
2019-07-01 16:17:27 +03:00
NTSTATUS do_lock ( files_struct * fsp ,
2019-08-08 20:26:28 +03:00
TALLOC_CTX * req_mem_ctx ,
const struct GUID * req_guid ,
2019-07-01 15:30:15 +03:00
uint64_t smblctx ,
uint64_t count ,
uint64_t offset ,
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
struct server_id * pblocker_pid ,
uint64_t * psmblctx )
1996-05-04 11:50:46 +04:00
{
2019-07-01 16:56:27 +03:00
struct do_lock_state state = {
. fsp = fsp ,
2019-08-08 20:26:28 +03:00
. req_mem_ctx = req_mem_ctx ,
. req_guid = req_guid ,
2019-07-01 16:56:27 +03:00
. smblctx = smblctx ,
. count = count ,
. offset = offset ,
. lock_type = lock_type ,
. lock_flav = lock_flav ,
} ;
2019-07-01 15:30:15 +03:00
NTSTATUS status ;
1999-12-21 12:25:59 +03:00
2010-04-29 03:42:04 +04:00
/* silently return ok on print files as we don't do locking there */
if ( fsp - > print_file ) {
2019-07-01 15:30:15 +03:00
return NT_STATUS_OK ;
2010-04-29 03:42:04 +04:00
}
2006-07-11 22:01:26 +04:00
if ( ! fsp - > can_lock ) {
2019-07-01 15:30:15 +03:00
if ( fsp - > is_directory ) {
return NT_STATUS_INVALID_DEVICE_REQUEST ;
}
return NT_STATUS_INVALID_HANDLE ;
2006-04-10 19:33:04 +04:00
}
2006-11-11 20:05:11 +03:00
if ( ! lp_locking ( fsp - > conn - > params ) ) {
2019-07-01 15:30:15 +03:00
return NT_STATUS_OK ;
2006-04-10 19:33:04 +04:00
}
1999-12-21 12:25:59 +03:00
2001-08-24 08:55:28 +04:00
/* NOTE! 0 byte long ranges ARE allowed and should be stored */
2019-07-01 15:23:27 +03:00
DBG_DEBUG ( " lock flavour %s lock type %s start=% " PRIu64 " len=% " PRIu64 " "
2019-07-01 15:42:50 +03:00
" requested for %s file %s \n " ,
2019-07-01 15:23:27 +03:00
lock_flav_name ( lock_flav ) ,
lock_type_name ( lock_type ) ,
offset ,
count ,
fsp_fnum_dbg ( fsp ) ,
fsp_str_dbg ( fsp ) ) ;
2006-04-10 19:33:04 +04:00
2019-07-01 16:56:27 +03:00
status = share_mode_do_locked ( fsp - > file_id , do_lock_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " share_mode_do_locked returned %s \n " ,
nt_errstr ( status ) ) ;
return status ;
2000-01-13 15:09:36 +03:00
}
1999-12-21 12:25:59 +03:00
2019-06-20 13:42:23 +03:00
if ( psmblctx ! = NULL ) {
2019-07-01 16:56:27 +03:00
* psmblctx = state . blocker_smblctx ;
2019-06-20 13:42:23 +03:00
}
2019-06-20 13:20:39 +03:00
if ( pblocker_pid ! = NULL ) {
2019-07-01 16:56:27 +03:00
* pblocker_pid = state . blocker_pid ;
2019-06-20 13:20:39 +03:00
}
2006-04-10 19:33:04 +04:00
2019-07-01 16:56:27 +03:00
DBG_DEBUG ( " returning status=%s \n " , nt_errstr ( state . status ) ) ;
2007-03-07 00:59:51 +03:00
2009-02-10 08:51:29 +03:00
increment_current_lock_count ( fsp , lock_flav ) ;
2019-07-01 15:30:15 +03:00
2019-07-01 16:56:27 +03:00
return state . status ;
1996-05-04 11:50:46 +04:00
}
2002-03-13 23:28:19 +03:00
/****************************************************************************
2006-07-18 01:09:02 +04:00
Utility function called by unlocking requests .
2002-03-13 23:28:19 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-07-01 16:33:58 +03:00
NTSTATUS do_unlock ( files_struct * fsp ,
uint64_t smblctx ,
uint64_t count ,
uint64_t offset ,
enum brl_flavour lock_flav )
2002-03-13 23:28:19 +03:00
{
2007-10-19 04:40:25 +04:00
bool ok = False ;
2006-07-18 01:09:02 +04:00
struct byte_range_lock * br_lck = NULL ;
2011-05-28 12:24:20 +04:00
2006-07-18 01:09:02 +04:00
if ( ! fsp - > can_lock ) {
return fsp - > is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE ;
2006-04-10 19:33:04 +04:00
}
2011-05-28 12:24:20 +04:00
2006-11-11 20:05:11 +03:00
if ( ! lp_locking ( fsp - > conn - > params ) ) {
2006-07-18 01:09:02 +04:00
return NT_STATUS_OK ;
}
2011-05-28 12:24:20 +04:00
2019-05-27 14:49:34 +03:00
DBG_DEBUG ( " unlock start=% " PRIu64 " len=% " PRIu64 " requested for %s file "
" %s \n " ,
offset ,
count ,
fsp_fnum_dbg ( fsp ) ,
fsp_str_dbg ( fsp ) ) ;
2002-03-13 23:49:57 +03:00
2008-01-06 18:15:45 +03:00
br_lck = brl_get_locks ( talloc_tos ( ) , fsp ) ;
2006-07-18 01:09:02 +04:00
if ( ! br_lck ) {
return NT_STATUS_NO_MEMORY ;
}
2006-04-10 19:33:04 +04:00
2019-07-01 16:28:10 +03:00
ok = brl_unlock ( br_lck ,
2010-05-07 17:20:50 +04:00
smblctx ,
2011-12-15 14:50:43 +04:00
messaging_server_id ( fsp - > conn - > sconn - > msg_ctx ) ,
2006-07-18 01:09:02 +04:00
offset ,
count ,
lock_flav ) ;
2011-05-28 12:24:20 +04:00
2006-07-18 01:09:02 +04:00
TALLOC_FREE ( br_lck ) ;
2006-04-10 19:33:04 +04:00
2006-07-18 01:09:02 +04:00
if ( ! ok ) {
DEBUG ( 10 , ( " do_unlock: returning ERRlock. \n " ) ) ;
return NT_STATUS_RANGE_NOT_LOCKED ;
2002-03-13 23:28:19 +03:00
}
2006-07-18 01:09:02 +04:00
2009-02-10 08:51:29 +03:00
decrement_current_lock_count ( fsp , lock_flav ) ;
2006-07-18 01:09:02 +04:00
return NT_STATUS_OK ;
2002-03-13 23:28:19 +03:00
}
2000-04-26 00:30:58 +04:00
/****************************************************************************
Remove any locks on this fd . Called from file_close ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-07-01 16:35:19 +03:00
void locking_close_file ( files_struct * fsp ,
2010-05-07 12:20:26 +04:00
enum file_close_type close_type )
2000-04-26 00:30:58 +04:00
{
2006-04-10 19:33:04 +04:00
struct byte_range_lock * br_lck ;
2000-04-26 00:30:58 +04:00
2006-11-11 20:05:11 +03:00
if ( ! lp_locking ( fsp - > conn - > params ) ) {
2000-04-26 00:30:58 +04:00
return ;
2006-04-10 19:33:04 +04:00
}
2000-04-26 00:30:58 +04:00
2013-09-10 16:01:58 +04:00
/* If we have no outstanding locks or pending
2007-03-07 00:59:51 +03:00
* locks then we don ' t need to look in the lock db .
*/
if ( fsp - > current_lock_count = = 0 ) {
return ;
}
2008-01-06 18:15:45 +03:00
br_lck = brl_get_locks ( talloc_tos ( ) , fsp ) ;
2006-07-18 01:09:02 +04:00
2006-07-11 22:01:26 +04:00
if ( br_lck ) {
2019-06-19 17:08:49 +03:00
/*
* Unlocks must trigger dbwrap_watch watchers ,
* normally in smbd_do_unlocking . Here it ' s done
* implictly , we ' re closing the file and thus remove a
* share mode . This will wake the waiters .
*/
2019-07-01 16:31:04 +03:00
brl_close_fnum ( br_lck ) ;
2006-07-11 22:01:26 +04:00
TALLOC_FREE ( br_lck ) ;
2000-04-26 00:30:58 +04:00
}
}
2002-01-08 03:52:36 +03:00
/*******************************************************************
Print out a share mode .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-02-07 13:05:33 +03:00
char * share_mode_str ( TALLOC_CTX * ctx , int num ,
const struct file_id * id ,
const struct share_mode_entry * e )
2002-01-08 03:52:36 +03:00
{
2015-04-23 19:06:17 +03:00
struct server_id_buf tmp ;
2019-09-06 08:29:10 +03:00
struct file_id_buf ftmp ;
2015-04-23 19:06:17 +03:00
2011-12-14 13:35:56 +04:00
return talloc_asprintf ( ctx , " share_mode_entry[%d]: "
2005-09-30 21:13:37 +04:00
" pid = %s, share_access = 0x%x, private_options = 0x%x, "
2011-12-25 14:35:07 +04:00
" access_mask = 0x%x, mid = 0x%llx, type= 0x%x, gen_id = %llu, "
2011-01-26 01:01:52 +03:00
" uid = %u, flags = %u, file_id %s, name_hash = 0x%x " ,
2006-01-27 22:54:39 +03:00
num ,
2015-04-23 19:06:17 +03:00
server_id_str_buf ( e - > pid , & tmp ) ,
2005-07-08 08:51:27 +04:00
e - > share_access , e - > private_options ,
2010-04-13 08:40:28 +04:00
e - > access_mask , ( unsigned long long ) e - > op_mid ,
2012-01-07 02:25:06 +04:00
e - > op_type , ( unsigned long long ) e - > share_file_id ,
2007-02-07 00:05:34 +03:00
( unsigned int ) e - > uid , ( unsigned int ) e - > flags ,
2019-09-06 08:29:10 +03:00
file_id_str_buf ( * id , & ftmp ) ,
2011-01-26 01:01:52 +03:00
( unsigned int ) e - > name_hash ) ;
2002-01-08 03:52:36 +03:00
}
2012-01-13 02:46:45 +04:00
/*******************************************************************
Fetch a share mode where we know one MUST exist . This call reference
counts it internally to allow for nested lock fetches .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-02-19 17:23:56 +04:00
struct share_mode_lock * get_existing_share_mode_lock ( TALLOC_CTX * mem_ctx ,
const struct file_id id )
2012-01-09 17:30:53 +04:00
{
2012-02-19 17:27:49 +04:00
return get_share_mode_lock ( mem_ctx , id , NULL , NULL , NULL ) ;
2012-01-09 17:30:53 +04:00
}
2018-09-17 14:24:56 +03:00
static bool rename_lease_fn ( struct share_mode_lock * lck ,
struct share_mode_entry * e ,
void * private_data )
{
struct share_mode_data * d = lck - > data ;
NTSTATUS status ;
status = leases_db_rename ( & e - > client_guid ,
& e - > lease_key ,
& d - > id ,
d - > servicepath ,
d - > base_name ,
d - > stream_name ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* Any error recovery possible here ? */
DBG_WARNING ( " Failed to rename lease key for "
" renamed file %s:%s. %s \n " ,
d - > base_name ,
d - > stream_name ,
nt_errstr ( status ) ) ;
}
return false ;
}
2005-12-13 01:07:36 +03:00
/*******************************************************************
Sets the service name and filename for rename .
2005-12-13 21:11:50 +03:00
At this point we emit " file renamed " messages to all
process id ' s that have this file open .
Based on an initial code idea from SATOH Fumiyasu < fumiya @ samba . gr . jp >
2005-12-13 01:07:36 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-08-16 16:40:55 +03:00
struct rename_share_filename_state {
struct messaging_context * msg_ctx ;
struct server_id self ;
uint32_t orig_name_hash ;
uint32_t new_name_hash ;
struct file_rename_message msg ;
} ;
static bool rename_share_filename_fn (
struct share_mode_entry * e ,
bool * modified ,
void * private_data )
{
struct rename_share_filename_state * state = private_data ;
DATA_BLOB blob ;
enum ndr_err_code ndr_err ;
bool ok ;
/*
* If this is a hardlink to the inode with a different name ,
* skip this .
*/
if ( e - > name_hash ! = state - > orig_name_hash ) {
return false ;
}
e - > name_hash = state - > new_name_hash ;
* modified = true ;
ok = serverid_equal ( & e - > pid , & state - > self ) ;
if ( ok ) {
return false ;
}
state - > msg . share_file_id = e - > share_file_id ;
ndr_err = ndr_push_struct_blob (
& blob ,
talloc_tos ( ) ,
& state - > msg ,
( ndr_push_flags_fn_t ) ndr_push_file_rename_message ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_DEBUG ( " ndr_push_file_rename_message failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ;
return false ;
}
if ( DEBUGLEVEL > = 10 ) {
struct server_id_buf tmp ;
DBG_DEBUG ( " sending rename message to %s \n " ,
server_id_str_buf ( e - > pid , & tmp ) ) ;
NDR_PRINT_DEBUG ( file_rename_message , & state - > msg ) ;
}
messaging_send ( state - > msg_ctx , e - > pid , MSG_SMB_FILE_RENAME , & blob ) ;
TALLOC_FREE ( blob . data ) ;
return false ;
}
2007-10-19 04:40:25 +04:00
bool rename_share_filename ( struct messaging_context * msg_ctx ,
2007-05-14 17:01:28 +04:00
struct share_mode_lock * lck ,
2014-03-20 17:36:11 +04:00
struct file_id id ,
2005-12-13 01:07:36 +03:00
const char * servicepath ,
2011-01-26 01:01:52 +03:00
uint32_t orig_name_hash ,
uint32_t new_name_hash ,
2009-07-09 03:22:44 +04:00
const struct smb_filename * smb_fname_dst )
2005-12-13 01:07:36 +03:00
{
2019-08-16 16:40:55 +03:00
struct rename_share_filename_state state = {
. msg_ctx = msg_ctx ,
. self = messaging_server_id ( msg_ctx ) ,
. orig_name_hash = orig_name_hash ,
. new_name_hash = new_name_hash ,
. msg . id = id ,
. msg . servicepath = servicepath ,
. msg . base_name = smb_fname_dst - > base_name ,
. msg . stream_name = smb_fname_dst - > stream_name ,
2019-05-17 11:41:25 +03:00
} ;
2019-08-16 16:40:55 +03:00
struct share_mode_data * d = lck - > data ;
2018-09-17 14:24:56 +03:00
bool ok ;
2005-12-13 21:11:50 +03:00
DEBUG ( 10 , ( " rename_share_filename: servicepath %s newname %s \n " ,
2009-07-09 03:22:44 +04:00
servicepath , smb_fname_dst - > base_name ) ) ;
2005-12-13 21:11:50 +03:00
2005-12-13 01:07:36 +03:00
/*
* rename_internal_fsp ( ) and rename_internals ( ) add ' . / ' to
* head of newname if newname does not contain a ' / ' .
*/
2005-12-13 21:11:50 +03:00
2019-08-16 16:40:55 +03:00
if ( strncmp ( state . msg . base_name , " ./ " , 2 ) = = 0 ) {
state . msg . base_name + = 2 ;
2005-12-13 21:11:50 +03:00
}
2006-01-13 01:17:54 +03:00
2019-08-16 16:40:55 +03:00
d - > servicepath = talloc_strdup ( d , state . msg . servicepath ) ;
d - > base_name = talloc_strdup ( d , state . msg . base_name ) ;
d - > stream_name = talloc_strdup ( d , state . msg . stream_name ) ;
2019-05-17 11:41:25 +03:00
if ( ( d - > servicepath = = NULL ) | |
( d - > base_name = = NULL ) | |
2019-08-16 16:40:55 +03:00
( ( state . msg . stream_name ! = NULL ) & & ( d - > stream_name = = NULL ) ) ) {
2019-05-17 11:41:25 +03:00
DBG_WARNING ( " talloc failed \n " ) ;
return false ;
}
d - > modified = True ;
2005-12-13 21:11:50 +03:00
2019-08-16 16:40:55 +03:00
ok = share_mode_forall_entries (
lck , rename_share_filename_fn , & state ) ;
if ( ! ok ) {
DBG_WARNING ( " share_mode_forall_entries failed \n " ) ;
2019-05-17 11:44:23 +03:00
}
2019-05-17 11:41:25 +03:00
2018-09-17 14:24:56 +03:00
ok = share_mode_forall_leases ( lck , rename_lease_fn , NULL ) ;
if ( ! ok ) {
/*
* Ignore error here . Not sure what to do . .
*/
DBG_WARNING ( " share_mode_forall_leases failed \n " ) ;
2014-12-04 21:14:23 +03:00
}
2005-12-13 01:07:36 +03:00
return True ;
}
2008-04-01 13:40:23 +04:00
void get_file_infos ( struct file_id id ,
2011-01-26 00:57:38 +03:00
uint32_t name_hash ,
2008-04-01 13:40:23 +04:00
bool * delete_on_close ,
struct timespec * write_time )
2008-03-12 17:32:47 +03:00
{
struct share_mode_lock * lck ;
2008-04-01 13:40:23 +04:00
if ( delete_on_close ) {
* delete_on_close = false ;
}
if ( write_time ) {
ZERO_STRUCTP ( write_time ) ;
}
2008-03-12 17:32:47 +03:00
2009-07-09 03:22:44 +04:00
if ( ! ( lck = fetch_share_mode_unlocked ( talloc_tos ( ) , id ) ) ) {
2008-04-01 13:40:23 +04:00
return ;
2008-03-12 17:32:47 +03:00
}
2008-04-01 13:40:23 +04:00
if ( delete_on_close ) {
2011-01-26 01:23:19 +03:00
* delete_on_close = is_delete_on_close_set ( lck , name_hash ) ;
2008-03-12 17:32:47 +03:00
}
2008-04-01 13:40:23 +04:00
if ( write_time ) {
2013-11-22 18:36:49 +04:00
* write_time = get_share_mode_write_time ( lck ) ;
2007-05-27 13:57:05 +04:00
}
2008-04-01 13:40:23 +04:00
2007-05-27 13:57:05 +04:00
TALLOC_FREE ( lck ) ;
1998-10-23 07:34:50 +04:00
}
2007-10-19 04:40:25 +04:00
bool is_valid_share_mode_entry ( const struct share_mode_entry * e )
1998-10-23 07:34:50 +04:00
{
2005-09-30 21:13:37 +04:00
int num_props = 0 ;
2013-08-30 16:49:43 +04:00
if ( e - > stale ) {
return false ;
}
2005-09-30 21:13:37 +04:00
num_props + = ( ( e - > op_type = = NO_OPLOCK ) ? 1 : 0 ) ;
num_props + = ( EXCLUSIVE_OPLOCK_TYPE ( e - > op_type ) ? 1 : 0 ) ;
num_props + = ( LEVEL_II_OPLOCK_TYPE ( e - > op_type ) ? 1 : 0 ) ;
2014-11-27 20:34:56 +03:00
num_props + = ( e - > op_type = = LEASE_OPLOCK ) ;
2005-09-30 21:13:37 +04:00
2012-06-01 17:15:07 +04:00
if ( ( num_props > 1 ) & & serverid_exists ( & e - > pid ) ) {
2012-05-14 16:57:34 +04:00
smb_panic ( " Invalid share mode entry " ) ;
}
2005-09-30 21:13:37 +04:00
return ( num_props ! = 0 ) ;
1998-10-23 07:34:50 +04:00
}
2019-08-05 19:50:08 +03:00
NTSTATUS remove_lease_if_stale ( const struct share_mode_data * d ,
const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key )
{
uint32_t i ;
NTSTATUS status ;
for ( i = 0 ; i < d - > num_share_modes ; i + + ) {
const struct share_mode_entry * e = & d - > share_modes [ i ] ;
bool same ;
if ( e - > stale ) {
continue ;
}
if ( e - > op_type ! = LEASE_OPLOCK ) {
continue ;
}
same = smb2_lease_equal (
& e - > client_guid ,
& e - > lease_key ,
client_guid ,
lease_key ) ;
if ( same ) {
return NT_STATUS_RESOURCE_IN_USE ;
}
}
status = leases_db_del ( client_guid , lease_key , & d - > id ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " leases_db_del failed: %s \n " ,
nt_errstr ( status ) ) ;
}
return status ;
}
2014-10-11 01:32:19 +04:00
/*
* See if we need to remove a lease being referred to by a
* share mode that is being marked stale or deleted .
*/
static void remove_share_mode_lease ( struct share_mode_data * d ,
struct share_mode_entry * e )
{
uint16_t op_type ;
op_type = e - > op_type ;
e - > op_type = NO_OPLOCK ;
d - > modified = true ;
if ( op_type ! = LEASE_OPLOCK ) {
return ;
}
2019-08-05 19:50:08 +03:00
remove_lease_if_stale ( d , & e - > client_guid , & e - > lease_key ) ;
2014-10-11 01:32:19 +04:00
}
2019-08-13 17:00:09 +03:00
bool share_entry_stale_pid ( struct share_mode_entry * e )
{
struct server_id_buf buf ;
bool exists ;
if ( e - > stale ) {
return true ;
}
exists = serverid_exists ( & e - > pid ) ;
if ( exists ) {
DBG_DEBUG ( " PID %s still exists \n " ,
server_id_str_buf ( e - > pid , & buf ) ) ;
return false ;
}
DBG_DEBUG ( " PID %s does not exist anymore \n " ,
server_id_str_buf ( e - > pid , & buf ) ) ;
e - > stale = true ;
return true ;
}
2012-05-07 14:57:07 +04:00
/*
* In case d - > share_modes [ i ] conflicts with something or otherwise is
* being used , we need to make sure the corresponding process still
2013-08-30 16:49:43 +04:00
* exists .
2012-05-07 14:57:07 +04:00
*/
2013-09-26 05:39:27 +04:00
bool share_mode_stale_pid ( struct share_mode_data * d , uint32_t idx )
2012-05-07 14:57:07 +04:00
{
struct share_mode_entry * e ;
2019-08-13 17:04:13 +03:00
bool stale ;
2012-05-07 14:57:07 +04:00
2013-08-30 16:27:36 +04:00
if ( idx > d - > num_share_modes ) {
2018-07-30 14:00:22 +03:00
DBG_WARNING ( " Asking for index % " PRIu32 " , "
" only % " PRIu32 " around \n " ,
idx ,
d - > num_share_modes ) ;
2012-05-07 14:57:07 +04:00
return false ;
}
2013-08-30 16:27:36 +04:00
e = & d - > share_modes [ idx ] ;
2019-08-13 17:04:13 +03:00
stale = share_entry_stale_pid ( e ) ;
if ( ! stale ) {
2012-05-07 14:57:07 +04:00
return false ;
}
2019-08-13 17:04:13 +03:00
d - > modified = true ;
2013-08-30 16:49:43 +04:00
if ( d - > num_delete_tokens ! = 0 ) {
2018-07-30 14:03:17 +03:00
uint32_t i ;
2013-08-30 16:49:43 +04:00
for ( i = 0 ; i < d - > num_share_modes ; i + + ) {
2018-07-30 14:03:17 +03:00
bool valid = ! d - > share_modes [ i ] . stale ;
if ( valid ) {
break ;
2013-08-30 16:49:43 +04:00
}
}
2018-07-30 14:03:17 +03:00
if ( i = = d - > num_share_modes ) {
2013-08-30 16:49:43 +04:00
/*
2018-07-30 14:03:17 +03:00
* No valid ( non - stale ) share mode found , all
* who might have set the delete token are
* gone .
2013-08-30 16:49:43 +04:00
*/
TALLOC_FREE ( d - > delete_tokens ) ;
d - > num_delete_tokens = 0 ;
}
2012-05-22 23:27:06 +04:00
}
2014-10-11 01:32:19 +04:00
remove_share_mode_lease ( d , e ) ;
2012-05-07 14:57:07 +04:00
d - > modified = true ;
return true ;
}
2013-09-02 15:37:57 +04:00
void remove_stale_share_mode_entries ( struct share_mode_data * d )
{
uint32_t i ;
i = 0 ;
while ( i < d - > num_share_modes ) {
if ( d - > share_modes [ i ] . stale ) {
struct share_mode_entry * m = d - > share_modes ;
m [ i ] = m [ d - > num_share_modes - 1 ] ;
d - > num_share_modes - = 1 ;
2018-07-30 14:21:26 +03:00
continue ;
2013-09-02 15:37:57 +04:00
}
2018-07-30 14:21:26 +03:00
i + = 1 ;
2013-09-02 15:37:57 +04:00
}
}
2018-09-18 12:31:27 +03:00
bool set_share_mode ( struct share_mode_lock * lck ,
struct files_struct * fsp ,
uid_t uid ,
uint64_t mid ,
uint16_t op_type ,
2019-07-25 16:01:37 +03:00
uint32_t share_access ,
2019-08-05 15:59:18 +03:00
uint32_t access_mask )
1999-12-13 16:27:58 +03:00
{
2013-09-17 01:02:48 +04:00
struct share_mode_data * d = lck - > data ;
struct share_mode_entry * tmp , * e ;
2014-11-27 20:34:56 +03:00
2013-09-17 01:02:48 +04:00
tmp = talloc_realloc ( d , d - > share_modes , struct share_mode_entry ,
d - > num_share_modes + 1 ) ;
if ( tmp = = NULL ) {
return false ;
}
d - > share_modes = tmp ;
e = & d - > share_modes [ d - > num_share_modes ] ;
d - > num_share_modes + = 1 ;
d - > modified = true ;
2005-09-30 21:13:37 +04:00
ZERO_STRUCTP ( e ) ;
2011-12-15 14:50:43 +04:00
e - > pid = messaging_server_id ( fsp - > conn - > sconn - > msg_ctx ) ;
2019-07-25 16:01:37 +03:00
e - > share_access = share_access ;
2005-09-30 21:13:37 +04:00
e - > private_options = fsp - > fh - > private_options ;
2019-07-25 16:01:37 +03:00
e - > access_mask = access_mask ;
2005-09-30 21:13:37 +04:00
e - > op_mid = mid ;
e - > op_type = op_type ;
2018-09-18 12:31:27 +03:00
if ( op_type = = LEASE_OPLOCK ) {
2019-08-05 15:59:18 +03:00
const struct GUID * client_guid = fsp_client_guid ( fsp ) ;
2018-09-18 12:31:27 +03:00
e - > client_guid = * client_guid ;
2019-08-05 15:59:18 +03:00
e - > lease_key = fsp - > lease - > lease . lease_key ;
2018-09-13 13:47:55 +03:00
}
2018-09-18 12:31:27 +03:00
2005-09-30 21:13:37 +04:00
e - > time . tv_sec = fsp - > open_time . tv_sec ;
e - > time . tv_usec = fsp - > open_time . tv_usec ;
2007-05-29 13:30:34 +04:00
e - > share_file_id = fsp - > fh - > gen_id ;
2015-05-10 02:14:39 +03:00
e - > uid = ( uint32_t ) uid ;
2015-11-27 20:29:55 +03:00
e - > flags = ( fsp - > posix_flags & FSP_POSIX_FLAGS_OPEN ) ?
SHARE_MODE_FLAG_POSIX_OPEN : 0 ;
2011-01-26 01:01:52 +03:00
e - > name_hash = fsp - > name_hash ;
2013-09-14 15:48:03 +04:00
return true ;
2005-09-30 21:13:37 +04:00
}
1999-12-13 16:27:58 +03:00
2019-07-03 12:25:41 +03:00
static struct share_mode_entry * find_share_mode_entry (
2013-09-17 00:58:54 +04:00
struct share_mode_lock * lck , files_struct * fsp )
2005-09-30 21:13:37 +04:00
{
2013-09-17 00:58:54 +04:00
struct share_mode_data * d = lck - > data ;
2019-08-10 23:15:05 +03:00
struct server_id pid = messaging_server_id ( fsp - > conn - > sconn - > msg_ctx ) ;
2018-02-07 12:05:57 +03:00
uint32_t i ;
2004-06-08 20:14:31 +04:00
2012-01-10 16:56:37 +04:00
for ( i = 0 ; i < d - > num_share_modes ; i + + ) {
struct share_mode_entry * e = & d - > share_modes [ i ] ;
2013-09-17 00:58:54 +04:00
if ( ! is_valid_share_mode_entry ( e ) ) {
continue ;
}
if ( ! serverid_equal ( & pid , & e - > pid ) ) {
continue ;
2005-09-30 21:13:37 +04:00
}
2013-09-17 00:58:54 +04:00
if ( fsp - > fh - > gen_id ! = e - > share_file_id ) {
continue ;
}
return e ;
2005-09-30 21:13:37 +04:00
}
return NULL ;
}
2004-06-08 20:14:31 +04:00
/*******************************************************************
2018-09-10 13:20:10 +03:00
Del the share mode of a file for this process .
2004-06-08 20:14:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool del_share_mode ( struct share_mode_lock * lck , files_struct * fsp )
2004-06-08 20:14:31 +04:00
{
2013-09-17 00:58:54 +04:00
struct share_mode_entry * e ;
2004-06-08 20:14:31 +04:00
2013-09-17 00:58:54 +04:00
e = find_share_mode_entry ( lck , fsp ) ;
2005-09-30 21:13:37 +04:00
if ( e = = NULL ) {
return False ;
2004-06-08 20:14:31 +04:00
}
2014-10-11 01:32:19 +04:00
remove_share_mode_lease ( lck - > data , e ) ;
2012-01-10 16:56:37 +04:00
* e = lck - > data - > share_modes [ lck - > data - > num_share_modes - 1 ] ;
lck - > data - > num_share_modes - = 1 ;
lck - > data - > modified = True ;
2005-09-30 21:13:37 +04:00
return True ;
2004-06-08 20:14:31 +04:00
}
2012-08-03 18:31:32 +04:00
bool mark_share_mode_disconnected ( struct share_mode_lock * lck ,
struct files_struct * fsp )
{
2013-09-17 00:58:54 +04:00
struct share_mode_entry * e ;
2012-08-03 18:31:32 +04:00
if ( lck - > data - > num_share_modes ! = 1 ) {
return false ;
}
if ( fsp - > op = = NULL ) {
return false ;
}
if ( ! fsp - > op - > global - > durable ) {
return false ;
}
2013-09-17 00:58:54 +04:00
e = find_share_mode_entry ( lck , fsp ) ;
2012-08-03 18:31:32 +04:00
if ( e = = NULL ) {
return false ;
}
DEBUG ( 10 , ( " Marking share mode entry disconnected for durable handle \n " ) ) ;
server_id_set_disconnected ( & e - > pid ) ;
/*
* On reopen the caller needs to check that
* the client comes with the correct handle .
*/
e - > share_file_id = fsp - > op - > global - > open_persistent_id ;
lck - > data - > modified = true ;
return true ;
}
2004-06-08 20:14:31 +04:00
/*******************************************************************
2005-09-30 21:13:37 +04:00
Remove an oplock mid and mode entry from a share mode .
2004-06-08 20:14:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool remove_share_oplock ( struct share_mode_lock * lck , files_struct * fsp )
2004-06-08 20:14:31 +04:00
{
2014-10-11 01:32:19 +04:00
struct share_mode_data * d = lck - > data ;
2013-09-17 00:58:54 +04:00
struct share_mode_entry * e ;
2004-06-08 20:14:31 +04:00
2013-09-17 00:58:54 +04:00
e = find_share_mode_entry ( lck , fsp ) ;
2005-09-30 21:13:37 +04:00
if ( e = = NULL ) {
return False ;
}
2004-06-08 20:14:31 +04:00
2014-10-11 01:32:19 +04:00
remove_share_mode_lease ( d , e ) ;
d - > modified = True ;
return true ;
2005-09-30 21:13:37 +04:00
}
2004-06-08 20:14:31 +04:00
2005-09-30 21:13:37 +04:00
/*******************************************************************
Downgrade a oplock type from exclusive to level II .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-08 20:14:31 +04:00
2007-10-19 04:40:25 +04:00
bool downgrade_share_oplock ( struct share_mode_lock * lck , files_struct * fsp )
2005-09-30 21:13:37 +04:00
{
2013-09-17 00:58:54 +04:00
struct share_mode_entry * e ;
2004-06-08 20:14:31 +04:00
2013-09-17 00:58:54 +04:00
e = find_share_mode_entry ( lck , fsp ) ;
2005-09-30 21:13:37 +04:00
if ( e = = NULL ) {
return False ;
2004-06-08 20:14:31 +04:00
}
2005-09-30 21:13:37 +04:00
e - > op_type = LEVEL_II_OPLOCK ;
2019-06-30 20:57:39 +03:00
lck - > data - > flags | = SHARE_MODE_HAS_READ_LEASE ;
2012-01-10 16:56:37 +04:00
lck - > data - > modified = True ;
2005-09-30 21:13:37 +04:00
return True ;
2004-06-08 20:14:31 +04:00
}
2006-02-02 23:44:50 +03:00
/****************************************************************************
2011-01-26 01:23:19 +03:00
Adds a delete on close token .
2006-02-02 23:44:50 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-01-10 16:56:37 +04:00
static bool add_delete_on_close_token ( struct share_mode_data * d ,
2011-01-26 01:23:19 +03:00
uint32_t name_hash ,
2012-04-05 01:54:02 +04:00
const struct security_token * nt_tok ,
2011-02-11 10:49:15 +03:00
const struct security_unix_token * tok )
2006-02-02 23:44:50 +03:00
{
2011-11-21 20:12:00 +04:00
struct delete_token * tmp , * dtl ;
2006-02-02 23:44:50 +03:00
2012-01-10 16:56:37 +04:00
tmp = talloc_realloc ( d , d - > delete_tokens , struct delete_token ,
d - > num_delete_tokens + 1 ) ;
2011-11-21 20:12:00 +04:00
if ( tmp = = NULL ) {
2011-01-26 01:23:19 +03:00
return false ;
}
2012-01-10 16:56:37 +04:00
d - > delete_tokens = tmp ;
dtl = & d - > delete_tokens [ d - > num_delete_tokens ] ;
2011-01-26 01:23:19 +03:00
dtl - > name_hash = name_hash ;
2012-04-05 01:54:02 +04:00
dtl - > delete_nt_token = dup_nt_token ( d - > delete_tokens , nt_tok ) ;
if ( dtl - > delete_nt_token = = NULL ) {
return false ;
}
2012-01-10 16:56:37 +04:00
dtl - > delete_token = copy_unix_token ( d - > delete_tokens , tok ) ;
2011-01-26 01:23:19 +03:00
if ( dtl - > delete_token = = NULL ) {
return false ;
}
2012-01-10 16:56:37 +04:00
d - > num_delete_tokens + = 1 ;
d - > modified = true ;
2011-01-26 01:23:19 +03:00
return true ;
2006-02-02 23:44:50 +03:00
}
2015-04-21 12:36:30 +03:00
void reset_delete_on_close_lck ( files_struct * fsp ,
struct share_mode_lock * lck )
{
struct share_mode_data * d = lck - > data ;
uint32_t i ;
for ( i = 0 ; i < d - > num_delete_tokens ; i + + ) {
struct delete_token * dt = & d - > delete_tokens [ i ] ;
if ( dt - > name_hash = = fsp - > name_hash ) {
d - > modified = true ;
/* Delete this entry. */
TALLOC_FREE ( dt - > delete_nt_token ) ;
TALLOC_FREE ( dt - > delete_token ) ;
* dt = d - > delete_tokens [ d - > num_delete_tokens - 1 ] ;
d - > num_delete_tokens - = 1 ;
}
}
}
2019-08-14 18:29:19 +03:00
struct set_delete_on_close_state {
struct messaging_context * msg_ctx ;
DATA_BLOB blob ;
} ;
static bool set_delete_on_close_fn (
struct share_mode_entry * e ,
bool * modified ,
void * private_data )
{
struct set_delete_on_close_state * state = private_data ;
NTSTATUS status ;
status = messaging_send (
state - > msg_ctx ,
e - > pid ,
MSG_SMB_NOTIFY_CANCEL_DELETED ,
& state - > blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
struct server_id_buf tmp ;
DBG_DEBUG ( " messaging_send to %s returned %s \n " ,
server_id_str_buf ( e - > pid , & tmp ) ,
nt_errstr ( status ) ) ;
}
return false ;
}
2005-09-30 21:13:37 +04:00
/****************************************************************************
Sets the delete on close flag over all share modes on this file .
Modify the share mode entry for all files open
on this device and inode to tell other smbds we have
changed the delete on close flag . This will be noticed
in the close code , the last closer will delete the file
if flag is set .
2011-02-11 10:49:15 +03:00
This makes a copy of any struct security_unix_token into the
2007-01-19 00:51:52 +03:00
lck entry . This function is used when the lock is already granted .
2005-09-30 21:13:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-08 20:14:31 +04:00
2011-01-26 01:23:19 +03:00
void set_delete_on_close_lck ( files_struct * fsp ,
struct share_mode_lock * lck ,
2012-04-05 01:54:02 +04:00
const struct security_token * nt_tok ,
2011-02-11 10:49:15 +03:00
const struct security_unix_token * tok )
2007-01-19 00:51:52 +03:00
{
2012-01-10 16:56:37 +04:00
struct share_mode_data * d = lck - > data ;
2019-08-14 18:29:19 +03:00
struct set_delete_on_close_state state = {
. msg_ctx = fsp - > conn - > sconn - > msg_ctx
} ;
2015-04-21 11:16:16 +03:00
uint32_t i ;
2011-01-26 01:23:19 +03:00
bool ret ;
2015-04-21 11:16:16 +03:00
enum ndr_err_code ndr_err ;
2011-01-26 01:23:19 +03:00
2015-04-21 12:36:30 +03:00
SMB_ASSERT ( nt_tok ! = NULL ) ;
SMB_ASSERT ( tok ! = NULL ) ;
2012-01-10 16:56:37 +04:00
for ( i = 0 ; i < d - > num_delete_tokens ; i + + ) {
struct delete_token * dt = & d - > delete_tokens [ i ] ;
2011-11-21 20:12:00 +04:00
if ( dt - > name_hash = = fsp - > name_hash ) {
2012-01-10 16:56:37 +04:00
d - > modified = true ;
2015-04-21 12:36:30 +03:00
/* Replace this token with the given tok. */
TALLOC_FREE ( dt - > delete_nt_token ) ;
dt - > delete_nt_token = dup_nt_token ( dt , nt_tok ) ;
SMB_ASSERT ( dt - > delete_nt_token ! = NULL ) ;
TALLOC_FREE ( dt - > delete_token ) ;
dt - > delete_token = copy_unix_token ( dt , tok ) ;
SMB_ASSERT ( dt - > delete_token ! = NULL ) ;
2012-04-07 02:35:55 +04:00
return ;
2007-01-19 00:51:52 +03:00
}
}
2011-01-26 01:23:19 +03:00
2012-04-05 01:54:02 +04:00
ret = add_delete_on_close_token ( lck - > data , fsp - > name_hash , nt_tok , tok ) ;
2011-01-26 01:23:19 +03:00
SMB_ASSERT ( ret ) ;
2015-04-21 11:16:16 +03:00
2019-08-14 18:29:19 +03:00
ndr_err = ndr_push_struct_blob (
& state . blob ,
talloc_tos ( ) ,
& fsp - > file_id ,
( ndr_push_flags_fn_t ) ndr_push_file_id ) ;
2015-04-21 11:16:16 +03:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 10 , ( " ndr_push_file_id failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ) ;
}
2019-08-14 18:29:19 +03:00
ret = share_mode_forall_entries (
lck , set_delete_on_close_fn , & state ) ;
if ( ! ret ) {
DBG_DEBUG ( " share_mode_forall_entries failed \n " ) ;
2015-04-21 11:16:16 +03:00
}
2019-08-14 18:29:19 +03:00
TALLOC_FREE ( state . blob . data ) ;
2007-01-19 00:51:52 +03:00
}
2012-04-05 01:54:02 +04:00
bool set_delete_on_close ( files_struct * fsp , bool delete_on_close ,
const struct security_token * nt_tok ,
const struct security_unix_token * tok )
2004-06-08 20:14:31 +04:00
{
2005-09-30 21:13:37 +04:00
struct share_mode_lock * lck ;
2011-05-28 12:24:20 +04:00
2005-09-30 21:13:37 +04:00
DEBUG ( 10 , ( " set_delete_on_close: %s delete on close flag for "
2012-06-14 14:25:43 +04:00
" %s, file %s \n " ,
delete_on_close ? " Adding " : " Removing " , fsp_fnum_dbg ( fsp ) ,
2009-07-11 01:50:37 +04:00
fsp_str_dbg ( fsp ) ) ) ;
2004-06-08 20:14:31 +04:00
2012-02-19 17:23:56 +04:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ) ;
2005-09-30 21:13:37 +04:00
if ( lck = = NULL ) {
2004-06-08 20:14:31 +04:00
return False ;
}
2006-02-02 23:44:50 +03:00
2012-04-05 01:54:02 +04:00
if ( delete_on_close ) {
2015-04-21 12:41:45 +03:00
set_delete_on_close_lck ( fsp , lck , nt_tok , tok ) ;
2012-04-05 01:54:02 +04:00
} else {
2015-04-21 12:38:32 +03:00
reset_delete_on_close_lck ( fsp , lck ) ;
2012-04-05 01:54:02 +04:00
}
2006-02-01 07:14:07 +03:00
2007-01-20 00:46:12 +03:00
if ( fsp - > is_directory ) {
2009-07-11 01:50:37 +04:00
SMB_ASSERT ( ! is_ntfs_stream_smb_fname ( fsp - > fsp_name ) ) ;
2010-07-07 00:43:14 +04:00
send_stat_cache_delete_message ( fsp - > conn - > sconn - > msg_ctx ,
fsp - > fsp_name - > base_name ) ;
2007-01-20 00:46:12 +03:00
}
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( lck ) ;
2010-01-13 03:04:44 +03:00
fsp - > delete_on_close = delete_on_close ;
2005-09-30 21:13:37 +04:00
return True ;
}
2001-08-21 05:25:45 +04:00
2012-06-01 17:50:39 +04:00
static struct delete_token * find_delete_on_close_token (
struct share_mode_data * d , uint32_t name_hash )
{
uint32_t i ;
2019-09-03 17:40:00 +03:00
DBG_DEBUG ( " name_hash = 0x% " PRIx32 " \n " , name_hash ) ;
2012-06-01 17:50:39 +04:00
for ( i = 0 ; i < d - > num_delete_tokens ; i + + ) {
struct delete_token * dt = & d - > delete_tokens [ i ] ;
2019-09-03 17:40:00 +03:00
DBG_DEBUG ( " dt->name_hash = 0x% " PRIx32 " \n " ,
dt - > name_hash ) ;
2012-06-01 17:50:39 +04:00
if ( dt - > name_hash = = name_hash ) {
return dt ;
}
}
return NULL ;
}
2012-04-05 01:54:02 +04:00
/****************************************************************************
Return the NT token and UNIX token if there ' s a match . Return true if
found , false if not .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool get_delete_on_close_token ( struct share_mode_lock * lck ,
uint32_t name_hash ,
const struct security_token * * pp_nt_tok ,
const struct security_unix_token * * pp_tok )
2011-01-26 01:23:19 +03:00
{
2012-06-01 17:50:39 +04:00
struct delete_token * dt ;
2011-01-26 01:23:19 +03:00
2012-06-01 17:50:39 +04:00
dt = find_delete_on_close_token ( lck - > data , name_hash ) ;
if ( dt = = NULL ) {
return false ;
}
2012-06-01 17:52:14 +04:00
* pp_nt_tok = dt - > delete_nt_token ;
* pp_tok = dt - > delete_token ;
2012-06-01 17:50:39 +04:00
return true ;
2011-01-26 01:23:19 +03:00
}
bool is_delete_on_close_set ( struct share_mode_lock * lck , uint32_t name_hash )
{
2012-06-01 17:50:39 +04:00
return find_delete_on_close_token ( lck - > data , name_hash ) ! = NULL ;
2011-01-26 01:23:19 +03:00
}
2009-07-08 04:27:50 +04:00
bool set_sticky_write_time ( struct file_id fileid , struct timespec write_time )
2008-03-12 17:32:47 +03:00
{
struct share_mode_lock * lck ;
2019-09-06 08:31:22 +03:00
struct file_id_buf ftmp ;
2008-03-12 17:32:47 +03:00
2019-09-06 08:31:22 +03:00
DBG_INFO ( " %s id=%s \n " ,
2009-11-03 12:59:18 +03:00
timestring ( talloc_tos ( ) ,
2008-03-12 17:32:47 +03:00
convert_timespec_to_time_t ( write_time ) ) ,
2019-09-06 08:31:22 +03:00
file_id_str_buf ( fileid , & ftmp ) ) ;
2008-03-12 17:32:47 +03:00
2012-02-19 17:23:56 +04:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fileid ) ;
2008-03-12 17:32:47 +03:00
if ( lck = = NULL ) {
return False ;
}
2012-01-10 16:56:37 +04:00
if ( timespec_compare ( & lck - > data - > changed_write_time , & write_time ) ! = 0 ) {
lck - > data - > modified = True ;
lck - > data - > changed_write_time = write_time ;
2008-03-12 17:32:47 +03:00
}
TALLOC_FREE ( lck ) ;
return True ;
}
2008-09-06 06:00:48 +04:00
bool set_write_time ( struct file_id fileid , struct timespec write_time )
{
struct share_mode_lock * lck ;
2008-09-06 07:37:00 +04:00
DEBUG ( 5 , ( " set_write_time: %s id=%s \n " ,
2009-11-03 12:59:18 +03:00
timestring ( talloc_tos ( ) ,
2008-09-06 06:00:48 +04:00
convert_timespec_to_time_t ( write_time ) ) ,
file_id_string_tos ( & fileid ) ) ) ;
2012-02-19 17:23:56 +04:00
lck = get_existing_share_mode_lock ( talloc_tos ( ) , fileid ) ;
2008-09-06 06:00:48 +04:00
if ( lck = = NULL ) {
return False ;
}
2012-01-10 16:56:37 +04:00
if ( timespec_compare ( & lck - > data - > old_write_time , & write_time ) ! = 0 ) {
lck - > data - > modified = True ;
lck - > data - > old_write_time = write_time ;
2008-09-06 06:00:48 +04:00
}
TALLOC_FREE ( lck ) ;
return True ;
}
2013-11-22 18:36:49 +04:00
struct timespec get_share_mode_write_time ( struct share_mode_lock * lck )
{
struct share_mode_data * d = lck - > data ;
if ( ! null_timespec ( d - > changed_write_time ) ) {
return d - > changed_write_time ;
}
return d - > old_write_time ;
}
2018-05-27 14:03:25 +03:00
2019-08-16 16:56:23 +03:00
struct file_has_open_streams_state {
bool found_one ;
} ;
static bool file_has_open_streams_fn (
struct share_mode_entry * e ,
bool * modified ,
void * private_data )
{
struct file_has_open_streams_state * state = private_data ;
if ( ( e - > private_options &
NTCREATEX_OPTIONS_PRIVATE_STREAM_BASEOPEN ) = = 0 ) {
return false ;
}
if ( share_entry_stale_pid ( e ) ) {
return false ;
}
state - > found_one = true ;
return true ;
}
2018-05-27 14:03:25 +03:00
bool file_has_open_streams ( files_struct * fsp )
{
2019-08-16 16:56:23 +03:00
struct file_has_open_streams_state state = { . found_one = false } ;
2018-05-27 14:03:25 +03:00
struct share_mode_lock * lock = NULL ;
2019-08-16 16:56:23 +03:00
bool ok ;
2018-05-27 14:03:25 +03:00
lock = get_existing_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ) ;
if ( lock = = NULL ) {
return false ;
}
2019-08-16 16:56:23 +03:00
ok = share_mode_forall_entries (
lock , file_has_open_streams_fn , & state ) ;
TALLOC_FREE ( lock ) ;
2018-05-27 14:03:25 +03:00
2019-08-16 16:56:23 +03:00
if ( ! ok ) {
DBG_DEBUG ( " share_mode_forall_entries failed \n " ) ;
return false ;
2018-05-27 14:03:25 +03:00
}
2019-08-16 16:56:23 +03:00
return state . found_one ;
2018-05-27 14:03:25 +03:00
}
2018-09-17 14:14:22 +03:00
2019-08-13 16:09:51 +03:00
bool share_mode_forall_entries (
struct share_mode_lock * lck ,
bool ( * fn ) ( struct share_mode_entry * e ,
bool * modified ,
void * private_data ) ,
void * private_data )
{
struct share_mode_data * d = lck - > data ;
uint32_t i ;
for ( i = 0 ; i < d - > num_share_modes ; i + + ) {
struct share_mode_entry * e = & d - > share_modes [ i ] ;
struct server_id pid = e - > pid ;
uint64_t share_file_id = e - > share_file_id ;
bool ok , stop ;
bool modified = false ;
ok = is_valid_share_mode_entry ( e ) ;
if ( ! ok ) {
continue ;
}
stop = fn ( e , & modified , private_data ) ;
if ( modified | | e - > stale ) {
d - > modified = true ;
}
if ( modified ) {
/*
* In a later commit we will sort the share
* mode array keyed by pid and
* share_file_id . Make sure that from within
* this routine those values don ' t change .
*/
SMB_ASSERT ( server_id_equal ( & pid , & e - > pid ) ) ;
SMB_ASSERT ( share_file_id = = e - > share_file_id ) ;
}
if ( stop ) {
return true ;
}
}
return true ;
}
2018-09-17 14:14:22 +03:00
/*
* Walk share mode entries , looking at every lease only once
*/
bool share_mode_forall_leases (
struct share_mode_lock * lck ,
bool ( * fn ) ( struct share_mode_lock * lck ,
struct share_mode_entry * e ,
void * private_data ) ,
void * private_data )
{
struct share_mode_data * d = lck - > data ;
uint32_t * leases = NULL ;
uint32_t num_leases = 0 ;
uint32_t i ;
leases = talloc_array ( talloc_tos ( ) , uint32_t , d - > num_share_modes ) ;
if ( leases = = NULL ) {
return false ;
}
for ( i = 0 ; i < d - > num_share_modes ; i + + ) {
struct share_mode_entry * e = & d - > share_modes [ i ] ;
uint32_t j ;
bool ok , stop ;
ok = is_valid_share_mode_entry ( e ) ;
if ( ! ok ) {
continue ;
}
if ( e - > op_type ! = LEASE_OPLOCK ) {
continue ;
}
/*
* See if we have already seen " e " ' s lease . This is
* O ( n ^ 2 ) . If we sort " leases " , we can get this down
* to O ( n ) .
*/
for ( j = 0 ; j < num_leases ; j + + ) {
uint32_t idx = leases [ j ] ;
struct share_mode_entry * l = & d - > share_modes [ idx ] ;
if ( smb2_lease_equal ( & e - > client_guid ,
& e - > lease_key ,
& l - > client_guid ,
& l - > lease_key ) ) {
break ;
}
}
if ( j < num_leases ) {
/*
* Don ' t look at " e " ' s lease , we ' ve already
* seen it .
*/
continue ;
}
stop = fn ( lck , e , private_data ) ;
if ( stop ) {
TALLOC_FREE ( leases ) ;
return true ;
}
leases [ num_leases ] = i ;
num_leases + = 1 ;
}
TALLOC_FREE ( leases ) ;
return true ;
}