summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/nttrans.c21
-rw-r--r--source3/smbd/open.c23
-rw-r--r--source3/smbd/trans2.c161
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;
}