diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/close.c | 45 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 31 | ||||
-rw-r--r-- | source3/smbd/open.c | 45 | ||||
-rw-r--r-- | source3/smbd/posix_acls.c | 10 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 218 |
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, ¤t_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. */ |