summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/close.c45
-rw-r--r--source3/smbd/nttrans.c31
-rw-r--r--source3/smbd/open.c45
-rw-r--r--source3/smbd/posix_acls.c10
-rw-r--r--source3/smbd/trans2.c218
5 files changed, 194 insertions, 155 deletions
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index 56aad64391..c290ee6f89 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -99,7 +99,9 @@ static int close_filestruct(files_struct *fsp)
static int close_normal_file(files_struct *fsp, BOOL normal_close)
{
- BOOL delete_on_close = fsp->delete_on_close;
+ share_mode_entry *share_entry = NULL;
+ size_t share_entry_count = 0;
+ BOOL delete_on_close = False;
connection_struct *conn = fsp->conn;
int err = 0;
int err1 = 0;
@@ -120,21 +122,25 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
return 0;
}
- lock_share_entry_fsp(fsp);
- del_share_mode(fsp);
- unlock_share_entry_fsp(fsp);
+ /*
+ * Lock the share entries, and determine if we should delete
+ * on close. If so delete whilst the lock is still in effect.
+ * This prevents race conditions with the file being created. JRA.
+ */
- if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- release_file_oplock(fsp);
+ lock_share_entry_fsp(fsp);
+ share_entry_count = del_share_mode(fsp, &share_entry);
- locking_close_file(fsp);
+ /*
+ * We delete on close if it's the last open, and the
+ * delete on close flag was set in the entry we just deleted.
+ */
- err = fd_close(conn, fsp);
+ if ((share_entry_count == 0) && share_entry &&
+ GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) )
+ delete_on_close = True;
- /* check for magic scripts */
- if (normal_close) {
- check_magic(fsp,conn);
- }
+ safe_free(share_entry);
/*
* NT can set delete_on_close of the last open
@@ -157,6 +163,21 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
}
}
+ unlock_share_entry_fsp(fsp);
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ release_file_oplock(fsp);
+
+ locking_close_file(fsp);
+
+ err = fd_close(conn, fsp);
+
+ /* check for magic scripts */
+ if (normal_close) {
+ check_magic(fsp,conn);
+ }
+
+
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
conn->user,fsp->fsp_name,
conn->num_files_open, err ? strerror(err) : ""));
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 58b484f44d..b67815ff69 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -47,6 +47,15 @@ static char *known_nt_pipes[] = {
NULL
};
+/* Map generic permissions to file object specific permissions */
+
+struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
/****************************************************************************
Send the required number of replies back.
We assume all fields other than the data fields are
@@ -332,6 +341,12 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
*pstat_open_only = False;
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&desired_access, &file_generic_mapping);
+
switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
case FILE_READ_DATA:
smb_open_mode = DOS_OPEN_RDONLY;
@@ -395,8 +410,22 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
* JRA.
*/
- if(share_access & FILE_SHARE_DELETE)
+ if(share_access & FILE_SHARE_DELETE) {
smb_open_mode |= ALLOW_SHARE_DELETE;
+ DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = %x\n", smb_open_mode));
+ }
+
+ /*
+ * We need to store the intent to open for Delete. This
+ * is what determines if a delete on close flag can be set.
+ * This is the wrong way (and place) to store this, but for 2.2 this
+ * is the only practical way. JRA.
+ */
+
+ if(desired_access & DELETE_ACCESS) {
+ smb_open_mode |= DELETE_ACCESS_REQUESTED;
+ DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = %x\n", smb_open_mode));
+ }
/* Add in the requested share mode. */
switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index c601121459..5f8657262a 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -341,18 +341,19 @@ static int access_table(int new_deny,int old_deny,int old_mode,
check if we can open a file with a share mode
****************************************************************************/
-static int check_share_mode( share_mode_entry *share, int deny_mode,
+static int check_share_mode( share_mode_entry *share, int share_mode,
const char *fname, BOOL fcbopen, int *flags)
{
+ int deny_mode = GET_DENY_MODE(share_mode);
int old_open_mode = GET_OPEN_MODE(share->share_mode);
int old_deny_mode = GET_DENY_MODE(share->share_mode);
/*
- * Don't allow any open once the delete on close flag has been
+ * Don't allow any opens once the delete on close flag has been
* set.
*/
- if(GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) {
+ if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) {
DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n",
fname ));
unix_ERR_class = ERRDOS;
@@ -360,6 +361,35 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
return False;
}
+ /*
+ * If delete access was requested and the existing share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share_mode) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
+ /*
+ * The inverse of the above.
+ * If delete access was granted and the new share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share->share_mode) && !GET_ALLOW_SHARE_DELETE(share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
{
int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
(share->pid == sys_getpid()),is_executable(fname));
@@ -405,7 +435,6 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
int oplock_contention_count = 0;
share_mode_entry *old_shares = 0;
BOOL fcbopen = False;
- int deny_mode = GET_DENY_MODE(share_mode);
BOOL broke_oplock;
if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB)
@@ -473,7 +502,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
/* someone else has a share lock on it, check to see
if we can too */
- if(check_share_mode(share_entry, deny_mode, fname, fcbopen, p_flags) == False) {
+ if(check_share_mode(share_entry, share_mode, fname, fcbopen, p_flags) == False) {
free((char *)old_shares);
errno = EACCES;
return -1;
@@ -532,6 +561,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
int flags2=0;
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 file_existed = VALID_STAT(*psbuf);
BOOL fcbopen = False;
SMB_DEV_T dev = 0;
@@ -768,7 +798,10 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
fsp->share_mode = SET_DENY_MODE(deny_mode) |
SET_OPEN_MODE(open_mode) |
- SET_ALLOW_SHARE_DELETE(allow_share_delete);
+ SET_ALLOW_SHARE_DELETE(allow_share_delete) |
+ SET_DELETE_ACCESS_REQUESTED(delete_access_requested);
+
+ DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode ));
if (Access)
(*Access) = open_mode;
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 5b0c22c77e..aa8f9376c7 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -559,6 +559,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
SEC_ACL *dacl)
{
extern DOM_SID global_sid_World;
+ extern struct generic_mapping *file_generic_mapping;
BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
@@ -589,8 +590,13 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
* to be so. Any other bits override the UNIX_ACCESS_NONE bit.
*/
- psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
- GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&psa->info.mask, &file_generic_mapping);
+
+ psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
if(psa->info.mask != UNIX_ACCESS_NONE)
psa->info.mask &= ~UNIX_ACCESS_NONE;
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 5a7a5c72cb..be130247c0 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1800,144 +1800,94 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
{
- if ((tran_call == TRANSACT2_SETFILEINFO) && (fsp != NULL))
- {
- BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
+ BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
- 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 ));
+ if (tran_call != TRANSACT2_SETFILEINFO)
+ return(ERROR(ERRDOS,ERRunknownlevel));
- }
- 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
- {
+ if (fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadfid));
- /*
- * We can only set the delete on close flag if
- * the share mode contained ALLOW_SHARE_DELETE
- */
-
- if(!GET_ALLOW_SHARE_DELETE(fsp->share_mode))
- return(ERROR(ERRDOS,ERRnoaccess));
-
- /*
- * If the flag has been set then
- * modify the share mode entry for all files we have open
- * on this device and inode to tell other smbds we have
- * changed the delete on close flag.
- */
-
- if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
- {
- int i;
- files_struct *iterate_fsp;
- SMB_DEV_T dev = fsp->dev;
- SMB_INO_T inode = fsp->inode;
- int num_share_modes;
- share_mode_entry *current_shares = NULL;
-
- if (lock_share_entry_fsp(fsp) == False)
- return(ERROR(ERRDOS,ERRnoaccess));
-
- /*
- * Before we allow this we need to ensure that all current opens
- * on the file have the GET_ALLOW_SHARE_DELETE flag set. If they
- * do not then we deny this (as we are essentially deleting the
- * file at this point.
- */
-
- num_share_modes = get_share_modes(conn, dev, inode, &current_shares);
- for(i = 0; i < num_share_modes; i++)
- {
- if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
- {
- DEBUG(5,("call_trans2setfilepathinfo: refusing to set delete on close flag for fnum = %d, \
-file %s as a share exists that was not opened with FILE_DELETE access.\n",
- fsp->fnum, fsp->fsp_name ));
- /*
- * Release the lock.
- */
-
- unlock_share_entry_fsp(fsp);
-
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
-
- free((char *)current_shares);
-
- /*
- * Even though share violation would be more appropriate here,
- * return ERRnoaccess as that's what NT does.
- */
-
- return(ERROR(ERRDOS,ERRnoaccess));
- }
- }
-
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
-
- free((char *)current_shares);
-
- 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 ));
-
- /*
- * 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 have to fend for themselves. We
- * take care of this (rare) case in close_file(). See the comment there.
- */
-
- for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp;
- iterate_fsp = file_find_di_next(iterate_fsp))
- {
- int new_share_mode = (delete_on_close ?
- (iterate_fsp->share_mode | DELETE_ON_CLOSE_FLAG) :
- (iterate_fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) );
-
- DEBUG(10,("call_trans2setfilepathinfo: Changing share mode for fnum %d, file %s \
-dev = %x, inode = %.0f from %x to %x\n",
- iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
- (double)inode, iterate_fsp->share_mode, new_share_mode ));
-
- if(modify_share_mode(iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
- DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
-dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
- }
-
- /*
- * Set the delete on close flag in the reference
- * counted struct. Delete when the last reference
- * goes away.
- */
- fsp->delete_on_close = delete_on_close;
-
- unlock_share_entry_fsp(fsp);
-
- 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 ));
-
- } /* end if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode)) */
- } /* end if is_directory. */
- } else
- return(ERROR(ERRDOS,ERRunknownlevel));
- break;
- }
+ /*
+ * Only allow delete on close for files/directories opened with delete intent.
+ */
- default:
- {
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
+ 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(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(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(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 ));
+
+ }
+
+ break;
+ }
+
+ default:
+ {
+ return(ERROR(ERRDOS,ERRunknownlevel));
+ }
}
/* get some defaults (no modifications) if any info is zero or -1. */