diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/nttrans.c | 21 | ||||
-rw-r--r-- | source3/smbd/open.c | 23 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 161 |
3 files changed, 125 insertions, 80 deletions
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index ae18fc9a53..2c3ac06f3c 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -330,7 +330,7 @@ static int map_create_disposition( uint32 create_disposition) Utility function to map share modes. ****************************************************************************/ -static int map_share_mode( BOOL *pstat_open_only, char *fname, +static int map_share_mode( BOOL *pstat_open_only, char *fname, uint32 create_options, uint32 desired_access, uint32 share_access, uint32 file_attributes) { int smb_open_mode = -1; @@ -423,6 +423,13 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname, DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = %x\n", smb_open_mode)); } + if (create_options & FILE_DELETE_ON_CLOSE) { + /* Implicit delete access requested... */ + smb_open_mode |= DELETE_ACCESS_REQUESTED; + smb_open_mode |= DELETE_ON_CLOSE_FLAG; + DEBUG(10,("map_share_mode: FILE_DELETE_ON_CLOSE requested. open_mode = %x\n", smb_open_mode)); + } + /* Add in the requested share mode. */ switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) { case FILE_SHARE_READ: @@ -650,7 +657,7 @@ int reply_ntcreate_and_X(connection_struct *conn, */ RESOLVE_DFSPATH(fname, conn, inbuf, outbuf); - if((smb_open_mode = map_share_mode(&stat_open_only, fname, desired_access, + if((smb_open_mode = map_share_mode(&stat_open_only, fname, create_options, desired_access, share_access, file_attributes)) == -1) { END_PROFILE(SMBntcreateX); @@ -681,7 +688,7 @@ int reply_ntcreate_and_X(connection_struct *conn, if(create_options & FILE_DIRECTORY_FILE) { oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); restore_case_semantics(file_attributes); @@ -749,7 +756,7 @@ int reply_ntcreate_and_X(connection_struct *conn, } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); @@ -1157,7 +1164,7 @@ static int call_nt_transact_create(connection_struct *conn, * and the share access. */ - if((smb_open_mode = map_share_mode( &stat_open_only, fname, desired_access, + if((smb_open_mode = map_share_mode( &stat_open_only, fname, create_options, desired_access, share_access, file_attributes)) == -1) return ERROR_DOS(ERRDOS,ERRbadaccess); @@ -1190,7 +1197,7 @@ static int call_nt_transact_create(connection_struct *conn, * CreateDirectory() call. */ - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); @@ -1226,7 +1233,7 @@ static int call_nt_transact_create(connection_struct *conn, } oplock_request = 0; - fsp = open_directory(conn, fname, &sbuf, smb_ofun, unixmode, &smb_action); + fsp = open_directory(conn, fname, &sbuf, smb_open_mode, smb_ofun, unixmode, &smb_action); if(!fsp) { restore_case_semantics(file_attributes); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 325913c3d9..1eae228f40 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -618,6 +618,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S int deny_mode = GET_DENY_MODE(share_mode); BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode); BOOL delete_access_requested = GET_DELETE_ACCESS_REQUESTED(share_mode); + BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); BOOL file_existed = VALID_STAT(*psbuf); BOOL fcbopen = False; SMB_DEV_T dev = 0; @@ -905,6 +906,17 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", set_share_mode(fsp, port, oplock_request); + if (delete_on_close) { + NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); + + if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { + unlock_share_entry_fsp(fsp); + fd_close(conn,fsp); + file_free(fsp); + return NULL; + } + } + unlock_share_entry_fsp(fsp); conn->num_files_open++; @@ -1019,11 +1031,12 @@ int close_file_fchmod(files_struct *fsp) ****************************************************************************/ files_struct *open_directory(connection_struct *conn, char *fname, - SMB_STRUCT_STAT *psbuf, int smb_ofun, mode_t unixmode, int *action) + SMB_STRUCT_STAT *psbuf, int share_mode, int smb_ofun, mode_t unixmode, int *action) { extern struct current_user current_user; BOOL got_stat = False; files_struct *fsp = file_new(conn); + BOOL delete_on_close = GET_DELETE_ON_CLOSE_FLAG(share_mode); if(!fsp) return NULL; @@ -1126,6 +1139,14 @@ files_struct *open_directory(connection_struct *conn, char *fname, fsp->conn = conn; string_set(&fsp->fsp_name,fname); + if (delete_on_close) { + NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); + + if (NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_OK)) { + file_free(fsp); + return NULL; + } + } conn->num_files_open++; return fsp; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 404d88260e..0e13d8d87a 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1672,6 +1672,90 @@ static int call_trans2qfilepathinfo(connection_struct *conn, } /**************************************************************************** + Deal with the internal needs of setting the delete on close flag. Note that + as the tdb locking is recursive, it is safe to call this from within + open_file_shared. JRA. +****************************************************************************/ + +NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close) +{ + /* + * Only allow delete on close for files/directories opened with delete intent. + */ + + if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) { + DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; + } + + if(fsp->is_directory) { + fsp->directory_delete_on_close = delete_on_close; + DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, directory %s\n", + delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); + } else if(fsp->stat_open) { + + DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, stat open %s\n", + delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); + + } else { + + files_struct *iterate_fsp; + + /* + * 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. + */ + + DEBUG(10,("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n", + delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name )); + + if (lock_share_entry_fsp(fsp) == False) + return NT_STATUS_ACCESS_DENIED; + + if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) { + DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n", + fsp->fsp_name )); + unlock_share_entry_fsp(fsp); + return NT_STATUS_ACCESS_DENIED; + } + + /* + * Release the lock. + */ + + unlock_share_entry_fsp(fsp); + + /* + * Go through all files we have open on the same device and + * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG. + * Other smbd's that have this file open will look in the share_mode on close. + * take care of this (rare) case in close_file(). See the comment there. + * NB. JRA. We don't really need to do this anymore - all should be taken + * care of in the share_mode changes in the tdb. + */ + + for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode); + iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp)) + fsp->delete_on_close = delete_on_close; + + /* + * Set the delete on close flag in the fsp. + */ + fsp->delete_on_close = delete_on_close; + + DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n", + delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); + + } + + return NT_STATUS_OK; +} + +/**************************************************************************** Reply to a TRANS2_SETFILEINFO (set file info by fileid). ****************************************************************************/ @@ -1931,6 +2015,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */ { BOOL delete_on_close = (CVAL(pdata,0) ? True : False); + NTSTATUS status; if (tran_call != TRANSACT2_SETFILEINFO) return ERROR_DOS(ERRDOS,ERRunknownlevel); @@ -1938,78 +2023,10 @@ static int call_trans2setfilepathinfo(connection_struct *conn, if (fsp == NULL) return(UNIXERROR(ERRDOS,ERRbadfid)); - /* - * Only allow delete on close for files/directories opened with delete intent. - */ - - if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) { - DEBUG(10,("call_trans2setfilepathinfo: file %s delete on close flag set but delete access denied.\n", - fsp->fsp_name )); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - if(fsp->is_directory) { - fsp->directory_delete_on_close = delete_on_close; - DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, directory %s\n", - delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); - } else if(fsp->stat_open) { - - DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, stat open %s\n", - delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); - - } else { - - files_struct *iterate_fsp; - - /* - * 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. - */ - - DEBUG(10,("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n", - delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name )); - - if (lock_share_entry_fsp(fsp) == False) - return ERROR_DOS(ERRDOS,ERRnoaccess); - - if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) { - DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close flag for file %s\n", - fsp->fsp_name )); - unlock_share_entry_fsp(fsp); - return ERROR_DOS(ERRDOS,ERRnoaccess); - } - - /* - * Release the lock. - */ - - unlock_share_entry_fsp(fsp); - - /* - * Go through all files we have open on the same device and - * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG. - * Other smbd's that have this file open will look in the share_mode on close. - * take care of this (rare) case in close_file(). See the comment there. - * NB. JRA. We don't really need to do this anymore - all should be taken - * care of in the share_mode changes in the tdb. - */ - - for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode); - iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp)) - fsp->delete_on_close = delete_on_close; - - /* - * Set the delete on close flag in the fsp. - */ - fsp->delete_on_close = delete_on_close; - - DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n", - delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name )); - - } + status = set_delete_on_close_internal(fsp, delete_on_close); + + if (NT_STATUS_V(status) != NT_STATUS_V(NT_STATUS_OK)) + return ERROR_NT(status); break; } |