From 3aeadef40b92d031036a50042bbf8fbe60d0954a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 4 Aug 1998 23:45:34 +0000 Subject: nttrans.c: Fix change_notify. Queue processing code wasn't changing to the correct directory before doing the stat. Doh ! uid.c: Fix for performance in security=share mode. Invalid vuid meant that in security=share mode Samba was always doing the become_user/ undebome_user pairs for *every* smb. This code fixes it, but tridge should review for security implications. Jeremy. (This used to be commit c3663379fdcec487feea2e5d848ee012ee6c6baf) --- source3/smbd/nttrans.c | 59 +++++++++++++++++++++++++++++++++++--------------- source3/smbd/uid.c | 13 ++++++++++- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index a30da8e6e03..1f724a4bfbd 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1071,6 +1071,19 @@ void process_pending_change_notify_queue(time_t t) continue; } + if(!become_service(cnum,True)) { + DEBUG(0,("process_pending_change_notify_queue: Unable to become service cnum=%d. \ +Error was %s.\n", cnum, strerror(errno) )); + /* + * Remove the entry and return an error to the client. + */ + change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess); + ubi_slRemNext( &change_notify_queue, prev); + cnbp = (change_notify_buf *)(prev ? ubi_slNext(prev) : ubi_slFirst(&change_notify_queue)); + unbecome_user(); + continue; + } + if(sys_stat(fsp->name, &st) < 0) { DEBUG(0,("process_pending_change_notify_queue: Unable to stat directory %s. \ Error was %s.\n", fsp->name, strerror(errno) )); @@ -1135,27 +1148,39 @@ static int call_nt_transact_notify_change(char *inbuf, char *outbuf, int length, if((!fsp->open) || (!fsp->is_directory) || (cnum != fsp->cnum)) return(ERROR(ERRDOS,ERRbadfid)); - /* - * Setup the current directory information in the - * directory entry in the files_struct. We will use - * this to check against when the timer expires. - */ - - if(sys_stat(fsp->name, &st) < 0) { - DEBUG(0,("call_nt_transact_notify_change: Unable to stat fnum = %d, name = %s. \ - Error was %s\n", fnum, fsp->name, strerror(errno) )); - return -1; - } - if(fsp->f_u.dir_ptr == NULL) { + + /* + * No currently stored directory info - we must + * generate it here. + */ + if((fsp->f_u.dir_ptr = (dir_status_struct *)malloc(sizeof(dir_status_struct))) == NULL) { DEBUG(0,("call_nt_transact_notify_change: Malloc fail !\n" )); return -1; } - } - fsp->f_u.dir_ptr->modify_time = st.st_mtime; - fsp->f_u.dir_ptr->status_time = st.st_ctime; + /* + * Setup the current directory information in the + * directory entry in the files_struct. We will use + * this to check against when the timer expires. + * NB. We only do this if there is no current directory + * information in the directory struct - as when we start + * monitoring file size etc. this information will start + * becoming increasingly expensive to maintain, so we won't + * want to re-generate it for every ChangeNofity call. + */ + + if(sys_stat(fsp->name, &st) < 0) { + DEBUG(0,("call_nt_transact_notify_change: Unable to stat fnum = %d, name = %s. \ +Error was %s\n", fnum, fsp->name, strerror(errno) )); + return -1; + } + + fsp->f_u.dir_ptr->modify_time = st.st_mtime; + fsp->f_u.dir_ptr->status_time = st.st_ctime; + + } /* * Now queue an entry on the notify change stack. We timestamp @@ -1183,8 +1208,8 @@ static int call_nt_transact_notify_change(char *inbuf, char *outbuf, int length, ubi_slAddTail(&change_notify_queue, cnbp); - DEBUG(3,("call_nt_transact_notify_change: notify change called on directory fid=%d, name = %s\n", - fnum, fsp->name )); + DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \ +fid=%d, name = %s\n", fnum, fsp->name )); return -1; } diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 82ff7ee7cea..9e669c301b9 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -216,7 +216,18 @@ BOOL become_user(connection_struct *conn, int cnum, uint16 vuid) int snum,gid; int uid; - if ((current_user.cnum == cnum) && (vuser != 0) && (current_user.vuid == vuid) && + /* + * We need a separate check in security=share mode due to vuid + * always being UID_FIELD_INVALID. If we don't do this then + * in share mode security we are *always* changing uid's between + * SMB's - this hurts performance - Badly. + */ + + if((lp_security() == SEC_SHARE) && (current_user.cnum == cnum) && + (current_user.uid == conn->uid)) { + DEBUG(4,("Skipping become_user - already user\n")); + return(True); + } else if ((current_user.cnum == cnum) && (vuser != 0) && (current_user.vuid == vuid) && (current_user.uid == vuser->uid)) { DEBUG(4,("Skipping become_user - already user\n")); return(True); -- cgit