diff options
-rw-r--r-- | source3/include/proto.h | 4 | ||||
-rw-r--r-- | source3/include/smb.h | 20 | ||||
-rw-r--r-- | source3/libsmb/clifile.c | 8 | ||||
-rw-r--r-- | source3/locking/locking.c | 71 | ||||
-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 |
9 files changed, 258 insertions, 194 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 9b6aab6645c..12a7478e0ab 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1155,11 +1155,11 @@ void unlock_share_entry_fsp(files_struct *fsp); int get_share_modes(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry **shares); -void del_share_mode(files_struct *fsp); +size_t del_share_mode(files_struct *fsp, share_mode_entry **ppse); BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type); BOOL remove_share_oplock(files_struct *fsp); BOOL downgrade_share_oplock(files_struct *fsp); -BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock); +BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close); int share_mode_forall(SHAREMODE_FN(fn)); /*The following definitions come from locking/posix.c */ diff --git a/source3/include/smb.h b/source3/include/smb.h index ba0a02e9507..e154c1eda2a 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -123,6 +123,11 @@ implemented */ #define GET_DELETE_ON_CLOSE_FLAG(x) (((x) & DELETE_ON_CLOSE_FLAG) ? True : False) #define SET_DELETE_ON_CLOSE_FLAG(x) ((x) ? DELETE_ON_CLOSE_FLAG : 0) +/* was delete access requested in NT open ? */ +#define DELETE_ACCESS_REQUESTED (1<<17) +#define GET_DELETE_ACCESS_REQUESTED(x) (((x) & DELETE_ACCESS_REQUESTED) ? True : False) +#define SET_DELETE_ACCESS_REQUESTED(x) ((x) ? DELETE_ACCESS_REQUESTED : 0) + /* open disposition values */ #define FILE_EXISTS_FAIL 0 #define FILE_EXISTS_OPEN 1 @@ -1060,7 +1065,7 @@ struct bitmap { #define FILE_READ_ATTRIBUTES 0x080 #define FILE_WRITE_ATTRIBUTES 0x100 -#define FILE_ALL_ATTRIBUTES 0x1FF +#define FILE_ALL_ACCESS 0x1FF /* the desired access to use when opening a pipe */ #define DESIRED_ACCESS_PIPE 0x2019f @@ -1088,6 +1093,19 @@ struct bitmap { #define GENERIC_WRITE_ACCESS (1<<30) #define GENERIC_READ_ACCESS (((unsigned)1)<<31) +/* Mapping of generic access rights for files to specific rights. */ + +#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS| SYNCHRONIZE_ACCESS|FILE_ALL_ACCESS) + +#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|FILE_READ_DATA|FILE_READ_ATTRIBUTES|\ + FILE_READ_EA|SYNCHRONIZE_ACCESS) + +#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE_ACCESS|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|\ + FILE_WRITE_EA|FILE_APPEND_DATA|SYNCHRONIZE_ACCESS) + +#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|FILE_READ_ATTRIBUTES|\ + FILE_EXECUTE|SYNCHRONIZE_ACCESS) + /* Mapping of access rights to UNIX perms. */ #define UNIX_ACCESS_RWX (UNIX_ACCESS_R|UNIX_ACCESS_W|UNIX_ACCESS_X) #define UNIX_ACCESS_R (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\ diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index e90bd7c41fa..d62a0a417a6 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -164,6 +164,9 @@ BOOL cli_rmdir(struct cli_state *cli, char *dname) } return True; +} + +/**************************************************************************** Set or clear the delete on close flag. ****************************************************************************/ @@ -183,7 +186,7 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag) data = flag ? 1 : 0; if (!cli_send_trans(cli, SMBtrans2, - NULL, 0, /* name, length */ + NULL, /* name */ -1, 0, /* fid, flags */ &setup, 1, 0, /* setup, length, max */ param, param_len, 2, /* param, length, max */ @@ -205,9 +208,6 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag) } /**************************************************************************** -} - -/**************************************************************************** open a file - exposing the full horror of the NT API :-). Used in smbtorture. ****************************************************************************/ diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 118d59cc10c..5824287e913 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -331,19 +331,24 @@ int get_share_modes(connection_struct *conn, } /******************************************************************* - Del the share mode of a file for this process + Del the share mode of a file for this process. Return the number + of entries left, and a memdup'ed copy of the entry deleted. ********************************************************************/ -void del_share_mode(files_struct *fsp) + +size_t del_share_mode(files_struct *fsp, share_mode_entry **ppse) { TDB_DATA dbuf; struct locking_data *data; int i, del_count=0; share_mode_entry *shares; pid_t pid = sys_getpid(); + size_t count; + + *ppse = NULL; /* read in the existing share modes */ dbuf = tdb_fetch(tdb, locking_key_fsp(fsp)); - if (!dbuf.dptr) return; + if (!dbuf.dptr) return 0; data = (struct locking_data *)dbuf.dptr; shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); @@ -354,6 +359,7 @@ void del_share_mode(files_struct *fsp) if (shares[i].pid == pid && memcmp(&shares[i].time, &fsp->open_time,sizeof(struct timeval)) == 0) { + *ppse = memdup(&shares[i], sizeof(*shares)); data->num_share_mode_entries--; memmove(&shares[i], &shares[i+1], dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); @@ -366,6 +372,8 @@ void del_share_mode(files_struct *fsp) /* the record has shrunk a bit */ dbuf.dsize -= del_count * sizeof(*shares); + count = data->num_share_mode_entries; + /* store it back in the database */ if (data->num_share_mode_entries == 0) { tdb_delete(tdb, locking_key_fsp(fsp)); @@ -374,6 +382,7 @@ void del_share_mode(files_struct *fsp) } free(dbuf.dptr); + return count; } /******************************************************************* @@ -529,42 +538,40 @@ BOOL downgrade_share_oplock(files_struct *fsp) return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL); } - /******************************************************************* - Static function that actually does the work for the generic function - below. + Get/Set the delete on close flag in a set of share modes. + Return False on fail, True on success. ********************************************************************/ -struct mod_val { - int new_share_mode; - uint16 new_oplock; -}; -static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, - void *param) +BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) { - struct mod_val *mvp = (struct mod_val *)param; - - DEBUG(10,("modify_share_mode_fn: changing share mode info from %x to %x for entry dev=%x ino=%.0f\n", - entry->share_mode, mvp->new_share_mode, (unsigned int)dev, (double)inode )); - DEBUG(10,("modify_share_mode_fn: changing oplock state from %x to %x for entry dev=%x ino=%.0f\n", - entry->op_type, (int)mvp->new_oplock, (unsigned int)dev, (double)inode )); - /* Change the share mode info. */ - entry->share_mode = mvp->new_share_mode; - entry->op_type = mvp->new_oplock; -} + TDB_DATA dbuf; + struct locking_data *data; + int i; + share_mode_entry *shares; -/******************************************************************* - Modify a share mode on a file. Used by the delete open file code. - Return False on fail, True on success. -********************************************************************/ -BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock) -{ - struct mod_val mv; + /* read in the existing share modes */ + dbuf = tdb_fetch(tdb, locking_key(dev, inode)); + if (!dbuf.dptr) return False; + + data = (struct locking_data *)dbuf.dptr; + shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); - mv.new_share_mode = new_mode; - mv.new_oplock = new_oplock; + /* Set/Unset the delete on close element. */ + for (i=0;i<data->num_share_mode_entries;i++,shares++) { + shares->share_mode = (delete_on_close ? + (shares->share_mode | DELETE_ON_CLOSE_FLAG) : + (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) ); + } - return mod_share_mode(fsp, modify_share_mode_fn, (void *)&mv); + /* store it back */ + if (data->num_share_mode_entries) { + if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1) + return False; + } + + free(dbuf.dptr); + return True; } diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 56aad643914..c290ee6f894 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 58b484f44d6..b67815ff694 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 c6011214599..5f8657262a2 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 5b0c22c77e5..aa8f9376c76 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 5a7a5c72cb1..be130247c0e 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. */ |