diff options
-rw-r--r-- | source3/include/proto.h | 5 | ||||
-rw-r--r-- | source3/include/smb.h | 15 | ||||
-rw-r--r-- | source3/locking/locking.c | 45 | ||||
-rw-r--r-- | source3/locking/locking_shm.c | 29 | ||||
-rw-r--r-- | source3/locking/locking_slow.c | 59 | ||||
-rw-r--r-- | source3/smbd/close.c | 1 | ||||
-rw-r--r-- | source3/smbd/files.c | 35 | ||||
-rw-r--r-- | source3/smbd/open.c | 23 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 52 |
10 files changed, 225 insertions, 41 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index 9b707adeef..9c78e84017 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -538,7 +538,8 @@ int get_share_modes(connection_struct *conn, share_mode_entry **shares); void del_share_mode(int token, files_struct *fsp); BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type); -BOOL remove_share_oplock(files_struct *fsp, int token); +BOOL remove_share_oplock(int token, files_struct *fsp); +BOOL modify_share_mode(int token, files_struct *fsp, int new_mode); int share_mode_forall(void (*fn)(share_mode_entry *, char *)); void share_status(FILE *f); @@ -2147,6 +2148,8 @@ void file_close_conn(connection_struct *conn); void file_init(void); void file_close_user(int vuid); files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval); +files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode); +files_struct *file_find_di_next(files_struct *start_fsp); files_struct *file_find_print(void); void file_sync_all(connection_struct *conn); void fd_ptr_free(file_fd_struct *fd_ptr); diff --git a/source3/include/smb.h b/source3/include/smb.h index d71d1cd1eb..2e27fa195f 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -201,14 +201,19 @@ implemented */ #define GET_DENY_MODE(x) (((x)>>SHARE_MODE_SHIFT) & SHARE_MODE_MASK) #define SET_DENY_MODE(x) ((x)<<SHARE_MODE_SHIFT) +/* Sync on open file (not sure if used anymore... ?) */ +#define FILE_SYNC_OPENMODE (1<<14) +#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? True : False) + /* allow delete on open file mode (used by NT SMB's). */ #define ALLOW_SHARE_DELETE (1<<15) -#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? 1 : 0) +#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? True : False) #define SET_ALLOW_SHARE_DELETE(x) ((x) ? ALLOW_SHARE_DELETE : 0) -/* Sync on open file (not sure if used anymore... ?) */ -#define FILE_SYNC_OPENMODE (1<<14) -#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? 1 : 0) +/* delete on close flag (used by NT SMB's). */ +#define DELETE_ON_CLOSE_FLAG (1<<16) +#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) /* open disposition values */ #define FILE_EXISTS_FAIL 0 @@ -669,7 +674,7 @@ struct share_ops { int (*get_entries)(connection_struct *, int , SMB_DEV_T , SMB_INO_T , share_mode_entry **); void (*del_entry)(int , files_struct *); BOOL (*set_entry)(int, files_struct *, uint16 , uint16 ); - BOOL (*remove_oplock)(files_struct *, int); + BOOL (*mod_entry)(int, files_struct *, void (*)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), void *); int (*forall)(void (*)(share_mode_entry *, char *)); void (*status)(FILE *); }; diff --git a/source3/locking/locking.c b/source3/locking/locking.c index f088720e0a..b71b775524 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -230,11 +230,52 @@ BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type) } /******************************************************************* + Static function that actually does the work for the generic function + below. +********************************************************************/ + +static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, + void *param) +{ + DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n", + (unsigned int)dev, (double)inode )); + /* Delete the oplock info. */ + entry->op_port = 0; + entry->op_type = 0; +} + +/******************************************************************* Remove an oplock port and mode entry from a share mode. ********************************************************************/ -BOOL remove_share_oplock(files_struct *fsp, int token) + +BOOL remove_share_oplock(int token, files_struct *fsp) +{ + return share_ops->mod_entry(token, fsp, remove_share_oplock_fn, NULL); +} + +/******************************************************************* + Static function that actually does the work for the generic function + below. +********************************************************************/ + +static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, + void *param) +{ + int new_share_mode = *(int *)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, new_share_mode, (unsigned int)dev, (double)inode )); + /* Change the share mode info. */ + entry->share_mode = new_share_mode; +} + +/******************************************************************* + 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(int token, files_struct *fsp, int new_mode) { - return share_ops->remove_oplock(fsp, token); + return share_ops->mod_entry(token, fsp, modify_share_mode_fn, (void *)&new_mode); } /******************************************************************* diff --git a/source3/locking/locking_shm.c b/source3/locking/locking_shm.c index 1077cf23eb..375a8b7f10 100644 --- a/source3/locking/locking_shm.c +++ b/source3/locking/locking_shm.c @@ -495,9 +495,12 @@ static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16 } /******************************************************************* -Remove an oplock port and mode entry from a share mode. + Call a generic modify function for a share mode entry. ********************************************************************/ -static BOOL shm_remove_share_oplock(files_struct *fsp, int token) + +static BOOL shm_mod_share_entry(int token, files_struct *fsp, + void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), + void *param) { SMB_DEV_T dev; SMB_INO_T inode; @@ -518,7 +521,7 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token) if(mode_array[hash_entry] == 0) { - DEBUG(0,("PANIC ERROR:remove_share_oplock: hash bucket %d empty\n", + DEBUG(0,("PANIC ERROR:modify_share_entry: hash bucket %d empty\n", hash_entry)); return False; } @@ -543,14 +546,14 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token) if(!found) { - DEBUG(0,("ERROR:remove_share_oplock: no entry found for dev=%x ino=%.0f\n", + DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n", (unsigned int)dev, (double)inode)); return False; } if(file_scanner_p->locking_version != LOCKING_VERSION) { - DEBUG(0,("ERROR: remove_share_oplock: Deleting old share mode v1=%d dev=%x ino=%.0f\n", + DEBUG(0,("ERROR: modify_share_entry: Deleting old share mode v1=%d dev=%x ino=%.0f\n", file_scanner_p->locking_version, (unsigned int)dev, (double)inode)); if(file_prev_p == file_scanner_p) @@ -571,9 +574,14 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token) (memcmp(&entry_scanner_p->e.time, &fsp->open_time,sizeof(struct timeval)) == 0) ) { - /* Delete the oplock info. */ - entry_scanner_p->e.op_port = 0; - entry_scanner_p->e.op_type = 0; + /* + * Call the generic function with the given parameter. + */ + + DEBUG(5,("modify_share_entry: Calling generic function to modify entry for dev=%x ino=%.0f\n", + (unsigned int)dev, (double)inode)); + + (*mod_fn)( &entry_scanner_p->e, dev, inode, param); found = True; break; } @@ -586,7 +594,7 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token) if(!found) { - DEBUG(0,("ERROR: remove_share_oplock: No oplock granted. dev=%x ino=%.0f\n", + DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n", (unsigned int)dev, (double)inode)); return False; } @@ -594,7 +602,6 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token) return True; } - /******************************************************************* call the specified function on each entry under management by the share mode system @@ -670,7 +677,7 @@ static struct share_ops share_ops = { shm_get_share_modes, shm_del_share_mode, shm_set_share_mode, - shm_remove_share_oplock, + shm_mod_share_entry, shm_share_forall, shm_share_status, }; diff --git a/source3/locking/locking_slow.c b/source3/locking/locking_slow.c index f2c2d3e9d9..f1e0fa2149 100644 --- a/source3/locking/locking_slow.c +++ b/source3/locking/locking_slow.c @@ -827,9 +827,12 @@ mode 0x%X pid=%d\n",fname,fsp->share_mode,pid)); } /******************************************************************* -Remove an oplock port and mode entry from a share mode. + Call a generic modify function for a share mode entry. ********************************************************************/ -static BOOL slow_remove_share_oplock(files_struct *fsp, int token) + +static BOOL slow_mod_share_entry(int token, files_struct *fsp, + void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), + void *param) { pstring fname; int fd = (int)token; @@ -841,20 +844,21 @@ static BOOL slow_remove_share_oplock(files_struct *fsp, int token) int pid; BOOL found = False; BOOL new_file; + share_mode_entry entry; share_name(fsp->conn, fsp->fd_ptr->dev, fsp->fd_ptr->inode, fname); if(read_share_file( fsp->conn, fd, fname, &buf, &new_file) != 0) { - DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n", + DEBUG(0,("ERROR: slow_mod_share_entry: Failed to read share file %s\n", fname)); return False; } if(new_file == True) { - DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \ + DEBUG(0,("ERROR: slow_mod_share_entry: share file %s is new (size zero), \ deleting it.\n", fname)); delete_share_file(fsp->conn, fname); return False; @@ -862,13 +866,13 @@ deleting it.\n", fname)); num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET); - DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n", + DEBUG(5,("slow_mod_share_entry: share file %s has %d share mode entries.\n", fname, num_entries)); /* PARANOIA TEST */ if(num_entries < 0) { - DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \ + DEBUG(0,("PANIC ERROR:slow_mod_share_entry: num_share_mode_entries < 0 (%d) \ for share file %s\n", num_entries, fname)); return False; } @@ -876,7 +880,7 @@ for share file %s\n", num_entries, fname)); if(num_entries == 0) { /* No entries - just delete the file. */ - DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n", + DEBUG(0,("slow_mod_share_entry: share file %s has no share mode entries - deleting.\n", fname)); if(buf) free(buf); @@ -886,10 +890,6 @@ for share file %s\n", num_entries, fname)); pid = getpid(); - /* Go through the entries looking for the particular one - we have set - remove the oplock settings on it. - */ - base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET); for(i = 0; i < num_entries; i++) @@ -902,18 +902,41 @@ for share file %s\n", num_entries, fname)); (IVAL(p,SME_PID_OFFSET) != pid)) continue; - DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \ + DEBUG(5,("slow_mod_share_entry: Calling generic function to modify entry number %d (of %d) \ from the share file %s\n", i, num_entries, fname)); - SSVAL(p,SME_PORT_OFFSET,0); - SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0); + /* + * Copy into the share_mode_entry structure and then call + * the generic function with the given parameter. + */ + + entry.pid = IVAL(p,SME_PID_OFFSET); + entry.op_port = SVAL(p,SME_PORT_OFFSET); + entry.op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET); + entry.share_mode = IVAL(p,SME_SHAREMODE_OFFSET); + entry.time.tv_sec = IVAL(p,SME_SEC_OFFSET) + entry.time.tv_sec = IVAL(p,SME_USEC_OFFSET); + + (*mod_fn)( &entry, fsp->fd_ptr->dev, fsp->fd_ptr->inode, param); + + /* + * Now copy any changes the function made back into the buffer. + */ + + SIVAL(p,SME_PID_OFFSET, entry.pid) + SSVAL(p,SME_PORT_OFFSET,entry.op_port); + SSVAL(p,SME_OPLOCK_TYPE_OFFSET,entry.op_type); + SIVAL(p,SME_SHAREMODE_OFFSET,entry.share_mode); + SIVAL(p,SME_SEC_OFFSET,entry.time.tv_sec) + SIVAL(p,SME_USEC_OFFSET,entry.time.tv_sec); + found = True; break; } if(!found) { - DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname)); + DEBUG(0,("slow_mod_share_entry: entry not found in share file %s\n", fname)); if(buf) free(buf); return False; @@ -922,7 +945,7 @@ from the share file %s\n", i, num_entries, fname)); /* Re-write the file - and truncate it at the correct point. */ if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0) { - DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \ + DEBUG(0,("ERROR: slow_mod_share_entry: lseek failed to reset to \ position 0 for share mode file %s (%s)\n", fname, strerror(errno))); if(buf) free(buf); @@ -932,7 +955,7 @@ position 0 for share mode file %s (%s)\n", fname, strerror(errno))); fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries); if(write(fd, buf, fsize) != fsize) { - DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \ + DEBUG(0,("ERROR: slow_mod_share_entry: failed to re-write share \ mode file %s (%s)\n", fname, strerror(errno))); if(buf) free(buf); @@ -1048,7 +1071,7 @@ static struct share_ops share_ops = { slow_get_share_modes, slow_del_share_mode, slow_set_share_mode, - slow_remove_share_oplock, + slow_mod_share_entry, slow_share_forall, slow_share_status, }; diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 2dba691a1c..50ad01f575 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -142,6 +142,7 @@ void close_file(files_struct *fsp, BOOL normal_close) */ if (normal_close && last_reference && delete_on_close) { + DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n")); if(dos_unlink(fsp->fsp_name) != 0) DEBUG(0,("close_file: file %s. Delete on close was set and unlink failed \ with error %s\n", fsp->fsp_name, strerror(errno) )); diff --git a/source3/smbd/files.c b/source3/smbd/files.c index c369a45bab..e58c3834a0 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -277,6 +277,41 @@ files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval return NULL; } +/**************************************************************************** + Find the first fsp given a device and inode. +****************************************************************************/ + +files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) +{ + files_struct *fsp; + + for (fsp=Files;fsp;fsp=fsp->next) { + if (fsp->open && + fsp->fd_ptr->dev == dev && + fsp->fd_ptr->inode == inode ) + return fsp; + } + + return NULL; +} + +/**************************************************************************** + Find the next fsp having the same device and inode. +****************************************************************************/ + +files_struct *file_find_di_next(files_struct *start_fsp) +{ + files_struct *fsp; + + for (fsp = start_fsp->next;fsp;fsp=fsp->next) { + if (fsp->open && + fsp->fd_ptr->dev == start_fsp->fd_ptr->dev && + fsp->fd_ptr->inode == start_fsp->fd_ptr->inode ) + return fsp; + } + + return NULL; +} /**************************************************************************** find a fsp that is open for printing diff --git a/source3/smbd/open.c b/source3/smbd/open.c index b6b2ef5bb8..aac4b02fba 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -659,6 +659,26 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, int old_open_mode = GET_OPEN_MODE(share->share_mode); int old_deny_mode = GET_DENY_MODE(share->share_mode); + /* + * Setup the potential error to return. + */ + + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + + /* + * Don't allow any open once the delete on close flag has been + * set. + */ + + 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_code = ERRnoaccess; + return False; + } + if (old_deny_mode > 4 || old_open_mode > 2) { DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n", @@ -688,6 +708,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, *flags = O_WRONLY; } + return True; } @@ -865,8 +886,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou free((char *)old_shares); unlock_share_entry(conn, dev, inode, token); errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; return; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index bc19f1a931..babdd2056c 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3615,7 +3615,7 @@ no oplock granted on this file.\n", fsp->fnum)); /* Remove the oplock flag from the sharemode. */ lock_share_entry(fsp->conn, dev, inode, &token); - if(remove_share_oplock(fsp, token)==False) { + if(remove_share_oplock(token, fsp)==False) { DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode)); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f8d90cd871..1c2bdb1ddf 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1655,14 +1655,64 @@ static int call_trans2setfilepathinfo(connection_struct *conn, { if (tran_call == TRANSACT2_SETFILEINFO) { files_struct *fsp = file_fsp(params,0); + BOOL delete_on_close = (CVAL(pdata,0) ? True : False); + if(fsp->is_directory) return(ERROR(ERRDOS,ERRnoaccess)); + + /* + * 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 changed from its previous value 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(GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode) != delete_on_close) + { + int token; + files_struct *iterate_fsp; + SMB_DEV_T dev = fsp->fd_ptr->dev; + SMB_INO_T inode = fsp->fd_ptr->inode; + int new_share_mode = (delete_on_close ? + (fsp->share_mode | DELETE_ON_CLOSE_FLAG) : + (fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) ); + + 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->conn, dev, inode, &token) == False) + return(ERROR(ERRDOS,ERRnoaccess)); + + /* + * 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. + */ + + for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp; + iterate_fsp = file_find_di_next(iterate_fsp)) + { + if(modify_share_mode(token, iterate_fsp, new_share_mode)==False) + DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \ +dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode)); + } + + unlock_share_entry(fsp->conn, dev, inode, token); + } + /* * Set the delete on close flag in the reference * counted struct. Delete when the last reference * goes away. */ - fsp->fd_ptr->delete_on_close = CVAL(pdata,0); + fsp->fd_ptr->delete_on_close = delete_on_close; } else return(ERROR(ERRDOS,ERRunknownlevel)); break; |